Spring MVC浅尝

本文讲解的主要是Spring MVC的运行原理,每个人都有自己的学习的习惯,我就从自行车的角度来讲解,那么从学自行车的角度是怎么样的呢
  1. 什么是自行车
  2. 尝试骑骑看
  3. 了解各部件的原理,如刹车等


一、运行原理图(什么是自行车):

原理图网上一大堆,我呢盗用了一个较为简单和清晰的:

这一部分,主要是看看个部分是怎么样的,所以,就像一辆自行车,看看有哪些玩意,有个把手,有两个轮子,回归正题:Spring MVC有什么呢?我先告诉你简单的,就像告诉刚学自行车的你:这个手柄是刹车,可以刹住车。
  1. 要有个客户:操作请求,对就这么一点作用
  2. 要有个DispatcherServlet:这是什么玩意,先不用管,不过要记得它告诉我们,这很重要,它告诉我们的,这是一个Dispather(收发)的Servlet。
  3. <sevlet-name>-servlet.xml:是个配置文件,什么用呢,后面接着说,先不要较真
  4. HandleMapping:handle百度翻译了下:处理或负责,我们就先当作是处理映射器好了
  5. HandleAdapter:就先按照上面的叫法,处理适配器。
  6. Handle:处理器,什么作用后面就知道,还是那句话,先不要较真
  7. ViewResolver:试图解析器
  8. View:视图

二、简单的搭建一遍(试着骑一骑):

我用的是myeclipse,为了方便,我就偷个懒吧所有的spring包都导进去了,加了些需要依赖的的包。

(1)先把重要的包导入:


(2)看一下整体的项目环境


(3)这才是正题,第一步(解决DispatcherServlet):

               DispatcherServlet是框架自带的,我们要做的就是把它“放入”我们的系统,它是一个“Servlet”,它自己说的,而且它处于核心,那么我们可想而知,把它放在哪里了:web.xml,下面源码:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns="http://java.sun.com/xml/ns/javaee" 
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>SpringMVC</display-name>
  
  <servlet>
  	<!-- 注意这个servlet-name,后面有用 -->
  	<servlet-name>dispatch</servlet-name>
  	
  	<!-- 正主DispatcherServlet -->
  	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  	
  	<!-- 这个配置很微妙,如果不这么配置,默认会加载:dispatch-servlet.xml,dispatch就是这个servlet名 -->
  	<init-param>
  		<param-name>contextConfigLocation</param-name>
  		<param-value>/WEB-INF/spring-servlet.xml</param-value>
  	</init-param>
  	
  	
  	<load-on-startup>1</load-on-startup>  
  </servlet>
  
  <servlet-mapping>
  	<servlet-name>dispatch</servlet-name>
  	<!-- 用习惯了struts,我就这么写了,当然也可以直接是/  --> 
     <url-pattern>*.do</url-pattern>  
  </servlet-mapping>
  
 <!--  <listener>
   <listener-class>
     org.springframework.web.context.ContextLoaderListener
   </listener-class>
</listener> -->
  
  <welcome-file-list>  
    <welcome-file>index.jsp</welcome-file>  
  </welcome-file-list>  
  
</web-app>


(4)第二步(解决<servlet-name>-servlet.xml):

我们回顾下运行原理图:DispatcherServlet需要一个<servlet-name>-servlet.xml文件,但是我在web.xml中指定了一个spring-servlet.xml,那么我们就创建这个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:mvc="http://www.springframework.org/schema/mvc"  
    xmlns:context="http://www.springframework.org/schema/context"  
    xsi:schemaLocation="  
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd  
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd  
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">  
	<!-- 自动扫描 -->
    <context:component-scan base-package="com"></context:component-scan>
    
   <!--  解决HandleMapping -->
    <mvc:annotation-driven />  
    
        <!-- 解决ViewResolver -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
    	<property name="prefix" value="/WEB-INF/jsp/"/>  
    	<property name="suffix" value=".jsp"/>  
    	<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
    </bean>  
    
    <!-- 文件上传 -->
    <bean id="multipartResolver"  class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    	<property name="maxUploadSize" value="102400000"></property>
	</bean>

</beans>

