基础通用接口复用

1 业务背景

在日常开发中,我们经常需要为不同模块,开发增删改查接口。而这些不同模块的接口及其相似,在不同的模块controller中造成代码大量重复。

2 解决方案

不同模块controller中增删改查接口,具备通用性,可以放置在baseController基础抽象父类中进行复用。

3 具体细节

3.1 自动生成代码

添加依赖

xml 复制代码
       <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.2</version>
        </dependency>   

        <!--自动生成增删改查代码-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.5.3</version>
        </dependency>

        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.31</version>
        </dependency>
        <!-- Swagger注解 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>3.0.0</version>
        </dependency>

编写代码生成逻辑,并配置数据源、包名称

typescript 复制代码
public class CodeGenerator {
    public static void main(String[] args) {
        // 数据库URL、用户名和密码
        String url = "jdbc:mysql://192.168.56.200:3306/db_data_stats?serverTimezone=Asia/Shanghai";
        String username = "root";
        String password = "123";

        // 项目路径
        String projectPath = System.getProperty("user.dir") + "/data-stats-app";

        // 使用快速生成器
        FastAutoGenerator.create(url, username, password)
                // 全局配置
                .globalConfig(builder -> {
                    builder.author("your_name") // 设置作者
                            .enableSwagger() // 开启Swagger文档
                            //.fileOverride() // 覆盖已有文件
                            .outputDir(projectPath + "/src/main/java") // 输出目录
                            .commentDate("yyyy-MM-dd") // 注释日期格式
                            .dateType(DateType.TIME_PACK); // 使用java8日期类型
                })
                // 包配置
                .packageConfig(builder -> {
                    builder.parent("data.stats.app") // 父包名
                            //.moduleName("system") // 模块名
                            .entity("po") // Entity包名
                            .service("service") // Service包名
                            .serviceImpl("service.impl") // ServiceImpl包名
                            .mapper("mapper") // Mapper包名
                            .controller("controller") // Controller包名
                            .pathInfo(Collections.singletonMap(
                                    OutputFile.xml,
                                    projectPath + "/src/main/resources/mapper")); // XML文件输出路径
                })
                // 策略配置
                .strategyConfig(builder -> {
                    // 设置需要生成的表名
                    builder.addTablePrefix("tb_")  // 根据你的实际表前缀进行配置
                            .addInclude("tb_test")
                            // Entity策略配置
                            .entityBuilder()
                            .enableLombok() // 开启Lombok
                            .enableTableFieldAnnotation() // 开启字段注解
                            .logicDeleteColumnName("deleted") // 逻辑删除字段
                            .naming(NamingStrategy.underline_to_camel) // 表名映射规则
                            .columnNaming(NamingStrategy.underline_to_camel) // 列名映射规则

                            // Controller策略配置
                            .controllerBuilder()
                            .enableRestStyle() // 开启RestController
                            .enableHyphenStyle() // 开启连字符风格
                            .formatFileName("%sController")
                            .build()  // 这里加上build()

                            // Service策略配置
                            .serviceBuilder()
                            .formatServiceFileName("%sService") // Service接口命名规则
                            .formatServiceImplFileName("%sServiceImpl") // Service实现类命名规则

                            // Mapper策略配置
                            .mapperBuilder()
                            .enableMapperAnnotation() // 开启@Mapper注解
                            .formatMapperFileName("%sMapper") // Mapper接口命名规则
                            .formatXmlFileName("%sMapper"); // XML文件命名规则
                })
                // 使用Freemarker模板引擎
                .templateEngine(new FreemarkerTemplateEngine())
                // 执行代码生成
                .execute();
    }
}

运行上面的代码生成逻辑即可生成service、mapper、model等代码。但是controller类中不会自动生成接口代码。

3.2 通用接口复用

于是我们手动去编写这种增、删、改、查接口,类似如下:

less 复制代码
@Slf4j
@RestController
@RequestMapping("/llm")
public class Llmv2Controller {

       @Resource
       private LlmService llmService;


