目录
一、设计思想
二、设计表白墙页面(前端--VSCode)
1、效果图
2、html部分(网页上有哪些内容)
html
<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">
xxx 对 xx 说 xxxx
</div>
</div>
<div class="container"> 表示一个包含内容的区域;
<div class="row"> 表示一个包含行内容的区域;
3、css部分(页面内容的具体样式)
html
<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>
选中某个标准,{}里描述这个标签应该具有什么样式。
4、js部分(页面行为)
javascript
<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 message = inputs[2].value;
if (from == '' || to == '' || message == '') {
return;
}
// 2. 构造新 div
let rowDiv = document.createElement('div');
rowDiv.className = 'row message';
rowDiv.innerHTML = from + ' 对 ' + to + ' 说: ' + message;
containerDiv.appendChild(rowDiv);
// 3. 清空之前的输入框内容
for (let input of inputs) {
input.value = '';
}
}
</script>
通过js代码可以实现网页和用户以及网页和服务器的交互。(以上代码还未实现和服务器的交互)
三、借助Servlet实现客户端与服务器交互
1、服务器的功能
以上代码也可以实现表白墙的功能,但是发现未和服务器建立连接,数据保存在浏览器内存里,刷新浏览器数据就会消失,且该客户端也看不到上一个客户端的留言,所以就要和服务器进行交互。
服务器的功能:(1)页面加载的时候要获取到当前表白数据,由服务器响应发送;(2)客户端发送数据时,服务器要接受并保存数据。
2、客户端发送数据--服务器保存并做出响应
(1)客户端发送数据(json类型请求)
①规定请求为json类型,方法为post,请求正文样子:
javascript
{
"from":from,
"to":to,
"message":message
}
在点击提交按钮后,发送数据给服务端,即在function函数里实现。需要引入第三方库:jquery库
②实现代码(VSCode--js语言)
javascript
// 4. 把用户填写的内容, 发送给服务器. 让服务器来保存.
// $ 是 jquery 提供的全局变量. ajax 就是 $ 的一个方法.
// ajax 的参数是一个 js 对象, 可以有很多属性
let requestBody = {
"from": from, // from 变量里的值, 就是第一个输入框的内容, "张三"
"to": to, // to 变量的值, 就是第二个输入框的内容, "李四"
"message": message // message 变量的值, 就是第三个输入框的内容, "我喜欢你很久了"
};
// 上述 body 是一个 js 对象, 还需要转成 json 字符串.
let jsonRequest = JSON.stringify(requestBody);
$.ajax({
type: 'post',
url: 'message',
contentType: 'application/json; charset=utf8',
data: jsonRequest,
success: function(responseBody) {
// 这个回调就是收到响应之后要执行的代码了.
// 前端使用 console.log 打印日志到控制台. (chrome 开发者工具的控制台)
console.log("responseBody: " + responseBody);
}
});
(2)服务器接收数据--保存数据并发送响应给客户端
①服务器需要把请求正文json字符串转为java对象,且把请求上传的数据增加到列表中,给客户端响应一个json字符串,响应正文为:
javascript
{
"ok" : "true"
}
②实现代码(IDEA--java语言)
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;
class Request{ //请求正文json字符串转为java对象
public String from;
public String to;
public String message;
@Override
public String toString() {
return "Request{" +
"from='" + from + '\'' +
", to='" + to + '\'' +
", message='" + message + '\'' +
'}';
}
}
class Response{
public boolean ok;
}
@WebServlet("/message")
public class messageServlet extends HttpServlet{
List<Request> list=new ArrayList<>();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ObjectMapper objectMapper=new ObjectMapper();
Request request=objectMapper.readValue(req.getInputStream(),Request.class); //转为java对象
System.out.println("请求内容:"+request);
list.add(request); //保存数据
resp.setStatus(200); //响应返回一个状态码
Response response=new Response(); //响应的java对象
response.ok=true;
String jsonResponse=objectMapper.writeValueAsString(response); //响应转为json字符串
resp.setContentType("application/json;charset=utf8");
resp.getWriter().write(jsonResponse);
}
}
3、客户端获取当前所有表白数据--服务端响应所有数据
(1)客户端发送请求(无请求正文)
①请求方法为get方法,加载页面时发送该请求。
②实现代码(VSCode--js语言)
javascript
// 直接在 script 里面写的 js 代码, 就是在页面加载时被执行到的.
// 发起一个 get 请求, 从服务器获取到数据
// get 请求不需要 body, 也就不需要上述 data 和 contentType 属性了.
$.ajax({
type:'get',
url:'message',
success:function(body){
//这个回调就是收到响应之后要执行的代码了.
//客户端将收到的所有数据显示到页面
}
})
客户端收到响应后,显示数据的代码下一步实现。
(2)服务器接收请求--将保存的所有表白数据响应给客户端
①服务器需要将保存数据的数组转为json数组,将json数组响应给客户端,
②实现代码(IDEA--java语言)
java
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ObjectMapper objectMapper=new ObjectMapper();
resp.setStatus(200); //响应返回一个状态码
resp.setContentType("application/json;charset=utf8");
String jsonResponse=objectMapper.writeValueAsString(list); //jackson支持把一个数组对象转为json数组
resp.getWriter().write(jsonResponse);
}
4、客户端将收到的所有数据显示到页面
①客户端将收到的所有表白数据显示在页面上,在success:function(body){}回调函数中实现;
②响应中header中带有:Content-Type:appliaction/json,jquery库就会自动把响应的json正文转为js对象。eg:resp.setContentType("application/json;charset=utf8");
若响应中header中没有:Content-Type:appliaction/json,客户端拿到响应后,在回调函数中就会调用body = JSON.parse(body) ;
③实现代码(VSCode--js语言)
javascript
success: function(body) {
//这个回调就是收到响应之后要执行的代码了.
//客户端将收到的所有数据显示到页面
// 由于响应中已经有 Content-Type: application/json 了, 就不需要使用 parse 方法手动转换了.
// body = JSON.parse(body);
// 拿到 container 这个元素
let containerDiv = document.querySelector('.container');
// 处理服务器返回的响应数据. (json 格式的数组了)
for (let i = 0; i < body.length; i++) {
// body 是一个数组, 此时 message 也就是 js 对象了.
// 这个 message 对象里, 有三个属性, from, to, message
let message = body[i];
// 根据 message 对象构建 html 片段, 把这个片段给显示到网页上.
// createElement 方法就能构造出一个 html 标签.
// 此时就得到了 <div></div>
let div = document.createElement('div');
// 还需要往里面设置一个 属性 , class="row" (设置这个属性, 是为了让 css 能够给这个元素设置一些样式)
// 此时就得到了 <div class="row"></div>
div.className = 'row';
// 给这个 div 里设置内容
// 此时就得到了 <div class="row">张三 对 李四 说: 我喜欢你很久了</div>
div.innerHTML = message.from + " 对 " + message.to + " 说: " + message.message;
// 把 div 添加到 containerDiv 的末尾
containerDiv.appendChild(div);
}
}
四、运行效果
需注意:需要将前端代码放在webapp包中(IDEA)
效果图
刷新或者重新打开页面,数据依旧存在。
五、问题改进
上述虽然实现了基于服务器的通信,但是若后台服务器停止运行,则所有的数据也都没有了,所以我们需要将数据存在数据库里,即使服务器停止运行了,再次重启时数据依然存在。
(1)引入mysql资源依赖
(2)建表
message表,里面有from、to、message属性。
sql
create database if not exists message_wall charset utf8;
use message_wall;
-- 删表目的是为了, 防止之前数据库里有一样的表, 对咱们的代码产生干扰.
drop table if exists message;
create table message (`from` varchar(1024), `to` varchar(1024), message varchar(1024));
(3)获得数据源
java
private DataSource datasource=new MysqlDataSource(); //导入数据源 向上转型
@Override
//获取数据源--在HttpServlet被实例化后调用该方法
public void init() throws ServletException {
((MysqlDataSource) datasource).setUrl("jdbc:mysql://127.0.0.1:3306/message_wall?characterEncoding=utf8&useSSL=false");
((MysqlDataSource) datasource).setUser("root"); //用户名
((MysqlDataSource) datasource).setPassword("272222"); //密码
}
(4)收到客户端的post请求保存数据
java
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ObjectMapper objectMapper=new ObjectMapper();
Request request=objectMapper.readValue(req.getInputStream(),Request.class); //转为java对象
System.out.println("请求内容:"+request);
try {
save(request);//保存数据
} catch (SQLException e) {
throw new RuntimeException(e);
}
resp.setStatus(200); //响应返回一个状态码
Response response=new Response(); //响应的java对象
response.ok=true;
String jsonResponse=objectMapper.writeValueAsString(response); //响应转为json字符串
resp.setContentType("application/json;charset=utf8");
resp.getWriter().write(jsonResponse);
}
private void save(Request request) throws SQLException {
//建立连接
Connection connection=datasource.getConnection();
//创建执行语句
String sql="insert into message values(?,?,?)"; //?是通配符
//转成服务器能看懂的语句 客户端已提前解析好,mysql直接运行
PreparedStatement statement=connection.prepareStatement(sql);
statement.setString(1,request.from); //第一个问号内容
statement.setString(2,request.to); //第二个问号内容
statement.setString(3,request.message); //第三个问号内容
//执行sql语句
statement.executeUpdate();
//回收资源
statement.close();
connection.close();
}
(5)收到客户端的get请求返回数据
java
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
List<Request> list=null;
ObjectMapper objectMapper=new ObjectMapper();
resp.setStatus(200); //响应返回一个状态码
resp.setContentType("application/json;charset=utf8");
try {
list=load();
} catch (SQLException e) {
throw new RuntimeException(e);
}
String jsonResponse=objectMapper.writeValueAsString(list); //jackson支持把一个数组对象转为json数组
resp.getWriter().write(jsonResponse);
}
private List<Request> load() throws SQLException {
//建立连接
Connection connection=datasource.getConnection();
//创建执行语句
String sql="select * from message";
//转成服务器能看懂的语句 客户端已提前解析好,mysql直接运行
PreparedStatement statement=connection.prepareStatement(sql);
//执行sql语句
ResultSet resultSet=statement.executeQuery();
//添加到返回数组
List<Request> list1=new ArrayList<>();
while (resultSet.next()){
Request request=new Request();
request.from=resultSet.getString("from");
request.to=resultSet.getString("to");
request.message=resultSet.getString("message");
list1.add(request);
}
return list1;
}
服务器重启后,数据依旧存在。