Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

motan -> feign | jpa -> mybatis

NotificationsYou must be signed in to change notification settings

nimeia/motan-2-restful

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

[toc]

样例阅读说明

项目说明

项目说明
api主要演示motan 转 feign后的 接口层的变化
client主要演示了怎样使用feign 调用后端接口
server主要演示motan 转feign 的交换器层的变化 与 jpa 转mybatis 的变化

motan 转 feign

一般 motan 定义的接口会需要先定义一个接口类interface

例如

packagetest.api;publicinterfaceDemoApi {Stringhello(Stringworld);UserupdateUser(Useruser);}

服务提供方只需要实现该接口,同时使用注解@MotanService() 明确该服务为motan 的服务,

例如

importcom.weibo.api.motan.config.springsupport.annotation.MotanService;importtest.api.DemoApi;importtest.api.User;@MotanService(export ="demoMotan:8002")publicclassDemoApiImplimplementsDemoApi {@OverridepublicStringhello(Stringworld) {return"hello:"+world;    }@OverridepublicUserupdateUser(Useruser) {user.setRemark("信息已经修改");returnuser;    }}

当客户端调用时只需使用注解标明某对象为motan 调用接口即可

例如

@MotanRefererDemoApidemoApi;

当需要改造成feign 调用restfulapi 接口时

接口定义类需要增加对应的注解,例如:

注意其中的@FeignClient("demo") ,其中demo 为服务名,另外还有一些spring mvc 的注解,这些注解与spring mvc 定义的restful 接口一致。

@FeignClient("demo")@RequestMapping("_api")publicinterfaceDemoRestApi {@RequestMapping("/")Stringhello(@RequestParam("world")Stringworld);@RequestMapping("/user")UserupdateUser(@RequestBodyUseruser);}

下面为spring mvc 实现类

importorg.springframework.web.bind.annotation.RequestBody;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RequestParam;importorg.springframework.web.bind.annotation.RestController;importtest.api.DemoApi;importtest.api.User;@RestController@RequestMapping("_api")publicclassDemoApiRestfulImplimplementsDemoApi {@Override@RequestMappingpublicStringhello(@RequestParam("world")Stringworld) {return"restful hello !" +world;    }@Override@RequestMapping("user")publicUserupdateUser(@RequestBodyUseruser) {user.setRemark("restful 信息已经修改");returnuser;    }}

请注意,当一个服务有直接提供给浏览器端和后端调用的接口时,后端接口请用统一的url前缀区分。例如@RequestMapping("_api") .

当客户端调用时,直接使用@Autowired 标记即可

@AutowiredDemoRestApidemoRestApi;

当提示找不到对应的服务时,请检查包扫描路径,使用@EnableFeignClients(basePackages = "test.api")

当测试不使用注册中心时,可以使用下面的方式配置对应的服务。其中demo@FeignClient 注解中的名称对应

demo:ribbon:listOfServers:http://localhost:8081

多参数改成单参数

/** * 替换例子,把motan 的多参数封装成一个参数传输 * @param rpcRequestVo * @return */@RequestMapping("update")List<User>update(RpcRequestVo<User>rpcRequestVo);

调用样例

//多参数封装例子RpcRequestVo<User>rpcRequestVo =newRpcRequestVo<>();//设置一些分页参数rpcRequestVo.setPageNumber(0);rpcRequestVo.setPageSize(10);//传递一些排序参数RpcRequestOrderVorpcRequestOrderVo =newRpcRequestOrderVo("name",RpcRequestOrderVo.ORDER_TYPE_DESC);rpcRequestVo.addOrder(rpcRequestOrderVo);rpcRequestVo.setArgs(user);demoRestApi.update(rpcRequestVo);

jpa 转 mybatic

样例说明

样例程序入口

