Servlet 综合案例:表白墙

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
简介: 在学习过上文【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

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


相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
存储 前端开发 JavaScript
Servlet实现一个简单的表白墙网站
前言 前面我们学习了 Java 中知名的 HTTP 服务器 tomcat 的安装和使用,还学习了 servlet 相关 API 的学习,今天,这篇文章我们将运用前面学习的 HTTP 知识、tomcat和servlet来实现一个简单的表白墙网站。
Servlet实现一个简单的表白墙网站
Servlet使用适配器模式进行增删改查案例(IDeptService.java)
Servlet使用适配器模式进行增删改查案例(IDeptService.java)
Servlet使用适配器模式进行增删改查案例(EmpDaoImpl.java)
Servlet使用适配器模式进行增删改查案例(EmpDaoImpl.java)
Servlet使用适配器模式进行增删改查案例(DeptDaoImpl.java)
Servlet使用适配器模式进行增删改查案例(DeptDaoImpl.java)
Servlet使用适配器模式进行增删改查案例(IDeptDao.java和IEmpDao.java)
Servlet使用适配器模式进行增删改查案例(IDeptDao.java和IEmpDao.java)
Servlet使用适配器模式进行增删改查案例(IBaseDaoUtil.java)
Servlet使用适配器模式进行增删改查案例(IBaseDaoUtil.java)
Servlet使用适配器模式进行增删改查案例(BaseDao.java)
Servlet使用适配器模式进行增删改查案例(BaseDao.java)
Servlet使用适配器模式进行增删改查案例(Dept.java)
Servlet使用适配器模式进行增删改查案例(Dept.java)
|
前端开发 应用服务中间件 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的配置。(二)
Servlet使用适配器模式进行增删改查案例(Emp.java)
Servlet使用适配器模式进行增删改查案例(Emp.java)