条纹噪声_教程–条纹:精简的Java Web框架

条纹噪声

条纹是Web框架真正隐藏的瑰宝。 它相对低调,但是使用它的人会发誓。 并且有充分的理由-它简单,有效,并且专注于做一些事情,并且确实非常好地完成它们。 这为您提供了一个框架,该框架为您提供的功能比您要做的要多得多,同时又避免了您遇到的麻烦,让您以自己想要的方式来做事情。 它还使您可以为开发完整的Web应用程序所涉及的其他层选择自己喜欢的工具,例如持久性,安全性和灵活的用户界面。

如果您从未听说过Stripes,您可能想知道它是否已在实际应用程序中使用。 必然是。 现代化医学就是一个例子,我和我的同事们使用Stripes为皮肤科医生开发了功能强大的电子医学助手。 现代化医学的总裁兼首席执行官丹尼尔·坎恩(Daniel Cane)表示:“我怎么听说过条纹,我不知道。 但是,一旦做完,我立刻就迷上了:绑定和验证的便捷性,以及对表单进行操作的优雅性,本地化的力量以及愿意提供帮助的坚实的社区。 在看Stripes书时,标语“…和Java Web开发再次变得有趣”在平台上卖了我。 我对这个框架非常满意,每个星期我都会学到一些新知识。”

给我看一些代码

感兴趣了吗? 让我们看一些代码。 假设您要显示库存中的产品列表,并且想要创建一个链接,该链接将转到每个产品的详细信息页面。 页面中的代码可能如下所示:

<%-- sample01.jsp --%>
  <ul>
    <c:forEach var="${products}" item="product">
      <li>
       <stripes:link beanclass="com.example.ProductActionBean" event="showDetail">
          <stripes:param name="productId" value="${product.id}"/>
          ${product.name}
       </stripes:link>
      </li>
    </c:forEach>
  </ul>

这个例子值得一提的是:

  • Stripes使用JSP进行模板化。 它易于使用,在您的IDE中具有强大的支持,拥有庞大的用户基础,大量的第三方库和支持,并且有大量的参考页,文章,书籍和博客文章记录在案。
  • Stripes不会重塑标准JSP中已经可用的任何内容,例如forEach标记。
  • 条纹标签很简单。 该链接清楚地表明它针对com.jaxenter.stripes.action.ProductActionBean类和showDetail事件。 您确切知道下一步要去哪里。 另外,如果重命名ProductActionBean或更改其程序包,这是一个简单的搜索,以查找在JSP中引用的位置。 最后,将productId参数添加到链接也很容易(而且很干净)。

让我们看一下Java方面的东西:

/* ProductActionBean.java */
  package com.jaxenter.stripes.action;
  
  import net.sourceforge.stripes.action.ForwardResolution;
  import net.sourceforge.stripes.action.Resolution;
  import com.jaxenter.stripes.model.Product;
  
  public class ProductActionBean extends BaseActionBean {
    private Integer productId;
    private Product product;
  
    public Resolution showDetail() {
      product = loadProduct(productId);
      return new ForwardResolution("/WEB-INF/jsp/productDetails.jsp");
    }
  
    public Product getProduct() {
      return product;
    }
  
    public Integer getProductId() {
      return productId;
    }
    public void setProductId(Integer productId) {
      this.productId = productId;
    }
  }

现在,我们还有更多收获:

  • 该类包括一个名为showDetail的方法,该方法与JSP中的event =” showDetail”属性的值匹配。 当用户单击链接时,将自动调用此方法。
  • 该类还包括productId属性。 它的值将被设置为与链接关联的产品ID,因为我们在链接的主体中具有<stripes:param name =“ productId”>标记。
  • 虽然到达了HTTP的所有参数值是一个 String,我们可以用整数我们的productId属性。 Stripes将自动进行类型转换,并且还支持开箱即用的DateBigDecimalBigInteger以及所有原始类型和包装类型。 同样,为自己的类型编写类型转换也很容易。
  • showDetail方法返回的结果是Resolution ,它定义了接下来发生的事情。 在这里,我们使用ForwardResolution ,它清楚地表明我们正在转发到productDetail.jsp 。 信息就在这里,无需搜索单独的文件即可弄清楚“成功”字符串的含义!
  • Stripes使用Action Bean之所以这样命名,是因为它们将动作与JavaBean属性结合在一起。 在这里, 动作showDetail ,而beanproductIdproduct属性的包含。

