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

2023-08-21 10:16:17 浏览数 (1)

这个是干什么的?

简单介绍下:

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

原理:核心就是BasicControllerPostProcessor ,通过动态生成代理对象,完成逻辑实现。这里呢经过实践呢后续也有不少优化的,后续我总结后发一个新版的

一、核心处理类

代码语言:javascript复制
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

代码语言:javascript复制
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

代码语言:javascript复制
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

代码语言:javascript复制
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

代码语言:javascript复制
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

代码语言:javascript复制
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

代码语言:javascript复制
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

代码语言:javascript复制
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

代码语言:javascript复制
  <org.mapstruct.version>1.5.5.Final</org.mapstruct.version>
  
  <dependency>
      <groupId>org.mapstruct</groupId>
      <artifactId>mapstruct</artifactId>
      <version>${org.mapstruct.version}</version>
  </dependency>
代码语言:javascript复制
<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 多平台发布

0 人点赞