• 首页

  • 归档

  • 分类

  • 标签

  • 喵星人

  • 心情

  • 关于
W e A r e F a m i l y ! m i a o ~
W e A r e F a m i l y ! m i a o ~

柴子

青春流逝,记录往昔

08月
05
后端

springboot请求全异常处理

发表于 2021-08-05 • 字数统计 11634 • 被 205 人看爆

功能

springboot请求全异常处理,已在公司项目使用,处理所有请求异常,自定义异常,未捕获异常的统一格式输出处理
可配合@Validated 进行请求参数校验,让代码更优雅、健壮

pom依赖

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

请求全异常handler处理类

package com.hongkun.exception.handler;

import com.hongkun.tools.ResponseUtil;
import com.hongkun.enums.ResultEnum;
import com.hongkun.exception.GlobalException;
import com.hongkun.tools.LoggerUtil;
import com.hongkun.model.vo.ResultVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MaxUploadSizeExceededException;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.*;

@ResponseBody
@ControllerAdvice
@Slf4j
public class ExceptionHandlers {


    @ExceptionHandler(GlobalException.class)
    public ResultVO handler(HttpServletRequest request, GlobalException e) {
        log.error("【全局自定义异常】: err = {} url = {} ", LoggerUtil.getLogReplace(e.getMessage()), request.getRequestURL());
        return ResponseUtil.error(e.getCode(), e.getMessage());
    }


    /**
     * 忽略参数异常处理器
     *
     * @param e 忽略参数异常
     * @return ResponseResult
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    public ResultVO parameterMissingExceptionHandler(HttpServletRequest request, MissingServletRequestParameterException e) {
        log.error("【忽略参数异常】: err = {} url = {} ", LoggerUtil.getLogReplace(e.getMessage()), request.getRequestURL());
        return ResponseUtil.error(ResultEnum.PARAM_ERROR.getCode(), "请求参数 " + e.getParameterName() + " 不能为空");
    }

    /**
     * 缺少请求体异常处理器
     *
     * @param e 缺少请求体异常
     * @return ResponseResult
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public ResultVO parameterBodyMissingExceptionHandler(HttpServletRequest request, HttpMessageNotReadableException e) {
        log.error("【缺少请求体异常】: err = {} url = {} ", LoggerUtil.getLogReplace(e.getMessage()), request.getRequestURL());
        return ResponseUtil.error(ResultEnum.PARAM_ERROR.getCode(), "参数体不能为空");
    }


    /**
     * 参数效验异常处理器
     *
     * @param ex
     * @return
     */
    @ResponseBody
    @ExceptionHandler(ConstraintViolationException.class)
    public ResultVO constraintViolationExceptionHandler(HttpServletRequest request, ConstraintViolationException ex) {
        log.error("【参数效验异常】: err = {} url = {} ", LoggerUtil.getLogReplace(ex.getMessage()), request.getRequestURL());
        Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
        Iterator<ConstraintViolation<?>> iterator = constraintViolations.iterator();
        List<String> msgList = new ArrayList<>();
        while (iterator.hasNext()) {
            ConstraintViolation<?> cvl = iterator.next();
            msgList.add(cvl.getMessageTemplate());
        }
        if (!msgList.isEmpty()) {
            return ResponseUtil.error(ResultEnum.PARAM_ERROR.getCode(), msgList.get(0));
        }
        return ResponseUtil.error(ResultEnum.PARAM_ERROR);
    }


    /**
     * 参数效验异常处理器
     *
     * @param e 参数验证异常
     * @return ResponseInfo
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResultVO parameterExceptionHandler(HttpServletRequest request, MethodArgumentNotValidException e) {
        // 获取异常信息
        BindingResult exceptions = e.getBindingResult();
        // 判断异常中是否有错误信息,如果存在就使用异常中的消息,否则使用默认消息
        if (exceptions.hasErrors()) {
            List<ObjectError> errors = exceptions.getAllErrors();
            if (!errors.isEmpty()) {
                // 这里列出了全部错误参数,按正常逻辑,只需要第一条错误即可
                FieldError fieldError = (FieldError) errors.get(0);
                log.error("【参数验证异常】: err = {} url = {} ", fieldError.getDefaultMessage(), request.getRequestURL());
                return ResponseUtil.error(ResultEnum.PARAM_ERROR.getCode(), fieldError.getDefaultMessage());
            }
        }
        return ResponseUtil.error(ResultEnum.PARAM_ERROR);
    }


    /**
     * 不支持当前媒体类型 参数类型不对
     *
     * @param e
     * @return
     */
    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    public ResultVO handleHttpMediaTypeNotSupportedException(HttpServletRequest request, HttpMediaTypeNotSupportedException e) {
        log.error("【请求异常】: err = {} url = {} ", e.getMessage(), request.getRequestURL());
        return ResponseUtil.error(ResultEnum.PARAM_ERROR.getCode(), e.getMessage());
    }


