接口生成工具

feasure
lld 2025-12-30 03:17:01 +08:00
parent 87b4645da0
commit bcb4995d2c
19 changed files with 1341 additions and 1 deletions

View File

@ -60,7 +60,11 @@
<groupId>com.agri</groupId> <groupId>com.agri</groupId>
<artifactId>agri-generator</artifactId> <artifactId>agri-generator</artifactId>
</dependency> </dependency>
<!-- 三方接口-->
<dependency>
<groupId>com.agri</groupId>
<artifactId>agri-api</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>

View File

@ -0,0 +1,3 @@
wrapperVersion=3.3.4
distributionType=only-script
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.12/apache-maven-3.9.12-bin.zip

54
agri-api/pom.xml Normal file
View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>agri</artifactId>
<groupId>com.agri</groupId>
<version>3.9.0</version>
</parent>
<artifactId>agri-api</artifactId>
<description>
三方接口接入模块
</description>
<dependencies>
<!-- 通用工具-->
<dependency>
<groupId>com.agri</groupId>
<artifactId>agri-common</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.5.15</version>
<configuration>
<fork>true</fork> <!-- 如果没有该配置devtools不会生效 -->
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<warName>${project.artifactId}</warName>
</configuration>
</plugin>
</plugins>
<finalName>${project.artifactId}</finalName>
</build>
</project>

View File

@ -0,0 +1,13 @@
package com.agri;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AgriApiApplication {
public static void main(String[] args) {
SpringApplication.run(AgriApiApplication.class, args);
}
}

View File

@ -0,0 +1 @@
spring.application.name=agri-api

View File

