SpringBoot2 自定义异常

在使用SpringBoot2的时候,发现自定义异常和之前的springMVC有些不同。

1:在springMVC时候默认的少参数或者参数类型错误时
配置一个类轻松搞定DefaultExceptionHandler

public class DefaultExceptionHandler implements HandlerExceptionResolver {
    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultExceptionHandler.class);

    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
                                         Exception ex) {

        ModelAndView mv = new ModelAndView();
        /*  使用FastJson提供的FastJsonJsonView视图返回,不需要捕获异常   */
        FastJsonJsonView view = new FastJsonJsonView();
        Map<String, Object> attributes = new HashMap<String, Object>();
        attributes.put("code", 500);
        attributes.put("message", ex.getMessage());
        view.setAttributesMap(attributes);
        mv.setView(view);
        LOGGER.debug("异常:" + ex.getMessage(), ex);
        return mv;
    }
}

bean-conf.xml

2:使用SpringBoot2 时则不同
默认根据header请求的Accept参数值不同有不同的返回。

a): Accept = application/json

{
    "timestamp": "2018-07-03T07:20:19.686+0000",
    "status": 400,
    "error": "Bad Request",
    "message": "Failed to convert value of type &#39;java.lang.String&#39; to required type &#39;java.lang.Integer&#39;; nested exception is java.lang.NumberFormatException: For input string: &quot;a&quot;",
    "path": "/dmp/oppoUserLables"
}

b): Accept = text/html

<html>
    <body>
        <h1>Whitelabel Error Page</h1>
        <p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p>
        <div id='created'>Tue Jul 03 15:30:11 CST 2018</div>
        <div>There was an unexpected error (type=Bad Request, status=400).</div>
        <div>Failed to convert value of type &#39;java.lang.String&#39; to required type &#39;java.lang.Integer&#39;; nested exception is java.lang.NumberFormatException: For input string: &quot;a&quot;</div>
    </body>
</html>

问题:
项目是接口服务,不想有html的返回值?
json返回参数的格式和需求不太一样?

第一版本:基于ErrorController 进行修改

@RestController
@Slf4j
public class MyErrorController implements ErrorController {
    private static final String ERROR_PATH = "/error";
    private ErrorAttributes errorAttributes;

    @RequestMapping(value = ERROR_PATH)
    public Object error(HttpServletResponse response, HttpServletRequest request) {
        ShortResponse result = new ShortResponse();
        result.setCode(500);
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-type", "application/json;charset=UTF-8");
        response.setStatus(200);
        result.setMessage(request.getRequestURI() + " : request error!" );

        try {
            response.getWriter().write(JSON.toJSONString(result));
        } catch (IOException e) {
            log.error("IOException:" + e.getMessage(), e);
        } catch (Exception e) {
            log.error("Exception:" + e.getMessage(), e);
        }

        return new ModelAndView();

    }

    @Override
    public String getErrorPath() {
        return ERROR_PATH;
    }

}

效果不好,只能返回可怜的error,详情都丢了

第二版本:基于ErrorController 进行修改

@ControllerAdvice
public class MyControllerAdvice {

    /**
     * 应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器
     * @param binder
     */
    @InitBinder
    public void initBinder(WebDataBinder binder) {}

    /**
     * 把值绑定到Model中,使全局@RequestMapping可以获取到该值
     * @param model
     */
    @ModelAttribute
    public void addAttributes(Model model) {
        model.addAttribute("author", "echo");
    }

    /**
     * 全局异常捕捉处理
     * @param ex
     * @return
     */
    @ResponseBody
    @ExceptionHandler(value = Exception.class)
    public Map errorHandler(Exception ex) {
        Map map = new HashMap();
        map.put("code", 5);
        map.put("message", ex.getMessage());
        return map;
    }
}

发现错误可以被捕获,但是404错误确不行。好像需要和方法一结合来用。勉强好使。

但是方法1丢了errorpath.

第三版本:基于ErrorPageRegistrar 和 MyErrorController进行修改

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.server.ErrorPageRegistrar;
import org.springframework.boot.web.server.ErrorPageRegistry;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

