Thymeleaf+MVC初学项目

本文介绍了Thymeleaf视图模板技术及其在Java MVC项目中的应用,包括如何使用Thymeleaf动态显示数据、实现库存编辑、删除、添加和分页查询等功能。此外,还讨论了MVC模式的优化,如将多个Servlet整合到一个控制器中,利用反射技术减少代码重复,并引入中央控制器以提高代码组织性。
摘要由CSDN通过智能技术生成

Thymeleaf视图模板技术

Thymeleaf什么作用?

可以将数据呈现到静态页面上。比如可以将数据库查询的数据通过Thymeleaf动态的呈现到静态页面上。

使用Thymeleaf的步骤

我们的目标是在静态页面中动态展现从数据库中提取出来的数据。

 首先要有DAO从数据库中拿数据。

还需要一个ViewBaseServlet。

自己创建的servlet和静态页面。

除thymeleaf之外的相关代码

BaseDAO

public abstract class BaseDAO {
    //增删改
    public static int update(Connection connection, String sql, Object ...args){//可变形参
        PreparedStatement preparedStatement = null;
        try{
            //预编译sql
            preparedStatement = connection.prepareStatement(sql);
            //填充占位符
            //遍历可变数组,数组的内容就是传进来填写占位符的数据
            for (int i = 0;i < args.length;i++){
                preparedStatement.setObject(i+1,args[i]);
            }
            //执行
            return preparedStatement.executeUpdate();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            JDBCUtils.closeResource(null,preparedStatement,null);
        }
        return 0;
    }
    //查询一个对象
    public <T>T getInstance(Connection connection,Class<T> clazz,String sql,Object ...args){
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try{
            //预编译sql
            preparedStatement = connection.prepareStatement(sql);
            //填写占位符
            for(int i = 0;i < args.length;i++){
                preparedStatement.setObject(i+1,args[i]);
            }
            //执行并返回结果集
            resultSet = preparedStatement.executeQuery();


            ResultSetMetaData metaData = resultSet.getMetaData();
            //获取列数
            int columnCount = metaData.getColumnCount();

            if(resultSet.next()){
                //将传入的类创建实例
                T t = clazz.newInstance();
                //取的时候取多少次由要查询的字段的个数决定
                for(int i = 0;i<columnCount;i++){
                    //这个地方就没法强转了,没有办法判断具体是什么类型,获取这一行中某一个字段的值
                    Object columnValue = resultSet.getObject(i + 1);
                    //获取每个列的列名
                    String columnLable = metaData.getColumnLabel(i + 1);
                    //给user对象指定的columnName属性复制columnValue
                    //利用反射,先拿到叫columnName的属性
                    Field field = clazz.getDeclaredField(columnLable);
                    //这个属性可能是私有的,设置能访问
                    field.setAccessible(true);
                    //给这个属性赋值
                    field.set(t,columnValue);
                }
                return t;
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            JDBCUtils.closeResource(null,preparedStatement,resultSet);
        }
        return null;
    }

    //查询多个对象
    public <T> List<T> getForList(Connection connection,Class<T> clazz, String sql, Object ...args){
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try{
            //预编译sql
            preparedStatement = connection.prepareStatement(sql);
            //填写占位符
            for(int i = 0;i < args.length;i++){
                preparedStatement.setObject(i+1,args[i]);
            }
            //执行并返回结果集
            resultSet = preparedStatement.executeQuery();


            ResultSetMetaData metaData = resultSet.getMetaData();
            //获取列数
            int columnCount = metaData.getColumnCount();
            //创建集合
            List<T> list = new ArrayList<T>();
            while (resultSet.next()){
                //将传入的类创建实例
                T t = clazz.newInstance();
                //处理每一行数据的每一列,给每一行看作一个对象,给字段(属性)赋值
                for(int i = 0;i<columnCount;i++){
                    //这个地方就没法强转了,没有办法判断具体是什么类型,获取这一行中某一个字段的值
                    Object columnValue = resultSet.getObject(i + 1);
                    //获取每个列的列名
                    String columnLable = metaData.getColumnLabel(i + 1);
                    //给user对象指定的columnName属性复制columnValue
                    //利用反射,先拿到叫columnName的属性
                    Field field = clazz.getDeclaredField(columnLable);
                    //这个属性可能是私有的,设置能访问
                    field.setAccessible(true);
                    //给这个属性赋值
                    field.set(t,columnValue);
                }
                list.add(t);
            }
            return list;
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            JDBCUtils.closeResource(null,preparedStatement,resultSet);
        }
        return null;
    }


    //聚合函数的查询
    //查最大值,最小值,数量
    //有多种类型,比如可以查员工中最大的生日,就是Date类型
    public <E>E getValue(Connection connection,String sql,Object ...args){
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try{
            preparedStatement = connection.prepareStatement(sql);
            for (int i = 0;i < args.length;i++){
                preparedStatement.setObject(i+1,args[i]);
            }
            resultSet = preparedStatement.executeQuery();
            if(resultSet.next()){
                return (E) resultSet.getObject(1);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            JDBCUtils.closeResource(null,preparedStatement,resultSet);
        }
        return null;
    }
}

工具类-获取关闭连接

public class JDBCUtils {
    //静态方法不需要获取对象
    public static Connection getConnection(){
        try{
            //加载配置文件
            InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
            Properties properties = new Properties();
            properties.load(is);

            //获取基本信息
            String url = properties.getProperty("url");
            String user = properties.getProperty("user");
            String password = properties.getProperty("password");
            String driverClass = properties.getProperty("driverClass");
            //与数据库连接
            Class.forName(driverClass);
            Connection connection = DriverManager.getConnection(url, user, password);
            return connection;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    //关闭资源
    public static void closeResource(Connection connection, Statement ps,ResultSet resultSet){
        try{
            if(connection!=null)
                connection.close();
            if(ps!=null)
                ps.close();
            if(resultSet!=null)
                resultSet.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

DAO接口

public interface FruitDAO {
    List<Fruit> getFruitList(Connection connection);
}

DAO实现类

public class FruitDAOImpl extends BaseDAO implements FruitDAO{
    @Override
    public List<Fruit> getFruitList(Connection connection) {
        String sql = "select fid,fname,price,fcount,remark from fruits";
        List<Fruit> list = getForList(connection,Fruit.class,sql);
        return list;
    }
}

数据库中各条数据对应的对象

public class Fruit {
    private int fid;
    private String fname ;
    private int price;
    private int fcount;
    private String remark;

    public Fruit() {

    }

    public Fruit(int fid, String fname, int price, int fcount, String remark) {
        this.fid = fid;
        this.fname = fname;
        this.price = price;
        this.fcount = fcount;
        this.remark = remark;
    }

    public int getFid() {
        return fid;
    }

    public void setFid(int fid) {
        this.fid = fid;
    }

    public String getFname() {
        return fname;
    }

    public void setFname(String fname) {
        this.fname = fname;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    public int getFcount() {
        return fcount;
    }

    public void setFcount(int fcount) {
        this.fcount = fcount;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }
}

静态页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="/css/index.css">
    <title>Title</title>
</head>
<body>
    <div>
        <div>
            <table>
                <tr>
                    <th class="w20">名称</th>
                    <th class="w20">单价</th>
                    <th class="w20">库存</th>
                    <th>操作</th>
                </tr>
                <tr>
                    <td>苹果</td>
                    <td>5</td>
                    <td>20</td>
                    <td><img src=""></td>
                </tr>
            </table>
        </div>
    </div>
</body>
</html>

自己创建的Servlet

@WebServlet("/index")
public class IndexServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) {
        try{
            //Connection connection = JDBCUtils.getConnection();
            Class.forName("com.mysql.cj.jdbc.Driver");
            Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/demo","root","niit");
            System.out.println(connection);
            FruitDAO fruitDAO = new FruitDAOImpl();
            List<Fruit> fruitList = fruitDAO.getFruitList(connection);
            //保存到session作用域
            HttpSession session = request.getSession();
            session.setAttribute("fruitList",fruitList);

        }catch (Exception e){
            e.printStackTrace();
        }

    }
}

Step1:添加相关jar包

Step2:在web.xml文件中配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

<!--    配置上下文参数-->
    <context-param>
        <param-name>view-prefix</param-name>
        <param-value>/</param-value>
    </context-param>
    <context-param>
        <param-name>view-suffix</param-name>
        <param-value>.html</param-value>
    </context-param>
</web-app>

Step3:创建ViewBaseServlet类

这个类继承了HttpServlet类,所以我们自己创建的Servlet继承ViewBaseServlet类即可,会用到里面的processTemplate()方法。调用这个方法时,当访问这个servlet,就会自动跳转到静态页面。这个方法有三个参数,"index",request,response,第一个参数加上配置文件中配置的前后缀会跳转到指定的页面,后两个参数会把request和response传过去。

public class ViewBaseServlet extends HttpServlet {

    private TemplateEngine templateEngine;

    @Override
    public void init() throws ServletException {

        // 1.获取ServletContext对象
        ServletContext servletContext = this.getServletContext();

        // 2.创建Thymeleaf解析器对象
        ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(servletContext);

        // 3.给解析器对象设置参数
        // ①HTML是默认模式,明确设置是为了代码更容易理解
        templateResolver.setTemplateMode(TemplateMode.HTML);

        // ②设置前缀
        String viewPrefix = servletContext.getInitParameter("view-prefix");

        templateResolver.setPrefix(viewPrefix);

        // ③设置后缀
        String viewSuffix = servletContext.getInitParameter("view-suffix");

        templateResolver.setSuffix(viewSuffix);

        // ④设置缓存过期时间(毫秒)
        templateResolver.setCacheTTLMs(60000L);

        // ⑤设置是否缓存
        templateResolver.setCacheable(true);

        // ⑥设置服务器端编码方式
        templateResolver.setCharacterEncoding("utf-8");

        // 4.创建模板引擎对象
        templateEngine = new TemplateEngine();

        // 5.给模板引擎对象设置模板解析器
        templateEngine.setTemplateResolver(templateResolver);

    }

    protected void processTemplate(String templateName, HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // 1.设置响应体内容类型和字符集
        resp.setContentType("text/html;charset=UTF-8");

        // 2.创建WebContext对象
        WebContext webContext = new WebContext(req, resp, getServletContext());

        // 3.处理模板数据
        templateEngine.process(templateName, webContext, resp.getWriter());
    }
}

Step4:继承ViewBaseServlet

@WebServlet("/index")
public class IndexServlet extends ViewBaseServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) {
        try{
            //Connection connection = JDBCUtils.getConnection();
            Class.forName("com.mysql.cj.jdbc.Driver");
            Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/demo","root","niit");
            System.out.println(connection);
            FruitDAO fruitDAO = new FruitDAOImpl();
            List<Fruit> fruitList = fruitDAO.getFruitList(connection);
            //保存到session作用域
            HttpSession session = request.getSession();
            session.setAttribute("fruitList",fruitList);

            //此处的视图名称为index,thymeleaf会将这个逻辑视图名称对应到物理视图名称上去
            //逻辑视图名称:index
            //物理视图名称:view-prefix + 逻辑视图名称 + view-suffix
            //真实的视图名称:     /    +     index  +     .html

            super.processTemplate("index",request,response);

        }catch (Exception e){
            e.printStackTrace();
        }

    }
}

Step5:在静态页面中使用Thymeleaf,将从数据库中拿到的集合应用到页面上。

 注意添加html标签中属性 xmlns:th="http://www.thymeleaf.org"

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="/css/index.css">
    <title>Title</title>
</head>
<body>
    <div>
        <div>
            <table>
                <tr>
                    <th class="w20">名称</th>
                    <th class="w20">单价</th>
                    <th class="w20">库存</th>
                    <th>操作</th>
                </tr>
<!--                判断session作用域的变量是否为空-->
                <tr th:if="${#lists.isEmpty(session.fruitList)}">
                    <td colspan="4">对不起,库存为空</td>
                </tr>
<!--                判断session作用域中fruitList是否为空-->
<!--                unless相当于else-->
<!--                each相当于while标签-->
<!--                每循环一次,就将fruitList中的一个数据存给fruit-->
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值