添加 模版生成相关依赖

This commit is contained in:
2026-01-12 09:17:24 +08:00
parent f07fee186d
commit 2c2ac6d032
7 changed files with 264 additions and 6 deletions

14
pom.xml
View File

@@ -22,6 +22,7 @@
<knife4j.version>4.4.0</knife4j.version>
<hibernate-validator.version>9.1.0.Final</hibernate-validator.version>
<springdoc-openapi-starter-webmvc-ui.version>2.8.15</springdoc-openapi-starter-webmvc-ui.version>
<ST4.version>4.3.4</ST4.version>
</properties>
<dependencies>
@@ -96,6 +97,19 @@
<artifactId>hibernate-validator</artifactId>
<version>${hibernate-validator.version}</version>
</dependency>
<!-- stringtemplate ST4-->
<dependency>
<groupId>org.antlr</groupId>
<artifactId>ST4</artifactId>
<version>${ST4.version}</version>
</dependency>
<!-- 测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>

View File

@@ -0,0 +1,42 @@
package com.cczsa.xinghe.codegen.controller;
import com.cczsa.xinghe.codegen.service.CodeGenService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author xia
* &#064;date 2026/1/10
* @version 0.0.1
*/
@RestController
@RequestMapping("/codegen")
@RequiredArgsConstructor
public class CodeGenController {
private final CodeGenService codeGenService;
@PostMapping("/download")
public ResponseEntity<byte[]> downloadCode() {
try {
byte[] zipData = codeGenService.generateCodeZip();
return ResponseEntity.ok()
// 设置下载文件名
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"generated-code.zip\"")
// 设置为二进制流
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.contentLength(zipData.length)
.body(zipData);
} catch (Exception e) {
return ResponseEntity.internalServerError().build();
}
}
}

View File

@@ -1,12 +1,22 @@
package com.cczsa.xinghe.codegen.controller;
import com.alibaba.fastjson2.JSONObject;
import com.cczsa.xinghe.codegen.util.XResult;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
* @author xia
@@ -14,17 +24,49 @@ import org.springframework.web.bind.annotation.RestController;
* @version 0.0.1
*
*/
@Slf4j
@Tag(name = "登录")
@RequiredArgsConstructor
@RestController
@RequestMapping("/login")
public class LoginController {
@PostMapping("/")
public XResult<String> login(String username, String password) {
return null;
@Operation(summary = "登录", description = "登录")
@PostMapping("/login")
@Parameters({
@Parameter(name = "username", description = "用户名", required = true),
@Parameter(name = "password", description = "密码", required = true)
})
public XResult<Object> login(@RequestBody JSONObject login) {
if(!login.containsKey("username") || !login.containsKey("password")){
return XResult.failed("参数错误");
}
String username = login.getString("username");
String password = login.getString("password");
if ("admin".equals(username) && "9527".equals(password)) {
Map<String, Object> info = new HashMap<>();
info.put("token", "sk-"+System.currentTimeMillis());
info.put("roles", List.of("admin"));
info.put("username", "admin");
return XResult.ok(info);
}
return XResult.failed();
}
@Operation(summary = "用户信息", description = "用户信息")
@GetMapping("/users/info")
public XResult<Object> login() {
Map<String, Object> info = new HashMap<>();
info.put("roles", List.of("admin"));
info.put("username", "admin");
return XResult.ok(info);
}
}

View File

@@ -0,0 +1,10 @@
package com.cczsa.xinghe.codegen.service;
/**
* @author xia
* &#064;date 2026/1/10
* @version 0.0.1
*/
public interface CodeGenService {
byte[] generateCodeZip();
}

View File

@@ -0,0 +1,22 @@
package com.cczsa.xinghe.codegen.service.impl;
import com.cczsa.xinghe.codegen.service.CodeGenService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @author xia
* &#064;date 2026/1/10
* @version 0.0.1
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class CodeGenServiceImpl implements CodeGenService {
@Override
public byte[] generateCodeZip() {
return null;
}
}

View File

@@ -3,7 +3,7 @@ server:
spring:
datasource:
url: jdbc:postgresql://192.168.1.40:5432/xinghe-codegen
url: jdbc:postgresql://192.168.1.26:5432/xinghe-codegen
username: postgres
password: root
driver-class-name: org.postgresql.Driver

View File

@@ -0,0 +1,128 @@
package com.cczsa.xinghe.codegen;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STGroup;
import org.stringtemplate.v4.STGroupString;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.nio.charset.StandardCharsets;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* @author xia
* &#064;date 2026/1/10
* @version 0.0.1
*/
public class CodeGenTest {
@Test
@DisplayName("直接运行代码生成逻辑并输出到本地文件")
void executeCodeGen() {
// 1. 模拟 CodeGenServiceImpl.java 中的逻辑
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ZipOutputStream zos = new ZipOutputStream(baos)) {
// 定义模板语法
String template = """
classTemplate(packageName, className, description, author) ::= <<
package <packageName>;
/**
* <description>
* @author <author>
*/
public class <className> {
// 自动生成的类
}
>>
""";
// 初始化 StringTemplate 组
STGroup group = new STGroupString(template);
ST st = group.getInstanceOf("classTemplate");
if (st == null) {
throw new RuntimeException("Template 'classTemplate' not found");
}
// 填充数据
st.add("packageName", "com.example.generated");
st.add("className", "HelloWorld");
st.add("description", "这是一个通过测试类直接生成的示例");
st.add("author", "Gemini_Test");
String result = st.render();
// 写入 ZIP 流
ZipEntry entry = new ZipEntry("com/example/generated/HelloWorld.java");
zos.putNextEntry(entry);
zos.write(result.getBytes(StandardCharsets.UTF_8));
zos.closeEntry();
zos.finish(); // 确保 ZIP 流结束
// 2. 将结果保存到本地磁盘(方便查看结果)
try (FileOutputStream fos = new FileOutputStream("generated_code.zip")) {
baos.writeTo(fos);
System.out.println("代码生成成功!请检查项目根目录下的 generated_code.zip");
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("测试执行失败", e);
}
}
/**
* 流写出
* @return
*/
public byte[] generateCodeZip() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ZipOutputStream zos = new ZipOutputStream(baos)) {
// 使用命名模板语法 ::=
String template = """
classTemplate(packageName, className, description, author) ::= <<
package <packageName>;
/**
* <description>
* @author <author>
*/
public class <className> {
// 自动生成的类
}
>>
""";
STGroup group = new STGroupString(template);
ST st = group.getInstanceOf("classTemplate"); // 使用正确的模板名称
if (st == null) {
throw new RuntimeException("Template 'classTemplate' not found");
}
st.add("packageName", "com.example.generated");
st.add("className", "HelloWorld");
st.add("description", "这是一个演示类");
st.add("author", "Gemini");
String result = st.render();
ZipEntry entry = new ZipEntry("com/example/generated/HelloWorld.java");
zos.putNextEntry(entry);
zos.write(result.getBytes(StandardCharsets.UTF_8));
zos.closeEntry();
} catch (Exception e) {
throw new RuntimeException("Code generation failed", e);
}
return baos.toByteArray();
}
}