springBoot集成mybatis使用ResultHandler返回map数据类型

29 篇文章 0 订阅
23 篇文章 0 订阅

在 springBoot 的 web 项目中,平时查询数据返回都是:集合 list 、实体类 bean 、数量 int / long 。如果返回 map ,也是Map<String,Map<String,Object>>Map<String,实体类bean>,直接返回Map<String,String>Map<String,Object>会报错,通过查询得知,可以使用 ResultHandler 实现。
ResultHandler,对返回的结果进行处理,最终得到自己想要的数据格式或类型。就是说,可以自定义返回类型。

参考

mybatis之ResultHandler如何使用
Spring Boot 下 MyBatis 的几种使用方式
mybatis中resulthandler的用法
Mybatis源码分析:MapperMethod中内部静态类MethodSignature的作用
springboot整合Mybatis 之 创建对象SqlSessionFactory和SqlSession(一)
Mybatis select返回值为map时,选取表字段的两列作为key,value
mybatis 中的 ResultHandler(传入map返回map)
MyBatis 核心配置综述之 ResultSetHandler

操作

代码

pom

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.3.1.RELEASE</spring-boot.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-core</artifactId>
            <version>5.3.8</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-crypto</artifactId>
            <version>5.3.8</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

配置

server:
  port: 8080
spring:
  datasource:
    password: 'xxxxxx'
    username: 'root'
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: 'jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai'
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8
mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: xx.xxx.pojo
  configuration:
    map-underscore-to-camel-case: true #使用驼峰命名法转换字段

java

启动类增加mybatis的扫描注解@MapperScan(basePackages = "xx.xxx.dao")

controller

import xx.xxx.common.MapResultHandler;
import xx.xxx.dao.DicTypeDao;
import xx.xxx.pojo.DicType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

/**
 * 测试数据接口
 *
 * @author z.y.l
 * @version v1.0
 * @date 2020-09-10
 */
@Controller
@RequestMapping("/db")
public class TestDbController {
    private final Logger logger = LoggerFactory.getLogger(TestDbController.class);
    @Resource private DicTypeDao dicTypeDao;
    @RequestMapping("")
    @ResponseBody
    public String root(){
        return "Hello Spring Boot DB demo.";
    }
    @RequestMapping("/all")
    @ResponseBody
    public List<DicType> all(){
        logger.info("查询 全部 数据");
        return dicTypeDao.selectAll();
    }
    @RequestMapping("/map")
    @ResponseBody
    public Map<String, Object> map(){
        logger.info("查询 全部 数据");
        MapResultHandler handler = new MapResultHandler("DIC_TYPE","DIC_NAME");
        dicTypeDao.selectMap(handler);
        Map<String, Object> map = handler.getResultMap();
        logger.info("map >> {}",map);
        return map;
    }
}

dao

import xx.xxx.DicType;
import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.ResultType;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.session.ResultHandler;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Map;

/**
 * DicTypeDao 接口说明:
 *
 * @author z.y.l
 * @version v1.0
 * @date 2022/10/9
 */
@Mapper
@Repository
public interface DicTypeDao {
    /**
     * 查询全部
     * @return 集合
     */
    List<DicType> selectAll();
    /**
     * 查询结果map
     * @param handler 自定义结果处理器
     */
    @ResultType(Map.class)
    @Select("select DIC_TYPE, DIC_NAME from test.dic_type_b")
    void selectMap(ResultHandler<Map<String, Object>> handler);
}

测试表

import java.util.Date;

/**
 * 字典类型表
 * <pre>
 *  CREATE TABLE `dic_type_b` (
 *   `ID` int NOT NULL COMMENT '主键',
 *   `DIC_TYPE` varchar(10) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '字典类型',
 *   `DIC_NAME` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '字典类型名称',
 *   `VALID` varchar(2) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '有效标志',
 *   `MEMO` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '字典类型说明',
 *   `CREATE_TIME` datetime DEFAULT NULL COMMENT '新增时间',
 *   `UPDATE_TIME` datetime DEFAULT NULL COMMENT '修改时间',
 *   `VERSION` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '版本',
 *   PRIMARY KEY (`ID`)
 * ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='字典类型表';
 * </pre>
 * @author z.y.l
 * @version v1.0
 * @date 2022/10/9
 */
