2004年10月22日

来到北京快两周了,结束日期还遥遥无期。

好想快点回到广州去啊。

虽然第二次来京,也只在上周六抽空去了一次天安门广场,但没有进去故宫,只因为那天睡懒觉。到下午3点多才来到紫禁城。呵呵……然后去了一趟西单,买了两件衣服。北京好大,好多地方都没有去过,以后一定要找机会来专门旅行。来工作的话就太没味了。

希望这次不是像上次一样病着回广州就好了。

2004年10月05日

      很久没有回来写东西了,这两个月一直在忙项目,每天都在加班中度过,还过了一个倒霉的九月,月头月尾各发烧一次。突然间发觉,本来身体单薄的我看来是一天不如一天了。呵呵~~~~

      每天回家都经过一个篮球场,每当我提头看那个生满铁锈的篮框,我就会有一股打篮球的冲动,并且想起过去同朋友一起打球的日子。但当爬上9楼后,我就发觉那真的是一时的冲动,我可是连动个手指头按按MOUSE都不想了(虽然我正在上网, :P)。

      想起来已经一年多没有碰过篮球了,记得刚打波的时候应该是94年吧。那时也不懂什么,见同学们打就玩玩。而且去关注篮球这项运动,也因为这样。我知道了这个地球上有一个上帝般人称小飞侠的Michael Jordan,他颠覆了这项运动!我开始像每一个打BASKETBALL的孩子一样崇拜他,可惜他那时在打着棒球,我想我是没有机会看他球场上的风采了。须知道那时没有BT,我也没有Internet玩,也找不到他的VCD,就只有一周几场NBA转播。

      后来,他复出了,又做了神一样的事出来。那时正是我打篮球狂热的时候,全部兄弟每天下午都要打上最少3个小时。整天想找人打比赛,那种热情现在想起来真的好怀念,是好怀念同大伙一起打球的日子和那份感情。想起来,那时的身体比现在强多了,起码不会一个月病两次啊……-_-!郁闷…….

      他第二次离开,我发现我已经没那么喜欢打球了。不,是没有了以前的那种热情。当他第三次回来,我没有看他打过比赛,因为我怕失望,怕他不再是神了。但我还是看了他精彩的ALL STAR演出。可惜让个蠢人废掉了,呵呵。

      这一两年没打过球,有工作的原因也有因为没有了过去一起打球的朋友为伴,篮球已经随着JORDAN的离开而离我而去,健康已经随着体育煅练的缺乏而离我而去。

      唉,有时间还是做做运动吧~~~

Hibernate快速上手

版权声明:CSDN是本Blog托管服务提供商。如本文牵涉版权问题,CSDN不承担相关责任,请版权拥有者直接与文章作者联系解决。

其实Hibernate本身是个独立的框架,它不需要任何web server或application server的支持。然而,大多数的Hibernate入门介绍都加入了很多非Hibernate的东西,比如: Tomcat, Eclipse, Log4J,Struts, XDoclet, 甚至JBoss。这容易让人产生Hibernate复杂难懂的误解,特别是打击了初学者的积极性。

在这篇文章将不涉及Eclipse, log4j, Struts, Tomcat, XDoclet,和JBoss。本文的目的是演示一下Hibernate的安装过程以及最基本的功能,从而给初学者一个低得不能再低的入门门槛。

下载文件

你需要Java SDK、 Hibernate包、Ant包、和JDBC Driver。

1、Hibernate包下载地址:
http://prdownloads.sourceforge.net/hibernate/?sort_by=date&sort=desc

2、Ant包下载地址:
http://apache.130th.net/ant/binaries/apache-ant-1.6.1-bin.zip

3、JDBC Driver要根据你用的database来定,一般database官方网站上都会有。Hibernate支持常用的database,比如 MySQL, Oracle, PostgreSQL, 和MS-SQL Server。这些数据库都有JDBC Driver:

Oracle JDBC Driver下载地址(下载前必须同意Oracle协议书)
http://otn.oracle.com/software/htdocs/distlic.html?/software/tech/java/sqlj_jdbc/htdocs/jdbc9201.html

MySQL JDBC Driver下载地址
http://dev.mysql.com/downloads/connector/j/3.0.html

PostgreSQL JDBC Driver下载地址
http://jdbc.postgresql.org/download.html

MS-SQL Server JDBC Driver下载地址
http://www.microsoft.com/downloads/details.aspx?FamilyID=9f1874b6-f8e1-4bd6-947c-0fc5bf05bf71&displaylang=en

4、将Hibernate包和Ant包分别解压至c:\dev\下(此目录不重要,你可以换其它任何目录)。

配置环境

