- 浏览: 511112 次
- 性别:
- 来自: 广州
文章分类
最新评论
-
jxq0816:
请问博主task:executortask:scheduler ...
Spring任务调度器之Task的使用 -
eithree:
thanks you so much! This proble ...
解决ECShop transport.js与jQuery冲突 -
周聪龙:
按照你的配置,点击登录按钮没反应呀,所有的Ip都改为自己的了呀 ...
自定义客户端登录CAS服务器-iframe实现 -
周聪龙:
denglihong 写道shangliuyan 写道我点击提 ...
自定义客户端登录CAS服务器-iframe实现 -
nihaonihao1987:
...
Spring任务调度器之Task的使用
本文是针对struts2的struts-tags中的s:url标签的使用进行扩展。
在J2EE开发中,使用struts2的时候我们很多时候会使用"/"来做URL地址定义,即使用项目的绝对路径。因为如果使用相对路径的话会十分麻烦,谁叫struts2中的"相对",指的并不是存放的目录结构,相对的是目标是指action的命名空间。
而由于实际服务器环境中的一些原因,可能会造成s:url生成后的地址的访问资源并不存在!
举个例子,当你部署的应用的服务器,在a机器的8080端口中。你可以在内网中使用http://ip:8080/a/ 访问,但外网访问时,却被映射到 http://www.foo.com/abc/a/ 中。
这样的情况下,通过s:url生成的url会变成是 /a 开头,而实际上是/abc/a/ 才能访问到你的应用。
陷入这个困境2天了,找不到好的解决方案,唯一的方案就是把应用映射到root,然后把应用名改成abc,前面用apache做proxy,这样的方案使用AJP的话会失败,但直接做跳转就成功,不过就丢失了request的IP。
所以最后只好把原因是使用s:url这个标签的生成不够自由的关系(没办法,我真的努力了,学艺不精啊)
基于把责任都推在s:url上的这个前提上就好办了,我决定重构一下他的标签,变得更加适合我用。
查了下源码,最后把目标定于org.apache.struts2.components.ComponentUrlProvider.java(其实方案比较多的,个人喜欢吧)
直接上源码
package org.apache.struts2.components; import java.util.Map; import java.util.Properties; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils; import com.foo.utils.file.PropertiesHelper; import com.opensymphony.xwork2.util.ValueStack; /** * Override org.apache.struts2.components.ComponentUrlProvider(struts2.core.jar) * * @author KennyLee <br /> * @version 1.0.0<br/> */ public class ComponentUrlProvider implements UrlProvider { private static final String URL_SEPARATOR = "/"; private static final String PROPERTY_FILE_NAME = "config.properties"; private static final String URL_CONTEXT_PATH_KEY = "url.context.path"; private static final String URL_SERVER_NAME_KEY = "url.server.name"; private static boolean isInitPro = false; private static String forceContextPath = ""; private static String forceServerName = ""; protected HttpServletRequest httpServletRequest; protected HttpServletResponse httpServletResponse; protected String includeParams; protected String scheme; protected String value; protected String action; protected String namespace; protected String method; protected boolean encode = true; protected boolean includeContext = true; protected boolean escapeAmp = true; protected String portletMode; protected String windowState; protected String portletUrlType; protected String anchor; protected boolean forceAddSchemeHostAndPort; protected String urlIncludeParams; protected ExtraParameterProvider extraParameterProvider; protected UrlRenderer urlRenderer; protected Component component; @SuppressWarnings("rawtypes") private Map parameters; /** * * @param component * The component used to delagete some calls to * @param parameters * parameters passed from <param...> */ public ComponentUrlProvider(Component component, @SuppressWarnings("rawtypes") Map parameters) { this.component = component; this.parameters = parameters; } @Override public String determineActionURL(String action, String namespace, String method, HttpServletRequest req, HttpServletResponse res, @SuppressWarnings("rawtypes") Map parameters, String scheme, boolean includeContext, boolean encodeResult, boolean forceAddSchemeHostAndPort, boolean escapeAmp) { // XXX add by KennyLee 2012-05-08 01:21:37, fix URL by Action. String url = null; String ori_path = component.determineActionURL(action, namespace, method, req, res, parameters, scheme, includeContext, encodeResult, forceAddSchemeHostAndPort, escapeAmp); url = ori_path; String forceContextPath = getForceContextPath(); if (StringUtils.isNotBlank(ori_path) && StringUtils.isNotBlank(forceContextPath)) { if (ori_path.startsWith(URL_SEPARATOR)) { url = new StringBuilder().append(URL_SEPARATOR) .append(forceContextPath).append(ori_path).toString(); } else if (ori_path.startsWith("http")) { String[] splits = StringUtils.split(ori_path, URL_SEPARATOR); int count = 0; for (String string : splits) { count++; url += string; if (count == 3) {// At after add serverName url += URL_SEPARATOR; url += forceContextPath; } if (count != splits.length) { url += URL_SEPARATOR; } } } } return url; } public String determineNamespace(String namespace, ValueStack stack, HttpServletRequest req) { return component.determineNamespace(namespace, stack, req); } public String findString(String expr) { return component.findString(expr); } @SuppressWarnings("rawtypes") public Map getParameters() { return parameters; } public HttpServletRequest getHttpServletRequest() { return httpServletRequest; } public void setHttpServletRequest(HttpServletRequest httpServletRequest) { this.httpServletRequest = httpServletRequest; } public HttpServletResponse getHttpServletResponse() { return httpServletResponse; } public void setHttpServletResponse(HttpServletResponse httpServletResponse) { this.httpServletResponse = httpServletResponse; } public String getIncludeParams() { return includeParams; } public void setIncludeParams(String includeParams) { this.includeParams = includeParams; } public String getScheme() { return scheme; } public void setScheme(String scheme) { this.scheme = scheme; } public boolean isPutInContext() { return component instanceof ContextBean; } public String getVar() { return isPutInContext() ? ((ContextBean) component).getVar() : null; } public String getValue() { // XXX add by KennyLee 2012-05-08 00:43:48, fix URL by value. if (StringUtils.isNotBlank(value)) { StringBuilder link = new StringBuilder(); String forceContextPath = getForceContextPath(); String forceServerName = getForceServerName(); if (StringUtils.startsWith(value, URL_SEPARATOR) && StringUtils.isNotBlank(forceContextPath)) { HttpServletRequest request = httpServletRequest; String path = request.getContextPath(); String serverName = request.getServerName(); if (StringUtils.isNotBlank(forceServerName)) { serverName = forceServerName; } String basePath = request.getScheme() + "://" + serverName + ":" + request.getServerPort(); link.append(basePath).append(URL_SEPARATOR) .append(forceContextPath).append(path).append(value); } else { link.append(value); } return link.toString(); } return value; } /** * <p> * get forceServerName * </p> * * @return */ private String getForceServerName() { if (StringUtils.isBlank(forceServerName)) { initProValues(); } return forceServerName; } /** * <p> * get forceContextPath * </p> * * @return */ private String getForceContextPath() { if (StringUtils.isBlank(forceContextPath)) { initProValues(); } return forceContextPath; } /** * <p> * init property values * </p> */ private synchronized void initProValues() { if (!isInitPro) { Properties pro = PropertiesHelper.getInstance() .getPropertiesInstance(PROPERTY_FILE_NAME, false); if (pro != null) { String contextPath = pro.getProperty(URL_CONTEXT_PATH_KEY, ""); String serverName = pro.getProperty(URL_SERVER_NAME_KEY, ""); if (StringUtils.isNotBlank(contextPath)) { forceContextPath = contextPath; } if (StringUtils.isNotBlank(serverName)) { forceServerName = serverName; } } isInitPro = true; } } public void setValue(String value) { this.value = value; } public String getAction() { return action; } public void setAction(String action) { this.action = action; } public String getNamespace() { return namespace; } public void setNamespace(String namespace) { this.namespace = namespace; } public String getMethod() { return method; } public void setMethod(String method) { this.method = method; } public boolean isEncode() { return encode; } public void setEncode(boolean encode) { this.encode = encode; } public boolean isIncludeContext() { return includeContext; } public void setIncludeContext(boolean includeContext) { this.includeContext = includeContext; } public boolean isEscapeAmp() { return escapeAmp; } public void setEscapeAmp(boolean escapeAmp) { this.escapeAmp = escapeAmp; } public String getPortletMode() { return portletMode; } public void setPortletMode(String portletMode) { this.portletMode = portletMode; } public String getWindowState() { return windowState; } public void setWindowState(String windowState) { this.windowState = windowState; } public String getPortletUrlType() { return portletUrlType; } public ValueStack getStack() { return component.getStack(); } public void setPortletUrlType(String portletUrlType) { this.portletUrlType = portletUrlType; } public String getAnchor() { return anchor; } public void setAnchor(String anchor) { this.anchor = anchor; } public boolean isForceAddSchemeHostAndPort() { return forceAddSchemeHostAndPort; } public void setForceAddSchemeHostAndPort(boolean forceAddSchemeHostAndPort) { this.forceAddSchemeHostAndPort = forceAddSchemeHostAndPort; } public void putInContext(String result) { if (isPutInContext()) { ((ContextBean) component).putInContext(result); } } public String getUrlIncludeParams() { return urlIncludeParams; } public void setUrlIncludeParams(String urlIncludeParams) { this.urlIncludeParams = urlIncludeParams; } public ExtraParameterProvider getExtraParameterProvider() { return extraParameterProvider; } public void setExtraParameterProvider( ExtraParameterProvider extraParameterProvider) { this.extraParameterProvider = extraParameterProvider; } public UrlRenderer getUrlRenderer() { return urlRenderer; } public void setUrlRenderer(UrlRenderer urlRenderer) { this.urlRenderer = urlRenderer; } }
说明:
回头想想我刚刚举的例子,其中最主要是那个我们预想之外的abc子域名,如果我们能把它都添加在应用名之前就完毕了,而且以后就算前面加多少个子域名目录,也依然可以正常访问。
所以,这里我用一个forceContextPath来存放这个值。
而另外一个关键的地方是 serverName,即我们访问时用的IP或者域名。用原生的requet方法getServerName的话,有些时候会造成跟访问域名不一致的情况。例如你用 www.foo.com 访问的,但request.getServerName得出的结果是 192.168.1.1 。这种情况下,有时候可能影响变大,但如果域名做了多映射的条件下,也会造成访问障碍,为了安全起见,也提供强制定义的方式来定义serverName。这也是为什么我不使用原生的forceAddSchemeHostAndPort参数来获取完整路径的原因。
即另外一个重要的参数值 forceServerName。
这个两个值我是放在classes根目录下的config.properties目录下,相信如果专注于J2EE开发的人对这类型文件不会陌生吧。forceContextPath在config.properties中的key为url.context.path,而forceServerName的key为url.server.name。
Q:为什么使用value构造URL时,我把http和域名等信息都加上了?
A:对于这点,其实我也挺无奈的。因为如果不这样做,我遇到会产生forceContextPath被重叠了两次的情况。即变成了 /abc/abc/ 但我实际需要的只是 /abc/ (注:我的应用映射到root中,而应用名跟子级域名一致,即应用名也叫abc)。也想过用javascript来解决这个问题,不过最后还是懒得再继续探究下去了。因为其实上线环境中,绑定域名其实没多大问题的。
附上上面代码中使用到的一个工具类PropertiesHelper的的代码
import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Map; import java.util.Properties; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; /** * <b>类名称:</b>PropertiesHelper<br/> * <b>类描述:</b>java.util.Properties的工具类<br/> * <b>创建时间:</b>2009-10-12 下午2:48:05<br/> * <b>备注:</b><br/> * * @author KennyLee <br /> * @version 1.0.0<br/> */ public class PropertiesHelper { private volatile static PropertiesHelper uniqueInstance; private static final Map<String, Properties> propertiesMap = new HashMap<String, Properties>(); private PropertiesHelper() { }; public static PropertiesHelper getInstance() { if (uniqueInstance == null) { synchronized (PropertiesHelper.class) { if (uniqueInstance == null) { uniqueInstance = new PropertiesHelper(); } } } return uniqueInstance; } /** * <p> * Get properties instance by fileName. * </p> * * @param fileName * @param isKeepProperties * 是否保存Properties对象到全局。 * @return */ public Properties getPropertiesInstance(String fileName, boolean isKeepProperties) { Properties resultInstence = null; if (StringUtils.isBlank(fileName)) return null; resultInstence = propertiesMap.get(fileName); if (resultInstence == null) { resultInstence = new Properties(); InputStream inputStream = null; try { inputStream = this.getClass().getClassLoader() .getResourceAsStream(fileName); resultInstence.load(inputStream); } catch (IOException e) { resultInstence = null; e.printStackTrace(); } finally { IOUtils.closeQuietly(inputStream); } if (resultInstence != null && isKeepProperties) propertiesMap.put(fileName, resultInstence); } return resultInstence; } /** * <p> * Get properties instance by fileName. * </p> * * @param fileName * @return */ public Properties getPropertiesInstance(String fileName) { return getPropertiesInstance(fileName, true); } }
希望对大家有用,或者给你带来一定的启发!
EOF
发表评论
-
【转】Struts2 result返回类型(type)小结
2012-08-06 11:42 1495在struts2的返回结果配置中,我们大部分情况使用默认 ... -
使用VisualVM监测Tomcat JVM情况的配置(Windows+Linux)
2012-04-17 10:02 4367一,Windows环境 1.若以服务的方式启 ... -
【转】Java内存泄露_JVM监控工具介绍jstack_jconsole_jinfo_jmap_jdb_jstat
2012-02-10 18:06 2111jstack -- 如果java程序崩溃生成core文件 ... -
DynaBean的体会
2011-12-29 22:16 0在开发中,为了减少一些不必要的VO和formBean(尽管在s ... -
【转】OGNL表达式struts2标签说明
2011-12-26 22:57 1459一、什么是OGNL,有什么特点? OGNL(Objec ... -
【转】Struts2与JSON资料学习合集
2011-12-07 17:06 3918最近又搜了一些struts2和JSON的学习资料, ... -
浅谈Struts2数据下载和AJAX服务端接口的实现
2011-12-04 21:13 3995在struts2中实现文件或特 ... -
自己的修改hibernate-tools的模板和修复Comment乱码问题
2011-11-02 11:38 8021关于自定义 之前一直用hibernate-tools来 ... -
SpringSecurity备忘配置
2011-11-01 11:37 12751.定义登录后的首页action.do,该action决定了用 ... -
【转】使用 Eclipse Memory Analyzer 检测内存泄漏问题
2011-09-28 11:39 1281本文是关于在开发Talend RCP 过程中碰到 ... -
编写使用SpringSecurity的JUnit测试提醒
2011-08-15 15:40 3423近日在使用SpringSecurity的项目中发现一个小问题, ... -
【转】sun.misc.BASE64Encoder找不到的解决方法
2011-08-09 11:21 3338sun.misc.BASE64Encoder/BASE64De ... -
【转】如何在win7系统上安装Jdk版本1.6
2011-07-27 17:10 1616鉴于有些朋友对JDK的安装不太熟悉,特意转载此教程。原地址如下 ... -
我的eclipse插件推荐
2011-07-03 19:56 114221. ER图工具 ERMaster - http: ... -
分享struts2做的一个分页按钮样式
2011-06-03 01:00 1843首先是分页内容的辅助类 package cn.com. ... -
使用Jakarta Common Digester解析XML的简单例子
2011-04-19 13:36 2365Jakarta Commons Digester官方网址 ht ... -
【转】Struts2+Spring的UnitTest编写(使用StrutsTestCase的子类StrutsSpringTestCase)
2011-01-16 00:37 8873我们都知道struts2有自己的对象工厂即obe ... -
精通Hibernate读书笔记
2010-01-31 00:58 1836生成Java类 使用hibernate tools( ... -
Struts2中的EL表达式兼容问题
2009-12-29 16:33 2284今天遇到一个郁闷的问题,页面某段文字显示的时候就显示一半,查看 ... -
获取上传文件的字符编码
2009-11-10 22:50 3503重点又回到了国人都很烦恼的字符编码问题,真羡慕老外们。不过作为 ...
相关推荐
Struts 2 标签库(文档手册) Tags-API-CLSW-JSP <%@ taglib prefix="s" uri="/struts-tags" %> 就能使用struts2.0的标签库 下面就介绍每个标签的具体应用实例说明:按字母排列 A: 1. 2. <s:a href=""></s:a>-...
component标签:生成一个自定义的组件。 div标签:AJAX标签,生成一个div片段。 fielderror标签:输出异常提示信息。 tabbedPanel:AJAX标签,生成HTML中的Tab页。 tree标签:生成一个树形结构。 treenode标签:...
该属性指定是否允许在Struts 2标签中使用表达式语法,因为通常都需要在标签中使用表达式语法,故此属性应该设置为true,该属性的默认值是true. struts.devMode 该属性设置Struts 2应用是否使用开发模式.如果设置该属性...
wint 是一个基于mvc易用的 java web框架,抛开了struts2 繁琐的配置,结合django,RoR,webx,play等框架的特点,使用约定优于配置的原则,使开发者能快速的搭建web和进行快速开发。 wint提供的主要功能有: 模板与...
JSP视窗组件所使用的struts标记库由四类标记组成: Bean标记:用来在JSP页中管理bean 逻辑标记:用来在JSP页中控制流程 HTML标记:用来生成HTML标记,在表单中显示数据,使用会话ID对URL进行编程 模板标记:使用...
前台制作采用标签制,分为系统标签和用户自义义标签两种,系统标签是自代的,用户不可以修改,而自定义标签则是用户根据相应的功能自己定制出来的,固此,可以自行删除或修改! 4、秉承JAVA开源理念,本新闻发布系统...
3. Struts 2 标签库说明及使用 160 4. set 描述 169 5. text 描述 170 6. property 描述 170 7. Struts的异常处理 171 8. Struts的上传与下载 178 五、 Hibernate 192 (一) 前言 192 (二) 持久化层 193 (三) ORM介绍...
漏洞检测包含MS17010、Weblogic、ActiveMQ、Tomcat、Struts2等,密码爆破11种含数据库(Mysql、Oracle、MSSQL)、FTP、SSH(Linux主机)、VNC、Windows密码(IPC、WMI、SMB)、Weblogic后台、Rar压缩包密码等,Web指纹识别...
\contentsline {chapter}{Contents}{2}{section*.1} {1}Java基础}{17}{chapter.1} {1.1}基本语法}{17}{section.1.1} {1.2}数字表达方式}{17}{section.1.2} {1.3}补码}{19}{section.1.3} {1.3.1}总结}{23}{...
10. Wicket链接和URL生成 10.1。PageParameters 10.2。可收藏的链接 10.3。使用标记wicket自动创建可收藏的链接:链接 10.4。外部链接 10.5。无状态链接 10.6。生成结构清晰的URL 10.7。摘要 11. Wicket模型和表格 ...
2.spring支持用户自定义的切面 面向切面编程(aop)是对面向对象编程(oop)的补充, 面向对象编程将程序分解成各个层次的对象,面向切面编程将程序运行过程分解成各个切面。 AOP从程序运行角度考虑程序的结构,...
JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (<jcaptcha:image label="Type the text "/> ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...
11.6 为一个应用的领域类生成CRUD控制器和视图 454 11.6.1 问题 454 11.6.2 解决方案 454 11.6.3 工作原理 455 11.7 国际化(I18n)信息属性 458 11.7.1 问题 458 11.7.2 解决方案 458 11.7.3 工作原理...
6. <property name="url" value="jdbc:oracle:thin:@localhost:1521:ora9i"/> 7. 8. 9. 10. !-- Hibernate会话工厂配置 //--> 11. 12. class="org.springframework.orm.hibernate3.LocalSessionFactoryBean...
Java生成自定义控件源代码 2个目标文件 Java实现HTTP连接与浏览,Java源码下载 1个目标文件 摘要:Java源码,网络相关,HTTP Java实现HTTP连接与浏览,Java源码下载,输入html文件地址或网址,显示页面和HTML源文件...
Java生成自定义控件源代码 2个目标文件 Java实现HTTP连接与浏览,Java源码下载 1个目标文件 摘要:Java源码,网络相关,HTTP Java实现HTTP连接与浏览,Java源码下载,输入html文件地址或网址,显示页面和HTML源文件...
JCaptcha4Struts2 是一个 Struts2的插件,用来增加验证码的支持,使用时只需要用一个 JSP 标签 (<jcaptcha:image label="Type the text "/> ) 即可,直接在 struts.xml 中进行配置,使用强大的 JCaptcha来生成验证码...