productDetail.jsp中 ,我们可以利用 Stripes提供的 actionBean 下的JSP中的action bean自动存在,来轻松显示所选产品的详细信息

<%-- productDetails.jsp --%>
  <h1>Product details</h1>
  <ul>
    <li>Name: ${actionBean.product.name}</li>
    <li>Description: ${actionBean.product.description}</li>
    <li>Price: ${actionBean.product.price}</li>
  </ul>

知道当前的动作bean在JSP的{actionBean}下总是可用的,可以轻松地将数据传输到视图:只需在动作bean类中为您要访问的信息添加一个getter方法。

有关动作豆的更多信息

动作bean是Stripes应用程序的主力军。 这些类是您接收输入并处理由用户单击链接或提交表单触发的事件的地方。 使您(开发人员)更轻松的一项功能是动作bean是线程安全的。 创建了一个新实例来处理每个请求,因此您可以放心使用实例变量而不必担心。 关于动作bean的下一件要知道的事是,您使用以下签名的方法处理事件:

public Resolution eventName()

方法名称确定了它处理的事件的名称。 我们已经看到了如何在链接中指示操作bean类和事件名称:

 

<stripes:link beanclass="..." event="...">

我们可以很容易地为表单做同样的事情:

<stripes:form beanclass="...">
    <stripes:submit name="save" value="Save Data"/>
    <stripes:submit name="cancel" value="Cancel everything"/>
  </stripes:form>

每个 名称 <条纹:提交> 标签指示在动作豆调用哪个事件处理方法(该 是按钮标签在浏览器中显示)。 这使得处理一个表单中的多个提交按钮非常容易! 只需为每个按钮编写一个事件处理程序方法:

public Resolution save() {
    // ... 
  }
  public Resolution cancel() {
    // ... 
  }

您可以通过 两种方式在操作bean中 具有 默认 事件处理程序:首先,如果它是操作bean中唯一的事件处理程序方法,则它自动是默认的。 其次,可以通过注释事件处理程序方法为默认方法:

@DefaultHandler
  public Resolution view() {
    // ... 
  }
  public Resolution cancel() {
    // ... 
  }

处理事件后,您需要告诉Stripes下一步去哪里。 您可以通过Resolution来执行此操作。 让我们现在谈论这些。

决议案

在Stripes中, Resolution是一个简单的界面,用于告诉Stripes处理请求后如何响应浏览器。 该接口只有一种方法:

void execute(HttpServletRequest request, HttpServletResponse response);

如您所见,它很简单,您可以执行几乎所有操作以将响应发送到浏览器。 当然,Stripes具有一些内置的实现以用于常见的响应:

  • ForwardResolution 转发到模板,通常是JSP
  • RedirectResolution 重定向 发送到浏览器,通常是另一个操作Bean
  • 通过StreamingResolution ,可以轻松发送二进制文件作为响应,例如PDF
  • JavaScriptResolution使用JavaScript 发送Java对象,这在使用Ajax时非常有用
  • ErrorResolution 发送HTTP错误,并带有错误代码和描述性消息

其中一种将在大多数时间满足您的需求,但是您可以扩展它们或从头开始编写自己的应用,以获取所需的任何自定义行为。 两种最常用的解决方案是 ForwardResolution RedirectResolution

 

// Forwards to a JSP
  return new ForwardResolution("/WEB-INF/jsp/productDetails.jsp");
  
  // Redirects to another action bean and its default event handler
  return new RedirectResolution(AnotherActionBean.class);
  
  // Redirects to another action bean and a specific event handler
  return new RedirectResolution(AnotherActionBean.class, "showDetails");
  
  // Redirects to another action bean and a specific event handler, 
  // with request parameters
  return new RedirectResolution(AnotherActionBean.class, "showDetails")
    .addParameter("productId", 42).addParameter("showDescription", true);

分辨率具有表现力,可以让您立即,确切地知道响应浏览器的下一步。

装订:超功能

包括我自己在内的许多Stripes用户都认为Stripes中最强大的功能是将请求参数绑定到动作bean属性。 我们已经简要介绍了该功能; 现在让我们深入研究。 假设您有一个模型对象,该模型对象的属性又是其他模型对象,例如 具有 Address Person

/* Person.java */ 
  package com.jaxenter.stripes.model;
  
  public class Person {
    private String firstName;
    private Address address;
  
    public String getFirstName() {
      return firstName;
    }
    public void setFirstName(String firstName) {
      this.firstName = firstName;
    }
    public Address getAddress() {
      return address;
    }
    public void setAddress(Address address) {
      this.address = address;
    }
  }
  /* Address.java */
  package com.jaxenter.stripes.model;
  
  public class Address {
    private String streetName;
  
    public String getStreetName() {
      return streetName;
    }
    public void setStreetName(String streetName) {
      this.streetName = streetName;
    }
  }

