1.@RestController和@Controller,@RestController = @Controller + @ResponseBodyhtml
2.@RequestMapping(mehtod="",value="")用於指定類和方法路徑映射java
RequestMapping註解有六個屬性,下面咱們把她分紅三類進行說明。git
value: 指定請求的實際地址,指定的地址能夠是URI Template 模式(後面將會說明);github
method: 指定請求的method類型, GET、POST、PUT、DELETE等;web
consumes: 指定處理請求的提交內容類型(Content-Type),例如application/json, text/html;spring
produces: 指定返回的內容類型,僅當request請求頭中的(Accept)類型中包含該指定類型才返回;json
params: 指定request中必須包含某些參數值是,才讓該方法處理。spring-mvc
headers: 指定request中必須包含某些指定的header值,才能讓該方法處理請求bash
3.@ResponseBody微信
做用:
該註解用於將Controller的方法返回的對象,經過適當的HttpMessageConverter轉換爲指定格式後,寫入到Response對象的body數據區,即寫入HttpEntity的body中。
在SpringMVC中,可使用@RequestBody和@ResponseBody兩個註解,分別完成請求報文到對象和對象到響應報文的轉換,底層這種靈活的消息轉換機制,就是Spring3.x中新引入的HttpMessageConverter即消息轉換器機制。
#Http請求的抽象 仍是回到請求-響應,也就是解析請求體,而後返回響應報文這個最基本的Http請求過程當中來。咱們知道,在servlet標準中,能夠用javax.servlet.ServletRequest接口中的如下方法:
public ServletInputStream getInputStream() throws IOException;
複製代碼
來獲得一個ServletInputStream。這個ServletInputStream中,能夠讀取到一個原始請求報文的全部內容。一樣的,在javax.servlet.ServletResponse接口中,能夠用如下方法:
public ServletOutputStream getOutputStream() throws IOException;
複製代碼
來獲得一個ServletOutputStream,這個ServletOutputSteam,繼承自java中的OutputStream,可讓你輸出Http的響應報文內容。
讓咱們嘗試着像SpringMVC的設計者同樣來思考一下。咱們知道,Http請求和響應報文本質上都是一串字符串,當請求報文來到java世界,它會被封裝成爲一個ServletInputStream的輸入流,供咱們讀取報文。響應報文則是經過一個ServletOutputStream的輸出流,來輸出響應報文。
咱們從流中,只能讀取到原始的字符串報文,一樣,咱們往輸出流中,也只能寫原始的字符。而在java世界中,處理業務邏輯,都是以一個個有業務意義的對象爲處理維度的,那麼在報文到達SpringMVC和從SpringMVC出去,都存在一個字符串到java對象的阻抗問題。這一過程,不可能由開發者手工轉換。咱們知道,在Struts2中,採用了OGNL來應對這個問題,而在SpringMVC中,它是HttpMessageConverter機制。咱們先來看兩個接口。
#HttpInputMessage 這個類是SpringMVC內部對一次Http請求報文的抽象,在HttpMessageConverter的read()方法中,有一個HttpInputMessage的形參,它正是SpringMVC的消息轉換器所做用的受體「請求消息」的內部抽象,消息轉換器從「請求消息」中按照規則提取消息,轉換爲方法形參中聲明的對象。
package org.springframework.http;
import java.io.IOException;
import java.io.InputStream;
public interface HttpInputMessage extends HttpMessage {
InputStream getBody() throws IOException;
}
複製代碼
#HttpOutputMessage 這個類是SpringMVC內部對一次Http響應報文的抽象,在HttpMessageConverter的write()方法中,有一個HttpOutputMessage的形參,它正是SpringMVC的消息轉換器所做用的受體「響應消息」的內部抽象,消息轉換器將「響應消息」按照必定的規則寫到響應報文中。
package org.springframework.http;
import java.io.IOException;
import java.io.OutputStream;
public interface HttpOutputMessage extends HttpMessage {
OutputStream getBody() throws IOException;
}
複製代碼
#HttpMessageConverter 對消息轉換器最高層次的接口抽象,描述了一個消息轉換器的通常特徵,咱們能夠從這個接口中定義的方法,來領悟Spring3.x的設計者對這一機制的思考過程。
package org.springframework.http.converter;
import java.io.IOException;
import java.util.List;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
public interface HttpMessageConverter<T> {
boolean canRead(Class<?> clazz, MediaType mediaType);
boolean canWrite(Class<?> clazz, MediaType mediaType);
List<MediaType> getSupportedMediaTypes();
T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException;
void write(T t, MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException;
}
複製代碼
HttpMessageConverter接口的定義出現了成對的canRead(),read()和canWrite(),write()方法,MediaType是對請求的Media Type屬性的封裝。舉個例子,當咱們聲明瞭下面這個處理方法。
@RequestMapping(value="/string", method=RequestMethod.POST)
public @ResponseBody String readString(@RequestBody String string) {
return "Read string '" + string + "'";
}
複製代碼
在SpringMVC進入readString方法前,會根據@RequestBody註解選擇適當的HttpMessageConverter實現類來將請求參數解析到string變量中,具體來講是使用了StringHttpMessageConverter類,它的canRead()方法返回true,而後它的read()方法會從請求中讀出請求參數,綁定到readString()方法的string變量中。
當SpringMVC執行readString方法後,因爲返回值標識了@ResponseBody,SpringMVC將使用StringHttpMessageConverter的write()方法,將結果做爲String值寫入響應報文,固然,此時canWrite()方法返回true。
咱們能夠用下面的圖,簡單描述一下這個過程。
#RequestResponseBodyMethodProcessor 將上述過程集中描述的一個類是org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor,這個類同時實現了HandlerMethodArgumentResolver和HandlerMethodReturnValueHandler兩個接口。前者是將請求報文綁定處處理方法形參的策略接口,後者則是對處理方法返回值進行處理的策略接口。兩個接口的源碼以下:
package org.springframework.web.method.support;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
public interface HandlerMethodArgumentResolver {
boolean supportsParameter(MethodParameter parameter);
Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception;
}
package org.springframework.web.method.support;
import org.springframework.core.MethodParameter;
import org.springframework.web.context.request.NativeWebRequest;
public interface HandlerMethodReturnValueHandler {
boolean supportsReturnType(MethodParameter returnType);
void handleReturnValue(Object returnValue,
MethodParameter returnType,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest) throws Exception;
}
複製代碼
RequestResponseBodyMethodProcessor這個類,同時充當了方法參數解析和返回值處理兩種角色。咱們從它的源碼中,能夠找到上面兩個接口的方法實現。
對HandlerMethodArgumentResolver接口的實現:
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(RequestBody.class);
}
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
Object argument = readWithMessageConverters(webRequest, parameter, parameter.getGenericParameterType());
String name = Conventions.getVariableNameForParameter(parameter);
WebDataBinder binder = binderFactory.createBinder(webRequest, argument, name);
if (argument != null) {
validate(binder, parameter);
}
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
return argument;
}
複製代碼
對HandlerMethodReturnValueHandler接口的實現
public boolean supportsReturnType(MethodParameter returnType) {
return returnType.getMethodAnnotation(ResponseBody.class) != null;
}
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException {
mavContainer.setRequestHandled(true);
if (returnValue != null) {
writeWithMessageConverters(returnValue, returnType, webRequest);
}
}
複製代碼
看完上面的代碼,整個HttpMessageConverter消息轉換的脈絡已經很是清晰。由於兩個接口的實現,分別是以是否有@RequestBody和@ResponseBody爲條件,而後分別調用HttpMessageConverter來進行消息的讀寫。
若是你想問,怎麼樣跟蹤到RequestResponseBodyMethodProcessor中,請你按照前面幾篇博文的思路,而後到這裏spring-mvc-showcase下載源碼回來,對其中HttpMessageConverter相關的例子進行debug,只要你肯下功夫,相信你必定會有屬於本身的收穫的。
#思考 張小龍在談微信的本質時候說:「微信只是個平臺,消息在其中流轉」。在咱們對SpringMVC源碼分析的過程當中,咱們能夠從HttpMessageConverter機制中領悟到相似的道理。在SpringMVC的設計者眼中,一次請求報文和一次響應報文,分別被抽象爲一個請求消息HttpInputMessage和一個響應消息HttpOutputMessage。
處理請求時,由合適的消息轉換器將請求報文綁定爲方法中的形參對象,在這裏,同一個對象就有可能出現多種不一樣的消息形式,好比json和xml。一樣,當響應請求時,方法的返回值也一樣可能被返回爲不一樣的消息形式,好比json和xml。
在SpringMVC中,針對不一樣的消息形式,咱們有不一樣的HttpMessageConverter實現類來處理各類消息形式。可是,只要這些消息所蘊含的「有效信息」是一致的,那麼各類不一樣的消息轉換器,都會生成一樣的轉換結果。至於各類消息間解析細節的不一樣,就被屏蔽在不一樣的HttpMessageConverter實現類中了
HttpMessageConverter<T> 是 Spring3.0 新添加的一個接口,負責將請求信息轉換爲一個對象(類型爲 T),將對象(類型爲 T)輸出爲響應信息
(1)HttpInputMessage 將請求的信息先轉爲 InputStream 對象,InputStream 再由 HttpMessageConverter 轉換爲 SpringMVC 須要的java對象;
(2)SpringMVC 返回一個 java 對象, 並經過 HttpMessageConverter 轉爲響應信息,接着 HttpOutputMessage 將響應的信息轉換爲 OutputStream,接着給出響應。
(1)DispatcherServlet 默認加載 HttpMessageConveter 的6個實現類,以下所示:
(2)加入 jackson jar包後,啓動的時候加載 7個 HttpMessageConverter 的實現類,以下所示:
(1) @ResponseBody 和 @RequestBody 示例:
(2) HttpEntity 和 ResponseEntity 示例
實現自定義的消息轉換器要實現AbstractHttpMessageConverter