xstream是个好东西。对于配置文件的读取很方便。在mybog中我就用到了。不过今天打算用yupoo的api来做相册。发现xstream对于xmlnode的attribute解析支持不是那么的好。
对于这种节点格式的非常的简单
<result>
    <page>1</page>
    <pages>1</pages>
    <perpage>100</perpage>
    <total>19</total>
    <photos>
        <photo>
            <id>ff8080810fc8ac78010fd3f158d40a52</id>
            <owner>ff8080810f1a387b010f1a83d6530dfc</owner>
            <title>Gmail-2</title>
            <host>4</host>
            <dir>20061230</dir>
            <filename>231905_1463411198</filename>
        </photo>
    </photos>
</result>
简单的alias一下就可以读到值了
File file = new File("src/test/java/com/jdkcn/test/result.xml");
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
XStream stream = new XStream();
stream.alias("result", YupooResult.class);
stream.alias("photo",YupooPhoto.class);
YupooResult result = (YupooResult)stream.fromXML(reader);
可是Yupoo的api返回的xmlrpc的结果是这样的
<result page="1" pages="1" perpage="100" total="19">
    <photos>
        <photo id="ff8080810fc8ac78010fd3f158d40a52"
            owner="ff8080810f1a387b010f1a83d6530dfc" title="Gmail-2" host="4"
            dir="20061230" filename="231905_1463411198" />
    </photos>
</result>
这样就load不到值了。没法去mailist里面找答案,果然有人问。
Hello,
I am not sure about the subject but here is what I needed help for:
XML:
<field name="value">I am a Field.</field>
I have already tried several structures and nothing seem to work.
Is this possible for XStream? :)
How is the Java class form to support this?
Thanks!
有人回答是看Converter的文档。果然找到答案了。
自己写一个converter就可以了。
下面是我的converter
package com.jdkcn.xstream;
import java.util.ArrayList;
import java.util.List;
import com.jdkcn.yupoo.YupooPhoto;
import com.jdkcn.yupoo.YupooResult;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
/**
 * @author <a href="mailto:rory.cn@gmail.com">somebody</a>
 * @since Jan 16, 2007 6:12:35 PM
 * @version $Id YupooResultConverter.java$
 */
public class YupooResultConverter implements Converter {
    /* (non-Javadoc)
     * @see com.thoughtworks.xstream.converters.Converter#marshal(java.lang.Object, com.thoughtworks.xstream.io.HierarchicalStreamWriter, com.thoughtworks.xstream.converters.MarshallingContext)
     */
    public void marshal(Object obj, HierarchicalStreamWriter writer, MarshallingContext context) {
        // FIXME unfinish.
    }
    /* (non-Javadoc)
     * @see com.thoughtworks.xstream.converters.Converter#unmarshal(com.thoughtworks.xstream.io.HierarchicalStreamReader, com.thoughtworks.xstream.converters.UnmarshallingContext)
     */
    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
        YupooResult result = new YupooResult();
        result.setPage(new Integer(reader.getAttribute("page")));
        result.setPages(new Integer(reader.getAttribute("pages")));
        result.setPerpage(new Integer(reader.getAttribute("perpage")));
        result.setTotal(new Integer(reader.getAttribute("total")));
        reader.moveDown();
        List<YupooPhoto> photos = new ArrayList<YupooPhoto>();
        while(reader.hasMoreChildren()) {
            reader.moveDown();
            YupooPhoto photo = new YupooPhoto();
            photo.setDir(reader.getAttribute("dir"));
            photo.setFilename(reader.getAttribute("filename"));
            photo.setHost(reader.getAttribute("host"));
            photo.setId(reader.getAttribute("id"));
            photo.setOwner(reader.getAttribute("owner"));
            photo.setTitle(reader.getAttribute("title"));
            photos.add(photo);
            reader.moveUp();
        }
        result.setPhotos(photos);
        return result;
    }
    /* (non-Javadoc)
     * @see com.thoughtworks.xstream.converters.ConverterMatcher#canConvert(java.lang.Class)
     */
    public boolean canConvert(Class clazz) {
        return clazz.equals(YupooResult.class);
    }
}
然后调用的地方修改一下就ok了。
XStream stream = new XStream();
stream.registerConverter(new YupooResultConverter());
stream.alias("result", YupooResult.class);
参考:
http://xstream.codehaus.org/converter-tutorial.html
2007年1月18日更新。
这里感谢网友  的提示。原来新版的xstream可以简单的解决了。在1.2.1的doc里面找到了这个两个方法。
useAttributeFor
public void useAttributeFor(java.lang.String fieldName,
                            java.lang.Class type)- Use an XML attribute for a field or a specific type. 
- Parameters:
- fieldName- the name of the field
- type- the Class of the type to be rendered as XML attribute
- Throws:
- XStream.InitializationException- if no- AttributeMapperis available
- Since:
- 1.2
 
useAttributeFor
public void useAttributeFor(java.lang.Class type)
- Use an XML attribute for an arbotrary type. 
- Parameters:
- type- the Class of the type to be rendered as XML attribute
- Throws:
- XStream.InitializationException- if no- AttributeMapperis available
- Since:
- 1.2
 