您想使用户能够使用HTML表单使用地址创建一个人。 使用Stripes,它看起来像这样-首先,您将拥有一个带有Person属性的动作Bean:

/* PersonActionBean.java */
  package com.jaxenter.stripes.action;
  
  import net.sourceforge.stripes.action.DefaultHandler;
  import net.sourceforge.stripes.action.ForwardResolution;
  import net.sourceforge.stripes.action.Resolution;
  import com.jaxenter.stripes.model.Person;
  
  public class PersonActionBean extends BaseActionBean {
    private Person person;
  
    @DefaultHandler
    public Resolution view() {
      return new ForwardResolution("/WEB-INF/jsp/personForm.jsp");
    }
  
    public Person getPerson() {
      return person;
    }
    public void setPerson(Person person) {
      this.person = person;
    }
  }

注意,我们还有一个默认的事件处理程序,可转发到 personForm.jsp 这是我们创建HTML表单的地方:

<%-- personForm.jsp --%>
  <stripes:form beanclass="com.jaxenter.stripes.action.PersonActionBean">
    <div>
      First name:
      <stripes:text name="person.firstName"/>
    </div>
    <div>
      Street name:
      <stripes:text name="person.address.streetName"/>
    </div>
    <div>
      <stripes:submit name="save" value="Save"/>
    </div>
  </stripes:form>

看到那是多么简单和直接? 我们使用<stripes:form>标记并指示目标操作bean类名称。 然后,我们创建的文本输入与name属性对应于目标属性:person.firstNameperson.address.streetName。 当用户提交表单时,Stripe将自动在操作bean上调用getPerson()。setFirstName(<value>)getPerson()。getAddress()。setStreetName(<value>) ,以填充人员对象及其嵌套属性。

会变得更好:您可能会认为您将获得NullPointerException,因为我们从未创建过新的Person()对象。 从不畏惧! 即使在嵌套属性上,Stripe也可以为您完成。 将请求参数绑定到属性时,如果它从getter中获取为null ,则Stripes将创建一个新对象并进行设置。 因此,您只需添加属性,然后让Stripes负责客房整理。 最后,我们只需要一个用于提交按钮的事件处理程序即可,该事件处理程序名为 save

 

public Resolution save() {
    // save the person object... 
  }

Stripes调用 save() 方法时,参数已绑定到动作bean属性,因此我们可以依靠 要创建,填充和准备保存 人员 对象。 嗯,这不是 完全 正确的:要正常工作,用户必须填写表格,而不是提交空白表格。 我们可以通过验证轻松解决此问题。

验证:简单而出色

Stripes提供了一种对用户输入执行验证的简单方法:Action bean属性的注释和自定义验证方法。 继续我们的“ 人” 表单示例; 说,我们要确保用户输入的 person.firstName person.address.streetName 领域 都值 我们在action bean中的person属性上使用注释:

/* PersonValidatedActionBean.java */
  package com.jaxenter.stripes.action;
  
  import net.sourceforge.stripes.action.DefaultHandler;
  import net.sourceforge.stripes.action.DontValidate;
  import net.sourceforge.stripes.action.ForwardResolution;
  import net.sourceforge.stripes.action.Resolution;
  import net.sourceforge.stripes.validation.Validate;
  import net.sourceforge.stripes.validation.ValidateNestedProperties;
  import com.jaxenter.stripes.model.Person;
  
  public class PersonValidatedActionBean extends BaseActionBean {
    @ValidateNestedProperties({
      @Validate(field="firstName", required=true),
      @Validate(field="address.streetName", required=true)
    })
    private Person person;
  
    @DefaultHandler
    @DontValidate
    public Resolution view() {
      return new ForwardResolution("/WEB-INF/jsp/personValidatedForm.jsp");
    }
  
    public Resolution save() {
      // save the person object... 
      return new ForwardResolution("/WEB-INF/jsp/personSaved.jsp");
    }
  
    public Person getPerson() {
      return person;
    }
    public void setPerson(Person person) {
      this.person = person;
    }
  }

