SpringCloud exception handling unified encapsulation for me to do-use

Posted by iijb on Sat, 23 May 2020 05:57:28 +0200

brief introduction

Repeat function for me to write.There are global exception handling and return wrapping in the SpringBoot project, and the return front end is with fields such as succ, code, msg, data, and so on.Single project scenario is a good solution, when there are many micro-service modules, many cases of development are to copy the original code to build another project, resulting in the upgrade of these functions need to modify multiple services, on this basis, we encapsulate a component unified-dispose-spring-cloud-starter It contains some basic exception handling and return wrapping.

Dependent Add Startup Function

Add Dependency
ps: Use the latest version for the actual version
Latest version:

Click to view the latest version

<dependency>
  <groupId>com.purgeteam.cloud</groupId>
  <artifactId>unified-dispose-spring-cloud-starter</artifactId>
  <version>0.3.0.RELEASE</version>
</dependency>

Startup class adds the @EnableGlobalDispose annotation to turn on the following features.

@EnableGlobalDispose
@SpringBootApplication
public class GlobalDisposeSpringBootApplication {

  public static void main(String[] args) {
    SpringApplication.run(GlobalDisposeSpringBootApplication.class, args);
  }

}

One exception handling⚠️

System exceptions, such as NullPointerException, are common in projects.If the default is not handled, springboot will respond to the default error prompt, which is not friendly to the user experience, system-level errors that the user cannot perceive, even if the error is 500, you can prompt the user with a friendly prompt similar to a server error, and so on.

The module contains some basic exception handling (and already has basic exception handling without any coding), as well as some common exception code s, which users only need to care about handling business exceptions and can throw directly by throw new exceptions.

Exception Handling Containment Type

#General 500 Exception
 Exception class catches 500 exception handling

# Feign exception
 FeignException class capture
 ClientException class capture

#Business Customization
 BusinessException class catches business common custom exceptions

#Parameter Check Exception
 HttpMessageNotReadableException parameter error exception
 BindException parameter error exception

Program actively throws an exception

throw new BusinessException(BusinessErrorCode.BUSINESS_ERROR);
// perhaps
throw new BusinessException("CLOUD800","No excess inventory");

It is not generally recommended to throw generic BusinessException exceptions directly. Instead, add exception handling classes for corresponding domains and corresponding enumeration error types to the corresponding modules.

For example, membership module:
Create UserException exception class, UserErrorCode enumeration.

UserException:

Inherit BusinessException

/**
 * {@link RuntimeException} user Business Exceptions
 *
 * @author purgeyao
 * @since 1.0
 */
@Getter
public class UserException extends BusinessException {

  private String code;
  private boolean isShowMsg = true;

  /**
   * Use enumeration parameters
   *
   * @param errorCode Exception Enumeration
   */
  public UserException(UserErrorCode errorCode) {
    super(errorCode.getCode(), errorCode.getMessage());
    this.code = errorCode.getCode();
  }

}

UserErrorCode:

@Getter
public enum UserErrorCode {
    /**
     * Permission Exception
     */
    NOT_PERMISSIONS("CLOUD401","You do not have permission to operate"),
    ;

    private String code;

    private String message;

    UserErrorCode(String code, String message) {
        this.code = code;
        this.message = message;
    }
}

The final business use is as follows:

// Determine whether you have permission to throw exceptions
throw new UserException(UserErrorCode.NOT_PERMISSIONS);

In this way, the exception is thrown and handled by the module.The foreground returns as follows:

{
  "succ": false,        // Success or not
  "ts": 1566467628851,  // time stamp
  "data": null,         // data
  "code": "CLOUD800",   // Error Type
  "msg": "Business Exceptions",    // Error Description
}

Tow Unified Return Encapsulation_

In REST-style development, avoid informing the foreground about success and status codes.Here we usually return with a util wrapper, such as Result-like classes containing fields such as succ, code, msg, data, and so on.

Interface call handling is similar to the following:

  @GetMapping("hello")
  public Result list(){
    return Result.ofSuccess("hello");
  }

Result:

{
  "succ": ture,         // Success or not
  "ts": 1566467628851,  // time stamp
  "data": "hello",      // data
  "code": null,         // Error Type
  "msg": null,          // Error Description
  "fail": true
}

Functional Use

By default, all web controller s are encapsulated in the following return format.

Interface:

@GetMapping("test")
public String test(){
  return "test";
}

Return

{
  "succ": true,             // Success or not
  "ts": 1566386951005,      // time stamp
  "data": "test",           // data
  "code": null,             // Error Type
  "msg": null,              // Error Description
}

Ignore encapsulation annotation @IgnoreResponseAdvice

public @interface IgnoreResponseAdvice {

    /**
     * Whether to encapsulate global exception handling
     * @return true:Handle; false: No exception handling
     */
    boolean errorDispose() default true;

}

The @IgnoreResponseAdvice permissible range is: class + method, returns identifying all methods under this class on the class will ignore return encapsulation.

Interface:

@IgnoreResponseAdvice // Ignore data packaging to add to classes, methods
@GetMapping("test")
public String test(){
  return "test";
}

Return to test

FeignClient calls exception return handling

The default FeignClient call exception returns a FeignException 500 exception, and because uniform exception handling is turned on, the callee's feign exception is handled and returned as a wrapped result.

Server:

@Override
public Boolean testBoolean() throws Exception {
    throw new Exception("Analogue exception");
}

Caller side:

@GetMapping("testBoolean")
public Boolean testBoolean() throws Exception {
    // Call service side exception
    // The following exception occurs if the server does not add @IgnoreResponseAdvice(errorDispose = false)
    // There was an unexpected error (type=Internal Server Error, status=500).
    // Error while extracting response for type [class java.lang.Boolean] and content type [application/json;charset=UTF-8]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of `java.lang.Boolean` out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.Boolean` out of START_OBJECT token at [Source: (PushbackInputStream); line: 1, column: 1]
    return exampleFeignClient.testBoolean();
}

So the exampleFeignClient#testBoolean call has a feign conversion exception.

The feign interface exception handling for the provider needs to be turned off here.Or add @IgnoreResponseAdvice (errorDispose = false) on this interface class with errorDispose set to false

/**
 * Adding IgnoreResponseAdvice#errorDispose to an exception does not require wrapping
 */
@Override
@IgnoreResponseAdvice(errorDispose = false)
public Boolean testBoolean() throws Exception {
    throw new Exception("Analogue exception");
}

summary

There are many duplicate code s in the project, and we can simplify them in some ways to reduce the amount of development.PurgeTeam has some excellent open source components that reduce daily development.

Sample code address: unified-dispose-spring-cloud-starter

Author GitHub:
Purgeyao Welcome to your attention

qq Group: 812321371 WeChat Group: MercyYao

WeChat Public Number:

This article is published by blog OpenWrite Release!

Topics: Java Spring SpringBoot JSON