• 技术层面上快速突破Servlet,带你快速上手HttpServlet,HttpServletRequest,HttpServletResponse


    Servlet API

    Servlet中有很多的类,其中HttpServletHttpServletRequestHttpServletResponse对于一开始使用Servlet是最关键的三个类。

    HttpServlet

    首先一个类需要继承HttpServlet类,然后重写其中的方法,这其实就是一种将我们自定义的代码逻辑插入到Tomcat框架的实现方式。

    核心方法

    • init:在HttpServlet对象被创建的时候被调用
    • destroy:HttpServlet对象不再被使用的时候被调用
    • service:收到HTTP请求的时候调用
    • doGet/doPost/doPut/doDelete...:收到对应的请求时被调用

    Servlet生命周期(创建出对象之后会自动调用哪些方法)也可以从上面的核心方法中看出来:Servlet对象被创建出来之后会调用init(),Servlet对象每一次收到请求都会调用service(),Servlet对象在被销毁之前会调用destroy()

    注意:实际开发中的时候主要重写doxxx方法,很少会重写initdestroyservice方法

    使用HttpServlet对象实现一个简单的Servlet项目:使用ajax模拟发送请求,服务器处理GET和POST请求

    • 前端代码
    DOCTYPE html>  
    <html lang="en">  
    <head>  
        <meta charset="UTF-8">  
        <meta http-equiv="X-UA-Compatible" content="IE=edge">  
        <meta name="viewport" content="width=device-width, initial-scale=1.0">  
        <title>Documenttitle>  
    head>  
    <body>  
        <button onclick="sendGet()">发送 GET 请求button>  
        <button onclick="sendPost()">发送 POST 请求button>  
      
        <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js">script>  
      
        <script>  
            // 使用ajax发送HTTP请求  
            const sendGet = () => {  
                $.ajax({  
                    type: "GET",  
                    // 注意:ajax的url有两种写法:  
                    // 1.相对路径,和当前地址前面的部分是相同的。  
                    // 例如当前地址是/test_servlet/index.html,那么就会跳转到/test_servlet/method  
                    // 2.绝对路径,从web根目录开始  
                    // 例如:直接写成url: "/test_servlet/method"  
                    url: "method",  
                    success: function(resp) {  
                        console.log(resp);  
                    }  
                });  
            }  
            const sendPost = () => {  
                $.ajax({  
                    type: "POST",  
                    url: "method",  
                    data: "post request body",  
                    success: function(resp) {  
                        console.log(resp);  
                    }  
                })  
            }  
        script>  
    body>  
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    注意:ajax中路径的写法。如果一旦使用/开头,就一定要写成绝对路径。这个要和Servlet中的@WebServlet注释不同,在@WebServlet注解中一定要给相对路径的前面加上/,例如@WebServlet("/method")

    • Servlet代码
    @WebServlet("/method")  
    public class MethodServlet extends HttpServlet {  
        @Override  
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {  
            // 因为windows上的浏览器默认的编码格式是GBK,而Tomcat和IDEA中的编码格式是UTF-8,如果直接发送中文过去的话  
            // 就会看到乱码。因为UTF-8是通用编码格式,所以我们就不修改IDEA中的编码格式了,而是修改浏览么渲染的编码格式  
            // 通过在HTTP中的header调价Content-Type: charset=utf-8就可以修改浏览器的编码格式了  
            resp.setContentType("text/html; charset=utf-8;");  
            resp.getWriter().write("get 响应");  
        }  
      
        @Override  
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {  
            resp.setContentType("text/plain; charset=utf-8;");  
            resp.getWriter().write("post 响应");  
        }  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    注意:给浏览器设置编码格式。在HTTP请求的header中设置Content-Type: charset=utf-8

    HttpServletRequest

    HttpServletRequest就是Tomcat对HTTP请求的封装。Tomcat将字符串结构的HTTP请求转化成了一个一个键值对的结构化数据,即将HTTP请求字符串进行了“反序列化”操作,这样更方便对数据进行操作。

    HTTP请求中包括:请求行(请求方法+URL(ContextPath+QueryString)+版本号)+ 请求头部 + 空行 + 请求正文

    其中的每一个部分,HttpServletRequest对象都有对应的方法可以获取到。

    核心方法

    ![[Pasted image 20220821155111.png]]

    使用HttpServletRequest获取HTTP请求信息

    • Servelt代码
    @WebServlet("/showrequest")  
    public class ShowRequestServlet extends HttpServlet {  
        @Override  
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {  
            resp.setContentType("text/html; charset=utf-8;");  
            StringBuilder respBody = new StringBuilder();  
      
            respBody.append("请求方法: " + req.getMethod() + "
    "
    ); respBody.append("请求路径URI: " + req.getRequestURI() + "
    "
    ); respBody.append("ContextPath: " + req.getContextPath() + "
    "
    ); respBody.append("QueryString: " + req.getQueryString() + "
    "
    ); respBody.append("版本号: " + req.getProtocol() + "
    "
    ); respBody.append("

    HttpHeader

    "
    ); Enumeration<String> headerNames = req.getHeaderNames(); while (headerNames.hasMoreElements()) { String headerName = headerNames.nextElement(); respBody.append(headerName + ": " + req.getHeader(headerName) + "
    "
    ); } resp.getWriter().write(respBody.toString()); } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 实验结果
      ![[Pasted image 20220821162134.png]]

    案例:使用HttpServletRequest获得GET请求传递的参数信息

    • Servlet代码
    @WebServlet("/getparameter")  
    public class GetParameterServlet extends HttpServlet {  
        @Override  
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {  
            resp.setContentType("text/html; chatset=utf-8;");  
            // 获取url中querystring  
            String userId = req.getParameter("userId");  
            String userName = req.getParameter("userName");  
            // 对参数不存在需要判断querystring是否为null或者是否为""  
            // 因为不传递userId和userName这两个参数的话,那么对象就为null  
            // 如果传递的参数为userId=&userName=的话,那么对象就位""  
            if (userId == null || userId.equals("")) {  
                System.out.println("不存在userId");  
            }  
            resp.getWriter().write(String.format("userId: %s, userName: %s 
    "
    , userId, userName)); } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 实验结果
      ![[Pasted image 20220821164347.png]]

    案例:使用HttpServletRequest获得POST请求传递的参数信息

    发起POST请求的时候,正文参数有三种格式:

    1. application/x-www-form-urlencoded格式,这种格式类似于直接使用url进行传递的参数。
    2. mutlipart/form-data,这种格式比较复杂,主要是用来提交文件的。(这种不详讲了)
    3. application/json,json类似于一个对象中有很多个key-value键值对。

    解析application/x-www-form-urlencoded格式的正文参数

    • Servlet代码
    @WebServlet("/postParameter")  
    public class PostParameterServlet extends HttpServlet {  
        @Override  
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {  
            resp.setContentType("text/html; charset=utf-8;");  
            // 直接使用getParamter就可以获取x-www-form-urlencoded格式的请求正文中的数据了  
            String userId = req.getParameter("userId");  
            String userName = req.getParameter("userName");  
            resp.getWriter().write(String.format("userId: %s, userName: %s 
    "
    , userId, userName)); } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 前端发起post请求代码
    DOCTYPE html>  
    <html lang="en">  
    <head>  
        <meta charset="UTF-8">  
        <meta http-equiv="X-UA-Compatible" content="IE=edge">  
        <meta name="viewport" content="width=device-width, initial-scale=1.0">  
        <title>Documenttitle>  
    head>  
    <body>  
        <form action="/test_servlet/postParameter" method="POST">  
            userId: <input type="text" name="userId">  
            <br/>  
            userName: <input type="text" name="userName">  
            <br/>  
            <input type="submit" name="提交">  
        form>  
    body>  
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 实验结果

    ![[Pasted image 20220821171830.png]]

    ![[Pasted image 20220821171815.png]]

    解析applicaion/jsno格式的正文参数

    • Servlet代码
    class JsonData {  
        public int userId;  
        public String userName;  
    }  
      
    @WebServlet("/postParameterJson")  
    public class PostParameterJsonServlet extends HttpServlet {  
        @Override  
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {  
            // 将请求正文先读取出来  
            String body = readBody(req);  
            // 使用第三方库jackson(Spring中的内置的json解析库)对json格式的字符串进行解析  
            ObjectMapper objectMapper = new ObjectMapper();  
            JsonData jsonData = objectMapper.readValue(body, JsonData.class);  
            resp.getWriter().write(String.format("userId: %d, userName: %s 
    "
    , jsonData.userId, jsonData.userName)); } private String readBody(HttpServletRequest req) throws IOException { // 使用HttpServletRequest中的inputStream流对象进行正文数据读取 InputStream inputStream = req.getInputStream(); int contentLength = req.getContentLength(); byte[] buffer = new byte[contentLength]; inputStream.read(buffer); return new String(buffer, "utf-8"); } }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    Jackson库基本原理就是先将json格式的字符串转换为键值对保存起来,然后根据类对象,通过反射机制获得类中有哪些属性,最后在前面保存的键值对结果中找类中属性对应的value。所以我们需要定义的JsonData这个类中属性和发送的json数据属性要一一对应,最后获得objectMapper.readValue()返回的对象就是解析完成的json数据。

    • 发送POST请求的前端代码
    DOCTYPE html>  
    <html lang="en">  
    <head>  
        <meta charset="UTF-8">  
        <meta http-equiv="X-UA-Compatible" content="IE=edge">  
        <meta name="viewport" content="width=device-width, initial-scale=1.0">  
        <title>Documenttitle>  
    head>  
    <body>  
        <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js">script>  
        <button onclick="sendJson()">发送 POST 请求button>  
        <script>  
            const sendJson = () => {  
                let body = {  
                    userId: 666,   
                    userName: "zhy"  
                };  
      
                $.ajax({  
                    url: "postParameterJson",  
                    type: "POST",  
                    contentType: "application/json",  
                    data: JSON.stringify(body),  
                    success: function(resp) {  
                        console.log(resp);  
                    }  
                });  
            }  
        script>  
    body>  
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    注意:使用ajax发送POST请求并带上json格式的数据的时候,需要将json数据使用JSON.stringify()转换为字符串进行发送。

    小结HttpServletRequest

    平时使用HttpServletRequest最常见的工作就是获得HTTP请求中的参数

    • 如果是GET请求,可以通过getParameter()获得url中的query string。
    • 如果是POST请求并且请求正文参数是application/x-www-form-urlencoded格式的,也是通过getParameter()获得正文中的参数
    • 如果是POST请求并且请求正文参数是application/json格式的,就需要先将请求正文数据读取出来,然后通过第三方库Jackson进行解析。

    HttpServletResponse

    核心方法

    ![[Pasted image 20220821200445.png]]

    案例:使用HttpServletResponse对象设置响应状态码

    • Servlet代码
    @WebServlet("/status")  
    public class StatusServlet extends HttpServlet {  
        @Override  
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {  
            resp.setContentType("text/html; charset=utf-8");  
            // 用户通过query string传递一个status,然后服务器返回对应状态码的响应  
            String statusString = req.getParameter("status");  
            if (statusString == null || statusString.equals("")) {  
                resp.getWriter().write("status 参数不存在");  
                return ;  
            }  
            resp.setStatus(Integer.parseInt(statusString));  
            resp.getWriter().write("status: " + statusString);  
        }  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 实验结果
      ![[Pasted image 20220821203553.png]]

    案例:使用HttpServletResponse对象在响应报头中添加键值对

    • Servlet代码
    @WebServlet("/autoRefresh")  
    public class AutoRefreshServlet extends HttpServlet {  
        @Override  
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {  
            resp.setContentType("text/html; charset=utf8");  
            // 在响应报头中添加一个键值对,将Refresh设置为1,那么浏览器就会每隔一秒进行一次刷新  
            resp.setHeader("Refresh", "1");  
            // 通过返回一个时间戳来看到浏览器每隔一秒都在进行刷新  
            long timeStamp = System.currentTimeMillis();  
            resp.getWriter().write("timeStamp: " + timeStamp);  
        }  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 实验结果
      ![[Pasted image 20220821204930.png]]

    案例:使用HttpServletResponse对象设置页面重定向

    • Servlet代码
    @WebServlet("/redirect")  
    public class RedirectServlet extends HttpServlet {  
        @Override  
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {  
            // 设置重定向有两种方法:  
            // 1.设置响应报文的状态码,并添加Location字段在响应报头中  
    //        resp.setStatus(302);  
    //        resp.setHeader("Location", "https://www.baidu.com");  
                    // 2.使用sendRedirect()进行重定向  
             resp.sendRedirect("https://www.baidu.com");  
        }  
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  • 相关阅读:
    Centos7.9 安装 clickhouse 24.6.1
    Flutter开发桌面应用的一些探索分享
    Python深度学习032:conda操作虚拟环境env的全部命令
    MongoDB磁盘空间占满,导致数据库被锁定,如何清理数据和磁盘空间
    react18【系列实用教程】useReducer —— 升级版的 useState (2024最新版)
    Kafka生产者消息发送流程
    hping3网络延迟检测工具——筑梦之路
    New Journal of Physics:不同机器学习力场特征的准确性测试
    gcc编译介绍
    开发一个商城需要多少钱 做一个电商网站大概多少钱
  • 原文地址:https://blog.csdn.net/zhybiancheng/article/details/126456259