文章目录
1、Servlet概述
1_介绍
-
S e r v l e t Servlet Servlet 是一个接口,即规范。
-
定义的实现类必须实现接口中的所有的抽象方法。
-
S e r v l e t Servlet Servlet 全称 Server Applet 服务器端的程序。
是 S u n Sun Sun公司提供一套规范,用来处理客户端请求、响应给浏览器的动态web资源。
其实 S e r v l e t Servlet Servlet的实质就是 j a v a java java代码,通过 j a v a java java的 A P I API API动态的向客户端输出内容,并且从客户端接收数据。
-
一个类要想通过浏览器被访问到,那么这个类就必须直接或间接的实现 S e r v l e t Servlet Servlet 接口。
2_Servlet作用
浏览器访问的静态资源即html。
web资源除了静态资源还有动态资源,即数据可以实现变化,并且前端浏览器通过动态资源可以实现数据的交互。
那么如果想实现客户端访问服务器的动态资源,需要我们在后端中定义类直接或者间接实现 S e r v l e t Servlet Servlet接口。
- 接收客户端的请求
- 处理业务逻辑
- 响应数据给浏览器客户端
2、Servlet开始
1_结构
2_实现步骤
1.创建web项目
2.导入 S e r v l e t Servlet Servlet 依赖
<!--导入servlet依赖-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
3.在创建的web项目中自定义类实现 S e r v l e t Servlet Servlet接口
4.在自定义类中实现 S e r v l e t Servlet Servlet接口中的所有的抽象方法
import javax.servlet.*;
import java.io.IOException;
//3.在创建的web项目中自定义类实现Servlet接口
public class HelloWorldServlet implements Servlet {
//4.在自定义类中实现Servlet接口中的所有的抽象方法 ctrl+i
@Override
public void init(ServletConfig config) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
//5.在实现Servlet接口的service方法体中书写代码处理业务逻辑
System.out.println("servlet入门案例");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
5.在实现
S
e
r
v
l
e
t
Servlet
Servlet接口的service
方法体中书写代码处理业务逻辑
void service(ServletRequest req, ServletResponse res)
6.在web项目的核心配置文件web.xml
中配置访问
s
e
r
v
l
e
t
servlet
servlet 的路径。
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<display-name>Archetype Created Web Application</display-name>
<!--
5.在web项目的核心配置文件web.xml中配置访问servlet的路径。
说明:这样配置是告知tomcat有具体的Servlet类需要被访问。
-->
<!--
1.<servlet> 表示将当前Servlet类注册到tomcat中,告知tomcat有一个类要被访问
一个servlet标签对应一个servlet对象
-->
<servlet>
<!--
表示当前要被访问类的标识,在当前web.xml中要唯一,helloWorldServlet属于标识符
-->
<servlet-name>helloWorldServlet</servlet-name>
<!--
配置要访问 的servlet类,必须是类的全路径:包名.类名。
说明:tomcat底层通过获取这里的类全路径使用反射技术调用当前类的无参构造方法创建对象
-->
<servlet-class>com.example.sh.HelloWorldServlet</servlet-class>
</servlet>
<!--
配置要访问的servlet类的映射路径
-->
<servlet-mapping>
<!--这里要和上面的servlet-name文本值一致,这里找到上面的servlet-name-->
<servlet-name>helloWorldServlet</servlet-name>
<!--浏览器上地址栏上输入的映射路径及访问路径,这里必须加/-->
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
说明:这样配置是告知 t o m c a t tomcat tomcat有具体的 S e r v l e t Servlet Servlet类需要被访问。
7.启动 t o m c a t tomcat tomcat
8.在浏览器中访问 S e r v l e t Servlet Servlet 类
3_执行原理
说明:
-
当我们运行的时候, t o m c a t tomcat tomcat之所以会启动,是因为程序入口(main方法)在 t o m c a t tomcat tomcat中
-
t o m c a t tomcat tomcat开始运行,会加载web项目里面的配置文件
web.xml
(xml解析,读取数据)主要是根据
url-pattern
找到对应的servlet-class
-
然后 t o m c a t tomcat tomcat 进入等待状态(永不停止,除非手动关闭)
-
当用户在浏览器中输入地址:
http://localhost:8080/hello
就会定位到 t o m c a t tomcat tomcat的访问的项目下面的某个 s e r v l e t servlet servlet中 -
t o m c a t tomcat tomcat会根据
/hello
的 s e r v l e t servlet servlet的虚拟路径 找到HelloServlet
的全限定名 -
t o m c a t tomcat tomcat底层通过反射创建
HelloServlet
的对象,并调用HelloServlet
的service
方法:Class clazz = Class.forName("全限定名"); Servlet servlet = clazz.newInstance();//实际上HelloServlet对象,向上转型 servlet.service();
4_生命周期
生命周期:指的是一个对象从生(创建)到死(销毁)的一个过程。
生命周期的api
:
// 1. servlet对象创建完毕,使用对象调用此方法,初始化方法,只有在第一次访问的时候执行一次
public void init(ServletConfig servletConfig);
// 2. 用户访问servlet时,调用此方法 (每次访问都会调用一次)
public void service(ServletRequest servletRequest, ServletResponse servletResponse);
// 3. servlet对象销毁时,调用此方法
public void destroy();
S
e
r
v
l
e
t
Servlet
Servlet 生命周期的api
执行时机图解
-
创建(默认情况下)
用户第一次访问时, t o m c a t tomcat tomcat 服务器创建 s e r v l e t servlet servlet,执行
init
方法 -
运行(提供服务)
用户每次访问时,都执行
service
方法 -
销毁
服务器正常关闭时, t o m c a t tomcat tomcat 服务器销毁 s e r v l e t servlet servlet,执行
destroy
方法
代码实现:
import javax.servlet.*;
import java.io.IOException;
public class Life01Servlet implements Servlet {
/*
反射调用无参构造方法创建对象
*/
public Life01Servlet() {
System.out.println("无参构造方法执行了......");
}
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("init......");
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("service......");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
System.out.println("destroy......");
}
}
结果:
5_配置立刻加载
服务器启动,立刻加载 S e r v l e t Servlet Servlet对象:
-
问题:发现
init
默认第一次被访问的时候才调用,适合用来初始化项目数据如果项目数据很多,加载就需要一定的时间,这样就会给用户的体验不好,因为要等比较久的时间
-
解决:服务器一启动,就执行
init
方法 -
实现:在
web.xml
核心配置文件中对应的 s e r v l e t servlet servlet 标签中按照如下配置:
注意:
使用
<load-on-startup></load-on-startup>
标签进行配置,表示标记容器是否应该在启动的时候加载这个 s e r v l e t servlet servlet(实例化并调用其init()
方法)它的文本值必须是一个整数,表示 s e r v l e t servlet servlet应该被载入的顺序
如果文本值是负数:默认值是
-1
【用户第一次访问时,创建】当值大于等于0时,表示容器在应用启动时就加载并初始化这个 s e r v l e t servlet servlet;
正数的值越小,该 s e r v l e t servlet servlet的优先级越高,应用启动时就越先加载。
当值相同时,容器就会自己选择顺序来加载
<servlet>
<servlet-name>life01Servlet</servlet-name>
<servlet-class>com.example.sh.Life01Servlet</servlet-class>
<!--
load-on-startup 标签可以让tomcat服务器启动就创建对应的servlet。标签文本值必须是整数:
数字越小,创建servlet的优先级越高
-->
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>life01Servlet</servlet-name>
<url-pattern>/life01</url-pattern>
</servlet-mapping>
load-on-startup
标签可以让
t
o
m
c
a
t
tomcat
tomcat服务器启动就创建对应的
s
e
r
v
l
e
t
servlet
servlet。标签文本值必须是整数——数字越小,创建
s
e
r
v
l
e
t
servlet
servlet的优先级越高,建议是大于等于0的整数。
<load-on-startup>2</load-on-startup>
配置load-on-startup
标签后
s
e
r
v
l
e
t
servlet
servlet生命周期如下:
6_Servlet实现方式
一共有三种:
1.自定义类实现 S e r v l e t Servlet Servlet接口
2.自定义类继承抽象类GenericServlet
解决问题:
-
S
e
r
v
l
e
t
Servlet
Servlet中使用频率最高,最重要的方法是
service
方法(大部分场景),但是我们每次编写 S e r v l e t Servlet Servlet实现类,都是直接实现 S e r v l e t Servlet Servlet接口,重写5个抽象方法(太冗余了) - 我们可以自定义类继承GenericServlet抽象类,只在子类中重写
service
即可。不用重写所有的抽象方法。
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
/*
1.自定义类继承GenericServlet类
*/
public class Demo01Servlet extends GenericServlet {
// 2.在子类中重写service方法,处理业务逻辑
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("service....");
}
}
在web.xml
中进行映射路径的配置
<!--3.在web.xml中进行映射路径的配置-->
<servlet>
<servlet-name>demo01Servlet</servlet-name>
<servlet-class>com.example.sh.Demo01Servlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>demo01Servlet</servlet-name>
<url-pattern>/demo01</url-pattern>
</servlet-mapping>
3.自定义类继承抽象类HttpServlet 重点
解决问题:
-
我们在前端的常用的请求方式有两种(
get/post
)。 -
但我们现在的
service
方法无论什么请求方式都会统一的执行service
方法,我们无法很好的区别是哪一种请求方式。 -
解决问题:我们可以自定义类继承HttpServlet就可以根据不同的请求做不同的处理:
get/post
。
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/*
1.自定义类继承HttpServlet
*/
public class Demo02Servlet extends HttpServlet {
/*
2.在子类中根据不同的请求方式重写请求方式的方法:
get请求---重写doGet方法
post请求---重写doPost方法
*/
// 3.在方法体中书写处理业务逻辑的代码
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//GET请求执行的方法
System.out.println("get....");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//POST请求执行的方法
System.out.println("post....");
}
}
实现 s e r v l e t servlet servlet方式三的好处:
-
可以根据不同的请求执行对应的方法
-
可以处理满足 h t t p http http协议的请求和响应
ServletRequest这个对象封装了浏览器发送的所有请求数据,兼容大部分协议。
HttpServletRequest是子接口,可以匹配 h t t p http http协议下的所有请求。
执行流程
正常浏览器访问
t
o
m
c
a
t
tomcat
tomcat服务器需要访问
s
e
r
v
l
e
t
servlet
servlet接口中的service
方法,但是方式三在子类中没有重写
s
e
r
v
l
e
t
servlet
servlet中的service
方法,只重写了doGet
和doPost
方法,那么底层是如何执行的呢?
当我们访问自定义类的
s
e
r
v
l
e
t
servlet
servlet的时候先访问HttpServlet类实现
S
e
r
v
l
e
t
Servlet
Servlet接口中的service
方法,在service
方法体中调用了重载的service
方法,在该方法体内部获取请求方式,根据不同的请求方式来执行对应的方法。
7_Servlet映射路径
一个
S
e
r
v
l
e
t
Servlet
Servlet映射单个url
:
一个
S
e
r
v
l
e
t
Servlet
Servlet映射多个url
:
注解版本:
8_Servlet映射路径配置规范
s e r v l e t servlet servlet 映射路径一共有四种:
1.完全路径匹配:就是访问什么在web.xml的<url-pattern>/path02</url-pattern>
标签文本中配置什么路径。/hello /user
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
public class PathOneServlet extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("PathOneServlet....");
}
}
<servlet>
<servlet-name>pathOneServlet</servlet-name>
<servlet-class>com.example.sh.PathOneServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>pathOneServlet</servlet-name>
<!--完全路径匹配-->
<url-pattern>/user/one</url-pattern>
</servlet-mapping>
2.目录匹配:/user/*
只要访问以/user
开始的的路径都可以访问对应的
S
e
r
v
l
e
t
Servlet
Servlet。
public class PathTwoServlet extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("PathTwoServlet....");
}
}
<servlet>
<servlet-name>pathTwoServlet</servlet-name>
<servlet-class>com.example.sh.PathTwoServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>pathTwoServlet</servlet-name>
<!--目录匹配-->
<url-pattern>/user/*</url-pattern>
</servlet-mapping>
3.后缀名匹配:*.do *.action
(注意这里不能书写/
),访问以.do
或者.action
结尾的资源路径(后缀都属于标识符)。
<servlet>
<servlet-name>pathThrServlet</servlet-name>
<servlet-class>com.example.sh.PathThrServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>pathThrServlet</servlet-name>
<!--后缀名匹配,前面不能加/-->
<url-pattern>*.do</url-pattern>
</servlet-mapping>
4.缺省路径:/
如果上述三种路径都不满足就访问缺省路径。
<servlet>
<servlet-name>pathFourServlet</servlet-name>
<servlet-class>com.example.sh.PathFourServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>pathFourServlet</servlet-name>
<!--缺省路径匹配-->
<url-pattern>/</url-pattern>
</servlet-mapping>
后缀名匹配和缺省路径都不推荐去配置:
-
缺省路径会使如
index.html
这种资源无法被访问,只能访问缺省路径的 s e r v l e t servlet servlet。 -
后缀名匹配也会导致某一类后缀的静态资源无法访问,比如:
.html
。
上述访问路径的优先级: 完全路径匹配 > 目录匹配 > 后缀名匹配 > 缺省路径 。
9_相对路径
绝对路径两种写法:
-
带网络三要素的绝对路径:
http://ip地址:端口号/资源路径
-
不带网络三要素的绝对路径:
/
资源路径 这里的/
不能省略 ,要求访问的资源必须在同一个服务器上。
相对路径:不是相对当前项目,而是针对当前浏览器地址栏上的url
而言的。
案例:
-
假设我们在浏览器地址栏访问的页面路径:
http://localhost:8080/demo01.html
。 -
而在
demo01.html
页面想使用相对路径访问 s e r v l e t servlet servlet:http://localhost:8080/pathAbso
说明:
-
如果在
http://localhost:8080/demo01.html
页面中访问http://localhost:8080/pathAbso
的 s e r v l e t servlet servlet,我们通过url
观察发现只有最后一级目录不一样。 -
所以在
demo01.html
页面中相对的路径的写法是:./pathAbso
这里的./
表示当前路径,可以省略不写即直接写pathAbso
。
10_常见问题
1.遇到500错误
表示服务器内部异常。
2.遇到404错误
浏览器客户端访问服务器的资源不存在。
注意:报404的根本原因是用户操作不当导致的。
3.遇到405错误
服务器
s
e
r
v
l
e
t
servlet
servlet 没有重写doGet
或者doPost
方法。
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/*
TODO:编写Servlet常见异常
1.服务器内部出现异常===在浏览器中显示的是500:HTTP Status 500 – Internal Server Error
解决方案:找出异常位置修改代码
2.浏览器出现404===就是用户问题,用户操作不当,访问的资源在服务器中不存在,基本都是路径有问题。HTTP Status 404 – Not Found
解决方案:
1)查看你在地址栏上输入的地址路径和服务器中的资源路径是否匹配
2)当前项目配置了虚拟路径,但是你访问的时候没有加虚拟路径
3) 访问的路径在当前项目中存在,但是在当前项目中的target位置不存在,
执行maven生命周期命令===clean清除target,重启启动tomcat即可
3.浏览器出现405===子类Servlet没有重写父类HttpServlet类中的doGet和doPost方法导致调用了父类
HttpServlet中doGet和doPost方法 HTTP Status 405 – Method Not Allowed
解决方案:子类重写HttpServlet的doGet和doPost方法,并且在子类方法体中不能调用父类中的doGet和doPost方法,不能书写:
super.doGet(req, resp);
*/
public class ExceptionDemo01Servlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//调用父类HttpServlet类中doGet(req, resp),那么就会报错HTTP Status 405 – Method Not Allowed
//详见父类源码
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
4.启动服务器报错
注意:只要启动服务器报错基本都是你的路径有问题。
路径没有书写 /
:
<url-pattern>demo04</url-pattern>
3、Servlet3.0注解开发
t o m c a t tomcat tomcat 7以上的版本都支持 S e r v l e t Servlet Servlet 3.0
使用web.xml
配置映射路径的方式属于
s
e
r
v
l
e
t
2.5
servlet2.5
servlet2.5的技术。
从
s
e
r
v
l
e
t
3.0
servlet3.0
servlet3.0开始引入注解配置访问
s
e
r
v
l
e
t
servlet
servlet取代了web.xml
配置。
1_Servlet3.0新增特性
- 注解支持;
S
e
r
v
l
e
t
Servlet
Servlet、Filter、Listener无需在
web.xml
中进行配置,可以通过对应注解进行配置; - 支持Web模块;
- S e r v l e t Servlet Servlet异步处理;
- 文件上传API简化;
2_Servlet3.0的注解
@WebServlet
:修饰 S e r v l e t Servlet Servlet类,用于部署 S e r v l e t Servlet Servlet类。@WebFilter
:修饰Filter类,用于部署Filter类@WebInitParam
:与@WebServlet
或@WebFilter
注解连用,为它们配置参数@MultipartConfig
:修饰 S e r v l e t Servlet Servlet类,指定该 S e r v l e t Servlet Servlet类负责处理multipart/form-data
类型的请求(主要用于处理上传文件)@ServletSecurity
:修饰 S e r v l e t Servlet Servlet类,与 J A A S JAAS JAAS(Java验证和授权API)有关的注解@HttpConstrait
:与@ServletSecurity
连用@HttpMethodConstrait
:与@ServletSecurity
连用
示例代码片:
修饰过滤器Filter:
@WebFilter(
filterName="log",
urlPatterns={"/*"},
initParams={
@WebInitParam(name="encoding",value="GBK"),
@WebInitParam(name="loginPage",value="/login.jsp")
})
public class MyFilter implements Filter {
//内容省略......
}
修饰 S e r v l e t Servlet Servlet
@WebServlet(name="test",
urlPatterns={"/basic.do"},
initParams={
@WebInitParam(name="userName",value="peter"),
@WebInitParam(name="age",value="100")
})
public class TestServlet extends HttpServlet{
//内容省略....
}
修饰监听器Listener:
@WebListener
public class MyRequestListener implements ServletRequestListener{
//内容省略...
}
3_Servlet3.0的Web模块支持
-
原来一个web应用的任何配置都需要在
web.xml
中进行,因此会使得web.xml
变得很混乱,而且灵活性差。现在可通过Web模块来部署管理它们。 -
Web模块对应一个Jar包,即 S e r v l e t Servlet Servlet 3.0可以将每个 S e r v l e t Servlet Servlet、Filter、Listener 打成jar包,然后放在
WEB-INF\lib
中。 -
每个模块都有自己的配置文件,这个配置文件的名称为
web-fragment.xml
。 -
制作一个 S e r v l e t Servlet Servlet 模块的步骤:
- 正常编写 S e r v l e t Servlet Servlet,并编译;
- 将此编译
class
文件及所在包通过jar包命令打成jar包; - 将此jar包用winrar打开,将
META-INF
中的manifest
删除后添加web-fragment.xml
; - 将此jar包放入
WEB-INF\lib
中即可;
-
web-fragment.xml
说明:<web-fragment>
为根元素;<name></name>
表示模块名称(模块的唯一标识);<ordering></ordering>
定义模块加载顺序的标签,当然可以不设置模块加载顺序;<before><others/></before>
表示在所有模块前面加载(第一个加载);<after><name>A</name></after>
表示在A模块后面加载;- 可以在里面部署 listener、filter、 s e r v l e t servlet servlet
- 值得注意的是,
web.xml
中用<absolute-ordering>
标签指定的模块加载顺序将会覆盖web模块的web-fragment.xml
文件中指定的加载顺序。
-
如何用myEclipse打jar包(有些人不知道)
右键你web项目里的编写的 s e r v l e t servlet servlet(或filter或listener)类——>Export…——>JAR file——>NEXT——>(Browser)填写导出名字和存放位置——>finish
这样就生成了我们需要的jar包了
-
示例
s e r v l e t servlet servlet类代码片:
@WebServlet(name="test",urlPatterns={"/basic.do"})
public class TestServlet extends HttpServlet{
//使用该方法可响应客户端的所有请求
public void service(HttpServletRequest req, HttpServletResponse resp)throws IOException{
System.out.println("进servlet了");
PrintStream out = new PrintStream(resp.getOutputStream());
//向页面输入下面字符串
out.print("1234567890");
}
}
web-fragment.xml
代码片
<web-fragment version="4.0" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-fragment_4_0.xsd">
<!-- 这里可以定义过滤器、Servlet等 -->
<!-- 指定模块名称 :唯一标识-->
<name>mySerModule</name>
<!-- 加载顺序 -->
<ordering>
<!-- 在其它模块之前加载 -->
<before>
<others/>
</before>
</ordering>
</web-fragment>
在web-fragment.xml
里的配置和之前的web.xml
里类似,如果是注解实现的
s
e
r
v
l
e
t
servlet
servlet的配置,则在web-fragment.xml
里就将不再写配置了,如果不是,则还需要写配置。
打成jar包放在一个项目里面启动后,就可通过上面
s
e
r
v
l
e
t
servlet
servlet注解配置的/basic.do
路径访问上面的service
了。
4_Servlet3.0提供的异步处理
提供异步原因
在以前的 s e r v l e t servlet servlet中,如果作为控制器的 s e r v l e t servlet servlet调用了一个较为耗时的业务方法,则 s e r v l e t servlet servlet必须等到业务执行完后才会生成响应,这使得这次调用成了阻塞式调用,效率比较差。
实现异步原理
重新开一个线程单独去调用耗时的业务方法。
配置servlet类成为异步的servlet类
- 通过注解
asyncSupported=true
实现 - 通过
web.xml
配置
<servlet>
<servlet-name>test1</servlet-name>
<servlet-class>com.example.servlet.AsyncServlet</servlet-class>
<async-suppored>true</async-suppored>
</servlet>
<servlet-mapping>
<servlet-name>test1</servlet-name>
<url-pattern>/basic.do</url-pattern>
</servlet-mapping>
具体实现
java代码:
@WebServlet(name = "AsyncServlet", urlPatterns = {"/testAsyn.do"}, asyncSupported = true)
public class AsyncServlet extends HttpServlet {
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//解决乱码
request.setCharacterEncoding("GBK");
response.setContentType("text/html;charset=GBK");
//通过request获得AsyncContent对象
AsyncContext actx = request.startAsync(); //重点方法**
//设置异步调用超时时长
actx.setTimeout(30 * 3000);
//启动异步调用的线程
actx.start(new MyThread(actx));//重点方法**
// 直接输出到页面的内容(不等异步完成就直接给页面)
//但这些内容必须放在标签内,否则会在页面输出错误内容,这儿反正我测试是这样,具体不知对不对??
PrintWriter out = response.getWriter();
out.println("<h1>不等异步返回结果就直接返到页面的内容</h1>");
out.flush();
}
}
//异步处理业务的线程类
public class MyThread implements Runnable {
private AsyncContext actx;
//构造
public MyThread(AsyncContext actx) {
this.actx = actx;
}
public void run() {
try {
//等待5秒,模拟处理耗时的业务
Thread.sleep(4 * 1000);
//获得request对象,添加数据给页面
ServletRequest req = actx.getRequest();
req.setAttribute("content", "异步获得的数据");
//将请求dispath到index.jsp页面,该页面的session必须设为false
actx.dispatch("/index.jsp");
} catch (Exception e) {
e.printStackTrace();
}
}
}
页面代码(页头里session
设为false
,表时该页面不会再创建session
):
<%@ page language="java" import="java.util.*" pageEncoding="utf-8" session="false"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<html>
<body>
<a href="<%=basePath%>/testAsyn.do">测试异步调用</a>
异步结果:${content}
</body>
</html>
异步监听器
异步监听器用来监听异步
S
e
r
v
l
e
t
Servlet
Servlet的异步处理事件,通过实现AsyncListener
接口实现,代码如下:
public class MyAsyncListener implements AsyncListener{
//异步调用完成时触发
@Override
public void onComplete(AsyncEvent event) throws IOException {
// 省略....
}
//异步调用出错时触发
@Override
public void one rror(AsyncEvent event) throws IOException {
// 省略....
}
//异步调用开始触发
@Override
public void onStartAsync(AsyncEvent event) throws IOException {
// 省略....
}
//异步调用超时触发
@Override
public void onTimeout(AsyncEvent event) throws IOException {
// 省略....
}
}
还需要在异步 S e r v l e t Servlet Servlet里注册异步监听器,即添加如下代码即可:
actx.addListener(new MyAsyncListener());
Filter异步调用与 S e r v l e t Servlet Servlet一样。
改进的ServletAPI(上传文件)
-
改进内容
- HttpServletRequest增加了对上传文件的支持
- ServletContext允许通过编程的方式动态注册 S e r v l e t Servlet Servlet、Filter
-
HttpServletRequest提供了如下两个方法处理文件的上传
-
Part getPart(String name)
根据名称获取文件上传域 -
Collection<Part> getParts()
获取所有文件上传域
-
-
上传文件时一定要为表单域设置enctype属性,它表示表单数据的编码方式,有如下三个值:
application/x-www-form-urlencoded
(默认),它只处理表单里的value属性值,它会将value值处理成URL编码方式。如果此时表单域里有上传文件的域(
type="file"
),则只会获取该文件在上传者电脑里的绝对路径串,该串没什么实际意义。multipart/form-data
此处编码方式会以二制流的方式来处理表单数据,此时会将文件内容也封装到请求参数里。texst/plain
当表单的action属性为mailto:URL
的形式时比较方便,主要适用于直接通过表单发送邮件的方式
-
上传文件的 S e r v l e t Servlet Servlet需要加上
@MultipartConfig
注解 -
通过
request
获取的Part对象就可以操作文件域了 -
示例
@WebServlet(name="uploadServlet",urlPatterns="/upload.do")
@MultipartConfig
public class UploaderServlet extends HttpServlet {
public void service(HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException{
//获得Par对象(每个Part对象对应一个文件域)
Part part = request.getPart("file");
long size = part.getSize(); //获取上传文件大小
String info = part.getHeader("content-disposition");//获得包含原始文件名的字符串
//获取原始文件名
String fileName = info.substring(info.indexOf("filename=\"")+10,info.length()-1);
//将文件上传到某个位置
part.write(getServletContext().getRealPath("/uploadFiles")+"/"+fileName);
}
}
ServletContext提供了如下方法动态注册 S e r v l e t Servlet Servlet、Filter
addServlet()
; 动态注册 S e r v l e t Servlet ServletaddFilter()
; 动态注册FilteraddListener()
; 动态注册ListenersetInitParameter(String name ,String value)
; 为Web应用设置初始化参数。
5_展望
S e r v l e t Servlet Servlet 4.0 中也引入了一些重要的新特性:
-
HTTP/2 支持:
- S e r v l e t Servlet Servlet 4.0 提供对 H T T P / 2 HTTP/2 HTTP/2 的原生支持,允许开发者利用新协议的特性,如多路复用、头部压缩和服务器推送。
-
异步处理的改进:
- 增强了异步处理
A
P
I
API
API,允许更灵活的非阻塞请求处理,提供了
AsyncContext
和ServletRequest
的新方法。
- 增强了异步处理
A
P
I
API
API,允许更灵活的非阻塞请求处理,提供了
-
Servlet 3.1 中的特性扩展:
- 对 S e r v l e t Servlet Servlet 3.1 中的异步功能和非阻塞 I/O 进行了扩展,提供更高效的处理能力。
-
HTTP 头支持:
- 增强了对 HTTP 头的处理,提供了更灵活的请求和响应头管理。
-
ServletRequest
和ServletResponse
的增强:- 添加了新的方法来支持更复杂的请求和响应处理。
S
e
r
v
l
e
t
Servlet
Servlet 5.0: 主要是把javax.servlet
包名改成了jakarta.servlet
;
S e r v l e t Servlet Servlet 6.0: 继续增加一些新功能,并废除一部分功能。
标签:web,service,tomcat,Servlet,public,servlet,梳理 From: https://blog.csdn.net/m0_62943934/article/details/143468097END…