【Java EE】-Servlet(三) MessageWall

作者:学Java的冬瓜
博客主页:☀冬瓜的主页🌙
专栏【JavaEE】
分享: 寂寞会发慌,孤独是饱满的。——史铁生《命若琴弦》

主要内容:前后端交互接口协商,约定好,使用什么数据格式传输,什么时候发送请求,发送什么请求。使用数据库对浏览器提交到服务器的信息进行长期的保存。前端html作为主体,CSS修饰html,使用js来操作dom树,并且在js中使用ajax来构造各种请求,使用ajax构造body为 json格式的post请求。后端内容将数据库连接过程使用DBUtil封装,使用MessageServlet.java来处理 前端发来的各种http请求。服务器根据请求对数据进行在数据库 存档,读档,删档的操作。

在这里插入图片描述

一、准备工作

重点:协商前后端交互接口
写web程序前,需要约定好,前后端如何进行交互,约定好交互的数据格式。比如请求的格式,响应的格式,浏览器什么时候发送请求,服务器按照什么格式来解析浏览器的请求,以及写回到浏览器使用什么格式数据。如下图,就使用post请求提交表白信息到服务器,再用get请求从服务器取表白信息,全过程中http报文交互的body格式全部使用json格式。

需求:点击提交时,浏览器使用post请求提交一份表白信息发送到浏览器存档;页面加载时,浏览器使用get请求发送给浏览器,从服务器读取全部表白信息;点击重置时,浏览器发送delete请求给服务器,删除服务器存档的最后一份表白信息。在这里插入图片描述
在这里插入图片描述


理解:为什么使用数据库存储数据?
1> 如果不使用后端代码,只使用前端代码,可以展示表白墙的效果,但是message数据只是保存在浏览器中,当刷新一下页面,表白的信息就不在了。
2> 加入后端代码后,如果是使用一个集合来保存message信息,那么提交数据给服务器可以使用post提交,获取数据可以在加载页面时,使用get请求从服务器获取,刷新页面是给浏览器发送一个get请求,从集合中取出全部message信息显示到浏览器上,因此刷新页面数据还在。但是因为数据是存储在集合中,也就是内存中,当服务器一关闭,数据就不存在了。
3> 为了防止上述问题,最后可以使用数据库,存储在本地硬盘中,这样的话,即使服务器关闭,数据仍然存在。

二、前端内容

下面为 message.html:代码,html作为页面的主体部分,并在html中引入css。在使用js中的ajax构造body为json格式的post请求前,先引入jQuery,然后在html的body标签中引入js文件。

<!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>

    <!--引入css-->
    <link rel="stylesheet" href="./messageWall.css">

</head>
<body>
    <div class="all">
        <div class="container">
            <h2>表白墙</h2>
            <p>输入后点击提交,信息会显示在表格下方</p>
            <div class="row">
                <span>谁:</span>
                <input type="text" class="from">
            </div>
            <div class="row">
                <span>对谁:</span>
                <input type="text" class="to">
            </div>
            <div class="row">
                <span>说:</span>
                <input type="text" class="message">
            </div>
            <div class="row">
                <button id="submit">提交</button>
                <button id="reset">重置</button>
            </div>
        </div>
        <div class="Conversation"></div>
    </div>
    


    <!-- 使用ajax前先引入jquery -->
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
    <!--引入js-->
    <script src="./messageWall.js"></script>
</body>
</html>

下面为 message.css:代码,使用css修饰html页面

/* 通配符选择器,选中所有标签 */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

.all{
    margin: 0 auto;
    padding: 0;
    background-color: pink;
    height: 650px;
}
.container{
    width: 600px;
    height: 280px;
    margin: 0px auto;
    padding: 20px;
}
/* 设置h2,p居中 */
h2 {
    text-align: center;
}
p {
    text-align: center;
    color: #666;
    /* 先竖直,再水平 */
    margin: 20px 0;
}


/* 设置弹性布局 */
.row {
    /* 开启弹性布局 */
    display: flex;
    height: 40px;
    /* 水平方向居中 */
    justify-content: center;
}
/* 设置提示框的长度 */
.row span {
    width: 80px;
}

/* 设置输入框的长度和高度 */
.row input {
    width: 200px;
    height: 30px;
}

.row button {
    color: white;
    background-color: orange;
    width: 120px;
    height: 35px;
    border: none;
    /* margin-left: 20px;
    margin-right: 20px; */
    margin: 20px;
}
/* 设置点击提交时变灰色 */
button:active {
    background-color: #666;
}

/* 设置结果的div样式 */
.result {
    text-align: center;
    margin: 5px;
    line-height: 40px;
}
.Conversation{
    width: 280px;
    height: 280px;
    margin-top: 40px;
    margin-left: auto;
    margin-right: auto;

    padding: 20px;
    background-color: rgba(0,128,0,0.6);
}

