目录
一、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 {@Overrideprotected 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 {@Overrideprotected 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 {@Overrideprotected 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();@Overrideprotected 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 {@Overrideprotected 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 {@Overrideprotected 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 {@Overrideprotected 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. 构造新 divlet 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;@Overridepublic 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<>();@Overrideprotected 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);}@Overrideprotected 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. 构造新 divlet 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/messagesuccess: 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;@Overridepublic 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<>();@Overrideprotected 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);}@Overrideprotected 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 操作页面内容)