1、你需要添加一个新的环境变量: ANT_HOME,让它指向c:\dev\<你的ANT包所在目录>。并在PATH环境变量里添加%ANT_HOME%\bin。

2、你需要添加一个新的环境变量: JAVA_HOME,让它指向你的j2sdk根目录。并在PATH环境变量里添加%JAVA_HOME%\bin。

3、创建一个项目目录,比如c:\workspace\My1stHibernate。

在项目目录下,另外创建三个目录: src, classes, lib。

在lib目录下,创建两个目录: hibernate和db。

这样你有了如下的文件结构:

c:\workspace\My1stHibernate\
c:\workspace\My1stHibernate\src
c:\workspace\My1stHibernate\classes
c:\workspace\My1stHibernate\lib
c:\workspace\My1stHibernate\lib\hibernate
c:\workspace\My1stHibernate\lib\db

4、将c:\dev\<你的Hibernate包所在目录>\hibernate2.jar文件copy到c:\workspace\My1stHibernate\lib\hibernate下。

将c:\dev\<你的Hibernate包所在目录>\lib\下的所有文件同样copy到c:\workspace\My1stHibernate\lib\hibernate下。

将你的JDBC Driver文件(一般是一个jar文件)copy到c:\workspace\My1stHibernate\lib\db下。

创建数据库

1、用你最喜爱的database软件,创建一个hibernate_test的数据库。

2、在此数据库下,新建一个table名为CUSTOMER

CREATE TABLE CUSTOMER
(
    CID INTEGER NOT NULL PRIMARY KEY,
    USERNAME VARCHAR(12) NOT NULL,
    PASSWORD VARCHAR(12)
);

编写Java文件

public class Customer {
   
    private int id;
    private String username;
    private String password;

    public int getId() {
        return id;
    }

    public String getPassword() {
        return password;
    }

    public String getUsername() {
        return username;
    }

    public void setId(int id) {
        this.id = id;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setUsername(String username) {
        this.username = username;
    }

}

将此类存为c:\workspace\My1stHibernate\src\Customer.java文件。

编写Test类

import net.sf.hibernate.*;
import net.sf.hibernate.cfg.*;

public class Test {

    public static void main(String[] args) {

        try {
            SessionFactory sf =
                new Configuration().configure().buildSessionFactory();
            Session session = sf.openSession();
            Transaction tx = session.beginTransaction();

            for (int i = 0; i < 200; i++) {
                Customer customer = new Customer();
                customer.setUsername(“customer” + i);
                customer.setPassword(“customer”);
                session.save(customer);
            }

            tx.commit();
            session.close();

        } catch (HibernateException e) {
            e.printStackTrace();
        }
    }
}

将此类存为c:\workspace\My1stHibernate\src\Test.java文件。

创建Hibernate映射文件

因为这里只有一个Class — Customer 和一个Table — CUSTOMER,你只需要建立一个映射文件— Customer.hbm.xml,来对应Customer类和CUSTOMER表之间的关系。

<?xml version=”1.0″?>
<!DOCTYPE hibernate-mapping PUBLIC
    “-//Hibernate/Hibernate Mapping DTD//EN”
    “http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd”>

<hibernate-mapping>
    <class name=”Customer” table=”CUSTOMER”>
        <id name=”id” column=”CID”>
            <generator class=”increment” />
        </id>
        <property name=”username” column=”USERNAME” />
        <property name=”password” column=”PASSWORD” />
    </class>
</hibernate-mapping>

把此文件存为c:\workspace\My1stHibernate\src\Customer.hbm.xml,和Customer.java放在同一目录下。


编写Ant build.xml文件

你不一定要知道这个build.xml的细节,其实Ant也不是Hibernate所必须的。这里用Ant是为了简化一些任务,比如: 编译、copy、运行,等。

<?xml version=”1.0″ ?>

<project name=”My1stHibernate” default=”build” basedir=”.”>

    <property name=”base.dir” value=”.” />
    <property name=”src.dir” value=”src” />
    <property name=”lib.dir” value=”lib” />
    <property name=”build.dir” value=”classes” />

    <path id=”myclasspath”>
        <fileset dir=”${lib.dir}”>
            <include name=”**/*.jar” />
        </fileset>
        <pathelement location=”${build.dir}” />
    </path>

    <target name=”init”>
        <mkdir dir=”${build.dir}” />
    </target>
   
    <target name=”build” depends=”init” description=”compile the source files”>
        <javac classpathref=”myclasspath” srcdir=”${src.dir}” destdir=”${build.dir}” />
        <copy todir=”${build.dir}” >
            <fileset dir=”${src.dir}” >
                <exclude name=”**/*.java”/>
            </fileset>
        </copy>
    </target>

