Spring整合JpaMapper(Mybatis通用插件)详情

Spring整合JpaMapper(Mybatis通用插件)详情

一、概述

如果你喜欢Jpa hibernate的简洁写法;

或许你不喜欢写sql;

或许你用了Mapper工具之后还是要写sql;

那就用JpaMapper吧!JpaMapper是尽量按照JPA hibernate的书写风格,对mybatis进行封装,是CRUD操作更加简单易用,免于不断写sql。

前面一篇《Spring和Mybatis整合详解》介绍了Spring如何结合mybatis进行数据库访问操作。这一篇介绍下springmvc环境下JpaMapper的使用。

代码可以在Spring组件化构建https://www.pomit.cn/java/spring/spring.html中的JpaMapper组件中查看,并下载。

首发地址:

  品茗IT-同步发布

品茗IT提供在线支持:

  一键快速构建Spring项目工具

  一键快速构建SpringBoot项目工具

  一键快速构建SpringCloud项目工具

  一站式Springboot项目生成

  Mysql一键生成Mybatis注解Mapper

  Mysql一键生成SpringDataRest项目

如果大家正在寻找一个java的学习环境,或者在开发中遇到困难,可以加入我们的java学习圈,点击即可加入,共同学习,节约学习时间,减少很多在学习中遇到的难题。

二、环境配置

本文假设你已经引入Spring必备的一切了,已经是个Spring项目了,如果不会搭建,可以打开这篇文章看一看《Spring和Spring Mvc 5整合详解》。

2.1 maven依赖

和前面的《Spring和Mybatis整合详解》的配置一样,
使用Mybatis需要引入mybatis和mybatis-spring,已经数据源和connector;另外,需要引入jpa-mapper-core。

注意:jpa-mapper要求Mybatis版本在3.4.6以上,如果mybatis-spring版本是1.3.2, Mybatis版本就是3.4.6。



    4.0.0
    
        cn.pomit
        SpringWork
        0.0.1-SNAPSHOT
    
    JpaMapper
    jar
    JpaMapper
    http://maven.apache.org
    
        
            org.springframework
            spring-web
        
        
            org.springframework
            spring-context
        
        
            org.springframework
            spring-orm
        
        
            mysql
            mysql-connector-java
        
        
            log4j
            log4j
        
        
            org.apache.commons
            commons-dbcp2
        
        
            org.mybatis
            mybatis
        
        
            org.mybatis
            mybatis-spring
        
        
            cn.pomit
            jpa-mapper-core
            2.1
        
                
            com.fasterxml.jackson.core
            jackson-annotations
        
        
            com.fasterxml.jackson.core
            jackson-core
        
        
            com.fasterxml.jackson.core
            jackson-databind
        
    
    
        JpaMapper
    



父模块可以在https://www.pomit.cn/spring/SpringWork/pom.xml获取。

2.2 Spring配置

需要配置数据源、jdbcTemplate、sqlSessionFactory、transactionManager和MapperScannerConfigurer。




    
        
        
        
            
                classpath:db.properties
            
        
    
    
    
        
        
        
        

        
        
        

        
        
        
        
    

    
        
    

    

    
    
        
    

    
    
        
        
        
    
    
        
    

这里面,需要注意的是:

  • dataSource,这里用的是dbcp2数据源。

  • sqlSessionFactory,是mybatis的连接信息配置。

  • MapperScannerConfigurer,指明mapper的路径,要使用Mybatis的注解sql必须指明。

  • transactionManager,事务处理器。

  • tx:annotation-driven:开启事务注解。

mybatis.properties中存放数据库的地址端口等连接信息。

mybatis.properties:

db.url=jdbc:mysql://127.0.0.1:3306/boot?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
db.username=cff
db.password=123456
db.dirverClass=com.mysql.cj.jdbc.Driver

mybatis/mybatis-config.xml:

  
  
 
    
              
     
  

这里我只配置了日志打印功能。

三、JpaMapper配置

@Configuration配置JpaMapper,@Autowired注入List sqlSessionFactoryList。

如果启动过程中出现:
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found):

