【JavaEE】Servlet:表白墙

文章目录

  • 一、前端
  • 二、前置知识
  • 三、代码
    • 1、后端
    • 2、前端
    • 3、总结
  • 四、存入数据库
    • 1、引入 mysql 的依赖,mysql 驱动包
    • 2、创建数据库数据表
    • 3、调整上述后端代码
      • 3.1 封装数据库操作,和数据库建立连接
      • 3.2 调整后端代码

一、前端

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>表白墙</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        .container {
            width: 800px;
            margin: 0 auto;
        }
        .container h2 {
            text-align: center;
            margin: 30px;
        }

        .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: 50px;

        }

        .row button {
            height: 50px;
            width: 400px;
            margin: 10px 0px;
            color: white;
            background-color: orange;
            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>
    </div>

    <script src="https://code.jquery.com/jquery-3.7.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() {
            let from = fromInput.value;
            let to = toInput.value;
            let message = messageInput.value;

            if(from=='' || to=='' || message=='||') {
                return;
            }
            let newDiv = document.createElement('div');
            newDiv.className = 'row';
            newDiv.innerHTML = from + "对" + to + "说" + message;
            container.appendChild(newDiv);
            fromInput.value = '';
            toInput.value = '';
            messageInput.value = ''; 
        }
    </script>
</body>
</html>

二、前置知识

pom.xml 里面的依赖确保了在开发阶段项目能够编译和运行,但在部署到Tomcat服务器时,Tomcat会提供这些类,因此不需要将它们打包到最终的WAR文件中。

运行项目一般是两级路径:

  1. 第一级:Context path:
    context path代表了当前的 webapp(网站),一个 tomcat 上是可以同时部署多个 webapp(网站)的,webapps 目录下的每个目录都是一个单独的 webapp,所以有的资料也把tomcat叫做容器。
    如何确定 Context path:
    (1)如果是通过 startup.bat 启动的 tomcat,webapps 里对应的 war 包名/目录名就是这个 webapp 的 Context path;
    (2)如果是通过 smart tomcat 启动 tomcat,是在启动的配置项中手动指定的 Context path(这种是另外的一种运行 tomcat 的方式)
  2. 第二级路径:就是 ServletPath
    这个是根据代码中的 @WebServlet 注解来确定的或者就是 webapp下面的静态文件/目录

以下是完整项目的目录:

三、代码

1、后端

创建 Message.java 和 MessageServlet.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.util.ArrayList;
import java.util.List;

// 对应到前端传来的请求 body 格式
// 此处要保证每个属性名字和 JSON 里的 key 对应
// 同时要保证这几个格式是 public 或者提供 public 的 getter 方法
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();
     List<Message> messageList = new ArrayList<>();

    // 负责实现让服务器从客户端拿数据
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1. 把 body 的 json 数据解析出来, 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"); // 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格式的字符串
        String respString = objectMapper.writeValueAsString(messageList);
        resp.getWriter().write(respString);
    }
}

2、前端

