1、常见状态码
http状态返回代码 1xx(临时响应)
表示临时响应并需要请求者继续执行操作的状态代码。
100 (继续) 请求者应当继续提出请求。 服务器返回此代码表示已收到请求的第一部分,正在等待其余部分。
101 (切换协议) 请求者已要求服务器切换协议,服务器已确认并准备切换。
http状态返回代码 2xx (成功)
表示成功处理了请求的状态代码。
200 (成功) 服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。
201 (已创建) 请求成功并且服务器创建了新的资源。
202 (已接受) 服务器已接受请求,但尚未处理。
203 (非授权信息) 服务器已成功处理了请求,但返回的信息可能来自另一来源。
204 (无内容) 服务器成功处理了请求,但没有返回任何内容。
205 (重置内容) 服务器成功处理了请求,但没有返回任何内容。
206 (部分内容) 服务器成功处理了部分 GET 请求。
http状态返回代码 3xx (重定向)
表示要完成请求,需要进一步操作。 通常,这些状态代码用来重定向。
300 (多种选择) 针对请求,服务器可执行多种操作。 服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择。
301 (永久移动) 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。
302 (临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
303 (查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。
304 (未修改) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。
305 (使用代理) 请求者只能使用代理访问请求的网页。 如果服务器返回此响应,还表示请求者应使用代理。
307 (临时重定向) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
http状态返回代码 4xx(请求错误)
这些状态代码表示请求可能出错,妨碍了服务器的处理。
400 (错误请求) 服务器不理解请求的语法。
401 (未授权) 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。
403 (禁止) 服务器拒绝请求。
404 (未找到) 服务器找不到请求的网页。
405 (方法禁用) 禁用请求中指定的方法。
406 (不接受) 无法使用请求的内容特性响应请求的网页。
407 (需要代理授权) 此状态代码与 401(未授权)类似,但指定请求者应当授权使用代理。
408 (请求超时) 服务器等候请求时发生超时。
409 (冲突) 服务器在完成请求时发生冲突。 服务器必须在响应中包含有关冲突的信息。
410 (已删除) 如果请求的资源已永久删除,服务器就会返回此响应。
411 (需要有效长度) 服务器不接受不含有效内容长度标头字段的请求。
412 (未满足前提条件) 服务器未满足请求者在请求中设置的其中一个前提条件。
413 (请求实体过大) 服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。
414 (请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理。
415 (不支持的媒体类型) 请求的格式不受请求页面的支持。
416 (请求范围不符合要求) 如果页面无法提供请求的范围,则服务器会返回此状态代码。
417 (未满足期望值) 服务器未满足"期望"请求标头字段的要求。
http状态返回代码 5xx(服务器错误)
这些状态代码表示服务器在尝试处理请求时发生内部错误。 这些错误可能是服务器本身的错误,而不是请求出错。
500 (服务器内部错误) 服务器遇到错误,无法完成请求。
501 (尚未实施) 服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码。
502 (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。
503 (服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。
504 (网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。
505 (HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。
一些常见的http状态返回代码为:
200 - 服务器成功返回网页
404 - 请求的网页不存在
503 - 服务不可用
2、SpringBoot默认的异常处理机制
默认情况下,Spring Boot为两种情况提供了不同的响应方式。
1. 一种是浏览器客户端请求一个不存在的页面或服务端处理发生异常时,一般情况下浏览器默认发送的请求头中Accept: text/html,所以Spring Boot默认会响应一个html文档内容,称作“Whitelabel Error Page”。
2. 另一种是使用Postman等调试工具发送请求一个不存在的url或服务端处理发生异常时,Spring Boot会返回类似如下的Json格式字符串信息
{
"timestamp": "2018-05-12T06:11:45.209+0000",
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/index.html"
}

2.1、自定义错误页面
好了,了解完Spring Boot默认的错误机制后,我们来点有意思的,浏览器端访问的话,任何错误Spring Boot返回的都是一个Whitelabel Error Page
的错误页面,这个很不友好,所以我们可以自定义下错误页面。
1、 先从最简单的开始,直接在/resources/templates
下面创建error.html就可以覆盖默认的Whitelabel Error Page
的错误页面,我项目用的是thymeleaf模板,对应的error.html代码如下:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
动态error错误页面
<p th:text="${error}"></p>
<p th:text="${status}"></p>
<p th:text="${message}"></p>
</body>
</html>
对应的异常测试的controller如下:
@RequestMapping("/testExce")
@ResponseBody
public String exceptionsDemo(){
int i=10/0;
return "测试";
}
这样运行的时候,请求一个不存在的页面或服务端处理发生异常时,展示的自定义错误界面如下:
可以发现,此时访问的是我们自定义的错误页面,覆盖了系统中的错误页面。
2、此外,如果你想更精细一点,根据不同的状态码返回不同的视图页面,也就是对应的404,500等页面,这里分两种,错误页面可以是静态HTML(即,添加到任何静态资源文件夹下),也可以使用模板构建,文件的名称应该是确切的状态码。
-
2.1、如果是动态模板页面,可以带上错误信息,在resources/templates/下面创建error目录,在error目录下面创建对应的状态码html即可 ,例如,要将404映射到静态HTML文件,您的文件夹结构如下所示:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
自定义错误页面500
<p th:text="${error}"></p>
<p th:text="${status}"></p>
<p th:text="${message}"></p>
</body>
</html>

注:如果同时存在第一种error.html页面,则状态码错误页面将覆盖error.html,状态码错误页面优先级比较高。
2.2、如果只是静态HTML页面,不带错误信息的,在resources/public/下面创建error目录,在error目录下面创建对应的状态码html即可 ,例如,要将404映射到静态HTML文件,您的文件夹结构如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
静态404错误页面
</body>
</html>

注:如果同时存在静态页面500.html和动态模板的500.html,则后者覆盖前者。即
templates/error/
这个的优先级比resources/public/error
高。
- 1.error.html会覆盖默认的 whitelabel Error Page 错误提示
- 2.静态错误页面优先级别比error.html高
- 3.动态模板错误页面优先级比静态错误页面高
@Configuration
public class ContainerConfig {
@Bean
public EmbeddedServletContainerCustomizer containerCustomizer(){
return new EmbeddedServletContainerCustomizer(){
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
container.addErrorPages(new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500"));
}
};
}
}
HttpStatus.INTERNAL_SERVER_ERROR
就是对应500错误码,也就是说程序如果发生500错误,就会将请求转发到/error/500
这个映射来,那我们只要实现一个方法是对应这个/error/500
映射即可捕获这个异常做出处理@RequestMapping("/error/500")
@ResponseBody
public String showServerError() {
return "server error";
}
上面这种方法虽然我们重写了/500映射,但是有一个问题就是无法获取错误信息,想获取错误信息的话,我们可以继承BasicErrorController或者干脆自己实现ErrorController接口,除了用来响应/error这个错误页面请求,可以提供更多类型的错误格式等(BasicErrorController在上面介绍SpringBoot默认异常机制的时候有提到)
这里博主选择直接继承BasicErrorController,然后把上面 /error/500
映射方法添加进来即可
@Controller
public class MyBasicErrorController extends BasicErrorController {
public MyBasicErrorController() {
super(new DefaultErrorAttributes(), new ErrorProperties());
}
// 定义500的ModelAndView
@RequestMapping(produces = "text/html",value = "/500")
public ModelAndView errorHtml500(HttpServletRequest request,HttpServletResponse response) {
response.setStatus(getStatus(request).value());
Map<String, Object> model = getErrorAttributes(request,isIncludeStackTrace(request, MediaType.TEXT_HTML));
model.put("msg","自定义错误信息");
return new ModelAndView("error/500", model);
}
// 定义500的错误JSON信息
@RequestMapping(value = "/500")
@ResponseBody
public ResponseEntity<Map<String, Object>> error500(HttpServletRequest request) {
Map<String, Object> body = getErrorAttributes(request,isIncludeStackTrace(request, MediaType.TEXT_HTML));
HttpStatus status = getStatus(request);
return new ResponseEntity<Map<String, Object>>(body, status);
}
}
代码也很简单,只是实现了自定义的500错误的映射解析,分别对浏览器请求以及json请求做了回应。
BasicErrorController默认对应的@RequestMapping是/error
,固我们方法里面对应的@RequestMapping(produces = "text/html",value = "/500")
实际上完整的映射请求是/error/500
,这就跟上面 customize 方法自定义的映射路径对上了。
errorHtml500 方法中,我返回的是模板页面,对应/templates/error/500.html,这里顺便自定义了一个msg信息,在500.html也输出这个信息<p th:text="${msg}"></p>
,如果输出结果有这个信息,则表示我们配置正确了。

3、全局异常和局部异常
Spring Boot提供的ErrorController是一种全局性的容错机制。此外,你还可以用@ControllerAdvice注解和@ExceptionHandler注解实现对指定异常的特殊处理。
这里介绍两种情况:
- 局部异常处理 @Controller + @ExceptionHandler
- 全局异常处理 @ControllerAdvice + @ExceptionHandler
全局异常处理 @ControllerAdvice + @ExceptionHandler
在spring 3.2中,新增了@ControllerAdvice 注解,可以用于定义@ExceptionHandler、@InitBinder、@ModelAttribute,并应用到所有@RequestMapping中。
简单的说,进入Controller层的错误才会由@ControllerAdvice处理,拦截器抛出的错误以及访问错误地址的情况@ControllerAdvice处理不了,由SpringBoot默认的异常处理机制处理。
我们实际开发中,如果是要实现RESTful API,那么默认的JSON错误信息就不是我们想要的,这时候就需要统一一下JSON格式,所以需要封装一下。这里使用了Lombok。
@Data //get ,set toString
@NoArgsConstructor //无参构造
@AllArgsConstructor //全参构造
public class MyJsonUtil implements Serializable {
//状态码
private String code;
//返回消息
private String message;
//数据
private Object data;
}
注:spring 对于 RuntimeException 异常才会进行事务回滚
Controler中添加一个json映射,用来处理这个异常
@RequestMapping("/testExce")
@ResponseBody
public String exceptionsDemo(){
int i=10/0;
return "测试";
}
全局异常处理:
//定义全局异常处理器
@ControllerAdvice
public class MyGlobalException {
//处理异常
@ExceptionHandler(Exception.class) //捕获所有异常
@ResponseBody
public Object handleException(Exception e,HttpServletRequest req){
AjaxObject r = new AjaxObject();
//业务异常
if(e instanceof BusinessException){
r.put("code", ((BusinessException) e).getCode());
r.put("msg", ((BusinessException) e).getMsg());
}else{//系统异常
r.put("code","500");
r.put("msg","未知异常,请联系管理员");
}
//使用HttpServletRequest中的header检测请求是否为ajax, 如果是ajax则返回json, 如果为非ajax则返回view(即ModelAndView)
String contentTypeHeader = req.getHeader("Content-Type");
String acceptHeader = req.getHeader("Accept");
String xRequestedWith = req.getHeader("X-Requested-With");
if ((contentTypeHeader != null && contentTypeHeader.contains("application/json"))
|| (acceptHeader != null && acceptHeader.contains("application/json"))
|| "XMLHttpRequest".equalsIgnoreCase(xRequestedWith)) {
return r;
} else {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg", e.getMessage());
modelAndView.addObject("url", req.getRequestURL());
modelAndView.addObject("stackTrace", e.getStackTrace());
modelAndView.setViewName("error");
return modelAndView;
}
}
}
@ExceptionHandler 拦截了异常,我们可以通过该注解实现自定义异常处理。其中,@ExceptionHandler 配置的 value 指定需要拦截的异常类型,上面我配置了拦截Exception,
局部异常主要用到的是@ExceptionHandler注解,此注解注解到类的方法上,当此注解里定义的异常抛出时,此方法会被执行。如果@ExceptionHandler所在的类是@Controller,则此方法只作用在此类。如果@ExceptionHandler所在的类带有@ControllerAdvice注解,则此方法会作用在全局。
该注解用于标注处理方法处理那些特定的异常。被该注解标注的方法可以有以下任意顺序的参数类型:
1.Throwable、Exception 等异常对象;
2.ServletRequest、HttpServletRequest、ServletResponse、HttpServletResponse;
3.HttpSession 等会话对象;
4.org.springframework.web.context.request.WebRequest;
5.java.util.Locale;
6.java.io.InputStream、java.io.Reader;
7.java.io.OutputStream、java.io.Writer;
8.org.springframework.ui.Model;
并且被该注解标注的方法可以有以下的返回值类型可选:
1.ModelAndView;
2.org.springframework.ui.Model;
3.java.util.Map;
4.org.springframework.web.servlet.View;
5.@ResponseBody 注解标注的任意对象;
6.HttpEntity<?> or ResponseEntity<?>;
7.void;
以上罗列的不完全,更加详细的信息可参考:Spring ExceptionHandler。
举个简单例子,这里我们对除0异常用@ExceptionHandler来捕捉。
@Controller
public class BaseErrorController extends AbstractController{
private Logger logger = LoggerFactory.getLogger(this.getClass());
@RequestMapping(value="/ex")
@ResponseBody
public String error(){
int i=5/0;
return "ex";
}
//局部异常处理
@ExceptionHandler(Exception.class)
@ResponseBody
public String exHandler(Exception e){
// 判断发生异常的类型是除0异常则做出响应
if(e instanceof ArithmeticException){
return "发生了除0异常";
}
// 未知的异常做出响应
return "发生了未知异常";
}
}
4、总结
到此,SpringBoot中对异常的使用也差不多全了,本项目中处理异常的顺序会是这样,当发送一个请求:
- 拦截器那边先判断是否登录,没有则返回登录页。
- 在进入Controller之前,譬如请求一个不存在的地址,返回404错误界面。
- 在执行@RequestMapping时,发现的各种错误(譬如数据库报错、请求参数格式错误/缺失/值非法等)统一由@ControllerAdvice处理,根据是否Ajax返回json或者view。
5、JSR303
JSR-303 是 JAVA EE 6 中的一项子规范,叫做 Bean Validation。
在任何时候,当你要处理一个应用程序的业务逻辑,数据校验是你必须要考虑和面对的事情。应用程序必须通过某种手段来确保输入进来的数据从语义上来讲是正确的。在通常的情况下,应用程序是分层的,不同的层由不同的开发人员来完成。很多时候同样的数据验证逻辑会出现在不同的层,这样就会导致代码冗余和一些管理的问题,比如说语义的一致性等。为了避免这样的情况发生,最好是将验证逻辑与相应的域模型进行绑定。
Bean Validation 为 JavaBean 验证定义了相应的元数据模型和 API。缺省的元数据是 Java Annotations,通过使用 XML 可以对原有的元数据信息进行覆盖和扩展。在应用程序中,通过使用 Bean Validation 或是你自己定义的 constraint,例如 @NotNull, @Max, @ZipCode, 就可以确保数据模型(JavaBean)的正确性。constraint 可以附加到字段,getter 方法,类或者接口上面。对于一些特定的需求,用户可以很容易的开发定制化的 constraint。Bean Validation 是一个运行时的数据验证框架,在验证之后验证的错误信息会被马上返回。
实例
引入依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
- 实体类:
@Data
public class TTeacher implements Serializable {
private String teacherId;
@NotNull //设置用户名不能为空
private String teacherName;
@Pattern(regexp = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,16}$", message = "密码必须为8~16个字母和数字组合")
private String teacherSubject;
@Email
private String teacherPhone;
}
- controller层如下:Controller 中需要校验的参数Bean前添加 @Valid 开启校验功能。
@RequestMapping("/addTeacher")
@ResponseBody
public String addTeachers(@Valid TTeacher teacher){
teacher.setTeacherId(UUID.randomUUID().toString().replaceAll("-",""));
System.out.println(teacher);
teacherService.addTeacher(teacher);
return teacher.toString();
}
- 全局异常处理如下:
//定义全局异常处理器
@ControllerAdvice
public class MyGlobalException {
//处理异常
@ExceptionHandler(Exception.class) //捕获所有异常
@ResponseBody
public MyJsonUtil MyWideEception(Exception exception){
MyJsonUtil myJsonUtil = new MyJsonUtil();
myJsonUtil.setCode(HttpStatus.SERVICE_UNAVAILABLE+""); //获取异常状态码
myJsonUtil.setMessage(exception.toString()); //获取异常信息
myJsonUtil.setData(exception.getCause());
return myJsonUtil;
}
}
- 测试结果如下:
- 如果输入的信息与其上面要求的信息不一致,则会抛出异常,这里我们使用全局异常来对异常信息进行封装,使得对用户更加的友好。
- 这里,我们的teacherSubject 和teacherPhone不按要求输入,经过全局异常处理,则会返回如下所示信息:
总结:使用jsr303来进行后端数据的校验可以省去很多的if判断,简化了代码。
- 这里只是简单的介绍一下jsr303的使用,更加详细的内容请参照官方文档。
全部评论