一,struts运行机制:
二,namesapce
1, packsge 解决重名问题
2 , namespace决定了action的访问路径,默认为"",可以接收所有路径的action
namespace可以写为/,或者/xxx,或者/xxx/yyy,对应的action访问路径为/index.action, /xxx/index.action,或者/xxx/yyy/index.action.
namespace最好也用模块来进行命名
3, 具体视图的返回可以由用户自己定义的Action来决定
具体的手段是根据返回的字符串找到对应的配置项,来决定视图的内容
具体Action的实现可以是一个普通的java类,里面有public String
execute方法即可
或者实现Action接口
不过最常用的是从ActionSupport继承,好处在于可以直接使用Struts2封装好的方法
<package name="front" extends="struts-default" namespace="/"> <action name="index" class="com.bjsxt.struts2.front.action.IndexAction3">//当访问action时,会找到class内容,通过IndexAction3的execute()方法返回的内容 <result name="success">/ActionIntroduction.jsp</result> //与result 中的name比对与来决定视图的内容 </action> </package>
public class IndexAction3 extends ActionSupport { @Override public String execute() { return "success"; } }
4, struts2中的路径问题是根据action的路径而不是jsp路径来确定,所以尽量不要使用相对路径。
虽然可以用redirect方式解决,但redirect方式并非必要。
解决办法非常简单,统一使用绝对路径。(在jsp中用request.getContextRoot方式来拿到webapp的路径)
或者使用myeclipse经常用的,指定basePath
<% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; //相当于http://localhost:8080/... %>
Head里面
<base href="<%=basePath%>" /》
5, Action执行的时候并不一定要执行execute方法可以在配置文件中配置Action的时候用method=来指定执行哪个方法
<struts> <constant name="struts.devMode" value="true" /> <package name="user" extends="struts-default" namespace="/user"> <action name="userAdd" class="com.bjsxt.struts2.user.action.UserAction" method="add"> <result>/user_add_success.jsp</result> </action> <action name="user" class="com.bjsxt.struts2.user.action.UserAction"> <result>/user_add_success.jsp</result> </action> </package> </struts>
也可以在url地址中动态指定(动态方法调用DMI)(推荐)
<a href="<%=context %>/user/userAdd">添加用户</a> <a href="<%=context %>/user/user!add">添加用户</a>
前者会产生太多的action,所以不推荐使用
6, 使用通配符,将配置量降到最低
不过,一定要遵守"约定优于配置"的原则
<action name="Student*" class="com.bjsxt.struts2.action.StudentAction" method="{1}"> <result>/Student{1}_success.jsp</result> </action> <action name="*_*" class="com.bjsxt.struts2.action.{1}Action" method="{2}"> <result>/{1}_{2}_success.jsp</result> <!-- {0}_success.jsp --> </action>
7, 参数传递的四个方法:
- 使用action属性接受参数name=a&age=2;
使用action属性接收参数<a href="user/user!add?name=a&age=8">添加用户</a>
public class UserAction extends ActionSupport { private String name; private int age; public String add() { System.out.println("name=" + name); System.out.println("age=" + age); return SUCCESS; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
- 域模型 user.name=a&user.age=2;
使用Domain Model接收参数<a href="user/user!add?user.name=a&user.age=8">添加用户</a>
public class UserAction extends ActionSupport { private User user; //private UserDTO userDTO; public String add() { System.out.println("name=" + user.getName()); System.out.println("age=" + user.getAge()); return SUCCESS; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } }
- DTO(数据传输对象),
DTO用于解决传入参数和DomainModel中属性不匹配问题。可以先将传入参数传入到DTO中,再将相应的参数传入搭配DomainModel中。
如何是用户登录,希望有一个用户名,一个密码,一个确认密码。可是我们的用户域模型通常只有两个属性:用户名,密码。
那么用域模型就不可以了。那么如何解决这个问题呢?
1、答:可以直接用属性接收,如果喜欢用域模型,则再建立一个user。
2、除了上面方法外,,还有一种方式,就是再定义一个DTO(data transfer object)数据传输对象。,由这个对象,再生成域对象。
public class UserDTO { private String name; private String password; private String confirmingpassword; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getConfirmingpassword() { return confirmingpassword; } public void setConfirmingpassword(String confirmingpassword) { this.confirmingpassword = confirmingpassword; } }
在UserAction类中用UserDTO属性
public class UserAction extends ActionSupport { private User user; //private UserDTO userDTO; public String add(){ System.out.println("name="+user.getName()); System.out.println("age="+user.getAge()); return SUCCESS; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } }
这样前台输入进来的参数,就与UserDTO相匹配了。
然后在UserAction里面处理完之后,再根据UserDTO ,生成User对象。
方法就是从UserDTO里面拿到相应的参数,添加到User里面。
UserDTO就是把参数传递过来,在new User时,再把参数传递给User对象。
- ModelDriven
实现了ModelDriven接口,当接收到参数时,先new一个action,发现它实现了ModelDrven接口,然后就会调用GetModel()方法并返回User类型的user
使用ModelDriven接收参数<a href="user/user!add?name=a&age=8">添加用户</a>
public class UserAction extends ActionSupport implements ModelDriven<User>{ private User user = new User(); public String add() { System.out.println("name=" + user.getName()); System.out.println("age=" + user.getAge()); return SUCCESS; } @Override public User getModel() { return user; } }
8, 传中文参数
在strust.xaml 中
<constant name="struts.i18n.encoding" value="GBK" /> <!-- internationalization -->
9, 使用addFieldError方法和s:fieldError标签简单处理数据校验
定义一个action
public class UserAction extends ActionSupport { private String name; public String add() { if(name == null || !name.equals("admin")) { this.addFieldError("name", "name is error"); //通过addFieldError方法把内容写到值栈中,在Jsp中s:fieldError标签或s:property读取 this.addFieldError("name", "name is too long"); //一个name可有多个值 return ERROR; } return SUCCESS; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
在jsp中
<?xml version="1.0" encoding="GB18030" ?> <%@ page language="java" contentType="text/html; charset=GB18030" pageEncoding="GB18030"%> <%@taglib uri="/struts-tags" prefix="s" %> <!-- 添加标签的url ,指向标签所在标签库,prefix指定所用标签的前缀--> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=GB18030" /> <title>Insert title here</title> </head> <body> User Add Error! <s:fielderror fieldName="name" theme="simple"/> <!-- 读取值栈中的值方法1--> <br /> <s:property value="errors.name[0]"/> <!-- 读取值栈中的值方法2,用来去valuestack和context的属性--> <s:debug></s:debug><!-- 调试,查看值栈内容--> </body> </html>
10,访问web元素
取得Map类型request,session,application的引用
方法一:依赖于容器
public class LoginAction1 extends ActionSupport { private Map request; private Map session; private Map application; public LoginAction1() { request = (Map)ActionContext.getContext().get("request"); session = ActionContext.getContext().getSession(); //actionContext 放置action执行时的内容 application = ActionContext.getContext().getApplication(); } public String execute() { request.put("r1", "r1"); session.put("s1", "s1"); application.put("a1", "a1"); return SUCCESS; } }
在jsp中
<body> User Login Success! <br /> <s:property value="#request.r1"/> | <%=request.getAttribute("r1") %> <br /> <!-- 取得Stack Context中的request--> <s:property value="#session.s1"/> | <%=session.getAttribute("s1") %> <br /> <s:property value="#application.a1"/> | <%=application.getAttribute("a1") %> <br /> <s:property value="#attr.a1"/><br /><!--不怎么用--> <s:property value="#attr.s1"/><br /> <s:property value="#attr.r1"/><br /> <s:debug></s:debug> <br /> </body>
方法二;DI/IOC,实现了RequestAware,SessionAware, ApplicationAware接口,让struts给我们拿到request。。。(最常用,其他可以不纪)
public class LoginAction2 extends ActionSupport implements RequestAware,SessionAware, ApplicationAware { private Map<String, Object> request; private Map<String, Object> session; private Map<String, Object> application; //DI dependency injection //IoC inverse of control public String execute() { request.put("r1", "r1"); session.put("s1", "s1"); application.put("a1", "a1"); return SUCCESS; } @Override public void setRequest(Map<String, Object> request) { this.request = request; } @Override public void setSession(Map<String, Object> session) { this.session = session; } @Override public void setApplication(Map<String, Object> application) { this.application = application; } }
在jsp中
<body> User Login Success! <br /> <s:property value="#request.r1"/> | <%=request.getAttribute("r1") %> <br /> <!-- 取得Stack Context中的request--> <s:property value="#session.s1"/> | <%=session.getAttribute("s1") %> <br /> <s:property value="#application.a1"/> | <%=application.getAttribute("a1") %> <br /> <s:property value="#attr.a1"/><br /><!--不怎么用--> <s:property value="#attr.s1"/><br /> <s:property value="#attr.r1"/><br /> <s:debug></s:debug> <br /> </body>
获取真实类型 HttpServletRequest, HttpSession, ServletContext的引用(不常用)
方法一:依赖于容器
public class LoginAction3 extends ActionSupport { private HttpServletRequest request; private HttpSession session; private ServletContext application; public LoginAction3() { request = ServletActionContext.getRequest(); session = request.getSession(); application = session.getServletContext(); } public String execute() { request.setAttribute("r1", "r1"); session.setAttribute("s1", "s1"); application.setAttribute("a1", "a1"); return SUCCESS; } }
方法二:DI/IOC
public class LoginAction4 extends ActionSupport implements ServletRequestAware { private HttpServletRequest request; private HttpSession session; private ServletContext application; public String execute() { request.setAttribute("r1", "r1"); session.setAttribute("s1", "s1"); application.setAttribute("a1", "a1"); return SUCCESS; } @Override public void setServletRequest(HttpServletRequest request) { this.request = request; this.session = request.getSession(); this.application = session.getServletContext(); } }
11,incluse
<struts> <constant name="struts.devMode" value="true" /> <include file="login.xml" /> </struts>
12,默认的action
<struts> <constant name="struts.devMode" value="true" /> <package name="default" namespace="/" extends="struts-default"> <default-action-ref name="index"></default-action-ref> //放访问的路径不存在时,会跳转到默认的界面 <action name="index"> <result>/default.jsp</result> </action> </package> </struts>
Action总结
- 实现一个Action的最常用方式:从ActionSupport继承
- DMI动态方法调用 user!add
- 通配符配置 * {1} {2} …
a) *_*
4.接收参数的方法(一般用属性或者DomainModel来接收)
5.简单参数验证addFieldError
a) 一般不使用Struts2的UI标签
6.访问Web元素
a) Map类型
i. IoC
ii. 依赖Struts2
b) 原始类型
i. IoC
ii. 依赖Struts2
7.包含文件配置
8.默认action处理