    <target name=”run” depends=”build”>
        <java classpathref=”myclasspath” classname=”Test” fork=”true” />
    </target>

    <target name=”clean”>
        <delete includeEmptyDirs=”true”>
            <fileset dir=”${build.dir}” />
        </delete>
    </target>

</project>

配置Hibernate描述文件

Hibernate描述文件可以是一个properties或xml 文件,其中最重要的是定义数据库的连接。我这里列出的是一个XML格式的hibernate.cfg.xml描述文件。

<?xml version=”1.0″ encoding=”utf-8″ ?>
<!DOCTYPE hibernate-configuration
    PUBLIC “-//Hibernate/Hibernate Configuration DTD//EN”
    “http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd”>

<hibernate-configuration>
   
    <session-factory name=”java:/hibernate/HibernateFactory”>
       
        <property name=”show_sql”>true</property>
        <property name=”connection.driver_class”>
            oracle.jdbc.driver.OracleDriver <!– 这里是Oracle 9i的JDBC driver class名 –>
        </property>
        <property name=”connection.url”>
            jdbc:oracle:oci8:@hibernate_test <!– 这里是Oracle的hibernate_test数据库URL –>
        </property>
        <property name=”connection.username”>
            你的数据库用户名
        </property>
        <property name=”connection.password”>
            你的数据库密码
        </property>
        <property name=”dialect”>
            net.sf.hibernate.dialect.Oracle9Dialect <!– 这里是Oracle 9i的Dialect –>
        </property>
       
        <mapping resource=”Customer.hbm.xml” /> <!– 指定Customer的映射文件 –>
       
    </session-factory>
   
</hibernate-configuration>

如果你用的不是Oracle 9i,可到C:\dev\<你的Hibernate包所在目录>\src\hibernate.properties文件里找到你的数据库,然后替换以上相对应的值。

开始运行

到c:\workspace\My1stHibernate下,运行ant run。如果你严格依照以上步骤,应该看到

run:
        [java] log4j:WARN No appenders could be found for logger (net.sf.hibernate.cfg.Environment).
        [java] log4j:WARN Please initialize the log4j system properly.
        [java] Hibernate: insert into CUSTOMER (USERNAME, PASSWORD, CID) values (?, ?, ?)
BUILD SUCCESSFUL

到你的hibernate_test数据库看一下,在CUSTMOR表里新添了200条记录,但你没有写任何JDBC code。
以后如果你要更换数据库,只需要改变hibernate.cfg.xml描述文件里相应的值即可。

2004年08月23日

在开发JSP时,经常用到像test.jsp?param1=value1&param2=value2&param3=value3这样的链接。通常我们可能这样做:

<a href=”test.jsp?param1=<%=value1%>&param2=<%=value2%>&param3=<%=value3%>”>link</a>

当只有一两个参数时,这倒成不了问题,但当有十个以上的参数要传递时(有时这是不可避免的)就不同了,而且容易出错,虽然调试起来很方便就知道有没有错了,但谁也不会愿意在这个地方耗费精力的。即使是那么一点。

那么在Struts中又是怎样呢?

当然,你可以像上面提到的那样去做,没有问题。但是否有更好的方法?的确是有的。从<html:link>的定义我知道,它允许我放入一个HashMap,因为我用的是动态FORM,我试着这样做

<%
java.util.HashMap newValues = (HashMap)(( org.apache.struts.validator.DynaValidatorForm)request.getAttribute(“searchRoadbill”)).getMap();
%>

这使我得到一个HashMap,也许还有更好的方法取得它,但我用了一个我最快想到的方法。然后该做什么呢?

嘻嘻,把它放到页作用域中去

pageContext.setAttribute(“links”,newValues);

最后:

      <html:link href=”afaa.jsp” name=”links”>dsfasfa</html:link>

这样,就生成一个这样的连接:

 <a href=”afaa.jsp?receiveDeptName=&amp;pre_SendDate=&amp;pre_FillBillDate=&amp;receiveDept=&amp;suf_SendDate=&amp;suf_FillBillDate=&amp;roadbillId=&amp;status=1201″>dsfasfa</a>

这里的receiveDeptName,pre_SendDate等都是从form里去定义的。当它有值时输出如status=1201,如果没有值就为空。

http://localhost:7001/transit/afaa.jsp?receiveDeptName=&pre_SendDate=&pre_FillBillDate=&receiveDept=&suf_SendDate=&suf_FillBillDate=&roadbillId=&status=1201

后记:

在这里,我没有限制自己必须使用标记库,也没有明确的告诉自己该怎样去写JSP页面,反正我觉得,该怎么方便就怎么用。

资源

http://struts.apache.org/userGuide/struts-html.html#link

2004年07月26日

struts中分页的一种实现

 

我的项目中的分页功能

1,  思路

 

使用一个页面控制类,它记录页面信息,如上页,下页,当前页等。在查询的Action中,将这个控制类和查询条件一起传递给数据库访问bean,然后将这两个参数保存在用户session中。在分页控制Action中,利用接收到的分页参数调用数据库访问的bean.

 

 

2,实现

 

(1)分页控制类

/* @author nick

 * Created on 2004-3-18

 * file name:PageController.java

 *

 *

 */

package com.tower.util;

 

/**

 * @author nick

 * 2004-3-18

 * 用来进行翻页控制

 *

 */

public class PageController {

    int totalRowsAmount; //总行数

    boolean rowsAmountSet; //是否设置过totalRowsAmount

    int pageSize=2;   //每页行数

    int currentPage=1; //当前页码

    int nextPage;

    int previousPage;

    int totalPages;  //总页数

    boolean hasNext;  //是否有下一页

    boolean hasPrevious; //是否有前一页

    String description;

    int pageStartRow;

    int pageEndRow;

   

    public PageController(int totalRows){

        setTotalRowsAmount(totalRows);

    }

    public PageController(){}

   

 

 

 

 

    /**

     * @param i

     * 设定总行数

     */

    public void setTotalRowsAmount(int i) {

        if(!this.rowsAmountSet){

           totalRowsAmount = i;

           totalPages=totalRowsAmount/pageSize+1;

           setCurrentPage(1);

           this.rowsAmountSet=true;

       }

      

    }

 

    /**

     * @param i

     *

     * 当前页

     *

     */

    public void setCurrentPage(int i) {

        currentPage = i;

        nextPage=currentPage+1;

        previousPage=currentPage-1;

       //计算当前页开始行和结束行

        if(currentPage*pageSize<totalRowsAmount){

           pageEndRow=currentPage*pageSize;

           pageStartRow=pageEndRow-pageSize+1;

          

        }else{

           pageEndRow=totalRowsAmount;

           pageStartRow=pageSize*(totalPages-1)+1;

       }

      

      

       //是否存在前页和后页

      

       if (nextPage>totalPages){

           hasNext=false;

        }else{

           hasNext=true;

       }

        if(previousPage==0){

          hasPrevious=false;

        }else{

           hasPrevious=true;

       };

        System.out.println(this.description());

    }

 

    /**

     * @return

     */

    public int getCurrentPage() {

        return currentPage;

    }

 

    /**

     * @return

     */

    public boolean isHasNext() {

        return hasNext;

    }

 

    /**

     * @return

     */

    public boolean isHasPrevious() {

        return hasPrevious;

    }

 

    /**

     * @return

     */

    public int getNextPage() {

        return nextPage;

    }

 

    /**

     * @return

     */

    public int getPageSize() {

        return pageSize;

    }

 

    /**

     * @return

     */

    public int getPreviousPage() {

        return previousPage;

    }

 

    /**

     * @return

     */

    public int getTotalPages() {

        return totalPages;

    }

 

    /**

     * @return

     */

    public int getTotalRowsAmount() {

        return totalRowsAmount;

    }

 

    /**

     * @param b

     */

    public void setHasNext(boolean b) {

        hasNext = b;

    }

 

    /**

     * @param b

     */

    public void setHasPrevious(boolean b) {

        hasPrevious = b;

    }

 

    /**

     * @param i

     */

    public void setNextPage(int i) {

        nextPage = i;

    }

 

    /**

     * @param i

     */

    public void setPageSize(int i) {

        pageSize = i;

    }

 

    /**

     * @param i

     */

    public void setPreviousPage(int i) {

        previousPage = i;

    }

 

    /**

     * @param i

     */

    public void setTotalPages(int i) {

        totalPages = i;

    }

    /**

     * @return

     */

    public int getPageEndRow() {

        return pageEndRow;

    }

 

    /**

     * @return

     */

    public int getPageStartRow() {

        return pageStartRow;

    }

 

    public String getDescription(){

       String description=“Total:”+this.getTotalRowsAmount()+

       ” items “+this.getTotalPages() +” pages”;

//     this.currentPage+” Previous “+this.hasPrevious +

//     ” Next:”+this.hasNext+

//     ” start row:”+this.pageStartRow+

//     ” end row:”+this.pageEndRow;

       return description;

    }

   

    public String description(){

       String description=“Total:”+this.getTotalRowsAmount()+

       ” items “+this.getTotalPages() +” pages,Current page:”+

       this.currentPage+” Previous “+this.hasPrevious +

       ” Next:”+this.hasNext+

       ” start row:”+this.pageStartRow+

       ” end row:”+this.pageEndRow;

       return description;

    }

   

   

