【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文件中。
运行项目一般是两级路径:
- 第一级: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 的方式) - 第二级路径:就是 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;@Overridepublic 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<>();// 负责实现让服务器从客户端拿数据@Overrideprotected 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=utf8resp.getWriter().write("{\"ok\": 1}");}// 负责实现让客户端从服务器拿数据@Overrideprotected 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 请求,提交给后端服务器// jsonlet 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、总结
- 打开页面/刷新页面,先执行前端load();
- load()会执行ajax,ajax会发生一个HTTP请求给服务器,GET /message,这里面的success先不执行,后面才会执行
- 这个HTTP请求通过网络发送给tomcat,进一步触发doGet方法,doGet方法执行里面的逻辑,将List转换成JSON,构造HTTP响应返回给客户端
- 客户端收到返回数据触发回调函数,也就是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<>();// 负责实现让服务器从客户端拿数据@Overrideprotected 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=utf8resp.getWriter().write("{\"ok\": 1}");}// 负责实现让客户端从服务器拿数据@Overrideprotected 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.执行SQLresultSet = 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;}
}
相关文章:

【JavaEE】Servlet:表白墙
文章目录 一、前端二、前置知识三、代码1、后端2、前端3、总结 四、存入数据库1、引入 mysql 的依赖,mysql 驱动包2、创建数据库数据表3、调整上述后端代码3.1 封装数据库操作,和数据库建立连接3.2 调整后端代码 一、前端 <!DOCTYPE html> <ht…...
C++特殊类设计(不能被拷贝的类、只能在堆上创建对象的类、不能被继承的类、单例模式)
C特殊类设计 在实际应用中,可能需要设计一些特殊的类对象,如不能被拷贝的类、只能在堆上创建对象的类、只能在栈上创建对象的类、不能被继承的类、只能创建一个对象的类(单例模式)。 1. 不能被拷贝的类 拷贝只会发生在两个场景…...

【小白学机器学习34】用python进行基础的数据统计 mean,var,std,median,mode ,四分位数等
目录 1 用 numpy 快速求数组的各种统计量:mean, var, std 1.1 数据准备 1.2 直接用np的公式求解 1.3 注意问题 1.4 用print() 输出内容,显示效果 2 为了验证公式的后背,下面是详细的展开公式的求法 2.1 均值mean的详细 2.2 方差var的…...
安装 Docker(使用国内源)
一、安装Docker-ce 1、下载阿里云的repo源 [rootlocalhost ~]# yum install yum-utils -y && yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo && yum makecache # 尝试列出 docker-ce 的版本 [rootlocalh…...

Ajax学习笔记,第一节:语法基础
Ajax学习笔记,第一节:语法基础 一、概念 1、什么是Ajax 使用浏览器的 XMLHttpRequest 对象 与服务器通信2、什么是axios Axios是一个基于Promise的JavaScript库,支持在浏览器和Node.js环境中使用。相较于Ajax,Axios提供了更多…...

《用Python画蔡徐坤:艺术与编程的结合》
简介 大家好!今天带来一篇有趣的Python编程项目,用代码画出知名偶像蔡徐坤的形象。这个项目使用了Python的turtle库,通过简单的几何图形和精心设计的代码来展示艺术与编程的结合。 以下是完整的代码和效果介绍,快来试试看吧&…...

