基于注解-简单

1、 引入依赖

  1. <dependency>
  2. <groupId>org.mybatis.spring.boot</groupId>
  3. <artifactId>mybatis-spring-boot-starter</artifactId>
  4. <version>1.3.1</version>
  5. </dependency>

2、 在启动类上加@MapperScan(“com.twx.db”)注解,告诉SpringBoot去哪找Mapper

@SpringBootApplication
@MapperScan("com.twx.db")
public class SpringBootEtlApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootEtlApplication.class, args);
    }
}

3、 在com.twx.db包下,新建一个接口 MonitorMapper,如下:

package com.twx.db;

import com.twx.entity.WarnEntity;
import org.apache.ibatis.annotations.*;

import java.util.List;

@Mapper
public interface MonitorMapper {

    /**
    * SQL语句中的变量 用#{}括起来,变量的名称要和方法参数里的注解@Param()中的一样。
    * 如下: #{warningTitle} == @Param("warningTitle")
    * @Result: 用来映射实体属性和表的字段
    */
    @Select("SELECT j.JobMasterID,w.WarningTitle,w.WarningType,j.IsActivated " +
            " FROM WarningTemplate w INNER join JobMaster j ON w.WarningCode = j.WarningCode " +
            " WHERE WarningTitle LIKE #{warningTitle} and w.WarningType=#{warningType} and j.IsActivated=#{isActivated}")
    @Results({
            @Result(property = "jobMasterId",column = "JobMasterID",javaType = Integer.class),
            @Result(property = "warningTitle",column = "WarningTitle",javaType = String.class),
            @Result(property = "warningType",column = "WarningType",javaType = String.class),
            @Result(property = "isActivated",column = "IsActivated",javaType = Boolean.class)
    })
    List<WarnEntity> query(@Param("warningTitle") String warningTitle,@Param("warningType") String warningType, @Param("isActivated") boolean isActivated);


    @Select("SELECT j.JobMasterID,w.WarningTitle,w.WarningType,j.IsActivated,j.JsonParameter,j.Version " +
            " FROM WarningTemplate w INNER join JobMaster j ON w.WarningCode = j.WarningCode " +
            " WHERE j.JobMasterID=#{jobMasterId}")
    @Results({
            @Result(property = "jobMasterId",column = "JobMasterID",javaType = Integer.class),
            @Result(property = "warningTitle",column = "WarningTitle",javaType = String.class),
            @Result(property = "warningType",column = "WarningType",javaType = String.class),
            @Result(property = "isActivated",column = "IsActivated",javaType = Boolean.class),
            @Result(property = "jsonParameter",column = "JsonParameter",javaType = String.class),
            @Result(property = "version",column = "Version",javaType = Integer.class)
    })
    WarnEntity edit(Integer jobMasterId);
}


@Data
public class WarnEntity {
    /** Job表主键 */
    private Integer jobMasterId;

    /** 预警名称 */
    private String warningTitle;

    /** 预警类型 */
    private String warningType;

    /** 启用状态  */
    private Boolean isActivated;

    /** 详细内容 */
    private String jsonParameter;

    /** 版本号 */
    private Integer version;

}

4、 单元测试

package com.twx.db;

import com.twx.entity.WarnEntity;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
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;

import static org.junit.Assert.*;

@RunWith(SpringRunner.class)
@SpringBootTest
public class MonitorMapperTest {
    @Autowired
    private MonitorMapper monitorMapper;

    @Test
    public void query() throws Exception {
        List<WarnEntity> tasks = monitorMapper.query("%集装箱%", "WaitDoingTask",true);
        Assert.assertNotEquals(0,tasks.size());
    }

    @Test
    public  void edit() {
        WarnEntity edit = monitorMapper.edit(10);
        Assert.assertNotNull(edit);
    }

}

基于注解-动态注入

上面例子中的sql都是静态的(意味着不需要动态拼接),但是现在我们需要根据传入参数的值来动态的拼接SQL.

怎么做呢?

现在不用@Select 而是要用 @SelectProvider (类似的还有@UpdateProvider @DeleteProvider @InsertProvider)

看下面的这段代码:

@SelectProvider(type = MonitorProvider.class,method = "query")
List<WarnEntity> query(String warningTitle,List<String> warningTypes, List<Boolean> activateLists,int page,int size);