    public static void main(String args[]){

        PageController pc=new PageController(3);

        System.out.println(pc.getDescription());

//        pc.setCurrentPage(2);

//      System.out.println(pc.description());

//      pc.setCurrentPage(3);

//      System.out.println(pc.description());

    }

 

 

}

 

2)查询Action的代码片断

 

    public ActionForward execute(

        ActionMapping mapping,

        ActionForm form,

        HttpServletRequest request,

        HttpServletResponse response)

        throws Exception {

       Base queryForm= (Base) form;

          

        if(!queryForm.getName().equals(“”)){

           PageController pc=new PageController();        

            EmployeeBase service=new EmployeeBase();      

            ArrayList result=(ArrayList)service.search(queryForm,pc);

          

            HttpSession session=request.getSession();

           

           session.setAttribute(“queryForm”,queryForm);

            session.setAttribute(“pageController”,service.getPageController());

          

            request.setAttribute(“queryResult”,result);   

           request.setAttribute(“pageController”,service.getPageController());       

           return mapping.findForward(“haveResult”);

        }else{

           return mapping.findForward(“noResult”);

        }

      

      

      

   

    }

 

3),翻页Action的代码片断

 

public ActionForward execute(

        ActionMapping mapping,

        ActionForm form,

        HttpServletRequest request,

        HttpServletResponse response)

        throws Exception {

   

          

        //读取翻页参数

              

        TurnPageForm turnPageForm=(TurnPageForm)form;

      

       //PageController中取出查询信息,并使用bean提供的调用接口处理结果

        

        HttpSession session=request.getSession();

        PageController pc=(PageController)session.getAttribute(“pageController”);    

       Base queryForm=(Base)session.getAttribute(“queryForm”);

      

   

        pc.setCurrentPage(turnPageForm.getViewPage());

      

        EmployeeBase service=new EmployeeBase();

      

        ArrayList result=(ArrayList)service.search(queryForm,pc);

      

       //根据参数将数据写入 request

      

        request.removeAttribute(“queryResult”);

        request.removeAttribute(“pageController”);

        request.setAttribute(“queryResult”,result);   

        request.setAttribute(“pageController”,pc);

              

        //forward 到显示页面

      

      

      

        return mapping.findForward(“haveResult”);

      

      

      

      

   

    }

 

4)数据库访问bean中的片断

 

public Collection search(Base base, PageController pc)

        throws SQLException {

        ArrayList emps = new ArrayList();

        ResultSet rs = getSearchResult(base);

 

        rs.absolute(-1);

        pc.setTotalRowsAmount(rs.getRow());

        setPageController(pc);

       if (rs.getRow() > 0) {

 

           rs.absolute(pc.getPageStartRow());

 

 

           do {

               System.out.println(“in loop” + rs.getRow());

 

               Base b = new Base();

               b.setName(rs.getString(“Name”));

               b.setIdCard(rs.getString(“IDCard”));

               System.out.println(“From db:” + rs.getString(“IDCard”));

               emps.add(b);

               if (!rs.next()) {

                   break;

               }

           } while (rs.getRow() < (pc.getPageEndRow() + 1));

       }

        return emps;

    }

 

 

(5)jsp中,翻页部分的代码片断

 

<bean:write name=”pageController” property=”description”/>

      

        <logic:equal name=”pageController” property=”hasPrevious” value=”true”>

              <a href=”turnPage.do?viewPage=<bean:write name=”pageController” property=”previousPage“/>” class=”a02″>

                Previous

             </a>

        </logic:equal>

 

        <logic:equal name=”pageController” property=”hasNext” value=”true”>

          <a href=”turnPage.do?viewPage=<bean:write name=”pageController” property=”nextPage“/>” class=”a02″>

          Next

          </a>

        </logic:equal>

 

 

 

这样一来,翻页的功能可以以你喜欢的方式表现给client

2004年07月17日

一. 步骤:  基本上缺一不可 
1.配置 Validator  plugin:  struts-config.xml   
plug-in  className=  “org.apache.struts.validator.ValidatorPlugIn  “   
    set-property   
  property=  “pathnames  “    value=  “/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml  “/   
/plug-in   
This  plug-in  should  be  the  very  last  thing  in  the  file  before  the    /struts-config 
2.  配置resource  properties  file:web.xml    (Copy  Struts例子中的文件到如下设置的位置) 
servlet-name  action  /servlet-name   
        servlet-class  org.apache.struts.action.ActionServlet &lt;/servlet-class 
        init-param   
            param-name  application  /param-name 
            param-value demo.ApplicationResources  /param-value   
        /init-param  
