先提供一个之前写过的表白墙的前端代码:
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>
<body>
<style>
.container {
width: 400px;
/* margin 外边距. 第一个数字上下外边距, 第二个数字表示水平外边距. 如果水平设置成 auto 表示元素就水平居中~~ */
margin: 0 auto;
}
h1 {
text-align: center;
}
p {
text-align: center;
color: #666;
}
.row {
height: 40px;
display: flex;
/* 水平居中 */
justify-content: center;
/* 垂直居中 */
align-items: center;
}
.row span {
width: 100px;
}
.row input {
width: 200px;
height: 30px;
}
.row button {
width: 306px;
height: 40px;
color: white;
background: orange;
border: none;
}
.row button:active {
background-color: #666;
}
style>
<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>提交button>
div>
div>
<script>
let container = document.querySelector('.container');
let button = document.querySelector('button');
button.onclick = function() {
// 1. 获取到输入框的内容
let inputs = document.querySelectorAll('input');
let from = inputs[0].value;
let to = inputs[1].value;
let message = inputs[2].value;
if (from == '' || to == '' || message == '') {
alert('当前输入框内容为空!');
return;
}
console.log(from + ", " + to + ", " + message);
// 2. 能够构造出新的 div, 用来保存用户提交的内容
let rowDiv = document.createElement('div');
rowDiv.className = 'row';
rowDiv.innerHTML = from + " 对 " + to + " 说: " + message;
container.appendChild(rowDiv);
// 3. 提交完之后, 清空输入框的内容
for (let i = 0; i < inputs.length; i++) {
inputs[i].value = '';
}
}
script>
body>
html>
当我们输入一些内容:
但是一旦刷新后,所有数据都没了!
因为当前的数据只是在内存中存储的!关了再开,内存中原来的数据就没了 ~~
这样显然不能达到我们的预期。解决方案:
需要让用户留言的数据能够在服务器这边保存,就可以保证即使页面关闭,数据也不会丢失!!!
参考博客:https://blog.csdn.net/yyhgo_/article/details/128468738?spm=1001.2014.3001.5501
创建一个新的 Maven 项目!(引入 Servlet 依赖 和 Jackson 依赖)
pom.xml:
<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.0modelVersion>
<groupId>org.examplegroupId>
<artifactId>MessageWallartifactId>
<version>1.0-SNAPSHOTversion>
<properties>
<maven.compiler.source>8maven.compiler.source>
<maven.compiler.target>8maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>3.1.0version>
<scope>providedscope>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>2.13.4version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.49version>
dependency>
dependencies>
project>
把之前实现的表白墙前端页面文件拷贝到 webapp 目录中!
首先创建一个 Message 类:
public class Message {
private String from;
private String to;
private String message;
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
MessageServlet 类:
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;
@WebServlet("/message")
public class MessageServlet extends HttpServlet {
// 这个对象在多个方法中都需要使用
private ObjectMapper objectMapper = new ObjectMapper();
private List<Message> messageList = new ArrayList<>();
// 负责让页面获取到数据
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
// 提交数据
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取到 body 中的数据并解析
Message message = objectMapper.readValue(req.getInputStream(), Message.class);
// 把这个 message 保存一下. 简单的办法就是保存在内存中.
messageList.add(message);
resp.setStatus(200);
System.out.println("提交数据成功: from=" + message.getFrom()
+ ", to=" + message.getTo() + ", message=" + message.getMessage());
}
}
补充 第4步:
点击发送按钮,给服务器发个 post 请求 ~~
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>
<body>
<style>
.container {
width: 400px;
/* margin 外边距. 第一个数字上下外边距, 第二个数字表示水平外边距. 如果水平设置成 auto 表示元素就水平居中~~ */
margin: 0 auto;
}
h1 {
text-align: center;
}
p {
text-align: center;
color: #666;
}
.row {
height: 40px;
display: flex;
/* 水平居中 */
justify-content: center;
/* 垂直居中 */
align-items: center;
}
.row span {
width: 100px;
}
.row input {
width: 200px;
height: 30px;
}
.row button {
width: 306px;
height: 40px;
color: white;
background: orange;
border: none;
}
.row button:active {
background-color: #666;
}
style>
<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>提交button>
div>
div>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js">script>
<script>
let container = document.querySelector('.container');
let button = document.querySelector('button');
button.onclick = function() {
// 1. 获取到输入框的内容
let inputs = document.querySelectorAll('input');
let from = inputs[0].value;
let to = inputs[1].value;
let message = inputs[2].value;
if (from == '' || to == '' || message == '') {
alert('当前输入框内容为空!');
return;
}
console.log(from + ", " + to + ", " + message);
// 2. 能够构造出新的 div, 用来保存用户提交的内容
let rowDiv = document.createElement('div');
rowDiv.className = 'row';
rowDiv.innerHTML = from + " 对 " + to + " 说: " + message;
container.appendChild(rowDiv);
// 3. 提交完之后, 清空输入框的内容
for (let i = 0; i < inputs.length; i++) {
inputs[i].value = '';
}
// 4. 点击发送按钮, 给服务器发个 post 请求.
let data = {
from: from,
to: to,
message: message
};
$.ajax({
type: 'post',
url: 'message',
// url: '/java105/message',
// 这里放的是 body 的内容
data: JSON.stringify(data),
contentType: "application/json; charset=utf8",
success: function(body) {
console.log("提交数据成功");
}
});
}
script>
body>
html>
2)通过 表白墙.html 发送请求
访问 http://127.0.0.1:8080/MessageWall/表白墙.html:
MessageServlet 类:
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;
@WebServlet("/message")
public class MessageServlet extends HttpServlet {
// 这个对象在多个方法中都需要使用
private ObjectMapper objectMapper = new ObjectMapper();
private List<Message> messageList = new ArrayList<>();
// 负责让页面获取到数据
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// body 就是响应的 body 内容 (json 数组).
// jquery 非常智能的帮我们把 json 数组给解析成了 js 对象数组
// 但是有个前提条件, 就是响应的 Content-Type 得是 application/json
resp.setContentType("application/json; charset=utf8");
// 把 messageList 转成 json 字符串,并且返回给页面就行了.
resp.getWriter().write(objectMapper.writeValueAsString(messageList));
}
// 提交数据
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取到 body 中的数据并解析
Message message = objectMapper.readValue(req.getInputStream(), Message.class);
// 把这个 message 保存一下. 简单的办法就是保存在内存中.
messageList.add(message);
resp.setStatus(200);
System.out.println("提交数据成功: from=" + message.getFrom()
+ ", to=" + message.getTo() + ", message=" + message.getMessage());
}
}
什么时候来发这个请求呢?
页面加载的时候,我们就希望进行读档操作!
==================================================================================
在 html 文件中,哪里是页面加载的时候呢?
直接写在 script 标签里的代码,都是在页面加载的时候执行的!
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>
<body>
<style>
.container {
width: 400px;
/* margin 外边距. 第一个数字上下外边距, 第二个数字表示水平外边距. 如果水平设置成 auto 表示元素就水平居中~~ */
margin: 0 auto;
}
h1 {
text-align: center;
}
p {
text-align: center;
color: #666;
}
.row {
height: 40px;
display: flex;
/* 水平居中 */
justify-content: center;
/* 垂直居中 */
align-items: center;
}
.row span {
width: 100px;
}
.row input {
width: 200px;
height: 30px;
}
.row button {
width: 306px;
height: 40px;
color: white;
background: orange;
border: none;
}
.row button:active {
background-color: #666;
}
style>
<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>提交button>
div>
div>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js">script>
<script>
let container = document.querySelector('.container');
let button = document.querySelector('button');
button.onclick = function() {
// 1. 获取到输入框的内容
let inputs = document.querySelectorAll('input');
let from = inputs[0].value;
let to = inputs[1].value;
let message = inputs[2].value;
if (from == '' || to == '' || message == '') {
alert('当前输入框内容为空!');
return;
}
console.log(from + ", " + to + ", " + message);
// 2. 能够构造出新的 div, 用来保存用户提交的内容
let rowDiv = document.createElement('div');
rowDiv.className = 'row';
rowDiv.innerHTML = from + " 对 " + to + " 说: " + message;
container.appendChild(rowDiv);
// 3. 提交完之后, 清空输入框的内容
for (let i = 0; i < inputs.length; i++) {
inputs[i].value = '';
}
// 4. 点击发送按钮, 给服务器发个 post 请求.
let data = {
from: from,
to: to,
message: message
};
$.ajax({
type: 'post',
url: 'message',
// url: '/java105/message',
// 这里放的是 body 的内容
data: JSON.stringify(data),
contentType: "application/json; charset=utf8",
success: function(body) {
console.log("提交数据成功");
}
});
}
// 直接写在 script 标签里的代码, 都是在页面加载的时候执行的.
// 来获取服务器的数据
function getMessages() {
$.ajax({
type: 'get' ,
url: 'message',
success: function(body) {
// body 就是响应的 body 内容 (json 数组).
// jquery 非常智能的帮我们把 json 数组给解析成了 js 对象数组
// 但是有个前提条件, 就是响应的 Content-Type 得是 application/json
let container = document.querySelector('.container');
// 观察 html, .row 都是在 .container 中存放的,所以获取到.container,把新的 .row 都加进去!
for (let i = 0; i < body.length; i++) {
let message = body[i];
// 根据这个元素构造一个 div.row, 来容纳数据
//
// 黑猫 对 白猫 说: 喵
//
let row = document.createElement('div');
row.className = 'row';
row.innerHTML = message.from + " 对 " + message.to + " 说: " + message.message;
container.appendChild(row);
}
}
});
}
getMessages();
script>
body>
html>
function 中的参数 body 就是响应的 body 内容 (json 数组)!
jquery 非常智能地帮我们把 json 数组给解析成了 js 对象数组!但是有个前提条件,就是响应的 Content-Type 得是 application/json 格式!
如果 jquery 没做这个事情,就需要使用 JSON.parse 来完成 ~~
2)访问 http://127.0.0.1:8080/MessageWall/表白墙.html
此时提交数据后,无论怎样刷新,数据仍然保留!!!成功 ~
服务器重启,原有的数据就没了 ~~
我们这个程序目前最大的问题就是:数据在内存中,服务器一旦重启就没了。我们需要让数据在数据库中持久化保存!JDBC!!!
设计有几张表,表里有什么 ~~
1.message 表;
2.三个列:from、to、message
注意: from 等关键字,需要加上反引号
``
!!!
Java的JDBC编程 博客链接:https://blog.csdn.net/yyhgo_/article/details/128061324?spm=1001.2014.3001.5501
通过数据库来 存 / 读 数据,就不再需要 ArrayList 了 ~~
主要是两个方法:
private void save(Message message)
:把数据保存到数据库中private List
:从数据库查询数据load()
完整代码:
public class Message {
private String from;
private String to;
private String message;
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
import javax.sql.DataSource;
// 使用这个类来封装 DataSource 的单例
public class DBUtil {
private static volatile DataSource dataSource = null;
private DBUtil() {}
public static DataSource getDataSource() {
if (dataSource == null) {
synchronized (DBUtil.class) {
if (dataSource == null) {
dataSource = new MysqlDataSource();
((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/java105?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");
// 数据库密码.
((MysqlDataSource)dataSource).setPassword("632yyh..");
}
}
}
return dataSource;
}
}
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 javax.sql.DataSource;
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;
@WebServlet("/message")
public class MessageServlet extends HttpServlet {
// 这个对象在多个方法中都需要使用
private ObjectMapper objectMapper = new ObjectMapper();
// 负责让页面获取到数据
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 显式声明当前的响应数据格式 不要让客户端去猜!!!
resp.setContentType("application/json; charset=utf8");
// 把 messageList 转成 json 字符串, 并且返回给页面就行了.
List<Message> messageList = null;
try {
messageList = load();
} catch (SQLException e) {
e.printStackTrace();
}
resp.getWriter().write(objectMapper.writeValueAsString(messageList));
}
// 提交数据
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取到 body 中的数据并解析
Message message = objectMapper.readValue(req.getInputStream(), Message.class);
// 把这个 message 保存一下. 简单的办法就是保存在内存中.
// messageList.add(message);
try {
save(message);
} catch (SQLException e) {
e.printStackTrace();
}
resp.setStatus(200);
System.out.println("提交数据成功: from=" + message.getFrom()
+ ", to=" + message.getTo() + ", message=" + message.getMessage());
}
private void save(Message message) throws SQLException {
// 把数据保存到数据库中
// 1. 先有一个数据源
DataSource dataSource = DBUtil.getDataSource();
// 2. 建立连接
Connection connection = dataSource.getConnection();
// 3. 构造 SQL
String sql = "insert into message values(?, ?, ?)";
PreparedStatement statement = connection.prepareStatement(sql);
statement.setString(1, message.getFrom());
statement.setString(2, message.getTo());
statement.setString(3, message.getMessage());
// 4. 执行 SQL
int ret = statement.executeUpdate();
System.out.println("ret = " + ret);
// 5. 关闭连接
statement.close();
connection.close();
}
private List<Message> load() throws SQLException {
// 从数据库查询数据
// 1. 先有一个数据源
DataSource dataSource = DBUtil.getDataSource();
// 2. 建立连接
Connection connection = dataSource.getConnection();
// 3. 构造 SQL
String sql = "select * from message";
PreparedStatement statement = connection.prepareStatement(sql);
// 4. 执行 SQL
ResultSet resultSet = statement.executeQuery();
// 5. 遍历结果集合
List<Message> messageList = new ArrayList<>();
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);
}
// 6. 关闭连接
statement.close();
connection.close();
return messageList;
}
}
细节:
数据源不需要创建多份,因此可以使用单例模式:单独构造一个 类DBUtil !
Servlet 代码中是否涉及到 多线程/线程安全 的问题呢?
Servlet 写的是一个服务器。同一时刻,可能要处理多个客户端的请求!
一旦同时有多个客户端都发来请求,服务器势必就需要同时处理多个请求。Tomcat 内部正是使用了多线程的方式来处理的 ~~
2)访问 http://127.0.0.1:8080/MessageWall/表白墙.html
此时提交数据后,无论怎样刷新,还是重新启动服务器,数据仍然保留!!!成功 ~
完!提前祝大家 2023 新年快乐!~~