Spring Boot系列六 Spring boot集成mybatis、分页插件pagehelper

来源:互联网 发布:js点赞心形动态效果 编辑:程序博客网 时间:2024/06/13 06:17

1. 概述

本文的内容包括如下内容:

  1. Spring Boot集成mybatis
  2. Spring Boot集成pagehelper分页插件,定义分页的相关类
  3. 实现工具类:model转dto,实现数据层和传输层的解耦
  4. 完整展示了从浏览器输入URL,并从数据库操作数据的完整流程

2. Spring Boot集成Mybatis

2.1. pom.xml

mybatis和数据库的相关的jar

<!-- druid --><dependency>    <groupId>com.alibaba</groupId>    <artifactId>druid</artifactId>    <version>1.0.31</version></dependency><!-- Spring Boot集成mybatis --><dependency>    <groupId>org.mybatis.spring.boot</groupId>    <artifactId>mybatis-spring-boot-starter</artifactId>    <version>1.3.1</version></dependency><!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --><dependency>    <groupId>mysql</groupId>    <artifactId>mysql-connector-java</artifactId>    <version>6.0.6</version></dependency>

2.2. Mapper java类和xml及Model

测试表sql如下

CREATE TABLE `test`.`test` (  `id` INT NOT NULL,  `age` INT NULL,  `name` VARCHAR(45) NULL,  PRIMARY KEY (`id`),  UNIQUE INDEX `id_UNIQUE` (`id` ASC));

表对应Model类: com.hry.spring.mybatis.model.TestModel

