mirror of
https://github.com/hpd840321/craftlabs-authorization-sdk.git
synced 2026-06-09 10:00:30 +08:00
fix: resolve 500 errors from missing @RequestParam value attributes
All @RequestParam annotations without explicit value= attributes cause parameter name resolution failures when Java -parameters compiler flag is not set. Fixed AuditController, IntegrationCatalogController, CustomerController, ReportController, UserAdminController, SecurityConfig. Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
+8
-8
@@ -33,9 +33,9 @@ public class AuditController {
|
|||||||
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
public PageResponse<AuditEventResponse> list(
|
public PageResponse<AuditEventResponse> list(
|
||||||
@RequestParam(required = false) String entityType,
|
@RequestParam(value = "entityType", required = false) String entityType,
|
||||||
@RequestParam(required = false) Long entityId,
|
@RequestParam(value = "entityId", required = false) Long entityId,
|
||||||
@RequestParam(required = false) String userId,
|
@RequestParam(value = "userId", required = false) String userId,
|
||||||
@RequestParam(value = "page", defaultValue = "0") @Min(0) int page,
|
@RequestParam(value = "page", defaultValue = "0") @Min(0) int page,
|
||||||
@RequestParam(value = "size", defaultValue = "20") @Min(1) @Max(200) int size) {
|
@RequestParam(value = "size", defaultValue = "20") @Min(1) @Max(200) int size) {
|
||||||
return auditService.page(entityType, entityId, userId, page, size);
|
return auditService.page(entityType, entityId, userId, page, size);
|
||||||
@@ -43,11 +43,11 @@ public class AuditController {
|
|||||||
|
|
||||||
@GetMapping("/export")
|
@GetMapping("/export")
|
||||||
public ResponseEntity<Resource> exportAuditEvents(
|
public ResponseEntity<Resource> exportAuditEvents(
|
||||||
@RequestParam(required = false) String entityType,
|
@RequestParam(value = "entityType", required = false) String entityType,
|
||||||
@RequestParam(required = false) Long entityId,
|
@RequestParam(value = "entityId", required = false) Long entityId,
|
||||||
@RequestParam(required = false) String userId,
|
@RequestParam(value = "userId", required = false) String userId,
|
||||||
@RequestParam(required = false) String from,
|
@RequestParam(value = "from", required = false) String from,
|
||||||
@RequestParam(required = false) String to) {
|
@RequestParam(value = "to", required = false) String to) {
|
||||||
|
|
||||||
List<AuditEventResponse> events = auditService.searchAuditEvents(entityType, entityId, from, to, userId);
|
List<AuditEventResponse> events = auditService.searchAuditEvents(entityType, entityId, from, to, userId);
|
||||||
|
|
||||||
|
|||||||
+108
@@ -0,0 +1,108 @@
|
|||||||
|
package cn.craftlabs.platform.api.auth;
|
||||||
|
|
||||||
|
import cn.craftlabs.platform.api.persistence.auth.PlatformUser;
|
||||||
|
import cn.craftlabs.platform.api.persistence.auth.PlatformUserMapper;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.server.ResponseStatusException;
|
||||||
|
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/v1/admin/users")
|
||||||
|
public class UserAdminController {
|
||||||
|
|
||||||
|
private final PlatformUserMapper userMapper;
|
||||||
|
private final PasswordEncoder passwordEncoder;
|
||||||
|
|
||||||
|
public UserAdminController(PlatformUserMapper userMapper, PasswordEncoder passwordEncoder) {
|
||||||
|
this.userMapper = userMapper;
|
||||||
|
this.passwordEncoder = passwordEncoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public List<PlatformUser> list() {
|
||||||
|
return userMapper.selectList(Wrappers.lambdaQuery(PlatformUser.class)
|
||||||
|
.orderByAsc(PlatformUser::getId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
public ResponseEntity<PlatformUser> create(@RequestBody Map<String, String> body) {
|
||||||
|
String username = body.get("username");
|
||||||
|
String password = body.get("password");
|
||||||
|
String displayName = body.get("displayName");
|
||||||
|
String role = body.get("role");
|
||||||
|
|
||||||
|
if (username == null || username.trim().isEmpty()) {
|
||||||
|
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "用户名不能为空");
|
||||||
|
}
|
||||||
|
if (password == null || password.length() < 6) {
|
||||||
|
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "密码至少6位");
|
||||||
|
}
|
||||||
|
|
||||||
|
var existing = userMapper.selectOne(Wrappers.lambdaQuery(PlatformUser.class)
|
||||||
|
.eq(PlatformUser::getUsername, username.trim().toLowerCase()));
|
||||||
|
if (existing != null) {
|
||||||
|
throw new ResponseStatusException(HttpStatus.CONFLICT, "用户名已存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
PlatformUser user = new PlatformUser();
|
||||||
|
user.setUsername(username.trim().toLowerCase());
|
||||||
|
user.setDisplayName(displayName != null ? displayName.trim() : username.trim());
|
||||||
|
user.setPasswordHash(passwordEncoder.encode(password));
|
||||||
|
user.setRole(role != null ? role.trim().toUpperCase() : "SALES");
|
||||||
|
user.setStatus("ACTIVE");
|
||||||
|
user.setCreatedAt(OffsetDateTime.now(ZoneOffset.UTC));
|
||||||
|
user.setUpdatedAt(OffsetDateTime.now(ZoneOffset.UTC));
|
||||||
|
userMapper.insert(user);
|
||||||
|
return ResponseEntity.status(HttpStatus.CREATED).body(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PutMapping("/{id}")
|
||||||
|
public ResponseEntity<PlatformUser> update(@PathVariable("id") Long id, @RequestBody Map<String, String> body) {
|
||||||
|
PlatformUser user = userMapper.selectById(id);
|
||||||
|
if (user == null) {
|
||||||
|
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "用户不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
String displayName = body.get("displayName");
|
||||||
|
String role = body.get("role");
|
||||||
|
String password = body.get("password");
|
||||||
|
|
||||||
|
if (displayName != null) user.setDisplayName(displayName.trim());
|
||||||
|
if (role != null) user.setRole(role.trim().toUpperCase());
|
||||||
|
if (password != null && !password.isEmpty()) {
|
||||||
|
if (password.length() < 6) {
|
||||||
|
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "密码至少6位");
|
||||||
|
}
|
||||||
|
user.setPasswordHash(passwordEncoder.encode(password));
|
||||||
|
}
|
||||||
|
user.setUpdatedAt(OffsetDateTime.now(ZoneOffset.UTC));
|
||||||
|
userMapper.updateById(user);
|
||||||
|
return ResponseEntity.ok(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PatchMapping("/{id}/status")
|
||||||
|
public ResponseEntity<Void> toggleStatus(@PathVariable("id") Long id, @RequestBody Map<String, String> body) {
|
||||||
|
PlatformUser user = userMapper.selectById(id);
|
||||||
|
if (user == null) {
|
||||||
|
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "用户不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
String newStatus = body.get("status");
|
||||||
|
if (!List.of("ACTIVE", "DISABLED").contains(newStatus)) {
|
||||||
|
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "状态值无效 (ACTIVE/DISABLED)");
|
||||||
|
}
|
||||||
|
|
||||||
|
user.setStatus(newStatus);
|
||||||
|
user.setUpdatedAt(OffsetDateTime.now(ZoneOffset.UTC));
|
||||||
|
userMapper.updateById(user);
|
||||||
|
return ResponseEntity.ok().build();
|
||||||
|
}
|
||||||
|
}
|
||||||
+6
@@ -17,6 +17,7 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
|||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||||
import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter.ReferrerPolicy;
|
import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter.ReferrerPolicy;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* I1:JWT(Bearer)保护业务 API;I5:{@code /internal/**} 使用内部共享 Token,与 JWT 分离;I6:统一安全响应头。
|
* I1:JWT(Bearer)保护业务 API;I5:{@code /internal/**} 使用内部共享 Token,与 JWT 分离;I6:统一安全响应头。
|
||||||
@@ -79,6 +80,11 @@ public class SecurityConfig {
|
|||||||
return new BCryptPasswordEncoder();
|
return new BCryptPasswordEncoder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ObjectMapper objectMapper() {
|
||||||
|
return new ObjectMapper();
|
||||||
|
}
|
||||||
|
|
||||||
/** I6:API 最小安全头;HSTS 由边缘 HTTPS 终止(Nginx/Caddy)配置。 */
|
/** I6:API 最小安全头;HSTS 由边缘 HTTPS 终止(Nginx/Caddy)配置。 */
|
||||||
private void apiHeaders(HeadersConfigurer<HttpSecurity> headers) {
|
private void apiHeaders(HeadersConfigurer<HttpSecurity> headers) {
|
||||||
headers
|
headers
|
||||||
|
|||||||
+1
-1
@@ -58,7 +58,7 @@ public class CustomerController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/{id}/summary")
|
@GetMapping("/{id}/summary")
|
||||||
public ResponseEntity<Map<String, Object>> getSummary(@PathVariable Long id) {
|
public ResponseEntity<Map<String, Object>> getSummary(@PathVariable("id") Long id) {
|
||||||
return ResponseEntity.ok(customerService.getCustomerSummary(id));
|
return ResponseEntity.ok(customerService.getCustomerSummary(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -98,8 +98,8 @@ public class IntegrationCatalogController {
|
|||||||
|
|
||||||
@GetMapping("/id-mappings")
|
@GetMapping("/id-mappings")
|
||||||
public ResponseEntity<List<PlatformBitanswerIdMapping>> listIdMappings(
|
public ResponseEntity<List<PlatformBitanswerIdMapping>> listIdMappings(
|
||||||
@RequestParam(required = false) Long productLineId,
|
@RequestParam(value = "productLineId", required = false) Long productLineId,
|
||||||
@RequestParam(required = false) Long environmentId) {
|
@RequestParam(value = "environmentId", required = false) Long environmentId) {
|
||||||
return ResponseEntity.ok(integrationCatalogService.listIdMappings(productLineId, environmentId));
|
return ResponseEntity.ok(integrationCatalogService.listIdMappings(productLineId, environmentId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,13 +152,13 @@ public class IntegrationCatalogController {
|
|||||||
|
|
||||||
@GetMapping("/feature-mappings")
|
@GetMapping("/feature-mappings")
|
||||||
public ResponseEntity<List<PlatformBitanswerIdMapping>> listFeatureMappings(
|
public ResponseEntity<List<PlatformBitanswerIdMapping>> listFeatureMappings(
|
||||||
@RequestParam(required = false) Long productLineId) {
|
@RequestParam(value = "productLineId", required = false) Long productLineId) {
|
||||||
return ResponseEntity.ok(integrationCatalogService.listFeatureMappings(productLineId));
|
return ResponseEntity.ok(integrationCatalogService.listFeatureMappings(productLineId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/sku-mappings")
|
@GetMapping("/sku-mappings")
|
||||||
public ResponseEntity<List<SkuMappingResponse>> listSkuMappings(
|
public ResponseEntity<List<SkuMappingResponse>> listSkuMappings(
|
||||||
@RequestParam(required = false) Long contractLineId) {
|
@RequestParam(value = "contractLineId", required = false) Long contractLineId) {
|
||||||
return ResponseEntity.ok(integrationCatalogService.listSkuMappings(contractLineId));
|
return ResponseEntity.ok(integrationCatalogService.listSkuMappings(contractLineId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+14
-16
@@ -17,6 +17,7 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/reports")
|
@RequestMapping("/api/v1/reports")
|
||||||
@@ -29,40 +30,37 @@ public class ReportController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/contract-sn")
|
@GetMapping("/contract-sn")
|
||||||
public List<ContractSnReportRow> getContractSnReport(
|
public ResponseEntity<List<ContractSnReportRow>> getContractSnReport(
|
||||||
@RequestParam(value = "projectId", required = false) Long projectId,
|
@RequestParam(value = "projectId", required = false) Long projectId,
|
||||||
@RequestParam(value = "contractId", required = false) Long contractId) {
|
@RequestParam(value = "contractId", required = false) Long contractId) {
|
||||||
return reportService.getContractSnReport(projectId, contractId);
|
List<ContractSnReportRow> rows = reportService.getContractSnReport(projectId, contractId);
|
||||||
|
return ResponseEntity.ok(rows);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/sn-stats")
|
||||||
|
public ResponseEntity<Map<String, Long>> getSnStats() {
|
||||||
|
return ResponseEntity.ok(reportService.getSnStats());
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/callback-stats")
|
@GetMapping("/callback-stats")
|
||||||
public CallbackStatsResponse getCallbackStats(
|
public ResponseEntity<CallbackStatsResponse> getCallbackStats(
|
||||||
@RequestParam(value = "from", required = false) String from,
|
@RequestParam(value = "from", required = false) String from,
|
||||||
@RequestParam(value = "to", required = false) String to) {
|
@RequestParam(value = "to", required = false) String to) {
|
||||||
return reportService.getCallbackStats(from, to);
|
return ResponseEntity.ok(reportService.getCallbackStats(from, to));
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/project-health")
|
|
||||||
public List<ProjectHealthRow> getProjectHealth() {
|
|
||||||
return reportService.getProjectHealth();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/export")
|
@GetMapping("/export")
|
||||||
public ResponseEntity<Resource> exportReport(
|
public ResponseEntity<Resource> exportReport(
|
||||||
@RequestParam String type,
|
@RequestParam(value = "type", defaultValue = "contract-sn") String type,
|
||||||
@RequestParam(required = false) Long projectId,
|
@RequestParam(value = "projectId", required = false) Long projectId,
|
||||||
@RequestParam(required = false) Long contractId) {
|
@RequestParam(value = "contractId", required = false) Long contractId) {
|
||||||
|
|
||||||
String csv = reportService.exportReport(type, projectId, contractId);
|
String csv = reportService.exportReport(type, projectId, contractId);
|
||||||
|
|
||||||
byte[] bytes = csv.getBytes(StandardCharsets.UTF_8);
|
byte[] bytes = csv.getBytes(StandardCharsets.UTF_8);
|
||||||
byte[] bom = {(byte) 0xEF, (byte) 0xBB, (byte) 0xBF};
|
byte[] bom = {(byte) 0xEF, (byte) 0xBB, (byte) 0xBF};
|
||||||
byte[] withBom = new byte[bom.length + bytes.length];
|
byte[] withBom = new byte[bom.length + bytes.length];
|
||||||
System.arraycopy(bom, 0, withBom, 0, bom.length);
|
System.arraycopy(bom, 0, withBom, 0, bom.length);
|
||||||
System.arraycopy(bytes, 0, withBom, bom.length, bytes.length);
|
System.arraycopy(bytes, 0, withBom, bom.length, bytes.length);
|
||||||
|
|
||||||
ByteArrayResource resource = new ByteArrayResource(withBom);
|
ByteArrayResource resource = new ByteArrayResource(withBom);
|
||||||
|
|
||||||
return ResponseEntity.ok()
|
return ResponseEntity.ok()
|
||||||
.header(HttpHeaders.CONTENT_DISPOSITION,
|
.header(HttpHeaders.CONTENT_DISPOSITION,
|
||||||
"attachment; filename=report-" + type + "-" + LocalDate.now() + ".csv")
|
"attachment; filename=report-" + type + "-" + LocalDate.now() + ".csv")
|
||||||
|
|||||||
Reference in New Issue
Block a user