在实际开发中,我们会遇到很多异常,在发生异常的时候Spring Boot默认提供了错误页面展示给用户。看似比较友好,其实页面很丑。
上面讲的是做页面开发的时候遇到的问题,还有一种情况就是用来开发Rest接口,当错误的时候我们希望返回给用户的是我们接口的标准格式,不是返回一段html代码。
接下来分别给大家介绍下解决方案:
首先我们来看页面错误的处理情况,当我们的程序内部报错的时候或者访问的页面找不到的时候,我们可以看到下面的错误页面:
我们可以自己设计好看一点的页面来替换这个页面,这样会更友好点,比如我们看今日头条的页面:
以前用Spring MVC时都是直接配置web.xml
<error-page> <error-code>404</error-code> <location>/WEB-INF/view/404.jsp</location> </error-page> <error-page> <error-code>400</error-code> <location>/WEB-INF/view/400.jsp</location> </error-page> <error-page> <error-code>500</error-code> <location>/WEB-INF/view/500.jsp</location> </error-page>
在Spring Boot中也非常简单,直接编写对应的错误页面,进行覆盖即可:
/** * 自定义错误页面覆盖spring boot中的错误页面 * @author yinjihuan * */ @Controller public class ErrorController { @GetMapping("/400") public String badRequest() { return "error/400"; } @GetMapping("/404") public String notFound() { return "error/404"; } @GetMapping("/500") public String serverError() { return "error/500"; } }
页面内容可以自己写:
<body> <section id="error" class="container text-center" style="height:800px;"> <h1>404, 页面没有找到</h1> <p>您正在寻找的页面不存在或发生其他错误。</p> <a class="btn btn-primary" href="http://pan.cxytiandi.com">回到网站首页</a> </section> </body>
在开发rest接口时,我们往往会定义统一的返回格式,列如:
{ "status": true, "code": 200, "message": null, "data": [ { "id": "101", "name": "jack" }, { "id": "102", "name": "jason" } ] }
但是如果调用方请求我们的api时把接口地址写错了,就会得到一个404错误页面,最友好的方式就是返回固定的JSON格式,里面有个code为404。
所以我们需要在发生这种系统错误时也能返回我们自定义的那种格式
定义一个异常处理类
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; @ControllerAdvice public class GlobalExceptionHandler { private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class); /** * 系统异常处理,比如:404,500 * @param req * @param resp * @param e * @return * @throws Exception */ @ExceptionHandler(value = Exception.class) @ResponseBody public ResponseData defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception { logger.error("", e); ResponseData r = new ResponseData(); r.setMessage(e.getMessage()); if (e instanceof org.springframework.web.servlet.NoHandlerFoundException) { r.setCode(404); } else { r.setCode(500); } r.setData(null); r.setStatus(false); return r; } }
ResponseData是我们返回格式的实体类
public class ResponseData { private Boolean status = true; private int code = 200; private String message; private Object data; }
这种在发生错误时这边会捕获到,然后封装好返回格式,返回给调用方
最后关键的一步是在spring boot的配置文件中加上如下配置:
#出现错误时, 直接抛出异常 spring.mvc.throw-exception-if-no-handler-found=true #不要为我们工程中的资源文件建立映射 spring.resources.add-mappings=false
然后我们调用一个不存在的接口时,返回的错误信息就是我们自定义的那种格式了
{ "status": false, "code": 404, "message": "No handler found for GET /rest11/auth", "data": null }
当我们加好rest接口处理的方式后,访问页面不存在就会返回一段json数据,如果你的项目中既有rest接口,又有页面,这个时候就有冲突了。
我们可以通过为rest接口增加统一的访问前缀,比如:/rest/xxxx来区分请求,然后用@ControllerAdvice来分别处理:
import java.io.PrintWriter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; @ControllerAdvice public class GlobalExceptionHandler { private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class); /** * 系统异常处理,比如:404,500 * * @param req * @param resp * @param e * @return * @throws Exception */ @ExceptionHandler(value = Exception.class) // @ResponseBody public Object defaultErrorHandler(HttpServletRequest req, HttpServletResponse response, Exception e) throws Exception { logger.error("", e); if (req.getRequestURI().startsWith("/rest")) { ResponseData r = new ResponseData(); r.setMessage(e.getMessage()); if (e instanceof org.springframework.web.servlet.NoHandlerFoundException) { r.setCode(404); } else { r.setCode(500); } r.setData(null); r.setStatus(false); PrintWriter writer = response.getWriter(); writer.println(JsonUtils.toJson(r)); writer.flush(); writer.close(); return null; } else { if (e instanceof org.springframework.web.servlet.NoHandlerFoundException) { return "error/404"; } else { return "error/500"; } } } }
更多技术分享请关注微信公众号:猿天地