Spring MVC 实现(原理分析)

来源:互联网 发布:罗技优联mac能用吗 编辑:程序博客网 时间:2024/06/14 01:50

暂且不谈Sping MVC的优缺点,先来上个例子,然后分析SpringMVC如何实现 。谈到框架我们不得不关注的一点---->配置文件 如果想用SpringMVC来代替Struts,配置文件(springmvc-servlet.xml)如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"   
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
    xmlns:p="http://www.springframework.org/schema/p"   
    xmlns:mvc="http://www.springframework.org/schema/mvc"   
    xmlns:context="http://www.springframework.org/schema/context"   
    xmlns:util="http://www.springframework.org/schema/util"   
    xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd   
            http://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.0.xsd   
            http://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd   
            http://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util-3.0.xsd">
    
    <!-- 对web包中的所有类进行扫描,以完成Bean创建和自动依赖注入的功能 -->
    <context:component-scan base-package="com.sxt.web"/>

   
    <mvc:annotation-driven />  <!-- 支持spring3.0新的mvc注解 -->

    <!-- 启动Spring MVC的注解功能,完成请求和注解POJO的映射 -->
    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>

    <!--对模型视图名称的解析,即在模型视图名称添加前后缀 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
        p:suffix=".jsp">
         <!-- 如果使用jstl的话,配置下面的属性 -->
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />   
    </bean>
</beans>
待会解释其中细节,然后是web.xml文件的配置:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/springmvc-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>

</web-app>

再然后呢就是web层也就是Controller层实现代码如下:
@Controller("userController")
@RequestMapping("/user.html") 
@SessionAttributes({"Y"})  //将ModelMap中属性名字为u、a的再放入session中。这样,request和session中都有了。
public class UserController  {

    @Resource
    private UserService userService;
/**
 *
 * @function 添加user
 * @param uname
 * @return 要跳转页面对应的字符串
 * @date 2013-4-24
 * @user Yangcs
 */
    @RequestMapping("/reg")
    public String reg(String uname) {
        System.out.println("HelloController.handleRequest()");
        userService.add(uname);
        return "index";
    }
    /**
     *
     * @function  测试ModelMap类 和HttpRequest 的作用域相当
     * 将传递控制方法返回的数据到结果页面
     * @date 2013-4-24
     * @user Yangcs
     */
   
    @RequestMapping(params="method=reg2")
    public String reg2(String uname,ModelMap map) {
        System.out.println("HelloController.handleRequest()");
        userService.add(uname);
        map.addAttribute("a", "ccc");
        return "index";
    }
    /**
     *
     * @function  测试传入参数名不同时的解决方案
     * @date 2013-4-24
     * @user Yangcs
     */
    @RequestMapping(params="method=reg3")
    public String reg3(@RequestParam("name")String uname,ModelMap map){
        System.out.println("测试传入参数名不同时的解决方案");
        userService.add(uname);
        map.addAttribute("a","bbbbb");
        return "index";
    }
    /**
     *
     * @function  测试将数据放入session 两种方式  1:用HttpRequest.getSession().setAttribute()方式
     * 2.使用此方式SpringMVC方式在类前边加@SessionAttribute(),然后将ModelMap中的值共享给session
     * @date 2013-4-24
     * @user Yangcs
     */
    @RequestMapping(params="method=reg4")
    public String reg4(String uname,ModelMap map){
        System.out.println("reg4:");
        map.addAttribute("Y","Yangcs");
        return "index";    
    }
    /**
     *
     * @function  测试ModelAndView类
     * 作用一 设置转向地址,如下所示(这也是ModelAndView和ModelMap的主要区别)
     * 作用二 用于传递控制方法处理结果数据到结果页面
     * @date 2013-4-24
     * @user Yangcs
     */
    @RequestMapping(params="method=reg5")
    public ModelAndView reg5(String uname){
        ModelAndView mav = new ModelAndView();
        mav.setViewName("index");     //设置要转向页面对应的字符串
        User user = new User();
        user.setUname("yangcs8912");
        mav.addObject(user);  //向ModelAndView中添加实体对象
        mav.addObject("q", user); //手动设定key  页面取值时也通过key取值  (建议使用)
        return mav;
    }
    public UserService getUserService() {
        return userService;
    }

    public void setUserService(UserService userService) {
        this.userService = userService;
    }

   
}
接下来 是视图源码(reg.jsp)Controller类中有N多个reg方法其中每一个都用来测试一个小功能,在下边隐藏标签中可以替换来测试:
<%@ page language="java" import="java.util.*" pageEncoding="GBK"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
   
    <title>My JSP 'reg.jsp' starting page</title>
   
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">   
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->

  </head>
 
  <body>
    <form action="user.html">
        <input type="hidden" name="method" value="reg"/><!--这是使用隐藏标签来作为要提交方法名,当然也可以使用user/reg.html方式访问)
        用户名:<input type="text" name="uname"/>
        <input type="submit" value="注册"/>
    </form>
  </body>
</html>

另外还有service层、dao层、model层(在此都略掉)下边看SpringMVC如何处理:

1.当用户发送一带*.html(这里可以任意更换后缀名,运行出来的项目有点小误导人,不仔细读了解的话)的请求时,tomcat容器(或者其它服务器)先去读取web.xml,每个请求都要被SpringMVC的DispatcherServlet类拦截一下,当拦截到带.html的后缀名时,他知道这是一个Controller类接下来交给HandlerMapping

2.HandlerMapping将会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象和多个HandlerInterceptor拦截器对象),通过这种策略模式,可以匹配N多种映射策略,处理完以后控制权再次交给DispatcherServlet对象

3.DispatcherServlet再将控制权交给HandlerAdapter,HandlerAdapter会把处理器包装成适配器,从而可以处理多种类型的处理器(这里是适配器设计模式的应用)4.HandlerAdapter根据适配的结果调用真正的控制器(也就是我们的UserController)的功能方法,完成功能处理,并返回一个ModelAndView对象,此对象包含两部分(模型对象,和视图对象)

5.返回的ModelAndView交给ViewResolver视图解析器对象,又ViewResolver对象将视图对象解析成具体的view,通过这种策略模式我们可以很容易的更换其它类型的视图,(SpringMVC是很强大的)

6.View来对传进的模型对象进行渲染,注意:此处的Moel对象实际上是一个Map结构的对象,也是它很容易实现其它视图技术

7.当这一系列步骤执行完后,控制权重返DispatcherServet手中,最后由DispatcherServlet来响应客户,从哪里进来,从哪里出去 ,到此一个流程结束

注:DispatcherServlet这个类很关键,从头到尾,他就是一个大管家,不执行具体业务,就负责分发任务,收回权限,最后领取功劳

接下来,看看SpringMVC的注解及配置文件

1.<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"  p:suffix=".jsp"> 这句用来在返回的每个字符串或者ModelAndView对象加上后缀,还可以设置前缀 加p:prefix="WEB-INF/jsp/"

2.@RequestMapping()用在类上用来指定要访问的类,用在方法上用来指定那个方法,也可以类中不配置直接在方法上一块配置, 如在方法上直接加注解.@RequestMapping(“user/reg”)

原创粉丝点击