/**
 * Created by echo.fx on 7/2 0002.
 */
@Component
@Slf4j
public class ErrorConfigurar implements ErrorPageRegistrar {
    @Override
    public void registerErrorPages(ErrorPageRegistry registry) {
        ErrorPage[] errorPages=new ErrorPage[2];
        errorPages[0]=new ErrorPage(HttpStatus.NOT_FOUND,"/error404");
        errorPages[1]=new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR,"/error500");
        log.info("registerErrorPages");
        registry.addErrorPages(errorPages);

    }
}


import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.alibaba.fastjson.JSON;
import com.alibaba.insight.olap.domain.bean.ShortResponse;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;


/**
 * Created by echo.fx on 5/7 0007.
 */

@RestController
@Slf4j
public class MyErrorController {
    private static final String ERROR_PATH = "/error";
    private ErrorAttributes errorAttributes;

    @RequestMapping("/error404")
    public Object error404(HttpServletResponse response, HttpServletRequest request) {
        ShortResponse result = new ShortResponse();
        result.setCode(404);
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-type", "application/json;charset=UTF-8");
        response.setStatus(404);
        result.setMessage(request.getRequestURI() + " : request error!" );

        try {
            response.getWriter().write(JSON.toJSONString(result));
        } catch (IOException e) {
            log.error("IOException:" + e.getMessage(), e);
        } catch (Exception e) {
            log.error("Exception:" + e.getMessage(), e);
        }
        return new ModelAndView();

    }

    @RequestMapping("/error500")
    public Object error500(HttpServletResponse response, HttpServletRequest request) {
        ShortResponse result = new ShortResponse();
        result.setCode(500);
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-type", "application/json;charset=UTF-8");
        response.setStatus(500);
        result.setMessage(request.getRequestURI() + " : request error!" );

        try {
            response.getWriter().write(JSON.toJSONString(result));
        } catch (IOException e) {
            log.error("IOException:" + e.getMessage(), e);
        } catch (Exception e) {
            log.error("Exception:" + e.getMessage(), e);
        }

        return new ModelAndView();
    }

}

和方法2没有什么区别。404和一般的异常错误需要分开管理,不够集中。

四:最终版本:
当用户访问了一个不存在的链接时, Spring 默认会将页面重定向到 /error 上, 而不会抛出异常。

1:在application.properties文件中, 增加下面两项设置

spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false
第一句配置SpringBoot 当出现 404 错误时, 直接抛出异常。
第二句配置SpringBoot 不要为我们工程中的资源文件建立映射。

2:@ControllerAdvice , @ExceptionHandler


@ControllerAdvice
@ResponseBody
@Slf4j
public class MyControllerAdvice {
    private static final String logExceptionFormat = "ExceptionHandler: Code: %s Detail: %s";

    //400错误-参数类型错误
    @ExceptionHandler({TypeMismatchException.class})
    public String requestTypeMismatch(TypeMismatchException ex) {
        return resultFormat(1001, ex);
    }

    //
    //400错误-缺失参数
    @ExceptionHandler({MissingServletRequestParameterException.class})
    public String requestMissingServletRequest(MissingServletRequestParameterException ex) {
        return resultFormat(1002, ex);
    }

    //其他错误
    @ExceptionHandler({Exception.class})
    public String exception(Exception ex) {
        return resultFormat(500, ex);
    }

    private <T extends Throwable> String resultFormat(Integer code, T ex) {
        log.error(String.format(logExceptionFormat, code, ex.getMessage()), ex);
        return JsonResult.failed(code, ex.getMessage());
    }

}

五:效果:
404时候:

{
 "code": 500,
 "data": {},
 "message": "No handler found for GET /dmp1/oppoUserLables"
}

参数错误时候:

{
 "code": 1001,
 "data": {},
 "message": "Failed to convert value of type 'java.lang.String' to required type 'java.lang.Integer'; nested exception is java.lang.NumberFormatException: For input string: \"a\""
}
{
 "code": 1002,
 "data": {},
 "message": "Required Integer parameter 'timestamp' is not present"
}

这就是我想要的自行车,完美

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值