README.md (avec badge CI) Remplace et par tes valeurs (ex. dominique-quevy et pdfbox-gateway). https://github.com///actions/workflows/ci.yml/badge.svg?branch=main](https://github.com///actions/workflows/ci.yml)
REST API Java 21 / Spring Boot 3 encapsulant Apache PDFBox :
- Extraction texte, rendu PNG, validation PDF/A (Preflight),
- Signature PKCS#7 detached avec keystore PKCS#12 (BouncyCastle),
- Metadata (DocumentInformation + XMP via xmpbox),
- Mode worker (file d’attente simple),
- Upload multipart (et option streaming via Apache Commons FileUpload),
- CI GitHub Actions (Maven + tests + Gatling + k6),
- Helm chart pour OpenShift + Service Mesh (mTLS STRICT, OIDC JWT en mesh).
mvn clean verify
mvn spring-boot:run
# http://localhost:8080/actuator/health
Endpoints principaux
• POST /api/v1/upload/extract/text (multipart, part file) → texte
• POST /api/v1/upload/render/png?dpi=150&pageIndex=0 → image (Base64)
• POST /api/v1/upload/validate/pdfa → VALID_PDF_A / INVALID_PDF_A: ...
• POST /api/v1/upload/metadata/set?title=...&author=... → PDF modifié (Base64)
• POST /api/v1/upload/sign/pkcs12?... → PDF signé (Base64)
• Worker : POST /api/v1/worker/submit?op=..., GET /status/{id}, GET /result/{id}
Build Docker
mvn -DskipTests package
docker build -t pdfbox-gateway:local .
docker run --rm -p 8080:8080 pdfbox-gateway:local
Tests de charge
• Gatling : mvn -DskipTests gatling:test
• k6 : k6 run --vus 1 --duration 10s --cwd loadtest/k6 loadtest/k6/upload_extract.js
---
## 2) `pom.xml` (Java 21, Spring Boot 3, PDFBox 3, Preflight, XMP, tools, BouncyCastle, Gatling)
> **Important** : on utilise `pdfbox-tools` (pour `ImageIOUtil`) et `preflight`.
> JUnit 5 est activé par défaut. Le plugin Gatling + Scala est configuré.
```xml
<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>
<groupId>com.example</groupId>
<artifactId>pdfbox-gateway</artifactId>
<version>1.0.0-SNAPSHOT</version>
<name>pdfbox-gateway</name>
<description>Spring Boot + PDFBox gateway</description>
<properties>
<java.version>21</java.version>
<spring-boot.version>3.3.4</spring-boot.version>
<pdfbox.version>3.0.5</pdfbox.version>
<gatling.plugin.version>4.6.0</gatling.plugin.version>
<scala.maven.plugin.version>4.10.0</scala.maven.plugin.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>${java.version}</maven.compiler.release>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Spring -->
<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.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- Apache PDFBox -->
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>${pdfbox.version}</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox-tools</artifactId>
<version>${pdfbox.version}</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>preflight</artifactId>
<version>${pdfbox.version}</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>xmpbox</artifactId>
<version>${pdfbox.version}</version>
</dependency>
<!-- Upload streaming -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.5</version>
</dependency>
<!-- BouncyCastle CMS (signature PKCS#7) -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId>
<version>1.78.1</version>
</dependency>
<!-- Tests -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.26.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Spring Boot -->
<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>
<!-- Compiler -->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<release>${java.version}</release>
</configuration>
</plugin>
<!-- Surefire/Failsafe -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.2.5</version>
<configuration>
<includes>
<include>**/*IT.java</include>
<include>**/*ITCase.java</include>
</includes>
</configuration>
</plugin>
<!-- Gatling -->
<plugin>
<groupId>io.gatling</groupId>
<artifactId>gatling-maven-plugin</artifactId>
<version>${gatling.plugin.version}</version>
<executions>
<execution>
<goals><goal>test</goal></goals>
</execution>
</executions>
</plugin>
<!-- Scala (pour simulations Gatling Scala) -->
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>${scala.maven.plugin.version}</version>
<executions>
<execution>
<id>scala-compile-first</id>
<phase>process-resources</phase>
<goals><goal>compile</goal></goals>
</execution>
<execution>
<id>scala-test-compile</id>
<phase>process-test-resources</phase>
<goals><goal>testCompile</goal></goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>