表白墙的实现【前后端交互】

news2024/11/16 0:17:58

目录

一、Servlet API 详解

1. HttpServletRequest

1.1 HttpServletRequest 方法

1.2 getParameter

2.HttpServletResponse

2.1  HttpServletResponse 方法 

2.2 代码示例: 设置状态码

2.3 代码示例: 重定向

二、表白墙

1.准备工作

 2.约定前后端交互接口

2.1 接口一:页面获取当前所有的留言消息

2.2 接口二:提交新消息给服务器

3.调整前端页面代码

4.数据持久化

4.1 数据存入数据库


🌈上节 Servlet 我们学习了 Tomcat 提供的 API;并且编写一个 Hello World 基本步骤:1️⃣创建项目(maven)2️⃣引入依赖(servler)3️⃣创建目录4️⃣编写代码(webapp/WEB-INF/web.xml)5️⃣打包程序(waven package)6️⃣部署程序(把 war 拷贝到 webapps 目录中)7️⃣验证代码;最后我们学习了 Servlet 中的三个核心类

一、Servlet API 详解

1. HttpServletRequest

HttpServletRequest 是一个 HTTP 请求:Tomcat 通过 Socket API 读取 HTTP 请求(字符串),就会按照 HTTP 协议的格式把字符串解析成 HttpServletRequest

1.1 HttpServletRequest 方法

String getProtocol()
返回请求协议的名称和版本
String getMethod()
返回请求的 HTTP 方法的名称,例如, GET POST PUT
String getRequestURI()
从协议名称直到 HTTP 请求的第一行的查询字符串中,返回该请求的 URL 的一部分
String getContextPath()
返回指示请求上下文的请求 URI 部分
String getQueryString()
返回包含在路径后的请求 URL 中的查询字符串
Enumeration getParameterNames()
返回一个 String 对象的枚举,包含在该请求中包含的参数的名称
String getParameter(String name)
以字符串形式返回请求参数的值,或者如果参数不存在则返回 null
String[] getParameterValues(String name)
返回一个字符串对象的数组,包含所有给定的请求参数的值,如果参数不存在则返回 null
Enumeration getHeaderNames()
返回一个枚举,包含在该请求中包含的所有的头名
String getHeader(String name)
以字符串形式返回指定的请求头的值
String getCharacterEncoding()
返回请求主体中使用的字符编码的名称
String getContentType()
返回请求主体的 MIME 类型,如果不知道类型则返回 null
int getContentLength()
以字节为单位返回请求主体的长度,并提供输入流,或者如果长度未知则返回 -1
InputStream getInputStream()
用于读取请求的 body 内容 . 返回一个 InputStream 对象

1️⃣ 其中 getRequestURI 不是 URL:URL 唯一资源定位符;URI 唯一资源标识符

2️⃣ query string 查询字符串:例如 http://餐厅:18/熏肉大饼?葱=少放,其中 葱=少放 就是查询字符串

3️⃣Enumeration getParameterNames() 和 String getParameter(String name) 是获取请求中的字符串:上述中 query string 中的键值对

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

//继承 HttpServlet
@WebServlet("/showRequest")
public class ShowRequest extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        StringBuilder result = new StringBuilder();
        result.append(req.getProtocol());
        result.append("<br>");
        result.append(req.getMethod());
        result.append("<br>");
        result.append(req.getRequestURI());
        result.append("<br>");
        result.append(req.getQueryString());
        result.append("<br>");
        result.append(req.getContextPath());
        result.append("<br>");

        //在响应中设置上 body 的类型,方便浏览器进行解析
        resp.setContentType("text/html;charset=utf8");
        resp.getWriter().write(result.toString());
    }
}

1.2 getParameter

getParameter 是最常用的 API 之一,是前端和后端传递数据非常常见的需求

1️⃣通过 query string 传递

约定:前端通过 query string 传递 username 和 password

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("/getParameter")
public class GetParameter extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //前端通过 url 的 query string 传递 username 和 password 两个属性
        String username = req.getParameter("username");
        if (username == null) {
            System.out.println("username 这个 key 在 query string 中不存在!");
        }
        String password = req.getParameter("password");
        if (password == null) {
            System.out.println("password 这个 key 在 query string 中不存在!");
        }
        System.out.println("username" + username + ", password" + password);

        resp.getWriter().write("ok");
    }
}