则对应ApplicationResources.properties文件要放在src/demo/下 
3.修改Form类代码:  LoginForm  extends  ValidatorForm  implements  Serializable{} 

4.修改Form的validate  方法:如果验证规则validation-rules都有的话,validate方法不用实现,
但如果需要一些自定义的验证条件,而又不想写一个plugin validator的话,就需要在form的validate方法中实现。
 
public  ActionErrors  validate(ActionMapping  actionMapping, 
                                                            HttpServletRequest  httpServletRequest)  { 
      /**@todo:  finish  this  method,  this  is  just  the  skeleton.*/ 
      ActionErrors  errors=super.validate(actionMapping,  httpServletRequest);    //必须调用
      if  (errors  ==  null) 
          errors  =  new  ActionErrors(); 
/*  自己的验证:但不应该有调用业务逻辑方法来验证。最后的“把关”验证可以放在Action的方法中,
* 因为不合格的数据不应该传递给业务层。 

      if  (  “S  “.equals(deliveryType))  { 

          if  (  “  “.equals(getShipVendor().trim()))  { 
              errors.add(ActionErrors.GLOBAL_ERROR, 
                                    new  ActionError(  “item.shipVendor.maskmsg  “)); 
          } 
*/ 
    if  (errors.isEmpty()) 
                return  null; 
    return  errors; 

 

5. 配置ActionMapping:  validate=”true”,  input=”/login.jsp”:  (should  reference  to  jsp  page  with  validated  form) 
6. Copy  Struts例子中的Validation.xml,  validator-rules  to  WEB-INF目录 
7. 添加到jbuilder中,在文件上右健,  properties  check  the  “copy”  radio 
8. 修改Validation.xml:add  formset-  &gt;  form-  &gt;  field,  名字要求一致:表单中字段的名字和form中的属性名,消息的key和对应资源文件中的key;  struts配置文件中form的名字与validation.xml的form名; 
9. 客户端javaScript验证:  需要在页面上加入 
a)  %@  taglib  uri=  “/WEB-INF/struts-html.tld  “  prefix=  “html  “  %   
b)  form    action=  “loginAction.do  “  onsubmit=  “return  validateLoginForm(this);  “   
c)  /form  后加入:  &lt;html:javascript  formName=  “loginForm  “  dynamicJavascript=  “true  “  staticJavascript=  “true  “/  
10.如果要页面上出现服务器端的验证错误信息,需要在jsp代码中加入
  html:errors/&gt;

二.        要点
1. 取消验证
客户端 取消javascript 验证:有些按钮可能不需要验证,如取消按钮,这是只要加上 onclick=”bCancel=true;” 即可
  服务器断取消验证:
    在form的validate()方法中:判断请求,如只有当按下保存按钮时才验证
String submitSave = req.getParameter(“submitSave”);

    if (submitSave != null) {

      System.out.println(“validate method called………………………..”);
      ActionErrors errors = super.validate(actionMapping, req);
     
      if (errors == null) {
        errors = new ActionErrors();

        /* //自己的验证
                */

      }
      if (errors.isEmpty()) {
        return null;
      }
      return errors;
    }
    else {
      System.out.println(“———————————-needn’t validate”);
      return null;
    }

2.        正则表达式
Struts 的mask支持对正则表达式的验证, 正则表达式语法参考: PHP之家的 正则表达式使用详解.htm

3.使ApplicationResources.properties支持中文 (参考某位网友的,名字忘了,谢谢)
建立一个ApplicationResources_ISO.properties文件,把应用程序用的message都写进去,然后在dos下执行这个命令,
native2ascii -encoding gb2312 ApplicationResources_ISO.properties ApplicationResources.properties
这样就会将ISO编码的ApplicationResources转换成GB2312编码的格式了,同时保存到ApplicationResources.properties.
native2ascii这个工具是jdk自带的一个东东,所以如果path都设定正确就可以直接运行了,你可以在$java_home$/bin下找到他。
转换后的中文类似于这个样子
iso 格式下 :tj.type=商品车类型
gb2312格式下 :tj.type=\u5546\u54c1\u8f66\u7c7b\u578b
然后在struts-config.xml中设置应用这个资源文件
message-resources parameter=”com.huahang.tj.ApplicationResources” key=”org.apache.struts.action.MESSAGE”
开发jsp时在jsp的开头写上%@ page contentType=”text/html; charset=gb2312″ %&gt;,将字符集设置成gb2312就可以了。       

4。详细资料参考:
Introductory book: Struts Kick Start, chapter 17
Reference book: Struts in Action, chapter 12
Struts例子: struts1.1自带的 struts-validator.war

