@ResponseStatus这个注解确实是个令我头疼的注解.

先记录下@ResponseStatus注解的定义. 记录几个得到的信息:@ResponseStatus声明在方法、类上, Spring3.0开始才有的, 三个属性其中 HttpStatus类型的  value  和 code是一个含义, 默认值就是 服务器 500错误的 HttpStatus.

用法一.标注在@RequestMapping方法上.

@Controller
@RequestMapping("/simple")
public class SimpleController { @RequestMapping("/demo2")
@ResponseBody
@ResponseStatus(code = HttpStatus.OK)
public String demo2(){
return "hello world";
}
}

上面说了 code 和 value一个意思,这里我就用code了,相对而言比较喜欢code单词.   这里作用就是改变服务器响应的状态码 ,比如一个本是200的请求可以通过@ResponseStatus 改成404/500等等.

常见的几个状态码 HttpStatus.OK 就是 200 , HttpStatus.INTERNAL_SERVER_ERROR 就是 500 等等 ,具体的查看 HttpStatus枚举 有详细说明.

实现原理呢,注解底层还是通过设置  response.setStatus来实现.

在@RequestMapping方法执行完成,Spring解析返回值之前,进行了responseStatus设置.

代码片段位于:org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#setResponseStatus

this对象指当前的ServletInvocableHandlerMethod,看到 @ResponseStatus的reason不为空,就调用response.sendError  ; reason为空,就调用setStatus方法仅仅设置响应状态码.

记录下在哪里调用了这个responseStatus方法?

代码片段位于:org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod#invokeAndHandle

发现如果ServletInvocableHandlerMethod的responseReason有值,也就是@ResponseStatus有reason属性,@RequestMapping方法返回值都不处理了,直接返回;

也就是说只要有@ResponseStatus的 reason属性标注在 处理器Controller类或者方法上,比如响应状态码code设置为 404,reason设置为页面没找到 ,那 tomcat 展示界面是这样大概,展示信息就是我们写的reason属性.

@ResponseStatus(code=A,reason=B)标注在 @RequestMapping方法上,作用效果与 response.sendError(A,B)是一样的.

所以,@ResponseStatus我建议啊, 这种方式下使用千万不要加 reason, 就把@ResponseStatus  当做一个用来改变响应状态码的方式!

用法二.标注在@ControllerAdvice中.

@ControllerAdvice
@ResponseStatus
public class MyControllerAdvice { @ExceptionHandler({ArithmeticException.class})
public ModelAndView fix(Exception e){
Map map=new HashMap();
map.put("ex",e.getMessage());
return new ModelAndView("error",map);
} }

@ControllerAdvice标注初衷我想就是程序运行过程中发生异常,对异常如何处理?  而@ResponseStatus标注在@ControllerAdvice类或者该类下的@ExceptionHandler上,区别大概就是,

原来比如请求程序抛出异常,异常被捕获,走@ExceptionHandler,正常走完状态码是200.

@ControllerAdvice或者 @ExceptionHandler标注了@ReponseStatus,那走完状态码就是500.

如果你再给@ResponseStatus添加了reason属性,不管捕获异常方法咋返回,都是服务器的错误码捕获界面,比如上面我的例子,给@ResponseStatus添加reason=”your defined message”.

不管怎么说,下面界面比一大堆异常堆栈信息看起来更简洁,但我还是不推荐使用诶,原因啊,界面不友好.

用法三.自定义类型的异常添加注解@ResponseStatus

@ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR,reason = "not  an error , just info")
public class MyException extends RuntimeException {
public MyException() {
} public MyException(String message) {
super(message);
}
}

这样子,在SpringMvc中如果有某个 @RequestMapping方法抛出该异常,  只要开启<mvc:annotation-driven/>,异常自动展示的界面都是如下的:

SpringMvc异常捕获方法如下.

代码片段位于:org.springframework.web.servlet.DispatcherServlet#processHandlerException