public class TestModel {    private Integer id;    private Integer age;    private String name;   // set/get略}

配置Mapper类: com.hry.spring.mybatis.mapper.TestMapper

public interface TestMapper {    int deleteByPrimaryKey(Integer id);    int insert(TestModel record);    int insertSelective(TestModel record);    TestModel selectByPrimaryKey(Integer id);    List<TestModel> selectAll();    int updateByPrimaryKeySelective(TestModel record);    int updateByPrimaryKey(TestModel record);}

配置Mapper xml: TestMapper.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.hry.spring.mybatis.mapper.TestMapper"> <resultMap id="BaseResultMap" type="com.hry.spring.mybatis.model.TestModel">   <id column="id" jdbcType="INTEGER" property="id" />   <result column="age" jdbcType="INTEGER" property="age" />   <result column="name" jdbcType="VARCHAR" property="name" /> </resultMap> <sql id="Base_Column_List">   id, age, name </sql> <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">   select    <include refid="Base_Column_List" />   from test   where id = #{id,jdbcType=INTEGER} </select> <select id="selectAll"  resultMap="BaseResultMap">   select   <include refid="Base_Column_List" />   from test     order by id desc </select> <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">   delete from test   where id = #{id,jdbcType=INTEGER} </delete> <insert id="insert" parameterType="com.hry.spring.mybatis.model.TestModel">   insert into test (id, age, name,      )   values (#{id,jdbcType=INTEGER}, #{age,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}    ) </insert> <insert id="insertSelective" parameterType="com.hry.spring.mybatis.model.TestModel">   insert into test   <trim prefix="(" suffix=")" suffixOverrides=",">     <if test="id != null">       id,     </if>     <if test="age != null">       age,     </if>     <if test="name != null">       name,     </if>   </trim>   <trim prefix="values (" suffix=")" suffixOverrides=",">     <if test="id != null">       #{id,jdbcType=INTEGER},     </if>     <if test="age != null">       #{age,jdbcType=INTEGER},     </if>     <if test="name != null">       #{name,jdbcType=VARCHAR},     </if>   </trim> </insert> <update id="updateByPrimaryKeySelective" parameterType="com.hry.spring.mybatis.model.TestModel">   update test   <set>     <if test="age != null">       age = #{age,jdbcType=INTEGER},     </if>     <if test="name != null">       name = #{name,jdbcType=VARCHAR},     </if>   </set>   where id = #{id,jdbcType=INTEGER} </update> <update id="updateByPrimaryKey" parameterType="com.hry.spring.mybatis.model.TestModel">   update test   set age = #{age,jdbcType=INTEGER},     name = #{name,jdbcType=VARCHAR}   where id = #{id,jdbcType=INTEGER} </update></mapper>

2.3. mybatis配置

spring_mybatis.xml
spring.datasource.url的值配置在application.yml

<!-- ### 配置数据源 begin ###--><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">   <!-- 基本属性 url、user、password -->  <property name="url" value="${spring.datasource.url}" />  <property name="username" value="${spring.datasource.username}" />  <property name="password" value="${spring.datasource.password}" />  <property name="driverClassName" value="${spring.datasource.driverClassName}" />  <!-- 配置初始化大小、最小、最大 -->  <property name="initialSize" value="${spring.datasource.initialSize:5}" />  <property name="minIdle" value="${spring.datasource.minIdle:5}" />   <property name="maxActive" value="${spring.datasource.maxActive:20}" />  <!-- 配置获取连接等待超时的时间 -->  <property name="maxWait" value="${spring.datasource.maxWait:30000}" />  <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->  <property name="timeBetweenEvictionRunsMillis" value="${spring.datasource.timeBetweenEvictionRunsMillis}" />  <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->  <property name="minEvictableIdleTimeMillis" value="${spring.datasource.minEvictableIdleTimeMillis}" />  <property name="validationQuery" value="${spring.datasource.validationQuery}" />  <property name="testWhileIdle" value="${spring.datasource.testWhileIdle}" />  <property name="testOnBorrow" value="${spring.datasource.testOnBorrow}" />  <property name="testOnReturn" value="${spring.datasource.testOnReturn}" />  <!-- 打开PSCache,并且指定每个连接上PSCache的大小 -->  <property name="poolPreparedStatements" value="${spring.datasource.poolPreparedStatements}" />  <property name="maxPoolPreparedStatementPerConnectionSize" value="${spring.datasource.maxPoolPreparedStatementPerConnectionSize}" />  <!-- 配置监控统计拦截的filters -->  <property name="filters" value="${spring.datasource.filters}" />  <property name="connectionProperties" value="{spring.datasource.connectionProperties}" /></bean><!-- ### 配置数据源  end ###--><!-- ### Mybatis和事务配置  begin ###--><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">    <property name="dataSource" ref="dataSource"/>    <!-- 配置扫描Mapper XML的位置 -->    <property name="mapperLocations" value="classpath:com/hry/spring/mybatis/mapper/*.xml"/>    <!-- 配置mybatis配置文件的位置 -->    <property name="configLocation" value="classpath:config/spring/mybatis_config.xml"/></bean><!-- 配置扫描Mapper接口的包路径 --><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">    <property name="basePackage" value="com.hry.spring.mybatis.mapper"/>    <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/></bean><!-- 事务配置 --><bean id="transactionManager"      class="org.springframework.jdbc.datasource.DataSourceTransactionManager"      p:dataSource-ref="dataSource"/><tx:advice id="txAdvice" transaction-manager="transactionManager" >    <tx:attributes>        <tx:method name="add*" propagation="REQUIRED" />    <tx:method name="create*" propagation="REQUIRED" />    <tx:method name="save*" propagation="REQUIRED" />        <tx:method name="insert*" propagation="REQUIRED" />    <tx:method name="update*" propagation="REQUIRED" />    <tx:method name="batch*" propagation="REQUIRED" />    <tx:method name="del*" propagation="REQUIRED" />    <tx:method name="get*" propagation="SUPPORTS" read-only="true" />    <tx:method name="find*" propagation="SUPPORTS" read-only="true" />        <tx:method name="*" read-only="true"/>    </tx:attributes></tx:advice><aop:config >    <aop:pointcut id="pt" expression="execution(* com.hry.spring.mybatis.service..*.*(..))" />    <aop:advisor pointcut-ref="pt" advice-ref="txAdvice"/></aop:config> <!-- ### Mybatis和事物配置  end ###-->

mybatis_config.xml

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configuration  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"  "http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration></configuration>

2.4. application.yml

配置数据库的信息如下:

# 数据库配置spring:  datasource:    #### Datasource 配置 ####    type: com.alibaba.druid.pool.DruidDataSource    username: root    password: root    url: jdbc:mysql://127.0.0.1:3306/test?zeroDateTimeBehavior=convertToNull&serverTimezone=GMT%2b8&useSSL=true    # url: jdbc:mysql://127.0.0.1:3306/test    driverClassName: com.mysql.cj.jdbc.Driver    # driverClassName: oracle.jdbc.driver.OracleDriver    # 下面为连接池的补充设置,应用到上面所有数据源中# 初始化大小,最小,最大    initialSize: 5    minIdle: 5    maxActive: 20    # 配置获取连接等待超时的时间    maxWait: 30000    # 配置一个连接在池中最小生存的时间,单位是毫秒    minEvictableIdleTimeMillis: 300000    timeBetweenEvictionRunsMillis: 60000    validationQuery: SELECT 1 FROM DUAL    # 打开PSCache,并且指定每个连接上PSCache的大小    poolPreparedStatements: false    maxPoolPreparedStatementPerConnectionSize: 20    testWhileIdle: true    testOnBorrow: false    testOnReturn: false    # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙    filters: log4j    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000

2.5. spring boot集成mybatis

通过@ImportResource加载mybatis的配置
用@Bean注解的方法fastJsonHttpMessageConverters表示使用fastjson解析json

@SpringBootApplication// 加载mybatis配置@ImportResource({"classpath:config/spring/spring_*.xml"})public class MybatisSpringBoot {    public static void main(String[] args){        SpringApplication.run(MybatisSpringBoot.class, args);    }    @Bean    public HttpMessageConverters fastJsonHttpMessageConverters() {        // 格式化时间        SerializeConfig mapping = new SerializeConfig();        mapping.put(Date.class, new SimpleDateFormatSerializer(               "yyyy-MM-dd HH:mm:ss"));        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();        FastJsonConfig fastJsonConfig = new FastJsonConfig();        //  fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);        fastJsonConfig.setSerializeConfig(mapping);        fastConverter.setFastJsonConfig(fastJsonConfig);        HttpMessageConverter<?> converter = fastConverter;        return new HttpMessageConverters(converter);    }}

3. Spring Boot集成分布插件Pagehelper

以上的功能实现了简单的mybatis应用。但是涉及到数据库的查询,不可避免需要使用到分页。这里我推荐pagehelper插件实现分页功能

3.1. pom.xml

引入相关的jar

<!-- 分布插件 --><dependency>    <groupId>com.github.pagehelper</groupId>    <artifactId>pagehelper</artifactId>    <version>5.1.1</version></dependency><!-- Spring Boot集成 pagehelper--><dependency>    <groupId>com.github.pagehelper</groupId>    <artifactId>pagehelper-spring-boot-starter</artifactId>    <version>1.2.1</version></dependency>

3.2. 分页相关的辅助类

MyPage
包装返回给前台的信息,包括本次查询的状态码、错误信息、记录总数和数据列表

public class MyPage<T> {    @JSONField(ordinal = 1)    private Integer code = 200;// 状态码,默认状态    @JSONField(ordinal = 2)    private String message = "";// 提示消息或者错误消息    @JSONField(ordinal = 3)    private String apiId = "";// 请求的唯一标识,预留    @JSONField(ordinal = 4)    private Integer totalCount = 0;//记录总数    @JSONField(ordinal = 5)    private List<T> rows = Collections.emptyList();//本次返回的数据列表   // set/get略}

IPageHelperPageCallBack
定义分页的回调方法,如果使分页,则必须在这个方法里使用mapper的方法。
此接口作为下文的PageCallBackUtil的参数

public interface IPageHelperPageCallBack {    <T> List<T> select();}

PageCallBackUtil
pagehelper的使用核心是:调用PageHelper.startPage(pageNum, pageSize,requireTotalCount)方法设置查询记录起始地址后,然后马上调用mapper类的方法,得到返回列表List,使用( PageInfo pageInfo = new PageInfo(list))包装list的PageInfo,PageInfo包含本次查询的信息,包括本次查询的总数,然后将Model转化为Dto类

/** * 分页的回调函数 * Created by huangrongyou@yixin.im on 2017/9/6. */public class PageCallBackUtil {    /**     * 封装公共PageHelper的操作     * @param qry     * @param callBack     * @param <T>     * @return     */    public static<T>  MyPage<T> selectRtnPage(AbstractQry qry, IPageHelperPageCallBack callBack){        Assert.notNull(qry, "qry can't be null!");        Assert.notNull(callBack, "callBack cant' be null!");        setPageHelperStartPage(qry);        List<T> list = callBack.select();        // 分页时,实际返回的结果list类型是Page<E>        if(!(list instanceof Page)){            throw new RuntimeException("list must be 'com.github.pagehelper.Page', now is " + list.getClass().getCanonicalName());        }        MyPage<T> myPage = new MyPage<T>();        PageInfo<T> pageInfo = new PageInfo<T>(list);        myPage.setTotalCount((int) pageInfo.getTotal());        myPage.setRows(pageInfo.getList());        return myPage;    }    /**     * 设置PageHelper的startPage     * @param qry     */    private static void setPageHelperStartPage(AbstractQry qry) {        // 设置分页信息        // pageNum        Integer pageNum = qry.getPageNum();        pageNum = pageNum == null? AbstractQry.DEFAULT_PAGENUM : pageNum;        // pageSize        Integer pageSize = qry.getPageSize();        pageSize = pageSize == null ? AbstractQry.DEFAULT_PAGESIZE : pageSize;        // requireTotalCount        Boolean requireTotalCount = qry.getRequireTotalCount();        requireTotalCount = requireTotalCount == null ? AbstractQry.DEFAULT_REQUIRETOTALCOUNT : requireTotalCount;        PageHelper.startPage(pageNum, pageSize,requireTotalCount);    }}

Qry
查询条件的基类

public interface Qry {    String getId();    void setId(String id);}

AbstractQry
定义分页的查询的页码信息

public class AbstractQry implements Qry {    public static final int DEFAULT_PAGENUM = 1;    public static final int DEFAULT_PAGESIZE = 1;    public static final boolean DEFAULT_REQUIRETOTALCOUNT = false;    private String id;    private Integer pageNum = 1;// 第几页,首页为1    private Integer pageSize = 10;// 每页记录条数    private Boolean requireTotalCount = Boolean.FALSE;// 是否需要记录总数    // set/get略}

TestQry
这个类用来定义具体的查询条件

public class TestQry extends AbstractQry{}

3.3. 服务层:ITestService和TestServiceImpl

ITestService

public interface ITestService {    int deleteByPrimaryKey(Integer id);    int insertSelective(TestModel record);    TestModel selectByPrimaryKey(Integer id);    List<TestModel> selectAll(TestQry qry);    MyPage<TestModel> selectAllWithPage(TestQry qry);}

TestServiceImpl
selectAllWithPage定义了方法的使用

@Service@Primarypublic class TestServiceImpl implements ITestService{    @Autowired    private TestMapper testMapper;    @Override    public int deleteByPrimaryKey(Integer id) {        Assert.notNull(id, "id can't be null!");        return testMapper.deleteByPrimaryKey(id);    }    @Override    public MyPage<TestModel> selectAllWithPage(TestQry qry) {        if(qry == null){            qry = new TestQry();        }        MyPage<TestModel> myPage = PageCallBackUtil.selectRtnPage(qry, new IPageHelperPageCallBack() {            @Override            public List<TestModel> select() {                return  testMapper.selectAll();            }        });        return myPage;    }    … 其他方法略}

3.4. Control层

类 TestCtl

@RestController@RequestMapping(value = "/simple")@EnableSwagger2public class TestCtl {    @Autowired    private ITestService testService;    @RequestMapping(value = "delete-by-primary-key/{id}", method = RequestMethod.GET)    public int deleteByPrimaryKey( @PathVariable("id") Integer id){        // 参数验证略        return testService.deleteByPrimaryKey(id);    }    @RequestMapping(value = "insert-selective", method = RequestMethod.POST)    public int insertSelective(@RequestBody TestDto dto){        // 参数验证略        TestModel record = new TestModel();        record.setId(dto.getId());        record.setAge(dto.getAge());        record.setName(dto.getName());        return testService.insertSelective(record);    }    @RequestMapping(value = "select-by-primary-key/{id}", method = RequestMethod.POST)    public TestDto selectByPrimaryKey(@PathVariable("id") String id){        // 参数验证略        return Model2DtoUtil.model2Dto(testService.selectByPrimaryKey(Integer.parseInt(id)), TestDto.class);    }    @RequestMapping(value = "select-all", method = {RequestMethod.POST })    public List<TestDto> selectAll(@RequestBody TestQry qry){        return Model2DtoUtil.model2Dto(testService.selectAll(qry), TestDto.class);    }    @RequestMapping(value = "select-all-with-page", method = {RequestMethod.POST })    public MyPage<TestDto> selectAllWithPage(@RequestBody TestQry qry){        MyPage<TestDto> page = Model2DtoUtil.model2Dto(testService.selectAllWithPage(qry), TestDto.class);        page.setMessage(getLocalInfo());        return page;    }    private String getLocalInfo(){        StringBuilder sb = new StringBuilder();        try {            InetAddress inetAddress = InetAddress.getLocalHost();            sb.append("server info :")                    .append("[ip:").append(inetAddress.getHostAddress()).append(",hostname:").append(inetAddress.getHostName())                    .append("]");        } catch (UnknownHostException e) {            e.printStackTrace();        }        return sb.toString();    }}

3.5. model转化为dto类的工具类

Model2DtoUtil
工具类,封装将model转化为dto类,实现数据层和传输层的解耦

public class Model2DtoUtil {    /**     * 将 MyPage<model> 修改为  MyPage<Dto>     *     * @param sourcePage     * @param cls     * @param <T>     * @param <K>     * @return     */    public static <T, K> MyPage<K> model2Dto(MyPage<T> sourcePage, Class<K> cls) {        if(sourcePage == null){            return null;        }        Assert.notNull(cls, "cls can't be null!");        MyPage<K> dstPage = new MyPage<K>();        dstPage.setTotalCount(sourcePage.getTotalCount());        dstPage.setApiId(sourcePage.getApiId());        dstPage.setMessage(sourcePage.getMessage());        dstPage.setCode(sourcePage.getCode());        // list        List<T> sourceList = sourcePage.getRows();        List<K> dstList = new ArrayList<K>();        dealListModel2Dto(sourceList, cls, dstList);        dstPage.setRows(dstList);        return dstPage;    }    private static <T, K> void dealListModel2Dto(List<T> sourceList, Class<K> cls, List<K> dstList) {        for (T source : sourceList) {            try {                K dst = cls.newInstance();                CommonBeanUtils.copyProperties(source, dst);                dstList.add(dst);            } catch (InstantiationException e) {                e.printStackTrace();                throw new BeanCreationException(e.getMessage());            } catch (IllegalAccessException e) {                e.printStackTrace();                throw new BeanCreationException(e.getMessage());            }        }    }}

CommonBeanUtils
BeanUtils工具类:

public class CommonBeanUtils {    public static void copyProperties(Object source, Object target){        BeanUtils.copyProperties(source, target);    }}

3.6. application.yml

pagehelper相关的配置,其它的配置参数见官网

如果不配置以下参数,则分页机制不会启作用

# 分页配置: https://github.com/pagehelper/Mybatis-PageHelper/blob/master/wikis/zh/HowToUse.mdpagehelper:    helperDialect: oracle    reasonable: true    supportMethodsArguments: true    params: count=countSql

4. Spring Boot集成swagger和测试

为了对测试方便,我们引入swagger

4.1. pom.xml

<!-- swagger2 --><!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 --><dependency>    <groupId>io.springfox</groupId>    <artifactId>springfox-swagger2</artifactId>    <version>2.7.0</version></dependency><!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui --><dependency>    <groupId>io.springfox</groupId>    <artifactId>springfox-swagger-ui</artifactId>    <version>2.7.0</version></dependency>

4.2. @EnableSwagger2

在TestCtl的类上加上@EnableSwagger2

@RestController@RequestMapping(value = "/simple")@EnableSwagger2public class TestCtl {    …}

4.3. 测试

打开地址:http://127.0.0.1:8080/swagger-ui.html
可以看到当前可用的url接口
这里写图片描述
测试 /simple/select-all-with-page接口的分页功能,设置查询功能
这里写图片描述
返回结果如下

这里写图片描述

5.代码

上文的详细代码见github代码,请尽量使用tag v0.2,不要使用master,因为master一直在变,不能保证文章中代码和github上的代码一直相同

阅读全文
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 去越南打工怎么办签证 越南到中国签证怎么办 去越南工作签证怎么办 马来西亚留学签证过期后怎么办 日本留学存款不够怎么办 没有工作单位怎么办签证 深户日本签证怎么办 土耳其跟团签证怎么办 公司取消交通车职工怎么办 出国健康证丢失怎么办 大三阳怎么办健康证 办不了健康证怎么办 办健康证不合格怎么办 美团健康证怎么办 便检取样很多怎么办 拉不出大便怎么办马上解决方法 无业人员怎么办健康证 健康证没身份证怎么办 身份证过期了怎么办护照 驾照体检表丢了怎么办 驾照体检表掉了怎么办 驾校体检表掉了怎么办 身份证掉了怎么办护照 驾照体检表过期了怎么办 助力车行驶证过期怎么办 c1证骑摩托车怎么办 别人知道驾驶证号码怎么办 摩托车卖了车牌怎么办 违章超过12分怎么办 违章扣分24分怎么办 驾驶证有效期过了怎么办 驾驶证到期没审怎么办 驾驶证扣不了分怎么办 集体户口怎么办户口本公证 强制保险单丢了怎么办 车子保险单丢了怎么办 汽车保险单子丢了怎么办 汽车保险贴丢了怎么办 保险本子丢了怎么办 平安保险单丢了怎么办 人寿保险单丢了怎么办