添加Apache Commons Codec依赖以支持SHA-256和十六进制工具,并在application.yml中新增外部脚本配置及链接过期时间设置。同时,删除不再使用的类文件以清理项目结构。

This commit is contained in:
zyh
2025-08-24 20:46:35 +08:00
parent c3762f985e
commit 3f01d8590a
53 changed files with 428 additions and 10 deletions

View File

@@ -0,0 +1,48 @@
package com.gameplatform.server.controller.link;
import com.gameplatform.server.model.dto.link.LinkGenerateRequest;
import com.gameplatform.server.model.dto.link.LinkGenerateResponse;
import com.gameplatform.server.service.link.LinkGenerationService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Mono;
@RestController
@RequestMapping("/api/link")
@Tag(name = "链接管理", description = "生成链接与二维码代理")
public class LinkController {
private final LinkGenerationService linkGenerationService;
public LinkController(LinkGenerationService linkGenerationService) {
this.linkGenerationService = linkGenerationService;
}
@PostMapping("/generate")
@ResponseStatus(HttpStatus.CREATED)
@Operation(summary = "生成链接批次", description = "times * perTimeQuantity = 目标点数;代理需扣点,管理员不扣")
public Mono<LinkGenerateResponse> generate(@Valid @RequestBody LinkGenerateRequest req,
@RequestHeader(value = "X-Operator-Id", required = false) Long operatorId,
@RequestHeader(value = "X-Operator-Type", required = false) String operatorType) {
// 暂时用两个 Header 传操作者信息;后续接入 JWT 解析
Long targetAccountId = req.getAgentAccountId() != null ? req.getAgentAccountId() : operatorId;
return linkGenerationService.generateLinks(operatorId, safeUpper(operatorType), targetAccountId,
defaultInt(req.getTimes(), 0), defaultInt(req.getPerTimeQuantity(), 0))
.map(r -> {
LinkGenerateResponse resp = new LinkGenerateResponse();
resp.setBatchId(r.getBatchId());
resp.setDeductPoints(r.getNeedPoints());
resp.setExpireAt(r.getExpireAt());
resp.setCodeNos(r.getCodeNos());
return resp;
});
}
private static String safeUpper(String s) { return s == null ? null : s.toUpperCase(); }
private static int defaultInt(Integer v, int d) { return v == null ? d : v; }
}

View File

@@ -0,0 +1,41 @@
package com.gameplatform.server.controller.link;
import com.gameplatform.server.service.external.ScriptClient;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.CacheControl;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
import java.util.concurrent.TimeUnit;
@RestController
@RequestMapping("/api/link")
@Tag(name = "二维码代理", description = "转发脚本端的二维码图片,避免混合内容")
public class QrProxyController {
private final ScriptClient scriptClient;
public QrProxyController(ScriptClient scriptClient) {
this.scriptClient = scriptClient;
}
@GetMapping(value = "/{codeNo}/qr.png", produces = MediaType.IMAGE_PNG_VALUE)
@Operation(summary = "二维码图片代理")
public Mono<ResponseEntity<byte[]>> qr(@PathVariable("codeNo") String codeNo) {
String path = "/" + codeNo + "/二维码.png";
return scriptClient.getQrPng(path)
.map(bytes -> ResponseEntity.ok()
.contentType(MediaType.IMAGE_PNG)
.cacheControl(CacheControl.maxAge(30, TimeUnit.SECONDS).cachePublic())
.header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=qr.png")
.body(bytes));
}
}