生成 C++ 代码工程

This commit is contained in:
root 2026-04-24 15:17:55 +08:00
parent bba7a6ac13
commit 4bc29c9a7d
11 changed files with 6034 additions and 1 deletions

View File

@ -1,2 +1,61 @@
# 任务自主规划系统
# Demo Spring Boot Project
## 项目说明
本项目是一个使用 **Spring Boot 3.x + Java 17** 构建的单体后端工程,集成了 **Knife4j (Swagger/OpenAPI)** 用于接口文档展示。
### 技术栈
- Java 17
- Spring Boot 3.2.4
- Knife4j 4.5.0 (OpenAPI 3)
- Maven
- Lombok
### 业务说明
- 当前所有业务数据使用**内存假数据**,未接入任何数据库或外部基础设施。
- 已预留 Repository 接口层扩展点,后续可对接数据库实现。
### 启动方式
```bash
# 编译
mvn clean package
# 运行
mvn spring-boot:run
# 或直接运行生成的 jar
java -jar target/demo-0.0.1-SNAPSHOT.jar
```
### 接口文档访问
启动后,打开浏览器访问:
- **Knife4j UI**: http://localhost:8080/doc.html
- **Swagger UI**: http://localhost:8080/swagger-ui/index.html
- **OpenAPI JSON**: http://localhost:8080/v3/api-docs
### 项目结构
```
src/main/java/com/example/demo/
├── DemoApplication.java # 启动类
├── config/
│ └── OpenApiConfig.java # Knife4j/Swagger 配置
├── controller/
│ ├── HealthController.java # 健康检查接口
│ └── BusinessController.java # 业务 REST 接口
├── model/
│ └── BusinessItem.java # 业务数据模型
└── service/
└── BusinessService.java # 业务逻辑(内存假数据)
```
### 扩展说明
- `repository/` 目录可扩展为数据库 Repository 层
- `service/` 中注入 Repository 即可切换为真实数据源
- 配置文件已预留 Spring Data JPA / MyBatis 相关配置注释

5433
events.ndjson Normal file

File diff suppressed because one or more lines are too long

77
pom.xml Normal file
View File

@ -0,0 +1,77 @@
<?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>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.4</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo Spring Boot project generated by codegen</description>
<properties>
<java.version>17</java.version>
<knife4j.version>4.5.0</knife4j.version>
</properties>
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot Validation -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- Knife4j (Swagger/OpenAPI) -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>${knife4j.version}</version>
</dependency>
<!-- Lombok (optional but convenient) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,15 @@
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 应用启动类
*/
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

View File

@ -0,0 +1,38 @@
package com.example.demo.config;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* OpenAPI / Knife4j 配置
* <p>
* 访问地址
* <ul>
* <li>Knife4j UI: <a href="http://localhost:8080/doc.html">http://localhost:8080/doc.html</a></li>
* <li>Swagger UI: <a href="http://localhost:8080/swagger-ui/index.html">http://localhost:8080/swagger-ui/index.html</a></li>
* <li>OpenAPI JSON: <a href="http://localhost:8080/v3/api-docs">http://localhost:8080/v3/api-docs</a></li>
* </ul>
*/
@Configuration
public class OpenApiConfig {
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("Demo 业务 API")
.version("1.0.0")
.description("Spring Boot 3.x 单体后端示例接口文档")
.contact(new Contact()
.name("Codegen")
.email("codegen@example.com")
.url("https://example.com"))
.license(new License()
.name("Apache 2.0")
.url("https://www.apache.org/licenses/LICENSE-2.0.html")));
}
}

View File

