Servlet 综合案例:表白墙

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: 在学习过上文【Servlet API详解】的各位小主们,相信对Servlet的基本使用已经有了一定的掌握,这篇博文,博主带大家来手把手搭建一个小网站——表白墙,是对【JavaScript进阶3.2 表白墙案例】的一个升级版,也是对前边知识的一个综合运用,相信通过这一篇博文,能让各位小主get到一个网站的开发流程大概是什么样的,期待与你的共同进步!

1.约定接口


实现这个表白墙案例的第一步,就是需要自定义应用层协议,确定好客户端和服务器如何进行交互。


数据能够进行存储的格式有很多种,也就是前后端需要共同指定数据格式,以便在客户端向服务器发送给去数据请求后,能够按照彼此约定好的应用层协议进行数据解析。


对于表白墙来说,主要要提供两个接口,要约定好客户端要发送一个怎样的HTTP请求,服务器返回一个怎样的HTTP响应,下边我们会直接指定数据格式为json格式:


接口一:

告诉服务器,当前留言了一条怎样的数据

(当用户点击提交按钮的时候,就会给服务器发送一个HTTP请求,让服务器把这个消息给存下来)


微信图片_20230111171450.png

接口二:

从服务器获取到当前都有哪些留言数据

(当页面加载,就需要从服务器获取到曾经存储的留言内容)


微信图片_20230111171447.png

在我们确定好接口后,就可以进行代码的编写了。


2.后端框架搭建


我们接下来,就按照常规Servlet程序的搭建流程进行搭建,先进性整体框架的搭建。


1.创建maven项目


微信图片_20230111171443.png

2.引入依赖

(引入Servlet依赖和JSON依赖)


微信图片_20230111171440.png

3.创建目录


微信图片_20230111171436.png

4.编写代码

(只编写简单代码,用于测试是否搭建接口完成)


@WebServlet("/message")
public class MessageServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("hello get");
    }
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.getWriter().write("hello post");
    }
}


5、6.打包部署


微信图片_20230111171432.png

7.验证


微信图片_20230111171429.png

3.实现服务器端代码


先将消息列表存储到内容中(通过顺序表实现)


/**
 * 与json格式对应的类
 */
class Message {
    public String from;
    public String to;
    public String message;
}
@WebServlet("/message")
public class MessageServlet extends HttpServlet {
    //用于将类和json进行转换的类
    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);
        //指定响应的数据格式
        resp.setContentType("application/json;charset=utf8");
        resp.getWriter().write("{\"ok\":true}");
    }
    /**
     *获取消息列表,把消息列表中的内容返回给客户端
     */
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //将Java对象转成JSON格式字符串
        String jsonString=objectMapper.writeValueAsString(messages);
        System.out.println("jsonString:"+jsonString);
        resp.setContentType("application/json;charset=utf8");
        resp.getWriter().write(jsonString);
    }
}

4.构造请求测试服务器端


利用应用postman来进行构造请求,用于测试服务器端代码。


postman可自行下载,专门用来构造HTTP请求,进行服务器端的测试。


首先我们在idea通过smart tomcat启动服务器,然后进行测试。


微信图片_20230111171418.png

对接口一进行测试,构造POST请求,输入数据。


微信图片_20230111171414.png

对接口二进行测试,构造GET请求,得到对接口一测试时输入的消息列表,测试完成。


微信图片_20230111171410.png

5.调整前端页面代码


在之前文章【JavaScript进阶3.2 表白墙案例】的表白墙代码可以直接拿来用,再进行调整,完成两个接口的功能即可。

微信图片_20230111171406.png

将该前端html文件拷贝到webapp目录下,再进一步调整完善前端代码的ajax请求


对前端代码的调整,主要的逻辑有两部分:

1.点击提交按钮时,ajax要构造数据发送给服务器。

2.页面加载的时候,从服务器获取消息列表,并在界面上直接显示。


首先我们还是先引入jQuery


微信图片_20230111171904.png

功能1:把当前输入框的内容,构造成一个HTTP POST请求,通过ajax发送给服务器。

微信图片_20230111171401.png

功能2:通过函数完成消息列表的获取打印。

微信图片_20230111171358.png

完整前端代码:


<!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>Document</title>
</head>
<body>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            background-color: rgb(30,100,200);
        }
        .container {
            width: 100%;
        }
        h3 {
            text-align: center;
            padding: 30px 0;
            font-size: 24px;
            color: rgb(255,140,10);
        }
        p {
            text-align: center;
            color: rgba(255, 50, 100);
            font-size: 18px;
            padding: 5px 0;
        }
        .row {
            width: 400px;
            height: 50px;
            margin: 0 auto;
            display: flex;
            justify-content: center;
            align-items: center;
        }
        .row span{
            width: 100px;
            height: 40px;
            text-align: center;
            padding-right: 0px;
            font-size: 24px;
            color: rgb(255,140,10);
        }
        .row input {
            width: 300px;
            height: 40px;
            border: 2px solid  rgb(255, 140,160);
            border-radius: 5px;
            outline: 0;
            text-align: left;
            padding-left: 0px;
            margin-left: 0px;
            text-indent: 0.4em;
            font-size: 20px;
            color: rgb(9, 245, 135);
        }
        .row #submit{
            width: 200px;
            height: 40px;
            border-radius: 10px;
            font-size: 24px;
            border: 0px solid  rgb(255, 140, 160);
            background-color:  rgb(255, 140, 160);
            color:  aliceblue;
            line-height: 40px;
            margin-top: 8px;
        }
        .row #submit:active{
            background-color: rgb(140,180,240);
        }
    </style>
    <div class="container">
        <h3>表白墙</h3>
        <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 id="submit">提交</button>
        </div>
    </div>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <script>
        function getMessages() {
            $.ajax({
                type:"get",
                url:'message',
                success:function(body) {
                    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 msg=inputs[2].value;
            if(from==''||to==''||msg=='') {
                // 用户还没有提交完,暂时先不提交数据
                return;
            }
            // 2.生成一个新的div,内容是input里面的内容,把这个新的div加到页面中
            let div=document.createElement('div');
            div.innerHTML=from+'对'+to+'说:'+msg;
            div.className='row';
            let container=document.querySelector('.container');
            container.appendChild(div);
            //3.清空之前输入框内的内容
            for(let i=0;i<inputs.length;i++) {
                inputs[i].value='';
            }
            //4.功能一
            let body={
                from:from,
                to:to,
                message:msg
            };
            $.ajax({
                type:"post",
                url:"message",
                contentType:"application/json;charset=utf8",
                data:JSON.stringify(body),
                success:function(body) {
                    alert("消息提交成功!");
                },
                error:function(body) {
                    alert("消息提交失败!");
                }
            });
        }
    </script>
</body>
</html>


效果预览:


微信图片_20230111171354.gif

通过将消息存入内容的方式,只要服务器不重启,可以使得页面即使刷新,消息列表也不会丢失,但如果将服务器重启,消息列表一定会丢失。所以如果想要将数据持久化存储,需要将数据写入硬盘,可以通过写入文件或者写入数据库的方式,下边我们就将消息存入数据库,实现数据的持久化存储。


6.数据存入数据库

1)引入mysql数据库依赖


微信图片_20230111171350.png

2)创建数据库


微信图片_20230111171347.png

3)创建DBUtil类,用于与数据库的交互。


public class DBUtil {
    private static final String url="jdbc:mysql://localhost:3306/homework?characterEncoding=utf8&useSSL=false";
    private static final String user="root";
    private static final String password="1234";
    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(user);
                    ((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();
            }
        }
    }
}

由于客户端发出的请求可能存在线程安全的问题,所以得到数据源的方法使用线程安全的单例模式


微信图片_20230111171342.png

4)调整Servlet代码,完成数据存入数据库


关键方法:


微信图片_20230111171338.png

微信图片_20230111171333.png

完整代码:


/**
 * 与json格式对应的类
 */
class Message {
    public String from;
    public String to;
    public String message;
}
@WebServlet("/message")
public class MessageServlet extends HttpServlet {
    //用于将类和json进行转换的类
    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);
        //指定响应的数据格式
        resp.setContentType("application/json;charset=utf8");
        resp.getWriter().write("{\"ok\":true}");
    }
    /**
     *获取消息列表,把消息列表中的内容返回给客户端
     */
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //将Java对象转成JSON格式字符串
        String jsonString=objectMapper.writeValueAsString(messages);
        System.out.println("jsonString:"+jsonString);
        resp.setContentType("application/json;charset=utf8");
        resp.getWriter().write(jsonString);
    }
    /**
     * 把一条消息保存到数据库中
     * @param message
     */
    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);
        }
    }
    /**
     * 从数据库中获取到所有的消息
     * @return
     */
    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;
    }
}


效果演示:


微信图片_20230111171323.gif

由上述演示可得,现在的消息已经写入数据库,能够持久化存储了,至此,表白墙小案例也就大功告成了,快自己动手试试吧!


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
6月前
Servlet使用适配器模式进行增删改查案例(IDeptService.java)
Servlet使用适配器模式进行增删改查案例(IDeptService.java)
|
6月前
Servlet使用适配器模式进行增删改查案例(EmpDaoImpl.java)
Servlet使用适配器模式进行增删改查案例(EmpDaoImpl.java)
|
6月前
Servlet使用适配器模式进行增删改查案例(DeptDaoImpl.java)
Servlet使用适配器模式进行增删改查案例(DeptDaoImpl.java)
|
6月前
Servlet使用适配器模式进行增删改查案例(IDeptDao.java和IEmpDao.java)
Servlet使用适配器模式进行增删改查案例(IDeptDao.java和IEmpDao.java)
|
6月前
Servlet使用适配器模式进行增删改查案例(IBaseDaoUtil.java)
Servlet使用适配器模式进行增删改查案例(IBaseDaoUtil.java)
|
6月前
Servlet使用适配器模式进行增删改查案例(BaseDao.java)
Servlet使用适配器模式进行增删改查案例(BaseDao.java)
|
6月前
Servlet使用适配器模式进行增删改查案例(Dept.java)
Servlet使用适配器模式进行增删改查案例(Dept.java)
|
6月前
|
存储 前端开发 JavaScript
Servlet实现一个简单的表白墙网站
前言 前面我们学习了 Java 中知名的 HTTP 服务器 tomcat 的安装和使用,还学习了 servlet 相关 API 的学习,今天,这篇文章我们将运用前面学习的 HTTP 知识、tomcat和servlet来实现一个简单的表白墙网站。
Servlet实现一个简单的表白墙网站
|
前端开发 应用服务中间件 C++
使用Servlet实现表白墙网站(前后端互联)小项目,Mac的M1(没有setting)在哪里找到Setting页面,下载smart tomcat及smart tomcat的配置。(二)
使用Servlet实现表白墙网站(前后端互联)小项目,Mac的M1(没有setting)在哪里找到Setting页面,下载smart tomcat及smart tomcat的配置。
使用Servlet实现表白墙网站(前后端互联)小项目,Mac的M1(没有setting)在哪里找到Setting页面,下载smart tomcat及smart tomcat的配置。(二)
|
6月前
Servlet使用适配器模式进行增删改查案例(Emp.java)
Servlet使用适配器模式进行增删改查案例(Emp.java)