SpringBoot秒杀系统:6.全局异常处理

本文介绍了一种全局异常处理策略,通过使用@ControllerAdvice注解和自定义异常类,实现业务代码中参数校验错误的自动捕获与处理,避免了重复的异常判断,简化了代码并提高了异常处理的统一性和效率。

巧妙的设计一种全局异常处理,业务代码无需重复书写参数校验等判断,
参数校验错误直接通过全局异常处理抛出

  1. 参数校验异常

我们用不符合我们参数的形式去请求接口会返回异常
但是页面无法捕获,如何拦截这些异常并将错误信息返回给页面是这里要做的
在这里插入图片描述
2. 全局异常捕获

我们定义一个统一的全局异常返回
知识点1:@ControllerAdvice是一个增强的 Controller

定义全局异常Controller,
这个ExceptionHandler可以在捕获我们下面定义的异常时自动向前台返回Result信息
从而使得我们无需自己判断这些异常

@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {
	@ExceptionHandler(value=Exception.class)
	public Result<String> exceptionHandler(HttpServletRequest request, Exception e){
		if(e instanceof BindException) {
			BindException ex = (BindException)e;
			List<ObjectError> errors = ex.getAllErrors();
			ObjectError error = errors.get(0);
			String msg = error.getDefaultMessage();
			return Result.error(CodeMsg.BIND_ERROR.fillArgs(msg));
		}else {
			return Result.error(CodeMsg.SERVER_ERROR);
		}
	}
}

其中在CodeMsg中添加方法fillArgs(msg)用于返回当前Code内容
添加一种异常BIND_ERROR
知识点1:Java中可变参数写法public CodeMsg fillArgs(Object... args)
知识点2:String.format(this.msg, args);将后面的数组转成字符串放入%s的位置

    public static CodeMsg BIND_ERROR = new CodeMsg(500101, "参数校验异常:%s");
	public CodeMsg fillArgs(Object... args) {
		int code = this.code;
		String message = String.format(this.msg, args);
		return new CodeMsg(code, message);
	}

这时候我们已经完成了自动捕获绑定异常

  1. 全局异常定义

我们可以再定义一个全局异常类GlobalException 用于捕获全部的异常
这样所有异常信息便无需判断!
全局异常类中添加private CodeMsg cm;从而让前台按照我们的信息执行。

package com.liuyang.seckill.exception;

import com.liuyang.seckill.result.CodeMsg;

public class GlobalException extends RuntimeException{

    private static final long serialVersionUID = 1L;
    private CodeMsg cm;

    public GlobalException(CodeMsg cm) {
        super(cm.toString());
        this.cm = cm;
    }

    public CodeMsg getCm() {
        return cm;
    }
}

全局异常控制类增加全局异常控制

@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {
	@ExceptionHandler(value=Exception.class)
	public Result<String> exceptionHandler(HttpServletRequest request, Exception e){
		e.printStackTrace();
		if(e instanceof GlobalException) {
			GlobalException ex = (GlobalException)e;
			return Result.error(ex.getCm());
		}else if(e instanceof BindException) {
			BindException ex = (BindException)e;
			List<ObjectError> errors = ex.getAllErrors();
			ObjectError error = errors.get(0);
			String msg = error.getDefaultMessage();
			return Result.error(CodeMsg.BIND_ERROR.fillArgs(msg));
		}else {
			return Result.error(CodeMsg.SERVER_ERROR);
		}
	}
}

Service业务代码中遇到问题直接抛出异常
前面GlobalExceptionHandler 可以直接返回Result

	public boolean login(LoginVo loginVo) {
		if(loginVo == null) {
			throw new GlobalException(CodeMsg.SERVER_ERROR);
		}
		String mobile = loginVo.getMobile();
		String formPass = loginVo.getPassword();
		//判断手机号是否存在
		SeckillUser user = getById(Long.parseLong(mobile));
		if(user == null) {
			throw new GlobalException(CodeMsg.MOBILE_NOT_EXIST);
		}
		//验证密码
		String dbPass = user.getPassword();
		String saltDB = user.getSalt();
		String calcPass = MD5Util.formPassToDBPass(formPass, saltDB);
		if(!calcPass.equals(dbPass)) {
			throw new GlobalException(CodeMsg.PASSWORD_ERROR);
		}
		return true;
	}

这时候Controller代码无需进行判断
直接在最后返回成功即可

    @ResponseBody
    @RequestMapping("/do_login")
    public Result<Boolean> doLogin(@Valid LoginVo loginVo) {
        log.info(loginVo.toString());
        seckillUserService.login(loginVo);
        return Result.success(true);
    }
  1. 测试
http://localhost:8080/login/do_login?mobile=18844118879&password=12345678912345678912345678900012

在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值