背景
SpringMVC在2.5之前是主配置风格的,2.5之后变成了主注解的风格,由于平时项目中用的还是主配置风格,再者我比较懒,对注解比较不了解,所以这里还是配置风格的。
必备知识
1、知道一个javaweb应用的结构
2、知道Spring IOC是怎么回事
正文
MVC框架大多是围绕一个核心的servlet来设计,这个核心的servlet提供了请求转发及很多其他便捷搭建web应用的功能。SpringMVC与此类似,提供了一个DispatcherServlet用来处理请求转发,同时,它天然的与Spring IOC容器集成,因此可以方便的使用Spring提供的任意功能。
<web-app> <servlet> <servlet-name>example</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>example</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> </web-app>
在上面的例子中,首先需要确保web容器启动时就需要加载名为example的servlet(DispatcherServlet),之后根据url-pattern,所有以.do结尾的请求都会被example处理。这将是SpringMVC的第一步,之后,就需要配置各种Spring的bean来实现功能。
当web容器初始化DispatcherServlet时,SpringMVC框架会在应用的WEB-INF目录下查找名为[servlet-name]-servlet.xml(即example-servlet.xml)的配置文件,然后根据定义创建bean。这里需要注意的是,该配置文件中的bean定义会覆盖掉全局其他任何与之同名的定义。
如果想加载其它位置的配置文件,则需要修改servlet的初始化参数,如下所示
<web-app> <servlet> <servlet-name>example</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:servlet/example-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>example</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> </web-app>
则SpringMVC框架将会去classes目录下的servlet目录里寻找example-servlet.xml配置文件并加载。
另外一点需要注意的是,既然我们选择用SpringMVC来处理请求,那请务必在web容器启动时就加载DispatcherServlet,即设置<load-on-startup>大于0。
接下来我们详细看下DispatcherServlet的工作流
Front Controller即是DispatcherServlet,request会被它根据相关配置文件转发给相关的Controller进行处理,处理结果存在model中返回DispatcherServlet,然后选择合适的view渲染结果,最终返回给客户端。
SpringMVC提供了AbstractCommandController、SimpleFormController、MultiActionController等多个可继承的controller父类,由于MultiActionController支持同一个controller处理多个功能方法,即多个请求可以映射到同一个controller,由其中的方法负责各个请求的处理,所以平时都是用的这个父类,下面是一个简单的小例子
public class DemoController extends MultiActionController { public ModelAndView doFirst(HttpServletRequest request, HttpServletResponse response) throws Exception { Map map = new HashMap(); map.put("message", "hello world"); return new ModelAndView("/first.jsp",map); } public ModelAndView doSecond(HttpServletRequest request, HttpServletResponse response) throws Exception { Map map = new HashMap(); map.put("message", "hello world"); return new ModelAndView("/second.jsp",map); } }
有了class,下一步就需要填写配置文件,好让框架加载。
SpringMVC的配置文件格式和Spring的一致,如上面的foo.bar.controller.DemoController,配置即为
<bean name="/demo.do" class="foo.bar.controller.DemoController"> <property name="methodNameResolver"> <ref bean="paraMethodResovler" /> </property> </bean>
这里有两点需要注意,1是bean声明的是name而不是id,因为name要映射访问的url,其中包含id属性禁止的非法字符"/";2是paraMethodResovler属性,该属性决定了继承自MultiActionController的DemoController可以一个controller处理多个请求。paraMethodResovler配置如下
<bean name="paraMethodResolver" class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver"> <property name="paramName" value="method" /> </bean>
这里有两点需要注意,1是bean声明的是name而不是id,因为name要映射访问的url,其中包含id属性禁止的非法字符"/";2是paraMethodResovler属性,该属性决定了继承自MultiActionController的DemoController可以一个controller处理多个请求。paraMethodResovler配置如下
<bean name="paraMethodResolver" class="org.springframework.web.servlet.mvc.multiaction.ParameterMethodNameResolver"> <property name="paramName" value="method" /> </bean>
paramName属性的值决定了处理多请求的参数名的值,如上例,对应的请求url即为
127.0.0.1:8080/mvc/demo.do?method=doFirst 127.0.0.1:8080/mvc/demo.do?method=doSecond
2、ModelAndView
上面例子中的两个方法,返回的都是ModelAndView类型。这个是SpringMVC提供的一种返回类型,它包含了数据和视图。
数据放到map中,然后ModelAndView会将map中的k-v对放到request的attribute中,方便视图获取。例如controller中我们有map.put("message", "hello world"),则对应跳转到的jsp中我们可以request.getAttribute("message")或更方便的${message}。
视图的话,SpringMVC支持多种视图,如JSP、Jstl、Velocity、FreeMarker等,具体选择交由viewResolver处理。这里我们需要使用JSP,这是SpringMVC默认的视图,配置如下
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternamResourceViewResolver"> <property name="viewClass"> <value>org.springframework.web.servlet.view.InternalResourceView</value> </preperty> <!-- <property name="prefix" value="/WEB-INF/demo/" /> <property name="suffix" value=".jsp" /> --> </bean>
viewClass表示用默认的视图处理。另外(为了方便?)还可以加上注释掉的前缀和后缀,例如之前例子中的doFirst,假设我们的first.jsp位于/WEB-INF/demo/first.jsp,则return的应该是new ModelAndView("first",map)。
一个DispatcherServlet可以对应多个viewResolver,多个viewResovler构成了一个viewResovlerChain,通过指定order属性,可以决定resolver的顺序,order值越大,则在Chain中的位置越靠后。请求被viewResolverChain从第一个resolver开始解析,如果能成功解析,则由该resolver负责渲染视图并返回给浏览器,如果不能,则返回null,并交由下一个resolver开始尝试解析。需要注意的是,有些resolver,如InternalResourceViewResolver,并不会检测是否能成功解析view,因而永远不会返回null,对于这些resolver,建议不配置order属性,则框架会默认为Integer.MAX_VALUE,放到Chain的最后。
自定义resolver
现在ajax用的很多,json因为处理方便成为了首选的数据传输格式。因为SpringMVC并没有提供json的viewResolver,这里需要我们自己开发一个,并将该resolver置于resolverChain中InternalResourceViewResolver之前。开发步骤如下
首先定义一个resolver的bean
<bean id="xmlViewResolver" class="org.springframework.web.servlet.view.XmlViewResolver"> <property name="order" value="1" /> <property name="location" value="classpath:servlet/ajax-views.xml" /> </bean>
ajax-views.xml内容如下
<bean name="jsonView" class="foo.bar.view.AjaxJsonView"></bean>foo.bar.view.AjaxJsonView继承自org.springframework.web.servlet.view.AbstractView,并重写了renderMergedOutputModel方法。这样对于controller中返回的ModelAndView对象,如果指定的viewName是"jsonView"的话,将指定由foo.bar.view.AjaxJsonView负责解析和渲染。AjaxJsonView内容如下
public class AjaxJsonView extends AbstractView{ @Override protected void renderMergedOutputModel(Map<String,Object> map, HttpServletRequest request,HttpServletResponse response) throws Exception{ // set ContentType response.setContentType("application/x-www-form-urlencoded;charset=UTF-8"); // set standard HTTP/1.1 no-cache headers response.setHeader("Cache-Control","no-store,max-age=0,no-cache,must-revalidate"); // set IE extended HTTP/1.1 no-cache headers response.addHeader("Cache-Control","post-check=0,pre-check=0"); // set standard HTTP/1.0 no-cache header response.setHeader("Pragma","no-cache"); String jsonObj = (String)map.get("ajax_json"); response.getWriter().write(jsonObj); response.flushBuffer(); } }即将controller返回的数据直接通过response写回去。注意,(String)map.get("ajax_json")中的ajax_json是controller返回的ModelAndView中的map中的key。综上,controller的类似代码如下
public ModelAndView doThird(HttpServletRequest request, HttpServletResponse response) throws Exception{ Map<String, String> map = new HashMap<String,String>(); // do something map.put("ajax_json","{\"username\":\""+username+"\"}"; return new ModelAndView("jsonView", map); }这样在jsp中就可以获取到ajax返回的json串。
总结
对于较浅层次的应用,SpringMVC和其他框架还是很类似的,稍微练习下很快就能掌握。
它主要包括一个核心的控制器DispatcherServlet,业务处理用controller管理,model负责传值,具体的视图渲染由viewResolverChain负责。
预祝大家都能顺利上手,期待您阅读本文后的feedback~
工程地址
https://my-test-attendance.googlecode.com/svn/trunk/mvc
相关推荐
SpringMVC入门文档,可做快速入门了解,有助于理解整体架构,如果工作需要只是简单了解使用,则足够,如果事要深入学习,建议去看视频之类的学习路径
springmvc入门程序 目的:对前端控制器、处理器映射器、处理器适配器、视图解析器学习 非注解的处理器映射器、处理器适配器 注解的处理器映射器、处理器适配器(掌握) springmvc和mybatis整合(掌握) ...
maven + springmvc 入门实例,安装好maven之后导入myeclipse即可运行。maven安装方法请自行百度
springMVC入门级项目
SpringMVC入门jar包(Spring4.3.7版本2017)
springmvc入门练习,常用配置。 访问user-add.jsp,Controller获取数据。
SpringMVC入门demo
Springmvc入门实例
刚接触springMvc时参考的教材,理论和操作兼顾,写的很好,对于springMvc的初学者帮助很大
关于SpringMVC入门级的实例demo
尚硅谷SpringMVC入门到精通,涵盖数据绑定、异常处理以及与Spring的基本整合
SpringMVC入门案例源码,提供Eclipse和MyEclipse的源码以及war文件.............................
SpringMVC学习(一)——SpringMVC入门小程序
springmvc 入门开发 helloworld
springmvc入门简单实现,基础过渡,理解springmvc的实现机制。
springMVC入门