利用BeanUtils在对象间复制属性

commons-beanutils是jakarta commons子项目中的一个软件包,其主要目的是利用反射机制对JavaBean的属性进行处理。我们知道,一个JavaBean通常包含了大量的属性,很多情况下,对JavaBean的处理导致大量get/set代码堆积,增加了代码长度和阅读代码的难度(什么,你的薪水按代码行数计算?那千万别让老板看到此帖哦)

file

BeanUtils是这个包里比较常用的一个工具类,这里只介绍它的copyProperties()方法。该方法定义如下:

public static void copyProperties(java.lang.Object dest,java.lang.Object orig)
  throws java.lang.IllegalAccessException,
         java.lang.reflect.InvocationTargetException

如果你有两个具有很多相同属性的JavaBean,一个很常见的情况就是Struts里的PO对象(持久对象)和对应的ActionForm,例如Teacher和TeacherForm。我们一般会在Action里从ActionForm构造一个PO对象,传统的方式是使用类似下面的语句对属性逐个赋值:

//得到TeacherForm
TeacherForm teacherForm=(TeacherForm)form;
//构造Teacher对象
Teacher teacher=new Teacher();
//赋值
teacher.setName(teacherForm.getName());
teacher.setAge(teacherForm.getAge());
teacher.setGender(teacherForm.getGender());
teacher.setMajor(teacherForm.getMajor());
teacher.setDepartment(teacherForm.getDepartment());

//持久化Teacher对象到数据库
HibernateDAO=;
HibernateDAO.save(teacher);

而使用BeanUtils后,代码就大大改观了,如下所示:

//得到TeacherForm
TeacherForm teacherForm=(TeacherForm)form;
//构造Teacher对象
Teacher teacher=new Teacher();
//赋值
BeanUtils.copyProperties(teacher,teacherForm);
//持久化Teacher对象到数据库
HibernateDAO=;
HibernateDAO.save(teacher);

如果Teacher和TeacherForm间存在名称不相同的属性,则BeanUtils不对这些属性进行处理,需要程序员手动处理。例如Teacher包含modifyDate(该属性记录最后修改日期,不需要用户在界面中输入)属性而TeacherForm无此属性,那么在上面代码的copyProperties()后还要加上一句:

teacher.setModifyDate(new Date());

怎么样,很方便吧!除BeanUtils外还有一个名为PropertyUtils的工具类,它也提供copyProperties()方法,作用与BeanUtils的同名方法十分相似,主要的区别在于后者提供类型转换功能,即发现两个JavaBean的同名属性为不同类型时,在支持的数据类型范围内进行转换,而前者不支持这个功能,但是速度会更快一些!

BeanUtils支持的转换类型如下:

  • java.lang.BigDecimal
  • java.lang.BigInteger
  • boolean and java.lang.Boolean
  • byte and java.lang.Byte
  • char and java.lang.Character
  • java.lang.Class
  • double and java.lang.Double
  • float and java.lang.Float
  • int and java.lang.Integer
  • long and java.lang.Long
  • short and java.lang.Short
  • java.lang.String
  • java.sql.Date
  • java.sql.Time
  • java.sql.Timestamp

这里要注意一点,java.util.Date是不被支持的,而它的子类java.sql.Date是被支持的。因此如果对象包含时间类型的属性,且希望被转换的时候,一定要使用java.sql.Date类型。否则在转换时会提示argument mistype异常。

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2004/07/30/28607.html

[Struts]学习日记3 – 在页面中显示条目列表

开发jsp/servlet最经常遇到的应用其中之一就是在页面上显示一个条目列表(例如用户列表、文章列表、商品列表等等),然后用户才好在浏览的基础上选择对某一个条目进行操作。现在就说一下怎样用struts实现这个功能。

一般来说,用struts开发的应用是不应该直接访问.jsp文件的,而是由action转发请求,jsp只是显示action传来的数据用。所以即使这样简单的一个应用,也还是需要一个action的。

1、还是使用easy struts的向导,在菜单里选择File->New->Other,然后选择Easy Action这一项。这就打开一个向导窗口,该向导只有两步,比学习日记1里的少了创建form bean的那一步。

2、我们给要创建的action起名叫listItems好了,也就是说,在user case框里输入listItems。Type最好根据需要修改一下包名称。按下一步继续。