@ -35,6 +35,29 @@
<artifactId>druid-spring-boot-starter</artifactId> <artifactId>druid-spring-boot-starter</artifactId>
</dependency> </dependency>
<!-- Freemarker模板引擎 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- 数据库操作(可选,若需从数据库读取配置) -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<!-- 工具类 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.20</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -0,0 +1,123 @@
package com.agri.generator.controller;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import com.agri.generator.dto.ApiConfigDTO;
import com.agri.generator.util.CodeGenerator;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.agri.common.annotation.Log;
import com.agri.common.core.controller.BaseController;
import com.agri.common.core.domain.AjaxResult;
import com.agri.common.enums.BusinessType;
import com.agri.generator.domain.SysApiInfo;
import com.agri.generator.service.ISysApiInfoService;
import com.agri.common.utils.poi.ExcelUtil;
import com.agri.common.core.page.TableDataInfo;
/**
* Controller
*
* @author agri
* @date 2025-12-30
*/
@RestController
@RequestMapping("/tool/api")
public class SysApiInfoController extends BaseController
{
@Autowired
private ISysApiInfoService sysApiInfoService;
@Autowired
private CodeGenerator codeGenerator;
/**
*
*/
@PreAuthorize("@ss.hasPermi('tool:api:list')")
@GetMapping("/list")
public TableDataInfo list(SysApiInfo sysApiInfo)
{
startPage();
List<SysApiInfo> list = sysApiInfoService.selectSysApiInfoList(sysApiInfo);
return getDataTable(list);
}
/**
*
*/
@PreAuthorize("@ss.hasPermi('tool:api:export')")
@Log(title = "接口基础信息", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HttpServletResponse response, SysApiInfo sysApiInfo)
{
List<SysApiInfo> list = sysApiInfoService.selectSysApiInfoList(sysApiInfo);
ExcelUtil<SysApiInfo> util = new ExcelUtil<SysApiInfo>(SysApiInfo.class);
util.exportExcel(response, list, "接口基础信息数据");
}
/**
*
*/
@PreAuthorize("@ss.hasPermi('tool:api:query')")
@GetMapping(value = "/{id}")
public AjaxResult getInfo(@PathVariable("id") Long id)
{
return success(sysApiInfoService.selectSysApiInfoById(id));
}
/**
*
*/
@PreAuthorize("@ss.hasPermi('tool:api:add')")
@Log(title = "接口基础信息", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@RequestBody SysApiInfo sysApiInfo)
{
return toAjax(sysApiInfoService.insertSysApiInfo(sysApiInfo));
}
/**
*
*/
@PreAuthorize("@ss.hasPermi('tool:api:edit')")
@Log(title = "接口基础信息", businessType = BusinessType.UPDATE)
@PutMapping
public AjaxResult edit(@RequestBody SysApiInfo sysApiInfo)
{
return toAjax(sysApiInfoService.updateSysApiInfo(sysApiInfo));
}
/**
*
*/
@PostMapping("/code")
public String generateCode(@RequestBody ApiConfigDTO apiConfig) {
try {
codeGenerator.generateApiCode(apiConfig);
return "代码生成成功,生成路径:" + System.getProperty("user.dir") + "/generated-code/";
} catch (Exception e) {
return "代码生成失败:" + e.getMessage();
}
}
/**
*
*/
@PreAuthorize("@ss.hasPermi('tool:api:remove')")
@Log(title = "接口基础信息", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public AjaxResult remove(@PathVariable Long[] ids)
{
return toAjax(sysApiInfoService.deleteSysApiInfoByIds(ids));
}
}

View File

@ -0,0 +1,128 @@
package com.agri.generator.domain;
import java.util.List;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.agri.common.annotation.Excel;
import com.agri.common.core.domain.BaseEntity;
/**
* sys_api_info
*
* @author agri
* @date 2025-12-30
*/
public class SysApiInfo extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** 主键ID */
private Long id;
/** 请求路径对应前端proprequestPath */
@Excel(name = "请求路径", readConverterExp = "对=应前端proprequestPath")
private String requestPath;
/** 接口类型厂家对应前端propapiVendor */
@Excel(name = "接口类型", readConverterExp = "厂=家")
private Long apiVendor;
/** 接口说明对应前端propapiDesc */
@Excel(name = "接口说明", readConverterExp = "对=应前端propapiDesc")
private String apiDesc;
/** 接口备注对应前端propapiRemark */
@Excel(name = "接口备注", readConverterExp = "对=应前端propapiRemark")
private String apiRemark;
/** 逻辑删除标识0-未删1-已删) */
private Integer isDeleted;
/** 接口参数信息 */
private List<SysApiParam> sysApiParamList;
public void setId(Long id)
{
this.id = id;
}
public Long getId()
{
return id;
}
public void setRequestPath(String requestPath)
{
this.requestPath = requestPath;
}
public String getRequestPath()
{
return requestPath;
}
public void setApiVendor(Long apiVendor)
{
this.apiVendor = apiVendor;
}
public Long getApiVendor()
{
return apiVendor;
}
public void setApiDesc(String apiDesc)
{
this.apiDesc = apiDesc;
}
public String getApiDesc()
{
return apiDesc;
}
public void setApiRemark(String apiRemark)
{
this.apiRemark = apiRemark;
}
public String getApiRemark()
{
return apiRemark;
}
public void setIsDeleted(Integer isDeleted)
{
this.isDeleted = isDeleted;
}
public Integer getIsDeleted()
{
return isDeleted;
}
public List<SysApiParam> getSysApiParamList()
{
return sysApiParamList;
}
public void setSysApiParamList(List<SysApiParam> sysApiParamList)
{
this.sysApiParamList = sysApiParamList;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("requestPath", getRequestPath())
.append("apiVendor", getApiVendor())
.append("apiDesc", getApiDesc())
.append("apiRemark", getApiRemark())
.append("createTime", getCreateTime())
.append("updateTime", getUpdateTime())
.append("isDeleted", getIsDeleted())
.append("sysApiParamList", getSysApiParamList())
.toString();
}
}

View File

