后端功能增强:全局异常处理、API控制器、JSP视图和单元测试
- 添加 GlobalExceptionHandler 全局异常处理 - 添加 ApiController REST API 控制器 - 更新 WebConfig 跨域配置和 ProductRepository 查询方法 - 新增 monitor/product-detail/profile JSP 视图页面 - 添加 FlashSaleServiceTest 秒杀服务单元测试 - 更新 application.yml 配置
This commit is contained in:
@@ -0,0 +1,414 @@
|
||||
package com.org.flashsalesystem.config;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.validation.ObjectError;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.ConstraintViolationException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
/**
|
||||
* 全局异常处理器
|
||||
* 统一处理应用中的各种异常,提供一致的错误响应格式
|
||||
*/
|
||||
@RestControllerAdvice
|
||||
@Slf4j
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
/**
|
||||
* 业务异常处理
|
||||
*/
|
||||
@ExceptionHandler(BusinessException.class)
|
||||
public ResponseEntity<ErrorResponse> handleBusinessException(BusinessException e, HttpServletRequest request) {
|
||||
log.warn("业务异常: {} - {}", e.getErrorCode(), e.getMessage(), e);
|
||||
|
||||
ErrorResponse errorResponse = ErrorResponse.builder()
|
||||
.timestamp(LocalDateTime.now())
|
||||
.status(HttpStatus.BAD_REQUEST.value())
|
||||
.error("Business Error")
|
||||
.message(e.getMessage())
|
||||
.errorCode(e.getErrorCode())
|
||||
.path(request.getRequestURI())
|
||||
.build();
|
||||
|
||||
return ResponseEntity.badRequest().body(errorResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* 秒杀相关异常处理
|
||||
*/
|
||||
@ExceptionHandler(FlashSaleException.class)
|
||||
public ResponseEntity<ErrorResponse> handleFlashSaleException(FlashSaleException e, HttpServletRequest request) {
|
||||
log.warn("秒杀异常: {} - {}", e.getErrorCode(), e.getMessage(), e);
|
||||
|
||||
ErrorResponse errorResponse = ErrorResponse.builder()
|
||||
.timestamp(LocalDateTime.now())
|
||||
.status(HttpStatus.BAD_REQUEST.value())
|
||||
.error("Flash Sale Error")
|
||||
.message(e.getMessage())
|
||||
.errorCode(e.getErrorCode())
|
||||
.path(request.getRequestURI())
|
||||
.build();
|
||||
|
||||
return ResponseEntity.badRequest().body(errorResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* 限流异常处理
|
||||
*/
|
||||
@ExceptionHandler(RateLimitException.class)
|
||||
public ResponseEntity<ErrorResponse> handleRateLimitException(RateLimitException e, HttpServletRequest request) {
|
||||
log.warn("限流异常: {}", e.getMessage(), e);
|
||||
|
||||
ErrorResponse errorResponse = ErrorResponse.builder()
|
||||
.timestamp(LocalDateTime.now())
|
||||
.status(HttpStatus.TOO_MANY_REQUESTS.value())
|
||||
.error("Rate Limit Exceeded")
|
||||
.message(e.getMessage())
|
||||
.errorCode("RATE_LIMIT_EXCEEDED")
|
||||
.path(request.getRequestURI())
|
||||
.build();
|
||||
|
||||
return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).body(errorResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据验证异常处理
|
||||
*/
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
public ResponseEntity<ErrorResponse> handleValidationException(MethodArgumentNotValidException e, HttpServletRequest request) {
|
||||
log.warn("数据验证异常: {}", e.getMessage());
|
||||
|
||||
StringBuilder errorMessages = new StringBuilder();
|
||||
for (ObjectError error : e.getBindingResult().getAllErrors()) {
|
||||
if (errorMessages.length() > 0) {
|
||||
errorMessages.append("; ");
|
||||
}
|
||||
errorMessages.append(error.getDefaultMessage());
|
||||
}
|
||||
|
||||
ErrorResponse errorResponse = ErrorResponse.builder()
|
||||
.timestamp(LocalDateTime.now())
|
||||
.status(HttpStatus.BAD_REQUEST.value())
|
||||
.error("Validation Error")
|
||||
.message(errorMessages.toString())
|
||||
.errorCode("VALIDATION_ERROR")
|
||||
.path(request.getRequestURI())
|
||||
.build();
|
||||
|
||||
return ResponseEntity.badRequest().body(errorResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* 参数绑定异常处理
|
||||
*/
|
||||
@ExceptionHandler(BindException.class)
|
||||
public ResponseEntity<ErrorResponse> handleBindException(BindException e, HttpServletRequest request) {
|
||||
log.warn("参数绑定异常: {}", e.getMessage());
|
||||
|
||||
StringBuilder errorMessages = new StringBuilder();
|
||||
for (ObjectError error : e.getBindingResult().getAllErrors()) {
|
||||
if (errorMessages.length() > 0) {
|
||||
errorMessages.append("; ");
|
||||
}
|
||||
errorMessages.append(error.getDefaultMessage());
|
||||
}
|
||||
|
||||
ErrorResponse errorResponse = ErrorResponse.builder()
|
||||
.timestamp(LocalDateTime.now())
|
||||
.status(HttpStatus.BAD_REQUEST.value())
|
||||
.error("Parameter Binding Error")
|
||||
.message(errorMessages.toString())
|
||||
.errorCode("BINDING_ERROR")
|
||||
.path(request.getRequestURI())
|
||||
.build();
|
||||
|
||||
return ResponseEntity.badRequest().body(errorResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* 约束违规异常处理
|
||||
*/
|
||||
@ExceptionHandler(ConstraintViolationException.class)
|
||||
public ResponseEntity<ErrorResponse> handleConstraintViolationException(ConstraintViolationException e, HttpServletRequest request) {
|
||||
log.warn("约束违规异常: {}", e.getMessage());
|
||||
|
||||
StringBuilder errorMessages = new StringBuilder();
|
||||
Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
|
||||
for (ConstraintViolation<?> violation : violations) {
|
||||
if (errorMessages.length() > 0) {
|
||||
errorMessages.append("; ");
|
||||
}
|
||||
errorMessages.append(violation.getMessage());
|
||||
}
|
||||
|
||||
ErrorResponse errorResponse = ErrorResponse.builder()
|
||||
.timestamp(LocalDateTime.now())
|
||||
.status(HttpStatus.BAD_REQUEST.value())
|
||||
.error("Constraint Violation")
|
||||
.message(errorMessages.toString())
|
||||
.errorCode("CONSTRAINT_VIOLATION")
|
||||
.path(request.getRequestURI())
|
||||
.build();
|
||||
|
||||
return ResponseEntity.badRequest().body(errorResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* 超时异常处理
|
||||
*/
|
||||
@ExceptionHandler(TimeoutException.class)
|
||||
public ResponseEntity<ErrorResponse> handleTimeoutException(TimeoutException e, HttpServletRequest request) {
|
||||
log.error("超时异常: {}", e.getMessage(), e);
|
||||
|
||||
ErrorResponse errorResponse = ErrorResponse.builder()
|
||||
.timestamp(LocalDateTime.now())
|
||||
.status(HttpStatus.REQUEST_TIMEOUT.value())
|
||||
.error("Timeout Error")
|
||||
.message("请求超时,请稍后重试")
|
||||
.errorCode("TIMEOUT_ERROR")
|
||||
.path(request.getRequestURI())
|
||||
.build();
|
||||
|
||||
return ResponseEntity.status(HttpStatus.REQUEST_TIMEOUT).body(errorResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* 非法参数异常处理
|
||||
*/
|
||||
@ExceptionHandler(IllegalArgumentException.class)
|
||||
public ResponseEntity<ErrorResponse> handleIllegalArgumentException(IllegalArgumentException e, HttpServletRequest request) {
|
||||
log.warn("非法参数异常: {}", e.getMessage(), e);
|
||||
|
||||
ErrorResponse errorResponse = ErrorResponse.builder()
|
||||
.timestamp(LocalDateTime.now())
|
||||
.status(HttpStatus.BAD_REQUEST.value())
|
||||
.error("Illegal Argument")
|
||||
.message(e.getMessage())
|
||||
.errorCode("ILLEGAL_ARGUMENT")
|
||||
.path(request.getRequestURI())
|
||||
.build();
|
||||
|
||||
return ResponseEntity.badRequest().body(errorResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* 空指针异常处理
|
||||
*/
|
||||
@ExceptionHandler(NullPointerException.class)
|
||||
public ResponseEntity<ErrorResponse> handleNullPointerException(NullPointerException e, HttpServletRequest request) {
|
||||
log.error("空指针异常: {}", e.getMessage(), e);
|
||||
|
||||
ErrorResponse errorResponse = ErrorResponse.builder()
|
||||
.timestamp(LocalDateTime.now())
|
||||
.status(HttpStatus.INTERNAL_SERVER_ERROR.value())
|
||||
.error("Null Pointer Error")
|
||||
.message("系统内部错误,请联系管理员")
|
||||
.errorCode("NULL_POINTER_ERROR")
|
||||
.path(request.getRequestURI())
|
||||
.build();
|
||||
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* 运行时异常处理
|
||||
*/
|
||||
@ExceptionHandler(RuntimeException.class)
|
||||
public ResponseEntity<ErrorResponse> handleRuntimeException(RuntimeException e, HttpServletRequest request) {
|
||||
log.error("运行时异常: {}", e.getMessage(), e);
|
||||
|
||||
// 对于已知的业务异常,使用友好的错误信息
|
||||
String message = e.getMessage();
|
||||
if (message == null || message.trim().isEmpty()) {
|
||||
message = "系统繁忙,请稍后重试";
|
||||
}
|
||||
|
||||
ErrorResponse errorResponse = ErrorResponse.builder()
|
||||
.timestamp(LocalDateTime.now())
|
||||
.status(HttpStatus.INTERNAL_SERVER_ERROR.value())
|
||||
.error("Runtime Error")
|
||||
.message(message)
|
||||
.errorCode("RUNTIME_ERROR")
|
||||
.path(request.getRequestURI())
|
||||
.build();
|
||||
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用异常处理
|
||||
*/
|
||||
@ExceptionHandler(Exception.class)
|
||||
public ResponseEntity<ErrorResponse> handleGenericException(Exception e, HttpServletRequest request) {
|
||||
log.error("系统异常: {}", e.getMessage(), e);
|
||||
|
||||
ErrorResponse errorResponse = ErrorResponse.builder()
|
||||
.timestamp(LocalDateTime.now())
|
||||
.status(HttpStatus.INTERNAL_SERVER_ERROR.value())
|
||||
.error("System Error")
|
||||
.message("系统异常,请联系管理员")
|
||||
.errorCode("SYSTEM_ERROR")
|
||||
.path(request.getRequestURI())
|
||||
.build();
|
||||
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一错误响应格式
|
||||
*/
|
||||
public static class ErrorResponse {
|
||||
private LocalDateTime timestamp;
|
||||
private int status;
|
||||
private String error;
|
||||
private String message;
|
||||
private String errorCode;
|
||||
private String path;
|
||||
private Map<String, Object> details;
|
||||
|
||||
public ErrorResponse() {
|
||||
this.details = new HashMap<>();
|
||||
}
|
||||
|
||||
public static ErrorResponseBuilder builder() {
|
||||
return new ErrorResponseBuilder();
|
||||
}
|
||||
|
||||
// Getters and Setters
|
||||
public LocalDateTime getTimestamp() { return timestamp; }
|
||||
public void setTimestamp(LocalDateTime timestamp) { this.timestamp = timestamp; }
|
||||
|
||||
public int getStatus() { return status; }
|
||||
public void setStatus(int status) { this.status = status; }
|
||||
|
||||
public String getError() { return error; }
|
||||
public void setError(String error) { this.error = error; }
|
||||
|
||||
public String getMessage() { return message; }
|
||||
public void setMessage(String message) { this.message = message; }
|
||||
|
||||
public String getErrorCode() { return errorCode; }
|
||||
public void setErrorCode(String errorCode) { this.errorCode = errorCode; }
|
||||
|
||||
public String getPath() { return path; }
|
||||
public void setPath(String path) { this.path = path; }
|
||||
|
||||
public Map<String, Object> getDetails() { return details; }
|
||||
public void setDetails(Map<String, Object> details) { this.details = details; }
|
||||
|
||||
public static class ErrorResponseBuilder {
|
||||
private ErrorResponse errorResponse = new ErrorResponse();
|
||||
|
||||
public ErrorResponseBuilder timestamp(LocalDateTime timestamp) {
|
||||
errorResponse.setTimestamp(timestamp);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ErrorResponseBuilder status(int status) {
|
||||
errorResponse.setStatus(status);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ErrorResponseBuilder error(String error) {
|
||||
errorResponse.setError(error);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ErrorResponseBuilder message(String message) {
|
||||
errorResponse.setMessage(message);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ErrorResponseBuilder errorCode(String errorCode) {
|
||||
errorResponse.setErrorCode(errorCode);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ErrorResponseBuilder path(String path) {
|
||||
errorResponse.setPath(path);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ErrorResponseBuilder detail(String key, Object value) {
|
||||
errorResponse.getDetails().put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ErrorResponse build() {
|
||||
return errorResponse;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 业务异常类
|
||||
*/
|
||||
public static class BusinessException extends RuntimeException {
|
||||
private final String errorCode;
|
||||
|
||||
public BusinessException(String message) {
|
||||
super(message);
|
||||
this.errorCode = "BUSINESS_ERROR";
|
||||
}
|
||||
|
||||
public BusinessException(String errorCode, String message) {
|
||||
super(message);
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
|
||||
public BusinessException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
this.errorCode = "BUSINESS_ERROR";
|
||||
}
|
||||
|
||||
public String getErrorCode() {
|
||||
return errorCode;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 秒杀异常类
|
||||
*/
|
||||
public static class FlashSaleException extends RuntimeException {
|
||||
private final String errorCode;
|
||||
|
||||
public FlashSaleException(String message) {
|
||||
super(message);
|
||||
this.errorCode = "FLASH_SALE_ERROR";
|
||||
}
|
||||
|
||||
public FlashSaleException(String errorCode, String message) {
|
||||
super(message);
|
||||
this.errorCode = errorCode;
|
||||
}
|
||||
|
||||
public String getErrorCode() {
|
||||
return errorCode;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 限流异常类
|
||||
*/
|
||||
public static class RateLimitException extends RuntimeException {
|
||||
public RateLimitException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public RateLimitException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.ViewResolver;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
@@ -76,4 +77,17 @@ public class WebConfig implements WebMvcConfigurer {
|
||||
public void addViewControllers(ViewControllerRegistry registry) {
|
||||
registry.addViewController("/").setViewName("index");
|
||||
}
|
||||
|
||||
/**
|
||||
* CORS跨域配置
|
||||
*/
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/**")
|
||||
.allowedOriginPatterns("http://localhost:*", "http://127.0.0.1:*")
|
||||
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
||||
.allowedHeaders("*")
|
||||
.allowCredentials(true)
|
||||
.maxAge(3600);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
package com.org.flashsalesystem.controller;
|
||||
|
||||
import com.org.flashsalesystem.dto.FlashSaleDTO;
|
||||
import com.org.flashsalesystem.dto.ProductDTO;
|
||||
import com.org.flashsalesystem.entity.Product;
|
||||
import com.org.flashsalesystem.repository.ProductRepository;
|
||||
import com.org.flashsalesystem.service.FlashSaleService;
|
||||
import com.org.flashsalesystem.service.ProductService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* API控制器 - 为Vue前端提供REST接口
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api")
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
@Tag(name = "API接口", description = "前端API接口")
|
||||
public class ApiController {
|
||||
|
||||
private final ProductRepository productRepository;
|
||||
private final ProductService productService;
|
||||
private final FlashSaleService flashSaleService;
|
||||
|
||||
/**
|
||||
* 获取热门商品
|
||||
*/
|
||||
@GetMapping("/products/hot")
|
||||
@Operation(summary = "获取热门商品")
|
||||
public ResponseEntity<Map<String, Object>> getHotProducts(
|
||||
@RequestParam(defaultValue = "8") int limit) {
|
||||
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
|
||||
try {
|
||||
// 获取前N个商品作为热门商品
|
||||
Pageable pageable = PageRequest.of(0, limit, Sort.by(Sort.Direction.DESC, "id"));
|
||||
Page<Product> productPage = productRepository.findAll(pageable);
|
||||
|
||||
List<Map<String, Object>> products = new ArrayList<>();
|
||||
for (Product product : productPage.getContent()) {
|
||||
Map<String, Object> item = new HashMap<>();
|
||||
item.put("id", product.getId());
|
||||
item.put("name", product.getName());
|
||||
item.put("description", product.getDescription());
|
||||
item.put("price", product.getPrice());
|
||||
item.put("stock", product.getStock());
|
||||
item.put("image", product.getImageUrl());
|
||||
item.put("category", "");
|
||||
products.add(item);
|
||||
}
|
||||
|
||||
response.put("success", true);
|
||||
response.put("data", products);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取热门商品失败", e);
|
||||
response.put("success", false);
|
||||
response.put("message", "获取热门商品失败");
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取活跃的秒杀活动
|
||||
*/
|
||||
@GetMapping("/flashsales/active")
|
||||
@Operation(summary = "获取活跃的秒杀活动")
|
||||
public ResponseEntity<Map<String, Object>> getActiveFlashSales() {
|
||||
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
|
||||
try {
|
||||
List<FlashSaleDTO> flashSales = flashSaleService.getActiveFlashSales();
|
||||
|
||||
// 转换数据格式
|
||||
List<Map<String, Object>> result = new ArrayList<>();
|
||||
for (FlashSaleDTO flashSale : flashSales) {
|
||||
Map<String, Object> item = new HashMap<>();
|
||||
item.put("id", flashSale.getId());
|
||||
item.put("productId", flashSale.getProductId());
|
||||
item.put("productName", flashSale.getProductName());
|
||||
item.put("productImage", "");
|
||||
item.put("originalPrice", flashSale.getOriginalPrice());
|
||||
item.put("flashPrice", flashSale.getFlashPrice());
|
||||
item.put("flashStock", flashSale.getFlashStock());
|
||||
item.put("startTime", flashSale.getStartTime());
|
||||
item.put("endTime", flashSale.getEndTime());
|
||||
item.put("status", flashSale.getStatus());
|
||||
result.add(item);
|
||||
}
|
||||
|
||||
response.put("success", true);
|
||||
response.put("data", result);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取活跃秒杀活动失败", e);
|
||||
response.put("success", false);
|
||||
response.put("message", "获取活跃秒杀活动失败");
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 参与秒杀
|
||||
*/
|
||||
@PostMapping("/flashsales/participate")
|
||||
@Operation(summary = "参与秒杀")
|
||||
public ResponseEntity<Map<String, Object>> participate(
|
||||
@RequestBody Map<String, Object> request,
|
||||
HttpServletRequest httpRequest) {
|
||||
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
|
||||
try {
|
||||
// 从session获取用户ID
|
||||
Long userId = (Long) httpRequest.getSession().getAttribute("userId");
|
||||
if (userId == null) {
|
||||
response.put("success", false);
|
||||
response.put("message", "请先登录");
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
Long flashSaleId = Long.valueOf(request.get("flashSaleId").toString());
|
||||
Integer quantity = request.containsKey("quantity") ?
|
||||
Integer.valueOf(request.get("quantity").toString()) : 1;
|
||||
|
||||
// 创建参与DTO
|
||||
FlashSaleDTO.ParticipateDTO participateDTO = new FlashSaleDTO.ParticipateDTO();
|
||||
participateDTO.setFlashSaleId(flashSaleId);
|
||||
participateDTO.setQuantity(quantity);
|
||||
|
||||
// 调用秒杀服务
|
||||
FlashSaleDTO.ResultDTO result = flashSaleService.participateFlashSale(userId, participateDTO);
|
||||
|
||||
response.put("success", result.getSuccess());
|
||||
response.put("message", result.getMessage());
|
||||
if (result.getOrderId() != null) {
|
||||
response.put("orderId", result.getOrderId());
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("参与秒杀失败", e);
|
||||
response.put("success", false);
|
||||
response.put("message", e.getMessage());
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取商品列表
|
||||
*/
|
||||
@GetMapping("/products")
|
||||
@Operation(summary = "获取商品列表")
|
||||
public ResponseEntity<Map<String, Object>> getProducts(
|
||||
@RequestParam(defaultValue = "0") int page,
|
||||
@RequestParam(defaultValue = "12") int size) {
|
||||
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
|
||||
try {
|
||||
Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "id"));
|
||||
Page<Product> productPage = productRepository.findAll(pageable);
|
||||
|
||||
List<Map<String, Object>> products = new ArrayList<>();
|
||||
for (Product product : productPage.getContent()) {
|
||||
Map<String, Object> item = new HashMap<>();
|
||||
item.put("id", product.getId());
|
||||
item.put("name", product.getName());
|
||||
item.put("description", product.getDescription());
|
||||
item.put("price", product.getPrice());
|
||||
item.put("stock", product.getStock());
|
||||
item.put("image", product.getImageUrl());
|
||||
item.put("category", "");
|
||||
products.add(item);
|
||||
}
|
||||
|
||||
response.put("success", true);
|
||||
response.put("list", products);
|
||||
response.put("total", productPage.getTotalElements());
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取商品列表失败", e);
|
||||
response.put("success", false);
|
||||
response.put("message", "获取商品列表失败");
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取秒杀活动列表
|
||||
*/
|
||||
@GetMapping("/flashsales")
|
||||
@Operation(summary = "获取秒杀活动列表")
|
||||
public ResponseEntity<Map<String, Object>> getFlashSales() {
|
||||
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
|
||||
try {
|
||||
List<FlashSaleDTO> flashSales = flashSaleService.getActiveFlashSales();
|
||||
|
||||
response.put("success", true);
|
||||
response.put("list", flashSales);
|
||||
response.put("total", flashSales.size());
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取秒杀活动列表失败", e);
|
||||
response.put("success", false);
|
||||
response.put("message", "获取秒杀活动列表失败");
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
}
|
||||
@@ -81,4 +81,9 @@ public interface ProductRepository extends JpaRepository<Product, Long> {
|
||||
* 统计库存小于指定数量的商品数量
|
||||
*/
|
||||
long countByStockLessThan(Integer stock);
|
||||
|
||||
/**
|
||||
* 根据名称模糊查询(忽略大小写)
|
||||
*/
|
||||
Page<Product> findByNameContainingIgnoreCase(String name, Pageable pageable);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user