本文介绍Servlet的使用。
Servlet简介
Servlet是java提供的一套动态Web资源开发技术。其实Servlet是JavaEE的一套规范,也就是接口,然后我们实现接口,web服务器运行Servlet。
在JavaWeb中Servlet用于接收Client的请求并处理请求,最后根据Client的请求信息返回相应的结果,这个结果可以是一个json字符串也可以是一个html页面(如果返回html则称为动态html)。
快速入门
- 导入包依赖
<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),不然会出现各种奇怪的问题。
- 实现Servlet接口,并重写service方法
@WebServlet("/login")
class LoginServlet : GenericServlet() {
override fun service(p0: ServletRequest?, p1: ServletResponse?) {
println("hello")
}
}
- 这里不直接实现Servlet接口是因为Servlet接口要重写的方法太多了,
GenericServlet类实现了Servlet接口并重写了很多方法。 - 使用了注解后web.xml中就可以不用再去配置了。
- 启动
浏览器访问http://localhost:8088/tomcat_demo_war/login
小结:Servlet由Tomcat服务器创建并运行,当我们使用url访问Servlet时,Tomcat服务器会为我们运行service方法。
Servlet生命周期
Servlet的生命周期由web服务器管理,分四个阶段:
- 加载和实例化:默认情况下,当Servlet第一次被访问时创建,还可以提前到在web服务器启动时就创建(注解时使用loadOnStartup属性配置,数字越小优先级越高)。
- 初始化:
init方法,Servlet实例化后会调用,并且只会调用一次。 - 处理请求:service方法,每次请求时都会调用
servce方法。 - 服务中止:当需要释放内存或者容器关闭时,会调用
destroy方法,只调用一次。
Servlet的urlPattern配置
以前都是用web.xml配置servlet信息,现在用WebServlet注解了,urlPattern分四种类型:
-
精确匹配
- 配置路径:
@WebServlet("/user/login") - 访问路径:
localhost:8088/xxx/user/login
- 配置路径:
-
目录匹配
- 配置路径:
@WebServlet("/user/*") - 访问路径:
localhost:8088/xxx/user/aaa或者localhost:8088/xxx/user/bbb
- 配置路径:
-
扩展名匹配
- 配置路径:
@WebServlet("*.txt") - 访问路径:
localhost:8088/xxx/a.txt或者localhost:8088/xxx/b.txt
- 配置路径:
-
任意匹配
- 配置路径:
@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编码解析,所以乱码了,解决方案有两种:
- 对于每个Servlet使用Java中的
URLDecoder.decode(text,"UTF-8")进行解码。 - 使用过滤器过滤所有请求
- 修改tomcat配置文件中的编码设置
- 对于每个Servlet使用Java中的
请求转发
把请求转发给另外一个Servlet处理。
req?.getRequestDispatcher("新路径")?.forward(req,resp)
可以使用req.setAttribute()设置转发数据
特点:
- 浏览器请求路径不改变
- 只能转发到当前服务器内部
- 一次请求,可以在转发的资源里使用request共享数据
Response重定向
重定向是指如果某个请求当前Servlet无法处理,但是它知道哪里可以处理,所以告诉客户端哪里可以处理,客户端收到返回结果后就发起一次新请求到新的路径处理。
resp?.status = 302
resp?.setHeader("location","新资源path")
//或者
resp?.sendRedirect("新资源path")
特点:
- 浏览器地址发生变化
- 可以重定向到任意资源(会有两次请求,)
- 不能通过request共享数据(有可能是两个域名,两个服务器)
路径问题
- 浏览器使用:需要加上虚拟目录
- 服务端使用:不需要加虚拟目录
举个例子:
<a href='路径'/>加虚拟目录<form acton='路径'/>加虚拟目录req.getDispatcher不加虚拟目录resp?.sendRedirect("新资源path")加虚拟目录
可以使用req.contextPath动态获取虚拟目录。
Response返回数据
Servlet中的Response即可以返回字符数据也可以返回字节数据,字符数据用于返回一些简单的字符串和html,而字节数据一般用于处理文件,譬如返回一张图片或者一个视频的二进制数据。
- 返回字符数据
resp?.writer对象处理
- 返回字节数据
resp?.outputStream对象处理
ps:可以使用commons-io处理一些简单的流操作。