当前位置: 首页 > article >正文

基于SpringBoot中通用Mapper源码解读以及设计通用Service和Controller

文章目录

    • 1、通用的Service抽取
    • 2、通用的Controller抽取

1、通用的Service抽取

​ 通过通用Mapper的思想,也就是将一些重复的代码抽出来,制作成一个框架或者工具,之后当某个Dao需要使用的时候,直接继承这个就可以解决了。

​ 分析一下这个通用Mapper是怎么制作的。image-20210809204115874

​ 可以看见我们的Dao层中的Mapper并没有定义任何的方法,但是却可以在Service层总结进行使用,如:

image-20210809204215208

​ 这都是通用Mapper帮我们做的事情,至于是怎么做的呢? 进一步看看

​ 我们可以通过SelectAll这个方法作为例子来进行查看,可以发现通用Mapper就是利用了反射等技术来构建Sql语句进行操作的

image-20210809210528619

​ 下面查看一下selectAll方法的字符串拼接:

image-20210809210558550


​ 那接下来看一看通用Service应该怎么制作

​ 从我们的Service层定义的方法中来看:

image-20210809210946781

​ 除了我们的POJO是不一样的之外,其他不管是方法还是别的都是一样的,这就是我们的突破口

​ 我们可以编写一个抽象类,也是一个实现类,去实现这些通用的方法,之后我们可以学习通用mapper一样,继承一些CURDP的接口,这样我们的Service只需要继承我们的CoreService,这个CoreService是继承了CURDP所有接口,这样我们具体的实现类就除了引用我们的接口之外,再去继承一个我们的抽象类,这样我们就可以完成这个通用Service的编写。

​ 具体编写代码的结构如下:

image-20210810094657646

​ CoreService的代码:

package com.yxinmiracle.core.service;public interface CoreService<T> extendsDeleteService<T>,InsertService<T>,PagingService<T>,SelectService<T>,UpdateService<T> {}

​ 抽象类的代码:

public abstract class CoreServiceImpl<T> implements CoreService<T> {//通用mapeprprotected Mapper<T> baseMapper;//操作的实体类protected Class<T> clazz;public CoreServiceImpl(Mapper<T> baseMapper, Class<T> clazz) {this.baseMapper = baseMapper;this.clazz = clazz;}@Overridepublic int delete(T record) {return baseMapper.delete(record);}@Overridepublic int deleteById(Object id) {return baseMapper.deleteByPrimaryKey(id);}@Overridepublic int insert(T record) {return baseMapper.insertSelective(record);}@Overridepublic List<T> selectAll() {return baseMapper.selectAll();}@Overridepublic T selectByPrimaryKey(Object id) {return baseMapper.selectByPrimaryKey(id);}@Overridepublic List<T> select(T record) {return baseMapper.select(record);}@Overridepublic int updateByPrimaryKey(T record) {return baseMapper.updateByPrimaryKeySelective(record);}@Overridepublic PageInfo<T> findByPage(Integer pageNo, Integer pageSize) {PageHelper.startPage(pageNo, pageSize);List<T> list = baseMapper.selectAll();PageInfo<T> pageInfo = new PageInfo<T>(list);return pageInfo;}@Overridepublic PageInfo<T> findByPage(Integer pageNo, Integer pageSize, T record) {Example example = new Example(clazz);Example.Criteria criteria = example.createCriteria();Field[] declaredFields = record.getClass().getDeclaredFields();for (Field declaredField : declaredFields) {try {//遇到 id注解 和 transient注解 不需要进行值的设置 直接跳过。if (declaredField.isAnnotationPresent(Transient.class) || declaredField.isAnnotationPresent(Id.class)) {//遇到continue;}//属性描述器  record.getClass()PropertyDescriptor propDesc = new PropertyDescriptor(declaredField.getName(), record.getClass());//获取这个值  先获取读方法的方法对象,并调用获取里面的值Object value = propDesc.getReadMethod().invoke(record);//Object value = propDesc.getValue(declaredField.getName());//如果是字符串if (value != null && value.getClass().getName().equals("java.lang.String")) {Column columnAnnotation = declaredField.getAnnotation(Column.class);//判断如果是长度为1 则 执行=号int length = columnAnnotation.length();if (length == 1) {criteria.andEqualTo(declaredField.getName(), value);} else {criteria.andLike(declaredField.getName(), "%" + value + "%");}}} catch (Exception e) {e.printStackTrace();}}PageHelper.startPage(pageNo, pageSize);List<T> ts = baseMapper.selectByExample(example);PageInfo<T> info = new PageInfo<T>(ts);return info;}@Overridepublic PageInfo<T> findByPageExample(Integer pageNo, Integer pageSize, Object example) {PageHelper.startPage(pageNo, pageSize);List<T> list = baseMapper.selectByExample(example);PageInfo<T> info = new PageInfo<T>(list);return info;}}

​ 这样一来,在我们的Service接口以及Service的实现类中一行代码都不用写就可以完成一些基本功能的开发,比如,单表中的CURD,基本手上只要手速快,一分钟就可以完成,不用像以前一样一个Mapper需要写一个xml,写一个接口,之后service层还要去调用DAO层,现在这些代码都不需要写了:

image-20210810095130054

