目录
一、Servlet API 详解
1. HttpServletRequest
1.1 HttpServletRequest 方法
1.2 getParameter
2.HttpServletResponse
2.1 HttpServletResponse 方法
2.2 代码示例: 设置状态码
2.3 代码示例: 重定向
二、表白墙
1.准备工作
2.约定前后端交互接口
2.1 接口一:页面获取当前所有的留言消息
2.2 接口二:提交新消息给服务器
3.调整前端页面代码
4.数据持久化
4.1 数据存入数据库
🌈上节 Servlet 我们学习了 Tomcat 提供的 API;并且编写一个 Hello World 基本步骤:1️⃣创建项目(maven)2️⃣引入依赖(servler)3️⃣创建目录4️⃣编写代码(webapp/WEB-INF/web.xml)5️⃣打包程序(waven package)6️⃣部署程序(把 war 拷贝到 webapps 目录中)7️⃣验证代码;最后我们学习了 Servlet 中的三个核心类
一、Servlet API 详解
1. HttpServletRequest
HttpServletRequest 是一个 HTTP 请求:Tomcat 通过 Socket API 读取 HTTP 请求(字符串),就会按照 HTTP 协议的格式把字符串解析成 HttpServletRequest
1.1 HttpServletRequest 方法
String getProtocol()
|
返回请求协议的名称和版本
|
String getMethod()
|
返回请求的
HTTP
方法的名称,例如,
GET
、
POST
或
PUT
|
String getRequestURI()
|
从协议名称直到
HTTP
请求的第一行的查询字符串中,返回该请求的 URL
的一部分
|
String getContextPath()
|
返回指示请求上下文的请求
URI
部分
|
String getQueryString()
|
返回包含在路径后的请求
URL
中的查询字符串
|
Enumeration getParameterNames()
|
返回一个
String
对象的枚举,包含在该请求中包含的参数的名称
|
String getParameter(String name)
|
以字符串形式返回请求参数的值,或者如果参数不存在则返回 null
|
String[] getParameterValues(String name)
|
返回一个字符串对象的数组,包含所有给定的请求参数的值,如果参数不存在则返回 null
|
Enumeration getHeaderNames()
|
返回一个枚举,包含在该请求中包含的所有的头名
|
String getHeader(String name)
|
以字符串形式返回指定的请求头的值
|
String getCharacterEncoding()
|
返回请求主体中使用的字符编码的名称
|
String getContentType()
|
返回请求主体的
MIME
类型,如果不知道类型则返回
null
|
int getContentLength()
|
以字节为单位返回请求主体的长度,并提供输入流,或者如果长度未知则返回 -1
|
InputStream getInputStream()
|
用于读取请求的
body
内容
.
返回一个
InputStream
对象
|
1️⃣ 其中 getRequestURI 不是 URL:URL 唯一资源定位符;URI 唯一资源标识符
2️⃣ query string 查询字符串:例如 http://餐厅:18/熏肉大饼?葱=少放,其中 葱=少放 就是查询字符串
3️⃣Enumeration getParameterNames() 和 String getParameter(String name) 是获取请求中的字符串:上述中 query string 中的键值对
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//继承 HttpServlet
@WebServlet("/showRequest")
public class ShowRequest extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
StringBuilder result = new StringBuilder();
result.append(req.getProtocol());
result.append("<br>");
result.append(req.getMethod());
result.append("<br>");
result.append(req.getRequestURI());
result.append("<br>");
result.append(req.getQueryString());
result.append("<br>");
result.append(req.getContextPath());
result.append("<br>");
//在响应中设置上 body 的类型,方便浏览器进行解析
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write(result.toString());
}
}
1.2 getParameter
getParameter 是最常用的 API 之一,是前端和后端传递数据非常常见的需求
1️⃣通过 query string 传递
约定:前端通过 query string 传递 username 和 password
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;
@WebServlet("/getParameter")
public class GetParameter extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//前端通过 url 的 query string 传递 username 和 password 两个属性
String username = req.getParameter("username");
if (username == null) {
System.out.println("username 这个 key 在 query string 中不存在!");
}
String password = req.getParameter("password");
if (password == null) {
System.out.println("password 这个 key 在 query string 中不存在!");
}
System.out.println("username" + username + ", password" + password);
resp.getWriter().write("ok");
}
}
在 URL 中 query string 如果是包含 中文/特殊字符,务必要使用 urlencode 的方式转码;如果是直接写 中文/特殊字符,就会存在很大风险;如果不转码,在有些浏览器/http服务器下对中文支持不好的花,会出现问题
2️⃣通过 body (from) 传递
相当于 body 里存的数据的格式,和 query string 一样,但是 Content-Type 是 application/x-www-form-urlencoded,此时也是通过 getParameter 来获取到键值对
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;
@WebServlet("/getParameter")
public class GetParameter extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//给请求设置编码方式
req.setCharacterEncoding("utf8");
//前端通过 body,以 form 表单的格式,把 username 和 password 传给服务器
String username = req.getParameter("username");
String password = req.getParameter("password");
if (username == null) {
System.out.println("username 这个 key 在 body 中不存在!");
}
if (password == null) {
System.out.println("password 这个 key 在 body 中不存在!");
}
System.out.println("username" + username + ", password" + password);
resp.getWriter().write("ok");
}
}
由于是 post 请求,在网页中不好表现,我们打开 postman
3️⃣通过 body (json) 传递(最常用的传递方式)
json 也是键值对格式的数据,但是 Servlet 自身没有内置 json 解析功能,因此就需要借助其他第三方库;用来处理 json 的第三方库有很多,常见的如 fastjson、gson、jackson...,我们使用 jackson 来解析
引入依赖:
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.0</version>
</dependency>
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;
class User {
public String username;
public String password;
}
@WebServlet("/json")
public class JsonServlet extends HttpServlet {
// 使用 jackson, 最核心的对象就是 ObjectMapper
// 通过这个对象, 就可以把 json 字符串解析成 java 对象; 也可以把一个 java 对象转成一个 json 格式字符串.
private ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 通过 post 请求的 body 传递过来一个 json 格式的字符串.
User user = objectMapper.readValue(req.getInputStream(), User.class);
System.out.println("username=" + user.username + ", password=" + user.password);
resp.getWriter().write("ok");
}
}
readValue 里面做的事情:
- 解析 json 字符串,转换成若干个键值对
- 根据第二个参数 User.class(.class 是类对象,就是这个类的图纸),去找到 User 里的所有的 public 的属性(或者有 public getter setter 的属性),依次遍历......
- 遍历属性,根据属性的名字取上述准备好的键值对里查询,看看这个属性名字是否存在对应的 value ,如果存在就把 value 复制到该属性中
2.HttpServletResponse
HttpServletResponse 表示一个 HTTP 响应
Servlet 中的 doXXX 方法的目的就是根据请求计算得到相应, 然后把响应的数据设置到 HttpServletResponse 对象中;然后 Tomcat 就会把这个HttpServletResponse 对象按照 HTTP 协议的格式, 转成一个字符串, 并通过 Socket 写回给浏览器.
2.1 HttpServletResponse 方法
void setStatus(int sc)
|
为该响应设置状态码
|
void setHeader(String name, String value)
|
设置一个带有给定的名称和值的
header.
如果
name
已经存在
, 则覆盖旧的值
|
void addHeader(String name, String value)
|
添加一个带有给定的名称和值的
header.
如果
name
已经存在
, 不覆盖旧的值,
并列添加新的键值对
|
void setContentType(String type)
|
设置被发送到客户端的响应的内容类型
|
void setCharacterEncoding(String charset)
|
设置被发送到客户端的响应的字符编码(
MIME
字符集)例如, UTF-8
|
void sendRedirect(String location)
|
使用指定的重定向位置
URL
发送临时重定向响应到客户端
|
PrintWriter getWriter()
|
用于往
body
中写入文本格式数据
|
OutputStream getOutputStream()
|
用于往
body
中写入二进制格式数据
|
2.2 代码示例: 设置状态码
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;
@WebServlet("/status")
public class StatusServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setStatus(404);
resp.setContentType("text/html; charset=utf8");
resp.getWriter().write("返回 404 响应!");
}
}
抓包结果:
2.3 代码示例: 自动刷新
通过 header 实现自动刷新效果:给 HTTP 响应中,设置 Refresh——时间
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;
//通过 header 实现自动刷新效果:给 HTTP 响应中,设置 Refresh——时间
@WebServlet("/refresh")
public class RefreshServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,IOException {
// 每隔 1s 自动刷新一次.
resp.setHeader("Refresh", "1");
resp.getWriter().write("time=" + System.currentTimeMillis());
}
}
2.3 代码示例: 重定向
代码案例:用户访问这个供暖这个路径的时候,自动重定向到搜狗主页
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;
@WebServlet("/redirect")
public class RedirectServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 用户访问这个路径的时候, 自动重定向到 搜狗主页 .
//resp.setStatus(302);
//resp.setHeader("Location", "https://www.sogou.com");
resp.sendRedirect("https://www.sogou.com");
}
}
部署程序, 通过 URL http://127.0.0.1:8080/hello_servlet/redirectServlet 访问, 可以看到, 页面自动跳转到 搜狗主页 了.
抓包结果:
二、表白墙
表白墙前端页面代码:message.html
<!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>
<!-- 引入 jquery -->
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
<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>
// 实现提交操作. 点击提交按钮, 就能够把用户输入的内容提交到页面上显示.
// 点击的时候, 获取到三个输入框中的文本内容
// 创建一个新的 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 = '';
}
}
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]);
}
</script>
</body>
</html>
1.准备工作
1️⃣创建一个 maven 项目
2️⃣引入依赖:servlet、jackson
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.0</version>
</dependency>
<!-- 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>
3️⃣创建必要的目录 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>
4️⃣把之前实现的表白墙前端页面拷贝到 webapp 目录中
5️⃣配置 Smart Tomcat
6️⃣运行程序就可以访问前端页面
2.约定前后端交互接口
写代码之前需要明确前后端交互端口
🙈什么时候发送请求❓❓
1️⃣页面加载完毕之后,需要给服务器发送请求,获取当前的留言数据都有什么
2️⃣用户点击提交的时候,就需要告诉服务器,当前用户发送了的消息是啥
在交互的过程中,有涉及到关键的问题:请求具体是什么样子❓❓响应具体是什么样子❓❓这些都需要程序猿来设计,这就叫“约定前后端交互端口”
此处给出一份典型的约定方式(并不是唯一的方式)
2.1 接口一:页面获取当前所有的留言消息
约定
1️⃣请求:GET/message
2️⃣响应:HTTP/1.1 200 OK
Content-Type:application/json
[
{
from: "从哪里来",
to: "到哪里去",
message: "消息是啥"
},
{
from: "从哪里来",
to: "到哪里去",
message: "消息是啥"
},
......
]
json 中使用[ ] 表示数组,[ ] 中的每个元素是一个 { } json 对象;每个对象里又有三个属性 from、to、message
2.2 接口二:提交新消息给服务器
1️⃣请求:POST/message
Content-Type:application/json
[
{
from: "从哪里来",
to: "到哪里去",
message: "消息是啥"
},
{
from: "从哪里来",
to: "到哪里去",
message: "消息是啥"
},
......
]
2️⃣响应:HTTP/1.1 200 OK
处理 "获取所有留言消息":创建 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;
class Message {
// 这几个属性必须设置 public !!!!
// 如果设置 private, 必须生成 public 的 getter 和 setter !!!
public String from;
public String to;
public String message;
@Override
public String toString() {
return "Message{" +
"from='" + from + '\'' +
", to='" + to + '\'' +
", message='" + message + '\'' +
'}';
}
}
@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 {
// 通过这个方法来处理 "获取所有留言消息"
// 需要返回一个 json 字符串数组. jackson 直接帮我们处理好了格式.
String respString = objectMapper.writeValueAsString(messageList);
resp.setContentType("application/json; charset=utf8");
resp.getWriter().write(respString);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 通过这个方法来处理 "提交新消息"
Message message = objectMapper.readValue(req.getInputStream(), Message.class);
messageList.add(message);
System.out.println("消息提交成功! message=" + message);
// 响应只是返回 200 报文. body 为空. 此时不需要额外处理. 默认就是返回 200 的.
}
}
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>
<!-- 引入 jquery -->
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
<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>
// 实现提交操作. 点击提交按钮, 就能够把用户输入的内容提交到页面上显示.
// 点击的时候, 获取到三个输入框中的文本内容
// 创建一个新的 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 = '';
}
//4. 通过 ajax 构造 post 请求,把这个新的消息提交给服务器
let body = {
"from": from,
"to": to,
"message": msg
}
$.ajax({
type: 'post',
url: 'message',
contentType: "application/json;charset=utf8",
// java 中使用 jackson 完成对象和 json 字符串的转换;objectMapper.writeValue 用来把 java 对象转成 json 格式字符串
//objectMapper.readValue 用来把 json 格式字符串转成 java对象
// JS 中使用 JSON 这个特殊对象,完成对象和json字符串的转化;JSON.stringify 把js对象转成json格式字符串
//JSON.parse 把 json格式字符串转成js对象
data: JSON.stringify(body),
success: function(nody) {
//这是响应成功之后要调用的回调
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]);
}
// 在页面加载的时候, 希望能够从服务器获取到所有的消息, 并显示在网页中.
$.ajax({
type: 'get',
url: 'message', // url 都是使用相对路径的写法. 相对路径意味着工作路径就是当前文件所在的路径.
// 当前文件所在路径是 /message_wall/ , 因此此时构造的请求就是 /message_wall/message
success: function(body) {
// body 是收到的响应的正文部分. 如我们之前的约定, body 应该是 json 数组
// 由于响应的 Content-Type 是 application/json, 此时收到的 body 会被 jquery 自动的把它从 字符串
// 转成 js 对象数组. 此处就不需要手动的进行 JSON.parse 了.
// 此处的 body 已经是一个 JSON.parse 之后得到的 js 对象数组了.
// 就需要遍历这个 body 数组, 取出每个元素, 再依据这样的元素构造出 html 标签, 并添加到页面上.
let container = document.querySelector('.container');//通过css选择器查找页面中的元素
for (let message of body) {
let rowDiv = document.createElement('div');
rowDiv.className = "row";
rowDiv.innerHTML = message.from + " 对 " + message.to + " 说: " + message.message;
container.appendChild(rowDiv);
}
}
});
</script>
</body>
</html>
此时通过浏览器的URL:127.0.0.1:8080/message_wall/messageWall.htm 访问服务器即可看到
此时我们每次提交的数据都会发送给服务器. 每次打开页面的时候页面都会从服务器加载数据. 因此及时关闭页面, 数据也不会丢失.
但是数据此时是存储在服务器的内存中 ( private List<Message> messages = new ArrayList<Message>(); ), 一旦服务器重启, 数据仍然会丢失
4.数据持久化
把数据存储到银盘上,才是让数据更让好的持久化的方法:1️⃣数据存储到文件里2️⃣数据存入数据可中
4.1 数据存入数据库
1️⃣引入 JDBC 依赖:
<!-- 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 table messages (`from` varchar(255), `to` varchar(255), `message` varchar(2048));
3️⃣修改代码
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;
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;
import static java.lang.System.load;
/**
* Created with IntelliJ IDEA.
* Description:
* User: Lenovo
* Date: 2023-06-02
* Time: 19:56
*/
class Message {
// 这几个属性必须设置 public !!!!
// 如果设置 private, 必须生成 public 的 getter 和 setter !!!
public String from;
public String to;
public String message;
@Override
public String toString() {
return "Message{" +
"from='" + from + '\'' +
", to='" + to + '\'' +
", message='" + message + '\'' +
'}';
}
}
@WebServlet("/message")
public class MessageServlet extends HttpServlet {
private ObjectMapper objectMapper = new ObjectMapper();
private List<Message> messageList = new ArrayList<>();
//private List<Message> messageList = new ArrayList<>();
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 通过这个方法来处理 "获取所有留言消息"
// 需要返回一个 json 字符串数组. jackson 直接帮我们处理好了格式.
List<Message> messageList = load();
String respString = objectMapper.writeValueAsString(messageList);
resp.setContentType("application/json; charset=utf8");
resp.getWriter().write(respString);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 通过这个方法来处理 "提交新消息"
Message message = objectMapper.readValue(req.getInputStream(), Message.class);
messageList.add(message);
save(message);
System.out.println("消息提交成功! message=" + message);
// 响应只是返回 200 报文. body 为空. 此时不需要额外处理. 默认就是返回 200 的.
}
// 这个方法用来往数据库中存一条记录
private void save(Message message) {
DataSource dataSource = new MysqlDataSource();
((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/java107?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("2222");
try {
Connection connection = dataSource.getConnection();
String sql = "insert into message values(?, ?, ?)";
PreparedStatement statement = connection.prepareStatement(sql);
statement.setString(1, message.from);
statement.setString(2, message.to);
statement.setString(3, message.message);
statement.executeUpdate();
statement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
// 这个方法用来从数据库查询所有记录
private List<Message> load() {
List<Message> messageList = new ArrayList<>();
DataSource dataSource = new MysqlDataSource();
((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/java107?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("2222");
try {
Connection connection = dataSource.getConnection();
String sql = "select * from message";
PreparedStatement statement = connection.prepareStatement(sql);
ResultSet resultSet = statement.executeQuery();
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);
}
resultSet.close();
statement.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
return messageList;
}
}
通过上述代码就已经写出一个很简单的网站;未来写的复杂网站都是这一套逻辑
1️⃣约定前后端交互接口
2️⃣实现服务器代码(通常回操作数据库)
3️⃣实现客户端代码(通常会使用 ajax 构造请求,并使用一些 js 的 webapi 操作页面内容)