本文主要是围绕Thymeleaf,需要有一定的Springboot和mybatis的基础

1.首先了解一下Thymeleaf

        1.1 简介

简单说, Thymeleaf 是一个跟 Velocity、FreeMarker 类似的模板引擎,它可以完全替代 JSP 。
从代码层次上讲:Thymeleaf是一个java类库,他是一个xml/xhtml/html5的模板引擎,可以作为mvc的web应用的view层。

        1.2 基本语法    

表达式

表达式名字

语法

用途

变量取值

${...}

获取请求域、session域、对象等值

选择变量

*{...}

获取上下文对象值

消息

#{...}

获取国际化等值

链接

@{...}

生成链接

片段表达式

~{...}

jsp:include 作用,引入公共页面片段

 

 th属性

html有的属性,Thymeleaf基本都有,而常用的属性大概有七八个。其中th属性执行的优先级从1~8,数字越低优先级越高。

1. th:text :设置当前元素的文本内容,相同功能的还有th:utext,两者的区别在于前者不会转义html标签,后者会。优先级不高:order=7
2. th:value:设置当前元素的value值,类似修改指定属性的还有th:src,th:href。优先级不高:order=6
3. th:each:遍历循环元素,和th:text或th:value一起使用。注意该属性修饰的标签位置。优先级很高:order=2
4. th:if:条件判断,类似的还有th:unless,th:switch,th:case。优先级较高:order=3
5. th:insert:代码块引入,类似的还有th:replace,th:include,三者的区别较大,若使用不恰当会破坏html结构,常用于公共代码块提取的场景。优先级最高:order=1
6. th:fragment:定义代码块,方便被th:insert引用。优先级最低:order=8
7. th:object:声明变量,一般和*{}一起配合使用,达到偷懒的效果。优先级一般:order=4
8. th:attr:修改任意属性,实际开发中用的较少,因为有丰富的其他th属性帮忙,类似的还有th:attrappend,th:attrprepend。优先级一般:order=5

注意使用Thymeleaf一定要加上命名空间  xmlns:th="http://www.thymeleaf.org"

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>

关系运算符

gt:great than(大于)
 ge:great equal(大于等于)
 eq:equal(等于)
 lt:less than(小于)
 le:less equal(小于等于)
 ne:not equal(不等于)

1.3springBoot中使用Thymeleaf

导入starter

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

springboot mybatis按月分表_mybatis

在这个路径下可以找到Thymeleaf在springboot中的自动装配类

 

@AutoConfiguration(
    after = {WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class}
)
@EnableConfigurationProperties({ThymeleafProperties.class})
@ConditionalOnClass({TemplateMode.class, SpringTemplateEngine.class})
@Import({ReactiveTemplateEngineConfiguration.class, DefaultTemplateEngineConfiguration.class})
public class ThymeleafAutoConfiguration {
}

    可以看到这个配置类是和ThymeleafProperties进行了配置绑定

@ConfigurationProperties(
    prefix = "spring.thymeleaf"
)
public class ThymeleafProperties {
    private static final Charset DEFAULT_ENCODING;
    public static final String DEFAULT_PREFIX = "classpath:/templates/";
    public static final String DEFAULT_SUFFIX = ".html";
    private boolean checkTemplate = true;
    private boolean checkTemplateLocation = true;
    private String prefix = "classpath:/templates/";
    private String suffix = ".html";
    private String mode = "HTML";
    private Charset encoding;
    private boolean cache;
    private Integer templateResolverOrder;
    private String[] viewNames;
    private String[] excludedViewNames;
    private boolean enableSpringElCompiler;
    private boolean renderHiddenMarkersBeforeCheckboxes;
    private boolean enabled;
    private final ThymeleafProperties.Servlet servlet;
    private final ThymeleafProperties.Reactive reactive;
}

可以看到springboot已经默认给我们配置视图解析器的前缀和后缀,如果我们想自定义配置,则可以在application.properties文件中以spring.Thymeleaf为前缀来修改配置

2.springboot+mybatis+Thymeleaf小练习

上面已经对Thymeleaf有了基本的了解,接下来就写一个小练习

效果如下图所示,在展示页面可以通过球队名称和球员名称进行模糊查询并且分页

springboot mybatis按月分表_spring boot_02

 删除采用异步方法,删除后直接从table移除当前行

springboot mybatis按月分表_mybatis_03

在添加页面所属球队的select框通过后台数据动态绑定,添加成功后返回首页展示页面

2.1新建一个springboot项目,并且引入如下依赖(我的boot版本为2.7.5大家可以根据自己版本进行调整)

<!--   thymeleaf模板引擎     -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
<!--    springbootweb    -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
<!--    mybatis    -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>
<!--springboot配置提醒-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
<!--    Lombok简化实体类开发    -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
<!--     SpringBoot测试单元   -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
<!--    mysql    -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
<!--   分页插件     -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
            <version>1.4.4</version>
        </dependency>

