JavaEE Elementary - Server Version Confession Wall Case

Issues covered by the original version


confession wall link

There are two very serious problems with the previously completed confession wall:

1. If the page is refreshed or closed and reopened, the messages saved before the confession wall will disappear

2. The data of the confession wall can only be seen in the local browser.



At this time, if the page is refreshed or closed and reopened, the data of the confession wall will disappear.



Solutions

Let the server store the data submitted by the user, and the server will save it.

Get data from the server when a new browser opens the page.

design process


To implement a web program, it is necessary to consider how the front-end and back-end interact, and to agree on the data format for the front-end and back-end interaction.

For example:
design the front-end and back-end interaction interfaces, what is the request, what is the response, when the browser sends the request, and what format the browser parses.


There are two links involving the interaction between the front and back ends:

One is when you click Submit, that is, the browser sends the confession information to the server.
One is when the page is loaded, that is, the browser obtains confession information from the server.

1 click to submit


The request can use POST , and then use a path like /message .

It is agreed that the current body is provided in json format

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


The response can be agreed upon as, HTTP/1.1 200 OK

2 page load


The request can be agreed to be GET , followed by a /message path, and the response can also be agreed to be HTTP/1.1 200 OK .

It's just that the response at this time should be parsed according to the format of the json array .

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


There are no fixed mandatory requirements for the agreement here, as long as the necessary requirements can be guaranteed.
The purpose here is to match the front-end code and the back-end code.

Implement the backend code

1 Create a new Maven project.


2 Follow the steps of the first Servlet program to set up


The first Servlet program link

1. First, introduce Servlet, jackson, and mysql dependencies , and introduce these three dependencies into the dependencies tag.

Open https://mvnrepository.com/ , search for servlet, and find version 3.1.0 .



Select the Servlet shown above, click to select version 3.1.0.



After clicking in, copy the code under Maven to the dependencies tag of the pom.xml file.



jackson select as shown below





and click on version 2.14.2 , and the rest of the steps are the same as servlet.



The mysql dependency is selected as shown in the figure below.


The mysql dependency is introduced here because the database can be used to save the data submitted by the user.

Select version 5.1.49 .



The rest of the steps are the same as servlet.




The above is a good look at the introduction of the three dependencies.


2. Next, start to create a directory




3. Add a little content to web.xml

3 Create a new MessageServlet class


The path here should be the same as agreed before.



1. Rewrite the doPost and doGet methods




2. Realize the POST request to submit data to the server

. First define a Message class to describe the content of the request body, so that jackson can parse the json.

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


First build an ObjectMapper, then read the content in the body, then parse it into a Message object,
and finally fill it in the List variable.

// 暂时使用 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. Realize the GET request to obtain data from the server.

The data can be obtained directly from the List variable, that is, the result corresponding to the List can be converted into a string in json format and returned.

// 从服务器获取数据
@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);
}


The getWriter() method simultaneously converts the java object into a json string and writes the string into the response object.

For doGet, just convert the messageList into a json string, and then return it to the browser.


At this point, the back-end code is finished, start the server, and then open postman to send a request for verification.



First select POST, enter the content in the body and click Send to send a request.

After that, switch to GET to receive, and click Send again to get the following result, which is the result of sending three requests.

Implement the front-end code


Write the front-end code so that the page can initiate a request and parse the response.

post is initiated when the submit button is clicked, and get is initiated when the page loads.

1 Send a POST request to the server when you click Submit


First, copy the files of the front-end code to the webapp directory.





Then open it with vscode.




First, import jQuery

to search jQuery cdn , and copy the link to the src attribute in the script tag.

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


POST is triggered when the submit button is clicked, clicking the button here means clicking the button.
At this point a POST request is triggered.

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




After the current code clicks the submit button, the onclick callback method will be triggered. The callback method here just constructs a new div.

The next thing to do is to implement a new step to submit the data in the above code to the server.

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

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




The body set here defines a js object, which is similar to the key-value pair of json.

The key is a string, which is "from", "to", and "message" in the figure.
value is a variable/constant in js, that is, the value after the string.


In js, the key of the object must be a string, so the code here can also be written as follows: the





vlaue value in the current body is put into the variable by the content read by the input box on the page.

It should be noted that the current js object is not a string. In network transmission, only strings can be transmitted, objects cannot be transmitted.
Next you need to convert this object into a string.




The next operation is to convert the js object into a string in json format.

The json conversion library is built in js, so there is no need for a third-party library jackson like java.

You can use JSON.stringify to convert to a string in json format.

// 将 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("数据发布成功!")
    }
});



Next start the server and observe the results.

After starting the server, you can open the confession wall page through the browser.

Enter the path in the address bar, and you can see the confession wall page.




Open fiddler to capture packets and observe the results.





According to the settings of the front-end code, it can be seen that the results of packet capture are the same for each setting.

2 Send a GET request on page load


What is constructed here is a get request.

 // [新增] 在页面加载的时候,发送 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); 
         }
     }
 });


It was originally necessary to convert the string in json format into an array of js objects, but it was automatically converted due to jQuery's ajax.
So the body here is already a js object.

3 Save the data to the database


Since the current data is saved by means of variables, restarting the server will cause the data to disappear.
Therefore, if you want to save it permanently, you need to save it with the help of a database.


1. First, create a data table.



Currently created.


2. Create a DBUtil class.

Note that jdbc:mysql://127.0.0.1:3306/web?characterEncoding=utf8&useSSL=false .
The web in this statement is my database name, which needs to be changed according to the actual situation.

// 通过这个类把数据库连接过程封装一下
// 此处把 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. Provide a pair of methods to save data

The save method is used to store data in the database.

 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);
        }
    }


The load method is used to get data from the database.

 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;
    }

Guess you like

Origin blog.csdn.net/m0_63033419/article/details/130278421