综合案例-使用 Thymeleaf 模板技术实现表白墙

2022/3/20 23:30:35

本文主要是介绍综合案例-使用 Thymeleaf 模板技术实现表白墙,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

综合案例-使用 Thymeleaf 模板技术实现表白墙

  • 步骤:
    • 1、准备工作
    • 2、创建模板文件
    • 3、编写代码
      • (1)监听器部分代码
      • (2)servlet 部分代码
      • (3)实体类部分代码
      • (4)数据库部分代码
      • (5)数据库工具类部分代码
  • 小结

步骤:

1、准备工作

  • 创建 webapp 并整理项目结构;

在这里插入图片描述

其中

(1) api 用来存放 servlet 代码;
(2) dao 用来存放数据录操作代码;
(3) listener 用来存放监听器;
(4) util 用来存放工具代码;
(5) model 用来存放实体类代码;

  • 配置 pom.xml 文件并在 maven 面板进行刷新;
<?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>web-practice</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

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

    <dependencies>
       <!--添加servlet依赖包-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>

        <!--添加模板引擎依赖包-->
        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf</artifactId>
            <version>3.0.12.RELEASE</version>
        </dependency>

        <!--添加数据库依赖包-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>
    </dependencies>

    <build>
        <finalName>wp</finalName>
    </build>
</project>

完成上面两步操作后,进行如下操作~


2、创建模板文件

  • 创建模板文件 templates
  • 创建表白墙.html, 并放到 WEB-INF/templates 中;

代码如下

<!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>
    <link rel="stylesheet" href="表白墙.css">
</head>

<body>
    <h2>表白墙</h2>
    <p id="desc">输入后点击提交,会将内容显示在表格中</p>
    <form action="message" method="post">
        <div class="form-row">
            <span>谁</span>
            <input type="text" id="from" name="from">
        </div>
        <div class="form-row">
            <span>对谁</span>
            <!-- name 作为键,输入的内容为值 -->
            <input type="text" id="to" name="to">
        </div>
        <div class="form-row">
            <span>说</span>
            <input type="text" id="content" name="content">
        </div>
        <div class="form-row">
            <!-- 普通按钮,可以使用input type=button,也可以使用button标签 -->
            <!-- 显示的内容,input按钮是设置为value属性值,button是设置标签内容 -->
            <input type="submit" id="submit" value="提交">
        </div>
    </form>
    <p class="row" th:each="m : ${messages}">
        <span th:text="${m.from}"></span>
        <span> 对 </span>
        <span th:text="${m.to}"></span>
        <span> 说:</span>
        <span th:text="${m.content}"></span>
    </p>

</body>
</html>

路径为 message,方法为post提交的表单格式,post方法后端解析时不用进行解码操作;

  • 创建表白墙.css 将其放置在 webapp 目录下;
*{
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

h2 {
    text-align: center;
    margin: 50px 0;
}
#desc {
    text-align: center;
    font-size: 0.8em;
    color: gray;
    margin-bottom: 10px;
}
.form-row {
    height: 50px;
    /* 内容居中: 第一种方式,div有宽度,设置margin */
    /* width: 400px;
    margin: 0 auto; */
    /* 第二种方式:div占据整行,设置为弹性布局, 子元素居中 */
    display: flex;
    /* 水平居中 */
    justify-content: center;
    /* 垂直居中:如果子元素高度小于父元素高度 */
    align-items: center;
}
div>span {
    height: 30px;
    width: 50px;
}
div>input {
    height: 40px;
    width: 200px;
    font-size: 22px;
    line-height: 30px;
    /* 输入框内容上下不间隔,左右间隔20px */
    padding: 0 10px;
}
#submit {
    width: 250px;
    height: 40px;
    background-color: orange;
    color: white;
    /* 消除边框 */
    border: none;
}
/* 按钮点击没有弹起的样式 */
#submit:active {
    background-color: gray;
}
.row {
    text-align: center;
}

3、编写代码

(1)监听器部分代码

package org.example.listener;