现在我们没在方法定义上写一大堆sql 和 @Results了。而是用 @SelectProvider(type = MonitorProvider.class,method = "query") 代替。 在类 MonitorProvider.class 的 query()方法中去拼接我们的SQL.

来看看是怎么拼SQL的。

public class MonitorProvider {

    public String query(Map<String,Object> map){
        String title = (String) map.get("arg0");
        List<String> types = (List<String>) map.get("arg1");
        List<Boolean> activates = (List<Boolean>) map.get("arg2");
        int page = (int)map.get("arg3");
        int size = (int)map.get("arg4");
        int offset = (page-1)*size;

        String sql = "SELECT j.JobMasterID,w.WarningTitle,w.WarningType,j.IsActivated "+
                " FROM WarningTemplate w INNER join JobMaster j ON w.WarningCode = j.WarningCode "+
                "WHERE WarningTitle LIKE \'"+title+"\' and w.WarningType in ("+list2StringByComma(types)+") " +
                "and j.IsActivated in ("+boolean2List(activates)+")"+
                " ORDER BY j.JobMasterID OFFSET "+(offset)+" ROWS FETCH NEXT "+size+" ROWS ONLY";
        return  sql;

    }
}

在这里我们传入的参数是 Map map。 再看方法里 我们是怎么把传入的 String warningTitle,List<String> warningTypes, List<Boolean> activateLists,int page,int size 这些参数提取出来的。

没错,arg0 arg1 arg2 arg3 arg4 …呵呵,很傻吧。

剩下的工作就是拼接 SQL 语句了,这里我个人觉得很烦。看title那里,前后还要加个 单引号 。累觉不爱。

所以,这一块,我还要看看别人是怎么做的。

或许用xml方式会简单点。(在拼接SQL的过程中,我都有点想放弃mybatis了,真的很累)。还要继续学习啊!!
好,那就来看xml是怎么写的吧!

基于xml

pom文件中的引入不需要变化,如上就可以了。。。

1、 修改 application.yml文件,告诉springboot去哪找mybatis的xml文件

