javaEE初阶 — 服务器版本的表白墙案例

文章目录

  • 原来版本涉及的问题
  • 设计程序
    • 1 点击提交
    • 2 页面加载
  • 实现后端代码
    • 1 新建一个 Maven 项目。
    • 2 按照之前第一个 Servlet 程序的步骤来进行设置
    • 3 新建一个 MessageServlet 类
  • 实现前端代码
    • 1 点击提交的时给服务器发送一个 POST 请求
    • 2 在页面加载时发送一个 GET 请求
    • 3 将数据保存到数据库中

原来版本涉及的问题


表白墙链接

之前完成的表白墙有两个非常严重的问题:

1、如果刷新页面或者关闭重开,此时表白墙之前保存的消息就消失了

2、表白墙的数据只能在本地浏览器中看见

javaEE初阶 — 服务器版本的表白墙案例_第1张图片

此时如果刷新页面或者关闭重开,此时表白墙的数据就消失了。



解决思路

让服务器来存储用户提交的数据,有服务器保存。

当有新的浏览器打开页面的时候,从服务器获取数据。

设计程序


实现一个 web 程序,务必要考虑前后端如何交互,要约定好前后端交互的数据格式。

比如说:
设计前后端交互接口、请求是什么样的、响应是什么样的、浏览器什么时候发这个请求、浏览器按照什么样的格式来解析。


有两个环节涉及到了前后端的交互:

一个是 点击提交 的时候,也就是浏览器把表白信息发到服务器。
一个是 页面加载 的时候,也就是浏览器从服务器获取到表白信息。

1 点击提交


请求 可以使用 POST,再使用一个 /message 这样的路径。

约定当前 body 是按照 json 格式来进行提供

{
  from: "张三",
  to: "李四",
  message: "卧槽"
}


响应 可以约定为,HTTP/1.1 200 OK

2 页面加载


请求 可以约定为 GET,再来一个 /message 路径,响应 也可以约定为 HTTP/1.1 200 OK

只不过此时的响应要按照 json数组 的格式来进行解析。

[
  {
    from: "张三",
    to: "李四",
    message: "卧槽"
  },
  
  {
    from: "张三",
    to: "李四",
    message: "卧槽"
  } 
]


此处的约定没有固定的强制要求,只要能保证必要的需求即可。
此处的目的就是为了前端代码和后端代码能够对上。

实现后端代码

1 新建一个 Maven 项目。


javaEE初阶 — 服务器版本的表白墙案例_第2张图片

2 按照之前第一个 Servlet 程序的步骤来进行设置


第一个Servlet 程序链接

1、首先要引入 Servlet、jackson、mysql 依赖,将这三个依赖引入到 dependencies 标签中。

打开 https://mvnrepository.com/,搜索 servlet,找到 3.1.0 版本。

javaEE初阶 — 服务器版本的表白墙案例_第3张图片

选择如上图的 Servlet,点击进去选择 3.1.0版。

javaEE初阶 — 服务器版本的表白墙案例_第4张图片

点击进去之后将 Maven 下的代码复制到 pom.xml 文件的 dependencies 标签中。



jackson 选择如下图的

javaEE初阶 — 服务器版本的表白墙案例_第5张图片

javaEE初阶 — 服务器版本的表白墙案例_第6张图片

点击 2.14.2 版本,其余的步骤与 servlet 一样。



mysql 依赖选择如下图的点击

javaEE初阶 — 服务器版本的表白墙案例_第7张图片
这里引入 mysql 依赖是因为可以使用 数据库来保存用户提交的数据。

选择 5.1.49 版本。

javaEE初阶 — 服务器版本的表白墙案例_第8张图片

其余的步骤也与 servlet 一样。


javaEE初阶 — 服务器版本的表白墙案例_第9张图片

以上是三个依赖引入好的样子。


2、接下来开始创建目录

javaEE初阶 — 服务器版本的表白墙案例_第10张图片


3、往web.xml 中添加一点内容

javaEE初阶 — 服务器版本的表白墙案例_第11张图片

3 新建一个 MessageServlet 类


这里的路径要和之前约定好的相同。



1、重写 doPost 和 doGet 方法

javaEE初阶 — 服务器版本的表白墙案例_第12张图片


2、实现向服务器提交数据的 POST 请求

要先定义一个 Message 类,描述请求 body 的内容,方便 jackson 进行 json 解析。

class Message {
    public String from;
    public String to;
    public String message;
}


先构建一个 ObjectMapper,再读取 body 里的内容,然后再解析成一个 Message 对象,
最后就是填到 List 变量里。