Unity中动态生成贴图并保存成png图片实现
实现原理: 要生成长x宽y的贴图,就是生成x*y个像素填充到贴图中,如下图: 如果要改变局部颜色,就是从x1到x2(x1<x2),y1到y2(y1<y2)这个范围做处理, 或者要想做圆形就是计算距某个点(x1,y1&…...

Mac配置maven环境及在IDEA中配置Maven
Mac配置maven环境及在IDEA中配置Maven 1. 介绍 Maven是一款广泛用于Java等JVM语言项目的工具,它以项目对象模型(POM)为基础进行项目管理,通过POM文件来定义项目信息和依赖关系。同时,它也是构建自动化工具࿰…...

Reactor 模式的理论与实践
1. 引言 1.1 什么是 Reactor 模式? Reactor 模式是一种用于处理高性能 I/O 的设计模式,专注于通过非阻塞 I/O 和事件驱动机制实现高并发性能。它的核心思想是将 I/O 操作的事件分离出来,通过事件分发器(Reactor)将事…...
vim 一次注释多行 的几种方法
在 Vim 中一次注释多行是一个常见操作。可以使用以下方法根据你的具体需求选择合适的方式: 方法 1:手动插入注释符 进入正常模式: 按 Esc 确保进入正常模式。 选择需要注释的多行: 移动到第一行,按下 Ctrlv 进入可视块…...

问题记录-Java后端
问题记录 目录 问题记录1.多数据源使用事务注意事项?2.mybatis执行MySQL的存储过程?3.springBoot加载不到nacos配置中心的配置问题4.服务器产生大量close_wait情况 1.多数据源使用事务注意事项? 问题:在springBoot项目中多表处理数…...

李春葆《数据结构》-课后习题代码题
一:假设不带权有向图采用邻接矩阵 g 存储,设计实现以下功能的算法: (1)求出图中每个顶点的入度。 代码: void indegree(MatGraph g){int i,j,n;printf("各个顶点的入度:\n");for(i…...

51c~C语言~合集2
我自己的原文哦~ https://blog.51cto.com/whaosoft/12652943 一、嵌入式开发中的C语言编译器 如果你和一个优秀的程序员共事,你会发现他对他使用的工具非常熟悉,就像一个画家了解他的画具一样。----比尔.盖茨1 不能简单的认为是个工具 嵌入式程序开发…...
【Python】构建事件驱动架构:用Python实现实时应用的高效系统
解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 事件驱动架构(Event-Driven Architecture,EDA)是一种基于事件流动进行系统设计的模式,广泛应用于游戏开发、实时监控和分布式系统中。它通过解耦事件的生产者和消费者,提升系统的可扩展性和灵活性。本文章从…...

Git(一)基本使用
目录 一、使用git -v 查看安装git版本 二、使用mkdir 创建一个文件,并使用 git init 在该目录下创建一个本地仓库, 三、通过git clone命令接入线上仓库 四、使用git status查看仓库状态信息 五、利用echo写入一个文件 并使用cat进行查看 【Linux】e…...
HarmonyOS应用开发者基础认证,Next版本发布后最新题库(10月8日更新题库未收录)
笔者会尽量找到答案的出处,力求答案准确无误。有些题目答案可能有错,也有一些笔者实在找不到出处,也不知道答案的,如果读者发现错误或有补充建议,欢迎评论或私信笔者。您的每一条反馈都是宝贵的,能够帮助笔…...

【PGCCC】Postgresql BRIN 索引原理
前言 postgresql 提供了块级索引(简称 BRIN),主要适用于类似时序数据之类的,有着天然的顺序,而且都是添加写的场景。相比于 btree 索引,它的体积小得多,非常适用于大数据量的场景。 原理 pos…...

腾讯云 AI 代码助手:产品研发过程的思考和方法论
一、文章摘要 本文将详细阐述 腾讯云 AI 代码助手的历史发展形态与产品整体架构,并从技术、研发方法论的角度分别阐述了产品的研发过程。 全文阅读约 5~8 分钟。 二、产品布局 AI 代码助手产品经历了三个时代的发展 第一代诸如 Eclipse、Jetbrains、V…...

Matlab 深度学习 PINN测试与学习
PINN 与传统神经网络的区别 与传统神经网络的不同之处在于,PINN 能够以微分方程形式纳入有关问题的先验专业知识。这些附加信息使 PINN 能够在给定的测量数据之外作出更准确的预测。此外,额外的物理知识还能在存在含噪测量数据的情况下对预测解进行正则…...
【Angular】async详解
在 Angular 中,async 关键字用于定义异步函数,通常与 await 一起使用来处理 Promise。这使得异步代码看起来更像同步代码,从而更容易理解和维护。 基本用法 定义异步函数:使用 async 关键字。等待 Promise 解析:使用…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...

HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...

el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...

ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...
掌握 HTTP 请求:理解 cURL GET 语法
cURL 是一个强大的命令行工具,用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中,cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...

企业大模型服务合规指南:深度解析备案与登记制度
伴随AI技术的爆炸式发展,尤其是大模型(LLM)在各行各业的深度应用和整合,企业利用AI技术提升效率、创新服务的步伐不断加快。无论是像DeepSeek这样的前沿技术提供者,还是积极拥抱AI转型的传统企业,在面向公众…...

云原生安全实战:API网关Envoy的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关 作为微服务架构的统一入口,负责路由转发、安全控制、流量管理等核心功能。 2. Envoy 由Lyft开源的高性能云原生…...