1、通过请求访问POJO类:

  1. package work.huacai.pojo;
  2. /**
  3. * @author mycomputer
  4. */
  5. public class LoginAction {
  6. public void execute(){
  7. System.out.println("LoginAction execute method!!!");
  8. }
  9. }

1. servlet方式:

  1. package work.huacai.servlet;
  2. import work.huacai.pojo.LoginAction;
  3. import javax.servlet.ServletException;
  4. import javax.servlet.annotation.WebServlet;
  5. import javax.servlet.http.HttpServlet;
  6. import javax.servlet.http.HttpServletRequest;
  7. import javax.servlet.http.HttpServletResponse;
  8. import java.io.IOException;
  9. /**
  10. * @author mycomputer
  11. */
  12. @WebServlet("/login")
  13. public class LoginServlet extends HttpServlet {
  14. @Override
  15. protected void doPost(HttpServletRequest req, HttpServletResponse resp)
  16. throws ServletException, IOException {
  17. //当请求为/login时,进入到LoginServlet的doPost方法里,创建POJO类对象,执行相应方法
  18. new LoginAction().execute();
  19. }
  20. }

2. filter方式:

  1. package work.huacai.filter;
  2. import work.huacai.pojo.LoginAction;
  3. import javax.servlet.*;
  4. import javax.servlet.annotation.WebFilter;
  5. import java.io.IOException;
  6. /**
  7. * @author mycomputer
  8. */
  9. @WebFilter("/login")
  10. public class LoginFilter implements Filter {
  11. @Override
  12. public void init(FilterConfig filterConfig) throws ServletException {
  13. }
  14. @Override
  15. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
  16. //当请求为/login时,拦截请求,进入到LoginFilter的doFilter方法里,
  17. //创建POJO类对象,执行相应方法
  18. new LoginAction().execute();
  19. }
  20. @Override
  21. public void destroy() {
  22. }
  23. }

上面的代码存在一些问题,请求与页面跳转没有进行绑定;一个请求对应一个servlet或者Filter,灵活性不高

  1. package work.huacai.pojo;
  2. /**
  3. * @author mycomputer
  4. */
  5. public class LoginAction {
  6. public String execute(){
  7. System.out.println("LoginAction execute method!!!");
  8. return "success";
  9. }
  10. }
  1. package work.huacai.filter;
  2. import javax.servlet.*;
  3. import javax.servlet.annotation.WebFilter;
  4. import javax.servlet.http.HttpServletRequest;
  5. import javax.servlet.http.HttpServletResponse;
  6. import java.io.IOException;
  7. import java.lang.reflect.InvocationTargetException;
  8. import java.util.HashMap;
  9. import java.util.Map;
  10. /**
  11. * @author mycomputer
  12. */
  13. @WebFilter("/login")
  14. public class LoginFilter implements Filter {
  15. @Override
  16. public void init(FilterConfig filterConfig) throws ServletException {
  17. }
  18. @Override
  19. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
  20. HttpServletResponse response = (HttpServletResponse)servletResponse;
  21. HttpServletRequest request = (HttpServletRequest)servletRequest;
  22. Map<String,String> map = new HashMap<>(10);
  23. map.put("/login","work.huacai.pojo.LoginAction");
  24. map.put("/list","work.huacai.pojo.ListAction");
  25. map.put("success","/index.jsp");
  26. map.put("error","/login.jsp");
  27. try {
  28. Class c1 = Class.forName(map.get(request.getServletPath()));
  29. //实例化对象
  30. Object obj = c1.newInstance();
  31. //调用方法
  32. Object result = c1.getMethod("execute").invoke(obj);
  33. //获取页面路径
  34. String path = map.get(result);
  35. //页面跳转
  36. response.sendRedirect(path);
  37. } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
  38. e.printStackTrace();
  39. }
  40. }
  41. @Override
  42. public void destroy() {
  43. }
  44. }

上方代码还是存在一个问题,每次绑定请求都需要向map集合中添加,需要不断地更改源代码,再重新编译;解决的方式便是通过配置文件的形式去绑定,请求与servlet或者filter的关系,当配置文件修改,不需要再去重新编译,只需要重新加载配置文件

2、MVC与三层架构

3、struts2框架

image.png

  • 特点:

非侵入式设计,struts2的Action类是一个POJO类,不依赖于Servlet API和Struts API
提供拦截器,可以实现AOP编程
提供类型转换器,将特殊的请求参数转换为需要的类型
输入验证,对指定方法进行验证
提供了全局范围、包范围和 Action范围的国际化资源文件管理实现

1. 搭建struts2的运行环境

  1. - 添加struts2运行所需的最基本jar(在路径:struts-2.3.37\apps\struts2-blank\WEB-INF\lib下复制)

image.png

上面图中,1、2、3、8这四个jar包是用于代理的;4、5用于文件上传;6是对java.lang包的一个扩展;7是模板引擎,一个基于模板生成文本输出的通用工具;9、10是通用日志记录包;11是支持ognl表达式;12是struts2的核心包;13是xwork的核心包(Struts 2以WebWork为核心)

  1. - 注册启动项
  1. <filter>
  2. <filter-name>struts2</filter-name>
  3. <!--
  4. 1.从示例中的web.xml拷贝
  5. 2.在struts2-core-2.3.37.jar包下,找org\apache\struts2\dispatcher\ng\filter包的
  6. StrutsPrepareAndExecuteFilter类
  7. -->
  8. <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
  9. </filter>
  10. <filter-mapping>
  11. <filter-name>struts2</filter-name>
  12. <url-pattern>/*</url-pattern>
  13. </filter-mapping>
  1. - struts.xml文件
  1. <!--
  2. 1.从示例中的src下的struts.xml拷贝
  3. 2.在struts2-core-2.3.37.jar包下找.dtd文件
  4. -->
  5. <!DOCTYPE struts PUBLIC
  6. "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
  7. "http://struts.apache.org/dtds/struts-2.3.dtd">

2. 实现第一个struts2程序

  1. - 编写Action类(包名需是xxx.actionsxxx.actionxxx.strutsxxx.struts2四个中的一种,因为在注解开发时存在这么一个约定)
  1. package work.huacai.actions;
  2. /**
  3. * @author mycomputer
  4. */
  5. public class LoginAction {
  6. public String execute(){
  7. return "success";
  8. }
  9. }
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE struts PUBLIC
  3. "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
  4. "http://struts.apache.org/dtds/struts-2.3.dtd">
  5. <struts>
  6. <!-- namespace可以理解为是一个请求的公共前缀的提取 -->
  7. <package name="user" namespace="/" extends="struts-default">
  8. <!-- 当请求地址为/login.action时,执行的work.huacai.actions.LoginAction类的execute方法 -->
  9. <action name="login" class="work.huacai.actions.LoginAction">
  10. <!-- name:execute方法返回的字符串内容 -->
  11. <result name="success">/success.jsp</result>
  12. </action>
  13. </package>
  14. </struts>

3. Struts2执行流程

4. tomcat的应用管理配置

  1. - 解决get请求的中文乱码问题(在server.xml文件如下位置,添加URIEncoding="UTF-8"
  1. <Connector
  2. connectionTimeout="20000"
  3. port="8080"
  4. protocol="HTTP/1.1"
  5. redirectPort="8443"
  6. URIEncoding="UTF-8"/>
  1. - 找到tomcattomcat-users.xml文件,添加一个用户,usernamepassword可以自定义
  1. <role rolename="manager-gui"/>
  2. <user roles="manager-gui" password="s3cret" username="tomcat"/>
  1. - 在浏览器上输入该网址:[http://localhost:8080/manager/](http://localhost:8080/manager/),输入用户名和密码即可进入下方的页面

image.png

  1. - server.xml8080端口号修改为为80,即可输入地址时,省略8080端口号
  2. - 通过将项目部署到路径:apache-tomcat-8.0.43\webapps\ROOT,可以**在地址栏上省去项目名**

5. 路径问题

  1. - 以斜杠开头的相对路径,前台相对路径的参照是web服务器的根路径:http://127.0.0.1:8080/;后台相对路径的参照web应用的根路径:http://127.0.0.1:8080/manager/
  2. - 不以斜杠开头的相对路径,无论前台、后台路径,其参照都是当前资源的访问路径(/test/index.jsp的访问路径是/test/,/test/index.jsp是资源路径),而不是当前资源的保存路径

jsp前台页面跳转路径建议前面加上${pageContext.request.contextPath},相当于前面加上了“/项目名” jsp使用base标签: 1、添加脚本: <% //相当于:http://localhost:8080/manager/ String base = request.getContextPath()+”/“; String url = request.getScheme()+”://“+request.getServerName()+”:” +request.getServerPort()+base; %> 2、标签中添加标签

4、struts-default.xml

struts-default.xml是Struts 2 框架的基础配置文件,为框架提供默认设置,这个文件包含在Struts2-core-2.0.11.jar中,由框架自动加载

5、default.properties

该文件对struts2框架进行了默认配置,开发者想要修改某些属性值得话,可以在src目录下新建一个文件struts.properties然后写入想修改的属性和值

default.properties中的信息可以在struts.xml中使用元素constant来进行配置,一般我们选择其一就行,不推荐交叉使用,对于上传文件属性maxsize而言,constant优先级高于default.properties,即如果两处都配置的话,constant配置的生效

6、struts-plugin.xml

struts2与第三方插件的整合配置文件,如果不是开发插件的话,是不需要编写这个配置文件的,一般是使用插件

7、struts.properties

可以通过 struts.properties 来管理 Struts2框架中定义的大量常量。struts.properties文件是一个标准的properties文件,其格式是 key-value ,key表示的是Struts2框架中的常量,而value则是其常量值

struts.properties文件必须放在 Web 应用下的类加载路径下才能使用,即 WEB-INF/classes 路径下(在 eclipse 中,通常直接将其放在 src 路径下就可以)

struts.properties文件中的属性同样也可以在struts.xml文件中配置,只是源于struts配置文件模块化管理思路,将其分文件管理,增加了程序的可读性,以及降低了后期维护的难度。小型的项目可以将属性直接配置在struts.xml文件中

8、配置文件优先级

web.xml > struts.properties > struts.xml > default.properties

9、struts.xml属性

1. package

  1. <!-- package的name属性和namespace属性存在一定的命名规范 -->
  2. <package name="xxx-ooo-user" namespace="/xxx/ooo/user" extends="struts-default">
  3. </package>

2. action-class属性

  1. <!--
  2. package work.huacai.actions;
  3. /**
  4. * @author mycomputer
  5. */
  6. public class LoginAction {
  7. public String execute(){
  8. return "success";
  9. }
  10. }
  11. 如果name为“login”的action所绑定的类的代码与上方类似,只是跳转到name = success 所绑定的页面,
  12. 没有其他作用时,class属性可以直接省略,省略之后,访问xxx/ooo/user/login请求时,会调用
  13. com.opensymphony.xwork2.ActionSupport类的execute方法
  14. -->
  15. <package name="xxx-ooo-user" namespace="/xxx/ooo/user" extends="struts-default">
  16. <action name="login">
  17. <result name="success">/success.jsp</result>
  18. </action>
  19. </package>

3. action-method属性

  1. <package name="xxx-ooo-user" namespace="/xxx/ooo/user" extends="struts-default">
  2. <!-- method属性可以修改action方法的名字,即方法名可以是除execute外的其他名称 -->
  3. <action name="login" class="work.huacai.actions.LoginAction" method="test">
  4. <result name="success">/success.jsp</result>
  5. </action>
  6. </package>

4. result-name属性

  1. <package name="xxx-ooo-user" namespace="/xxx/ooo/user" extends="struts-default">
  2. <action name="login" class="work.huacai.actions.LoginAction" method="execute">
  3. <!-- 如果name="success"可以省略不写 -->
  4. <result>/success.jsp</result>
  5. </action>
  6. </package>

5. result-请求转发与重定向

  1. <package name="xxx-ooo-user" namespace="/xxx/ooo/user" extends="struts-default">
  2. <action name="login" class="work.huacai.actions.LoginAction">
  3. <!-- type默认就是dispatcher(请求转发) -->
  4. <result type="dispatcher">/success.jsp</result>
  5. </action>
  6. </package>
  1. <package name="xxx-ooo-user" namespace="/xxx/ooo/user" extends="struts-default">
  2. <action name="login" class="work.huacai.actions.LoginAction">
  3. <result type="redirect">/success.jsp</result>
  4. <!-- 通过向地址栏中放入参数来获取数据,jsp通过 param.地址的参数名称 获取参数值 -->
  5. <result type="redirect">/success.jsp?uname=${name}&amp;uage=${age}</result>
  6. <!--上方跳转传参方式建议替换为以下方式 -->
  7. <result type="redirect">
  8. <param name="location">/success.jsp</param>
  9. <param name="uname">${name}</param>
  10. <!-- ${xx}ognl表达式 -->
  11. <param name="uage">${age}</param>
  12. </result>
  13. </action>
  14. </package>
  1. <package name="xxx-ooo-user" namespace="/xxx/ooo/user" extends="struts-default">
  2. <action name="login" class="work.huacai.actions.LoginAction">
  3. <result type="redirectAction">
  4. <!-- actionName后面不用加.action或者其他后缀 -->
  5. <param name="actionName">list</param>
  6. <param name="uname">${name}</param>
  7. <param name="uage">${age}</param>
  8. </result>
  9. </action>
  10. <action name="list" class="work.huacai.actions.ListAction">
  11. <result>/list.jsp</result>
  12. </action>
  13. </package>
  1. <package name="xxx-ooo-user" namespace="/xxx/ooo/user" extends="struts-default">
  2. <action name="login" class="work.huacai.actions.LoginAction">
  3. <!-- 后面不用加.action或者其他后缀 -->
  4. <result type="chain">list</result>
  5. </action>
  6. <action name="list" class="work.huacai.actions.ListAction">
  7. <result>/list.jsp</result>
  8. </action>
  9. </package>

6. 全局视图配置

  1. <package name="xxx-ooo-user" namespace="/xxx/ooo/user" extends="struts-default">
  2. <!--包范围全局视图,用于提取公共的result,需在action的前面-->
  3. <global-results>
  4. <result name="test">/test.jsp</result>
  5. </global-results>
  6. <action name="login" class="work.huacai.actions.LoginAction">
  7. <result type="chain">list</result>
  8. </action>
  9. <action name="list" class="work.huacai.actions.ListAction">
  10. <result>/list.jsp</result>
  11. </action>
  12. </package>
  1. <!-- 该包仅作为一个全局视图包,不需要action则可以将namespace属性去除,将其定义为abstract -->
  2. <package name="basepackage" extends="struts-default" abstract="true">
  3. <!--包范围全局视图,用于提取公共的result,需在action的前面-->
  4. <global-results>
  5. <result name="test">/test.jsp</result>
  6. </global-results>
  7. </package>
  8. <!-- 让其他的包继承上面的全局视图包 -->
  9. <package name="xxx-ooo-user" namespace="/xxx/ooo/user" extends="basepackage">
  10. <action name="login" class="work.huacai.actions.LoginAction">
  11. <result type="chain">list</result>
  12. </action>
  13. <action name="list" class="work.huacai.actions.ListAction">
  14. <result>/list.jsp</result>
  15. </action>
  16. </package>

7. 为应用指定多个配置文件

  1. - 随着应用规模的增加,系统中Action的数量也会大量增加,导致struts.xml配置文件变得非常臃肿,为了避免struts.xml文件过于庞大、臃肿,提高Struts.xml文件的可读性,我们可以将一个struts.xml配置文件分解成多个配置文件,然后再通过struts.xml文件中包含其他配置文件
  1. <struts>
  2. <!--
  3. 这种包含其实是struts2框架会自动地将这些文件拷贝到struts.xml文件中,所以每个xml文件的
  4. package的name、action是不可以重复的
  5. -->
  6. <include file="department.xml"/> 一个模块使用一个配置文件
  7. <include file="employee.xml"/>
  8. <!-- 当文件名前缀相同,可以通过通配符包含这些文件 -->
  9. <include file="manager-*.xml"/>
  10. <!-- 不需要在resources前面加上classpath: -->
  11. <include file="classpath:resources/manager-*.xml"/>
  12. </struts>

10、在Action中获取servletAPI

1. 通过ActionContext获取

  1. package work.huacai.actions;
  2. import com.opensymphony.xwork2.ActionContext;
  3. /**
  4. * @author mycomputer
  5. */
  6. public class ListAction {
  7. public String execute(){
  8. //这种方式获取到的仅是servletAPI的域属性空间,不是真正的API,且无法获取response
  9. ActionContext.getContext().getSession().put("session","session_value");
  10. ActionContext.getContext().put("req","req_value");
  11. ActionContext.getContext().getApplication().put("Application","Application_value");
  12. return "success";
  13. }
  14. }

2. 通过ServletActionContext获取

  1. ServletActionContext.getRequest().setAttribute("req","req_value");
  2. ServletActionContext.getRequest().getSession().setAttribute("session","session_value");
  3. ServletActionContext.getServletContext().setAttribute("Application","Application_value");

3. 通过实现特定的接口获取

  1. package work.huacai.actions;
  2. import org.apache.struts2.interceptor.ApplicationAware;
  3. import org.apache.struts2.interceptor.RequestAware;
  4. import org.apache.struts2.interceptor.SessionAware;
  5. import java.util.Map;
  6. /**
  7. * 不建议,这种方式污染了代码,不是一个POJO类了
  8. * @author mycomputer
  9. */
  10. public class ListAction implements RequestAware, SessionAware, ApplicationAware {
  11. private Map<String, Object> request;
  12. private Map<String, Object> session;
  13. private Map<String, Object> application;
  14. public String execute(){
  15. request.put("req","req_value");
  16. session.put("session","session_value");
  17. application.put("app","app_value");
  18. return "success";
  19. }
  20. @Override
  21. public void setRequest(Map<String, Object> map) {
  22. this.request = map;
  23. }
  24. @Override
  25. public void setApplication(Map<String, Object> map) {
  26. this.session = map;
  27. }
  28. @Override
  29. public void setSession(Map<String, Object> map) {
  30. this.application = map;
  31. }
  32. }

11、OGNL与值栈

  • OGNL是Object-Graph Navigation Language的缩写,一种功能强大的表达式语言,是一个第三方开源项目,struts框架用OGNL进行表达式的计算,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化

  • 相对于其它表达式语言,它提供了更加丰富的功能:

    • 支持对象方法调用
    • 支持静态方法调用(需要通过在struts2的配置文件struts.xml中设置常量struts.xml中设置常量struts.ognl.allowStaticMethodAccess的值为true进行开启)和常量访问,表达式的格式为:@[全限定类名]@[方法名 | 常量名]
    • 可以操作集合对象
    • 可以直接创建对象
      1. <constant name="struts.ognl.allowStaticMethodAccess" value="true"/>
      1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      2. <%@taglib uri="/struts-tags" prefix="s"%>
      3. <html>
      4. <head>
      5. <title>success</title>
      6. </head>
      7. <body>
      8. PI = <s:property value="@java.lang.Math@PI"/>
      9. random = <s:property value="@java.lang.Math@random() * 100"/>
      10. </body>
      11. </html>

在struts2框架里面,ognl的上下文是ActionText,ognl的根对象是是值栈;在ActionText对象之中还有application、session、request、parameters、attr(page、request、session、then application scopes),对于根对象的访问可以直接访问,对于非根对象的访问需要加#

1. 值栈(valueStack)

  1. - ValueStack是一个接口,它的实现只有一个OgnlValueStack,在OgnlValueStack之中有一个属性root,类型是CompoundRoot,而CompoundRoot其实是一个栈结构,且继承了ArrayList;还有一个属性context,类型是Map<String, Object>,当OgnlValueStack的构造方法调用后,会构建一个CompoundRoot类型的对象应用赋给属性root,并且会将Ognl构建的context对象的引用赋给属性context,从而将OgnlcontextOgnlValueStackcontext属性联系

2. 值栈的获取

  1. - 当一个 Action请求到来时,不仅会创建一个 Action 实例,还会创建一个 ValueStack对象,用于存放当前Action运行过程中的相关数据。当该请求结束,Action实例消失,用于记录其运行期间数据的栈也就没有了意义。所以,当请求结束时,同时需要将值栈对象销毁,即值栈的生命周期与请求Request的相同。为了保证这一点,就将值栈对象通过setAttribute()方法,将其放入到了 request域属性中,并将该属性的key以常量的形式保存在ServletActionContext 中。所以,为了获取值栈对象,首先需要获取到Request对象,然后再获取到其 key,这样才能获取到值栈对象。这个过程相对是比较麻烦的
  2. - 值栈的实质是**request中的一个属性值**,这个属性的名称为:struts.valueStack,保存在ServletActionContext的**常量 STRUTS_ VALUESTACK_KEY **中
  1. package work.huacai.actions;
  2. import com.opensymphony.xwork2.util.ValueStack;
  3. import org.apache.struts2.ServletActionContext;
  4. /**
  5. * @author mycomputer
  6. */
  7. public class ListAction {
  8. public String execute(){
  9. ValueStack valueStack = (ValueStack) ServletActionContext
  10. .getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
  11. return "success";
  12. }
  13. }

3. context属性的别名ActionContext

  1. - Struts2中,值栈的context属性所起的作用是比较大的,且在代码中需要经常访问。但从以上分析可知,要想获取到context 属性,首先要获取到值栈对象,而获取值栈对象本身就是个比较麻烦的过程,这就导致获取值栈的 context属性会更加麻烦。
  2. - 为了方便获取值恚的context属性Struts2专门为其又起了个别名---- ActionContext,通过ActionContextgetContext()就可以直接获取到值栈的context属性。
  3. - 无论是 ActionContext中存放的非根对象,还是值栈中 context 中存放的非根对象,它们均使用了同一个Map。即它们是同一个对象。
  1. package actions;
  2. import com.opensymphony.xwork2.ActionContext;
  3. import com.opensymphony.xwork2.util.ValueStack;
  4. import org.apache.struts2.ServletActionContext;
  5. import java.util.Map;
  6. /**
  7. * @author mycomputer
  8. */
  9. public class VauleStackTest {
  10. public String execute(){
  11. //获取ActionContext的context属性
  12. ActionContext actionContext = ActionContext.getContext();
  13. actionContext.put("key","ActionContext");
  14. //获取ValueStack的context属性
  15. String key = ServletActionContext.STRUTS_VALUESTACK_KEY;
  16. ValueStack valueStack = (ValueStack)ServletActionContext.getRequest().getAttribute(key);
  17. Map<String, Object> context = valueStack.getContext();
  18. context.put("key","context");
  19. return "success";
  20. }
  21. }

4. 值栈获取第二种方式

  1. package actions;
  2. import com.opensymphony.xwork2.ActionContext;
  3. import com.opensymphony.xwork2.util.ValueStack;
  4. /**
  5. * @author mycomputer
  6. */
  7. public class VauleStackTest {
  8. public String execute(){
  9. //通过ActionContext获取值栈对象
  10. ValueStack valueStack = ActionContext.getContext().getValueStack();
  11. return "success";
  12. }
  13. }

查看OgnlValueStack类中的peek()、pop()、push()方法可知,对valueStack对象的栈的操作,本质是对root栈对象的操作;从宏观上可以直接说值栈就是根对象。但,其实根对象指的是值栈的root对象,而非根对象是值栈的context对象。

5. 值栈操作

5.1 向root中添加无名参数(显示放入)

  1. package actions;
  2. import com.opensymphony.xwork2.ActionContext;
  3. import com.opensymphony.xwork2.util.ValueStack;
  4. import entity.Student;
  5. /**
  6. * @author mycomputer
  7. */
  8. public class VauleStackTest {
  9. public String execute(){
  10. ValueStack valueStack = ActionContext.getContext().getValueStack();
  11. Student student = new Student("张三",18);
  12. Student student1 = new Student("李四",20);
  13. valueStack.push(student);
  14. valueStack.getRoot().push(student1);
  15. return "success";
  16. }
  17. }
  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <%@taglib uri="/struts-tags" prefix="s"%>
  3. <html>
  4. <head>
  5. <title>success</title>
  6. </head>
  7. <body>
  8. <s:debug/>
  9. <s:property value="name"/>
  10. <s:property value="age"/>
  11. </body>
  12. </html>

image.png

5.2 向root添加有名对象(显示放入)

  1. package actions;
  2. import com.opensymphony.xwork2.ActionContext;
  3. import com.opensymphony.xwork2.util.ValueStack;
  4. import entity.Student;
  5. import java.util.HashMap;
  6. import java.util.Map;
  7. /**
  8. * @author mycomputer
  9. */
  10. public class VauleStackTest {
  11. public String execute(){
  12. ValueStack valueStack = ActionContext.getContext().getValueStack();
  13. Map<String,Student> map = new HashMap<>(10);
  14. Student student = new Student("张三",18);
  15. map.put("student",student);
  16. //向值栈中添加map
  17. valueStack.push(map);
  18. Student student1 = new Student("李四",20);
  19. //通过set方法添加,会判断栈顶是否为map,如果不是,则会创建一个map
  20. valueStack.set("student1",student1);
  21. return "success";
  22. }
  23. }
  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <%@taglib uri="/struts-tags" prefix="s"%>
  3. <html>
  4. <head>
  5. <title>success</title>
  6. </head>
  7. <body>
  8. <s:debug/>
  9. <s:property value="name"/>
  10. <s:property value="age"/>
  11. <s:property value="student.age"/>
  12. <s:property value="student1.age"/>
  13. </body>
  14. </html>

image.png

5.3 将root作为ArrayList放入数据(显示放入)

  1. package actions;
  2. import com.opensymphony.xwork2.ActionContext;
  3. import com.opensymphony.xwork2.util.ValueStack;
  4. import entity.Student;
  5. import java.util.HashMap;
  6. import java.util.Map;
  7. /**
  8. * @author mycomputer
  9. */
  10. public class VauleStackTest {
  11. public String execute(){
  12. ValueStack valueStack = ActionContext.getContext().getValueStack();
  13. Map<String,Student> map = new HashMap<>(10);
  14. Student student = new Student("张三",18);
  15. map.put("student",student);
  16. Student student1 = new Student("李四",20);
  17. Student student3 = new Student("王五",22);
  18. //向值栈中添加map
  19. valueStack.push(map);
  20. //通过set方法添加
  21. valueStack.set("student1",student1);
  22. //将root作为ArrayList放入数据
  23. valueStack.getRoot().add(student3);
  24. return "success";
  25. }
  26. }

image.png

5.4 向root隐式放入数据

  1. package actions;
  2. /**
  3. * @author mycomputer
  4. */
  5. public class VauleStackTest {
  6. private String name;
  7. private int age;
  8. public String getName() {
  9. return name;
  10. }
  11. public void setName(String name) {
  12. this.name = name;
  13. }
  14. public int getAge() {
  15. return age;
  16. }
  17. public void setAge(int age) {
  18. this.age = age;
  19. }
  20. public String execute(){
  21. name = "张三";
  22. age = 18;
  23. return "success";
  24. }
  25. }

image.png

5.5 向context中显式放入数据

  1. package actions;
  2. import com.opensymphony.xwork2.ActionContext;
  3. /**
  4. * @author mycomputer
  5. */
  6. public class VauleStackTest {
  7. private String name;
  8. private int age;
  9. public String getName() {
  10. return name;
  11. }
  12. public void setName(String name) {
  13. this.name = name;
  14. }
  15. public int getAge() {
  16. return age;
  17. }
  18. public void setAge(int age) {
  19. this.age = age;
  20. }
  21. public String execute(){
  22. ActionContext context = ActionContext.getContext();
  23. context.put("some","some_value");
  24. context.put("req","req_value");
  25. context.getSession().put("ses","ses_value");
  26. context.getApplication().put("app","app_value");
  27. return "success";
  28. }
  29. }
  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <%@taglib uri="/struts-tags" prefix="s"%>
  3. <html>
  4. <head>
  5. <title>success</title>
  6. </head>
  7. <body>
  8. <s:debug/>
  9. <s:property value="#request.req"/>
  10. <s:property value="#session.ses"/>
  11. <s:property value="#application.app"/>
  12. <s:property value="#some"/>
  13. </body>
  14. </html>

image.png

5.6 向context中隐式放入数据

  1. package actions;
  2. import com.opensymphony.xwork2.ActionContext;
  3. /**
  4. * @author mycomputer
  5. */
  6. public class LoginAction {
  7. private String name;
  8. private int age;
  9. public String getName() {
  10. return name;
  11. }
  12. public void setName(String name) {
  13. this.name = name;
  14. }
  15. public int getAge() {
  16. return age;
  17. }
  18. public void setAge(int age) {
  19. this.age = age;
  20. }
  21. public String zhuce(){
  22. name = "张三";
  23. age = 18;
  24. ActionContext context = ActionContext.getContext();
  25. context.put("name","赵六");
  26. context.put("age",20);
  27. return "success";
  28. }
  29. }
  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <%@taglib uri="/struts-tags" prefix="s"%>
  3. <html>
  4. <head>
  5. <title>success</title>
  6. </head>
  7. <body>
  8. <s:debug/>
  9. <!-- 底层执行的是request.getAttribute("key"); -->
  10. <s:property value="#name"/>
  11. <s:property value="#age"/>
  12. <!-- 隐式的放入数据有以下两种 -->
  13. <s:property value="#parameters.name"/>
  14. <!-- 底层执行的是request.getParameter("name"); -->
  15. <s:property value="#parameters.age"/>
  16. <s:property value="#action.name"/>
  17. <s:property value="#action.age"/>
  18. </body>
  19. </html>
  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <html>
  3. <head>
  4. <title>注册页面</title>
  5. </head>
  6. <body>
  7. <form action="zhuce" method="post">
  8. 名字:<input type="text" name="name"><br>
  9. 年龄:<input type="password" name="age"><br>
  10. <input type="submit" value="注册">
  11. </form>
  12. </body>
  13. </html>

5.7 root中数据的加载顺序

  1. package actions;
  2. import com.opensymphony.xwork2.ActionContext;
  3. /**
  4. * @author mycomputer
  5. */
  6. public class VauleStackTest {
  7. private String name;
  8. private int age;
  9. public String getName() {
  10. return name;
  11. }
  12. public void setName(String name) {
  13. this.name = name;
  14. }
  15. public int getAge() {
  16. return age;
  17. }
  18. public void setAge(int age) {
  19. this.age = age;
  20. }
  21. public String execute(){
  22. ActionContext.getContext().put("value","context_value");
  23. return "success";
  24. }
  25. }
  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <%@taglib uri="/struts-tags" prefix="s"%>
  3. <html>
  4. <head>
  5. <title>success</title>
  6. </head>
  7. <body>
  8. <%--在 Action中仅向context放入某数据value后,页面无论是通过#从context中读取数据,--%>
  9. <%--还是不使用#直接从 root中读取数据,均可得到放入的值。会先去root中找,再去context中找--%>
  10. <s:property value="value"/><br>
  11. <s:property value="#value"/><br>
  12. </body>
  13. </html>

5.8 request中数据的加载顺序

  1. package actions;
  2. import com.opensymphony.xwork2.ActionContext;
  3. import org.apache.struts2.ServletActionContext;
  4. /**
  5. * @author mycomputer
  6. */
  7. public class VauleStackTest {
  8. private String name;
  9. private int age;
  10. public String getName() {
  11. return name;
  12. }
  13. public void setName(String name) {
  14. this.name = name;
  15. }
  16. public int getAge() {
  17. return age;
  18. }
  19. public void setAge(int age) {
  20. this.age = age;
  21. }
  22. public String execute(){
  23. ActionContext.getContext().put("value","context_value");
  24. ActionContext.getContext().getValueStack().set("value","request_value");
  25. ServletActionContext.getRequest().setAttribute("value","req_value");
  26. return "success";
  27. }
  28. }
  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <%@taglib uri="/struts-tags" prefix="s"%>
  3. <html>
  4. <head>
  5. <title>success</title>
  6. </head>
  7. <body>
  8. <%--当前的request并不是servletAPI中的request,而是struts2封装后的request;--%>
  9. <%--request.value底层执行的是request.getAttribute("some") --%>
  10. <%--request.someStruts2包装后的查找顺序是:--%>
  11. <%--1request域空间--%>
  12. <%--2root--%>
  13. <%--3context--%>
  14. <s:property value="value"/><br>
  15. <s:property value="#request.value"/><br>
  16. <%--运行结果:--%>
  17. <%--request_value--%>
  18. <%--req_value--%>
  19. </body>
  20. </html>

5.9 创建和遍历list

  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <%@taglib uri="/struts-tags" prefix="s"%>
  3. <html>
  4. <head>
  5. <title>success</title>
  6. </head>
  7. <body>
  8. <%-- set标签定义的对象均存于context --%>
  9. <s:set name="list" value="{'张三','李四','王五'}"/>
  10. <%-- iterator标签默认会将当前的迭代对象放入到值栈栈顶 --%>
  11. <s:iterator value="#list">
  12. <%-- property标签默认会输出值栈栈顶元素 --%>
  13. <s:property/><br>
  14. </s:iterator>
  15. </body>
  16. </html>

5.10 创建和遍历Map

  1. <s:set name="map" value="#{'phone':'123456','email':'234567'}"/>
  2. <s:iterator value="#map">
  3. <s:property/><br>
  4. </s:iterator>
  5. <s:iterator value="#map" var="entry">
  6. <s:property value="entry"/><br>
  7. </s:iterator>
  8. <s:iterator value="#map">
  9. <s:property value="key"/> = <s:property value="value"/><br>
  10. </s:iterator>

5.11 集合元素的判断

  1. <s:set name="list" value="{'张三','李四','王五'}"/>
  2. <s:property value="'张三' in #list"/>
  3. <s:property value="'张三' not in #list"/>

5.12 集合投影

  1. <%-- 创建三个对象 --%>
  2. <s:bean name="entity.Student" id="student1">
  3. <%--字符串需要加上单引号--%>
  4. <s:param name="name" value="'张三'"/>
  5. <s:param name="age" value="18"/>
  6. </s:bean>
  7. <s:bean name="entity.Student" id="student2">
  8. <s:param name="name" value="'李四'"/>
  9. <s:param name="age" value="20"/>
  10. </s:bean>
  11. <s:bean name="entity.Student" id="student3">
  12. <s:param name="name" value="'王五'"/>
  13. <s:param name="age" value="22"/>
  14. </s:bean>
  15. <s:set name="students" value="{#student1,#student2,#student3}"/>
  16. <s:iterator value="#students">
  17. <%-- 调用的是对象的toString方法 --%>
  18. <s:property/><br>
  19. </s:iterator>
  20. <%-- 集合投影 --%>
  21. <s:set name="students1" value="#students.{name}"/>
  22. <s:iterator value="#students1">
  23. <s:property/><br>
  24. </s:iterator>

5.13 集合查询

  1. <%-- 获取满足条件的所有元素 --%>
  2. <s:iterator value="#students.{?#this.age > 18}">
  3. <s:property/><br>
  4. </s:iterator>
  5. <br>
  6. <%-- 获取满足条件的第一个元素 --%>
  7. <s:iterator value="#students.{^#this.age > 18}">
  8. <s:property/><br>
  9. </s:iterator>
  10. <br>
  11. <%-- 获取满足条件的最后一个元素 --%>
  12. <s:iterator value="#students.{$#this.age > 18}">
  13. <s:property/><br>
  14. </s:iterator>

6. 动态调用方法

6.1 第一种方式

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE struts PUBLIC
  3. "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
  4. "http://struts.apache.org/dtds/struts-2.3.dtd">
  5. <struts>
  6. <!-- 设置动态方法调用为开启状态 -->
  7. <constant name="struts.enable.DynamicMethodInvocation" value="true"/>
  8. <package name="zhuce" namespace="/" extends="struts-default">
  9. <!-- 在浏览器/test后面加上 “!方法名”便可以动态的执行相应的方法 -->
  10. <action name="test" class="actions.VauleStackTest">
  11. <result>/success.jsp</result>
  12. </action>
  13. </package>
  14. </struts>

6.2 第二种方式(建议)

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE struts PUBLIC
  3. "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
  4. "http://struts.apache.org/dtds/struts-2.3.dtd">
  5. <struts>
  6. <package name="zhuce" namespace="/" extends="struts-default">
  7. <!-- 在浏览器/test后面加上 “_方法名”便可以动态的执行相应的方法,
  8. _也可以是!或者不写,建议是_;1表示第一个*的位置 -->
  9. <action name="test_*" class="actions.VauleStackTest" method="{1}">
  10. <result>/success.jsp</result>
  11. </action>
  12. </package>
  13. </struts>

7. 接受请求参数

7.1 属性驱动

  1. package actions;
  2. /**
  3. * @author mycomputer
  4. */
  5. public class LoginAction {
  6. private String name;
  7. private int age;
  8. public String getName() {
  9. return name;
  10. }
  11. public void setName(String name) {
  12. this.name = name;
  13. }
  14. public int getAge() {
  15. return age;
  16. }
  17. public void setAge(int age) {
  18. this.age = age;
  19. }
  20. public String zhuce(){
  21. //通过getter、setter方法接收参数,适用于表单数据接收
  22. name = "张三";
  23. age = 18;
  24. return "success";
  25. }
  26. }

7.2 域驱动

  1. package actions;
  2. import entity.Student;
  3. /**
  4. * @author mycomputer
  5. */
  6. public class LoginAction {
  7. //域属性
  8. private Student student;
  9. public Student getStudent() {
  10. return student;
  11. }
  12. public void setStudent(Student student) {
  13. this.student = student;
  14. }
  15. public String zhuce(){
  16. System.out.println(student);
  17. return "success";
  18. }
  19. }
  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <html>
  3. <head>
  4. <title>注册页面</title>
  5. </head>
  6. <body>
  7. <%--<s:set name="student" value=""/>--%>
  8. <form action="zhuce" method="post">
  9. 名字:<input type="text" name="student.name"><br>
  10. 年龄:<input type="password" name="student.age"><br>
  11. <input type="submit" value="注册">
  12. </form>
  13. </body>
  14. </html>
  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <%@taglib uri="/struts-tags" prefix="s"%>
  3. <html>
  4. <head>
  5. <title>success</title>
  6. </head>
  7. <body>
  8. <s:property value="student.name"/>
  9. <s:property value="student.age"/>
  10. </body>
  11. </html>

7.3 模型驱动

  1. package actions;
  2. import com.opensymphony.xwork2.ModelDriven;
  3. import entity.Student;
  4. /**
  5. * @author mycomputer
  6. */
  7. public class LoginAction implements ModelDriven<Student> {
  8. private Student student;
  9. @Override
  10. public Student getModel() {
  11. if (student == null){
  12. student = new Student();
  13. }
  14. return student;
  15. }
  16. public String zhuce(){
  17. System.out.println(student);
  18. return "success";
  19. }
  20. }
  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <html>
  3. <head>
  4. <title>注册页面</title>
  5. </head>
  6. <body>
  7. <%--<s:set name="student" value=""/>--%>
  8. <form action="zhuce" method="post">
  9. 名字:<input type="text" name="name"><br>
  10. 年龄:<input type="password" name="age"><br>
  11. <input type="submit" value="注册">
  12. </form>
  13. </body>
  14. </html>
  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <%@taglib uri="/struts-tags" prefix="s"%>
  3. <html>
  4. <head>
  5. <title>success</title>
  6. </head>
  7. <body>
  8. <s:property value="name"/>
  9. <s:property value="age"/>
  10. </body>
  11. </html>

7.4 集合数据接收(域属性的扩展)

  1. package actions;
  2. import entity.Student;
  3. import java.util.List;
  4. /**
  5. * @author mycomputer
  6. */
  7. public class LoginAction {
  8. /**
  9. * 多个对象数据使用集合
  10. */
  11. private List<Student> student;
  12. public List<Student> getStudent() {
  13. return student;
  14. }
  15. public void setStudent(List<Student> student) {
  16. this.student = student;
  17. }
  18. public String zhuce(){
  19. System.out.println(student);
  20. return "success";
  21. }
  22. }
  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <html>
  3. <head>
  4. <title>注册页面</title>
  5. </head>
  6. <body>
  7. <%--<s:set name="student" value=""/>--%>
  8. <form action="zhuce" method="post">
  9. 名字1:<input type="text" name="student[0].name"><br>
  10. 年龄1:<input type="password" name="student[0].age"><br>
  11. 名字2:<input type="text" name="student[1].name"><br>
  12. 年龄2:<input type="password" name="student[1].age"><br>
  13. <input type="submit" value="注册">
  14. </form>
  15. </body>
  16. </html>
  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <%@taglib uri="/struts-tags" prefix="s"%>
  3. <html>
  4. <head>
  5. <title>success</title>
  6. </head>
  7. <body>
  8. <s:property value="student[0].name"/>
  9. <s:property value="student[0].age"/>
  10. <s:property value="student[1].name"/>
  11. <s:property value="student[1].age"/>
  12. </body>
  13. </html>

Action是多例的,在web中多个用户同时进行访问,会为每个用户创建一个Action实例,接受来自不同用户的内容,各个用户之间的Action互不相干,所以Action是线程安全的

回顾: servlet是单实例的,对于同一个业务web容器只会创建一个Servlet实例,是线程共享的,所以对于Servlet的使用,定义成员变量可能会导致线程安全问题