Servlet程序:表白墙
明确表白墙程序和服务器的交互过程
- 约定前端和后端,数据交互的格式
- 此处约定的是以json字符串的格式进行传输
1、点击提交,浏览器先把数据提交到服务器
2、页面加载,浏览器从服务器获取表白信息
3、把客户端传过来的数据存储到数据库中
持久化保存:把浏览器传递来的数据保存到服务器中进行持久化保存
前端页面代码
<!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;
}
</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="row">
xxx 对 xx 说 xxxx
</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('.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 message';
rowDiv.innerHTML = from + ' 对 ' + to + ' 说: ' + msg;
containerDiv.appendChild(rowDiv);
// 3. 清空之前的输入框内容
for (let input of inputs) {
input.value = '';
}
//[新增]给服务器发起一个post请求,把数据提交给服务器这边
//定义一个js对象
let body={
from:from,
to:to,
message:msg
};
let strBody = JSON.stringify(body);
$.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('.container');
for(let message of body){
let rowDiv = document.createElement('div');
rowDiv.className = 'row message';
rowDiv.innerHTML = message.from+ ' 对 ' + message.to + ' 说: ' + message.message;
containerDiv.appendChild(rowDiv)
}
}
});
</script>
</body>
</html>
后端代码
工具类Util
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;
/**
* Created with IntelliJ IDEA.
* Description:工具类 进行连接数据库的操作
*
* User: Wangduan
* Date: 2023-07-07
* Time: 4:10
*/
public class DBUtil{
//首先要有DataSource
private static DataSource dataSource = new MysqlDataSource();
static
{
((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/messagewall?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){
if(resultSet!=null){
try {
resultSet.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (preparedStatement!=null){
try{
preparedStatement.close();
}catch (Exception e){
e.printStackTrace();
}
}
if (connection!=null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
-
实例化DataSource对象,来更方便地进行与数据连接
-
在静态代码块中,对mysql的URL、用户名、密码进行配置
-
写连接和关闭的方法,方便在主类中调用
下面是在chatgpt中查询的:
MysqlDataSource
是MySQL提供的一个实现了DataSource
接口的类,用于与MySQL数据库建立连接。通过使用MysqlDataSource
,可以配置和管理与MySQL数据库相关的连接信息,如URL、用户名、密码等。- 通过
dataSource
就可以获取与MySQL数据库建立连接所需的信息,并在需要的时候通过dataSource.getConnection()
方法获取一个数据库连接对象。
在使用JDBC进行数据库操作时,使用DataSource
可以提供一种更灵活和可管理的方式来获取数据库连接。DataSource
是一个接口,代表了与数据库连接池进行交互的对象。
使用DataSource
的主要好处包括:
-
连接池管理:
DataSource
可以管理一组数据库连接,这些连接被预先创建并保存在连接池中。这样,在需要与数据库建立连接时,可以从连接池中获取一个可用的连接,而不需要每次都创建和销毁连接。这种连接池管理可以提高性能和可伸缩性,特别是在高并发的情况下。 -
连接配置和管理:
DataSource
可以统一管理数据库连接的配置信息,如数据库URL、用户名、密码、连接超时等。这样,可以集中管理这些配置信息,而不需要在每个连接获取的地方都进行硬编码。同时,可以通过调整连接池的配置参数来优化连接的使用和性能。 -
连接的重用和共享:使用
DataSource
可以实现连接的重用和共享。当一个连接不再需要时,可以将其释放回连接池中,以供其他请求复用。这样可以减少连接的创建和销毁开销,提高系统资源的利用率。 -
连接的生命周期管理:通过
DataSource
,可以定义连接的生命周期,包括连接的创建、销毁、空闲时的检查和回收等。这样可以确保连接的有效性和可靠性,并防止长时间占用连接而导致资源浪费。
总之,使用DataSource
可以简化和优化数据库连接的管理和使用,提供更好的性能、可靠性和可维护性。它提供了一种连接池的机制,允许开发人员更方便地获取和释放数据库连接,而无需手动管理连接的创建和销毁。同时,它还提供了连接配置的集中管理,使得数据库连接的使用更加灵活和可配置。
主类
- 导入所需的类和包。
- 创建一个
Message
类,使用@Getter
和@Setter
注解生成相应的 getter 和 setter 方法,用于表示消息对象。 MessageTwo
类继承自HttpServlet
,并使用@WebServlet
注解指定了它处理的 URL 路径为/message
。- 在
MessageTwo
类中定义了一个ObjectMapper
对象,用于进行 JSON 数据的序列化和反序列化。 doPost
方法用于处理 POST 请求,从请求中获取 JSON 数据,将其转换为Message
对象,并保存到数据库中。doGet
方法用于处理 GET 请求,从数据库中加载消息数据,并将其序列化为 JSON 格式返回给客户端。save
方法用于将Message
对象保存到数据库中,使用 JDBC 进行数据库操作。load
方法用于从数据库中加载消息数据,使用 JDBC 进行数据库查询操作。
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Getter;
import lombok.Setter;
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.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
/**
* Created with IntelliJ IDEA.
* Description:
* User: Wangduan
* Date: 2023-07-07
* Time: 4:03
*/
@Getter
@Setter
class Message{
private String from;
private String to;
private String message;
}
@WebServlet("/message")
public class MessageTwo extends HttpServlet {
//List<Message> messageList = new ArrayList<>();
ObjectMapper objectMapper=new ObjectMapper();
//像服务器提交请求
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取请求的字符流
InputStream inputStream = req.getInputStream();
//把字符流构造成类对象
Message message = objectMapper.readValue(inputStream,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");
List<Message> messageList = load();
objectMapper.writeValue(resp.getWriter(),messageList);
}
public void save(Message message){
//提供一对方法,往jdbc中添加数据
Connection connection = null;
PreparedStatement preparedStatement=null;
//1、先建立连接
try {
connection = DBUtil.getConnection();
//2、编写sql语句
String sql = "insert into message values(?,?,?)";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1,message.getFrom());
preparedStatement.setString(2,message.getTo());
preparedStatement.setString(3,message.getMessage());
//3、执行sql语句
preparedStatement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}finally {
//4、关闭连接
DBUtil.close(connection,preparedStatement,null);
}
}
public List<Message> load(){
List<Message> messageList = new ArrayList<>();
Connection connection =null;
PreparedStatement preparedStatement = null;
ResultSet resultSet=null;
//从服务器获取到数据库中的数据
try {
//1、建立连接
connection = DBUtil.getConnection();
//2、构造Sql语句
String sql = "select *from message";
preparedStatement = connection.prepareStatement(sql);
//3、执行sql语句
resultSet = preparedStatement.executeQuery();
//4、遍历查询
while(resultSet.next()){
Message message = new Message();
message.setFrom(resultSet.getString("from"));
message.setTo(resultSet.getString("to"));
message.setMessage(resultSet.getString("message"));
messageList.add(message);
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
DBUtil.close(connection,preparedStatement,resultSet);
}
return messageList;
}
}
1、★★★executeQuery()
和 executeUpdate()
是 JDBC 中用于执行不同类型操作的方法。
-
executeQuery()
方法:- 用于执行 SELECT 查询操作。
- 返回一个
ResultSet
对象,该对象包含查询结果集的数据。 - 适用于从数据库中获取数据,可以使用
ResultSet
提供的方法来访问和处理查询结果的数据。 - 该方法不返回受影响的行数,因为它只用于查询操作,不修改数据库的内容。
-
executeUpdate()
方法:- 用于执行 INSERT、UPDATE 或 DELETE 等更新操作。
- 返回一个整数值,表示受影响的行数,即数据库中受到影响的记录数量。
- 适用于修改数据库中的数据,如插入新记录、更新现有记录或删除记录。
- 该方法不返回查询结果集,因为它主要用于更新操作,而不是从数据库中获取数据。
需要注意的是,这两个方法的使用场景是不同的,根据操作类型选择合适的方法。如果需要执行查询操作并获取查询结果集,应该使用 executeQuery()
方法;如果需要执行更新操作并获取受影响的行数,应该使用 executeUpdate()
方法。
同时,需要确保在调用这些方法之前,已经设置了正确的参数值,并且相关的 PreparedStatement
对象和数据库连接都是有效的。根据具体的需求和操作类型,选择适当的方法来执行数据库操作。
2、在你提供的代码中,preparedStatement.setString()
方法用于设置 PreparedStatement
对象中的参数值。
具体来说,setString(int parameterIndex, String value)
方法用于将字符串值设置到预编译的 SQL 语句中的指定参数位置。在你的代码中,你使用了 message.getFrom()
、message.getTo()
和 message.getMessage()
方法分别获取 message
对象中的 “from”、“to” 和 “message” 属性的值,并将它们作为参数值传递给 setString()
方法。
例如,preparedStatement.setString(1, message.getFrom())
表示将 message.getFrom()
的返回值设置为预编译的 SQL 语句中的第一个参数的值。同样地,preparedStatement.setString(2, message.getTo())
和 preparedStatement.setString(3, message.getMessage())
分别设置了第二个和第三个参数的值。
通过这样的设置,当执行预编译的 SQL 语句时,参数的值会被替换为相应的属性值,从而构建出最终的可执行的 SQL 语句。
需要确保在调用 preparedStatement.setString()
方法之前,已经创建了有效的 PreparedStatement
对象,并且相关的属性和方法在 Message
类中都有正确的定义和实现。同时,还要确保 message
对象中的属性值是有效的,并可以正确地通过 getFrom()
、getTo()
和 getMessage()
方法获取到。
3、在你提供的代码中,resultSet.getString("from")
是用于从结果集中获取 “from” 列的值,并将其设置到 message
对象的属性中。
具体来说,resultSet.getString(String columnLabel)
方法用于从结果集中获取指定列(字段)的字符串值。在你的代码中,你通过传递 “from” 给 getString()
方法,从结果集中获取 “from” 列的值作为一个字符串。
然后,你使用 message.setFrom()
方法将获取到的字符串值设置到 message
对象的 “from” 属性中,以便后续的处理和使用。
需要注意的是,确保在调用 resultSet.getString("from")
之前,已经执行了查询操作,并将结果集移到了有效的位置,以便能够正确获取列的值。同时,确保 message
对象和相关的类定义中有一个合适的属性和设置方法来存储和获取 “from” 列的值。
pom.xml
<?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>messagewallReview</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- 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>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.14.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.14.8</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.49</version>
</dependency>
</dependencies>
</project>
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>