3、Struts2的API访问和数据封装
一、API的访问
在使用Struts2的框架的过程中,发现Struts2和Servlet的API是解耦合的。在实际开发中,经常使用到Servlet的API,比如进行登录,将用户的信息保存到Session中,
有的时候需要向页面输出一些内容,用到response对象。涉及到Servlet的API的访问。
1、完全解耦合的方式,通过ActionContext类访问[推荐]
Struts2框架提供了ActionContext类来访问Servlet API,ActionContext是Action执行的上下文对象。在ActionContext中保存了Action执行所需要的所有对象,
包括parameters,request,session,application等。
// 将key-value键值对放入ActionContext中,模拟Servlet API中的HTTPServletRequest 的setAttribute()方法 void put(String key,Object value) // 通过参数Key来查找当前ActionContext中的值 Object get(String key) // 返回一个Application级的对象 Map<String,Object> getApplication() // 获取当前线程的ActionContext对象 static ActionContext getContext() // 返回一个包含所有HttpServletRequest参数信息 Map<String,Object> getParameters() // 返回一个Map类型的HttpSession对象 Map<String,Object> getSession() // 设置Application上下文 void SetApplication(Map<String,Object> application) // 设置一个Map类型的Session值 void setSession(Map<String,Object> session)
注意:这种方式只能获得代表request、session、application的数据的Map集合,不能操作这些对象的本身的方法。
案例:
Action类
package com.turtle.demo4.action; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionSupport; import java.util.Map; public class Demo4Action extends ActionSupport { public String save(){ // 从前端返回来的参数中取值 // 通过ActionContext来取得ActionContext对象 ActionContext actionContext = ActionContext.getContext(); // actionContext.getParameters()可以取到map值的对象 Map<String, Object> contextParameters = actionContext.getParameters(); // 遍历输出值 for (Map.Entry<String,Object> entry : contextParameters.entrySet()){ String key = entry.getKey(); String value = entry.getValue().toString(); } // 向返回前端的参数中设置值 // 把值设置到session中 actionContext.getSession().put("name1","session"); // request.setAttribute("","") actionContext.put("name2","request"); // application.setAttribute("","") actionContext.getApplication().put("name3", "application"); return SUCCESS; } }
Jsp页面
<%-- Created by IntelliJ IDEA. User: 22274 Date: 2019/10/27 Time: 23:52 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Servlet</title> </head> <body> <h1>使用ServletContext</h1> <form action="${pageContext.request.contextPath}/demo4Action.action" method="post"> 用户名:<input type="text" name="name" value=""/><br/> 密 码:<input type="password" name="password" value=""/><br/> <input type="submit" value="提交"> </form> </body> </html>
<%-- Created by IntelliJ IDEA. User: 22274 Date: 2019/10/27 Time: 23:52 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <html> <head> <title>Servlet</title> </head> <body> <h1>使用ServletContext</h1> <form action="${pageContext.request.contextPath}/demo4Action.action" method="post"> Session :<input type="text" name="name1" value="${name1}"/><br/> Request :<input type="text" name="name2" value="${name2}"/><br/> Application:<input type="text" name="name3" value="${name3}"/><br/> <input type="submit" value="提交"> </form> </body> </html>
配置文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <package name="demo4" extends="struts-default" namespace="/"> <action name="demo4Action" class="com.turtle.demo4.action.Demo4Action" method="save"> <result name="success">/demo4/success.jsp</result> </action> </package> </struts>
结果:
2、使用Servlet的API的原生方式
该方法可以直接访问Servle API,提供了ServletActionContext类,该类包含了我么所需要的几个方法
// 获取web应用中的HttpServletRequest对象 static HttpServletRequest() // 获取web应用中的HttpServletResponse对象 static HttpServletResponse getResponse() // 获取web应用中的ServletContext对象 static ServletContext getServletContext() // 获取WEb应用中的PageContext对象 static PageContext getPageContext()
Action类:
package com.turtle.demo4.action; import com.opensymphony.xwork2.ActionSupport; import org.apache.struts2.ServletActionContext; import javax.servlet.http.HttpServletRequest; import java.util.Map; public class Demo4Action extends ActionSupport { public String save(){ // 取从前端页面带过来的数据 HttpServletRequest request = ServletActionContext.getRequest(); Map<String, String[]> parameterMap = request.getParameterMap(); for(Map.Entry<String,String[]> entry : parameterMap.entrySet()){ String key = entry.getKey(); String[] value = entry.getValue(); } // 往前端传的数据 request.setAttribute("name1","request"); request.getSession().setAttribute ("name2","session"); ServletActionContext.getServletContext().setAttribute("name3","servletContext"); return SUCCESS; } }
JSP页面和配置文件不做改变,显示的结果也是一样的。
3、接口注入的方式
// 实现该接口可以直接访问WEb应用中的HttpServletRequest实例 ServletRequestAware // 实现该接口可以直接访问WEb应用中的HttpServletResponse实例 ServletResponseAware // 实现该接口可以直接访问WEb应用中的HttpSession实例 SessionAware // 实现该接口可以直接访问WEb应用中的ServletContexte实例 ServletContextAware
Action:
package com.turtle.demo4.action; import com.opensymphony.xwork2.ActionSupport; import org.apache.struts2.ServletActionContext; import org.apache.struts2.interceptor.ServletRequestAware; import javax.servlet.http.HttpServletRequest; import java.util.Map; public class Demo4Action extends ActionSupport implements ServletRequestAware { private HttpServletRequest request; @Override public void setServletRequest(HttpServletRequest httpServletRequest) { this.request = httpServletRequest; } public String save(){ // 取从前端页面带过来的数据 Map<String, String[]> parameterMap = request.getParameterMap(); for(Map.Entry<String,String[]> entry : parameterMap.entrySet()){ String key = entry.getKey(); String[] value = entry.getValue(); } // 往前端传的数据 request.setAttribute("name1","request"); request.getSession().setAttribute ("name2","session"); ServletActionContext.getServletContext().setAttribute("name3","servletContext"); return SUCCESS; } }
配置文件和结果显示页面与上面的一致。
Servlet是单例的,多个程序访问同一个Servlet只会创建一个Servlet的实例。Action是多例的,一次请求,创建一个Action的实例(不会出现线程安全的问题)。
二、结果页面的配置
1、局部结果页面的配置:
局部结果页面指的是,只能在当前的action中的配置有效。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <package name="demo4" extends="struts-default" namespace="/"> <action name="demo4Action" class="com.turtle.demo4.action.Demo4Action" method="save"> <result name="success">/demo4/success.jsp</result> </action> </package> </struts>
2、全局结果页面的配置:
全局结果页面:全局结果页面指的是,在包中配置一次,其他的在这个包中的所有的action只要返回了这个值,都可以跳转到这个页面。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <package name="demo4" extends="struts-default" namespace="/"> <global-results> <result name="success">/demo4/success.jsp</result> </global-results> <action name="demo4Action" class="com.turtle.demo4.action.Demo4Action" method="save"> <!--<result name="success">/demo4/success.jsp</result>--> </action> </package> </struts>
3、result标签的配置
result标签用于配置页面的跳转。在result标签上有两个属性:
name属性 :逻辑视图的名称。默认值:success
type属性 :页面跳转的类型。
dispatcher :默认值,请求转发。(Action转发JSP)
redirect :重定向。(Action重定向JSP)
chain :转发。(Action转发Action)
redirectAction :重定向。(Action重定向Action)
stream :Struts2中提供文件下载的功能。
三、数据封装:
1、属性驱动:提供属性set方法的方式(不常用)
Action类:
package com.turtle.demo5; import com.opensymphony.xwork2.ActionSupport; public class Demo5Action extends ActionSupport { // 用户名 private String name; // 密码 private String password; 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 save() { System.out.println("用户名"+name); System.out.println("密码"+password); return null; } }
前端页面:
<%-- Created by IntelliJ IDEA. User: 22274 Date: 2019/10/27 Time: 23:52 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Servlet</title> </head> <body> <h1>属性驱动第一种方法</h1> <form action="${pageContext.request.contextPath}/demo5Action.action" method="post"> 用户名:<input type="text" name="name" /><br/> 密 码:<input type="password" name="password"/><br/> <input type="submit" value="提交"> </form> </body> </html>
2、属性驱动:页面中提供表达式方式
封装的对象
package com.turtle.demo5; public class User { // 名字 private String name; // 密码 private String password; 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; } }
Action类
package com.turtle.demo5; import com.opensymphony.xwork2.ActionSupport; public class Demo5Action extends ActionSupport { // 用户对象 private User user; public String save() { System.out.println("用户名"+user.getName()); System.out.println("密码"+user.getPassword()); return null; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } }
Jsp页面:
<%-- Created by IntelliJ IDEA. User: 22274 Date: 2019/10/27 Time: 23:52 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Servlet</title> </head> <body> <h1>属性驱动第一种方法</h1> <form action="${pageContext.request.contextPath}/demo5Action.action" method="post"> 用户名:<input type="text" name="user.name" /><br/> 密 码:<input type="password" name="user.password"/><br/> <input type="submit" value="提交"> </form> </body> </html>
3、模型驱动,采用模型驱动方式(最常用)
通过实现ModelDriven接口来接收参数,Action类必须实现ModelDerven接口,并且要重写getModel方法,这个方法返回的是Action类所要使用的数据模型对象。
Action类
package com.turtle.demo5; import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.ModelDriven; public class Demo5Action extends ActionSupport implements ModelDriven<User> { // 用户对象,需要手动进行实例化 private User user = new User(); /** * 主要就是这个方法 * @return */ @Override public User getModel() { return user; } public String save() { System.out.println("用户名"+user.getName()); System.out.println("密码"+user.getPassword()); return null; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } }
jsp页面
<%-- Created by IntelliJ IDEA. User: 22274 Date: 2019/10/27 Time: 23:52 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Servlet</title> </head> <body> <h1>属性驱动第一种方法</h1> <form action="${pageContext.request.contextPath}/demo5Action.action" method="post"> 用户名:<input type="text" name="name" /><br/> 密 码:<input type="password" name="password"/><br/> <input type="submit" value="提交"> </form> </body> </html>
汇总:大部分我们会优先使用模型驱动的方式,因为Struts2内部有很多结果都是围绕模型驱动设计的。但如果页面中向
多个对象中封装,那么就要使用属性驱动的方式二了。
4、封装到List集合中
Action类
package com.turtle.demo5; import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.ModelDriven; import java.util.List; public class Demo5Action extends ActionSupport { // 用户对象,需要手动进行实例化 // 该变量和jsp中使用的list名字要一致,而且get/set方法也要一致 private List<User> userList; public String save() { for(User user : userList){ System.out.println("用户名"+user.getName()); System.out.println("密码"+user.getPassword()); } return null; } public List<User> getUserList() { return userList; } public void setUserList(List<User> userList) { this.userList = userList; } }
JSp页面:
<%-- Created by IntelliJ IDEA. User: 22274 Date: 2019/10/27 Time: 23:52 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Servlet</title> </head> <body> <h1>属性驱动第一种方法</h1> <form action="${pageContext.request.contextPath}/demo5Action.action" method="post"> 用户名:<input type="text" name="userList[0].name" /><br/> 密 码:<input type="password" name="userList[0].password"/><br/> <hr/> 用户名:<input type="text" name="userList[1].name" /><br/> 密 码:<input type="password" name="userList[1].password"/><br/> <input type="submit" value="提交"> </form> </body> </html>
5、封装到Map集合中
Action类
package com.turtle.demo5; import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.ModelDriven; import java.util.List; import java.util.Map; public class Demo5Action extends ActionSupport { private Map<String,User> userMap; public String save() { for(Map.Entry<String,User> user : userMap.entrySet()){ System.out.println("用户名"+user.getValue().getName()); System.out.println("密码"+user.getValue().getPassword()); } return null; } public Map<String, User> getUserMap() { return userMap; } public void setUserMap(Map<String, User> userMap) { this.userMap = userMap; } }
Jsp页面
<%-- Created by IntelliJ IDEA. User: 22274 Date: 2019/10/27 Time: 23:52 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Servlet</title> </head> <body> <h1>属性驱动第一种方法</h1> <form action="${pageContext.request.contextPath}/demo5Action.action" method="post"> 用户名:<input type="text" name="userMap['0'].name" /><br/> 密 码:<input type="password" name="userMap['0'].password"/><br/> <hr/> 用户名:<input type="text" name="userMap['1'].name" /><br/> 密 码:<input type="password" name="userMap['1'].password"/><br/> <input type="submit" value="提交"> </form> </body> </html>