实现第一个服务器版本的表白墙程序

news2024/11/27 2:33:33

文章目录

  • 表白墙
    • 前言
    • 1. 环境部署
      • 1.1 创建maven项目
      • 1.2 引入依赖
      • 1.3 创建目录结构
      • 1.4 部署程序
    • 2. 前端页面
    • 3. 后端实现
      • 3.1 后端逻辑
      • 3.2 后端代码

表白墙

前言

基于MySQL数据库和servlet实现的前后端交互的服务器版本表白墙。在页面输入表白内容,在本地通过数据库存储历次表白内容,保证网页刷新重进时数据仍存在。以下为打开表白墙效果展示:

在这里插入图片描述
我们可以在输入框输入表白对象,表白内容然后提交就能显示到新动态中,提交之后输入框自动清空内容。

完整项目代码可以通过我的gitee获取MessageWall

1. 环境部署

1.1 创建maven项目

我们在idea里面点击new project创建一个maven项目,然后一路next选择好项目位置以及命名即可。
在这里插入图片描述
在这里插入图片描述

1.2 引入依赖

在创建完maven项目之后我们需要加载依赖,部分同学可能由于网络问题难以加载,可以多试几遍,实在不行可以更换国内的镜像下载此处不作多介绍。以下需要引入的依赖主要有:java.servlet-api、mysql-connector-java,以及后续发送json格式的数据需要的jackson依赖(jackson-databind)

我们通过maven仓库官网https://mvnrepository.com/ 即可获取。

如图:复制链接黏贴到我们项目的pom.xml文件
在这里插入图片描述

代码 : 以下是我部署的依赖可以直接复制黏贴

 <dependencies>
<!--        servlet依赖-->
        <!-- 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>
<!--        jackson依赖-->
        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.14.2</version>
        </dependency>
<!--        数据库依赖-->
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
    </dependencies>

1.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>

1.4 部署程序

我们在插件市场搜索 Smart Tomcat 插件,将Tomcat集成到idea就不用我们手动打包,之后点击即可运行。
在这里插入图片描述
然后点击新增运行配置,将Smart Tomcat加入,此处选择Tomcat路径,如果还没有下载Tomcat,可以通过官网下载。博主使用的是 3.1版本的servlet+tomcat 8

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

然后就可以点击运行:出现以下结果就是部署成功了。之后我们就可以通过127.0.0.1:8080/MessageWall/xx.html(html页面)访问,其中MessageWall是Context path,一般默认是项目名。

在这里插入图片描述

2. 前端页面

由于该程序只是作为我们学习使用servlet实现前后端交互的一个开端,我们我们前端页面只包括:输入框 input 、提交按钮 button 、无语义标签 div 用来划分页面。

页面展示:
在这里插入图片描述

HTML代码: 除了html本身代码还包含通过 style 标签引入的css代码,通过 script 标签引入的js代码。

通过css实现页面样式以及布局,通过js实现提交按钮的点击效果(点击变灰)以及向服务器发送GET请求并获取数据加载到页面。

注意: 本次我们采用的是通过 form表单构造json格式的get请求发送到服务器 ,需要通过 jquery的ajax 实现:

  1. 导入jquery cdn,在浏览器搜索即可,也可以直接下载我的
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>

  1. 通过ajax构造请求
 $.ajax({
        type: 'get',
        url: 'message',
        success: function(body) {
            // 此处拿到的 body 就是一个 js 的对象数组了.
            // 本来服务器返回的是一个 json 格式的字符串, 但是 jquery 的 ajax 能够自动识别
            // 自动帮我们把 json 字符串转成 js 对象数组
            // 接下来遍历这个数组, 把元素取出来, 构造到页面中即可
            let containerDiv = document.querySelector('.qian')
            for (let message of body) {
                // 针对每个元素构造一个 div
                let rowDiv = document.createElement('div');
                rowDiv.className = 'row message';
                rowDiv.innerHTML = message.from + ' 对 ' + message.to + ' 说: ' + message.message;
                containerDiv.appendChild(rowDiv);
            }
        }
    });

完整代码:

<!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: 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;
        }
        .qian{
            width: 300px;
            height: 500px;
            margin: 20px auto;
            background-color: pink;
            text-align: center;

            }
    </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="qian">
        <h2>新动态</h2>
    </div>

</div>

<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>