出现这种问题,是因为JpaMapper处理Mapper的过程中,Mapper还未生成,而mapper是在service注入的时候才生成的。所以需要调整bean的生成顺序。可以使用下面两种方式:

  • 将MapperScanner作为bean生成,需要使用@Order将MapperScanner生成顺序调整到最低,以便在生成mapper的所有bean之后再初始化。经试验,这种方式不带@Order也可以将bean的生成顺序调整到Service相关bean之后。

  • 将JpaMapperConfig的bean生成时间使用@DependsOn("userInfoService")调整顺序到userInfoService之后。

JpaMapperConfig:

package cn.pomit.springwork.mybatis;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.apache.ibatis.binding.MapperRegistry;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import cn.pomit.jpamapper.core.MapperScanner;
import cn.pomit.jpamapper.core.mapper.register.MappedStatementRegister;

/**
 * Mapper 配置
 *
 * @author cff
 */
@Configuration
public class JpaMapperConfig {

    @Bean
    public MapperScanner mapperScanner(List sqlSessionFactoryList) throws SQLException {
        MapperScanner mapperScanner = new MapperScanner();
        for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) {
            org.apache.ibatis.session.Configuration configuration = sqlSessionFactory.getConfiguration();
            MapperRegistry mapperRegistry = configuration.getMapperRegistry();
            List> mappers = new ArrayList<>(mapperRegistry.getMappers());
            MappedStatementRegister mappedStatementRegister = new MappedStatementRegister(configuration);
            mappedStatementRegister.addMappers(mappers);
            mapperScanner.addMappedStatementRegister(mappedStatementRegister);
        }

        mapperScanner.scanAndRegisterJpaMethod();
        return mapperScanner;
    }
}

这里,使用 mapperScanner.scanAndRegisterJpaMethod(); 对mybatis已有的mapper进行扫描,自动记录jpaMapper支持的方法,并加入mybatis的mapper管理中。

四、数据访问

4.1 普通CRUD

4.1.1 Mapper

mybatis的Mapper直接继承CrudMapper即可.

可以使用以下方式进行数据库的操作:

  • CrudMapper中定义的方法
  • findBy+字段名进行查询。
  • deleteBy + 字段名进行查询。
  • 主键取回策略@GeneratedValue与@SelectKey;@GeneratedValue(generator="JDBC")代表使用mybatis的Jdbc3KeyGenerator。对应自增。@SelectKey注解(非mybatis的注解,但和mybatis的注解一致,这里是为了将SelectKey注解扩展到字段上)添加到字段上,和mybatis的@SelectKey注解功能一致

UserInfoDao :

package cn.pomit.springwork.mybatis.mapper;


import java.util.Collection;
import java.util.List;

import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import cn.pomit.jpamapper.core.mapper.CrudMapper;
import cn.pomit.springwork.mybatis.domain.UserInfo;

@Mapper
public interface UserInfoDao extends CrudMapper {

    List findByMobile(String mobile);
    
    int saveAllWithId(@Param("list") Collection entities);
    
    @Insert({""})
    int saveTest(UserInfo entity);

    int deleteByUserName(String userName);
    
    List findByNameAndMobile(String name, String mobile);
    
    int deleteByNameAndMobile(String name, String mobile);
}

4.1.2 实体

实体类需要加上@Table注解,指明数据库表,同时需要和数据库字段对应的变量加上@Column注解,主键加@Id即可。

注意:所有非主键字段都要加上@Column注解,无论是否需要改变字段名称。

UserInfo :

package cn.pomit.springwork.mybatis.domain;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;


/**
 * The persistent class for the user_info database table.
 * 
 */
@Table(name="user_info")
public class UserInfo implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name="user_name")
    private String userName;

    @Column()
    private String mobile;

    @Column()
    private String name;

    @Column()
    private String passwd;

    @Column()
    private String valid;

    public UserInfo() {
    }

    public String getUserName() {
        return this.userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getMobile() {
        return this.mobile;
    }

    public void setMobile(String mobile) {
        this.mobile = mobile;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPasswd() {
        return this.passwd;
    }

    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }

    public String getValid() {
        return this.valid;
    }

    public void setValid(String valid) {
        this.valid = valid;
    }

    @Override
    public String toString() {
        return "UserInfo [userName=" + userName + ", mobile=" + mobile + ", name=" + name + ", passwd=" + passwd
                + ", valid=" + valid + "]";
    }
}

