表白墙 - 进阶(MySQL版本) - 持久化存储

news2024/9/29 13:22:32

想要解决上面那个版本存在的问题:服务器重启,数据不丢失

最好的办法:将数据存储到硬盘上。
存储的方式:

        1、直接使用 流对象 写入文本文件

        2、借助数据库

我们采取的方式:是 MySQL 数据库的方式 来实现 持久化存储。

首先,既然我们要使用数据库来实现持久化存储。
那么,我们在服务器代码中,需要引入依赖(MySQL)。

Maven Repository: mysql » mysql-connector-java (mvnrepository.com)

既然我们使用MySQL 作为存储数据的手段。
那么原先的代码有些东西,就不在需要了!

为了“嵌入”MySQL,我们需要添加一些方法去辅助我们。

在实现 save 和 load 方法之前,我们先来在 MySQL上创建一个数据表来存储告白墙的信息。 

在实现 save 和 load 方法之前,我们先来在 MySQL上创建一个数据表来存储告白墙的信息。表结构为:message(from,to,message)

 这下就有了数据库和表了,接下来就需要和数据库建立起连接。

下面,我们就来为完善 save 和 load 方法做准备。

 

 下面,我们可以来完善 MessageServlet 当中的 save 和 load 方法。

save 方法

 load 方法

 DButil - 数据库访问程序

主要是简化 MessageServlet 中的程序。将 数据库连接,创建数据源,资源释放,具体实现细节给封装成一个类,来供 MessageServlet 中的程序使用。

//封装数据库连接过程
//作为工具类
public class DBUtil {
    //单例饿汉模式
    private static DataSource dataSource = new MysqlDataSource();
    static{
        //使用静态代码块初始化
        ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/lovewall?characterEncoding=utf8&useSSL=false");
        ((MysqlDataSource)dataSource).setUser("root");
        ((MysqlDataSource)dataSource).setPassword("123456");
    }
    //建立连接
    public static Connection getConnection() throws SQLException {
        return dataSource.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);
            }
        }
    }
}

MessageServlet 服务器总程序

class Message{
    public String from;
    public String to;
    public String message;
}

@WebServlet("/message")
public class MessageServlet extends HttpServlet {
//    使用这个List变量保存所有消息
    private List<Message> messageList = new ArrayList<>();//有 mysql 了就不需要把 message 存在内存中了,注释掉了
    private ObjectMapper objectMapper = new ObjectMapper();


