SpringBoot 전역 이상 을 우아 하 게 처리 하 는 방법

머리말
이 글 은 주로 SpringBoot 프로젝트 의 전체적인 이상 처 리 를 소개 한다.
SpringBoot 전역 이상 준비
설명:프로젝트 를 직접 가 져 오 려 면 끝까지 뛰 어 내 려 링크 를 통 해 프로젝트 코드 를 다운로드 할 수 있 습 니 다.
개발 준비
환경 요구
JDK:1.8
SpringBoot:1.5.17.RELEASE
우선 Maven 의 의존:

 <properties>
 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 <java.version>1.8</java.version>
 <maven.compiler.source>1.8</maven.compiler.source>
 <maven.compiler.target>1.8</maven.compiler.target>
 </properties>
 <parent>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-parent</artifactId>
 <version>1.5.17.RELEASE</version>
 <relativePath />
 </parent>
 <dependencies>
 <!-- Spring Boot Web       -->
 <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
 </dependency>
 <!-- Spring Boot Test    -->
 <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-test</artifactId>
  <scope>test</scope>
 </dependency>

 <dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>fastjson</artifactId>
  <version>1.2.41</version>
 </dependency>
 </dependencies>
설정 파일 은 기본적으로 변경 할 필요 가 없습니다.전역 이상 처 리 는 코드 에서 만 이 루어 지면 됩 니 다.
코드 작성
SpringBoot 의 프로젝트 는 이미 어느 정도 이상 처 리 를 했 지만 우리 개발 자 에 게 는 적합 하지 않 을 수 있 습 니 다.따라서 우 리 는 이러한 이상 을 통일 적 으로 포착 하고 처리 해 야 합 니 다.SpringBoot 에는 Controller Advice 의 설명 이 있 습 니 다.이 주 해 를 사용 하면 전체 이상 캡 처 를 열 었 음 을 표시 합 니 다.우 리 는 하나의 방법 으로 ExceptionHandler 주 해 를 사용 한 다음 에 캡 처 이상 유형 을 정의 하면 이 캡 처 이상 을 통일 적 으로 처리 할 수 있 습 니 다.
우 리 는 아래 의 이 예시 에 근거 하여 이 주해 가 어떻게 사용 되 는 지 보 자.
예제 코드:

@ControllerAdvice
public class MyExceptionHandler {

 @ExceptionHandler(value =Exception.class)
 public String exceptionHandler(Exception e){
 System.out.println("    !   :"+e);
 return e.getMessage();
 }
}
상술 한 예 에서 우 리 는 포획 한 이상 에 대해 간단 한 2 차 처 리 를 하고 이상 한 정 보 를 되 돌려 준다.비록 이런 것 은 우리 가 이상 한 원인 을 알 수 있 지만 많은 상황 에서 말하자면 인성 화 되 지 않 고 우리 의 요구 에 부합 되 지 않 을 수도 있다.
그러면 우 리 는 사용자 정의 이상 류 와 매 거 진 류 를 통 해 우리 가 원 하 는 데 이 터 를 실현 할 수 있 습 니 다.
사용자 정의 기본 인터페이스 클래스
먼저 기본 인터페이스 클래스 를 정의 합 니 다.사용자 정의 오류 설명 매 거 진 클래스 는 이 인 터 페 이 스 를 실현 해 야 합 니 다.
코드 는 다음 과 같 습 니 다:

public interface BaseErrorInfoInterface {
 /**    */
 String getResultCode();
 
 /**     */
 String getResultMsg();
}
사용자 정의 매 거 진 클래스
그리고 나 서 우 리 는 매 거 진 종 류 를 사용자 정의 하고 이 인 터 페 이 스 를 실현 합 니 다.
코드 는 다음 과 같 습 니 다:

public enum CommonEnum implements BaseErrorInfoInterface {
 //         
 SUCCESS("200", "  !"), 
 BODY_NOT_MATCH("400","         !"),
 SIGNATURE_NOT_MATCH("401","          !"),
 NOT_FOUND("404", "      !"), 
 INTERNAL_SERVER_ERROR("500", "       !"),
 SERVER_BUSY("503","     ,     !")
 ;

 /**     */
 private String resultCode;

 /**      */
 private String resultMsg;

 CommonEnum(String resultCode, String resultMsg) {
 this.resultCode = resultCode;
 this.resultMsg = resultMsg;
 }