  • 为什么要用抽象类?

因为抽象类是不能实例化的,这样就不能交给spring容器进行管理,引起多个相同类型对象的错误。

  • 那抽象类中的Mapper我们怎么知道是谁的Mapper呢?

我们不能通过使用@Autowired注解的方式来进行赋值,首先我们并不知道Mapper是什么类型的,其次我们自己写的通用框架尽量不用使用第三方的东西,我们还是使用Java原生的东西来进行。既然是抽象来,我们就可以利用构造函数,使用子类来给父类进行赋值

  • 在抽象类中继承的接口,是不需要将接口中的全部方法进行重写的,这样一来也很利于我们框架的扩展性

2、通用的Controller抽取

​ 跟通用Service也是一样的方式

​ 代码结构:

微信截图_20210810100309

ICoreController代码:

package com.yxinmiracle.core;public interface ICoreController<T> extendsISelectController<T>,IInsertController<T>,IPagingController<T>,IDeleteController<T>,IUpdateController<T> {
}

AbstractCoreController代码:

public abstract class AbstractCoreController<T> implements ICoreController<T> {//调用方的serviceprotected CoreService<T> coreService;//调用方的类型protected Class<T> clazz;public AbstractCoreController(CoreService<T> coreService, Class<T> clazz) {this.coreService = coreService;this.clazz = clazz;}/*** 删除记录** @param id* @return*/@DeleteMapping("/{id}")@Overridepublic Result deleteById(@PathVariable(name = "id") Object id) {coreService.deleteById(id);return new Result(true, StatusCode.OK, "删除成功");}/*** 添加记录** @param record* @return*/@PostMapping@Overridepublic Result insert(@RequestBody T record) {coreService.insert(record);return new Result(true, StatusCode.OK, "添加成功");}/*** 分页查询记录** @param pageNo* @param pageSize* @return*/@GetMapping(value = "/search/{page}/{size}")@Overridepublic Result<PageInfo<T>> findByPage(@PathVariable(name = "page") Integer pageNo,@PathVariable(name = "size") Integer pageSize) {PageInfo<T> pageInfo = coreService.findByPage(pageNo, pageSize);return new Result<PageInfo<T>>(true, StatusCode.OK, "分页查询成功", pageInfo);}@PostMapping(value = "/search/{page}/{size}")@Overridepublic Result<PageInfo<T>> findByPage(@PathVariable(name = "page") Integer pageNo,@PathVariable(name = "size") Integer pageSize,@RequestBody T record) {PageInfo<T> pageInfo = coreService.findByPage(pageNo, pageSize, record);return new Result<PageInfo<T>>(true, StatusCode.OK, "条件分页查询成功", pageInfo);}@Override@GetMapping("/{id}")public Result<T> findById(@PathVariable(name = "id") Object id) {T t = coreService.selectByPrimaryKey(id);return new Result<T>(true, StatusCode.OK, "查询单个数据成功", t);}@Override@GetMappingpublic Result<List<T>> findAll() {List<T> list = coreService.selectAll();return new Result<List<T>>(true, StatusCode.OK, "查询所有数据成功", list);}//更新数据@Override@PutMappingpublic Result updateByPrimaryKey(@RequestBody T record) {coreService.updateByPrimaryKey(record);return new Result(true, StatusCode.OK, "更新成功");}
}

​ 使用:

@RestController
@RequestMapping("/brand")
public class BrandController extends AbstractCoreController<Brand> {@Autowiredprivate BrandService brandService;@Autowiredpublic BrandController(BrandService brandService) {super(brandService, Brand.class);}
}

​ 这样一来controller层也是一行都不用敲了。

http://www.lryc.cn/news/2417142.html

相关文章:

  • 5年了,ViewPager2 终于支持 overScrollMode,没错,我干的。
  • VBA学习(34):Split函数应用|分离商品和数量
  • 时间相减_【数学】「干货」错位相减其实没这么难!
  • js 中汉字和Unicode 互转
  • 智能交通系统:未来城市交通的可视化展示
  • rapidgator.net的下载方法
  • 语音识别系列1:语音识别Speech recognition综述
  • 不知道为什么在公司登陆不了csdn
  • poi-生成excel文档并返还给浏览器
  • python排序算法 ——冒泡排序(附代码)
  • 微机原理小题知识点总结
  • 计算机网络概述(入门篇)
  • Windows API大全
  • printStackTrace()方法在exception中的理解
  • Python:打包生成.pyc、.pyd文件
  • Secure CRT8.1.3 64位安装及注册激活
  • 什么是XHTML,XHTML学习笔记
  • linux基础IO——用户缓冲区——概念深度探索、IO模拟实现
  • kotlin基础 变量,函数 1
  • 虚拟内存、物理内存与OOM Killer
  • SurfaceView和View区别总结
  • html table th分层,html中 table的结构 彻底搞清 caption th thead等
  • tsearch, tfind, tdelete, twalk, tdestr函数—标准树
  • 『TopCoder 组件开发指南』
  • 创建共享网盘、访问共享网盘
  • ubuntu切换软件源为国内源
  • windows 2000 系统安装和配置
  • 修改Win10右键菜单
  • 机器学习——RBF神经网络
  • 信息增益与信息增益率详解