Spring的Web MVC框架
Spring的Web MVC框架是一个请求驱动的Web框架,该框架的核心是基于分发器(DispatchServlet)设计的,它是一个将请求分发到控制器的Servlet。DispatchServlet将从Web page收集到的不同请求分发到不同的控制器,控制器Controller收到request和reponse参数,干脆利落的返回ModelAndView。而其他框架的控制器一般只返回View name。
控制器,Spring中的控制器概念相当于Struts框架中的action。Spring 的缺省处理器是一个简单的控制器(Conroller)接口,这个接口仅仅定义了ModelAndView handleRequest(request,resporme)方法。你可以自己实现这个
接口生成应用的控制器,但使用Spring提供的一系列控制器实现会更好一些,比如AbstractContoller,AbstractComnmndContoller等应用控制器一般都从它们继承。
1一个简单的实例:
<html>
<body>
<form method="POST" action="/mySpring/login.do">
<p align="center">登录</p>
<br>
用户名:
<input type="text" name="username" >
<br>
密 码 :
<input type="password" name="password" >
<br>
<p>
<input type="submit" value="提交" name="B1">
<input type="reset" value="重置" name="B2">
</p>
</form>
</body>
</html>
上面的的是请求页面,下面我们在web.xml中配置DispatchServlet来处理*.do的请求。在web.xml增加下面的配置:
如果找不到org.springframework.web.servlet.DispatcherServlet,则需要spring-webmvc.jar包。如果报jstl的异常,则导入jstl.jar包。
<!-- 配置Spring MVC -->
<servlet>
<servlet-name>Dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-name>/WEB-INF/Config.xml</param-name>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Dispatcher</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
Servlet定义
这里我们定义了请求分发Servlet,即:
org.springframework.web.servlet.DispatcherServlet
DispatcherServlet 是Spring MVC 中负责请求调度的核心引擎,所有的请求将由此Servlet 根据配置分发至各个逻辑处理单元。其内部同时也维护了一个ApplicationContext实例。
我们在<init-param>节点中配置了名为“contextConfigLocation”的Servlet参数,此参数指定了Spring配置文件的位置“/WEB-INF/Config.xml”。如果忽略此设定,则默认为“/WEB-INF/<servlet name>-servlet.xml”,其中<servlet name>以Servlet 名替换(在当前环境下,默认值也就是/WEB-INF/Dispatcher-servlet.xml)。
我们将所有以.do结尾的请求交给Spring MVC进行处理。
Dispatcher根据什么来分发请求,我们需要在配置文件加以设定,这也就是上面的Config.xml。此文件包含了所有的"请求/处理单元"关系映射设定,以及返回时表现层的一些属性设置。下面是Config.xml文件的内容:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!--Definition of View Resolver -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass">
<value>
org.springframework.web.servlet.view.JstlView
</value>
</property>
<!--
<property name="prefix">
<value>
/WEB-INF/view/
</value>
</property>
-->
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<!--Request Mapping -->
<bean id="urlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/login.do">LoginAction</prop>
</props>
</property>
</bean>
<!---Action Definition-->
<bean id="LoginAction"
class="springmvc.action.LoginAction">
<property name="commandClass">
<value>springmvc.action.LoginInfo</value>
</property>
<property name="fail_view">
<value>loginfail</value>
</property>
<property name="success_view">
<value>main</value>
</property>
</bean>
</beans>
viewResolver设定
在<bean id="viewResolver" ...>...</bean>中,Resolver将把输出结果与输出界面相融合,为表现层提供呈现资源。
viewResolver的viewClass属性,这里使用JSP页面作为输出,因此设定为:
org.springframework.web.servlet.view.JstlView
其余可选的viewClass还有:
org.springframework.web.servlet.view.freemarker.FreeMarker,View(用于基于FreeMarker模板的表现层实现)
org.springframework.web.servlet.view.velocity.VelocityView,(用于基于velocity模板的表现层实现)
viewResolver的prefix属性和suffix属性,制定了表现层资源的前缀和后缀,运行时,Spring 将为指定的表现层资源自动追加
前缀和后缀,以形成一个完整的资源路径。一般我们不加前缀,默认是当前项目的webRoot下的路径。
"请求/处理单元"关系映射
这里我们将“/login.do”请求映射到处理单元LoginAction。<props>节点下可以有多个映射关系存在,目前我们只定义了一个。login.do可以加上"/"也可以不加"/",都是表示当前项目根路径下。如我们的项目名为mySpring则,请求路径为/mySpring/login.do
LoginAction处理单元的请求数据对象
commandClass 属性源于LoginAction 的基类BaseCommandController,
BaseCommandController,包含了请求数据封装和验证方法。
(BaseCommandController.bindAndValidate),它将根据传入的HttpServletRequest构造请求数据对象。
这里的commandClass为springmvc.action.LoginInfo,这是一个非常简单的java Bean,它封装了登录请求所需的数据内容。
package springmvc.action;
public class LoginInfo{
public String username;
public String password;
public String getUsername()
{
return username;
}
public void setUsername(String username)
{
this.username = username;
}
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
}
Spring会根据LoginAction的commandClass定义自动加载对应的LoginInfo实例,然后对Http请求中的参数进行遍历,并查找LoginInfo 对象中是否存在与之同名的属性,如果找到,则将此参数值复制到LoginInfo对象的同名属性中。
请求数据转换完成之后,我们得到了一个封装了所有请求参数的Java 对象,并将此对象作为输入参数传递给LoginAction。
LoginAction处理单元的返回视图定义
对于这里的LoginAction 而言,有两种返回结果,即登录失败时返回错误界面,登录成功时进入系统主界面。
对应我们配置了fail_view、success_view两个自定义参数。
参数值将由Resolver进行处理,为其加上前缀后缀,如对于fail_view而言,实际的视图路径为/WEB-INF/view/loginfail.jsp。
之后,Resolver 会将LoginAction的返回数据与视图相融合,返回最终的显示界面。
业务逻辑处理单元:LoginAction.java
package springmvc.action;
import java.net.BindException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;
public class LoginAction extends SimpleFormController
{
private String fail_view;
private String success_view;
public String getFail_view()
{
return fail_view;
}
public void setFail_view(String failView)
{
fail_view = failView;
}
public String getSuccess_view()
{
return success_view;
}
public void setSuccess_view(String successView)
{
success_view = successView;
}
protected ModelAndView onSubmit(Object o, org.springframework.validation.BindException errors)
throws Exception
{
LoginInfo loginInfo = (LoginInfo) o;
if (login(loginInfo) == 0) {
return new ModelAndView(this.getSuccessView(),"loginInfo", loginInfo);
} else {
return new ModelAndView(this.getFail_view());
}
}
private int login(LoginInfo loginInfo) {
if ("Erica".equalsIgnoreCase(loginInfo.getUsername())
&& "mypass".equals(loginInfo.getPassword())) {
return 0;
}
return 1;
}
}
成功后的视图main.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<html>
<head>
</head>
<body>
<p>Login Success!!!</p>
<p>Current User:
${loginInfo.username}
</p>
</body>
</html>
onSubmit方法
我们在子类中覆盖了父类的onSubmit方法;而onSubmit方法用于处理业务请求。负责数据封装和请求分发的Dispatcher,将对传入的HttpServletRequest进行封装,形成请求数据对象,之后根据配置文件,调用对应业务逻辑类的入口方法(这里就是LoginAction的onSubmit()方法),并将请求数据对象及其他相关资源引用传入。
onSubmit方法包含了两个参数:Object o和BindException errors。前面曾经多次提到请求数据对象,这个名为o的Object型参数,正是传入的请求数据对象的引用。
BindException errors参数则提供了数据绑定错误的跟踪机制。它作为错误描述工具用于向上层反馈错误信息。
在Spring MVC中,BindException将被向上层表现层反馈,以便在表现层统一处理异常情况(如显示对应的错误提示),这一机制稍后在“输入参数合法性校验”部分再具体探讨。
onSubmit还有另外一个版本:
protected ModelAndView onSubmit(
HttpServletRequest request,
HttpServletResponse response,
Object cmd,
BindException errors
)
可以看到,类似Servlet的doGet/doPost方法,此版本的onSubmit方法中包含了Servlet规范中的HttpServletRequest、HttpServletResponse以提供与Web服务器的交互功能(如Session的访问)。此参数类型的onSubmit方法的调用优先级较高。也就是说,如果我们在子类中同时覆盖了这两个不同参数的onSubmit方法,那么只有此版本的方法被执行,另一个将被忽略。
在onSubmit中LoginInfo loginInfo = (LoginInfo) o;将输入的请求数据对象强制转型为预定义的请求对象类型。
返回处理结果
ModelAndView类包含了逻辑单元返回的结果数据集和表现层信息。ModelAndView本身起到关系保存的作用。它将被传递给Dispatcher,由Dispatcher 根据其中保存的结果数据集和表现层设定合成最后的界面。
这里我们用到了两种签名版本的ModelAndView构造方法:
public ModelAndView(String viewname)
返回界面无需通过结果数据集进行填充。
public ModelAndView(String viewname, Map model)
返回界面由指定的结果数据集加以填充。可以看到,结果数据集采用了Map接口实现的数据类型。其中包含了返回结果中的各个数据单元。
上面这两个版本的构造子中,通过viewname指定了表示层资源。
new ModelAndView(this.getSuccessView(),"loginInfo", loginInfo);上例中的ModelAndView的对象,将loginInfo对象一起传递到SuccessView的视图,我们在视图中通过${loginInfo.username}来得到loginInfo对象的内容。
另外,我们也可以通过传递View对象指定表示层资源。
public ModelAndView(View view)
public ModelAndView(View view, Map model)
我们可以结合RedirectView完成转向功能,如:
return new ModelAndView(new RedirectView("/redirected.jsp"));
当然,我们也可以在带有HttpServletRequest参数的onSubmit方法实现中,通过HttpServletRequest/HttpServletResponse完成forward/redirect功能,这两种途径可以达到同样的效果。
2 AbstractController 和 WebContentGenerator控制器
所有的Spring控制器都继承了 AbstractController ,AbstractController提供了诸如缓存支持和mimetype设置这样的功能。
当从AbstractController继承时,只需要实现handleRequestInternal(HttpServletRequest, HttpServletResponse)抽象方法,该方法将用来实现自定义的逻辑,并返回一个ModelAndView对象。
MultiActionController控制器
Spring提供了MultiActionController来将多个请求处理方法合并在一个控制器里,这样可以把请求功能组合在一起。MultiActionController位于org.springframework.web.mvc.multiaction包中,它可以定义页面请求到控制器方法名的映射,然后在处理相应请求时调用该方法。
MultiActionController有两种使用方式:
一是创建MultiActionController的子类,并指定将被MethodNameResolver解析的方法(这种情况下不需要这个delegate参数);我们通常会使用ParameterMethodNameResolver或PropertiesMethodNameResolver,在一個网址上結合請求参数,以参数來決定要执行哪一個Action,以ParameterMethodNameResolver为例。
<bean id="paraMethodResolver"
class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver">
<property name="paramName"><value>method</value></property>
<property name="defaultMethodName"><value>list</value></property>
</bean>
<bean id="bookAction" class="onlyfun.caterpillar.GuestBookAction">
<property name="methodNameResolver">
<ref bean="paraMethodResolver"/>
</property>
<property name="testPage">
<value>test</value>
</property>
</bean>
在paraMethodResolver中,我们使用paramName定义在http请求中使用method参数来指定要呼叫的方法,如果请求中没有指定method参数,则会使用defaultMethodName所指定的方法,这边指定的是list()方法。GuestBookAction是继承MultiActionController类,其中定义了我们在method参数指定所要呼叫的方法。如:
package onlyfun.caterpillar;
import javax.servlet.http.*;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
public class GuestBookAction extends MultiActionController {
privateString testPage;
public ModelAndView list(HttpServletRequest req, HttpServletResponse res) {
returnnew ModelAndView(this.getTestPage(),"executed", "list");
}
public ModelAndView add(HttpServletRequest req, HttpServletResponse res) {
returnnew ModelAndView(this.getTestPage(),"executed", "add");
}
public ModelAndView delete(HttpServletRequest req, HttpServletResponse res) {
returnnew ModelAndView(this.getTestPage(),"executed", "delete");
}
publicString getTestPage() {
return testPage;
}
public void setTestPage(String testPage) {
this.testPage = testPage;
}
}
注意我们的方法必须包括HttpServletRequest与HttpServletResponse作为参数,你可以使用带有第三个参数HttpSession的版本。所以当我们请求http://localhost:8080/springapp/book.do?method=add,将会执行method参数的值add方法。
二你可以将所对应的方法专门组织在一个委托(delegate)类中,而不是写在Contoller类别中,当请求来到时,将委托给这个类来执行指定的方法,你只要定义MultiActionContoller的delegate属性既可。委托类如下:
package onlyfun.caterpillar;
import javax.servlet.http.*;
import org.springframework.web.servlet.ModelAndView;
public class BookActionDelegate {
privateString testPage;
public ModelAndView list(HttpServletRequest req, HttpServletResponse res) {
returnnew ModelAndView(this.getTestPage(),"executed", "list");
}
public ModelAndView add(HttpServletRequest req, HttpServletResponse res) {
returnnew ModelAndView(this.getTestPage(),"executed", "add");
}
public ModelAndView delete(HttpServletRequest req, HttpServletResponse res) {
returnnew ModelAndView(this.getTestPage(),"executed", "delete");
}
publicString getTestPage() {
return testPage;
}
public void setTestPage(String testPage) {
this.testPage = testPage;
}
}
委托类BookActionDelegate.java和GuestBookAction.java的方法一样,只是它不需要继承MultiActionController。
然后我们在配置文件中作一些修改,直接使用MultiActionController:
<bean id="paraMethodResolver"
class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver">
<property name="paramName"><value>method</value></property>
<property name="defaultMethodName"><value>list</value></property>
</bean>
<bean id="bookActionDelegate" class="onlyfun.caterpillar.BookActionDelegate">
<property name="testPage">
<value>test</value>
</property>
</bean>
<bean id="bookAction" class="org.springframework.web.servlet.mvc.multiaction.MultiActionController">
<property name="methodNameResolver">
<ref bean="paraMethodResolver"/>
</property>
<property name="delegate">
<ref bean="bookActionDelegate"/>
</property>
</bean>
delegate属性指定了委托类bookActionDelegate。
3ModelAndView
通常,Controller在将Web请求处理完成后,会返回一个ModelAndView实例。该ModelAndView实例将包含两部分内容,一部分为视图相关内容,可以是逻辑视图名称,也可以是具体的View实例;另一部分则是模型数据,视图渲染过程中将会把这些模型数据合并入最终的视图输出。
为了方便实例化ModelAndView,该类定义了两组参数各异的构造方法,一组使用逻辑视图名称(logic named view)标志视图,一组直接使用View实例标志视图,如下所示:
public ModelAndView(String viewName)
public ModelAndView(String viewName,Map model)
public ModelAndView(String viewName,String modelName,Object modelObject)
public ModelAndView(View view)
public ModelAndView(View view,Map model)
public ModelAndView(View view,String modelName,Object modelObject)
每组的第一个构造方法只接受视图信息,所以构造完成后,我们通过addAllObject(..)或者addObject(..)实例方法,向构造完成的ModelAndView实例添加模型数据;每组第二个构造方法则可以同时指定视图信息和模型数据信息,如果要添加到模型的只有一个数据对象,那么可以使用每组的第三个构造方法,该构造方法属于第二个构造方法的简化版。
虽然通过ModelAndView可以保存视图的逻辑名称或者具体的View实现类,但是我们更倾向于使用逻辑视图名来标志视图。这样可以给我们的视图选择带来很大的灵活性。
4可用的ViewResolver实现类
Spring MVC提供的ViewResolver划分为两类,一类称为"面向单一视图类型的ViewResolver,另一个类称为面向多视图类型的ViewResolver。
面向单一视图类型的ViewResolver有如下几个:
InternalResourceViewResolver。它是我们使用最多的ViewResolver实现类型,是用来处理JSP模板类型的视图映射。它作为默认的ViewResolver被使用。
FreeMarkerViewResolver/VelocityViewResolver。FreeMarkerViewResolver和Velo- cityViewResolver分别负责对应FreeMarkerView和VelocityView类型视图的查找工作,它们将根据逻辑视图名到指定的位置获取对应的模板文件,并构造FreeMarkerView和VelocityView的实例返回给DispatcherServlet使用。
JasperReportsViewResolver。JasperReportsViewResolver只关心根据逻辑视图名到指定位置查找JasperReport类型模板文件,并返回AbstractJasperReportsView的具体子类型View实例
XsltViewResolver。只负责根据逻辑视图名查找并返回XsltView类型的View实例。
启用以上这些ViewResolver,与使用InternalResourceViewResolver一样简单。最基本的方法是,使用prefix属性指定模板所在路径,使用suffix属性指定模板文件的后缀名。这样,在获取逻辑视图名之后,相应的ViewResolver内部就能够根据[prefix]+viewName+[suffix]这样的URL找到对应的模板文件,并构造对应的View实例而返回了。VelocityViewResolver的配置代码示例:
<bean id="viewResolver" class="org.springframework.Web.servlet.view.velocity.VelocityViewResolver">
<property name="prefix" value="../velocity/"/>
<property name="suffix" value=".vm"/>
</bean>
面向多视图类型的ViewResolver
使用面向多视图类型的ViewResolver,我们需要通过某种配置方式明确指定逻辑视图名与具体视图之间的映射关系,面向多视图类型的ViewResolver可以顾及多种视图类型的映射管理。面向多视图类型的ViewResolver的主要实现类有三个:
ResourceBundleViewResolver
ResourceBundleViewResolver构建在ResourceBundle上,继承了ResourceBundle国际化支持的能力,也是所有的ViewResolver实现类中唯一提供视图国际化支持的ViewResolver。ResourceBundleViewResolver管理的视图的逻辑名称与具体视图的映射关系保存在properties文件中。
使用ResourceBundleViewResolver之前,我们得先将其添加到spring配置文件中,如下所示:
<bean id="resourceBundleViewResolver" class="org.springframework.Web.servlet.view.ResourceBundleViewResolver">
<property name="basenames">
<list>
<value>default_views</value>
<value>protocal_views</value>
</list>
</property>
</bean>
如果我们没有指定properties配置文件从何处加载的话,ResourceBundleViewResolver默认将从classpath(WEB-INF/classes目录下)的根路径加载以views为basename的properties文件,如:views.properties、views_zh_CN.properties等。如果我们想改变这种默认加载行为,可以通过setBasename(string)或setBasenames(String[])方法来进行变更。如上面通过<list>...</list>给basenames[]属性注入值default_views,default_views则,ResourceBundleViewResolver将会加载default_views.properties和protocal_views.properties。也可以对basename属性进行注入<property name="basename" value="views"/>,将会加载views.properties。
WEB-INF/classes目录下default_views.properties内容如下
welcome.class=org.springframework.web.servlet.view.JstlView
welcome.url=/WEB-INF/jsp/welcome.jsp
productList.class=org.springframework.web.servlet.view.JstlView
productList.url=/WEB-INF/jsp/productlist.jsp
welcome与productList是视图名称,它的class属性指出该视图的类型(JstlView为jsp类型的视图);url指出了改视图名称对应的页面路径。
XmlViewResolver
XmlViewResolver与ResourceBundleViewResolver之间最主要的区别就是,它们所采用的配置文件格式不同。ResourceBundleViewResolver按照Spring IoC容器所接受的properties配置格式配置逻辑视图名与具体视图之间的映射关系,而XmlViewResolver则是按照Spring IoC容器接受的XML配置文件格式来加载映射信息。
使用XmlViewResolver,也是同样要先到Spring配置文件中添加如下配置:
<bean id="xmlViewResolver" class="org.springframework.Web.servlet.view.XmlViewResolver">
<property name="location" value="classpath:views.xml"/>
</bean>
XmlViewResolver默认会加载/WEB-INF/views.xml作为配置文件。不过我们配置它的location属性来改变要加载的xml配置文件的路径。上例中将从Classpath的根路径加载名为views.xml的配置文件。views.xml文件的内容如下:
<bean name="hello" class="org.springframework.Web.servlet.view.velocity.VelocityView" p:url="cn/spring21/simplefx/resources/velocity/hello.vm">
</bean>
BeanNameViewResolver
BeanNameViewResolver可以认为是XmlViewResolver的原型版或者简化版。它不会将View实例的配置写在单独的xml文件中而是一起写在Spring的配置文件中。
http://www.my11120.cn/entry/spring3_mvc_20111021.html
***********************************
<mvc:annotation-driven/>配置
相当于注册了DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter两个bean,配置一些messageconverter。即解决了@Controller注解的使用前提配置
<!-- 处理在类级别上的@RequestMapping注解 -->
<bean
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<list>
<!-- 多个拦截器,顺序执行 -->
<ref bean="SpringMVCInterceptor" />
<ref bean="OpenSessionInViewInterceptor"/>
</list>
</property>
</bean>
<!-- 处理方法级别上的@RequestMapping注解 -->
<bean id="annotationMethodHandlerAdapter"
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<bean
class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=utf-8</value>
<value>text/plain;charset=utf-8</value>
</list>
</property>
</bean>
<bean
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverterv2">
<property name="objectMapper">
<bean class="net.pm.misc.Hibernate4AwareObjectMapper" />
</property>
</bean>
</list>
</property>
</bean>
配置了<mvc:annotation-driven/>这个配置声明,就不用再注册了DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter。
否则会实例化两个DefaultAnnotationHandlerMapping,并且不使用你配置的那个 DefaultAnnotationHandlerMapping.
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter与<mvc:annotation-driven />
关系与上同理.
*********************************
<context:annotation-config />配置
<context:annotation-config/>是对包进行扫描,实现注释驱动Bean定义,同时将bean自动注入容器中使用。即解决了@Controller标识的类的bean的注入(@Autowired,@Resource)和使用。
默认会初始化AnnotationMethodHanlderAdapter,但我们返回xml内容需要对这个HandlerAdapter进行一定的修改,所以配置文件如下:
<context:component-scan base-package="com.controls" />
<context:annotation-config />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="stringHttpMessageConverter" />
<ref bean="jsonHttpMessageConverter" />
<ref bean="marshallingHttpMessageConverter" />
</list>
</property>
</bean>
<bean id="stringHttpMessageConverter" class="org.springframework.http.converter.StringHttpMessageConverter" />
<bean id="jsonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
<bean id="marshallingHttpMessageConverter" class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<constructor-arg ref="jaxbMarshaller" />
<property name="supportedMediaTypes" value="application/xml"></property>
</bean>
<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.model.User</value>
</list>
</property>
</bean>
注:要使用Jaxb2Marshaller我们在对应的实体,比如User类上需要标明
<context:annotation-config/>这样一条配置,他的作用是式地向 Spring 容器注册
AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、
PersistenceAnnotationBeanPostProcessor 以及 RequiredAnnotationBeanPostProcessor 这 4 个BeanPostProcessor。
注册这4个 BeanPostProcessor的作用,就是为了你的系统能够识别相应的注解。
例如:
如果你想使用@Autowired注解,那么就必须事先在 Spring 容器中声明 AutowiredAnnotationBeanPostProcessor Bean。传统声明方式如下
<bean class="org.springframework.beans.factory.annotation. AutowiredAnnotationBeanPostProcessor "/>
如果想使用@ Resource 、@ PostConstruct、@ PreDestroy等注解就必须声明CommonAnnotationBeanPostProcessor
如果想使用@PersistenceContext注解,就必须声明PersistenceAnnotationBeanPostProcessor的Bean。
如果想使用 @Required的注解,就必须声明RequiredAnnotationBeanPostProcessor的Bean。同样,传统的声明方式如下:
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>
一般来说,这些注解我们还是比较常用,尤其是Antowired的注解,在自动注入的时候更是经常使用,所以如果总是需要按照传统的方式一条一条配置显得有些繁琐和没有必要,于是spring给我们提供<context:annotation-config/>的简化配置方式,自动帮你完成声明。
不过,我们使用注解一般都会配置扫描包路径选项
<context:component-scan base-package=”XX.XX”/>s
该配置项其实也包含了自动注入上述processor的功能,因此当使用 <context:component-scan/> 后,就可以将 <context:annotation-config/> 移除了。
******************************************
@Autowired与 @Resource区别:
@Autowired
@Autowired是Spring 提供的,需导入
Package:org.springframework.beans.factory.annotation.Autowired;
只按照byType 注入。
@Resource
@Resource默认按 byName 自动注入,是J2EE提供的, 需导入Package:
javax.annotation.Resource;
@Resource有两个中重要的属性:name和type ,而Spring将@Resource注解的name属性解析为bean的
名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用
type属性时则使用 byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用by
Name自动注入策略。
推荐使用@Resource注解在字段上,这样就不用写setter方法了.并且这个注解是属于J2EE的,减少了与Spring的耦合,这样代码看起就比较优雅 。
另外byName装配应该byType装配更快,因为byName是直接反射,byType需要遍历applicationContext;所以byName方式定位的过程更简单 开销更小搜索
但是装载应该是只发生一次只要是默认的单例模式 这些东西在运行期对于效率应该是没有影响。
Spring的Web MVC框架是一个请求驱动的Web框架,该框架的核心是基于分发器(DispatchServlet)设计的,它是一个将请求分发到控制器的Servlet。DispatchServlet将从Web page收集到的不同请求分发到不同的控制器,控制器Controller收到request和reponse参数,干脆利落的返回ModelAndView。而其他框架的控制器一般只返回View name。
控制器,Spring中的控制器概念相当于Struts框架中的action。Spring 的缺省处理器是一个简单的控制器(Conroller)接口,这个接口仅仅定义了ModelAndView handleRequest(request,resporme)方法。你可以自己实现这个
接口生成应用的控制器,但使用Spring提供的一系列控制器实现会更好一些,比如AbstractContoller,AbstractComnmndContoller等应用控制器一般都从它们继承。
1一个简单的实例:
<html>
<body>
<form method="POST" action="/mySpring/login.do">
<p align="center">登录</p>
<br>
用户名:
<input type="text" name="username" >
<br>
密 码 :
<input type="password" name="password" >
<br>
<p>
<input type="submit" value="提交" name="B1">
<input type="reset" value="重置" name="B2">
</p>
</form>
</body>
</html>
上面的的是请求页面,下面我们在web.xml中配置DispatchServlet来处理*.do的请求。在web.xml增加下面的配置:
如果找不到org.springframework.web.servlet.DispatcherServlet,则需要spring-webmvc.jar包。如果报jstl的异常,则导入jstl.jar包。
<!-- 配置Spring MVC -->
<servlet>
<servlet-name>Dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-name>/WEB-INF/Config.xml</param-name>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Dispatcher</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
Servlet定义
这里我们定义了请求分发Servlet,即:
org.springframework.web.servlet.DispatcherServlet
DispatcherServlet 是Spring MVC 中负责请求调度的核心引擎,所有的请求将由此Servlet 根据配置分发至各个逻辑处理单元。其内部同时也维护了一个ApplicationContext实例。
我们在<init-param>节点中配置了名为“contextConfigLocation”的Servlet参数,此参数指定了Spring配置文件的位置“/WEB-INF/Config.xml”。如果忽略此设定,则默认为“/WEB-INF/<servlet name>-servlet.xml”,其中<servlet name>以Servlet 名替换(在当前环境下,默认值也就是/WEB-INF/Dispatcher-servlet.xml)。
我们将所有以.do结尾的请求交给Spring MVC进行处理。
Dispatcher根据什么来分发请求,我们需要在配置文件加以设定,这也就是上面的Config.xml。此文件包含了所有的"请求/处理单元"关系映射设定,以及返回时表现层的一些属性设置。下面是Config.xml文件的内容:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<!--Definition of View Resolver -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass">
<value>
org.springframework.web.servlet.view.JstlView
</value>
</property>
<!--
<property name="prefix">
<value>
/WEB-INF/view/
</value>
</property>
-->
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<!--Request Mapping -->
<bean id="urlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/login.do">LoginAction</prop>
</props>
</property>
</bean>
<!---Action Definition-->
<bean id="LoginAction"
class="springmvc.action.LoginAction">
<property name="commandClass">
<value>springmvc.action.LoginInfo</value>
</property>
<property name="fail_view">
<value>loginfail</value>
</property>
<property name="success_view">
<value>main</value>
</property>
</bean>
</beans>
viewResolver设定
在<bean id="viewResolver" ...>...</bean>中,Resolver将把输出结果与输出界面相融合,为表现层提供呈现资源。
viewResolver的viewClass属性,这里使用JSP页面作为输出,因此设定为:
org.springframework.web.servlet.view.JstlView
其余可选的viewClass还有:
org.springframework.web.servlet.view.freemarker.FreeMarker,View(用于基于FreeMarker模板的表现层实现)
org.springframework.web.servlet.view.velocity.VelocityView,(用于基于velocity模板的表现层实现)
viewResolver的prefix属性和suffix属性,制定了表现层资源的前缀和后缀,运行时,Spring 将为指定的表现层资源自动追加
前缀和后缀,以形成一个完整的资源路径。一般我们不加前缀,默认是当前项目的webRoot下的路径。
"请求/处理单元"关系映射
这里我们将“/login.do”请求映射到处理单元LoginAction。<props>节点下可以有多个映射关系存在,目前我们只定义了一个。login.do可以加上"/"也可以不加"/",都是表示当前项目根路径下。如我们的项目名为mySpring则,请求路径为/mySpring/login.do
LoginAction处理单元的请求数据对象
commandClass 属性源于LoginAction 的基类BaseCommandController,
BaseCommandController,包含了请求数据封装和验证方法。
(BaseCommandController.bindAndValidate),它将根据传入的HttpServletRequest构造请求数据对象。
这里的commandClass为springmvc.action.LoginInfo,这是一个非常简单的java Bean,它封装了登录请求所需的数据内容。
package springmvc.action;
public class LoginInfo{
public String username;
public String password;
public String getUsername()
{
return username;
}
public void setUsername(String username)
{
this.username = username;
}
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
}
Spring会根据LoginAction的commandClass定义自动加载对应的LoginInfo实例,然后对Http请求中的参数进行遍历,并查找LoginInfo 对象中是否存在与之同名的属性,如果找到,则将此参数值复制到LoginInfo对象的同名属性中。
请求数据转换完成之后,我们得到了一个封装了所有请求参数的Java 对象,并将此对象作为输入参数传递给LoginAction。
LoginAction处理单元的返回视图定义
对于这里的LoginAction 而言,有两种返回结果,即登录失败时返回错误界面,登录成功时进入系统主界面。
对应我们配置了fail_view、success_view两个自定义参数。
参数值将由Resolver进行处理,为其加上前缀后缀,如对于fail_view而言,实际的视图路径为/WEB-INF/view/loginfail.jsp。
之后,Resolver 会将LoginAction的返回数据与视图相融合,返回最终的显示界面。
业务逻辑处理单元:LoginAction.java
package springmvc.action;
import java.net.BindException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;
public class LoginAction extends SimpleFormController
{
private String fail_view;
private String success_view;
public String getFail_view()
{
return fail_view;
}
public void setFail_view(String failView)
{
fail_view = failView;
}
public String getSuccess_view()
{
return success_view;
}
public void setSuccess_view(String successView)
{
success_view = successView;
}
protected ModelAndView onSubmit(Object o, org.springframework.validation.BindException errors)
throws Exception
{
LoginInfo loginInfo = (LoginInfo) o;
if (login(loginInfo) == 0) {
return new ModelAndView(this.getSuccessView(),"loginInfo", loginInfo);
} else {
return new ModelAndView(this.getFail_view());
}
}
private int login(LoginInfo loginInfo) {
if ("Erica".equalsIgnoreCase(loginInfo.getUsername())
&& "mypass".equals(loginInfo.getPassword())) {
return 0;
}
return 1;
}
}
成功后的视图main.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<html>
<head>
</head>
<body>
<p>Login Success!!!</p>
<p>Current User:
${loginInfo.username}
</p>
</body>
</html>
onSubmit方法
我们在子类中覆盖了父类的onSubmit方法;而onSubmit方法用于处理业务请求。负责数据封装和请求分发的Dispatcher,将对传入的HttpServletRequest进行封装,形成请求数据对象,之后根据配置文件,调用对应业务逻辑类的入口方法(这里就是LoginAction的onSubmit()方法),并将请求数据对象及其他相关资源引用传入。
onSubmit方法包含了两个参数:Object o和BindException errors。前面曾经多次提到请求数据对象,这个名为o的Object型参数,正是传入的请求数据对象的引用。
BindException errors参数则提供了数据绑定错误的跟踪机制。它作为错误描述工具用于向上层反馈错误信息。
在Spring MVC中,BindException将被向上层表现层反馈,以便在表现层统一处理异常情况(如显示对应的错误提示),这一机制稍后在“输入参数合法性校验”部分再具体探讨。
onSubmit还有另外一个版本:
protected ModelAndView onSubmit(
HttpServletRequest request,
HttpServletResponse response,
Object cmd,
BindException errors
)
可以看到,类似Servlet的doGet/doPost方法,此版本的onSubmit方法中包含了Servlet规范中的HttpServletRequest、HttpServletResponse以提供与Web服务器的交互功能(如Session的访问)。此参数类型的onSubmit方法的调用优先级较高。也就是说,如果我们在子类中同时覆盖了这两个不同参数的onSubmit方法,那么只有此版本的方法被执行,另一个将被忽略。
在onSubmit中LoginInfo loginInfo = (LoginInfo) o;将输入的请求数据对象强制转型为预定义的请求对象类型。
返回处理结果
ModelAndView类包含了逻辑单元返回的结果数据集和表现层信息。ModelAndView本身起到关系保存的作用。它将被传递给Dispatcher,由Dispatcher 根据其中保存的结果数据集和表现层设定合成最后的界面。
这里我们用到了两种签名版本的ModelAndView构造方法:
public ModelAndView(String viewname)
返回界面无需通过结果数据集进行填充。
public ModelAndView(String viewname, Map model)
返回界面由指定的结果数据集加以填充。可以看到,结果数据集采用了Map接口实现的数据类型。其中包含了返回结果中的各个数据单元。
上面这两个版本的构造子中,通过viewname指定了表示层资源。
new ModelAndView(this.getSuccessView(),"loginInfo", loginInfo);上例中的ModelAndView的对象,将loginInfo对象一起传递到SuccessView的视图,我们在视图中通过${loginInfo.username}来得到loginInfo对象的内容。
另外,我们也可以通过传递View对象指定表示层资源。
public ModelAndView(View view)
public ModelAndView(View view, Map model)
我们可以结合RedirectView完成转向功能,如:
return new ModelAndView(new RedirectView("/redirected.jsp"));
当然,我们也可以在带有HttpServletRequest参数的onSubmit方法实现中,通过HttpServletRequest/HttpServletResponse完成forward/redirect功能,这两种途径可以达到同样的效果。
2 AbstractController 和 WebContentGenerator控制器
所有的Spring控制器都继承了 AbstractController ,AbstractController提供了诸如缓存支持和mimetype设置这样的功能。
当从AbstractController继承时,只需要实现handleRequestInternal(HttpServletRequest, HttpServletResponse)抽象方法,该方法将用来实现自定义的逻辑,并返回一个ModelAndView对象。
MultiActionController控制器
Spring提供了MultiActionController来将多个请求处理方法合并在一个控制器里,这样可以把请求功能组合在一起。MultiActionController位于org.springframework.web.mvc.multiaction包中,它可以定义页面请求到控制器方法名的映射,然后在处理相应请求时调用该方法。
MultiActionController有两种使用方式:
一是创建MultiActionController的子类,并指定将被MethodNameResolver解析的方法(这种情况下不需要这个delegate参数);我们通常会使用ParameterMethodNameResolver或PropertiesMethodNameResolver,在一個网址上結合請求参数,以参数來決定要执行哪一個Action,以ParameterMethodNameResolver为例。
<bean id="paraMethodResolver"
class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver">
<property name="paramName"><value>method</value></property>
<property name="defaultMethodName"><value>list</value></property>
</bean>
<bean id="bookAction" class="onlyfun.caterpillar.GuestBookAction">
<property name="methodNameResolver">
<ref bean="paraMethodResolver"/>
</property>
<property name="testPage">
<value>test</value>
</property>
</bean>
在paraMethodResolver中,我们使用paramName定义在http请求中使用method参数来指定要呼叫的方法,如果请求中没有指定method参数,则会使用defaultMethodName所指定的方法,这边指定的是list()方法。GuestBookAction是继承MultiActionController类,其中定义了我们在method参数指定所要呼叫的方法。如:
package onlyfun.caterpillar;
import javax.servlet.http.*;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
public class GuestBookAction extends MultiActionController {
privateString testPage;
public ModelAndView list(HttpServletRequest req, HttpServletResponse res) {
returnnew ModelAndView(this.getTestPage(),"executed", "list");
}
public ModelAndView add(HttpServletRequest req, HttpServletResponse res) {
returnnew ModelAndView(this.getTestPage(),"executed", "add");
}
public ModelAndView delete(HttpServletRequest req, HttpServletResponse res) {
returnnew ModelAndView(this.getTestPage(),"executed", "delete");
}
publicString getTestPage() {
return testPage;
}
public void setTestPage(String testPage) {
this.testPage = testPage;
}
}
注意我们的方法必须包括HttpServletRequest与HttpServletResponse作为参数,你可以使用带有第三个参数HttpSession的版本。所以当我们请求http://localhost:8080/springapp/book.do?method=add,将会执行method参数的值add方法。
二你可以将所对应的方法专门组织在一个委托(delegate)类中,而不是写在Contoller类别中,当请求来到时,将委托给这个类来执行指定的方法,你只要定义MultiActionContoller的delegate属性既可。委托类如下:
package onlyfun.caterpillar;
import javax.servlet.http.*;
import org.springframework.web.servlet.ModelAndView;
public class BookActionDelegate {
privateString testPage;
public ModelAndView list(HttpServletRequest req, HttpServletResponse res) {
returnnew ModelAndView(this.getTestPage(),"executed", "list");
}
public ModelAndView add(HttpServletRequest req, HttpServletResponse res) {
returnnew ModelAndView(this.getTestPage(),"executed", "add");
}
public ModelAndView delete(HttpServletRequest req, HttpServletResponse res) {
returnnew ModelAndView(this.getTestPage(),"executed", "delete");
}
publicString getTestPage() {
return testPage;
}
public void setTestPage(String testPage) {
this.testPage = testPage;
}
}
委托类BookActionDelegate.java和GuestBookAction.java的方法一样,只是它不需要继承MultiActionController。
然后我们在配置文件中作一些修改,直接使用MultiActionController:
<bean id="paraMethodResolver"
class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver">
<property name="paramName"><value>method</value></property>
<property name="defaultMethodName"><value>list</value></property>
</bean>
<bean id="bookActionDelegate" class="onlyfun.caterpillar.BookActionDelegate">
<property name="testPage">
<value>test</value>
</property>
</bean>
<bean id="bookAction" class="org.springframework.web.servlet.mvc.multiaction.MultiActionController">
<property name="methodNameResolver">
<ref bean="paraMethodResolver"/>
</property>
<property name="delegate">
<ref bean="bookActionDelegate"/>
</property>
</bean>
delegate属性指定了委托类bookActionDelegate。
3ModelAndView
通常,Controller在将Web请求处理完成后,会返回一个ModelAndView实例。该ModelAndView实例将包含两部分内容,一部分为视图相关内容,可以是逻辑视图名称,也可以是具体的View实例;另一部分则是模型数据,视图渲染过程中将会把这些模型数据合并入最终的视图输出。
为了方便实例化ModelAndView,该类定义了两组参数各异的构造方法,一组使用逻辑视图名称(logic named view)标志视图,一组直接使用View实例标志视图,如下所示:
public ModelAndView(String viewName)
public ModelAndView(String viewName,Map model)
public ModelAndView(String viewName,String modelName,Object modelObject)
public ModelAndView(View view)
public ModelAndView(View view,Map model)
public ModelAndView(View view,String modelName,Object modelObject)
每组的第一个构造方法只接受视图信息,所以构造完成后,我们通过addAllObject(..)或者addObject(..)实例方法,向构造完成的ModelAndView实例添加模型数据;每组第二个构造方法则可以同时指定视图信息和模型数据信息,如果要添加到模型的只有一个数据对象,那么可以使用每组的第三个构造方法,该构造方法属于第二个构造方法的简化版。
虽然通过ModelAndView可以保存视图的逻辑名称或者具体的View实现类,但是我们更倾向于使用逻辑视图名来标志视图。这样可以给我们的视图选择带来很大的灵活性。
4可用的ViewResolver实现类
Spring MVC提供的ViewResolver划分为两类,一类称为"面向单一视图类型的ViewResolver,另一个类称为面向多视图类型的ViewResolver。
面向单一视图类型的ViewResolver有如下几个:
InternalResourceViewResolver。它是我们使用最多的ViewResolver实现类型,是用来处理JSP模板类型的视图映射。它作为默认的ViewResolver被使用。
FreeMarkerViewResolver/VelocityViewResolver。FreeMarkerViewResolver和Velo- cityViewResolver分别负责对应FreeMarkerView和VelocityView类型视图的查找工作,它们将根据逻辑视图名到指定的位置获取对应的模板文件,并构造FreeMarkerView和VelocityView的实例返回给DispatcherServlet使用。
JasperReportsViewResolver。JasperReportsViewResolver只关心根据逻辑视图名到指定位置查找JasperReport类型模板文件,并返回AbstractJasperReportsView的具体子类型View实例
XsltViewResolver。只负责根据逻辑视图名查找并返回XsltView类型的View实例。
启用以上这些ViewResolver,与使用InternalResourceViewResolver一样简单。最基本的方法是,使用prefix属性指定模板所在路径,使用suffix属性指定模板文件的后缀名。这样,在获取逻辑视图名之后,相应的ViewResolver内部就能够根据[prefix]+viewName+[suffix]这样的URL找到对应的模板文件,并构造对应的View实例而返回了。VelocityViewResolver的配置代码示例:
<bean id="viewResolver" class="org.springframework.Web.servlet.view.velocity.VelocityViewResolver">
<property name="prefix" value="../velocity/"/>
<property name="suffix" value=".vm"/>
</bean>
面向多视图类型的ViewResolver
使用面向多视图类型的ViewResolver,我们需要通过某种配置方式明确指定逻辑视图名与具体视图之间的映射关系,面向多视图类型的ViewResolver可以顾及多种视图类型的映射管理。面向多视图类型的ViewResolver的主要实现类有三个:
ResourceBundleViewResolver
ResourceBundleViewResolver构建在ResourceBundle上,继承了ResourceBundle国际化支持的能力,也是所有的ViewResolver实现类中唯一提供视图国际化支持的ViewResolver。ResourceBundleViewResolver管理的视图的逻辑名称与具体视图的映射关系保存在properties文件中。
使用ResourceBundleViewResolver之前,我们得先将其添加到spring配置文件中,如下所示:
<bean id="resourceBundleViewResolver" class="org.springframework.Web.servlet.view.ResourceBundleViewResolver">
<property name="basenames">
<list>
<value>default_views</value>
<value>protocal_views</value>
</list>
</property>
</bean>
如果我们没有指定properties配置文件从何处加载的话,ResourceBundleViewResolver默认将从classpath(WEB-INF/classes目录下)的根路径加载以views为basename的properties文件,如:views.properties、views_zh_CN.properties等。如果我们想改变这种默认加载行为,可以通过setBasename(string)或setBasenames(String[])方法来进行变更。如上面通过<list>...</list>给basenames[]属性注入值default_views,default_views则,ResourceBundleViewResolver将会加载default_views.properties和protocal_views.properties。也可以对basename属性进行注入<property name="basename" value="views"/>,将会加载views.properties。
WEB-INF/classes目录下default_views.properties内容如下
welcome.class=org.springframework.web.servlet.view.JstlView
welcome.url=/WEB-INF/jsp/welcome.jsp
productList.class=org.springframework.web.servlet.view.JstlView
productList.url=/WEB-INF/jsp/productlist.jsp
welcome与productList是视图名称,它的class属性指出该视图的类型(JstlView为jsp类型的视图);url指出了改视图名称对应的页面路径。
XmlViewResolver
XmlViewResolver与ResourceBundleViewResolver之间最主要的区别就是,它们所采用的配置文件格式不同。ResourceBundleViewResolver按照Spring IoC容器所接受的properties配置格式配置逻辑视图名与具体视图之间的映射关系,而XmlViewResolver则是按照Spring IoC容器接受的XML配置文件格式来加载映射信息。
使用XmlViewResolver,也是同样要先到Spring配置文件中添加如下配置:
<bean id="xmlViewResolver" class="org.springframework.Web.servlet.view.XmlViewResolver">
<property name="location" value="classpath:views.xml"/>
</bean>
XmlViewResolver默认会加载/WEB-INF/views.xml作为配置文件。不过我们配置它的location属性来改变要加载的xml配置文件的路径。上例中将从Classpath的根路径加载名为views.xml的配置文件。views.xml文件的内容如下:
<bean name="hello" class="org.springframework.Web.servlet.view.velocity.VelocityView" p:url="cn/spring21/simplefx/resources/velocity/hello.vm">
</bean>
BeanNameViewResolver
BeanNameViewResolver可以认为是XmlViewResolver的原型版或者简化版。它不会将View实例的配置写在单独的xml文件中而是一起写在Spring的配置文件中。
http://www.my11120.cn/entry/spring3_mvc_20111021.html
***********************************
<mvc:annotation-driven/>配置
相当于注册了DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter两个bean,配置一些messageconverter。即解决了@Controller注解的使用前提配置
<!-- 处理在类级别上的@RequestMapping注解 -->
<bean
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<list>
<!-- 多个拦截器,顺序执行 -->
<ref bean="SpringMVCInterceptor" />
<ref bean="OpenSessionInViewInterceptor"/>
</list>
</property>
</bean>
<!-- 处理方法级别上的@RequestMapping注解 -->
<bean id="annotationMethodHandlerAdapter"
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<bean
class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=utf-8</value>
<value>text/plain;charset=utf-8</value>
</list>
</property>
</bean>
<bean
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverterv2">
<property name="objectMapper">
<bean class="net.pm.misc.Hibernate4AwareObjectMapper" />
</property>
</bean>
</list>
</property>
</bean>
配置了<mvc:annotation-driven/>这个配置声明,就不用再注册了DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter。
否则会实例化两个DefaultAnnotationHandlerMapping,并且不使用你配置的那个 DefaultAnnotationHandlerMapping.
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter与<mvc:annotation-driven />
关系与上同理.
*********************************
<context:annotation-config />配置
<context:annotation-config/>是对包进行扫描,实现注释驱动Bean定义,同时将bean自动注入容器中使用。即解决了@Controller标识的类的bean的注入(@Autowired,@Resource)和使用。
默认会初始化AnnotationMethodHanlderAdapter,但我们返回xml内容需要对这个HandlerAdapter进行一定的修改,所以配置文件如下:
<context:component-scan base-package="com.controls" />
<context:annotation-config />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="stringHttpMessageConverter" />
<ref bean="jsonHttpMessageConverter" />
<ref bean="marshallingHttpMessageConverter" />
</list>
</property>
</bean>
<bean id="stringHttpMessageConverter" class="org.springframework.http.converter.StringHttpMessageConverter" />
<bean id="jsonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
<bean id="marshallingHttpMessageConverter" class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<constructor-arg ref="jaxbMarshaller" />
<property name="supportedMediaTypes" value="application/xml"></property>
</bean>
<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.model.User</value>
</list>
</property>
</bean>
注:要使用Jaxb2Marshaller我们在对应的实体,比如User类上需要标明
<context:annotation-config/>这样一条配置,他的作用是式地向 Spring 容器注册
AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、
PersistenceAnnotationBeanPostProcessor 以及 RequiredAnnotationBeanPostProcessor 这 4 个BeanPostProcessor。
注册这4个 BeanPostProcessor的作用,就是为了你的系统能够识别相应的注解。
例如:
如果你想使用@Autowired注解,那么就必须事先在 Spring 容器中声明 AutowiredAnnotationBeanPostProcessor Bean。传统声明方式如下
<bean class="org.springframework.beans.factory.annotation. AutowiredAnnotationBeanPostProcessor "/>
如果想使用@ Resource 、@ PostConstruct、@ PreDestroy等注解就必须声明CommonAnnotationBeanPostProcessor
如果想使用@PersistenceContext注解,就必须声明PersistenceAnnotationBeanPostProcessor的Bean。
如果想使用 @Required的注解,就必须声明RequiredAnnotationBeanPostProcessor的Bean。同样,传统的声明方式如下:
<bean class="org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>
一般来说,这些注解我们还是比较常用,尤其是Antowired的注解,在自动注入的时候更是经常使用,所以如果总是需要按照传统的方式一条一条配置显得有些繁琐和没有必要,于是spring给我们提供<context:annotation-config/>的简化配置方式,自动帮你完成声明。
不过,我们使用注解一般都会配置扫描包路径选项
<context:component-scan base-package=”XX.XX”/>s
该配置项其实也包含了自动注入上述processor的功能,因此当使用 <context:component-scan/> 后,就可以将 <context:annotation-config/> 移除了。
******************************************
@Autowired与 @Resource区别:
@Autowired
@Autowired是Spring 提供的,需导入
Package:org.springframework.beans.factory.annotation.Autowired;
只按照byType 注入。
@Resource
@Resource默认按 byName 自动注入,是J2EE提供的, 需导入Package:
javax.annotation.Resource;
@Resource有两个中重要的属性:name和type ,而Spring将@Resource注解的name属性解析为bean的
名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用
type属性时则使用 byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用by
Name自动注入策略。
推荐使用@Resource注解在字段上,这样就不用写setter方法了.并且这个注解是属于J2EE的,减少了与Spring的耦合,这样代码看起就比较优雅 。
另外byName装配应该byType装配更快,因为byName是直接反射,byType需要遍历applicationContext;所以byName方式定位的过程更简单 开销更小搜索
但是装载应该是只发生一次只要是默认的单例模式 这些东西在运行期对于效率应该是没有影响。