【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;@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、总结

  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<>();// 负责实现让服务器从客户端拿数据@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;}
}

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

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

相关文章

WebRTC音视频同步原理与实现详解(上)

第一章、RTP时间戳与NTP时间戳 1.1 RTP时间戳 时间戳&#xff0c;用来定义媒体负载数据的采样时刻&#xff0c;从单调线性递增的时钟中获取&#xff0c;时钟的精度由 RTP 负载数据的采样频率决定。 音频和视频的采样频率是不一样的&#xff0c;一般音频的采样频率有 8KHz、…

蓝桥杯每日真题 - 第21天

题目&#xff1a;(空间) 题目描述&#xff08;12届 C&C B组A题&#xff09; 解题思路&#xff1a; 转换单位&#xff1a; 内存总大小为 256MB&#xff0c;换算为字节&#xff1a; 25610241024268,435,456字节 计算每个整数占用空间&#xff1a; 每个 32 位整数占用…

利用Python爬虫获得1688按关键字搜索商品:技术解析

在电商领域&#xff0c;1688作为中国领先的B2B电商平台&#xff0c;其商品搜索功能对于商家来说具有极高的价值。通过获取搜索结果&#xff0c;商家可以更好地了解市场趋势&#xff0c;优化产品标题&#xff0c;提高搜索排名。本文将介绍如何使用Python编写爬虫&#xff0c;以获…

三、计算机视觉_05MTCNN人脸检测

0、人脸识别流程概述 人脸识别流程包括两个主要步骤&#xff1a; Step1&#xff1a;人脸检测&#xff0c;确保我们处理的是正确的人脸区域 Step2&#xff1a;身份识别&#xff0c;确定该人脸的身份 0.1 人脸检测 人脸检测是从图像中定位人脸并抠出人脸区域的过程&#xff…

「Chromeg谷歌浏览器/Edge浏览器」篡改猴Tempermongkey插件的安装与使用

1. 谷歌浏览器安装及使用流程 1.1 准备篡改猴扩展程序包。 因为谷歌浏览器的扩展商城打不开&#xff0c;所以需要准备一个篡改猴压缩包。 其他浏览器只需打开扩展商城搜索篡改猴即可。 没有压缩包的可以进我主页下载。 也可直接点击下载&#xff1a;Chrome浏览器篡改猴(油猴…

STM32F103C8T6实时时钟RTC

目录 前言 一、RTC基本硬件结构 二、Unix时间戳 2.1 unix时间戳定义 2.2 时间戳与日历日期时间的转换 2.3 指针函数使用注意事项 ​三、RTC和BKP硬件结构 四、驱动代码解析 前言 STM32F103C8T6外部低速时钟LSE&#xff08;一般为32.768KHz&#xff09;用的引脚是PC14和PC…

【JavaEE初阶】多线程初阶下部

文章目录 前言一、volatile关键字volatile 能保证内存可见性 二、wait 和 notify2.1 wait()方法2.2 notify()方法2.3 notifyAll()方法2.4 wait 和 sleep 的对比&#xff08;面试题&#xff09; 三、多线程案例单例模式 四、总结-保证线程安全的思路五、对比线程和进程总结 前言…

【人工智能】Python在机器学习与人工智能中的应用

Python因其简洁易用、丰富的库支持以及强大的社区&#xff0c;被广泛应用于机器学习与人工智能&#xff08;AI&#xff09;领域。本教程通过实用的代码示例和讲解&#xff0c;带你从零开始掌握Python在机器学习与人工智能中的基本用法。 1. 机器学习与AI的Python生态系统 Pyth…

“iOS profile文件与私钥证书文件不匹配”总结打ipa包出现的问题

目录 文件和证书未加载或特殊字符问题 证书过期或Profile文件错误 确认开发者证书和私钥是否匹配 创建证书选择错误问题 申请苹果 AppId时勾选服务不全问题 ​总结 在上线ios平台的时候&#xff0c;在Hbuilder中打包遇见了问题&#xff0c;生成ipa文件时候&#xff0c;一…

element-ui 中el-calendar 日历插件获取显示的第一天和最后一天【原创】