这两个方法都是从1.2开始支持的。
也不用自己写converter了。这样就可以了
        stream.alias("result", YupooResult.class);
        stream.useAttributeFor("page", Integer.class);
        stream.useAttributeFor("pages", Integer.class);
        stream.useAttributeFor("perpage", Integer.class);
        stream.useAttributeFor("total", Integer.class);
        stream.alias("photo", YupooPhoto.class);
        stream.useAttributeFor("id", String.class);
        stream.useAttributeFor("owner", String.class);
        stream.useAttributeFor("title", String.class);
        stream.useAttributeFor("host", String.class);
        stream.useAttributeFor("dir", String.class);
        stream.useAttributeFor("filename", String.class);

   除经特别注明外,本文章版权归
莫多泡泡所有. 
署名,非商业用途,保持一致.   somebody(莫多)
			posted @ 
2007-01-17 18:24 莫多 阅读(8031) | 
评论 (2) | 
编辑 收藏  上周更新了一下myblog,添加了一个Filter,做统计访问用。可是后来发现出现乱码问题了。找了很久都没有找到问题。debug的时候看到 CharacterEncodingFilter确实是执行了。不过就是没有效果。执行之前是ISO-8859-1编码的,执行之后还是, CharacterEncodingFilter就没有起到作用。后来终于找到问题的原因了。原来是Filter配置先后顺序的原因。
       刚开始的配置是这样的:
		
				    
				<
				filter-mapping
				>
				
						
        
				<
				filter-name
				>
				requestCounterFilter
				</
				filter-name
				>
				
						
        
				<
				url-pattern
				>
				*.jhtml
				</
				url-pattern
				>
				
						
    
				</
				filter-mapping
				>
				
				
				
						
								
   
    
						<
						filter-mapping
						>
						
								
        
						<
						filter-name
						>
						encodingFilter
						</
						filter-name
						>
						
								
        
						<
						url-pattern
						>
						/dwr/*
						</
						url-pattern
						>
						
								
    
						</
						filter-mapping
						>
						
								
    
    
						<
						filter-mapping
						>
						
								
        
						<
						filter-name
						>
						encodingFilter
						</
						filter-name
						>
						
								
        
						<
						url-pattern
						>
						*.jhtml
						</
						url-pattern
						>
						
								
    
						</
						filter-mapping
						>
						
								
    
    
						<
						filter-mapping
						>
						
								
        
						<
						filter-name
						>
						encodingFilter
						</
						filter-name
						>
						
								
        
						<
						url-pattern
						>
						*.jsp
						</
						url-pattern
						>
						
								
    
						</
						filter-mapping
						>
				
		
		  先经过那个统计的filter然后再经过编码的filter。这样的话编码的filter就不起作用了。只要吧编码的filter放到最前面就没有问题了。改成这样就好。
		
				    
				<
				filter-mapping
				>
				
						
        
				<
				filter-name
				>
				encodingFilter
				</
				filter-name
				>
				
						
        
				<
				url-pattern
				>
				/dwr/*
				</
				url-pattern
				>
				
						
    
				</
				filter-mapping
				>
				
						
    
    
				<
				filter-mapping
				>
				
						
        
				<
				filter-name
				>
				encodingFilter
				</
				filter-name
				>
				
						
        
				<
				url-pattern
				>
				*.jhtml
				</
				url-pattern
				>
				
						
    
				</
				filter-mapping
				>
				
						
    
    
				<
				filter-mapping
				>
				
						
        
				<
				filter-name
				>
				encodingFilter
				</
				filter-name
				>
				
						
        
				<
				url-pattern
				>
				*.jsp
				</
				url-pattern
				>
				
						
    
				</
				filter-mapping
				>
				
						
    
    
				<
				filter-mapping
				>
				
						
        
				<
				filter-name
				>
				requestCounterFilter
				</
				filter-name
				>
				
						
        
				<
				url-pattern
				>
				*.jhtml
				</
				url-pattern
				>
				
						
    
				</
				filter-mapping
				>
		
		
				
以后大家一定要注意啊。顺序问题也是很重要的。
 除经特别注明外,本文章版权归莫多泡泡所有.
   除经特别注明外,本文章版权归莫多泡泡所有. 
署名,非商业用途,保持一致.   somebody(莫多)
			posted @ 
2006-12-27 10:37 莫多 阅读(2720) | 
评论 (3) | 
编辑 收藏
			昨天晚上配置myblog的rewrite。发现一个奇怪的问题。由于现在使用的这个pjblog,为了让搜索引擎收录的连接有效。我想把原来的asp连接rewrite到我的新程序上面。所以有这样一条规则。
    <rule>
        <from>^/article.asp\?id=(.*)$</from>
        <to type="redirect">/entry/$1.jhtml</to>
    </rule>
     但是我这样的连接总是匹配不到,只要去掉那个?就可以了。这个正则表达式是没有问题的。/article.asp?id=64是可以匹配的到的。
    后来看3.0的manual (http://tuckey.org/urlrewrite/manual/3.0/)才发现原来是这个的问题。
<urlrewrite> element
The top level element.
| Attribute | Possible Value | Explanation | 
|---|
| default-match-type (optional)
 | regex (default) | All rules and thier conditions will be processed using the Java Regular Expression engine (unless match-typeis specified on a rule). | 
| wildcard | All rules and thier conditions will be processed using the Wildcard Expression engine (unless match-typeis specified on a rule). | 
| decode-using (optional)
 | utf8 (default) | When URL is decoded UTF-8 will be used. | 
| null | Do not decode. | 
| [encoding] | Any string representing a supported character encoding eg, ISO-8859-1. See Java Charset Object for more info. | 
| use-query-string (optional)
 | false (default) | The query string will not be appended to the url that the "from" element matches against. | 
| true | The query string will be appended to the url that the "from" element matches against. | 
| use-context (optional)
 | false (default) | The context path will not be added to the url that the "from" element matches against. | 
| true | The context path will be added to the url that the "from" element matches against. | 
就是那个use-query-string 的问题,默认的是不使用query-string就是把?后面的都忽略了。所以就不能匹配到了。只要在<urlrewrite>里面加一个属性就可以了。
<urlrewrite use-query-string="true">
    
</urlrewrite>  除经特别注明外,本文章版权归莫多泡泡所有.
   除经特别注明外,本文章版权归莫多泡泡所有. 
署名,非商业用途,保持一致.   somebody(莫多)
			posted @ 
2006-12-12 10:33 莫多 阅读(2375) | 
评论 (0) | 
编辑 收藏      我们的项目用到了xmlrpc,不过还是用的2.x版本的。由于xmlrpc3.x地推出。提供了NULL,Serializable等的支持,将原来的Hashtable改成了Map,Vector改成了List。都是不错的进步。所以我们决定从xmlrpc2.x升级到xmlrpc3.x.
      在spring里面有几个ServiceExporter,org.springframework.remoting.rmi.RmiServiceExporter、org.springframework.remoting.caucho.HessianServiceExporter、org.springframework.remoting.caucho.BurlapServiceExporter。不过没有xmlrpc的serviceExporter,原来我们是自己封装的XmlRpcServer,用servlet提供服务。(eg:http://localhost:8080/community/service/xmlrpc)没有和spring集成虽然用了spring。
    考虑到spring的便利以及配置的同意我决定将xmlrpcService放入spring中。xmlrpc3.x和xmlrpc2.x的代码基本上没有一样的。改了很多东西。除了类型变化之外,还添加了对异常的支持。详细信息请参照xmlrpc3.x源代码。
XmlRpcServiceExporter.java
		
				package
				 com.jdkcn.xmlrpc;
				import
				 javax.servlet.ServletException;
				/**
				
						
 * 
				@author
				 <a href="mailto:rory.cn@gmail.com">somebody</a>
 * 
				@since
				 2006-9-27 03:59:22 pm
 * 
				@version
				 $Id XmlRpcServiceExporter.java$
 
				*/
				
						
				
				public
				 
				class
				 XmlRpcServiceExporter 
				extends
				 RemoteExporter 
				implements
				
						
        Controller, InitializingBean {
    
    
				private
				 XmlRpcServletServer server;
    
    
				public
				 String serviceName;
    
    
				public
				 Resource configFile;
    
    
				public
				 Boolean enabledForExtensions;
    
    
				public
				 
				void
				 setEnabledForExtensions(Boolean enabledForExtensions) {
        
				this
				.enabledForExtensions 
				=
				 enabledForExtensions;
    }
    
				public
				 
				void
				 setConfigFile(Resource configFile) {
        
				this
				.configFile 
				=
				 configFile;
    }
    
				public
				 String getServiceName() {
        
				return
				 serviceName;
    }
    
				public
				 
				void
				 setServiceName(String serviceName) {
        
				this
				.serviceName 
				=
				 serviceName;
    }
    
				public
				 XmlRpcServletServer getXmlRpcServletServer() {
        
				return
				 server;
    }
    
    
				/*
				 (non-Javadoc)
     * @see org.springframework.web.servlet.mvc.Controller#handleRequest(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
     
				*/
				
						
    
				public
				 ModelAndView handleRequest(HttpServletRequest request,
            HttpServletResponse response) 
				throws
				 Exception {
        
				if
				 (
				!
				WebContentGenerator.METHOD_POST.equals(request.getMethod())) {
            
				throw
				 
				new
				 ServletException(
				"
				XmlRpcServiceExporter only supports POST requests
				"
				);
        }
        server.execute(request, response);
        
				return
				 
				null
				;
    }
    
				/*
				 (non-Javadoc)
     * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
     
				*/
				
						
    
				public
				 
				void
				 afterPropertiesSet() 
				throws
				 Exception {
        server 
				=
				 
				new
				 XmlRpcServletServer();
        server.setHandlerMapping(newXmlRpcHandlerMapping());
        
				if
				 (enabledForExtensions
				!=
				null
				) {
            ((XmlRpcServerConfigImpl) server.getConfig()).setEnabledForExtensions(enabledForExtensions.booleanValue());
        }
        
    }
    
				/**
				 Creates a new handler mapping. The default implementation loads
     * a property file from the resource
     * 
     
				*/
				
						
    
				protected
				 XmlRpcHandlerMapping newXmlRpcHandlerMapping() 
				throws
				 XmlRpcException {
        
        SpringHandlerMapping mapping 
				=
				 
				new
				 SpringHandlerMapping(getServiceInterface());
        mapping.addHandler(getServiceName(), getServiceInterface());
        mapping.setTagetObject(getProxyForService());
        
				return
				 mapping;
    }
    
}
		
		spring配置文件
 <bean id="accountService"  class="com.jdkcn.service.impl.AccountServiceImpl">
    <bean id="accountService"  class="com.jdkcn.service.impl.AccountServiceImpl">
 </bean>
    </bean>
 <bean name="rpcAccountService" class="com.jdkcn.xmlrpc.XmlRpcServiceExporter">
        <bean name="rpcAccountService" class="com.jdkcn.xmlrpc.XmlRpcServiceExporter">
 <property name="service">
        <property name="service">
 <ref bean="accountService"/>
            <ref bean="accountService"/>
 </property>
        </property>
 <property name="serviceName">
        <property name="serviceName">
 <value>jdkcn.accountService</value>
            <value>jdkcn.accountService</value>
 </property>
        </property>
 <property name="enabledForExtensions">
        <property name="enabledForExtensions">
 <value>true</value>
            <value>true</value>
 </property>
        </property>
 <property name="serviceInterface">
        <property name="serviceInterface">
 <value>com.jdkcn.service.AccountService</value>
            <value>com.jdkcn.service.AccountService</value>
 </property>
        </property>
 </bean>
    </bean>然后映射一个地址就可以通过xmlrpc访问服务了
    <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props> 
                <prop key="/account">rpcAccountService</prop>
            </props>
        </property>
    </bean>
