在线表白墙项目

  • 一、首先要清楚前端要工作的内容
  • 二、前端代码
  • 三、后端
  • 1. 准备idea环境
  • 2. 约定前后端交互接口
  • 3. 后端代码
  • 1. Message类 用于发送和接收数据(也用于方便存储数据库)
  • 2. 连接数据库的类 DBUtil
  • 3. 实现后端功能 类



【项目—前后端交互 案例】表白墙

  • 一、首先要清楚前端要工作的内容
  • 二、前端代码
  • 三、后端
  • 1. 准备idea环境
  • 2. 约定前后端交互接口
  • 3. 后端代码
  • 1. Message类 用于发送和接收数据(也用于方便存储数据库)
  • 2. 连接数据库的类 DBUtil
  • 3. 实现后端功能 类


先学习servlet

一、首先要清楚前端要工作的内容

JAVA 如何使OOM项目假死_java

二、前端代码

<!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>表白墙</title>
</head>
<body>
    <style>
        .container {
            width: 400px;
            /* margin 外边距. 第一个数字上下外边距, 第二个数字表示水平外边距. 如果水平设置成 auto 表示元素就水平居中~~ */
            margin: 0 auto;
        }

        h1 {
            text-align: center;
        }

        p {
            text-align: center;
            color: #666;
        }

        .row {
            height: 40px;
            display: flex;
            /* 水平居中 */
            justify-content: center;
            /* 垂直居中 */
            align-items: center;
        }

        .row span {
            width: 100px;
        }

        .row input {
            width: 200px;
            height: 30px;
        }

        .row button {
            width: 306px;
            height: 40px;
            color: white;
            background: orange;
            border: none;
        }

        .row button:active {
            background-color: #666;
        }
    </style>

    <div class="container">
        <h1>表白墙</h1>
        <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>提交</button>
        </div>

        <!-- 需要构造出一个形如 -->
        <!-- <div class="row">
            黑猫 对 白猫 说: 喵
        </div> -->
    </div>

    <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>

    <script>
        let container = document.querySelector('.container');
        let button = document.querySelector('button');
        button.onclick = function() {
            // 1. 获取到输入框的内容
            let inputs = document.querySelectorAll('input');
            let from = inputs[0].value;
            let to = inputs[1].value;
            let message = inputs[2].value;
            if (from == '' || to == '' || message == '') {
                alert('当前输入框内容为空!');
                return;
            }
            console.log(from + ", " + to + ", " + message);
            // 2. 能够构造出新的 div, 用来保存用户提交的内容
            let rowDiv = document.createElement('div');
            rowDiv.className = 'row';
            rowDiv.innerHTML = from + " 对 " + to + " 说: " + message;
            container.appendChild(rowDiv);
            // 3. 提交完之后, 清空输入框的内容
            for (let i = 0; i < inputs.length; i++) {
                inputs[i].value = '';
            }

            let data = {
                from: from,
                to: to,
                message: message
            };
            // 4. 点击发送按钮, 给服务器发个 post 请求. 
            $.ajax({
                type: 'post',
                url: 'message',
                // url: '/java105/message',
                // 这里放的是 body 的内容
                data: JSON.stringify(data),
                contentType: "application/json; charset=utf8",
                success: function(body) {
                    console.log("提交数据成功");
                }
            });
        }

        // 直接写在 script 标签里的代码, 都是在页面加载的时候执行的. 
        // 来获取服务器的数据
        function getMessages() {
            $.ajax({
                type: 'get' ,
                url: 'message',
                success: function(body) {
                    // body 就是响应的 body 内容, json 数组. 
                    // jquery 非常智能的帮我们把 json 数组给解析成了 js 对象数组
                    // 但是有个前提条件, 就是响应的 Content-Type 得是 application/json
                    let container = document.querySelector('.container');
                    for (let i = 0; i < body.length; i++) {
                        let message = body[i];
                        // 根据这个元素构造一个 div.row, 来容纳数据
                        // <div class="row">
                        //     黑猫 对 白猫 说: 喵
                        // </div>
                        let row = document.createElement('div');
                        row.className = 'row';
                        row.innerHTML = message.from + " 对 " + message.to + " 说: " + message.message;
                        container.appendChild(row);
                    }
                }
            });
        }

        getMessages();
    </script>
</body>
</html>

三、后端

1. 准备idea环境

  1. 创建 maven 项目.
  2. 创建必要的目录 webapp, WEB-INF, web.xml
<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
    <display-name>Archetype Created Web Application</display-name>
</web-app>
  1. 调整 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>MessageWall</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.13.4.1</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>

    </dependencies>

