天天看點

Velocity執行個體

Velocity 是一個基于 Java 的通用模闆工具,來自于 jakarta.apache.org 。 

Velocity 的介紹請參考 Velocity -- Java Web 開發新技術。這裡是它的一個應用示例。

這個例子參照了 PHP-Nuke 的結構, 即所有 HTTP 請求都以 

Velocity執行個體

http://www.some.com/xxx/Modules?name=xxx&arg1=xxx&bbb=xxx ;的形式進行處理。例子中所有檔案都是 .java 和 .html , 沒有其他特殊的檔案格式。除了 Modules.java 是 Java Servlet, 其餘的 .java 檔案都是普通的 Java Class.

所有 HTTP 請求都通過 Modules.java 處理。Modules.java 通過 Velocity 加載 Modules.htm。 Modules.htm 有頁頭,頁腳,頁左導航連結,頁中内容幾個部分。其中頁頭廣告、頁中内容是變化部分。頁頭廣告由 Modules.java 處理,頁中内容部分由 Modules.java dispatch 到子頁面類處理。

1) Modules.java

import javax.servlet.*;

import javax.servlet.http.*;

import org.apache.velocity.*;

import org.apache.velocity.context.*;

import org.apache.velocity.exception.*;

import org.apache.velocity.servlet.*;

import commontools.*;

public class Modules

  extends VelocityServlet {

  public Template handleRequest(HttpServletRequest request,

                 HttpServletResponse response,

                 Context context) {

    //init

    response.setContentType("text/html; charset=UTF-8");

    response.setCharacterEncoding("utf-8");

    //prepare function page

    ProcessSubPage page = null;

    ProcessSubPage mainPage = new HomeSubPage();

    String requestFunctionName = (String) request.getParameter("name");

    boolean logined = false;

    String loginaccount = (String) request.getSession(true).getAttribute(

      "loginaccount");

    if (loginaccount != null) {

      logined = true;

    }

    //default page is mainpage

    page = mainPage;

    if (requestFunctionName == null||requestFunctionName.equalsIgnoreCase("home")) {

      page = mainPage;

    }

    //no login , can use these page

    else if (requestFunctionName.equalsIgnoreCase("login")) {

      page = new LoginProcessSubPage();

    }

    else if (requestFunctionName.equalsIgnoreCase("ChangePassword")) {

      page = new ChangePasswordSubPage();

    }

    else if (requestFunctionName.equalsIgnoreCase("ForgetPassword")) {

      page = new ForgetPassword();

    }

    else if (requestFunctionName.equalsIgnoreCase("about")) {

      page = new AboutSubPage();

    }

    else if (requestFunctionName.equalsIgnoreCase("contact")) {

      page = new ContactSubPage();

    }

    //for other page, need login first

    else if (logined == false) {

      page = new LoginProcessSubPage();

    }

    else if (requestFunctionName.equalsIgnoreCase("listProgram")) {

      page = new ListTransactionProgramSubPage();

    }

    else if (requestFunctionName.equalsIgnoreCase(

      "ViewProgramItem")) {

      page = new ViewTransactionProgramItemSubPage();

    }

    else if (requestFunctionName.equalsIgnoreCase(

      "UpdateProgramObjStatus")) {

      page = new UpdateTransactionProgramObjStatusSubPage();

    }

    else if (requestFunctionName.equalsIgnoreCase(

      "Search")) {

      page = new SearchSubPage();

    }

    //check if this is administrator

    else if (Utilities.isAdministratorLogined(request)) {

      //Utilities.debugPrintln("isAdministratorLogined : true");

      if (requestFunctionName.equalsIgnoreCase("usermanagement")) {

        page = new UserManagementSubPage();

      }

      else if (requestFunctionName.equalsIgnoreCase(

        "UploadFiles")) {

        page = new UploadFilesSubPage();

      }

      else if (requestFunctionName.equalsIgnoreCase(

        "DownloadFile")) {

        page = new DownloadFileSubPage();

      }

      else if (requestFunctionName.equalsIgnoreCase(

        "Report")) {

        page = new ReportSubPage();

      }

    }

    else {

      //no right to access.

      //Utilities.debugPrintln("isAdministratorLogined : false");

      page = null;

    }

    //Utilities.debugPrintln("page : " + page.getClass().getName());

    if(page != null){

      context.put("function_page",

            page.getHtml(this, request, response, context));

    }else{

      String msg = "Sorry, this module is for administrator only.You are not administrator.";

      context.put("function_page",msg);

    }

    

    context.put("page_header",getPageHeaderHTML());

    context.put("page_footer",getPageFooterHTML());

    Template template = null;

    try {

      template = getTemplate("/templates/Modules.htm"); //good

    }

    catch (ResourceNotFoundException rnfe) {

      Utilities.debugPrintln("ResourceNotFoundException 2");

      rnfe.printStackTrace();

    }

    catch (ParseErrorException pee) {

      Utilities.debugPrintln("ParseErrorException2 " + pee.getMessage());

    }

    catch (Exception e) {

      Utilities.debugPrintln("Exception2 " + e.getMessage());

    }

    return template;

  }

  

  protected java.util.Properties loadConfiguration(ServletConfig config) throws

    java.io.IOException, java.io.FileNotFoundException {

    return Utilities.initServletEnvironment(this);

  }

}