<mvc:annotation-driven/>注册了三个HandlerExceptionResolver:ExceptionHandlerExceptionResolver用来处理@ExceptionHandler,而ResponseStatusExceptionResolver是用来处理抛出的异常上标注了@ResponseStatus的解析器.

ResponseStatusExceptionResolver解析异常方式:

代码片段位于:org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver#doResolveException

ex就是@RequestMapping方法抛出自定义的异常,使用工具类解析自定义异常上的@ResponseStatus注解,找到注解就调用resolveResponseStatus进行响应的处理。

protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) { ResponseStatus responseStatus = AnnotatedElementUtils.findMergedAnnotation(ex.getClass(), ResponseStatus.class);
if (responseStatus != null) {
try {
return resolveResponseStatus(responseStatus, request, response, handler, ex);
}
catch (Exception resolveEx) {
logger.warn("Handling of @ResponseStatus resulted in Exception", resolveEx);
}
}
else if (ex.getCause() instanceof Exception) {
ex = (Exception) ex.getCause();
return doResolveException(request, response, handler, ex);
}
return null;
}

ResponseStatusExceptionResolver如何根据异常上的@ResponseStatus处理响应?

代码片段位于:org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver#resolveResponseStatus

获取了@ReponseStatus的 code   reason属性,reason不为空就 response.sendError(statusCode, reason) ,并且返回一个空的ModelAndView,这里的ModelAndView已经没有意义了,SendError方法简单来说就是会跳转到web.xml中配置的 错误状态码 对应的页面, 没有配置就是默认的服务器的那种错误界面,且只展示 前面的reason信息,即响应类型为text/html .

总结:

不管哪种方式,@ReponseStatus最后都是通过response.setStatus或response.sendError来处理.

如果只是为了返回状态码,建议只使用 @ResponseStatus(code=xxxx)这样来设置响应状态码;

如果抛出异常呢,不建议@ControllerAdvice里面的 @ResponseStatus和   自定义异常上的  @ResponseStatus一起使用,  按照我的阅读理解,两个一起使用肯定是一个生效,而且是 @ControllerAdvice中的@ResponseStatus生效.

场景分析:假设抛出异常不是我们自定义的异常,我们想改变响应的状态码,通过@ExceptionHandler来处理异常,并在@ExceptionHandler方法上也可以设置@ResponseStatus来达到效果;

假如抛出自定义的异常,自己没有定义异常处理界面,那在异常上标注@ResponseStatus就可以走 服务器默认的界面展示,或者通过web.xml 配置error-code \ error-page来自定义界面处理异常;