下面为message.js代码,用于操作dom树,以及使用ajax构造请求的body格式为json的post请求。

  • 按下提交时,使用ajax(得先引入jquery)给服务器发送一条post请求,提交表白信息到服务器
  • 加载页面时,使用ajax给服务器发送一条get请求,从服务器获得所有表白信息
  • 点击重置时,使用ajax给服务器发送一条delete请求,服务器将数据库的最后一条表白信息删除,然后将剩下的全部表白信息响应到ajax中,这里就需要用 js先把原来页面中的所有表白信息div删除,使用响应结果(删除最后一条表白信息后的数据) 构造表白信息div,再展示到浏览器上。
// 一.实现表白墙展示
let ConversationDiv = document.querySelector('.Conversation');
let inputs = document.querySelectorAll('input');
let submit = document.querySelector('#submit');

submit.onclick = function(){
    // 1.获取到三个input的值
    let from = inputs[0].value;
    let to = inputs[1].value;
    let mesg = inputs[2].value;
    if(from == '' || to == '' || mesg == ''){
        return;
    }
    // 2.构造新的展示div
    let resultDiv = document.createElement('div');
    resultDiv.className = 'row message result';
    resultDiv.innerHTML = from + ' 对: ' + to + ' 说: ' + mesg;
    ConversationDiv.appendChild(resultDiv);
    // 3.清空表格中的内容
    for(let input of inputs){
        input.value = '';
    }

    // 【新增一】 按下提交时,使用ajax(得先引入jquery)给服务器发送一条post请求
    // 注意:body内的数据的名称(左边)必须和后端的使用jackson解析成的 Message的字段类型一致;右边的则是上面定义获取的变量
    let body = {
        "from":from,
        "to":to,
        "message":mesg
    }
    let jsonBody = JSON.stringify(body);
    $.ajax({
        type: 'post',
        url: './message',
        contentType: 'application/json; charset=utf-8',
        data: jsonBody,
        success: function(){
            // 这里的body是响应报文json格式的字符串 转换成的js对象
            console.log("请求发送成功!");
        }
    })
}
// 【新增二】 页面加载时,从服务器获取 所有信息并显示在浏览器上
$.ajax({
    type: 'get',
    url: './message',
    success: function(body){
        console.log("响应接收成功!");
        let ConversationDiv = document.querySelector('.Conversation');
        for(let message of body){
            // 对每一个message元素构造一个div
            let resultDiv = document.createElement('div');
            resultDiv.className = 'row message result';
            resultDiv.innerHTML = message.from + ' 对: ' + message.to + ' 说: ' + message.message;
            ConversationDiv.appendChild(resultDiv);
        }
    }
})


// 二.重置时把表格下的最后一条内容清除
let reset = document.querySelector('#reset');
reset.onclick = function(){
    //【新增三】 点击重置时,不是直接删除最后一个节点,而是发送delete请求,服务器处理delete请求,然后显示剩下的所有信息
    $.ajax({
        type: 'delete',
        url: './message',
        success: function(body){
            // 1.先选中父元素ConversationDiv,然后删除所有子元素
            let ConversationDiv = document.querySelector('.Conversation');
            while(ConversationDiv.firstChild){
                ConversationDiv.removeChild(ConversationDiv.firstChild)
            }

            for(let message of body){
                // 2.对响应数据内容进行页面显示,对每一个message元素构造一个div
                let resultDiv = document.createElement('div');
                resultDiv.className = 'row message result';
                resultDiv.innerHTML = message.from + ' 对: ' + message.to + ' 说: ' + message.message;
                ConversationDiv.appendChild(resultDiv);
            }
        }
    })
}

三、后端内容

  • 使用MessageServlet处理前端发来的各种请求,注意这里需要针对前端发来的body类型为json格式的内容进行解析,可以使用jackson来解析。
  • doPost方法处理前端提交 表白信息的post请求,会在执行doPost方法中 调用save方法 将表白信息保存在数据库中。
  • doGet方法处理前端加载页面时 发来的get请求,会在执行doGet方法中 调用load方法将数据库中所有表白信息查出来,写回到浏览器。
  • doDelete方法处理前端重置,发来的删除最后一条表白信息的delete请求,会在执行doDelete方法中 调用delete方法将数据库中的最后一条信息删除,然后将剩下的内容写回浏览器。
  • 使用 MessageServlet.java类解决浏览器发来的各种请求,使用 DBUtil.java类作为工具类,用来封装数据库连接的过程。

使用 MessageServlet.java类解决浏览器发来的各种请求。

package servlet;

import com.fasterxml.jackson.databind.ObjectMapper;
import util.DBUtil;

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;

// 使用Message来装填jackson解析的前端发来的json格式的字符串。
class Message {
    public String from;
    public String to;
    public String message;
}

@WebServlet("/message")
public class MessageServlet extends HttpServlet {
    // 使用jackson解析浏览器发来的json格式的数据
    private ObjectMapper objectMapper = new ObjectMapper();