// 暂时使用 List 变量保存所有消息 —— 比较简单粗暴
private List<Message> messageList = new ArrayList<>();

// 向服务器提交数据
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
    // 构造一个 ObjectMapper
    ObjectMapper objectMapper = new ObjectMapper();
    // 把 body 的内容读取出来,解析成一个 Massage 对象
    Message message = objectMapper.readValue(req.getInputStream(), Message.class);
    messageList.add(message);
    // 设置状态码,不设置默认也是 200
    resp.setStatus(200);
}



3、实现从服务器获取数据的 GET 请求

获取数据直接从 List 变量获取即可,也就是把 List 对应的结果给转成 json 格式的字符串,返回即可。

// 从服务器获取数据
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
    // 显示的告诉浏览器,数据格式是 json 格式,字符集是 utf-8
    resp.setContentType("application/json; charset = utf-8");
    // 第一个参数表示写到哪里,第二个参数表示写的内容是什么
    objectMapper.writeValue(resp.getWriter(), messageList);
}


getWriter() 这个方法同时把 java 对象转成了 json 字符串和吧这个字符串写到响应对象中。

针对 doGet,只是把 messageList 转成 json 字符串,然后返回给浏览器即可。


此时后端代码就写完了,启动服务器,然后打开 postman 发送请求验证一下。

javaEE初阶 — 服务器版本的表白墙案例_第13张图片

先选择 POST,在 body 里输入内容后点击 Send 发送一个请求。

之后,切换为 GET 接收,再次点击 Send 就可以得到下面的结果了,下面是发送了三次请求的结果。

javaEE初阶 — 服务器版本的表白墙案例_第14张图片

实现前端代码


编写前端代码,让页面能够发起请求,并解析响应。

post 是点击提交按钮的时候发起的,get 是页面加载的时候发起的。

1 点击提交的时给服务器发送一个 POST 请求


首先要将前端代码的文件复制到 webapp 目录下。

javaEE初阶 — 服务器版本的表白墙案例_第15张图片

javaEE初阶 — 服务器版本的表白墙案例_第16张图片

然后以 vscode 打开。

javaEE初阶 — 服务器版本的表白墙案例_第17张图片


首先要引入 jQuery

搜索 jQuery cdn,将链接复制到 script 标签里的 src 属性里。

 <script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>


POST 是在点击提交按钮的时候触发的,点击这里的 button 就是点击了按钮。
此时就会触发了 POST 请求。

 let button = document.querySelector('#submit');


javaEE初阶 — 服务器版本的表白墙案例_第18张图片

当前的代码再点击提交按钮后,会触发 onclick 回调方法,这里的回调方法只是构造了一个新的 div。

接下来要做的就是实现一个新的步骤,把上述代码中的数据提交到服务器里。

 // [新增]4. 使用 ajax 构造一个 post 请求, 把上述数据提交到服务器里
 // 构造一个 body
 let body = {
     "from": from,
     "to": to,
     "message": message 
 }

 $.ajax({
     // 这里是要构造的请求类型
     type: 'post',
     // 这里的路径要和之前约定好的前后端交互接口一致
     url: i'message',
     // post 请求是有 body 的,所以就要设置一个 body
     data: 
 });


javaEE初阶 — 服务器版本的表白墙案例_第19张图片

这里设置的 body 是 定义了一个 js 对象,类似于 json 的键值对。

key 是一个字符串,也就是图中的 “from”、“to”、“message” 三个。
value 则是 js 中的变量/常量,也就是字符串后面的值。


在 js 中要求对象的 key 务必是字符串,因此此处的代码还可以是以下的写法:

javaEE初阶 — 服务器版本的表白墙案例_第20张图片

javaEE初阶 — 服务器版本的表白墙案例_第21张图片

当前 body 里的 vlaue 值是由页面上的输入框读取到的内容放到变量里的。

需要注意的是当前的 js 对象不是字符串,在网络传输中,只能传字符串,不能传对象。
接下来需要把这个对象转成一个字符串。

javaEE初阶 — 服务器版本的表白墙案例_第22张图片


接下来进行的操作是将 js 对象转成一个 json 格式的字符串。

在 js 中内置了 json 的转换库,此时就不需要像 java 好要有第三方库 jackson 了。

可以使用 JSON.stringify 转为 json 格式的字符串。

// 将 js 对象转为 json 格式的字符串
let strBody = JSON.stringify(body);
// 打印日志
console.log("strBody:" + strBody);
$.ajax({
    // 这里是要构造的请求类型
    type: 'post',
    // 这里的路径要和之前约定好的前后端交互接口一致
    url: 'message',
    // post 请求是有 body 的,所以就要设置一个 body
    data: strBody,
    // 指定 body 的具体格式
    setContentType: "application/json; charset = utf-8",
    success: function(body) {
        console.log("数据发布成功!")
    }
});