web.xml
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:spring/global.xml
        </param-value>
    </context-param>
    
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
        <servlet>
            <servlet-name>service</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>service</servlet-name>
            <url-pattern>/service/xmlrpc3/*</url-pattern>
        </servlet-mapping>
然后我们的service地址就是这样的http://localhost:8080/service/xmlrpc3/account
希望对大家有用,这里提供project下载。包含一个client程序。com.jdkcn.xmlrpc.Client
 点击下载完整代码
点击下载完整代码
   除经特别注明外,本文章版权归
莫多泡泡所有. 
署名,非商业用途,保持一致.   somebody(莫多)
			posted @ 
2006-10-22 16:12 莫多 阅读(2207) | 
评论 (0) | 
编辑 收藏
			不知道大家有没有碰到,还是没有这种需求。就是用like来查询,我们没有用Lucene,Compass这种全文索引的方案,我们只是简单的添加%进行like查询。用户搜索的时候就使用*和?来代表任意和一个。所以要对"%"和"_"进行转义,我们使用的是oracle数据库。sql语句看起来可能是这样的。
SELECT * FROM t_user where nickname like '%Goo\_D' escape '\'
这里对_进行转义了。因为用户昵称包含下划线,如果不进行转义就表示一个任意字符。有时候我们可能还需要对%进行转义。同样的方法在%前加\% 但是比起普通的like语句。多了一个声明转义符的语句。所以我们会想到这样的语句
DetachedCriteria criteria = DetachedCriteria.forClass(User.class);
criteria.add(Restrictions.like("nickname", user.getNickname()+"' escape'\"));
但是这样是不管用的。
接下来可能会想到使用Hibernate3的原生sql查询,其实我们不需要这样做。我们还是使用Criteria条件查询。
criteria.add(Restrictions.sqlRestriction("{alias}.nickname like ? escape'/'", StringUtil.escapeSQLLike(user.getNickname()), Hibernate.STRING));
这样Hibernate产生的语句就是我们想要的语句了。
    /**
     * 转义like语句中的
     * <code>'_'</code><code>'%'</code>
     * 将<code>'?'</code>转成sql的<code>'/_'</code>
     * 将<code>'%'</code>转成sql的<code>'/%'</code>
     * <p>
     *   例如搜索<code>?aa*bb?c_d%f</code>将转化成<br/>
     *   <code>_aa%bb_c/_d/%f</code>
     * </p>
     * @param likeStr
     * @return
     * @author <a href="http://jdkcn.com">somebody</a>
     */
    public static String escapeSQLLike(String likeStr) {
        String str = StringUtils.replace(likeStr, "_", "/_");
        str = StringUtils.replace(str, "%",    "/%");
        str = StringUtils.replace(str, "?", "_");
        str = StringUtils.replace(str, "*", "%");
        return str;
    }

   除经特别注明外,本文章版权归
莫多泡泡所有. 
署名,非商业用途,保持一致.   somebody(莫多)
			posted @ 
2006-10-16 23:29 莫多 阅读(2514) | 
评论 (1) | 
编辑 收藏  jspark 的这篇文章《开发阶段eclipse下面的spring容器的启动优化 》讲到如何加快spring的启动速度。非常感谢jspark. 一下是引用的原文:
  最近在负责一个大项目,项目组成员包括项目经理大概10个人左右。项目技术用struts+spring+hibernate实现。项目的规模相对来说是比较大的,总共有10大模块,每个大模块又分为有十几个、甚至几十个小模块。开发工具用eclipse,由于在开发阶段,项目开发成员需要频繁重启服务器。在启动服务器的时候,每次启动时间总是会超过1分钟。记得以前在做另外一个项目时,启动时间不到5秒钟,相差了10倍,而且项目规模是差不多的。
    从初步分析来说,应该是hibernate解释hbm.xml时花费时间,或者可能是spring容器启动并解释所有的bean配置文件。诊断了一下,发现1分钟消耗的时间主要分布在hibernate解释hbm.xml花费5秒;spring容器从启动到解释bean配置文件竟然花了58秒,真是太嚣张了。当时非常怀疑spring的效率问题。企图从网上搜索相关资料,看看有什么优化措施。
    首先是找到了hibernate的启动优化 http://www.hibernate.org/194.html  里面的主要思想是通过将xml序列花到本地的文件里,每次读取的时候根据情况,从本地文件读取并反序列化,节省了hibernate xml的解析时间。按照这个方式测试了一下,发现hibernate的启动时间从5秒降低到3秒,但是这个优化对于整个启动过程是杯水车薪的,毫无用处。
    没办法,又仔细查看了spring的资料,终于发现spring的容器是提供了lazy-load的,即默认的缺省设置是bean没有lazy- load,该属性处于false状态,这样导致spring在启动过程导致在启动时候,会默认加载整个对象实例图,从初始化ACTION配置、到 service配置到dao配置、乃至到数据库连接、事务等等。这么庞大的规模,难怪spring的启动时间要花将近1分钟。尝试了一下,把beans的 default-lazy-init改为true就,再次启动,速度从原来的55秒,降到8秒钟!!Great!虽然是非常小一个改动,但是影响确实非常大。一个项目组10个人,假若每个人一天平均需要在eclipse下启动测试服务器50次。那么一天项目组需要重启500次,每次节省50秒的话,就是 25000秒,将近几个小时,差不多一个工作日,多么可观的数字!
   不过在运行期间第一次点页面的时候,由于spring做了lazy-load,现在就需要启动一部分需要的beans,所以稍微慢2-3秒钟,但是明显比等几十秒要快很多,值得一鉴。
    以上是针对开发阶段的spring容器启动优化,在部署到实际环境中,倒是没必要设置为lazy-load。毕竟部署到实际环境中不是经常的事,每次启动1分钟倒不是大问题。 