    // 客户端(浏览器)按提交按钮时,向服务器提交数据
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 将req里的键值对读出,并和Message比对属性名给value,返回Message对象
        Message message = objectMapper.readValue(req.getInputStream(),Message.class);
        // 把这一份表白信息保存到数据库
        int count =  save(message);
        if(count == 1){
            System.out.println("表白信息成功写入数据库");
        }else {
            System.out.println("表白信息写入数据库失败");
        }
    }

    // 浏览器加载时,从服务器获取数据
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 把messageList这个Java集合对象转成json格式的字符串,再把字符串写入resp的body中

        //注意:一定要记得设置响应报文的格式,否则前端代码会认为是其它格式,可能会按照其它格式解析
        resp.setContentType("application/json; charset=utf-8");
        // 从数据库获取所有表白信息
        List<Message> messageList = load();
        objectMapper.writeValue(resp.getOutputStream(), messageList);
    }

    @Override
    protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("application/json; charset=utf-8");
        // 从数据库获取所有表白信息
        // 1.获取最后一份表白信息,并从数据库删除
        List<Message> messageList = load();
        if(messageList.size() == 0){
            return;
        }
        Message messageEnd = messageList.get(messageList.size()-1);
        int count = delete(messageEnd);
        if(count == 1){
            System.out.println("表白信息删除成功");
        }else {
            System.out.println("表白信息删除失败");
        }
        // 2.获取删除最后一条信息后的 全部表白信息,并写回到浏览器
        messageList = load();
        objectMapper.writeValue(resp.getOutputStream(), messageList);
    }


    private int save(Message message){
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        int count = 0;

        try {
            // 1.获取连接
            connection = DBUtil.getConnection();
            // 2.编写sql
            String sql = "insert into message values(?,?,?)";
            // 3.获取预编译对象,进行预编译
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1,message.from);
            preparedStatement.setString(2,message.to);
            preparedStatement.setString(3,message.message);
            // 4.执行sql语句
            count = preparedStatement.executeUpdate();
            // 5.处理结果
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            DBUtil.close(connection, preparedStatement, null);
        }
        return count;
    }
    private List<Message> load(){
        // 从数据库查询表白信息,把每条信息都放进这个集合里
        List<Message> messageList = new ArrayList<>();

        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            // 1.获取连接
            connection = DBUtil.getConnection();
            // 2.编写sql
            String sql = "select * from message";
            // 3.获取预编译对象,进行预编译
            preparedStatement = connection.prepareStatement(sql);
            // 4.执行sql语句
            resultSet = preparedStatement.executeQuery();
            // 5.处理结果集
            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 throwables) {
            throwables.printStackTrace();
        } finally {
            DBUtil.close(connection, preparedStatement, resultSet);
        }
        return messageList;
    }
    private int delete(Message message){
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        int count = 0;
        try {
            // 1.获取连接
            connection = DBUtil.getConnection();
            // 2.编写sql
            String sql = "delete from message where `from` = ? and `to` = ? and message = ?";
            // 3.获取预编译对象,进行预编译
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1, message.from);
            preparedStatement.setString(2, message.to);
            preparedStatement.setString(3, message.message);
            // 4.执行sql语句
            count = preparedStatement.executeUpdate();
            // 5.处理结果

        } catch (SQLException throwables) {
            throwables.printStackTrace();
        } finally {
            DBUtil.close(connection, preparedStatement, null);
        }
        return count;
    }
}

使用 DBUtil.java类作为工具类,用来封装数据库连接的过程

package util;

import com.mysql.cj.jdbc.MysqlDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

// DBUtil作为一个工具类,通过这个类,把数据库连接过程封装一下
public class DBUtil {
    // 数据源是单例,饿汉模式创建mysql数据源
    private static DataSource dataSource = new MysqlDataSource();

    static {
        // 使用静态代码块, 对 dataSource初始化
        // 理解:这里的Url中的 jdbc:mysql是协议名称,其后跟ip和端口,然后是数据库 + query string
        ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/myProject?characterEncoding=utf8&useSSL=false");
        ((MysqlDataSource)dataSource).setUser("root");
        ((MysqlDataSource)dataSource).setPassword("xxx");//写你自己的数据库密码哦
    }

    // 获取数据库连接对象
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    // 关闭资源封装
    public static void close(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet){
        if(resultSet != null){
            try {
                resultSet.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (preparedStatement != null){
            try {
                preparedStatement.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (connection != null){
            try {
                connection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

四、成果展示

1、输入:
输入表白信息(提交两份表白信息):
在这里插入图片描述
点击提交:
在这里插入图片描述
在这里插入图片描述

数据库中:
在这里插入图片描述

2、查询
提交表白信息后,重启服务器,输入地址,可以查询到之前提交的表白信息
在这里插入图片描述
会先展示出页面,过一小段时间后,就从数据库中查询出来,展示在页面上了
在这里插入图片描述

3、重置
点击重置后,页面中可以看到删除了最后一条表白信息:
在这里插入图片描述

数据库中:
在这里插入图片描述

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学Java的冬瓜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值