需要获取el-calendar 日历组件上的第1天和最后一天。可以通过document.querySelector()方法进行获取dom元素中的值&#xff0c;这样避免计算问题。 获取的过程中主要有两个难点&#xff0c;第1个是处理上1月和下1月的数据&#xff0c;第2个是跨年的数据。 直接贴代码&#xff…

JavaScript的基础数据类型

一、JavaScript中的数组 定义 数组是一种特殊的对象&#xff0c;用于存储多个值。在JavaScript中&#xff0c;数组可以包含不同的数据类型&#xff0c;如数字、字符串、对象、甚至其他数组。数组的创建有两种常见方式&#xff1a; 字面量表示法&#xff1a;let fruits [apple…

5.5 W5500 TCP服务端与客户端

文章目录 1、TCP介绍2、W5500简介2.1 关键函数socketlistensendgetSn_RX_RSRrecv自动心跳包检测getSn_SR 1、TCP介绍 TCP 服务端&#xff1a; 创建套接字[socket]&#xff1a;服务器首先创建一个套接字&#xff0c;这是网络通信的端点。绑定套接字[bind]&#xff1a;服务器将…

Android 15 版本更新及功能介绍

Android 15版本时间戳 Android 15,代号Vanilla Ice Cream(香草冰淇淋),是当下 Android 移动操作系统的最新主要版本。 开发者预览阶段:2024年2月,谷歌发布了Android 15的第一个开发者预览版本(DP1),这标志着新系统开发的正式启动。随后,在3月和4月,谷歌又相继推出了D…

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

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

红队笔记--W1R3S、JARBAS、SickOS、Prime打靶练习记录

W1R3S(思路为主) 信息收集 首先使用nmap探测主机&#xff0c;得到192.168.190.147 接下来扫描端口&#xff0c;可以看到ports文件保存了三种格式 其中.nmap和屏幕输出的一样&#xff1b;xml这种的适合机器 nmap -sT --min-rate 10000 -p- 192.168.190.147 -oA nmapscan/ports…

学习笔记|MaxKB对接本地大模型时,选择Ollma还是vLLM?

在使用MaxKB开源知识库问答系统的过程中&#xff0c;除了对接在线大模型&#xff0c;一些用户出于资源配置、长期使用成本、安全性等多方面考虑&#xff0c;还在积极尝试通过Ollama、vLLM等模型推理框架对接本地离线大模型。而在用户实践的过程中&#xff0c;经常会对候选的模型…

计算机网络八股整理(一)

计算机网络八股文整理 一&#xff1a;网络模型 1&#xff1a;网络osi模型和tcp/ip模型分别介绍一下 osi模型是国际标准的网络模型&#xff0c;它由七层组成&#xff0c;从上到下分别是&#xff1a;应用层&#xff0c;表示层&#xff0c;会话层&#xff0c;传输层&#xff0c;…

Spring Boot教程之五:在 IntelliJ IDEA 中运行第一个 Spring Boot 应用程序

在 IntelliJ IDEA 中运行第一个 Spring Boot 应用程序 IntelliJ IDEA 是一个用 Java 编写的集成开发环境 (IDE)。它用于开发计算机软件。此 IDE 由 Jetbrains 开发&#xff0c;提供 Apache 2 许可社区版和商业版。它是一种智能的上下文感知 IDE&#xff0c;可用于在各种应用程序…

单片机学习笔记 9. 8×8LED点阵屏

更多单片机学习笔记&#xff1a;单片机学习笔记 1. 点亮一个LED灯单片机学习笔记 2. LED灯闪烁单片机学习笔记 3. LED灯流水灯单片机学习笔记 4. 蜂鸣器滴~滴~滴~单片机学习笔记 5. 数码管静态显示单片机学习笔记 6. 数码管动态显示单片机学习笔记 7. 独立键盘单片机学习笔记 8…

vue 预览pdf 【@sunsetglow/vue-pdf-viewer】开箱即用,无需开发

sunsetglow/vue-pdf-viewer 开箱即用的pdf插件sunsetglow/vue-pdf-viewer, vue3 版本 无需多余开发&#xff0c;操作简单&#xff0c;支持大文件 pdf 滚动加载&#xff0c;缩放&#xff0c;左侧导航&#xff0c;下载&#xff0c;页码&#xff0c;打印&#xff0c;文本复制&…