2) ProcessSubPage.java , 比較簡單,隻定義了一個函數接口 getHtml

import javax.servlet.http.*;

import org.apache.velocity.context.*;

import org.apache.velocity.servlet.*;

import commontools.*;

public abstract class ProcessSubPage implements java.io.Serializable {

  public ProcessSubPage() {

  }

  public String getHtml(VelocityServlet servlet, HttpServletRequest request,

             HttpServletResponse response,

             Context context) {

    Utilities.debugPrintln(

      "you need to override this method in sub class of ProcessSubPage:"

      + this.getClass().getName());

    return "Sorry, this module not finish yet.";

  }

}

他的 .java 檔案基本上是 ProcessSubPage 的子類和一些工具類。 ProcessSubPage 的子類基本上都是一樣的流程, 用類似

context.put("page_footer",getPageFooterHTML());

的寫法置換 .html 中的可變部分即可。如果沒有可變部分,完全是靜态網頁,比如 AboutSubPage, 就更簡單。

3) AboutSubPage.java

import org.apache.velocity.servlet.VelocityServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.apache.velocity.context.Context;

public class AboutSubPage extends ProcessSubPage {

  public AboutSubPage() {

  }

  public String getHtml(VelocityServlet servlet, HttpServletRequest request,

             HttpServletResponse response, Context context) {

    //prepare data

    //context.put("xxx","xxxx");         

             

    Template template = null;

    String fileName = "About.htm";

    try {

      template = servlet.getTemplate(fileName);

      StringWriter sw = new StringWriter();

      template.merge(context, sw);

      return sw.toString();

    }

    catch (Exception ex) {

      return "error get template " + fileName + " " + ex.getMessage();

    }

  }

}

其他 ProcessSubPage 的子類如上面基本類似,隻不過會多了一些 context.put("xxx","xxxx") 的語句。 

通過以上的例子,我們可以看到,使用 Velocity + Servlet , 所有的代碼為: 1 個 java serverlet + m 個 java class + n 個 Html 檔案。

這裡是用了集中處理,然後分發(dispatch)的機制。不用擔心使用者在沒有登陸的情況下通路某些頁面。使用者驗證,頁眉頁腳包含都隻寫一次,易于編寫、修改和維護。代碼比較簡潔,并且很容易加上自己的頁面緩沖功能。可以随意将某個頁面的 html 在記憶體中儲存起來,緩存幾分鐘,實作頁面緩沖功能。成功、出錯頁面也可以用同樣的代碼封裝成函數,通過參數将 Message/Title 傳入即可。

因為 Java 代碼與 Html 代碼完全在不同的檔案中,美工與java代碼人員可以很好的分工,每個人修改自己熟悉的檔案,基本上不需要花時間做協調工作。而用 JSP, 美工與java代碼人員共同修改維護 .jsp 檔案,麻煩多多,噩夢多多。而且這裡沒有用 xml ,說實話,懂 xml/xls 之類的人隻占懂 Java 程式員中的幾分之一,人員不好找。

因為所有 java 代碼人員寫的都是标準 Java 程式,可以用任何 Java 編輯器,調試器,是以開發速度也會大大提高。美工寫的是标準 Html 檔案,沒有 xml, 對于他們也很熟悉,速度也很快。并且,當需要網站改版的時候,隻要美工把 html 檔案重新修飾排版即可,完全不用改動一句 java 代碼。

爽死了!!

4) 工具類 Utilities.java 

import java.io.*;

import java.sql.*;

import java.text.*;

import java.util.*;

import java.util.Date;

import javax.naming.*;

import javax.servlet.*;

import javax.servlet.http.*;

import org.apache.velocity.*;

import org.apache.velocity.app.*;

import org.apache.velocity.context.Context;

import org.apache.velocity.servlet.*;

public class Utilities {

  private static Properties m_servletConfig = null;

  private Utilities() {

  }

  static {

    initJavaMail();

  }

  public static void debugPrintln(Object o) {

    String msg = "proj debug message at " + getNowTimeString() +

      " ------------- ";

    System.err.println(msg + o);

  }

