在使用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 'java.lang.String' to required type 'java.lang.Integer'; nested exception is java.lang.NumberFormatException: For input string: "a"",
"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 'java.lang.String' to required type 'java.lang.Integer'; nested exception is java.lang.NumberFormatException: For input string: "a"</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"
}
这就是我想要的自行车,完美