3、增加一个名为success的forward,path为/form/listItems.jsp。按finish按钮完成整个向导。

4、下面,首先编辑刚刚生成的ListItemsAction.java文件,修改execute方法如下:

public ActionForward execute(ActionMapping mapping, ActionForm form,
    HttpServletRequest request, HttpServletResponse response) throws Exception {

    User user = new User();
    List items = new ArrayList();
    items.add(new Item("001", "Medicine"));
    items.add(new Item("002", "Ticket"));
    items.add(new Item("003", "Clothes"));
    user.setItems(items);
    request.getSession().setAttribute("user", user);

    return (mapping.findForward("success"));
}

这里的User和Item都是我们自己写的类,一个User可以拥有多个items,Item具有id和name两个属性。具体代码见后。

5、接下来在/form下创建名为listItems.jsp的文件,内容如下:

<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html"%>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<html>
 <head>
  <title>itemlist</title>
 </head>
 <body>
  <table>
  <logic:iterate name="user" property="items" id="item">
   <tr>
    <td><bean:write name="item" property="id" filter="true"/></td>
    <td><bean:write name="item" property="name" filter="true"/></td>
   </tr>
  </logic:iterate>
  </table>
 <body>
</html>

这里关键的就是这个标签,在这个例子中,它用来遍历session或request中key为user对应的对象的items属性,在遍历过程中可用item引用每个对象()。用于输出每个对象的不同属性,filter="true"表示把特殊字符进行转换,例如<转换为<等等。

6、这样,就可以通过 http://localhost:8080/struts-test/listItems.do 看到一个条目列表了,如下所示:

001 Medicine
002 Ticket
003 Clothes

7、我们可以修改struts-config.xml文件,让用户登录成功后直接转向条目列表页面。只需要把原来logon action的名为success的forward的path由/form/main.htm改为/listItems.do就可以了。

附:

User.java代码:

public class User {  
   
    private List items;  
   
    public User(){  
        items=new ArrayList();  
    }  
   
    public List getItems() {  
        return items;  
    }

    public void setItems(List list) {  
        items = list;  
    }
}

Item.java代码:

public class Item {  
   
    private String id;  
    private String name;

    public Item(String arg0, String arg1){  
        id=arg0;  
        name=arg1;  
    }

    public String getId() {  
        return id;  
    }

    public String getName() {  
        return name;  
    }

    public void setId(String string) {  
        id = string;  
    }

    public void setName(String string) {  
        name = string;  
    }
}

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2004/07/28/28074.html

[Struts]报告异常”Cannot find bean in any scope”之一解

问题描述

今天在开发中遇到一奇怪问题,有一个action,在该action里使用request.setAttribute()方法将一个List类型对象放在request中,然后forward到一个jsp文件,该文件的主要内容是使用<logic:iterate>标签将这个List对象中的条目列表显示。与它同样逻辑但位于另一模块(teacher)中的代码执行正常。但这个模块(xxgl)中的代码,本来很简单的逻辑,却总是提示:

org.apache.jasper.JasperException: Cannot find bean t in any scope 
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:254) 
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:295) 
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:241) 
at javax.servlet.http.HttpServlet.service(HttpServlet.java:853) 
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:684) 
at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:432) 
at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:356) 
at org.apache.struts.action.RequestProcessor.doForward(RequestProcessor.java:1069) 
at org.apache.struts.action.RequestProcessor.processForwardConfig(RequestProcessor.java:455) 
at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:279) 
at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1482) 
at org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:507) 
at javax.servlet.http.HttpServlet.service(HttpServlet.java:740) 
at javax.servlet.http.HttpServlet.service(HttpServlet.java:853) 
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:247) 
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:193) 
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:256) 
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643) 
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480) 
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995) 
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) 
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643) 
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480) 
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995) 
at org.apache.catalina.core.StandardContext.invoke(StandardContext.java:2417) 
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:180) 
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643) 
at org.apache.catalina.valves.ErrorDispatcherValve.invoke(ErrorDispatcherValve.java:171) 
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641) 
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:172) 
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641) 
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480) 
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995) 
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:174) 
at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643) 
at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480) 
at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995) 
at org.apache.coyote.tomcat4.CoyoteAdapter.service(CoyoteAdapter.java:193) 
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:781) 
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:549) 
at org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java:589) 
at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:666) 
at java.lang.Thread.run(Unknown Source) 