import org.thymeleaf.TemplateEngine;
import org.thymeleaf.templateresolver.ServletContextTemplateResolver;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class TemplateEngineListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        //创建一个模板引擎和解析器
       TemplateEngine engine = new TemplateEngine();
       //拿到上下文sc
       ServletContext sc=sce.getServletContext();
       ServletContextTemplateResolver resolver =new ServletContextTemplateResolver(sc);
        //设置属性
        resolver.setCharacterEncoding("utf-8");
        //设置前缀
        resolver.setPrefix("/WEB-INF/templates/");
        //设置后缀
        resolver.setSuffix(".html");

        //将解析器绑定到引擎上
        engine.setTemplateResolver(resolver);

        //将引擎放入上下文环境中,目的:通过上下文路径就可以获取到引擎对象
        sc.setAttribute("engine",engine);
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {

    }
}

(2)servlet 部分代码

package org.example.api;

import org.example.dao.MessageDao;
import org.example.model.Message;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.WebContext;

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 java.io.IOException;
import java.util.ArrayList;
import java.util.List;

//整个表白墙,需要两个后端接口,两个接口1个是获取保存的信息,第2个是提交信息
//实现:可以使用两个servlet不同的路径,也可以是一个路径,不同请求方法
@WebServlet("/message")
public class MessageServlet extends HttpServlet {

    private List<Message> messages = new ArrayList<>();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取表白信息
        resp.setContentType("text/html; charset=utf-8");

        TemplateEngine engine = (TemplateEngine) getServletContext()
                .getAttribute("engine");
        //表白墙页面展示的时候,就应该显示表白的信息
        WebContext wc = new WebContext(req, resp, getServletContext());
        // 调整为数据库查询所有表白信息
        wc.setVariable("messages", MessageDao.list());
        String html = engine.process("表白墙", wc);
        resp.getWriter().write(html);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        //获取前端提交表白的信息
        // post提交表单body格式: from=...&to=...&content=...
        String from = req.getParameter("from");
        String to = req.getParameter("to");
        String content = req.getParameter("content");

        //保存这些信息:设计为以上三个字段,保存在一个对象的三个属性中,然后把对象放在List中
        Message m = new Message();
        m.setFrom(from);
        m.setTo(to);
        m.setContent(content);

        //调整为数据库添加一行数据
        MessageDao.insertMessage(m);

        //提交数据后,还需要看到表白墙的页面(其实和访问网页内容的请求是一个逻辑)
        doGet(req, resp);
    }
}

(3)实体类部分代码

package org.example.model;

//model包:存放实体类(这些类用于转换http数据及数据库的数据)
public class Message {
    private String from;
    private String to;
    private String content;

    @Override
    public String toString() {
        return "Message{" +
                "from='" + from + '\'' +
                ", to='" + to + '\'' +
                ", content='" + content + '\'' +
                '}';
    }


    //生成 getter与setter方法
    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 getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }
}

(4)数据库部分代码

package org.example.dao;

import org.example.model.Message;
import org.example.util.DBUtil;
import org.junit.Test;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

//dao这个名词,是专门做数据操作的(我们这里是做数据库的操作)
public class MessageDao {

    //根据messageServlet.doGet中,需要保存数据的代码
    //messages.add(m);需要把m这个message,保存到数据库message表的一行数据
    public static void insertMessage(Message m){
        //jdbc步骤:

        Connection c = null;
        PreparedStatement ps = null;
        try {
            //1.获取数据库连接
            c = DBUtil.getConnection();
            //2.获取操作命令对象
            String sql = "insert into message(`from`, `to`, content) values(?,?,?)";
            ps = c.prepareStatement(sql);
            //3.执行sql
            ps.setString(1, m.getFrom());
            ps.setString(2, m.getTo());
            ps.setString(3, m.getContent());
            int n = ps.executeUpdate();
            //4.如果是查询操作,需要处理结果集对象
        } catch (SQLException e) {
            throw new RuntimeException("插入message出错", e);
        } finally {
            //5.释放资源
            DBUtil.close(c, ps);
        }
    }

