高端網(wǎng)站定制建站企業(yè)培訓(xùn)課程ppt
在我們之前博客中寫到的留言墻頁面,有很嚴(yán)重的問題:(留言墻博客)
- 如果刷新頁面/關(guān)閉頁面重開,之前輸入的消息就不見了.
- 如果一個(gè)機(jī)器上輸入了數(shù)據(jù),第二個(gè)機(jī)器上是看不到的.
針對(duì)以上問題,我們的解決思如如下:
讓服務(wù)器來存儲(chǔ)用戶提交的數(shù)據(jù),由服務(wù)器保存.
當(dāng)有新的瀏覽器打開頁面的時(shí)候,從服務(wù)器獲取數(shù)據(jù).
此時(shí)服務(wù)器就可以用來存檔和讀檔.
設(shè)計(jì)程序:
寫web程序,務(wù)必要重點(diǎn)考慮前后端如何交互,約定好前后端交互的數(shù)據(jù)格式.
設(shè)計(jì)前后端交互接口: 1.請(qǐng)求是什么樣 2. 響應(yīng)是什么樣 3.瀏覽器什么時(shí)候發(fā)送這個(gè)請(qǐng)求 4. 瀏覽器按照什么格式來解析
在我們的留言墻程序中,以下環(huán)節(jié)涉及到前后端交互:
- 點(diǎn)擊提交,瀏覽器把表白墻信息發(fā)送到服務(wù)器這里
- 頁面加載,瀏覽器從服務(wù)器獲取到表白信息.
- 點(diǎn)擊提交,瀏覽器把表白墻信息發(fā)送到服務(wù)器這里
請(qǐng)求:
POST/message
按照json格式:
{from:"i",to:"you",message:"hello"
}
響應(yīng):
HTTP/1.1 200 OK
- 頁面加載,瀏覽器從服務(wù)器獲取到表白信息.
請(qǐng)求:
GET/message
響應(yīng):
HTTP/1.1 200 OK
body部分:
[{from:"i",to:"you",message:"hello"}{from:"i",to:"you",message:"hello"}
]
此處約定的目的是為了前端代碼和后端代碼能夠?qū)?yīng)上.約定的方式可以有很多種.
通過約定,我們可以寫出后端代碼為:
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 String from;public String to;public String message;
}
@WebServlet("/message")
public class MessageServlet extends HttpServlet {private List<Message> messageList = new ArrayList<>();ObjectMapper objectMapper = new ObjectMapper();// 向服務(wù)器提交數(shù)據(jù)@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//讀取body中的內(nèi)容,解析成 Message 對(duì)象Message message = objectMapper.readValue(req.getInputStream(),Message.class);//保存messageList.add(message);//設(shè)置狀態(tài)碼resp.setStatus(200);}// 從服務(wù)器獲取數(shù)據(jù)@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//顯示告訴瀏覽器,數(shù)據(jù)是 json 格式,字符集是 utf8resp.setContentType("application/json;charset=utf8");//通過 writeValue 將 messageList(java對(duì)象) 轉(zhuǎn)成 json 格式并將其寫入 resp 中//objectMapper.writeValue(resp.getWriter(),messageList);//把java對(duì)象轉(zhuǎn)成json字符串String jsonResp = objectMapper.writeValueAsString(messageList);System.out.println("jsonResp: "+jsonResp);//把這個(gè)字符串寫回到響應(yīng) body 中resp.getWriter().write(jsonResp);}
}
通過Postman 構(gòu)造POST請(qǐng)求,使用json語法編輯body部分,點(diǎn)擊兩次發(fā)送,再通過GET獲取得到響應(yīng)如下:
存檔:
其次,我們?cè)倏辞岸舜a:在前端代碼中使用ajax發(fā)送一個(gè)post請(qǐng)求.
通過fiddler得到:
通過dopost 執(zhí)行:
通過resp.setStatus(200);
回到回調(diào)函數(shù):
讀檔:根據(jù)ajax創(chuàng)建GET響應(yīng):
打開fiddler可以看到:
GET請(qǐng)求觸發(fā)doGet方法:
我們可以得到完整的前端代碼(包含撤銷功能):
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>MessageBoard</title><style>*{/* 消除瀏覽器的默認(rèn)樣式 */margin: 0;padding: 0;/* 保證盒子不會(huì)撐大 */box-sizing: border-box;/* background-color: rgba(255, 192, 203, 0.436); */}.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;}/* 點(diǎn)擊的時(shí)候有個(gè)反饋 */.row button:active {background-color: grey;}</style>
</head>
<body><div class="container"><h1>留言板</h1><p>輸入內(nèi)容后點(diǎn)擊提交,信息會(huì)顯示到下方表格中</p><div class="row"><span>誰:</span><input type="text"></div><div class="row"><span>對(duì)誰:</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><script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.3/jquery.min.js"></script><script>//實(shí)現(xiàn)提交操作,點(diǎn)擊提交,就能夠吧用戶輸入的內(nèi)容提交到頁面上顯示//點(diǎn)擊時(shí),獲取到三個(gè)輸入框的文本內(nèi)容//創(chuàng)建一個(gè)新的div.rom把內(nèi)容構(gòu)造到這個(gè)div中即可.let containerDiv = document.querySelector('.container');let inputs = document.querySelectorAll('input');let button = document.querySelector('#submit');button.onclick = function(){//1.獲取到三個(gè)輸入框的內(nèi)容let from = inputs[0].value;let to = inputs[1].value;let msg = inputs[2].value;if(from == '' || to == '' || msg == ''){return;}//2.構(gòu)造新的divlet rowDiv = document.createElement('div');rowDiv.className = 'row message';rowDiv.innerHTML = from +" 對(duì) "+to+' 說 : '+msg;containerDiv.appendChild(rowDiv);//3.清空輸入聊天框for(let input of inputs){input.value = '';}//4. [新增] 給服務(wù)器發(fā)起post請(qǐng)求,把上述數(shù)據(jù)提交到服務(wù)器//定義一個(gè)js對(duì)象let body = {from:from,to:to,message:msg};//將對(duì)象轉(zhuǎn)成json字符串strBody = JSON.stringify(body);$.ajax({type:'post',url:'message',data:strBody,contentType:"application/json; charset=utf-8",success:function(body){console.log("發(fā)布成功.");}});}let revertButton = document.querySelector('#revert');revertButton.onclick = function(){//刪除最后一條消息//選中所有的row,找出最后一個(gè)row,然后刪除let rows = document.querySelectorAll('.message');if (rows == null || rows.length == 0) {return;}containerDiv.removeChild(rows[rows.length - 1]);//[新增]刪除$.ajax({type: 'delete',url: 'message',success: function(body){// 1.先選中父元素ConversationDiv,然后刪除所有子元素let ConversationDiv = document.querySelector('.Conversation');while(ConversationDiv.firstChild){ConversationDiv.removeChild(ConversationDiv.firstChild)}for(let message of body){// 2.對(duì)響應(yīng)數(shù)據(jù)內(nèi)容進(jìn)行頁面顯示,對(duì)每一個(gè)message元素構(gòu)造一個(gè)divlet resultDiv = document.createElement('div');resultDiv.className = 'row message result';resultDiv.innerHTML = message.from + ' 對(duì): ' + message.to + ' 說: ' + message.message;ConversationDiv.appendChild(resultDiv);}}})}//[新增]在頁面加載的時(shí)候,發(fā)送GET請(qǐng)求,從服務(wù)器獲取到數(shù)據(jù)并添加到頁面中$.ajax({type:'get',url:'message',success:function(body){let containerDiv = document.querySelector('.container');for(let message of body){let rowDiv = document.createElement('div');rowDiv.className ='row message';rowDiv.innerHTML = message.from +' 對(duì) '+ message.to +' 說 : ' + message.message;containerDiv.appendChild(rowDiv);}}});</script>
</body>
</html>
刷新頁面后數(shù)據(jù)也不會(huì)消失.
但是以上重啟服務(wù)器后數(shù)據(jù)就消失了,所以我們可以把數(shù)據(jù)寫入數(shù)據(jù)庫中進(jìn)行長久的保存.
C:\Users\xxxflower>mysql -uroot -p
Enter password: ****
create table message(from
varchar(20),to
varchar(20),message varchar(1024));
注意,由于from和to都是sql中的關(guān)鍵字,所以需要使用`
.
創(chuàng)建表:
完整的后端代碼:
MessageServlet.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.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;class Message{public String from;public String to;public String message;
}
@WebServlet("/message")
public class MessageServlet extends HttpServlet {//private List<Message> messageList = new ArrayList<>();private ObjectMapper objectMapper = new ObjectMapper();// 向服務(wù)器提交數(shù)據(jù)@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//讀取body中的內(nèi)容,解析成 Message 對(duì)象Message message = objectMapper.readValue(req.getInputStream(),Message.class);//保存save(message);//messageList.add(message);//設(shè)置狀態(tài)碼resp.setStatus(200);}// 從服務(wù)器獲取數(shù)據(jù)@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//顯示告訴瀏覽器,數(shù)據(jù)是 json 格式,字符集是 utf8resp.setContentType("application/json;charset=utf-8");//通過 writeValue 將 messageList(java對(duì)象) 轉(zhuǎn)成 json 格式并將其寫入 resp 中//objectMapper.writeValue(resp.getWriter(),messageList);//把java對(duì)象轉(zhuǎn)成json字符串List<Message> messageList = load();String jsonResp = objectMapper.writeValueAsString(messageList);System.out.println("jsonResp: " + jsonResp);//把這個(gè)字符串寫回到響應(yīng) body 中resp.getWriter().write(jsonResp);}//使用jdbc 往數(shù)據(jù)庫里面存消息private void save(Message message) {//JDBCConnection connection = null;PreparedStatement statement = null;try {//1.建立連接connection = DBUtil.getConnection();//2.構(gòu)造sql語句String sql = "insert into message values(?, ?, ?)";statement = connection.prepareStatement(sql);statement.setString(1,message.from);statement.setString(2,message.to);statement.setString(3,message.message);//3.執(zhí)行sqlstatement.executeUpdate();} catch (SQLException e) {throw new RuntimeException(e);}finally {//4.關(guān)閉連接DBUtil.close(connection,statement,null);}}//從數(shù)據(jù)庫取所有消息private List<Message> load(){List<Message> messageList = new ArrayList<>();Connection connection = null;PreparedStatement statement = null;ResultSet resultSet = null;try {//1.與數(shù)據(jù)庫建立連接connection = DBUtil.getConnection();//2.構(gòu)造sqlString sql = "select * from message";statement = connection.prepareStatement(sql);//3.執(zhí)行sqlresultSet = statement.executeQuery();//4.遍歷集合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);}} catch (SQLException e) {e.printStackTrace();}finally {//5.釋放資源 斷開連接DBUtil.close(connection,statement,resultSet);}return messageList;}@Overrideprotected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.setContentType("application/json; charset=utf-8");// 從數(shù)據(jù)庫獲取所有表白信息// 1.獲取最后一份表白信息,并從數(shù)據(jù)庫刪除List<Message> messageList = load();if(messageList.size() == 0){return;}Message messageEnd = messageList.get(messageList.size()-1);int count = delete(messageEnd);if(count == 1){System.out.println("留言信息刪除成功");}else {System.out.println("留言信息刪除失敗");}// 2.獲取刪除最后一條信息后的 全部表白信息,并寫回到瀏覽器messageList = load();objectMapper.writeValue(resp.getOutputStream(), messageList);}private int delete(Message message) {Connection connection = null;PreparedStatement preparedStatement = null;int count = 0;try {// 1.獲取連接connection = DBUtil.getConnection();// 2.編寫sqlString sql = "delete from message where `from` = ? and `to` = ? and message = ?";// 3.獲取預(yù)編譯對(duì)象,進(jìn)行預(yù)編譯preparedStatement = connection.prepareStatement(sql);preparedStatement.setString(1, message.from);preparedStatement.setString(2, message.to);preparedStatement.setString(3, message.message);// 4.執(zhí)行sql語句count = preparedStatement.executeUpdate();// 5.處理結(jié)果} catch (SQLException throwables) {throwables.printStackTrace();} finally {DBUtil.close(connection, preparedStatement, null);}return count;}
}
DBUtil
:
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;//這個(gè)類用于封裝數(shù)據(jù)庫連接過程
//此處把 DBUtil 作為一個(gè)工具類,提供 static 方法供其他代碼使用
public class DBUtil {//靜態(tài)成員跟隨類對(duì)象,類對(duì)象在整個(gè)進(jìn)程中只有唯一一份//靜態(tài)成員相當(dāng)于也是唯一的實(shí)例(單例模式,餓漢模式)private static DataSource dataSource = new MysqlDataSource();//使用靜態(tài)代碼塊針對(duì) DataDource 進(jìn)行初始化操作static {((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/javaee?characterEncoding=utf8&useSSL=false");((MysqlDataSource)dataSource).setUser("root");((MysqlDataSource)dataSource).setPassword("0828");}//建立連接public static Connection getConnection() throws SQLException {return dataSource.getConnection();}//斷開連接 釋放資源public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet){if (resultSet != null) {try {resultSet.close();} catch (SQLException e) {e.printStackTrace();}}if (statement != null) {try {statement.close();} catch (SQLException e) {e.printStackTrace();}}if (connection != null) {try {connection.close();} catch (SQLException e) {e.printStackTrace();}}}
}
最終實(shí)現(xiàn)效果: