SpringBoot全局异常处理

     有时候我们需要对返回到前端的数据做统一的格式处理,在实际开发中我们都会定义一个Result来封装返回的数据,一般会包含code、msg、data等等参数,不论请求是成功还是失败,都希望也需要返回这些统一的信息。例如:

      如果我们不对返回信息做全局处理的话,当我们在service层处理异常逻辑的时候就必须手动判断并封装数据到Result,重复代码比较多而且看起来很臃肿。在一般的项目中,全局异常处理不需要像网上其他文章那样定义那么详细,每个业务模块只需要自定义一个异常就基本够用了。

1.controller和service

只是做一个简单的测试,controller和service中能制造异常就行了。

package com.wzk.demo.controller;

import com.wzk.demo.common.Result;
import com.wzk.demo.pojo.User;
import com.wzk.demo.service.MyExceptionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;


/**
 * @author WangZhiKai
 * @date 2019/9/12 11:27
 */
@RestController
@RequestMapping("/exp")
public class MyExceptionController {

    @Autowired
    private MyExceptionService myExceptionService;

    /**
     *  登录
     */
    @RequestMapping("/login")
    public Result testExp(@RequestBody @Valid User user, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return Result.error(bindingResult.getFieldErrors().get(0).getDefaultMessage());
        }
        return myExceptionService.login(user);
    }

    /**
     *  注册
     */
    @RequestMapping("/registry")
    public Result registry(@RequestBody @Valid User user, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return Result.error(bindingResult.getFieldErrors().get(0).getDefaultMessage());
        }
        return myExceptionService.registry(user);
    }
}
package com.wzk.demo.service.impl;

import com.wzk.demo.common.Result;
import com.wzk.demo.common.ResultEnum;
import com.wzk.demo.exception.MyException;
import com.wzk.demo.pojo.User;
import com.wzk.demo.service.MyExceptionService;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

/**
 * @author WangZhiKai
 * @date 2019/9/12 14:18
 */
@Service
public class MyExceptionServiceImpl implements MyExceptionService {

    @Override
    public Result login(User user) {
        if (!"wangzk".equals(user.getUsername())) {
            throw new MyException(ResultEnum.EXCEPTION_PARAM_ERROR);
        }else if (!"66666".equals(user.getPassword())) {
            throw new MyException(ResultEnum.EXCEPTION_DB_ERROR);
        }else {
            return new Result(ResultEnum.OK);
        }
    }


    @Override
    public Result registry(User user) {
        if (!StringUtils.hasLength(user.getTelephone())) {
            throw new MyException(ResultEnum.EXCEPTION_PHONE_MISS);
        }else if (!"18100000000".equals(user.getTelephone())) {
            throw new MyException(ResultEnum.EXCEPTION_PHONE_ERROR);
        }else {
            return new Result(ResultEnum.OK);
        }
    }
}

 1.controller方法参数里面有一个 BindingResult 参数,这个是spring检查被@valid注解修饰的对象入参合法性的,可以先忽略,      如果感兴趣可以在网上搜@valid+BindingResult实现参数校验的文章,这里不细述;

2.Result是我自定义的返回对象,可以看一下:

@Data
public class Result {

    private String code;
    private String msg;
    private Object data;

    public Result() {
    }

    public Result(ResultEnum resultEnum) {
        this.code = resultEnum.getCode();
        this.msg = resultEnum.getMsg();
    }

    public static Result error() {
        return error("0", "未知异常!");
    }

    public static Result error(String msg) {
        return error("1",msg);
    }

    private static Result error(String code, String msg) {
        Result result = new Result();
        result.code = code;
        result.msg = msg;
        return result;
    }
}

3.Result里面有一个构造方法传入ResultEnum枚举对象,这个是为了简化传参,code和msg放在枚举中就不用分别设值,例如:

return new Result(ResultEnum.OK);

 顺便看一下ResultEnum:

package com.wzk.demo.common;

/**
 * @author WangZhiKai
 * @date 2019/9/12 11:35
 */
public enum ResultEnum {

    OK("0","操作成功!"),
    EXCEPTION_PARAM_ERROR("PARAM-1001","参数错误,操作失败!"),
    EXCEPTION_DB_ERROR("PARAM-1002","数据库操作异常,操作失败!"),
    EXCEPTION_PHONE_MISS("PARAM-1003","参数缺失,操作失败!电话号不能为空!"),
    EXCEPTION_PHONE_ERROR("PARAM-1004","参数错误,操作失败!电话号错误!");

    private String code;
    private String msg;


    public String getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

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

2.pojo类

package com.wzk.demo.pojo;

import lombok.Data;

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;

/**
 * @author WangZhiKai
 * @date 2019/9/12 11:30
 */
@Data
public class User {

    public static final String REGEXP_PHONE =
            "^((13[0-9])|(14[5,7,9])|(15([0-3]|[5-9]))|(166)|(17[0,1,3,5,6,7,8])|(18[0-9])|(19[8|9]))\\d{8}$";

    @NotNull(message = "用户名不能为空!")
    private String username;

    @NotNull(message = "密码不能为空!")
    @Size(min = 1, max = 12, message = "密码长度不能超过12位字符")
    private String password;

    @Max(value = 150,message = "年龄不在合法范围!")
    @Min(value = 0,message = "年龄不在合法范围!")
    private Integer age;

    @Pattern(regexp = REGEXP_PHONE, message = "手机号码格式错误!")
    private String telephone;

}

参数上面的注解都是为了避免在service层进行繁琐的参数校验,service只需要关注业务逻辑即可,具体的使用可以在网上看看  其他的文章;

3.自定义异常类MyException

package com.wzk.demo.exception;

import com.wzk.demo.common.ResultEnum;
import lombok.Data;
import lombok.EqualsAndHashCode;

/**
 * @author WangZhiKai
 * @date 2019/9/12 15:08
 */
@EqualsAndHashCode(callSuper = true)
@Data
public class MyException extends RuntimeException{

    private String code;
    private String msg;


    public MyException(String msg) {
        this.code = "0";
        this.msg = msg;
    }

    public MyException(ResultEnum resultEnum) {
        super(resultEnum.getMsg());
        this.code = resultEnum.getCode();
        this.msg = resultEnum.getMsg();
    }
}

这里同样有一个传入ResultEnum的构造方法,方便对异常信息做统一处理,例如:

throw new MyException(ResultEnum.EXCEPTION_PARAM_ERROR);

4.全局异常处理器 MyExceptionHandler

package com.wzk.demo.exception;

import com.wzk.demo.common.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import javax.servlet.http.HttpServletRequest;

/**
 * @author WangZhiKai
 * @date 2019/9/12 16:40
 */
@RestControllerAdvice
public class MyExceptionHandler extends ResponseEntityExceptionHandler {

    private static Logger logger = LoggerFactory.getLogger(MyExceptionHandler.class);

    @ExceptionHandler(value = MyException.class)
    public ResponseEntity<Result> handleMyException(MyException e, HttpServletRequest request) {

        logger.error(e.getMsg(),e);

        Result result = new Result();
        result.setCode(e.getCode());
        result.setMsg(e.getMsg());
        result.setData(false);

        return new ResponseEntity<>(result, HttpStatus.BAD_REQUEST);
    }
}

1.@RestControllerAdvice注解是标明它只会捕获被@RestController修饰的类中的异常,而且不能在里面做try catch,否则不会被捕获,要注意的是,在service中的异常也是可以捕获到的,但是也不能进行try catch。如果controller层使用的是@Controller注解,这里的@RestControllerAdvice也要改成@ControllerAdvice,否则无效;

2.@ExceptionHandler(value = MyException.class)标明需要捕获的异常类型,这里我是只捕获自定义异常,这里也可以改成其他的异常,可以写多个方法分别处理不同的异常

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值