程序设计——前后端分离实现简单表白墙

文章目录

  • 一、前端页面样式代码
  • 二、前后端衔接
    • 1. 后端创建 maven 项目
    • 2. 针对前后端交互的解释以及后端代码的实现
      • 针对 post 请求解释前后端衔接
      • 针对 Get 请求解释前后端衔接
    • 3.后端与数据库的联系以及对数据的存取
      • 单独封装数据库连接代码
      • 解释后端存储 save 数据的代码
      • 解释后端读取 load 数据代码
  • 三、总结

本篇文章所实现的这个表白墙,是一个前后端分离的一个 web 程序。

本篇文章中整体的代码本人以及上传至 gitee 如有需要可以访问查看:整体代码

这篇文章会重点解释后端的实现,对此,前端页面样式构建的代码不会进行过多的解释,将会直接的呈现在大家面前。

一、前端页面样式代码

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

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

    .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: wheat;
        background-color: #ff6600;
        border: none;
        
    }
    /* 让点击的时候有一个反馈 */
    .row button:active{
        background-color: #535350;
    }
</style>

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


 <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script>
    // 在这里实现提交操作,点击提交按钮,就可以将用户输入的内容提交到页面上来显示
    //在点击的时候获取三个输入框中的文本内容
    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 massage';
        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('.massage');
        if (rows == null || rows.length == 0) {
                return;
        }
        containerDiv.removeChild(rows[rows.length-1]);
    }


       // [新增] 在页面加载的时候, 发送 GET 请求, 从服务器获取到数据并添加到页面中
       $.ajax({
        // 将前面获取到变量名的值 给到这边对应的 value
        type: 'get',
        url: 'message',
        success: function(body) {
            // 此处拿到的 body 就是一个 js 的对象数组了. 
            // 本来服务器返回的是一个 json 格式的字符串, 但是 jquery 的 ajax 能够自动识别
            // 自动帮我们把 json 字符串转成 js 对象数组
            // 接下来遍历这个数组, 把元素取出来, 构造到页面中即可
            let containerDiv = document.querySelector('.container')
            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>

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

二、前后端衔接

1. 后端创建 maven 项目

  1. 创建必要的目录文件 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. 调整 pom.xml
    这里需要再 maven 仓库中引入三个对应的 jar 包。分别是:
    servlet: 该 jar 包提供了大量后续代码需要使用的 Tomcat API。
    jackson: 便于前后端使用 Jackson 进行键值对构建
    mysql: 用于之后将交互信息存储到数据库中,用于之后访问时信息不会消失。
    代码展示:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>MassageWall</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
<!--对应的 servlet 的 jar 包-->
        <!-- 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 的 jar 包-->
        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.14.1</version>
        </dependency>

<!--对应的 mysql 的 jar 包-->
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
    </dependencies>

</project>
  1. 将前端页面拷贝到 webapp 中
    在这里插入图片描述
    要注意,这里的 html 文件必须放对地方,否则后面代码的运行就会出现问题。

2. 针对前后端交互的解释以及后端代码的实现

首先,这里我们需要在 main 文件下创建一个新的 Java 文件,并在其中创建出两个新的类,来书写我们的后端代码。如图:
在这里插入图片描述

当前的代码是在 massageServlet 中实现的。

在所有的代码实现之前,我们都需要进行规划,来确保我们每一步都在正确的方向上。
对于这里的代码,我们首先就需要进行约定。

这里的约定,本质上就是描述一个 前后端信息交互时的格式。

针对 post 请求解释前后端衔接

  • 前端页面的 post 请求约定

这里切记一点,这里的 前端页面 是存放在 webapp 文件夹中的,后端代码是可以接收到其发出的 post 请求的。

前端页面中,点击提交时就会发出一个 post 请求。
此时,就会发送一个如下图所示的 Json 字符串。这个字符串就是对应的约定格式。
在这里插入图片描述
在前端代码中,构建这样的请求代码截取下来就是下图形式:
在这里插入图片描述

  • 后端页面接受 post 请求的约定

对于后端代码,接受 post 请求实现的是 doPost 方法。在接受传入的信息之前,后端代码需要定义一个 class 来作为约定来接受信息。如图:
在这里插入图片描述
下半部分是 doPost 方法的实现,其中 readValue 会将获取到的 json 字符串转化为 java 对象。
后端代码这里的作用是: 将前端传递的信息进行获取并储存起来。

注: 在这里插入图片描述
这个问题会在后面与数据库连接的代码中进行讲解。

整体上来简单解释一下前后端 post 请求之间的配合。
在这里插入图片描述

针对 Get 请求解释前后端衔接

  • 前端页面的 get 请求

对于前端页面,我们知道,在我们根据文件目录进行访问时,每次访问,前面的数据信息就会消失。
但是,在与后端连接时,前端页面在加载时,就会向后端服务器发送一个 get 请求获取之前的信息。
之后将其显示在浏览器的页面上。

前端连接的代码如下:
在这里插入图片描述
这里的 ajax 会将后端传递过来的 json 格式字符串识别为 js 能够识别的数据。

  • 后端代码实现 doGet 方法

对于后端,在得到前端 get 请求之后。就会执行 doGet 方法来实现对前端的相应。
即就是,将之前的信息进行读取并解析为 json 字符串后,将其发送到前端的 body 中
代码如下:
在这里插入图片描述

注:
在这里插入图片描述
同样的,这句读取代码会在后面与数据库连接时进行解释。

整体上简单解释一下前后端在 get 请求之间的配合。大致如下:
在这里插入图片描述

3.后端与数据库的联系以及对数据的存取

到这里,前后端之间的信息交互的代码已经结束了。
从这里开始,我将会进行后端对数据的存储,以及前端页面加载时数据从数据库中的读取进行解释。

单独封装数据库连接代码

首先在 DBUtil 中单独实现一个数据库连接的类,将其进行封装。

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;

//通过这个类将数据库连接封装一下
// 此处这个类作为一个工具类,提供 static 方法供以调用
public class DBUtil {
    //静态成员跟随类对象,类对象在整个进程中只有一份
    //静态成员相当于是唯一的事例。(单例模式,饿汉模式)
    private static DataSource dataSource = new MysqlDataSource();

    //这里的代码在类加载的时间就会被创建出来
    static{
        //使用静态代码块,针对 DataSource 进行初始化
        //这里与 JDBC 有相似之处,需要将连接的信息建立起来
        ((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/wall?characterEncoding=utf8&useSSL=false");
        ((MysqlDataSource)dataSource).setUser("root");
        ((MysqlDataSource)dataSource).setPassword("wjh123456");
    }

    //通过这个方法来建立连接
    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    //通过这个方法断开连接,释放资源
    //connection    就是指连接的状态
    //statement     是指当前正在执行的 sql 语句
    //resultSet     是指当前正在获取 sql 语句执行的结果
    public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet){
        // 此处的三个 try catch 分开写更好, 避免前面的异常导致后面的代码不能执行.
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

这里的代码还是比较好理解的,大致分为两部分:
1、实现一个连接方法,将代码和数据库的连接独立出来,在其他方法请求时立即反应并进行连接。(饿汉模式)。

这里的 static 使得代码在类加载时就已经生产出来了,也就是说一直在等待着被连接。

2、实现一个关闭方法,断开连接,并注意异常的处理。

注意事项:这里是引用

解释后端存储 save 数据的代码

在这里插入图片描述
这里解释的就是在 doPost 中的 save 方法。

这里的 save 与 JDBC 中的存储非常相似,代码不难理解,大致分为四步:
1、建立连接
2、构造 SQL 语句
3、执行 SQL 语句
4、断开连接

代码如下:

    private void save(Message message){
        //JDBC 操作
        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
            statement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            // 4. 关闭连接.保证代码一定可以执行到
            DBUtil.close(connection, statement, null);
        }
    }

注意事项:
在这里插入图片描述

解释后端读取 load 数据代码

在这里插入图片描述
这里解释的就是 doGet 中的 load 方法。

同样的,这里的代码与 JDBC 中的操作很是相似,代码同样不难理解,大致分为下面四步:
1、与数据库建立连接
2、构造 SQL 语句
3、执行 SQL 语句
4、遍历结果集合,并存放到链表中进行返回
5、断开与数据库连接

    //从数据库中获取所有消息
    private List<Message> load(){
        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;
    }

三、总结

到这里,前后端分离的实现就已经大功告成了。

整体的运行展示:
1.启动服务器
在这里插入图片描述
2.访问网页页面
在这里插入图片描述

从整体的逻辑上看,前端,后端,数据库三者之间的联系,大致如下图所示:
在这里插入图片描述
码子不易,您小小的点赞是对我最大的鼓励!!!

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

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

相关文章

神经网络中的算法优化(皮毛讲解)

抛砖引玉 在深度学习中&#xff0c;优化算法是训练神经网络时至关重要的一部分。 优化算法的目标是最小化&#xff08;或最大化&#xff09;一个损失函数&#xff0c;通常通过调整神经网络的参数来实现。 这个过程可以通过梯度下降法来完成&#xff0c;其中梯度指的是损失函数…

【Unity】位图字体制作工具:蒲公英

一般来讲&#xff0c;如果需要制作位图字体&#xff0c;一般是使用 BMFont 这种第三方工具&#xff1a;BMFont - AngelCode.comhttp://www.angelcode.com/products/bmfont/ 然而这个工具对于非程序员来说&#xff0c;操作起来较为繁琐困难。每次美术修改了字体之后&…

【短剧在线表格搜索-附模板】

短剧在线表格搜索-附模板 介绍电脑界面手机界面送附加功能&#xff1a;反馈缺失短剧送&#xff1a;资源更新源头获取 介绍 你好&#xff01; 这是你第一次使用 金山在线文档 所生成的短剧搜索表格&#xff0c;支持批量导入自己转存的短剧名字和链接&#xff0c;实现在线搜索&a…

【AI】openai-quickstart 运行Jupyter Lab

openai-quickstart/openai_api /README-CN.md 【AI】指定python3.10安装Jupyter Lab 可以安装3.10版本的jupyter lab 但是直接输入命令无法启动 突然发现自己电脑2023年安装过anaconda3 C:\ProgramData\anaconda3\python.exe C:\ProgramData\anaconda3\cwp.py C:\ProgramData…

一款开源的原神工具箱,专为现代化 Windows 平台设计,旨在改善桌面端玩家的游戏体验

Snap.Hutao 胡桃工具箱是一款以 MIT 协议开源的原神工具箱&#xff0c;专为现代化 Windows 平台设计&#xff0c;旨在改善桌面端玩家的游戏体验。通过将既有的官方资源与开发团队设计的全新功能相结合&#xff0c;提供了一套完整且实用的工具集&#xff0c;且无需依赖任何移动设…

WordPress MasterStudy LMS插件 SQL注入漏洞复现(CVE-2024-1512)

0x01 产品简介 WordPress和WordPress plugin都是WordPress基金会的产品。WordPress是一套使用PHP语言开发的博客平台。该平台支持在PHP和MySQL的服务器上架设个人博客网站。WordPress plugin是一个应用插件。 0x02 漏洞概述 WordPress Plugin MasterStudy LMS 3.2.5 版本及之…

SpringCloudAlibaba:4.1云原生网关higress的搭建

概述 简介 Higress是基于阿里内部的Envoy Gateway实践沉淀、以开源Istio Envoy为核心构建的下一代云原生网关&#xff0c; 实现了流量网关 微服务网关 安全网关三合一的高集成能力&#xff0c;深度集成Dubbo、Nacos、Sentinel等微服务技术栈 定位 在虚拟化时期的微服务架构…

STM32 PWM波定时溢出中断

打开定时器和中断 主函数初始化开启PWM和中断 HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_1); __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, Pwm_data); HAL_TIM_Base_Start_IT(&htim2); 回调函数中判断是否为tim2 void HAL_TIM_PeriodElapsedCallback(TIM_Han…

【ARM】ARM寄存器和异常处理

1.指令的执行过程 &#xff08;1&#xff09;一条指令的执行分为三个阶段 1.取址&#xff1a; CPU将PC寄存器中的地址发送给内存&#xff0c;内存将其地址中对应的指令返回 到CPU中的指令寄存器&#xff08;IR&#xff09; 2.译码&#xff1a; 译码器对IR中的指令…

51单片机入门:DS1302时钟

51单片机内部含有晶振&#xff0c;可以实现定时/计数功能。但是其缺点有&#xff1a;精度往往不高、不能掉电使用等。 我们可以通过DS1302时钟芯片来解决以上的缺点。 DS1302时钟芯片 功能&#xff1a;DS1302是一种低功耗实时时钟芯片&#xff0c;内部有自动的计时功能&#x…

裸金属服务器,云用户的新体验

定义 裸金属服务器&#xff08;Bare Metal Server&#xff09;&#xff0c;是一台既具有传统物理服务器特点的硬件设备&#xff0c;又具备云计算技术的虚拟化服务功能&#xff0c;是硬件和软件优势结合的产物。可以为企业提供专属的云上物理服务器&#xff0c;为核心数据库、关…

15_Scala面向对象编程_访问权限

文章目录 Scala访问权限1.同类中访问2.同包不同类访问3.不同包访问4.子类权限小结 Scala访问权限 知识点概念 private --同类访问private[包名] --包私有&#xff1b; 同类同包下访问protected --同类&#xff0c;或子类 //同包不能访问(default)(public)默认public --公…

学习大数据,所需要的shell基础(1)

文章目录 Shell概述shell脚本入门变量系统预定义变量自定义变量特殊变量$n$#\$*、$$&#xff1f; 运算符条件判断流程控制&#xff08;重点&#xff09;if判断case语句for循环while循环 Shell概述 shell是一个命令解释器&#xff0c;他接受应用程序/用户命令&#xff0c;然后调…

【Python项目】基于opencv的的【疲劳检测系统】

技术简介&#xff1a;使用Python技术、OpenCV图像处理库、MYSQL数据库等实现。 系统简介&#xff1a;用户可以通过登录系统平台实现实时的人脸照片的拍摄和上传&#xff0c;结合上传图像的内容进行后台的图像预处理和运算分析&#xff0c;用户可以通过照片分析界面查看到当前检…

【iOS】KVO

文章目录 前言一、KVO使用1.基本使用2.context使用3.移除KVO通知的必要性4.KVO观察可变数组 二、代码调试探索1.KVO对属性观察2.中间类3.中间类的方法3.dealloc中移除观察者后&#xff0c;isa指向是谁&#xff0c;以及中间类是否会销毁&#xff1f;总结 三、KVO本质GNUStep窥探…

虚拟化技术 使用Vsphere Client管理ESXi服务器系统

使用Vsphere Client管理ESXi服务器系统 一、实验目的与要求 1.掌握使用vSphere Client管理ESXi主机 2.掌握将CentOS的安装介质ISO上传到ESXi存储 3.掌握在VMware ESXi中创建虚拟机 4.掌握在所创建的虚拟机中安装CentOS6.5操作系统 5.掌握给CentOS6.5安装VMware Tools 6.掌…

HCIP的学习(11)

OSPF的LSA详解 LSA头部信息 ​ [r2]display ospf lsdb router 1.1.1.1----查看OSPF某一条LSA的详细信息&#xff0c;类型以及LS ID参数。 链路状态老化时间 指一条LSA的老化时间&#xff0c;即存在了多长时间。当一条LSA被始发路由器产生时&#xff0c;该参数值被设定为0之后…

RK3568 学习笔记 : u-boot 千兆网络无法 ping 通PC问题的解决方法二

参考 RK3568 学习笔记 : u-boot 千兆网络无法 ping 通PC问题的解决 前言 rk3568 rockchip 提供的 u-boot&#xff0c;默认的设备树需要读取 单独分区 resouce.img 镜像中的 设备树文件&#xff0c;也就是 Linux 内核的设备树 dtb 文件&#xff0c;gmac 网络才能正常的 ping 通…

知识图谱和大语言模型的共存之道

导读 知识图谱和大型语言模型都是用来表示和处理知识的手段。大模型补足了理解语言的能力&#xff0c;知识图谱则丰富了表示知识的方式&#xff0c;两者的深度结合必将为人工智能提供更为全面、可靠、可控的知识处理方法。在这一背景下&#xff0c;OpenKG组织新KG视点系列文章—…

Microsoft Remote Desktop Beta for Mac:远程办公桌面连接工具

Microsoft Remote Desktop Beta for Mac不仅是一款远程桌面连接工具&#xff0c;更是开启远程办公新篇章的利器。 它让Mac用户能够轻松访问和操作远程Windows计算机&#xff0c;实现跨平台办公的无缝衔接。无论是在家中、咖啡店还是旅途中&#xff0c;只要有网络连接&#xff0…