Rory's Blog
Happy study,Happy work,Happy life
posts - 22,  comments - 46,  trackbacks - 0
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日更新。
这里感谢网友 Ivan Chen(西滨) 的提示。原来新版的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.

AttributePossible ValueExplanation
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).
wildcardAll 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.
nullDo 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.
trueThe 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.
trueThe 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)编辑 收藏

  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 莫多 阅读(3304) | 评论 (2)编辑 收藏

     虽然项目全部采用了UTF-8编码,所有的源文件*.java,*.jsc,*.html,*.ftl都采用了UTF-8编码。可是还是出现了乱码问题。很是不爽,后来找到了tomcat,和resin的配置。

  1. 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"/>
  2. 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 >
      
< character-encoding > UTF-8 </ character-encoding >
      
    
</ web-app-default >

希望对你的项目有帮助。

创造共用协议:署名,非商业,保持一致    除经特别注明外,本文章版权归莫多泡泡所有.
署名,非商业用途,保持一致.   somebody(莫多)  

posted @ 2006-07-22 18:13 莫多 阅读(1809) | 评论 (4)编辑 收藏

<2006年7月>
2526272829301
2345678
9101112131415
16171819202122
23242526272829
303112345

常用链接

留言簿(1)

随笔分类(27)

随笔档案(22)

Friends

搜索

  •  

积分与排名

  • 积分 - 61849
  • 排名 - 845

最新评论

阅读排行榜

评论排行榜