[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

[转载]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