我这里要提醒的是不是说有的beans都能设置default-lazy-init成为true.对于scheduler的bean不能用lazy-init
		
				<
				beans 
				default-lazy-init
				="true"
				>
				
						
    
    
				<
				bean 
				class
				="org.springframework.scheduling.quartz.SchedulerFactoryBean"
				>
				
						
        
				<
				property 
				name
				="triggers"
				>
				
						
            
				<
				list
				>
				
						
                
				<
				ref 
				bean
				="buildHtmlTrigger"
				/>
				
						
                
				<
				ref 
				bean
				="askTrigger"
				/>
				
						
                
				<
				ref 
				bean
				="mailSenderTrigger"
				/>
				
						
                
				<
				ref 
				bean
				="topicDetailBuildTrigger"
				/>
				
						
                
				<
				ref 
				bean
				="forumBuildTrigger"
				/>
				
						
                
				<
				ref 
				bean
				="topicBuildTrigger"
				/>
				
						
            
				</
				list
				>
				
						
        
				</
				property
				>
				
						
    
				</
				bean
				>
				
						
				
				</
				beans
				>
		
		
				
				
				
这样的话。所有的scheduler就都不管用了。所以请大家要注意。
		
				<
				beans
				
				
				
				
				>
				
						
    
    
				<
				bean 
				class
				="org.springframework.scheduling.quartz.SchedulerFactoryBean"
				>
				
						
        
				<
				property 
				name
				="triggers"
				>
				
						
            
				<
				list
				>
				
						
                
				<
				ref 
				bean
				="buildHtmlTrigger"
				/>
				
						
                
				<
				ref 
				bean
				="askTrigger"
				/>
				
						
                
				<
				ref 
				bean
				="mailSenderTrigger"
				/>
				
						
                
				<
				ref 
				bean
				="topicDetailBuildTrigger"
				/>
				
						
                
				<
				ref 
				bean
				="forumBuildTrigger"
				/>
				
						
                
				<
				ref 
				bean
				="topicBuildTrigger"
				/>
				
						
            
				</
				list
				>
				
						
        
				</
				property
				>
				
						
    
				</
				bean
				>
				
						
				
				</
				beans
				>
		
		
				
 
			posted @ 
2006-08-10 10:59 莫多 阅读(3349) | 
评论 (2) | 
编辑 收藏     虽然项目全部采用了UTF-8编码,所有的源文件*.java,*.jsc,*.html,*.ftl都采用了UTF-8编码。可是还是出现了乱码问题。很是不爽,后来找到了tomcat,和resin的配置。
		
				- Tomcat的配置。(conf/server.xml)
     <!-- Define a non-SSL HTTP/1.1 Connector on port 8080 -->
 <Connector port="80" maxHttpHeaderSize="8192"
 maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
 enableLookups="false" redirectPort="8443" acceptCount="100"
 connectionTimeout="20000" disableUploadTimeout="true" URIEncoding="UTF-8"/>
 
- Resin的配置。(conf/resin.conf)
 | character-encoding | Resin 1.1 |  
 child of: resin, server, host-default, host, web-app-default, web-app default: The default value is ISO-8859-1. Specifies the default character encoding for the environment. | <web-app id='/'>
  <character-encoding>shift_jis</character-encoding>
  ...
</web-app>
 |  
 
 
		
		     这个是resin doc里面的我是在web-app-default里面加上了encoding的配置
		
		
		
				 <
				web-app-default
				>
				    
				<
				web-app-default
				>
				
						
						 <
				character-encoding
				>
				UTF-8
				</
				character-encoding
				>
      
				<
				character-encoding
				>
				UTF-8
				</
				character-encoding
				>
				
						
						 
      
 </
				web-app-default
				>
    
				</
				web-app-default
				>
		 
		希望对你的项目有帮助。
		
				
						 除经特别注明外,本文章版权归莫多泡泡所有.
				   除经特别注明外,本文章版权归莫多泡泡所有. 
署名,非商业用途,保持一致.   somebody(莫多)   
			posted @ 
