VelocityServlet的应用

来源:互联网 发布:管理快递的软件 编辑:程序博客网 时间:2024/06/04 17:51

在Velocity 1.4版本中,org.apache.velocity.servlet.VelocityServlet继承了HttpServlet,因此它继承了HttpSetvlet的对生命周期的管理,而且,只要我们在实现自己velocity servlet的时候,继承org.apache.velocity.servlet.VelocityServlet,然后继承它的一些重要的方法就可以完成实际的业务。

下载 velocity-1.4.zip 后将它的jar包导入工程即可。

详细配置

Windows Server 2003 SP2 + SQL Server 2000 + Eclipse 3.2 + MyEclipse 5.0 + Tomcat 5.5.9 + Hibernate 3.0 + Velocity 1.4

开发测试过程

我的工程的目录结构如下所示:

VelocityServlet
│ .classpath
│ .myhibernatedata
│ .mymetadata
│ .project

├─.myeclipse
├─src
│ │ hibernate.cfg.xml
│ │ velocity.properties
│ │
│ └─org
│      └─shirdrn
│          │ HibernateSessionFactory.java
│          │
│          └─velocity
│              ├─dao
│              │      PersonDao.java
│              │
│              ├─entity
│              │      Person.hbm.xml
│              │      Person.java
│              │
│              ├─service
│              │      PersonService.java
│              │
│              └─servlet
│                      ListPersonsServlet.java

└─WebRoot
    ├─log
    │      velocity.log
    │
    ├─META-INF
    │      MANIFEST.MF
    │
    ├─templates
    │      lists.vm
    │
    └─WEB-INF
        │ web.xml
        │
        ├─classes
        │ │ hibernate.cfg.xml
        │ │ velocity.properties
        │ │
        │ └─org
        │      └─shirdrn
        │          │ HibernateSessionFactory.class
        │          │
        │          └─velocity
        │              ├─dao
        │              │      PersonDao.class
        │              │
        │              ├─entity
        │              │      Person.class
        │              │      Person.hbm.xml
        │              │
        │              ├─service
        │              │      PersonService.class
        │              │
        │              └─servlet
        │                      ListPersonsServlet.class
        │
        └─lib
                antlr-2.7.5H3.jar
                asm-attrs.jar
                asm.jar
                cglib-2.1.jar
                commons-collections-2.1.1.jar
                commons-logging-1.0.4.jar
                dom4j-1.6.jar
                ehcache-1.1.jar
                hibernate3.jar
                jaas.jar
                jaxen-1.1-beta-4.jar
                jdbc2_0-stdext.jar
                jta.jar
                log4j-1.2.9.jar
                msbase.jar
                mssqlserver.jar
                msutil.jar
                xerces-2.6.2.jar
                xml-apis.jar

下面就详细介绍上面的核心代码。

Person实体对应的POJO,这对Velocity模板中使用Person的属性非常重要,其实是Person实体的setter和getter方法,如下所示:

package org.shirdrn.velocity.entity;

 

/**
* Person generated by MyEclipse - Hibernate Tools
*/

public class Person implements java.io.Serializable {


    // Fields   

     private String id;
     private String name;
     private String gender;
     private Integer age;
     private String addr;


    // Constructors

    /** default constructor */
    public Person() {
    }

/** minimal constructor */
    public Person(String id, String name) {
        this.id = id;
        this.name = name;
    }
   
    /** full constructor */
    public Person(String id, String name, String gender, Integer age, String addr) {
        this.id = id;
        this.name = name;
        this.gender = gender;
        this.age = age;
        this.addr = addr;
    }

  
    // Property accessors

    public String getId() {
        return this.id;
    }
   
    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return this.name;
    }
   
    public void setName(String name) {
        this.name = name;
    }

    public String getGender() {
        return this.gender;
    }
   
    public void setGender(String gender) {
        this.gender = gender;
    }

    public Integer getAge() {
        return this.age;
    }
   
    public void setAge(Integer age) {
        this.age = age;
    }

    public String getAddr() {
        return this.addr;
    }
   
    public void setAddr(String addr) {
        this.addr = addr;
    }
}

编写了一个实现查询数据库表person中的数据的DAO,接口如下:

package org.shirdrn.velocity.dao;

import java.util.List;

public interface PersonDao {
public List queryPersons(String hql);
}

具体实现是在PersonService类中实现的,代码如下所示:

package org.shirdrn.velocity.service;

import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.shirdrn.HibernateSessionFactory;
import org.shirdrn.velocity.dao.PersonDao;

public class PersonService implements PersonDao {

public List queryPersons(String hql) {
   Session session = null;
   try{
    session = HibernateSessionFactory.getSession();
    Query query = session.createQuery(hql);
    return query.list();
   }
   catch(HibernateException e){
    e.printStackTrace();
   }
   finally{
    HibernateSessionFactory.closeSession();
   }
   return null;
}
}

应用Velocity最关键,最核心的Servlet的实现是在ListPersonsServlet类中,代码如下所示:

package org.shirdrn.velocity.servlet;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;
import java.util.Properties;

import javax.servlet.ServletConfig;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.velocity.Template;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.context.Context;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.servlet.VelocityServlet;
import org.shirdrn.velocity.dao.PersonDao;
import org.shirdrn.velocity.service.PersonService;

public class ListPersonsServlet extends VelocityServlet {
  
protected Properties loadConfiguration(ServletConfig config)throws IOException, FileNotFoundException{    // 重写了VelocityServlet中的loadConfiguration方法
   String propsFileName = config.getInitParameter(INIT_PROPS_KEY);
   Properties props = new Properties();
   if(propsFileName != null){
    String realPath = getServletContext().getRealPath(propsFileName);
    if(realPath != null){
     propsFileName = realPath;
    }
    props.load(new FileInputStream(propsFileName));    // 加载属性配置文件
   }
//   将日志文件所在路径加入到Velocity上下文中
   String logFileName = props.getProperty(Velocity.RUNTIME_LOG);
   if(logFileName != null){
    String log = getServletContext().getRealPath(logFileName);
    if(log != null){
     props.setProperty(Velocity.RUNTIME_LOG,log);
    }
   }
   // 将Velocity模板加入到Velocity上下文(Context)中
   String path = props.getProperty(Velocity.FILE_RESOURCE_LOADER_PATH);
   if(path != null){
    String realPath = getServletContext().getRealPath(path);
    if(realPath != null){
     props.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, realPath);
    }
   }
   //System.out.println("props = "+props);
   //props = {file.resource.loader.path=D:/Tomcat 5.5/webapps/VelocityServlet/templates, runtime.log=D:/Tomcat 5.5/webapps/VelocityServlet/log/velocity.log}

   return props;
}

public Template handleRequest(HttpServletRequest request,HttpServletResponse response,Context ctx){
   PersonDao personDao = new PersonService();
   List personList = personDao.queryPersons("from Person");
   ctx.put("personList", personList);    // 将查询的数据列表放到Velocity上下文中
   Template template = null;
   try {
    template = getTemplate("lists.vm","UTF-8");    // 获取Velocity模板文件lists.vm
   } catch (ResourceNotFoundException e) {
    e.printStackTrace();
   } catch (ParseErrorException e) {
    e.printStackTrace();
   } catch (Exception e) {
    e.printStackTrace();
   }
   return template;
}
}

因为是VelocityServlet也是Servlet,所以要在web.xml中配置,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

<servlet>
   <servlet-name>ListPersonsServlet</servlet-name>
   <servlet-class>org.shirdrn.velocity.servlet.ListPersonsServlet</servlet-class>
   <init-param>
    <param-name>org.apache.velocity.properties</param-name>
    <param-value>/WEB-INF/classes/velocity.properties</param-value>
   </init-param>
   <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
   <servlet-name>ListPersonsServlet</servlet-name>
   <url-pattern>/ListPersonsServlet</url-pattern>
</servlet-mapping>

<welcome-file-list>
   <welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>

上面web.xml文件中:

<init-param>
    <param-name>org.apache.velocity.properties</param-name>
    <param-value>/WEB-INF/classes/velocity.properties</param-value>
   </init-param>

配置了velocity.properties属性文件,该文件的内容如下所示:

default.contentType=text/html; charset=UTF-8
input.encoding=UTF-8
output.encoding=UTF-8
file.resource.loader.path = templates
runtime.log = log/velocity.log

