Struts2学习之3(文件的上传下载,OGNL表达式,常用标签,表单重复提交)

文件的上传和下载

文件的上传

必要前提:
表单的method必须是post
表单的enctype必须是multipart/form-data
提供input type=”file”类型上传输入域
在Struts2中,文件上传是由一个叫做fileUpload拦截器完成的。

上传页面

<body>
    <s:actionerror/><!-- 显示错误信息 -->
    <s:form action="upload" namespace="/uploadFile" enctype="multipart/form-data" method="post">
    <!-- name属性一定要和动作类中的属性名一致 -->
    <s:file name="photo" label="文件1" ></s:file>
    <s:file name="photo" label="文件2" ></s:file>
    <s:submit value="上传"></s:submit>
   </s:form>
</body>

配置信息

<!-- 限制上传文件的总大小 -->
    <constant name="struts.multipart.maxSize" value="10485760"></constant>
    <!-- 国际化加载资源信息,用来回显上传出错的错误信息,fileupload为信息配置文件的名字 -->
    <constant name="struts.custom.i18n.resources" value="fileupload"></constant>
    <!-- 文件上传 -->
    <package name="uploadFile" extends="struts-default" namespace="/uploadFile">
        <action name="upload" class="com.jyh.action.Upload1Action" method="upload">
            <!-- 引用defaultStack默认的拦截器栈 -->
            <interceptor-ref name="defaultStack">
                <!-- 设置文件的MIME类型 -->
                <param name="fileUpload.allowedTypesSet">image/jpeg,image/bmp</param>
                <!-- 设置该栈中fileUpload拦截器的allowedExtensions属性值(允许上传文件的类型,即后缀名 )-->
                <param name="fileUpload.allowedExtensions">.jpg,.bmp,.png</param>
             </interceptor-ref>
            <result name="success">/success.jsp</result>
            <result name="input">/upload.jsp</result>
            <result name="error">/error.jsp</result>
        </action>
    </package>

动作类

package com.jyh.action;

import java.io.File;
import java.io.IOException;

import javax.servlet.ServletContext;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionSupport;

@SuppressWarnings("serial")
public class Upload1Action extends ActionSupport {

    private String name;
    private File[] photo;//多文件上传,用数组或者集合
    private String[] photoFileName;//上传文件的文件名,xxxFileName固定写法
    private String[] photoContentType;//上传文件的MIME类型,xxxContentType固定写法

    public String upload() {
        ServletContext context = ServletActionContext.getServletContext();
        String directory = context.getRealPath("/files");
        if(StringUtils.isBlank(photoFileName[0])){
            return INPUT;
        }else{
            for (int i = 0; i < photo.length; i++) {
                File target = new File(directory, photoFileName[i]);
                try {
                    FileUtils.copyFile(photo[i], target);//将源文件复制到上传目录
                } catch (IOException e) {
                    return INPUT;
                }
            }
        }
        return SUCCESS;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public File[] getPhoto() {
        return photo;
    }

    public void setPhoto(File[] photo) {
        this.photo = photo;
    }

    public String[] getPhotoFileName() {
        return photoFileName;
    }

    public void setPhotoFileName(String[] photoFileName) {
        this.photoFileName = photoFileName;
    }

    public String[] getPhotoContentType() {
        return photoContentType;
    }

    public void setPhotoContentType(String[] photoContentType) {
        this.photoContentType = photoContentType;
    }

}

错误信息配置

这里写图片描述

文件的下载:结果类型的使用

配置信息

<package name="downloadFile" extends="struts-default" namespace="/downloadFile">
    <action name="download" class="com.jyh.action.DownloadAction" method="download">
        <!-- type结果类型为stream -->
        <result name="success" type="stream">
            <!-- 指定是动作类中的哪个属性 -->
            <param name="inputName">inputStream</param>
            <!-- 通知浏览器以下载的方式打开 -->
            <param name="contentDisposition">attachment;filename=${fileName}</param>
            <!-- MIME类型 -->
            <param name="contentType">application/octet-stream</param>
        </result>
        <result name="error">/error.jsp</result>
    </action>
</package>

动作类

package com.jyh.action;

import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URLEncoder;

import org.apache.commons.io.FilenameUtils;
import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionSupport;

@SuppressWarnings("serial")
public class DownloadAction extends ActionSupport {

    private InputStream inputStream;
    private String fileName;

    public String download(){
        try {
            String realPath = ServletActionContext.getServletContext().getRealPath("/files/" + fileName);
            inputStream = new FileInputStream(realPath);
        } catch (Exception e) {
            return ERROR;
        }
        return SUCCESS;
    }

    public InputStream getInputStream() {
        return inputStream;
    }

    public void setInputStream(InputStream inputStream) {
        this.inputStream = inputStream;
    }

    public String getFileName() {
        return fileName;
    }