@ -0,0 +1,149 @@
package com.agri.generator.domain;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.agri.common.annotation.Excel;
import com.agri.common.core.domain.BaseEntity;
/**
* sys_api_param
*
* @author agri
* @date 2025-12-30
*/
public class SysApiParam extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** 主键ID */
private Long id;
/** 关联api_info的主键ID */
private Long apiId;
/** 参数类型0-入参1-出参) */
@Excel(name = "参数类型", readConverterExp = "0=-入参1-出参")
private Long paramType;
/** 参数名对应前端propparamName */
@Excel(name = "参数名", readConverterExp = "对=应前端propparamName")
private String paramName;
/** 是否必选仅入参有效对应前端proprequired */
@Excel(name = "是否必选", readConverterExp = "仅=入参有效")
private Long required;
/** 参数数据类型对应前端propparamType */
@Excel(name = "参数数据类型", readConverterExp = "对=应前端propparamType")
private String paramDataType;
/** 参数说明/注释入参paramDesc出参paramComment */
@Excel(name = "参数说明/注释", readConverterExp = "入=参paramDesc出参paramComment")
private String paramDesc;
/** 是否生成实体入参genRequestEntity出参genResponseEntity */
@Excel(name = "是否生成实体", readConverterExp = "入=参genRequestEntity出参genResponseEntity")
private Long genEntity;
/** 是否生成实体 */
private Long isDeleted;
public void setId(Long id)
{
this.id = id;
}
public Long getId()
{
return id;
}
public void setApiId(Long apiId)
{
this.apiId = apiId;
}
public Long getApiId()
{
return apiId;
}
public void setParamType(Long paramType)
{
this.paramType = paramType;
}
public Long getParamType()
{
return paramType;
}
public void setParamName(String paramName)
{
this.paramName = paramName;
}
public String getParamName()
{
return paramName;
}
public void setRequired(Long required)
{
this.required = required;
}
public Long getRequired()
{
return required;
}
public void setParamDataType(String paramDataType)
{
this.paramDataType = paramDataType;
}
public String getParamDataType()
{
return paramDataType;
}
public void setParamDesc(String paramDesc)
{
this.paramDesc = paramDesc;
}
public String getParamDesc()
{
return paramDesc;
}
public void setGenEntity(Long genEntity)
{
this.genEntity = genEntity;
}
public Long getGenEntity()
{
return genEntity;
}
public void setIsDeleted(Long isDeleted)
{
this.isDeleted = isDeleted;
}
public Long getIsDeleted()
{
return isDeleted;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("apiId", getApiId())
.append("paramType", getParamType())
.append("paramName", getParamName())
.append("required", getRequired())
.append("paramDataType", getParamDataType())
.append("paramDesc", getParamDesc())
.append("genEntity", getGenEntity())
.append("createTime", getCreateTime())
.append("updateTime", getUpdateTime())
.append("isDeleted", getIsDeleted())
.toString();
}
}

View File

@ -0,0 +1,40 @@
package com.agri.generator.dto;
import lombok.Data;
import java.util.List;
/**
*
*/
@Data
public class ApiConfigDTO {
/** 请求路径 */
private String requestPath;
/** 接口类型(厂家) */
private String apiVendor;
/** 接口说明 */
private String apiDesc;
/** 接口备注 */
private String apiRemark;
/** 入参列表 */
private List<ApiParamDTO> requestParams;
/** 出参列表 */
private List<ApiParamDTO> responseParams;
/**
*
*/
@Data
public static class ApiParamDTO {
/** 参数名 */
private String paramName;
/** 是否必选(仅入参) */
private Boolean required;
/** 参数类型String/Integer等 */
private String paramType;
/** 参数说明/注释 */
private String paramDesc;
/** 是否生成实体 */
private Boolean genEntity;
}
}

View File

@ -0,0 +1,87 @@
package com.agri.generator.mapper;
import java.util.List;
import com.agri.generator.domain.SysApiInfo;
import com.agri.generator.domain.SysApiParam;
/**
* Mapper
*
* @author agri
* @date 2025-12-30
*/
public interface SysApiInfoMapper
{
/**
*
*
* @param id
* @return
*/
public SysApiInfo selectSysApiInfoById(Long id);
/**
*
*
* @param sysApiInfo
* @return
*/
public List<SysApiInfo> selectSysApiInfoList(SysApiInfo sysApiInfo);
/**
*
*
* @param sysApiInfo
* @return
*/
public int insertSysApiInfo(SysApiInfo sysApiInfo);
/**
*
*
* @param sysApiInfo
* @return
*/
public int updateSysApiInfo(SysApiInfo sysApiInfo);
/**
*
*
* @param id
* @return
*/
public int deleteSysApiInfoById(Long id);
/**
*
*
* @param ids
* @return
*/
public int deleteSysApiInfoByIds(Long[] ids);
/**
*
*
* @param ids
* @return
*/
public int deleteSysApiParamByApiIds(Long[] ids);
/**
*
*
* @param sysApiParamList
* @return
*/
public int batchSysApiParam(List<SysApiParam> sysApiParamList);
/**
*
*
* @param id ID
* @return
*/
public int deleteSysApiParamByApiId(Long id);
}