<script>
    // 实现提交操作. 点击提交按钮, 就能够把用户输入的内容提交到页面上显示.
    // 点击的时候, 获取到三个输入框中的文本内容
    // 创建一个新的 div.row 把内容构造到这个 div 中即可.
    let containerDiv = document.querySelector('.qian');
    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. [新增] 给服务器发起 post 请求, 把上述数据提交到服务器这边
        let body = {
            "from": from,
            "to": to,
            "message": msg
        };
        let 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("数据发布成功");
            }
        });
    }
    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]);
    }


    // [新增] 在页面加载的时候, 发送 GET 请求, 从服务器获取到数据并添加到页面中
    $.ajax({
        type: 'get',
        url: 'message',
        success: function(body) {
            // 此处拿到的 body 就是一个 js 的对象数组了.
            // 本来服务器返回的是一个 json 格式的字符串, 但是 jquery 的 ajax 能够自动识别
            // 自动帮我们把 json 字符串转成 js 对象数组
            // 接下来遍历这个数组, 把元素取出来, 构造到页面中即可
            let containerDiv = document.querySelector('.qian')
            for (let message of body) {
                // 针对每个元素构造一个 div
                let rowDiv = document.createElement('div');
                rowDiv.className = 'row message';
                rowDiv.innerHTML = message.from + ' 对 ' + message.to + ' 说: ' + message.message;
                containerDiv.appendChild(rowDiv);
            }
        }
    });
</script>
</body>
</html>

3. 后端实现

在后端实现中创建两个类即可,MessageServlet类由于实现前后端交互,DBUtils类用于操作数据库的工具类。

3.1 后端逻辑

  1. 前后端交互的数据约定为 json格式,在后端实现中也是通过导入的jackson库 解析该数据。
  2. 点击提交:浏览器将表白信息发送到服务器,对应着一对请求(Post)和响应
  3. 页面加载:浏览器从服务器哪获取到我们之前输入过的表白信息显示在页面,也对应一组请求(Get)与响应,该响应的body部分 通过json数组存储json格式的每条数据(json对象)。

由此我们在MassageServlet代码中只用实现 doPost()方法向服务器发送数据,doGet()方法从服务器获取数据,save()方法调用DBUtils类向数据库存储信息,load()方法从数据库取所有信息;

3.2 后端代码

MassageServlet.class:

  1. 在该类中 @WebServlet(“/message”) 对应着我们前端页面通过ajax构造请求发送的url路径一致,此处我们写的是相对路径。
  2. 导入jackson库之后我们就可以通过ObjectMapper类的readValue()读取请求中body的数据并规定以Massage.class格式读取,然后赋值给massage;
 Message message = objectMapper.readValue(req.getInputStream(),Message.class);
      
  1. massage.class,该类是为了存储读取到的json格式的键值对数据而创建。
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;

/**
 * @author zq
 */
class Message{
    public String from;
    public String to;
    public String message;
}

@WebServlet("/message")

public class MessageServlet extends HttpServlet {
    //private List<Message> messageList = new ArrayList<>();
    //向服务器发送数据
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        //读取body中的内容赋值给massage对象
        Message message = objectMapper.readValue(req.getInputStream(),Message.class);
        //通过简单粗暴的方法保存,list
        //messageList.add(message);
        save(message);
        //设置响应状态码(可以不设置)
        resp.setStatus(200);
    }

    //从服务器获取数据
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("application/json;charset=utf8");
        ObjectMapper objectMapper = new ObjectMapper();
        List<Message> messageList = load();
       // objectMapper.writeValue(resp.getWriter(),messageList);
        objectMapper.writeValue(resp.getWriter(),messageList);
    }

    //提供一对方法
    //王数据库存一条消息
    private void save(Message message)  {
        //这是基本的jdbc操作
        //1.建立连接
        Connection connection = null;
        PreparedStatement statement =null;

        try {
            connection = DBUtil.getConnection();
            //2.构造sql语句
            String sql = "insert into message value(?,?,?)";
            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(){
        List<Message> messageList = new ArrayList<>();
        //1.建立连接
        Connection connection = null;
        PreparedStatement statement =null;
        ResultSet resultSet = null;

        try {
            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();
                //根据列名取出sql语句
                message.from = resultSet.getString("from");
                message.to = resultSet.getString("to");
                message.message = resultSet.getString("message");
                messageList.add(message);

            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //4.关闭连接
            DBUtil.close(connection,statement,resultSet);
        }
        return messageList;
    }
}

DBUtils.class:

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

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

/**
 * @author zq
 */
/*通过这个类将数据库连接封装起来
* 此处将DBUtil作为一个工具类,提供static方法共其他代码使用
* */
public class DBUtil {
    //静态成员跟随类对象,类对象在整个进程中只有唯一一份
    //静态成员相对于也是唯一实例,(单例模式,饿汉模式)
    private static DataSource dataSource = new MysqlDataSource();

    static{
        //使用静态代码块,针对dataSource进行初始化操作
        ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/javaee?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 preparedStatement, ResultSet resultSet){
       //此处三个try-catch分开写更好
        // 避免前面的出问题后面的执行不了
        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();
            }
        }
    }
}

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

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

