Spring フレームワークを学習しているときに、Spring in ActionModelandView
という本の中で、著者はコントローラーでメソッドの戻り値の型を使用していないことに気付きました。作成者はコントローラー メソッドを戻り値の型として宣言しておりString
、メソッドの return 句は次のような文字列を返すだけです。return "/views/theview";
誰かがこれがどのように機能するかの内部の違いを詳しく説明できますか?
Spring フレームワークを学習しているときに、Spring in ActionModelandView
という本の中で、著者はコントローラーでメソッドの戻り値の型を使用していないことに気付きました。作成者はコントローラー メソッドを戻り値の型として宣言しておりString
、メソッドの return 句は次のような文字列を返すだけです。return "/views/theview";
誰かがこれがどのように機能するかの内部の違いを詳しく説明できますか?
これが詳細な外観です。
Spring はDispatcherServlet
、通常、すべてのリクエストを処理するクラスを提供します。それはそのdoDispatch(HttpServletRequest request, HttpServletResponse response)
方法でこれを行います
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
wheremv
は最終ModelAndView
オブジェクトで、ha
は で注釈が付けられたコントローラー メソッドのラッパー@RequestMapping
です。
これは通常、メソッド呼び出しのスタックを経由して、ServletInvocableHandlerMethod.invokeAndHandle
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle
at org.springframework.web.servlet.DispatcherServlet.doDispatch
ソースを見てみると
public final void invokeAndHandle(ServletWebRequest webRequest,
ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
if (returnValue == null) {
if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {
mavContainer.setRequestHandled(true);
return;
}
} else if (StringUtils.hasText(this.responseReason)) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
try {
this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
}
catch (Exception ex) {
if (logger.isTraceEnabled()) {
logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
}
throw ex;
}
}
returnValue
@RequestMapping
メソッドによって返されるオブジェクトです。通じます
this.returnValueHandlers.handleReturnValue
ここで、Spring はHandlerMethodReturnValueHandler
そのオブジェクトを処理する を決定します。
public void handleReturnValue(
Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws Exception {
HandlerMethodReturnValueHandler handler = getReturnValueHandler(returnType); // returns the appropriate handler
Assert.notNull(handler, "Unknown return value type [" + returnType.getParameterType().getName() + "]");
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
getReturnValueHandler(returnType);
適切なハンドラを返します。は、ハンドラーがその型 ( 、、など(サポートされている戻り値の型を探す) ) をサポートしている場合に戻るメソッドをHandlerMethodReturnValueHandler
持つインターフェイスです。そのため、このメソッドは、その型をサポートする最初に見つかったハンドラーを返し、それを実行します。supportsReturnType
true
String
View
ResponseEntity
Spring は、初期化時に、 の多数の実装を登録しますHandlerMethodReturnValueHandler
。基本的に、javadoc 内のすべての既知の実装クラス。
たとえば、文字列を返す場合、Spring は a を使用しViewNameMethodReturnValueHandler
て応答を処理します。
さて、どの戻り型を使用するかはあなた次第です。Model
jsp ビューでリクエスト属性を使用できるように を返したい場合は、Spring にModel
インスタンスをメソッドに渡すか、Model
自分でオブジェクトを作成してModelAndView
それを返すことができます。ほとんどの場合、それはスタイルの問題です。
機能的に違いはありません。これらはどちらも同等です。
@RequestMapping(..)
public String requestMapping1(Model model){
model.addAttribute("attr1", attr1);
return "viewName";
}
@RequestMapping(..)
public ModelAndView requestMapping2(){
ModelAndView modelAndView = new ModelAndView("viewName");
modelAndView.addObject("attr1", attr1);
return modelAndView;
}
ただし、好ましいアプローチは前者であり、それが著者が本のサンプルで後者を使用しなかった理由です。
Spring のソース コードでは、このクラスが表示されますorg.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
。メソッド public ModelAndView getModelAndView(...)
では、sping-mvc がオブジェクトを生成する方法を取得できModelAandView
ます。
if (returnValue instanceof HttpEntity) { // returnValue is returned Value of Handler method
handleHttpEntityResponse((HttpEntity<?>) returnValue, webRequest);
return null;
}
else if (AnnotationUtils.findAnnotation(handlerMethod, ResponseBody.class) != null) {
handleResponseBody(returnValue, webRequest);
return null;
}
else if (returnValue instanceof ModelAndView) {
ModelAndView mav = (ModelAndView) returnValue;
mav.getModelMap().mergeAttributes(implicitModel);
return mav;
}
else if (returnValue instanceof Model) {
return new ModelAndView().addAllObjects(implicitModel).addAllObjects(((Model) returnValue).asMap());
}
else if (returnValue instanceof View) {
return new ModelAndView((View) returnValue).addAllObjects(implicitModel);
}
else if (AnnotationUtils.findAnnotation(handlerMethod, ModelAttribute.class) != null) {
addReturnValueAsModelAttribute(handlerMethod, handlerType, returnValue, implicitModel);
return new ModelAndView().addAllObjects(implicitModel);
}
else if (returnValue instanceof Map) {
return new ModelAndView().addAllObjects(implicitModel).addAllObjects((Map) returnValue);
}
else if (returnValue instanceof String) { // String is here, return new ModelAndView
return new ModelAndView((String) returnValue).addAllObjects(implicitModel);
}
したがって、このメソッドでは、spring-mvc が返された多くのタイプのハンドラー メソッドを処理して ModleAndView オブジェクトを構築できることを学習できます。