Servlet 的相关知识梳理

作者: 右耳菌 | 来源:发表于2022-05-07 00:17 被阅读0次
1. Servlet知识脉络梳理
  • 简化版

    Servlet知识脉络梳理
  • 详细版

    Servlet知识脉络梳理详细版
2. 推荐的网站教程
3. Servlet3.0新特性
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) 异步处理的支持

servlet3异步操作
  • 添加 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新特性
servlet4.0新特性

(1) http2协议的支持

servlet4.0新特性.png
  • 开启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类

如果觉得有收获就点个赞吧,更多知识,请点击关注查看我的主页信息哦~

相关文章

网友评论

    本文标题:Servlet 的相关知识梳理

    本文链接:https://www.haomeiwen.com/subject/hzwoyrtx.html