4.2 分表查询

4.2.1 Mapper

新建Mapper直接继承SimpleShardingMapper即可。但是需要在泛型实体中对分表字段做配置。

package cn.pomit.springwork.mybatis.mapper;

import org.apache.ibatis.annotations.Mapper;

import cn.pomit.jpamapper.core.mapper.SimpleShardingMapper;
import cn.pomit.springwork.mybatis.domain.UserInfoHis;

@Mapper
public interface UserInfoHisDao extends SimpleShardingMapper {
    
}

4.2.2 实体

实体类需要加上@Table注解,指明数据库表,同时需要和数据库字段对应的变量加上@Column注解,主键加@Id即可。

在分表字段上,使用@ShardingKey注解。

注意:所有非主键字段都要加上@Column注解,无论是否需要改变字段名称。

SimpleShardingMapper只支持SimpleShardingMapper中定义的方法。不支持xxxBy这样写法。

这里的@Table指明的是分表的通用前缀。结合@ShardingKey注解,构成了多个表名称。

@ShardingKey注解:

  • prefix,表名称与分表策略返回值之间的分割符。

  • methodPrecis,唯一表的指定策略。

  • methodRange,多个表的指定策略。

  • suffix,表名称与分表策略返回值组合后可以添加的后缀。

UserInfoHis :

package cn.pomit.springwork.mybatis.domain;

import java.io.Serializable;
import javax.persistence.*;

import com.fasterxml.jackson.annotation.JsonIgnore;

import cn.pomit.jpamapper.core.annotation.ShardingKey;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * The persistent class for the user_info database table.
 * 
 */
@Table(name="user_info_his")
public class UserInfoHis implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name="user_name")
    private String userName;

    @Column()
    @ShardingKey(prefix="_", methodPrecis="getTable", methodRange = "getTables")
    private String mobile;

    @Column()
    private String name;

    @Column()
    private String passwd;

    @Column()
    private String valid;

    public UserInfoHis() {
    }

    public String getUserName() {
        return this.userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getMobile() {
        return this.mobile;
    }
    
    @JsonIgnore
    public static String getTable(Object mobile) {
        int index = Integer.parseInt(mobile.toString()) % 5;
        return String.valueOf(index);
    }
    
    @JsonIgnore
    public static String[] getTables(Object start, Object end) {
        Map maps = new HashMap<>();
        int index = 0;
        for(int i = Integer.parseInt(start.toString()); i < Integer.parseInt(end.toString()); i++){
            if(index >= 5)break;
            maps.put(index, String.valueOf(i % 5));
            index++;    
        }
        
        List mapValueList = new ArrayList(maps.values()); 
        String[] arr = new String[mapValueList.size()];
        return mapValueList.toArray(arr);
    }

    public void setMobile(String mobile) {
        this.mobile = mobile;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPasswd() {
        return this.passwd;
    }

    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }

    public String getValid() {
        return this.valid;
    }

    public void setValid(String valid) {
        this.valid = valid;
    }

    @Override
    public String toString() {
        return "UserInfo [userName=" + userName + ", mobile=" + mobile + ", name=" + name + ", passwd=" + passwd
                + ", valid=" + valid + "]";
    }
}

这里:

  • @ShardingKey的methodPrecis和methodRange指定是该实体中的static方法,这一点一定要注意。

  • @ShardingKey的prefix是分表策略与表名称结合时候的前缀。如上面的实体指定表名为user_info_his,prefix是_。methodPrecis和methodRange指定的两个方法返回的是数字1、2、3 ...;这时,分表就包含了user_info_his_1、user_info_his_2、user_info_his_3 ...

  • 上面的getTable方法是按照mobile取余标明了从哪一张表中取数据。getTables方法根据起始字段查出一个表的范围。

4.3 分页查询