在 URL 中 query string 如果是包含 中文/特殊字符,务必要使用 urlencode 的方式转码;如果是直接写 中文/特殊字符,就会存在很大风险;如果不转码,在有些浏览器/http服务器下对中文支持不好的花,会出现问题

2️⃣通过 body (from) 传递

相当于 body 里存的数据的格式,和 query string 一样,但是 Content-Type 是 application/x-www-form-urlencoded,此时也是通过 getParameter 来获取到键值对

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("/getParameter")
public class GetParameter extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //给请求设置编码方式
        req.setCharacterEncoding("utf8");        
        //前端通过 body,以 form 表单的格式,把 username 和 password 传给服务器
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        if (username == null) {
            System.out.println("username 这个 key 在 body 中不存在!");
        }
        if (password == null) {
            System.out.println("password 这个 key 在 body 中不存在!");
        }
        System.out.println("username" + username + ", password" + password);

        resp.getWriter().write("ok");
    }
}

 由于是 post 请求,在网页中不好表现,我们打开 postman 

3️⃣通过 body (json) 传递(最常用的传递方式)

 json 也是键值对格式的数据,但是 Servlet 自身没有内置 json 解析功能,因此就需要借助其他第三方库;用来处理 json 的第三方库有很多,常见的如 fastjson、gson、jackson...,我们使用 jackson 来解析

 引入依赖:

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.15.0</version>
</dependency>
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;

class User {
    public String username;
    public String password;
}

@WebServlet("/json")
public class JsonServlet extends HttpServlet {
    // 使用 jackson, 最核心的对象就是 ObjectMapper
    // 通过这个对象, 就可以把 json 字符串解析成 java 对象; 也可以把一个 java 对象转成一个 json 格式字符串.
    private ObjectMapper objectMapper = new ObjectMapper();

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 通过 post 请求的 body 传递过来一个 json 格式的字符串.
        User user = objectMapper.readValue(req.getInputStream(), User.class);
        System.out.println("username=" + user.username + ", password=" + user.password);

        resp.getWriter().write("ok");
    }
}

 readValue 里面做的事情:

  1. 解析 json 字符串,转换成若干个键值对
  2. 根据第二个参数 User.class(.class 是类对象,就是这个类的图纸),去找到 User 里的所有的 public 的属性(或者有 public getter setter 的属性),依次遍历......
  3. 遍历属性,根据属性的名字取上述准备好的键值对里查询,看看这个属性名字是否存在对应的 value ,如果存在就把 value 复制到该属性中

2.HttpServletResponse

HttpServletResponse 表示一个 HTTP 响应

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

2.1  HttpServletResponse 方法 

void setStatus(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 字符集)例如, UTF-8
void sendRedirect(String location)
使用指定的重定向位置 URL 发送临时重定向响应到客户端
PrintWriter getWriter()
用于往 body 中写入文本格式数据
OutputStream getOutputStream()
用于往 body 中写入二进制格式数据

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;

@WebServlet("/status")
public class StatusServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setStatus(404);
        resp.setContentType("text/html; charset=utf8");
        resp.getWriter().write("返回 404 响应!");
    }
}

 抓包结果

 2.3 代码示例: 自动刷新

通过 header 实现自动刷新效果:给 HTTP 响应中,设置 Refresh——时间

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;

//通过 header 实现自动刷新效果:给 HTTP 响应中,设置 Refresh——时间

@WebServlet("/refresh")
public class RefreshServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException {
        // 每隔 1s 自动刷新一次.
        resp.setHeader("Refresh", "1");
        resp.getWriter().write("time=" + System.currentTimeMillis());
    }
}

2.3 代码示例: 重定向

 代码案例:用户访问这个供暖这个路径的时候,自动重定向到搜狗主页

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);
        //resp.setHeader("Location", "https://www.sogou.com");
        resp.sendRedirect("https://www.sogou.com");
    }
}

部署程序, 通过 URL http://127.0.0.1:8080/hello_servlet/redirectServlet 访问, 可以看到, 页面自动跳转到 搜狗主页 了.

抓包结果:

二、表白墙