View File

@ -0,0 +1,61 @@
package com.agri.generator.service;
import java.util.List;
import com.agri.generator.domain.SysApiInfo;
/**
* Service
*
* @author agri
* @date 2025-12-30
*/
public interface ISysApiInfoService
{
/**
*
*
* @param id
* @return
*/
public SysApiInfo selectSysApiInfoById(Long id);
/**
*
*
* @param sysApiInfo
* @return
*/
public List<SysApiInfo> selectSysApiInfoList(SysApiInfo sysApiInfo);
/**
*
*
* @param sysApiInfo
* @return
*/
public int insertSysApiInfo(SysApiInfo sysApiInfo);
/**
*
*
* @param sysApiInfo
* @return
*/
public int updateSysApiInfo(SysApiInfo sysApiInfo);
/**
*
*
* @param ids
* @return
*/
public int deleteSysApiInfoByIds(Long[] ids);
/**
*
*
* @param id
* @return
*/
public int deleteSysApiInfoById(Long id);
}

View File

@ -0,0 +1,134 @@
package com.agri.generator.service.impl;
import java.util.List;
import com.agri.common.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import com.agri.common.utils.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import com.agri.generator.domain.SysApiParam;
import com.agri.generator.mapper.SysApiInfoMapper;
import com.agri.generator.domain.SysApiInfo;
import com.agri.generator.service.ISysApiInfoService;
/**
* Service
*
* @author agri
* @date 2025-12-30
*/
@Service
public class SysApiInfoServiceImpl implements ISysApiInfoService
{
@Autowired
private SysApiInfoMapper sysApiInfoMapper;
/**
*
*
* @param id
* @return
*/
@Override
public SysApiInfo selectSysApiInfoById(Long id)
{
return sysApiInfoMapper.selectSysApiInfoById(id);
}
/**
*
*
* @param sysApiInfo
* @return
*/
@Override
public List<SysApiInfo> selectSysApiInfoList(SysApiInfo sysApiInfo)
{
return sysApiInfoMapper.selectSysApiInfoList(sysApiInfo);
}
/**
*
*
* @param sysApiInfo
* @return
*/
@Transactional
@Override
public int insertSysApiInfo(SysApiInfo sysApiInfo)
{
sysApiInfo.setCreateTime(DateUtils.getNowDate());
int rows = sysApiInfoMapper.insertSysApiInfo(sysApiInfo);
insertSysApiParam(sysApiInfo);
return rows;
}
/**
*
*
* @param sysApiInfo
* @return
*/
@Transactional
@Override
public int updateSysApiInfo(SysApiInfo sysApiInfo)
{
sysApiInfo.setUpdateTime(DateUtils.getNowDate());
sysApiInfoMapper.deleteSysApiParamByApiId(sysApiInfo.getId());
insertSysApiParam(sysApiInfo);
return sysApiInfoMapper.updateSysApiInfo(sysApiInfo);
}
/**
*
*
* @param ids
* @return
*/
@Transactional
@Override
public int deleteSysApiInfoByIds(Long[] ids)
{
sysApiInfoMapper.deleteSysApiParamByApiIds(ids);
return sysApiInfoMapper.deleteSysApiInfoByIds(ids);
}
/**
*
*
* @param id
* @return
*/
@Transactional
@Override
public int deleteSysApiInfoById(Long id)
{
sysApiInfoMapper.deleteSysApiParamByApiId(id);
return sysApiInfoMapper.deleteSysApiInfoById(id);
}
/**
*
*
* @param sysApiInfo
*/
public void insertSysApiParam(SysApiInfo sysApiInfo)
{
List<SysApiParam> sysApiParamList = sysApiInfo.getSysApiParamList();
Long id = sysApiInfo.getId();
if (StringUtils.isNotNull(sysApiParamList))
{
List<SysApiParam> list = new ArrayList<SysApiParam>();
for (SysApiParam sysApiParam : sysApiParamList)
{
sysApiParam.setApiId(id);
list.add(sysApiParam);
}
if (list.size() > 0)
{
sysApiInfoMapper.batchSysApiParam(list);
}
}
}
}

View File