 @Override
 public String getResultCode() {
 return resultCode;
 }

 @Override
 public String getResultMsg() {
 return resultMsg;
 }

}
사용자 정의 이상 클래스
그리고 우 리 는 우리 가 발생 한 업무 이상 을 처리 하기 위해 이상 종 류 를 사용자 정의 하고 있 습 니 다.
코드 는 다음 과 같 습 니 다:

public class BizException extends RuntimeException {

 private static final long serialVersionUID = 1L;

 /**
 *    
 */
 protected String errorCode;
 /**
 *     
 */
 protected String errorMsg;

 public BizException() {
 super();
 }

 public BizException(BaseErrorInfoInterface errorInfoInterface) {
 super(errorInfoInterface.getResultCode());
 this.errorCode = errorInfoInterface.getResultCode();
 this.errorMsg = errorInfoInterface.getResultMsg();
 }
 
 public BizException(BaseErrorInfoInterface errorInfoInterface, Throwable cause) {
 super(errorInfoInterface.getResultCode(), cause);
 this.errorCode = errorInfoInterface.getResultCode();
 this.errorMsg = errorInfoInterface.getResultMsg();
 }
 
 public BizException(String errorMsg) {
 super(errorMsg);
 this.errorMsg = errorMsg;
 }
 
 public BizException(String errorCode, String errorMsg) {
 super(errorCode);
 this.errorCode = errorCode;
 this.errorMsg = errorMsg;
 }

 public BizException(String errorCode, String errorMsg, Throwable cause) {
 super(errorCode, cause);
 this.errorCode = errorCode;
 this.errorMsg = errorMsg;
 }
 

 public String getErrorCode() {
 return errorCode;
 }

 public void setErrorCode(String errorCode) {
 this.errorCode = errorCode;
 }

 public String getErrorMsg() {
 return errorMsg;
 }

 public void setErrorMsg(String errorMsg) {
 this.errorMsg = errorMsg;
 }

 public String getMessage() {
 return errorMsg;
 }

 @Override
 public Throwable fillInStackTrace() {
 return this;
 }

}
사용자 정의 데이터 형식
참고 로 데이터 전송 형식 을 정의 합 니 다.
코드 는 다음 과 같 습 니 다:

public class ResultBody {
 /**
 *     
 */
 private String code;

 /**
 *     
 */
 private String message;

 /**
 *     
 */
 private Object result;

 public ResultBody() {
 }

 public ResultBody(BaseErrorInfoInterface errorInfo) {
 this.code = errorInfo.getResultCode();
 this.message = errorInfo.getResultMsg();
 }

 public String getCode() {
 return code;
 }

 public void setCode(String code) {
 this.code = code;
 }

 public String getMessage() {
 return message;
 }

 public void setMessage(String message) {
 this.message = message;
 }

 public Object getResult() {
 return result;
 }

 public void setResult(Object result) {
 this.result = result;
 }

 /**
 *   
 * 
 * @return
 */
 public static ResultBody success() {
 return success(null);
 }

 /**
 *   
 * @param data
 * @return
 */
 public static ResultBody success(Object data) {
 ResultBody rb = new ResultBody();
 rb.setCode(CommonEnum.SUCCESS.getResultCode());
 rb.setMessage(CommonEnum.SUCCESS.getResultMsg());
 rb.setResult(data);
 return rb;
 }

 /**
 *   
 */
 public static ResultBody error(BaseErrorInfoInterface errorInfo) {
 ResultBody rb = new ResultBody();
 rb.setCode(errorInfo.getResultCode());
 rb.setMessage(errorInfo.getResultMsg());
 rb.setResult(null);
 return rb;
 }

 /**
 *   
 */
 public static ResultBody error(String code, String message) {
 ResultBody rb = new ResultBody();
 rb.setCode(code);
 rb.setMessage(message);
 rb.setResult(null);
 return rb;
 }

 /**
 *   
 */
 public static ResultBody error( String message) {
 ResultBody rb = new ResultBody();
 rb.setCode("-1");
 rb.setMessage(message);
 rb.setResult(null);
 return rb;
 }

 @Override
 public String toString() {
 return JSONObject.toJSONString(this);
 }

}
사용자 정의 전역 이상 처리 클래스
마지막 으로 전역 이상 처 리 를 사용자 정의 하 는 클래스 를 만 들 고 있 습 니 다.
코드 는 다음 과 같 습 니 다:

@ControllerAdvice
public class GlobalExceptionHandler {
 private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
 
 /**
 *           
 * @param req
 * @param e
 * @return
 */
 @ExceptionHandler(value = BizException.class) 
 @ResponseBody 
 public ResultBody bizExceptionHandler(HttpServletRequest req, BizException e){
 logger.error("      !   :{}",e.getErrorMsg());
 return ResultBody.error(e.getErrorCode(),e.getErrorMsg());
 }

 /**
 *         
 * @param req
 * @param e
 * @return
 */
 @ExceptionHandler(value =NullPointerException.class)
 @ResponseBody
 public ResultBody exceptionHandler(HttpServletRequest req, NullPointerException e){
 logger.error("       !   :",e);
 return ResultBody.error(CommonEnum.BODY_NOT_MATCH);
 }


 /**
 *       
 * @param req
 * @param e
 * @return
 */
 @ExceptionHandler(value =Exception.class)
 @ResponseBody
 public ResultBody exceptionHandler(HttpServletRequest req, Exception e){
 logger.error("    !   :",e);
 return ResultBody.error(CommonEnum.INTERNAL_SERVER_ERROR);
 }
}
여기 서 우 리 는 전체 이상 처리 기능 의 실현 과 테스트 에 만 사용 되 기 때문에 여기 서 우 리 는 하나의 실체 류 와 하나의 제어 층 류 를 추가 하면 된다.
실체 류
또 만능 사용자 표(^^)
코드 는 다음 과 같 습 니 다:

public class User implements Serializable{
 private static final long serialVersionUID = 1L;
 /**    */
  private int id;
  /**    */
  private String name;
  /**    */
  private int age;
  
  public User(){
  }

 public int getId() {
  return id;
 }
 
 public void setId(int id) {
  this.id = id;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public int getAge() {
  return age;
 }

 public void setAge(int age) {
  this.age = age;
 }

 public String toString() {
  return JSONObject.toJSONString(this);
 }
}
컨트롤 러 제어 층
컨트롤 층 이쪽 도 간단 합 니 다.Restful 스타일 로 이 루어 진 CRUD 기능 을 사용 합 니 다.다른 것 은 제 가 일부러 이상 을 만들어 서 이 이상 을 포착 하고 처리 하도록 했 습 니 다.이 이상 중 에는 사용자 정의 이상 던 지기 도 있 고 빈 포인터 의 이상 던 지기 도 있 습 니 다.물론 예측 할 수 없 는 이상 던 지기 도 있 습 니 다.(여 기 는 형식 변환 이상 으로 대체 합 니 다)코드 작성 을 마 친 후에 이 이상 이 캡 처 되 어 처리 되 는 지 확인 하 겠 습 니 다!
코드 는 다음 과 같 습 니 다:

@RestController
@RequestMapping(value = "/api")
public class UserRestController {

 @PostMapping("/user")
 public boolean insert(@RequestBody User user) {
  System.out.println("    ...");
  //                   !
  if(user.getName()==null){
   throw new BizException("-1","        !");
  }
  return true;
 }

 @PutMapping("/user")
 public boolean update(@RequestBody User user) {
  System.out.println("    ...");
  //              ,       
  String str=null;
  str.equals("111");
  return true;
 }

 @DeleteMapping("/user")
 public boolean delete(@RequestBody User user) {
  System.out.println("    ...");
  //          ,       
  Integer.parseInt("abc123");
  return true;
 }

