1. Servlet知识脉络梳理
-
简化版
Servlet知识脉络梳理
-
详细版
Servlet知识脉络梳理详细版
2. 推荐的网站教程
- 菜鸟教程
https://www.runoob.com/servlet/servlet-intro.html - Tomcat官网(仅Tomcat7还支持)
https://tomcat.apache.org/tomcat-7.0-doc/servletapi/
3. Servlet3.0新特性

(1) 注解的支持
- @WebServlet:将一个类声明为Servlet
属性名 | 类型 | 描述 | 是否必需 |
---|---|---|---|
name | String | 指定Servlet的name 属性,等价于<servlet-name>。如果没有显式指定,则该Servlet的取值即为类的全限定名。 | 否 |
value | String[] | 该属性等价于urlPatterns属性。两个属性不能同时使用。 | 是 |
urlPatterns | String[] | 指定一组Servlet的URL匹配模式。等价于<url-pattern>标签。 | 是 |
loadOnStartup | int | 指定Servlet的加载顺序,等价于<load-on-startup>标签。 | 否 |
initParams | WebInitParam[] | 指定一组Servlet初始化参数,等价于<init-param>标签。 | 否 |
asyncSupported | boolean | 声明Servlet是否支持异步操作模式,等价于<async-supported>标签。 | 否 |
description | String | 该Servlet的描述信息,等价于<description>标签。 | 否 |
displayName | String | 该Servlet的显示名,通常配合工具使用,等价于<display-name>标签。 | 否 |
package servlet3;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**java
* @Author: Neco
* @Description:
* @Date: create in 2022/5/6 0:23
*/
@WebServlet(urlPatterns = "/annotation")
public class AnnotationServletDemo extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter writer = resp.getWriter();
writer.println("say Hello Neco with the servlet!!!");
writer.flush();
writer.close();
}
}
-
@WebInitParam:为Servlet或者过滤器指定初始化参数
该注解通常不单独使用,而是配合@WebServlet或者@WebFilter使用
属性名 | 类型 | 描述 | 是否必需 |
---|---|---|---|
name | String | 指定参数的名字,等价于<param-name>。 | 是 |
value | String | 指定参数的值,等价于<param-value>。 | 是 |
description | String | 关于参数的描述,等价于<description>。 | 否 |
package servlet3;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @Author: Neco
* @Description:
* @Date: create in 2022/5/6 0:23
*/
@WebServlet(urlPatterns = "/annotation", initParams = {
@WebInitParam(name = "name", value = "Neco", description = "desc for the name"),
@WebInitParam(name = "age", value = "18", description = "desc for the age")})
public class AnnotationServletDemo extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = this.getInitParameter("name");
String age = this.getInitParameter("age");
PrintWriter writer = resp.getWriter();
writer.println("say Hello Neco with the servlet!!!");
writer.println("I am " + name + ", I am " + age + " years old");
writer.flush();
writer.close();
}
}
- @WebFilter:用于将一个类声明为过滤器
属性名 | 类型 | 描述 | 是否必需 |
---|---|---|---|
filterName | String | 指定过滤器的name属性,等价于<filter-name> | 否 |
value | String[] | 该属性等价于urlPatterns 属性。但是两者不应该同时使用。 | 否 |
urlPatterns | String[] | 指定一组过滤器的URL匹配模式。等价于<url-pattern>标签。 | 否 |
servletNames | String[] | 指定过滤器将应用于哪些Servlet。取值是@WebServlet中的name属性的取值,或者是web.xml 中<servlet-name>的取值。 | 否 |
dispatcherTypes | DispatcherType | 指定过滤器的转发模式。具体取值包括: ASYNC、ERROR、FORWARD、INCLUDE、REQUEST。 |
否 |
initParams | WebInitParam[] | 指定一组过滤器初始化参数,等价于<init-param>标签。 | 否 |
asyncSupported | boolean | 声明过滤器是否支持异步操作模式,等价于<async-supported>标签。 | 否 |
description | String | 该过滤器的描述信息,等价于<description>标签。 | 否 |
displayName | String | 该过滤器的显示名,通常配合工具使用,等价于<display-name>标签。 | 否 |
package servlet3;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* @Author: Neco
* @Description:
* @Date: create in 2022/5/6 22:10
*/
@WebFilter(urlPatterns = "/*")
public class AnnotationFilterDemo implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
System.out.println("do something before");
filterChain.doFilter(request,response);
System.out.println("do something after");
}
}
- @WebListener:该注解用于将类声明为监听器
属性名 | 类型 | 描述 | 是否必需 |
---|---|---|---|
value | String | 该监听器的描述信息。 | 否 |
- @MultipartConfig: 为了辅助HttpServletRequest提供的对上传文件的支持
属性名 | 类型 | 描述 | 是否必需 |
---|---|---|---|
fileSizeThreshold | int | 当数据量大于该值时,内容将被写入文件。 | 否 |
location | String | 存放生成的文件地址。 | 否 |
maxFileSize | Long | 允许上传的文件最大值。默认值为-1,表示没有限制。 | 否 |
maxRequestSize | Long | 针对该multipart/form-data请求的最大数量,默认值为-1,表示没有限制。 | 否 |
(2) 异步处理的支持