</project>
  1. 把之前实现的表白墙前端页面拷贝到 webapp 目录中.

2. 约定前后端交互接口

所谓 “前后端交互接口” 是进行 Web 开发中的关键环节.
具体来说, 就是允许页面给服务器发送哪些 HTTP 请求, 并且每种请求预期获取什么样的 HTTP 响应

  1. 获取全部留言
  2. JAVA 如何使OOM项目假死_sql_02

  3. 我们期望浏览器给服务器发送一个 GET /message 这样的请求, 就能返回当前一共有哪些留言记录. 结果以 json 的格式返回过来.
  4. 发表新留言

请求: body 也为 JSON 格式.

JAVA 如何使OOM项目假死_java_03


我们期望浏览器给服务器发送一个 POST /message 这样的请求, 就能把当前的留言提交给服务


3. 后端代码

1. Message类 用于发送和接收数据(也用于方便存储数据库)
public class Message {
    private String from;
    private String to;
    private String message;

    public String getFrom() {
        return from;
    }

    public void setFrom(String from) {
        this.from = from;
    }

    public String getTo() {
        return to;
    }

    public void setTo(String to) {
        this.to = to;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
2. 连接数据库的类 DBUtil
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;

import javax.sql.DataSource;

// 使用这个类来封装 DataSource 的单例
public class DBUtil {
    private static volatile DataSource dataSource = null;

    public static DataSource getDataSource() {
        if (dataSource == null) {
            synchronized (DBUtil.class) {
                if (dataSource == null) {
                    dataSource = new MysqlDataSource();
                    ((MysqlDataSource)dataSource).setUrl("jdbc:mysql://127.0.0.1:3306/MessageWall?characterEncoding=utf8&useSSL=false");
                    ((MysqlDataSource)dataSource).setUser("root");
                    // 我这里的数据库是没密码的.
                    ((MysqlDataSource)dataSource).setPassword("123456");
                }
            }
        }
        return dataSource;
    }

    private DBUtil() {}
}
3. 实现后端功能 类
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;

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 javax.sql.DataSource;
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;

@WebServlet("/message")
public class MessageServlet extends HttpServlet {
    // 这个对象在多个方法中都需要使用
    private ObjectMapper objectMapper = new ObjectMapper();

    // 负责让页面获取到数据
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 显式声明当前的响应数据格式 不要让客户端去猜!!!
        resp.setContentType("application/json; charset=utf8");
        // 把 messageList 转成 json 字符串, 并且返回给页面就行了.
        List<Message> messageList = null;
        try {
            messageList = load();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        resp.getWriter().write(objectMapper.writeValueAsString(messageList));
    }

    // 提交数据
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取到 body 中的数据并解析
        Message message = objectMapper.readValue(req.getInputStream(), Message.class);
        // 把这个 message 保存一下. 简单的办法就是保存在内存中.
        // messageList.add(message);
        try {
            save(message);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        resp.setStatus(200);

        System.out.println("提交数据成功: from=" + message.getFrom()
                + ", to=" + message.getTo() + ", message=" + message.getMessage());
    }

    private List<Message> load() throws SQLException {
        // 从数据库查询数据

        // 1. 先有一个数据源
        DataSource dataSource = DBUtil.getDataSource();

        // 2. 建立连接
        Connection connection = dataSource.getConnection();

        // 3. 构造 SQL
        String sql = "select * from messages";
        PreparedStatement statement = connection.prepareStatement(sql);

        // 4. 执行 SQL
        ResultSet resultSet = statement.executeQuery();

        // 5. 遍历结果集合
        List<Message> messageList = new ArrayList<>();
        while (resultSet.next()) {
            Message message = new Message();
            message.setFrom(resultSet.getString("from"));
            message.setTo(resultSet.getString("to"));
            message.setMessage(resultSet.getString("message"));
            messageList.add(message);
        }

        // 6. 关闭连接
        statement.close();
        connection.close();
        return messageList;
    }

    private void save(Message message) throws SQLException {
        // 把数据保存到数据库中

        // 1. 先有一个数据源
        DataSource dataSource = DBUtil.getDataSource();

        // 2. 建立连接
        Connection connection = dataSource.getConnection();

        // 3. 构造 SQL
        String sql = "insert into messages values(?, ?, ?)";
        PreparedStatement statement = connection.prepareStatement(sql);
        statement.setString(1, message.getFrom());
        statement.setString(2, message.getTo());
        statement.setString(3, message.getMessage());

        // 4. 执行 SQL
        int ret = statement.executeUpdate();
        System.out.println("ret = " + ret);

        // 5. 关闭连接
        statement.close();
        connection.close();
    }
}