(转自http://java.mblogger.cn/zouwenyan/posts/2516.aspx)

前两种是利用javascript,后面一种是在使用Struts的情况下的参考实现

  • 1 javascript ,设置一个变量,只允许提交一次。
    <script language="javascript"> var checkSubmitFlg = false; function checkSubmit() { if (checkSubmitFlg == true) { return false; } checkSubmitFlg = true; return true; } document.ondblclick = function docondblclick() { window.event.returnValue = false; } document.onclick = function doconclick() { if (checkSubmitFlg) { window.event.returnValue = false; } }</script>

    <html:form action=”myAction.do” method=”post” onsubmit=”return checkSubmit();”>

  • 2 还是javascript,将提交按钮或者image置为disable

     <html:form action="myAction.do" method="post"  onsubmit="getElById('submitInput').disabled = true; return true;"> 
    
     <html:image styleId="submitInput" src="images/ok_b.gif" border="0" />
    
     </html:form>
    
    
  • 3 利用struts的同步令牌机制

    利用同步令牌(Token)机制来解决Web应用中重复提交的问题,Struts也给出了一个参考实现。

    基本原理:

    服务器端在处理到达的请求之前,会将请求中包含的令牌值与保存在当前用户会话中的令牌值进行比较,
    看是否匹配。在处理完该请求后,且在答复发送给客户端之前,将会产生一个新的令牌,该令牌除传给
    客户端以外,也会将用户会话中保存的旧的令牌进行替换。这样如果用户回退到刚才的提交页面并再次
    提交的话,客户端传过来的令牌就和服务器端的令牌不一致,从而有效地防止了重复提交的发生。

    if (isTokenValid(request, true)) { // your code here return mapping.findForward("success");} else { saveToken(request); return mapping.findForward("submitagain");}

    Struts根据用户会话ID和当前系统时间来生成一个唯一(对于每个会话)令牌的,具体实现可以参考
    TokenProcessor类中的generateToken()方法。

    1. //验证事务控制令牌,<html:form >会自动根据session中标识生成一个隐含input代表令牌,防止两次提交
    2. 在action中:

     //<input type="hidden" name="org.apache.struts.taglib.html.TOKEN"  // value="6aa35341f25184fd996c4c918255c3ae"> if (!isTokenValid(request)) errors.add(ActionErrors.GLOBAL_ERROR, new ActionError("error.transaction.token")); resetToken(request); //删除session中的令牌

    3. action有这样的一个方法生成令牌

     protected String generateToken(HttpServletRequest request) {
    
     HttpSession session = request.getSession(); try { byte id[] = session.getId().getBytes(); byte now[] = new Long(System.currentTimeMillis()).toString().getBytes(); MessageDigest md = MessageDigest.getInstance("MD5"); md.update(id); md.update(now); return (toHex(md.digest())); } catch (IllegalStateException e) { return (null); } catch (NoSuchAlgorithmException e) { return (null); } } 
  • 2004年07月02日

             一直以来都是使用JB来开发,JB也没有什么不好,而且现在越来越变得强劲,但随之带来的,就是性能的低下了。而且,感觉在JB中编译和打包特别慢,常常要十多分钟不等。早就听说过Eclipse的好处,开源而且同样功能强大。但工作上一直都离不开JB,所以也没有深入的使用它。毕竟当你用一个工具去开发时,你才知道它是否真的适合你使用。

                这几天,有了一点时间,就下了Eclipse 3.0的正式版来试试。并找到了一些插件,包括Lomboz,MyEclipse,Struts Studio,全都装上了。其他还有一些有名的,因为暂时不会用到,就没有去下。然后随便建了一些简单的项目试了试,感觉还不错,只是老是用JB的快捷键去操作。不过这还好,慢慢会习惯过来的。

                但还没有真正下决心把我的开发工具转到Eclipse去,毕竟有公司项目规定开发工具的原因,而且感觉用Eclipse开发EJB没有JB的强大。在JB中可以创建一个EJB Designer进行可视化开发,而且有强大的向导功能。我不敢说在Eclipse中没有,但我真的感觉不好。或者有更好的EJB插件,但还没有找到。看来会有以下的可能,用JB开发EJB(其实只要建好模就好了),然后用Eclipse开发Struts(上面提到的几个插件对开发Struts比JB中强多了。虽然要付费……但……..嘻嘻)。但会不会太过麻烦了呢?还是要继续忍受JB的缓慢?

    刚准备回家,找到下面一篇关于Eclipse下开发EJB的文章,看看不错,但没有细看:

    http://www.tusc.com.au/tutorial/html/index.html

    JBuilder 还是Eclipse?看来是一个问题。

    2004年06月30日

    Money is not everything. There‘s Mastercard & Visa.
       钞票不是万能的,有时还需要信用卡.
      
       One should love animals. They are so tasty.
       每个人都应该热爱动物,因为它们很好吃.
      
       Love the neighbor. But don‘t get caught.
       要用心去爱你的邻居,不过不要让她的老公知道.
      
       Behind every successful man, there is a woman. And behind every unsuccessful man, there are two.
       每个成功男人的背后都有一个女人,每个不成功男人的背后都有两个女人。
      
       Every man should marry. After all, happiness is not the only thing in life.
       再快乐的单身汉迟早也会结婚,幸福不是永久的嘛.
      
       The wise never marry, And when they marry they become otherwise.
       聪明人都是未婚的,结婚的人很难再聪明起来.
      
       Success is a relative term. It brings so many relatives.
       成功是一个相关名词,他会给你带来很多不相关的亲戚(联系).
      
       Never put off the work till tomorrow what you can put off today.
       不要等明天交不上差再找借口, 今天就要找好.
      
       Love is photogenic. It needs darkness to develop.
       爱情就象照片,需要大量的暗房时间来培养.
      
       Children in backseats cause accidents. Accidents in backseats cause children.
       后排座位上的小孩会生出意外, 后排座位上的意外会生出小孩.
      
       “Your future depends on your dreams.” So go to sleep.
       “现在的梦想决定着你的将来”,所以还是再睡一会吧.
      
       There should be a better way to start a day than waking up every morning.
       应该有更好的方式开始新一天,而不是千篇一律的在每个上午都醒来.
      
       “Hard work never kills anybody.” But why take the risk? ”
       努力工作不会导致死亡!”不过我不会用自己去证明.
      
       “Work fascinates me.” I can look at it for hours! ”
       工作好有意思耶!”尤其是看着别人工作.

      
       God made relatives; Thank God we can choose our friends.
       神决定了谁是你的亲戚,幸运的是在选择朋友方面他给了你留了余地。
      
       When two‘s company, three‘s the result!
       两个人的状态是不稳定的,三个人才是!
      
       A dress is like a barbed fence. It protects the premises without restricting the view.
       服饰就象铁丝网,它阻止你冒然行动,但并不妨碍你尽情地观看.
      
       The more you learn, the more you know, The more you know, the more you forget. The more you forget, the less you know. So why bother to learn.
       学的越多,知道的越多, 知道的越多;忘记的越多, 忘记的越多;知道的越少, 为什么学来着?

    2004年05月25日

    以下翻译自eclipse网站

     

    1 可以保存/读取workspace
    2 可以选择使用2.1的外观
    3 “进度”对话框改进,可以显示更详尽的进程/进度信息
    4 editor支持斜体
    5 对话框可以使用系统图标(警告/信息/错误等)
    6 可以同时支持多个文件的多种encoding,并且可以设置
    7 “提示”和”快速纠正”的设置选项合并
    8 选中文本的颜色可以定制
    9 提供文本的折叠(flolding)功能,方法等代码也可以折叠了
    10 支持无标题的提示(不太明白)
    11 查找/替换支持正则表达式
    12 帮助窗口外观与workbench一致
    13 帮助窗口提供”最大化/恢复”按钮
    14 安装额外的文档不需要重启
    15 帮助窗口支持双向的语言(从右往左看或从左往右看)
    16 插件更新支持本地安装的站点(用的不多,所以不太理解)
    17 根据语义进行着色(highlighting),也就是说,可以给静态变量,本地变量,静态方法等设置不同的着色和样式,并且可以使用斜体
    18 java working set可以包含非java projects
    19 重载的方法可以在editor里标明(象error/warning那样)
    20 javadoc使用SWT BROWSER WIDGET来显示
    21 可配置的”occurence marking”
    22 在使用模板的时候也能根据情况给出建议(提示)
    23 可以从inner type中提取方法
    24 给方法的返回点着色
    25 快速菜单:源代码的重构菜单可以用快捷键的方式调出(Alt+Shift+S和Alt+Shift+T)
    26 提取本地变量和转换本地变量时也提供代码提示
    27 改进了NLS wizard
    28 粘贴代码时,自动判断是否需要添加新的import
    29 更多的”快速纠正”选项
    30 更便捷的方式来生成getter/setter方法
    40 给基类生成指定的方法
    41 格式化多个文件
    42 java search支持过滤
    43 可以自动标出空的流程控制语句
    44 自动判断在else块中不需要的语句
    45 可以根据指定的样式来配置build path
    46 预览J2SE1.5的新功能(需要下载插件)