【JavaEE+Servlet】练习小项目:服务器版表白墙

本文档详细介绍了如何使用Servlet API创建一个服务器版的表白墙程序,实现了数据的持久化存储,确保页面关闭后数据不丢失。通过约定前后端交互接口,使用GET和POST请求获取和提交留言,结合jQuery AJAX进行异步通信,并利用MySQL数据库保存数据,确保即使服务器重启,留言记录依然保留。此外,还展示了前端页面的HTML和JavaScript代码,以及数据库连接和操作的方法。
摘要由CSDN通过智能技术生成

结合servlet API,实现一个服务器版本的表白墙程序. 即使页面关闭, 表白墙的内容也不会丢失(实现持久化存储数据)

1. 准备工作

  1. 创建 maven 项目.
  2. 创建必要的目录 webapp, WEB-INF, web.xml
    在这里插入图片描述
    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
    引入依赖, 配置生成 war 包, 以及 war 包名字
<?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>message_wall</artifactId>
    <version>1.0-SNAPSHOT</version>

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

<!--    servlet驱动包-->
    <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>

<!--        Jackson驱动包-->
        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.12.6.1</version>
        </dependency>

<!--   引入MySQL驱动包     -->
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>


    </dependencies>

</project>
  1. 实现表白墙前端页面拷贝到 webapp 目录中.
<!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>
        *{
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        .container{
            width: 100%;
        }
        h3{
            text-align: center;
            padding: 20px 0;
            font-size: 30px;
        }
        p{
            text-align: center;
            color: #666;
            padding: 10px 0;
        }

        .row {
            width: 400px;
            height: 50px;
            margin: 0 auto;

            display:flex;
            justify-content: center;
            align-items: center;
        }

        .row span{
            width: 100px;
            font-size: 20px;
        }
        .row input{
            width: 300px;
            height: 40px;
            line-height: 40px;
            font-size: 20px;
            text-indent: 0.5em ;
            outline: none;

        }
        .row #submit{
            width: 300px;
            height: 40px;
            font-size: 20px;
            line-height: 40ox;
            margin: 0 auto;

            color: white;
            background-color: orange;

            border: none;
            border-radius: 10px;
        }
        .row #submit:active{
            background-color: grey;
        }
    </style>
    <h3>表白墙</h3>
    <p>输入后点击提交,信息会显示在表格中</p>
    <div class="container">
        <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="http://code.jquery.com/jquery-2.1.1.min.js"></script>

    <script>
        //当用户点击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 mesg=inputs[2].value;

            if(from==''||to==''||mesg==''){
                //用户还没填写完,暂时先不提交数据
                return;
            }
            //2.生成一个新的div,内容就是input里的内容,把这个新的div加到页面中
            let div=document.createElement('div');
            div.innerHTML=from+'对'+to+'说'+mesg;
            div.className='row';
            let container=document.querySelector('.container');
            container.appendChild(div);

            //3.提交后清空原有数据操作
        
            for(let i=0;i<inputs.length;i++){
                inputs[i].value='';
            }

       
    </script>
</body>
</html>

在这里插入图片描述

2. 约定前后端交互接口

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

2.1 获取全部留言功能接口

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

GET /message

响应: JSON 格式

[
{
from: “xx”,
to: “xx”,
message: “x”
},
{
from: “xxx”,
to: “xxx”,
message: “xx”
},

]

2.2 发表新留言功能接口

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

请求: body 也为 JSON 格式

POST /message
{
from: “xxx”,
to: “xxx”,
message: “xx”
}

响应: JSON 格式.

{
ok: true
}

3. 服务器端代码整体如下

// import具体省略
class Message {
    public String from;
    public String to;
    public String message;
}
@WebServlet("/message")
public class MessageServlet extends HttpServlet {
    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);
        // 通过 ContentType 来告知页面, 返回的数据是 json 格式.
        // 有了这样的声明, 此时 jquery ajax 就会自动的帮我们把字符串转成 js 对象.
        // 如果没有, jquery ajax 就只是当成字符串来处理的~~
        save(message);

        resp.setContentType("application/json; charset=utf8");
        resp.getWriter().write("{\"ok\":true}");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取到消息列表
        // 获取到消息列表. 只要把消息列表中的内容整个的都返回给客户端即可
        // 此处需要使用 ObjectMapper 把 Java 对象, 转成 JSON 格式字符串~
        List<Message> messages=load();
        String jsonString=objectMapper.writeValueAsString(messages);
        System.out.println("jsonString"+jsonString);
        resp.setContentType("application/json; charset=utf8");
        resp.getWriter().write(jsonString);

    }

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

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

  • ObjectMapperreadValue 方法能直接从一个 InputStream 对象读取数据.,将json格式字符串转成Java对象
  • ObjectMapperwriteValueAsString 方法也能把一个对象数组直接转成 JSON 格式的字符串

