Struts2(二)— Result结果配置、Servlet的API的访问、模型驱动、属性驱动
一.Result结果配置
1.全局和局部结果
平常我们设置跳转页面,是在action标签里面加上 result标签来控制,这种设置的页面跳转,称之为局部结果页面但是我们有时候在很多个action里面,针对不同的结果进行跳转时,也有可能跳转同一个页面,那么这个时候就可以配置全局结果页面。
-
在action里面写上的result跳转的页面,称之为局部结果页面配置
<action name="demo01_*" class="com.pri.web.action.ActionDemo01" method="{1}"> <result name="error">/error.jsp</result> </action>
1.2全局结果
-
如果有多个action的结果跳转的页面是一样的,那么我们可以提取出来,做成全局结果页面的配置. 全局页面通过
package
标签中配置global-results
标签来定义<package name="test" extends="struts-default" namespace="/"> <global-results> <result name="error">/error.jsp</result> </global-results> .... </package>
优先级: 局部>全局
1.3不同包里面的全局结果的配置
<!--把全局的结果抽取到父包里面 --> <package name="base" extends="struts-default" abstract="true"> <global-results> <!--全局的结果: 配置在package里面的 特点:可以被当前包里面所有的Action共用; 使用场景:不同的Action需要跳转到相同的结果的时候eg: 错误页面, msg页面等 --> <result name="error">/msg.jsp</result> </global-results> </package> <package name="test" extends="base" namespace="/"> <action name="demo01_fun01" class="com.pri.web.ActionDemo01" method="fun01"> </action> <action name="demo02_fun02" class="com.pri.web.ActionDemo02" method="fun02"> </action> </package>
2.结果的类型【常用】
根据前面学的servlet知识,我们知道服务器响应给浏览器的时候,有三种类型:response响应JSON数据&请求转发 & 重定向。 对于Struts2而言,无非就是Action跳转(转发重定向)到页面,Action跳转到Action....
文档位置 docs/docs/result-types.html
2.1Action跳转页面
-
转发(默认)
<result name="success" type="dispatcher">/index.jsp</result>
- 重定向
<result name="success" type="redirect">/index.jsp</result>
2.2Action跳转Action
-
转发
<action name="demo01_*" class="com.pri.web.action.ActionDemo01" method="{1}"> <result name="success" type="chain">demo02_fun02</result> </action> <action name="demo02_*" class="com.pri.web.action.ActionDemo02" method="{1}"> </action>
-
重定向
<action name="demo01_*" class="com.pri.web.action.ActionDemo01" method="{1}"> <result name="success" type="redirectAction">demo02_fun02</result> </action> <action name="demo02_*" class="com.pri.web.action.ActionDemo02" method="{1}"> </action>
2.3其它的结果
一般来说,我们平常的请求到来,我们要不就是跳转到 页面上 ,要不就是跳转到下一个action 去。 但是除了这两种结果之外,我们仍然还有一些其他结果类型可以控制.
比如: 我们可以返回一个文件数据给客户端 (比如文件下载).再比如: 我们可以返回一个json字符串给来请求的页面,而不是重新打开新的页面 (有点像之前的Ajax请求,返回json数据)
2.3.1响应JSON数据【了解】
-
导入struts-json-plugin-xxx.jar
-
Java代码
-
1 public class ActionDemo01 extends ActionSupport { 2 private User json; 3 4 public User getJson() { 5 return json; 6 } 7 8 public String fun01(){ 9 json = new User(); 10 json.setName("张三"); 11 json.setAge(18); 12 json.setPassword("123456"); 13 14 return "success"; 15 } 16 }
-
-
配置文件
-
<struts> <package name="test" extends="json-default" namespace="/"> <action name="demo01" class="com.pri.web.action.ActionDemo01" method="fun01"> <result name="success" type="json"> <param name="root">json</param> <!--这里的name必须是root 至于这个json 是我们在action里面的成员 变量 json(属性) --> </result> </action> </package> </struts>
-
注意:
-
- root:配置对象。action类中必须提供一个和root值相同的属性名称,且需要提供getter方法。
- package需要继承json-default
- result的type值是json
2.3.2响应流(文件下载)【了解】
-
Action里面的代码
-
1 public class ActionDemo01 extends ActionSupport { 2 private InputStream stream; 3 4 public void setStream(InputStream stream) { 5 this.stream = stream; 6 } 7 public InputStream getStream() { 8 return stream; 9 } 10 public String fun01() throws Exception{ 11 System.out.println("demo01 执行了..."); 12 stream = new FileInputStream("E:/data/Desktop/a.jpg"); 13 14 return "success"; 15 } 16 }
-
配置文件
<struts> <package name="test" extends="struts-default" namespace="/"> <action name="demo01" class="com.pri.web.action.ActionDemo01" method="fun01"> <result name="success" type="stream"> <param name="contentType">image/jpeg</param> <param name="inputName">stream</param> <param name="contentDisposition">attachment;filename="b.jpg"</param> <param name="bufferSize">1024</param> </result> </action> </package> </struts>
注意:
- contentType:下载文件类型
- contentDisposition:下载到客户端时,客户端文件名称
- bufferSize:读文件的缓存大小
- inputName:对应要输出到客户端流声明的名称,也就是说需要和Action里面声明的变量名要一致
二、Struts2中的Servlet的API的访问
客户端与服务端交互时,通常会带参数过来,服务器也会回写数据给客户端。在此过程中,参与着请求,和响应,以及会话。servlet在此过程中提供了HttpServletRequest作为获取请求数据的方案,HttpServletResponse作为响应的方案,HttpSession负责了会话方案。Struts其实是基于servlet实现的web框架,他需要遵循规则提供请求,响应和会话的API供开发人员使用,因此Struts针对这一问题提供了自己的一套API封装,提供了多种方式的访问。
1.ActionContext
1.1概述
ActionContext是Action的上下文,Struts2自动在其中保存了一些在Action执行过程中所需的对象,比如session, parameters等。Struts2会根据每个执行HTTP请求的线程来创建对应的ActionContext,即一个线程有一个唯一的ActionContext。
1.2使用
-
获得(创建)ActionContext
ActionContext context = ActionContext.getContext();
-
获得请求参数
Map<String, Object> parameters = context.getParamters();
相当于Servlet中的request.getParamters()方法,只能获得所有的请求参数
2.ServletActionContext
2.1概述
ServletActionContext继承ActionContext,因此比ActionContext功能要强大。ServletActionContext提供了多个静态方法。
2.2使用
-
获得Request对象
HttpServletRequest request = ServletActionContext.getRequest();
-
获得Response对象
HttpServletResponse response = ServletActionContext.getResponse();
-
获得ServletContext
ServletContext servletContext = ServletActionContext.getServletContext();
3.实现接口的方式
- 编写Action,让Action使用实现特定的接口的方式访问Servlet的API,有如下接口可以实现
- ServletContextAware
- ServletRequestAware
- ServletResponseAware
- SessionAware
- ApplicationAware
-
Eg:
-
1 public class ActionDemo03 extends ActionSupport implements ServletRequestAware { 2 private HttpServletRequest request; 3 public String fun03() throws IOException{ 4 HttpServletRequest request = ServletActionContext.getRequest(); 5 String username = request.getParameter("username"); 6 String password = request.getParameter("password"); 7 System.out.println(username+":"+password); 8 return NONE; 9 } 10 11 @Override 12 public void setServletRequest(HttpServletRequest request) { 13 this.request = request; 14 } 15 }
三、获得请求参数
1.获得零散数据
1.1使用上面介绍的Struts2中的Servlet的API获取
-
ActionContext
//1.创建ActionContext对象 ActionContext context = ActionContext.getContext(); //2.获得所有的请求参数 Map<String, Object> parameters = context.getParamters();
-
ServletActionContext
//1.获得request对象 HttpServletRequest request = ServletActionContext.getRequest(); requet.getParameter(String key); requet.getParameterValues(String key); requet.getParameterMap();
1.2属性驱动【常用】
-
页面
<h1>01使用属性驱动</h1> <form method="post" action="${pageContext.request.contextPath }/demo01"> 用户名:<input type="text" name="username"/><br/> 密 码:<input type="password" name="password"/><br/> <input type="submit"/> </form>
-
Action.java
public class ActionDemo01 extends ActionSupport { private String username;//和表单里面的name属性值要一致,并且提供set方法 private String password;//和表单里面的name属性值要一致,并且提供set方法 public void setUsername(String username) { this.username = username; } public void setPassword(String password) { this.password = password; } public String fun01(){ System.out.println(username+":"+password); return NONE; } }
2.获得封装后的数据(对象)
2.1属性驱动
-
页面
<h1>01使用属性驱动方式</h1> <form method="post" action="${pageContext.request.contextPath }/demo01"> 用户名:<input type="text" name="user.username"/><br/> 密 码:<input type="password" name="user.password"/><br/> <input type="submit"/> </form>
-
Action.java
-
1 public class ActionDemo01 extends ActionSupport { 2 //1. User类里面的字段属性需要和表单里面的name属性一致, 且提供无参构造 3 //2. user需要set和get方法 4 private User user; 5 public User getUser() { 6 return user; 7 } 8 public void setUser(User user) { 9 this.user = user; 10 } 11 12 public String fun01(){ 13 System.out.println(user.toString()); 14 return NONE; 15 } 16 }
2.2模型驱动【常用】
-
页面
<h1>02使用模型驱动方式</h1> <form method="post" action="${pageContext.request.contextPath }/demo02"> 用户名:<input type="text" name="username"/><br/> 密 码:<input type="password" name="password"/><br/> <input type="submit"/> </form>
Action.java
1 public class ActionDemo02 extends ActionSupport implements ModelDriven<User> { 2 3 private User user; 4 5 public String fun02(){ 6 System.out.println(user.toString()); 7 return NONE; 8 } 9 @Override 10 public User getModel() { 11 if(user == null){ 12 user = new User(); 13 } 14 return user; 15 } 16 }
结论:我们在实际开发里面,
- 如果要获得单个(零散)的数据,我们通常用属性驱动
- 如果要获得封装后的数据, 我们通常用模型驱动
2.3封装到集合
封装到集合,一般我们会在批量添加 、批量更新场景下见到。也就是说页面上同一个请求,这时候提交过来多份数据,如果我们是批量添加用户的话,可能会提交过来多个用户,那么这个时候,我们就需要把他们封装到List集合或者Map集合中去。 刨去批量操作、我们比较少用这种封装到集合的知识点。
2.3.1封装到list
-
页面
<h1>01封装到list</h1> <form method="post" action="${pageContext.request.contextPath }/demo01"> 用户名:<input type="text" name="list[0].username"/><br/> 密 码:<input type="password" name="list[0].password"/><br/> 用户名:<input type="text" name="list[1].username"/><br/> 密 码:<input type="password" name="list[1].password"/><br/> <input type="submit"/> </form>
-
Action.java
public class ActionDemo01 extends ActionSupport { private List<User> list; public List<User> getList() { return list; } public void setList(List<User> list) { this.list = list; } public String fun01(){ System.out.println(list.toString()); return NONE; } }
2.3.2封装到Map
-
页面
<h1>02封装到map</h1> <form method="post" action="${pageContext.request.contextPath }/demo02"> 用户名:<input type="text" name="map['user1'].username"/><br/> 密 码:<input type="password" name="map['user1'].password"/><br/> 用户名:<input type="text" name="map['user2'].username"/><br/> 密 码:<input type="password" name="map['user2'].password"/><br/> <input type="submit"/> </form>
-
Action.java
-
public class ActionDemo02 extends ActionSupport { private Map<String, User> map; public Map<String, User> getMap() { return map; } public void setMap(Map<String, User> map) { this.map = map; } public String fun02(){ Set<Entry<String, User>> entrySet = map.entrySet(); for (Entry<String, User> entry : entrySet) { System.out.println(entry.getKey()+":"+entry.getValue().toString()); } return NONE; }