    public void setFileName(String fileName) {
        this.fileName = fileName;
    }

}

Struts中的数据中心与OGNL表达式

Stack Context,Value Stack Contents(root),ValueStack和ActionContext之间的关系

这里写图片描述

keyvalue备注
requestServletRequest中的所有属性(Attributes)相当于EL表达式中的requestScope
sessionHttpSession中的所有Attributes相当于EL表达式中的sessionScope
applicationServletContext中的所有Attributes相当于EL表达式中的applicationScope
action动作类
value stack(根)一个List栈
parametersrequest.getParameterMap(),请求中的参数相当于EL表达式中的paramValues
attr按照request>session>application的顺序查找数据${}

OGNL表达式简介

前提:在struts2中要使用OGNL表达式,必须放到Struts2的标签中。
OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,
它是一个开源项目。webwork用它作为表达式语言。
功能:

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

2.支持类静态的方法调用和值访问;

 <body>
    <!-- s:property 就相当于JSTL中的 c:out -->
   <!-- 调用任意对象的任意方法  -->
   <s:property value="'abcdefg'.length()"/>
   <hr/>
   <!-- 访问静态变量 -->
   <s:property value="@java.lang.Integer@MAX_VALUE"/>
    <hr/>
   <!-- 访问静态方法 配置参数:<constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>-->
   <s:property value="@java.lang.Math@abs(-100)"/>
    <hr/>
 </body>

3.访问OGNL上下文(OGNL context)和ActionContext;

java代码添加数据

package com.jyh.action;

import java.util.Calendar;
import java.util.Date;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.util.CompoundRoot;
import com.opensymphony.xwork2.util.ValueStack;

@SuppressWarnings("serial")
public class Demo1Action extends ActionSupport {

    private String userName = "哈哈哈";


    public String getUserName() {
        return userName;
    }


    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String m1(){
        ActionContext actionContext = ActionContext.getContext();//action
        ValueStack vs = actionContext.getValueStack();//根栈
        Map<String, Object> contextMap = vs.getContext();//上下文Map
        //验证
        actionContext.put("p1", "pppp1");
        String s1 = (String)contextMap.get("p1");
        contextMap.put("p2", "pppp2");
        String s2 = (String)actionContext.get("p2");
        System.out.println("s1:" + s1 + ",s2:" + s2);
        //得出结论:actionContextput进去的数据contextMap可以取出来,反之亦可,
        //查看源码可知,actionContextput和get方法就是调用contextMap的put和get方法

        vs.set("p3", "pp3");//检测栈顶中有没有map,没有就创建一个map,把本值塞入map中后再将map push进去
        vs.set("p4", "p4");//检测到栈顶是一个map,直接将数据塞入到 map中去

        vs.setValue("p4", "pp4");//从栈顶开始搜索p4,找到之后就调用setAbc方法设置值
        vs.setValue("#p5", "p5");//添加进contextMap中去

        Object obj = vs.findValue("p3");//查找栈中的值,如果栈中找不到,就将值当做key在Stack Context中找
        System.out.println(obj.toString());

        Object obj2 = vs.findValue("#p5");
        System.out.println(obj2.toString());
        //-----------------------------
        CompoundRoot root =  vs.getRoot();//contextMap中的根
        //System.out.println(root);
        //压对象进栈
        vs.push(new Date());
        vs.push("d1");
        System.out.println("d1:" + root.peek());
        root.push("d2");
        System.out.println("d2:" + vs.peek());

        //压两个时间对象
        Calendar c1 = Calendar.getInstance();
        c1.set(2000, 0, 1);
        vs.push(c1.getTime());//2000-1-1

        Calendar c2 = Calendar.getInstance();
        c2.set(2014, 10,2);
        vs.push(c2.getTime());//2014-11-2

        HttpServletRequest request = ServletActionContext.getRequest();
        request.setAttribute("r1", "r1");//将值塞入request域中去

        actionContext.put("r2", "r2");//将值塞入Stack Context中去
        return SUCCESS;
    }

    public String regist(){
        System.out.println(userName);
        return null;
    }
    public String regist1(){
        System.out.println(userName);
        return SUCCESS;
    }
}

页面用OGNL表达式获取数据

<body>
    <s:debug></s:debug>
    <!-- 取根栈中对象的属性 -->
    <s:property value="time"/><hr>
    <s:property value="userName"/><hr>
    <!-- 取第二个时间的月份 -->
    <s:property value="[1].month"/><hr>

    <!-- #表示获取Stack Context中的数据 -->
    <s:property value="#p1"/><br>
    <s:property value="p1"/><hr>

    <s:property value="p3"/><br>
    <s:property value="p4"/><hr>

    <s:property value="#p5"/><br>
    <s:property value="p5"/><hr>

    <s:property value="#request.r1"/><br>
    ${r1}<br>
    <s:property value="r2"/><br>
    ${r2}<hr>
</body>

4.操作集合对象。

<s:property value="{'a','b','c'}.getClass()"/><br/>
    <s:property value="#{'1':'a','2':'b','3':'c'}.getClass()"/><br/>
    <s:radio name="gender" list="#{'0':'男','1':'女'}"></s:radio><br/>
    <s:checkboxlist name="hobbies" list="{'吃饭','睡觉','打逗逗'}"></s:checkboxlist><br/>

5.字符串和OGNL表达式转换

<!-- 字符串转OGNL表达式,%{}括起来 -->
<s:textfield name="姓名" label="%{姓名}"></s:textfield><br/>
<!-- OGNL表达式转字符串,引号 包含起来 (property标签的value属性都是OGNL表达式 )-->
<s:property value="'0'"/>

6.在配置文件中xml或properties也可以使用OGNL表达式,请使用${ognl}

<!-- 通知浏览器以下载的方式打开 -->
<param name="contentDisposition">attachment;filename=${fileName}</param>

Struts2中的常用标签

<body>
    <!-- 输出标签 -->
    <s:property value="{'a','b','c'}.getClass()"/><br/>
    <s:property value="#{'1':'a','2':'b','3':'c'}.getClass()"/><br/>
    <!-- radio标签 -->
    <s:radio name="gender" list="#{'0':'男','1':'女'}"></s:radio><br/>
    <!-- 相当于checkbox -->
    <s:checkboxlist name="hobbies" list="{'吃饭','睡觉','打逗逗'}"></s:checkboxlist><br/>
    <!-- 相当于input -->
    <s:textfield name="姓名" label="%{姓名}"></s:textfield><br/>
    <br/><hr><br/>
    <!-- 
        set标签,存数据,
        范围有:application|request|session|action
        默认范围是action,1.放到请求范围request和2.放到Stack Context中去 
    -->
    <s:set value="'session'" var="ss" scope="session"></s:set><br/>
    <s:property value="#session.ss"/>
    <s:set value="'value'" var="key"></s:set><br/>
    StackContext:<s:property value="#key"/><br/>
    requestScope:<s:property value="#request.key"/><br/>

    <!-- bean:new一个对象放入Stack Context中去 -->
    <s:bean name="java.util.Date" var="now"></s:bean><!-- new一个名为now的时间对象放入StackContext中去 -->
    <s:property value="#now.time"/><br>

    <!-- 包含另一个动作 -->
    <s:action name="demo2" executeResult="true"></s:action><br/>

    <!-- 循环 -->
    <table border="1">
        <tr>
            <td>key</td>
            <td>value</td>
        </tr>
        <!-- 把当前遍历的元素压如StackContext中去,var的值就是所对应的key,var对应的value就是需要的键值对象 -->
        <s:iterator value="#request" var="me">
            <tr>
                <td><s:property value="#me.key"/></td>
                <td><s:property value="#me.value"/></td>
            </tr>
        </s:iterator>
        <tr><td>---</td><td>---</td></tr>
        <!-- 不指定var,将要遍历的数据压入根栈中去 -->
        <s:iterator value="#request">
            <tr>
                <td><s:property value="key"/></td>
                <td><s:property value="value"/></td>
            </tr>
        </s:iterator>
    </table>
    <br>

    <!-- 
        status存当前遍历的数据并放入StackContext,并提供以下方法
        isOdd,isEven,isLast,isFirst,getIndex,getCount
     -->
    <table border="1">
        <tr><td>key</td><td>value</td><td>index</td></tr>
        <!-- 不指定var,将要遍历的数据压入根栈中去 -->
        <s:iterator value="#request" status="s">
            <tr>
                <td><s:property value="key"/></td>
                <td><s:property value="value"/></td>
                <td><s:property value="#s.count"/></td>
            </tr>
        </s:iterator>
    </table>

    <!-- a标签链接 -->
    <s:a action="stackDemo/demo1">戳这里<s:param name="userName" value="'不明'"></s:param></s:a>
    <s:url action="stackDemo/demo1" var="url">
        <s:param name="userName" value="'不明'"></s:param>
    </s:url>
    <a href="${url}">猛戳</a>

</body>

防止表单重复提交

表单页面

<body>
    <s:form action="/form/formRegist1" method="post">
        <s:textfield name="userName" label="姓名"></s:textfield>
        <s:token></s:token><!-- 关键 -->
        <s:submit value="注册"></s:submit>
    </s:form>
</body>

配置信息

<!-- 防止表单重复提交 -->
    <package name="form" extends="struts-default" namespace="/form">
        <action name="formRegist" class="com.jyh.action.Demo1Action" method="regist">
            <interceptor-ref name="defaultStack"></interceptor-ref>
            <interceptor-ref name="token"></interceptor-ref>
            <!-- 拦截器转向,在表单重复提交的时候 -->
            <result name="invalid.token">/msg.jsp</result>
        </action>
        <action name="formRegist1" class="com.jyh.action.Demo1Action" method="regist1">
            <interceptor-ref name="defaultStack"></interceptor-ref>
            <!-- 与token不同的是,重复提交之后会返回提交的界面 -->
            <interceptor-ref name="tokenSession"></interceptor-ref>
            <result>/success.jsp</result>
        </action>
</package>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值