@ -0,0 +1,290 @@
package com.agri.generator.util;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.agri.generator.dto.ApiConfigDTO;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.*;
import java.util.stream.Collectors;
/**
*
*/
@Component
public class CodeGenerator {
// Freemarker配置
private Configuration freemarkerConfig;
// 代码生成根目录可配置到application.yml
private static final String CODE_ROOT_PATH = System.getProperty("user.dir") + "/generated-code/";
// 基础包名
private static final String BASE_PACKAGE = "com.example.api";
@PostConstruct
public void init() {
// 初始化Freemarker
freemarkerConfig = new Configuration(Configuration.VERSION_2_3_31);
// 设置模板目录resources/templates
freemarkerConfig.setClassForTemplateLoading(this.getClass(), "/templates/");
freemarkerConfig.setDefaultEncoding("UTF-8");
// 创建代码根目录
FileUtil.mkdir(CODE_ROOT_PATH);
}
/**
* ++
*/
public void generateApiCode(ApiConfigDTO apiConfig) {
try {
// 1. 生成入参实体仅生成标记为genEntity=true的参数
generateRequestEntity(apiConfig);
// 2. 生成出参实体仅生成标记为genEntity=true的参数
generateResponseEntity(apiConfig);
// 3. 生成接口方法
generateApiMethod(apiConfig);
// 4. 生成枚举(需传入所有接口配置,此处示例传单个,实际可传列表)
List<ApiConfigDTO> apiList = Collections.singletonList(apiConfig);
generateApiEnum(apiList);
} catch (Exception e) {
throw new RuntimeException("代码生成失败", e);
}
}
/**
*
*/
private void generateRequestEntity(ApiConfigDTO apiConfig) throws IOException, TemplateException {
// 过滤需要生成实体的入参
List<ApiConfigDTO.ApiParamDTO> requestParams = apiConfig.getRequestParams().stream()
.filter(ApiConfigDTO.ApiParamDTO::getGenEntity)
.collect(Collectors.toList());
if (requestParams.isEmpty()) {
return;
}
// 实体类名(路径转驼峰,如/api/user/login → UserLoginRequest
String className = getClassName(apiConfig.getRequestPath(), "Request");
// 模板参数
Map<String, Object> dataModel = new HashMap<>();
dataModel.put("packageName", BASE_PACKAGE + ".request");
dataModel.put("className", className);
dataModel.put("apiDesc", apiConfig.getApiDesc());
dataModel.put("apiRemark", apiConfig.getApiRemark());
dataModel.put("params", requestParams);
dataModel.put("createTime", new Date());
// 生成文件
Template template = freemarkerConfig.getTemplate("entity.ftl");
String filePath = CODE_ROOT_PATH + "request/" + className + ".java";
writeFile(template, dataModel, filePath);
}
/**
*
*/
private void generateResponseEntity(ApiConfigDTO apiConfig) throws IOException, TemplateException {
// 过滤需要生成实体的出参
List<ApiConfigDTO.ApiParamDTO> responseParams = apiConfig.getResponseParams().stream()
.filter(ApiConfigDTO.ApiParamDTO::getGenEntity)
.collect(Collectors.toList());
if (responseParams.isEmpty()) {
return;
}
// 实体类名(路径转驼峰,如/api/user/login → UserLoginResponse
String className = getClassName(apiConfig.getRequestPath(), "Response");
// 模板参数
Map<String, Object> dataModel = new HashMap<>();
dataModel.put("packageName", BASE_PACKAGE + ".response");
dataModel.put("className", className);
dataModel.put("apiDesc", apiConfig.getApiDesc());
dataModel.put("apiRemark", apiConfig.getApiRemark());
dataModel.put("params", responseParams);
dataModel.put("createTime", new Date());
// 生成文件
Template template = freemarkerConfig.getTemplate("entity.ftl");
String filePath = CODE_ROOT_PATH + "response/" + className + ".java";
writeFile(template, dataModel, filePath);
}
/**
*
*/
private void generateApiMethod(ApiConfigDTO apiConfig) throws IOException, TemplateException {
// 接口类名(路径转驼峰,如/api/user/login → UserLoginApi
String className = getClassName(apiConfig.getRequestPath(), "Api");
// 方法名(路径转小驼峰,如/api/user/login → userLogin
String methodName = this.uncapitalize(getClassName(apiConfig.getRequestPath(), ""));
// 出参实体名默认用Response若生成则用实际实体名
String responseEntityName = "Response";
List<ApiConfigDTO.ApiParamDTO> responseParams = apiConfig.getResponseParams().stream()
.filter(ApiConfigDTO.ApiParamDTO::getGenEntity)
.collect(Collectors.toList());
if (!responseParams.isEmpty()) {
responseEntityName = getClassName(apiConfig.getRequestPath(), "Response");
}
// 模板参数
Map<String, Object> dataModel = new HashMap<>();
dataModel.put("packageName", BASE_PACKAGE + ".controller");
dataModel.put("className", className);
dataModel.put("methodName", methodName);
dataModel.put("requestMethod", "Post"); // 默认POST可根据实际需求调整
dataModel.put("requestPath", apiConfig.getRequestPath());
dataModel.put("apiVendor", apiConfig.getApiVendor());
dataModel.put("apiDesc", apiConfig.getApiDesc());
dataModel.put("apiRemark", apiConfig.getApiRemark());
dataModel.put("requestParams", apiConfig.getRequestParams());
dataModel.put("responseEntityName", responseEntityName);
dataModel.put("createTime", new Date());
// 生成文件
Template template = freemarkerConfig.getTemplate("apiMethod.ftl");
String filePath = CODE_ROOT_PATH + "controller/" + className + ".java";
writeFile(template, dataModel, filePath);
}
/**
*
*/
private void generateApiEnum(List<ApiConfigDTO> apiList) throws IOException, TemplateException {
// 处理枚举数据(路径转枚举名,如/api/user/login → USER_LOGIN
List<Map<String, String>> enumDataList = new ArrayList<>();
for (ApiConfigDTO api : apiList) {
Map<String, String> enumData = new HashMap<>();
enumData.put("enumName", getEnumName(api.getRequestPath()));
enumData.put("requestPath", api.getRequestPath());
enumData.put("apiDesc", api.getApiDesc());
enumDataList.add(enumData);
}
// 模板参数
Map<String, Object> dataModel = new HashMap<>();
dataModel.put("packageName", BASE_PACKAGE + ".enums");
dataModel.put("apiList", enumDataList);
dataModel.put("createTime", new Date());
// 生成文件
Template template = freemarkerConfig.getTemplate("enum.ftl");
String filePath = CODE_ROOT_PATH + "enums/ApiPathEnum.java";
writeFile(template, dataModel, filePath);
}
/**
* /api/user/login UserLogin + suffix
*/
private String getClassName(String path, String suffix) {
// 去除前缀/,按/分割,转驼峰
String[] parts = StrUtil.removePrefix(path, "/").split("/");
StringBuilder className = new StringBuilder();
for (String part : parts) {
className.append(StrUtil.upperFirst(part));
}
return className + suffix;
}
/**
* /api/user/login USER_LOGIN
*/
private String getEnumName(String path) {
String[] parts = StrUtil.removePrefix(path, "/").split("/");
StringBuilder enumName = new StringBuilder();
for (int i = 0; i < parts.length; i++) {
enumName.append(parts[i].toUpperCase());
if (i < parts.length - 1) {
enumName.append("_");
}
}
return enumName.toString();
}
/**
*
*/
private void writeFile(Template template, Map<String, Object> dataModel, String filePath) throws IOException, TemplateException {
File file = new File(filePath);
FileUtil.mkParentDirs(file); // 创建父目录
try (Writer writer = new FileWriter(file, false)) {
template.process(dataModel, writer);
}
}
// ==================== 替代StrUtil的原生方法 ====================
/**
*
*/
private boolean isBlank(String str) {
if (str == null) {
return true;
}
int length = str.length();
for (int i = 0; i < length; i++) {
if (!Character.isWhitespace(str.charAt(i))) {
return false;
}
}
return true;
}
/**
*
*/
private boolean isNotBlank(String str) {
return !isBlank(str);
}
/**
*
*/
private String removePrefix(String str, String prefix) {
if (str == null || prefix == null) {
return str;
}
if (str.startsWith(prefix)) {
return str.substring(prefix.length());
}
return str;
}
/**
*
*/
private String upperFirst(String str) {
if (isBlank(str)) {
return str;
}
char firstChar = str.charAt(0);
if (Character.isUpperCase(firstChar)) {
return str;
}
return Character.toUpperCase(firstChar) + str.substring(1);
}
/**
*
*/
private String uncapitalize(String str) {
if (isBlank(str)) {
return str;
}
char firstChar = str.charAt(0);
if (Character.isLowerCase(firstChar)) {
return str;
}
return Character.toLowerCase(firstChar) + str.substring(1);
}
}

