Struts2学习之文件上传/下载&ValueStack(三)

简介

今天是学习Struts2第三天,也算struts2准备前奏告一段落,提升部分只能在后期深入了解,多看源码,多参阅资料。今天所学的知识点文件上传、下载/ValueStack&OGNL/Struts2标签

文件上传/下载

文件上传简介
	a). 企业常用文件上传技术 : jspSmartUpload(主要应用 JSP model1 时代) 、 fileupload (Apache commons项目中一个组件)、 Servlet3.0 集成文件上传 Part类
	b). Struts2 对文件上传的支持
	提供 FileUpload 拦截器,用于解析 multipart/form-data 编码格式请求,解析上传文件的内容
	fileUpload拦截器 默认在 defaultStack 栈中, 默认会执行的
1. 单文件上传
	a). 页面编写:
		存在 <input type="file" name="upload"/> 上传项,必须提供name属性
		表单提交方式 必须 post 提交
		表单编码类型 enctype="multipart/form-data"
	b). 编写Action类,按照约定定义接收表单属性
		private File upload; // 这里变量名 和 页面表单元素 name 属性一致
		private String uploadContentType;
		private String uploadFileName;
		* 为三个对象 提供 setter 方法
		通过FileUtils 提供 copyFile 进行文件复制,将上传文件 保存到服务器端
	c). Struts2 上传文件过程中错误处理
		1). 配置 input 视图 ,作为上传出错后 跳转页面
		在文件上传时,如果发生错误 ,fileUpload拦截器 会设置错误信息,workflow拦截器 跳转到 input 视图
		2). 通过:
			jsp:<s:actionError/> <s:feildError/>显示错误消息的提示
			错误消息提示改为中文版:借助国际化的消息资源文件
			如果是通过配置全局默认参数引起的错误,最好用全局的消息资源文件
			**struts2默认的提示资源文件:struts2-core-**.jar 的org.apache.struts2的struts-message.properties文件中。比着key值覆盖对应的value即可
2. 多文件上传
	表单上传字段名设置一样,Action类中可以定义属性为数组或者为集合进行接收,然后在下载操作时进行遍历处理

3. 文件下载

	第一种方式:在配置文件中进行处理(原理:使用结果类型进行处理。Stream)
		a). 在Action类中中定义InputStream 和 文件名
		b). 关联资源文件,截取文件名进行URLEncode编码
		c). 返回结果逻辑视图
		d). 配置struts.xml文件
			inputName/contentType/
			<param name="contentDisposition">attachment;filename=${@[email protected](filename,‘UTF-8‘)}</param>
			<param name="contentLength">${filesize}</param>
	第二种方式:
		文件下载原理: 服务器读取下载文件内容,通过Response响应流写回, 设置 ContentType、 ContentDisposition 头信息
		a). 在Action中定义contentType/contentDisposition/filename进行编码,添加相应的get方法
			getInputStream()
			ServletActionContext.getServletContext().getMimeType(filename);
			encodeDownloadFilename(String filename, String agent)文件名编码问题
		b). struts中配置结果参数OGNL表达式进行获取

自定义的结果类型

1.开发一个直接或间接实现com.opensymphony.xwork2.Result接口
	public class CaptchaResult implements Result{
		public void execute(ActionInvocation arg0) throws Exception {
			//实现结果视图的输出代码
		}
	}
2.在struts.xml中进行定义
	<package name="default" namespace="/" extends="struts-default">
		<result-types>
			<result-type name="captcha" class="com.itheima.results.CaptchaResult"/>
		</result-types>
	</package>
3.在配置Action时,引入该结果类型
<action name="genCaptcha" >
   <result type="captcha">
	 <!--  <param name="width">240</param>
	  <param name="height">50</param> -->
   </result>
</action>

4.在页面中,访问第三步配置好的Action
	<img src="${pageContext.request.contextPath}/genCaptcha.action"/>

ValueStack(值栈)

问题一 : 什么是值栈 ValueStack ?
	ValueStack 是 struts2 提供一个接口,实现类 OgnlValueStack ---- 值栈对象 (OGNL是从值栈中获取数据的 )
	每个Action实例都有一个ValueStack对象 (一个请求 对应 一个ValueStack对象 )
	在其中保存当前Action 对象和其他相关对象 (值栈中 是有Action 引用的 )
	Struts 框架把 ValueStack 对象保存在名为 “struts.valueStack” 的请求属性中,request中 (值栈对象 是 request一个属性)
	valueStack vs = request.getAttribute("struts.valueStack");