@ -0,0 +1,108 @@
package com.example.demo.controller;
import com.example.demo.model.BusinessItem;
import com.example.demo.service.BusinessService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 业务 REST 控制器
*/
@Tag(name = "业务管理", description = "业务数据 CRUD 接口")
@RestController
@RequestMapping("/api/business")
@RequiredArgsConstructor
public class BusinessController {
private final BusinessService businessService;
@Operation(summary = "获取所有业务项")
@GetMapping
public List<BusinessItem> getAll() {
return businessService.findAll();
}
@Operation(summary = "根据 ID 获取业务项")
@GetMapping("/{id}")
public ResponseEntity<BusinessItem> getById(
@Parameter(description = "业务项 ID") @PathVariable Long id) {
return businessService.findById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
@Operation(summary = "创建业务项")
@PostMapping
public ResponseEntity<BusinessItem> create(
@Valid @RequestBody CreateRequest request) {
BusinessItem item = BusinessItem.builder()
.name(request.getName())
.description(request.getDescription())
.status(request.getStatus() != null ? request.getStatus() : "ENABLED")
.build();
BusinessItem created = businessService.create(item);
return ResponseEntity.status(HttpStatus.CREATED).body(created);
}
@Operation(summary = "更新业务项")
@PutMapping("/{id}")
public ResponseEntity<BusinessItem> update(
@Parameter(description = "业务项 ID") @PathVariable Long id,
@Valid @RequestBody UpdateRequest request) {
BusinessItem item = BusinessItem.builder()
.name(request.getName())
.description(request.getDescription())
.status(request.getStatus())
.build();
return businessService.update(id, item)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
@Operation(summary = "删除业务项")
@DeleteMapping("/{id}")
public ResponseEntity<Void> delete(
@Parameter(description = "业务项 ID") @PathVariable Long id) {
boolean deleted = businessService.delete(id);
return deleted ? ResponseEntity.noContent().build()
: ResponseEntity.notFound().build();
}
// ---------- 请求体 DTO ----------
private record CreateRequest(
@NotBlank(message = "名称不能为空")
@Size(max = 100, message = "名称最长 100 个字符")
String name,
@Size(max = 500, message = "描述最长 500 个字符")
String description,
String status
) {}
private record UpdateRequest(
@NotBlank(message = "名称不能为空")
@Size(max = 100, message = "名称最长 100 个字符")
String name,
@Size(max = 500, message = "描述最长 500 个字符")
String description,
@NotBlank(message = "状态不能为空")
String status
) {}
}

View File

@ -0,0 +1,27 @@
package com.example.demo.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import java.util.Map;
/**
* 健康检查控制器
*/
@Tag(name = "健康检查", description = "系统健康状态接口")
@RestController
public class HealthController {
@Operation(summary = "健康检查", description = "返回服务运行状态和时间")
@GetMapping("/api/health")
public Map<String, Object> health() {
return Map.of(
"status", "UP",
"timestamp", LocalDateTime.now().toString(),
"service", "demo-service"
);
}
}

View File

@ -0,0 +1,30 @@
package com.example.demo.model;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 业务数据模型
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Schema(description = "业务数据项")
public class BusinessItem {
@Schema(description = "唯一标识", example = "1")
private Long id;
@Schema(description = "名称", example = "示例项目")
private String name;
@Schema(description = "描述信息", example = "这是一个示例描述")
private String description;
@Schema(description = "状态ENABLED / DISABLED", example = "ENABLED")
private String status;
}

View File

@ -0,0 +1,98 @@
package com.example.demo.service;
import com.example.demo.model.BusinessItem;
import jakarta.annotation.PostConstruct;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
/**
* 业务服务层 当前使用内存假数据
* <p>
* 扩展说明后续可注入 {@code BusinessRepository} 接口切换为数据库实现
* 只需将下面的 {@link ConcurrentHashMap} 操作替换为 Repository 调用即可
*/
@Service
public class BusinessService {
private final Map<Long, BusinessItem> store = new ConcurrentHashMap<>();
private final AtomicLong idGenerator = new AtomicLong(1);
@PostConstruct
public void init() {
// 初始化几条假数据
create(BusinessItem.builder()
.name("项目 Alpha")
.description("第一个示例项目")
.status("ENABLED")
.build());
create(BusinessItem.builder()
.name("项目 Beta")
.description("第二个示例项目")
.status("DISABLED")
.build());
create(BusinessItem.builder()
.name("项目 Gamma")
.description("第三个示例项目")
.status("ENABLED")
.build());
}
/**
* 查询所有业务项
*/
public List<BusinessItem> findAll() {
List<BusinessItem> list = new ArrayList<>(store.values());
Collections.sort(list, (a, b) -> Long.compare(a.getId(), b.getId()));
return list;
}
/**
* 根据 ID 查询
*/
public Optional<BusinessItem> findById(Long id) {
return Optional.ofNullable(store.get(id));
}
/**
* 新建业务项
*/
public BusinessItem create(BusinessItem item) {
Long id = idGenerator.getAndIncrement();
item.setId(id);
store.put(id, item);
return item;
}
/**
* 更新业务项全量替换
*/
public Optional<BusinessItem> update(Long id, BusinessItem item) {
if (!store.containsKey(id)) {
return Optional.empty();
}
item.setId(id);
store.put(id, item);
return Optional.of(item);
}
/**
* 删除业务项
*/
public boolean delete(Long id) {
return store.remove(id) != null;
}
/**
* 获取当前数据总量用于测试验证
*/
public int count() {
return store.size();
}
}

View File

@ -0,0 +1,30 @@
server:
port: 8080
spring:
application:
name: demo-service
# ========== 数据库配置(预留,当前未启用) ==========
# datasource:
# url: jdbc:h2:mem:demo
# driver-class-name: org.h2.Driver
# username: sa
# password:
# jpa:
# hibernate:
# ddl-auto: update
# show-sql: true
# ========== Knife4j / Swagger 配置 ==========
springdoc:
swagger-ui:
path: /swagger-ui/index.html
api-docs:
path: /v3/api-docs
packages-to-scan: com.example.demo.controller
# ========== 日志级别 ==========
logging:
level:
com.example.demo: debug

View File

@ -0,0 +1,118 @@
package com.example.demo;
import com.example.demo.model.BusinessItem;
import com.example.demo.service.BusinessService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.*;
/**
* BusinessService 单元测试
*/
@SpringBootTest
class BusinessServiceTest {
@Autowired
private BusinessService businessService;
@BeforeEach
void setUp() {
// 每次测试前重新初始化确保数据干净
// 由于 @PostConstruct init() 已在启动时执行这里不再重复调用
}
@Test
void testFindAll_shouldReturnInitialData() {
List<BusinessItem> items = businessService.findAll();
assertEquals(3, items.size(), "初始化应包含 3 条假数据");
}
@Test
void testFindById_existingId_shouldReturnItem() {
// 先获取所有取第一个的 ID
List<BusinessItem> items = businessService.findAll();
assertFalse(items.isEmpty());
Long firstId = items.get(0).getId();
Optional<BusinessItem> found = businessService.findById(firstId);
assertTrue(found.isPresent());
assertEquals(firstId, found.get().getId());
}
@Test
void testFindById_nonExistingId_shouldReturnEmpty() {
Optional<BusinessItem> found = businessService.findById(999L);
assertFalse(found.isPresent());
}
@Test
void testCreate_shouldAddItem() {
BusinessItem newItem = BusinessItem.builder()
.name("测试项目")
.description("由测试创建")
.status("ENABLED")
.build();
BusinessItem created = businessService.create(newItem);
assertNotNull(created.getId());
assertEquals("测试项目", created.getName());
// 验证总数增加
assertEquals(4, businessService.count());
}
@Test
void testUpdate_existingId_shouldUpdateItem() {
List<BusinessItem> items = businessService.findAll();
assertFalse(items.isEmpty());
Long id = items.get(0).getId();
BusinessItem updateData = BusinessItem.builder()
.name("更新后的名称")
.description("更新后的描述")
.status("DISABLED")
.build();
Optional<BusinessItem> updated = businessService.update(id, updateData);
assertTrue(updated.isPresent());
assertEquals("更新后的名称", updated.get().getName());
assertEquals("DISABLED", updated.get().getStatus());
}
@Test
void testUpdate_nonExistingId_shouldReturnEmpty() {
BusinessItem updateData = BusinessItem.builder()
.name("不存在")
.description("")
.status("ENABLED")
.build();
Optional<BusinessItem> updated = businessService.update(999L, updateData);
assertFalse(updated.isPresent());
}
@Test
void testDelete_existingId_shouldRemoveItem() {
List<BusinessItem> items = businessService.findAll();
assertFalse(items.isEmpty());
Long id = items.get(0).getId();
boolean deleted = businessService.delete(id);
assertTrue(deleted);
// 验证总数减少
assertEquals(2, businessService.count());
}
@Test
void testDelete_nonExistingId_shouldReturnFalse() {
boolean deleted = businessService.delete(999L);
assertFalse(deleted);
}
}