    // 提供一对方法
    // 往数据库中 存 一条 消息
    private void save(Message message) throws SQLException {
        Connection connection=null;
        PreparedStatement statement=null;
        // JDBC 操作
        try {
            // 1.建立连接
            connection = DBUtil.getConnection();
            // 2.构造 SQL 语句
            String sql = "insert into message values(?,?,?)";
            statement = connection.prepareStatement(sql);
            statement.setString(1, message.from);
            statement.setString(2, message.to);
            statement.setString(3, message.message);
            // 3.执行 sql
            statement.executeUpdate();

        }catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //4、关闭连接
            DBUtil.close(connection,statement,null);
        }
    }
    // 从数据库 取 所有 消息
    private List<Message> load() throws SQLException {
        List<Message> messageList = new ArrayList<>();
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        try {
            // 1.和数据库建立连接
            connection = DBUtil.getConnection();
            // 2.构造 SQL
            String sql = "select * from message";
            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;
    }

//    向服务器提交数据
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("application/json;charset=utf-8");
        //把body中的内容读取出来了,解析成了一个Message对象
        Message message = objectMapper.readValue(req.getInputStream(), Message.class);

        //1、内存方式:此处通过简单粗暴的方式保存
//      messageList.add(message);//有 mysql 了就不需要了
        //2、mysql方式存一条数据:调用save方法
        try {
            save(message);

        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

        //此处的设定状态码可以省略,不设置也是200
        resp.setStatus(200);
    }
//    服务器获取数据
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("application/json;charset=utf-8");

        //1、内存方法:messageList
//        objectMapper.writeValue(resp.getWriter(),messageList);//有 mysql 了就不需要了
        //2、mysql方法取数据:调用 load 方法
        try {
            List<Message> messageList = load();
            String jsonResp = objectMapper.writeValueAsString(messageList);
            System.out.println("jsonResp"+jsonResp);
            resp.getWriter().write(jsonResp);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

前端代码:

<!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>
        /* *是通配符选择器,会选中页面所有的元素 */
        /* 消除浏览器的默认显示模式 */
         *{
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        .container{
            width: 600px;
            margin: 0 auto;
        }
        h1{
            margin-top: 100px;
            text-align: center;
        }
        p{
            text-align: center;
            color: #666;
            margin: 20px auto;
        }
        .row{
            /* 开启弹性布局 */
            display: flex;
            height: 40px;
            /* 水平方向居中 */
            justify-content: center;
            /* 垂直方向居中 */
            align-items: center;

        }
        .row span{
            width: 50px;
        }
        .row input{
            width: 200px;
            height: 30px;
        }
        .row button{
            width: 250px;
            height: 30px;
            color: aliceblue;
            background-color: orange;
            /* 去掉边框 */
            border: none;
            border-radius: 3px;
        }
        /* 点击反馈 */
        .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>提交</button>
    </div>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script>
        //实现提交操作,点击提交按钮,将用户输入的内容提交到页面上
        //点击的时候获取输入框内容,然后创建一个新的div.row,将内容构造进去
        let containerDiv = document.querySelector('.container');
        let inputs = document.querySelectorAll('input');
        let button = document.querySelector('button');
        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';
            rowDiv.innerHTML = from + ' 对 ' + to + ' 说: ' + msg;
            containerDiv.appendChild(rowDiv)
            //3.清空之前的输入
            for(let input of inputs){
                input.value = '';
            }
            //4.新增代码,将数据提交给服务器,构造post请求
            //定义js对象,key是字符串,value是js中的变量常量
            let body =  {
                "from":from,
                "to":to,
                "message":msg
            };
            //转换
            strBody = JSON.stringify(body);
            console.log("strBody = "+strBody);
            $.ajax({
                type:'post',
                url:'message',
                data:strBody,
                contentType:"application/json;charset = utf8",
                success :function(body){
                    console.log("发布成功");
                }
            });

        }


        //新增:浏览器在页面加载的时候发送get请求,从服务器获取数据并添加到页面中
        $.ajax({
            type:'get',
            url:'message',
            success:function(body){
                //此处拿到的body是一个js数组
                //本来服务器返回的是一个json字符串,但是jquery的ajax能够自动识别并转换成js对象数组
                //遍历数组,取出元素,构造到页面
                for(let message of body){
                     //2.构造新的div
                    let rowDiv = document.createElement('div');
                    rowDiv.className = 'row message';
                    rowDiv.innerHTML = message.from + ' 对 ' + message.to + ' 说: ' + message.message;
                    containerDiv.appendChild(rowDiv);
                }
            }
        });

    </script>
</body>
</html>

 

效果图

 控制台打印日志

数据库的表中增加了数据


 小结 

开发一个表白墙(一个简单网站)基本步骤:

1、约定前后端交互的接口
        请求是什么格式?响应是什么格式?
2、开发服务器代码
  2.1、先编写 Servlet 能够处理的前端请求
  2.2、编写数据库代码,来 存储 / 获取 关键数据
3、开发客户端代码
  3.1、基于 ajax 能够构造请求以及解析响应
  3.2、能够响应用户的操作。
比如:我们在点击按钮之后,触发给服务器发送请求的行为。


以后遇到像这种“网站”类的程序,实现过程都是类似的!
可以说,这就是一个模板。

说到这里,我们就需要拓展一下了。
MVC
M:Model(模式) - 操作数据存取的逻辑
V:View(视图)- 页面的显示
C:Controller(控制器) - 处理请求之后的关键逻辑

View 是和用户进行交互的,View 再和 Controller 进行交互。
相当于是 View 构造 请求,Controller 在进行处理。
Controller 再和 Model 进行交互,Model 开始操作数据 

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

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

相关文章

Python卷积详解

文章目录 卷积函数对比测试卷积应用 卷积函数 python提供了多种卷积方案&#xff0c;相比之下&#xff0c;定义在ndimage中的卷积函数&#xff0c;在功能上比numpy和signal中的卷积要稍微复杂一些&#xff0c;这点仅从输入参数的多少就可略窥一二 numpy.convolve(a, v, modef…

拥抱汽车行业新时代,移远通信着力打造“七大产品技术生态”

汽车市场和消费者的需求正在发生日新月异的变化。以往中国新能源汽车的推广&#xff0c;大多倚重政策补贴&#xff0c;而如今新能源汽车已经走过了这个阶段&#xff0c;开始变成消费者自愿选择。除了汽车的电动化&#xff0c;“智能化”是不少车型拨动消费者心弦的另一主要因素…

光学仿真小作品集

光学仿真小作品集 传播方向与 z 轴平行的二维平面波自由空间中的传输传播方向与 z 轴有一定夹角的二维平面波自由空间中的传输 本文将展示一些作者本人平时自制的光学仿真小作品。 传播方向与 z 轴平行的二维平面波自由空间中的传输 传播方向与 z 轴有一定夹角的二维平面波自由…

(九)【软件设计师】计算机系统-浮点数习题

文章目录 一、2009年下半年第3、4题二、2011年上半年第5题三、2012年下半年第3题四、2015年上半年第1题五、2015年下半年第3题六、2016年下半年第3题七、2018年上半年第1题八、2020年下半年第3题 知识点回顾 &#xff08;八&#xff09;【软件设计师】计算机系统—浮点数 一、…

怎么使用AS推送项目到Github上,一文解决!

废话不多说&#xff0c;直接发车了&#xff01;在android studio上推送项目到GitHub上有个基本可以解决所有推送失败问题的步骤&#xff0c;如下图&#xff1a; 路径&#xff1a;File —— Setting —— Version Control —— GitHub —— 加号&#xff0c;添加用户 上述步骤是…

河道船舶识别检测系统 python

河道船舶识别检测系统通过ppythonYOLOv5网络模型算法技术&#xff0c;河道船舶识别检测系统对画面中的船只进行7*24小时实时监测&#xff0c;若发现存在进行违规采砂或者捕鱼立即自动抓拍触发告警。与C / C等语言相比&#xff0c;Python速度较慢。也就是说&#xff0c;Python可…

mui.ajax

mui.ajax(http:xxxxxxxxxx/login,//请求的地址{data:{},//传给服务器的数据&#xff0c;一般在post请求中dataType:json,//服务器返回数据的格式&#xff1b;type:post,//HTTP请求类型&#xff1b;目前仅支持post/gettimeout:5000,//设置超时时间async:true,//是否异步&#xf…

应急照明和疏散指示系统在化工厂房中的设计与产品选型

【摘 要】《消防应急照明和疏散指示系统技术标准》(GB 51309-2018)的颁布&#xff0c;使应急照明和疏散指示的设计理念及设计方案发生了颠覆性的改变。化工企业在进行系统设计时也有其自身的特点及问题&#xff0c;现根据实际案例&#xff0c;解析化工企业应急照明和疏散指示系…

echrts 工程项目可视化

Echarts 常用各类图表模板配置 注意&#xff1a; 这里主要就是基于各类图表&#xff0c;更多的使用 Echarts 的各类配置项&#xff1b; 以下代码都可以复制到 Echarts 官网&#xff0c;直接预览&#xff1b; 图标模板目录 Echarts 常用各类图表模板配置一、工程项目可视化二、…

记录-new Date() 我忍你很久了!

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 大家平时在开发的时候有没被new Date()折磨过&#xff1f;就是它的诸多怪异的设定让你每每用的时候&#xff0c;都可能不小心踩坑。造成程序意外出错&#xff0c;却一下子找不到问题出处&#xff0c;那…

受安全威胁困扰的时代的可见性和人工智能

安全漏洞和事件以惊人的规律性发生&#xff0c;媒体报道的大人物&#xff0c;只是发生的实际数量的一小部分。 就在上周&#xff0c;横跨澳大利亚和新西兰的主要金融服务提供商 Latitude Financial 公布了影响其 1400 万客户的网络攻击和数据泄露的详细信息。 如果我们要确保…

一致性框架设计方案

补充组件依赖 前言 对于供应链业务&#xff0c;一般对数据一致性要求高。且由于业务复杂&#xff0c;可能会存在一个业务功能触发几个异步操作的场景&#xff0c;且要保证相关操作同时触发或不触发。 为了降低技术设计难度、代码编写难度&#xff0c;特意设计最终一致性框架&a…

Vue - 实现垂直菜单分类栏目,鼠标移入后右侧出现悬浮二级菜单容器效果(完整示例源码,详细代码注释,一键复制开箱即用)

前言 网上的教程都太乱了,各种杂乱无注释代码、图片资源丢失、一堆样式代码,根本无法改造后应用到自己的项目中。 本文实现了 在 Vue / Nuxt 项目中,垂直分类菜单项,当用户鼠标移入菜单后,右侧自动出现二级分类悬浮容器盒子效果, 您可以直接复制源码,然后按照您的需求再…

pyecharts从入门到精通-地图专题BMap-世界地图和中国城市地图

文章目录 参考安装与查看pyecharts地图实现-BMap案例演示案例演示-杭州热门旅行线路图拓展-pyecharts中BMap源码 参考 官方文档:https://pyecharts.org/#/zh-cn/quickstart Bmap - Hiking_trail_in_hangzhou 安装与查看pyecharts 安装pyecharts pip install pyecharts2.0.3…

傅里叶级数FS,连续时间傅里叶变换CTFT,离散时间傅里叶变换DTFT,离散傅里叶变换DFT,推导与联系(二)

由于本文公式所占用的字符比较多&#xff0c;无法在一篇博客中完整发布&#xff0c;所以将其分为两篇博客。本篇主要介绍了离散傅里叶变换 DFT 的内容&#xff0c;以及相关的总结。对于前置内容&#xff0c;包括傅里叶级数 FS&#xff0c;连续时间傅里叶变换 CTFT&#xff0c;以…

【小程序】手动实现switch开关中带文字效果(开关左右文字相同/不同都可以)

最终效果&#xff1a; 左右文字宽度相同 左右文字宽度不同 左右长度相同 效果&#xff1a;配合wx:show切换 注意&#xff1a;左右长度相同的话可以设置合适的相同的宽度。 html&#xff1a; <view class"switch"><viewclass"switchNums {{ swi…

什么是Web1.0时代、Web2.0时代、Web3.0时代?

什么是Web1.0时代、Web2.0时代、Web3.0时代&#xff1f; 互联网的起源。1969年美国的阿帕网的出现标志着互联网的诞生&#xff0c;而1973年第一台个人电脑The Xerox Alto的出现就预示了互联网将蓬勃生长&#xff0c;随之而来的就是我们迈入了信息时代。短短几十年的发展&#x…

【服务器数据恢复】Storwize存储上的Oracle数据库数据恢复案例

服务器数据恢复环境&#xff1a; IBM Storwize某型号存储&#xff0c;共10块磁盘&#xff0c;组建了2组Mdisk加入到一个存储池中&#xff0c;创建了一个通用卷存放数据&#xff0c;存放的数据包含oracle数据库。 服务器故障&#xff1a; 存储中其中一组Mdisk有两块磁盘出现故障…

三百左右蓝牙耳机选哪个?300元左右半入耳式耳机推荐

目前TWS耳机十分火热&#xff0c;成为许多人出行、娱乐的必要工具&#xff0c;但同时许多厂商也看到了这块的市场&#xff0c;大小品牌、各种形态的耳机产品应有尽有&#xff0c;某宝随便一搜就是几万个链接&#xff0c;下面整理了几款300左右价位的耳机品牌分享给大家。 一、南…

【GPT4】微软 GPT-4 测试报告(2)多模态与跨学科的组合

欢迎关注【youcans的AGI学习笔记】原创作品&#xff0c;火热更新中 微软 GPT-4 测试报告&#xff08;1&#xff09;总体介绍 微软 GPT-4 测试报告&#xff08;2&#xff09;多模态与跨学科能力 微软 GPT-4 测试报告&#xff08;3&#xff09;编程能力 微软 GPT-4 测试报告&…