2006-07-22 18:13 莫多 阅读(1877) | 
评论 (4) | 
编辑 收藏
			项目中多个项目需要同时引用一个静态资源,所以就想到配置不同的虚拟目录指到同一个目录。于是有下面的配置:
    <!-- configures the default host, matching any host name -->
    <host id="" root-directory=".">
      <!--
         - configures an explicit root web-app matching the
         - webapp's ROOT
        -->
      <web-app id="/" document-directory="webapps/ROOT"/>
      <web-app id="/community/jsvm2" document-directory="D:\\projects\\FelooComponents\\jsvm2"/>
      <web-app id="/passport/jsvm2" document-directory="D:\\projects\\FelooComponents\\jsvm2"/>
    </host>
       但是发现这样只有后面一个管用(http://localhost:8080/passport/jsvm2)这个是可以,可是(http://localhost:8080/community/jsvm2)就不行,很是郁闷。只要后面的document-directory不是同一个目录就成。
       后来在resin的doc里面看到path的配置
path-mapping
child of: web-app-default, web-app
Maps url patterns to real paths. If using a server like IIS, you may need to match the server's path aliases.
| Attribute | Meaning | default | 
|---|
| url-pattern | A pattern matching the url: /foo/*, /foo, or *.foo | 
| url-regexp | A regular expression matching the url | 
| real-path | The prefix of the real path. When used with url-regexp, allows substitution variables like $1. | 
| <web-app id='/'>
            <path-mapping url-pattern='/resin/*'
            real-path='e:\resin'/>
            <path-mapping url-regexp='/~([^/]*)'
            real-path='e:\home$1'/>
            </web-app>
             | 
 改正这样的配置就ok了。
        <web-app id="/community" document-directory="D:\\projects\\FelooCommunityWeb">
          <path-mapping url-pattern='jsvm2/*'
              real-path='D:\\projects\\FelooComponents\\jsvm2'/>
      </web-app>
      
            <web-app id="/passport" document-directory="D:\\projects\\FelooPassportWeb">
          <path-mapping url-pattern='jsvm2/*'
              real-path='D:\\projects\\FelooComponents\\jsvm2'/>
      </web-app>

   除经特别注明外,本文章版权归
莫多泡泡所有. 
署名,非商业用途,保持一致.   somebody(莫多)
			
posted @ 
2006-07-18 19:41 莫多 阅读(2925) | 
评论 (0) | 
编辑 收藏自从换工作之后就没有研究过DWR了。下载了最新的DWR2.0M2版本。2.0加了很多东西,也有不少变化的地方。最容易看到的变化就是包名的变化了,由 uk.ltd.getahead 变成了 org.directwebremoting 。
        换上了新的配置
		
				    
				<
				servlet
				>
				
						
        
				<
				servlet-name
				>
				dwr-invoker
				</
				servlet-name
				>
				
						
        
				<
				servlet-class
				>
				org.directwebremoting.servlet.DwrServlet
				</
				servlet-class
				>
				
						
        
				<
				init-param
				>
				
						
          
				<
				param-name
				>
				debug
				</
				param-name
				>
				
						
          
				<
				param-value
				>
				true
				</
				param-value
				>
				
						
        
				</
				init-param
				>
				
						
        
				<
				load-on-startup
				>
				1
				</
				load-on-startup
				>
				
						
    
				</
				servlet
				>
		
		启动服务,抱错了。
		java.lang.IllegalArgumentException: DefaultContainer can't find a classes
       at org.directwebremoting.impl.DefaultContainer.getBean(DefaultContainer.java:216)
       at org.directwebremoting.annotations.AnnotationsConfigurator.configure(AnnotationsConfigurator.java:50)
       at org.directwebremoting.servlet.DwrServlet.init(DwrServlet.java:121)
		      在DWR的Maillist里面搜索了一下,还有答案,原来DWR2.0 加入了JDK5的注释(annotations).DwrServlet初始化的时候会去检查注释的类,找不到就抱错了。如果你不用annotations也可以忽略掉这个错误。不过看起来总是不爽。有人提出了方案。这样就ok了。
		
				    
				<
				servlet
				>
				
						
        
				<
				servlet-name
				>
				dwr-invoker
				</
				servlet-name
				>
				
						
        
				<
				servlet-class
				>
				org.directwebremoting.servlet.DwrServlet
				</
				servlet-class
				>
				
						
        
				<
				init-param
				>
				
						
          
				<
				param-name
				>
				debug
				</
				param-name
				>
				
						
          
				<
				param-value
				>
				true
				</
				param-value
				>
				
						
        
				</
				init-param
				>
				
						
        
				<
				init-param
				>
				
						
           
				<
				param-name
				>
				classes
				</
				param-name
				>
				
						
           
				<
				param-value
				>
				java.lang.Object
				</
				param-value
				>
				
						
        
				</
				init-param
				>
				
						
        
				<
				load-on-startup
				>
				100
				</
				load-on-startup
				>
				
						
    
				</
				servlet
				>
		
		
				
						 除经特别注明外,本文章版权归莫多泡泡所有.
				   除经特别注明外,本文章版权归莫多泡泡所有. 
署名,非商业用途,保持一致.   somebody(莫多)   
			posted @ 
2006-07-17 02:11 莫多 阅读(2900) | 
评论 (0) | 
编辑 收藏
			首先感谢JScud提供的好文章。《
使用FreeMarker生成Html静态文件(实例)》
      在我们的项目中也用到了Freemarker生成静态文件。不过这里我要说的是编码的问题。我们的项目使用的都是UTF-8编码,我直接使用 飞云小侠 提供的方法生成的文件在UTF-8编码下察看是乱码,而GBK正常(后来发现因为我用的中文操作系统所以用GBK查看正常)。
      当然我把Freemarker的配置都改成了UTF-8,我的模版文件也是UTF-8编码的。下面是原来的代码
    public void setTemplatePath(Resource templatePath) {
        this.templatePath = templatePath;
        //设置freemarker的参数
        freemarkerCfg = new Configuration();
        try {
            freemarkerCfg.setDirectoryForTemplateLoading(this.templatePath.getFile());
            freemarkerCfg.setObjectWrapper(new DefaultObjectWrapper());
            freemarkerCfg.setDefaultEncoding("UTF-8");
        } catch (IOException ex) {
            throw new SystemException("No Directory found,please check you config.");
        }
    }
    /**
     * 生成静态文件
     * @param templateFileName 模版名称eg:(biz/order.ftl)
     * @param propMap 用于处理模板的属性Object映射 
     * @param htmlFilePath 要生成的静态文件的路径,相对设置中的根路径,例如 "/biz/2006/5/" 
     * @param htmlFileName 要生成的文件名,例如 "123.htm" 
     * @return
     */
    private boolean buildHtml(String templateFileName,Map propMap, String htmlFilePath,String htmlFileName){
        try {
            Template template = freemarkerCfg.getTemplate(templateFileName);
            template.setEncoding("UTF-8");
            //创建生成文件目录
            creatDirs(buildPath.getFilename(),htmlFilePath);
            File htmlFile = new File(buildPath + htmlFilePath + htmlFileName);
            Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(htmlFile)));
            template.process(propMap,out);
            out.flush();
            return true;
        } catch (TemplateException ex){
            log.error("Build Error"+templateFileName,ex);
            return false;
        } catch (IOException e) {
            log.error("Build Error"+templateFileName,e);
            return false;
        }
        
    }
