• Servlet API(HttpSerrvlet+HttpServletRequest+HttpServletResponse)


    目录

    🐲 1. HttpServlet

    🐲 2. HttpServletRequest HTTP请求

    🦄 2.1 打印请求信息(创建 ShowRequest 类)  

    🦄 2.2 获取 GET 请求中的参数(创建 GetParameter 类)

    🦄 2.3 获取 POST 请求中的参数(创建 PostParameter 类)

    2.3.1 请求的 body 是 x-www-form-urlencoded   form表单

    2.3.2 请求的 body 是 json 格式

    🐲 3. HttpServletResponse  HTTP响应

    🦄 3.1 设置状态码(创建 StatusServlet 类)

    🦄 3.2 自动刷新(创建 AutoRefreshServlet 类)

    🦄 3.3  重定向(创建 RedirectServlet 类)


    🐲 1. HttpServlet

    写 Servlet 代码的时候, 首先第一步就是先创建类, 继承自 HttpServlet, 并重写其中的某些方法.
    方法名称调用时机
    init在 HttpServlet 实例化之后被调用一次
    destroy在 HttpServlet实例不再使用的时候调用一次
    service收到HTTP请求的时候调用
    doGet收到GET请求的时候调用(由 service 方法调用)
    doPost收到Post请求的时候调用(由 service 方法调用)
    doPut / doDelete / doOptions / ...收到其他请求的时候调用(由 service 方法调用)

    需要注意开发常用的是 下面这几个 (doGet / doPost / doPut / .....)

    而面试考的是上面这三个(init / destroy / service)

    (1) init  创建出 HttpServlet 实例会调用一次 

    init 方法的作用,就是用来初始化 ,也就是首次被访问到的时候会被实例化

    (2) destroy 在 HttpServlet 实例不再使用的时候调用一次,

    这个不一定真的能调用到

    a) 杀进程,比如cmd直接点 x      或是通过任务管理器结束任务   或是idea关闭运行状态

    此时destroy无法被调用到(相当于直接拔电源)

    b) 通过8005端口,用来控制tomcat的,通过这个端口给tomcat发送一个关闭操作,这个时候tomcat就可以正常关闭,就可以调用到destroy(相当于正常关闭电脑)

    (3) service 收到HTTP请求的时候调用

    tomcat 收到请求,实际上是先调用 service

    在 service 中再去根据方法,调用不同的 doxxx

    但在实际开发中,很少会重写 service 就是直接重写 doxxx 就可以了

    面试题:谈谈 Servlet 的生命周期

    先理解什么叫生命周期:就是什么阶段,干什么事

    可以这样回答,在 Servlet中有三个主要的方法

    init 在 Servlet 被实例化时,调用一次,用来初始化

    destroy 在 Servlet 被销毁之前,调用一次

    service 每次收到请求调用一次


    🐲 2. HttpServletRequest HTTP请求

    方法描述
    String getProtocol()返回请求协议的名称和版本,例如 HTTP/1.1
    String getMethod()返回请求的HTTP方法的名称,例如 GET/POST/PUT
    String getRequestURI()从协议名称直到HTTP请求的第一行的查询字符串中,返回该请求的URL的一部分
    String getContextPath()

    返回指示请求上下文的请求URI部分

    URL两层 context path   servlet path

    这个方法就是返回 context path部分的

    String getQueryString()

    返回包含在路径后的请求 URL 中的查询字符串

    ?studentId=10&classId=1

    Enumeration getParameterNames()返回一个 String 对象的枚举,包含在该请求中包含的参数的名称
    String getParameter(String name)以字符串形式返回请求参数的值,或者如果参数不存在则返回null
    String[] getParameterValues(String name)

    返回一个字符串对象的数组,包含所有给定的请求参数的值(返回多个value),如果参数不存在则返回null

    ?score=1&score=2&score=3 使用这个方法返回数组[1,2,3]

    Enumeration getHeaderNames()返回一个枚举,包含在该请求中包含的所有的头名(key)
    String getHeader(String name)以字符串形式返回指定的请求头的值(value)
    String getCharacterEncoding()返回请求主体中使用的字符编码的名称
    String getContentType()返回请求主体的 MIME 类型,如果不知道类型则返回null

    int getContentLength()

    以字节为单位返回请求主体的长度,并提供输入流,或者如果长度未知则返回-1
    InputStream getInputStream()用于读取请求的 body 内容,返回一个 InputStream 对象


    🦄 2.1 打印请求信息(创建 ShowRequest 类)  

    1. import javax.servlet.ServletException;
    2. import javax.servlet.annotation.WebServlet;
    3. import javax.servlet.http.HttpServletRequest;
    4. import javax.servlet.http.HttpServletResponse;
    5. import java.io.IOException;
    6. import java.util.Enumeration;
    7. @WebServlet("/showRequest")
    8. public class ShowRequestServlet extends HelloServlet{
    9. @Override
    10. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    11. StringBuilder sb = new StringBuilder();
    12. //查看协议的名称和版本
    13. sb.append(req.getProtocol());
    14. sb.append("\n");
    15. //查看HTTP方法的名称
    16. sb.append(req.getMethod());
    17. sb.append("\n");
    18. //从协议名称直到HTTP请求的第一行的查询字符串中,返回该请求的URL的一部分
    19. sb.append(req.getRequestURI());
    20. sb.append("\n");
    21. //返回ContextPath部分的路径
    22. sb.append(req.getContextPath());
    23. sb.append("\n");
    24. //返回请求URL查询的字符串
    25. sb.append(req.getQueryString());
    26. sb.append("\n");
    27. //把请求的 header 也拼进来
    28. Enumeration headerNames = req.getHeaderNames();
    29. while(headerNames.hasMoreElements()) {
    30. String name = headerNames.nextElement();
    31. String value = req.getHeader(name);
    32. sb.append(name + ": " + value);
    33. sb.append("\n");
    34. }
    35. resp.getWriter().write(sb.toString());
    36. }
    37. }

    如果不写context type,此时浏览器就不知道这里的body应该是啥格式,就会导致不一定是你想要的那种格式

    所以要注意要写上context type让浏览器知道你想要什么格式,

    格式有很多 text/plain  text/html   text/css  application/js  application.json  image/png

    我这里写一个 text/html (纯文本的格式),浏览器就知道了(而下面写的\n就会失效了)

     写什么context type  就要对应什么格式

    完整代码:

    1. import javax.servlet.ServletException;
    2. import javax.servlet.annotation.WebServlet;
    3. import javax.servlet.http.HttpServletRequest;
    4. import javax.servlet.http.HttpServletResponse;
    5. import java.io.IOException;
    6. import java.util.Enumeration;
    7. @WebServlet("/showRequest")
    8. public class ShowRequestServlet extends HelloServlet{
    9. @Override
    10. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    11. //resp 是响应对象 setContextType,给响应的 ContextType设置了值:html
    12. //声明响应 body 是 html结构的数据
    13. resp.setContentType("text/html");
    14. StringBuilder sb = new StringBuilder();
    15. //查看协议的名称和版本
    16. sb.append(req.getProtocol());
    17. sb.append("
      "
      );
    18. //查看HTTP方法的名称
    19. sb.append(req.getMethod());
    20. sb.append("
      "
      );
    21. //返回请求的URL的一部分
    22. sb.append(req.getRequestURI());
    23. sb.append("
      "
      );
    24. //返回ContextPath部分的路径
    25. sb.append(req.getContextPath());
    26. sb.append("
      "
      );
    27. //返回请求URL查询的字符串
    28. sb.append(req.getQueryString());
    29. sb.append("
      "
      );
    30. //把请求的 header 也拼进来
    31. Enumeration headerNames = req.getHeaderNames();
    32. while(headerNames.hasMoreElements()) {
    33. String name = headerNames.nextElement();
    34. String value = req.getHeader(name);
    35. sb.append(name + ": " + value);
    36. sb.append("
      "
      );
    37. }
    38. resp.getWriter().write(sb.toString());
    39. }
    40. }

    🦄 2.2 获取 GET 请求中的参数(创建 GetParameter 类)

    使用 api 获取到请求中的重要参数(query string 中的值 , 以及 body 中的值)

    比如: https://v.bitedu.vip/personInf/student?studentId=666&classId=888

    GET请求中的参数通过query string传递给服务器,

    如果此时浏览器通过 query string给服务器传递了两个参数,

    studentId 和 classId 值分别是 666 和 二班,

    在服务器端就可以通过 getParameter来获取到参数的值

    1. import javax.servlet.ServletException;
    2. import javax.servlet.annotation.WebServlet;
    3. import javax.servlet.http.HttpServlet;
    4. import javax.servlet.http.HttpServletRequest;
    5. import javax.servlet.http.HttpServletResponse;
    6. import java.io.IOException;
    7. @WebServlet("/getParameter")
    8. public class GetParameterServlet extends HttpServlet {
    9. @Override
    10. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    11. //获取 query string 中的键值对
    12. // 浏览器的请求比如: ?studentId=666&classId=二班
    13. String studentId = req.getParameter("studentId");
    14. String classId = req.getParameter("classId");
    15. System.out.println(studentId);
    16. System.out.println(classId);
    17. resp.getWriter().write(studentId + ", " + classId);
    18. }
    19. }

    浏览器没有正确识别出中文,不是没有urlencode的原因(服务器这里的打印结果是正确的,说明urlencode没有,也不是肯定会出错的)

    而是返回响应的页面,浏览器没有正确识别

    为了能够让浏览器能够正确识别,需要显示在响应中加上 context type

     

     重新运行,

    特殊情况

    getParameter 获取键值对时

    如果键不存在,得到的就是null

    如果键存在,值不存在,得到的就是 " " 

     完整代码

    1. import javax.servlet.ServletException;
    2. import javax.servlet.annotation.WebServlet;
    3. import javax.servlet.http.HttpServlet;
    4. import javax.servlet.http.HttpServletRequest;
    5. import javax.servlet.http.HttpServletResponse;
    6. import java.io.IOException;
    7. @WebServlet("/getParameter")
    8. public class GetParameterServlet extends HttpServlet {
    9. @Override
    10. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    11. //获取 query string 中的键值对
    12. // 浏览器的请求比如: ?studentId=666&classId=二班
    13. String studentId = req.getParameter("studentId");
    14. String classId = req.getParameter("classId");
    15. System.out.println(studentId);
    16. System.out.println(classId);
    17. resp.setContentType("text/html; charset=utf8");
    18. resp.getWriter().write(studentId + ", " + classId);
    19. }
    20. }

    🦄 2.3 获取 POST 请求中的参数(创建 PostParameter 类)

    如果请求是 post,获取到 body 中的参数

    2.3.1 请求的 body 是 x-www-form-urlencoded   form表单

    也是可以通过 getParameter获取参数的值

    1. import javax.servlet.ServletException;
    2. import javax.servlet.annotation.WebServlet;
    3. import javax.servlet.http.HttpServlet;
    4. import javax.servlet.http.HttpServletRequest;
    5. import javax.servlet.http.HttpServletResponse;
    6. import java.io.IOException;
    7. @WebServlet("/getParameter")
    8. public class GetParameterServlet extends HttpServlet {
    9. @Override
    10. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    11. // 通过 body 获取,发送 post 请求
    12. // 请求的 body 比如: studentId=666&classId=二班
    13. String studentId = req.getParameter("studentId");
    14. String classId = req.getParameter("classId");
    15. System.out.println(studentId);
    16. System.out.println(classId);
    17. resp.setContentType("text/html; charset=utf8");
    18. resp.getWriter().write(studentId + ", " + classId);
    19. }
    20. }

    需要注意的doPost中写的代码和前面doGet中写的代码是一样的,

    但是发送请求的方式是不一样的,之前doGet发送请求是直接在浏览器上面输入的

    doPost不能这样直接发送请求,

    a) 可以使用postman来给body中写内容发送请求

    如果对于postman还不了解,大家可以看我这一篇博客里面有很好的讲解

    b)  还可以写一个html通过form发送请求

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
    6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    7. <title>Documenttitle>
    8. head>
    9. <body>
    10. <form action="getParameter" method="post">
    11. <input type="text" name="studentId">
    12. <input type="text" name="classId">
    13. <input type="submit" value="提交">
    14. form>
    15. body>
    16. html>

     运行程序,用fiddler抓包可以看到

     当前发现响应的页面乱码了,但是我们代码中不是设置了吗,怎么还会乱码

    需要注意的是,我们设置的是响应 ,并且服务器收到的也是一个乱码,

    说明服务器针对请求的解析就已经乱了(也就是servlet不知道你传过来的是哪种编码方式),所以需要显示的告诉servlet按照哪种方式编码,来理解请求的body

     所以我们就需要给请求这里也加上对于编码方式的声明

    运行程序可以看到

    ​ 

     最终代码

    1. import javax.servlet.ServletException;
    2. import javax.servlet.annotation.WebServlet;
    3. import javax.servlet.http.HttpServlet;
    4. import javax.servlet.http.HttpServletRequest;
    5. import javax.servlet.http.HttpServletResponse;
    6. import java.io.IOException;
    7. @WebServlet("/getParameter")
    8. public class GetParameterServlet extends HttpServlet {
    9. @Override
    10. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    11. // 通过 body 获取,发送 post 请求
    12. // 请求的 body 比如: studentId=666&classId=二班
    13. req.setCharacterEncoding("utf8");
    14. String studentId = req.getParameter("studentId");
    15. String classId = req.getParameter("classId");
    16. System.out.println(studentId);
    17. System.out.println(classId);
    18. //响应这里设置字符集有两种写法,但是还是建议使用 setContentType 完整写法
    19. //设置的字符集只是一小部分,还需要设置格式
    20. resp.setContentType("text/html; charset=utf8");
    21. resp.getWriter().write(studentId + ", " + classId);
    22. }
    23. }

    2.3.2 请求的 body 是 json 格式

    {

        studentId: 666,

        classId: "二班"

    }

    要想获取json中的数据,就要先读取body中的内容,
    可以使用getInputStream进一步的再来读取流对象
    那么如何解析 json 格式呢?
    需要注意的一点是 Servlet 没有内置 json 解析
    这就需要使用到第三方库来解析,目前有很多的json第三方库比如 fastjson,jackson,gson...
    (下面使用的是jackson是因为spring用的json)
    还是到中央仓库中去搜索jackson

    这个随便选

     

     复制这个

    1. com.fasterxml.jackson.core
    2. jackson-databind
    3. 2.13.4.1

     jackson 提供"一个类两个方法"

    一个类 :   ObjectMapper

    一个方法: readValue,把json格式的数据转成 java 的对象

    另一个方法: writeValueAsString,把 java 对象转成 json 格式的字符串

    完整代码

    1. import com.fasterxml.jackson.databind.ObjectMapper;
    2. import javax.servlet.ServletException;
    3. import javax.servlet.annotation.WebServlet;
    4. import javax.servlet.http.HttpServlet;
    5. import javax.servlet.http.HttpServletRequest;
    6. import javax.servlet.http.HttpServletResponse;
    7. import java.io.IOException;
    8. import java.util.ArrayList;
    9. class Student {
    10. //1.这个类的属性必须是public或者带有public的getter/setter
    11. // 否则jackson无法访问到这个对象的属性
    12. //2.这个类必须要有无参版本的构造方法
    13. public int studentId;
    14. public String classId;
    15. }
    16. @WebServlet("/jsonServlet")
    17. public class JsonServlet extends HttpServlet {
    18. @Override
    19. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    20. // 请求的 body 格式为
    21. // { studentId: 666, classId: "二班" }
    22. ObjectMapper objectMapper = new ObjectMapper();
    23. //readValue,第一个参数可以是字符串也可以是输入流
    24. //第二个参数是一个类对象
    25. Student s = objectMapper.readValue(req.getInputStream(),Student.class);
    26. System.out.println(s.studentId);
    27. System.out.println(s.classId);
    28. // resp.setContentType("text/html; charset=utf8");
    29. // resp.getWriter().write(s.studentId + ", " + s.classId);
    30. resp.setContentType("application/json; charset=utf8");
    31. resp.getWriter().write(objectMapper.writeValueAsString(s));
    32. }
    33. }

    使用postman来给body发送数据

    如果是更复杂的json,那就是 "套娃"

     

    1. import com.fasterxml.jackson.databind.ObjectMapper;
    2. import javax.servlet.ServletException;
    3. import javax.servlet.annotation.WebServlet;
    4. import javax.servlet.http.HttpServlet;
    5. import javax.servlet.http.HttpServletRequest;
    6. import javax.servlet.http.HttpServletResponse;
    7. import java.io.IOException;
    8. import java.util.ArrayList;
    9. class Score {
    10. public ArrayList scores;
    11. }
    12. class Student {
    13. //1.这个类的属性必须是public或者带有public的getter/setter
    14. // 否则jackson无法访问到这个对象的属性
    15. //2.这个类必须要有无参版本的构造方法
    16. public int studentId;
    17. public String classId;
    18. public Score score;
    19. }
    20. @WebServlet("/jsonServlet")
    21. public class JsonServlet extends HttpServlet {
    22. @Override
    23. protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    24. // 请求的 body 格式为
    25. // { studentId: 666, classId: "二班" }
    26. ObjectMapper objectMapper = new ObjectMapper();
    27. //readValue,第一个参数可以是字符串也可以是输入流
    28. //第二个参数是一个类对象
    29. Student s = objectMapper.readValue(req.getInputStream(),Student.class);
    30. System.out.println(s.studentId);
    31. System.out.println(s.classId);
    32. // resp.setContentType("text/html; charset=utf8");
    33. // resp.getWriter().write(s.studentId + ", " + s.classId);
    34. resp.setContentType("application/json; charset=utf8");
    35. resp.getWriter().write(objectMapper.writeValueAsString(s));
    36. }
    37. }

    🐲 3. HttpServletResponse  HTTP响应

    方法描述
    void setStaus(int sc)为该响应设置状态码
    void setHeader(String name, String value)设置一个带有给定的名称和值的header,如果name已经存在则覆盖旧的值
    void addHeader(String name,String value)添加一个带有给定的名称和值的header,如果name已经存在,不覆盖旧的值,并列添加新的键值对(新旧同时存在)
    void setContentType(String type)设置被发送到客户端的响应的内容类型
    void setCharacterEncoding(String charset)设置被发送到客户端的响应的字符编码(MIME 字符集) 例如,utf8
    void sendRedirect(String location)使用指定的重定向位置URL,发送临时重定向响应到客户端
    PrintWriter getWriter()

    用于往 body 中写入文本格式数据

    (HTTP响应式啥样的数据,显示到浏览器上的)

    OutputStream getOutputStream()用于往 body 中写入二进制格式数据


     

    🦄 3.1 设置状态码(创建 StatusServlet 类)

    1. import javax.servlet.ServletException;
    2. import javax.servlet.annotation.WebServlet;
    3. import javax.servlet.http.HttpServlet;
    4. import javax.servlet.http.HttpServletRequest;
    5. import javax.servlet.http.HttpServletResponse;
    6. import java.io.IOException;
    7. @WebServlet("/statusServlet")
    8. public class StatusServlet extends HttpServlet {
    9. @Override
    10. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    11. //约定, 浏览器 query string 传个参数过来 type
    12. //如果type=1,就返回200;type=2,就返回404;type=3返回一个500
    13. String type = req.getParameter("type");
    14. if(type.equals("1")) {
    15. resp.setStatus(200);
    16. }else if(type.equals("2")) {
    17. resp.setStatus(404);
    18. }else if(type.equals("3")) {
    19. resp.setStatus(500);
    20. }else {
    21. resp.setStatus(504);
    22. }
    23. }
    24. }

    运行程序

    抓包查看响应

     再看一下 type=2

    这个是浏览器默认的404的显示结果

     

    也可以让显示的这个404更好看一些(比如这个里返回一个tomcat的404)

     

     这些状态码具体应该怎么来处理,也就是页面中显示什么,都是属于程序员自定义的


    🦄 3.2 自动刷新(创建 AutoRefreshServlet 类)

    实现一个程序 , 让浏览器每秒钟自动刷新一次 . 并显示当前的时间戳 .

    设置响应的 header ,通过这个实现页面自动刷新, 

     header设置 refresh 属性,值是一个"秒数" 浏览器就会在时间到了之后自动刷新

    1. import javax.servlet.ServletException;
    2. import javax.servlet.annotation.WebServlet;
    3. import javax.servlet.http.HttpServletRequest;
    4. import javax.servlet.http.HttpServletResponse;
    5. import java.io.IOException;
    6. @WebServlet("/autoRefresh")
    7. public class AutoRefreshServlet extends HelloServlet{
    8. @Override
    9. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    10. // 直接返回响应就可以
    11. resp.setHeader("refresh", "2");
    12. resp.getWriter().write(System.currentTimeMillis() + "");
    13. }
    14. }

    每2000ms自动刷新 (但这个并不是精确的,会比2000ms略多一点,是因为执行这个语句还要花费一点时间)


    🦄 3.3  重定向(创建 RedirectServlet 类)

    实现一个程序 , 返回一个重定向 HTTP 响应 , 自动跳转到另外一个页面
    1. import javax.servlet.ServletException;
    2. import javax.servlet.annotation.WebServlet;
    3. import javax.servlet.http.HttpServlet;
    4. import javax.servlet.http.HttpServletRequest;
    5. import javax.servlet.http.HttpServletResponse;
    6. import java.io.IOException;
    7. @WebServlet("/redirect")
    8. public class RedirectServlet extends HttpServlet {
    9. @Override
    10. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    11. // 进行重定向,收到请求,跳转到 百度主页
    12. // resp.setStatus(302);
    13. // resp.setHeader("Location","https://www.baidu.com");
    14. //和上面代码的效果一样
    15. resp.sendRedirect("https://www.baidu.com");
    16. }
    17. }

    输入这个,按回车,就自动跳转到百度主页上去 

     


  • 相关阅读:
    webpack中loader和plugin的区别
    剖析容器运行时
    破解软件的原理是什么(软件被破解公开)
    B树和B+树的区别
    互联网摸鱼日报(2023-11-20)
    Methoxy-PEG-PCL,Methoxy-PEG-Poly(ε-caprolactone)可以作为制备纳米颗粒的重要原料
    torchscript相关知识介绍(二)
    企业电子招标采购系统项目说明+开发类型+解决方案+功能描述
    excel利用正则匹配和替换指定内容
    基于simulink的单相光伏系统并网储能控制仿真
  • 原文地址:https://blog.csdn.net/m0_58761900/article/details/127957600