事实上只有注释行为新的步骤(也就是第103行)后面才是更新的代码,前面和上面的前端代码一样。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>表白墙</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        .container {
            width: 800px;
            margin: 0 auto;
        }
        .container h2 {
            text-align: center;
            margin: 30px;
        }

        .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: 50px;

        }

        .row button {
            height: 50px;
            width: 400px;
            margin: 10px 0px;
            color: white;
            background-color: orange;
            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>
    </div>

    <script src="https://code.jquery.com/jquery-3.7.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() {
            let from = fromInput.value;
            let to = toInput.value;
            let message = messageInput.value;

            if(from=='' || to=='' || message=='||') {
                return;
            }
            let newDiv = document.createElement('div');
            newDiv.className = 'row';
            newDiv.innerHTML = from + "对" + to + "说" + message;
            container.appendChild(newDiv);
            fromInput.value = '';
            toInput.value = '';
            messageInput.value = '';

            // 新的步骤,将刚才输入框里取得的数据构造成 POST 请求,提交给后端服务器
            // json
            let messageJson = {
                // 字符串: 变量
                from: from,
                to: to,
                message: message
            };
            $.ajax({
                type: 'post',
                // 相对路径
                url: 'message',
                // 绝对路径
                // url: '/MessageWall1/message',
                contentType: 'application/json;charset=utf8',
                data: JSON.stringify(messageJson), // JSON 转成 JSON 格式的字符串
                success: function() {
                    alert("提交成功");
                },
                // 返回状态码不是2xx就触发此函数
                error: function() {
                    alert("提交失败");
                }
            });
        }

        // 这个函数在页面加载/刷新的时候调用,通过这个函数从服务器获取到当前的消息列表,显示在页面上
        function load() {
            $.ajax({
                type: 'get',
                url: 'message',
                success: function(body) {
                    // 此处 body 已经是 json , ajax 会根据contentType自动转换
                    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>

json的key只能是字符串类型.此处写的 from其实是"from" .只不过咱们这里图省事,把"省略了
json中表示字符串,单弓|号或者双引号都行.
在这里插入图片描述

在这里插入图片描述

3、总结

  1. 打开页面/刷新页面,先执行前端load();
  2. load()会执行ajax,ajax会发生一个HTTP请求给服务器,GET /message,这里面的success先不执行,后面才会执行
  3. 这个HTTP请求通过网络发送给tomcat,进一步触发doGet方法,doGet方法执行里面的逻辑,将List转换成JSON,构造HTTP响应返回给客户端
  4. 客户端收到返回数据触发回调函数,也就是success,success执行里面的逻辑,将服务器返回的数据(body)显示到页面上

四、存入数据库

当服务器重启,List 里面的数据会丢失,应该怎样解决这个问题?
关键是要把数据存储在服务器的硬盘上面
1、存入文件里面,使用 IO 流来写文件/读文件
2、存入数据库里面,使用 MYSQL+JDBC

JDBC(Java Database Connectivity)是Java编程语言中用于执行SQL语句的一组API(应用程序接口)。它为数据库访问提供了一种标准的方法,使得Java程序可以与各种关系型数据库进行交互,而无需关心具体的数据库实现细节。

这里使用存入数据库的方式来解决问题:

1、引入 mysql 的依赖,mysql 驱动包

<!-- 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 database MessageWall;
use MessageWall;

drop table if exists MessageWall;
create table MessageWall (
    `from` varchar(100),
    `to` varchar(100),
    message varchar(1024)
);

3、调整上述后端代码

3.1 封装数据库操作,和数据库建立连接

新建一个类 DBUtil.java

import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
//import com.mysql.jdbc.Connection;

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

// 通过这个类完成建立数据库的连接的过程
// 建立连接需要使用 DataSource,并且一个程序有一个 DataSource 实例即可,这里用单例模式来实现
public class DBUtil {

    private static DataSource dataSource = null;

    private static DataSource getDataSource() {
        if (dataSource == null) {
            dataSource = new MysqlDataSource();
            ((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1/messagewall?characterEncoding=utf8&useSSL=false");
            ((MysqlDataSource)dataSource).setUser("root");
            ((MysqlDataSource)dataSource).setPassword("1234");

        }
        return dataSource;
    }

    public static Connection getConnection() throws SQLException {
        return getDataSource().getConnection();
    }

    public static void close(Connection connection, PreparedStatement preparedStatement, ResultSet resultSet) {
        // 后创建的先释放
        // 此处分开写 try-catch 是因为一个地方异常了不会影响其他的 close 执行
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (preparedStatement != null) {
            try {
                preparedStatement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

3.2 调整后端代码

MessageServlet.java

@WebServlet("/message")
public class MessageServlet extends HttpServlet {

    private ObjectMapper objectMapper = new ObjectMapper();
    // List<Message> messageList = new ArrayList<>();

    // 负责实现让服务器从客户端拿数据
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 1. 把 body 的 json 数据解析出来, 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"); // 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格式的字符串
        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 message 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 message";
            statement = connection.prepareStatement(sql);
            // 3.执行SQL
            resultSet = statement.executeQuery(sql);
            // 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;
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

小程序-使用 iconfont 图标库报错:Failed to load font

官方默认可以忽略此错误&#xff0c;在清除缓存后首次刷新会显示此错误&#xff0c;重新渲染错误消失 解决方法&#xff1a; 在 iconfont 图标库选择项目设置 选中 Base64 保存&#xff0c;重新点击链接 -> 复制代码到项目中 操作步骤&#xff1a;

用CAXA CAD电子图板导入图框、标题栏并导出pdf的方法

1.导入图框&#xff1a; 点击调入图框->出现读入图框文件 一个一个点击&#xff0c;选择合适的图框 然后点击导入 2.导入标题栏&#xff1a; 调入标题栏->出现读入标题栏文件 一个一个点击&#xff0c;选择合适的标题栏&#xff0c;然后点击导入 3.导出pdf&#x…

《Shader入门精要》透明效果

代码以及实例图可以看github &#xff1a;zaizai77/Shader-Learn: 实现一些书里讲到的shader 在实时渲染中要实现透明效果&#xff0c;通常会在渲染模型时控制它的透明通道&#xff08;Alpha Channel&#xff09;​。当开启透明混合后&#xff0c;当一个物体被渲染到屏幕上时&…

加速科技精彩亮相中国国际半导体博览会IC China 2024

11月18日—20日&#xff0c;第二十一届中国国际半导体博览会&#xff08;IC China 2024&#xff09;在北京国家会议中心顺利举办&#xff0c;加速科技携重磅产品及全系测试解决方案精彩亮相&#xff0c;加速科技创始人兼董事长邬刚受邀在先进封装创新发展论坛与半导体产业前沿与…

【JavaEE初阶 — 多线程】线程池

目录 1. 线程池的原理 1.1 为什么要有线程池 1.2 线程池的构造方法 1.3 线程池的核心参数 1.4 TimeUnit 1.5 工作队列的类型 1.6 工厂设计模式 1.6.1 工厂模式概念 1.6.2 使用工厂模式的好处 1.6.3 使用工厂模式的典型案例 1.6.4 Thread…

JSON 性能测试 - WastJson 性能也很快

WAST 是一个高性能 Java 工具集库包&#xff0c;包括 JSON、YAML、CSV、HttpClient、JDBC 和 EL 引擎. WastJson 无论是小中大文本各种数据类型等性能都没有明显的短板&#xff0c;除了推广外可以说是六边形战士&#xff0c;更多测试参考 wast-jmh-test: wast性能测试 (并非所…

数据库-基础理论

文章目录 前言一、ORM框架二、ACID原则三、事务Transaction四、N1问题五、Normalization三范式六、FMEA方法论&#xff08;Failure Mode and Effects Analysis&#xff09;七、Profiling和PerformanceSchema查询分析 前言 基础理论 ORM框架、ACID原则、事务Transaction、N1问…

AI赋能电商:构建高效、智能化的新零售生态

随着人工智能&#xff08;AI&#xff09;技术的不断进步&#xff0c;其在电商领域的应用日益广泛&#xff0c;从购物推荐到供应链管理&#xff0c;再到商品定价&#xff0c;AI正在全面改变传统电商的运营模式&#xff0c;并推动行业向智能化和精细化方向发展。本文将探讨如何利…

[极客大挑战 2019]BabySQL--详细解析

信息搜集 进入界面&#xff1a; 输入用户名为admin&#xff0c;密码随便输一个&#xff1a; 发现是GET传参&#xff0c;有username和password两个传参点。 我们测试一下password点位能不能注入&#xff1a; 单引号闭合报错&#xff0c;根据报错信息&#xff0c;我们可以判断…

计算机网络socket编程(2)_UDP网络编程实现网络字典

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 计算机网络socket编程(2)_UDP网络编程实现网络字典 收录于专栏【计算机网络】 本专栏旨在分享学习计算机网络的一点学习笔记&#xff0c;欢迎大家在评论区交流讨…

GitLab|应用部署

创建docker-compose.yaml文件 输入docker-compose配置 version: 3.8 services:gitlab:image: gitlab/gitlab-ce:15.11.2-ce.0restart: alwayscontainer_name: gitlab-ceprivileged: truehostname: 192.168.44.235environment:TZ: Asia/ShanghaiGITLAB_OMNIBUS_CONFIG: |exter…

虚拟苹果系统MacOS中新建自定义C++Dylib并用C++测试程序测试

前言 苹果系统中Dylib的建立和使用是一个非常基础的功能。本博客使用苹果虚拟机MacOS Ventura 13.6.7&#xff0c;XCode15.2&#xff0c;来复现这个过程。供参考。 1、Dylib框架的建立 2、增加一个函数 注意&#xff0c;向导自动生成的Helloworld函数中嵌套了一个函数Helloworl…

利用 Jsoup 进行高效 Web 抓取与 HTML 处理

Jsoup 是一款 Java 的 HTML 解析器&#xff0c;可直接解析某个 URL 地址、HTML 文本内容。它提供了一套非常省力的 API&#xff0c;可通过 DOM&#xff0c;CSS 以及类似于 JQuery 的操作方法来取出和操作数据。 官网&#xff1a;https://jsoup.org/ 中文文档&#xff1a;Jsou…

基于IPMI的服务器硬件监控指标解读

在现代化数据中心中&#xff0c;服务器的稳定运行对于保障业务连续性至关重要。为了实时掌握服务器的健康状况&#xff0c;运维团队需要借助高效的监控工具。监控易作为一款功能强大的监控软件&#xff0c;支持使用IPMI&#xff08;Intelligent Platform Management Interface&…

windows C#-属性

属性提供了一种将元数据或声明性信息与代码(程序集、类型、方法、属性等)关联的强大方法。将属性与程序实体关联后&#xff0c;可以使用称为反射的技术在运行时查询该属性。 属性具有以下属性&#xff1a; 属性将元数据添加到您的程序中。元数据是有关程序中定义的类型的信息…

【Mybatis】@Param注解 resultMap手动映射

文章目录 一、映射文件参数二、查询映射2-1 一对一2-2 一对多2-3 总结 一、映射文件参数 Param 注解官方文档解释 1、单个参数&#xff08;对象&#xff09;不使用注解 public int save(User user);<!-- 添加用户 --> <insert id"save" parameterType&quo…

第02章_MySQL环境搭建(基础)

1. MySQL 的卸载 1.1 步骤1&#xff1a;停止 MySQL 服务 在卸载之前&#xff0c;先停止 MySQL8.0 的服务。按键盘上的 “Ctrl Alt Delete” 组合键&#xff0c;打开“任务管理器”对话 框&#xff0c;可以在“服务”列表找到“MySQL8.0” 的服务&#xff0c;如果现在“正在…

ES 和Kibana-v2 带用户登录验证

1. 前言 ElasticSearch、可视化操作工具Kibana。如果你是Linux centos系统的话&#xff0c;下面的指令可以一路CV完成服务的部署。 2. 服务搭建 2.1. 部署ElasticSearch 拉取docker镜像 docker pull elasticsearch:7.17.21 创建挂载卷目录 mkdir /**/es-data -p mkdir /**/…

H.265流媒体播放器EasyPlayer.js无插件H5播放器关于移动端(H5)切换网络的时候,播放器会触发什么事件

EasyPlayer.js无插件H5播放器作为一款功能全面的H5流媒体播放器&#xff0c;凭借其多种协议支持、多种解码方式、丰富的渲染元素和强大的应用功能&#xff0c;以及出色的跨平台兼容性&#xff0c;为用户提供了高度定制化的选项和优化的播放体验。无论是视频直播还是点播&#x…

SpringBoot(9)-Dubbo+Zookeeper

目录 一、了解分布式系统 二、RPC 三、Dubbo 四、SpringBootDubboZookeeper 4.1 框架搭建 4.2 实现RPC 一、了解分布式系统 分布式系统&#xff1a;由一组通过网络进行通信&#xff0c;为了完成共同的任务而协调工作的计算机节点组成的系统 二、RPC RPC&#xff1a;远程…