表白墙前端页面代码:message.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>
    <!-- 引入 jquery -->
    <script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
    <style>
        /* * 通配符选择器, 是选中页面所有元素 */
        * {
            /* 消除浏览器的默认样式. */
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        .container {
            width: 600px;
            margin: 20px auto;
        }

        h1 {
            text-align: center;
        }

        p {
            text-align: center;
            color: #666;
            margin: 20px 0;
        }

        .row {
            /* 开启弹性布局 */
            display: flex;
            height: 40px;
            /* 水平方向居中 */
            justify-content: center;
            /* 垂直方向居中 */
            align-items: center;
        }

        .row span {
            width: 80px;
        }

        .row input {
            width: 200px;
            height: 30px;
        }

        .row button {
            width: 280px;
            height: 30px;
            color: white;
            background-color: orange;
            /* 去掉边框 */
            border: none;
            border-radius: 5px;
        }

        /* 点击的时候有个反馈 */
        .row button:active {
            background-color: grey;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>表白墙</h1>
        <p>输入内容后点击提交, 信息会显示到下方表格中</p>
        <div class="row">
            <span>谁: </span>
            <input type="text">
        </div>
        <div class="row">
            <span>对谁: </span>
            <input type="text">
        </div>
        <div class="row">
            <span>说: </span>
            <input type="text">
        </div>
        <div class="row">
            <button id="submit">提交</button>
        </div>
        <div class="row">
            <button id="revert">撤销</button>
        </div>
        <!-- <div class="row">
            xxx 对 xx 说 xxxx
        </div> -->
    </div>

    <script>
        // 实现提交操作. 点击提交按钮, 就能够把用户输入的内容提交到页面上显示. 
        // 点击的时候, 获取到三个输入框中的文本内容
        // 创建一个新的 div.row 把内容构造到这个 div 中即可. 
        let containerDiv = document.querySelector('.container');
        let inputs = document.querySelectorAll('input');
        let button = document.querySelector('#submit');
        button.onclick = function() {
            // 1. 获取到三个输入框的内容
            let from = inputs[0].value;
            let to = inputs[1].value;
            let msg = inputs[2].value;
            if (from == '' || to == '' || msg == '') {
                return;
            }
            // 2. 构造新 div
            let rowDiv = document.createElement('div');
            rowDiv.className = 'row message';
            rowDiv.innerHTML = from + ' 对 ' + to + ' 说: ' + msg;
            containerDiv.appendChild(rowDiv);
            // 3. 清空之前的输入框内容
            for (let input of inputs) {
                input.value = '';
            }
        }
        let revertButton = document.querySelector('#revert');
        revertButton.onclick = function() {
            // 删除最后一条消息. 
            // 选中所有的 row, 找出最后一个 row, 然后进行删除
            let rows = document.querySelectorAll('.message');
            if (rows == null || rows.length == 0) {
                return;
            }
            containerDiv.removeChild(rows[rows.length - 1]);
        }
    </script>
</body>
</html>

1.准备工作

1️⃣创建一个 maven 项目

2️⃣引入依赖:servlet、jackson

<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.15.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
</dependency>

3️⃣创建必要的目录 webapp、WEB-INF、web.xml

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>

4️⃣把之前实现的表白墙前端页面拷贝到 webapp 目录中

 5️⃣配置 Smart Tomcat

 6️⃣运行程序就可以访问前端页面

 2.约定前后端交互接口

 写代码之前需要明确前后端交互端口

 🙈什么时候发送请求❓❓


1️⃣页面加载完毕之后,需要给服务器发送请求,获取当前的留言数据都有什么

2️⃣用户点击提交的时候,就需要告诉服务器,当前用户发送了的消息是啥

在交互的过程中,有涉及到关键的问题:请求具体是什么样子❓❓响应具体是什么样子❓❓这些都需要程序猿来设计,这就叫“约定前后端交互端口

此处给出一份典型的约定方式(并不是唯一的方式)

2.1 接口一:页面获取当前所有的留言消息

约定

1️⃣请求:GET/message

2️⃣响应:HTTP/1.1 200 OK

    Content-Type:application/json

[
   {
        from: "从哪里来",
        to: "到哪里去",
        message: "消息是啥"
   },
   {
        from: "从哪里来",
        to: "到哪里去",
        message: "消息是啥"
   },
    ......
]

json 中使用[ ] 表示数组,[ ] 中的每个元素是一个 { } json 对象;每个对象里又有三个属性 from、to、message

2.2 接口二:提交新消息给服务器

1️⃣请求:POST/message

    Content-Type:application/json

[
   {
        from: "从哪里来",
        to: "到哪里去",
        message: "消息是啥"
   },
   {
        from: "从哪里来",
        to: "到哪里去",
        message: "消息是啥"
   },
    ......
]

2️⃣响应:HTTP/1.1 200 OK

处理 "获取所有留言消息":创建 Message 类、创建 MessageServlet

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;

class Message {
    // 这几个属性必须设置 public !!!!
    // 如果设置 private, 必须生成 public 的 getter 和 setter !!!
    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 doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 通过这个方法来处理 "获取所有留言消息"
        // 需要返回一个 json 字符串数组. jackson 直接帮我们处理好了格式.
        String respString = objectMapper.writeValueAsString(messageList);
        resp.setContentType("application/json; charset=utf8");
        resp.getWriter().write(respString);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 通过这个方法来处理 "提交新消息"
        Message message = objectMapper.readValue(req.getInputStream(), Message.class);
        messageList.add(message);
        System.out.println("消息提交成功! message=" + message);

        // 响应只是返回 200 报文. body 为空. 此时不需要额外处理. 默认就是返回 200 的.
    }
}

3.调整前端页面代码

<!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>
    <!-- 引入 jquery -->
    <script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
    <style>
        /* * 通配符选择器, 是选中页面所有元素 */
        * {
            /* 消除浏览器的默认样式. */
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        .container {
            width: 600px;
            margin: 20px auto;
        }

        h1 {
            text-align: center;
        }

        p {
            text-align: center;
            color: #666;
            margin: 20px 0;
        }

        .row {
            /* 开启弹性布局 */
            display: flex;
            height: 40px;
            /* 水平方向居中 */
            justify-content: center;
            /* 垂直方向居中 */
            align-items: center;
        }

        .row span {
            width: 80px;
        }

        .row input {
            width: 200px;
            height: 30px;
        }

        .row button {
            width: 280px;
            height: 30px;
            color: white;
            background-color: orange;
            /* 去掉边框 */
            border: none;
            border-radius: 5px;
        }

        /* 点击的时候有个反馈 */
        .row button:active {
            background-color: grey;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>表白墙</h1>
        <p>输入内容后点击提交, 信息会显示到下方表格中</p>
        <div class="row">
            <span>谁: </span>
            <input type="text">
        </div>
        <div class="row">
            <span>对谁: </span>
            <input type="text">
        </div>
        <div class="row">
            <span>说: </span>
            <input type="text">
        </div>
        <div class="row">
            <button id="submit">提交</button>
        </div>
        <div class="row">
            <button id="revert">撤销</button>
        </div>
        <!-- <div class="row">
            xxx 对 xx 说 xxxx
        </div> -->
    </div>

    <script>
        // 实现提交操作. 点击提交按钮, 就能够把用户输入的内容提交到页面上显示. 
        // 点击的时候, 获取到三个输入框中的文本内容
        // 创建一个新的 div.row 把内容构造到这个 div 中即可. 
        let containerDiv = document.querySelector('.container');
        let inputs = document.querySelectorAll('input');
        let button = document.querySelector('#submit');
        button.onclick = function() {
            // 1. 获取到三个输入框的内容
            let from = inputs[0].value;
            let to = inputs[1].value;
            let msg = inputs[2].value;
            if (from == '' || to == '' || msg == '') {
                return;
            }
            // 2. 构造新 div
            let rowDiv = document.createElement('div');
            rowDiv.className = 'row message';
            rowDiv.innerHTML = from + ' 对 ' + to + ' 说: ' + msg;
            containerDiv.appendChild(rowDiv);
            // 3. 清空之前的输入框内容
            for (let input of inputs) {
                input.value = '';
            }
            //4. 通过 ajax 构造 post 请求,把这个新的消息提交给服务器
            let body = {
                "from": from,
                "to": to,
                "message": msg
            }
            $.ajax({
                type: 'post',
                url: 'message',
                contentType: "application/json;charset=utf8",
                // java 中使用 jackson 完成对象和 json 字符串的转换;objectMapper.writeValue 用来把 java 对象转成 json 格式字符串
                //objectMapper.readValue 用来把 json 格式字符串转成 java对象
                // JS 中使用 JSON 这个特殊对象,完成对象和json字符串的转化;JSON.stringify 把js对象转成json格式字符串
                //JSON.parse 把 json格式字符串转成js对象
                data: JSON.stringify(body),
                success: function(nody) {
                    //这是响应成功之后要调用的回调
                    console.log("消息发送给服务器成功!")
                }
            })
        }
        let revertButton = document.querySelector('#revert');
        revertButton.onclick = function() {
            // 删除最后一条消息. 
            // 选中所有的 row, 找出最后一个 row, 然后进行删除
            let rows = document.querySelectorAll('.message');
            if (rows == null || rows.length == 0) {
                return;
            }
            containerDiv.removeChild(rows[rows.length - 1]);
        }

        // 在页面加载的时候, 希望能够从服务器获取到所有的消息, 并显示在网页中. 
        $.ajax({
            type: 'get',
            url: 'message',  // url 都是使用相对路径的写法. 相对路径意味着工作路径就是当前文件所在的路径. 
                             // 当前文件所在路径是 /message_wall/ , 因此此时构造的请求就是 /message_wall/message
            success: function(body) {
                // body 是收到的响应的正文部分. 如我们之前的约定, body 应该是 json 数组
                // 由于响应的 Content-Type 是 application/json, 此时收到的 body 会被 jquery 自动的把它从 字符串 
                // 转成 js 对象数组. 此处就不需要手动的进行 JSON.parse 了. 
                // 此处的 body 已经是一个 JSON.parse 之后得到的 js 对象数组了. 
                // 就需要遍历这个 body 数组, 取出每个元素, 再依据这样的元素构造出 html 标签, 并添加到页面上. 
                let container = document.querySelector('.container');//通过css选择器查找页面中的元素
                for (let message of body) {
                    let rowDiv = document.createElement('div');
                    rowDiv.className = "row";
                    rowDiv.innerHTML = message.from + " 对 " + message.to + " 说: " + message.message;
                    container.appendChild(rowDiv);
                }
            }
        });
    </script>
</body>
</html>

此时通过浏览器的URL:127.0.0.1:8080/message_wall/messageWall.htm 访问服务器即可看到

 此时我们每次提交的数据都会发送给服务器. 每次打开页面的时候页面都会从服务器加载数据. 因此及时关闭页面, 数据也不会丢失.

但是数据此时是存储在服务器的内存中 ( private List<Message> messages = new ArrayList<Message>(); ), 一旦服务器重启, 数据仍然会丢失

4.数据持久化

把数据存储到银盘上,才是让数据更让好的持久化的方法:1️⃣数据存储到文件里2️⃣数据存入数据可中

4.1 数据存入数据库

1️⃣引入 JDBC 依赖:

<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.49</version>
</dependency>

2️⃣建库建表

create table messages (`from` varchar(255), `to` varchar(255), `message` varchar(2048));

3️⃣修改代码

import com.fasterxml.jackson.databind.ObjectMapper;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;

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.sql.DataSource;
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;

import static java.lang.System.load;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: Lenovo
 * Date: 2023-06-02
 * Time: 19:56
 */
class Message {
    // 这几个属性必须设置 public !!!!
    // 如果设置 private, 必须生成 public 的 getter 和 setter !!!
    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<>();
    //private List<Message> messageList = new ArrayList<>();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 通过这个方法来处理 "获取所有留言消息"
        // 需要返回一个 json 字符串数组. jackson 直接帮我们处理好了格式.
        List<Message> messageList = load();
        String respString = objectMapper.writeValueAsString(messageList);
        resp.setContentType("application/json; charset=utf8");
        resp.getWriter().write(respString);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 通过这个方法来处理 "提交新消息"
        Message message = objectMapper.readValue(req.getInputStream(), Message.class);
        messageList.add(message);
        save(message);
        System.out.println("消息提交成功! message=" + message);

        // 响应只是返回 200 报文. body 为空. 此时不需要额外处理. 默认就是返回 200 的.
    }

    // 这个方法用来往数据库中存一条记录
    private void save(Message message) {
        DataSource dataSource = new MysqlDataSource();
        ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/java107?characterEncoding=utf8&useSSL=false");
        ((MysqlDataSource)dataSource).setUser("root");
        ((MysqlDataSource)dataSource).setPassword("2222");

        try {
            Connection connection = dataSource.getConnection();
            String sql = "insert into message values(?, ?, ?)";
            PreparedStatement statement = connection.prepareStatement(sql);
            statement.setString(1, message.from);
            statement.setString(2, message.to);
            statement.setString(3, message.message);
            statement.executeUpdate();

            statement.close();
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    // 这个方法用来从数据库查询所有记录
    private List<Message> load() {
        List<Message> messageList = new ArrayList<>();

        DataSource dataSource = new MysqlDataSource();
        ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/java107?characterEncoding=utf8&useSSL=false");
        ((MysqlDataSource)dataSource).setUser("root");
        ((MysqlDataSource)dataSource).setPassword("2222");

        try {
            Connection connection = dataSource.getConnection();
            String sql = "select * from message";
            PreparedStatement statement = connection.prepareStatement(sql);
            ResultSet resultSet = statement.executeQuery();

            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);
            }

            resultSet.close();
            statement.close();
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return messageList;
    }
}

通过上述代码就已经写出一个很简单的网站;未来写的复杂网站都是这一套逻辑

1️⃣约定前后端交互接口

2️⃣实现服务器代码(通常回操作数据库)

3️⃣实现客户端代码(通常会使用 ajax 构造请求,并使用一些 js 的 webapi 操作页面内容)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/605499.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

项目引入Spring Security的参考步骤token

后端&#xff1a; 1、在数据库中创建t_user用户表&#xff0c;参照建表SQL。 2、pom文件中引入Spring Security依赖、JWT依赖&#xff08;复制粘贴即可&#xff09; <!--security--> <dependency> <groupId>org.springfr…

全志V3S嵌入式驱动开发(pwm驱动)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 pwm驱动也是常见的一种驱动方式。常见的pwm&#xff0c;其实就是一组方波&#xff0c;方波中的高低电平之比称之为空占比。通过调节这个空占比&…

前端学习--ES6模块化与异步编程高级用法

一、ES6模块化 1.1 概念与规则 ES6 模块化规范是浏览器端与服务器端通用的模块化开发规范 ES6 模块化规范中定义&#xff1a; 每个 js 文件都是一个独立的模块导入其它模块成员使用 import 关键字向外共享模块成员使用 export 关键字 1.2 在node.js体验es6模块化 配置如下&…

【问题】常见问题解决方法

记录在项目运行中遇到的问题&#xff0c;和常用的软件安装包 文章目录 安装包下载第一章&#xff1a;运行C/C小白运行须知1.DevC运行&#xff08;最简单&#xff0c;推荐&#xff09;2.Visual Studio 运行3.VC运行 第二章&#xff1a;运行C#项目1.VS环境2.打开C#项目启动失败&a…

LiteDram仿真验证(二):仿真中,DDR3初始化问题

目录 前言一、讨论1、[init_done never goes to 1 in simulation #145](https://github.com/enjoy-digital/litedram/issues/145)2、[Add ECP5 support to standalone core generator #106](https://github.com/enjoy-digital/litedram/issues/106)3、[Help generating DDR3 Ve…

【unity插件】2d切割破坏插件-Smart Slicer 2D

文章目录 效果1.切割2.破坏3.创建源码使用1.导入插件2.摄像机3.新建地面4.新建切割刀5.新建切割食物6. 运行即可不同slicer Type的切割刀类型测试1.线性2.Complex3.点4.多边形5.explode6.创建效果 1.切割

华为OD机试之数列描述(Java源码)

数列描述 题目描述 有一个数列a[N] (N60)&#xff0c;从a[0]开始&#xff0c;每一项都是一个数字。数列中a[n1]都是a[n]的描述。其中a[0]1。规则如下&#xff1a; a[0]:1a[1]:11(含义&#xff1a;其前一项a[0]1是1个1&#xff0c;即“11”。表示a[0]从左到右&#xff0c;连续出…

Java简单实现短信验证登录(Session、Redis)

前端设计 <div class"login-form"><div style"display: flex; justify-content: space-between"><el-input style"width: 60%" placeholder"请输入手机号" v-model"form.phone" ></el-input><e…

winform的RichTextBox控件追加文本及图片(实现笔记录入和笔记搜索功能)

在工作中&#xff0c;在工作中&#xff0c;难免有一些笔记要记录下来&#xff0c;方便后续工作中快速找到。之前用的是共享文档来记录的&#xff0c;但有一个缺点就是随着写的内容越来越多&#xff0c;打开变得很慢&#xff0c;搜索更加慢&#xff0c;网络不好的时候&#xff0…

Redis的常用数据结构之有序集合类型

有序集合的特点 集合中的元素有序&#xff0c;不可以重复与列表通过索引实现有序不同&#xff0c;有序集合实现有序的方式是通过给每一个集合元素设置一个分数score字段作为排序依据集合中的元素不能重复&#xff0c;但是score可以重复无法通过某一个下标的方式获取元素单个集…

大数据:spark环境搭建,local模式,standalone模式,zookeeper standby,yarn模式

大数据&#xff1a;spark环境搭建&#xff0c;local模式 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能很多算法学生都得去找开发&#xff0c;测开 测开的话&#xff0c;你就得学数据库&#xff0c;sql&#xff0c;or…

chatgpt赋能python:Python列表倒序排列

Python列表倒序排列 介绍 Python是一种强大的编程语言&#xff0c;经过多年的发展&#xff0c;它已成为最受欢迎的编程语言之一。Python列表是一个非常有用的数据结构&#xff0c;它允许您将多个项目组合在一起&#xff0c;并可以轻松地对它们进行排序和操作。本篇文章将介绍…

Cubase12没有声音解决办法(Windows 11专用)

本文章由CSDN 不想加班呀 原创&#xff0c;转载请注明出处。 作者首页&#xff1a;不想加班呀的博客_CSDN博客-Python爬虫,电脑小知识,程序员剪视频领域博主 目录 前言 解决办法 第一步&#xff08;进入系统硬件和声音设置界面&#xff09; 第二步&#xff08;在声音设置中…

【正点原子STM32连载】 第二十五章 TFT-LCD(MCU屏)实验 摘自【正点原子】STM32F103 战舰开发指南V1.2

1&#xff09;实验平台&#xff1a;正点原子stm32f103战舰开发板V4 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id609294757420 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html 第二十…

05.JavaWeb-Servlet

1.Servlet基础 1.1 Servlet概述 用于处理客户端传来的HTTP请求&#xff0c;并返回一个响应&#xff08;特点&#xff1a;方便、跨平台、灵活性和可扩展性&#xff09; 1.2 Servlet开发入门 1.2.1 Servlet接口及实现类 1.最基本的接口是javax.servlet.Servlet&#xff0c;Ser…

高完整性系统工程(十二):Separation Logic for Automated Verification

目录 1. INTRODUCTION TO SEPARATION LOGIC 分离逻辑 1.1 霍尔推理&#xff08;Hoare Reasoning&#xff09; 1.2 堆指针的影响 1.3 全局和局部推理&#xff08;Global and Local Reasoning&#xff09; 1.4 组合推理&#xff08;Compositional Reasoning&#xff09; 1.…

SpringBoot通过加装外部JAR包中的类实现业务插件功能

综合记录一下关于ClassLoader和Spring Bean的动态加载卸载功能 目录 一、需要说明二、总体设计三、具体设计3.1 加载卸载Bean工具类3.2 创建卸载方法3.3 创建加载方法3.4 创建获取具体服务类方法 四、总结 一、需要说明 有一个公共的发送通知的接口&#xff0c;这个接口需要做…

CUDA配置正确,但是torch.cuda.is_available()却是False的解决方案

1.torch.cuda.is_available()返回为False 有时候我们想要使用GPU加速&#xff0c;但是发现CUDA、pytorch都安装好了&#xff0c;且版本也匹配&#xff0c;但是仍然无法使用GPU,显示信息如下&#xff1a; 这时候我们可以看看是不是我们的Pytorch的问题 2.输入下面命令查看pyto…

(学习日记)2023.04.26

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…

cesium-native编译

我相信点进这个博客的都是一些cesium专业人才&#xff0c;这文章只起了一个抛砖引玉的作用&#xff0c;希望各位人才不惜赐教。 Github地址&#xff1a;CesiumGS/cesium-native (github.com) 编译需求&#xff1a;升级公司的3dtile的架构&#xff0c;提高性能 博客目的&…