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 AttributeMapper
is 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 AttributeMapper
is 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 莫多 阅读(7982) |
评论 (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 莫多 阅读(2677) |
评论 (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-type is specified on a rule). |
wildcard | All rules and thier conditions will be processed using the Wildcard Expression engine (unless match-type is 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 莫多 阅读(2332) |
评论 (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>
<bean name="rpcAccountService" class="com.jdkcn.xmlrpc.XmlRpcServiceExporter">
<property name="service">
<ref bean="accountService"/>
</property>
<property name="serviceName">
<value>jdkcn.accountService</value>
</property>
<property name="enabledForExtensions">
<value>true</value>
</property>
<property name="serviceInterface">
<value>com.jdkcn.service.AccountService</value>
</property>
</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 莫多 阅读(2168) |
评论 (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 莫多 阅读(2477) |
评论 (1) |
编辑 收藏