`

SpringMVC入门

 
阅读更多

背景

SpringMVC在2.5之前是主配置风格的,2.5之后变成了主注解的风格,由于平时项目中用的还是主配置风格,再者我比较懒,对注解比较不了解,所以这里还是配置风格的。

必备知识

1、知道一个javaweb应用的结构

2、知道Spring IOC是怎么回事

正文

MVC框架大多是围绕一个核心的servlet来设计,这个核心的servlet提供了请求转发及很多其他便捷搭建web应用的功能。SpringMVC与此类似,提供了一个DispatcherServlet用来处理请求转发,同时,它天然的与Spring IOC容器集成,因此可以方便的使用Spring提供的任意功能。

DispatcherServlet继承自HttpServlet,需要在web.xml中配置相关信息。下面是一个DispatcherServlet的配置例子,可以发现它就是一个标准的servlet配置
<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的工作流

SpringMVC flow

Front Controller即是DispatcherServlet,request会被它根据相关配置文件转发给相关的Controller进行处理,处理结果存在model中返回DispatcherServlet,然后选择合适的view渲染结果,最终返回给客户端。

SpringMVC提供了AbstractCommandControllerSimpleFormController、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

 

转:http://my.oschina.net/achi/blog/88489

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics