深入分析JavaWeb Item44 -- Struts2开发核心之动作类Action
2016-01-05 21:39
549 查看
一、Action动作类(一般用**Action结尾)
struts2 的Action可以是POJO(Plain Old Java Object)为了让用户开发的Action更加规范struts2提供了一个Action接口
通过method属性指定Action执行方法
没有指定method属性,默认执行execute方法
[code]<action name="addCustomer" class="xgp.struts.actions.CustomerAction" />
通过method属性,指定调用Action相应方法处理请求
[code]<action name="addCustomer" class="xgp.struts.actions.CustomerAction" method="add">
因为指定了method=”add”,所以HelloAction的ass方法会被调用.
1、编写动作类的三种方式
a、第一种方法是,动作类不实现、也不继承任何的接口和类。即动作类是一个非常普通的JavaBean。[code]public class HelloAction { public String sayHello(){ System.out.println("动作类执行了,访问成功!"); return "success"; } }
b、动作类实现
com.opensymphony.xwork2.Action接口。可以使用常量
Action接口:
[code]public static final String SUCCESS = "success"; //成功时转向的视图 public static final String NONE = "none";//执行成功后,不转向的任何视图。比如下载任务 public static final String ERROR = "error";//转向错误视图 public static final String INPUT = "input";//转向输入视图。(回显:验证与转换失败,转向原有页面) public static final String LOGIN = "login";//登录视图(用户没有登录) public String execute() throws Exception;// public 修饰符,String 返回值,无参数
c、继承
com.opensymphony.xwork2.ActionSupport(开发中建议)
Struts2为Action接口提供了一个实现类 ActionSupport,定义了 表单域校验、错误信息设置和获得国际化信息相关一些方法
[code]public class ActionSupport implements Action, Validateable, ValidationAware, TextProvider, LocaleProvider, Serializable { protected static Logger LOG = LoggerFactory.getLogger(ActionSupport.class); private final ValidationAwareSupport validationAware = new ValidationAwareSupport(); private transient TextProvider textProvider; private Container container; public void setActionErrors(Collection<String> errorMessages) { validationAware.setActionErrors(errorMessages); } public Collection<String> getActionErrors() { return validationAware.getActionErrors(); } public void setActionMessages(Collection<String> messages) { validationAware.setActionMessages(messages); } public Collection<String> getActionMessages() { return validationAware.getActionMessages(); }
2、动作类中的动作方法
要求:a、必须是public的
b、必须返回String类型的
c、必须没有参数
3.动作类的生命周期
动作类每次访问都会重新被实例化,是线程安全的。[code]public class HelloAction { public HelloAction() { System.out.println("执行构造函数HelloAction,实例化对象。"); } public String sayHello(){ System.out.println("动作方法sayHello执行了,访问成功!"); return "success"; } }
测试结果:
二、动作类中动作方法的调用
动作方法:动作类中的定义的处理业务有关的方法实例:模拟一个curd的动作类
工程目录如下:
1、新建一个 curd.jsp
[code] <body> <a href="${pageContext.request.contextPath}/customer/addCustomer.action">增加用户</a> <a href="${pageContext.request.contextPath}/customer/editCustomer.action">修改用户</a> <a href="${pageContext.request.contextPath}/customer/findCustomer.action">查询用户</a> <a href="${pageContext.request.contextPath}/customer/delCustomer.action">删除用户</a> </body>
2、在struts.xml中配置
如下图所示:
[code]<struts> <constant name="struts.devMode" value="true" /> <package name="p1" extends="struts-default" namespace="/customer"> <action name="addCustomer" class="xgp.struts.actions.CustomerAction" method="add"> <result name="success" type="dispatcher">/addCustomer.jsp</result> <result name="error" type="dispatcher">/error.jsp</result> </action> <action name="editCustomer" class="xgp.struts.actions.CustomerAction" method="edit"> <result name="success" type="dispatcher">/editCustomer.jsp</result> </action> <action name="findCustomer" class="xgp.struts.actions.CustomerAction" method="find"> <result name="success" type="dispatcher">/findCustomer.jsp</result> </action> <action name="delCustomer" class="xgp.struts.actions.CustomerAction" method="del"> <result name="success" type="dispatcher">/delCustomer.jsp</result> </action> </package> </struts>
3、建立动作处理类CustomerAction
[code]package xgp.struts.actions; import xgp.struts.service.BusinessService; import xgp.struts.serviceImpl.BusinessServiceImpl; import com.opensymphony.xwork2.ActionSupport; public class CustomerAction extends ActionSupport{ private BusinessService bs = new BusinessServiceImpl(); public String add(){ //调用Service添加方法 try { bs.add(); return SUCCESS; } catch (Exception e) { return ERROR; } } public String edit(){ bs.edit(); return SUCCESS; } public String find(){ bs.find(); return SUCCESS; } public String del(){ bs.del(); return SUCCESS; } }
4、建立相应的业务接口BusinessService和实现类BusinessServiceImpl
BusinessService
[code]package xgp.struts.service; public interface BusinessService { public void add(); public void edit(); public void del(); public Object find(); }
BusinessServiceImpl
[code]package xgp.struts.serviceImpl; import xgp.struts.service.BusinessService; public class BusinessServiceImpl implements BusinessService{ @Override public void add() { System.out.println("Serviece的add方法执行成功!"); } @Override public void edit() { System.out.println("Serviece的edit方法执行成功!"); } @Override public void del() { System.out.println("Serviece的del方法执行成功!"); } @Override public Object find() { System.out.println("Serviece的find方法执行成功!"); return null; } }
结果如下:
1、使用通配符配置Action
在配置<action...>元素时,允许在指定name属性时,使用模式字符串(用
"*"代表一个或多个任意字符)
在class、method属性及
<result>子元素中通过 {N} 形式代表前面地N个
*匹配子串
例如上面的案例中struts.xml我们可以改写如下:
[code] <!-- 使用通配符:* {2}:匹配第2个星花的内容 --> <!-- http://localhost:8080/xgp.struts/customer/add_Customer.action 第一个*: add 第二个*:Customer --> <action name="*_*" class="xgp.struts.actions.{2}Action" method="{1}"> <result name="success" type="dispatcher">/{1}{2}.jsp</result> </action>
2、使用Action的动态方法调用(官方不建议使用)
动态方法调用:DMIhttp://localhost:8080/xgp.struts/customer/add_Customer!add
希望执行CustomerAction的add动作方法(动态方法调用)
动态方法调用:Struts2框架默认是禁止的。可以通过配置一个常量打开它:
[code]<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>
通过url动态指定调用Action哪个方法而无需配置
<action>的method属性, 通过 !方法名 指定调用Action哪个方法
[code]<a href="${pageContext.request.contextPath}/customer/customer!add.action">添加用户</a><br/> <a href="${pageContext.request.contextPath}/customer/customer!edit.action">修改用户</a><br/> <a href="${pageContext.request.contextPath}/customer/customer!del.action">删除用户</a><br/>
3、配置默认Action和 配置Action默认处理类
用户可以为每个package定义一个默认的Action,如果访问路径在package没有匹配<action>就会执行默认action
[code]<default-action-ref name="defaultAction"></default-action-ref> <action name="defaultAction"> <result name="success" type="dispatcher">/whatareuwant.jsp</result> </action>
如果配置
<action>没有指定class属性,就会执行Action的默认处理类,在struts-default.xml中.
指定默认的动作处理类
[code] <!-- 指定默认的动作:当用户访问的动作在本包中没有找到时执行的动作 --> <default-action-ref name="defaultAction"></default-action-ref> <!-- 指定默认的动作处理类 --> <default-class-ref class="xgp.struts.actions.DefaultAction"></default-class-ref> <action name="customer" class="xgp.struts.actions.CustomerAction"> <result name="success" type="dispatcher">/success.jsp</result> </action> <action name="defaultAction"> <result name="success" type="dispatcher">/whatareuwant.jsp</result> </action>
三、在动作类中访问ServletAPI
Struts2的Action没有与任何Servlet API耦合,便于测试.这是他的优点之一.1、三大实现方法
1、ActionContextgetContext() 返回ActionContext实例对象
get(key) 相当于 HttpServletRequest的getAttribute(String name)方法
put(String,Object) 相当于HttpServletRequest的setAttribute方法
getApplication() 返回一个Map对象,存取ServletContext属性
getSession() 返回一个Map对象,存取HttpSession属性
getParameters() 类似调用HttpServletRequest的getParameterMap()方法
setApplication(Map) 将该Map实例里key-value保存为ServletContext的属性名、属性值
setSession(Map) 将该Map实例里key-value保持为HttpSession的属性名、属性值
2、方式二:(简单,推荐使用)使用ServletActionContext
[code]static PageContext getPageContext() static HttpServletRequest getRequest() static HttpServletResponse getResponse() static ServletContext getServletContext()
该方案可避免Action类实现XxxAware接口,但Action依然与Servlet API直接耦合
开发中优先使用ActionContext 这样可以避免耦合
[code]package com.itheima.actions; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.jsp.PageContext; import org.apache.struts2.ServletActionContext; import org.apache.struts2.interceptor.ServletRequestAware; import com.opensymphony.xwork2.ActionSupport; public class ServletAPIAction1 extends ActionSupport{ //打印当前应用名称到控制台上 //获取ServletAPI有关类的实例 //方式一: public String execute() throws Exception { //实际上利用ThreadLocal这个类 //ServletActionContext:记住 HttpServletRequest request = ServletActionContext.getRequest(); System.out.println(request.getContextPath()); PageContext pc = ServletActionContext.getPageContext(); HttpServletResponse response = ServletActionContext.getResponse(); response.getWriter().write(request.getContextPath());//自己输出 ServletContext sc = ServletActionContext.getServletContext(); System.out.println(sc.getRealPath("/")); return NONE; } }
3、方式三:(麻烦)实现接口,访问Action时完成注入
[code]ServletContextAware void setServletContext(javax.servlet.ServletContext context) ServletRequestAware void setServletRequest(javax.servlet.http.HttpServletRequest request) ServletResponseAware void setServletResponse(javax.servlet.http.HttpServletResponse response)
动作类实现特定的接口。就必须实现特定的方法,调用动作方法前,框架会把响应的对象给注入进来。
[code]package com.itheima.actions; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.struts2.interceptor.ServletRequestAware; import org.apache.struts2.interceptor.ServletResponseAware; import com.opensymphony.xwork2.ActionSupport; //获取ServletAPI有关类实例的方式二 public class ServletAPIAction2 extends ActionSupport implements ServletRequestAware,ServletResponseAware{ private HttpServletRequest request; private HttpServletResponse response; //该方法会在调用动作方法之前先执行:把当前的HttpServletRequest对象给你注入进来 public void setServletRequest(HttpServletRequest request) { this.request = request; } public void setServletResponse(HttpServletResponse response) { this.response = response; } @Override public String execute() throws Exception{ //要使用HttpServletRequest对象 //System.out.println(request.getContextPath()); response.getWriter().write(request.getContextPath()); return NONE; } }
原理:是一个拦截器给你注入进来的。struts-default.xml
[code]<interceptor name="servletConfig" class="org.apache.struts2.interceptor.ServletConfigInterceptor"/>
一看源码便知。
配置struts.xml:
[code]<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <constant name="struts.devMode" value="true" /> <package name="p1" extends="struts-default"> <!-- 因为包继承了struts-default,默认使用struts-default.xml中定义的那个默认的拦截器栈:defaultStack 在执行动作方法之前:defaultStack中的组员都会拦截你的动作调用 包含:一个叫做servletConfig的拦截器。 --> <!-- 演示在动作类中获取Servlet有关的类的实例:HttpServletRequest HttpServletResponse HttpSession ServletContext等 Struts2已经将ServletAPI和动作类进行解耦,这是他的优点之一 --> <action name="showContextPath1" class="com.itheima.actions.ServletAPIAction1"> <result name="success" type="dispatcher">/success.jsp</result> </action> <action name="showContextPath2" class="com.itheima.actions.ServletAPIAction2" method="execute"> <result name="success" type="dispatcher">/success.jsp</result> </action> </package> </struts>
2、局部和全局结果视图
result元素:指定动作类的动作方法执行完后的结果视图.属性:
- name:字符串,与动作方法返回的值一致。默认是success
- type:指定处理结果的结果类型的别名。(struts-default.xml有定义,共10个)。默认值是dispatcher
Action处理完用户请求后,将返回一个普通字符串整个普通字符串就是一个逻辑视图名,Struts2 根据逻辑视图名,决定响应哪个结果。
Struts2处理结果使用
<result>元素配置
局部结果:将
<result>作为
<action>子元素配置
全局结果:将
<result>作为
<global-results>元素的子元素配置
配置
<result>元素通常需要指定两个属性
name 该属性指定配置逻辑视图名
type 该属性指定结果类型
当多个action中都使用到了相同result,这时我们应该把result定义为全局结果。struts1中提供了全局forward,struts2中也提供了相似功能:
[code]<package ....> <global-results> <result name="message">/message.jsp</result> </global-results> </package>
注:局部的会覆盖全局
Struts1中应用范围内action的实例 action是单实例(执行时,现在缓存中查找实例,有用,没有创建新的实例)Struts2中 应用范围内action的实例,每个请求都会创建一个action实例Servlet属于单实例多线程的应用,实例只在初始化时被加载多实例比单实例的优点,不会产生并发问题,但执行速度不如单实例。
如下:
[code]<struts> <constant name="struts.devMode" value="true" /> <package name="mydefault" extends="struts-default" abstract="ture"> <global-results> <result name="success" type="dispatcher">/success.jsp</result> </global-results> </package> <package name="p1" extends="mydefault"> <action name="action1" class="xgp.struts.actions.Demo1Action"> <!-- <result name="success" type="dispatcher">/success.jsp</result> --> </action> <action name="action2" class="xgp.struts.actions.Demo2Action"> <!-- <result name="success" type="dispatcher">/success.jsp</result> --> </action> </package> <package name="p2" extends="mydefault"> <action name="action3" class="xgp.struts.actions.Demo3Action"> <!-- <result name="success" type="dispatcher">/success.jsp</result> --> </action> </package> </struts>
3、Struts2提供的结果视图 (共10个)
[code]<result-type name="dispatcher" class="org.apache.struts2.dispatcher.ServletDispatcherResult" default="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="redirectAction" class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/> <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" />
1. chain:从一个动作转发到另外一个动作
同一个包内的动作转发
[code] <package name="p3" namespace="/result" extends="struts-default"> <!-- action1的结果是另外一个Action的请求:一个动作转发到了另外一个动作 演示:同包内的动作转发--> <action name="action1"> <result name="success" type="chain">action2</result> </action> <action name="action2"> <result>/success.jsp</result> </action> </package>
不同包之间的动作转发
[code] <package name="p3" namespace="/result" extends="struts-default"> <action name="action1"> <result name="success" type="chain"> <param name="namespace">/user</param> 给chain的实际处理类注入参数 <param name="actionName">action2</param> </result> </action> </package>
2. dispatcher:从一个动作转发到另外一个JSP
dispatcher 结果类型是最常用的结果类型, 也是 struts 框架默认的结果类型
该结果类型有一个 location 参数, 它是一个默认参数
dispatcher 结果类型将把控制权转发给应用程序里的某个资源
3. redirect:从一个动作重定向到一个JSP
最明显的是地址栏发生变化。
[code]<action name="action2"> <result type="redirect">/success.jsp</result> </action>
4. redirectAction:从一个动作重定向到另外一个动作
action1先将动作重定向到action2,然后action2在转发到success.jsp,地址栏应该显示的是action2.
[code]<action name="action1"> <result name="success" type="redirectAction">action2</result> </action> <action name="action2"> <result>/success.jsp</result> </action>
5. plainText:以纯文本的形式显示JSP
[code]<package name="p4" namespace="/user" extends="struts-default"> <action name="action2"> <result type="plainText">/success.jsp</result> </action> </package>
6. stream:文件下载
[code]<package name="p5" extends="struts-default"> <action name="download" class="xgp.struts.actions.DownLoadAction" method="download"> <result name="success" type="stream"> <!-- 配置输入流 --> <param name="inputName">imageInputStream</param> <!-- 告知浏览器响应正文的MIME类型 --> <param name="contentType">application/octet-stream</param> <!-- 告知浏览器用下载的方式打开 --> <param name="contentDisposition">attachment;filename=26.jpg</param> <!-- 下载时使用的缓存大小 --> <param name="bufferSize">1024</param> </result> </action> </package>
DownLoadAction类
[code]package com.itheima.actions; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import javax.servlet.ServletContext; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; //文件下载;结果类型stream的使用 public class DownLoadAction extends ActionSupport { private InputStream imageInputStream; public InputStream getImageInputStream() { return imageInputStream; } public void setImageInputStream(InputStream imageInputStream) { this.imageInputStream = imageInputStream; } public String download() throws Exception{ //得到文件的真实路径 ServletContext sc = ServletActionContext.getServletContext(); String filePath = sc.getRealPath("/WEB-INF/classes/26.jpg"); //构建输入流 imageInputStream = new FileInputStream(filePath); //用stream结果视图输出 //返回逻辑视图 return SUCCESS; } }
结果显示
阶段性小结
相关文章推荐
- java项目中常用的分页对象Page
- 深入理解java虚拟机(三)(一个类加载器只初始化一次类对象,不同类加载器可以对同一类对象进行初始化)
- Java语言注意事项
- java基础:多线程之生产者消费者问题
- 用指定jdk执行jar包
- [java] java 线程join方法详解
- 隐马尔科夫模型的维特比算法java实现,详细原理请自行查看52nlp的
- java实现二叉树的创建及遍历
- Spring基础—装配bean(一)
- 隐马尔可夫训练参数,BaumWelch算法,java实现【参考52nlp的博客算法原理实现】
- Java之final特性简述
- java读取文件——字符流输入和输出
- 浏览器地址传递中文到java后台乱码
- spring+mybatis利用interceptor(plugin)兑现数据库读写分离
- spring+mybatis 物理分页
- java基础之输入输出,数组
- spring与mybatis三种整合方法
- Java的匿名对象
- Java异常捕获之try...catch...finally语句
- Java温习(1)