1、通用的Service抽取
通过通用Mapper的思想,也就是将一些重复的代码抽出来,制作成一个框架或者工具,之后当某个Dao需要使用的时候,直接继承这个就可以解决了。
分析一下这个通用Mapper是怎么制作的。
可以看见我们的Dao层中的Mapper并没有定义任何的方法,但是却可以在Service层总结进行使用,如:
这都是通用Mapper帮我们做的事情,至于是怎么做的呢? 进一步看看
我们可以通过SelectAll这个方法作为例子来进行查看,可以发现通用Mapper就是利用了反射等技术来构建Sql语句进行操作的
下面查看一下selectAll方法的字符串拼接:
那接下来看一看通用Service应该怎么制作
从我们的Service层定义的方法中来看:
除了我们的POJO是不一样的之外,其他不管是方法还是别的都是一样的,这就是我们的突破口
我们可以编写一个抽象类,也是一个实现类,去实现这些通用的方法,之后我们可以学习通用mapper一样,继承一些CURDP的接口,这样我们的Service只需要继承我们的CoreService,这个CoreService是继承了CURDP所有接口,这样我们具体的实现类就除了引用我们的接口之外,再去继承一个我们的抽象类,这样我们就可以完成这个通用Service的编写。
具体编写代码的结构如下:
CoreService的代码:
package com.yxinmiracle.core.service;
public interface CoreService<T> extends
DeleteService<T>,
InsertService<T>,
PagingService<T>,
SelectService<T>,
UpdateService<T> {
}
抽象类的代码:
public abstract class CoreServiceImpl<T> implements CoreService<T> {
//通用mapepr
protected Mapper<T> baseMapper;
//操作的实体类
protected Class<T> clazz;
public CoreServiceImpl(Mapper<T> baseMapper, Class<T> clazz) {
this.baseMapper = baseMapper;
this.clazz = clazz;
}
@Override
public int delete(T record) {
return baseMapper.delete(record);
}
@Override
public int deleteById(Object id) {
return baseMapper.deleteByPrimaryKey(id);
}
@Override
public int insert(T record) {
return baseMapper.insertSelective(record);
}
@Override
public List<T> selectAll() {
return baseMapper.selectAll();
}
@Override
public T selectByPrimaryKey(Object id) {
return baseMapper.selectByPrimaryKey(id);
}
@Override
public List<T> select(T record) {
return baseMapper.select(record);
}
@Override
public int updateByPrimaryKey(T record) {
return baseMapper.updateByPrimaryKeySelective(record);
}
@Override
public 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;
}
@Override
public 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;
}
@Override
public 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层,现在这些代码都不需要写了:
- 为什么要用抽象类?
因为抽象类是不能实例化的,这样就不能交给spring容器进行管理,引起多个相同类型对象的错误。
- 那抽象类中的Mapper我们怎么知道是谁的Mapper呢?
我们不能通过使用@Autowired注解的方式来进行赋值,首先我们并不知道Mapper是什么类型的,其次我们自己写的通用框架尽量不用使用第三方的东西,我们还是使用Java原生的东西来进行。既然是抽象来,我们就可以利用构造函数,使用子类来给父类进行赋值。
- 在抽象类中继承的接口,是不需要将接口中的全部方法进行重写的,这样一来也很利于我们框架的扩展性
2、通用的Controller抽取
跟通用Service也是一样的方式
代码结构:
ICoreController代码:
package com.yxinmiracle.core;
public interface ICoreController<T> extends
ISelectController<T>,
IInsertController<T>,
IPagingController<T>,
IDeleteController<T>,
IUpdateController<T> {
}
AbstractCoreController代码:
public abstract class AbstractCoreController<T> implements ICoreController<T> {
//调用方的service
protected 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}")
@Override
public Result deleteById(@PathVariable(name = "id") Object id) {
coreService.deleteById(id);
return new Result(true, StatusCode.OK, "删除成功");
}
/**
* 添加记录
*
* @param record
* @return
*/
@PostMapping
@Override
public Result insert(@RequestBody T record) {
coreService.insert(record);
return new Result(true, StatusCode.OK, "添加成功");
}
/**
* 分页查询记录
*
* @param pageNo
* @param pageSize
* @return
*/
@GetMapping(value = "/search/{page}/{size}")
@Override
public 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}")
@Override
public 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
@GetMapping
public Result<List<T>> findAll() {
List<T> list = coreService.selectAll();
return new Result<List<T>>(true, StatusCode.OK, "查询所有数据成功", list);
}
//更新数据
@Override
@PutMapping
public Result updateByPrimaryKey(@RequestBody T record) {
coreService.updateByPrimaryKey(record);
return new Result(true, StatusCode.OK, "更新成功");
}
}
使用:
@RestController
@RequestMapping("/brand")
public class BrandController extends AbstractCoreController<Brand> {
@Autowired
private BrandService brandService;
@Autowired
public BrandController(BrandService brandService) {
super(brandService, Brand.class);
}
}
这样一来controller层也是一行都不用敲了。