Fork me on GitHub

(三)、Struts第三天

()Struts第三天

Struts核心业务:

(Struts提供了哪些功能?)

1.  请求数据自动封装(params拦截器)

2.  struts数据处理方式

* ActionContext

实现RequestAware 等接口  (servletConfig拦截器)

* ServletActionContext

3.  拦截器功能

4.  Ognl表达式语言与Struts标签   (今天)

5.  文件上传 下载  (今天)

6.  数据效验

7.  类型转换、国际化

8 .  其他技术

模型驱动、数据回显等!

 

 

 

 

 

 

1.  Ognl表达式语言与Struts标签 

问题1

Struts在运行时候,产生的数据,如果传递到页面,再jsp中取出显示的?

问题2

Ognl表达式语言与Struts标签关系?

 

 

Ognl表达式概述:

Struts2默认 必须引入Ognl.jar。这个jar包就是对Ognl 表达式语言的支持!

 

OGNL表达式 

       OGNLObject Graphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目。 Struts2框架使用OGNL作为默认的表达式语言。

Strut2标签取值使用的表达式,就是Ognl表达式!

问题:标签取值方式?

E表达式语言

jsp2.0以后官方默认支持标准!

Struts2标签:

struts2环境支持时候才可以用!

(功能更加强大!)

 

OGNL优势

      1、支持对象方法调用,如xxx.doSomeSpecial(); 

       2、支持类静态的方法调用和值访问,表达式的格式:

             @[类全名(包括包路径)]@[方法名 |  值名],例如:

             @java.lang.String@format('foo %s', 'bar')

             或@tutorial.MyConstant@APP_NAME; 

       3、支持赋值操作和表达式串联,如price=100, discount=0.8,

             calculatePrice(),这个表达式会返回80; 

       4、访问OGNL上下文(OGNL context)和ActionContext; 

       5、操作集合对象。

总结

        OGNL 有一个上下文(Context)概念,说白了上下文就是一个MAP结构,它实现  java.utils.Map 的接口。   这个Map就是值:OgnlContext!

 

OgnlContext对象

OgnlContext对象,是Ognl表达式语言的核心!

注意:

一般情况,很少直接用这个对象! Struts2标签取值时候使用!

 

硬编码方式,来了解一下这个对象:

 

/**

 * 硬编码,了解OgnlContext对象!

 * @author AdminTH

 *

 */

public class OgnlContextDemo {

 

// 1. OgnlContext实际上是一个Map!

@Test

public void testApp() throws Exception {

// 创建OgnlContext对象是一个Map!

OgnlContext context = new OgnlContext();

// map中放数据

context.put("cn""China");

// 获取map中数据

System.out.println(context.get("cn"));

}

// 2. OgnlContext对象,表达式取值:取根元素值

@Test

public void testApp2() throws Exception {

OgnlContext context = new OgnlContext();

// 往根元素设置值

context.setRoot(new User(100,"Jack"new Address()));

// 通过Ognl表达式取值

// a. 构建一个表达式

Object ognl = Ognl.parseExpression("address.city");

// b. 解析表达式

Object value = Ognl.getValue(ognl, context, context.getRoot());

// 输出值

System.out.println(value);

}

// 3. OgnlContext对象,表达式取值:取非根元素值

// 总结: Ognl表达式语言取值,如果获取根元素值,直接写表达式; 非根元素值,在表达式前要加上#

@Test

public void testApp3() throws Exception {

OgnlContext context = new OgnlContext();

// map里面放数据(也叫往非根元素存放数据)

context.put("user"new User(100,"Jack"new Address()));

// 通过Ognl表达式获取值

Object ognl = Ognl.parseExpression("#user.address.city");

Object value = Ognl.getValue(ognl, context, context.getRoot());

System.out.println(value);

}

//4. 其他功能,调用静态方法!

@Test

public void testApp4() throws Exception {

OgnlContext context = new OgnlContext();

// 如果是Math类的静态方法调用,可以省略类名称! 其他类,就必须写上类名!

// Object ognl = Ognl.parseExpression("@Math@floor(10.1)");  // 得到表达式

Object ognl = Ognl.parseExpression("@@floor(10.1)");  // 得到表达式

Object value = Ognl.getValue(ognl, context, context.getRoot());// 解析表达式,获取值

System.out.println(value);

}

}

 

ValustStack值栈对象

问题:

OgnlContext对象与值栈对象的关系?

 

 

ValueStack

       ValueStack实际是一个接口

    Struts2运行时候,时候的是接口的实现类:OgnlValueStack!

ValueStack特点

        ValueStack贯穿整个 Action 的生命周期! 

相当于一个数据的中转站在其中保存当前Action 对象和其他相关对象.

 

Strut2运行时候,产生的数据都会保存值栈中!

Struts中数据流转:

用户每次访问Strutsactionstruts2都会创建:

1.  ActionContext对象

ActionContext.getContext.getSessionMap(key);

这个数据就是从值栈获取的!

2.  值栈对象

3.  Action对象

然后会把action对象放到值栈中,

且通过ActionContext是可以获取值栈数据的!

 

获取方式

         Struts2框架把 ValueStack 对象保存在名为 “struts.valueStack” 

 request请求属性中。

方式1: 通过ActionContext可以获取

方式2: 通过request对象获取!  

 

值栈结构

List栈:   存储Action对象!或其他根元素对象(Root)  【不用#

Map栈:  存储映射数据!Map数据(非根元素数据)    【需要#符号】

 requestMap.put();

  Request.setAttribute(“”,””)

 

  

 

Struts2标签取值 

 

 

// 查看值栈结构

public class VsAction extends ActionSupport{

private User user;

public User getUser() {

return user;

}

 

@Override

public String execute() throws Exception {

// 模拟:调用Service查询!

this.user = new User(1,"班长",new Address("骏景花园"));

// 获取值栈,方式1

// ValueStack vs2 = 

// (ValueStack) ServletActionContext.getRequest().getAttribute("struts.valueStack");

// 获取值栈,方式2  

ActionContext ac = ActionContext.getContext();

ValueStack vs1 = ac.getValueStack();

 

/*

 * ValustStack:

 * 

 * 1. 往根据元素root, list,  节点存放数据  【root   CompoundRoot

 */

vs1.set("cn""China");   // 存储以Map结构存储!

vs1.set("usa""Ameraica");

vs1.setValue("test""test");

User user = new User(1,"杰克",new Address("广州"));

vs1.push(user); // 入栈, 放入list栈中第一个元素

/*

 * 2. 往非给元素存放数据,map栈!   【context  OgnlContext

 */

// 获取request/session/applicationmap

Map<String,Object> request = (Map<String, Object>) ac.get("request");

Map<String, Object> session = ac.getSession();

Map<String, Object> application = ac.getApplication();

// 存数据

ac.getContextMap().put("test_contextMap""test_contextMap");

request.put("request_data""request_data");

request.put("request_data2""request_data2");

session.put("session_data""session_data");

application.put("application_data""application_data");

return SUCCESS;

}

}

 

<body>

  <!-- 引入struts标签库 -->

  <%@taglib uri="/struts-tags" prefix="s" %>

     <!--  一、   通过el,  获取struts运行产生的数据 -->

     ${user.id }

     ${user.name }

     ${user.address.city }

     ${requestScope.test_contextMap }   

     ${requestScope.request_data }

     ${sessionScope.session_data }  <hr/>

     

 

     <!--  二、使用Ognl表达式语言取值! (必须要使用struts标签!)-->

     <!-- property标签取值,默认获取栈顶元素的值 -->

     <s:property/>

     <s:property value="user.id"/>

     <s:property value="user.name"/>

     <s:property value="user.address.city"/> <hr/>

     

     <!-- 非根元素取值 -->

     <s:property value="#test_contextMap"/>

     <s:property value="#request.test_contextMap"/>

     <s:property value="#request.request_data"/>   <hr/>

     

     <s:property value="#session.session_data"/>

     <s:property value="#application.application_data"/>   <hr/>

     

     <!-- 使用attr取值 自动搜索requestMapsessionmapapplicationmap,找到后立刻返回!-->

     <s:property value="#attr.request_data"/>

     <s:property value="#attr.session_data"/>

     <s:property value="#attr.application_data"/>   <hr/>

  

     <!-- 

      封装请求数据值的map:parameters

      访问:http://localhost:8080/day29/ognl.jsp?userName=Jack&pwd=888

      -->

      <s:property value="#parameters"/>

      <s:property value="#parameters.userName"/>   <!-- 输出:Jack -->

      <s:property value="#parameters.pwd"/>        <!-- 输出:888 -->

  

     <!-- 查看值栈数据 -->

     <s:debug></s:debug>

  </body>

 

 

 

 

 

 

 

 

取值中几个符号用法 & Struts2常用标签

 

Struts2中几个取值符号的用法:

$   配置文件取值符号

#   非根元素取域中值; 动态构建Map集合!

%   提供一个Ognl表达式运行环境

 

 

 

 

 

 

5.文件上传 下载

文件上传

Struts2提供的文件上传,主要是简化传统的上传操作!

在引入struts2jar包中,默认必须引入文件上传的2jar包!

 

回顾文件上传:

客户端:

1. 提交方式:post

2. 表单类型: multipart/form-data

3. 文件域

服务器段:

a. 自己解析内容

b.  apache提供的fileUpload组件!

c.  其他文件上传组件

 

Struts2如何简化上传操作?

 

 

ü 上传单个文件

Jsp页面:

<body>

   <form action="/day29/fileUpload.action" method="post" enctype="multipart/form-data">

   用户名:<input type="text" name="userName">   <br/>

   文件:   <input type="file" name="file1">   <br/>

   <input type="submit">

   </form>

  </body>

 

Action:

package cn.itcast.c_upload;

 

import java.io.File;

import java.io.IOException;

 

import org.apache.commons.io.FileUtils;

import org.apache.struts2.ServletActionContext;

 

import com.opensymphony.xwork2.ActionContext;

import com.opensymphony.xwork2.ActionSupport;

 

// 上传一个处理

public class UploadAction_上传一个 extends ActionSupport{

 

// 封装普通表单数据

private String userName;

public void setUserName(String userName) {

this.userName = userName;

}

// 封装文件上传数据

private File file1;     // 上传的文件; 对象名称与表单元素名称一致

private String file1FileName; // 上传的文件名 = 元素名称+ FileName(固定)

private String file1ContentType;// 文件类型

public void setFile1(File file1) {

this.file1 = file1;

}

public void setFile1FileName(String file1FileName) {

this.file1FileName = file1FileName;

}

public void setFile1ContentType(String file1ContentType) {

this.file1ContentType = file1ContentType;

}

// 主要测试“上传”!

@Override

public String execute() {

// 文件上传到服务器的: "/day27/upload目录"

// 获取Actioncontext对象

ActionContext ac = ActionContext.getContext();

try {

//1. 获取上传目录,路径

String path = ServletActionContext.getServletContext().getRealPath("/upload");

//2. 在目录下创建文件对象

File dest = new File(path,file1FileName);

//3. 上传

// 参数1: 源文件

// 参数2: 上传到的目标文件

FileUtils.copyFile(file1, dest);

// 提示

ac.put("msg""上传" + file1FileName +"成功!");

catch (Exception e) {

ac.put("msg""上传" + file1FileName +"失败!!");

e.printStackTrace();

}

return SUCCESS;

}

}

 

 

ü 上传多个文件

Jsp页面:

<body>

   <form action="/day29/fileUpload.action" method="post" enctype="multipart/form-data">

   用户名:<input type="text" name="userName">   <br/>

   文件:   <input type="file" name="file1">   <br/>

   文件:   <input type="file" name="file1">   <br/>

  

   <input type="submit">

   </form>

  </body>

 

package cn.itcast.c_upload;

 

import java.io.File;

import java.util.ArrayList;

import java.util.List;

 

import org.apache.commons.io.FileUtils;

import org.apache.struts2.ServletActionContext;

 

import com.opensymphony.xwork2.ActionContext;

import com.opensymphony.xwork2.ActionSupport;

 

// 上传多个

public class UploadAction extends ActionSupport{

 

// 封装普通表单数据

private String userName;

public void setUserName(String userName) {

this.userName = userName;

}

// 封装文件上传数据

private File[] file1;     // 上传的文件; 对象名称与表单元素名称一致

private String[] file1FileName; // 上传的文件名 = 元素名称+ FileName(固定)

private String[] file1ContentType;// 文件类型

public void setFile1(File[] file1) {

this.file1 = file1;

}

public void setFile1FileName(String[] file1FileName) {

this.file1FileName = file1FileName;

}

public void setFile1ContentType(String[] file1ContentType) {

this.file1ContentType = file1ContentType;

}

// 主要测试“上传”!

@Override

public String execute() {

// 文件上传到服务器的: "/day27/upload目录"

// 获取Actioncontext对象

ActionContext ac = ActionContext.getContext();

// 提示信息保存

List<String> list = new ArrayList<String>();

try {

//1. 获取上传目录,路径

String path = ServletActionContext.getServletContext().getRealPath("/upload");

// 上传多个,增加遍历功能!

for (int i=0; i<file1.length; i++){

//2. 在目录下创建文件对象

File dest = new File(path,file1FileName[i]);

//3. 上传

// 参数1: 源文件

// 参数2: 上传到的目标文件

FileUtils.copyFile(file1[i], dest);

list.add("第"+(i+1)+"个文件:" +file1FileName[i] + ", 上传成功!");

}

// 保存提示

ac.put("list", list);

catch (Exception e) {

ac.put("msg""上传失败!!");

e.printStackTrace();

}

return SUCCESS;

}

}

 

 

ü 错误处理、大小限制、类型限制

错误处理:

 

<global-results>

<!-- struts在文件上传失败的时候,会自动返回input视图,即错误页面对应的视图 -->

<result name="input">/c/error.jsp</result>

</global-results>

大小、类型限制:

<!-- 下载返回处理:stream -->

<result name="down" type="stream">

   <!-- 下载的文件的mime类型; 指定为二进制类型即可,支持所有文件类型;(tomcat/confg/web.xml搜索exe) -->

   <param name="contentType">application/octet-stream</param>

   

   <!-- 对应Action类中get属性名称!(即:action类返回流的方法!) -->

   <param name="inputName">fileStream</param>

   

   <!-- 指定下载的响应头; 以及下载显示的文件的文件名(中文,需要url编码后) -->

   <param name="contentDisposition">attachment;filename=${downFileName}</param>

   

   <!-- 每次读取文件的缓存大小 -->

   <param name="bufferSize">1024</param>

</result>

 

ü 完整的struts.xml

<?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>

 

<!-- 配置struts上传默认支持的大小限制是:20M, 默认是2M -->

<constant name="struts.multipart.maxSize" value="20971520"></constant>

 

<package name="upload" extends="struts-default">

<global-results>

<!-- struts在文件上传失败的时候,会自动返回input视图,即错误页面对应的视图 -->

<result name="input">/c/error.jsp</result>

</global-results>

<action name="fileUpload" class="cn.itcast.c_upload.UploadAction">

<!-- 指定执行默认的拦截器,给fileUpload拦截器设置参数值 -->

<interceptor-ref name="defaultStack">

<!-- 限制允许的文件扩展名称 -->

<param name="fileUpload.allowedExtensions">txt,jar,zip,jpg</param>

<!-- 限制允许的文件类型  (注意:如果与线面的扩展名名称限制一起使用,取交集!)

<param name="fileUpload.allowedTypes">text/plain</param>

-->

</interceptor-ref>

<result>/c/msg.jsp</result>

</action>

<!-- 下载的action -->

<action name="down_*" class="cn.itcast.c_upload.DownAction" method="{1}">

<!--下载 列表 -->

<result name="list">/c/down.jsp</result>

<!-- 下载返回处理:stream -->

<result name="down" type="stream">

   <!-- 下载的文件的mime类型; 指定为二进制类型即可,支持所有文件类型;(tomcat/confg/web.xml搜索exe) -->

   <param name="contentType">application/octet-stream</param>

   

   <!-- 对应Action类中get属性名称!(即:action类返回流的方法!) -->

   <param name="inputName">fileStream</param>

   

   <!-- 指定下载的响应头; 以及下载显示的文件的文件名(中文,需要url编码后) -->

   <param name="contentDisposition">attachment;filename=${downFileName}</param>

   

   <!-- 每次读取文件的缓存大小 -->

   <param name="bufferSize">1024</param>

</result>

</action>

 

</package>

 

</struts>

 

 

 

下载

方式1:传统的servlet中下载!

设置下载响应头!

注意:

Action的业务方法,返回null

 

方式2: strtus2提供的下载方式!

 

 

 

代码(补充)

package cn.itcast.c_upload;

 

import java.io.File;

import java.io.InputStream;

import java.io.UnsupportedEncodingException;

import java.net.URLEncoder;

 

import org.apache.struts2.ServletActionContext;

 

import com.opensymphony.xwork2.ActionContext;

import com.opensymphony.xwork2.ActionSupport;

 

public class DownAction extends ActionSupport{

 

/****************一、 下载列表显示********************/

public String list() {

// 获取上传目录路径

String path = ServletActionContext.getServletContext().getRealPath("/upload");

// 目录对象

File file = new File(path);

// 获取目录下的所有“文件名”

String[] names = file.list();

// 保存

ActionContext.getContext().getContextMap().put("names", names);

return "list";

}

/****************二、 下载, 处理********************/

// 1. 封装数据 (下载的文件的文件名称) 

private String fileName;

public void setFileName(String fileName) {  // 传入的文件名(get提交,中文)

// 中文处理

try {

fileName = new String(fileName.getBytes("ISO8859-1"),"UTF-8");

} catch (UnsupportedEncodingException e) {

e.printStackTrace();

}

this.fileName = fileName;

}

// 2. 处理下载请求

public String down(){

return "down";  // 字符换,对应的跳转类型“stream

}

// 3. 返回文件流

public InputStream getFileStream(){

// 返回文件为fileName的文件流

return ServletActionContext.getServletContext().getResourceAsStream("/upload/"+ fileName);

}

// 4. 下载的文件名称(中文,需要url编码)

public String getDownFileName(){

// fileName进行URL编码!

try {

return URLEncoder.encode(fileName, "UTF-8");  // 确保浏览器显示的下载文件是正确的!

} catch (UnsupportedEncodingException e) {

throw new RuntimeException(e);

}

}

}

 

 

 

 





posted @ 2015-09-24 06:40  Dantefung  阅读(273)  评论(0编辑  收藏  举报