Struts最佳实践

背景:

      从本期的电子杂志内容介绍中,大家已经看到了web发展的整个历史,  

      Struts 自从 2001 61.0 Release之后经历了漫长的春秋,有着庞大的用户群体, 并且IBM, Tomcat Web控制台都采用了Struts Framework..

      web框架有好多种选择,并不一定要使用Struts, 但如果你正刚开始使用的话,希望下面的一些实践能给你带来帮助, 仅此而已所以,请原谅,本文没有什么实例代码, 因为今天早上,我的好友Leemassn 跟我说,这东西已经烂掉了:( ,所以相信基本用法你们了解的比我多,也并没有涉及到一些高级用法, 我下面所说的内容, 也均属纸上谈兵.

1. 正确是导向,才是使用Web Framework的真正目的.

   并不时因为Struts 耳儒目染的多了,我们才一定要使用Struts ,并不时MVC就一定要使用Struts ,当你能灵活游刃于StrutsActionForm ,Action ,Lib之间, "疏能跑马,密不透风而且能够扩展的你的Web 框架时,之后才是我们运用框架的真正灵便之处.

 

    先说一些与Struts 无关的话题,因为Struts并不能取代你应用框架的全部,无论项目大或小,复杂或者简单

一些建议:

 1. 请选用支持广泛的JDO  或者Hibernate,或者iBates,来做你的数据持久层,

 2. 请加入Struts-el标签,

 3. 请选用应用服务器的JNDI连接数据库

 4. 请使用StrutsTestCase做单元测试

 5. 请阅读sun 的命名规范.

 

.Struts 之对象使用篇

   Struts 版本换了好多了,,如果你只是使用最基本的FormAction相信0.5 就够了,但眼下大家用的都是1.1 

    每写个应用都用继承BaseAction ,BaseForm , 当然BaseAction 最好是继承LookupDispatchAction, BaseForm 最好是继承ValidatorActionForm (这两个都是从1.1开始有的)

      

  ValidatorActionForm也是继承ActionForm ,   因为1.1有了PlugIn,当你使用ValidatorPlugIn使得你的FormBean具备了验证能力啦.  

 

  (1.1 也同时 DynaActionForm ,相信大家都知道这个Bean,但它似乎除了让你少写一些ActionForm之外没什么用处,除非你是想完全不给予ActionForm,这样偶尔用到ActionForm的时候也可以小用一把DynaActionForm, 看来Struts对自己的ActionForm似乎没有多信息,欲弃欲留,我们都知道ActionForm 是不能完全充当ModelModel已应该是你的持久层)的,那我们至少可以用它来传值吧,方便支出就是不需要 一个个表单内容去get ,set了.所以,我们有必要使用ActionForm , 同时我们也要对每个属性进行用户端的输入校验,于是我们选用ValidatorActionForm.)

 

     LookupDispatchAction 继承DispatchAction, 自己多加两个方法,就是getKeyMethod(),localMap ,它能帮你 从本地submit的资源文件,比如submite 的名字是add 就能找到你的add方法.

 

 

.Struts 之标签库篇.

   相信Struts是很讲究复用的

  标签库主要还是用做View,所以,在设计ActionForm的时候大可大胆设计,别担心他们不能在jsp页面上很好的显示, 该是Data类型就是,也可以使用List,Map ,这样的符合类型,也可以是引用对象类型,因为他们能很方便的在页面上显示

    如果Test1Form包含了 各种Model对象,

   Test1Form{

        Student student      //id,name等属性

        Teach teach    //有id, classid等属性

        List classes   //一组Classes 对象 Classes又含有 classid等属性

        Test2Form test2form --- // attr2 property

        ....

     }   

     那么

      <html:form action="/test1">
     <bean:define name="test1Form" property="test2Form" id="test2"
                type="com.yourcompony.Test2Form" />
      <html:text  name="test2" property="test2.
