创建控制器组件:HelloAction.java
控制器组件包括ActionServlet类和Action类。ActionServlet类是Struts框架自带的,它是整个Struts框架的控制枢纽,通常不需要扩展。Struts框架提供了可供扩展的Action类,它用来处理特定的HTTP请求,例程2-4为HelloAction类的源程序。
例程2-4 HelloAction.java
package hello;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.util.MessageResources;
public final class HelloAction extends Action {
/**
* Process the specified HTTP request, and create the corresponding HTTP
* response (or forward to another web component that will create it).
* Return an
* control should be forwarded, or
* already been completed.
*/
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
// These "messages" come from the ApplicationResources.properties file
MessageResources messages = getResources(request);
/*
* Validate the request parameters specified by the user
* Note: Basic field validation done in HelloForm.java
* Business logic validation done in HelloAction.java
*/
ActionMessages errors = new ActionMessages();
String userName = (String)((HelloForm) form).getUserName();
String badUserName = "Monster";
if (userName.equalsIgnoreCase(badUserName)) {
errors.add("username", new ActionMessage("hello.dont.talk.to.monster",
badUserName ));
saveErrors(request, errors);
return (new ActionForward(mapping.getInput()));
}
/*
* Having received and validated the data submitted
* from the View, we now update the model
*/
PersonBean pb = new PersonBean();
pb.setUserName(userName);
pb.saveToPersistentStore();
/*
* If there was a choice of View components that depended on the model
* (or some other) status, we'd make the decision here as to which
* to display. In this case, there is only one View component.
*
* We pass data to the View components by setting them as attributes
* in the page, request, session or servlet context. In this case, the
* most appropriate scoping is the "request" context since the data
* will not be neaded after the View is generated.
*
* Constants.PERSON_KEY provides a key accessible by both the
* Controller component (i.e. this class) and the View component
* (i.e. the jsp file we forward to).
*/
request.setAttribute( Constants.PERSON_KEY, pb);
// Remove the Form Bean - don't need to carry values forward
request.removeAttribute(mapping.getAttribute());
// Forward control to the specified success URI
return (mapping.findForward("SayHello"));
}
}
HelloAction.java是本应用中最复杂的程序,下面分步讲解它的工作机制和流程。
Action类的工作机制
所有的Action类都是org.apache.struts.action.Action的子类。Action子类应该覆盖父类的execute() 方法。当ActionForm Bean被创建,并且表单验证顺利通过后, Struts框架就会调用Action类的execute()方法。execute()方法的定义如下:
execute()方法包含以下参数:
·ActionMapping:包含了这个Action的配置信息,和struts-config.xml文件中的元素对应。
·ActionForm:包含了用户的表单数据,当Struts框架调用execute()方法时,ActionForm中的数据已经通过了表单验证。
·HttpServletRequest:当前的HTTP请求对象
·HttpServletResponse:当前的HTTP响应对象
Action类的execute()方法返回ActionForward对象,它包含了请求转发路径信息。
访问封装在MessageResources中的本地化文本
在本例中,Action类的execute()方法首先获得MessageResources对象:
MessageResources messages = getResources(request);
在Action类中定义了getResources(HttpServletRequest request)方法,该方法返回当前默认的MessageResources对象,它封装了Resource Bundle中的文本内容。接下来Action类就可以通过MessageResources对象来访问文本内容。例如,如果要读取消息key为"hello.jsp.title"对应的文本内容,可以调用MessageResources类的getMessage(String key)方法:
String title=messages.getMessage("hello.jsp.title");
业务逻辑验证
接下来,Action类的execute()方法执行业务逻辑验证:
如果用户输入的姓名为"Monster",将创建包含错误信息的ActionMessage对象,ActionMessage对象被保存到ActionMessages对象中。接下来调用在Action基类中定义的saveErrors()方法,它负责把ActionMessages对象保存到request范围内。最后返回ActionForward对象,Struts框架会根据ActionForward对象包含的转发信息把请求转发到恰当的视图组件,视图组件通过标签把request范围内的ActionMessages对象中包含的错误消息显示出来,提示用户修改错误。
在本文中还提到了ActionErrors对象,图2-3显示了ActionMessages、ActionErrors、ActionMessage和ActionError类的类框图。ActionErrors继承ActionMessages,ActionError继承ActionMessage,ActionMessages和ActionMessage之间为聚集关系,即一个ActionMessages对象中可以包含多个ActionMessage对象。
图2-3 ActionMessages、ActionErrors、ActionMessage和ActionError类的类框图
表单验证通常只对用户输入的数据进行简单的语法和格式检查,而业务逻辑验证会对数据进行更为复杂的验证,很多情况下,需要模型组件的介入,才能完成业务逻辑验证。
访问模型组件
接下来,HelloAction类创建了一个模型组件PersonBean对象,并调用它的saveTopersistentStore()方法来保存userName属性:
本例仅提供了Action类访问模型组件简单的例子。在实际应用中,Action类会访问模型组件,完成更加复杂的功能,例如:
·从模型组件中读取数据,用于被视图组件显示
·和多个模型组件交互
·依据从模型组件中获得的信息,来决定返回哪个视图组件
向视图组件传递数据
Action类把数据存放在request或session范围内,以便向视图组件传递信息。以下是 HelloAction.java向视图组件传递数据的代码:
以上代码完成两件事:
·把PersonBean对象保存在request范围内。
·从request范围内删除ActionForm Bean。由于后续的请求转发目标组件不再需要HelloForm Bean,所以可将它删除。
把HTTP请求转发给合适的视图组件
最后,Action类把流程转发给合适的视图组件。
(T111)
本文选自飞思图书《精通Struts:基于MVC的Java Web设计与开发》
例程2-4 HelloAction.java
package hello;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.util.MessageResources;
public final class HelloAction extends Action {
/**
* Process the specified HTTP request, and create the corresponding HTTP
* response (or forward to another web component that will create it).
* Return an
ActionForward
instance describing where and how
* control should be forwarded, or
null
if the response has
* already been completed.
*/
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
// These "messages" come from the ApplicationResources.properties file
MessageResources messages = getResources(request);
/*
* Validate the request parameters specified by the user
* Note: Basic field validation done in HelloForm.java
* Business logic validation done in HelloAction.java
*/
ActionMessages errors = new ActionMessages();
String userName = (String)((HelloForm) form).getUserName();
String badUserName = "Monster";
if (userName.equalsIgnoreCase(badUserName)) {
errors.add("username", new ActionMessage("hello.dont.talk.to.monster",
badUserName ));
saveErrors(request, errors);
return (new ActionForward(mapping.getInput()));
}
/*
* Having received and validated the data submitted
* from the View, we now update the model
*/
PersonBean pb = new PersonBean();
pb.setUserName(userName);
pb.saveToPersistentStore();
/*
* If there was a choice of View components that depended on the model
* (or some other) status, we'd make the decision here as to which
* to display. In this case, there is only one View component.
*
* We pass data to the View components by setting them as attributes
* in the page, request, session or servlet context. In this case, the
* most appropriate scoping is the "request" context since the data
* will not be neaded after the View is generated.
*
* Constants.PERSON_KEY provides a key accessible by both the
* Controller component (i.e. this class) and the View component
* (i.e. the jsp file we forward to).
*/
request.setAttribute( Constants.PERSON_KEY, pb);
// Remove the Form Bean - don't need to carry values forward
request.removeAttribute(mapping.getAttribute());
// Forward control to the specified success URI
return (mapping.findForward("SayHello"));
}
}
HelloAction.java是本应用中最复杂的程序,下面分步讲解它的工作机制和流程。
Action类的工作机制
所有的Action类都是org.apache.struts.action.Action的子类。Action子类应该覆盖父类的execute() 方法。当ActionForm Bean被创建,并且表单验证顺利通过后, Struts框架就会调用Action类的execute()方法。execute()方法的定义如下:
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException ; |
execute()方法包含以下参数:
·ActionMapping:包含了这个Action的配置信息,和struts-config.xml文件中的元素对应。
·ActionForm:包含了用户的表单数据,当Struts框架调用execute()方法时,ActionForm中的数据已经通过了表单验证。
·HttpServletRequest:当前的HTTP请求对象
·HttpServletResponse:当前的HTTP响应对象
Action类的execute()方法返回ActionForward对象,它包含了请求转发路径信息。
访问封装在MessageResources中的本地化文本
在本例中,Action类的execute()方法首先获得MessageResources对象:
MessageResources messages = getResources(request);
在Action类中定义了getResources(HttpServletRequest request)方法,该方法返回当前默认的MessageResources对象,它封装了Resource Bundle中的文本内容。接下来Action类就可以通过MessageResources对象来访问文本内容。例如,如果要读取消息key为"hello.jsp.title"对应的文本内容,可以调用MessageResources类的getMessage(String key)方法:
String title=messages.getMessage("hello.jsp.title");
业务逻辑验证
接下来,Action类的execute()方法执行业务逻辑验证:
ActionMessages errors = new ActionMessages(); String userName = (String)((HelloForm) form).getUserName(); String badUserName = "Monster"; if (userName.equalsIgnoreCase(badUserName)) { errors.add("username", new ActionMessage("hello.dont.talk.to.monster", badUserName )); saveErrors(request, errors); return (new ActionForward(mapping.getInput())); } |
如果用户输入的姓名为"Monster",将创建包含错误信息的ActionMessage对象,ActionMessage对象被保存到ActionMessages对象中。接下来调用在Action基类中定义的saveErrors()方法,它负责把ActionMessages对象保存到request范围内。最后返回ActionForward对象,Struts框架会根据ActionForward对象包含的转发信息把请求转发到恰当的视图组件,视图组件通过标签把request范围内的ActionMessages对象中包含的错误消息显示出来,提示用户修改错误。
在本文中还提到了ActionErrors对象,图2-3显示了ActionMessages、ActionErrors、ActionMessage和ActionError类的类框图。ActionErrors继承ActionMessages,ActionError继承ActionMessage,ActionMessages和ActionMessage之间为聚集关系,即一个ActionMessages对象中可以包含多个ActionMessage对象。
图2-3 ActionMessages、ActionErrors、ActionMessage和ActionError类的类框图
表单验证通常只对用户输入的数据进行简单的语法和格式检查,而业务逻辑验证会对数据进行更为复杂的验证,很多情况下,需要模型组件的介入,才能完成业务逻辑验证。
访问模型组件
接下来,HelloAction类创建了一个模型组件PersonBean对象,并调用它的saveTopersistentStore()方法来保存userName属性:
PersonBean pb = new PersonBean(); pb.setUserName(userName); pb.saveToPersistentStore(); |
本例仅提供了Action类访问模型组件简单的例子。在实际应用中,Action类会访问模型组件,完成更加复杂的功能,例如:
·从模型组件中读取数据,用于被视图组件显示
·和多个模型组件交互
·依据从模型组件中获得的信息,来决定返回哪个视图组件
向视图组件传递数据
Action类把数据存放在request或session范围内,以便向视图组件传递信息。以下是 HelloAction.java向视图组件传递数据的代码:
request.setAttribute( Constants.PERSON_KEY, pb); // Remove the Form Bean - don't need to carry values forward request.removeAttribute(mapping.getAttribute()); |
以上代码完成两件事:
·把PersonBean对象保存在request范围内。
·从request范围内删除ActionForm Bean。由于后续的请求转发目标组件不再需要HelloForm Bean,所以可将它删除。
把HTTP请求转发给合适的视图组件
最后,Action类把流程转发给合适的视图组件。
// Forward control to the specified success URI return (mapping.findForward("SayHello")); |
(T111)
本文选自飞思图书《精通Struts:基于MVC的Java Web设计与开发》