1.约定接口
实现这个表白墙案例的第一步,就是需要自定义应用层协议,确定好客户端和服务器如何进行交互。
数据能够进行存储的格式有很多种,也就是前后端需要共同指定数据格式,以便在客户端向服务器发送给去数据请求后,能够按照彼此约定好的应用层协议进行数据解析。
对于表白墙来说,主要要提供两个接口,要约定好客户端要发送一个怎样的HTTP请求,服务器返回一个怎样的HTTP响应,下边我们会直接指定数据格式为json格式:
接口一:
告诉服务器,当前留言了一条怎样的数据
(当用户点击提交按钮的时候,就会给服务器发送一个HTTP请求,让服务器把这个消息给存下来)
接口二:
从服务器获取到当前都有哪些留言数据
(当页面加载,就需要从服务器获取到曾经存储的留言内容)
在我们确定好接口后,就可以进行代码的编写了。
2.后端框架搭建
我们接下来,就按照常规Servlet程序的搭建流程进行搭建,先进性整体框架的搭建。
1.创建maven项目
2.引入依赖
(引入Servlet依赖和JSON依赖)
3.创建目录
4.编写代码
(只编写简单代码,用于测试是否搭建接口完成)
@WebServlet("/message") public class MessageServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().write("hello get"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().write("hello post"); } }
5、6.打包部署
7.验证
3.实现服务器端代码
先将消息列表存储到内容中(通过顺序表实现)
/** * 与json格式对应的类 */ class Message { public String from; public String to; public String message; } @WebServlet("/message") public class MessageServlet extends HttpServlet { //用于将类和json进行转换的类 private ObjectMapper objectMapper=new ObjectMapper(); //用于存放消息的顺序表 private List<Message> messages=new ArrayList<>(); /** * 处理提交消息请求,对数据进行保存 */ @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Message message=objectMapper.readValue(req.getInputStream(),Message.class); messages.add(message); //指定响应的数据格式 resp.setContentType("application/json;charset=utf8"); resp.getWriter().write("{\"ok\":true}"); } /** *获取消息列表,把消息列表中的内容返回给客户端 */ @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //将Java对象转成JSON格式字符串 String jsonString=objectMapper.writeValueAsString(messages); System.out.println("jsonString:"+jsonString); resp.setContentType("application/json;charset=utf8"); resp.getWriter().write(jsonString); } }
4.构造请求测试服务器端
利用应用postman来进行构造请求,用于测试服务器端代码。
postman可自行下载,专门用来构造HTTP请求,进行服务器端的测试。
首先我们在idea通过smart tomcat启动服务器,然后进行测试。
对接口一进行测试,构造POST请求,输入数据。
对接口二进行测试,构造GET请求,得到对接口一测试时输入的消息列表,测试完成。
5.调整前端页面代码
在之前文章【JavaScript进阶3.2 表白墙案例】的表白墙代码可以直接拿来用,再进行调整,完成两个接口的功能即可。
将该前端html文件拷贝到webapp目录下,再进一步调整完善前端代码的ajax请求
对前端代码的调整,主要的逻辑有两部分:
1.点击提交按钮时,ajax要构造数据发送给服务器。
2.页面加载的时候,从服务器获取消息列表,并在界面上直接显示。
首先我们还是先引入jQuery
功能1:把当前输入框的内容,构造成一个HTTP POST请求,通过ajax发送给服务器。
功能2:通过函数完成消息列表的获取打印。
完整前端代码:
<!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>Document</title> </head> <body> <style> * { margin: 0; padding: 0; box-sizing: border-box; background-color: rgb(30,100,200); } .container { width: 100%; } h3 { text-align: center; padding: 30px 0; font-size: 24px; color: rgb(255,140,10); } p { text-align: center; color: rgba(255, 50, 100); font-size: 18px; padding: 5px 0; } .row { width: 400px; height: 50px; margin: 0 auto; display: flex; justify-content: center; align-items: center; } .row span{ width: 100px; height: 40px; text-align: center; padding-right: 0px; font-size: 24px; color: rgb(255,140,10); } .row input { width: 300px; height: 40px; border: 2px solid rgb(255, 140,160); border-radius: 5px; outline: 0; text-align: left; padding-left: 0px; margin-left: 0px; text-indent: 0.4em; font-size: 20px; color: rgb(9, 245, 135); } .row #submit{ width: 200px; height: 40px; border-radius: 10px; font-size: 24px; border: 0px solid rgb(255, 140, 160); background-color: rgb(255, 140, 160); color: aliceblue; line-height: 40px; margin-top: 8px; } .row #submit:active{ background-color: rgb(140,180,240); } </style> <div class="container"> <h3>表白墙</h3> <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> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script> <script> function getMessages() { $.ajax({ type:"get", url:'message', success:function(body) { let container=document.querySelector('.container'); for(let message of body) { let div=document.createElement('div'); div.innerHTML=message.from+'对'+message.to+'说:'+message.message; div.className='row'; container.appendChild(div); } } }) } getMessages(); // 当用户点击submit,就会获取到input中的内容,从而把内容构造成一个div,插入到页面末尾 let submitBtn=document.querySelector('#submit'); submitBtn.onclick=function() { // 1.获取到3个input中的内容 let inputs=document.querySelectorAll('input'); let from=inputs[0].value; let to=inputs[1].value; let msg=inputs[2].value; if(from==''||to==''||msg=='') { // 用户还没有提交完,暂时先不提交数据 return; } // 2.生成一个新的div,内容是input里面的内容,把这个新的div加到页面中 let div=document.createElement('div'); div.innerHTML=from+'对'+to+'说:'+msg; div.className='row'; let container=document.querySelector('.container'); container.appendChild(div); //3.清空之前输入框内的内容 for(let i=0;i<inputs.length;i++) { inputs[i].value=''; } //4.功能一 let body={ from:from, to:to, message:msg }; $.ajax({ type:"post", url:"message", contentType:"application/json;charset=utf8", data:JSON.stringify(body), success:function(body) { alert("消息提交成功!"); }, error:function(body) { alert("消息提交失败!"); } }); } </script> </body> </html>
效果预览:
通过将消息存入内容的方式,只要服务器不重启,可以使得页面即使刷新,消息列表也不会丢失,但如果将服务器重启,消息列表一定会丢失。所以如果想要将数据持久化存储,需要将数据写入硬盘,可以通过写入文件或者写入数据库的方式,下边我们就将消息存入数据库,实现数据的持久化存储。
6.数据存入数据库
1)引入mysql数据库依赖
2)创建数据库
3)创建DBUtil类,用于与数据库的交互。
public class DBUtil { private static final String url="jdbc:mysql://localhost:3306/homework?characterEncoding=utf8&useSSL=false"; private static final String user="root"; private static final String password="1234"; private volatile static DataSource dataSource=null; //线程安全的单例模式 private static DataSource getDataSource() { if(dataSource==null) { synchronized (DBUtil.class) { if(dataSource==null) { dataSource=new MysqlDataSource(); ((MysqlDataSource)dataSource).setURL(url); ((MysqlDataSource)dataSource).setUser(user); ((MysqlDataSource)dataSource).setPassword(password); } } } return dataSource; } public static Connection getConnection() throws SQLException { return getDataSource().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(); } } } }
由于客户端发出的请求可能存在线程安全的问题,所以得到数据源的方法使用线程安全的单例模式
4)调整Servlet代码,完成数据存入数据库
关键方法:
完整代码:
/** * 与json格式对应的类 */ class Message { public String from; public String to; public String message; } @WebServlet("/message") public class MessageServlet extends HttpServlet { //用于将类和json进行转换的类 private ObjectMapper objectMapper=new ObjectMapper(); //用于存放消息的顺序表 // private List<Message> messages=new ArrayList<>(); /** * 处理提交消息请求,对数据进行保存 */ @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Message message=objectMapper.readValue(req.getInputStream(),Message.class); // messages.add(message); //指定响应的数据格式 resp.setContentType("application/json;charset=utf8"); resp.getWriter().write("{\"ok\":true}"); } /** *获取消息列表,把消息列表中的内容返回给客户端 */ @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //将Java对象转成JSON格式字符串 String jsonString=objectMapper.writeValueAsString(messages); System.out.println("jsonString:"+jsonString); resp.setContentType("application/json;charset=utf8"); resp.getWriter().write(jsonString); } /** * 把一条消息保存到数据库中 * @param message */ private void save(Message message) { Connection connection=null; PreparedStatement statement=null; try { //1.和数据库建立连接 connection=DBUtil.getConnection(); //2.构造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.执行SQL statement.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } finally { DBUtil.close(connection,statement,null); } } /** * 从数据库中获取到所有的消息 * @return */ private List<Message> load() { List<Message> messages=new ArrayList<>(); Connection connection=null; PreparedStatement statement=null; ResultSet resultSet=null; try { connection=DBUtil.getConnection(); String sql="select * from message"; statement=connection.prepareStatement(sql); 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"); messages.add(message); } } catch (SQLException e) { e.printStackTrace(); } finally { DBUtil.close(connection,statement,resultSet); } return messages; } }
效果演示:
由上述演示可得,现在的消息已经写入数据库,能够持久化存储了,至此,表白墙小案例也就大功告成了,快自己动手试试吧!