SpringBoot custom exception to gracefully resolve errors in business logic

Keywords: Java Lombok

outline

Are you worried about the anomalies in business logic, often reporting errors in the background, but the front-end can not prompt the wrong content, resulting in poor user experience? For example, if the order fails, the front end can only prompt the order fails, but do not know why the failure is due to insufficient inventory, insufficient balance, or the failure of the goods?

Before, I wanted to return the encapsulated Reponse(code, data,msg) object directly in the service layer, so I would prompt the cause of the error directly in the service layer (msg: error prompt), but this code is not beautiful, because the Response was originally designed as a unified object returned from the back end, which is too bulky, and finally decided to use custom exceptions to complete.

Define common error enumeration classes

import lombok.AllArgsConstructor;
import lombok.Getter;

/**
 * @author: zp
 * @Date: 2019-10-10 14:47
 * @Description:
 */
@Getter
@AllArgsConstructor
public enum  ErrorType {
    /**
     * Error type
     */
    OBJECT_NOT_FOUND(0,"Object does not exist"),

    INVALID_PARAMS(1,"parameter is incorrect"),

    result_not_exist(2,"Records do not exist")

    ;

    /**
     * Error code
     */
    private int code;

    /**
     * Prompt information
     */
    private String msg;
}

Custom exception

Two constructive methods are provided, one for prompting common errors (in enumeration classes) and the other for uncommon ones (the one that happens twice at a time), which can be extended.

import com.example.demojpa.enums.ErrorType;
import lombok.Getter;

/**
 * @author: zp
 * @Date: 2019-10-10 14:42
 * @Description:
 */
@Getter
public class ServiceException extends RuntimeException{
    private Integer code;

    /**
     * Use existing error types
     * @param type Error types in enumeration classes
     */
    public ServiceException(ErrorType type){
        super(type.getMsg());
        this.code = type.getCode();
    }

    /**
     * Customize error types
     * @param code Customized error codes
     * @param msg Customized error prompts
     */
    public ServiceException(Integer code, String msg){
        super(msg);
        this.code = code;
    }
}

Define response objects and tool classes (this is not required)

  • Response object

    /**
     * @author: zp
     * @Date: 2019-10-10 15:22
     * @Description:
     */
    @Data
    public class Response<T> {
    
            /**
             * Status code
             */
            private Integer code;
    
            /**
             * Objects returned when the request succeeds
             */
            private T data;
    
            /**
             * Prompt information
             */
            private String msg;
    
    }
  • Tool class

    import com.example.demojpa.model.Response;
    
    /**
     * @author: zp
     * @Date: 2019-10-10 15:48
     * @Description:
     */
    public class ResponseUtils {
            /**
             * Successful call
             */
            private static final String SUCCESS = "The call was successful!";
    
            public static Response success(Object obj){
                    Response res = new Response();
                    res.setCode(200);
                    res.setData(obj);
                    res.setMsg(SUCCESS);
                    return res;
            }
    
            public static Response success(){
                    return success(null);
            }
    
            public static Response error(Integer code, String msg){
                    Response res = new Response();
                    res.setCode(code);
                    res.setMsg(msg);
                    return res;
            }
    
    }

Exception handling class

import com.example.demojpa.exception.ServiceException;
import com.example.demojpa.model.Response;
import com.example.demojpa.utils.ResponseUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @author: zp
 * @Date: 2019-10-10 15:11
 * @Description:
 */

@ControllerAdvice 
public class ServiceExceptionHandler {

    /**
     * @ExceptionHandler The @RequestMapping equivalent of controller
     * If ServiceException is thrown, the method is called
     * @param se Business exception
     * @return
     */
    @ExceptionHandler(ServiceException.class)
    @ResponseBody
    public Response handle(ServiceException se){
        return ResponseUtils.error(se.getCode(),se.getMessage());
    }
}

test

For simplicity, I just throw an exception in the controller to see the result.

@GetMapping("/exception/{msg}")
    public String exception(@PathVariable String msg) throws InvalidParamExceptionAbstract, NoSuchObjectExceptionAbstract {
        if(StringUtils.isEmpty(msg)){
            throw new ServiceException(ErrorType.INVALID_PARAMS);
        }else if("null".equals(msg)) {
            throw new ServiceException(ErrorType.OBJECT_NOT_FOUND);
        }else{
            throw new ServiceException(250,"Look at your silliness!");
        }
    }


Focusing on me won't disappoint you.

Posted by mrdeadman on Thu, 10 Oct 2019 14:04:56 -0700