Spring @ResponseStatus的更多相关文章

  1. SPRING IN ACTION 第4版笔记-第七章Advanced Spring MVC-005- 异常处理@ResponseStatus、@ExceptionHandler、@ControllerAdvice

    No matter what happens, good or bad, the outcome of a servlet request is a servlet response. If an e ...

  2. spring mvc @ResponseStatus 注解 注释返回中文乱码的问题

    前言 前文中讲到,使用@ResponseStatus注解,可以修饰一个异常类,在发生异常的时候返回指定的错误码和消息,在返回的 reason中包含中文的时候,就会出现中文乱码的问题 现象 reason ...

  3. Spring 4 异常处理

    异常与HTTP状态码的映射(@ResponseStatus) Spring默认会将自身抛出的异常自动映射到合适的状态码,如下是一些示例: 举个例子,当后端抛出如下异常(TypeMismatchExce ...

  4. spring mvc统一异常处理(@ControllerAdvice + @ExceptionHandler)

    spring 封装了非常强大的异常处理机制.本文选取@ControllerAdvice + @ExceptionHandler 这种零配置(全注解),作为异常处理解决方案! @ControllerAd ...

  5. Spring中文文档

    前一段时间翻译了Jetty的一部分文档,感觉对阅读英文没有大的提高(*^-^*),毕竟Jetty的受众面还是比较小的,而且翻译过程中发现Jetty的文档写的不是很好,所以呢翻译的兴趣慢慢就不大了,只能 ...

  6. spring mvc异常统一处理(ControllerAdvice注解)

    首先我的项目是一个为移动端提供的json数据的,当后台报错时如果为移动端返回一个错误页面显得非常不友好,于是通过ControllerAdvice注解返回json数据. 首先创建一个异常处理类: pac ...

  7. 详细解说Java Spring的JavaConfig注解 【抄】

    抄自: http://www.techweb.com.cn/network/system/2016-01-05/2252188.shtml @RestController spring4为了更方便的支 ...

  8. spring注解记录

    集中记录spring常见注解 供今后查阅 @ControllerAdvice: ControllerAdvice的定义为: @Target(ElementType.TYPE) @Retention(R ...

  9. 【WEB】初探Spring MVC框架

    Spring MVC框架算是当下比较流行的Java开源框架.但实话实说,做了几年WEB项目,完全没有SpringMVC实战经验,乃至在某些交流场合下被同行严重鄙视“奥特曼”了.“心塞”的同时,只好默默 ...

随机推荐

  1. 《mysql必知必会》学习_第四章_20180724_欢

    P27: select prod_name from products; # select 列 from 表 # 从表products 中检索 名为 prod_name 的列 P28 多个语句一起必须 ...

  2. rsync+sersync+inotify实现服务器间文件同步之一

    rsync+sersync+inotify实现服务器间文件同步之一:rsync安装配置 2013年12月14日 ⁄ Linux管理, 服务器集群技术 ⁄ 共 4925字 ⁄ rsync+sersync ...

  3. 分形之谢尔宾斯基(Sierpinski)四面体

    前面讲了谢尔宾斯基三角形,这一节的将对二维三角形扩展到三维,变成四面体.即将一个正四面体不停地拆分,每个正四面体可以拆分成四个小号的正四面体.由二维转变到三维实现起来麻烦了许多.三维的谢尔宾斯基四面体 ...

  4. vs2017常用快捷键

    项目相关的快捷键 Ctrl + Shift + B = 生成项目 Ctrl + Alt + L = 显示 Solution Explorer(解决方案资源管理器) Ctrl + Shift + A = ...

  5. .net core 部署 docker (CentOS7)

    最近研究 docker 在Linux 下部署 .net core 项目,在过程中踩了很多坑,网上的资料对我帮助确实大,但有些问题未指明出来. 特地整理一份在发布文档 本文使用的是 root 账号操作, ...

  6. 你所不知道的ASP.NET Core MVC/WebApi基础系列 (一)

    转自博客:https://www.cnblogs.com/CreateMyself/p/9235968.html 前言 最近发表的EF Core貌似有点多,可别误以为我只专攻EF Core哦,私下有时 ...

  7. 浏览器环境下Javascript脚本加载与执行探析之DOMContentLoaded

    在”浏览器环境下Javascript脚本加载与执行探析“系列文章的前几篇,分别针对浏览器环境下JavaScript加载与执行相关的知识点或者属性进行了探究,感兴趣的同学可以先行阅读前几篇文章,了解相关 ...

  8. " XSS易容术---bypass之编码混淆篇+辅助脚本编写"

    一.前言本文原创作者:vk,本文属i春秋原创奖励计划,未经许可禁止转载!很多人对于XSS的了解不深.一提起来就是:“哦,弹窗的”.”哦,偷cookie的.”骚年,你根本不知道什么是力量.虽然我也不知道 ...

  9. 套接字:Socket

    在进行通信之前,一般要先建立Socket连接,Socket编程是端到端的通信,往往意识不到中间经过了多少局域网,多少路由器,他能操作的是端到端协议之上的网络层和传输层. 在网络层,Socket函数可以 ...

  10. Synchronzied(内置锁)

    原文地址:深入JVM锁机制1-synchronized 1. 线程的状态与转换 当多个线程同时请求某个对象监视器时,对象监视器会设置几种状态用来区分请求的线程: Contention List:所有请 ...