下面是修改之后的代码
    /**
     * 生成静态文件
     * @param templateFileName 模版名称eg:(biz/order.ftl)
     * @param propMap 用于处理模板的属性Object映射 
     * @param htmlFilePath 要生成的静态文件的路径,相对设置中的根路径,例如 "/biz/2006/5/" 
     * @param htmlFileName 要生成的文件名,例如 "123.htm" 
     * @return
     */
    private boolean buildHtml(String templateFileName,Map propMap, String htmlFilePath,String htmlFileName){
        try {
            Template template = freemarkerCfg.getTemplate(templateFileName);
            template.setEncoding("UTF-8");
            //创建生成文件目录
            creatDirs(buildPath.getFilename(),htmlFilePath);
            File htmlFile = new File(buildPath + htmlFilePath + htmlFileName);
            Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(htmlFile),"UTF-8"));
            template.process(propMap,out);
            out.flush();
            return true;
        } catch (TemplateException ex){
            log.error("Build Error"+templateFileName,ex);
            return false;
        } catch (IOException e) {
            log.error("Build Error"+templateFileName,e);
            return false;
        }
        
    }
原因就在于OutputStreamWriter的不同构造方法
OutputStreamWriter(OutputStream out)
          创建使用默认字符编码的 OutputStreamWriter。
OutputStreamWriter(OutputStream out, String charsetName)
          创建使用指定字符集的 OutputStreamWriter。
 这个是中文JDK的文档说明,刚开始我使用默认的构造函数,所以使用了系统默认的编码,GBK,所以在生成静态文件的时候把UTF-8内容用GBK编码写入了,所以在UTF-8下浏览就有问题。
还有关于修改模版文件同样也要注意这个问题。
    public String loadTemplate(String templateName) {
        StringBuffer sb = new StringBuffer();
        try {
            File file = new File(templatePath+"/"+templateName);
            BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file),"UTF-8"));
            String line = reader.readLine();
            while(line != null)    {
                sb.append(line);
                sb.append("\r\n");
                line = reader.readLine();
            }
            reader.close();
        } catch (IOException e) {
            throw new SystemException("Loading template Error:",e);
        }
        return sb.toString();
    }
    public void saveTemplate(String templateName, String templateContent) {
        try {
            File file = new File(templatePath + "/" + templateName);
            Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file),"UTF-8"));
            out.write(templateContent);
            out.flush();
            //扔出templatesave事件
            TemplateSaveEvent evt = new TemplateSaveEvent();
            evt.setTemplateName(templateName);
            dispatchTemplateEvent(evt);
        } catch (IOException e) {
            throw new SystemException("Write template Error",e);
        }
    }
 | posted @ 
2006-06-21 10:46 莫多 阅读(2882) | 
评论 (0) | 
编辑 收藏
			在以前的项目中对于一些资源的配置基本上都是通过spring的IOC注入一个目录的地址字符串。而这样的问题是,对于开发中的团队来说还是很有问题的,因为每个可能都配置一个不同的本地目录,而发布到服务器之后又有不同的目录。这样造成每个人提交了配置文件之后其他人都可能需要修改配置文件才能正确启动服务。这确实很令人烦劳。
     最近看《Professional Java Development with the Spring Framework》时看到了spring对底层资源的抽象,才找到了完美解决方案。
     原来的代码:
    private String templatePath;
    public void setTemplatePath(String templatePath) {
        this.templatePath = templatePath;
    }
    public void initListener() {
        TemplateEventListener templateListener = new TemplateEventListener(){
            public void handleTemplateEvent(TemplateEventSupport evt) {
                // 添加事件到队列中
                queue.offer(evt);
                if(log.isDebugEnabled()){
                    log.debug("Add Template about:" + evt.getTemplateName());
                }
            }
            
        };
        
        //注册模版监听事件
        templateManager.addEventListener(Constants.TEMPLATE_SAVE_EVENT, templateListener,false);
        
        
        //设置freemarker的参数
        freemarkerCfg = new Configuration();
        try {
            freemarkerCfg.setDirectoryForTemplateLoading(new File(templatePath));
            freemarkerCfg.setObjectWrapper(new DefaultObjectWrapper());
            freemarkerCfg.setDefaultEncoding("UTF-8");
        } catch (IOException ex) {
            throw new SystemException("No Directory found,please check you config.");
        }
    }
