目录
在之前的一篇博客中,已经写过了表白墙的页面代码实现,这里就不再重复了
页面代码如下:
- html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>表白墙title>
- head>
- <body>
- <div class="container">
- <h1>表白墙h1>
- <p>输入后点击提交,会将信息显示在表格中p>
- <div class="row">
- <span>谁:span>
- <input type="text" class="edit">
- div>
- <div class="row" >
- <span>对谁:span>
- <input type="text" class="edit">
- div>
- <div class="row">
- <span>说什么:span>
- <input type="text" class="edit">
- div>
- <div class="row">
- <input type="button" value="提 交" id="submit">
- div>
- <script>
- let submitButton=document.querySelector('#submit');
- submitButton.onclick=function(){
- //1.先获取到编辑框的内容
- let edits=document.querySelectorAll('.edit');
- //依靠.value来获得其输入框的值
- let from=edits[0].value;
- let to=edits[1].value;
- let message=edits[2].value;
- console.log(from,to,message);
- //这里是对用户输入进行合法的校验,看用户输入是否合法
- if(from==''||to==' '||message==''){
- return;
- }
- //2.根据内容,构造HTML元素(.row里面包含用户输入的话)
- //createElement:创建一个元素
- let row=document.createElement('div');
- row.className='row';
- row.innerHTML=from+'对'+to+'说:'+message;
- //3.把这个新的元素添加到DOM树上
- let container=document.querySelector('.container');
- container.appendChild(row);
- //4.清空原来的输入框
- for(let i=0;i
length;i++){ - edits[i].value='';
- }
- }
- script>
- <style>
- /*去除浏览器默认样式:内边距,外边距,内边框和外边框不会撑大盒子*/
- *{
- margin:0;
- padding: 0;
- box-sizing: border-box;
- }
- /*margin:0 auto :意思是 中央居中*/
- .container{
- width: 400px;
- margin:0 auto;
- }
- /*padding:20px auto :h1标签:上下间距20*/
- h1{
- text-align:center;
- padding:20px auto;
- }
- p{
- text-align:center;
- color:#666;
- padding: 10px 0;
- font-size:14px;
- }
- /*display:flex:基于弹性布局
- justify-content:center:水平居中
- align-items:center:垂直居中
- */
- .row{
- height:50px ;
- display: flex;
- justify-content: center;
- align-items:center;
- }
- /*现在对于span和input的长度进行调整*/
- span{
- width:90px;
- font-size: 20px;
- }
- input{
- width:310px;
- height: 40px;
- font-size: 18px;
- }
- /*现在处理一下 提交 按钮
- 首先,提交按钮宽度和父元素一样宽
- 其次,设置字体颜色和背景颜色
- 然后,border:none:作用:为了去除黑边框
- border-radius:设置四个角角为圆矩形
- font-size:设置 提交 字体的大小
- */
-
- #submit{
- width: 400px;
- color: white;
- background-color:orange;
- border:none;
- border-radius:5px;
- font-size: 18px;
- }
- /*点击 提交 按钮 就会改变其背景颜色*/
- #submit:active{
- background-color: black;
- }
- style>
- div>
- body>
- html>
之前写的页面有两个非常严重的问题:
1、如果刷新页面 / 关闭页面 重开,之前输入的消息就不见了
2、如果一个机器上输入了数据,第二个机器是看不到的(这些数据都是在本地浏览器中)
解决思路:
让服务器来存储用户提交的数据,由服务器保存
当由新的浏览器打开页面的时候,再从服务器获取数据
此处服务器就可以用来存档和读档的操作
写 web 程序,务必要重点考虑前后端如何交互,也就是约定好前后端交互的数据格式
这个过程,称为 设计前后端交互接口
请求时什么样的,响应是什么样的,浏览器什么时候发送请求,浏览器按照什么格式来解析....
那么哪些环节涉及到前后端交互呢?
1、点击提交,浏览器把表白信息发送到服务器这里
2、页面加载,浏览器从服务器获取到表白信息
1、点击提交,浏览器把表白信息发送到服务器这里
2、页面加载,浏览器从服务器获取到表白信息
此处的约定,没有固定的强制要求,只要保证能够实现必要的需求即可,此处的目的是为了前后端可以对上号
注意:这里的路径得和之前约定的保持一致
我们要先定义一个类,描述请求的 body 内容,方便 jackson 进行 json 解析
- class Message{
- public String from;
- public String to;
- public String message;
- }
然后使用 List 来存储数据
- //使用 List 变量保存所有消息
- private List
messagesList = new ArrayList<>(); -
-
- //向服务器提交数据
- @Override
- protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- ObjectMapper objectMapper = new ObjectMapper();
- //把 body 中的内容读取出来,解析成 message 对象
- Message message = objectMapper.readValue(req.getInputStream(),Message.class);
- //此处,通过一个简单粗暴的方式来完成保存
- messagesList.add(message);
- //此处的设定状态码可以省略,不设置,默认也是200
- resp.setStatus(200);
- }
doPost 做的事情,就是把解析的 message 往 List 里面添加
另一方面,实现 doGet ,也就是把 List 的结果,返回给前端
响应数据,也是一个 json 数据
基于 objectMapper 的 writeValue 方法,就可以把 List
这个方法,同时完成了把 java 对象,转换成 json 和把 json 字符串写到响应对象中
第一个参数是 Writer 对象,表示转成的 json 字符串,往哪个地方去写,第二个参数就是当前存储消息的 List ,意思是要把哪个对象转换成 json
如果分成两步,就是这样写的:
- //从服务器获取数据
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- ObjectMapper objectMapper = new ObjectMapper();
- //显示告诉浏览器,数据是 json 格式,并且字符集是 utf8
- resp.setContentType("applicaion/json; charseet=utf8");
- objectMapper.writeValue(resp.getWriter(),messagesList);
- }
针对 doGet ,只是把 MessageList 给转换成 json 字符串,返回给浏览器
- class Message{
- public String from;
- public String to;
- public String message;
- }
-
- @WebServlet("/message")
- public class MessageServlet extends HttpServlet {
-
- //使用 List 变量保存所有消息
- private List
messagesList = new ArrayList<>(); -
-
- //向服务器提交数据
- @Override
- protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- ObjectMapper objectMapper = new ObjectMapper();
- //把 body 中的内容读取出来,解析成 message 对象
- Message message = objectMapper.readValue(req.getInputStream(),Message.class);
- //此处,通过一个简单粗暴的方式来完成保存
- messagesList.add(message);
- //此处的设定状态码可以省略,不设置,默认也是200
- resp.setStatus(200);
- }
-
- //从服务器获取数据
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- ObjectMapper objectMapper = new ObjectMapper();
- //显示告诉浏览器,数据是 json 格式,并且字符集是 utf8
- resp.setContentType("applicaion/json; charset=utf8");
- //objectMapper.writeValue(resp.getWriter(),messagesList);
-
- //把 java 对象转换成 json 字符串
- String jsonResp = objectMapper.writeValueAsString(messagesList);
- //把字符串写回到响应 body 中
- resp.getWriter().write(jsonResp);
- }
- }
写到这里,表白墙的后端就大功告成了,我们可以打开 postman 对代码进行测试
当前这只是给前端返回 json 字符串,要想成为键值对,还需要额外的代码
接下来,我们来编写前端代码,也就是让页面能够发起上述请求,并解析响应
post 是点击提交按钮的时候发起,get 是页面加载的时候发起
这个代码是在定义一个 js 对象(类似于 json 的键值对)
key 其实是字符串,value 则是 js 中的变量/常量
js 中要求, 对象中的 key 务必是 字符串,所以这里的 "" 可以省略
当前 body 是个 js 对象,不是字符串,网络传输,只能串字符串,不能传对象
所以,我们需要把目前这个对象转成字符串
js 内置了转换 json 的库
- //4、[新增] 给服务器发起 post 请求,把上述数据提交到服务器
- let body = {
- from :from,
- to:to,
- message:msg
- };
- strBody = JSON.stringify(body);
- console.log("strBody: " + strBody);
- $.ajax({
- type:'post',
- url:'message',
- data:strBody,
- contentType:"application/json;charset=utf8",
- success:function(body){
- console,log("数据发布成功");
- }
- });
接下来需要实现下 读档操作,让 ajax 发送 GET 请求
- //[新增] 在页面加载的时候,发送 GET 请求,从服务器获取到数据并添加到页面中
- $.ajax({
- type:'get',
- url:'message',
- success:function(body){
- //此处拿到的 body 就是一个 js 的对象数组了
- //本来服务器返回的是一个 json 格式的字符串,但是 jquery 的 ajax 可以自动识别,
- //自动帮我们把 json 字符串转成 js 对象数组
- //接下来,遍历这个数组,把元素取出来,并且构造到页面中即可
- for(let message of body){
- //针对每个元素构造一个 div
- let row=document.createElement('div');
- row.className='row';
- row.innerHTML=message.from +'对'+message.to +'说:'+message.message;
- containerDiv.appendChild(rowDiv);
- }
- }
- });
当前我们的数据是在内存(变量) 中保存的,重启服务器就没了
要想持久化保存,就需要写入文件中(硬盘)
1、直接使用 流对象 写入文本文件
2、借助数据库
创建数据表
此处只有一个表:message(from ,to,message)
实现数据库操作:
- //通过这个类,把数据库连接过程封装一下
- //此处,把 DBUtil 作为一个工具类,提供 static 方法,供其它方法来调用
- public class DBUtil {
- //静态成员是跟随类对象的,类对象在整个进程中,只有唯一一份
- //静态成员相当于也是唯一的实例(单例模式,饿汉模式)
- private static DataSource dataSource = new MysqlDataSource();
-
- static {
- //使用静态代码块,针对 dataSourse 进行初始化
- ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/java?charactorEncoding=utf8&useSSL=false");
- ((MysqlDataSource)dataSource).setUser("root");
- ((MysqlDataSource)dataSource).setPassword("123456");
- }
-
- //通过这个方法来建立连接
- public static Connection getConnection() throws SQLException {
- return dataSource.getConnection();
- }
-
- //通过这个方法来断开连接,释放资源
- public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet) {
- //此处的三个 try catch 分开写更好,避免前面的异常导致后面的代码无法执行
- if (resultSet != null){
- try {
- resultSet.close();
- } catch (SQLException e) {
- throw new RuntimeException(e);
- }
- }
- if (statement != null){
- try {
- statement.close();
- } catch (SQLException e) {
- throw new RuntimeException(e);
- }
- }
- if (connection != null){
- try {
- connection.close();
- } catch (SQLException e) {
- throw new RuntimeException(e);
- }
- }
- }
- }
要插入的数据,是三个变量,要把这三个变量给填充到 Sql 中,就需要占位符
- class Message{
- public String from;
- public String to;
- public String message;
- }
-
- @WebServlet("/message")
- public class MessageServlet extends HttpServlet {
-
- //使用 List 变量保存所有消息
- //private List
messagesList = new ArrayList<>(); -
-
- //向服务器提交数据
- @Override
- protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- ObjectMapper objectMapper = new ObjectMapper();
- //把 body 中的内容读取出来,解析成 message 对象
- Message message = objectMapper.readValue(req.getInputStream(),Message.class);
- //此处,通过一个简单粗暴的方式来完成保存
- //messagesList.add(message);
- save(message);
- //此处的设定状态码可以省略,不设置,默认也是200
- resp.setStatus(200);
- }
-
- //从服务器获取数据
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- ObjectMapper objectMapper = new ObjectMapper();
- //显示告诉浏览器,数据是 json 格式,并且字符集是 utf8
- resp.setContentType("applicaion/json; charset=utf8");
- //objectMapper.writeValue(resp.getWriter(),messagesList);
-
- //把 java 对象转换成 json 字符串
- List
messagesList = load(); - String jsonResp = objectMapper.writeValueAsString(messagesList);
- //把字符串写回到响应 body 中
- resp.getWriter().write(jsonResp);
- }
-
- //提供一对方法
- //往数据库中存一条消息
- private void save(Message message) {
- //JDBC 操作
- //1、建立连接
- Connection connection = null;
- PreparedStatement statement = null;
- try {
- 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) {
- throw new RuntimeException(e);
- }finally {
- //4、关闭连接
- DBUtil.close(connection,statement,null);
- }
- }
-
- //从数据库中取所有消息
- private List
load(){ - List
messageList = new ArrayList<>(); - PreparedStatement statement = null;
- Connection connection = null;
- ResultSet resultSet = null;
- try {
- //1、和数据库建立连接
- connection = DBUtil.getConnection();
- //2、构造 SQL
- String sql = "select *from message";
- statement = connection.prepareStatement(sql);
- //3、执行 SQL
- resultSet = 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;
- }
- }