前三行指定了输入输出的编码方式为UTF-8,这样设置以后,使用Velocity模板显示数据的时候,不会出现乱码问题。

第四行指定了模板文件所在的目录。

第五行指定了日志文件所在的目录。

我们实现的模板文件lists.vm的代码如下所示:

<html>
<head>
   <title>Velocity在Servlet中的应用</title>
</head>
<body bgcolor="#FFFFFF" border="1" borderColor="green" borderDarkColor="#FFFFFF" borderLightColor="#000000">
   <h1>Velocity应用的例子</h1>
   <table align="center" width="60%">
    <tr>
     <td>ID</td>
     <td>姓名</td>
     <td>性别</td>
     <td>年龄</td>
     <td>住址</td>
    </tr>
    #foreach($person in $personList)
    <tr>
     <td>$!person.id</td>
     <td>$!person.name</td>
     <td>$!person.gender</td>
     <td>$!person.age</td>
     <td>$!person.addr</td>
    </tr>
    #end
   </table>
</body>
</html>

上面使用$!person.addr可以使得:如果Person的某个字段为空,显示的时候用空格代替,如果使用$person.addr,则当addr字段为null的时候,页面显示的内容为$person.addr。

启动Tomcat Web Server,在浏览器地址栏中键链接:

http://localhost:8080/VelocityServlet/ListPersonsServlet

就可以看到从数据库中读取出来的Person的数据显示出来,如下所示:

Velocity应用的例子

ID姓名性别年龄住址200804140001shirdrnmale25ChangChun200804150001Poolinafemale24Changchun200804150002Selibymale25Changchun200804150006Koppafemale24Changchun200804150008Justinmale24New York200804150009Soloorfemale24London200804150015Sujnnmale22Shanghai200804160001SAgoop   200804160002SAgoop   200804160003SAgoop   200804160004SAgoop   200804160005SAgoop   200804160006SAgoop   200804160007SAgoop   200804160008SAgoop   200804160009SAgoop   200804160010SAgoop   200804160011SAgoop   200804160012SAgoop   200804160013SAgoop   200804160014SAgoop   200804160015SAgoop   200804160016SAgoop   200804160017SAgoop   200804160018SAgoop   200804160019异域王者男20Beijing200804160021异域王者男20Beijing200804160022风平浪静female22长春200804160023风平浪静female22长春200804160024异域王者男20Beijing200804170001异域王者female20Beijing200804170030飞鱼男20Beijing200804170032飞鱼男20Beijing200804170033飞鱼男20Beijing200804170035飞鱼男20Beijing

关于异常

如果发生下面的空指针异常:

java.lang.NullPointerException
at org.apache.velocity.runtime.resource.ResourceManagerImpl.getResource(ResourceManagerImpl.java:288)
at org.apache.velocity.runtime.RuntimeInstance.getTemplate(RuntimeInstance.java:1102)
at org.apache.velocity.runtime.RuntimeSingleton.getTemplate(RuntimeSingleton.java:324)
at org.apache.velocity.servlet.VelocityServlet.getTemplate(VelocityServlet.java:603)
at org.shirdrn.velocity.servlet.ListPersonsServlet.handleRequest(ListPersonsServlet.java:61)
at org.apache.velocity.servlet.VelocityServlet.doRequest(VelocityServlet.java:365)
at org.apache.velocity.servlet.VelocityServlet.doGet(VelocityServlet.java:318)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:689)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:856)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:744)
at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
at java.lang.Thread.run(Thread.java:595)

可能是由于使用Velocity的版本的问题,我在开始测试的时候,使用Velocity 1.5的jar包就发生上面的异常。而且在编写ListPersonsServlet文件的时候,总是提示VelocityServlet类已经过时,其实在Velocity 1.5的JavaDoc中可以看到只有是VelocityServlet类中的属性或者方法,都是过时的,所以版本问题要处理好。

心得总结

关于Velocty中出现中文乱码问题,可以在velocity.properties文件中加入下面的三行就可以解决:

default.contentType=text/html; charset=UTF-8
input.encoding=UTF-8
output.encoding=UTF-8

非常关键的三行。