目前在写一个项目由于需要兼顾多浏览器(主要还是IE6、IE7和FF),和同学讨论使用了两套CSS来达到这一目的。这就遇到了一个问题,怎样根据不同的浏览器来加载不同的CSS文件?最开始是使用jQuery来在前台进行判断,后来否定了这个方法;之后是使用IE浏览器的条件注释来进判断,这种方法虽然可行,但总是有种剑走偏锋的感觉。于是最终方案定为在后台来根据request请求来判断,然后响应到前台页面。
使用后台判断是使用JSP的request对象,使用getHeader()方法可以获得客户端的请求头数据,然后进一步分析出浏览器的类型与版本,加载CSS。由于加载CSS几乎是每个JSP页面都要做的事情,所以如果单抽取出一个类来做这件事不是不可以,但每个Action类都要调用这个类进行一次判断,这显然是很笨拙的办法。于是决定使用Struts2的栏截器机制,把这段代码抽取到一个自定义栏截器中,是最好的方案。
首先创建一个自定义栏截器,这里叫做“BrowserInterceptor”,它继承自com.opensymphony.xwork2.interceptor.MethodFilterInterceptor,从这个类继承的好处是,不必把Action的所有方法全部栏截,只需配置我们想要栏截的方法,这比使用AbstractInterceptor类又更进了一步,具体此栏截器的讲解请参阅《Struts2权威指南》这本书。
package com.yue.interceptor; import javax.servlet.http.HttpServletRequest; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor; import com.yue.action.AjaxAction; public class BrowserInterceptor extends MethodFilterInterceptor { @Override protected String doIntercept(ActionInvocation arg0) throws Exception { AjaxAction action = (AjaxAction) arg0.getAction(); HttpServletRequest req = ServletActionContext.getRequest(); String browser = req.getHeader("User-Agent"); //取得浏览器信息串进行分析 if (browser.indexOf("Firefox") != -1) { //根据不同的浏览器来加载不同的样式文件 System.out.println("Mozilla Firefox"); req.setAttribute("Browser", "<link rel='stylesheet' href='Style/Site.css'>"); } else if (browser.indexOf("MSIE 6.0") != -1) { System.out.println("MSIE 6.0"); req.setAttribute("Browser", "<link rel='stylesheet' href='Style/Site_IE6.css'>"); } else { System.out.println("MSIE"); req.setAttribute("Browser", "<link rel='stylesheet' href='Style/Site.css'>"); } return arg0.invoke(); } }
上面的代码原理很简单,就是分析了getHeader("User-Agent")返回的字串进行分析,但这种分析方法感觉很笨拙,希望大家有更好的判断方法可以给出,在这里我也向大家多多学习。
然后将结果赋予到request对象中,进便于前台显示。
下面配置了这个栏截器:
<package name="default" extends="json-default"> <interceptors> <interceptor name="browser" class="com.yue.interceptor.BrowserInterceptor"> </interceptor> </interceptors> <action name="ajax" class="com.yue.action.AjaxAction"> <result name="success">/json.jsp</result> <interceptor-ref name="defaultStack"></interceptor-ref> <interceptor-ref name="browser"> <!-- 这里定义了栏截的方法名,我只需栏截execute方法,别的方法不要栏截 --> <param name="includeMethods">execute</param> </interceptor-ref> </action> </package>
上面对这个栏截器进行了配置,可以看到使用了includeMethods指定了哪些方法需要进行栏截处理,相当于白名单。
如果想指定哪些方法不被栏截,配置excludeMethods参数即可,多个方法名使用逗号分开。
JSP页面就简单了,只需在加载CSS的位置使用Struts2的标签进行输出即可:<s:property value="#request.Browser" escape="false"/>
需要注意的是,escape属性必须置为false,这是因为默认来说内容是转义的。