格式修改

This commit is contained in:
2026-08-05 10:35:07 +08:00
parent 81c9c92f5d
commit 496fc58a90
241 changed files with 5600 additions and 2088 deletions
@@ -1,16 +1,14 @@
package com.baiyue.integration.provider;
import jakarta.annotation.Resource;
import com.baiyue.integration.config.IntegrationProperties;
import com.baiyue.integration.dto.ProviderStatus;
import org.springframework.stereotype.Component;
@Component
public class AmazonLogisticsAdapter implements IntegrationProviderAdapter {
private final IntegrationProperties properties;
public AmazonLogisticsAdapter(IntegrationProperties properties) {
this.properties = properties;
}
@Resource private IntegrationProperties properties;
@Override
public ProviderStatus status() {
@@ -1,16 +1,14 @@
package com.baiyue.integration.provider;
import jakarta.annotation.Resource;
import com.baiyue.integration.config.IntegrationProperties;
import com.baiyue.integration.dto.ProviderStatus;
import org.springframework.stereotype.Component;
@Component
public class BaiduOcrAdapter implements IntegrationProviderAdapter {
private final IntegrationProperties properties;
public BaiduOcrAdapter(IntegrationProperties properties) {
this.properties = properties;
}
@Resource private IntegrationProperties properties;
@Override
public ProviderStatus status() {
@@ -1,5 +1,8 @@
package com.baiyue.integration.provider.ocr;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import com.baiyue.common.core.api.ResultCode;
import com.baiyue.common.core.exception.BizException;
import com.baiyue.integration.config.IntegrationProperties;
@@ -31,18 +34,19 @@ public class BaiduMeterClient {
private static final int QPS_LIMIT_ERROR_CODE = 18;
private static final long INITIAL_RETRY_DELAY_MILLIS = 1_000;
private final IntegrationProperties.BaiduOcr config;
private final ObjectMapper objectMapper;
private final HttpClient httpClient;
@Resource private IntegrationProperties properties;
@Resource private ObjectMapper objectMapper;
private IntegrationProperties.BaiduOcr config;
private HttpClient httpClient;
private final Object requestRateLock = new Object();
private volatile CachedToken cachedToken;
private long nextRequestAtMillis;
public BaiduMeterClient(IntegrationProperties properties, ObjectMapper objectMapper) {
this.config = properties.baiduOcr();
this.objectMapper = objectMapper;
this.httpClient = HttpClient.newBuilder()
@PostConstruct
void initializeClient() {
config = properties.baiduOcr();
httpClient = HttpClient.newBuilder()
.connectTimeout(config == null ? java.time.Duration.ofSeconds(10)
: config.effectiveConnectTimeout())
.build();
@@ -1,5 +1,7 @@
package com.baiyue.integration.security;
import jakarta.annotation.PostConstruct;
import com.baiyue.common.core.api.ResultCode;
import com.baiyue.common.core.exception.BizException;
import org.springframework.beans.factory.annotation.Value;
@@ -10,9 +12,11 @@ import java.security.MessageDigest;
@Component
public class InternalServiceTokenGuard {
private final byte[] expectedToken;
@Value("${baiyue.security.internal-service-token}") private String token;
private byte[] expectedToken;
public InternalServiceTokenGuard(@Value("${baiyue.security.internal-service-token}") String token) {
@PostConstruct
void initializeToken() {
if (token == null || token.getBytes(StandardCharsets.UTF_8).length < 32) {
throw new IllegalStateException("INTERNAL_SERVICE_TOKEN 至少需要 32 字节");
}
@@ -1,5 +1,7 @@
package com.baiyue.integration.service;
import jakarta.annotation.Resource;
import com.baiyue.integration.dto.ProviderStatus;
import com.baiyue.integration.provider.IntegrationProviderAdapter;
import org.springframework.stereotype.Service;
@@ -8,11 +10,7 @@ import java.util.List;
@Service
public class ProviderStatusService {
private final List<IntegrationProviderAdapter> adapters;
public ProviderStatusService(List<IntegrationProviderAdapter> adapters) {
this.adapters = adapters;
}
@Resource private List<IntegrationProviderAdapter> adapters;
public List<ProviderStatus> providers() {
return adapters.stream().map(IntegrationProviderAdapter::status).toList();
@@ -1,5 +1,7 @@
package com.baiyue.integration.service.ocr;
import jakarta.annotation.Resource;
import com.baiyue.common.core.api.ResultCode;
import com.baiyue.common.core.exception.BizException;
import com.baiyue.integration.config.IntegrationProperties;
@@ -33,28 +35,14 @@ import java.util.stream.Stream;
public class WeightOcrBatchService {
private static final Set<String> SUPPORTED_EXTENSIONS = Set.of("jpg", "jpeg", "png", "bmp");
private final IntegrationProperties properties;
private final WeightOcrStoragePolicy storagePolicy;
private final ImageCropper imageCropper;
private final BaiduMeterClient baiduMeterClient;
private final WeightCandidateSelector candidateSelector;
private final ObjectMapper objectMapper;
@Resource private IntegrationProperties properties;
@Resource private WeightOcrStoragePolicy storagePolicy;
@Resource private ImageCropper imageCropper;
@Resource private BaiduMeterClient baiduMeterClient;
@Resource private WeightCandidateSelector candidateSelector;
@Resource private ObjectMapper objectMapper;
private final Semaphore batchSlot = new Semaphore(1);
public WeightOcrBatchService(IntegrationProperties properties,
WeightOcrStoragePolicy storagePolicy,
ImageCropper imageCropper,
BaiduMeterClient baiduMeterClient,
WeightCandidateSelector candidateSelector,
ObjectMapper objectMapper) {
this.properties = properties;
this.storagePolicy = storagePolicy;
this.imageCropper = imageCropper;
this.baiduMeterClient = baiduMeterClient;
this.candidateSelector = candidateSelector;
this.objectMapper = objectMapper;
}
public WeightOcrBatchResult recognize(WeightOcrBatchRequest request) throws IOException {
baiduMeterClient.validateReady();
if (!batchSlot.tryAcquire()) {
@@ -1,5 +1,7 @@
package com.baiyue.integration.service.ocr;
import jakarta.annotation.Resource;
import com.baiyue.common.core.api.ResultCode;
import com.baiyue.common.core.exception.BizException;
import com.baiyue.integration.config.IntegrationProperties;
@@ -19,13 +21,8 @@ import java.util.UUID;
@Service
public class WeightOcrSingleImageService {
private static final Set<String> CONTENT_TYPES = Set.of("image/jpeg", "image/png", "image/bmp");
private final IntegrationProperties properties;
private final WeightOcrBatchService batches;
public WeightOcrSingleImageService(IntegrationProperties properties, WeightOcrBatchService batches) {
this.properties = properties;
this.batches = batches;
}
@Resource private IntegrationProperties properties;
@Resource private WeightOcrBatchService batches;
public WeightOcrImageResult recognize(MultipartFile file) throws IOException {
IntegrationProperties.BaiduOcr config = properties.baiduOcr();
@@ -1,5 +1,7 @@
package com.baiyue.integration.service.ocr;
import jakarta.annotation.Resource;
import com.baiyue.common.core.api.ResultCode;
import com.baiyue.common.core.exception.BizException;
import com.baiyue.integration.config.IntegrationProperties;
@@ -14,11 +16,7 @@ import java.nio.file.Path;
*/
@Component
public class WeightOcrStoragePolicy {
private final IntegrationProperties properties;
public WeightOcrStoragePolicy(IntegrationProperties properties) {
this.properties = properties;
}
@Resource private IntegrationProperties properties;
public BatchPaths resolve(String inputValue, String outputValue, String batchId) throws IOException {
IntegrationProperties.BaiduOcr config = requireConfig();
@@ -72,6 +72,6 @@ logging:
rollingpolicy:
file-name-pattern: "${LOGGING_ROLLING_FILE_NAME_PATTERN:${LOG_PATH:./logs}/${spring.application.name}.%d{yyyy-MM-dd}.%i.log.gz}"
max-file-size: "${LOGGING_ROLLING_MAX_FILE_SIZE:100MB}"
max-history: "${LOGGING_ROLLING_MAX_HISTORY:30}"
max-history: "${LOGGING_ROLLING_MAX_HISTORY:7}"
total-size-cap: "${LOGGING_ROLLING_TOTAL_SIZE_CAP:5GB}"
clean-history-on-start: "${LOGGING_ROLLING_CLEAN_HISTORY_ON_START:false}"
@@ -6,10 +6,15 @@ import com.baiyue.integration.dto.ocr.WeightOcrBatchRequest;
import com.baiyue.integration.dto.ocr.WeightOcrImageResult.Status;
import com.baiyue.integration.provider.ocr.BaiduMeterClient;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.springframework.util.unit.DataSize;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import javax.imageio.ImageIO;
import java.awt.Color;
@@ -26,9 +31,14 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@DisplayName("OCR 重量批量识别功能")
@SpringJUnitConfig(classes = {WeightOcrBatchService.class, WeightOcrStoragePolicy.class,
ImageCropper.class, WeightCandidateSelector.class, WeightOcrBatchServiceTest.TestConfig.class})
class WeightOcrBatchServiceTest {
@TempDir
Path tempDirectory;
@MockBean private IntegrationProperties properties;
@MockBean private BaiduMeterClient client;
@Resource private WeightOcrBatchService service;
@Test
void completesBatchAndWritesArtifactsWithoutCallingRealProvider() throws Exception {
@@ -43,15 +53,10 @@ class WeightOcrBatchServiceTest {
}
ImageIO.write(image, "png", batchInput.resolve("weight.png").toFile());
IntegrationProperties properties = properties(inputRoot, outputRoot);
BaiduMeterClient client = mock(BaiduMeterClient.class);
when(properties.baiduOcr()).thenReturn(properties(inputRoot, outputRoot).baiduOcr());
when(client.recognize(any())).thenReturn(new BaiduMeterClient.MeterResponse(
"{\"words_result\":[]}",
List.of(new OcrCandidate("12.35", 0.98, 10, 10, 80, 30))));
ObjectMapper objectMapper = new ObjectMapper().findAndRegisterModules();
WeightOcrBatchService service = new WeightOcrBatchService(
properties, new WeightOcrStoragePolicy(properties), new ImageCropper(), client,
new WeightCandidateSelector(), objectMapper);
var result = service.recognize(new WeightOcrBatchRequest("batch-a", null, null, null, false));
@@ -72,4 +77,12 @@ class WeightOcrBatchServiceTest {
50, Duration.ZERO, 0);
return new IntegrationProperties(baidu, null);
}
@Configuration
static class TestConfig {
@Bean
ObjectMapper objectMapper() {
return new ObjectMapper().findAndRegisterModules();
}
}
}
@@ -7,6 +7,9 @@ import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.springframework.util.unit.DataSize;
import jakarta.annotation.Resource;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
import java.net.URI;
import java.nio.file.Files;
@@ -15,17 +18,21 @@ import java.time.Duration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.when;
@DisplayName("OCR 文件存储策略功能")
@SpringJUnitConfig(WeightOcrStoragePolicy.class)
class WeightOcrStoragePolicyTest {
@TempDir
Path tempDirectory;
@MockBean private IntegrationProperties properties;
@Resource private WeightOcrStoragePolicy policy;
@Test
void resolvesDirectoriesInsideConfiguredRoots() throws Exception {
Path input = Files.createDirectories(tempDirectory.resolve("input/batch-a"));
Path outputRoot = tempDirectory.resolve("output");
WeightOcrStoragePolicy policy = new WeightOcrStoragePolicy(properties(input.getParent(), outputRoot));
when(properties.baiduOcr()).thenReturn(config(input.getParent(), outputRoot));
WeightOcrStoragePolicy.BatchPaths paths = policy.resolve("batch-a", null, "batch-id");
@@ -38,7 +45,7 @@ class WeightOcrStoragePolicyTest {
Path inputRoot = Files.createDirectories(tempDirectory.resolve("input"));
Path outputRoot = tempDirectory.resolve("output");
Path outside = Files.createDirectories(tempDirectory.resolve("outside"));
WeightOcrStoragePolicy policy = new WeightOcrStoragePolicy(properties(inputRoot, outputRoot));
when(properties.baiduOcr()).thenReturn(config(inputRoot, outputRoot));
assertThatThrownBy(() -> policy.resolve(outside.toString(), null, "batch-id"))
.isInstanceOfSatisfying(BizException.class,
@@ -48,12 +55,12 @@ class WeightOcrStoragePolicyTest {
exception -> assertThat(exception.getResultCode()).isEqualTo(ResultCode.FORBIDDEN));
}
private IntegrationProperties properties(Path inputRoot, Path outputRoot) {
private IntegrationProperties.BaiduOcr config(Path inputRoot, Path outputRoot) {
IntegrationProperties.BaiduOcr baidu = new IntegrationProperties.BaiduOcr(
true, "key", "secret", URI.create("https://example.com/token"),
URI.create("https://example.com/meter"), Duration.ofSeconds(1), Duration.ofSeconds(1),
inputRoot, outputRoot, DataSize.ofMegabytes(3), 40_000_000L,
50, Duration.ZERO, 0);
return new IntegrationProperties(baidu, null);
return baidu;
}
}