springboot官方推荐的就是springboot+thymleaf框架,这里讲述一下搭建过程
需要源码的可以到我的github下载 : https://github.com/Feiyu123/Springboot-thymleaf
建立过程和上一篇差不多,新建一个Spring Initializr的WEB工程
一. 项目的pom.xml文件:
先来看一下项目结构:
springboot+thymleaf基本jar包: spring-boot-starter-web ,spring-boot-starter-test,spring-boot-starter-thymeleaf
mybatis 基本jar包 :mybatis-spring-boot-starter,mapper-spring-boot-starter,mysql-connector-java
分页插件jar包 :pagehelper-spring-boot-starter
<?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>com.lrq</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.1.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<mybatis.version>1.1.1</mybatis.version>
<mybatis.tk.version>1.0.0</mybatis.tk.version>
<pagehelper.version>1.1.0</pagehelper.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.version}</version>
</dependency>
<!--mapper -->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>${mybatis.tk.version}</version>
</dependency>
<!--pagehelper 分页插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>${pagehelper.version}</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
二. application.properties(定义各种配置常量)
#启用模板缓存(开发时建议关闭)
spring.thymeleaf.cache = false
#Content-Type值
spring.thymeleaf.content-type = text/html
#在构建URL时预先查看名称的前缀
spring.thymeleaf.prefix = classpath:/templates/
#构建URL时附加查看名称的后缀
spring.thymeleaf.suffix = .html
#测试连接数据库,mybatis用的是SELECT 1
spring.datasource.tomcat.validation-query=SELECT 1
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.driver-class-name= com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root
#连接池中允许的最大连接数。缺省值:10;推荐的公式:((core_count * 2) + effective_spindle_count)
spring.datasource.hikari.maximum-pool-size=50
#一个连接的生命时长(毫秒),超时而且没被使用则被释放(retired),缺省:30分钟,建议设置比数据库超时时长少30秒以上
spring.datasource.hikari.max-lifetime=1765000
#端口号
server.port=28082
#访问路径
server.context-path=/demo
#指明mybatis实体类包位置
mybatis.type-aliases-package=com.lrq.demo.model
#指明mappers位置,可以指明多个位置
mybatis.mapper-locations=classpath:mapper/*.xml
#指明分页插件是给mysql用的
pagehelper.helper-dialect=mysql
pagehelper.reasonable=true
pagehelper.support-methods-arguments=true
pagehelper.params=count=countSql
三. logback.xml (配置日志地址)
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds">
<property name="LOG_HOME" value="D://log/ejbx" />
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出,%d:日期;%thread:线程名;%-5level:级别,从左显示5个字符宽度;%msg:日志消息;%n:换行符 -->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} -%msg%n</pattern>
</encoder>
</appender>
<!-- 按照每天生成日志文件 -->
<appender name="FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名 -->
<FileNamePattern>${LOG_HOME}/springboot_demo.log.%d{yyyy-MM-dd}.log
</FileNamePattern>
</rollingPolicy>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<!--格式化输出,%d:日期;%thread:线程名;%-5level:级别,从左显示5个字符宽度;%msg:日志消息;%n:换行符 -->
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{50} -%msg%n</pattern>
</encoder>
</appender>
<!-- 日志输出级别 -->
<root level="INFO">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
</root>
</configuration>
四. src 三层架构搭建
1.model 层
User 类
package com.lrq.demo.model;
import java.util.Objects;
public class User {
private Integer id;
private String name;
private String idNo;
private String gender;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getIdNo() {
return idNo;
}
public void setIdNo(String idNo) {
this.idNo = idNo;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return Objects.equals(id, user.id) &&
Objects.equals(name, user.name) &&
Objects.equals(idNo, user.idNo) &&
Objects.equals(gender, user.gender);
}
@Override
public int hashCode() {
return Objects.hash(id, name, idNo, gender);
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", idNo='" + idNo + '\'' +
", gender='" + gender + '\'' +
'}';
}
}
PageInfo类(需要把Page包装成PageInfo对象才能序列化)
package com.lrq.demo.model;
import com.github.pagehelper.Page;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
public class PageInfo<T> implements Serializable {
private static final long serialVersionUID = 1L;
//当前页
private int pageNum;
//每页的数量
private int pageSize;
//总记录数
private long total;
//总页数
private int pages;
//结果集
private List<T> list;
//是否为第一页
private boolean isFirstPage = false;
//是否为最后一页
private boolean isLastPage = false;
public PageInfo() {
}
/**
* 包装Page对象
*
* @param list
*/
public PageInfo(List<T> list) {
if (list instanceof Page) {
Page page = (Page) list;
this.pageNum = page.getPageNum();
this.pageSize = page.getPageSize();
this.pages = page.getPages();
this.list = page;
this.total = page.getTotal();
} else if (list instanceof Collection) {
this.pageNum = 1;
this.pageSize = list.size();
this.pages = 1;
this.list = list;
this.total = list.size();
}
if (list instanceof Collection) {
//判断页面边界
judgePageBoudary();
}
}
/**
* 判定页面边界
*/
private void judgePageBoudary() {
isFirstPage = pageNum == 1;
isLastPage = pageNum == pages;
}
public int getPageNum() {
return pageNum;
}
public void setPageNum(int pageNum) {
this.pageNum = pageNum;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public long getTotal() {
return total;
}
public void setTotal(long total) {
this.total = total;
}
public int getPages() {
return pages;
}
public void setPages(int pages) {
this.pages = pages;
}
public List<T> getList() {
return list;
}
public void setList(List<T> list) {
this.list = list;
}
public boolean isIsFirstPage() {
return isFirstPage;
}
public void setIsFirstPage(boolean isFirstPage) {
this.isFirstPage = isFirstPage;
}
public boolean isIsLastPage() {
return isLastPage;
}
public void setIsLastPage(boolean isLastPage) {
this.isLastPage = isLastPage;
}
@Override
public String toString() {
final StringBuffer sb = new StringBuffer("PageInfo{");
sb.append("pageNum=").append(pageNum);
sb.append(", pageSize=").append(pageSize);
sb.append(", total=").append(total);
sb.append(", pages=").append(pages);
sb.append(", list=").append(list);
sb.append(", isFirstPage=").append(isFirstPage);
sb.append(", isLastPage=").append(isLastPage);
sb.append(", navigatepageNums=");
sb.append('}');
return sb.toString();
}
}
2.dao层
UserDao类
package com.lrq.demo.dao;
import com.github.pagehelper.Page;
import com.lrq.demo.model.User;
import org.springframework.stereotype.Repository;
import java.util.Map;
@Repository
public interface UserDao {
User getUserByName(Map<String,Object> map);
void addUser(User user);
Page<User> findPageInfoByName(Map<String,Object> map);
}
dao的实现层mapper:user.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.lrq.demo.dao.UserDao">
<resultMap id="BaseResultMap" type="com.lrq.demo.model.User">
<id column="id" property="id" jdbcType="INTEGER" />
<result column="name" property="name" jdbcType="VARCHAR" />
<result column="idNo" property="idNo" jdbcType="VARCHAR" />
<result column="gender" property="gender" jdbcType="VARCHAR" />
</resultMap>
<insert id="addUser" parameterType="com.lrq.demo.model.User">
insert into user
(
name,
idNo,
gender
)values(
#{name},
#{idNo},
#{gender}
)
</insert>
<select id="getUserByName" parameterType="map" resultMap="BaseResultMap">
select * from user o
<where>
<if test='name != null and name != ""'>
o.name = #{name}
</if>
</where>
</select>
<select id="findPageInfoByName" parameterType="map" resultMap="BaseResultMap">
select * from user o
<where>
<if test='name != null and name != ""'>
o.name like concat('%',#{name},'%')
</if>
</where>
</select>
</mapper>
3.service层
UserService
package com.lrq.demo.service;
import com.github.pagehelper.Page;
import com.lrq.demo.model.User;
public interface UserService {
User getUserByName(String name);
void addUser(User user);
Page<User> findByPage(String name,int pageNo, int pageSize);
}
UserService的实现层:UserServiceImpl类
package com.lrq.demo.service.impl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.lrq.demo.dao.UserDao;
import com.lrq.demo.model.User;
import com.lrq.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Service
public class UserServiceImpl implements UserService{
@Autowired
private UserDao userDao;
@Override
public User getUserByName(String name) {
Map<String,Object> map = new HashMap<>();
map.put("name",name);
return userDao.getUserByName(map);
}
@Override
public void addUser(User user) {
userDao.addUser(user);
}
@Override
public Page<User> findByPage(String name,int pageNo, int pageSize) {
Map<String,Object> map = new HashMap<>();
map.put("name",name);
PageHelper.startPage(pageNo, pageSize);
return userDao.findPageInfoByName(map);
}
}
4.controller层
package com.lrq.demo.controller;
import com.lrq.demo.model.User;
import com.lrq.demo.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class UserController {
private static final Logger LOGGER = LoggerFactory.getLogger(UserController.class);
@Autowired
private UserService userService;
@GetMapping("/toUserPage")
public String toUserPage(Model model){
LOGGER.info("跳转到用户页面");
model.addAttribute("name","Henry");
return "userPage";
}
@PostMapping("/getUser")
@ResponseBody
public User getUser(String name){
LOGGER.info("获取用户信息.name={}",name);
User user = userService.getUserByName(name);
LOGGER.info("获取用户信息.user={}",user.toString());
return user;
}
}
5.测试用例测试分页
package com.lrq.demo;
import com.github.pagehelper.Page;
import com.lrq.demo.dao.UserDao;
import com.lrq.demo.model.PageInfo;
import com.lrq.demo.model.User;
import com.lrq.demo.service.UserService;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoApplicationTests {
private Logger logger = LoggerFactory.getLogger(DemoApplicationTests.class);
@Autowired
private UserService userService;
@Test
public void testFindByPage() {
Page<User> persons = userService.findByPage("H",0,2);
// 需要把Page包装成PageInfo对象才能序列化。该插件也默认实现了一个PageInfo
PageInfo<User> pageInfo = new PageInfo<>(persons);
Assert.assertNotNull(persons);
List<User> list = pageInfo.getList();
for(User u : list){
System.out.println(u.toString());
}
}
}
控制台结果:
表数据:
表中有3条数据带有H的,从pageNo=0开始 取2条数据,刚好吻合
五. thymleaf + html 页面(现在基本用H5页面,不用jsp)
由于现在前后端分离盛行,采用H5页面的方式进行配置。thymleaf作为全新的页面模板框架,比较适用于html。
要html支持thymleaf必须加<html xmlns:th="http://www.thymeleaf.org">
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>userInfo</title>
</head>
<body>
<form id="iform" th:action="@{/getUser}" method="post">
<input type="text" th:value="${name}" id="name" name="name" readonly="readonly"/>
<input type="submit" />
</form>
</body>
</html>
用th:value="${name}" 来取model的值,在浏览器输入http://localhost:28082/demo/toUserPage访问页面
提交表单返回结果,成功
再看一下后台