快速生成通用接口业务配置

简介: 快速生成通用接口业务配置


这个是干什么的?

简单介绍下:

作用:通过插件一键生成某个表对应的增删改查等基础或者说通用接口,这里面的代码是基础版的,后续改良后,很多业务的通用功能,比如流程的启动,自动下一步,通用导出,通用导入等等。

原理:核心就是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 多平台发布


相关文章
|
1月前
|
消息中间件 设计模式 监控
如何优雅地实现接口统一调用?
【2月更文挑战第6天】
132 3
|
1月前
|
SQL XML JSON
Hasor【部署 04】Dataway接口配置服务扩展能力实例分享
Hasor【部署 04】Dataway接口配置服务扩展能力实例分享
78 0
|
7月前
|
程序员 C++
论接口的封装能力
论接口的封装能力
30 0
|
10月前
快速生成通用接口业务配置
快速生成通用接口业务配置
|
11月前
|
SQL 消息中间件 缓存
12种接口优化的通用方案
12种接口优化的通用方案
162 0
|
11月前
|
算法 安全 网络协议
如何设计一个安全的对外接口 ?
最近有个项目需要对外提供一个接口,提供公网域名进行访问,而且接口和交易订单有关,所以安全性很重要;这里整理了一下常用的一些安全措施以及具体如何去实现。
|
11月前
|
SQL 存储 缓存
18种接口实用优化方案总结
18种接口实用优化方案总结
118 0
|
测试技术
【业务架构】通用业务能力列表
【业务架构】通用业务能力列表
|
算法 安全 网络协议
如何设计一个安全的对外接口?
对外接口安全措施的作用主要体现在两个方面,一方面是如何保证数据在传输过程中的安全性,另一方面是数据已经到达服务器端,服务器端如何识别数据。
115 0
|
算法 安全 网络协议
如何设计一个安全的对外接口
如何设计一个安全的对外接口
279 0