<logic:iterate>之间的代码去掉后就不会提示错误了,所以怀疑是<bean:write>中的代码有错误。相关文件ListSfzxJbxxAction.java中的execute方法如下:

public ActionForward execute(ActionMapping mapping, ActionForm form, 
   HttpServletRequest request, HttpServletResponse response) throws Exception {

   HibernateDAO dao = HibernateDAO.getInstance(getServlet().getServletContext()); 
   List sfzxjbxxs = dao.find("from " + SfzxJbxx.class.getName()); 
   SfzxJbxx tmp = new SfzxJbxx(); 
   tmp.setSfzxid("id"); 
   tmp.setXxdm("pku"); 
   sfzxjbxxs.add(tmp); 
   request.setAttribute("sfzxjbxxs", sfzxjbxxs); 
   return mapping.findForward("success"); 
} 

listsfzxjbxx.jsp内容如下:

<%@ page contentType="text/html;charset=UTF-8" language="java" %> 
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%> 
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html"%> 
<head> 
      <title>SfzxJbxxList</title> 
</head> 
<body> 
<logic:iterate  name="sfzxjbxxs" id="sfzxjbxx"> 
  <tr> 
    <td align="left"> 
      <bean:write name="sfzxjbxx" property="sfzxId" filter="true"/> 
    </td> 
    <td align="left"> 
      <bean:write name="sfzxjbxx" property="xxdm" filter="true"/> 
    </td> 
    <td> 
    </td> 
  </tr> 
</logic:iterate> 
<body> 
</html> 

模块配置文件中相关内容如下:

<action-mappings> 
    <action 
        attribute="Form" 
        input="/form/sfzxjbxx.jsp" 
        name="sfzxJbxxForm" 
        path="/saveSfzxJbxx" 
        type="edu.pku.cc.sfzx.xxgl.action.SaveSfzxJbxxAction" /> 
    <action path="/listsfzxjbxx" type="edu.pku.cc.sfzx.xxgl.action.ListSfzxJbxxAction"> 
        <forward name="success" path="/form/listsfzxjbxx.jsp"/> 
    </action> 

</action-mappings> 

问题解决

经过三个小时的检查,发现是listsfzxjbxx.jsp里缺少<logic:iterate>标签的声明,在前面增加上:

<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic"%> 

一切OK!

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2004/07/28/28065.html

[Hibernate]使用XDoclet生成hbm.xml

Hibernate真是受欢迎,有那么多工具为它服务,XDoclet、MiddleGen、各种插件。。。

用XDoclet生成hbm.xml就是在.java文件里写入一些元数据,XDoclet会从这些数据以及类本身得到足够的信息来生成目标文件。当然,除了用于hibernate,XDoclet还可以用于web、ejb等等很多用途。

XDoclet要从sourceforge上下载,包含了很多jar包、文档和例子,我觉得文档做得还是不错的,查起来比较方便。要使用XDoclet,一般要通过ant来完成,也就是在ant脚本里加入XDoclet的内容。

由于eclipse已经包含了ant支持,因此我没有专门去下载一个ant回来,而是直接使用eclipse带的,版本是1.5.3。

创建一个名为build.xml的脚本(其实应该换个名,比如gen-hbm.xml,看起来比较明白),内容如下:

<?xml version="1.0" encoding="ISO-8859-1"?>

<project name="XDoclet Examples" default="hibernate" basedir=".">
    <property name="xdoclet.root.dir" value="c:/xdoclet-1.2.1"/>
    <property name="xdoclet.lib.dir" value="${xdoclet.root.dir}/lib"/>
    <path id="myclasspath">
        <fileset dir="${xdoclet.lib.dir}">
            <include name="*.jar"/>
        </fileset>
    </path>
     <taskdef
        name="hibernatedoclet"
        classname="xdoclet.modules.hibernate.HibernateDocletTask"
        classpathref="myclasspath"
        />
    <target name="hibernate" description="Generate mapping documents">

        <echo>+---------------------------------------------------+</echo>
        <echo>|                                                   |</echo>
        <echo>| R U N N I N G   H I B E R N A T E D O C L E T     |</echo>
        <echo>|                                                   |</echo>
        <echo>+---------------------------------------------------+</echo>

        <hibernatedoclet
            destdir="./src"
            excludedtags="@version,@author,@todo,@see"
            addedtags="@xdoclet-generated at ${TODAY},@copyright The XDoclet Team,@author XDoclet,@version ${version}"
            force="false"
            verbose="true">

            <fileset dir="./src">
                <include name="org/haree/struts/form/UserForm.java"/>
            </fileset>

            <hibernate version="2.0"/>

        </hibernatedoclet>
    </target>