View File

@ -0,0 +1,127 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.agri.generator.mapper.SysApiInfoMapper">
<resultMap type="SysApiInfo" id="SysApiInfoResult">
<result property="id" column="id" />
<result property="requestPath" column="request_path" />
<result property="apiVendor" column="api_vendor" />
<result property="apiDesc" column="api_desc" />
<result property="apiRemark" column="api_remark" />
<result property="createTime" column="create_time" />
<result property="updateTime" column="update_time" />
<result property="isDeleted" column="is_deleted" />
</resultMap>
<resultMap id="SysApiInfoSysApiParamResult" type="SysApiInfo" extends="SysApiInfoResult">
<collection property="sysApiParamList" ofType="SysApiParam" column="id" select="selectSysApiParamList" />
</resultMap>
<resultMap type="SysApiParam" id="SysApiParamResult">
<result property="id" column="id" />
<result property="apiId" column="api_id" />
<result property="paramType" column="param_type" />
<result property="paramName" column="param_name" />
<result property="required" column="required" />
<result property="paramDataType" column="param_data_type" />
<result property="paramDesc" column="param_desc" />
<result property="genEntity" column="gen_entity" />
<result property="createTime" column="create_time" />
<result property="updateTime" column="update_time" />
<result property="isDeleted" column="is_deleted" />
</resultMap>
<sql id="selectSysApiInfoVo">
select id, request_path, api_vendor, api_desc, api_remark, create_time, update_time, is_deleted from sys_api_info
</sql>
<select id="selectSysApiInfoList" parameterType="SysApiInfo" resultMap="SysApiInfoResult">
<include refid="selectSysApiInfoVo"/>
<where>
<if test="requestPath != null and requestPath != ''"> and request_path like concat('%', #{requestPath}, '%')</if>
<if test="apiVendor != null "> and api_vendor = #{apiVendor}</if>
<if test="apiDesc != null and apiDesc != ''"> and api_desc like concat('%', #{apiDesc}, '%')</if>
<if test="apiRemark != null and apiRemark != ''"> and api_remark = #{apiRemark}</if>
<if test="isDeleted != null "> and is_deleted = #{isDeleted}</if>
</where>
</select>
<select id="selectSysApiInfoById" parameterType="Long" resultMap="SysApiInfoSysApiParamResult">
select id, request_path, api_vendor, api_desc, api_remark, create_time, update_time, is_deleted
from sys_api_info
where id = #{id}
</select>
<select id="selectSysApiParamList" resultMap="SysApiParamResult">
select id, api_id, param_type, param_name, required, param_data_type, param_desc, gen_entity, create_time, update_time, is_deleted
from sys_api_param
where api_id = #{api_id}
</select>
<insert id="insertSysApiInfo" parameterType="SysApiInfo" useGeneratedKeys="true" keyProperty="id">
insert into sys_api_info
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="requestPath != null and requestPath != ''">request_path,</if>
<if test="apiVendor != null">api_vendor,</if>
<if test="apiDesc != null and apiDesc != ''">api_desc,</if>
<if test="apiRemark != null">api_remark,</if>
<if test="createTime != null">create_time,</if>
<if test="updateTime != null">update_time,</if>
<if test="isDeleted != null">is_deleted,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="requestPath != null and requestPath != ''">#{requestPath},</if>
<if test="apiVendor != null">#{apiVendor},</if>
<if test="apiDesc != null and apiDesc != ''">#{apiDesc},</if>
<if test="apiRemark != null">#{apiRemark},</if>
<if test="createTime != null">#{createTime},</if>
<if test="updateTime != null">#{updateTime},</if>
<if test="isDeleted != null">#{isDeleted},</if>
</trim>
</insert>
<update id="updateSysApiInfo" parameterType="SysApiInfo">
update sys_api_info
<trim prefix="SET" suffixOverrides=",">
<if test="requestPath != null and requestPath != ''">request_path = #{requestPath},</if>
<if test="apiVendor != null">api_vendor = #{apiVendor},</if>
<if test="apiDesc != null and apiDesc != ''">api_desc = #{apiDesc},</if>
<if test="apiRemark != null">api_remark = #{apiRemark},</if>
<if test="createTime != null">create_time = #{createTime},</if>
<if test="updateTime != null">update_time = #{updateTime},</if>
<if test="isDeleted != null">is_deleted = #{isDeleted},</if>
</trim>
where id = #{id}
</update>
<delete id="deleteSysApiInfoById" parameterType="Long">
delete from sys_api_info where id = #{id}
</delete>
<delete id="deleteSysApiInfoByIds" parameterType="String">
delete from sys_api_info where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
<delete id="deleteSysApiParamByApiIds" parameterType="String">
delete from sys_api_param where api_id in
<foreach item="apiId" collection="array" open="(" separator="," close=")">
#{apiId}
</foreach>
</delete>
<delete id="deleteSysApiParamByApiId" parameterType="Long">
delete from sys_api_param where api_id = #{apiId}
</delete>
<insert id="batchSysApiParam">
insert into sys_api_param( id, api_id, param_type, param_name, required, param_data_type, param_desc, gen_entity, create_time, update_time, is_deleted) values
<foreach item="item" index="index" collection="list" separator=",">
( #{item.id}, #{item.apiId}, #{item.paramType}, #{item.paramName}, #{item.required}, #{item.paramDataType}, #{item.paramDesc}, #{item.genEntity}, #{item.createTime}, #{item.updateTime}, #{item.isDeleted})
</foreach>
</insert>
</mapper>

View File

@ -0,0 +1,38 @@
package ${packageName};
import org.springframework.web.bind.annotation.${requestMethod};
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
/**
* ${apiVendor}接口实现类
* ${apiDesc}
* 备注:${apiRemark}
* @author 自动生成
* @date ${createTime}
*/
@RestController
@RequestMapping("/api")
public class ${className} {
/**
* ${apiDesc}
* 接口路径:${requestPath}
*/
@${requestMethod}("${requestPath}")
public ${responseEntityName} ${methodName}(
<#if requestParams?exists && requestParams?size > 0>
<#list requestParams as param>
<#if param.required?? && param.required>@RequestParam(required = true) </#if>
<#if !param.required?? || !param.required>@RequestParam(required = false) </#if>
${param.paramType} ${param.paramName}
<#if param_has_next>,</#if>
</#list>
</#if>
) {
// 接口业务逻辑(需手动实现)
return new ${responseEntityName}();
}
}

View File

@ -0,0 +1,26 @@
package ${packageName};
import lombok.Data;
import java.io.Serializable;
/**
* ${className}
* ${apiDesc}
* 备注:${apiRemark}
* @author 自动生成
* @date ${createTime}
*/
@Data
public class ${className} implements Serializable {
private static final long serialVersionUID = 1L;
<#list params as param>
/**
* ${param.paramDesc}
<#if param.required?? && param.required>
* 必选参数
</#if>
*/
private ${param.paramType} ${param.paramName};
</#list>
}

View File

@ -0,0 +1,32 @@
package ${packageName};
/**
* 接口路径枚举
* @author 自动生成
* @date ${createTime}
*/
public enum ApiPathEnum {
<#list apiList as api>
/**
* ${api.apiDesc}
*/
${api.enumName}("${api.requestPath}", "${api.apiDesc}")
<#if api_has_next>,</#if>
</#list>;
private final String path;
private final String desc;
ApiPathEnum(String path, String desc) {
this.path = path;
this.desc = desc;
}
public String getPath() {
return path;
}
public String getDesc() {
return desc;
}
}

View File

@ -219,6 +219,12 @@
<version>${agri.version}</version> <version>${agri.version}</version>
</dependency> </dependency>
<!-- 通用工具-->
<dependency>
<groupId>com.agri</groupId>
<artifactId>agri-api</artifactId>
<version>${agri.version}</version>
</dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>
@ -229,6 +235,7 @@
<module>agri-quartz</module> <module>agri-quartz</module>
<module>agri-generator</module> <module>agri-generator</module>
<module>agri-common</module> <module>agri-common</module>
<module>agri-api</module>
</modules> </modules>
<packaging>pom</packaging> <packaging>pom</packaging>