- 浏览: 515680 次
- 性别:
- 来自: 广州
文章分类
最新评论
-
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 1530在struts2的返回结果配置中,我们大部分情况使用默认 ... -
使用VisualVM监测Tomcat JVM情况的配置(Windows+Linux)
2012-04-17 10:02 4416一,Windows环境 1.若以服务的方式启 ... -
【转】Java内存泄露_JVM监控工具介绍jstack_jconsole_jinfo_jmap_jdb_jstat
2012-02-10 18:06 2186jstack -- 如果java程序崩溃生成core文件 ... -
DynaBean的体会
2011-12-29 22:16 0在开发中,为了减少一些不必要的VO和formBean(尽管在s ... -
【转】OGNL表达式struts2标签说明
2011-12-26 22:57 1488一、什么是OGNL,有什么特点? OGNL(Objec ... -
【转】Struts2与JSON资料学习合集
2011-12-07 17:06 3984最近又搜了一些struts2和JSON的学习资料, ... -
浅谈Struts2数据下载和AJAX服务端接口的实现
2011-12-04 21:13 4024在struts2中实现文件或特 ... -
自己的修改hibernate-tools的模板和修复Comment乱码问题
2011-11-02 11:38 8056关于自定义 之前一直用hibernate-tools来 ... -
SpringSecurity备忘配置
2011-11-01 11:37 13121.定义登录后的首页action.do,该action决定了用 ... -
【转】使用 Eclipse Memory Analyzer 检测内存泄漏问题
2011-09-28 11:39 1323本文是关于在开发Talend RCP 过程中碰到 ... -
编写使用SpringSecurity的JUnit测试提醒
2011-08-15 15:40 3466近日在使用SpringSecurity的项目中发现一个小问题, ... -
【转】sun.misc.BASE64Encoder找不到的解决方法
2011-08-09 11:21 3401sun.misc.BASE64Encoder/BASE64De ... -
【转】如何在win7系统上安装Jdk版本1.6
2011-07-27 17:10 1662鉴于有些朋友对JDK的安装不太熟悉,特意转载此教程。原地址如下 ... -
我的eclipse插件推荐
2011-07-03 19:56 114601. ER图工具 ERMaster - http: ... -
分享struts2做的一个分页按钮样式
2011-06-03 01:00 1912首先是分页内容的辅助类 package cn.com. ... -
使用Jakarta Common Digester解析XML的简单例子
2011-04-19 13:36 2392Jakarta Commons Digester官方网址 ht ... -
【转】Struts2+Spring的UnitTest编写(使用StrutsTestCase的子类StrutsSpringTestCase)
2011-01-16 00:37 8917我们都知道struts2有自己的对象工厂即obe ... -
精通Hibernate读书笔记
2010-01-31 00:58 1892生成Java类 使用hibernate tools( ... -
Struts2中的EL表达式兼容问题
2009-12-29 16:33 2327今天遇到一个郁闷的问题,页面某段文字显示的时候就显示一半,查看 ... -
获取上传文件的字符编码
2009-11-10 22:50 3550重点又回到了国人都很烦恼的字符编码问题,真羡慕老外们。不过作为 ...
相关推荐
在Struts2中,自定义标签可以用来扩展JSP页面的功能,使其能够更好地与后台业务逻辑交互。 自定义标签的实现通常分为以下几个步骤: 1. **创建标签库**:定义一个XML文件(如struts-tags.xml),用于声明自定义...
一、Struts2标签库概述 Struts2的标签库是由一系列预定义的JSP标签组成的,这些标签用于处理表单、显示数据、控制流程等任务,减少了开发者编写大量Java脚本和HTML代码的工作量。它们遵循JavaServer Pages (JSP) 2.0...
Struts2标签库是Java开发Web应用程序时常用的一个强大工具,尤其在构建MVC(Model-View-Controller)架构的应用程序中发挥着重要作用。Struts2框架提供了丰富的自定义标签库,极大地简化了视图层的开发,使得开发者...
Struts 2 标签库(文档手册) Tags-API-CLSW-JSP <%@ taglib prefix="s" uri="/struts-tags" %> 就能使用struts2.0的标签库 下面就介绍每个标签的具体应用实例说明:按字母排列 A: 1. 2. <s:a href=""></s:a>-...
### SSH2中的URLRewrite与Struts2生成静态页面 #### URLRewrite的理解与应用 在SSH2(Spring + Struts2 + Hibernate)框架中,URLRewrite是一种强大的工具,可以用于实现URL重写功能,使得网站的URL更加友好、易于...
在实际项目中,通过Struts2标签,我们可以轻松实现用户界面的动态渲染,比如根据后端数据动态生成表格、列表等。同时,利用其强大的逻辑控制标签,可以简化前端的逻辑处理,提高开发效率。 7. **优化与扩展**: ...
#### 二、Struts2标签分类 根据功能的不同,Struts2中的标签可以大致分为以下几类: 1. **基本HTML标签**:如`<s:textfield>`、`<s:textarea>`等,主要用于表单元素的生成。 2. **表单标签**:如`<s:form>`,用于...
5. **Struts2配置**:在struts.xml文件中,配置一个Action映射,让Struts2知道何时调用报表生成的方法。例如: ```xml <param name="contentType">application/pdf <param name="inputName">reportStream ...
Struts 2标签库包含了大量预定义的标签,这些标签封装了常见的Web页面元素和交互逻辑,如表单控件、数据绑定、条件判断等,可以显著提高开发效率和代码质量。以下是对部分标签的详细介绍: #### `<s:a>` 标签 该...
4. **实现过程**:在Struts2中,可以通过自定义Result类型来实现静态化。这个Result类型会在Action处理完请求后,将生成的FreeMarker模板内容写入到一个静态HTML文件中。同时,需要设置适当的缓存策略,例如根据内容...
一、Struts2标签库概述 Struts2的标签库主要由两个部分组成:核心标签库和自由标签库。核心标签库提供了一些基础的控制流和数据处理功能,而自由标签库则包含了更复杂的UI组件,如表单元素、数据展示等。 1. 核心...
在"struts2+MySQL+jfreechart生成带热点"的场景中,我们可以构建一个Web应用,该应用能够从MySQL数据库中检索数据,然后使用JFreeChart生成包含热点的图表。热点是指图表上的区域,当用户点击这些区域时,可以触发...
### Struts2 S 标签库详解 #### 引言 Struts2 是一款流行的 Java Web 开发框架,它提供了一系列强大的功能来帮助开发者构建健壮的 Web 应用程序。其中,Struts2 的标签库是其核心特性之一,为开发者提供了丰富的 ...
Struts2标签详解 在Java Web开发中,Struts2框架因其强大的控制层能力而备受开发者喜爱。它提供了一套丰富的标签库,使得视图层的构建更为便捷,减轻了开发者的工作负担。本文将深入探讨Struts2标签库,帮助你更好...
`id`定义了自定义标签的脚本变量名,`name`和`scope`用于定位和访问JavaBeans,`property`用于指定bean中的特定属性。此外,Struts标签支持嵌套引用,使得处理复杂的对象结构变得简单。 **使用注意事项** 使用...
Struts2提供了一个内置的JSON插件,这个插件使得在Action中生成JSON输出变得简单。要使用JSON插件,首先需要在`struts.xml`配置文件中添加相关的配置,启用JSON结果类型。例如: ```xml ...
在本教程中,我们将深入理解Struts2标签库的各个方面。 首先,Struts2标签库由多种类型的标签组成,包括用户界面(UI)标签、表单标签、非表单标签以及非用户界面(非UI)标签。UI标签主要用于生成HTML元素,表单标签...
2. **struts2-tags-API**:这可能是Struts2标签库的中文API文档,提供了所有可用标签的详细说明,对开发者进行视图层开发非常有帮助。 通过阅读这两个资源,开发者可以全面了解Struts2框架,掌握其核心概念和使用...
- Struts2的拦截器是其一大特色,它们允许在Action执行前后插入自定义逻辑,如日志记录、权限验证、数据校验等。用户可以自由组合拦截器栈,以实现不同的业务需求。 4. **结果类型(Result Types)** - 结果类型...
2. **struts2-convention-plugin**: 这个插件实现了约定优于配置的原则,使得开发者可以不写XML配置文件,而通过类名和方法名自动映射URL。 3. **struts2-dojo-plugin**: 提供了与Dojo JavaScript库的集成,便于...