SpringMVC学习笔记(三) --- 映射处理器

 

映射处理器Handler Mapping

1.简析映射处理器
在spring mvc中,使用映射处理器可以把web请求映射到正确的处理器上,spring内置了很多映射处理器,而且我们也可以自定义映射处理器。

下面的实例展示spring中最常用的两个映射处理器:

 BeanNameUrlHandlerMapping和SimpleUrlHandlerMapping。

在正式开始前有必要了解以下相关要点:
(1)映射处理器都能把请求传递到处理器执行链接(HandlerExecutionChain)上,并且处理器执行链接必须包含能处理该请求的处理器(实质就是处理器链上动态添加了了此处理器,可以结合filter工作原理理解),而且处理器链接也能包含一系列拦截器。
(2)上面列举的spring最常用的两种处理器都是继承自AbstractHandlerMapping类 ,因而它们具备父类的属性。


2.实例:BeanNameUrlHandlerMapping
在我们上面的工程的基础上进行修改
步骤一:建立后端控制器HelloWorldController.java,


  步骤二:配置web.xml,


 步骤三:配置spmvc-servlet.xml,


 步骤四:在WEB-INF/page目录下hello.jsp

 步骤五:启动服务器,输入…/helloController.do访问测试。

简析执行过程

  (1)启动服务器后,当我们向服务器发送message.do请求时,首先被在web.xml中配置的前端控制器DispatcherServlet拦截到。
  (2)前端控制器把此请求转交给后端控制器,下面分析转交过程:当在spmvc-servlet.xml中查找能执行 helloController .do请求的映射处理器时,发现没有能处理此请求的映射处理器,这时便使用默认的映射处理器BeanNameUrlHandlerMapping:This is the default implementation used by the DispatcherServlet, along with DefaultAnnotationHandlerMapping (on Java 5 and higher).   

            我们还需注意:这种后端控制器的bean Name必须以“/”开头 ,并且要结合DispatcherServlet的映射配置。同时beanName支持通配符配置 。比如如果配置:<bean name="/m*.do " class="com.wy.controller.HelloWorldController" /> 时,当访问 helloController .do时也可以成功访问到 HelloWorldController 类。
  (3)BeanNameUrlHandlerMapping处理器,会查找在spring容器中是否在名为“ helloController .do”的bean实例 。当查找到此实例后,则把此bean作为处理此请求的后端控制器。同时把自身加到映射处理器链上,并向处理器链传递此请求。
  (4)后端控制器进行处理,并返回视图。

 

小结

       BeanNameUrlHandlerMapping的实现更为简单,每个Controller的URL与其name属性对应,因此,只需要对每个Controller以URL作为name,就可以实现URL映射。

配置示例如下:

<bean id="beanNameUrlHandlerMapping" class="org.springframework.web.servlet. handler.BeanNameHandlerMapping" />

<bean name="/a.html" class="example.chapter7.ControllerA" />

<bean name="/a.html" class="example.chapter7.ControllerB" />

 之所以用Bean的name作为URL而不是id,是因为XML规范不允许在id标识中使用特殊字符“/”。当用户请求一个URL时,Spring将直接查找name为URL的Controller。

使用 SimpleUrlHandlerMapping的麻烦之处在于,添加或删除Controller时必须要对 SimpleUrlHandlerMapping做相应的修改,而BeanNameUrlHandlerMapping则无需手工编写映射,只需要在每个 Controller中仔细定义name属性。

如果使用XDoclet自动生成配置文件,则可以将name在Controller的注释中定义,维护起来 更加方便。

因此,我们推荐首先考虑使用BeanNameUrlHandlerMapping。

事实上,如果没有在XML配置文件中定义任何 UrlHandlerMapping,则Spring MVC默认使用BeanNameUrlHandlerMapping。

 

3.SimpleUrlHandlerMapping

 

   步骤一:建立后端控制器UserContrller.java.代码如下:

 

package com.asm;
//...省略导入的相关类
public class UserController extends SimpleFormController {
	protected ModelAndView processFormSubmission(HttpServletRequest request, HttpServletResponse response,
			Object command, BindException errors) throws Exception {
		System.out.println("调用逻辑层,处理表单");
		ModelAndView mav = new ModelAndView("loginSuc");
		return mav;
	}
}
 

 

步骤二:在spmvc-servlet.xml中增加如下配置:

<bean id="simpleUrlHandlerMapping"		class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<!-- 为映射处理器引入拦截器bean -->
		<property name="interceptors">
			<list>
				<ref bean="workTimeInterceptor" />
			</list>
		</property>
		<property name="mappings">
			<props>
				<prop key="/op/*/login.do">userController</prop>
			</props>
		</property>
	</bean>

	<bean id="userController" class="com.asm.UserController">
		<property name="commandClass" value="com.asm.User"/>
	</bean>

	<!-- 拦截器bean -->
	<bean id="workTimeInterceptor"
		class="com.asm.LoginTimeInterceptor">
		<property name="startTime" value="6" />
		<property name="endTime" value="18" />
	</bean>
 

说明 :(1 )通过前面实例我们可以知道,SimpleController 这样的后端控制器必须绑定一个commandClass 对象,在这里我们通过配置文件 < property name = "commandClass" value = "com.asm.User" /> 绑定。
2 < prop key = "/op/*/login.do" > userController </ prop > 配置说明只要访问是以op 开头,中间* 可以是任意字符,并以login.do 结尾的请求,便能访问到 userController 控制器。

3 SimpleUrlHandlerMapping 是一个更强大的映射处理器,它除了支持上面 < props > 的这种配置,还支持Ant 风格的路径匹配。另外也可以进行如下形式的配置:

< property name = "mappings" >

       < value >

           /op/*/login.do= userController

       </ value >

</ property >

4 )拦截器:为了为某些特殊请求提供特殊功能,spring 为映射处理器提供了拦截器支持。它的配置文件很简单:一是把拦截器类纳入spring 容器管理,二是在映射处理器引入配置的拦截器bean

 

步骤三 :编写拦截器 LoginTimeInterceptor.java ,主要代码如下:

 

package com.asm;
//...省略导入的相关类
public class LoginTimeInterceptor extends HandlerInterceptorAdapter {
	private int startTime;
	private int endTime;

	public void setStartTime(int startTime) {
		this.startTime = startTime;
	}
	public void setEndTime(int endTime) {
		this.endTime = endTime;
	}

	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
			Exception ex) throws Exception {
		System.out.println("执行afterCompletion方法-->03");
		super.afterCompletion(request, response, handler, ex);
	}

	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {
		System.out.println("执行postHandle方法-->02");
		super.postHandle(request, response, handler, modelAndView);
	}

	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		System.out.println("执行preHandle方法-->01");
		Calendar cal = Calendar.getInstance();
		int hour = cal.get(Calendar.HOUR_OF_DAY);	
		if (startTime <= hour && hour < endTime) {
			return true;
		} else {
			response.sendRedirect("http://www.iteye.com");
			return false;
		}
	}
}
 

 说明:此拦截器作用:如果用户没有在6-18点登录,则重定向到javaeye站点

          (1)拦截器必须HandlerInterceptorAdapter接口

          (2)preHandle方法在后端控制器执行前被调用,postHandle方法在后端控制器执行后被调用;afterCompletion方法在整个请求处理完成后被调用。

           (3) preHandle方法:返回true,映射处理器执行链将继续执行;当返回false时,DispatcherServlet处理器认为拦截器已经处理完了请求,而不继续执行执行链中的其它拦截器和处理器。它的API文档解释如下:true if the execution chain should proceed with the next interceptor or the handler itself. Else, DispatcherServlet assumes that this interceptor has already dealt with the response itself.

         (4)这三个方法都是相同的参数,Object handler参数可以转化成一个后端控制器对象,比如这里可以转换成UserController对象。

 

步骤四:完成其它相关代码的编写

 

User.java 代码

 

package com.asm;

public class User {

    private String username;

    private String password;

    //省略getter/setter方法

}

 

WEB-INF/page/loginSuc.jsp , 主要代码如下:

<body>

    登录成功!欢迎来到后台管理页面 

</body>

 

index.jsp 代码:

<form action="<%=request.getContextPath()%>/op/luanXie/login.do" method="post">

    用户名:<input type="text" name="username"><br/>

    密 码:<input type="password" name="password"><br/>

    <input type="submit" value="登录">

  </form>

 

步骤五 :访问index.jsp 页面,完成测试。

分析执行过程:为了清晰体会到整个处理器执行过程,我们首先在UserController.java 中增加如下代码:

	protected Object formBackingObject(HttpServletRequest request) throws Exception {
		System.out.println("formBackingObject方法执行-->01");
		return super.formBackingObject(request);
	}
	protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
		System.out.println("initBinder方法执行-->02");
		super.initBinder(request, binder);
	}
	protected void onBind(HttpServletRequest request, Object command) throws Exception {
		System.out.println("onBind方法执行-->03");
		super.onBind(request, command);
	}
	protected void onBindAndValidate(HttpServletRequest request, Object command, BindException errors)
			throws Exception {
		System.out.println("onBindAndValidate方法执行-->04");
		super.onBindAndValidate(request, command, errors);
	}

 

1 )当访问…/login.do 时,会首先被前端控制器DispatcherServlet 拦截到,前端控制器通过查找spmvc-servlet.xml 配置文件,并交给后端控制器处理。

 (2) 执行后,得到如下打印结果,通过打印结果我们知道它的一个大致执行过程。

执行 preHandle 方法 -->01

formBackingObject 方法执行 -->01

initBinder 方法执行 -->02

onBind 方法执行 -->03

onBindAndValidate 方法执行 -->04

调用逻辑层,处理表单

Admin----123456

执行 postHandle 方法 -->02

执行 afterCompletion 方法 -->03

 

小结:

        混合使用多种 UrlHandlerMapping,但是必须为每个UrlHandlerMapping指定order属性来表示优先级 ,order值越小优先级越 高,Spring会先查询优先级高的UrlHandlerMapping。

        若找到了对应的Controller,就不再继续查询,否则,按照优先级依次查 询,直到找到为止。

         若所有的UrlHandlerMapping都无法返回一个合适的Controller,并且没有设置默认的Controller时, 就会返回给客户端一个“404 Not Found”错误,表示不存在这个URL。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值