Spring的MVC详解——处理器映射、数据绑定、本地化支持

处理器映射

下面的代码就是请求到处理器的映射:

当遇到helloWorld.do请求时,会转向处理器helloWorldAction。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
	<!--定义映射-->
	<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
		<property name="mappings">
			<props>
				<prop key="helloWorld.do">helloWorldAction</prop>
			</props>
		</property>
	</bean>
	<!--定义视图及JSP存放的路径-->
	......
	<!--定义控制器-->
	......
</beans>

org.springframework.web.servlet.handler.SimpleUrlHandlerMapping,是用来具体负责请求转换的类,实现了HandlerMapping接口。HandlerMapping接口的代码如下:

public interface HandlerMapping {
    HandlerExecutionChain getHandler(HttpServletRequest request)throws Exception;
}

而要实现把对*.do的请求转换给配置文档中设定的相应处理器,则依赖于org.springframework.web.servlet.DispatcherServlet中的getHandler()方法:

protected HandlerExecutionChain getHandler(HttpServletRequest request,boolean cache) throws Exception {
    //HANDLER_EXECUTION_CHAIN_ATTRIBUTE在DispatcherServlet类中被定义为static final String,其值为DispatcherServlet.class.getName()+".HANDLER"
    HandlerExecutionChain handler = (HandlerExecutionChain)request.getAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE);
    //假如获取的handler不为null
    if(handler!=null){
        //再判断cache是否为false
        if(!cache){
            request.removeAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE);
        }
        return handler;
    }
    //获取handler
    Iterator it = this.handlerMappings.iterator();
    while(it.hasNext()){
        HandlerMapping hm = (HandlerMapping)it.next();
        //调试时使用的日志信息
        if(logger.isDebugEnabled()){
            logger.debug("Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
        }
        //通过HandlerMapping的getHandler()方法获取handler
        handler = hm.getHandler(request);
        //假如获取的handler不为null
        if(handler!=null){
            if(!cache){
                request.setAttribute(HANDLER_EXECUTION_CHAIN_ATTRIBUTE,handler);
            }
            return handler;
        }
    }
    return null;
}

因为有了处理器映射,因此需要在映射请求时添加一个拦截器,以做某种动作或检查。在映射请求时添加一个拦截器,自定义的拦截器就必须实现 org.springframework.web.servlet.HandlerInterceptor 接口。

//******HandlerInterceptor.java******
public interface HandlerInterceptor {
    //在处理器执行前被调用
    boolean preHandle(HttpServletRequest request,HttpServletResponse response,Object handler) throws Exception;
    //在整个请求处理完后调用
    void afterCompletion(HttpServletRequest request,HttpServletResponse response,Object handler, Exception ex) throws Exception;
}

preHandle()方法的返回值为true时,处理器将继续执行,当返回值为false时,DispatcherServlet认为拦截器本身将处理请求,而不继续执行处理器

示例:正常上班时间,早8点到下午5点,如果登录BBS则转内网首页,即不允许访问留言。其余时间可以登录企业BBS留言。

(1)定义拦截器NotLeaveWord,实现HandlerInterceptor接口。

import java.util.Calendar;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

public class NotLeaveWord 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 boolean preHandle(HttpServletRequest request,HttpServletResponse response,Object handler) throws Exception {
		Calendar cal = Calendar.getInstance();
		int hour = cal.get(HOUR_OF_DAY);
		//假如在规定的时间之间,则转向内网
		if (startTime<=hour && hour<endTime) {
			response.sendRedirect("http://localhost:8080/jlerp/index.jsp");
			return false;
		} else {
			return true;
		}
	}
}

(2)配置spring文档,在处理器映射中添加拦截器。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    ......
	<!--定义映射-->
    <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="interceptors">
            <list>
                <ref bean="NotLeaveWord"/>
            </list>
        </property>
        <property name="mappings">
            <props>
                <prop key="helloWorld.do">helloWorldAction</prop>
            </props>
        </property>
    </bean>
    <!--定义视图及JSP存放的路径-->
    ......
    <!--定义控制器-->
    ......
    <!--设定开始和结束时间-->
    <bean id="NotLeaveWord" class="com.gc.action.NotLeaveWord">
        <property name="startTime"><value>8</value></property>
        <property name="endTime"><value>17</value></property>	
    </bean>
    ......
</beans>

数据绑定

之前的示例,如果要进行数据验证,则必须把验证的代码写在逻辑里,当然这不是好的做法。Spring提供了分离业务逻辑和数据验证的方法,即数据绑定。

Spring中,有两种数据绑定的方法:

(1)使用自定义标签

可以对页面、错误信息进行数据绑定。需要引入spring.tld,并将其放入WEB-INF文件夹下。

<taglib>
    <taglib-uri>/spring</taglib-uri>
    <taglib-location>/WEB-INF/spring.tld</taglib-location>
</taglib>

(2)使用Validator

可以使用Validator,负责具体的验证工作。org.springframework.validation.Validator代码如下:

//*******Validator.java*******
public interface Validator {
    boolean supports(Class clazz);
    //在此方法里进行验证
    void validate(Object obj,Errors errors);
}
  • supports()方法,表示是否支持对传进来的对象进行验证。返回值是true,则表示支持对传进来的类进行验证;如果是false,则表示不支持对传进来的类进行验证。
  • validate()方法,表示对传入的对象进行验证。如果有错,则可以把错误放在Errors里。

本地化支持

  • Spring提供了本地化支持。
  • 主要依赖于 org.springframework.web.servlet.LocaleResolver。
//*********LocaleResolver.java**********
public interface LocaleResolver{
    //取得Locale信息
    Locale resolveLocale(HttpServletRequest request);
    //设定locale
    void setLocale(HttpServletRequest request,HttpServletResponse response,Locale locale);
}

Spring可以根据客户端浏览器语言设定,自动切换符合客户端浏览器语言设定的信息,从而灵活地实现本地化支持。

实现本地化支持

根据浏览器的语言设定,有3种方式实现本地化支持:

(1)在头信息中包含客户端的本地化信息。

只需在头文件中增加一个Bean。

<bean id="localeResolver" class="org.springframework.web.servlet.i18n.AcceptHeaderLocaleResoler">
</bean>

然后,Spring会根据客户端浏览器的Locale设定决定返回界面所采用的语言种类。

public class AcceptHeaderLocaleResolver implements LocaleResolver{
    //获得当前语言设定
	@Override
	public Locale resolveLocale(HttpServletRequest request) {
		return request.getLocale();
	}
	//设定Locale
	@Override
	public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
		throw new UnsupportedOperationException("Cannot change HTTP accept header - use a different locale resolution strategy");		
	}
}

(2)根据cookie获取本地化信息。

只需在头文件中增加一个Bean。

<bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
    <!--设定cookie的名称-->
    <property name="cookieName">
        <value>clientlanguageLocal</value>
    </property>
    <!--设定cookie的最大保存时间-->
    <property name="cookieMaxAge">
        <value>100000</value>
    </property>
    <!--设定cookie的路径-->
    <property name="cookiePath">
        <value>myApp</value>
    </property>
</bean>
  • cookieMaxAge的默认值是Integer.MAX_INT,表示cookie在客户端存在的最大时间。如果值是 -1 ,则表示这个cookie一直存在,直到关闭浏览器
  • cookiePath可以限制cookie只有一部分网站页面可以访问。
public class CookieLocaleResolver extends CookieGenerator implements LocaleResolver {
	public static final String LOCALE_REQUEST_ATTRIBUTE_NAME = CookieLocaleResolver.class.getName()+".LOCALE";
	public static final String DEFAULT_COOKIE_NAME = CookieLocaleResolver.class.getName()+".LOCALE";
	
	public CookieLocaleResolver() {
		setCookieName(DEFAULT_COOKIE_NAME);
	}

	@Override
	public Locale resolveLocale(HttpServletRequest request) {
		Locale locale = (Locale)request.getAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME);
		if (locale!=null) {
			return locale;
		}
		Cookie cookie = WebUtils.getCookie(request, getCookieName());
		if (cookie!=null) {
			locale = StringUtils.parseLocaleString(cookie.getValue());
			if (logger.isDebugEnabled()) {
				logger.debug("Parsed cookie value [" + cookie.getValue() + "] into locale '" + locale + "'");
			}
			if (locale != null) {
				request.setAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME, locale);
				return locale;
			}
		}
		return request.getLocale();
	}

	@Override
	public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
		if (locale != null) {
			request.setAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME, locale);
			addCookie(response, locale.toString());
		}
		else {
			request.setAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME, locale);
			removeCookie(response);
		}
	}
}

(3)从会话中获取本地化信息。

只需在头文件中增加一个Bean。

<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResoler">
</bean>

然后,Spring会根据客户端浏览器的Locale设定决定返回界面所采用的语言种类。

public class SessionLocaleResoler implements LocaleResolver {
	public static final String LOCALE_SESSION_ATTRIBUTE_NAME = SessionLocaleResoler.class.getName()+".LOCALE";
	
	@Override
	public Locale resolveLocale(HttpServletRequest request) {
		Locale locale = (Locale)WebUtils.getSessionAttribute(request, LOCALE_SESSION_ATTRIBUTE_NAME);
		return (locale!=null?locale:request.getLocale());
	}

	@Override
	public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
		WebUtils.setSessionAttribute(request, LOCALE_SESSION_ATTRIBUTE_NAME, locale);
	}
}

根据参数修改本地化信息

我们可以根据参数修改本地化信息,需要借助拦截器的支持。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
	<!--根据参数修改本地化信息-->
	<bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
		<property name="paramName"><value>language</value></property>
	</bean>
	<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
	</bean>
	<!--定义映射-->
	<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
		<property name="interceptor">
			<list>
				<ref local="localeChangeInterceptor"/>
			</list>
		</property>
		<property name="mappings">
			<props>
				<prop key="helloWorld.do">helloWorldAction</prop>
			</props>
		</property>
	</bean>
	<!--定义视图及JSP存放的路径-->
	<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="viewClass">
			<value>org.springframework.web.servlet.view.JstlView</value>
		</property>
		<!--JSP存放的目录-->
		<property name="prefix">
			<value>/WEB-INF/jsp/</value>
		</property>
		<!--JSP文件的后缀-->
		<property name="suffix">
			<value>.jsp</value>
		</property>
	</bean>
	<!--定义控制器-->
	<bean id="helloWorldAction" class="com.gc.action.HelloWorldAction">
		<property name="helloWorld">
			<value>HelloWorld</value>
		</property>
		<property name="viewPage">
			<value>index</value>
		</property>
	</bean>
</beans>
public class LocaleChangeInterceptor extends HandlerInterceptorAdapter {
	public static final String DEFAULT_PARAM_NAME = "locale";
	private String paramName = DEFAULT_PARAM_NAME;
	public void setParamName(String paramName) {
		this.paramName = paramName;
	}
	//该方法用来提取拦截,并设定language
	public boolean preHandle(HttpServletRequest request,HttpServletResponse response,Object handler) throws ServletException {
		String newLocale = request.getParameter(this.paramName);
		if (newLocale != null) {
			//解析新的locale
			LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
			if (localeResolver == null) {
				throw new IllegalStateException("No LocaleResolver found: not in a DispatcherServlet request?");
			}
			//设定新的locale
			LocaleEditor localeEditor = new LocaleEditor();
			localeEditor.setAsText(newLocale);
			localeResolver.setLocale(request, response, (Locale)localeEditor.getValue());
		}
		return true;
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

肥羊汤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值