        /**
         * 模型列表接口
         * @return
         */
        @GetMapping("/list")
        public List<LlmVO> list() {
            // 查询模型列表
            List<Llm> llmList = llmService.list();
            // 模型实体List->转VO类型的List
            return BeanConvertUtils.convertList(llmList, LlmVO.class);
        }

}

封装一个实体转VO的工具类,支持各种实体转换,避免每次都要重复编写转换代码。

php 复制代码
/**
 * Bean转换工具类
 */
public class BeanConvertUtils {

    /**
     * 将源对象列表转换为目标对象列表
     * @param sourceList 源对象列表
     * @param targetClass 目标对象类型
     * @return 目标对象列表
     */
    public static <S, T> List<T> convertList(List<S> sourceList, Class<T> targetClass) {
        return sourceList.stream().map(source -> convert(source, targetClass))
                .collect(Collectors.toList());
    }

    /**
     * 将源对象转换为目标对象
     * @param source 源对象
     * @param targetClass 目标对象类型
     * @return 目标对象
     */
    public static <S, T> T convert(S source, Class<T> targetClass) {
        if (source == null) {
            return null;
        }
        try {
            T target = targetClass.getDeclaredConstructor().newInstance();
            BeanUtils.copyProperties(source, target);
            return target;
        } catch (Exception e) {
            throw new RuntimeException("Bean conversion failed", e);
        }
    }
} 

我们分析下这个list列表接口的逻辑:

  1. 定义接口url
  2. 查询llmService获取列表
  3. 实体转VO

这个list接口基本流程,除了service对象不一样以外,其他的逻辑都是通用的,可以被复用的。

复用list接口

因此, 基础的通用的接口,放在抽象父类BaseController中进行复用。

继承list接口

scala 复制代码
/**
 * 通用的接口,放在抽象Base中进行复用
 * @param <T>
 * @param <V>
 */
public abstract class BaseController<T, V, S extends IService<T>> {


    protected final S baseService;

    private Class<V> voClass;

    public BaseController(S baseService, Class<V> voClass) {
        this.baseService = baseService;
        this.voClass = voClass;
    }

    /**
     * 获取列表
     * @return
     */
    @GetMapping("/list")
    public List<V> list() {
        List<T> entityList = baseService.list();
        return BeanConvertUtils.convertList(entityList, voClass);
    }

} 

具体业务控制器类继承抽象父类BaseController中进行复用。

less 复制代码
/**
 * 模型控制器,复用基础的增、删、改、查
 */
@Slf4j
@RestController
@RequestMapping("/llm")
public class Llmv2Controller extends BaseController<Llm, LlmVO, LlmService> {


    @Autowired
    public Llmv2Controller(LlmService llmService) {
        super(llmService, LlmVO.class);
    }

}

这样就不必重复写基础的增、删、改、查接口了,直接复用基础父类BaseController中的接口。

相关推荐
程序员爱钓鱼1 分钟前
Go语言实战案例-创建模型并自动迁移
后端·google·go
javachen__7 分钟前
SpringBoot整合P6Spy实现全链路SQL监控
spring boot·后端·sql
uzong6 小时前
技术故障复盘模版
后端
GetcharZp6 小时前
基于 Dify + 通义千问的多模态大模型 搭建发票识别 Agent
后端·llm·agent
桦说编程6 小时前
Java 中如何创建不可变类型
java·后端·函数式编程
IT毕设实战小研6 小时前
基于Spring Boot 4s店车辆管理系统 租车管理系统 停车位管理系统 智慧车辆管理系统
java·开发语言·spring boot·后端·spring·毕业设计·课程设计
wyiyiyi7 小时前
【Web后端】Django、flask及其场景——以构建系统原型为例
前端·数据库·后端·python·django·flask
阿华的代码王国8 小时前
【Android】RecyclerView复用CheckBox的异常状态
android·xml·java·前端·后端
Jimmy8 小时前
AI 代理是什么,其有助于我们实现更智能编程
前端·后端·ai编程
AntBlack8 小时前
不当韭菜V1.1 :增强能力 ,辅助构建自己的交易规则
后端·python·pyqt