2.2 建立数据库,我这里的数据库名叫nbaplayers,相对应字段在下面实体类有注释

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for clubs
-- ----------------------------
DROP TABLE IF EXISTS `clubs`;
CREATE TABLE `clubs`  (
  `cid` int(0) NOT NULL AUTO_INCREMENT,
  `cname` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `city` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`cid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of clubs
-- ----------------------------
INSERT INTO `clubs` VALUES (1, '太阳', '纽约');
INSERT INTO `clubs` VALUES (2, '湖人', '宾夕法尼亚');
INSERT INTO `clubs` VALUES (3, '勇士', '洛杉矶');

-- ----------------------------
-- Table structure for players
-- ----------------------------
DROP TABLE IF EXISTS `players`;
CREATE TABLE `players`  (
  `pid` int(0) NOT NULL AUTO_INCREMENT,
  `pname` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `birthday` date NULL DEFAULT NULL,
  `height` int(0) NULL DEFAULT NULL,
  `weight` int(0) NULL DEFAULT NULL,
  `position` varchar(255) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  `cid` int(0) NULL DEFAULT NULL,
  PRIMARY KEY (`pid`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 14 CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of players
-- ----------------------------
INSERT INTO `players` VALUES (1, '大卫', '1997-02-05', 182, 182, '小前锋', 1);
INSERT INTO `players` VALUES (2, '彼得', '1982-05-02', 193, 156, '大前锋', 1);
INSERT INTO `players` VALUES (5, '柯南', '1978-05-06', 188, 162, '大前锋', 3);
INSERT INTO `players` VALUES (6, '博客', '1986-08-06', 185, 175, '小前锋', 3);
INSERT INTO `players` VALUES (9, '猪', '2022-11-08', 23, 123, '2', 2);
INSERT INTO `players` VALUES (11, '彼得', '2022-11-14', 123, 23, '1', 1);
INSERT INTO `players` VALUES (12, '彼得', '2022-12-15', 100, 25, '1', 2);
INSERT INTO `players` VALUES (14, '彭志', '2001-03-25', 140, 280, '中锋', 1);

SET FOREIGN_KEY_CHECKS = 1;

2.3设置配置文件

spring:
  #配置数据源
  datasource:
    url: jdbc:mysql://localhost:3306/nbaplayers?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT-8&useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver

#配置mybatis规则
mybatis:
  mapper-locations: classpath:mapper/*.xml
  configuration:
    #自动将下划线命名映射为驼峰命名
    map-underscore-to-camel-case: true
    #开启延迟加载
    lazy-loading-enabled: true
    #类型别名
  type-aliases-package: com.example.day_01_thymleaf.pojo
#配置分页插件
pagehelper:
  helperDialect: mysql
  reasonable: true
  params: count=countSql

整体项目结构如下

springboot mybatis按月分表_java_04

相关实体类

//球员类
public class Players {
    //球员id
    private Integer pid;
    //球员名称
    private String pname;
    //球员生日
    private String  birthday;
    //球员身高
    private Integer height;
    //球员体重
    private Integer weight;
    //球员定位
    private String position;
    //球队id
    private Integer cid;
    //所属球队名称
    private String cname;

}
@Data
//球队类
public class Clubs {

    //球队id
    private Integer cid;
    //球队名称
    private String cname;
    //所属城市
    private String city;

}

然后建立相关的service mapper

相关前端页面

main页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script th:src="@{/js/jquery.js}"></script>
    <style>
        a{
            margin-left: 50px;
        }
        h2{
            color: pink;
            font-family: 楷体;
        }
    </style>
</head>
<body>
    <h1 style="margin: auto">NBA篮球管理</h1>
    <form th:action="@{/plays}" method="get">
        球员姓名 : <input type="text" name="pname" th:value="${session.pname}">
        球队名称 : <select name="typeId" >
        <option  value="" >请选择</option>
        <option th:each="club : ${session.clubs}" th:text="${club.cname}" th:value="${club.cid}" th:selected="${session.typeId} eq ${club.cid}"></option>
                  </select>
        <input type="submit" value="搜索">
    </form>
    <a th:href="@{/add}">新增球员</a>
    <table>
        <tr>
            <th>球队编号</th>
            <th>球员名称</th>
            <th>出生时间</th>
            <th>球员身高</th>
            <th>球员体重</th>
            <th>球员位置</th>
            <th>所属球队</th>
            <th>相关操作</th>
        </tr>
        <tr th:each="p : ${session.page.list}">
            <td th:text="${p.pid}" th:id="${p.pid}"></td>
            <td th:text="${p.pname}"></td>
            <td th:text="${p.birthday}"></td>
            <td th:text="${p.height}"></td>
            <td th:text="${p.weight}"></td>
            <td th:text="${p.position}"></td>
            <td th:text="${p.cname}"></td>
            <td>
                <button th:pid="${p.pid}" th:onclick="deletePlayer(this.getAttribute('pid'))">删除</button>
            </td>
        </tr>
    </table>
    <a th:href="@{/plays?pageNum=1}"  th:if="${session.page.hasPreviousPage}">首页</a>
    <a th:href="'/plays?pageNum='+${session.page.prePage}"  th:if="${session.page.hasPreviousPage}">上一页</a>
    <a th:href="'/plays?pageNum='+${session.page.nextPage}"  th:if="${session.page.hasNextPage}">下一页</a>
    <a th:href="'/plays?pageNum='+${session.page.pages}" th:if="${session.page.hasNextPage}">尾页</a>
    <h2>第 <span th:text="${session.page.pageNum}"></span>页</h2>
    <h2>共 <span th:text="${session.page.total}"></span>条记录 </h2>

</body>
<script>
    function deletePlayer(id){
        $.ajax({
            url:"./delete/"+id,    //请求的url地址
            dataType:"text",   //返回格式为json
            type:"GET",   //请求方式
            success:function(req){
                if(req=="true"){
                    alert("删除成功")
                    $("#"+id).parent().remove()
                }
            },
        });
    }
</script>
</html>

add页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1 style="text-align: center">添加球员信息</h1>
<form th:action="@{/plays}" method="post" style="margin: auto;background-color: #9ddf9d;text-align: center;font-size: 25px">

    球员姓名: <input type="text" name="pname"> <br>
    出生时间: <input type="text" name="birthday">(yyyy-MM-dd) <br>
    球员身高: <input type="text" name="height"> <br>
    球员体重: <input type="text" name="weight"> <br>
    球员位置: <input name="position" type="radio" value="控球后卫"> 控球后卫
            <input  name="position" type="radio" value="得分后卫"> 得分后卫
            <input name="position" type="radio" value="小前锋"> 小前锋
            <input name="position" type="radio" value="大前锋"> 大前锋
            <input name="position" type="radio" value="中锋"> 中锋
    <br>
    所属球队 : <select name="cid" >
    <option  value="" >请选择</option>
    <option th:each="club : ${session.clubs}" th:text="${club.cname}" th:value="${club.cid}"></option>
    </select>
    相关操作 :<input type="submit" value="新增">  <input type="button" onclick="window.history.back()" value="返回">
</form>
</body>
</html>

 

2.4编写Controller

   因为我们使用了模板引擎,所以我们编写一个请求方法,将 / 请求重定向到plays请求上去,默认加载相关数据,因为在展示页和添加页面都需要球队数据,所以我们把球队数据存入session中,其中删除方法为异步调用,所以一定要加上@ResponseBody注解,才能给前端返回数据。否则返回的是一个逻辑视图名称。

@Slf4j
@Controller
public class MainController {

    @Autowired
    private PlayersService playersService;

    @Autowired
    private ClubsService clubsService;

    /**
     * 启动项目默认访问main页面
     * @return
     */
    @GetMapping("/")
    public String index(){

        return "redirect:/plays";
    }


    @GetMapping("plays")
    public String getAllPlays(@RequestParam(required = false) Integer pageNum,
                              @RequestParam(required = false) String typeId,
                              @RequestParam(required = false)String pname,
                              HttpSession session){
       //判断执行的是分页还是查询
        //如果查询则分页为空
        Object clubs = session.getAttribute("clubs");
        if(clubs==null){
            session.setAttribute("clubs",clubsService.getAllClubs());
        }
        if(pageNum==null){
            pageNum=1;
            session.setAttribute("typeId",typeId);
            session.setAttribute("pname",pname);
        }else {
         //如果分页不为空则执行的是分页
         typeId=(String) session.getAttribute("typeId");
         pname=(String) session.getAttribute("pname");
        }
        PageInfo<Players> page = playersService.getAllPlays(pageNum, typeId, pname);
        session.setAttribute("page",page);
        return "main";
    }


    /**
     *  根据id删除
     * @param id
     * @return
     */
    @GetMapping("/delete/{id}")
    @ResponseBody
    public String deletePlays(@PathVariable("id")Integer id){
       if(playersService.deleteByID(id)>0){
           return "true";
       }else {
           return "false";
       }
    }


    /**
     * 添加球员
     * @param players
     * @return
     */
    @PostMapping("plays")
    public String addPlays(Players players){
        return playersService.addPlays(players);
    }

    /**
     * 跳转到新增页面
     * @return
     */
    @GetMapping("/add")
    public String toAdd(){
        return "add";
    }
}