自定义异常和全局异常
异常是什么在这里不多做解释了。在实际的项目开发中,程序会发生各种异常,如果这些异常不做处理,将会直接暴露给前端,即暴露给用户,降低体验质量,也留下安全隐患。对可能发生的异常进行处理和日志记录,能保证后端程序的正常运行,也能给用户带来更好的体验。采用全局异常将减少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 {
@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)异常处理结果