</project>

我曾经卡住的一个地方就是在taskdef里的classpathref属性。一开始我在eclipse的ant运行参数里设置了XDoclet相关的包,总是提示:

Can't create a hibernate element under hibernatedoclet. Make sure the jar file
containing the corresponding subtask class is on the classpath specified in the
<taskdef> that defined {2}.

后来如上设置了classpathref,即包含了XDoclet使用到的包,并将eclipse的ant里关于XDoclet的包都去掉,竟然就成功了。其实现在也不明白为什么会这样。。。

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2004/07/28/28072.html

[Hibernate]关于ID的一个容易混淆的地方

用了这么久的Hibernate了,今天却遇到一个从未遇到的问题,幸好我思维敏捷,善于联想,才得以在短时间内发现并解决了问题。以下是具体描述。

我在HibernateDAO这个类里增加了一个方法如下:

public Object getById(Class clazz, String id) throws HibernateException{
   return session.find("from "+clazz.getName()+" o where o.id=?",id,Hibernate.STRING).get(0);
}

你知道,我的PO类的主键都是名为oid的。凑巧的是,有一些PO类除了具有oid属性外,还具有名为id的属性,用来表示业务编号,例如教师编号、文化程度的编号等等。这些类在使用这个方法时总报下面的异常:

java.lang.IndexOutOfBoundsException: Index: 0, Size: 0

郁闷了半个小时,终于想到,会不会是查询语句中的o.id,Hibernate认为这里的id表示的是主键oid呢?在debug里把参数按oid的值一改,发现果然如此!

解决方法:暂时还不知道有什么方法能起到转义的作用,不过id这个属性确实有点容易产生歧义,还是改名为code吧。

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2004/07/28/28064.html

[转载]HibernatePlugIn for Struts

这个Plugin的作用是在Struts应用程序启动时进行hibernate的初始化操作,原文请移步 HibernatePlugIn for Struts

步骤很简单:

1、在struts-config.xml里增加:

<plug-in className="org.haree.struts.HibernatePlugIn"> 
  <!-- 'path-to-config-file' is relative to the root of the class 
       path.  It MUST start with a '/'. The default is 
       "/hibernate.cfg.xml --> 
  <set-property property="configFilePath" value="path-to-config-file" /> 
  <set-property property="storeInServletContext" value="true-or-false" /> 
</plug-in> 

2、HibernatePlugIn.java的内容

package org.haree.struts; 

import java.net.URL; 

import javax.servlet.ServletContext; 
import javax.servlet.ServletException; 

import net.sf.hibernate.SessionFactory; 
import net.sf.hibernate.cfg.Configuration; 

import org.apache.commons.logging.Log; 
import org.apache.commons.logging.LogFactory; 
import org.apache.struts.action.ActionServlet; 
import org.apache.struts.action.PlugIn; 
import org.apache.struts.config.ModuleConfig; 

/** 
 * Implements the <code>PlugIn</code> interface to configure the Hibernate 
 * data persistence library.  A configured 
 * <code>net.sf.hibernate.SessionFactory</code> is stored in the 
 * <code>ServletContext</code> of the web application unless the property 
 * <code>storedInServletContext</code> is set to <code>false</code>. 
 * 
 * <p> 
 * <plugin class="net.sf.hibernate.plugins.struts.HibernatePlugIn"> 
 *   <set-property name="configFilePath&quot" 
 *                value="path-to-config-file"/> 
 *   <set-property name="storedInServletContext&quot" 
 *                value="true-or-false"/> 
 * </plugin> 
 * 
 * @author  <a href="mailto:bhandy@users.sf.net">Bradley M. Handy</a> 
 * @version 1.0 
 */ 
public class HibernatePlugIn implements PlugIn { 

    /** 
     * the key under which the <code>SessionFactory</code> instance is stored 
     * in the <code>ServletContext</code>. 
     */ 
    public static final String SESSION_FACTORY_KEY 
            = SessionFactory.class.getName(); 

    private static Log _log = LogFactory.getLog(HibernatePlugIn.class); 