 @GetMapping("/user")
 public List<User> findByUser(User user) {
  System.out.println("    ...");
  List<User> userList =new ArrayList<>();
  User user2=new User();
  user2.setId(1L);
  user2.setName("xuwujing");
  user2.setAge(18);
  userList.add(user2);
  return userList;
 }
 
}
앱 입구
일반적인 SpringBoot 프로젝트 와 거의 같 습 니 다.
코드 는 다음 과 같 습 니 다:

@SpringBootApplication
public class App 
{
 public static void main( String[] args )
 {
  SpringApplication.run(App.class, args);
  System.out.println("      ...");
 }
}
기능 테스트
우 리 는 이 프로그램 을 성공 적 으로 시작 한 후에 Postman 도 구 를 사용 하여 인터페이스 테스트 를 진행 했다.
우선 프로그램 이 정상적으로 작 동 하 는 지 확인 하고 GET 방식 으로 요청 합 니 다.
GET http://localhost:8181/api/user
다음 매개 변 수 를 되 돌려 줍 니 다:
{"id":1,"name":"xuwujing","age":18}
예제 그림:

프로그램 이 정상적으로 돌아 오 는 것 을 볼 수 있 습 니 다.사용자 정의 전역 이상 에 영향 을 주지 않 았 습 니 다.
그리고 사용자 정의 이상 이 정확하게 포착 되 고 처 리 될 수 있 는 지 다시 한번 테스트 해 봅 시다.
POST 방식 으로 요청
POST http://localhost:8181/api/user
Body 매개 변 수 는:
{"id":1,"age":18}
다음 매개 변 수 를 되 돌려 줍 니 다:
{"code":"-1","message":"사용자 이름 이 비어 있 으 면 안 됩 니 다!","result":null}
예제 그림:

우리 가 던 진 이상 을 데이터 로 밀봉 한 후 이상 을 되 돌려 주 는 것 을 알 수 있다.
그리고 빈 포인터 이상 이 정확하게 포착 되 고 처 리 될 수 있 는 지 다시 한번 테스트 해 보 자.사용자 정의 전역 이상 에서 우 리 는 빈 포인터 의 이상 처 리 를 정의 하 는 것 외 에 최고 단계 중 하나 인 Exception 이상 도 정의 합 니 다.그러면 빈 포인터 이상 이 발생 한 후에 어떤 것 을 우선 사용 하 시 겠 습 니까?여기 테스트 해 보 겠 습 니 다.
PUT 방식 으로 요청 합 니 다.
PUT http://localhost:8181/api/user
Body 매개 변 수 는:
{"id":1,"age":18}
다음 매개 변 수 를 되 돌려 줍 니 다:
{"code":"400","message":"요청 한 데이터 형식 이 맞지 않 습 니 다!","result":null}
예제 그림:

우 리 는 빈 지침 으로 돌아 가 는 이상 관 리 를 통 해 전체 이상 처리 하위 클래스 의 이상 을 우선 처리 할 수 있 음 을 알 수 있다.
이 이상 이 잡 힐 수 있 는 지 없 는 지 확인 해 보 자.
DELETE 방식 으로 요청 합 니 다.
DELETE http://localhost:8181/api/user
Body 매개 변 수 는:
{"id":1}
다음 매개 변 수 를 되 돌려 줍 니 다:
{"code":"500","message":"서버 내부 오류!","result":null}

전역 이상 처리 클래스 의 Exception 이상 처 리 를 사용자 정의 하 는 방법 을 사용 한 것 을 볼 수 있 습 니 다.
여기까지 테스트 가 끝 났 습 니 다.참고 로 전체 이상 처 리 는 상기 데이터 형식 을 처리 할 수 있 는 것 외 에 페이지 의 점프 도 처리 할 수 있 습 니 다.새로 추 가 된 이상 방법의 반환 처리 에 이 점프 경 로 를 입력 하고 Response Body 주 해 를 사용 하지 않 으 면 됩 니 다.세심 한 학생 들 은 GlobalException Handler 류 에서 Controller Advice 주해 가 아 닌 Controller Advice 주 해 를 사용 하 는 것 을 발견 할 수 있 습 니 다.RestController Advice 주 해 를 사용 하면 데 이 터 를 자동 으로 JSON 형식 으로 변환 합 니 다.이런 것 은 Controller 와 RestController 와 유사 하기 때문에 우 리 는 전체적인 이상 처 리 를 사용 한 후에 유연 한 선택 처 리 를 할 수 있 습 니 다.
기타
SpringBoot 의 우아 한 전역 이상 처리 에 관 한 글 은 여기까지 입 니 다.만약 타당 하지 않 으 면 지적 을 환영 합 니 다!
항목 주소
SpringBoot 전역 이상 처리 프로젝트 주소:
https://github.com/xuwujing/springBoot-study/tree/master/springboot-exceptionHandler
SpringBoot 전체 집합 주소:
https://github.com/xuwujing/springBoot-study
총결산
이상 은 이 글 의 모든 내용 입 니 다.본 고의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가 치 를 가지 기 를 바 랍 니 다.여러분 의 저희 에 대한 지지 에 감 사 드 립 니 다.

좋은 웹페이지 즐겨찾기