问题二 : 值栈的内部结构 ?
    值栈由两部分组成
		ObjectStack  (root): Struts  把动作和相关对象压入 ObjectStack 中--List
		ContextMap   (context): Struts 把各种各样的映射关系(一些 Map 类型的对象) 压入 ContextMap 中
	Struts 会把下面这些映射压入 ContextMap 中
		parameters: 该 Map 中包含当前请求的请求参数  ?name=xxx
		request: 该 Map 中包含当前 request 对象中的所有属性
		session: 该 Map 中包含当前 session 对象中的所有属性
		application:该 Map 中包含当前 application  对象中的所有属性
		attr: 该 Map 按如下顺序来检索某个属性: request, session, application
	ValueStack和ContextMap
		ValueStack中 存在root属性 (CompoundRoot) 、 context 属性 (OgnlContext )
			* CompoundRoot 就是ArrayList
			* OgnlContext 就是 Map
		context 对应Map 引入 root对象
			* context中还存在 request、 session、application、 attr、 parameters 对象引用
			* OGNL表达式,访问root中数据时 不需要 #, 访问 request、 session、application、 attr、 parameters 对象数据 必须写 #
			* 操作值栈 默认指 操作 root 元素

问题三 : 值栈对象的创建 ,ValueStack 和 ActionContext 是什么关系 ?
	值栈对象 是请求时 创建的
	doFilter中 prepare.createActionContext(request, response);
		* 创建ActionContext 对象过程中,创建 值栈对象ValueStack
		* ActionContext对象 对 ValueStack对象 有引用的 (在程序中 通过 ActionContext 获得 值栈对象 )
	Dispatcher类 serviceAction 方法中 将值栈对象保存到 request范围
		request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());

问题四 : 如何获得值栈对象
	获得值栈对象 有两种方法
		ValueStack valueStack = (ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
		ValueStack valueStack2 = ActionContext.getContext().getValueStack();

问题五: 向值栈保存数据 (主要针对 root)
	两种方式
		// 将数据保存root的索引0位置,放置到第一个元素 ArrayList add(0,element);
		valueStack.push("itcast");

		// 在值栈创建参数map, 将数据保存到map中
		valueStack.set("company", "传智播客");

	在jsp中 通过 <s:debug /> 查看值栈的内容 

问题六: 在JSP中获取值栈的数据
    访问root中数据 不需要#
    访问 其它对象数据 加 #

	通过下标获取root中对象
	   <s:property value="[0].top"/> //取值栈顶对象
	直接在root中查找对象属性 (自上而下自动查找)
	  valueStack:<s:property value="username"/>

哪些数据默认会放入到值栈?
	1)每次请求,访问Action对象 会被压入值栈 ------- DefaultActionInvocation 的 init方法 stack.push(action);
	* Action如果想传递数据给 JSP,只有将数据保存到成员变量,并且提供get方法就可以了
	2)ModelDriven 接口 有一个单独拦截器
	<interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>
	在拦截器中 ,将model对象 压入了 值栈 stack.push(model);
	* 如果Action 实现ModelDriven接口,值栈默认栈顶对象 就是model对象 

问题七:为什么 EL也能访问值栈中的数据
StrutsPreparedAndExecuteFilter的doFilter代码中 request = prepare.wrapRequest(request);
	* 对Request对象进行了包装 ,StrutsRequestWrapper
	* 重写request的 getAttribute
		Object attribute = super.getAttribute(s);
		if (attribute == null) {
		   attribute = stack.findValue(s);
		}
      访问request范围的数据时,如果数据找不到,去值栈中找
	* request对象 具备访问值栈数据的能力 (查找root的数据)

OGNL

OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目。 Struts2框架使用OGNL作为默认的表达式语言。
	* xwork 提供 OGNL表达式
	* ognl-3.0.5.jar
OGNL 是一种比EL 强大很多倍的语言
OGNL 提供五大类功能
   1、支持对象方法调用,如xxx.doSomeSpecial();
   2、支持类静态的方法调用和值访问
   3、访问OGNL上下文(OGNL context)和ActionContext; (重点 操作ValueStack值栈 )
   4、支持赋值操作和表达式串联
   5、操作集合对象
使用OGNL访问 对象方法 和 静态方法
	* OGNL 在jsp 结合 struts2 标签库 使用 , <s:property value="ognl表达式" /> 执行 ognl表达式
	调用 实例方法 : 对象.方法()  ----  <s:property value="‘hello,world‘.length()"/>
	调用 静态方法 : @[类全名(包括包路径)]@[方法名]  --- <s:property value="@[email protected](‘您好,%s‘,‘小明‘)"/>
	* 使用 静态方法调用 必须 设置 struts.ognl.allowStaticMethodAccess=true

访问OGNL上下文(OGNL context)和ActionContext
	OGNL上下文(OGNL context) 对象 ----- 值栈 ValueStack 

在OgnlContext中获取数据
	request:<s:property value="#request.username"/>
	session:<s:property value="#session.username"/>
	application:<s:property value="#application.username"/>
	attr:<s:property value="#attr.username"/>
	parameters:<s:property value="#parameters.cid[0]"/>

 OGNL表达式 常见使用
#、 % 、$ 符号使用
1) # 的 使用
	用法一  # 代表 ActionContext.getContext() 上下文
	  <s:property value="#request.name" />  ------------>  ActionContext().getContext().getRequest().get("name");
	  #request
	  #session
	  #application
	  #attr
	  #parameters 

	用法二 : 不写# 默认在 值栈中root中进行查找
	   <s:property value="name" /> 在root中查找name属性
	* 查询元素时,从root的栈顶元素 开始查找, 如果访问指定栈中元素    <s:property value="[1].name" />  访问栈中第二个元素name属性
	* 访问第二个元素对象 <s:property value="[1].top" />

	用法三 :进行投影映射 (结合复杂对象遍历 )
	   1)集合的投影(只输出部分属性
	   <h1>遍历集合只要name属性</h1>
		<s:iterator value="products.{name}" var="pname">
			<s:property value="#pname"/>
		</s:iterator>
	   2)遍历时,对数据设置条件
		<h1>遍历集合只要price大于1500商品</h1>
		<s:iterator value="products.{?#this.price>1500}" var="product">
			<s:property value="#product.name"/> --- <s:property value="#product.price"/>
		</s:iterator>
	   3)综合
	   <h1>只显示价格大于1500 商品名称</h1>
		<s:iterator value="products.{?#this.price>1500}.{name}" var="pname">
			<s:property value="#pname"/>
		</s:iterator>   

	用法四: 使用#构造map集合
		经常结合 struts2 标签用来生成 select、checkbox、radio
		<h1>使用#构造map集合 遍历</h1>
		<s:iterator value="#{‘name‘:‘aaa‘,‘age‘:‘20‘, ‘hobby‘:‘sport‘ }" var="entry">
			key : <s:property value="#entry.key"/> , value:  <s:property value="#entry.value"/> <br/>
	</s:iterator>

2) %的使用
   用法一: 结合struts2 表单表单使用, 通过%通知struts, %{}中内容是一个OGNL表达式,进行解析
   <s:textfield name="username" value="%{#request.username}"/>
   用法二: 设置ognl表达式不解析 %{‘ognl表达式‘}
   <s:property value="%{‘#request.username‘}"/>

3)$的使用
   用法一 :用于在国际化资源文件中,引用OGNL表达式
	在properties文件 msg=欢迎您, ${#request.username}
	在页面
	    <s:i18n name="messages">
			<s:text name="msg"></s:text>
		</s:i18n>
		* 自动将值栈的username 结合国际化配置信息显示
   用法二 :在Struts 2配置文件中,引用OGNL表达式
		<!-- 在Action 提供 getContentType方法 -->
		<param name="contentType">${contentType}</param>
       *  ${contentType} 读取值栈中contentType数据,在Action提供 getContentType 因为Action对象会被压入值栈,
	      contentType是Action属性,从值栈获得

结论: #用于写ognl表达式获取数据,% 控制ognl表达式是否解析 ,$ 用于配置文件获取值栈的数据 

Struts2 标签库

tag-reference.html 就是 struts2 标签规范
1、 通用标签库 的学习
<s:property> 解析ognl表达式,设置默认值,设置内容是否HTML转义
<s:set> 向四个数据范围保存数据
<s:iterator> 遍历值栈中数据
<s:if> <s:elseif> <s:else> 进行条件判断 -------- elseif 可以有多个
<s:url> 进行URL重写(追踪Session ) ,结合s:param 进行参数编码
	*   <s:url action="download" namespace="/" var="myurl">
			<s:param name="filename" value="%{‘MIME协议简介.txt‘}"></s:param>
		</s:url>
		<s:property value="#myurl"/>
<s:a> 对一个链接 进行参数编码
    * <s:a action="download" namespace="/" >下载MIME协议简介.txt
			<s:param name="filename" value="%{‘MIME协议简介.txt‘}"></s:param>
	  </s:a>

OGNL 了解部分 : 支持赋值操作和表达式串联 、 操作集合对象
	 1) 在值栈中保存一个对象
     <s:property value="price=1000,name=‘冰箱‘,getPrice()"/>  自动查找值栈中 price 和 name 属性 为其赋值
	 2) ognl操作集合
		<s:property value="products[0].name"/> 访问集合第一个元素name属性
		<s:property value="map[‘name‘]"/> 访问map中key为name的值
		{} 直接构造List 元素、 #{} 直接构造 Map元素
			<s:iterator value="{‘aaa‘,‘bbb‘}" var="s">
				<s:property value="#s"/>
			</s:iterator>
			<s:iterator value="#{‘ccc‘:‘111‘,‘ddd‘:‘222‘ }" var="entry">
				<s:property value="#entry.key"/>
			</s:iterator>