-
添加 asyncSupported = true
-
例子
package servlet3;
import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
/**
* @Author: Neco
* @Description:
* @Date: create in 2022/5/6 22:54
*/
@WebServlet(urlPatterns = "/async", asyncSupported = true)
public class AsyncServletDemo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=UTF-8");
PrintWriter writer = resp.getWriter();
writer.println("进入Servlet的时间:" + new Date() + ".");
writer.flush();
// 在子线程中执行业务调用,并由其负责输出响应,主线程退出
AsyncContext ctx = req.startAsync();
new Thread(new Runnable() {
@Override
public void run() {
try {
//等待十秒钟,以模拟业务方法的执行
Thread.sleep(10000);
PrintWriter out = ctx.getResponse().getWriter();
out.println("业务处理完毕的时间:" + new Date() + ".");
out.flush();
ctx.complete();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
writer.println("结束Servlet的时间:" + new Date() + ".");
writer.flush();
}
}
- Tips
如果有过滤器,且能匹配上对应的接口,则对应的过滤器也要 添加 asyncSupported = true
,如下
@WebFilter(urlPatterns = "/*", asyncSupported = true)
否则会报错:
org.apache.catalina.connector.Request.startAsync 无法启动async,因为处理链中的下列类不支持async[servlet3.AnnotationFilterDemo]
java.lang.IllegalStateException: 当前链的筛选器或servlet不支持异步操作
(3) 文件上传的支持
-
Servlet2.5+三方jar包完成文件上传
Servlet2.5+三方jar包完成文件上传
- 例子
package servlet3;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* @Author: Neco
* @Description:
* @Date: create in 2022/5/6 23:28
*/
@WebServlet(urlPatterns = "/upload")
public class UploadServlet extends HttpServlet {
@Override
public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全
String savePath = this.getServletContext().getRealPath("/WEB-INF/upload");
File file = new File(savePath);
//判断上传文件的保存目录是否存在
if (!file.exists() && !file.isDirectory()) {
System.out.println(savePath + "目录不存在,需要创建");
//创建目录
file.mkdir();
}
//消息提示
String message = "";
try {
//使用Apache文件上传组件处理文件上传步骤:
//1、创建一个DiskFileItemFactory工厂
DiskFileItemFactory factory = new DiskFileItemFactory();
//2、创建一个文件上传解析器
ServletFileUpload upload = new ServletFileUpload(factory);
//解决上传文件名的中文乱码
upload.setHeaderEncoding("UTF-8");
//3、判断提交上来的数据是否是上传表单的数据
if (!ServletFileUpload.isMultipartContent(request)) {
//按照传统方式获取数据
return;
}
//4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合,每一个FileItem对应一个Form表单的输入项
List<FileItem> list = upload.parseRequest(request);
for (FileItem item : list) {
//如果fileitem中封装的是普通输入项的数据
if (item.isFormField()) {
String name = item.getFieldName();
//解决普通输入项的数据的中文乱码问题
String value = item.getString("UTF-8");
value = new String(value.getBytes("iso8859-1"), "UTF-8");
System.out.println(name + "=" + value);
} else {//如果fileitem中封装的是上传文件
//得到上传的文件名称,
String filename = item.getName();
System.out.println(filename);
if (filename == null || filename.trim().equals("")) {
continue;
}
//注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,如: c:\a\b\1.txt,而有些只是单纯的文件名,如:1.txt
//处理获取到的上传文件的文件名的路径部分,只保留文件名部分
filename = filename.substring(filename.lastIndexOf("\\") + 1);
//获取item中的上传文件的输入流
InputStream in = item.getInputStream();
//创建一个文件输出流
FileOutputStream out = new FileOutputStream(savePath + "\\" + filename);
//创建一个缓冲区
byte buffer[] = new byte[1024];
//判断输入流中的数据是否已经读完的标识
int len = 0;
//循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据
while ((len = in.read(buffer)) > 0) {
//使用FileOutputStream输出流将缓冲区的数据写入到指定的目录(savePath + "\\" + filename)当中
out.write(buffer, 0, len);
}
//关闭输入流
in.close();
//关闭输出流
out.close();
//删除处理文件上传时生成的临时文件
item.delete();
message = "文件上传成功!";
}
}
} catch (Exception e) {
message = "文件上传失败!";
e.printStackTrace();
}
}
}
- Servlet3完成文件上传
- 客户端(浏览器)∶
1.表单的提交方法必须是post
2.必须有一个文件上传组件<input type="file" name="file" >
3.必须设置表单的enctype="multipart/form-data"- 服务器:
1.在Servelt上添加注解@MultipartConfig
2.Part getPart(String name)或者collection<Part> getParts()- 例子
package servlet3;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @Author: Neco
* @Description:
* @Date: create in 2022/5/6 23:29
*/
@WebServlet(urlPatterns = "/uploadServlet")
@MultipartConfig
public class UploadServlet3 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
//创建目录
String savePath = this.getServletContext().getRealPath("/WEB-INF/upload");
File file = new File(savePath);
//判断上传文件的保存目录是否存在
if (!file.exists() && !file.isDirectory()) {
System.out.println(savePath+"目录不存在,需要创建");
//创建目录
file.mkdir();
}
//获取文件
Part img = request.getPart("file");
//文件全路径
String filePath = file.getPath() + File.separator + img.getSubmittedFileName();
//写入文件
img.write(filePath);
//输出信息
PrintWriter out = response.getWriter();
out.println("File Upload : " + filePath);
}
}
4. Servlet4.0新特性

