Explorar el Código

feat: 调整异常处理逻辑和日志切面

weijianghai hace 2 años
padre
commit
639235c06e

+ 4 - 0
pom.xml

@@ -43,6 +43,10 @@
             <artifactId>spring-boot-starter-test</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.projectlombok</groupId>
             <artifactId>lombok</artifactId>

+ 70 - 0
src/main/java/com/nokia/domainb/config/ControllerExceptionHandler.java

@@ -0,0 +1,70 @@
+package com.nokia.domainb.config;
+
+import com.nokia.common.http.R;
+import lombok.extern.slf4j.Slf4j;
+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.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import javax.validation.ConstraintViolationException;
+
+/**
+ * 请求异常处理
+ */
+@Slf4j
+@RestControllerAdvice
+public class ControllerExceptionHandler
+{
+    @ExceptionHandler(HttpMessageNotReadableException.class)
+    public ResponseEntity<Object> httpMessageNotReadableExceptionValidatorHandler(HttpMessageNotReadableException e)
+    {
+        log.warn("╭( ′• o •′ )╭☞ 请求参数校验未通过: {}", e.getMessage());
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(R.error().message(e.getMessage()));
+    }
+
+    @ExceptionHandler(BindException.class)
+    public ResponseEntity<Object> bindExceptionValidatorHandler(BindException e)
+    {
+        FieldError fieldError = e.getBindingResult().getFieldError();
+        String message = "";
+        if (fieldError != null)
+        {
+            message = fieldError.getDefaultMessage();
+            log.warn("╭( ′• o •′ )╭☞ 请求参数校验未通过: {}", message);
+        }
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(R.error().message(message));
+    }
+
+    @ExceptionHandler(ConstraintViolationException.class)
+    public ResponseEntity<Object> constraintViolationExceptionValidatorHandler(ConstraintViolationException e)
+    {
+        String message = e.getConstraintViolations().iterator().next().getMessage();
+        log.warn("╭( ′• o •′ )╭☞ 请求参数校验未通过: {}", message);
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(R.error().message(message));
+    }
+
+    @ExceptionHandler(MethodArgumentNotValidException.class)
+    public ResponseEntity<Object> methodArgumentNotValidExceptionValidatorHandler(MethodArgumentNotValidException e)
+    {
+        FieldError fieldError = e.getBindingResult().getFieldError();
+        String message = "";
+        if (fieldError != null)
+        {
+            message = fieldError.getDefaultMessage();
+            log.warn("╭( ′• o •′ )╭☞ 请求参数校验未通过: {}", message);
+        }
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(R.error().message(message));
+    }
+    
+    @ExceptionHandler({Exception.class})
+    public ResponseEntity<Object> exceptionHandler(Exception e)
+    {
+        log.error("╭( ′• o •′ )╭☞ 发生错误了 {}", e.getMessage(), e);
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(R.error());
+    }
+}

+ 50 - 16
src/main/java/com/nokia/domainb/config/LogAspectConfig.java

@@ -1,6 +1,6 @@
 package com.nokia.domainb.config;
 
-import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson.JSON;
 import lombok.extern.slf4j.Slf4j;
 import org.aspectj.lang.JoinPoint;
 import org.aspectj.lang.ProceedingJoinPoint;
@@ -8,7 +8,9 @@ import org.aspectj.lang.annotation.Around;
 import org.aspectj.lang.annotation.Aspect;
 import org.aspectj.lang.annotation.Before;
 import org.aspectj.lang.annotation.Pointcut;
+import org.slf4j.MDC;
 import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
 import org.springframework.util.StopWatch;
 import org.springframework.web.context.request.RequestContextHolder;
 import org.springframework.web.context.request.ServletRequestAttributes;
@@ -17,22 +19,50 @@ import org.springframework.web.multipart.MultipartFile;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
 
 /**
- * 日志切面
+ * 日志配置
+ *
  */
 @Aspect
 @Component
 @Slf4j
 public class LogAspectConfig
 {
+    @Pointcut("execution(* com.nokia..ControllerExceptionHandler.*ValidatorHandler(..))")
+    public void validatorExceptionHandlerPointcut()
+    {
+        // Pointcut
+    }
+
     @Pointcut("execution(public * com.nokia..*Controller.*(..))")
     public void controllerPointcut()
     {
         // Pointcut
     }
 
-    @Before("controllerPointcut()")
+    @Pointcut("execution(* com.nokia..ControllerExceptionHandler.*(..))")
+    public void controllerExceptionHandlerPointcut()
+    {
+        // Pointcut
+    }
+
+    @Pointcut("controllerPointcut() || validatorExceptionHandlerPointcut()")
+    public void beforePointCut()
+    {
+        // Pointcut
+    }
+
+    @Pointcut("controllerPointcut() || controllerExceptionHandlerPointcut()")
+    public void afterPointCut()
+    {
+        // Pointcut
+    }
+
+    @Before("beforePointCut()")
     public void doBefore(JoinPoint joinPoint)
     {
         ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
@@ -41,32 +71,36 @@ public class LogAspectConfig
             return;
         }
         HttpServletRequest request = attributes.getRequest();
+        // 打印请求信息
         log.info("请求地址: {} {}", request.getRequestURL().toString(), request.getMethod());
+        // 打印请求参数
         Object[] args = joinPoint.getArgs();
-        Object[] arguments = new Object[args.length];
-        for (int i = 0; i < args.length; i++)
-        {
-            if (args[i] instanceof ServletRequest
-                    || args[i] instanceof ServletResponse
-                    || args[i] instanceof MultipartFile
-                    || args[i] instanceof Exception
-            )
-            {
+        List<Object> list = new ArrayList<>();
+        for (Object arg : args) {
+            if (arg instanceof ServletRequest
+                    || arg instanceof ServletResponse
+                    || arg instanceof MultipartFile
+                    || arg instanceof Exception
+            ) {
                 continue;
             }
-            arguments[i] = args[i];
+            list.add(arg);
+        }
+        if (CollectionUtils.isEmpty(list)) {
+            return;
         }
-        log.info("入参: {}", JSON.toJSONString(arguments));
+        log.info("请求参数: {}", JSON.toJSONString(list));
     }
 
-    @Around("controllerPointcut()")
+    @Around("afterPointCut()")
     public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable
     {
         StopWatch stopWatch = new StopWatch();
         stopWatch.start();
+        MDC.put("traceId", UUID.randomUUID().toString().replace("-", ""));
         Object result = proceedingJoinPoint.proceed();
-        log.info("结果: {}", JSON.toJSONString(result));
         stopWatch.stop();
+        log.info("返回: {}", JSON.toJSONString(result));
         log.info("耗时:{} ms", stopWatch.getTotalTimeMillis());
         return result;
     }

+ 0 - 24
src/main/java/com/nokia/domainb/exception/ControllerExceptionHandler.java

@@ -1,24 +0,0 @@
-package com.nokia.domainb.exception;
-
-import com.nokia.common.http.R;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.bind.annotation.ExceptionHandler;
-import org.springframework.web.bind.annotation.RestControllerAdvice;
-
-/**
- * 请求异常处理
- */
-@Slf4j
-@RestControllerAdvice
-public class ControllerExceptionHandler
-{
-    @SuppressWarnings("rawtypes")
-    @ExceptionHandler({Exception.class})
-    public ResponseEntity exceptionHandler(Exception e)
-    {
-        log.error("╭( ′• o •′ )╭☞ 发生错误了 {}", e.getMessage(), e);
-        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(R.error().message(e.getMessage()));
-    }
-}

+ 30 - 0
src/main/java/com/nokia/domainb/service/DomainService.java

@@ -30,6 +30,11 @@ public class DomainService {
         JsonObject rsp = jsonObject.getAsJsonObject("UNI_BSS_BODY")
                 .getAsJsonObject("QRYROUTEALL_RSP")
                 .getAsJsonObject("RSP");
+        if (rsp == null) {
+            log.error("路由查询接口响应异常");
+            return R.error().message("能开接口调用异常");
+        }
+
         String rspCode = rsp.get("RSP_CODE").getAsString();
         if (!"0000".equals(rspCode)) {
             String rspDesc = rsp.get("RSP_DESC").getAsString();
@@ -83,6 +88,11 @@ public class DomainService {
         JsonObject rsp = jsonObject.getAsJsonObject("UNI_BSS_BODY")
                 .getAsJsonObject("QRY_USER_IS_UDM_RSP")
                 .getAsJsonObject("RSP");
+        if (rsp == null) {
+            log.error("5g用户查询接口响应异常");
+            return R.error().message("能开接口调用异常");
+        }
+
         String rspCode = rsp.get("RSP_CODE").getAsString();
         if (!"0000".equals(rspCode)) {
             String rspDesc = rsp.get("RSP_DESC").getAsString();
@@ -111,6 +121,11 @@ public class DomainService {
         JsonObject rsp = jsonObject.getAsJsonObject("UNI_BSS_BODY")
                 .getAsJsonObject("FOREIGN_PRODUCT_RSP")
                 .getAsJsonObject("RSP");
+        if (rsp == null) {
+            log.error("已订购产品查询接口响应异常");
+            return R.error().message("能开接口调用异常");
+        }
+
         String rspCode = rsp.get("RSP_CODE").getAsString();
         if (!"0000".equals(rspCode)) {
             String rspDesc = rsp.get("RSP_DESC").getAsString();
@@ -150,6 +165,11 @@ public class DomainService {
         JsonObject rsp = jsonObject.getAsJsonObject("UNI_BSS_BODY")
                 .getAsJsonObject("SP_THREEPART_CHECK_RSP")
                 .getAsJsonObject("RSP");
+        if (rsp == null) {
+            log.error("用户资料三户返回接口响应异常");
+            return R.error().message("能开接口调用异常");
+        }
+
         String rspCode = rsp.get("RSP_CODE").getAsString();
         if (!"0000".equals(rspCode)) {
             String rspDesc = rsp.get("RSP_DESC").getAsString();
@@ -222,6 +242,11 @@ public class DomainService {
             JsonObject rsp = jsonObject.getAsJsonObject("UNI_BSS_BODY")
                     .getAsJsonObject("QRY_OWE_FEE_RSP")
                     .getAsJsonObject("RSP");
+            if (rsp == null) {
+                log.error("欠费查询接口响应异常");
+                return R.error().message("能开接口调用异常");
+            }
+
             String rspCode = rsp.get("RSP_CODE").getAsString();
             if (!"0000".equals(rspCode)) {
                 String rspDesc = rsp.get("RSP_DESC").getAsString();
@@ -265,6 +290,11 @@ public class DomainService {
             JsonObject rsp = jsonObject.getAsJsonObject("UNI_BSS_BODY")
                     .getAsJsonObject("GET_ECREDIT_RSP")
                     .getAsJsonObject("RSP");
+            if (rsp == null) {
+                log.error("用户信用度查询接口响应异常");
+                return R.error().message("能开接口调用异常");
+            }
+
             String rspCode = rsp.get("RSP_CODE").getAsString();
             if (!"0000".equals(rspCode)) {
                 String rspDesc = rsp.get("RSP_DESC").getAsString();

+ 2 - 2
src/main/java/com/nokia/domainb/util/Utils.java

@@ -25,12 +25,12 @@ public class Utils {
 //        String location = "classpath:data/2000.txt";
 //        String location = "classpath:data/5000.txt";
 //        String location = "classpath:data/8000.txt";
-        String location = "classpath:data/10000.txt";
+//        String location = "classpath:data/10000.txt";
 //        String location = "classpath:data/10000+.txt";
 //        String location = "classpath:data/测试号码2.txt";
 //        String location = "classpath:data/测试号码1万多.txt";
 //        String location = "classpath:data/100route.txt";
-//        String location = "classpath:data/1000route.txt";
+        String location = "classpath:data/1000route.txt";
         FileInputStream fis;
         try {
             File file = ResourceUtils.getFile(location);

+ 3 - 3
src/main/resources/logback-spring.xml

@@ -3,7 +3,7 @@
     <property name="PATH" value="./log"/>
     <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
         <encoder>
-            <Pattern>%d{HH:mm:ss.SSS} %highlight(%-5level) %blue(%logger:%line) %msg%n</Pattern>
+            <Pattern>%d{HH:mm:ss.SSS} %highlight(%-5level) %yellow(%X{traceId}) %cyan(%logger:%line) %msg%n</Pattern>
         </encoder>
     </appender>
     <appender name="TRACE_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
@@ -17,7 +17,7 @@
             <totalSizeCap>20GB</totalSizeCap>
         </rollingPolicy>
         <encoder>
-            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) %blue(%logger:%line) %msg%n</Pattern>
+            <Pattern>%d %highlight(%-5level) %yellow(%X{traceId}) %cyan(%logger:%line) %msg%n</Pattern>
         </encoder>
     </appender>
     <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
@@ -31,7 +31,7 @@
             <totalSizeCap>20GB</totalSizeCap>
         </rollingPolicy>
         <encoder>
-            <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) %blue(%logger:%line) %msg%n</Pattern>
+            <Pattern>%d %highlight(%-5level) %yellow(%X{traceId}) %cyan(%logger:%line) %msg%n</Pattern>
         </encoder>
         <filter class="ch.qos.logback.classic.filter.LevelFilter">
             <level>ERROR</level>

+ 31 - 8
src/test/java/com/nokia/domainb/capability/QryOweFeeTest.java

@@ -2,12 +2,18 @@ package com.nokia.domainb.capability;
 
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
+import com.nokia.domainb.util.Utils;
+import de.siegmar.fastcsv.writer.CsvWriter;
 import lombok.extern.slf4j.Slf4j;
 import org.junit.jupiter.api.Test;
 
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.time.LocalDateTime;
+import java.util.Set;
+
 @Slf4j
 class QryOweFeeTest {
     @Test
@@ -38,10 +44,27 @@ class QryOweFeeTest {
         System.out.println(realFee);
     }
 
-    @AllArgsConstructor
-    @NoArgsConstructor
-    @Data
-    static class Dto {
-        private String data;
+    @Test
+    void test() {
+        QryOweFee qryOweFee = new QryOweFee();
+        Set<String> phones = Utils.readPhones();
+        String filePath = "result/欠费查询接口1000条数据测试结果.csv";
+        try (OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(Paths.get(filePath)), "GBK");
+             CsvWriter csv = CsvWriter.builder().build(osw);) {
+            csv.writeRow("手机号", "时间", "调用时长", "结果");
+            phones.forEach(t -> {
+                String[] a = t.split(",");
+                String phone = a[0];
+                String provinceCode = a[1];
+                LocalDateTime startTime = LocalDateTime.now();
+                long startTimestamp = System.currentTimeMillis();
+                String result = qryOweFee.query(phone, provinceCode);
+                long endTimestamp = System.currentTimeMillis();
+                long cost = endTimestamp - startTimestamp;
+                csv.writeRow(phone, startTime.toString(), String.valueOf(cost), result);
+            });
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
     }
 }