  public static Properties initServletEnvironment(VelocityServlet v) {

    // init only once

    if (m_servletConfig != null) {

      return m_servletConfig;

    }

    //debugPrintln("initServletEnvironment....");

    try {

      

      Properties p = new Properties();

      ServletConfig config = v.getServletConfig();

      // Set the Velocity.FILE_RESOURCE_LOADED_PATH property

      // to the root directory of the context.

      String path = config.getServletContext().getRealPath("/");

      //debugPrintln("real path of / is : " + path);

      p.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, path);

      // Set the Velocity.RUNTIME_LOG property to be the file

      // velocity.log relative to the root directory

      // of the context.

      p.setProperty(Velocity.RUNTIME_LOG, path +

             "velocity.log");

// Return the Properties object.

//return p;

      Velocity.init(p);

      m_servletConfig = p;

      return p;

    }

    catch (Exception e) {

      debugPrintln(e.getMessage());

      //throw new ServletException("Error initializing Velocity: " + e);

    }

    return null;

    //this.getServletContext().getRealPath("/");

  }

  private static void initJavaMail() {

  }

  public static Connection getDatabaseConnection() {

    Connection con = null;

    try {

      InitialContext initCtx = new InitialContext();

      javax.naming.Context context = (javax.naming.Context) initCtx.

        lookup("java:comp/env");

      javax.sql.DataSource ds = (javax.sql.DataSource) context.lookup(

        "jdbc/TestDB");

      //Utilities.debugPrintln("ds = " + ds);

      con = ds.getConnection();

    }

    catch (Exception e) {

      Utilities.debugPrintln("Exception = " + e.getMessage());

      return null;

    }

    //Utilities.debugPrintln("con = " + con);

    return con;

  }

  public static java.sql.ResultSet excuteDbQuery(Connection con, String sql,

    Object[] parameters) {//請替換[]

    //Exception err = null;

    //Utilities.debugPrintln("excuteDbQuery" + parameters[0] + " ,sql=" + sql);//請替換[]

    try {

      java.sql.PreparedStatement ps = con.prepareStatement(sql);

      for (int i = 0; i < parameters.length; i++) {

        processParameter(ps, i + 1, parameters[i]);

//請替換[]

      }

      return ps.executeQuery();

    }

    catch (Exception e) {

      //Utilities.debugPrintln(e.getMessage());

      e.printStackTrace();

    }

    return null;

  }

  public static void excuteDbUpdate(String sql, Object[]parameters) {//請替換[]

    Connection con = Utilities.getDatabaseConnection();

    excuteDbUpdate(con, sql, parameters);

    closeDbConnection(con);

  }

  public static void excuteDbUpdate(Connection con, String sql,

                   Object[] parameters) {//請替換[]

    Exception err = null;

    try {

      java.sql.PreparedStatement ps = con.prepareStatement(sql);

      for (int i = 0; i < parameters.length; i++) {

        processParameter(ps, i + 1, parameters[i]);//請替換[]

      }

      ps.execute();

    }

    catch (Exception e) {

      err = e;

      //Utilities.debugPrintln(err.getMessage());

      e.printStackTrace();

    }

  }

  private static void processParameter(java.sql.PreparedStatement ps,

                     int index, Object parameter) {

    try {

      if (parameter instanceof String) {

        ps.setString(index, (String) parameter);

      }

      else {

        ps.setObject(index, parameter);

      }

    }

    catch (Exception e) {

      //Utilities.debugPrintln(e.getMessage());

      e.printStackTrace();

    }

  }

  public static void closeDbConnection(java.sql.Connection con) {

    try {

      con.close();

    }

    catch (Exception e) {

      Utilities.debugPrintln(e.getMessage());

    }

  }

  public static String getResultPage(

    String title, String message, String jumpLink,

    VelocityServlet servlet, HttpServletRequest request,

    HttpServletResponse response, Context context) {

    Template template = null;

    context.put("MessageTitle", title);

    context.put("ResultMessage", message);

    context.put("JumpLink", jumpLink);

    try {

      template = servlet.getTemplate(

        "/templates/Message.htm");

      StringWriter sw = new StringWriter();

      template.merge(context, sw);

      return sw.toString();

    }

    catch (Exception ex) {

      return "error get template Message.htm " + ex.getMessage();

    }

  }

  public static String mergeTemplate(String fileName, VelocityServlet servlet,

                    Context context) {

    Template template = null;

    try {

      template = servlet.getTemplate(fileName);

      StringWriter sw = new StringWriter();

      template.merge(context, sw);

      return sw.toString();

    }

    catch (Exception ex) {

      return "error get template " + fileName + " " + ex.getMessage();

    }

  }

}

注意:基于排版的需要,代碼中使用了中文全角空格。如果要複制代碼,請在複制後進行文字替換。