springboot官方推荐的就是springboot+thymleaf框架,这里讲述一下搭建过程

需要源码的可以到我的github下载 : https://github.com/Feiyu123/Springboot-thymleaf

建立过程和上一篇差不多,新建一个Spring Initializr的WEB工程

一. 项目的pom.xml文件:


先来看一下项目结构:

idea springboot关联BIRT报表_thymleaf



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());
      }
   }
}

控制台结果:

idea springboot关联BIRT报表_thymleaf_02


表数据:

idea springboot关联BIRT报表_springboot_03



表中有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访问页面

idea springboot关联BIRT报表_IntelliJ_04

提交表单返回结果,成功

idea springboot关联BIRT报表_thymleaf_05


再看一下后台

idea springboot关联BIRT报表_thymleaf_06