接下来启动服务器观察结果。

在启动服务器之后,就可以通过浏览器来打开表白墙的页面了。

在地址栏输入路径,就可以看到表白墙页面了。

javaEE初阶 — 服务器版本的表白墙案例_第23张图片


打开 fiddler 抓包观察结果。

javaEE初阶 — 服务器版本的表白墙案例_第24张图片

javaEE初阶 — 服务器版本的表白墙案例_第25张图片

根据前端代码的设置可以看到抓包的结果各个设置是一样的。

2 在页面加载时发送一个 GET 请求


这里构造的就是一个 get 请求了。

 // [新增] 在页面加载的时候,发送 GET 请求,从服务器获取数据并添加到页面中
 $.ajax({
     type: 'get',
     url: 'message',
     success: function(body) {
         // 这里的 body 已经是一个 js 的对象数组了 
         // 本来服务器返回的是一个 json 格式的字符串,但是 jQuery 的 ajax 自动识别并转化了
         // 接下来遍历这个数据,把元素取出来构造页面中即可
         for(let message of body) {
             // 针对每一个元素构造一个 div
             let rowDiv = document.createElement('div');
             rowDiv.className = 'row'; // 有了一个 row 的属性
             rowDiv.innerHTML = message.from + ' 对 ' + message.to + ' 说: ' + message.message;
             containerDiv.appendChild(rowDiv); 
         }
     }
 });


本来需要将 json 格式的字符串转为一个 js 对象数组,但是由于 jQuery 的 ajax 自动转化了。
因此这里的 body 已经是一个 js 对象了。

3 将数据保存到数据库中


由于当前的数据是借助变量保存的,重启服务器后就会导致数据消失。
因此想要永久的保存,就需要来借助数据库保存。


1、首先要创建一个数据表。

javaEE初阶 — 服务器版本的表白墙案例_第26张图片

当前已创建完成。


2、创建一个 DBUtil 类。

需要注意的是 jdbc:mysql://127.0.0.1:3306/web?characterEncoding=utf8&useSSL=false
这条语句里的 web 是我的数据库名,在这里要根据实际情况来更改。

// 通过这个类把数据库连接过程封装一下
// 此处把 DBUtil 作为一个工具类,提供 static 方法来供其他代码调用
public class DBUtil {
    private static DataSource dataSource = new MysqlDataSource();
    
    static {
        // 使用静态代码块,针对 dataSource 进行初始化操作
        ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/web?characterEncoding=utf8&useSSL=false");
        ((MysqlDataSource)dataSource).setUser("root");
         // 密码是什么,写什么
        ((MysqlDataSource)dataSource).setPassword("000000");
    }

    // 通过这个方法来建立连接
    public static Connection getConnection() throws SQLException {
        return (Connection)dataSource.getConnection();
    }

    // 通过这个方法来释放资源
    public static void close(Connection connection, PreparedStatement statement, ResultSet resultSet) {
        // 此处的 三个 try catch 分开写,避免前面的异常导致后面的代码不能运行
        if (resultSet != null) {
            try {
                connection.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();
            }
        }
    }
}



3、提供一对方法来保存数据

save 方法是用来往数据库中存数据。

 private void save(Message messageWall) {
        // JDBC 操作
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            // 1.建立连接
            connection = DBUtil.getConnection();
            // 2.构造 sql 语句
            String sql = "insert into messagewall values(?, ?, ?)";
            statement = (PreparedStatement)connection.prepareStatement(sql);
            // 将上面的三个 ? 占位符替换为 from to message
            statement.setString(1, messageWall.from);
            statement.setString(2, messageWall.to);
            statement.setString(3, messageWall.message);
            // 3.执行 sql
            statement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 4.关闭连接
            DBUtil2.close(connection, statement, null);
        }
    }


load 方法是用来从数据库中拿数据。

 private List<Message> load() {

        List<Message> messageList = new ArrayList<>();

        Connection connection = null;
        ResultSet resultSet = null;
        PreparedStatement statement = null;
        try {
            // 1.和数据库建立连接
            connection = DBUtil.getConnection();
            // 2.构造 sql 语句
            String sql = "select * from messagewall";
            statement = (PreparedStatement)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 中
                messageList.add(message);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            // 5.断开连接
            DBUtil2.close(connection, statement, resultSet);
        }
        return messageList;
    }

你可能感兴趣的:(项目,java-ee,服务器,servlet,javascript,java)