• javaEE初阶---Servlet


    一 : Servlet的定义

    Servlet 是一种实现动态页面的技术. 是一组 Tomcat 提供给程序猿的 API, 帮助程序猿简单高效的开发一个 web app.
    
    • 1

    Java Servlet 是运行在 Web服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。使用 Servlet,您可以收集来自网页表单的用户输入,呈现来自数据库或者其他源的记录,还可以动态创建网页 .

    Servlet用于开发动态页面 , 根据用户输入内容的不同 , 来返回出不同的页面结果 .

    什么是动态页面 , 什么是静态页面呢 ?

    • 静态页面也就是内容始终固定的页面. 即使用户不同/时间不同/输入的参数不同 , 页面内容也不会发生 ;
      变化. (除非网站的开发人员修改源代码, 否则页面内容始终不变).
    • 动态页面指的就是 用户不同/时间不同/输入的参数不同, 页面内容会发生变化 .

    在这里插入图片描述

    在这里插入图片描述

    二 : Servlet的任务

    1. 允许程序猿注册一个类, 在 Tomcat 收到某个特定的 HTTP 请求的时候, 执行这个类中的一些代码.
    2. 帮助程序猿解析 HTTP 请求, 把 HTTP 请求从一个字符串解析成一个 HttpRequest 对象.
    3. 帮助程序猿构造 HTTP 响应. 程序猿只要给指定的 HttpResponse 对象填写一些属性字段, Servlet就会自动安装 HTTP 协议的方式构造出一个 HTTP 响应字符串, 并通过 Socket 写回给客户端.
    4. 发送显式的数据(即文档)到客户端(浏览器)。该文档的格式可以是多种多样的,包括文本文件(HTML 或 XML)、二进制文件(GIF 图像)、Excel 等。
    5. 发送隐式的 HTTP 响应到客户端(浏览器)。这包括告诉浏览器或其他客户端被返回的文档类型(例如 HTML),设置 cookies 和缓存参数,以及其他类似的任务。

    三 : 写一个简单的Servlet程序

    一共需要七大步骤 .
    
    • 1

    2.1创建项目

    在这里插入图片描述

    maven叫做"构建工具" , 针对代码进行依赖管理 , 编译 , 打包 , 验证 , 部署等功能 , 可以视为是针对复杂项目进行管理的一个解决方案 .

    maven自身的功能是很多的 , 我们主要使用 :

    1. 管理依赖 : 想使用某个第三方库,就使用maven把这个库下载下来并导入到项目中 .
    2. 打包 : 把代码编译好,把.class 文件打成压缩包(.jar 或者.war) .

    在这里插入图片描述

    2.2 引入依赖

    此处谈到的依赖 , 是编写Servlet程序所需要的依赖(Servlet的jar包) , 需要把这个jar下载导入到项目中 .

    下载步骤 :

    1. 打开 Maven的中央仓库
    2. 找到我们所需要的内容 :

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    1. 把这段文字 , 粘贴到pom.xml里面 .

    在这里插入图片描述
    注意 : 首次使用 , 会标红 , 这是因为在首次使用时 , maven会从中央视仓库下载对应的jar包 , 这需要一定的时间 . 你也可是点击刷新 , 主动触发下载 !

    在这里插入图片描述
    在这里插入图片描述

    2.3 创建目录

    在这里插入图片描述
    将下面的内容复制粘贴到web.xml中 .

    <!DOCTYPE web-app PUBLIC
    "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd" >
    <web-app>
    <display-name>Archetype Created Web Application</display-name>
    </web-app>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    webapp 目录就是未来部署到 Tomcat 中的一个重要的目录. 当前我们可以往 webapp 中放一些静态资源, 比如 html , css 等.

    在这个目录中还有一个重要的文件 web.xml. Tomcat 找到这个文件才能正确处理 webapp 中的动态资源.

    2.4编写代码

    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;
    
    @WebServlet("/hello")
    public class HelloServet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("hello world");
            resp.getWriter().write("hello world");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述

    doGet()方法不是咱们自己手动调用的 , 而是Tomcat自动调用的 , Tomcat 会自动的识别出合适的时机,来自动调用doGet方法 , —定是通过GET请求触发的!!! doGet做的工作,就是Tomcat收到请求之后,到返回响应之前,中间的过程 !

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    @WebServlet 属于类级别的注解,标注在继承了 HttpServlet 的类之上。常用的写法是将 Servlet 的相对请求路径(即 value)直接写在注解内 .

    上述代码没有main方法 , 不能单独执行,main方法在Tomcat内 , 上述代码需要部署到Tomcat中,由Tomcat进行调用.main好比汽车的发动机 , 我们写的Servlet代码就是车厢 . 只有个车头 , 可以自己跑 ; 但是车厢直接不能跑 , 得挂在车头上 .

    在这里插入图片描述

    2.5 打包

    借助maven , 一键式完成 !
    
    • 1

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    再次双击package进行打包 !

    在这里插入图片描述

    2.6 部署

    把刚才得到的war包 , 拷贝到Tomcat的webapps目录中 !
    
    • 1

    在这里插入图片描述

    2.7 验证

    让浏览器构造一个HTTP Get请求 !
    
    • 1

    在这里插入图片描述
    注意目录结构:
    在这里插入图片描述

    总结 :

    在这里插入图片描述

    注意 : Spring Boot可以简化这里的流程 , 现在先介绍一种中间的方案 , 即借助IDEA中的一个插件 , Smart Tomcat , 来简化打包和部署 .

    在这里插入图片描述
    在这里插入图片描述

    smart tomcat不是tomcat , 其功能就是能够在IDEA中调用tomcat , 我们就无需手动双击tomcat的启动脚本来运行 , 而是直接在IDEA中一点就能运行tomcat了 .

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    点击运行, 会在IDEA中显示tomcat的日志 .

    在这里插入图片描述

    此处中文也不再乱码了 !

    在这里插入图片描述

    smart tomcat的工作原理 , 和前面的手动拷贝部署不太一样 , 是让tomcat直接加载了我们代码中的webapp目录 , 这时候就跳过了打包 + 拷贝的过程 , 但是也起到了部署的效果 !

    常见错误集合 :

    1. 404 : 大概率是URL写错了 , 也可能是webapp未正确加载(比如web.xml写错了) .
    2. 405 : method not allowed , 发送GET请求但未实现doGet() , 或实现了doGet() , 但未把super.doGet这个代码删掉 ;
    3. 505 : 服务器内部错误 , 即服务器挂了 , 这说明你的代码中抛出了异常 .
    4. 返回空白页面 , 大概率是未执行write()方法 .
    5. 无法访问此网站 , 大概率是tomcat没有正确启动 .

    Tomcat 的定位

    上面的实现是在tomcat的基础上实现的 .

    HTTP 协议作为一个应用层协议, 需要底层协议栈来支持工作. 如下图所示 :

    在这里插入图片描述
    更详细的交互过程见下图 :

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    四 : Servlet API 详解

    重点关注三个类 !
    
    • 1

    在这里插入图片描述

    4.1HttpServlet

    4.1.1核心方法

    在这里插入图片描述

    • init只会在该Servlet类第一次被使用的时候调用到 , 相当于是用来初始化 ;
    • destroy是在Servlet对象被销毁的时候才会调用到 , 仅调用一次 , 相当于收尾工作 . 这个方法不一定能执行到 , 仅在tomcat是通过8005端口进行关闭时会执行destroy , 如果是直接杀死tomcat进程 , 则不会调用 .
    • service在每次收到请求(无论什么方法)时都会调用到service , 默认父类的service里面就会根据方法调用doGet/doPost .

    最常用的 : doXXX系列!!!

    这些方法的调用时机, 就称为 “Servlet 生命周期”. (也就是描述了一个 Servlet 实例从生到死的过程).

    在这里插入图片描述

    4.1.2构造POST请求

    前面我们通过在浏览器里输入url构造了GET请求 , 那POST请求该如何构造呢 ?

    form可以支持get和post , 在此处我们可以使用ajax .

    在这里插入图片描述
    在这里插入图片描述

    加载 : jQuery

    在这里插入图片描述

    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;
    
    @WebServlet("/hello")
    public class HelloServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("doGet!");
            resp.getWriter().write("doGet!");
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("doPost!");
            resp.getWriter().write("doPost!");
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    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://code.jquery.com/jquery-3.6.1.min.js">script>
        <script>
            $.ajax({
               type:'post',
               url:'hello',
               //url:'/hello_servlet/hello',
                success:function(body){
                    console.log(body);
                }
            });
        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

    在这里插入图片描述

    此处我们只在控制台看到了响应 , 在控制台打印了"doPost!" , 这是因为ajax拿到的响应数据,是根据回调函数的方法处理的 , 可以显示 , 也可以不显示 ; 而直接通过浏览器输入url得到的响应内容是直接被浏览器渲染到页面上的 .

    路径问题

    如何把内容打印到页面上呢 ?

    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;
    
    @WebServlet("/hello")
    public class HelloServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("doGet!");
            resp.getWriter().write("doGet!");
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("doPost!");
            resp.getWriter().write("doPost!");
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    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>
        <style>
            .one{
                font-size: 50px;
                color: aqua;
            }
        style>
    head>
    <body>
        <div class="one">div>
        <script src="https://code.jquery.com/jquery-3.6.1.min.js">script>
        <script>
            $.ajax({
               type:'post',
               url:'hello',
                success:function(body){
                    //console.log(body);
                    let div = document.querySelector('.one');
                    div.innerHTML = body;
                }
            });
        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

    在这里插入图片描述

    根据当前的请求"doPost" , 决定调用我们自己代码中的doGet方法!!!

    在进行这部分操作时 , 一开始出现了下面的问题 , 显示报错信息为 :

    无法在地址[localhost]和端口[8005]上创建服务器关闭套接字(基本端口[8005]和偏移量[0]).

    经过查阅资料 , 发现这是端口占用导致的问题 . 解决方案如下 :

    1. 查看端口占用
      在windows命令行窗口下执行:netstat -aon|findstr “8080”

    在这里插入图片描述
    端口“8080”被PID(进程号)为16160的进程占用 .

    1. 查看端口“8080”被哪个应用占用,,继续执行下面命令:tasklist|findstr “16160”

    在这里插入图片描述

    3.关闭进程(此处按进程名关闭进程) : taskkill /im java.exe

    在这里插入图片描述

    扩展 : 关闭进程的方式 :

    1. 按进程号关闭进程 taskkill /pid 2152
      多个时格式为:taskkill /pid 2152 /pid 1284 / …
    2. 按进程名关闭进程 如要关闭notepad.exe,格式为:taskkill /im notepad.exe
      指定多个时格式为:taskkill /im notepad.exe /im iexplorer.exe / im…
      如果是要关闭所有的,则使用通配符*,即:taskkill /im *.exe
    3. 有提示的关闭进程 taskkill /t /im notepad.exe
      taskkill /t /pid 2152
      这个效果是提示后在使用者确定后关闭,有提示框。
    4. 强行终止进程 taskkill /f /im notepad.exe
      taskkill /f /pid 2152

    被拒绝时 , 尝试使用命令行 taskkill /f /t /im java.exe,可以关闭,亲测可用 .

    通过按钮触发ajax请求的发送 :

    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;
    
    @WebServlet("/hello")
    public class HelloServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("doGet!");
            resp.getWriter().write("doGet!");
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("doPost!");
            resp.getWriter().write("doPost!");
        }
    
        @Override
        protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("doPut!");
            resp.getWriter().write("doPut!");
        }
    
        @Override
        protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            System.out.println("doDelete!");
            resp.getWriter().write("doDelete!");
        }
    }
    
    
    • 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
    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>
        <style>
            .one{
                font-size: 50px;
                color: aqua;
            }
        style>
    head>
    <body>
        <div class="one">div>
    
        <button id="doGet">getbutton>
        <button id="doPost">postbutton>
        <button id="doPut">putbutton>
        <button id="doDelete">deletebutton>
        <script src="https://code.jquery.com/jquery-3.6.1.min.js">script>
        <script>
            let doGetBtn = document.querySelector('#doGet');
            doGetBtn.onclick = function(){
                $.ajax({
               type:'get',
               url:'hello',
                success:function(body){
                    let div = document.querySelector('.one');
                    div.innerHTML = body;
                }
            });
            }
    
            let doPostBtn = document.querySelector('#doPost');
            doPostBtn.onclick = function(){
                $.ajax({
               type:'post',
               url:'hello',
                success:function(body){
                    //console.log(body);
                    let div = document.querySelector('.one');
                    div.innerHTML = body;
                }
            });
            }
    
            let doPutBtn = document.querySelector('#doPut');
            doPutBtn.onclick = function(){
                $.ajax({
               type:'put',
               url:'hello',
                success:function(body){
                    //console.log(body);
                    let div = document.querySelector('.one');
                    div.innerHTML = body;
                }
            });
            }
    
            let doDeleteBtn = document.querySelector('#doDelete');
            doDeleteBtn.onclick = function(){
                $.ajax({
               type:'delete',
               url:'hello',
                success:function(body){
                    //console.log(body);
                    let div = document.querySelector('.one');
                    div.innerHTML = body;
                }
            });
            }
    
        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
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77

    在这里插入图片描述

    注意文件位置 :

    在这里插入图片描述

    Q : 当前使用ajax构造出了上述几种请求.但是还是比较麻烦.毕竟要写代码 . 是否有办法,不写代码,也能构造出任意的http请求呢?

    A : 此处还可以使用第三方工具,来构造HTTP请求. (类似功能的工具种类繁多),咱们在工作中一个非常常用的,叫做 PostMan(各种请求都能构造 , 真香) . Postman本来是chrome的一个插件.现在已经是独立的程序了 . 可以去官网下载安装 !

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述
    简单演示用法 :

    在这里插入图片描述

    在这里插入图片描述

    Q : 面试题 : 谈谈HttpServlet的生命周期 ?

    A :

    1. 首次使用 , 先调用一次init ;
    2. 每次收到请求 , 调用service , 在service内部通过具体方法来决定调用哪个doXXX代码 ;
    3. 销毁之前调用destroy .

    4.2 HttpServletRequest

    在这里插入图片描述

    这个类就提供了一组方法 , 让我们能够获取到HTTP请求中的这些信息 .

    4.2.1 核心方法

    在这里插入图片描述
    在这里插入图片描述

    4.2.2实例

    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.util.Enumeration;
    
    @WebServlet("/requestServlet")
    public class RequestServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append(req.getProtocol());//返回请求协议的名称和版本
            stringBuilder.append("
    "
    ); stringBuilder.append(req.getMethod());//返回请求的HTTP方法的名称 stringBuilder.append("
    "
    ); stringBuilder.append(req.getRequestURI());//返回请求的URL的一部分 stringBuilder.append("
    "
    ); stringBuilder.append(req.getQueryString());//返回包含在路径后的请求URL中的查询字符串 stringBuilder.append("
    "
    ); Enumeration<String> headersnames = req.getHeaderNames(); while(headersnames.hasMoreElements()){ String name = headersnames.nextElement(); stringBuilder.append(name+":"+req.getHeader(name)); stringBuilder.append("
    "
    ); } //设置Content Type resp.setContentType("test/html;charset=utf8"); resp.getWriter().write(stringBuilder.toString()); } }
    • 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

    在这里插入图片描述

    更多的情况下 , 需要通过API拿到请求中传来的必要的参数 !!! 假如教务系统上 , 需要获取某个同学的信息 , 给服务器发个请求 :

     /studentInfo?classId=368&studentId=20
    
    • 1

    此时服务器就需要知道传过来的信息是什么 .

    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;
    class Student{
        public int classId;
        public int studentId;
    }
    @WebServlet("/studentInfo")
    public class StudentInofoServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // 假设客户端发来的请求形如 /studentInfo?classId=368&studentId=20
            // 就可以通过 getParameter 方法来拿到这两个 id 的值.
            resp.setContentType("text/html,charset=utf8");
            String queryString = req.getQueryString();
            System.out.println(queryString);
            String classId = req.getParameter("classId");
            String studentId = req.getParameter("studentId");
            System.out.println("classId: " + classId + "studentId: " + studentId);
            resp.getWriter().write("classId: " + classId + "studentId: " + studentId);
        }
    }
    
    
    • 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

    在这里插入图片描述

    在这里插入图片描述

    getParameter的效果就是拿到query string中的键值对 , 根据key获取value(key和value都是String类型的) .

    前端除了通过query string来传参 , 还有其他的传参方式 , 比如可以通过post请求 , 通过body来传参到服务器 .

    在这里插入图片描述

    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.util.function.DoublePredicate;
    
    class Student{
        public int classId;
        public int studentId;
    }
    @WebServlet("/studentInfo")
    public class StudentInofoServlet extends HttpServlet {
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            // 约定 body 使用 application/x-www-form-urlencoded 这种格式来传参.
            // 这个格式就形如 classId=368&studentId=05
            // 这个格式和 query string 相同!!! 只是数据是在 body 中!
            // 针对这种格式, 获取到值的方式, 仍然是 getParameter !!!!
            resp.setContentType("text/html,charset=utf8");
            String queryString = req.getQueryString();
            System.out.println(queryString);
            String classId = req.getParameter("classId");
            String studentId = req.getParameter("studentId");
            System.out.println("classId: " + classId + " studentId: " + studentId);
            resp.getWriter().write("classId: " + classId + " studentId: " + studentId);
        }
    }
    
    
    • 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

    通过Postman构造POST请求 :

    在这里插入图片描述

    使用Fiddler抓包的结果 :

    在这里插入图片描述
    还可以通过form构造请求 :

    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>通过form构造请求title>
    head>
    <body>
        <form action="studentInfo" method="post">
                <input type="text" name="classId">
                <input type="text" name="studentId">
                <input type="submit" name="提交">
        form>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述
    如果 POST 请求中的 body 是按照 JSON 的格式来传递, 那么获取参数的代码就要发生调整.

    在这里插入图片描述
    结果是这样的 :

    在这里插入图片描述
    显然我们没法正确解析 .

    如果我们自己写代码按照字符串解析的方式获取到这里的键值对 , 是很费劲的 , 所以我们选择使用第三方库 . Java世界中有很多处理Json的第三方库 , 此处我们使用Jackson . (Spring官方推荐使用且内部集成了) .

    打开 maven中央仓库

    在这里插入图片描述
    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    将依赖下载到本地 : (点击刷新)

    在这里插入图片描述
    在这里插入图片描述

    此时 , maven就把这个库给下载到了本地 .

    在这里插入图片描述

    对于jackson , 只需要掌握两个操作 :

    • 把json格式的字符串转化为Java对象 ;
    • 把Java对象转成json字符串 .

    对应到一个类ObjectMapper .

    import com.fasterxml.jackson.databind.ObjectMapper;
    
    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.util.function.DoublePredicate;
    
    class Student{
        public int classId;
        public int studentId;
    }
    @WebServlet("/studentInfo")
    public class StudentInofoServlet extends HttpServlet {
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
              //处理json格式的请求
            ObjectMapper objectMapper = new ObjectMapper();
            //使用readValue把json字符串转成Java对象
            Student student = objectMapper.readValue(req.getInputStream(),Student.class);
            System.out.println(student.classId+","+student.studentId);
            resp.getWriter().write(student.classId+","+student.studentId);
            
        }
    }
    
    
    • 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

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    加入json中的key和类里的属性不一致, 会发生什么?

    在这里插入图片描述

    此时出现内部服务器错误 .

    4.3 HttpServletResponse

    Servlet 中的 doXXX 方法的目的就是根据请求计算得到相应, 然后把响应的数据设置到
    HttpServletResponse 对象中. 然后 Tomcat 就会把这个 HttpServletResponse 对象按照 HTTP 协议的格式, 转成一个字符串, 并通过Socket 写回给浏览器.

    4.3.1 核心方法

    在这里插入图片描述

    注意 : Request是get系列的方法, Response则是一些set系列的方法.
    
    • 1

    在这里插入图片描述
    简单演示上述API :

    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;
    
    @WebServlet("/status")
    public class StatusCodeServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //设置相应的状态码
            resp.setStatus(500);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述

    代码示例 : 自动刷新

    给响应报文header设置Refresh属性 , 跟上的value表示让浏览N秒之后刷新 .

    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;
    
    @WebServlet("/refresh")
    public class RefreshServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.setHeader("Refresh","1");
            resp.getWriter().write(System.currentTimeMillis()+"");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述
    显示时间戳, 每隔1秒刷新一次 .

    实际运用: 文字直播 .

    在这里插入图片描述

    代码示例: 重定向

    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;
    
    @WebServlet("/redirect")
    public class RedirectServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.setStatus(302);//3xx表示重定向, 默认用302
            resp.setHeader("Location","https://www.baidu.com");
    
            /*
             另一种简单的写法
             resp.sendRedirect("https://www.baidu.com");
             */
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在这里插入图片描述

    简单总结 :
    在这里插入图片描述

    五 :应用—留言板

    效果回顾 :

    在这里插入图片描述

    当前这些数据只是在浏览器的内存中保存着 , 一旦浏览器重启或刷新页面 , 数据就消失了 .

    解决方案就是把数据保存在服务器上 .

    5.1准备工作

    1. 创建好项目 ;
    2. 构建好目录 ;
    3. 引入依赖 ;
    4. 把留言板项目拷贝到项目中 .

    在这里插入图片描述
    这个html应该放在webapp目录下 .

    此时我们就可以换一种打开方式了 .

    5.2 约定好前后端交换的接口

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    5.3 实现提交数据

    在这里插入图片描述

    编写前端请求代码(第3部分)

                    //5.[新步骤]需要把刚才输入框里取到的数据, 构造成 POST 请求, 交给后端服务器!
                    let messageJson = {
                        "from" : from,
                        "to" : to,
                        "message" : message
                    };
                    $.ajax({
                        type:"post",
                        url:'message',//或者写url='/MessageWall/message'
                        contentType:"application/json;charset=utf8",
                        data:JSON.stringify(messageJson),
                        success:function(body){
                            alert("提交成功!");
                        },
                        error:function(){//在服务器返回的状态码不是2xx时触发这个error
                            alert("提交失败!");
                        }
                    });
     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述

    整体代码

    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>留言板title>
        <style>
            * {
                padding: 0;
                margin: 0;
                box-sizing: border-box;
            }
    
            .container {
                width : 800px;
                margin : 10 px auto;
            }
    
            .container h2 {
                text-align: center;
                margin: 30px 0px;
            }
    
            .row {
                height: 50px;
                display: flex;
                justify-content: center;
                margin-top: 5px;
                line-height: 50px;
            }
    
            .row span {
                height: 50px;
                width: 100px;
                line-height: 50px;
            }
    
            .row input {
                height: 50px;
                width: 300px;
                line-height: 40px;
                font-size: 30px;
                color: cadetblue;
            }
    
            .row button {
                width: 400px;
                height: 50px;
                color: #000;
                background-color: aquamarine;
                border: none;
                border-radius: 10px;
            }
    
            .row button:active {
                background-color: grey;
            }
        style>
    head>
    <body>
        
        <div class="container">
            <h2>留言板h2>
            <div class="row">
                <span>span>
                <input type="text" id="from">
            div>
    
            <div class="row">
                <span>对谁span>
                <input type="text" id="to">
            div>
    
            <div class="row">
                <span>说什么span>
                <input type="text" id="message">
            div>
    
            <div class="row">
                <button>提交button>
            div>
    
            <script src="https://code.jquery.com/jquery-3.6.1.min.js">script>
            <script>
                let container = document.querySelector('.container');
                let fromInput = document.querySelector('#from');
                let toInput = document.querySelector('#to');
                let messageInput = document.querySelector('#message');
                let button = document.querySelector('button');
                button.onclick = function() {
                    //1.把用户输入的内容获取到
                    let from = fromInput.value;
                    let to = toInput.value;
                    let message = messageInput.value;
                    if(from == '' || to == '' || message == ''){
                        return;
                    }
                    //2.构造一个div,把这个div插入到.container的末尾
                    let newDiv = document.createElement('div');
                    newDiv.className = 'row';
                    newDiv.innerHTML = from + "对" + to + "说" + message;
                    //3.把div挂在container里面
                    container.appendChild(newDiv);
                    //4.把之前输入框中的内容清空
                    fromInput.value = '';
                    toInput.value = '';
                    messageInput.value = '';
    
                    //5.[新步骤]需要把刚才输入框里取到的数据, 构造成 POST 请求, 交给后端服务器!
                    let messageJson = {
                        "from" : from,
                        "to" : to,
                        "message" : message
                    };
                    $.ajax({
                    type: 'post',
                    contentType: 'application/json;charset=utf8',
                    url: 'message',// 绝对路径的写法url: '/MessageWall/message',
                    data: JSON.stringify(messageJson),
                    success: function(body) {
                        alert("提交成功!");
                    },
                    error: function() {// 会在服务器返回的状态码不是 2xx 的时候触发这个 error. 
                        alert("提交失败!");
                    }
                });
            }
    
            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
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132

    编写后端响应代码(第4部分)

    在这里插入图片描述

    import com.fasterxml.jackson.databind.ObjectMapper;
    
    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.util.ArrayList;
    import java.util.List;
    
    //对应前端传来的请求body
    //保证这几个属性的名字都和json里的key对应
    class Message{
        public String from;
        public String to;
        public String message;
    
        @Override
        public String toString() {
            return "Message{" +
                    "from='" + from + '\'' +
                    ", to='" + to + '\'' +
                    ", message='" + message + '\'' +
                    '}';
        }
    }
    
    @WebServlet("/message")
    public class MessageServlet extends HttpServlet {
        private ObjectMapper objectMapper = new ObjectMapper();
        private List<Message> messageList = new ArrayList<>();
        //负责实现让客户端提交数据给服务器
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //1.把body的json数据解析出来
            Message message = objectMapper.readValue(req.getInputStream(),Message.class);
            //2.把这个对象保存起来,最简单的方法,就是存到内存中.
            messageList.add(message);
            System.out.println("message : " + message);
            //3.返回保存成功的响应
            resp.setContentType("application/json;charset=utf8");
            resp.getWriter().write("{\"ok\" : 1}");
        }
    
        //负责实现让客户端从服务器拿到数据
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        }
    
    }
    
    
    • 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
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    使用Fiddler , 来查看结果 :

    在这里插入图片描述

    编写后端请求代码(第1部分)

    在这里插入图片描述

        //负责实现让客户端从服务器拿到数据
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.setContentType("application/json;charset=utf8");
            //把对象转成json格式的字符串,此处messageList是一个List,直接被转成json数组
            String respString = objectMapper.writeValueAsString(messageList);
            resp.getWriter().write(respString);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    整体代码

    import com.fasterxml.jackson.databind.ObjectMapper;
    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.util.ArrayList;
    import java.util.List;
    
    //对应前端传来的请求body
    //保证这几个属性的名字都和json里的key对应
    class Message{
        public String from;
        public String to;
        public String message;
    
        @Override
        public String toString() {
            return "Message{" +
                    "from='" + from + '\'' +
                    ", to='" + to + '\'' +
                    ", message='" + message + '\'' +
                    '}';
        }
    }
    
    @WebServlet("/message")
    public class MessageServlet extends HttpServlet {
        private ObjectMapper objectMapper = new ObjectMapper();
        private List<Message> messageList = new ArrayList<>();
        //负责实现让客户端提交数据给服务器
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //1.把body的json数据解析出来
            Message message = objectMapper.readValue(req.getInputStream(),Message.class);
            //2.把这个对象保存起来,最简单的方法,就是存到内存中.
            messageList.add(message);
            System.out.println("message : " + message);
            //3.返回保存成功的响应
            resp.setContentType("application/json;charset=utf8");
            resp.getWriter().write("{\"ok\" : 1}");
        }
    
        //负责实现让客户端从服务器拿到数据
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.setContentType("application/json;charset=utf8");
            //把对象转成json格式的字符串,此处messageList是一个List,直接被转成json数组
            String respString = objectMapper.writeValueAsString(messageList);
            resp.getWriter().write(respString);
        }
    
    }
    
    
    • 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
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    编写前端响应代码(第2部分)在这里插入图片描述

     /*
            这个函数在页面加载时,从服务器获取到当前的消息列表
            并显示到页面上
            */
           function load(){
            $.ajax({
                type:'get',
                url:'message',
                success:function(body){
                    /*
                    此处得到的body是一个js对象的数组了
                    本来服务器返回的是JSON格式的字符串,ajax会自动根据
                    Content-Type对响应的body进行解析,解析成js对象
                    */
                   let container = document.querySelector('.container');
                   for(let message of body){
                    let newDiv = document.createElement('div');
                    newDiv.className = 'row';
                    newDiv.innerHTML = message.from + "对" + message.to + "说" +  message.message;
                    container.appendChild(newDiv); 
                   }
                }
            });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    整体代码

    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>留言板title>
        <style>
            * {
                padding: 0;
                margin: 0;
                box-sizing: border-box;
            }
    
            .container {
                width : 800px;
                margin : 10 px auto;
            }
    
            .container h2 {
                text-align: center;
                margin: 30px 0px;
            }
    
            .row {
                height: 50px;
                display: flex;
                justify-content: center;
                margin-top: 5px;
                line-height: 50px;
            }
    
            .row span {
                height: 50px;
                width: 100px;
                line-height: 50px;
            }
    
            .row input {
                height: 50px;
                width: 300px;
                line-height: 40px;
                font-size: 30px;
                color: cadetblue;
            }
    
            .row button {
                width: 400px;
                height: 50px;
                color: #000;
                background-color: aquamarine;
                border: none;
                border-radius: 10px;
            }
    
            .row button:active {
                background-color: grey;
            }
        style>
    head>
    <body>
        
        <div class="container">
            <h2>留言板h2>
            <div class="row">
                <span>span>
                <input type="text" id="from">
            div>
    
            <div class="row">
                <span>对谁span>
                <input type="text" id="to">
            div>
    
            <div class="row">
                <span>说什么span>
                <input type="text" id="message">
            div>
    
            <div class="row">
                <button>提交button>
            div>
    
            <script src="https://code.jquery.com/jquery-3.6.1.min.js">script>
            <script>
                let container = document.querySelector('.container');
                let fromInput = document.querySelector('#from');
                let toInput = document.querySelector('#to');
                let messageInput = document.querySelector('#message');
                let button = document.querySelector('button');
                button.onclick = function() {
                    //1.把用户输入的内容获取到
                    let from = fromInput.value;
                    let to = toInput.value;
                    let message = messageInput.value;
                    if(from == '' || to == '' || message == ''){
                        return;
                    }
                    //2.构造一个div,把这个div插入到.container的末尾
                    let newDiv = document.createElement('div');
                    newDiv.className = 'row';
                    newDiv.innerHTML = from + "对" + to + "说" + message;
                    //3.把div挂在container里面
                    container.appendChild(newDiv);
                    //4.把之前输入框中的内容清空
                    fromInput.value = '';
                    toInput.value = '';
                    messageInput.value = '';
    
                    //5.[新步骤]需要把刚才输入框里取到的数据, 构造成 POST 请求, 交给后端服务器!
                    let messageJson = {
                        "from" : from,
                        "to" : to,
                        "message" : message
                    };
                    $.ajax({
                    type: 'post',
                    contentType: 'application/json;charset=utf8',
                    url: 'message',// 绝对路径的写法url: '/MessageWall/message',
                    data: JSON.stringify(messageJson),
                    success: function(body) {
                        alert("提交成功!");
                    },
                    error: function() {// 会在服务器返回的状态码不是 2xx 的时候触发这个 error. 
                        alert("提交失败!");
                    }
                });
            }
    
            /*
            这个函数在页面加载时,从服务器获取到当前的消息列表
            并显示到页面上
            */
           function load(){
            $.ajax({
                type:'get',
                url:'message',
                success:function(body){
                    /*
                    此处得到的body是一个js对象的数组了
                    本来服务器返回的是JSON格式的字符串,ajax会自动根据
                    Content-Type对响应的body进行解析,解析成js对象
                    */
                   let container = document.querySelector('.container');
                   for(let message of body){
                    let newDiv = document.createElement('div');
                    newDiv.className = 'row';
                    newDiv.innerHTML = message.from + "对" + message.to + "说" +  message.message;
                    container.appendChild(newDiv); 
                   }
                }
            });
           }
    
    
           //函数调用写在这里,表示在页面加载时进行执行
           load();
            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
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160

    在这里插入图片描述
    执行一下!!!

    1.一开始加载页面 .

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    2.往服务器提交个数据 .
    在这里插入图片描述
    在这里插入图片描述

    3.刷新页面 , 重新从服务器获取数据 .
    在这里插入图片描述
    在这里插入图片描述
    此时已经从服务器获取到想要的数据了 , 不再是返回空列表了 .

    过程解释 :

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    接下来的问题是 , 当服务器从重启时 , List里的内容就会丢失 ! 如何解决这个问题呢 ?

    1. 存文件 , 使用IO流来读文件/写文件 .
    2. 数据库 , 使用MySQL + JDBC编程 .

    此处我们让服务器把数据保存在MySQL服务器上 .

    5.4将数据保存在MySQL服务器上

    1.引入MySQL依赖 .

    在这里插入图片描述

    从中央仓库导入即可 .

    1. 创建数据库数据表 .

    在这里插入图片描述

    可以把上述操作写到一个单独的文件中 , 以备后用 .

    在这里插入图片描述

    1. 调整后端代码 .
      a. 和数据库建立连接 , 单独搞一个DBUtil类 , 来实现数据库的建立连接 ;
      b. 封装数据库操作 , 通过JDBC来完成数据库的操作 .

    DBUtil.java

    import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
    
    import javax.sql.DataSource;
    import javax.swing.*;
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    /**
     * 期望通过这个类来完成数据库建立连接的过程
     * 建立连接需要使用DataSource,且一个程序有一个DDataSource实例即可.
     */
    public class DBUtil {
        private static DataSource dataSource = null;
        private static DataSource getDataSource() throws SQLException {
            if(dataSource == null){
                dataSource = new MysqlDataSource();
                ((MysqlDataSource)dataSource).setURL("jdbc:mysql:://127.0.0.1:3306/MessageWall?characterEncoding=utf8&useSSL=false");
                ((MysqlDataSource)dataSource).setUser("root");
                ((MysqlDataSource)dataSource).setPassword("111111");
            }
            return dataSource;
        }
        public static Connection getConnection() throws SQLException{
            return getDataSource().getConnection();
        }
    
        public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet){
            if(resultSet != null){
                try {
                    resultSet.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
            if(statement != null){
                try {
                    statement.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
            if(connection != null){
                try {
                    connection.close();
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    
    
    }
    
    
    • 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
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    MessageServletl.java

    import com.fasterxml.jackson.databind.ObjectMapper;
    
    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.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.ArrayList;
    import java.util.List;
    
    //对应前端传来的请求body
    //保证这几个属性的名字都和json里的key对应
    class Message{
        public String from;
        public String to;
        public String message;
    
        @Override
        public String toString() {
            return "Message{" +
                    "from='" + from + '\'' +
                    ", to='" + to + '\'' +
                    ", message='" + message + '\'' +
                    '}';
        }
    }
    
    @WebServlet("/message")
    public class MessageServlet extends HttpServlet {
        private ObjectMapper objectMapper = new ObjectMapper();
        //private List messageList = new ArrayList<>();
        //负责实现让客户端提交数据给服务器
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            //1.把body的json数据解析出来
            Message message = objectMapper.readValue(req.getInputStream(),Message.class);
            //2.把这个对象保存起来,最简单的方法,就是存到内存中.
            //messageList.add(message);
            save(message);
            System.out.println("message : " + message);
            //3.返回保存成功的响应
            resp.setContentType("application/json;charset=utf8");
            resp.getWriter().write("{\"ok\" : 1}");
        }
    
        //负责实现让客户端从服务器拿到数据
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.setContentType("application/json;charset=utf8");
            //把对象转成json格式的字符串,此处messageList是一个List,直接被转成json数组
            List<Message> messageList = load();
            String respString = objectMapper.writeValueAsString(messageList);
            resp.getWriter().write(respString);
        }
    
    
        /**
         *  把当前的消息保存到数据库中
         *  */
        private void save(Message message){
            Connection connection = null;
            PreparedStatement statement = null;
            try {
                //1.和数据库建立连接
               connection = DBUtil.getConnection();
                //2.构造SQL语句
                String sql = "insert into walldata values(?,?,?)";
                statement = connection.prepareStatement(sql);
                statement.setString(1,message.from);
                statement.setString(2,message.to);
                statement.setString(3,message.message);
                //3.执行SQL语句
                int ret = statement.executeUpdate();
                if(ret != 1){
                    System.out.println("插入失败!");
                } else {
                    System.out.println("插入成功!");
                }
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                //4.关闭连接
                DBUtil.close(connection,statement,null);
            }
        }
    
        /**
         * 从数据库查询到记录
         */
        private List<Message> load(){
            Connection connection = null;
            PreparedStatement statement = null;
            ResultSet resultSet = null;
            List<Message> messageList = new ArrayList<>();
            try {
                //1.建立连接
                connection = DBUtil.getConnection();
                //2.构造SQL
                String sql = "select * from walldata";
                statement = connection.prepareStatement(sql);
                //3.执行SQL
                resultSet = statement.executeQuery();
                //4.遍历结果集
                while(resultSet.next()){
                    Message message = new Message();
                    message.from = resultSet.getString("from");
                    message.to = resultSet.getString("to");
                    message.message = resultSet.getString("message");
                    messageList.add(message);
                }
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                //5.释放资源
                DBUtil.close(connection,statement,resultSet);
            }
        return messageList;
        }
    }
    
    
    • 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
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125

    允许效果如下 :

    在这里插入图片描述

    此时查询数据库中的walldata表 , 已经保存了这条数据 !
    在这里插入图片描述
    再次刷新页面 :

    在这里插入图片描述
    内容任然存在 !

    中断程序的运行 , 并再次启动 :

    在这里插入图片描述

    在这里插入图片描述

    再次刷新页面 ,内容仍然存在 !

    在这里插入图片描述

    在这里插入图片描述

    如果你发现结果不符合预期 , 怎么办 ?

    起手式–抓包 !!!

    1.一个是抓页面加载,看看GET /message方法请求和响应是啥样的 .

    1. 如果请求没问题,响应有问题,说明是后端问题 .
    2. 如果请求有问题,响应没问题,说明是前端问题.(检查发送ajax的代码)
    3. 如果请求响应都没问题,但是页面不能正确显示,还是前端问题~~(检查ajax的回调)

    2.还可以再抓包POST看看有没有问题 .

    3.还可以看看数据库里有没有正确数据.

    如果数据库有数据,说明大概率是GET的时候出问题了.如果数据库没数据,说明大概率是POST的时候出问题了!!!

    顺便记录一下笔者在这里出现的问题 :

    1.没有加载jQuery .

    在这里插入图片描述
    2. 数据库密码写错了 .

    在这里插入图片描述

    你可能会问了 , 你这数据库密码不就泄露了吗 ?

    我只能说 , 银行卡里没有余额,那掩盖密码也是无用的 .

    六 : Cookie和Session

    6.1 工作方式回顾

    Cookie是浏览器给HTTP协议提供的一个持久化存储数据的方案.
    
    • 1

    在这里插入图片描述

    典型应用 : 保存用户的身份信息 !

    在这里插入图片描述
    在这里插入图片描述

    注意 : Cookie是在客户端存的 , Session是在服务器存的 , Sessionid是在客户端和服务器都存了 .

    在这里插入图片描述

    注意 : 实现登录和身份验证是Cookie的一种典型的应用 , 此时需要Cookie和Session搭配工作 , 其他场景则不一定需要搭配Session . Cookie里是可以存多个键值对的 , 具体存什么 , 是程序猿自己约定的 . 比如你想存登录的时间 , 就可以以LoginTime为key , 以登录的时间戳为value .

    6.2 Servlet对Cookie和Session提供的API

    6.2.1 HttpServletRequest 类中的相关方法

    在这里插入图片描述

    6.2.2 HttpServletResponse 类中的相关方法

    在这里插入图片描述

    6.2.3 HttpSession 类中的相关方法

    一个 HttpSession 对象里面包含多个键值对. 我们可以往 HttpSession 中存任何我们需要的信息.
    
    • 1

    在这里插入图片描述

    6.2.4 Cookie 类中的相关方法

    每个 Cookie 对象是一个键值对
    
    • 1

    在这里插入图片描述

    6.3 代码示例—实现用户登录

    在这里插入图片描述

    功能 : 登录页可输入用户名和密码 , 服务器验证正确性 . 如果正确跳转到主页 , 并在主页中显示出当前用户的身份信息 , 且显示出当前用户的登录的访问次数 . (当用户第一次登录成功后 , 就无须重新登录了) .

    主页代码 : IndexServlet.java

    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 javax.servlet.http.HttpSession;
    import java.io.IOException;
    
    //用这个Servlet返回主页信息
    @WebServlet("/index")
    public class IndexServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            HttpSession session = req.getSession(false);
            if(session == null){
                //用户未登录,跳转到登录页面,要去用户重新登录
                resp.sendRedirect("login.html");
                return;
            }
            //已经成功登录
            String username = (String) session.getAttribute("username");
            Integer visitCount = (Integer) session.getAttribute("visitCount");
            visitCount = visitCount + 1;
            session.setAttribute("visitCount",visitCount);
    
            resp.setContentType("text/html;charset=utf8");
            resp.getWriter().write("当前用户为: " + username + "访问次数 :" + visitCount);
        }
    }
    
    
    • 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

    登录页代码 LoginServlet.java

    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 javax.servlet.http.HttpSession;
    import java.io.IOException;
    
    //用来处理登录请求
    @WebServlet("/login")
    public class LoginServlet extends HttpServlet {
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.setContentType("text/html;charset=utf8");
            //读取请求中的参数,判定当前用户信息是否正确
            String username = req.getParameter("username");
            String password = req.getParameter("password");
            if(username == null || username.equals("") || password == null || password.equals("") ){
                //返回提示
                resp.getWriter().write("用户名或密码不完整!登录失败");
                return;
            }
            if(!username.equals("baizong") || !password.equals("123456")){
                resp.getWriter().write("用户名或密码错误!登录失败!");
                return;
            }
            //登录成功,创建一个会话,把用户信息填写到session里
            HttpSession session = req.getSession(true);
            session.setAttribute("username","baizong");
            Integer visitCount = (Integer) session.getAttribute("visitCount");
            if(visitCount == null){
                session.setAttribute("visitCount",0);
            }
            resp.sendRedirect("index");
    
        }
    }
    
    
    • 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

    login.html

    <!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>登录页</title>
    </head>
    <body>
        <form action="login" method="post">
            <input type="text" name="username">
            <input type="password" name="password">
            <input type="submit" value="提交">
        </form>
    </body>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    实现效果 :

    在这里插入图片描述

    存储结构 :

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    七 : 上传文件

    在这里插入图片描述

    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.IOException;
    
    @MultipartConfig
    @WebServlet("/upload")
    public class UploadServlet extends HttpServlet {
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            Part part = req.getPart("MyFile");
            //获取到文件的真实名字
            System.out.println(part.getSubmittedFileName());
            //获取文件大小
            System.out.println(part.getSize());
            //获取文件的类型
            System.out.println(part.getContentType());.
            //把文件写入服务器这边的磁盘中
             part.write("C:\\Users\\86177\\Desktop\\result.jpg");
            resp.getWriter().write("upload ok!");
        }
    }
    
    • 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
    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>uploadtitle>
    head>
    <body>
        <form action="upload" method="post" enctype="multipart/form-data">
            <input type="file" name="MyFile">
            <input type="submit" value="上传">
        form>
    
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述

    最终效果 :

    在这里插入图片描述

    至此 , Servlet及其API全部介绍完毕 !

  • 相关阅读:
    js的cookie设置
    DevSecOps 安全即代码基础指南
    如何在 JavaScript 中使用 Cache-Control 头来控制缓存?
    十四天算法快速入门第四天之「双指针」
    【c++百日刷题计划】 ———— DAY20,刷题百天,养成刷题好习惯
    Python:让我教你如何让电脑永不息屏
    向量机SVM代码实现
    当酷雷曼VR直播遇上视频号,会摩擦出怎样的火花?
    java虚拟机详解篇五(类的加载器)
    数据结构与算法之折半查找
  • 原文地址:https://blog.csdn.net/baijaiyu/article/details/127393289