项目文件结构
Struts2应用的分层体系架构
要点:
1.将处理逻辑放到service里,如Action层不准许出现在sql语句,session、request不允许传到service层去。
示例:
LoginAction.java
package com.struts2.struts2;
……该导入的包……
public class LoginAction extends ActionSupport
{
private String username;
private String password;
private int age;
private Date date;
private LoginService loginService = new LoginServiceImpl();
……Set与get方法……
public String execute() throws Exception
{ //业务逻辑不写到Action里
// if(!"hello".equals(username))
// {
// throw new UsernameException("username invalid");
// }
// if(!"world".equals(password))
// {
// throw new PasswordException("password invalid");
// }
// return SUCCESS;
//利用ServletActionContext,获得HttpServletRequest请求
HttpServletRequest request = ServletActionContext.getRequest();
HttpSession session = request.getSession();
session.setAttribute("hello", "helloworld");
ActionContext actionContext = ActionContext.getContext();
Map<String, Object> map = actionContext.getSession(); //获取session
Object object = map.get("hello"); //打印出session的信息
System.out.println(object);
if(this.loginService.isLogin(username, password))
{
return SUCCESS;
}
return INPUT;
}
………………
}
LoginService.java
package com.struts2.service;
public interface LoginService
{
public boolean isLogin(String username, String password);
}
LoginServiceImpl.java
package com.struts2.service.impl;
import com.struts2.service.LoginService;
public class LoginServiceImpl implements LoginService
{
public boolean isLogin(String username, String password)
{
if("hello".equals(username) && "world".equals(password))
{
return true;
}
return false;
}
}
编辑struts2.xml文件
…………
<action name="login" class="com.struts2.struts2.LoginAction">
<result name="success" type="dispatcher">/result.jsp</result>
<result name="input">/login.jsp</result>
</action>
…………
Struts2的模型驱动(model driven)
要点:
- 属性驱动(propertity driven)与模型驱动的区别:之前的都是属性驱动,属性驱动与模型驱动的处理方式差不多,但它们导致的结果却不同,属性驱动是在接收的请求后,将对象里的值一个一个的 set 好,此时并没有new 出一个整的对象。而模型驱动是在接收到用户提交表单请求后,就将对象创建好了,并把对象的值也设定好了,可以直接拿对象来用了。
- 实现了ModelDriven接口的Action的执行过程
1).首先调用getModel()方法,返回一个person对象
2).模型查找提交过来的表单中有没有username、password等属性名是否匹配,如果匹配,则将对应的值自动设置到对象中,放到模型当中。
3).当在结果页面,以request.getAttribute()或requestScope取值时,同样通过Action从模型当中取值。
- 属性驱动与模型驱动的比较
1)属性驱动灵活,准确;模型驱动不灵活,因为很多时候,页面所提交过来的参数并不属于模型中的属性,也就是说页面所提交过来的参数与模型中的属性并不一致,这是很常见的情况。
2)模型驱动更加符合面向对象的编程风格,使得我们获得的是对象而不是一个个离散的值。
小结:推荐使用属性驱动编写 Action。
- Preparable接口的作用是让 Action完成一些初始化工作,这些初始化工作是放在 Preparable接口的prepare方法中完成的,该方法会在execute方法执行之前得到调用。
示例:
Person.java
package com.struts2.bean;
import java.util.Date;
public class Person
{
private String username;
private String password;
private int age;
private Date date;
……get、set方法……
}
LoginAction2.java
package com.struts2.struts2;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import com.opensymphony.xwork2.Preparable;
import com.struts2.bean.Person;
public class LoginAction2 extends ActionSupport implements ModelDriven<Person>, Preparable
{ //模型驱动
private Person person = new Person();
//1.首先调用getModel()方法,返回一个person对象
//2.模型查找提交过来的表单中有没有username、password等属性值,如果有,则模型自动设置到对象中
public Person getModel()
{
System.out.println("getModel invoked!");
return person; //返回生成的person
}
//调用这个方法让action准备自身
public void prepare() throws Exception
{
System.out.println("prepare invoked!!");
}
public String execute() throws Exception
{
System.out.println("execute invoked!");
//System.out.println(person.getUsername());
return SUCCESS;
}
}
struts.xml
向struts.xml文件中,添加一个action,如下:
<action name="login2" class="com.struts2.struts2.LoginAction2">
<result name="success">/result.jsp</result>
username: <input type="text" name="username"><br>
password: <input type="password" name="password"><br>
age: <input type="text" name="age"><br>
date: <input type="text" name="date"><br>
<input type="submit" value="submit">
username: ${requestScope.username }<br><!-- requestScope相当于request.getAttribute() -->
password: ${requestScope.password }<br>
date: ${requestScope.date }<br>
session: ${sessionScope.hello }<!-- 取得通过ServletActionContext方式获取的session -->
2) Mock 测试 ( 继承 HttpServletRequest 、 HttpSession 、HttpServletResponse等Servlet API) 。
打开struts2-core-2.2.1.1.jar下的struts-default.xml文件,其中定义了的结果类型,如下:
<package name="struts-default" abstract="true">
<result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/>
<result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult"/>
<result-type name="httpheader" class="org.apache.struts2.dispatcher.HttpHeaderResult"/>
<result-type name="redirect" class="org.apache.struts2.dispatcher.ServletRedirectResult"/>
<result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/>
<result-type name="velocity" class="org.apache.struts2.dispatcher.VelocityResult"/>
<result-type name="xslt" class="org.apache.struts2.views.xslt.XSLTResult"/>
<result-type name="plainText" class="org.apache.struts2.dispatcher.PlainTextResult" />
在struts.xml文件中,设置Action中的result元素的type属性即可,如下:
<action name="login" class="com.struts2.struts2.LoginAction">
<result name="success" type="dispatcher">/result.jsp</result>
<result name="success" type="redirect">/result.jsp</result>
<result name="input">/login.jsp</result>
<form action="action1.action">
username: <input type="text" name="username"><br>
password: <input type="password" name="password"><br>
<input type="submit" value="submit">
username: <s:property value="username"/><br>
password: <s:property value="password"/><br>
usernameAndPassword: <s:property value="usernameAndPassword"/>
import com.opensymphony.xwork2.ActionSupport;
public class Action1 extends ActionSupport
private String usernameAndPassword;
public String execute() throws Exception
this.usernameAndPassword = this.username + this.password;
import com.opensymphony.xwork2.ActionSupport;
public class Action2 extends ActionSupport
private String usernameAndPassword;
public String execute() throws Exception
<action name="action1" class="com.struts2.struts2.Action1">
<result name="success" type="redirectAction">
<!--如果不传参数,可把action2直接写到result的text域中 -->
<param name="actionName">action2</param>
<param name="username">${username}</param><!-- 获取Action1的成员变量 -->
<param name="password">${password}</param>
<param name="usernameAndPassword">${usernameAndPassword}</param>
<action name="action2" class="com.struts2.struts2.Action2">
<result name="success">/action2.jsp</result>
要点:直接修改struts.xml文件中的action的result的type属性的值为 chain ,如下:
<action name="action1" class="com.vvvv.struts2.Action1">
<result name="success" type=chain">
<!--如果不传参数,可把action2直接写到result的text域中 -->
<param name="actionName">action2</param>
<param name="username">${username}</param><!-- 获取Action1的成员变量 -->
<param name="password">${password}</param>
<param name="usernameAndPassword">${usernameAndPassword}</param>
<s:form action="token.action" theme="simple">
username: <s:textfield name="username"></s:textfield><br>
password: <s:password name="password"></s:password><br>
<s:submit value="submit"></s:submit>
import com.opensymphony.xwork2.ActionSupport;
public class TokenAction extends ActionSupport
public String execute() throws Exception
username: <s:property value="username"/><br>
password: <s:property value="password"/>
<action name="token" class="com.struts2.struts2.TokenAction">
<result name="success">/tokenSuccess.jsp</result>
<result name="invalid.token">/tokenFail.jsp</result>
<interceptor-ref name="token"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
package com.struts2.interceptor;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;
public class TheInterceptor1 implements Interceptor
public void setTest(String test)
System.out.println("setTest invoked!"); //set方法先于init方法执行
System.out.println("init invoked!");
System.out.println("test: " + this.test);
//服务器永远不会去执行挂截器,只不过是在执行拦截器之前,执行一个invoke方法
public String intercept(ActionInvocation invocation) throws Exception
String result = invocation.invoke();
<package name="struts2" extends="struts-default">
<interceptor name="theInterceptor1" class="com.vvvv.interceptor.TheInterceptor1">
<param name="test">vvvv</param>
<action name="token" class="com.struts2.struts2.TokenAction">
<result name="success">/tokenSuccess.jsp</result>
<result name="invalid.token">/tokenFail.jsp</result>
<interceptor-ref name="token"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
一旦定义了自己的拦截器,将其配置到 action上后,我们需要在action的最后加上默认的拦截器栈:defaultStack。
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
public class TheInterceptor2 extends AbstractInterceptor
public String intercept(ActionInvocation invocation) throws Exception
System.out.println("interceptor before...");
System.out.println("interceptor2: " + invocation.getAction().getClass());
String result = invocation.invoke();
System.out.println("interceptor after...");
<interceptor name="theInterceptor1" class="com.vvvv.interceptor.TheInterceptor1">
<param name="test">vvvv</param>
<interceptor name="theInterceptor2" class="com.vvvv.interceptor.TheInterceptor2">
<interceptor name="theInterceptor3" class="com.vvvv.interceptor.TheInterceptor3">
<interceptor name="loginInterceptor" class="com.vvvv.interceptor.LoginInterceptor">
<action name="action1" class="com.vvvv.struts2.Action1" method="myExecute">
<result name="success" type="chain">
<param name="actionName">action2</param>
<param name="username">${username}</param>
<param name="password">${password}</param>
<param name="usernameAndPassword">${usernameAndPassword}</param>
<interceptor-ref name="theInterceptor1"></interceptor-ref>
<interceptor-ref name="theInterceptor2"></interceptor-ref>
<interceptor-ref name="theInterceptor3">
<param name="includeMethods">execute, myExecute</param>
<param name="excludeMethods">myExecute</param>
<interceptor-ref name="defaultStack"></interceptor-ref>
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
import com.vvvv.listener.TheListener;
public class TheInterceptor3 extends MethodFilterInterceptor
protected String doIntercept(ActionInvocation invocation) throws Exception
invocation.addPreResultListener(new TheListener());
System.out.println("before interceptor3");
String result = invocation.invoke();
System.out.println("after interceptor3");