从上面的步骤,我们解决了很多东西:HandleMapping,ViewResolver,再回头看看,对于HandleMaping,还没有完整,我们接下去接着写。


(5)第三步(解决HandleMapping):

有没有注意到,我说的是解决,不是创建,当然也是一种创建,那么怎么创建呢,有两种方式,一种是用XML,一种是用注解,XML后面再讲,在这里我用的是注解的方式(annotation):
目录:src/com/HomeController.java
 package com;  
      
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
      
    @Controller  
    public class HomeController {  
          
        @RequestMapping("home")  
        public String home(){  
            return "home";  
        }
       @RequestMapping("hello")
       public ModelAndView hello(User user){
          System.out.println("传递方式(使用ModelAndView对象):hello "+user.getName()+" my age is "+ user.getAge());
          ModelAndView mv = new ModelAndView();
          mv.setViewName("hello");
          mv.addObject("user", user);
          return mv;
      }
       
    } 


这里用到了两个注解:@Controller:就是告诉Spring这是MVC中的C,@RequestMapping("home")这就是设置请求路径,如这个home,那么在请求的URL中就如下:http://localhost:8080/SpringMVC/home.do

(6)第四步(解决Bean)

这是最简单的一步,直接上代码:
目录:src/bean/User.java
package bean;

public class User {
	private String name;
	private int age;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
}
(7)第五步(解决View):
这也是简单的,我们先创建3个:WEB-INF/helloInput.jsp,WEB-INF/JSP/hello.jsp,WEB-INF/JSP/home.jsp,先看看最简单的home吧:
WEB-INF/JSP/home.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<%
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 'home.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>
     hello ,this is a spring mvc demo!!  
  </body>
</html>
现在用: http://localhost:8080/SpringMVC/home.do访问,就会出现下面的界面


WEB-INF/JSP/hello.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<%
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 'hello.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>
   hello you have login<br/>
   user.name=${user.name}<br/>
   user.age=${user.age}<br/>
  </body>
</html>

WEB-INF/ helloInput.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
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 'helloInput.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>
  <h2>获取值</h2>
    <form action="hello.do">
    	姓名:<input name="name"/><br/>
    	年龄:<input name="age"><br/>
    	<input type="submit" value="提交">
    </form>
  </body>
</html>
先用这个链接访问:http://localhost:8080/SpringMVC/helloInput.jsp,出现下面界面,然后提交





好了,关于Spring MVC的简单使用就到这,下面会稍微稍微深入的讲解下原理,建议上面没有搭建过的读者,先搭建下,就当玩玩也好。

三、从代码中看原理(看看各个自行车是怎么跑起来的)

(1)Spring MVC中最主要的几个类:

1、DispatcherServlet  -- 前置控制器

前端控制器是整个MVC框架中最为核心的一块,它主要用来拦截符合要求的外部请求,并把请求分发到不同的控制器去处理,根据控制器处理后的结果,生成相应的响应发送到客户端。前端控制器既可以使用Filter实现(Struts2采用这种方式),也可以使用Servlet来实现(spring MVC框架)。(注:摘于网络)

学过servlet的人应该知道servlet主要经过了三个方法,完成了它的整个生命周期:init(),service(),destroy()

Servlet和这个DispatcherServlet有什么关系呢?首先重命名上讲,DispatcherServlet也是一个Servlet,这是它自己说的,我不信,我查了下源码,有这么一个玩意,


FrameworkServlet是什么,也自己给自己一个称呼Servlet,也是个Servlet?不过是通过继承它的想来也应该是个抽象类,我看了下源码如下:


它继承了一个类HttpServletBean,实现了一个接口,这个接口我们先不用管,这个HttpServletBean是什么玩意,往里面看:


这个HttpServlet总熟悉了吧,

由此看来还真的是一个servlet,那么DispatcherServlet也相当于间接的继承了servlet,往里面翻,FrameworkServlet还有一些方法,这样会显的比较清晰好理解,我截下了其中的一些方法:


注意我红色圈起来的这几个,有没有想到什么?

有没有发现,这部分的方法很熟悉,它们就是完成了servlet的整个生命周期。

在这里我值分析下这个类的流程不对具体的代码做分析,能力有限,精力有限。

