• java练习生 AOP【日志】【异常处理】


    一、添加依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    
    

    二、添加AOP操作类

    2.1 指定方法切面,做日志输出

    package com.vcredit.fts.common.aop.exception;
    
    import com.alibaba.fastjson.JSON;
    import com.vcredit.fts.common.util.IPUtil;
    import lombok.Setter;
    import lombok.extern.log4j.Log4j2;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    
    import javax.servlet.http.HttpServletRequest;
    
    @Log4j2
    @Aspect
    @Component
    public class LogAspect {
        private ThreadLocal<ApiLogAspect.ApiLog> apiLogThreadLocal = new ThreadLocal<>();
    
    
        /**
         * 声明切点
         */
        @Pointcut("execution(* com..web.*Controller.*(..))")
        public void pointCut() {
        }
    
        @Around("pointCut()")
        public final Object doPrintLog(ProceedingJoinPoint joinPoint) throws Throwable {
            return check(joinPoint);
        }
    
        protected Object check(ProceedingJoinPoint joinPoint) throws Throwable {
            Object result = null;
            try {
                apiLogThreadLocal.set(ApiLogAspect.ApiLog.newInstance());
                doBefore(joinPoint);
                result = joinPoint.proceed(joinPoint.getArgs());
                doAfterReturning(result);
            } catch (Throwable e) {
                doException(e);
                throw e;
            } finally {
                apiLogThreadLocal.remove();
            }
            return result;
        }
    
        private void doException(Throwable e) {
            // 处理完请求,返回内容
            ApiLogAspect.ApiLog apiLog = apiLogThreadLocal.get();
            apiLog.setResponseBody("exception:" + e.getMessage());
            apiLog.setEndTime(System.currentTimeMillis());
            log.info(apiLog.toString());
        }
    
        private void doBefore(ProceedingJoinPoint joinPoint) {
            // 接收到请求,记录请求内容
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            // 记录下请求内容
            ApiLogAspect.ApiLog apiLog = apiLogThreadLocal.get();
            apiLog.setApiClassName(joinPoint.getSignature().getDeclaringTypeName());
            apiLog.setApiMethodName(joinPoint.getSignature().getName());
            apiLog.setRequestBody(JSON.toJSONString(joinPoint.getArgs()));
            apiLog.setRequestMethod(request.getMethod());
            apiLog.setRequestIp(IPUtil.getIpAddr(request));
            apiLog.setRequestUrl(request.getRequestURL().toString());
        }
    
        private void doAfterReturning(Object result) {
            // 处理完请求,返回内容
            ApiLogAspect.ApiLog apiLog = apiLogThreadLocal.get();
            apiLog.setResponseBody(JSON.toJSONString(result));
            apiLog.setEndTime(System.currentTimeMillis());
            log.info(apiLog.toString());
        }
    
    
        @Setter
        public static class ApiLog {
            private Long startTime;
            private Long endTime;
            private Long consumeTime;
            private String requestUrl;
            private String requestMethod;
            private String requestIp;
            private String apiClassName;
            private String apiMethodName;
            private String requestBody;
            private String responseBody;
    
            public static LogAspect.ApiLog newInstance() {
                return new LogAspect.ApiLog();
            }
    
            private ApiLog() {
                startTime = System.currentTimeMillis();
            }
    
            public void setEndTime(Long endTime) {
                this.endTime = endTime;
                this.consumeTime = this.endTime - this.startTime;
            }
    
            @Override
            public String toString() {
                StringBuffer buffer = new StringBuffer();
                buffer.append("耗时:").append(consumeTime).append("ms").append(" , ");
                buffer.append("URL:").append(requestUrl).append(" , ");
                buffer.append("IP:").append(requestIp).append(" , ");
                buffer.append("方式:").append(requestMethod).append(" , ");
                buffer.append("请求方法:").append(apiClassName).append(".").append(apiMethodName).append(" , ");
                buffer.append("\r\n");
                buffer.append("输入:").append(requestBody);
                buffer.append("\r\n");
                buffer.append("输出:").append(responseBody);
                return buffer.toString();
            }
    
        }
    }

    2.2 指定注解切面,做日志输出

    A:创建标记注解

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface OperationLog {
        /**
         * 操作方法
         *
         * @return
         */
        String value() default "";
    }

    B:创建切面处理类(包括mongo类)

    package com.vcredit.fts.common.aop.exception;
    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.JSONObject;
    import com.google.common.collect.Maps;
    import com.vcredit.fts.common.aop.exception.annotation.OperationLog;
    import com.vcredit.fts.common.service.mongo.MongoService;
    import com.vcredit.fts.common.util.IPUtil;
    import io.netty.util.internal.StringUtil;
    import lombok.Data;
    import lombok.extern.slf4j.Slf4j;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.aspectj.lang.reflect.MethodSignature;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.data.mongodb.core.index.Indexed;
    import org.springframework.data.mongodb.core.mapping.Document;
    import org.springframework.stereotype.Component;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.context.request.RequestContextHolder;
    import org.springframework.web.context.request.ServletRequestAttributes;
    
    import javax.annotation.Resource;
    import javax.servlet.http.HttpServletRequest;
    import java.lang.reflect.Method;
    import java.lang.reflect.Parameter;
    import java.time.LocalDateTime;
    import java.util.Map;
    
    @Slf4j
    @Aspect
    @Component
    public class OperationLogAspect {
        private ThreadLocal<WebOperationLogPO> sysOperatorLogThreadLocal = new ThreadLocal<>();
    
        @Resource
        private MongoService mongoService;
    
        @Pointcut("@annotation(com.vcredit.fts.common.aop.exception.annotation.OperationLog)")
        public void pointcut() {
        }
    
        @Around("pointcut()")
        public final Object doSaveUserLog(ProceedingJoinPoint joinPoint) throws Throwable {
            return check(joinPoint);
        }
    
        /**
         * 功能描述: 切面检查<br> 〈功能详细描述〉
         *
         * @param joinPoint 切面
         * @return Object
         * @throws Throwable
         */
        protected Object check(ProceedingJoinPoint joinPoint) throws Throwable {
            setSysOperatorLogBefore(joinPoint);
            Object result = joinPoint.proceed();
            setSysOperatorLogAfter(joinPoint);
            saveUserOperatorLog();
            return result;
        }
    
        /**
         * 设置操作日志属性(之前)
         *
         * @param joinPoint 代理对象
         */
        private void setSysOperatorLogBefore(ProceedingJoinPoint joinPoint) {
            WebOperationLogPO sysOperatorLog = new WebOperationLogPO();
            // 操作类型
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            OperationLog logAnnotation = method.getAnnotation(OperationLog.class);
            if (logAnnotation != null) {
                sysOperatorLog.setOperation(logAnnotation.value());
            }
            // 用户信息
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            String userName = request.getHeader(USER_NAME_KEY);
            if (StringUtil.isNullOrEmpty(userName)) {
                userName = "未知";
            }
            sysOperatorLog.setMethod(request.getMethod());
            sysOperatorLog.setCreaterUser(userName);
            sysOperatorLog.setCreateTime(LocalDateTime.now());
            sysOperatorLog.setIp(IPUtil.getIpAddr(request));
            sysOperatorLogThreadLocal.set(sysOperatorLog);
        }
    
        /**
         * 获取用户名key
         */
        private static final String USER_NAME_KEY = "userName";
    
        /**
         * 设置操作日志属性(之后)
         *
         * @param joinPoint 代理对象
         */
        private void setSysOperatorLogAfter(ProceedingJoinPoint joinPoint) {
            WebOperationLogPO sysOperatorLog = sysOperatorLogThreadLocal.get();
            // 请求参数
    //        Map paramMap = generateValueMap(joinPoint);
    //        sysOperatorLog.setContext(JSON.toJSONString(paramMap));
            sysOperatorLog.setContext(JSON.toJSONString(joinPoint.getArgs()));
        }
    
        /**
         * 保存操作日志
         */
        private void saveUserOperatorLog() {
            try {
                // 用户操作异常时,不保存操作日志
                WebOperationLogPO sysOperatorLog = sysOperatorLogThreadLocal.get();
                if (sysOperatorLog == null) {
                    return;
                }
                // 保存日志
                mongoService.save(sysOperatorLog, "Demo.OperationLog");
            } catch (Exception e) {
                log.warn("用户操作日志保存失败:{} , log : {}", e.getMessage(), JSON.toJSONString(sysOperatorLogThreadLocal.get()));
            } finally {
                // 清除threadLocal
                sysOperatorLogThreadLocal.remove();
            }
        }
    
    
        /**
         * 生成参数信息
         *
         * @param joinPoint
         * @return
         */
        protected final Map<String, Object> generateValueMap(ProceedingJoinPoint joinPoint) {
            Map<String, Object> valueMap = Maps.newHashMap();
            // 获取当前注解方法
            Object[] args = joinPoint.getArgs();
            MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
            Method method = methodSignature.getMethod();
            for (int i = 0; i < method.getParameters().length; i++) {
                Parameter parameter = method.getParameters()[i];
                if (parameter.getAnnotation(RequestBody.class) != null) {
                    JSONObject jsonObject;
                    if (args[i] instanceof String) {
                        jsonObject = JSON.parseObject(args[i].toString());
                    } else {
                        jsonObject = JSON.parseObject(JSON.toJSONString(args[i]));
                    }
                    generateValueMap(valueMap, jsonObject);
                } else {
                    valueMap.put(parameter.getName(), args[i]);
                }
            }
            return valueMap;
        }
    
        /**
         * 生成参数信息
         *
         * @param valueMap
         * @param jsonObject
         */
        protected final void generateValueMap(Map<String, Object> valueMap, JSONObject jsonObject) {
            for (Map.Entry<String,Object> entry : jsonObject.entrySet()) {
                String key = entry.getKey();
                Object value = entry.getValue();
                valueMap.put(key, value);
                if (value instanceof JSONObject) {
                    generateValueMap(valueMap, jsonObject.getJSONObject(key));
                }
            }
        }
    
    
        @Data
        @Document(collection = "Demo.OperationLog")
        public static class WebOperationLogPO{
            /**
             * 创建人
             */
            private String createrUser;
            /**
             * 内容
             */
            private String context;
            /**
             * ip地址
             */
            private String ip;
            /**
             * 目标方法
             */
            private String method;
            /**
             * 操作
             */
            @Indexed
            private String operation;
            /**
             * 创建时间
             */
            @Indexed
            private LocalDateTime createTime;
        }
    }

    C: 在需要添加操作记录的方法上添加注解

    /**
    * 清除指定缓存
    */
    @GetMapping(value = "/clear-redis/{redisKey}")
    @OperationLog("测试-clearRedis")
    public CommonResult clearRedis(@PathVariable String redisKey) {
    if (StringUtil.isNullOrEmpty(redisKey)) {
    return CommonResult.init(SystemStatus.PARAM_VALID_ERROR);
    }
    redisKey = RedisKeyFlag.BASE + redisKey;
    // 任务结束时,移除redis
    if (redisService.exists(redisKey)) {
    redisService.del(redisKey);
    } else if (redisKey.endsWith("*")) {
    var keys = redisService.keys(redisKey);
    if (!ListUtil.isNullOrEmpty(keys)) {
    redisService.del(keys);
    }
    }
    return CommonResult.successBase();
    }

    D:查看结果

    2.3 全局异常切面,做统一输出及报警

    A:创建系统公共返回枚举

    /**
     * 系统通用状态枚举
     *
     * @author huangzhongqing
     * @date 2020-12-04
     */
    public enum SystemStatus {
        // --------------- 成功 ---------------
        SYS_SUCCESS(0,"成功!"),
        // --------------- 系统异常 ---------------
        SYS_ERROR(1001,"系统异常!"),
        PARAM_VALID_ERROR(1002,"参数校验失败!"),
        CONGIG_ERROR(1003,"配置异常!"),
        EMPTY_ERROR(1003,"结果为空!"),
        PARAM_VALIDATE_ERROR(1003,"用户交互验证失败!"),
        IDEMPOTENT_CHECK_ERROR(1004,"幂等校验不通过!"),
        PROCESS_IS_RUNNING(1005,"当前流程正在处理中"),
        ENCRYPT_ERROR(1006,"数据加密异常"),
        DECRYPT_ERROR(1007,"数据解密异常"),
        // --------------- 外部异常 ---------------
        OUT_REQUEST_ERROR(2001,"调用外部接口异常"),
        ECM_DOWNLOAD_ERROR(2002,"调用ecm下载服务异常"),
        ECM_UPLOAD_ERROR(2003,"调用ecm上传服务异常"),
        SFTP_LOGIN_ERROR(2004,"sftp连接异常"),
        SFTP_CREAT_PATH_ERROR(2005,"sftp创建路径异常"),
        SFTP_SERVICE_ERROR(2006,"sftp服务器异常"),
        SFTP_UPLOAD_ERROR(2007,"sftp上传文件异常"),
        // --------------- 其他异常 ---------------
        EMAIL_SEND_ERROR(3001,"发送邮件异常"),
        CONTRACT_QUERY_DOING(3002,"合同文件列表为空,可能原因bid不存在或者合同生成中"),
        CONTRACT_QUERY_SERVICE_ERROR(3002,"查询文件异常"),
        FILE_QUERY_SERVICE_ERROR(3002,"查询合同文件列表异常"),
        FILE_QUERY_SQL_ERROR(3002,"查询合同文件异常"),
        FILE_TYPE_LIST_ERROR(3002,"文件类型列表为空"),
        DOC_SAVE_SQL_ERROR(3002,"保存文件信息异常"),
        QUERY_COUNT_CONFIG_ERROR(3002,"获取查询数量限制配置异常"),
        QUERY_COUNT_OVER_LIMIT_ERROR(3002,"查询数量查过配置限制查询数量"),
        UPDATE_QUERY_ERROR(3002,"更新流程信息失败,未查询到订单数据"),
        UPDATE_PROCESS_ERROR(3002,"更新流程信息异常"),
        SYNC_DATA_PROCESS_ERROR(3002,"流程类型不存在"),
        QUERY_SERVICE_ERROR(3002,"未查询到数据"),
        FILE_QUERY_CANCEL_ERROR(9000,"订单已解约"),
        NOT_ENUM_TYPE(9001,"aop参数类型错误,非枚举类型!"),
        ;
    
        private int code;
    
        private String message;
    
        SystemStatus(int code, String message) {
            this.code = code;
            this.message = message;
        }
    
        public int getCode() {
            return code;
        }
    
        public String getMessage() {
            return message;
        }
    
        public void setMessage(String message) { this.message = message; }
    }

    B:创建公共返回类

    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.experimental.Accessors;
    
    /**
     * 系统通用返回参数
     *
     * @author huangzhongqing
     * @date 2020-12-04
     */
    @Data
    @Accessors(chain = true)
    @NoArgsConstructor
    public class CommonResult<T> extends BaseModel {
        /**
         * 状态码
         */
        private int Code;
        /**
         * 消息
         */
        private String Message;
        /**
         * 结果
         */
        private T Result;
    
        private CommonResult(SystemStatus baseEnum) {
            this.Code = baseEnum.getCode();
            this.Message = baseEnum.getMessage();
        }
        private CommonResult(T result) {
            this.Code = SystemStatus.SYS_SUCCESS.getCode();
            this.Message = SystemStatus.SYS_SUCCESS.getMessage();
            this.Result = result;
        }
    
        private CommonResult( Integer code, String message) {
            this.Code = code;
            this.Message = message;
        }
    
        /**
         * 基本正确的返回
         * @return Result
         */
        public static CommonResult successBase() { return new CommonResult( SystemStatus.SYS_SUCCESS); }
    
        /**
         * 正确的返回帶返回体
         * @return Result
         */
        public static <T> CommonResult<T> successBase(T body) {
            return new CommonResult(body);
        }
    
        /**
         * 基本异常的返回
         * @return Result
         */
        public static CommonResult errorBase() {
            return new CommonResult(SystemStatus.SYS_ERROR);
        }
    
        /**
         * 自定义返回
         * @return Result
         */
        public static CommonResult init(SystemStatus code) {
            return new CommonResult(code);
        }
        /**
         * 指定异常枚举,返回错误信息
         * @param baseEnum 异常枚举
         * @return Result
         */
        public static CommonResult error(SystemStatus baseEnum) {
            return new CommonResult(baseEnum);
        }
    
        public static CommonResult error(Integer code, String alertMessage) {
            return new CommonResult(code,alertMessage);
        }
    }

    C:创建自定义异常类

    import com.vcredit.fts.common.model.enums.SystemStatus;
    import com.vcredit.fts.common.model.consts.ConstParam;
    import com.vcredit.fts.common.util.StringUtil;
    import lombok.Data;
    
    import java.util.Objects;
    
    /**
     * 基本异常
     *
     * @author huangzhongqing
     * @date 2020-12-04
     */
    @Data
    public class SysException extends RuntimeException {
        /**
         * serialVersionUID
         */
        private static final long serialVersionUID = ConstParam.ONE_L;
        /**
         * 异常详情
         */
        private Exception Exp;
        /**
         * 系统状态
         */
        private SystemStatus Status;
        /**
         * 是否通知
         */
        private Boolean IsNotice;
    
        // --------------- 构造函数 begain ---------------
        /**
         * 基本异常
         */
        public SysException() {
            this.Status = SystemStatus.SYS_ERROR;
        }
        /**
         * 基本异常
         *
         * @param message
         */
        public SysException(String message) {
            this.Status = SystemStatus.SYS_ERROR;
            this.Status.setMessage(message);
        }
        /**
         * 基本异常
         */
        public SysException(SystemStatus status) {
            this.Status = status;
        }
        /**
         * 基本异常
         *
         * @param status
         * @param message
         */
        public SysException(SystemStatus status, String message) {
            this.Status = status;
            this.Status.setMessage(message);
        }
        /**
         * 基本异常
         *
         * @param ex
         */
        public SysException(Exception ex) {
            this.Status = SystemStatus.SYS_ERROR;
            this.Status.setMessage(ex.getMessage());
            this.Exp = ex;
        }
        /**
         * 基本异常
         *
         * @param status
         * @param ex
         */
        public SysException(SystemStatus status, Exception ex) {
            this.Status = status;
            this.Exp = ex;
        }
        /**
         * 基本异常
         *
         * @param isNotice
         */
        public SysException(Boolean isNotice) {
            this.Status = SystemStatus.SYS_ERROR;
            this.IsNotice = isNotice;
        }
        /**
         * 基本异常
         *
         * @param message
         * @param isNotice
         */
        public SysException(String message, Boolean isNotice) {
            this.Status = SystemStatus.SYS_ERROR;
            this.Status.setMessage(message);
            this.IsNotice = isNotice;
        }
        /**
         * 基本异常
         *
         * @param status
         * @param isNotice
         */
        public SysException(SystemStatus status, Boolean isNotice) {
            this.Status = status;
            this.IsNotice = isNotice;
        }
        /**
         * 基本异常
         *
         * @param status
         * @param message
         * @param isNotice
         */
        public SysException(SystemStatus status, String message, Boolean isNotice) {
            this.Status = status;
            this.Status.setMessage(message);
            this.IsNotice = isNotice;
        }
        /**
         * 基本异常
         *
         * @param ex
         * @param isNotice
         */
        public SysException(Exception ex, Boolean isNotice) {
            this.Status = SystemStatus.SYS_ERROR;
            this.Status.setMessage(ex.getMessage());
            this.Exp = ex;
            this.IsNotice = isNotice;
        }
        /**
         * 基本异常
         *
         * @param status
         * @param ex
         * @param isNotice
         */
        public SysException(SystemStatus status, Exception ex, Boolean isNotice) {
            this.Status = status;
            this.Exp = ex;
            this.IsNotice = isNotice;
        }
        // --------------- 构造函数 end ---------------
        /**
         * 获取消息
         *
         * @return 结果
         */
        @Override
        public String getMessage() {
            if(!Objects.isNull(this.Status) && !StringUtil.isNullOrEmpty(this.Status.getMessage())){
    
                return this.Status.getMessage();
            }
            else{
                return "未知";
            }
        }
    }

    D:创建切面处理类

    import com.alibaba.fastjson.JSON;
    import com.vcredit.fts.common.exception.SysException;
    import com.vcredit.fts.common.model.consts.ConstParam;
    import com.vcredit.fts.common.model.dto.CommonResult;
    import com.vcredit.fts.common.model.enums.SystemStatus;
    import com.vcredit.fts.common.util.EmailUtil;
    import com.vcredit.fts.common.util.StringUtil;
    import lombok.extern.log4j.Log4j2;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.MessageSource;
    import org.springframework.http.converter.HttpMessageConversionException;
    import org.springframework.util.StringUtils;
    import org.springframework.validation.BindingResult;
    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.annotation.Resource;
    
    @RestControllerAdvice
    @Log4j2
    public class ExceptionAspect {
        @Resource
        private EmailUtil email;
    
        @Autowired
        protected MessageSource messageSource;
    
        /**
         * 全局异常处理
         *
         * @param e 异常对象
         * @return CommonResult
         */
        @ExceptionHandler(Throwable.class)
        public CommonResult handleException(Throwable e) {
            log.error("Exception :", e);
            String subject = e.getMessage();
            if(StringUtil.isNullOrEmpty(subject)) {
                subject="系统异常";
            }
            email.sendMail(e.toString(), "【异常】" + e.getMessage());
            return CommonResult.errorBase().setMessage(e.getMessage());
        }
    
        /**
         * HTTP消息转换异常
         *
         * @param e 异常对象
         * @return Result
         */
        @ExceptionHandler(HttpMessageConversionException.class)
        public CommonResult handleHttpMessageConversionException(HttpMessageConversionException e) {
            log.error("HTTP消息转换异常 : {}", e.getMessage());
            return CommonResult.error(SystemStatus.PARAM_VALIDATE_ERROR);
    
        }
    
        /**
         * 参数验证异常处理
         *
         * @param ex 异常对象
         * @return Result
         */
        @ExceptionHandler(MethodArgumentNotValidException.class)
        public CommonResult handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
            log.debug("参数验证异常处理 :{}" + ex.getMessage());
            return CommonResult.errorBase().setCode(SystemStatus.PARAM_VALID_ERROR.getCode()).setMessage(errorMessage(ex));
        }
    
        /**
         * 内置异常处理
         *
         * @param e 异常对象
         * @return CommonResult
         */
        @ExceptionHandler(SysException.class)
        public CommonResult handleSysException(SysException e) {
            log.error("sysException :", e);
            if(e.getIsNotice() != null && e.getIsNotice().compareTo(true) == ConstParam.ZERO){
                email.sendMail(JSON.toJSONString(e),"【异常】XX系统");
            }
            return CommonResult.init(e.getStatus());
        }
    
    
        private String errorMessage(MethodArgumentNotValidException e) {
            BindingResult bindingResult = e.getBindingResult();
            StringBuilder stringBuilder = new StringBuilder();
            // 只返回一个错误
            if (bindingResult.hasErrors()) {
                ObjectError firstError = bindingResult.getAllErrors().get(0);
                String messages = firstError.getArguments()[0].toString().split("default message")[1];
                stringBuilder.append(StringUtils.isEmpty(firstError.getDefaultMessage()) ? "param is invalid" : String.format("参数%s : %s", messages, firstError.getDefaultMessage()));
            }
            return stringBuilder.toString();
        }
    }

    三、详细解析

    生命周期相关注解主要包括@Around、@Before、@After、@AfterReturning、@AfterThrowing

     执行顺序为

    @Around作用
    1.可以在目标方法之前进行增强动作,也可以执行完目标方法后执行
    2.可以决定目标方法何时,以何种方式执行,甚至可以不执行
    3.可以改变目标方法的参数值,也可以改变执行目标方法之后的返回值;当需要改变目标方法的返回值时只能使用@Around

    注意: 使用@Around的方法的第一个形参必须是ProceedJoinPoint类型,只有调用该参数的proceed()方法才会执行目标函数

    ProceedJoinPoint是JoinPoint的子类,多了proceed()方法,并可以抛出异常。

    @Pointcut("execution(* com..web.*Controller.*(..))")
    @Pointcut("@annotation(com.vcredit.fts.common.aop.exception.annotation.OperationLog)")

    execution表达式基本语法格式为:

    execution(<修饰符模式>?<返回类型模式><方法名模式>(<参数模式>)<异常模式>?)

    说明1:
    1、除了返回类型模式,方法名模式和参数模式外,其它项都是可选的。
    2、多个execution表达式通过 || 进行连接

    说明2:
    1、【非必填】修饰符模式。public 表示public 级别方法。 可以不写,不写就是所有的方法(public,private,protected等级别的方法)。
    2、【必填】返回类型模式。表示方法返回值的类型, * 表示全部。
    3、【必填】方法名模式。表示通配符; .. 表示包以及包下面的子包。
    4、【必填】参数模式。括号表示参数,两个点表示任何参数类型。 *(..) 表示全部方法。
    5、【非必填】异常模式。

    四、补充

    springboot添加启动日志

    @Log4j2
    public class MainShowInfoUtil {
        private MainShowInfoUtil() {
        }
    
        private static final String NOT_SET = "[Not Set]";
    
        public static void showApplicationSummary(Environment env) {
            String protocol = StringUtils.hasText(env.getProperty("server.ssl.key-store")) ? "https" : "http";
            String appId = env.getProperty("spring.application.appId");
            if (!StringUtils.hasText(appId)) {
                appId = NOT_SET;
            }
            String nodeId = env.getProperty("nodeId");
            if (!StringUtils.hasText(nodeId)) {
                nodeId = NOT_SET;
            }
            try {
                log.info("\n---------------------------程序启动完成-------------------------------\n\t" +
                                "Application '{}' is running! \n\t" +
                                "Access URLs:\n\t" +
                                " - Local: {}://localhost:{}/swagger-ui.html\n\t" +
                                " - External: {}://{}:{}/swagger-ui.html\n\t" +
                                " - Prometheus: {}://localhost:{}/actuator/prometheus\n\t" +
                                "Runtime Parameters: \n\t" +
                                " - appID: {}\n\t" +
                                " - nodeId: {}\n\t" +
                                "Active Profile(s): {}\n" +
                                "-------------------------------------------------------------------",
                        env.getProperty("spring.application.name"),
                        protocol, env.getProperty("local.server.port"),
                        protocol,InetAddress.getLocalHost().getHostAddress(), env.getProperty("local.server.port"),
                        protocol, env.getProperty("local.server.port"),
                        appId, nodeId, env.getActiveProfiles());
            } catch (UnknownHostException e) {
                log.catching(e);
            }
        }
    }
    @EnableApolloConfig
    @SpringBootApplication(scanBasePackages = "com.hzq.fts")
    @EnableEcmService
    @Slf4j
    public class FtsProcessApplication {
    
        public static void main(String[] args) {
            ConfigurableEnvironment environment = SpringApplication.run(FtsProcessApplication.class,args).getEnvironment();
            MainShowInfoUtil.showApplicationSummary(environment);
        }
    }
  • 相关阅读:
    python之set
    python之tuple
    python之list
    python之Number
    LAMP源码安装,搭建zabbix监控
    linux sshd服务
    linux rsync服务
    linux 实时同步inotify
    搭建LNMP;搭建WIKI
    数字,列表,函数
  • 原文地址:https://www.cnblogs.com/ariter/p/15528629.html
Copyright © 2020-2023  润新知