文章用于记录自己更改若依框架集成mybatis换成mybatis-plus的一些些问题,最重要的是怎么在最小的代价下不影响原有代码的情况下,进行自己的开发,同时方便后续的更改。
1. mybatis与mybatis-plus能否共存
mybatis是SqlSessionFactoryBean,而mybatis-plus是MybatisSqlSessionFactoryBean,所以一般最好是项目中使用一个最好,当然想要共存也可以,mybatis-plus的版本最好要高。
2.修改yml,当使用mybatis或者mybatis-plus时,配置文件只需要出现一个就行。
这是原本的配置直接注解掉 因为yml中的Configuration和mybatis-config文件的configruation配置是不能共存的。否则会报以下错误
Property 'configuration' and 'configLocation' can not specified with together
# # MyBatis配置
# mybatis:
# # 搜索指定包别名
# typeAliasesPackage: org.bf.**.domain
# # 配置mapper的扫描,找到所有的mapper.xml映射文件
# mapperLocations: classpath*:mapper/**/*Mapper.xml
# # 加载全局的配置文件
# configLocation: classpath:mybatis/mybatis-config.xml
这是需要新增的
mybatis-plus:
# 配置要扫描的xml文件目录,classpath* 代表所有模块的resources目录 classpath 不加星号代表当前模块下的resources目录
mapper-locations: classpath*:mapper/**/*Mapper.xml
# 实体扫描,*通配符
typeAliasesPackage: org.bf.**.domain
3.导入mybatis-plus的包
在父pom.xml中新增mybatis-plus的jar包,当然你也可以去maven仓库选择对应版本,同时也有lombok的jar包
<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
然后在common模块下的pom.xml引入
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
因为我不想影响原有代码运行,所以我是新增了一个模块,在新增的模块需要引入common模块
4.代码注释
原因:诺依中ruoyi-framework模块有对mybatis的配置类,而mybatis的sql工厂和mybatis-plus的sql工厂不同,否则会报以下错:(所以需要将这个配置类的相关代码注释即可)
mybatis-plus Invalid bound statement (not found): com.ruoyi.file.mapper.UserfileMapper.selectCount
当然到这里是集成了,但怎么用呢?
5.首先先改一波自动生成代码
也就是如图所示的.vm代码模板,当然为了不改的面目全非,我备份了一份原有的文件出来即myVm这个文件夹,这个文件夹没有做任何更改,同时修改这个模块的VelocityUtils类中的getTemplateList方法,即获取模板方法,
原本长这样
你加个判断让他读你自己的,判断条件,从yml拿,或者直接写true都行
Controller.java.vm,上面导包有些是我自己的路径记得修改,例如org.bf.common.annotation.Log;等等
package ${packageName}.controller;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.bf.common.annotation.Log;
import org.bf.common.core.controller.BaseController;
import org.bf.common.core.domain.AjaxResult;
import org.bf.common.enums.BusinessType;
import ${packageName}.domain.${ClassName};
import ${packageName}.service.I${ClassName}Service;
import org.bf.common.utils.poi.ExcelUtil;
#if($table.crud || $table.sub)
import org.bf.common.core.page.TableDataInfo;
#elseif($table.tree)
#end
/**
* ${functionName}Controller
*
* @author ${author}
*/
@RestController
@RequestMapping("/${moduleName}/${businessName}")
public class ${ClassName}Controller extends BaseController
{
@Autowired
private I${ClassName}Service ${className}Service;
/**
* 查询${functionName}列表
*/
@PreAuthorize("@ss.hasPermi('${permissionPrefix}:list')")
@GetMapping("/list")
#if($table.crud || $table.sub)
public TableDataInfo list(${ClassName} ${className})
{
startPage();
List<${ClassName}> list = ${className}Service.select${ClassName}List(${className});
return getDataTable(list);
}
#elseif($table.tree)
public AjaxResult list(${ClassName} ${className})
{
List<${ClassName}> list = ${className}Service.select${ClassName}List(${className});
return success(list);
}
#end
/**
* 导出${functionName}列表
*/
@PreAuthorize("@ss.hasPermi('${permissionPrefix}:export')")
@Log(title = "${functionName}", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, ${ClassName} ${className})
{
List<${ClassName}> list = ${className}Service.select${ClassName}List(${className});
ExcelUtil<${ClassName}> util = new ExcelUtil<${ClassName}>(${ClassName}.class);
util.exportExcel(response, list, "${functionName}数据");
}
/**
* 获取${functionName}详细信息
*/
@PreAuthorize("@ss.hasPermi('${permissionPrefix}:query')")
@GetMapping(value = "/{${pkColumn.javaField}}")
public AjaxResult getInfo(@PathVariable("${pkColumn.javaField}") ${pkColumn.javaType} ${pkColumn.javaField})
{
return success(${className}Service.getById(${pkColumn.javaField}));
}
/**
* 新增${functionName}
*/
@PreAuthorize("@ss.hasPermi('${permissionPrefix}:add')")
@Log(title = "${functionName}", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody ${ClassName} ${className})
{
return toAjax(${className}Service.saveOrUpdate(${className}));
}
/**
* 修改${functionName}
*/
@PreAuthorize("@ss.hasPermi('${permissionPrefix}:edit')")
@Log(title = "${functionName}", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody ${ClassName} ${className})
{
return toAjax(${className}Service.saveOrUpdate(${className}));
}
/**
* 删除${functionName}
*/
@PreAuthorize("@ss.hasPermi('${permissionPrefix}:remove')")
@Log(title = "${functionName}", businessType = BusinessType.DELETE)
@DeleteMapping("/{${pkColumn.javaField}s}")
public AjaxResult remove(@PathVariable ${pkColumn.javaType}[] ${pkColumn.javaField}s)
{
return toAjax(${className}Service.removeByIds(Arrays.asList(${pkColumn.javaField}s)));
}
}
domain.java.vm,额外加lombok.Data、com.baomidou.mybatisplus.annotation.TableName、org.bf.common.core.domain.MyBaseEntity这三个包
package ${packageName}.domain;
import lombok.Data;
import com.baomidou.mybatisplus.annotation.TableName;
import org.bf.common.core.domain.MyBaseEntity;
#foreach ($import in $importList)
import ${import};
#end
import org.bf.common.annotation.Excel;
#if($table.crud || $table.sub)
#elseif($table.tree)
#end
/**
* ${functionName}对象 ${tableName}
*
* @author ${author}
*/
#if($table.crud || $table.sub)
#set($Entity="MyBaseEntity")
#elseif($table.tree)
#set($Entity="TreeEntity")
#end
@Data
@TableName("${tableName}")
public class ${ClassName} extends ${Entity}
{
private static final long serialVersionUID = 1L;
#foreach ($column in $columns)
#if(!$table.isSuperColumn($column.javaField))
/** $column.columnComment */
#if($column.list)
#set($parentheseIndex=$column.columnComment.indexOf("("))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
#if($parentheseIndex != -1)
@Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()")
#elseif($column.javaType == 'Date')
@JsonFormat(pattern = "yyyy-MM-dd")
@Excel(name = "${comment}", width = 30, dateFormat = "yyyy-MM-dd")
#else
@Excel(name = "${comment}")
#end
#end
private $column.javaType $column.javaField;
#end
#end
#if($table.sub)
/** $table.subTable.functionName信息 */
private List<${subClassName}> ${subclassName}List;
#end
}
MyBaseEntity是我自定义的基类,因为原有基类,不是很满足需求,同时全项目都继承了,不便更改
在/common/core/domain/目录下新增MyBaseEntity.java 当然的当然,这些字段在你构建的表中一定要有,除了@TableField(exist = false)注解的params请求参数
/**
* Entity基类
*
* @author
*/
@Data
public class MyBaseEntity implements Serializable
{
private static final long serialVersionUID = 1L;
/**
* id
*/
@TableId(type = IdType.ASSIGN_ID)
private Long id;
/** 逻辑删除 */
@TableLogic //逻辑删除
@TableField(fill = FieldFill.INSERT)
private int deleted;
/** 创建者 */
@TableField(fill = FieldFill.INSERT)
private String createBy;
/** 创建时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField(fill = FieldFill.INSERT)
private Date createTime;
/** 更新者 */
@TableField(fill = FieldFill.INSERT_UPDATE)
private String updateBy;
/** 更新时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
/** 备注 */
private String remark;
/** 请求参数 */
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@TableField(exist = false)
private Map<String, Object> params;
public Map<String, Object> getParams()
{
if (params == null)
{
params = new HashMap<>();
}
return params;
}
}
mapper.java.vm
package ${packageName}.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import ${packageName}.domain.${ClassName};
#if($table.sub)
import ${packageName}.domain.${subClassName};
#end
/**
* ${functionName}Mapper接口
*
* @author ${author}
*/
@Mapper
public interface ${ClassName}Mapper extends BaseMapper<${ClassName}>
{
}
service.java.vm,这里保留了原有的select${ClassName}List接口,为了方便你自己添加查询条件
package ${packageName}.service;
import java.util.List;
import ${packageName}.domain.${ClassName};
import com.baomidou.mybatisplus.extension.service.IService;
/**
* ${functionName}Service接口
*
* @author ${author}
*/
public interface I${ClassName}Service extends IService<${ClassName}>
{
/**
* 查询${functionName}列表
*
* @param ${className} ${functionName}
* @return ${functionName}集合
*/
public List<${ClassName}> select${ClassName}List(${ClassName} ${className});
}
serviceImpl.java.vm,在实现类使用了构造器去查询
package ${packageName}.service.impl;
import java.util.List;
#foreach ($column in $columns)
#if($column.javaField == 'createTime' || $column.javaField == 'updateTime')
import org.bf.common.utils.DateUtils;
#break
#end
#end
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#if($table.sub)
import java.util.ArrayList;
import org.bf.common.utils.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import ${packageName}.domain.${subClassName};
#end
import ${packageName}.mapper.${ClassName}Mapper;
import ${packageName}.domain.${ClassName};
import ${packageName}.service.I${ClassName}Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
/**
* ${functionName}Service业务层处理
*
* @author ${author}
*/
@Service
public class ${ClassName}ServiceImpl extends ServiceImpl<${ClassName}Mapper,${ClassName}> implements I${ClassName}Service
{
/**
* 查询${functionName}列表
*
* @param ${className} ${functionName}
* @return ${functionName}
*/
@Override
public List<${ClassName}> select${ClassName}List(${ClassName} ${className})
{
QueryWrapper<${ClassName}> queryWrapper = new QueryWrapper<>();
return baseMapper.selectList(queryWrapper);
}
}
当然修改完成你可以去自带的自动生成生成对应的代码了,但是还需要一点点配置,在之前MyBaseEntity基类中配置了 @TableField(fill = FieldFill.INSERT)逻辑删除、@TableField(fill = FieldFill.INSERT)更新插入、 @TableField(fill = FieldFill.INSERT_UPDATE)更新修改插入都需要对应配置
6.配置MetaObjectHandler
如图在/org/bf/framework/下新建了myBatisPlus文件夹和MyMetaObjectHandler.java类
package org.bf.framework.myBatisPlus;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.bf.common.utils.SecurityUtils;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.Date;
/**
* bf
*/
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
public static final String CREATE_BY = "createBy";
public static final String CREATE_TIME = "createTime";
public static final String UPDATE_BY = "updateBy";
public static final String UPDATE_TIME = "updateTime";
public static final String DELETED = "deleted";
//插入时的填充策略
@Override
public void insertFill(MetaObject metaObject) {
// log.info("start intsert fill ....");
//strictInsertFill(MetaObject metaObject, String fieldName, Class<T> fieldType, E fieldVal)
// 起始版本 3.3.0(推荐使用)
this.setFieldValByName(CREATE_BY, SecurityUtils.getUsername(),metaObject);
this.setFieldValByName(CREATE_TIME,formatDate(metaObject.getSetterType(CREATE_TIME)),metaObject);
this.setFieldValByName(UPDATE_BY, SecurityUtils.getUsername(),metaObject);
this.setFieldValByName(UPDATE_TIME,formatDate(metaObject.getSetterType(CREATE_TIME)),metaObject);
this.setFieldValByName(DELETED, 0,metaObject);
}
//更新时的填充策略
@Override
public void updateFill(MetaObject metaObject) {
// log.info("start update fill ....");
this.setFieldValByName(UPDATE_BY, SecurityUtils.getUsername(),metaObject);
this.setFieldValByName(UPDATE_TIME,formatDate(metaObject.getSetterType(CREATE_TIME)),metaObject);
}
/**
* 处理特殊日期
* @param setterType 参数类型
* @return 日期类型
*/
private Object formatDate(Class<?> setterType){
if (Date.class.equals(setterType)){
return new Date();
} else if (LocalDateTime.class.equals(setterType)) {
return LocalDateTime.now();
} else if (Long.class.equals(setterType)) {
return System.currentTimeMillis();
}
return null;
}
}
到这算是完成基本配置可以完成crud,并且不大量修改原有代码,原有代码也是依然正常。(当然,也可能有遗漏,出现问题可以参考以下文档)