4. 调整前端页面代码

加上ajax发送http请求给服务器的前端页面代码如下:

<!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>
        *{
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        .container{
            width: 100%;
        }
        h3{
            text-align: center;
            padding: 20px 0;
            font-size: 30px;
        }
        p{
            text-align: center;
            color: #666;
            padding: 10px 0;
        }

        .row {
            width: 400px;
            height: 50px;
            margin: 0 auto;

            display:flex;
            justify-content: center;
            align-items: center;
        }

        .row span{
            width: 100px;
            font-size: 20px;
        }
        .row input{
            width: 300px;
            height: 40px;
            line-height: 40px;
            font-size: 20px;
            text-indent: 0.5em ;
            outline: none;

        }
        .row #submit{
            width: 300px;
            height: 40px;
            font-size: 20px;
            line-height: 40ox;
            margin: 0 auto;

            color: white;
            background-color: orange;

            border: none;
            border-radius: 10px;
        }
        .row #submit:active{
            background-color: grey;
        }
    </style>
    <h3>表白墙</h3>
    <p>输入后点击提交,信息会显示在表格中</p>
    <div class="container">
        <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="http://code.jquery.com/jquery-2.1.1.min.js"></script>

    <script>
        //加入ajax的代码,此处要加入的逻辑有两个部分
        //点击提交按钮的时候,ajax要构造数据发送给服务器
        //页面加载时候,从服务器获取消息列表,显示在页面上
        function getMessages(){
            $.ajax({
                type:'get',
                url:'message',
                success:function(body){
                    //当前body已经是一个js对象数组了,ajax会根据相应的content type来进行自动解析
                    //如果服务器返回的content type已经是applocation/json了,ajax就会把body自动转成js的对象
                    //如果客服端没有自己转,也可以通过 json.parse()这个函数来手动转

                    //依次来取数组中的每个元素
                    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 mesg=inputs[2].value;

            if(from==''||to==''||mesg==''){
                //用户还没填写完,暂时先不提交数据
                return;
            }
            //2.生成一个新的div,内容就是input里的内容,把这个新的div加到页面中
            let div=document.createElement('div');
            div.innerHTML=from+'对'+to+'说'+mesg;
            div.className='row';
            let container=document.querySelector('.container');
            container.appendChild(div);

            //3.提交后清空原有数据操作
        
            for(let i=0;i<inputs.length;i++){
                inputs[i].value='';
            }

            //4.把当前获取到的输入框内容,构造成一个post请求,通过ajax发送给服务器
            let body={
                from:from,
                to:to,
                message:mesg
            };

            $.ajax({
                type: "post",
                url: "message",
                contentType: "application/json;charset=utf8",
                // 把body转json格式的字符串
                data: JSON.stringify(body),
                success:function(body){
                    alert("消息提交成功!")
                },
                error:function(body){
                    alert("消息提交失败!")
                }
            });
        }
    </script>
</body>
</html>

此时我们每次提交的数据都会发送给服务器. 每次打开页面的时候页面都会从服务器加载数据. 因此及时
关闭页面, 数据也不会丢失.

6. 数据存入数据库

可以借助数据库完成存储工作,此时即使重启服务器, 留言数据也不会丢失了.

  1. 在 pom.xml 中引入 mysql 的依赖
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.45</version>
</dependency>
  1. 创建数据库, 创建 messages 表,表结构如下:
    在这里插入图片描述
  2. 创建 DBUtil 类
    DBUtil 类主要实现以下功能:
  • 创建 MysqlDataSource 实例, 设置 URL, username, password 等属性.
    提供 getConnection 方法, 和 MySQL 服务器建立连接.
    提供 close 方法, 用来释放必要的资源.

代码如下:

import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class DBUtil {
    private static final String URL = "jdbc:mysql://127.0.0.1:3306/java102?characterEncoding=utf8&useSSL=false";
    private static final String USERNAME = "root";
    private static final String PASSWORD = "1963";

    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(USERNAME);
                    ((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();
            }
        }
    }
}
  1. 实现 load 和 save 方法, 改成操作数据库 :
    save方法:
 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);
        }

    }

load方法:

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

doget方法和dopost方法需要注意的点如下:
在这里插入图片描述
重新部署程序, 此时使用数据库之后也可以保证即使服务器重启, 数据也不丢失

7. 整体效果演示 :

因为之前已经提交过四次操作,此时一打开页面就能显示之前提交的记录:
在这里插入图片描述
提交相应的记录,数据库记录相应增加
在这里插入图片描述
在这里插入图片描述
所有功能均实现成功无异常~

  • over~✨
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值