Action类在MVC模式中发挥着控制器(Controller)的作用。Action类响应用户的动作,执行业务逻辑或调用其他类来执行业务逻辑,然后返回一个result用来告诉Struts应该呈现哪个视图。
Struts2的Action类常常继承由Struts2框架提供的ActionSupport类,该类提供了一些常见动作的默认实现,如execute、input等,还实现了一些有用的Struts2接口。当你的Action类继承ActionSupport时,它既可以重载默认实现,也可以继承默认实现。在上一章的例子中,HelloWorldAction中的execute()方法就是我们想要这个控制器做的事情,来响应hello.action。
Action的最常见职责之一就是处理用户在表单中的输入,让处理结果可以在视图页面中显示。例如,我们在HelloWorld.jsp中想要显示一个个性化的hello,在index.jsp中我们要添加一个表单:
注意textfield的name属性的值"userName"。当用户点击该表单的提交按钮时,hello action将会被执行。该表单域的值将会被提交到Struts2的Action类,也就是HelloWorldAction。为了让HelloWorldAction类能够自动地接收到userName的值,该类必须有一个public的方法setUserName(符合JavaBean规范)。如此,在提交的时候,框架就会自动调用serUserName()方法,将表单中的value值作为参数传入,以此来设置userName的值。
在HelloWorldAction中添加setter方法:
private String userName;
public void setUserName(String username) {
this.userName = username;
}
public String getUserName() {
return userName;
}
为了让MessageStore中存储的message个性化,在HelloWorldAction的execute()方法中添加以下代码段:
public String execute() throws Exception {
messageStore = new MessageStore();
if (userName != null) {
messageStore.setMessage("Hello,"+userName);
}
return SUCCESS;
}
如果MessageStore类中没有setter方法,那么添加一个setMessage方法:
public void setMessage(String message) {
this.message = message;
}
当index.jsp提交表单时,因为参数的名字为userName,所以Struts将该参数的值,即"张三"传给了setUserName方法,从而设置了userName的值。
本节介绍了如何对编写Action类来处理用户在表单上的输入。对于get方法中url后面的?userName=张三,也会采用相同的逻辑来执行。那么,如果一个表单中含有许多值域,那么为每一个表单域都设置一个set方法将会非常麻烦。所以下一节我们要学习如何来将模型类、视图中的表单域以及Action类的表单处理过程进行整合。
这一节我们学习如何使用一个Java模型类来存储表单的输入以及如何创建与该模型类匹配的Struts2表单。例如,我们需要提供一个用户登记信息进行抽奖的表单。规定用户必须提供Ta的姓、名、邮箱地址和年龄。为了封装这个数据,我们使用一个简单的遵循基本JavaBean规范的Java类(每一个实例域都有set/get方法)。
src/prizedrawing/model/Person.java
package prizedrawing.model;
public class Person {
private String firstName;
private String lastName;
private String email;
private int age;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "First Name='" + firstName +
"', lastName='" + lastName +
"', email='" + email +
"', age=" + age ;
}
}
为了收集上述信息,我们使用struts2表单。当创建这个表单的时候,我们需要使用的关键理论是将每一个表单域与Person类对象的对应特定的实例域绑定起来。创建一个jsp视图.
web/register.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
Register
补充表单内容,注册抽奖
由于我们使用了Struts2自定义tag,在jsp首部我们需要声明tag库。Struts2表单将会提交到一个名为"register"的action。我们需要在struts.xml中定义该action。
注意四个文本框标签,每一个标签都有一个名字,包含了一个Person类的属性。名字属性的值也会引用到一个叫做personBean的对象。这个对象是Person类型的,当我们创建对应的Action类的时候,需要在Action类中创建该对象。另外,所有的表单域的值都是String。当调用personBean的setAge方法Struts2将会自动转换用户输入的String类型的值“25”为一个int类型25。
当用户点击提交按钮时,action"register"和表单数据将会被传输到Struts2 框架。我们需要一个Action类来处理该表单。
src/prizedrawing/action/Register.java
package prizedrawing.action;
import com.opensymphony.xwork2.ActionSupport;
import prizedrawing.model.Person;
public class Register extends ActionSupport {
private static final long serialVersionUID = 1L;
private Person personBean;
@Override
public String execute() throws Exception {
//调用工具类将personBean的状态存储到数据库中
return SUCCESS;
}
public Person getPersonBean() {
return personBean;
}
public void setPersonBean(Person personBean) {
this.personBean = personBean;
}
}
在Register类中我们声明了一个名为personBean的Person类对象,并且声明了相关的get/set方法。Register类重写了execute(),在实际应用中我们会调用其他的工具类来完成表单的业务处理,例如将数据存储到数据库中。
有了模型类,我们就不必在Action类中定义不同的set/get方法对应每一个表单域了。
web/thankyou.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
Registration Successful
Thank you for registering for a prize.
Your registration information:
这里用到的标签也是之前用到过的。在
/thankyou.jsp
现在,运行web应用,访问localhost:8080/register.jsp,补充表格
在实际应用中,用户输入的信息不一定是正确的格式,所以需要对用户的输入数据进行确认。
例如,如果我们希望用户的firstName,email和age必须输入,且age必须要大于等于18岁,那么如果不满足条件就要返回相应的结果在。我们Register类中添加以下方法:
@Override
public void validate() {
if (personBean.getFirstName().length() == 0) {
addFieldError("personBean.firstName","First name is required.");
}
if (personBean.getEmail().length() == 0) {
addFieldError("personBean.email", "Email is required.");
}
if (personBean.getAge() < 18) {
addFieldError("personBean.age", "Age is required and must be 18 or older");
}
}
当用户点击提交按钮时,Struts2框架将会将用户输入转换为personBean的实例域。然后Struts2会自动执行validate()方法。如果if语句中的条件有成立的,Struts2将会调用它的addFiledError方法(从ActionSupport类继承而来的方法)。如果添加了任何error,那么框架将不会调用execute方法,而是会返回一个"input"的result。
这个"input"的result,就代表用户输入了不正确的信息。在大部分情况下我们都希望重新显示表单以及对应的输入错误,来告诉用户哪里输入的不对。为了处理result为"input"的情况,需要在struts.xml中对我们的action节点添加:
/register.jsp
此时,如果确认失败,Struts2返回input,那么框架将会重新显示register.jsp。由于我们已经使用了Struts的表单标签,Struts将会自动将错误信息加入到页面中。这些错误信息就是我们在addFieldError方法中添加的。
addFieldError()方法有两个参数,比如addFieldError(personBean.firstName","First name is required.") ,第一个参数就是输入错误的表单域对应的实例域,第二个就是错误信息。
上面的错误信息也许不够醒目,Struts2的 s:head标签可以为错误信息提供CSS作用。将
现在,我们可以使用Struts2框架进行一些基础的应用,但是仅限于基础应用~Struts2框架作为一个企业级的web框架,其知识体系并不简单,想要继续学习struts2框架的高级应用,需要求知若渴地去寻找、学习。不过,通过这两篇博文的学习,我们已经对于MVC的设计模式有了一定的认识,这是最重要的~