(1) http2协议的支持

- 开启Http/2所需要的软件
(网盘地址 链接: https://pan.baidu.com/s/1ZKmrZG2-mTXUaQSY6l9EgA?pwd=c46r )
1.apache-tomcat-9.0.14-windows-x64.zip
2.tomcat-native-1.2.24-openssl-1.1.1g-win32-bin.zip
3.Win640penSSL-1_1_1g.exe
4.私钥生成命令.txt - 开启Http/2的操作步骤
1、下载并解压缩tomcat9,然后执行bin文件夹下面的startup.bat,测试是否正常;
2、进入到conf目录下,设置server.xml文件,把http/1.1改成http/2,注意把倒数第二行删掉,改完之后,保存,重新打开startup.bat,发现启动报错;
3、下载tomcat-native和OpenSSL两个软件;
4、解压缩tomcat-native,并且执行里面的bin目录下的openssl.exe文件,然后把生成秘钥的命令输入进去,发现第二个命令报错;
5、安装OpenSSL软件,并且把安装目录下的bin下的cnf里面的openssl.cnf文件拷贝到C:\Program Files (x86)\Common Files\SSL目录下;
6、再次打开tomcat-native下的openssl.exe文件,再次把两个秘钥命令输入进去,发现一切正常了,注意,第二个命令输入完成之后需要你填写一些信息,不用管,一路回车即可;
7、把生成出来的秘钥和证书文件(在openssl.exe文件同一个目录下)放入到tomcat9的conf目录下即可;
8、复制tomcat-native下面的bin目录下的x64下面的2个文件拷贝到jdk1.8的bin目录下,如果你是32位系统,则拷贝bin目录下的相同文件名的2个文件即可;
9、在tomcat9下,点击启动startup.bat,启动完成,打开浏览器,输入https://localhost:8443,测试是否正常访问;
10、打开IDEA,进行相关配置之后,测试是否能正常启动工程
(2) 进行服务器推送
- 什么是服务器推送
所谓服务器推送,就是指服务器预测性的提前将资源发给浏览器进行缓存,当用户访问到需要这些资源的页面时,就可以直接从缓存中读取,从而加快页面的访问速度,增加用户的体验感。 - 服务器推送的步骤
a)设置推送资源
PushBuilder pb = request.newPushBuilder();
pb.path(“1.jpg”);
b)进行推送
pb.push();
(3) HttpServletMapping的使用
- HttpServletMapping的API
- getMatchValue()︰返回部分URI路径,该路径会导致请求匹配。
- getPattern()∶返回URL模式的String表示形式。
- getServletName()∶返回servlet名称的String表示形式。
- getMappingMatch():返回匹配的类型,表示为MappingMatch枚举值,该枚举值将为以下值之一:
CONTEXT_ROOT(根目录)、DEFAULT (默认)、EXACT(精准)、EXTENSION(拓展)或PATH(路径)。
- HttpServletMapping的方法返回值与URI的对应关系
URI Path(in quotes) | matchValue | Pattern | mappingMatch |
---|---|---|---|
CONTEXT_ROOT | |||
/index.html | / | DEFAULT | |
/MyServelet | MyServlet | EXACT | |
/foo.extension | foo | *.extension | EXTENSION |
/path/foo | foo | /path/* | PATH |
(4) HttpFilter的使用
- HttpFilter和Filter的区别
- HttpFilter是一个类,直接继承即可,而Filter是一个接口,需要实现
- HttpFilter是Filter接口的一个实现类,多了对http协议的支持
- HttpFilter里的doFilter方法里面的参数带Http协议的,而Filter里面的这两个参数是不带http协议的
- 如果我们在拦截器里需要使用到带http协议的请求和响应的话,就优先使用HttpFilter类
如果觉得有收获就点个赞吧,更多知识,请点击关注查看我的主页信息哦~
网友评论