public class DicType {
    private Integer id;
    private String dicType;
    private String dicName;
    private String valid;
    private String memo;
    private Date createTime;
    private Date updateTime;
    private String version;
    set...
    get...
}

mapper

<?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="xx.xxx.dao.DicTypeDao">
    <select id="selectAll" resultType="xx.xxx.pojo.DicType">
        select ID, DIC_TYPE, DIC_NAME,VALID,MEMO,CREATE_TIME,UPDATE_TIME,VERSION
        from test.dic_type_b
    </select>
</mapper>

自定义ResultHandler

import org.apache.ibatis.session.ResultContext;
import org.apache.ibatis.session.ResultHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;

/**
 * mybatis 返回 map 结果处理器
 *
 * @author z.y.l
 * @version v1.0
 * @date 2022/10/9
 */
public class MapResultHandler implements ResultHandler<Map<String, Object>> {
    private final Logger logger = LoggerFactory.getLogger(MapResultHandler.class);
    private final Map<String, Object> resultMap = new HashMap<>();
    private final String key,val;
    @Override
    public void handleResult(ResultContext<? extends Map<String, Object>> resultContext) {
        Map<String, Object> map = resultContext.getResultObject();
        logger.debug("自定义查询处理器-行-map,{}",map);
        Object value = map.get(key);
        if (null != value && !resultMap.containsKey(value.toString())) {
            resultMap.put(map.get(key).toString(),map.get(val));
        }else{
            logger.debug("自定义查询处理器-行异常-map,{}",value);
        }
    }
    public MapResultHandler(String key,String val){
        this.key = key;
        this.val = val;
    }
    public Map<String, Object> getResultMap() {
        return resultMap;
    }
}

测试

访问:http://localhost:8080/db/map
在这里插入图片描述

{
    "STATUS": "状态",
    "GEND": "性别",
    "TYPE": "类型"
}

日志

TestDbController [TestDbController.java:46] =.= map >> {STATUS=状态, GEND=性别, TYPE=类型}

其他

通过查询的网络文章得知,执行自定义ResultHandler的代码位置。org.apache.ibatis.binding.MapperMethod类方法

public Object execute(SqlSession sqlSession, Object[] args) {
    Object result;
    switch (command.getType()) {
      case INSERT: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.insert(command.getName(), param));
        break;
      }
      case UPDATE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.update(command.getName(), param));
        break;
      }
      case DELETE: {
        Object param = method.convertArgsToSqlCommandParam(args);
        result = rowCountResult(sqlSession.delete(command.getName(), param));
        break;
      }
      case SELECT:
      // 查询的处理
        if (method.returnsVoid() && method.hasResultHandler()) {
        // 只有符合这个判断的才能使用自定义ResultHandler
        // 方法返回void,并且 入参含 ResultHandler 实现
          executeWithResultHandler(sqlSession, args);
          result = null;
        } else if (method.returnsMany()) {
          result = executeForMany(sqlSession, args);
        } else if (method.returnsMap()) {
          result = executeForMap(sqlSession, args);
        } else if (method.returnsCursor()) {
          result = executeForCursor(sqlSession, args);
        } else {
          Object param = method.convertArgsToSqlCommandParam(args);
          result = sqlSession.selectOne(command.getName(), param);
          if (method.returnsOptional()
              && (result == null || !method.getReturnType().equals(result.getClass()))) {
            result = Optional.ofNullable(result);
          }
        }
        break;
      case FLUSH:
        result = sqlSession.flushStatements();
        break;
      default:
        throw new BindingException("Unknown execution method for: " + command.getName());
    }
    if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
      throw new BindingException("Mapper method '" + command.getName()
          + " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
    }
    return result;
  }

自定义 DefaultSqlSession 未成功实现

再看了 mybatis 的查询返回 map 源码(太菜买看完),如果要想通过扩展 mybatis 来支持Map<String,String> ,但是因为部分核心bean(org.apache.ibatis.mapping.ResultMap)不太好处理内部字段,故放弃。
本标题只做记录,可以不用看
重写的类有:
org.apache.ibatis.session.defaults.DefaultSqlSessionFactory方法SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit)
org.apache.ibatis.session.defaults.DefaultSqlSessio方法SqlSession <K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds)
org.apache.ibatis.executor.result.DefaultMapResultHandler方法void handleResult(ResultContext<? extends V> context)

END

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值