    /**
     * 上传文件过大异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public ResultVO handleHttpMediaTypeNotSupportedException(HttpServletRequest request, MaxUploadSizeExceededException e) {
        log.error("【请求异常】: err = {} url = {} ", e.getMessage(), request.getRequestURL());
        return ResponseUtil.error(ResultEnum.FILE_PARAM_ERROR);
    }


    /**
     * 未捕获异常处理器
     *
     * @param e 未捕获异常
     * @return ResponseInfo
     */
    @ExceptionHandler(Exception.class)
    public ResultVO unCatchExceptionHandler(HttpServletRequest request, Exception e) {
        e.printStackTrace();
        log.error("【未捕获异常】: err = {} url = {}", LoggerUtil.getLogReplace(e.getMessage()), request.getRequestURL());
        return ResponseUtil.error(ResultEnum.SERVER_ERROR);
    }


}

统一格式封装vo类

package com.chai.model.vo;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.io.Serializable;


/**
 * @author chaixuhong
 * @apiNote 数据返回标准化输出类
 * @date 2019-08-12
 */
@ApiModel(value = "返回类")
@Data
public class ResultVO<T> implements Serializable {

    private static final long serialVersionUID = 3068837394742385883L;

    @ApiModelProperty(value = "错误码,默认1是成功,0是失败;以及其它错误码",example = "1")
    private Integer code;
    @ApiModelProperty("提示信息")
    private String errMsg;
    @ApiModelProperty("数据")
    private T data;
}

统一格式输出工具类

package com.chai.utils;


import com.chai.enums.ResultEnum;
import com.chai.model.vo.ResultVO;

/**
 * @Auther: chaixuhong
 */
public class ResponseUtil {
    /**
     * 错误返回
     * @param resultEnum
     * @return
     */
    public static ResultVO error(ResultEnum resultEnum){
        ResultVO resultVO = new ResultVO();
        resultVO.setCode(resultEnum.getCode());
        resultVO.setErrMsg(resultEnum.getErrMsg());
        return resultVO;
    }

    /**
     * 自定义返回
     * @param code
     * @param errMsg
     * @return
     */
    public static ResultVO error(int code , String errMsg){
        ResultVO resultVO = new ResultVO();
        resultVO.setCode(code);
        resultVO.setErrMsg(errMsg);
        return resultVO;
    }

    /**
     * 有参成功返回
     * @param data
     * @return
     */
    public static ResultVO success(Object data){
        ResultVO resultVO = new ResultVO();
        resultVO.setCode(ResultEnum.SUCCESS.getCode());
        resultVO.setErrMsg(ResultEnum.SUCCESS.getErrMsg());
        resultVO.setData(data);
        return resultVO;
    }

    /**
     * 无参成功返回
     * @return
     */
    public static ResultVO success(){
        ResultVO resultVO = new ResultVO();
        resultVO.setCode(ResultEnum.SUCCESS.getCode());
        resultVO.setErrMsg(ResultEnum.SUCCESS.getErrMsg());
        return resultVO;
    }
}

统一格式枚举类

package com.chai.enums;

import lombok.Getter;

@Getter
public enum ResultEnum {
    SUCCESS(1, "success"),
    SERVER_ERROR(500,"服务器异常!"),
    MP_NO_LOGIN(1000,"没有授权登录"),
    PARAM_ERROR(1002, "参数错误"),
    PARAM_NOT_NULL(1003, "参数不能为空"),
    NO_OPERATION_AUTHORITY(1004, "没有权限操作"),


    /**********业务状态码*********/
    /******授权状态码*****/
    TOKEN_MISSING(1000, "token缺失"),

    TOKEN_NOT_AFFECTIVE(1000, "token无效"),

    NEED_REGISTER(2, "用户没有授权"),

    OPENID_IS_NOT_RIGHT(1009,"openid不合法"),

