这个是干什么的?
简单介绍下:
作用:通过插件一键生成某个表对应的增删改查等基础或者说通用接口,这里面的代码是基础版的,后续改良后,很多业务的通用功能,比如流程的启动,自动下一步,通用导出,通用导入等等。
原理:核心就是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) publicclass BasicControllerPostProcessor extends CommonAnnotationBeanPostProcessor { privatestaticfinallong 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(); returnnull; } } 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(); returnnull; } } 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(); returnnull; } } } returnnull; } 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 publicclass 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 */ publicinterface BasicDao<T extends BasicModel, D, Q extends BaseParam> extends BaseMapper<T> { List<D> selectPageRel(@Param("page") PageParam<D, Q> page, @Param("param") Q param); } • 1
BasicEnum
package com.nari.core.basic; /** * 基础枚举 * 主要用来配合apijson实现枚举展示 * * @author <a href="mailto:17602556550@189.cn">朱永胜</a> * @version 1.0.0 * @since 2023/5/25 */ publicinterface 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 */ publicinterface 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 publicclass 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 publicclass 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); returnnew 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; publicclass GenericSuperclassUtil { /* * 获取泛型类Class对象,不是泛型类则返回null */ publicstatic 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>
本文由 mdnice 多平台发布