mirror of
https://github.com/hpd840321/craftlabs-authorization-sdk.git
synced 2026-06-09 01:50: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
|
||||
public PageResponse<AuditEventResponse> list(
|
||||
@RequestParam(required = false) String entityType,
|
||||
@RequestParam(required = false) Long entityId,
|
||||
@RequestParam(required = false) String userId,
|
||||
@RequestParam(value = "entityType", required = false) String entityType,
|
||||
@RequestParam(value = "entityId", required = false) Long entityId,
|
||||
@RequestParam(value = "userId", required = false) String userId,
|
||||
@RequestParam(value = "page", defaultValue = "0") @Min(0) int page,
|
||||
@RequestParam(value = "size", defaultValue = "20") @Min(1) @Max(200) int size) {
|
||||
return auditService.page(entityType, entityId, userId, page, size);
|
||||
@@ -43,11 +43,11 @@ public class AuditController {
|
||||
|
||||
@GetMapping("/export")
|
||||
public ResponseEntity<Resource> exportAuditEvents(
|
||||
@RequestParam(required = false) String entityType,
|
||||
@RequestParam(required = false) Long entityId,
|
||||
@RequestParam(required = false) String userId,
|
||||
@RequestParam(required = false) String from,
|
||||
@RequestParam(required = false) String to) {
|
||||
@RequestParam(value = "entityType", required = false) String entityType,
|
||||
@RequestParam(value = "entityId", required = false) Long entityId,
|
||||
@RequestParam(value = "userId", required = false) String userId,
|
||||
@RequestParam(value = "from", required = false) String from,
|
||||
@RequestParam(value = "to", required = false) String to) {
|
||||
|
||||
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.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
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:统一安全响应头。
|
||||
@@ -79,6 +80,11 @@ public class SecurityConfig {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ObjectMapper objectMapper() {
|
||||
return new ObjectMapper();
|
||||
}
|
||||
|
||||
/** I6:API 最小安全头;HSTS 由边缘 HTTPS 终止(Nginx/Caddy)配置。 */
|
||||
private void apiHeaders(HeadersConfigurer<HttpSecurity> headers) {
|
||||
headers
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ public class CustomerController {
|
||||
}
|
||||
|
||||
@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));
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -98,8 +98,8 @@ public class IntegrationCatalogController {
|
||||
|
||||
@GetMapping("/id-mappings")
|
||||
public ResponseEntity<List<PlatformBitanswerIdMapping>> listIdMappings(
|
||||
@RequestParam(required = false) Long productLineId,
|
||||
@RequestParam(required = false) Long environmentId) {
|
||||
@RequestParam(value = "productLineId", required = false) Long productLineId,
|
||||
@RequestParam(value = "environmentId", required = false) Long environmentId) {
|
||||
return ResponseEntity.ok(integrationCatalogService.listIdMappings(productLineId, environmentId));
|
||||
}
|
||||
|
||||
@@ -152,13 +152,13 @@ public class IntegrationCatalogController {
|
||||
|
||||
@GetMapping("/feature-mappings")
|
||||
public ResponseEntity<List<PlatformBitanswerIdMapping>> listFeatureMappings(
|
||||
@RequestParam(required = false) Long productLineId) {
|
||||
@RequestParam(value = "productLineId", required = false) Long productLineId) {
|
||||
return ResponseEntity.ok(integrationCatalogService.listFeatureMappings(productLineId));
|
||||
}
|
||||
|
||||
@GetMapping("/sku-mappings")
|
||||
public ResponseEntity<List<SkuMappingResponse>> listSkuMappings(
|
||||
@RequestParam(required = false) Long contractLineId) {
|
||||
@RequestParam(value = "contractLineId", required = false) Long 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.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/reports")
|
||||
@@ -29,40 +30,37 @@ public class ReportController {
|
||||
}
|
||||
|
||||
@GetMapping("/contract-sn")
|
||||
public List<ContractSnReportRow> getContractSnReport(
|
||||
public ResponseEntity<List<ContractSnReportRow>> getContractSnReport(
|
||||
@RequestParam(value = "projectId", required = false) Long projectId,
|
||||
@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")
|
||||
public CallbackStatsResponse getCallbackStats(
|
||||
public ResponseEntity<CallbackStatsResponse> getCallbackStats(
|
||||
@RequestParam(value = "from", required = false) String from,
|
||||
@RequestParam(value = "to", required = false) String to) {
|
||||
return reportService.getCallbackStats(from, to);
|
||||
}
|
||||
|
||||
@GetMapping("/project-health")
|
||||
public List<ProjectHealthRow> getProjectHealth() {
|
||||
return reportService.getProjectHealth();
|
||||
return ResponseEntity.ok(reportService.getCallbackStats(from, to));
|
||||
}
|
||||
|
||||
@GetMapping("/export")
|
||||
public ResponseEntity<Resource> exportReport(
|
||||
@RequestParam String type,
|
||||
@RequestParam(required = false) Long projectId,
|
||||
@RequestParam(required = false) Long contractId) {
|
||||
|
||||
@RequestParam(value = "type", defaultValue = "contract-sn") String type,
|
||||
@RequestParam(value = "projectId", required = false) Long projectId,
|
||||
@RequestParam(value = "contractId", required = false) Long contractId) {
|
||||
String csv = reportService.exportReport(type, projectId, contractId);
|
||||
|
||||
byte[] bytes = csv.getBytes(StandardCharsets.UTF_8);
|
||||
byte[] bom = {(byte) 0xEF, (byte) 0xBB, (byte) 0xBF};
|
||||
byte[] withBom = new byte[bom.length + bytes.length];
|
||||
System.arraycopy(bom, 0, withBom, 0, bom.length);
|
||||
System.arraycopy(bytes, 0, withBom, bom.length, bytes.length);
|
||||
|
||||
ByteArrayResource resource = new ByteArrayResource(withBom);
|
||||
|
||||
return ResponseEntity.ok()
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION,
|
||||
"attachment; filename=report-" + type + "-" + LocalDate.now() + ".csv")
|
||||
|
||||
Reference in New Issue
Block a user