    /** 
     * indicates whether the <code>SessionFactory</code> instance will be stored 
     * in the <code>ServletContext</code>, or not. 
     */ 
    private boolean _storedInServletContext = true; 

    /** 
     * the path to the xml configuration file.  the path should start with a 
     * '/' character and be relative to the root of the class path. 
     * (DEFAULT:  "/hibernate.cfg.xml") 
     */ 
    private String _configFilePath = "/hibernate.cfg.xml"; 

    private ActionServlet _servlet = null; 
    private ModuleConfig _config = null; 
    private SessionFactory _factory = null; 

    /** 
     * Destroys the <code>SessionFactory</code> instance. 
     */ 
    public void destroy() { 
        _servlet = null; 
        _config = null; 

        try { 
            _log.debug("Destroying SessionFactory"); 

            _factory.close(); 

            _log.debug("SessionFactory destroyed"); 
        } catch (Exception e) { 
            _log.error("Unable to destroy SessionFactory(exception ignored)", 
                    e); 
        } 
    } 

    /** 
     * Initializes the <code>SessionFactory</code>. 
     * @param servlet the <code>ActionServlet</code> instance under which the 
     *        plugin will run. 
     * @param config the <code>ModuleConfig</code> for the module under which 
     *        the plugin will run. 
     */ 
    public void init(ActionServlet servlet, ModuleConfig config) 
    throws ServletException { 
        _servlet = servlet; 
        _config = config; 

        initHibernate(); 
    } 

    /** 
     * Initializes Hibernate with the config file found at 
     * <code>configFilePath</code>. 
     */ 
    private void initHibernate() throws ServletException { 
        Configuration configuration = null; 
        URL configFileURL = null; 
        ServletContext context = null; 

        try { 
            configFileURL = HibernatePlugIn.class.getResource(_configFilePath); 

            context = _servlet.getServletContext(); 

            if (_log.isDebugEnabled()) { 
                _log.debug("Initializing Hibernate from " 
                        + _configFilePath + ""); 
            } 

            configuration = (new Configuration()).configure(configFileURL); 
            _factory = configuration.buildSessionFactory(); 

            if (_storedInServletContext) { 
                _log.debug("Storing SessionFactory in ServletContext"); 

                context.setAttribute(SESSION_FACTORY_KEY, _factory); 
            } 

        } catch (Throwable t) { 
            _log.error("Exception while initializing Hibernate."); 
            _log.error("Rethrowing exception", t); 

            throw (new ServletException(t)); 
        } 
    } 

    /** 
     * Setter for property configFilePath. 
     * @param configFilePath New value of property configFilePath. 
     */ 
    public void setConfigFilePath(String configFilePath) { 
        if ((configFilePath == null) || (configFilePath.trim().length() == 0)) { 
            throw new IllegalArgumentException( 
                    "configFilePath cannot be blank or null."); 
        } 

        if (_log.isDebugEnabled()) { 
            _log.debug("Setting 'configFilePath' to '" 
                    + configFilePath + "'"); 
        } 

        _configFilePath = configFilePath; 
    } 

    /** 
     * Setter for property storedInServletContext. 
     * @param storedInServletContext New value of property storedInServletContext. 
     */ 
    public void setStoredInServletContext(String storedInServletContext) { 
        if ((storedInServletContext == null) 
                || (storedInServletContext.trim().length() == 0)) { 
            storedInServletContext = "false"; 
        } 

        if (_log.isDebugEnabled()) { 
            _log.debug("Setting 'storedInServletContext' to '" 
                    + storedInServletContext + "'"); 
        } 

        _storedInServletContext 
                = new Boolean(storedInServletContext).booleanValue(); 
    } 

}

[Struts]分模块后文件命名的考虑

例如有一个模块名为teacher,包含对教师的列表、增、删、改等操作,因此应该有与这些操作相对应的Action。这样就涉及到它们的命名问题。

一开始我为他们的path起名为/listTeachers、/editTeacher和/saveTeacher(删除操作暂时没写),其中listTeachers用于列表,editTeacher判断request中的action参数产生新增或编辑的Form并跳转至Form页,saveTeacher则是在用户提交表单后执行实际的操作。

随后我发现,这样一来在IE路径中就有两个teacher了,比如:

http://localhost:8080/democenter/teacher/listTeachers.do 