test.server.web.OrmController
/*** jap 使用例子** @return*/@RequestMapping("jpa")publicObjectjpa() {//jpa 保存级联例子businessUserService.japSave();//jpa 查询例子businessUserService.jpaQuery();returnMaps.newHashMap();}@RequestMapping("mybatis")publicObjectmybatis() {// mybatis 保存例子,例子中使用了mybatis plus ,未使用过的同事请先阅读对应的文档List<User>userPos =businessUserService.mybatisSave();// mybatis 查询例子businessUserService.mybatis`();returnuserPos;}/**     * jpa 转 mybatis 显示     * @return     */@RequestMapping("j2m")publicObjectjpaToMybatis(){UserEntityuserEntity =newUserEntity();userEntity.setName("jpa to mybatis demo");businessUserService.jpaToMybatisDemo(userEntity);returnnull;}

如果对jpa 或者mybatis 不是很熟悉的用户,请先阅读 jpa 与 mybatis 的两个方法。

jpaToMybatis 方法演示了的是一个转换的例子

开发人员改造时请先阅读完对应的代码

mybatisjpa说明
VoEntity两者都需要一个pojo 类完成与数据库的映射。
MapperRepository可以理解成查询每个实体对应的工具类,一般为接口非实现类

转换时注意点。

mybatis 一般没有一对多等关联操作。jpa 转mybatis 后,需要自动手工完成对应子类的查询

例如

//jpa code ...List<Order>orders =user.getOrders();//mybatis code ...LonguserId =user.getId();List<Order>orders =orderMappers.findByUserId(userId);

​关于分页处理,mybatis 需要自己手写或者封装插件,对应比较著名的组件有

mybatis plus

https://github.com/pagehelper/Mybatis-PageHelper

https://github.com/abel533/Mapper

下面以mybatis plus 插件整合为例描述整个迁移过程

mybatis 编码建议

项目中整合了mybatis plus ,当单表查询,无需动态组合条件时,建议使用mybatis plus 的QueryWrapper。

多表查询或者更加复杂的条件时,可以使用xml 组织sql

整合mybatis plus

  • 增加对应的依赖
        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-data-jpa</artifactId>        </dependency><!--        mybatis plus 依赖, generator 用于从数据库反向生成代码-->        <dependency>            <groupId>com.baomidou</groupId>            <artifactId>mybatis-plus-boot-starter</artifactId>            <version>3.2.0</version>        </dependency>        <dependency>            <groupId>com.baomidou</groupId>            <artifactId>mybatis-plus-generator</artifactId>            <version>3.4.1</version>            <scope>test</scope>        </dependency><!--        用于开发时输出对应的sql 日志-->        <dependency>            <groupId>com.googlecode.log4jdbc</groupId>            <artifactId>log4jdbc</artifactId>            <version>1.2</version>        </dependency><!--        方便演示使用内嵌的数据库,web 界面请见 application.yml-->        <dependency>            <groupId>com.h2database</groupId>            <artifactId>h2</artifactId>        </dependency>

其中需要注意的是,当去除spring-boot-starter-data-jpa 后可能会报没有数据源相关依赖,需要改成引用spring-boot-starter-data-jdbc

MybatisPlug 插件配置

下面主要启动了mybatisplug 的分页插件,

@Configuration@MapperScan("test.server.mybatis.mapper")publicclassMybatisConfig {/**     * 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)     */@BeanpublicMybatisPlusInterceptormybatisPlusInterceptor() {MybatisPlusInterceptorinterceptor =newMybatisPlusInterceptor();interceptor.addInnerInterceptor(newPaginationInnerInterceptor(DbType.H2));returninterceptor;    }@BeanpublicConfigurationCustomizerconfigurationCustomizer() {returnconfiguration ->configuration.setUseDeprecatedExecutor(false);    }}

相关配置项

例子中使用log4jdbc输出sql ,配置如下

spring:jpa:hibernate:ddl-auto:updatedatasource:#    url: jdbc:h2:~/testurl:jdbc:log4jdbc:h2:~/testusername:sapassword:sadriver-class-name:net.sf.log4jdbc.DriverSpy#    driver-class-name: org.h2.Driverh2:console:enabled:truesettings:web-allow-others:truetrace:truepath:/h2logging:level:jdbc:errorjdbc.sqltiming:info

相关配置主要有下面三部分

#    url: jdbc:h2:~/testurl:jdbc:log4jdbc:h2:~/test
driver-class-name:net.sf.log4jdbc.DriverSpy#    driver-class-name: org.h2.Driver
jdbc:errorjdbc.sqltiming:info

代码自动生成

配置反射代码生成,详细主见MybatisGenerator.java

packagetest.server;importcom.baomidou.mybatisplus.annotation.DbType;importcom.baomidou.mybatisplus.core.exceptions.MybatisPlusException;importcom.baomidou.mybatisplus.core.toolkit.StringPool;importcom.baomidou.mybatisplus.generator.AutoGenerator;importcom.baomidou.mybatisplus.generator.InjectionConfig;importcom.baomidou.mybatisplus.generator.config.*;importcom.baomidou.mybatisplus.generator.config.po.TableInfo;importcom.baomidou.mybatisplus.generator.config.rules.NamingStrategy;importcom.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;importorg.apache.commons.lang3.StringUtils;importjava.util.ArrayList;importjava.util.List;importjava.util.Scanner;publicclassMybatisGenerator {/*代码生成器        AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。        特别说明:        自定义模板有哪些可用参数?Github Gitee AbstractTemplateEngine 类中方法 getObjectMap 返回 objectMap 的所有值都可用。        演示效果图:        relationship*/// 演示例子,执行 main 方法控制台输入模块表名回车自动生成对应项目目录中/**     * <p>     * 读取控制台内容     * </p>     */publicstaticStringscanner(Stringtip) {Scannerscanner =newScanner(System.in);StringBuilderhelp =newStringBuilder();help.append("请输入" +tip +":");System.out.println(help.toString());if (scanner.hasNext()) {Stringipt =scanner.next();if (StringUtils.isNotBlank(ipt)) {returnipt;            }        }thrownewMybatisPlusException("请输入正确的" +tip +"!");    }publicstaticvoidmain(String[]args) {// 代码生成器AutoGeneratormpg =newAutoGenerator();// 全局配置GlobalConfiggc =newGlobalConfig();StringprojectPath ="D:\\dev\\motan-demo\\server";gc.setOutputDir(projectPath +"/src/main/java");gc.setAuthor("hgq@sinosoft");gc.setOpen(false);// gc.setSwagger2(true); 实体属性 Swagger2 注解mpg.setGlobalConfig(gc);// 数据源配置DataSourceConfigdsc =newDataSourceConfig();//        dsc.setUrl("jdbc:mysql://localhost:3306/ant?useUnicode=true&useSSL=false&characterEncoding=utf8");dsc.setUrl("jdbc:h2:~/test");dsc.setDbType(DbType.H2);// dsc.setSchemaName("public");dsc.setDriverName("org.h2.Driver");dsc.setUsername("sa");dsc.setPassword("sa");mpg.setDataSource(dsc);// 包配置PackageConfigpc =newPackageConfig();//        pc.setModuleName(scanner("模块名"));pc.setModuleName("mybatis");pc.setParent("test.server");mpg.setPackageInfo(pc);// 自定义配置InjectionConfigcfg =newInjectionConfig() {@OverridepublicvoidinitMap() {// to do nothing            }        };// 如果模板引擎是 freemarkerStringtemplatePath ="/templates/mapper.xml.ftl";// 如果模板引擎是 velocity// String templatePath = "/templates/mapper.xml.vm";// 自定义输出配置List<FileOutConfig>focList =newArrayList<>();// 自定义配置会被优先输出focList.add(newFileOutConfig(templatePath) {@OverridepublicStringoutputFile(TableInfotableInfo) {// 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!returnprojectPath +"/src/main/resources/mapper/" +pc.getModuleName()                        +"/" +tableInfo.getEntityName() +"Mapper" +StringPool.DOT_XML;            }        });/*        cfg.setFileCreate(new IFileCreate() {            @Override            public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {                // 判断自定义文件夹是否需要创建                checkDir("调用默认方法创建的目录,自定义目录用");                if (fileType == FileType.MAPPER) {                    // 已经生成 mapper 文件判断存在,不想重新生成返回 false                    return !new File(filePath).exists();                }                // 允许生成模板文件                return true;            }        });        */cfg.setFileOutConfigList(focList);mpg.setCfg(cfg);// 配置模板TemplateConfigtemplateConfig =newTemplateConfig();// 配置自定义输出模板//指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别// templateConfig.setEntity("templates/entity2.java");// templateConfig.setService();// templateConfig.setController();templateConfig.setXml(null);mpg.setTemplate(templateConfig);// 策略配置StrategyConfigstrategy =newStrategyConfig();strategy.setNaming(NamingStrategy.underline_to_camel);strategy.setColumnNaming(NamingStrategy.underline_to_camel);//        strategy.setSuperEntityClass("你自己的父类实体,没有就不用设置!");strategy.setEntityLombokModel(false);//        strategy.setEntityLombokModel(true);strategy.setRestControllerStyle(true);// 公共父类//        strategy.setSuperControllerClass("你自己的父类控制器,没有就不用设置!");// 写于父类中的公共字段strategy.setSuperEntityColumns("id");//        strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));strategy.setInclude("USER,ORDERT".split(","));strategy.setControllerMappingHyphenStyle(true);strategy.setTablePrefix(pc.getModuleName() +"_");mpg.setStrategy(strategy);mpg.setTemplateEngine(newFreemarkerTemplateEngine());mpg.execute();    }}

其中代码中需要注意带注释的地方,使用请先看一遍代码。另外代码生成器需要选择对应的模板引擎,例子中使用

<dependency>    <groupId>org.springframework.boot</groupId>    <artifactId>spring-boot-starter-freemarker</artifactId></dependency>

代码生成器会自动生成如下格式代码。

D:.├─controller│      OrdertController.java│      UserController.java│├─entity│      Ordert.java│      User.java│├─mapper│      OrdertMapper.java│      UserMapper.java│└─service    │  IOrdertService.java    │  IUserService.java    │    └─impl            OrdertServiceImpl.java            UserServiceImpl.java------------------------------D:.│  application.yml│└─mapper    └─mybatis            OrdertMapper.xml            UserMapper.xml

其中controller 是controller ,如果没用可以删除。生成代码时建议生成到一个独立的 package 下,再改自己的需要进行重构命名

在改造时 你可以使用mapper 直接代替 jpa 中的 repos 。service 是自动生成的一些实用方法的封装,在项目当前情况你可以当前一个dao 层代替直接访问 mapper 。 为了与现有的service 层区分开,建议在代码生成时配置生成后缀为其它,例如dao

gc.setServiceName("I%sDao");gc.setServiceImplName("%sDaoImpl");

一对多关联配置

mybatis 的级联查询主要使用了associationcollection 。配置如下

usermapp.mxl

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPEmapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mappernamespace="test.server.mybatis.mapper.UserMapper">    <resultMapid="userResultMap"type="test.server.mybatis.entity.User">        <idcolumn="id"property="id"></id>        <resultproperty="name"column="name"/>        <collectionproperty="ordertList"column="id"select="selectOrderByUserId"/>    </resultMap>    <selectid="selectOrderByUserId"parameterType="int"resultMap="test.server.mybatis.mapper.OrdertMapper.orderResultMap">        select id,name,user_id from ordert where user_id = #{id}    </select>    <selectid="selectByUserId"parameterType="long"resultMap="userResultMap">        select id,name from user where id= #{id}    </select></mapper>

OrdertMapper.xml

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPEmapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mappernamespace="test.server.mybatis.mapper.OrdertMapper">    <resultMapid="orderResultMap"type="test.server.mybatis.entity.Ordert">        <idcolumn="id"property="id"></id>        <resultproperty="name"column="name"/>        <resultproperty="userId"column="user_id"/>        <associationproperty="user"column="user_id"select="test.server.mybatis.mapper.UserMapper.selectByUserId"></association>    </resultMap></mapper>

这两个文件的变更都为新增。需要生成自动改mybatis 的规范配置,这不做说明。

在映射类里需要用tablename 注意指定对应的resultmap,否则不生效。

packagetest.server.mybatis.entity;importcom.baomidou.mybatisplus.annotation.IdType;importcom.baomidou.mybatisplus.annotation.TableId;importcom.baomidou.mybatisplus.annotation.TableName;importjava.io.Serializable;importjava.util.Objects;/** * <p> * * </p> * * @author hgq@sinosoft * @since 2020-11-11 */@TableName(value ="ORDERT",resultMap ="orderResultMap")publicclassOrdertimplementsSerializable {privatestaticfinallongserialVersionUID =1L;@TableId(type =IdType.AUTO)privateLongid;privateStringname;privateUseruser;publicUsergetUser() {returnuser;    }publicvoidsetUser(Useruser) {this.user =user;    }//    private Long userId;publicLonggetId() {returnid;    }publicvoidsetId(Longid) {this.id =id;    }publicStringgetName() {returnname;    }publicvoidsetName(Stringname) {this.name =name;    }//    public Long getUserId() {//        return userId;//    }////    public void setUserId(Long userId) {//        this.userId = userId;//    }@OverridepublicStringtoString() {return"Ordert{" +"}";    }}

其中一对多的关联需要自动加。对应的注解中增加resultmap@TableName(value = "ORDERT",resultMap = "orderResultMap")

级联保存

请在自动生成的代码 service层中自行处理。mybatis 并没有官方的解决方案

注意事项

不能直接把po ,entity 层的对象输出成json

About

motan -> feign | jpa -> mybatis

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages


[8]ページ先頭

©2009-2025 Movatter.jp