自定义异常和全局异常
异常是什么在这里不多做解释了。在实际的项目开发中,程序会发生各种异常,如果这些异常不做处理,将会直接暴露给前端,即暴露给用户,降低体验质量,也留下安全隐患。对可能发生的异常进行处理和日志记录,能保证后端程序的正常运行,也能给用户带来更好的体验。采用全局异常将减少try catch这样重复的异常处理,减少代码量,防止漏网的异常没被处理。
1、自定义异常
1)创建异常枚举类
package com.example.demo.enums;
public class ErrorCode {
private ErrorCode() {
throw new IllegalStateException("Utility class");
}
/**
* 我就试一下
*/
public static final String HELLO_EXCEPTION = "90000001";
public static final String SERVICE_EXCEPTION = "90000002";
}
2)自定义异常类
package com.example.demo.exceptions;
public class AppServiceException extends Exception{
private static final long serialVersionUID = -2416380262384957964L;
/**
* 错误编码
*/
private String code;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public AppServiceException() {}
public AppServiceException(final String message) {
super(message);
}
public AppServiceException(final Throwable cause) {
super(cause);
}
public AppServiceException(String code, String message) {
this(message);
this.code = code;
}
}
3)项目结构及Resource Bundle的创建
在resource的目录下创建resource bundle。
项目结构:
4)application.yml配置文件
logging:
file:
name: slf4j-test
path: ./logs
max-size: 10MB
level:
root: info
config: classpath:logback-gnete.xml
spring:
messages:
basename: messages_zh
5)业务层接口及实现类
- interface
package com.example.demo.interfaces;
import com.example.demo.exceptions.AppServiceException;
public interface ExceptionService {
void exceptionTest() throws AppServiceException;
double GlobalExceptionTest(Integer num);
}
- AbstractService
package com.example.demo.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Service;
@Service
public class AbstractService {
// 注入messageSource
@Autowired
private MessageSource messageSource;
public String getMessage(String code, String defaultMsg) {
return this.messageSource.getMessage(code, null, defaultMsg, LocaleContextHolder.getLocale());
}
public String getMessage(String code) {
return this.getMessage(code, "");
}
}
- serviceImp
package com.example.demo.service;
import com.example.demo.enums.ErrorCode;
import com.example.demo.exceptions.AppServiceException;
import com.example.demo.interfaces.ExceptionService;
import org.springframework.stereotype.Service;
@Service
public class ExceptionServiceImp extends AbstractService implements ExceptionService {
@Override
public void exceptionTest() throws AppServiceException {
throw new AppServiceException(ErrorCode.HELLO_EXCEPTION, this.getMessage(ErrorCode.HELLO_EXCEPTION));
}
@Override
public double GlobalExceptionTest(Integer num){
return (double) num / 0;
}
}
6)返回的结果类
package com.example.demo.pojo;
import java.io.Serializable;
public class ReponseResult<T> implements Serializable {
private static final long serialVersionUID = 9191892693219217387L;
private static final String RESP_CODE_SUCCESS = "00000000";
private String code;
private boolean success;
private String message;
private T data;
public ReponseResult() {
}
public String getCode() {
return this.code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return this.message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return this.data;
}
public void setData(T data) {
this.data = data;
}
public boolean isSuccess() {
return this.success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public static <T> ReponseResult<T> success(T data) {
ReponseResult<T> result = new ReponseResult();
result.setCode("00000000");
result.setMessage("成功");
result.setSuccess(true);
result.setData(data);
return result;
}
public static <T> ReponseResult<T> fail(String code, String message, T data) {
ReponseResult<T> result = new ReponseResult();
result.setCode(code);
result.setData(data);
result.setMessage(message);
result.setSuccess(false);
return result;
}
public static <T> ReponseResult<T> fail(String code, String message) {
ReponseResult<T> result = new ReponseResult();
result.setCode(code);
result.setMessage(message);
result.setSuccess(false);
result.setData((T) null);
return result;
}
}
7)全局异常处理handler
package com.example.demo.handler;
import com.example.demo.enums.ErrorCode;
import com.example.demo.exceptions.AppServiceException;
import com.example.demo.pojo.ReponseResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler(value = AppServiceException.class)
@ResponseBody
public ReponseResult appServiceExceptionHandler(AppServiceException e){
log.error("发生业务异常!原因是:{}",e.getMessage());
return ReponseResult.fail(e.getCode(),e.getMessage());
}
@ExceptionHandler(value = RuntimeException.class)
@ResponseBody
public ReponseResult appServiceRuntimeException(RuntimeException e){
log.error("发生运行时业务异常!原因是:{}",e.getMessage());
return ReponseResult.fail(String.valueOf(400),e.getMessage());
}
@ExceptionHandler(value = NullPointerException.class)
@ResponseBody
public ReponseResult noPermissionException(NullPointerException e){
log.error("空指针异常!原因是:{}",e.getMessage());
return ReponseResult.fail("90000003","数据不存在");
}
@ExceptionHandler(value = Exception.class)
@ResponseBody
public ReponseResult commonExceptionHandler(Exception e){
log.error("通用异常!原因是:{}",e.getMessage());
return ReponseResult.fail(ErrorCode.SERVICE_EXCEPTION,e.getMessage());
}
}
- @ControllerAdvice 捕获
Controller
层抛出的异常,如果添加@ResponseBody
返回信息则为JSON
格式。 - @RestControllerAdvice 相当于
@ControllerAdvice
与@ResponseBody
的结合体。 - @ExceptionHandler 统一处理一种类的异常,减少代码重复率,降低复杂度。
8)控制层
package com.example.demo.controller;
import com.example.demo.exceptions.AppServiceException;
import com.example.demo.interfaces.ExceptionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Slf4j
public class TestController {
@Autowired
ExceptionService exceptionService;
@GetMapping("/exceptionTest")
public String test2() throws AppServiceException {
log.debug("自定义异常处理");
exceptionService.exceptionTest();
return "ok";
}
@GetMapping("/GlobalExceptionTest")
public double test2(Integer num) throws AppServiceException {
log.debug("全局异常处理");
return exceptionService.GlobalExceptionTest(num);
}
}
9)异常处理结果