2、 UI标签库的学习 (Form标签)
    使用struts2 form标签 好处 : 支持数据回显 , 布局排班(基于Freemarker 模板定义 )
	struts2 表单标签 value属性。 必须写 %{} 进行设值
******* 使用struts2表单标签前, 必须配置 StrutsPrepareAndExecuteFilter
  The Struts dispatcher cannot be found.  This is usually caused by using Struts tags without the associated filter. Struts tags are only usable when the request has passed through its servlet filter, which initializes the Struts dispatcher needed for this tag

<s:form> 表单标签
	<s:form action="regist" namespace="/" method="post" theme="xhtml">  ---   theme="xhtml" 默认布局样式
<s:textfield> 生成 <input type="text" >
<s:password > 生成 <input type="password" >

<s:submit type="submit" value="注册"/> 生成 <input type="submit" >
<s:reset type="reset" value="重置" />	生成 <input type="reset" >

* struts2 除了支持JSP之外,支持两种模板技术 Velocity (扩展名 .vm ) 、 Freemarker (扩展名 .ftl)

<s:textarea> 生成 <textarea> 多行文本框

<s:checkboxlist> 生成一组checkbox
	* 使用ognl构造 Map (看到值和提交值 不同时)
	* <s:checkboxlist list="#{‘sport‘:‘体育‘,‘read‘:‘读书‘,‘music‘:‘音乐‘ }" name="hobby"></s:checkboxlist>
<s:radio> 生成一组radio
	* 使用 ognl构造 List  (看到内容和提交值 相同时)
	* <s:radio list="{‘男‘,‘女‘}" name="gender"></s:radio>
<s:select> 生成一个<select>
	* <s:select list="{‘北京‘,‘上海‘,‘南京‘,‘广州‘}" name="city"></s:select>

============= struts2 开发 密码框 默认不回显
      <s:password name="password" id="password" showPassword="true"/>

3、 页面元素主题设置
    default.properties  ----  struts.ui.theme=xhtml 设置struts2 页面元素使用默认主题
	                          struts.ui.templateSuffix=ftl 默认模板引擎 Freemarker
	修改主题
     方式一 :<s:textfield name="username"  label="用户名“ theme="simple"></s:textfield> 只对当前元素有效
	 方式二 :<s:form  action="" method="post" namespace="/ui“    theme="simple"> 对form中所有元素有效
	 方式三 : struts.xml
	     <constant name="struts.ui.theme" value="simple"></constant>  修改默认主题样式,页面所有元素都有效
     优先级 : 方式一 > 方式二  > 方式三 

小结

1、 文件上传  (完成上传、设置上传参数【限制上传大小、扩展名】)
2、 文件下载 一个流 两个头 (不同浏览器附件名乱码解决 ),自定义结果类型
3、 OGNL表达式
	值栈原理和OGNL对值栈数据访问
		* valueStack 何时创建(生命周期 )
		* valueStack内部结构 ,和ActionContext 关系
		* 在Action获取valueStack对象
		* 如何向 valueStack保存数据
		* 在JSP如何 通过struts2 标签显示值栈的内容
		* Action元素何时加入值栈, Model对象何时加入值栈
		* Request对象装饰类 StrutsRequestWrapper 作用? (重写getAttribute 访问request范围数据时,可以查找值栈)
	#、%、$的 使用
		* # 解析ognl表达式,访问值栈内容
		* # 投影
		* #{} 构造Map ---- {} 构造list
		* % 控制OGNL表达式是否解析
		* $ 配置文件中使用 xml配置、properties国际化配置
4、 通用标签
	<s:property> <s:iterator> <s:set> <s:if> [s:elseif、s:else] 、<s:url> 、<s:a>
5、 form标签
	* 使用struts2标签 编写注册页面 regist.jsp 
 
时间: 2024-10-02 06:04:04

Struts2学习之文件上传/下载&ValueStack(三)的相关文章

Struts2学习总结——文件上传与下载

Struts2文件上传与下载 1.1.1新建一个Maven项目(demo02) 在此添加Web构面以及 struts2 构面 1.2.1配置Maven依赖(pom.xml 文件) <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20

Java中实现文件上传下载的三种解决方案

第一点:Java代码实现文件上传 FormFile file=manform.getFile(); String newfileName = null; String newpathname=null; String fileAddre="/numUp"; try { InputStream stream = file.getInputStream();// 把文件读入 String filePath = request.getRealPath(fileAddre);//取系统当前路径

struts2中的文件上传和下载

天下大事,必做于细.天下难事,必作于易. 曾经见过某些人,基础的知识还不扎实就去学习更难的事,这样必然在学习新的知识会很迷惑结果 再回来重新学习一下没有搞懂的知识,这必然会导致学习效率的下降!我写的这篇上传和下载都很基础. 十分适合初学者! jsp:页面 <!--在进行文件上传时,表单提交方式一定要是post的方式,因为文件上传时二进制文件可能会很大,还有就是enctype属性,这个属性一定要写成multipart/form-data, 不然就会以二进制文本上传到服务器端--> <for

【SSH2(实践篇)】--Struts2文件上传下载实例

上篇文章又一次回顾了Struts2的运行机制,对它的运行步骤做了一步步的解析,这个解析不但再一次理清了Struts2的使用方法,而且对它的映射机制进行了深入的解析,并在最后通过一个实例来介绍了Struts2的一种使用方法,这里将做一个有关文件上传下载的实例. 一.文件上传 Struts2并没有提供文件上传的组件,所以想要实现上传的功能就必须通过第三方组件来实现,在Struts2引用的jar中包含了文件上传的组件,它是通过commons-fileupload.jar和commons-io.jar来

笨鸟先飞之Java(一)--使用struts2框架实现文件上传和下载

不管是.net还是Java,我们最常接触到的就是文件的上传和下载功能,在Java里要实现这两个常用功能会有很多种解决方式,但是struts2的框架却能给我们一个比较简单的方式,下面就一起来看吧: 文件上传: 首先来看实现上传功能的表单,Index.jsp: <span style="font-family:FangSong_GB2312;font-size:18px;"><%@ page language="java" contentType=&q

struts2 文件上传下载

四.文件的上传(拦截器)和下载(stream结果类型)(需要练一遍) 1.文件上传 必要前提: a.表单method必须是post: b.enctype取值必须是multipart/form-data: c.提供文件选择域. 1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> 2 <%@ taglib uri="/struts-t

Selenium2学习-039-WebUI自动化实战实例-文件上传下载

通常在 WebUI 自动化测试过程中必然会涉及到文件上传的自动化测试需求,而开发在进行相应的技术实现是不同的,粗略可划分为两类:input标签类(类型为file)和非input标签类(例如:div.a或其他方式结合实现). 非input标签类因其有各式各样的实现方式,需要考虑具体的场景,因而此文对此类文件上传不做讲解,以input标签实现文件上传的方式进行讲解,请知悉! 解决方案有如下三种: 1.定位元素直接通过sendkeys修改input标签的文件链接: 2.通过第三方控件(AutoIt)编

深入分析JavaWeb 47 -- Struts2拦截器与文件上传下载

一.struts2中的拦截器(框架功能核心) 1.过滤器VS拦截器 过滤器VS拦截器功能是一回事.过滤器是Servlet规范中的技术,可以对请求和响应进行过滤. 拦截器是Struts2框架中的技术,实现AOP(面向切面)的编程思想,是可插拔的, 可以对访问某个 Action 方法之前或之后实施拦截. 拦截器栈(Interceptor Stack): 将拦截器按一定的顺序联结成一条链. 在访问被拦截的方法时, Struts2拦截器链中的拦截器就会按其之前定义的顺序被依次调用 Struts2执行原理

深入分析JavaWeb Item47 -- Struts2拦截器与文件上传下载

一.struts2中的拦截器(框架功能核心) 1.过滤器VS拦截器 过滤器VS拦截器功能是一回事. 过滤器是Servlet规范中的技术,能够对请求和响应进行过滤. 拦截器是Struts2框架中的技术.实现AOP(面向切面)的编程思想.是可插拔的, 能够对訪问某个 Action 方法之前或之后实施拦截. 拦截器栈(Interceptor Stack): 将拦截器按一定的顺序联结成一条链. 在訪问被拦截的方法时, Struts2拦截器链中的拦截器就会按其之前定义的顺序被依次调用 Struts2运行原