相关文章

大数据Doris(二十三):Rollup物化索引作用和注意点

文章目录 Rollup物化索引作用和注意点 一、Rollup物化索引作用 1、改变索引 2、聚合数据

操作系统王道考研学习(二)操作系统的特征

目录 操作系统的特征&#xff1a;并发、共享、虚拟、异步 操作系统中并发为什么那么重要&#xff1f; 讲一讲多道程序技术 介绍一下空分复用技术 异步下程序是走走停停的 操作系统的特征&#xff1a;并发、共享、虚拟、异步 并发和共享 虚拟和异步 &#xff08;为什么要并…

物联网的体系架构

物联网中常见的计算模式&#xff1a;云计算、边缘计算、雾计算等 云计算&#xff1a;一种利用互联网实现随时随地、按需、便捷地使用共享计算设施、存储设备、应用程序等资源的计算模式。边缘计算&#xff1a;在靠近物或数据源头的网络边缘侧&#xff0c;融合网络、计算、存储…

本周前半周总结

刷题刷了六道 青训营视频补看 软件杯项目素材收集&#xff0c;首页制作ing 前面这六道题的题解&#xff1a; 题目1&#xff1a; 这是个交互题&#xff0c;目前遇到的交互题都是用二分解决的。 本题使用二分精准定位拥有重量为2的石头的堆。 为避免时间超限&#xff0c;应该再…

k8s1.20版本部署RabbitMQ集群(持久化)——2023.05

文章目录 一、集群概况二、RabbitMQ集群部署2.1 安装NFS2.2 创建storageclass存储类2.3 部署RabbitMQ集群2.4 测试 一、集群概况 主机规划 节点IPk8s-master1192.168.2.245k8s-master2192.168.2.246k8s-master3192.168.2.247k8s-node1192.168.2.248NFS、Rancher192.168.2.251…

阿里巴巴 菜鸟Java面经

目录 1.ArrayList和LinkedList的区别2.两个各自装啥数据合适3.final和finally的区别4.catch里面有个return&#xff0c;finally执行不执行5.线程的创建方式6.ThreadLocal7.序列化8.抽象类和接口的区别9.数据库的四大特性10.事务的一致性是啥11.事务的隔离级别12.可重复读是个啥…

inspect.exe安装使用

官网下载 https://developer.microsoft.com/zh-cn/windows/downloads/windows-sdk/ 官网教程 https://learn.microsoft.com/zh-cn/windows/win32/winauto/inspect-objects 要求 系统要求 Windows SDK 具有以下最低系统要求&#xff1a; 支持的操作系统 Windows 10版本 150…

chatgpt赋能Python-pycharm如何跳过教程

PyCharm如何跳过教程&#xff1a;快速掌握Python编程 如果你是一个有10年python编程经验的工程师&#xff0c;那么你肯定不需要再从头开始学习python&#xff0c;更不需要花费大量时间来学习PyCharm的教程。你需要的是一个快速而高效地使用PyCharm的方法&#xff0c;以便能够更…

chatgpt赋能Python-pandas预处理

介绍 Pandas是一个强大的Python库&#xff0c;专门用于数据操作和分析。在数据处理和分析的过程中&#xff0c;Pandas是一个不可或缺的工具。它提供了简单而灵活的数据结构&#xff0c;如Series和DataFrame&#xff0c;这些数据结构可以帮助我们快速预处理数据。 本文将介绍P…

虚拟机 01 jdk环境的安装与配置