mybatis:
  mapper-locations: classpath:mapper/*.xml

2、 在基于注解的动态SQL中,我们是这样声明接口的

@SelectProvider(type = MonitorProvider.class,method = "query")
List<WarnEntity> query(String warningTitle,List<String> warningTypes, List<Boolean> activateLists,int page,int size);

然后在MonitorProvider的query方法中手动拼接SQL字符串,这种方法很累,要特别注意拼接时的空格、引号。其实官方提供了new SQL() 的java方法,但是我没找到有IN(),所以就放弃了。

现在我们来看在xml中怎么配置query方法吧!

现在query()方法的声明是这样的:

List query(MonitorQueryParam param);

查询参数是个对象 MonitorQueryParam。它长下面这样:

package com.twx.db.param;

import lombok.Data;

import java.util.List;

@Data
public class MonitorQueryParam {
    private String warningTitle;
    private List<String> warningTypes;
    private List<Boolean> activateLists;
    private int offset;
    private int size;

}

该对象对应的属性名,其实就是我们之前定义query方法时的参数啦~

3、 在claspath下新建个mapper目录,然后新建个MonitorMapper.xml。(看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.twx.db.MonitorMapper">
    <!-- 这里的id: query  对应的是MonitorMapper中的方法名 -->
    <!-- 我把select的结果 as 成了 WarnEntity的属性名,这样mybatis就能自动帮我们封装成对象了 -->
    <!-- 现在的in (?,?,?) 中的变量 用foreach循环出来,不需要再手动加单引号,逗号和圆括号了,开心! -->
    <select id="query" parameterType="com.twx.db.param.MonitorQueryParam" resultType="WarnEntity">
        SELECT j.JobMasterID as jobMasterId,
            w.WarningTitle as warningTitle,
            w.WarningType as warningType,
            j.IsActivated as isActivated
        FROM WarningTemplate w INNER join JobMaster j ON w.WarningCode = j.WarningCode
        WHERE WarningTitle LIKE #{warningTitle}
        AND w.WarningType in
        <foreach collection="warningTypes" item="type" open="(" close=")" separator=",">
            #{type}
        </foreach>
        AND j.IsActivated in
        <foreach collection="activateLists" item="activate" open="(" close=")" separator=",">
            #{activate}
        </foreach>
        ORDER BY j.JobMasterID OFFSET #{offset} ROWS FETCH NEXT #{size} ROWS ONLY
    </select>
</mapper>

4、 单元测试

 @Test
public void query() throws Exception {
    MonitorQueryParam param = new MonitorQueryParam();
    param.setWarningTitle("%集装箱%");
    param.setWarningTypes(Arrays.asList("WaitDoingTask"));
    param.setActivateLists(Arrays.asList(true,false));
    param.setOffset(0);
    param.setSize(5);
    List<WarnEntity> tasks = monitorMapper.query(param);
    Assert.assertNotEquals(0,tasks.size());
}

5、 对了,如果我想要再测试时,看到mybatis生成的sql语句,该怎么办呢?

很简单,在logback中把com.twx.db包的日志级别设置成 trace就行了

<logger name="com.twx.db" level="trace" />


另外再举个例子,在xml中使用 resultMap

1、 在 dao包下新建个接口 OrderMasterMapper

package com.twx.springbootmybatis.dao;


import org.apache.ibatis.annotations.Mapper;
import com.twx.springbootmybatis.entity.OrderMaster;

@Mapper
public interface OrderMasterMapper {

     OrderMaster findByOrderId(String orderId);
}

注意要加个@Mapper注解,不然@Autowired时会提示.(或者在启动类上加@MapperScan)
No qualifying bean of type 'com.twx.springbootmybatis.dao.OrderMasterMapper' available

2、 xml文件 (classpath:mapper/OrderMasterMapper.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.twx.springbootmybatis.dao.OrderMasterMapper">

    <!--OrderMaster这里我们写了类的完整路径,每次这样写多麻烦啊。-->
    <!--如果我们只写OrderMaster会怎样呢?当然会提示找不到OrderMaster类啊-->
    <!--所以 得在application.yml配置一下啊,加上这么一句:-->
        <!--mybatis.type-aliases-package: com.twx.springbootmybatis.entity-->
   <resultMap id="orderMasterMap" type="com.twx.springbootmybatis.entity.OrderMaster">
        <id column="order_id" property="orderId" jdbcType="VARCHAR"></id>
        <result column="buyer_name" property="buyerName" jdbcType="VARCHAR"></result>
        <result column="buyer_phone" property="buyerPhone" jdbcType="VARCHAR" />
        <result column="buyer_address" property="buyerAddress" jdbcType="VARCHAR" />
        <result column="buyer_openid" property="buyerOpenid" jdbcType="VARCHAR" />
        <result column="order_amount" property="orderAmount" jdbcType="DECIMAL" />
        <result column="order_status" property="orderStatus" jdbcType="TINYINT" />
        <result column="pay_status" property="payStatus" jdbcType="TINYINT" />
        <result column="create_time" property="createTime" jdbcType="TIMESTAMP" />
        <result column="update_time" property="updateTime" jdbcType="TIMESTAMP" />
    </resultMap>

    <select id="findByOrderId" parameterType="String" resultMap="orderMasterMap">
        SELECT * FROM order_master WHERE order_id = #{orderId}
    </select>
</mapper>

3、 对应的OrderMaster.java

package com.twx.springbootmybatis.entity;

import lombok.Data;

import java.math.BigDecimal;
import java.util.Date;

@Data
public class OrderMaster {
    private String orderId;

    private String buyerName;
    private String buyerPhone;
    private String buyerAddress;

    /** 微信ID */
    private String buyerOpenid;
    /** 订单总价 */
    private BigDecimal orderAmount;

    /** 订单状态 */
    private Integer orderStatus;

    /** 支付状态 */
    private Integer payStatus;

    /** 创建时间 */
    private Date  createTime;
    /** 更新时间 */
    private Date updateTime;

}

5、 单元测试

package com.twx.springbootmybatis.dao;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.Map;

import static org.junit.Assert.*;

@RunWith(SpringRunner.class)
@SpringBootTest
public class OrderMasterMapperTest {

    @Autowired
    private OrderMasterMapper masterMapper;

   @Test
    public void findByOrderId() throws Exception {
        OrderMaster orderMaster = masterMapper.findByOrderId("123321");
        System.out.println(orderMaster);
        Assert.assertNotNull(orderMaster);
    }

}