5.抽象CRUD公共方法,并自动生成接口文档
后台管理系统的CRUD方法都有公共的相同之处,那我们可以写一个抽象方法来继承实现自动CRUD
首先
创建一个BaseManageCrudController.java 公共接口
package com.yy.youbimanage.base;
import com.yy.youbimanage.pojo.PageDto;
import com.yy.youbimanage.pojo.Result;
import java.util.List;
/**
* @author chase
* @description
* @date 2021-12-04 13:50:45
*/
public interface BaseManageCrudController<D> {
Result<D> info(Long id);
Result<List<D>> list(D d);
Result<PageDto<D>> page(PageDto pageDto, D d);
Result save(D d);
Result update(D d);
Result delete(Long[] ids);
}
实现公共接口
package com.yy.youbimanage.base;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yy.youbimanage.annotation.Add;
import com.yy.youbimanage.annotation.Update;
import com.yy.youbimanage.exception.GlobalException;
import com.yy.youbimanage.pojo.PageDto;
import com.yy.youbimanage.pojo.Result;
import com.yy.youbimanage.utils.ArgsUtil;
import com.yy.youbimanage.utils.ConvertUtil;
import com.yy.youbimanage.utils.GenericUtil;
import com.yy.youbimanage.utils.PageDtoUtil;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author chase
* @description
* @date 2021-12-04 13:36:58
*/
public abstract class AbstractManageCrudController<E, D> implements BaseManageCrudController<D> {
protected ConvertUtil convertUtil = ConvertUtil.SINGLETON;
protected GenericUtil genericUtil = GenericUtil.SINGLETON;
protected ArgsUtil argsUtil = ArgsUtil.SINGLETON;
@Autowired
protected RedissonClient redissonClient;
protected abstract AbstractCrudService<E> getService();
protected abstract List<String> notAccessMethod();
protected final Result ok() {
return new Result().ok();
}
protected final Result ok(Object data) {
return new Result().ok(data);
}
protected final Result fail() {
return new Result().fail();
}
protected final Result fail(String msg) {
return new Result().fail(msg);
}
protected final Result fail(Result.Response response) {
return new Result().fail(response);
}
@Override
@GetMapping(value = "/{id}")
@ApiOperation(value = "查看")
@ApiResponses({
@ApiResponse(code = 200, message = "请求成功"),
@ApiResponse(code = 400, message = "非法请求"),
@ApiResponse(code = 401, message = "尚未登录"),
@ApiResponse(code = 403, message = "权限不足"),
@ApiResponse(code = 500, message = "请求失败"),
})
public Result<D> info(@PathVariable Long id) {
if (notAccessMethod().contains("info")) {
throw new GlobalException("该地址禁止访问");
}
E entity = getService().getById(id);
D dto = (D) convertUtil.sourceToTarget(entity, genericUtil.getClass(this, 1));
return ok(dto);
}
@Override
@GetMapping(value = "/list")
@ApiOperation(value = "列表")
@ApiResponses({
@ApiResponse(code = 200, message = "请求成功"),
@ApiResponse(code = 400, message = "非法请求"),
@ApiResponse(code = 401, message = "尚未登录"),
@ApiResponse(code = 403, message = "权限不足"),
@ApiResponse(code = 500, message = "请求失败"),
})
public Result<List<D>> list(D d) {
if (notAccessMethod().contains("list")) {
throw new GlobalException("该地址禁止访问");
}
E e = (E) convertUtil.sourceToTarget(d, genericUtil.getClass(this, 0));
List<E> entityList = getService().getByList(e);
List<D> dtoList = convertUtil.sourceToTarget(entityList, genericUtil.getClass(this, 1));
return ok(dtoList);
}
@Override
@GetMapping(value = "/page")
@ApiOperation(value = "分页")
@ApiResponses({
@ApiResponse(code = 200, message = "请求成功"),
@ApiResponse(code = 400, message = "非法请求"),
@ApiResponse(code = 401, message = "尚未登录"),
@ApiResponse(code = 403, message = "权限不足"),
@ApiResponse(code = 500, message = "请求失败"),
})
public Result<PageDto<D>> page(PageDto pageDto, D d) {
if (notAccessMethod().contains("page")) {
throw new GlobalException("该地址禁止访问");
}
E entity = (E) convertUtil.sourceToTarget(d, genericUtil.getClass(this, 0));
Page<E> entityPage = getService().getByPage(new Page<E>(pageDto.getCurrentPage(), pageDto.getPageSize()), entity);
PageDto<D> resultPage = PageDtoUtil.pageToPageDto(entityPage);
resultPage.setData(convertUtil.sourceToTarget(entityPage.getRecords(), genericUtil.getClass(this, 1)));
return ok(resultPage);
}
@Override
@PostMapping
@ApiOperation(value = "新增")
@ApiResponses({
@ApiResponse(code = 200, message = "请求成功"),
@ApiResponse(code = 400, message = "非法请求"),
@ApiResponse(code = 401, message = "尚未登录"),
@ApiResponse(code = 403, message = "权限不足"),
@ApiResponse(code = 500, message = "请求失败"),
})
public Result save(@Validated(value = Add.class) @RequestBody D d) {
if (notAccessMethod().contains("save")) {
throw new GlobalException("该地址禁止访问");
}
E entity = (E) convertUtil.sourceToTarget(d, genericUtil.getClass(this, 0));
entity = getService().save(entity);
D dto = (D) convertUtil.sourceToTarget(entity, genericUtil.getClass(this, 1));
return ok(dto);
}
@Override
@PutMapping
@ApiOperation(value = "修改")
@ApiResponses({
@ApiResponse(code = 200, message = "请求成功"),
@ApiResponse(code = 400, message = "非法请求"),
@ApiResponse(code = 401, message = "尚未登录"),
@ApiResponse(code = 403, message = "权限不足"),
@ApiResponse(code = 500, message = "请求失败"),
})
public Result update(@Validated(value = Update.class) @RequestBody D d) {
if (notAccessMethod().contains("update")) {
throw new GlobalException("该地址禁止访问");
}
E entity = (E) convertUtil.sourceToTarget(d, genericUtil.getClass(this, 0));
int row = getService().update(entity);
return ok(row);
}
@Override
@DeleteMapping
@ApiOperation(value = "删除")
@ApiResponses({
@ApiResponse(code = 200, message = "请求成功"),
@ApiResponse(code = 400, message = "非法请求"),
@ApiResponse(code = 401, message = "尚未登录"),
@ApiResponse(code = 403, message = "权限不足"),
@ApiResponse(code = 500, message = "请求失败"),
})
public Result delete(@RequestBody Long[] ids) {
if (notAccessMethod().contains("delete")) {
throw new GlobalException("该地址禁止访问");
}
getService().delete(ids);
return ok();
}
}
创建一个分页的pageDto类
package com.chase.frame.base;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* @auor chase
* @date 2021-08-16 20:53:42
* @apiNote
*/
@Data
@ApiModel(value = "分页Dto")
public class PageDto<T> implements Serializable {
@ApiModelProperty(value = "页")
private int currentPage;
@ApiModelProperty(value = "行")
private int pageSize;
@ApiModelProperty(value = "总条数")
private int total;
@ApiModelProperty(value = "总页数")
private int totalPage;
@ApiModelProperty(value = "结果")
private List<T> data;
public PageDto() {
this.currentPage = 1;
this.pageSize = 10;
}
}
对象转换工具类
package com.chase.frame.tools;
import cn.hutool.core.bean.BeanUtil;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* @author fengbiao
* @apiNote entity转dto工具类
* @date 2021/6/9 10:28
*/
public enum ConvertUtil {
SINGLETON;
/**
* 将单个类转换成另外一种类
*
* @param source
* @param target
* @param <T>
* @return
*/
public <T> T sourceToTarget(Object source, Class<T> target) {
if (source == null) {
return null;
}
T targetObject = null;
try {
targetObject = target.newInstance();
BeanUtil.copyProperties(source, targetObject);
} catch (Exception e) {
e.printStackTrace();
}
return targetObject;
}
/**
* 将多个类转换成另外一种类
*
* @param sourceList
* @param target
* @param <T>
* @return
*/
public <T> List<T> sourceToTarget(Collection<?> sourceList, Class<T> target) {
if (sourceList == null) {
return null;
}
List<T> targetList = new ArrayList<>(sourceList.size());
try {
for (Object source : sourceList) {
T targetObject = target.newInstance();
BeanUtil.copyProperties(source, targetObject);
targetList.add(targetObject);
}
} catch (Exception e) {
e.printStackTrace();
}
return targetList;
}
}
package com.yy.youbimanage.utils;
import java.lang.reflect.ParameterizedType;
/**
* @author liyang
* @date 2021-08-18 19:23:03
* @apiNote
*/
public enum GenericUtil {
SINGLETON;
public Class getClass(Object o, int index) {
return (Class) (((ParameterizedType) o.getClass().getGenericSuperclass()).getActualTypeArguments()[index]);
}
}
参数校验工具类
package com.chase.frame.tools;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* @author fengbiao
* @apiNote 参数校验工具类
* @date 2021/6/9 10:37
*/
public enum ArgsUtil {
SINGLETON;
/**
* 检验参数是否为Null
*
* @param o
* @return
*/
@SuppressWarnings(value = "all")
public boolean argsIsNull(Object... o) {
for (Object index : o) {
if (index == null) {
return true;
}
if (index instanceof String) {
if (((String) index).trim().isEmpty()) {
return true;
}
}
if (index instanceof List) {
if (((List) index).isEmpty()) {
return true;
}
}
if (index instanceof Set) {
if (((Set) index).isEmpty()) {
return true;
}
}
if (index instanceof Map) {
if (((Map) index).isEmpty()) {
return true;
}
}
}
return false;
}
}
page工具类
package com.chase.frame.tools;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.chase.frame.base.PageDto;
/**
* @author chase
* @description
* @date 2021-12-10 14:41:42
*/
public class PageDtoUtil {
public static PageDto pageToPageDto(Page page) {
PageDto<?> pageDto = new PageDto<>();
pageDto.setCurrentPage((int) page.getCurrent());
pageDto.setPageSize((int) page.getSize());
pageDto.setTotal((int) page.getTotal());
pageDto.setTotalPage((int) page.getPages());
return pageDto;
}
}
全局异常处理
package com.chase.frame.exception;
import com.chase.frame.base.Result;
/**
* @author chase
* @description
* @date 2021-12-04 10:56:12
*/
public class GlobalException extends RuntimeException {
private String msg;
private Integer code;
public GlobalException(String message) {
super(message);
}
public GlobalException(Result.Response response) {
super(response.getMsg());
this.code = response.getCode();
this.msg = response.getMsg();
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
}
自定义注解类创建
package com.chase.frame.annotation;
/**
* @author chase
* @description
* @date 2021-12-09 17:34:50
*/
public @interface Add {
}
package com.chase.frame.annotation;
/**
* @author chase
* @description
* @date 2021-12-09 17:39:18
*/
public @interface Update {
}
创建service接口
package com.chase.frame.base;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import java.util.List;
/**
* @author chase
* @date 2021-08-17 19:23:30
* @description CRUD的Service接口
*/
public interface BaseCrudService<E> {
/**
* 通过主键查询
*
* @param id
* @return
*/
E getById(Long id);
/**
* 通过构造器条件查询
*
* @param wrapper
* @return
*/
Integer count(Wrapper<E> wrapper);
/**
* 通过多个主键查询
*
* @param ids
* @return
*/
List<E> getByIds(Long[] ids);
/**
* 通过一个对象查询
*
* @param e
* @param columns
* @return
*/
List<E> getByList(E e, String... columns);
/**
* 通过构造器条件查询
*
* @param wrapper
* @return
*/
List<E> getByList(Wrapper<E> wrapper);
/**
* 通过对象条件分页查询
*
* @param page
* @param e
* @param columns
* @return
*/
Page<E> getByPage(Page<E> page, E e, String... columns);
/**
* 通过构造器条件分页查询
*
* @param page
* @param wrapper
* @return
*/
Page<E> getByPage(Page<E> page, Wrapper<E> wrapper);
/**
* 通过构造器查询
*
* @param wrapper
* @return
*/
E getByObj(Wrapper<E> wrapper);
/**
* 通过对象查询
*
* @param e
* @return
*/
E getByObj(E e);
/**
* 新增
*
* @param e
* @return
*/
E save(E e);
/**
* 修改
*
* @param e
* @return
*/
int update(E e);
/**
* 通过构造器修改
*
* @param e
* @param uw
* @return
*/
int update(E e, Wrapper<E> uw);
/**
* 通过多个id删除
*
* @param ids
* @return
*/
int delete(Long[] ids);
/**
* 通过构造器删除
*
* @param wrapper
* @return
*/
int delete(Wrapper<E> wrapper);
}
package com.chase.frame.base;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import java.util.Arrays;
import java.util.List;
/**
* @author liyang
* @apiNote
* @date 2021-08-16 15:17:34
*/
public abstract class AbstractCrudService<E> implements BaseCrudService<E> {
@Autowired
protected RedissonClient redissonClient;
/**
* 获得具体实现BaseMapper
*
* @return
*/
protected abstract BaseMapper<E> getMapper();
@Override
public E getById(Long id) {
return getMapper().selectById(id);
}
@Override
public Integer count(Wrapper<E> wrapper) {
return getMapper().selectCount(wrapper);
}
@Override
public List<E> getByIds(Long[] ids) {
return getMapper().selectBatchIds(Arrays.asList(ids));
}
@Override
public List<E> getByList(E e, String... columns) {
QueryWrapper<E> queryWrapper = new QueryWrapper<>(e);
if (columns != null && columns.length > 0) {
queryWrapper.select(columns);
}
return getMapper().selectList(queryWrapper);
}
@Override
public List<E> getByList(Wrapper<E> wrapper) {
return getMapper().selectList(wrapper);
}
@Override
public Page<E> getByPage(Page<E> page, E e, String... columns) {
QueryWrapper<E> queryWrapper = new QueryWrapper<>(e);
if (columns != null && columns.length > 0) {
queryWrapper.select(columns);
}
return getMapper().selectPage(page, queryWrapper);
}
@Override
public Page<E> getByPage(Page<E> page, Wrapper<E> wrapper) {
return getMapper().selectPage(page, wrapper);
}
@Override
public E getByObj(Wrapper<E> wrapper) {
return getMapper().selectOne(wrapper);
}
@Override
public E getByObj(E e) {
QueryWrapper<E> queryWrapper = new QueryWrapper<>(e);
return getMapper().selectOne(queryWrapper);
}
@Override
@Transactional
public E save(E e) {
RLock lock = redissonClient.getLock(this.getClass().getSimpleName() + "Save");
try {
lock.lock();
getMapper().insert(e);
} catch (Exception ex) {
throw ex;
} finally {
if (lock.isHeldByCurrentThread() && lock.isLocked()) {
lock.unlock();
}
}
return e;
}
@Override
@Transactional
public int update(E e) {
RLock lock = redissonClient.getLock(this.getClass().getSimpleName() + "Update");
int row = 0;
try {
lock.lock();
row = getMapper().updateById(e);
} catch (Exception ex) {
throw ex;
} finally {
if (lock.isHeldByCurrentThread() && lock.isLocked()) {
lock.unlock();
}
}
return row;
}
@Override
public int update(E e, Wrapper<E> uw) {
RLock lock = redissonClient.getLock(this.getClass().getSimpleName() + "BatchUpdate");
int row = 0;
try {
lock.lock();
row = getMapper().update(e, uw);
} catch (Exception ex) {
throw ex;
} finally {
if (lock.isHeldByCurrentThread() && lock.isLocked()) {
lock.unlock();
}
}
return row;
}
@Override
@Transactional public int delete(Long[] ids) {
return getMapper().deleteBatchIds(Arrays.asList(ids));
}
@Override
public int delete(Wrapper<E> wrapper) {
return getMapper().delete(wrapper);
}
}
都创建完成之后,测试一下
controller
package com.chase.frame.controller;
import com.chase.frame.base.AbstractCrudService;
import com.chase.frame.base.AbstractManageCrudController;
import com.chase.frame.model.dto.RuleDefineTypeDTO;
import com.chase.frame.model.entity.RuleDefineType;
import com.chase.frame.service.RuleDefineTypeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Arrays;
import java.util.List;
/**
* @author chase
* @Desc
* @date 2022/8/18 16:26
*/
@RestController
@RequestMapping("/ruleDefineType")
public class RuleDefineTypeController extends AbstractManageCrudController<RuleDefineType, RuleDefineTypeDTO> {
@Autowired
private RuleDefineTypeService ruleDefineTypeService;
@Override
protected List<String> notAccessMethod() {
return Arrays.asList();
}
@Override
protected AbstractCrudService<RuleDefineType> getService() {
return ruleDefineTypeService;
}
}
service
package com.chase.frame.service;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.chase.frame.base.AbstractCrudService;
import com.chase.frame.mapper.RuleDefineTypeMapper;
import com.chase.frame.model.entity.RuleDefineType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author chase
* @Desc
* @date 2022/8/29 16:37
*/
@Service
public class RuleDefineTypeService extends AbstractCrudService<RuleDefineType> {
@Autowired
private RuleDefineTypeMapper ruleDefineTypeMapper;
@Override
protected BaseMapper<RuleDefineType> getMapper() {
return ruleDefineTypeMapper;
}
}
对象类中写上接口文档的注解
自动生成对应的CRUD,分页接口