精彩的后面再讲,这里到此为止,我们主要掌握这个流程便好。

推荐个链接文章:http://www.cnblogs.com/davidwang456/p/4090058.html,大家可以仔细看看。


我们接着往下看:

DispatcherServlet是个前置控制器,但是也是一个分发器(Dispatcher),这是它自己告诉我的,我们先具体看下这个分发服务器(前置控制器),它的初始化,它的销毁就不讲了,看看它是怎么处理的,以及怎么分发的,源代码如下:


这个doService就相当于servlet中的service方法,我就不深入了,看下我圈起来的部分,在最后调用了一个doDispatch方法,这个方法才是核心,在看这个核心之前我们先看下这个DispatcherServlet还有哪些东西,

            


其中定义了两个重要的List数组:

private List<HandlerMapping>handlerMappings;//关于映射的集合

private List<HandlerAdapter>handlerAdapters;//关于适配器的集合

再看下源码



前面这段代码做了什么?看下这两个就明白了:

processedRequest= checkMultipart(request);
multipartRequestParsed= (processedRequest != request);
//Determine handler for the current request.
mappedHandler =getHandler(processedRequest);

将请求分发给了Handler,那么它是怎么找到这个handle的呢,这里有个getHandler方法,看下源码:


这里面有个很重要的一句:this.handleMappings,这个就是之前定义的List对象。

根据这个映射返回一个HandlerExecutionChain对象,接着做什么呢?获取HandlerAdapter对象:

HandlerAdapter ha =getHandlerAdapter(mappedHandler.getHandler());

这里有个很有意思的地方mappedHandler.getHandler(),这句说明什么,说明这个HandlerExecutionChain对象带有一个handle对象。并且呢,将这个handle传递给了HandlerAdapter。

我们看下这个方法,还算有意思:


这里面有一句重要的语句:this.handleAdapters,是不是很熟悉,这个就是之前定义的List对象。

我们接着看源码,看看这个HandlerAdapter又做了些什么:



这里面有一句:

mv =ha.handle(processedRequest, response, mappedHandler.getHandler());

mv就是这个方法之前定义的ModelAndView对象,具体怎么执行我就不深入了,并且返回ModelAndView对象。接下去:

applyDefaultViewName(request,mv);

它执行了这个方法,去看下源码:


很简单,但是同时调用了另一个方法,去看下源码:


也很简单,看下这个viewNameTranslator是什么


获取默认视图名,接着要做的一件事

mappedHandler.applyPostHandle(processedRequest,response, mv);

申请注册posthandle拦截方法。

哈哈,讲完了,有点杂,好在讲完了,我们在看一幅图,也是网站找的,这副图有助于更好的理解其中的过程:



现在看它是不是清晰点?我们结合我们之前写的代码一起再看看:

再web.xml中,不知道还记不记得,这个配置:

<!-- 这个配置很微妙,如果不这么配置,默认会加载:dispatch-servlet.xml,dispatch就是这个servlet名 -->
  	<init-param>
  		<param-name>contextConfigLocation</param-name>
  		<param-value>/WEB-INF/spring-servlet.xml</param-value>
  	</init-param>

为什么要这个来配置呢,为什么需要这个文件呢:

先看看为什么要用这个来配置,当然不配置也要创建个默认的<servlet-name>-servlet.xml,我们先去翻下源码:


 主要呢是用来寻找它的配置文件,配置文件的作用,联合之前的可以很明确的知道,里面对整个MVC映射以及视图还有一些常规属性的配置,最后将这些封装到之前所设定的各个List属性中。

接下去要配置,spring-servlet.xml这个文件了,要配哪些内容呢:

1、 自动扫描的包名

2、默认的注解映射的支持

3、视图解释类

(2)HandlerMapping

HandlerMapping接口的实现类:

SimpleUrlHandlerMapping  通过配置文件,把一个URL映射到Controller

DefaultAnnotationHandlerMapping 通过注解,把一个URL映射到Controller类上

至于用注解的方式,上面也演示了,我就不在说了,通过配置文件的方式呢,我们也要看看,这样有更好的理解:


应该好理解这个配置吧,好了,到此结束,深入的大家一起再慢慢挖。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值