Servlet的使用

199 阅读4分钟

本文介绍Servlet的使用。

Servlet简介

Servlet是java提供的一套动态Web资源开发技术。其实Servlet是JavaEE的一套规范,也就是接口,然后我们实现接口,web服务器运行Servlet。

在JavaWeb中Servlet用于接收Client的请求并处理请求,最后根据Client的请求信息返回相应的结果,这个结果可以是一个json字符串也可以是一个html页面(如果返回html则称为动态html)。

快速入门

  1. 导入依赖
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>servlet-api</artifactId>
  <version>3.0-alpha-1</version>
  <scope>provided</scope>
</dependency>
  • scope必须是provided,provided只在编译和测试环境有效,正是环境不存在。因为tomcat自带Servlet的依赖,会有冲突。
  • Tomcat10使用了jakarta版本的servlet api,所以建议开发时使用真实web服务器内tomcat里的那个servlet的jar包(servlet-api.jar),不然会出现各种奇怪的问题。
  1. 实现Servlet接口,并重写service方法
@WebServlet("/login")
class LoginServlet : GenericServlet() {

    override fun service(p0: ServletRequest?, p1: ServletResponse?) {
        println("hello")
    }
}
  • 这里不直接实现Servlet接口是因为Servlet接口要重写的方法太多了,GenericServlet类实现了Servlet接口并重写了很多方法。
  • 使用了注解后web.xml中就可以不用再去配置了。
  1. 启动

浏览器访问http://localhost:8088/tomcat_demo_war/login

小结:Servlet由Tomcat服务器创建并运行,当我们使用url访问Servlet时,Tomcat服务器会为我们运行service方法。

Servlet生命周期

Servlet的生命周期由web服务器管理,分四个阶段:

  1. 加载和实例化:默认情况下,当Servlet第一次被访问时创建,还可以提前到在web服务器启动时就创建(注解时使用loadOnStartup属性配置,数字越小优先级越高)。
  2. 初始化:init方法,Servlet实例化后会调用,并且只会调用一次
  3. 处理请求:service方法,每次请求时都会调用servce方法。
  4. 服务中止:当需要释放内存或者容器关闭时,会调用destroy方法,只调用一次。

Servlet的urlPattern配置

以前都是用web.xml配置servlet信息,现在用WebServlet注解了,urlPattern分四种类型:

  1. 精确匹配

    • 配置路径:@WebServlet("/user/login")
    • 访问路径:localhost:8088/xxx/user/login
  2. 目录匹配

    • 配置路径:@WebServlet("/user/*")
    • 访问路径:localhost:8088/xxx/user/aaa或者localhost:8088/xxx/user/bbb
  3. 扩展名匹配

    • 配置路径:@WebServlet("*.txt")
    • 访问路径:localhost:8088/xxx/a.txt或者localhost:8088/xxx/b.txt
  4. 任意匹配

    • 配置路径:@WebServlet("/")或者@WebServlet("/*")
    • 访问路径:localhost:8088/xxx/haha或者localhost:8088/xxx/hehe
  • 对于/,如果我们项目里配置了/那就会覆盖掉Tomcat默认DefaultServlet,默认情况下如果其他url-pattern都匹配不上时走DefaultServlet
  • 如果配置了/*,意味着匹配任意路径
  • 匹配优先级:精确路径>目录路径>扩展名匹配>/*>/

web.xml配置Servlet信息

webapp/web-inf/web.xml文件里配置,举个例子如下:

<servlet>
  <servlet-name>MapServlet</servlet-name>
  <servlet-class>com.mawei.tomcat.MapServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>MapServlet</servlet-name>
  <url-pattern>/map</url-pattern>
</servlet-mapping>

这里的url-pattern与注解urlPattern类似。

关于请求参数乱码问题

  • 对于post请求,使用req.setCharacterEncoding("UTF-8")就行

  • 对于get请求,由于http协议存在url encoding,所以浏览器使用utf-8对参数进行编码,之后tomcat服务端解析时默认使用ISO-8859-1编码解析,所以乱码了,解决方案有两种:

    1. 对于每个Servlet使用Java中的URLDecoder.decode(text,"UTF-8")进行解码。
    2. 使用过滤器过滤所有请求
    3. 修改tomcat配置文件中的编码设置

请求转发

把请求转发给另外一个Servlet处理。

req?.getRequestDispatcher("新路径")?.forward(req,resp)

可以使用req.setAttribute()设置转发数据

特点:

  1. 浏览器请求路径不改变
  2. 只能转发到当前服务器内部
  3. 一次请求,可以在转发的资源里使用request共享数据

Response重定向

重定向是指如果某个请求当前Servlet无法处理,但是它知道哪里可以处理,所以告诉客户端哪里可以处理,客户端收到返回结果后就发起一次新请求到新的路径处理。

resp?.status = 302
resp?.setHeader("location","新资源path")
//或者
resp?.sendRedirect("新资源path")

特点:

  1. 浏览器地址发生变化
  2. 可以重定向到任意资源(会有两次请求,)
  3. 不能通过request共享数据(有可能是两个域名,两个服务器)

路径问题

  • 浏览器使用:需要加上虚拟目录
  • 服务端使用:不需要加虚拟目录

举个例子:

  1. <a href='路径'/> 加虚拟目录
  2. <form acton='路径'/> 加虚拟目录
  3. req.getDispatcher 不加虚拟目录
  4. resp?.sendRedirect("新资源path") 加虚拟目录

可以使用req.contextPath动态获取虚拟目录。

Response返回数据

Servlet中的Response即可以返回字符数据也可以返回字节数据,字符数据用于返回一些简单的字符串和html,而字节数据一般用于处理文件,譬如返回一张图片或者一个视频的二进制数据。

  • 返回字符数据
resp?.writer对象处理
  • 返回字节数据
resp?.outputStream对象处理

ps:可以使用commons-io处理一些简单的流操作。