Rory's Blog
Happy study,Happy work,Happy life
posts - 22,  comments - 46,  trackbacks - 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">
        
<property name="templatePath"><value>${templatePath}</value></property>
    
</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 莫多 阅读(1844) | 评论 (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 莫多 阅读(4990) | 评论 (12)编辑 收藏
现在的系统中虽然使用了。Hibernate但是没有使用Hibernate的关联关系来进行数据库操作。所有的管理操作都是单独实现的。所以也不能用Criteria.add()这种方式去查询关联的一方。所以只能用Native SQL去查询结果返回对象了。按照Hibernate3的reference里面说的

16.1. 使用SQLQuery

对原生SQL查询执行的控制是通过SQLQuery接口进行的,通过执行Session.createSQLQuery()获取这个接口。最简单的情况下,我们可以采用以下形式:

List cats = sess.createSQLQuery("select * from cats")
    .addEntity(Cat.class)
    .list();

这个查询指定了:

  • SQL查询字符串

  • 查询返回的实体

这里,结果集字段名被假设为与映射文件中指明的字段名相同。对于连接了多个表的查询,这就可能造成问题,因为可能在多个表中出现同样名字的字段。下面的方法就可以避免字段名重复的问题:

List cats = sess.createSQLQuery("select {cat.*} from cats cat")
    .addEntity("cat", Cat.class)
    .list();

这个查询指定了:

  • SQL查询语句,它带一个占位符,可以让Hibernate使用字段的别名.

  • 查询返回的实体,和它的SQL表的别名.

addEntity()方法将SQL表的别名和实体类联系起来,并且确定查询结果集的形态。

addJoin()方法可以被用于载入其他的实体和集合的关联.

List cats = sess.createSQLQuery(
        "select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
    )
    .addEntity("cat", Cat.class)
    .addJoin("kitten", "cat.kittens")
    .list();

原生的SQL查询可能返回一个简单的标量值或者一个标量和实体的结合体。

Double max = (Double) sess.createSQLQuery("select max(cat.weight) as maxWeight from cats cat")
        .addScalar("maxWeight", Hibernate.DOUBLE);
        .uniqueResult();

除此之外,你还可以在你的hbm文件中描述结果集映射信息,在查询中使用。

List cats = sess.createSQLQuery(
        "select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id"
    )
    .setResultSetMapping("catAndKitten")
    .list();

后来我使用了命名SQL查询方式。

16.3. 命名SQL查询

可以在映射文档中定义查询的名字,然后就可以象调用一个命名的HQL查询一样直接调用命名SQL查询.在这种情况下,我们 需要调用addEntity()方法.

<sql-query name="persons">
    <return alias="person" class="eg.Person"/>
    SELECT person.NAME AS {person.name},
           person.AGE AS {person.age},
           person.SEX AS {person.sex}
    FROM PERSON person
    WHERE person.NAME LIKE :namePattern
</sql-query>
List people = sess.getNamedQuery("persons")
    .setString("namePattern", namePattern)
    .setMaxResults(50)
    .list();

我觉得这种发式比较好。这样写出来的sql可以很整齐。我们的数据库使用的是oracle,不过按照这上面的写法发现sql语句有错误。
后来拿到控制台执行也抱错。因为原来都用sqlserver,而sqlserver都是可以的。后来发现是表不能有别名改成这样就好了。
            SELECT T_PAY.sys_id as {pay.sysId},
                   T_PAY.sys_flag 
as {pay.sysFlag},
                   T_PAY.sys_domain 
as {pay.sysDomain},
                   T_PAY.sys_owner 
as {pay.sysOwner},
                   T_PAY.sys_create_date 
as {pay.sysCreateDate},
                   T_PAY.sys_update_date 
as {pay.sysUpdateDate},
                   T_PAY.pay_id 
as {pay.payId},
                   T_PAY.pay_name 
as {pay.payName},
                   T_PAY.pay_type_id 
as {pay.payTypeId},
                   T_PAY.pay_date 
as {pay.payDate},
                   T_PAY.money_type_id 
as {pay.moneyTypeId},
                   T_PAY.amount 
as {pay.amount},
                   T_PAY.payer_id 
as {pay.payerId},
                   T_PAY.payer_name 
as {pay.payerName},
                   T_PAY.accept_id 
as {pay.acceptId},
                   T_PAY.accept_name 
as {pay.acceptName},
                   T_PAY.pay_state_id 
as {pay.payStateId},
                   T_PAY.remark 
as {pay.remark}
            
FROM   T_PAY
            
JOIN   T_BIZ_PAY
            
ON       T_PAY.pay_id = T_BIZ_PAY.pay_id
            
WHERE  T_BIZ_PAY.biz_id = :bizId
  这里要特别的提醒一下大家千万不要把主键忘了。刚开始我就忘了主键,后来调试了半天才找出原因来。

这样在sping里面用回调查询一下就ok了。真的很方便.
    public List getPaysByBizId(final String bizId) {
        
return (List)getHibernateTemplate().execute(new HibernateCallback(){
            
public Object doInHibernate(Session session)throws HibernateException{
                Query query 
= session.getNamedQuery("find.pays.by.bizid");
                query.setParameter(
"bizId",bizId);
                
return query.list();
            }
        },
true);
    }
posted @ 2006-05-26 10:33 莫多 阅读(3769) | 评论 (0)编辑 收藏
今天把myblog用sql server部署了一下,可是发现分页查询的时候出现错误,看控制台报错说语句有错,由来发现分页的时候先查询总记录数目的那条语句出错了
select count(*as y0_ from myblog_Blog this_ inner join myblog_Blog_Category categories3_ on this_.id=categories3_.blogId inner join myblog_Category category1_ on categories3_.categoryId=category1_.id where category1_.id=order by this_.postTime desc
      原来开发的时候我是用的mysql,没有任何问题。原因就在最后面的order by 语句,sql server 在select count(*)里面不能用 order by。然后跟踪代码发现:
    public PaginationSupport getBlogsByCategoryByPage(final String categoryId, final int startIndex, final int pageSize) {
        
return (PaginationSupport) getHibernateTemplate().execute(new HibernateCallback() {
            
public Object doInHibernate(Session session) throws HibernateException {
                Criteria criteria 
= session.createCriteria(Blog.class);
                Criteria cateCriteria 
= criteria.createCriteria("categories");
                cateCriteria.add(Expression.eq(
"id",categoryId));
                criteria.addOrder(Order.desc(
"postTime"));
                
int totalCount = ((Integer) criteria.setProjection(Projections.rowCount())
                        .uniqueResult()).intValue();
                criteria.setProjection(
null);
                
                List items 
= criteria.setFirstResult(startIndex).setMaxResults(pageSize).list();
                List blogs 
= new ArrayList();
                
for(Iterator ite = items.iterator(); ite.hasNext();) {
                    Object[] objs 
= (Object[])ite.next();
                    blogs.add(objs[
1]);
                }
                PaginationSupport ps 
= new PaginationSupport(blogs, totalCount, pageSize, startIndex);
                
return ps;
            }
        }, 
true);
    }
原来问题就在Criteria.addOrder(Order.desc("postTime"));这句话的位置上面,int totalCount = ((Integer) criteria.setProjection(Projections.rowCount())
      .uniqueResult()).intValue();
这句话的时候就会生成上面那句话,如果在这之前addOrder就会出现问题,如果你用mysql不会出现问题,如果你用sql server就会报错。解决方法就是把addOrder语句放到totalCount下面就可以了。
    public PaginationSupport getBlogsByCategoryByPage(final String categoryId, final int startIndex, final int pageSize) {
        
return (PaginationSupport) getHibernateTemplate().execute(new HibernateCallback() {
            
public Object doInHibernate(Session session) throws HibernateException {
                Criteria criteria 
= session.createCriteria(Blog.class);
                Criteria cateCriteria 
= criteria.createCriteria("categories");
                cateCriteria.add(Expression.eq(
"id",categoryId));
                
int totalCount = ((Integer) criteria.setProjection(Projections.rowCount())
                        .uniqueResult()).intValue();
                criteria.setProjection(
null);
                
                
/*
                 * Fix a bug ,Order must add after get the totalCount,
                 * beacuse SqlServer not support order by in the select count(*).
                 
*/
                criteria.addOrder(Order.desc(
"postTime"));
                List items 
= criteria.setFirstResult(startIndex).setMaxResults(pageSize).list();
                List blogs 
= new ArrayList();
                
for(Iterator ite = items.iterator(); ite.hasNext();) {
                    Object[] objs 
= (Object[])ite.next();
                    blogs.add(objs[
1]);
                }
                PaginationSupport ps 
= new PaginationSupport(blogs, totalCount, pageSize, startIndex);
                
return ps;
            }
        }, 
true);
    }

这样生成的sql语句就是这样的。
select count(*as y0_ from myblog_Blog this_ inner join myblog_Blog_Category categories3_ on this_.id=categories3_.blogId inner join myblog_Category category1_ on categories3_.categoryId=category1_.id where category1_.id=?

以后大家也要注意了。呵呵。
posted @ 2006-05-21 22:49 莫多 阅读(6421) | 评论 (4)编辑 收藏
我们的项目比较特殊,基本上每天都要发布一次。为了不影响系统的正常使用,我们的做法是在下班之前把打包好的war放到服务器的一个目录下面(eg:d:\bak)。然后用windows的计划任务在晚上12点自动部署系统,也就是net stop tomcat,删除xx.war,删除xx,然后把d:\bak\xx.war拷贝到webapps下面。然后再net start tomcat。这样在第二天来的上班的时候就可以使用升级过的系统了。也不会影响其他人的使用,不需要中断操作。
    关于项目的一个配置我的前几篇文章我也提到过,那个upload的问题就不会发生了。还有就是关于项目开发中的一些问题。比如数据库的连接地址,upload directory的配置等,这些在团队中的每个人都是不一样的,那么在发布的时候都要改成服务器上的正确配置,如果一个月部署一次这到没有什么。但是像我们这样每天部署就不是那么轻松了。而且如果一时不注意很容易造成配置的不正确。所以对于很多配置文件我们都有两份。一份是用户自己开发用的,一份是部署到服务器的配置,这样在开发的时候团队中的每个人都不一样,关于服务器的配置都是一样的,在发布的时候是用的服务器的配置而不是用开发用的配置。eg:web.xml(个人的配置)web-dest.xml 而关键的配置也就是下面这段。
web.xml
    <context-param>
        
<param-name>contextConfigLocation</param-name>
        
<param-value>
            classpath:spring/*_context.xml,
            classpath:spring/global.xml 

        
</param-value>
    
</context-param>
web-dest.xml
    <context-param>
        
<param-name>contextConfigLocation</param-name>
        
<param-value>
            classpath:spring/*_context.xml,
            classpath:spring/global-dest.xml,
            classpath:spring/scheduler.xml
        
</param-value>
    
</context-param>
注意到其中不一样的。dest里少了scheduler.xml这个主要是定时执行的一些任务,一般在开发的时候都不需要,去掉也可以提升速度,也不会出现那么多的log。还有就是发布的web.xml用了global-dest.xml这个是关于spring的总的配置。
global.xml
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        
<property name="driverClassName"><value>net.sourceforge.jtds.jdbc.Driver</value></property>
        
<property name="url">
            
<value>jdbc:jtds:sqlserver://192.168.0.240:1433/fivefortunes;SelectMethod=cursor</value>
            
</property>
        
<property name="username"><value>sa</value></property>
        
<property name="password"><value></value></property>
    
</bean>
    
    
<bean id="dataSource2" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        
<property name="driverClassName"><value>net.sourceforge.jtds.jdbc.Driver</value></property>
        
<property name="url">
            
<value>jdbc:jtds:sqlserver://192.168.0.240:1433/outmail;SelectMethod=cursor</value>
            
</property>
        
<property name="username"><value>sa</value></property>
        
<property name="password"><value></value></property>
    
</bean>
    
    
<bean id="customDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        
<property name="driverClassName"><value>net.sourceforge.jtds.jdbc.Driver</value></property>
        
<property name="url">
            
<value>jdbc:jtds:sqlserver://192.168.0.240:1433/custom;SelectMethod=cursor</value>
            
</property>
        
<property name="username"><value>sa</value></property>
        
<property name="password"><value></value></property>
    
</bean>
global-dest.xml
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        
<property name="driverClassName"><value>net.sourceforge.jtds.jdbc.Driver</value></property>
        
<property name="url">
            
<value>jdbc:jtds:sqlserver://192.168.0.5:1433/fivefortunes;SelectMethod=cursor</value>
            
</property>
        
<property name="username"><value>sa</value></property>
        
<property name="password"><value></value></property>
    
</bean>
    
    
<bean id="dataSource2" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        
<property name="driverClassName"><value>net.sourceforge.jtds.jdbc.Driver</value></property>
        
<property name="url">
            
<value>jdbc:jtds:sqlserver://192.168.0.5:1433/outmail;SelectMethod=cursor</value>
            
</property>
        
<property name="username"><value>sa</value></property>
        
<property name="password"><value></value></property>
    
</bean>
    
    
<bean id="customDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        
<property name="driverClassName"><value>net.sourceforge.jtds.jdbc.Driver</value></property>
        
<property name="url">
            
<value>jdbc:jtds:sqlserver://192.168.0.5:1433/custom;SelectMethod=cursor</value>
            
</property>
        
<property name="username"><value>sa</value></property>
        
<property name="password"><value></value></property>
    
</bean>
还有关于一些properties文件我们采用了用ant部署的时候改名字来达到目的。
build.xml
        <move file="${dist.dir}/mail.properties" tofile="${dist.dir}/mail-dev.properties" />
        
<copy file="${dist.dir}/mail-dest.properties" tofile="${dist.dir}/mail.properties" />
        
<move file="${dist.dir}/upload.properties" tofile="${dist.dir}/upload-dev.properties" />
        
<copy file="${dist.dir}/upload-dest.properties" tofile="${dist.dir}/upload.properties" />

这个是在war之前做的,大家眼看也就明白吧,就是把xx-dest.properties,改名成xx.propeties。在打完包之后
        <move file="${dist.dir}/mail-dev.properties" tofile="${dist.dir}/mail.properties" />
        
<move file="${dist.dir}/upload-dev.properties" tofile="${dist.dir}/upload.properties" />
这样就达到了我们无忧的目的了。只要每天部署的时候保证程序能正常运行,ant war一下就安心部署吧。
以上就是全部内容,如果有什么不正确欢迎砸板砖。
posted @ 2006-04-28 22:27 莫多 阅读(2671) | 评论 (3)编辑 收藏
前面一篇文章提到通过webwork的interceptor给webwork的action设置初始值,

如何给webwork的action里的Field设置初始值

jdev说到"为什么要放在这里,而不是放到系统配置文件中,然后在系统设置界面中提供设置",后来我就用spring来注入了。现在就把值放入properties文件中了。

    <bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
      
<property name="locations">
        
<list>
          
<value>classpath:mail.properties</value>
          
<value>classpath:upload.properties</value>
        
</list>
      
</property>
    
</bean>
    
<!-- 收发外部邮箱 author:somebody-->
    
<bean id="outMailManager" class="cn.com.fivefortunes.mail.manager.impl.OutMailManagerImpl">
        
<property name="javaMailSender"><ref bean="javaMailSender"/></property>
        
<property name="attachementDirectory"><value>${mail.attachementDirectory}</value></property>
        
<property name="uploadFileDirectory"><value>${upload.directory}</value></property>
        
<property name="outMailHibernateManager"><ref bean="outMailHibernateManager"/></property>
        
<property name="outMailAccountManager"><ref bean="outMailAccountManager"/></property>
    
</bean>
这样把uploadFileDirectory放入mananger中去了。在properties里面配置一下就ok了。

upload.directory
=D:\\tomcat5\\webapps\\files
mail.attachementDirectory
=D:\\tomcat5\\webapps\\files
上次还有网友这样说到"return ServletActionContext.getServletContext().getRealPath("/");

你这样换了部署环境每次都要改
而且也该是
D://tomcat5//webapps//files"
也许很多人都以为这是最好的方式,可是实际情况不是这样,我们的uploadfile目录已经有3G的文件,而基本上每天我们都要发布新的webapp,如果把uploadfile目录放到webapp的一个子目录,每次部署的时候都要先把uploadfile copy出来然后再部署。所以我们这么做就是把upload目录放到其他目录不影响uploadfile目录里面的文件。关于我们项目的部署见我的下一篇文章。谢谢大家。如果您有什么更好的方法请您指教。
posted @ 2006-04-22 11:21 莫多 阅读(1167) | 评论 (0)编辑 收藏
刚才在tss上看到Joe发布的消息,DWR允许异步调用Javascript了。DWR 2.0 builds on this to allow you to asynchronously call Javascript code from Java. Reverse Ajax makes writing interactive applications much easier.
值得去看看。
posted @ 2006-04-12 09:23 莫多 阅读(299) | 评论 (0)编辑 收藏
Rss,Atom,基本上是Web2.0的基本特征,今天终于有时间决定实现一下。对于动态的Rss,Atom其实就是选取最新的内容,迭迨一下生成一个固定格式的xml文件就可以了。其实也很简单。
       我用webwork2,用freemarker做模版,在网上找了一个标准的Rss2.0格式就生成我的模版文件rss.ftl
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title><![CDATA[我的小站]]></title>
<link>http://leaf.jdk.cn/</link>
<description><![CDATA[泡出好心情,泡出好技术]]></description>
<language>zh-cn</language>
<copyright><![CDATA[Copyright 2006 PaoPao v4.0]]></copyright>
<webMaster><![CDATA[rory.cn@gmail.com (Rory Ye)]]></webMaster>
<generator>PaoPao v4.0</generator> 
    
<image>
        
<title>我的小站</title> 
        
<url>http://leaf.jdk.cn/logo.gif</url> 
        
<link>http://leaf.jdk.cn</link> 
        
<description>莫多泡泡2006</description> 
    
</image>
    
<#list blogs as blog>
    
<item>
        
<link>http://leaf.jdk.cn/entry.action?entryId=${blog.id}</link>
        
<title><![CDATA[${blog.title}]]></title>
        
<author>${blog.authorMail}(${blog.author})</author>
        
<category><![CDATA[ ${blog.categories} ]]></category>
        
<pubDate>${blog.pubDate}</pubDate>
        
<guid>http://leaf.jdk.cn/entry.action?id=${blog.id}</guid>    
        
<description><![CDATA[${blog.content}]]></description>
    
</item>
    
</#list>
</channel>
</rss>
我在rss.action里面去取blogs就可以了。
    public String execute() throws Exception {
        PaginationSupport ps 
= blogManager.getBlogsByPage(0);
        blogs 
= new ArrayList();
        
        
for(Iterator ite = ps.getItems().iterator(); ite.hasNext();){
            Blog blog 
= (Blog)ite.next();
            WrapRssBlog wrapBlog 
= new WrapRssBlog();
            wrapBlog.setId(blog.getId());
            wrapBlog.setAuthor(blog.getAuthor().getNickname());
            wrapBlog.setAuthorMail(blog.getAuthor().getMail());
            wrapBlog.setTitle(blog.getTitle());
            wrapBlog.setContent(StringUtil.extractText(blog.getContent()));
            wrapBlog.setPubDate(DateUtil.formatRssDate(blog.getPostTime()));
            StringBuffer sb 
= new StringBuffer();
            
for(Iterator ite2 = blog.getCategories().iterator(); ite2.hasNext();){
                Category cate 
= (Category) ite2.next();
                sb.append(
" ")
                  .append(cate.getName());
            }
            wrapBlog.setCategories(sb.toString());
            blogs.add(wrapBlog);
        }
        
return super.execute();
    }
这里把blog包装了一下,主要是处理了一下日期,内容,还有把分类拼成字符串。关于日期的处理,参考了飞云小侠写的rss日期的研究。实现代码如下。
    public static String formatRssDate(Date date){
        SimpleDateFormat sdf 
= new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z",Locale.US);
        
//TODO TimeZone
        SimpleTimeZone zone = new SimpleTimeZone(8,"GMT");
        sdf.setTimeZone(zone);
        
return sdf.format(date);
    }
这样就得到了这样的日期
Thu, 6 Apr 2006 16:01:36 GMT
做好了这些,配置一下action
        <action name="rss" class="cn.jdk.leaf.action.RssAction">        
            
<result name="success" type="freemarker">/WEB-INF/pages/rss.ftl</result>
        
</action>
不过像这样配置的话,你访问http://xxx.xxx.com/rss.action看到的不是一个xml
因为返回结果的contentType是text/html.而不是xml,这样是不行的。看了一下webwork源码。原来可以这样简单的解决。改成这样配置就可以了。
        <action name="rss" class="cn.jdk.leaf.action.RssAction">
            
<result name="success" type="freemarker">
                
<param name="location">/WEB-INF/pages/rss.ftl</param>
                
<param name="contentType">application/xml</param>
            
</result>
        
</action>

简单吧。其实你还可以把这个contentType改成其他类型的。比如excle的。这样用户执行就可以得到一个xls文件。哈哈。
posted @ 2006-04-10 22:40 莫多 阅读(1316) | 评论 (2)编辑 收藏
以前一直都没有试过,前几天打算把wordpress换成自己写的程序,就想到了数据的导入和导出,首先想到的是用数据库工具来导。可是觉得有些麻烦,我自己的程序是用spring+hibernate的。后来我就试了一下spring的JdbcTemplate,就和HibernateTemplate一样的好用。首先增加一个连接到wp数据库的dataSource
    <bean id="dataSource2" class="org.springframework.jdbc.datasource.DriverManagerDataSource" destroy-method="close">
        
<property name="driverClassName"><value>org.hibernate.dialect.MySQLDialect</value></property>
        
<property name="url">
            
<value>jdbc:mysql://192.168.0.240:3306/wordpressωuseUnicode=true&amp;characterEncoding=utf8</value>
            
</property>
        
<property name="username"><value>root</value></property>
        
<property name="password"><value></value></property>
    
</bean>

    然后在转换程序里面get这个dataSource,new 一个JdbcTemplate(dataSource2),这样就ok了。很简单吧。

    public void testCopyData() throws Exception{
        DataSource ds 
= (DataSource)applicationContext.getBean("dataSource2");
        
        CategoryManager cateManager 
= (CategoryManager) applicationContext.getBean("categoryManager");
        
        JdbcTemplate jt 
= new JdbcTemplate(ds);
        System.out.println(
"Total posts:"+jt.queryForInt("select count(*) from wp_posts"));
        assertNotNull(ds);
        
        List cates 
= jt.queryForList("select * from wp_categories");
        
int i= 0;
        
for(Iterator ite = cates.iterator(); ite.hasNext();){
            i
++;
            Map result 
= (Map) ite.next();
            Category cate 
= new Category();
            cate.setName((String)result.get(
"cat_name"));
            cate.setOrder(i);
            
if(i==1)
                cate.setDefaultCategory(
true);
            cateManager.saveCategory(cate);
            System.out.println(
"cat_name:"+result.get("cat_name")+"\n");
        }
    }
posted @ 2006-04-07 00:03 莫多 阅读(3572) | 评论 (7)编辑 收藏
只是自己的想法,不对不要扔鸡蛋哦。

今天突发奇想的实现一个小小的cache。把分类categories放入map中,cache起来。
    private void cache() {
        
if(log.isDebugEnabled()){
            log.debug(
"Starting cache the categories");
        }
        cacheCategoryMap 
= new HashMap();
        cacheCategoryMap.put(
"categories",categoryDao.getCategories());
    }

然后我想在interceptor里面把categories写到ognlvaluestack里面这样我在ftl里面就可以<#list categories>....</#list>了。因为这个是在每个页面的header.ftl里面的。我也就不需要再每个action里面去get一下了。
刚开始我implements Interceptor

        final OgnlValueStack stack = ActionContext.getContext().getValueStack();
        stack.setValue(
"categories" ,categoryManager.getCategories());
        
return invocation.invoke();
可是这样也不可以。后来我想到是不是action执行完毕之后就把stack中的这个值清空了我又用了。AroundInterceptor 我想在after里面去设置不就可以了。
    protected void after(ActionInvocation dispatcher, String result) throws Exception {
        
final OgnlValueStack stack = ActionContext.getContext().getValueStack();
        stack.setValue(
"categories" ,categoryManager.getCategories());
    }
可是这样还是不可以。我晕了。我想是不是要在action里面声明一下categories。
    private List categories;

    
public List getCategories() {
        
return categories;
    }


    
public void setCategories(List categories) {
        
this.categories = categories;
    }

然后在before里面去get就可以了。
    protected void before(ActionInvocation invocation) throws Exception {
        
final OgnlValueStack stack = ActionContext.getContext().getValueStack();
        stack.setValue(
"categories" ,categoryManager.getCategories());
    }

总算实现了。不过还要在每个action里面声明一下categories,这样还是很不好的。刚才有人建议用filter。我在试试吧.


http://leaf.jdk.cn/index.php/archives/91
posted @ 2006-03-21 11:37 莫多 阅读(1116) | 评论 (0)编辑 收藏
仅列出标题
共3页: 上一页 1 2 3 下一页 

<2024年9月>
25262728293031
1234567
891011121314
15161718192021
22232425262728
293012345

常用链接

留言簿(1)

随笔分类(27)

随笔档案(22)

Friends

搜索

  •  

积分与排名

  • 积分 - 61686
  • 排名 - 845

最新评论

阅读排行榜

评论排行榜