配置文件

 <bean id="buildHtmlService" class="cn.jdk.leaf.service.impl.BuildHtmlServiceImpl" init-method="initListener">
    <bean id="buildHtmlService" class="cn.jdk.leaf.service.impl.BuildHtmlServiceImpl" init-method="initListener">
 <property name="templatePath"><value>${templatePath}</value></property>
        <property name="templatePath"><value>${templatePath}</value></property>
 </bean>
    </bean>templatePath.path=D:/template
使用spring对底层资源的抽象只要把templatePath改成Resource就可以了
    private Resource templatePath;
    public void setTemplatePath(Resource templatePath) {
        this.templatePath = templatePath;
    }
    public void initListener() {
            TemplateEventListener templateListener = new TemplateEventListener(){
            public void handleTemplateEvent(TemplateEventSupport evt) {
                // 添加事件到队列中
                queue.offer(evt);
                if(log.isDebugEnabled()){
                    log.debug("Add Template about:" + evt.getTemplateName());
                }
            }
            
        };    
        //注册模版监听事件
        templateManager.addEventListener(Constants.TEMPLATE_SAVE_EVENT, templateListener,false);
        
        
        //设置freemarker的参数
        freemarkerCfg = new Configuration();
        try {
            freemarkerCfg.setDirectoryForTemplateLoading(templatePath.getFile());
            freemarkerCfg.setObjectWrapper(new DefaultObjectWrapper());
            freemarkerCfg.setDefaultEncoding("UTF-8");
        } catch (IOException ex) {
            throw new SystemException("No Directory found,please check you config.");
        }
    }
bean的配置不变,只要修改properties文件就可以了。
    <bean id="buildHtmlService" class="cn.jdk.leaf.service.impl.BuildHtmlServiceImpl" init-method="initListener">
        <property name="templatePath"><value>${templatePath}</value></property>
    </bean>
把properties文件修改成
templatePath.path=template
在webcontext目录下面建立一个template目录就可以了。在部署到服务器的时候需要部署到一个特定的目录只要修改这个配置文件为
templatePath.path=file:/D:/template
这样就可以了。
|   | 除经特别注明外,本文章版权归莫多泡泡所有. 署名,非商业用途,保持一致.   somebody(莫多)
 | 
			posted @ 
2006-06-11 23:01 莫多 阅读(1902) | 
评论 (2) | 
编辑 收藏
			上篇文章:《
今天发现一个hibernate的bug,或者说一个应该注意的地方比较合适 》里面我提到了Hibernate查询需要注意的一个问题。今天发现了一个最好的解决办法。如果大家现在用Hibernate,相信大家都回用到DetachedCriteria.关于DetachedCriteria查询请查看
http://dev.yesky.com/241/2033241.shtml。
      DetachedCriteria给我们的Hibernate查询带来了很多方便,但是如果你带上排序信息就会出现我的上一篇文章里面说的那种错误,今天发现一个很好的解决方法,其实也很简单。就是先把传入的带Order信息的DetachedCriteria去掉order信息查询数据总条数,然后再把Order加回来查询满足条件的对象。通过查看Hibernate的源代码发现Criteria的实现CriteriaImpl发现其实addOrder是给private List orderEntries = new ArrayList();这个List加值。这个List里面放的是OrderEntry对象。这个OrderEntry里面放了一个criteria 和 order.     
    public PaginationSupport findPageByCriteria(final DetachedCriteria detachedCriteria, final int pageSize, final int startIndex) {
        return (PaginationSupport) getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException {
                Criteria criteria = detachedCriteria.getExecutableCriteria(session);
                CriteriaImpl impl = (CriteriaImpl) criteria;
                List orderEntrys = new ArrayList();
                try{
                    Field field = CriteriaImpl.class.getDeclaredField("orderEntries");
                    //Get orders
                    orderEntrys = (List) field.get(impl);
                    //Remove orders
                    field.set(criteria,new ArrayList());
                }catch(Exception ex){
                    ex.printStackTrace();
                    //TODO xxxx
                }
                int totalCount = ((Integer) criteria.setProjection(Projections.rowCount())
                        .uniqueResult()).intValue();
                criteria.setProjection(null);
                
                try{
                    Field field = CriteriaImpl.class.getDeclaredField("orderEntries");
                    //Add orders return
                    for(int i=0; i<orderEntrys.size(); i++){
                        List innerOrderEntries = (List) field.get(criteria);
                        innerOrderEntries.add(orderEntrys.get(i));
                    }
                }catch(Exception ex){
                    ex.printStackTrace();
                    //TODO cccc
                }
                List items = criteria.setFirstResult(startIndex).setMaxResults(pageSize).list();
                PaginationSupport ps = new PaginationSupport(items, totalCount, pageSize,
                        startIndex);
                return ps;
            }
        }, true);
    }
希望大家多多交流
			
posted @ 
2006-05-29 23:29 莫多 阅读(5083) | 
评论 (12) | 
编辑 收藏