SpringMVC的运行机制和配置文件

SpringMVC的运行流程:用户发出一个url请求在web.xml文件中被前端控制器DispatcherServlet进行拦截匹配,然后根据web.xml文件中的接口访问SpringMVC的核心配置文件springmvc-servlet.xml。处理器映射器将url映射到相对应的处理器上,但是真正执行处理器的是处理器适配器。在处理器适配器执行处理器方法进行参数绑定的时候,会先判断该参数类型是否需要自定义参数绑定器进行绑定,是否需要进行参数校验,是否存在文件类型的上传等,然后才进行参数绑定!执行完处理器方法后一般将逻辑视图交给视图解析器进行解析,前端控制器再将解析后的视图和模型进行渲染,最后返回给用户浏览器界面进行显示。 

                                                 一、SpringMVC的运行原理

  • 第一步:发起请求到前端控制器(DispatcherServlet)
  • 第二步:前端控制器请求HandlerMapping查找 Handler
  • 可以根据xml配置、注解进行查找
  • 第三步:处理器映射器HandlerMapping向前端控制器返回Handler
  • 第四步:前端控制器调用处理器适配器去执行Handler
  • 第五步:处理器适配器去执行Handler
  • 第六步:Handler执行完成给适配器返回ModelAndView
  • 第七步:处理器适配器向前端控制器返回ModelAndView
  • ModelAndView是springmvc框架的一个底层对象,包括 Model和view
  • 第八步:前端控制器请求视图解析器去进行视图解析
  • 根据逻辑视图名解析成真正的视图(jsp)
  • 第九步:视图解析器向前端控制器返回View
  • 第十步:前端控制器进行视图渲染
  • 视图渲染将模型数据(在ModelAndView对象中)填充到request域
  • 第十一步:前端控制器向用户响应结果 


                                                  二、SpringMVC的核心组件

1、前端控制器DispatcherServlet【不需要程序员开发】
 作用:接受用户请求,响应结果,相当于转发器,在struts中也存在类似一个。
 有个DispatcherServlet减少了其他组件之间的耦合度
2、处理器映射器HandlerMapping【不需要程序员开发】
作用:根据请求的url查找Hander
3、处理器适配器HandlerAdapter【不需要程序员开发】
作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler
4、处理器Handler(controller)【需要程序员开发,分两步:一是Handler代码编写,二是在配置文件中进行配置注册

  • 注意:我们在编写Handler(controller)时必须按照HandlerAdapter要求的去做,这样适配器才可以正确执行Handler

5、视图解析器View resolver【不需要程序员开发】
作用:进行视图解析,根据逻辑视图名解析成真正的视图(View)
6、视图View【需要程序员开发jsp
View是一个接口,实现类支持不同的View类型(例如:jsp、freemarker、pdf...)

  • 注意:不需要我们开发的组件在实际应用中就需要去配置,而需要开发的组件就需要我们去手动编程实现,所以首先看需要程序员做的配置事情如下:

项目地址: 

                                                  三、需要程序员做的配置

1.web.xml:配置前端控制器(DispatcherServlet)

<?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">

  	<welcome-file-list>
    	<welcome-file>index.jsp</welcome-file>
  	</welcome-file-list>
  	
  	<!-- 配置springmvc前端控制器 -->
	<servlet>  
    	<servlet-name>springmvc</servlet-name>  
    	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 
    	<!-- 配置springmvc加载的核心配置文件所在路径,如果不配置,默认加载的是
    	/WEB-INF/pages/【servlet-name】-servlet.xml(在这里是springmvc-servlet.xml)  -->
    	<!-- <init-param>  
        	<param-name>contextConfigLocation</param-name>  
        	<param-value>classpath:web/springmvc-servlet.xml</param-value>  
    	</init-param>  --> 
    	<load-on-startup>1</load-on-startup>  
	</servlet>  
          
	<servlet-mapping>  
    	<servlet-name>springmvc</servlet-name>
    	<!-- 
    	第一种:*.mvc,访问以*.mvc结尾由DispatcherServlet进行解析
    	第二种:/,所有访问的地址都由DispatcherServlet进行解析,对于静态文件的解析需要配置DispatcherServlet
    	进行解析,使用此种方式可以实践RESTful风格的url【拦截所有的请求排除jsp!】
    	第三种:/*,这样配置不对,使用这种配置,最终要转发到一个jsp页面时无法找到handler,会报错!
    	 -->
    	<url-pattern>*.mvc</url-pattern>  
	</servlet-mapping>
</web-app>

2.springmvc-servlet.xml:配置处理器映射器(HandlerMapping)、处理器适配器(HandlerAdapter)、视图解析器(View resolver)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"  
       xmlns:mvc="http://www.springframework.org/schema/mvc"  
       xmlns:context="http://www.springframework.org/schema/context"  
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
       xsi:schemaLocation="http://www.springframework.org/schema/beans  
            http://www.springframework.org/schema/beans/spring-beans-3.1.xsd  
            http://www.springframework.org/schema/context   
            http://www.springframework.org/schema/context/spring-context-3.1.xsd  
            http://www.springframework.org/schema/mvc  
            http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd">  

    <!-- 一、配置处理器Handler -->
    <!-- 加载如下所述的两个Handler到Spring容器 -->
    <!-- 第一种Handler:实现 Controller接口 -->
    <bean id = "usercontroller1" name="/login1.mvc" class="com.cyn.controller.UserController1">
    </bean>
    <!-- 第二种Handler:实现 HttpRequestHandler接口-->
    <bean id = "usercontroller2" class="com.cyn.controller.UserController2">
    </bean>
    <bean id = "usercontroller3" class="com.cyn.controller.UserController3">
    </bean>
    <!-- 第三种Handler:基于注解的Handler -->
    <!-- 因为不可能每写一个Handler都在这里添加一个bean进行注册
               所以就出现了下面通过context:component-scan进行组件扫描的方式
    *切记:同一个Handler不可以通过不同方法多次注册!否则会报错找不到该路径
    -->
    <!-- <bean class="com.cyn.controller.UserController3">
    </bean> -->		
    
    						
    <!-- 二、配置处理器映射器   -->
    <!-- 注意:
              所有的映射器都实现了HandlerMapping接口,所有不同实现形成了不同的映射方法。
              在配置文件中可以有同一个url被多个映射器映射,但是存在优先级!
    ·多种映射器可以共存使用,在这里通过三种url均可访问UserController1控制器进行处理 
    ·第一种url:/login.mvc通过第一种映射器进行映射
    ·第二、三种url:/login1.mvc和/login2.mvc通过第二种映射器进行映射
    -->
	<!-- 第一种映射器(基于xml映射):
	   将bean的name作为url进行查找,需要在配置Handler时知道beanname(就是url) 
	-->
    <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
    </bean>
    <!-- 第二种映射器(基于xml映射) -->
    <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    	<property name="mappings">
    		<props>
    			<!-- 对id为usercontroller1的这个bean进行url映射,
    			 url是/login1.mvc或者是/login2.mvc
    			 -->
    			<prop key="/login2.mvc">usercontroller1</prop>
    			<prop key="/login3.mvc">usercontroller1</prop>
    			<prop key="/login4.mvc">usercontroller2</prop>
    		</props>
    	</property>
    </bean>
    <!-- 第三种映射器 (基于注解映射)-->
    <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
    </bean>
    
     
    <!-- 三、配置处理器适配器  -->
    <!-- 注意:所有的适配器都实现了HandlerAdapter方法	-->
    <!-- 第一种适配器(基于xml)
              要求Handler实现 Controller接口
    -->
    <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter">
    </bean> 
    <!-- 第二种适配器 (基于xml)
              要求Handler实现 HttpRequestHandler接口
    -->
    <bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter">
    </bean>
    <!-- 第三种适配器(基于注解)-->
    <bean class = "org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    </bean>
    
    
    <!-- 重要:实际开发中使用以下基于注解的处理器、映射器和适配器 -->
    <!-- 【1.配置基于注解的映射器和适配器】 -->
    <!-- 使用mvc:annotation-driven可以代替上面注解映射器和注解适配器
             另外实际开发选择这种方法,因为mvc:annotation-driven默认还加载了很
             多的参数绑定方法,比如:json转换解析器默认加载...
    -->
    <!--属性:
    (1)conversion-service:在适配器中注入我们以后自定义的参数绑定器 
    (2)validator:在适配器中注入我们以后自定义的校验器 
    -->
    
    <mvc:annotation-driven>
    </mvc:annotation-driven>
    <!-- 【2.配置基于注解的处理器】 -->
    <!-- 组件扫描:可以扫描controller、service、dao
             这里让扫描controller,扫描controller包下所有@Controller标识的Handler
             目的:加载所有Handler到Spring容器中 ,通过注解映射器进行查找!
    -->
    <!-- <context:component-scan base-package="com.cyn.controller">
    </context:component-scan> -->
    <!-- 【3.配置视图解析器 】
              解析jsp视图,默认使用jstl标签,classpath下面得有jstl的jar包
    -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    	<!-- 配置jsp路径的前缀 -->
    	<property name="prefix" value="/WEB-INF/pages/" />
    	<!-- 配置jsp路径的后缀 -->    
        <property name="suffix" value=".jsp" />   
    </bean>
</beans>

                                          四、需要程序员编程实现处理器Handler

1.第一种Hnadler:实现 Controller接口

package com.cyn.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

//第一种适配器要求Handler实现 Controller接口
public class UserController1 implements Controller{

	@Override
	public ModelAndView handleRequest(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception {
		// TODO Auto-generated method stub
		ModelAndView model = new ModelAndView();
		//设置视图
		model.setViewName("login");
		//ModelAndView的addObject()方法相当于在Servlet中request的setAttribute()
		//设置模型数据
		model.addObject("username","user1");
		//相当于转发,但是需要视图解析器进行解析
		return model;
	}

}

2.第二种Hnadler:实现 HttpRequestHandler接口

package com.cyn.controller;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.HttpRequestHandler;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

import jdk.nashorn.internal.ir.RuntimeNode.Request;

//第二种适配器 要求Handler实现 HttpRequestHandler接口
public class UserController2 implements HttpRequestHandler{

	@Override
	public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		//设置模型数据
		request.setAttribute("username", "user2");
		//设置转发的视图,转发不需要视图解析器进行解析
		request.getRequestDispatcher("login.jsp").forward(request, response);
		
		//使用此种方法可以通过response,设置响应的数据格式,比如json数据
		/*response.setCharacterEncoding("utf-8");
		response.setContentType("application/json;charset=utf-8");
		response.getWriter().write("json串");*/
		
	}

	

}

3.第三种Handlr:基于注解【实际开发使用】

package com.cyn.controller;


import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;

import org.apache.tomcat.jni.File;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import com.cyn.controller.validation.ValidGroup1;
import com.cyn.po.User;
import com.cyn.po.po.ItemUser;

//第三种适配器:注解开发下的Handler
//使用@Controller标识它是一个控制器
@Controller
/*为了对url进行分类管理,分层拦截类和方法,可以在这里定义根路径,最终访
 *问url是根路径(确定某个controller类)+子路径(确定method方法)
 *例如:请求用户登陆界面的url为:/user/login.mvc
 *第一个/user:映射到有关用户操作的Controller控制类
 *第二个/login:映射用户的具体请求操作为登陆
 */
@RequestMapping("/user")
public class UserController3{
	
	@ModelAttribute("itemuser")
	public Map<String,String> getItemUser(){
		Map<String,String> itemUser = new HashMap<String,String>();
		itemUser.put("user1", "lisi");
		itemUser.put("user2", "zhangsan");
		return itemUser;
	}
	
	/*使用@RequestMapping实现对getLogin()方法和url进行
	 *映射一个方法对应一个url,一般建议url和方法名一致,方便维护
	 *method:用来限制http请求方法
	 */
	@RequestMapping(value = "/login",method = {RequestMethod.GET})
	//切记:不论是哪种返回值类型,最终都要经过SpringMVC的适配器内置策略返回ModelAndView类型!
	public ModelAndView getLogin(){
		ModelAndView modelAndView = new ModelAndView();
		//设置视图,如果在视图解析器中配置了jsp路径的前缀和后缀,修改为如下:
		//model.setViewName("/WEB-INF/pages/login.jsp");
		modelAndView.setViewName("login");
		//ModelAndView的addObject()方法相当于在Servlet中request的setAttribute()
		//设置模型数据
		modelAndView.addObject("username","user1");
		//相当于转发,但是需要视图解析器进行解析
		return modelAndView;
	}
}

猜你喜欢

转载自blog.csdn.net/qq_37230121/article/details/83418573
今日推荐