4.3.1 Mapper

mybatis的Mapper直接继承PagingAndSortingMapper即可实现分页功能.

支持功能如下:

  1. CrudMapper中定义的方法
  2. findBy和deleteBy功能(不能带分页实体)
  3. PagingAndSortingMapper中定义的方法
  4. pageBy分页查询(类似带分页实体的findBy)。
  5. sortBy排序条件查询(2.0版本新特性)。

UserInfoSortDao :

package cn.pomit.springwork.mybatis.mapper;


import java.util.List;

import org.apache.ibatis.annotations.Mapper;

import cn.pomit.jpamapper.core.domain.page.Page;
import cn.pomit.jpamapper.core.domain.page.Pageable;
import cn.pomit.jpamapper.core.domain.page.Sort;
import cn.pomit.jpamapper.core.mapper.PagingAndSortingMapper;
import cn.pomit.springwork.mybatis.domain.UserInfo;


@Mapper
public interface UserInfoSortDao extends PagingAndSortingMapper {
    Page pageByPasswd(String passwd, Pageable pageable);
    
    List sortByPasswd(String passwd, Sort sort);
}

4.3.2 实体

实体类需要加上@Table注解,指明数据库表,同时需要和数据库字段对应的变量加上@Column注解,主键加@Id即可

实体和4.1.2的实体一致。

4.4 联表查询

4.4.1 Mapper

同样,将新建的Mybatis的Mapper直接继承CrudMapper即可.

在需要联表查询的字段上,增加@Many或者@One注解,同时增加@JoinColumns或者@JoinColumn注解。即可实现联表查询。

分表情况下不能使用联表操作,联表默认无效。

UserInfoUnionDao:

package cn.pomit.springwork.mybatis.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;

import cn.pomit.jpamapper.core.mapper.CrudMapper;
import cn.pomit.springwork.mybatis.domain.UserInfoUnion;

@Mapper
public interface UserInfoUnionDao extends CrudMapper {
    List findByMobile(String mobile);
}

4.4.2 实体

在需要联表查询的字段上,增加@Many或者@One注解,同时增加@JoinColumns或者@JoinColumn注解。即可实现联表查询。

其中,@Many和@One是JpaMapper的注解。@JoinColumns和@JoinColumn使用了javax.persistence包中的注解。

@JoinColumn注解只有name和referencedColumnName字段有效,并且这两个字段分别对应着两个实体中的属性名,而不是表字段名。

UserInfoUnion :

package cn.pomit.springwork.mybatis.domain;

import java.io.Serializable;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinColumns;
import javax.persistence.Table;

import org.apache.ibatis.mapping.FetchType;

import cn.pomit.jpamapper.core.annotation.Many;

/**
 * The persistent class for the user_info database table.
 * 
 */
@Table(name = "user_info")
public class UserInfoUnion implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "user_name")
    private String userName;

    @Column()
    private String mobile;

    @Column()
    private String name;

    @Column()
    private String passwd;

    @Column()
    private String valid;

    @Many(fetchType = FetchType.EAGER)
    @JoinColumns({ @JoinColumn(name = "userName", referencedColumnName = "userName") })
    private List userRole;

    public UserInfoUnion() {
    }

    public String getUserName() {
        return this.userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getMobile() {
        return this.mobile;
    }

    public void setMobile(String mobile) {
        this.mobile = mobile;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPasswd() {
        return this.passwd;
    }

    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }

    public String getValid() {
        return this.valid;
    }

    public void setValid(String valid) {
        this.valid = valid;
    }

    public List getUserRole() {
        return userRole;
    }

    public void setUserRole(List userRole) {
        this.userRole = userRole;
    }

    @Override
    public String toString() {
        return "UserInfo [userName=" + userName + ", mobile=" + mobile + ", name=" + name + ", passwd=" + passwd
                + ", valid=" + valid + "]";
    }
}

五、Service层逻辑

service分别对各个mapper进行调用。

UserInfoService :

package cn.pomit.springwork.mybatis.service;

import java.util.Collection;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import cn.pomit.jpamapper.core.domain.page.Page;
import cn.pomit.jpamapper.core.domain.page.Pageable;
import cn.pomit.springwork.mybatis.domain.UserInfo;
import cn.pomit.springwork.mybatis.domain.UserInfoHis;
import cn.pomit.springwork.mybatis.domain.UserInfoUnion;
import cn.pomit.springwork.mybatis.mapper.UserInfoDao;
import cn.pomit.springwork.mybatis.mapper.UserInfoHisDao;
import cn.pomit.springwork.mybatis.mapper.UserInfoSortDao;
import cn.pomit.springwork.mybatis.mapper.UserInfoUnionDao;

@Service
public class UserInfoService {
    @Autowired
    UserInfoDao userInfoDao;
    @Autowired
    UserInfoHisDao userInfoHisDao;
    @Autowired
    UserInfoSortDao userInfoSortDao;
    @Autowired
    UserInfoUnionDao userInfoUnionDao;

    public UserInfo getUserInfoByUserName(String userName) {
        return userInfoDao.findOne(userName);
    }

    public List findByMobile(String mobile) {
        return userInfoDao.findByMobile(mobile);
    }

    public Collection findByMobileSharding(String mobile) {
        UserInfoHis userInfoHis = new UserInfoHis();
        userInfoHis.setMobile(mobile);
        return userInfoHisDao.find(userInfoHis);
    }

    public Page findByPage(String passwd) {
        Pageable pageable = new Pageable();
        pageable.setPage(1);
        pageable.setSize(5);
        Page page = userInfoSortDao.pageByPasswd(passwd, pageable);
        return page;
    }

    public List findUnion(String mobile) {

        return userInfoUnionDao.findByMobile(mobile);
    }
}

六、测试web

写一个测试web对这些mapper进行测试。

JpaMapperRest :

package cn.pomit.springwork.mybatis.web;

import java.util.Collection;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import cn.pomit.jpamapper.core.domain.page.Page;
import cn.pomit.springwork.mybatis.domain.UserInfo;
import cn.pomit.springwork.mybatis.domain.UserInfoHis;
import cn.pomit.springwork.mybatis.domain.UserInfoUnion;
import cn.pomit.springwork.mybatis.service.UserInfoService;

@RestController
@RequestMapping("/jpamapper")
public class JpaMapperRest {

    @Autowired
    UserInfoService userInfoService;

    @RequestMapping("/user")
    public UserInfo getUserInfoByUserName() {
        return userInfoService.getUserInfoByUserName("cff");
    }

    @RequestMapping("/findByMobile")
    public List findByMobile() {
        return userInfoService.findByMobile("3242");
    }

    @RequestMapping("/findByMobileSharding")
    public Collection findByMobileSharding() {
        return userInfoService.findByMobileSharding("3242");
    }

    @RequestMapping("/findByPage")
    public Page findByPage() {
        return userInfoService.findByPage("123455");
    }

    @RequestMapping("/findUnion")
    public List findUnion() {
        return userInfoService.findUnion("3242");
    }
}

七、过程中用到的其他实体

UserRole :

package cn.pomit.springwork.mybatis.domain;

import java.io.Serializable;
import javax.persistence.*;


/**
 * The persistent class for the user_role database table.
 * 
 */
@Table(name="user_role")
public class UserRole implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(generator="JDBC")
    @Column()
    private Integer id;

    @Column(length=10)
    private String role;
    
    @Column(name="user_name")
    private String userName;
    
    @Column(name ="phone")
    private String phone;


    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public UserRole() {
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getRole() {
        return this.role;
    }

    public void setRole(String role) {
        this.role = role;
    }

    @Override
    public String toString() {
        return "UserRole [id=" + id + ", role=" + role + ", userName=" + userName + "]";
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    
}

快速构建项目

Spring组件化构建

SpringBoot组件化构建

SpringCloud服务化构建

喜欢这篇文章么,喜欢就加入我们一起讨论Java技术吧!


Spring整合JpaMapper(Mybatis通用插件)详情_第1张图片
品茗IT交流群

你可能感兴趣的:(Spring整合JpaMapper(Mybatis通用插件)详情)