简单优雅的mybatis接口化组件

batis-rest是一款旨在简化mybatis使用的组件,能够自动将mapper操作方法转换为REST接口,减少service与controller层代码开发工作量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

batis-rest是一个简单而优雅的组件,可以将mybatis的mapper操作方法暴露为rest接口,从而减少service和controller的代码开发。

使用方法和源码详见https://gitee.com/wangbaishi_libi/data-rest

本组件实现过程:

  1. 组件初始化(BatisRestAutoConfig);
  2. 扫描mybatis mapper方法(MapperComponentScanAndRegister);
  3. 将mapper方法代理对象注册为rest接口。

 

SpringCloud的data-rest组件功能令我印象深刻,于是打算参考该组件给mybatis做一个自动rest化的组件,毕竟国内用mybatis还是蛮多的。

先扫描mapper。mybatis内部mapper的管理类是MapperRegistry,它可以通过mybatis的configuration对象取到。为了方便,本组件内只引用了SqlSessionTemplate,通过这个bean对象获取mapper。注册Spring的ContextRefreshedEvent事件,待mybatis初始化之后就可以获取到mapper了。

sqlSessionTemplate.getConfiguration().getMapperRegistry().getMappers().forEach(mapperCls -> {
    if(mapperCls.getAnnotation(EnableRestMapper.class) != null){
        restInterfaceRegister.register(mapperCls);
    }
});

 

构建代理mapper代理。一般情况下,接口(Interface)方法是不能执行的,为了能调用mapper方法,需要用到代理对象Proxy(实际上,mybatis也是给mapper方法构建了代理对象),用于处理mapper方法对应的实际逻辑。

执行操作。Mybatis中每个mapper方法会有一个对应的MapperMethod对象来执行,这里我们可以通过构造MapperMethod来实现mapper的具体逻辑。

public class RestMapperProxy implements InvocationHandler, Serializable {

    Class<?> mapperInterface;

    SqlSessionTemplate sqlSessionTemplate;


    public RestMapperProxy(Class<?> mapperInterface, SqlSessionTemplate sqlSessionTemplate) {
        this.mapperInterface = mapperInterface;
        this.sqlSessionTemplate = sqlSessionTemplate;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) {
        MapperMethod mapperMethod = new MapperMethod(mapperInterface, method, sqlSessionTemplate.getConfiguration());
        return mapperMethod.execute(sqlSessionTemplate, args);
    }

}

rest接口注册。Spring中接口映射管理对象为requestMappingHandlerMapping,注册方法参数中,mapper方法的代理对象作为handler参数,mapper方法名称作为RequestMappingInfo的映射地址,sql类型转化为请求类型。

public Object register(Class<?> mapperInterface){

        EnableRestMapper enableRestMapper = mapperInterface.getAnnotation(EnableRestMapper.class);

        RestMapperProxy restMapperProxy = new RestMapperProxy(mapperInterface, sqlSessionTemplate);
        //注册代理
        Object proxy = Proxy.newProxyInstance(RestInterfaceRegister.class.getClassLoader(), new Class[]{mapperInterface}, restMapperProxy);

        //注册接口
        for(Method method : mapperInterface.getMethods()){

            String uri = enableRestMapper.value() + "/" + method.getName();
            log.info("mapper rest [{} - {}]", uri, method.getDeclaringClass());

            RequestMappingInfo mappingInfo = new RequestMappingInfo(
                    new PatternsRequestCondition(uri),
                    new RequestMethodsRequestCondition(commandTypeToRequestMethod(method)),
                    null, null, null, null, null);

            requestMappingHandlerMapping.registerMapping(mappingInfo, proxy, method);

        }

        return proxy;

    }

    private RequestMethod commandTypeToRequestMethod(Method method){
        MappedStatement statement = sqlSessionTemplate.getConfiguration().getMappedStatement(method.getName());
        SqlCommandType commandType = statement.getSqlCommandType();

        if(SqlCommandType.SELECT == commandType){
            return RequestMethod.GET;
        }
        return RequestMethod.POST;
    }

 

参数匹配。正常编译情况下,Spring的几个ParameterNameDiscoverer是无法获取Interface方法参数名称的。mybatis为确保获取参数名称,增加了@Param注解。于是我自定义了BatisParameterNameDiscoverer,用于适配mybatis的ParamNameResolver。虽然没有经过完整测试,但我试了多参数、对象参数等情况,都是完美支持的。

结果装配。@EnableRestMapper继承了@ResponseBody,意味着加了EnableRestMapper注解的mapper返回结果会使用ResponseBody组装。

 

后续。本来想多花点时间好好做一下,为此专门研究了data-rest和mybatis的源码,实际却很快搞定了上述核心功能,这或许就是Spring强大的框架集成和扩展能力吧。当然,还有诸如事务、异常处理、结果封装等场景尚未经过测试和处理,敬请期待!

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值