解决使用struts2标签s:url以及s:a时中文产生乱码的问题

    在平常使用web框架进行web开发时,经常讨论的一个问题就是一个中文的乱码问题。一般情况下,包括get乱码和post乱码,都能很好的解决,只需要通过配置tomcat以及增加相应的filter即可。但如果,本身tomcat并不参与解析编码时,即就不能很好地解决了。

    通常在使用一些链接时,我们偶尔会显式地传递一些中文的参数,用于显式查询。如下面的一段url地址(使用源代码查看时的链接地址):

/admin/calc/do/calcSellGoodsbyBatch.j?1=1&operation=销售&startDate=2011-07-01&endDate=2011-07-13

    这个地址在参数中直接带了一个中文的参数"销售",那么这个参数传递在服务器端时,采用的何种编码进行传递的呢。如果使用firefox,我们会看到firefox将其转化为gbk编码进行传输,如下所示:

http://localhost:4444/admin/calc/do/calcSellGoodsbyBatch.j?1=1&operation=%CF%FA%CA%DB
&startDate=2011-07-01&endDate=2011-07-13

    值得注意的是,这个转换是由firefox在界面上直接进行转换的,即在源代码中查看为"销售"的中文,在界面上转换时就自动转换成了%CF%FA%CA%DB。
    而使用ie时,则不会发生转换,也就是说,ie直接发送中文信息到服务器端,地址信息即会变为:

/admin/calc/do/calcSellGoodsbyBatch.j?1=1&operation=销售&startDate=2011-07-01&endDate=2011-07-13

    这个和在源代码中看到的是一样的。

    正常情况下,这两种情况都不会有问题,对于firefox,因为已经转换为gbk的url编码格式,在由tomcat进行转码时,会自动转换为CFFA CADB(即销售的gbk编码形式);对于ie,由于是直接发送,传递到tomcat时就是CFFA CADB的编码,经由gbk转换,自然就变成了正确的形式。即在底层发送时,对于"销售"这个中文参数值,firefox发送为%CF%FA%CA%DB,而ie发送为CFFACADB(字节流方式),两者在经由tomcat的gbk编码转换时,都没有问题。

    问题出现在哪儿,当需要在浏览器上,重现当前请求的地址时,即将刚才请求的地址信息,重新显示在界面上(通常这种应用在分页上用得多,即整个请求地址不变,只替换其中的分布参数信息)。这时候,在使用struts2的<s:url/>标签时以及<s:a/>标签时,就会出问题了。
    如在分页应用时,ie在地址栏出现的中文参数,在使用分页重新进行地址引用时,就会出现如下的结果:
    问题就出现在struts2对于url标签,在进行地址重现时的处理手段上,在解析地址信息时(通常是get形式),它并没有使用标签的getParameter形式,而是使用了getQueryString形式。

继续阅读“解决使用struts2标签s:url以及s:a时中文产生乱码的问题”

使用正确的dtd声明和entityResolver避免saxReader联网验证

    在使用许多使用xml配置文件的框架时,都会碰到以下的问题。有时候项目运行起来,需要花费许多的时间,有时候项目甚至还启动不起来。如使用hibernate时,经常报以下的错误:

org.dom4j.DocumentException: XXXXXXX
	at org.dom4j.io.SAXReader.read(SAXReader.java:484)
	at org.hibernate.cfg.Configuration.doConfigure(Configuration.java:2211)

    这是由于在hibernate中在解析xml时,默认会对所需要解析的xml进行validate,即进行验证,验证所写的xml是否符合声明格式要求。在网上搜索相关的帖子,提出的办法就是禁用掉这个验证。但是hibernate解析xml工作是在它的内部进行的,程序上不能对其进行修改;同时,既然hibernate内部使用了这个验证,即有它验证的需要,仅仅禁用掉这个验证并不能解决实际的问题。

    在hibernate3.X版本一直到hibernate3.5版本,在hibernate.xml配置文件中,一直使用的xml声明即是如下:

<!DOCTYPE hibernate-configuration PUBLIC
	"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

    而是hibernate3.6以上版本,所写的声明中的url地址就变了(当然以前的还继续有效),变成了

http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd

    这两个声明,在3.6以上版本都是可以接受了。前一声明在3.5及以前版本是正确的。但对于这个声明,如果修改了其中任意一个字符,在启动时都会报错。究其原因,则由于在对xml进行验证时,hibernate提供了一个自己实现的entityResolver。

继续阅读“使用正确的dtd声明和entityResolver避免saxReader联网验证”

解析struts2中的监测配置文件中的变化以方便开发时重新加载

    在进行开发时,经常需要修改配置文件,而修改配置文件之后,则必须要重新启动web容器,以重新启动相应的加载框架了。在项目部署时,一般不需要重新加载配置文件。而在开发时,则需要经常重新加载,因为配置文件经常需要被修改。如果重新容器的启动速度较慢,则大大地减慢了开发的速度。如果能够在修改了配置文件之后,即能够重新加载相应的对象,则相比重新启动容器要快一些了。

    在struts2中,就提供了一个在开发时,重新加载配置文件的设置。配置关键字为struts.configuration.xml.reload,当配置此值为true时,在每次请求相应的struts action时,则去判断struts2的文件是否有改变,当有改变发生时,就去重新加载相应的配置文件。这时就会将新修改的配置文件纳入到整个struts配置容器当中。

    在struts2中,负责重新加载配置文件的类由类ConfigurationManager的方法getConfiguration负责,此方法通过调用方法conditionalReload来实现重新加载配置文件,实现如下所示:

if (FileManager.isReloadingConfigs()) {
......
//判断是否需要重新加载
if(provider.needsReload()){
...
}
//准备重新加载所有的配置文件
if (reload) {
        ......
        packageProviders = configuration.reloadContainer(providers);
   }
}

    如上所示,所有的实现均由provider.needsReload()来确实,当发生有配置文件需要被重新加载时,就去重新加载所有配置文件。此方法一个实现为XmlConfigurationProvider,此实现如下所示:

public boolean needsReload() {

		for(String url : loadedFileUrls) {
			if(FileManager.fileNeedsReloading(url)) {
				return true;
			}
		}
		return false;
	}

    即最后,则最终取决于FileManager.fileNeedsReloading来确实,以下专门分析一下此文件如何来确定指定的url是否需要被改变。

继续阅读“解析struts2中的监测配置文件中的变化以方便开发时重新加载”

运用struts2和ajax进行动态对象数据的加载

    现在的项目中,存在着许多的列表选择数据,比如在一个界面中有许多的选择项。通过这些选择项是由一个select下拉列表来进行选择的,而加载这些下拉列表,除普通的在action中主动获取之外,另外一种方式进行ajax方式在界面加载时加载。
    在我们的项目中,现在运用的即是在界面加载时,通过ajax方式来加载相应的列表数据,这样的好处即是不需要在表单加载时,由处理表单的action来生成相应的列表数据,而是交给产生这个列表数据的action来加载数据。现在存在的主要问题就是,每个列表的数据来源不一样,这就导致了需要写不同的加载代码来加载这些数据,而每个加载数据的action代码分布在不同的处理action中(比如用户数据由UserAction处理,字典数据由DictionaryAction处理),而每个加载逻辑还需要根据不同的参数进行不同的service转发,而经以dao来获取数据。在界面上,相应的js加载代码也不尽相同,但大体逻辑均是相同(即获取数据,填充列表)。

继续阅读“运用struts2和ajax进行动态对象数据的加载”