如果去掉path中的teacher字样不就简明多了吗。因此我修改了path名,为统一起见,类名中也去掉了teacher字样。幸好目前的代码还很少,否则光这么一改就不知道要反复调试多少时间了。现在,我可以用下面的路径访问了:

http://localhost:8080/democenter/teacher/list.do 

问题又来了,我想到等模块多起来以后,按这样的命名方法,工程里就会有大量的EditAction.java等文件,虽然它们的包名不同,但在程序中看过去还是会有些费劲的,特别是使用eclipse的Ctrl+Alt+T打开类的时候,要在众多同名文件中根据包来选,远不如直接输入唯一的类名方便。

因此,我觉得比较好的命名方式是把path和类名分开,path使用省略包的命名方法(如/edit),而类名还保持EditTeacherAction的方式。

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2004/07/28/28063.html

[Struts]学习日记2 – 增加一些验证

使用struts的一个好处就是,很多传统jsp/servlet开发中十分琐碎的事情都有规范化的方法来处理了。例如表单验证、错误提示、HTML字符过滤等等。今天简单说一说在form类里进行验证。

在上一篇文章里的LogonForm.java里加入下面这个validate方法:

import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;

public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
    ActionErrors errs=new ActionErrors();
    if(userId.trim().equals(""))
        errs.add("userId",new ActionError("error.userId.empty"));
    return errs;
}

该方法验证用户是否输入了用户Id,若用户没有输入则返回登录页面并在用户Id文本框后面提示。

其中,errs.add方法的第一个参数对应/form/logon.jsp中<html:errors property="userId"/>中的property值,这个logon.jsp是向导在创建form bean时自动生成的。第二个参数会从ApplicationResources.properties文件中寻找key为error.userId.empty的值作为错误提示信息,所以在这个.properties文件中应该有这么一行:

error.userId.empty=UserId can not be empty.

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2004/07/28/28075.html

[Struts]学习日记1 – 一个简单的例子

这个例子是提供一个登录界面,用户输入用户Id和密码,如果一致则判断为登录成功。使用easy struts这个eclipse的插件要做这件事很容易,步骤如下:

1、创建一个新工程,并为在工程属性里为该工程添加easy struts支持。

2、在eclipse菜单File->New->Other里选择Easy Action assosiated with a form。这就打开一个向导,共有三步,下面分别说明。

3、第一步是创建form。Module留空(使用缺省),我们的use case填logon,easy struts会自动根据这个名称更改form name和form type这两个域,最好根据需要更改一下后者的包名称。点form properties右边的add按钮,增加userId和password两个属性,type都是java.lang.String,jsp input type分别是text和password类型。点next进入下一步。

4、第二步是创建action。全部使用缺省值即可。点next进入下一步。

5、第三步是创建forwards和exceptions。我们为刚刚创建的action添加一个名为success的forward,path为/form/main.htm,该页面就是登录成功后看见的页面了。当然,你还要实际创建这个页面,否则登录成功后会出现404错误。按finish按钮完成向导。

6、在向导帮你生成的LogonAction.java文件的execute方法里写下验证登录并跳转的代码如下:

public ActionForward execute(ActionMapping mapping, ActionForm form,
    HttpServletRequest request, HttpServletResponse response) throws Exception {

    LogonForm logonForm = (LogonForm)form;
    ActionErrors errors = new ActionErrors();

    if(!logonForm.getUserId().equals(logonForm.getPassword()))
    errors.add(ActionErrors.GLOBAL_ERROR,new ActionError("error.password.mismatch"));

    if(!errors.isEmpty()){
        saveErrors(request,errors);
        return mapping.getInputForward();
    }

    return (mapping.findForward("success"));
}

7、把这个项目加成一个Tomcat的context,具体方法就是在Tomcat的server.xml中加上下面这句:

<Context path="/struts-test" reloadable="true" docBase="C:\eclipse\workspace\struts-test" />

8、启动Tomcat,使用 http://localhost:8080/struts-test/form/logon.jsp 访问,应该可以看到登录画面。

注意:我发现Easy Struts虽然会帮你把需要的jar拷到WEB-INF/lib里,但这只是一部分,还得手动把其他Struts的lib/*.jar文件拷过来,否则会提示"Cannot find ActionMappings or ActionFormBeans collection"

搬家前链接:https://www.cnblogs.com/bjzhanghao/archive/2004/07/28/28062.html