所述 @Validate(所需=真) 注释标记的属性作为必需字段。 如果我们直接向该属性提交值,则可以将该注释直接放置在动作bean属性上。 在我们的示例中,我们没有这样做。 我们正在将值提交给person属性的嵌套属性。 在这种情况下,我们需要把我们的@Validate注释 @ValidateNestedProperties注释里面,使用字段属性以指示嵌套属性我们正在验证。 请注意,我们还向 view() 方法中 添加了 @DontValidate 以便在用户首次到达动作bean时不执行验证-此时他们没有机会填写表单。

现在,通过这些验证,空白表格将不会导致我们的保存事件处理程序被调用。 相反,Stripes将捕获验证错误并改为重新显示表单,并在我们添加<stripes:errors />标记的位置显示错误消息:

<%-- personValidatedForm.jsp --%>
  <stripes:form beanclass="com.jaxenter.stripes.action.PersonValidatedActionBean">
    <stripes:errors/>
    <div>
      First name:
      <stripes:text name="person.firstName"/>
    </div>
    <div>
      Street name:
      <stripes:text name="person.address.streetName"/>
    </div>
    <div>
      <stripes:submit name="save" value="Save"/>
    </div>
  </stripes:form>

提交空白表格将显示一个页面,如下图所示(图1)。

真正的好处是,如果用户填写其中一个字段,而不填写其他字段,则将重新显示该页面,并显示有关必填字段的错误消息, 该字段将自动填充。 注意,我们不必在<stripes:text>标记中进行任何操作即可实现。 这样可以使您的JSP代码保持整洁。 Stripes带有以下内置验证:

  • 必填项目
  • 最小和最大长度
  • 最小值和最大值,用于数字输入
  • 匹配正则表达式掩码
  • JSP表达式的求值

编写自定义验证方法也很容易。 只需编写一个带有@ValidationMethod注释的方法。 例如:

@ValidationMethod
  public void validateSomething(ValidationErrors errors) {
    if (!password.equals(confirmPassword)) {
      errors.add(new SimpleError("The passwords do not match."));
    }
  }

通过将错误添加到错误列表,我们使Stripes返回到表单,而不是调用事件处理程序,就像内置验证失败时一样。

最后,请注意,Stripe仅在内置验证通过后才调用验证方法。 同样,这可以使您的代码干净整洁,因为例如,您不必对密码进行检查,如果您将密码设置为必填字段,则无需确认密码。 如果所需的验证失败,则不会调用自定义验证方法。 将显示有关必填字段的错误消息。

有关表单和绑定的更多信息

我说过,参数绑定是Stripes最强大的功能之一。 结合Stripes的form标签,这是一个强大的一键二拳。 因此,让我们进一步探讨。 假设您有一个枚举Gender ,如下所示:

package com.jaxenter.stripes.model;
  
  public enum Gender {
    FEMALE("Female"),
    MALE("Male");
  
    private String description;
  
    private Gender(String description) {
      this.description = description;
    }
  
    public String getDescription() {
      return description;
    }
  }

这是创建表单的方式,该表单可以使用单选按钮选择一种性别,使用复选框选择任意数量的性别,并使用选择框选择一种性别:

<%-- formControls.jsp --%>
  <stripes:form beanclass="com.jaxenter.stripes.action.FormControlsActionBean">
    <div>
      Radio buttons:
      <c:forEach var="gender"
        items="<%= com.jaxenter.stripes.model.Gender.values() %>">
        <stripes:radio name="radioChoice" value="${gender}"/>${gender.description}
      </c:forEach>
    </div>
    <div>
      Checkboxes:
      <c:forEach var="gender"
        items="<%= com.jaxenter.stripes.model.Gender.values() %>">
        <stripes:checkbox name="checkboxChoices" value="${gender}"/>
        ${gender.description}
      </c:forEach>
    </div>
    <div>
      Select box:
      <stripes:select name="selectChoice">
        <stripes:option value="">Select...</stripes:option>
        <stripes:options-enumeration enum="com.jaxenter.stripes.model.Gender"
          label="description"/>
      </stripes:select>
    </div>
    <div><stripes:submit name="view" value="Send"/></div>
  </stripes:form>

如您所见,Stripes标记库使创建表单和使用表单控件变得容易。 请记住,表单控件会自动从以前的值重新填充。 同样,Stripes将自动处理String和我们的Gender枚举类型之间的转换。 最后,注意<条纹:选择枚举>标签需要一个枚举的类名,并自动创建的,从它的值的选项列表。 它默认情况下呈现枚举的常量,但是我们也可以通过指定label属性来使用另一个属性,就像在这里所做的那样。 Stripes还具有<stripes:options-collection><stripes:options-map>标记,以分别呈现任何CollectionMap的选项列表。

另一个非常好的功能是,我们可以在列表中的第一个选项中包含一个“选择...”选项,以提示用户选择一个选项,而不是默认情况下选择一个选项。 通过这样做,我们可以确保用户进行选择。 实际上,由于“ Select…”选项的值是一个空字符串,因此如果用户未进行选择,则动作Bean上的相应属性将为null 。 使用@Validate(required = true) ,我们可以强制执行选择选项的要求。 这是干净多了比使用-1或其他一些魔法值,然后手动检查该值作为意思是“没有选择制定了”! 我们准备看一下动作bean:

package com.jaxenter.stripes.action;
  
  import java.util.List;
  import net.sourceforge.stripes.action.ForwardResolution;
  import net.sourceforge.stripes.action.Resolution;
  import com.jaxenter.stripes.model.Gender;
  
  public class FormControlsActionBean extends BaseActionBean {
    private Gender radioChoice;
    private List<Gender> checkboxChoices;
    private Gender selectChoice;
  
    public Resolution view() {
      return new ForwardResolution("/WEB-INF/jsp/formControls.jsp");
    }
  
    public Gender getRadioChoice() {
      return radioChoice;
    }
    public void setRadioChoice(Gender radioChoice) {
      this.radioChoice = radioChoice;
    }
    public List<Gender> getCheckboxChoices() {
      return checkboxChoices;
    }
    public void setCheckboxChoices(List<Gender> checkboxChoices) {
      this.checkboxChoices = checkboxChoices;
    }
    public Gender getSelectChoice() {
      return selectChoice;
    }
    public void setSelectChoice(Gender selectChoice) {
      this.selectChoice = selectChoice;
    }
  }

这些属性与 我们在JSP中拥有 名称 属性 相对应 如前所述,Stripes将传入的String转换为相应的Gender 。 此外,对于复选框,我们具有List <Gender>属性。 该列表将自动包含用户选择的性别。 我们甚至不必创建新的ArrayList ; 条纹也会为我们做到这一点!

功能丰富,但没有多余

Stripes提供许多有用的功能,同时专注于其存在的理由 :它是服务器端Web框架,而不是全栈框架,也不是客户端图形用户界面。 它的理念是针对应用程序的这些层有许多出色的解决方案,因此它不会浪费时间,也不会阻止您为持久性,JavaScript小部件等选择自己喜欢的解决方案。 这是Stripes提供的更多功能的摘要:

  • 只需一劳永逸地提及动作bean的根包,即可自动发现动作bean。 每次添加,修改或删除操作Bean时都不需要调整配置。
  • 同样,自动发现扩展 :这些扩展是自定义类型转换器,格式化程序和其他扩展或实现的Stripes工件,可以满足您的需求。
  • 简单而强大的布局系统 。 不需要配置的重复主题在这里也适用。
  • 轻松创建多页表单的向导的批注。
  • 拦截器 ,您可以利用Stripes的生命周期,几乎可以做任何事情来定制框架以满足您的要求。
  • 异常处理在一个地方定义了如何处理从特定到一般的异常。
  • 测试工具,以便您可以为Stripes Web应用程序编写自动化测试。
  • 本地化可轻松使您的应用程序以多种语言提供。

结论

Stripes完美地平衡了强大功能,简单性和紧密关注的焦点,从而为您提供了一个可以为您做很多事情的框架,而不会妨碍您,也不会造成功能膨胀。 它简单易学且直观,因此您可以Swift提高工作效率。 它是可定制和可扩展的,因此您可以对其进行调整以满足您的更高级或特定要求。 最后但并非最不重要的一点,它是开放源代码框架空间中最友好的社区之一,因此,如果您需要帮助,请在邮件列表中写一条消息。

作者简介

弗雷德·达乌德Fred Daoud)是《 条纹》(Stripes )的作者,《 Java Web Development再次有趣》(Java Web Development is Fun Again) 目前在 Modernizing Medicine,Inc . 使用条纹 自1997年以来,他一直在使用Java,并且喜欢Web框架。 他还喜欢使用其他基于JVM的语言,例如Clojure,JRuby和Groovy。

本文以前出现在Java Tech Journal – Java Web Frameworks中。 此处找到有关Web框架的更多文章。


翻译自: https://jaxenter.com/tutorial-stripes-a-lean-mean-java-web-framework-104577.html

条纹噪声

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值