生成 C++ 代码工程
This commit is contained in:
parent
bba7a6ac13
commit
4bc29c9a7d
61
README.md
61
README.md
|
|
@ -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 相关配置注释
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -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>
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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")));
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
) {}
|
||||
}
|
||||
|
|
@ -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"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue