处理器映射
下面的代码就是请求到处理器的映射:
当遇到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;
}
}