01.第一步&#xff1a;进入到工作目录中&#xff0c;然后将目录中所有的资源都删掉 &#xff0c;此处的工作目录/usr/local/src 使用的命令是rm -rf * 02.第二步&#xff1a;将windows系统的jdk8的安装文件上传到Linux中 直接在window界面中选中压缩文件拖到Linux命令行中 完…

区间预测 | MATLAB实现QGPR高斯过程分位数回归时间序列区间预测

区间预测 | MATLAB实现QGPR高斯过程分位数回归时间序列区间预测 目录 区间预测 | MATLAB实现QGPR高斯过程分位数回归时间序列区间预测效果一览基本介绍模型描述程序设计参考资料 效果一览 基本介绍 MATLAB实现QGPR高斯过程分位数回归时间序列区间预测 1.基于高斯过程回归&#…

chatgpt赋能Python-pycharm怎么粘贴代码

PyCharm&#xff1a;如何在编辑器中粘贴代码 作为一个有多年 Python 编程经验的工程师&#xff0c;我可以说 PyCharm 是 Python 编辑器中的佼佼者&#xff0c;它凭借其智能化、强大的功能和用户友好的界面而受到广泛赞誉。在该编程软件中&#xff0c;如果你需要粘贴代码&#…

【我的C++入门之旅】(上)

前言 C的发展史 1979年&#xff0c;贝尔实验室的Bjarne等人试图分析unix内核的时候&#xff0c;试图将内核模块化&#xff0c;但是发现C语言有很多的不足之处&#xff0c;于是在C语言的基础上进行扩展&#xff0c;增加了类的机制&#xff0c;完成了一个可以运行的预处理程序&…

chatgpt赋能Python-pycharm备份

PyCharm备份——数据安全之道 在软件开发过程中&#xff0c;数据备份是一项至关重要的任务。特别是对于PyCharm这样的IDE来说&#xff0c;开发者在其中执行大量的代码编写、调试、测试、运行等操作&#xff0c;需要在相对固定的时间点 backup 数据&#xff0c;以防止数据丢失带…

【AFNetWorking源码一】

文章目录 前言一.原生的网络请求发送方式1.1 原生GET1.2 原生PSOT 二.AFN2.1 AFN的基本架构分析2.2 以GET为例分析AFN使用流程&#xff08;AFHTTPSessionManager2.2.1 AFN如何生生成对应的sessionManager2.2.2. AFURLSessionManager的初始化2.2.3 task的三种代理2.2.3.1 setDel…

力扣sql中等篇练习(二十二)

力扣sql中等篇练习(二十二) 1 坚定的友谊 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 # Write your MySQL query statement below # ①求出所有朋友关系的总表 WITH T as (SELECT user1_id ,user2_idFROM friendshipUNION SELECT user2_id user1…

前端学习--Vue(1)webpack

前端工程化 模块化&#xff08;js、css模块化、资源模块化&#xff09; 组件化&#xff08;复用现有的UI结构、样式、行为&#xff09; 规范化&#xff08;目录结构划分、编码规范化、接口文档规范化、git分支管理&#xff09; 自动化&#xff08;自动化构建、自动部署、自动化…

试用阿里云云拨测对Web网站的网页性能进行测试并分析

目录 前言 云拨测操作步骤 1.开通应用实时监控服务ARMS 2.成功登录后&#xff0c;在产品类别下选择中间件>应用实时监控服务&#xff0c;在云拨测卡片上单击立即试用。 3.登录ARMS控制台&#xff0c;在左侧导航栏中选择云拨测>定时拨测&#xff0c;在定时拨测页面右上…

chatgpt赋能Python-pycharm怎么与python关联

Pycharm怎么与Python关联&#xff1f; 介绍 对于Python开发人员来说&#xff0c;Pycharm是一个非常强大的IDE。它提供了各种工具和功能&#xff0c;用于快速开发和调试Python代码。但是&#xff0c;在开始开发之前&#xff0c;必须将Pycharm与Python关联起来。否则&#xff0…

chatgpt赋能Python-pulp_python

Pulp Python: 介绍与优点 在数据分析和决策优化领域&#xff0c;线性规划是一种非常有效的数学模型。而Pulp Python是一款优秀的线性规划库&#xff0c;它可以帮助用户快速进行线性规划求解&#xff0c;同时还具备可扩展性和易使用性等优点。 什么是线性规划&#xff1f; 线…