From 5554d943d1144c7b91db644b2f239dee4e154b9e Mon Sep 17 00:00:00 2001 From: huangqizhen <15552608129@163.com> Date: Wed, 3 Dec 2025 17:42:54 +0800 Subject: [PATCH 1/3] =?UTF-8?q?12.3=20=E5=86=B2=E5=88=BA=E8=AE=A1=E5=88=92?= =?UTF-8?q?=E7=B4=AF=E8=AE=A1=E5=85=85=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/demo/DemoApplication.java | 1 + .../demo/config/GlobalExceptionHandler.java | 370 +++++++++++++++++++++ .../demo/controller/Temporary/RedController.java | 39 +++ src/main/java/com/example/demo/domain/vo/Red.java | 32 ++ .../example/demo/mapper/Temporary/RedMapper.java | 19 ++ .../com/example/demo/security/SecurityConfig.java | 2 +- .../example/demo/service/Temporary/RedService.java | 17 + .../demo/serviceImpl/Temporary/RedServiceImpl.java | 35 ++ src/main/resources/mapper/RedMapper.xml | 9 + 9 files changed, 523 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/example/demo/config/GlobalExceptionHandler.java create mode 100644 src/main/java/com/example/demo/controller/Temporary/RedController.java create mode 100644 src/main/java/com/example/demo/domain/vo/Red.java create mode 100644 src/main/java/com/example/demo/mapper/Temporary/RedMapper.java create mode 100644 src/main/java/com/example/demo/service/Temporary/RedService.java create mode 100644 src/main/java/com/example/demo/serviceImpl/Temporary/RedServiceImpl.java create mode 100644 src/main/resources/mapper/RedMapper.xml diff --git a/src/main/java/com/example/demo/DemoApplication.java b/src/main/java/com/example/demo/DemoApplication.java index 8fc0e36..9afc0e2 100644 --- a/src/main/java/com/example/demo/DemoApplication.java +++ b/src/main/java/com/example/demo/DemoApplication.java @@ -16,6 +16,7 @@ import org.springframework.scheduling.annotation.EnableScheduling; @MapperScan(basePackages = "com.example.demo.mapper.live", sqlSessionTemplateRef = "mysql5SqlSessionTemplate") @MapperScan(basePackages = "com.example.demo.mapper.sqlserver", sqlSessionTemplateRef = "sqlserver1SqlSessionTemplate") @MapperScan(basePackages = "com.example.demo.mapper.cash", sqlSessionTemplateRef = "mysql1SqlSessionTemplate") +@MapperScan(basePackages = "com.example.demo.mapper.Temporary", sqlSessionTemplateRef = "mysql1SqlSessionTemplate") public class DemoApplication { public static void main(String[] args) { diff --git a/src/main/java/com/example/demo/config/GlobalExceptionHandler.java b/src/main/java/com/example/demo/config/GlobalExceptionHandler.java new file mode 100644 index 0000000..02a1af6 --- /dev/null +++ b/src/main/java/com/example/demo/config/GlobalExceptionHandler.java @@ -0,0 +1,370 @@ +package com.example.demo.config; + +import cn.hutool.core.io.resource.NoResourceException; + +import com.example.demo.Util.BusinessException; +import com.example.demo.Util.ExecutionContextUtil; +import com.example.demo.Util.FeiShuAlertUtil; +import com.example.demo.domain.vo.coin.ExecutionContext; +import com.example.demo.domain.vo.coin.Result; +import com.example.demo.exception.SystemException; +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.exc.InvalidFormatException; +import io.micrometer.common.util.StringUtils; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.validation.BindException; +import org.springframework.validation.FieldError; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.MissingServletRequestParameterException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; +import org.springframework.web.servlet.NoHandlerFoundException; +import org.springframework.web.servlet.resource.NoResourceFoundException; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.Date; +import java.util.stream.Collectors; + +/** + * 全局异常处理器 - 优化封装版 + */ +@RestControllerAdvice +public class GlobalExceptionHandler { + private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class); + + // ==================== 业务异常处理 ==================== + + /** + * 处理业务异常 + */ + @ExceptionHandler({BusinessException.class}) + @ResponseBody + public ResponseEntity handleBusinessException(BusinessException e) { + logger.warn("业务异常: {}", e.getMessage()); + return ResponseEntity.status(HttpStatus.OK).body(Result.error(e)); + } + + /** + * 处理系统异常 + */ + @ExceptionHandler(SystemException.class) + @ResponseBody + public ResponseEntity handleSystemException(SystemException e) { + logger.error("系统异常: ", e); + + // 发送飞书报警 + sendFeishuAlert(e, "系统异常: " + e.getMessage(), getCauseMessage(e)); + + // 返回通用的错误信息 + return ResponseEntity.status(HttpStatus.OK) + .body(Result.error(new BusinessException("正在为您努力加载中..."))); + } + + // ==================== 资源未找到异常处理 ==================== + + /** + * 处理资源未找到异常 + */ + @ExceptionHandler(NoResourceFoundException.class) + @ResponseBody + public ResponseEntity handleNoResourceFoundException(NoResourceFoundException e) { + logger.warn("资源未找到: {} - {}", e.getHttpMethod(), e.getResourcePath()); + + String errorMessage = String.format("接口[%s %s]不存在,请检查接口地址", + e.getHttpMethod(), e.getResourcePath()); + + Result result = Result.error(new BusinessException(404, errorMessage)); + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + // ==================== 参数校验异常处理 ==================== + + /** + * 处理参数校验异常 + */ + @ExceptionHandler(MethodArgumentNotValidException.class) + @ResponseBody + public ResponseEntity handleMethodArgumentNotValid(MethodArgumentNotValidException e) { + String errorMessage = e.getBindingResult().getFieldErrors().stream() + .map(FieldError::getDefaultMessage) + .collect(Collectors.joining(", ")); + + logger.warn("参数校验异常: {}", errorMessage); + return ResponseEntity.status(HttpStatus.OK) + .body(Result.error(new BusinessException(errorMessage))); + } + + /** + * 处理约束违反异常 + */ + @ExceptionHandler(ConstraintViolationException.class) + @ResponseBody + public ResponseEntity handleConstraintViolation(ConstraintViolationException e) { + String errorMessage = e.getConstraintViolations().stream() + .map(ConstraintViolation::getMessage) + .collect(Collectors.joining(", ")); + + logger.warn("约束违反异常: {}", errorMessage); + return ResponseEntity.status(HttpStatus.OK) + .body(Result.error(new BusinessException(errorMessage))); + } + + /** + * 处理请求方法不支持异常 + */ + @ExceptionHandler(HttpRequestMethodNotSupportedException.class) + @ResponseBody + public ResponseEntity handleHttpRequestMethodNotSupported( + HttpRequestMethodNotSupportedException e) { + + String errorMessage = "请求方法不支持,请使用: " + e.getSupportedHttpMethods(); + logger.warn("请求方法不支持: {}", e.getMethod()); + return ResponseEntity.status(HttpStatus.OK) + .body(Result.error(new BusinessException(errorMessage))); + } + + /** + * 处理参数类型不匹配异常 + */ + @ExceptionHandler(MethodArgumentTypeMismatchException.class) + @ResponseBody + public ResponseEntity handleMethodArgumentTypeMismatch( + MethodArgumentTypeMismatchException e) { + + String errorMessage = handleTypeMismatch(e); + logger.warn("参数类型不匹配: {} - {}", e.getName(), e.getValue()); + return ResponseEntity.status(HttpStatus.OK) + .body(Result.error(new BusinessException(errorMessage))); + } + +// /** +// * 处理表单绑定异常 +// */ +// @ExceptionHandler(BindException.class) +// @ResponseBody +// public ResponseEntity handleBindException(BindException e) { +// String errorMessage = handleBindException(e); +// logger.warn("表单绑定异常: {}", errorMessage); +// return ResponseEntity.status(HttpStatus.OK) +// .body(Result.error(new BusinessException(errorMessage))); +// } + + /** + * 处理缺失请求参数异常 + */ + @ExceptionHandler(MissingServletRequestParameterException.class) + @ResponseBody + public ResponseEntity handleMissingServletRequestParameter( + MissingServletRequestParameterException e) { + + String errorMessage = handleMissingParameter(e); + logger.warn("缺失请求参数: {}", e.getParameterName()); + return ResponseEntity.status(HttpStatus.OK) + .body(Result.error(new BusinessException(errorMessage))); + } + + /** + * 处理请求体不可读异常 + */ +// @ExceptionHandler(HttpMessageNotReadableException.class) +// @ResponseBody +// public ResponseEntity handleHttpMessageNotReadable( +// HttpMessageNotReadableException e) { +// +// String errorMessage = handleHttpMessageNotReadable(e); +// logger.warn("请求体不可读: {}", e.getMessage()); +// return ResponseEntity.status(HttpStatus.BAD_REQUEST) +// .body(Result.error(new BusinessException(errorMessage))); +// } + + // ==================== 通用异常处理 ==================== + + /** + * 处理未预期的异常 + */ + @ExceptionHandler(Exception.class) + @ResponseBody + public ResponseEntity handleUnexpectedException(Exception e) { + // 如果是参数校验相关异常,已经被上面的方法处理,这里作为兜底 + if (isValidationException(e)) { + String errorMessage = getValidationErrorMessage(e); + logger.warn("参数校验异常(兜底): {}", errorMessage); + Result result = Result.error(new BusinessException(errorMessage)); + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + logger.error("未预期异常: {}", e.getMessage(), e); + + // 发送飞书报警 + sendFeishuAlert(e, "未预期异常: " + e.getClass().getName(), e.getMessage()); + + // 返回通用错误信息 + Result result = Result.error(new BusinessException("正在为您努力加载中...")); + return ResponseEntity.status(HttpStatus.OK).body(result); + } + + // ==================== 异常处理工具方法 ==================== + + /** + * 发送飞书报警 + */ + private void sendFeishuAlert(Exception e, String title, String detail) { + ExecutionContext context = ExecutionContextUtil.getExecutionContext(); + if (context != null) { + String message = title; + if (StringUtils.isNotBlank(detail)) { + message += "\n错误详情: " + detail; + } + + FeiShuAlertUtil.sendAlertMessage( + context, + e.getStackTrace()[0].getFileName(), + e.getStackTrace()[0].getLineNumber(), + message, + context.getRequestParams() + ); + } + } + + /** + * 获取异常原因信息 + */ + private String getCauseMessage(Exception e) { + if (e.getCause() != null) { + return e.getCause().getMessage(); + } + return ""; + } + + /** + * 判断是否是字段校验异常 + */ + private boolean isValidationException(Exception e) { + return e instanceof MethodArgumentNotValidException || + e instanceof ConstraintViolationException || + e instanceof HttpMessageNotReadableException || + e instanceof HttpRequestMethodNotSupportedException || + e instanceof MethodArgumentTypeMismatchException || + e instanceof BindException || + e instanceof MissingServletRequestParameterException || + e instanceof NoHandlerFoundException || + e instanceof NoResourceException; + } + + /** + * 获取校验异常的错误信息(兜底方法) + */ + private String getValidationErrorMessage(Exception e) { + if (e instanceof MethodArgumentNotValidException) { + return ((MethodArgumentNotValidException) e).getBindingResult().getFieldErrors().stream() + .map(FieldError::getDefaultMessage) + .collect(Collectors.joining(", ")); + } else if (e instanceof ConstraintViolationException) { + return ((ConstraintViolationException) e).getConstraintViolations().stream() + .map(ConstraintViolation::getMessage) + .collect(Collectors.joining(", ")); + } else if (e instanceof MethodArgumentTypeMismatchException) { + return handleTypeMismatch((MethodArgumentTypeMismatchException) e); + } else if (e instanceof BindException) { + return handleBindException((BindException) e); + } else if (e instanceof MissingServletRequestParameterException) { + return handleMissingParameter((MissingServletRequestParameterException) e); + } else if (e instanceof HttpMessageNotReadableException) { + return handleHttpMessageNotReadable((HttpMessageNotReadableException) e); + } else if (e instanceof HttpRequestMethodNotSupportedException) { + return "请求方法不支持,请使用: " + ((HttpRequestMethodNotSupportedException) e).getSupportedHttpMethods(); + } + return "参数校验失败"; + } + + /** + * 处理类型不匹配异常 + */ + private String handleTypeMismatch(MethodArgumentTypeMismatchException ex) { + String parameterName = ex.getName(); + Class requiredType = ex.getRequiredType(); + + String errorMsg = String.format("参数'%s'的值'%s'格式错误", + parameterName, ex.getValue()); + + if (requiredType != null) { + if (Number.class.isAssignableFrom(requiredType)) { + errorMsg += ",应为数字类型"; + } else if (requiredType == Boolean.class || requiredType == boolean.class) { + errorMsg += ",应为布尔值(true/false)"; + } else if (requiredType == Date.class || requiredType == LocalDate.class) { + errorMsg += ",日期格式应为: yyyy-MM-dd"; + } else if (requiredType == LocalDateTime.class) { + errorMsg += ",日期时间格式应为: yyyy-MM-dd HH:mm:ss"; + } else if (requiredType.isEnum()) { + errorMsg += ",可选值为: " + Arrays.toString(requiredType.getEnumConstants()); + } + } + return errorMsg; + } + + /** + * 处理表单对象绑定错误 + */ + private String handleBindException(BindException ex) { + return ex.getBindingResult().getFieldErrors().stream() + .map(error -> { + String field = error.getField(); + String message = error.getDefaultMessage(); + Object rejectedValue = error.getRejectedValue(); + + return rejectedValue == null + ? String.format("字段'%s': %s", field, message) + : String.format("字段'%s'的值'%s'无效: %s", field, rejectedValue, message); + }) + .collect(Collectors.joining("; ")); + } + + /** + * 处理必填参数缺失异常 + */ + private String handleMissingParameter(MissingServletRequestParameterException ex) { + return String.format("缺少必填参数: '%s' (类型: %s)", + ex.getParameterName(), ex.getParameterType()); + } + + /** + * 处理请求体解析异常 + */ + private String handleHttpMessageNotReadable(HttpMessageNotReadableException ex) { + Throwable rootCause = ex.getRootCause(); + + if (rootCause instanceof JsonParseException) { + return "JSON格式错误: " + rootCause.getMessage(); + } else if (rootCause instanceof InvalidFormatException) { + InvalidFormatException ife = (InvalidFormatException) rootCause; + return String.format("字段'%s'的值'%s'格式不正确,期望类型: %s", + ife.getPath().get(ife.getPath().size() - 1).getFieldName(), + ife.getValue(), + ife.getTargetType().getSimpleName()); + } else if (rootCause != null) { + return "请求体格式错误: " + rootCause.getMessage(); + } + return "请求体格式错误或无法解析"; + } + + /** + * 获取异常根源信息 + */ + private String getRootCauseMessage(Throwable e) { + Throwable rootCause = ExceptionUtils.getRootCause(e); + return rootCause != null ? rootCause.getMessage() : e.getMessage(); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/demo/controller/Temporary/RedController.java b/src/main/java/com/example/demo/controller/Temporary/RedController.java new file mode 100644 index 0000000..332c3cc --- /dev/null +++ b/src/main/java/com/example/demo/controller/Temporary/RedController.java @@ -0,0 +1,39 @@ +package com.example.demo.controller.Temporary; + +import com.example.demo.domain.vo.Red; +import com.example.demo.domain.vo.coin.Result; +import com.example.demo.service.Temporary.RedService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.math.BigDecimal; + +/** + * @program: GOLD + * @ClassName RedController + * @description: + * @author: huangqizhen + * @create: 2025−12-03 16:47 + * @Version 1.0 + **/ +@RestController +@RequestMapping("/Temporary") +@RequiredArgsConstructor +@Slf4j +@CrossOrigin +public class RedController { + @Autowired + private RedService redService; + @RequestMapping("/Red") + public Result selectSum(@RequestBody Red red) { + try { + redService.selectSum(red.getJwcode(),red.getType()); + } + catch (Exception e) { + return Result.error(e.getMessage()); + } + return Result.success(redService.selectSum(red.getJwcode(),red.getType())); + } +} diff --git a/src/main/java/com/example/demo/domain/vo/Red.java b/src/main/java/com/example/demo/domain/vo/Red.java new file mode 100644 index 0000000..4607f41 --- /dev/null +++ b/src/main/java/com/example/demo/domain/vo/Red.java @@ -0,0 +1,32 @@ +package com.example.demo.domain.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.checkerframework.checker.units.qual.N; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * @program: GOLD + * @ClassName red + * @description: + * @author: huangqizhen + * @create: 2025−12-03 16:31 + * @Version 1.0 + **/ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class Red { + private Integer id; + private Integer jwcode; + private BigDecimal sum; + private Integer type; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") + private Date czTime; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") + private Date updateTime; +} diff --git a/src/main/java/com/example/demo/mapper/Temporary/RedMapper.java b/src/main/java/com/example/demo/mapper/Temporary/RedMapper.java new file mode 100644 index 0000000..347cf55 --- /dev/null +++ b/src/main/java/com/example/demo/mapper/Temporary/RedMapper.java @@ -0,0 +1,19 @@ +package com.example.demo.mapper.Temporary; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.math.BigDecimal; + +/** + * @program: GOLD + * @ClassName RedMapper + * @description: + * @author: huangqizhen + * @create: 2025−12-03 17:03 + * @Version 1.0 + **/ +@Mapper +public interface RedMapper { + BigDecimal selectSum(@Param("jwcode") Integer jwcode, @Param("type") Integer type); +} diff --git a/src/main/java/com/example/demo/security/SecurityConfig.java b/src/main/java/com/example/demo/security/SecurityConfig.java index 3e6d045..a237b44 100644 --- a/src/main/java/com/example/demo/security/SecurityConfig.java +++ b/src/main/java/com/example/demo/security/SecurityConfig.java @@ -60,7 +60,7 @@ public class SecurityConfig { request .requestMatchers( HttpMethod.POST, // 用户不登录就可以访问的路径 - "/admin/login","/upload/**","/detailY/ERP","/home/java/haiwaiyanfa/gold1/**","/home/java/haiwaiyanfa/**","/statistics/**","/Mysql/**").permitAll() + "/admin/login","/upload/**","/detailY/ERP","/home/java/haiwaiyanfa/gold1/**","/home/java/haiwaiyanfa/**","/statistics/**","/Mysql/**","/Temporary/**").permitAll() .requestMatchers( "/error","alipay/**","/upload/**","/home/java/haiwaiyanfa/gold1/**","/home/java/haiwaiyanfa/**" ).permitAll() diff --git a/src/main/java/com/example/demo/service/Temporary/RedService.java b/src/main/java/com/example/demo/service/Temporary/RedService.java new file mode 100644 index 0000000..3a8de81 --- /dev/null +++ b/src/main/java/com/example/demo/service/Temporary/RedService.java @@ -0,0 +1,17 @@ +package com.example.demo.service.Temporary; + +import com.example.demo.domain.vo.Red; + +import java.math.BigDecimal; + +/** + * @program: GOLD + * @ClassName RedService + * @description: + * @author: huangqizhen + * @create: 2025−12-03 16:38 + * @Version 1.0 + **/ +public interface RedService { + BigDecimal selectSum(Integer jwcode, Integer type); +} diff --git a/src/main/java/com/example/demo/serviceImpl/Temporary/RedServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/Temporary/RedServiceImpl.java new file mode 100644 index 0000000..7971507 --- /dev/null +++ b/src/main/java/com/example/demo/serviceImpl/Temporary/RedServiceImpl.java @@ -0,0 +1,35 @@ +package com.example.demo.serviceImpl.Temporary; + +import com.example.demo.Util.BusinessException; +import com.example.demo.domain.vo.Red; +import com.example.demo.exception.SystemException; +import com.example.demo.mapper.Temporary.RedMapper; +import com.example.demo.service.Temporary.RedService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; + +/** + * @program: GOLD + * @ClassName RedServiceImpl + * @description: + * @author: huangqizhen + * @create: 2025−12-03 16:37 + * @Version 1.0 + **/ +@Service +public class RedServiceImpl implements RedService { + @Autowired + private RedMapper redMapper; + @Override + public BigDecimal selectSum(Integer jwcode,Integer type) { + if (jwcode == null){ + throw new BusinessException("未接受到精网号"); + } + if (type == null){ + throw new BusinessException("未接受到类型"); + } + return redMapper.selectSum(jwcode,type); + } +} diff --git a/src/main/resources/mapper/RedMapper.xml b/src/main/resources/mapper/RedMapper.xml new file mode 100644 index 0000000..51046ad --- /dev/null +++ b/src/main/resources/mapper/RedMapper.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file From 72d63cbc167e46b2985f4ea6eca0349a54471f45 Mon Sep 17 00:00:00 2001 From: huangqizhen <15552608129@163.com> Date: Wed, 3 Dec 2025 20:43:54 +0800 Subject: [PATCH 2/3] =?UTF-8?q?12.3=20=E5=86=B2=E5=88=BA=E8=AE=A1=E5=88=92?= =?UTF-8?q?=E7=B4=AF=E8=AE=A1=E5=85=85=E5=80=BC=E9=80=BB=E8=BE=91=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/demo/config/RedTimeRuleConfig.java | 23 +++++++ .../example/demo/mapper/Temporary/RedMapper.java | 6 ++ .../example/demo/service/Temporary/RedService.java | 1 + .../demo/serviceImpl/Temporary/RedServiceImpl.java | 70 ++++++++++++++++++++++ .../demo/serviceImpl/coin/AuditServiceImpl.java | 24 +++++++- src/main/resources/mapper/RedMapper.xml | 15 +++++ 6 files changed, 137 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/example/demo/config/RedTimeRuleConfig.java diff --git a/src/main/java/com/example/demo/config/RedTimeRuleConfig.java b/src/main/java/com/example/demo/config/RedTimeRuleConfig.java new file mode 100644 index 0000000..4396b0b --- /dev/null +++ b/src/main/java/com/example/demo/config/RedTimeRuleConfig.java @@ -0,0 +1,23 @@ +package com.example.demo.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.time.ZoneId; + +// 可放入 application.yml(推荐),或写死在代码(演示用) +@ConfigurationProperties(prefix = "business.rules.red") +@Data +@Component +public class RedTimeRuleConfig { + // 充值开放时间:2025-12-04 20:00:00(北京时间) + private LocalDateTime rechargeStartTime = LocalDateTime.of(2025, 12, 4, 20, 0, 0); + + // 消费开放时间:2025-12-06 10:00:00(北京时间) + private LocalDateTime consumeStartTime = LocalDateTime.of(2025, 12, 6, 10, 0, 0); + + // 时区:中国标准时间 + private ZoneId zoneId = ZoneId.of("Asia/Shanghai"); +} \ No newline at end of file diff --git a/src/main/java/com/example/demo/mapper/Temporary/RedMapper.java b/src/main/java/com/example/demo/mapper/Temporary/RedMapper.java index 347cf55..9dd1af7 100644 --- a/src/main/java/com/example/demo/mapper/Temporary/RedMapper.java +++ b/src/main/java/com/example/demo/mapper/Temporary/RedMapper.java @@ -16,4 +16,10 @@ import java.math.BigDecimal; @Mapper public interface RedMapper { BigDecimal selectSum(@Param("jwcode") Integer jwcode, @Param("type") Integer type); + //查询是否有该精网号 + boolean selectJwcode(@Param("jwcode") Integer jwcode); + + int upsertAndAdd(@Param("jwcode") Integer jwcode, + @Param("type") Integer type, + @Param("sum") BigDecimal sum); } diff --git a/src/main/java/com/example/demo/service/Temporary/RedService.java b/src/main/java/com/example/demo/service/Temporary/RedService.java index 3a8de81..97672bb 100644 --- a/src/main/java/com/example/demo/service/Temporary/RedService.java +++ b/src/main/java/com/example/demo/service/Temporary/RedService.java @@ -14,4 +14,5 @@ import java.math.BigDecimal; **/ public interface RedService { BigDecimal selectSum(Integer jwcode, Integer type); + void addAmount(Integer jwcode,BigDecimal sum, Integer type); } diff --git a/src/main/java/com/example/demo/serviceImpl/Temporary/RedServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/Temporary/RedServiceImpl.java index 7971507..d4beee3 100644 --- a/src/main/java/com/example/demo/serviceImpl/Temporary/RedServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/Temporary/RedServiceImpl.java @@ -1,14 +1,18 @@ package com.example.demo.serviceImpl.Temporary; import com.example.demo.Util.BusinessException; +import com.example.demo.config.RedTimeRuleConfig; import com.example.demo.domain.vo.Red; import com.example.demo.exception.SystemException; import com.example.demo.mapper.Temporary.RedMapper; import com.example.demo.service.Temporary.RedService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; /** * @program: GOLD @@ -22,14 +26,80 @@ import java.math.BigDecimal; public class RedServiceImpl implements RedService { @Autowired private RedMapper redMapper; + @Autowired + private RedTimeRuleConfig timeRuleConfig; @Override public BigDecimal selectSum(Integer jwcode,Integer type) { if (jwcode == null){ throw new BusinessException("未接受到精网号"); } + if (redMapper.selectJwcode(jwcode)==false){ + throw new BusinessException("未找到该精网号"); + } + if(redMapper.selectJwcode(jwcode)) if (type == null){ throw new BusinessException("未接受到类型"); } + if (type !=1 && type != 2){ + throw new BusinessException("类型错误"); + } return redMapper.selectSum(jwcode,type); } + + @Override + @Transactional(rollbackFor = Exception.class) + public void addAmount(Integer jwcode, BigDecimal sum, Integer type) { + // 1. 基础参数校验 + validateParams(jwcode, type, sum); + + // 2. ⭐⭐⭐ 时间窗口校验(关键!) + validateTimeWindow(type, sum); + + // 3. 执行原子累加 + int affected = redMapper.upsertAndAdd(jwcode, type, sum); + if (affected == 0) { + throw new BusinessException("操作失败,请重试"); + } + } + + // --- 校验方法 --- + private void validateParams(Integer jwcode, Integer type, BigDecimal delta) { + if (jwcode == null || jwcode <= 0) { + throw new BusinessException("精网号无效"); + } + if (type == null || (type != 1 && type != 2)) { + throw new BusinessException("类型必须为 1(充值)或 2(消费)"); + } + if (delta == null || delta.compareTo(BigDecimal.ZERO) == 0) { + throw new BusinessException("变动金额不能为0"); + } + } + + private void validateTimeWindow(Integer type, BigDecimal delta) { + LocalDateTime now = LocalDateTime.now(timeRuleConfig.getZoneId()); + + if (type == 1) { + // 充值:必须 delta > 0,且当前时间 >= rechargeStartTime + if (delta.compareTo(BigDecimal.ZERO) < 0) { + throw new BusinessException("充值金额不能为负数"); + } + if (now.isBefore(timeRuleConfig.getRechargeStartTime())) { + String openTime = timeRuleConfig.getRechargeStartTime() + .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")); + throw new BusinessException("红包充值通道暂未开放,请于 " + openTime + " 后操作"); + } + } + else if (type == 2) { + // 消费:必须 delta < 0(或你设计为正数+方向,此处按负数扣款) + if (delta.compareTo(BigDecimal.ZERO) > 0) { + throw new BusinessException("消费金额应为负数(表示扣款)"); + } + if (now.isBefore(timeRuleConfig.getConsumeStartTime())) { + String openTime = timeRuleConfig.getConsumeStartTime() + .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")); + throw new BusinessException("红包消费通道暂未开放,请于 " + openTime + " 后操作"); + } + } + } } + diff --git a/src/main/java/com/example/demo/serviceImpl/coin/AuditServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/coin/AuditServiceImpl.java index c704f61..846706d 100644 --- a/src/main/java/com/example/demo/serviceImpl/coin/AuditServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/coin/AuditServiceImpl.java @@ -10,16 +10,19 @@ import com.example.demo.domain.vo.coin.RefundAudit; import com.example.demo.mapper.coin.AuditMapper; import com.example.demo.mapper.coin.MarketMapper; import com.example.demo.mapper.coin.UserMapper; +import com.example.demo.service.Temporary.RedService; import com.example.demo.service.coin.AdminService; import com.example.demo.service.coin.AuditService; import com.example.demo.service.coin.GeneralService; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; +import java.math.RoundingMode; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; @@ -35,6 +38,7 @@ import java.util.List; **/ @Service +@Slf4j public class AuditServiceImpl implements AuditService { @Autowired private AuditMapper auditMapper; @@ -46,6 +50,8 @@ public class AuditServiceImpl implements AuditService { private GeneralService generalService; @Autowired private MarketMapper marketMapper; + @Autowired + private RedService redService; /* 审核订单并修改用户余额等 */ @@ -111,15 +117,29 @@ public class AuditServiceImpl implements AuditService { auditMapper.updateFirstRecharge(order.getJwcode());//设置首充时间为当前时间 } auditMapper.updateUserGold(update); + + + //累充 + try { + BigDecimal sum = BigDecimal.valueOf( + order.getPermanentGold() + order.getFreeJune() + order.getFreeDecember() + ).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP); + + redService.addAmount(order.getJwcode(), sum, 1); // ← 直接调你写好的方法! + } catch (Exception e) { + log.warn("红包累加失败,主流程继续 | jwcode={}", order.getJwcode(), e); + } + + //erp增加充值数据 - // if(update.getJwcode().equals(94226013)){ + GoldTistV2.addCoinNew(order.getJwcode().toString(), 64, //充值永久金币 (double) (order.getPermanentGold() ) /100, order.getRemark(),(double) (order.getPermanentGold() ) /100, auditName, "金币充值"); GoldTistV2.addCoinNew(order.getJwcode().toString(), 63, //充值免费 (double) (order.getFreeDecember()+order.getFreeJune() ) /100, order.getRemark(),0, auditName, "金币充值"); - // } + }else if (order.getType()==2) { //退款 //2.获取对应的订单(退款订单号去掉开头"TK"即为对应原始订单) String oldOrderCode = order.getOrderCode().replaceFirst("TK_", ""); diff --git a/src/main/resources/mapper/RedMapper.xml b/src/main/resources/mapper/RedMapper.xml index 51046ad..56d6479 100644 --- a/src/main/resources/mapper/RedMapper.xml +++ b/src/main/resources/mapper/RedMapper.xml @@ -3,7 +3,22 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> + + INSERT INTO red_account (jwcode, type, sum) + VALUES ( + #{jwcode}, + #{type}, + #{sum}, + ) + ON DUPLICATE KEY UPDATE + sum = sum + #{sum} + + \ No newline at end of file From 8e40c6cdb65eecb1652f0e1834fe92717df11259 Mon Sep 17 00:00:00 2001 From: lijianlin Date: Thu, 4 Dec 2025 09:59:19 +0800 Subject: [PATCH 3/3] =?UTF-8?q?12-04=20=E5=8F=91=E9=80=81=E7=B2=BE?= =?UTF-8?q?=E7=BD=91=E5=8F=B7=E6=96=B9=E6=B3=95=EF=BC=8C=E5=82=A8=E5=80=BC?= =?UTF-8?q?=E5=8F=91=E9=80=81=E7=B2=BE=E7=BD=91=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/demo/service/Temporary/RedService.java | 3 +- .../demo/serviceImpl/Temporary/RedServiceImpl.java | 44 ++++++++++++++++++++++ .../demo/serviceImpl/coin/AuditServiceImpl.java | 9 +++-- 3 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/example/demo/service/Temporary/RedService.java b/src/main/java/com/example/demo/service/Temporary/RedService.java index 97672bb..c34495e 100644 --- a/src/main/java/com/example/demo/service/Temporary/RedService.java +++ b/src/main/java/com/example/demo/service/Temporary/RedService.java @@ -14,5 +14,6 @@ import java.math.BigDecimal; **/ public interface RedService { BigDecimal selectSum(Integer jwcode, Integer type); - void addAmount(Integer jwcode,BigDecimal sum, Integer type); + void addAmount(Integer jwcode,BigDecimal sum, Integer type); + String sendJwcode(Integer jwcode); } diff --git a/src/main/java/com/example/demo/serviceImpl/Temporary/RedServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/Temporary/RedServiceImpl.java index d4beee3..91041e7 100644 --- a/src/main/java/com/example/demo/serviceImpl/Temporary/RedServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/Temporary/RedServiceImpl.java @@ -1,19 +1,27 @@ package com.example.demo.serviceImpl.Temporary; +import com.alibaba.fastjson.JSON; import com.example.demo.Util.BusinessException; import com.example.demo.config.RedTimeRuleConfig; import com.example.demo.domain.vo.Red; import com.example.demo.exception.SystemException; import com.example.demo.mapper.Temporary.RedMapper; import com.example.demo.service.Temporary.RedService; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.io.IOException; import java.math.BigDecimal; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; + /** * @program: GOLD * @ClassName RedServiceImpl @@ -22,8 +30,15 @@ import java.time.format.DateTimeFormatter; * @create: 2025−12-03 16:37 * @Version 1.0 **/ +@Slf4j @Service public class RedServiceImpl implements RedService { + private static final String BASE_URLProd = "http://39.101.133.168:8828/scms"; + private static final String BASE_URLDev = "http://gf977328.natappfree.cc"; + private static final String PATH = "/api/coupon/IssueRechargeRedPacket"; + + private static final HttpClient CLIENT = HttpClient.newHttpClient(); + @Autowired private RedMapper redMapper; @Autowired @@ -62,6 +77,35 @@ public class RedServiceImpl implements RedService { } } + + /* + 调用充值红包发放接口 + + */ + @Override + public String sendJwcode(Integer jwcode) { + try { + String body = JSON.toJSONString(java.util.Map.of("jwcode", jwcode)); + + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(BASE_URLDev + PATH)) //URL记得换 + .header("Content-Type", "application/json") + .POST(HttpRequest.BodyPublishers.ofString(body)) + .build(); + + HttpResponse resp = CLIENT.send(request, HttpResponse.BodyHandlers.ofString()); + + if (resp.statusCode() != 200) { + log.warn("红包接口异常,status:{},body:{}", resp.statusCode(), resp.body()); + } + return resp.body(); + } catch (IOException | InterruptedException e) { + log.error("调用红包接口失败,jwcode:{}", jwcode, e); + return "{\"success\":false,\"msg\":\"网络异常\"}"; + } + } + + // --- 校验方法 --- private void validateParams(Integer jwcode, Integer type, BigDecimal delta) { if (jwcode == null || jwcode <= 0) { diff --git a/src/main/java/com/example/demo/serviceImpl/coin/AuditServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/coin/AuditServiceImpl.java index 846706d..4c5772d 100644 --- a/src/main/java/com/example/demo/serviceImpl/coin/AuditServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/coin/AuditServiceImpl.java @@ -120,15 +120,16 @@ public class AuditServiceImpl implements AuditService { //累充 - try { + /* try { BigDecimal sum = BigDecimal.valueOf( - order.getPermanentGold() + order.getFreeJune() + order.getFreeDecember() - ).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP); + order.getPermanentGold()) + .divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP); redService.addAmount(order.getJwcode(), sum, 1); // ← 直接调你写好的方法! } catch (Exception e) { log.warn("红包累加失败,主流程继续 | jwcode={}", order.getJwcode(), e); - } + }*/ + redService.sendJwcode(order.getJwcode()); //erp增加充值数据