    WEIXIN_JS_CODE_OAUTH_ERROR(1005, "微信JS_CODE换取用户信息错误"),

    ACCESS_TOKEN_GET_FAIL(1103,"获取accessToken失败!"),

    UNIOIN_ID_ERROR(1104,"获取UNIOIN_ID失败!"),

    GET_MINI_CODE_ERROR(1105,"获取小程序二维码失败!"),

    ACCOUNT_IS_EXIST(1106, "用户账号已存在"),

    ;
    private int code;
    private String errMsg;

    ResultEnum(int code, String errMsg) {
        this.code = code;
        this.errMsg = errMsg;
    }
}

测试requestParam请求校验

    public ResultVO getOrderDetailById(@NotNull(message = "orderId不能为空") Integer orderId) {
        LoginUserModel loginUser = UserLocalCache.getUser();
        LambdaQueryWrapper<RepairOrder> queryWrapper = new LambdaQueryWrapper();
        queryWrapper.eq(RepairOrder::getUserId,loginUser.getUserId())
                .eq(RepairOrder::getOrderId,orderId);
        return ResponseUtil.success(repairOrderService.getOne(queryWrapper));
    }

测试requestBody请求

实体类

package com.chai.model.rev;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.springframework.validation.annotation.Validated;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.time.LocalDateTime;

/**
 *
 * @author chaixuhong
 * @since 2021-08-04
 */
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@ApiModel(value = "RepairOrder接收类", description = "")
public class RepairOrderRev implements Serializable {

    private static final long serialVersionUID = -6258584086487961208L;

    @ApiModelProperty(value = "报修服务")
    @NotBlank(message = "报修服务不能为空")
    private String repairServerType;

    @ApiModelProperty(value = "报修故障")
    @NotBlank(message = "报修故障不能为空")
    private String repairFault;

    @ApiModelProperty(value = "报修区域")
    @NotBlank(message = "报修区域不能为空")
    private String repairArea;

    @ApiModelProperty(value = "报修照片")
    private String repairUrl;

    @ApiModelProperty(value = "报修备注")
    private String repairDesc;

    @ApiModelProperty(value = "报修用户预约时间")
    @NotNull(message = "预约时间不能为空")
    private LocalDateTime userReserveDate;

    @ApiModelProperty(value = "报修用户姓名")
    @NotBlank(message = "报修用户姓名不能为空")
    private String userName;

    @ApiModelProperty(value = "报修用户手机号")
    @NotBlank(message = "报修用户手机号不能为空")
    private String userPhone;

    @ApiModelProperty(value = "报修用户地址")
    @NotBlank(message = "报修用户地址不能为空")
    private String userAddress;

}

controller

    @ApiOperation("提交订单")
    @PutMapping("/save")
    public ResultVO saveOrder(@RequestBody @Validated RepairOrderRev repairOrderRev) {
        LoginUserModel loginUser = UserLocalCache.getUser();
        RepairOrder repairOrder = new RepairOrder();
        BeanUtils.copyProperties(repairOrderRev,repairOrder);
        repairOrder.setUserId(loginUser.getUserId());
        boolean save = repairOrderService.save(repairOrder);
        if (save){
            return ResponseUtil.success("保存成功");
        }
        return ResponseUtil.error(ResultEnum.PARAM_ERROR);
    }

分享到:
@Resource与@AutoWired 区别
mybatis-plus代码生成器
  • 文章目录
  • 站点概览
柴子

内蒙 柴子

what do U want?

Github QQ Email RSS
最喜欢的电影
最喜欢的游戏
最喜欢的音乐
最喜欢的图书
最喜欢的动漫
夏洛特的烦恼
英雄联盟
痴心绝对
数据库从入门到删库跑路
斗破苍穹
看爆 Top5
  • 微信getUserProfile兼容性调整以及uniapp写法 2,041次看爆
  • gateway转发微服务请求丢失header参数 1,016次看爆
  • mybatis-plus代码生成器 950次看爆
  • SpringBoot防重复提交与限流的优雅解决 546次看爆
  • Spring Boot Security从入门到进阶到高级 544次看爆
转载注明出处

站点已萌萌哒运行 00 天 00 小时 00 分 00 秒(●'◡'●)ノ♥

Copyright © 2022 柴子 京ICP备17035556号-1

由 Halo 强力驱动 · Theme by Sagiri · 站点地图