attr2" />

         <html: text name="studentsid" property="student.id">

         <html: text name="techname" property="teach.name">

         <html: text name="classid" property="classes[0].classid">
   </html:form >
 

  看到了,它们其实什么都能得到,发挥你的想象标签库能展示你的任何对象属性值.

    记得在ActionForm reset里初始化一下,并且依次得到对象.这样你同样能把这些内容全部递交给ActionServlet. 如果没使用过这些,赶紧试试吧.

   

     尽量使用EL标签: 主要用于复杂的逻辑判断,

   举个例子 <logic:present name="yourForm" property="a"> 判断了a是否存在,但你又想知道a 是否等于1,怎么样头痛了吧,换成el 那就是 <c:if test='${yourForm.a =="1" }'>  ..../c:if

  

    补充一些:对于前台的显示,,Struts标签不得不说是似乎已经成了一根鸡肋美丽,容易操作的的界面,往往要以来于其他技术,Struts的标签使用的最大的目的也是为了方便于数据显示, 美丽复杂操作还是要依赖你的HtmlJavaScript

 

3.Struts 之异常处理篇.

      基本上来讲,Struts 给异常处理提供了较为完善的框架.

      按道理讲,当一个系统正式交付的时候,,我们还让用户看到那些 一大串英文字母是一种极端粗暴的行为, 所以,我们从两头专起.

      1.使用validationForm做可验证的确formBean , 当然你也可以使用你积累下来比较丰富的javascript,无论那种方式,都有一点会让你受益,就是学会使用正则表达.

      2.Action处理中,try catch 使用saveMessage 使用saveErrors()或者saveMessaes,因为(Struts1.2开始抛弃了ActionErrors,全部是ActionMessages)

       

         这里就不得不说到一些构架上的一些东西了. Struts Action中处理的异常,已经不该是你的原始异常了.在你的Dao层要抛出DataException,而在你的业务层,需要捕获到,作为你的自定义异常抛出,这样你在struts里捕获到的异常才是友好的,且是有意义的.

    我们都知道Dao那一层都是抛一个统一的异常比如DataExpcetion

   然后到你的业务处理 Service 那一层能就捕获DataExpcetion, 因为Serivce那一层,你总归是知道自己要做什么, 因此建议在Service 那层捕获DataException 之后,打印 debug日志, 然后再抛出业务逻辑异常

   比如在业务处理,添加一个学生过程,如果

          public void doAddStudent(Student student) throws DupKeyExption,Ser{

      try{

              if((Student)load(student.getId()).getId()==student.getId()){

                throw new DupKeyExcption("改同学已经存在");

              }

              studentDao.add();

          }catch(DataException e){

            logger.debug("错误信息:",e);

            throws new StudentException("增加失败");

          }

        }

 

    try {

            service.doAddStudent();

       }catch (DupikeyException e1){

           //重复添加了

      errors.add("message",new ActionError("student.error.dupkey"));

        }catch (Exception e) {

           //添加失败

                 errors.add("message",new ActionError("student.error.add"));

          logger.error(e.getMessage());

          e.printStackTrace();

        }

        saveErrors(request, errors);

 

    

    至于显示嘛,直接使用<html:errors/>OK了.但是你要觉得没有空白的地方显示,也可以使用

    <html:messages id="message">

       <script language=javascript>window.alert('<bean:write name="message"/>')</script>

    </html:messages>

  对于,全局的异常,那你最好forward一个 gloable-forward showErorr.jsp之类的jsp

  (注:Struts1.2开始,抛弃了ActionErrors了,统一使用使用ActionMessages error其实是个多余的对象,用法一样)

 

4 Struts 扩展篇

    Struts Plugin Struts应用程序算是留了一到后门,扩展Struts 可以由此窃入

     Plugin 能使得你的web应用程序在startupshutdown 的时候,能完成一部分操作. 它是基于配置的,你可以很方便的外挂一些应用程序,

    比如HibernatePlugin

    public class HibernatePlugIn implements PlugIn {
    

    public static final String SESSION_FACTORY_KEY
            = SessionFactory.class.getName();

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

    private boolean _storedInServletContext = true;
    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();
    }
   
}

 

5. 测试篇

   Struts通过传统的手工输入进行测试, 效率教低, 请尽量使用单元测试

   

基本使用如下

public class BaseActionTest extends MockStrutsTestCase {

public StudentActionTest(String arg0) {

super(arg0);

}

 

public static void main(String[] args) {

junit.textui.TestRunner.run(UserActionTest.class);

}

 

public void setUp() throws Exception {

super.setUp();

    setContextDirectory(new File("E://webapp//webContext"));

}

protected void tearDown() throws Exception {

    super.tearDown();

}

 

public void testAdd() {

setRequestPathInfo("/student");

addRequestParameter("method","add");

actionPerform(); //执行

verifyForward("success");

 

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值