    @Test
    public void testInsertMessage(){
        Message m = new Message();
        m.setFrom("张三");
        m.setTo("李四");
        m.setContent("我喜欢你");
        insertMessage(m);
    }

    //获取所有数据库message表中,保存的数据(多行数据,定义为List<Message为返回值类型)
    public static List<Message> list(){
        List<Message> list = new ArrayList<>();
        Connection c = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            //1.获取数据库连接
            c = DBUtil.getConnection();
            //2.获取操作命令对象
            String sql = "select `from`, `to`, content from message";
            ps = c.prepareStatement(sql);
            //3.执行sql
            rs = ps.executeQuery();
            //4.如果是查询操作,需要处理结果集对象
            while(rs.next()){//遍历多行数据
                //每一行数据,转换为一个message对象,然后放到返回的list里边
                Message m = new Message();
                String from = rs.getString("from");
                String to = rs.getString("to");
                String content = rs.getString("content");
                m.setFrom(from);
                m.setTo(to);
                m.setContent(content);
                list.add(m);
            }
        } catch (SQLException e) {
            throw new RuntimeException("插入message出错", e);
        } finally {
            //5.释放资源
            DBUtil.close(c, ps);
        }
        return list;
    }

    @Test
    public void testList(){
        List<Message> list = list();
        System.out.println(list);
    }
}

(5)数据库工具类部分代码

package org.example.util;

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

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

//数据库工具类:提供获取数据库连接,释放资源的统一代码
public class DBUtil {

    //静态变量,是类加载的时候初始化,只执行一次
    private static MysqlDataSource ds;

    //一个程序,连接一个数据库,只需要一个连接池,其中保存了多个数据库连接对象
    //获取连接池,内部使用,不开放
    private static DataSource getDataSource(){
        //TODO 有点问题:多线程环境,还有有点问题,留待后续解决
        //ds类加载的时候,初始化为null,方法使用的时候,每次都判断一下
        if(ds == null) {//判断为空,就创建及初始化属性
            ds = new MysqlDataSource();
            ds.setURL("jdbc:mysql://localhost:3306/biaobai");
            ds.setUser("root");
            ds.setPassword("123456");
            ds.setUseSSL(false);//不安全连接,如果不设置,也不影响,只是有警告
            ds.setCharacterEncoding("UTF-8");
        }
        return ds;
    }

    //获取数据库连接对象:开放给外部的jdbc代码使用
    public static Connection getConnection(){
        try {
            return getDataSource().getConnection();
        } catch (SQLException e) {
            throw new RuntimeException("获取数据库连接出错,可能是url,账号密码写错了", e);
        }
    }

    //查询操作需要释放三个资源,更新操作(插入,修改,删除)只需要释放前两个资源
    public static void close(Connection c, Statement s, ResultSet r) {
        try {
            if (r != null) r.close();
            if (s != null) s.close();
            if (c != null) c.close();
        } catch (SQLException e) {
            throw new RuntimeException("释放资源出错", e);
        }
    }

        //提供更新操作方便的释放资源功能
    public static void close(Connection c, Statement s){
        close(c, s, null);
    }

    public static void main(String[] args) {
        System.out.println(getConnection());
    }
}

初始化数据库操作,将其放入resources下:

drop database if exists biaobai;
create database biaobai character set utf8mb4;

use biaobai;

create table message(
    `from` varchar(20),
    `to` varchar(20),
    `content` varchar(200)
);


启动服务器,运行显示
在这里插入图片描述

小结

不管什么功能,使用模板技术

前端需要做的事情考虑如何发请求

如以上发请求的方式为:

  • 浏览器地址栏输入URL
  • 表单提交;

对应后端需要考虑的事情
(1)获取请求数据:如以上第一个功能没有请求数据所以不用管,而第二个功能是提交数据,因此要解析请求数据;
(2)执行需要的业务逻辑:如以上第一个功能没有逻辑;第二个需要保存数据;
(3)返回响应:如以上两个功能都需要返回表白墙网页+list数据,渲染动态html网页;



这篇关于综合案例-使用 Thymeleaf 模板技术实现表白墙的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程