This commit is contained in:
CloseIn
2026-05-07 15:54:19 +08:00
commit ac5a30844e
18 changed files with 461 additions and 0 deletions
+33
View File
@@ -0,0 +1,33 @@
HELP.MD
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/
+15
View File
@@ -0,0 +1,15 @@
FROM eclipse-temurin:25-jre-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY target/gmp-mock-service.jar app.jar
RUN chown -R appuser:appgroup /app
USER appuser
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
+15
View File
@@ -0,0 +1,15 @@
Write-Host "===== 开始构建 gmp-mock-service =====" -ForegroundColor Cyan
mvn clean package -DskipTests
if ($LASTEXITCODE -eq 0) {
Write-Host "===== 构建成功 =====" -ForegroundColor Green
$jarPath = "target\gmp-mock-service.jar"
if (Test-Path $jarPath) {
$size = [math]::Round((Get-Item $jarPath).Length / 1MB, 2)
Write-Host "JAR 文件: $jarPath ($size MB)" -ForegroundColor Green
}
} else {
Write-Host "===== 构建失败 =====" -ForegroundColor Red
exit 1
}
+19
View File
@@ -0,0 +1,19 @@
#!/bin/bash
set -e
echo "===== 开始构建 gmp-mock-service ====="
mvn clean package -DskipTests
if [ $? -eq 0 ]; then
echo "===== 构建成功 ====="
JAR_PATH="target/gmp-mock-service.jar"
if [ -f "$JAR_PATH" ]; then
SIZE=$(du -h "$JAR_PATH" | cut -f1)
echo "JAR 文件: $JAR_PATH ($SIZE)"
fi
else
echo "===== 构建失败 ====="
exit 1
fi
+14
View File
@@ -0,0 +1,14 @@
$jarPath = "target\gmp-mock-service.jar"
if (-not (Test-Path $jarPath)) {
Write-Host "JAR 文件不存在,请先执行 build.ps1 进行构建" -ForegroundColor Red
exit 1
}
$env:JAVA_OPTS = $env:JAVA_OPTS ?? "-Xms256m -Xmx512m"
Write-Host "===== 启动 gmp-mock-service =====" -ForegroundColor Cyan
Write-Host "端口: 8080" -ForegroundColor Cyan
Write-Host "接口: POST http://localhost:8080/api/docx/export" -ForegroundColor Cyan
java $env:JAVA_OPTS -jar $jarPath
+16
View File
@@ -0,0 +1,16 @@
#!/bin/bash
JAR_PATH="target/gmp-mock-service.jar"
if [ ! -f "$JAR_PATH" ]; then
echo "JAR 文件不存在,请先执行 build.sh 进行构建"
exit 1
fi
JAVA_OPTS="${JAVA_OPTS:--Xms256m -Xmx512m}"
echo "===== 启动 gmp-mock-service ====="
echo "端口: 8080"
echo "接口: POST http://localhost:8080/api/docx/export"
java $JAVA_OPTS -jar "$JAR_PATH"
+60
View File
@@ -0,0 +1,60 @@
<?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.5.1</version>
<relativePath/>
</parent>
<groupId>com.gmp</groupId>
<artifactId>gmp-service</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>gmp-mock-service</name>
<description>GMP Mock Service - 提供简单接口的模拟服务</description>
<properties>
<java.version>25</java.version>
<poi.version>5.4.0</poi.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,12 @@
package com.gmp.mock;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MockApplication {
public static void main(String[] args) {
SpringApplication.run(MockApplication.class, args);
}
}
@@ -0,0 +1,36 @@
package com.gmp.mock.controller;
import java.io.IOException;
import jakarta.validation.Valid;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.gmp.mock.dto.ApiResponse;
import com.gmp.mock.dto.DocxExportData;
import com.gmp.mock.dto.DocxExportRequest;
import com.gmp.mock.service.DocxService;
@RestController
@RequestMapping("/api/docx")
public class DocxController {
private final DocxService docxService;
public DocxController(DocxService docxService) {
this.docxService = docxService;
}
@PostMapping("/export")
public ResponseEntity<ApiResponse<DocxExportData>> exportDocx(@Valid @RequestBody DocxExportRequest request) throws IOException {
DocxExportData data = docxService.export(request.getExportId());
if (data == null) {
return ResponseEntity.ok(ApiResponse.error(404, "模板不存在"));
}
return ResponseEntity.ok(ApiResponse.success(data));
}
}
@@ -0,0 +1,50 @@
package com.gmp.mock.dto;
public class ApiResponse<T> {
private int code;
private T data;
private String msg;
private ApiResponse(int code, T data, String msg) {
this.code = code;
this.data = data;
this.msg = msg;
}
public static <T> ApiResponse<T> success(T data) {
return new ApiResponse<>(0, data, "success");
}
public static <T> ApiResponse<T> success(T data, String msg) {
return new ApiResponse<>(0, data, msg);
}
public static <T> ApiResponse<T> error(int code, String msg) {
return new ApiResponse<>(code, null, msg);
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
@@ -0,0 +1,28 @@
package com.gmp.mock.dto;
public class DocxExportData {
private String fileName;
private String fileBase64;
public DocxExportData(String fileName, String fileBase64) {
this.fileName = fileName;
this.fileBase64 = fileBase64;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getFileBase64() {
return fileBase64;
}
public void setFileBase64(String fileBase64) {
this.fileBase64 = fileBase64;
}
}
@@ -0,0 +1,31 @@
package com.gmp.mock.dto;
import java.util.Map;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
public class DocxExportRequest {
@NotBlank(message = "exportId 不能为空")
private String exportId;
@NotNull(message = "businessData 不能为空")
private Map<String, Object> businessData;
public String getExportId() {
return exportId;
}
public void setExportId(String exportId) {
this.exportId = exportId;
}
public Map<String, Object> getBusinessData() {
return businessData;
}
public void setBusinessData(Map<String, Object> businessData) {
this.businessData = businessData;
}
}
@@ -0,0 +1,22 @@
package com.gmp.mock.handler;
import java.util.stream.Collectors;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import com.gmp.mock.dto.ApiResponse;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ApiResponse<Void>> handleValidation(MethodArgumentNotValidException ex) {
String message = ex.getBindingResult().getFieldErrors().stream()
.map(e -> e.getDefaultMessage())
.collect(Collectors.joining("; "));
return ResponseEntity.ok(ApiResponse.error(400, message));
}
}
@@ -0,0 +1,37 @@
package com.gmp.mock.service;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.springframework.stereotype.Service;
import com.gmp.mock.dto.DocxExportData;
import com.gmp.mock.template.TemplateProvider;
import com.gmp.mock.template.TemplateRegistry;
@Service
public class DocxService {
private final TemplateRegistry templateRegistry;
public DocxService(TemplateRegistry templateRegistry) {
this.templateRegistry = templateRegistry;
}
public DocxExportData export(String exportId) throws IOException {
TemplateProvider provider = templateRegistry.get(exportId);
if (provider == null) {
return null;
}
try (XWPFDocument document = new XWPFDocument();
ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
provider.generate(document);
document.write(baos);
String base64 = Base64.getEncoder().encodeToString(baos.toByteArray());
return new DocxExportData(provider.getFileName(), base64);
}
}
}
@@ -0,0 +1,14 @@
package com.gmp.mock.template;
import java.io.IOException;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
public interface TemplateProvider {
String getTemplateId();
String getFileName();
void generate(XWPFDocument document) throws IOException;
}
@@ -0,0 +1,27 @@
package com.gmp.mock.template;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.springframework.stereotype.Component;
@Component
public class TemplateRegistry {
private final Map<String, TemplateProvider> providers;
public TemplateRegistry(List<TemplateProvider> providers) {
this.providers = providers.stream()
.collect(Collectors.toMap(TemplateProvider::getTemplateId, Function.identity()));
}
public TemplateProvider get(String templateId) {
return providers.get(templateId);
}
public boolean exists(String templateId) {
return providers.containsKey(templateId);
}
}
@@ -0,0 +1,26 @@
package com.gmp.mock.template.annualReport;
import java.io.IOException;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.springframework.stereotype.Component;
import com.gmp.mock.template.TemplateProvider;
@Component
public class AnnualReportProvider implements TemplateProvider {
@Override
public String getTemplateId() {
return "annualReport";
}
@Override
public String getFileName() {
return "annualReport.docx";
}
@Override
public void generate(XWPFDocument document) throws IOException {
}
}
+6
View File
@@ -0,0 +1,6 @@
server:
port: 8080
spring:
application:
name: gmp-mock-service