添加 模版生成相关依赖
This commit is contained in:
14
pom.xml
14
pom.xml
@@ -22,6 +22,7 @@
|
|||||||
<knife4j.version>4.4.0</knife4j.version>
|
<knife4j.version>4.4.0</knife4j.version>
|
||||||
<hibernate-validator.version>9.1.0.Final</hibernate-validator.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>
|
<springdoc-openapi-starter-webmvc-ui.version>2.8.15</springdoc-openapi-starter-webmvc-ui.version>
|
||||||
|
<ST4.version>4.3.4</ST4.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@@ -96,6 +97,19 @@
|
|||||||
<artifactId>hibernate-validator</artifactId>
|
<artifactId>hibernate-validator</artifactId>
|
||||||
<version>${hibernate-validator.version}</version>
|
<version>${hibernate-validator.version}</version>
|
||||||
</dependency>
|
</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>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@@ -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
|
||||||
|
* @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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,12 +1,22 @@
|
|||||||
package com.cczsa.xinghe.codegen.controller;
|
package com.cczsa.xinghe.codegen.controller;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import com.cczsa.xinghe.codegen.util.XResult;
|
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 io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import lombok.RequiredArgsConstructor;
|
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.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author xia
|
* @author xia
|
||||||
@@ -14,17 +24,49 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
* @version 0.0.1
|
* @version 0.0.1
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
@Tag(name = "登录")
|
@Tag(name = "登录")
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/login")
|
|
||||||
public class LoginController {
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package com.cczsa.xinghe.codegen.service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author xia
|
||||||
|
* @date 2026/1/10
|
||||||
|
* @version 0.0.1
|
||||||
|
*/
|
||||||
|
public interface CodeGenService {
|
||||||
|
byte[] generateCodeZip();
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
* @date 2026/1/10
|
||||||
|
* @version 0.0.1
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class CodeGenServiceImpl implements CodeGenService {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] generateCodeZip() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ server:
|
|||||||
|
|
||||||
spring:
|
spring:
|
||||||
datasource:
|
datasource:
|
||||||
url: jdbc:postgresql://192.168.1.40:5432/xinghe-codegen
|
url: jdbc:postgresql://192.168.1.26:5432/xinghe-codegen
|
||||||
username: postgres
|
username: postgres
|
||||||
password: root
|
password: root
|
||||||
driver-class-name: org.postgresql.Driver
|
driver-class-name: org.postgresql.Driver
|
||||||
|
|||||||
128
src/test/java/com/cczsa/xinghe/codegen/CodeGenTest.java
Normal file
128
src/test/java/com/cczsa/xinghe/codegen/CodeGenTest.java
Normal 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
|
||||||
|
* @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();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user