这个是干什么的?
简单介绍下:
作用:通过插件一键生成某个表对应的增删改查等基础或者说通用接口,这里面的代码是基础版的,后续改良后,很多业务的通用功能,比如流程的启动,自动下一步,通用导出,通用导入等等。
原理:核心就是BasicControllerPostProcessor
,通过动态生成代理对象,完成逻辑实现。这里呢经过实践呢后续也有不少优化的,后续我总结后发一个新版的
一、核心处理类
package com.nari.core.handler;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.List;
import java.util.Map;
/**
* 动态加载baseMapper,baseDao,baseService
*
* @author <a href="mailto:njpkhuan@gmail.com">朱永胜</a>
* @version 1.0.0
* @since 2021/3/2
*/
@Slf4j
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class BasicControllerPostProcessor extends CommonAnnotationBeanPostProcessor {
private static final long serialVersionUID = -945664767382485314L;
@SuppressWarnings("NullableProblems")
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
String packageName = beanClass.getPackage().getName();
log.trace("beanName---{},packageName:{}", beanName, packageName);
List<String> per = ListUtil.of("com.nari.supervision.daily");
List<String> tail = ListUtil.of("outbound","personal");
if (per.stream().anyMatch(packageName::contains)) {
if (tail.stream().map(v -> v + ".controller").anyMatch(packageName::contains)) {
try {
updateResourceName(beanClass, beanName, "basicService", "Controller", "Service");
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
if (tail.stream().map(v -> v + ".service").anyMatch(packageName::contains)) {
try {
updateResourceName(beanClass, beanName, "basicMapper", "Service", "TransformImpl");
updateResourceName(beanClass, beanName, "basicDao", "Service", "Mapper");
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
if (tail.stream().map(v -> v + "serviceImpl").anyMatch(packageName::contains)) {
try {
updateResourceName(beanClass, beanName, "basicMapper", "Service", "TransformImpl");
updateResourceName(beanClass, beanName, "basicDao", "Service", "Mapper");
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
return null;
}
private void updateResourceName(Class<?> beanClass, String beanName, String destField, String searchString, String replaceString)
throws NoSuchFieldException, IllegalAccessException {
Field field = beanClass.getSuperclass().getDeclaredField(destField);
Resource basicMapper = field.getAnnotation(Resource.class);
InvocationHandler invocationHandler = Proxy.getInvocationHandler(basicMapper);
Field memberValues = invocationHandler.getClass().getDeclaredField("memberValues");
memberValues.setAccessible(true);
//noinspection unchecked
Map<String, Object> map = (Map<String, Object>) memberValues.get(invocationHandler);
map.put("name", StringUtils.replace(beanName, searchString, replaceString));
}
}
二、基础类
BasicController
package com.nari.core.basic;
import com.nari.core.annotation.OperationLog;
import com.nari.core.groups.basic.InsertGroup;
import com.nari.core.groups.basic.UpdateGroup;
import com.nari.core.groups.query.PageQueryGroup;
import com.nari.core.web.ApiResult;
import com.nari.core.web.BaseParam;
import com.nari.core.web.PageResult;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiSort;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
/**
* 基础接口管理
*
* @author <a href="mailto:njpkhuan@gmail.com">朱永胜</a>
* @version 1.0.0
* @since 2021/3/1
*/
@Slf4j
@Valid
public class BasicController<T extends BasicModel, Q extends BaseParam, V, D, M extends BasicMapper<T, Q, D, V>> extends com.nari.core.web.BaseController {
@Resource
private BasicService<T, Q, V, D, M> basicService;
/**
* 添加
*
* @param query {@link Q}
*/
@PostMapping
@ApiOperation(value = "1.1 添加")
@OperationLog(value = "添加")
@Validated(value = InsertGroup.class)
public ApiResult insert(@RequestBody Q query) {
basicService.insert(query);
return success("添加成功!");
}
/**
* 根据id删除
*
* @param id 主键
*/
@DeleteMapping("/{id}")
@ApiOperation(value = "1.2 根据id删除")
@OperationLog(value = "根据id删除")
public ApiResult del(@PathVariable("id") String id) {
basicService.del(id);
return success("删除成功!");
}
/**
* 根据id删除-软删除,实际修改标识符
*
* @param id 主键
*/
@DeleteMapping("/{id}/weak")
@ApiOperation(value = "1.3 根据id删除-软删除,实际修改标识符")
@OperationLog(value = "根据id删除-软删除,实际修改标识符")
public ApiResult delWeak(@PathVariable("id") String id) {
basicService.delWeak(id);
return success("删除成功!");
}
/**
* 根据id更新信息
*
* @param query {@link Q}
*/
@PutMapping("update")
@ApiOperation(value = "1.4 根据id更新信息")
@OperationLog(value = "根据id更新信息")
@Validated(value = UpdateGroup.class)
public ApiResult<V> update(@RequestBody Q query) {
return success(basicService.update(query));
}
/**
* 根据id更新信息-批量
*
* @param query {@link Q}
*/
@PutMapping("updateBatch")
@ApiOperation(value = "1.5 根据id更新信息-批量")
@OperationLog(value = "根据id更新信息-批量")
@Validated(value = UpdateGroup.class)
public ApiResult updateBatch(@RequestBody List<Q> query) {
basicService.updateBatch(query);
return success();
}
/**
* 查询单个数据
*
* @param id 主键
*/
@GetMapping("/{id}")
@ApiOperation(value = "1.6 查询单个数据")
@OperationLog(value = "查询单个数据")
public ApiResult<V> select(@PathVariable("id") String id) {
return success(basicService.select(id));
}
/**
* 分页
*
* @param query {@link Q}
*/
@GetMapping("page")
@ApiOperation(value = "1.7 分页")
@OperationLog(value = "分页")
@Validated(value = PageQueryGroup.class)
public ApiResult<PageResult<V>> listUser(Q query) {
return success(basicService.page(query));
}
}
BasicDao
package com.nari.core.basic;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.nari.core.web.BaseParam;
import com.nari.core.web.PageParam;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 基础接口
*
* @author <a href="mailto:njpkhuan@gmail.com">朱永胜</a>
* @version 1.0.0
* @since 2021/3/1
*/
public interface BasicDao<T extends BasicModel, D, Q extends BaseParam> extends BaseMapper<T> {
List<D> selectPageRel(@Param("page") PageParam<D, Q> page, @Param("param") Q param);
}
BasicEnum
package com.nari.core.basic;
/**
* 基础枚举
* 主要用来配合apijson实现枚举展示
*
* @author <a href="mailto:17602556550@189.cn">朱永胜</a>
* @version 1.0.0
* @since 2023/5/25
*/
public interface BasicEnum {
String getName();
Integer getValue();
}
BasicMapper
package com.nari.core.basic;
import org.mapstruct.MappingTarget;
import java.util.List;
/**
* 基础转换
*
* @author <a href="mailto:njpkhuan@gmail.com">朱永胜</a>
* @version 1.0.0
* @since 2021/3/1
*/
public interface BasicMapper<T, Q, D, V> {
T query2do(Q query);
V dto2View(D dto);
D do2dto(T role);
void update(Q query, @MappingTarget T t);
List<V> dto2ViewPage(List<D> dto);
}
BasicModel
package com.nari.core.basic;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* 通用模型
*
* @author <a href="mailto:17602556550@189.cn">朱永胜</a>
* @version 1.0.0
* @since 2023/5/26
*/
@Data
public class BasicModel {
/**
* 主键
*/
private String id;
/**
* 删除标识
*/
@ApiModelProperty(value = "删除标识")
private String deleted;
}
BasicService
package com.nari.core.basic;
import cn.hutool.core.util.IdUtil;
import com.nari.core.web.BaseParam;
import com.nari.core.web.PageParam;
import com.nari.core.web.PageResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* 基础服务
*
* @author <a href="mailto:njpkhuan@gmail.com">朱永胜</a>
* @version 1.0.0
* @since 2021/3/1
*/
@Slf4j
public class BasicService<T extends BasicModel, Q extends BaseParam, V, D, M extends BasicMapper<T, Q, D, V>> {
@Resource
private BasicDao<T, D, Q> basicDao;
@Resource
private BasicMapper<T, Q, D, V> basicMapper;
/**
* 添加
*
* @param query {@link Q}
* @author <a href = "mailto:njpkhuan@gmail.com" >朱永胜</a >
* @since 2021/3/1
* @since 1.0.0
*/
@Transactional(rollbackFor = Exception.class)
public void insert(@Valid Q query) {
T t = basicMapper.query2do(query);
t.setId(IdUtil.simpleUUID());
basicDao.insert(t);
}
/**
* 删除
*
* @param id {@link Q}
* @author <a href = "mailto:njpkhuan@gmail.com" >朱永胜</a >
* @since 2021/3/1
* @since 1.0.0
*/
@Transactional(rollbackFor = Exception.class)
public void del(@NotNull String id) {
basicDao.deleteById(id);
}
/**
* 根据用户id更新
*
* @param query @{@link Q}
* @author <a href = "mailto:njpkhuan@gmail.com" >朱永胜</a >
* @since 2021/3/1
* @since 1.0.0
*/
@Transactional(rollbackFor = Exception.class)
public V update(@Valid Q query) {
T data = basicMapper.query2do(query);
basicDao.updateById(data);
D d = basicMapper.do2dto(data);
return basicMapper.dto2View(d);
}
/**
* 查询
*
* @param id 主键
* @author <a href = "mailto:njpkhuan@gmail.com" >朱永胜</a >
* @since 2021/3/1
* @since 1.0.0
*/
public V select(@NotNull String id) {
T data = basicDao.selectById(id);
D d = basicMapper.do2dto(data);
return basicMapper.dto2View(d);
}
/**
* 查询多条记录
*
* @param query {@link Q}
* @author <a href = "mailto:njpkhuan@gmail.com" >朱永胜</a >
* @since 2021/2/23
* @since 1.0.0
*/
public PageResult<V> page(@Valid Q query) {
PageParam<D, Q> page = new PageParam<>(query);
page.setDefaultOrder("create_time desc");
List<D> list = basicDao.selectPageRel(page, query);
List<V> vList = basicMapper.dto2ViewPage(list);
log.trace("{}", list);
return new PageResult<>(vList, page.getTotal());
}
/**
* 软删除
*
* @author <a href="mailto:17602556550@189.cn">朱永胜</a>
* @since 2023/5/26
*/
@Transactional(rollbackFor = Exception.class)
public void delWeak(String id) {
T t = basicDao.selectById(id);
t.setDeleted("1");
basicDao.updateById(t);
}
/**
* 批量更新
*
* @author <a href="mailto:17602556550@189.cn">朱永胜</a>
* @since 2023/6/6
*/
@Transactional(rollbackFor = Exception.class)
public void updateBatch(List<Q> query) {
query.forEach(this::update);
}
}
GenericSuperclassUtil
package com.nari.core.basic;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public class GenericSuperclassUtil {
/*
* 获取泛型类Class对象,不是泛型类则返回null
*/
public static Class<?> getActualTypeArgument(Class<?> clazz) {
Class<?> entitiClass = null;
Type genericSuperclass = clazz.getGenericSuperclass();
if (genericSuperclass instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) genericSuperclass)
.getActualTypeArguments();
if (actualTypeArguments != null && actualTypeArguments.length > 0) {
entitiClass = (Class<?>) actualTypeArguments[0];
}
}
return entitiClass;
}
/*
* 获取泛型类Class对象,不是泛型类则返回null
*/
static Class<?> getActualTypeArgument(Class<?> clazz, Integer pos) {
Class<?> entitiClass = null;
Type genericSuperclass = clazz.getGenericSuperclass();
if (genericSuperclass instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) genericSuperclass)
.getActualTypeArguments();
if (actualTypeArguments != null && actualTypeArguments.length > pos) {
entitiClass = (Class<?>) actualTypeArguments[pos];
}
}
return entitiClass;
}
}
三、POM
<org.mapstruct.version>1.5.5.Final</org.mapstruct.version>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>0.2.0</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>