文件上传底层细节(Struts2)

  1. 说明:如果使用的是Struts2进行文件上传,此文章可以帮你更进一步理解和应用文件上传。
  2. 主代码如下:
****************************一、视图层******************************
1.upload.jsp 文件

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">

    <title>My JSP 'upload.jsp' starting page</title>

    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->

  </head>

  <body>
   <form action="upload/uplo.action" enctype="multipart/form-data" method="post">
    <input type="file" name="filesrc">&nbsp;<input type="submit" value="上传">
   </form>
  </body>
</html>



2.success.jsp 文件 >>>>>

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">

    <title>My JSP 'success.jsp' starting page</title>

    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->

  </head>

  <body>
   <h1>上传成功</h1>
  </body>
</html>





****************************二、控制层******************************
        package com.cs.action;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionSupport;

/**
 * 1.StaticParametersInterceptor把UploadAction配置
 * <param name="uploadDir">/upload</param>的"/upload"
 * 通过Ognl注入到UploadAction成员变量uploadDir中。
 * 这个过程中有个重要方法 final Map<String, String> parameters = config.getParams();
 * 
 * 2.ParametersInterceptor+Ognl注入UploadAction中的以下成员变量
 *  file, fileFileName, fileContontType(这些变量命名有一定规则,看下面注释"以下属性是如何映射的?")
 * 
 * 3. JakartaMultiPartRequest(结合文件上传组件commons-fileupload进行的扩展) + FileUploadInterceptor
 *    初始化:在StrutsPrepareAndExecuteFilter的doFilter方法中初始化JakartaMultiPartRequest:
 *              request = prepare.wrapRequest(request);
 *    应用:在FileUploadInterceptor拦截器中,Enumeration fileParameterNames = multiWrapper.getFileParameterNames();
 *      
 * 
 * 
 * @author 拈花为何不一笑
 *
 * 其它:
 *  1.依赖注入:
 *       (1).注册常量bean
 *          <constant name="struts.multipart.maxSize" value="4194304"></constant>
 *       (2).使用:通过注解,参数类型Class-->找到常量bean
 *          @Inject(StrutsConstants.STRUTS_MULTIPART_MAXSIZE)
 *          public void setMaxSize(String maxSize) {
 *              this.maxSize = Long.parseLong(maxSize);
 *          }
 *  2.setRepository方法用于设置存放上传文件的临时目录,当上传文件尺寸大于setSizeThreshold方法设置的临界值时,将文件存储在临时目录下(磁盘)。
 *  3.setSizeThreshold设置上传文件在内存中的阀值,默认为10KB,超出阀值将存储于磁盘上。
 *  4.ServletFileUpload upload = new ServletFileUpload(fac)
 *
 *  5.fileupload组件存储上传文件的默认临时目录:
 *      使用了commons-io组件的方法来获取
 *  源码片段:
 *      protected File getTempFile() {
        if (tempFile == null) {
            File tempDir = repository;
            if (tempDir == null) {
                tempDir = new File(System.getProperty("java.io.tmpdir"));
            }
            …………
        }
     说明:Struts2中设置了repository为:
        File tempdir = (File) servletContext.getAttribute("javax.servlet.context.tempdir");中的tempdir.toString();
     若不设置repository使用默认的目录:System.getProperty("java.io.tmpdir")。这里的源码片段就不贴出来了……

 */
public class UploadAction extends ActionSupport {

    private static final long serialVersionUID = 1L;

    /**
     * 以下属性是如何映射的(文件,文件名,文件类型,文件上传目录)?
     * 
     *  FileUploadInterceptor从MultiPartRequestWrapper(结合fileupload组件解析文件上传请求)中收集参数
     *   然后放到ActionContext(ac)的参数Map中:
     *        Map<String, Object> params = ac.getParameters();
     *        params.put(inputName, acceptedFiles.toArray(new File[acceptedFiles.size()]));
     *        params.put(contentTypeName, acceptedContentTypes.toArray(new String[acceptedContentTypes.size()]));
     *        params.put(fileNameName, acceptedFileNames.toArray(new String[acceptedFileNames.size()]));
     *    由于,文件上传拦截器(FileUploadInterceptor)给参数名作了如下处理:
     *       String contentTypeName = inputName + "ContentType";
     *       String fileNameName = inputName + "FileName";
     *     那么UploadAction中的成员变量(文件,文件类型名,文件名)命名规则就为:
     *          比如:File filesrc;(inputName为前端标签元素<input type="file" name="filesrc">中的name属性的值)
     *          则文件类型名为:"filesrc" + "ContentType";
     *          则文件名为: "filesrc" + "FileName";
     *   
     *   ParametersInterceptor拦截器通过ActionContext: ac.getParameters();再结合Ognl设值,完成UploadAction成员属性的映射。
     *   
     *   类比自己是如何使用fileupload组件的
     *    
     */

    private File filesrc;              //文件

    private String filesrcFileName;    //上传的文件名

    private String filesrcContontType; //上传的文件类型

    private String uploadDir;          //上传文件到服务器那个目录下

    /**
     * 文件上传业务处理
     */
    public String execute() throws IOException{
        System.out.println("uploadDir: "+uploadDir);
        System.out.println("文件开始上传...");


        /**
         * 一些常量路径说明:
         */

        /*
         * 获取绝对路径,用于上传文件至此路径
         *  getRealPath("/")表示在struts2_upload目录下(当前项目根路径)
         *  getRealPath("/upload")//表示在struts2_upload/upload目录下
         */
        String path = ServletActionContext.getServletContext()
                    .getRealPath(uploadDir)
                    + filesrc.separator
                    + filesrcFileName;


        System.out.println("文件绝对路径*******: " + path);

        System.out.println("当前服务器临时目录*******:"+System.getProperty("java.io.tmpdir"));


        /*
         * Struts2中
         *   Unable to find 'struts.multipart.saveDir' property setting.
         *   "此常量bean"在struts2-core.jar包中的default.properties中,"有键无值",由开发人员指定
         *   很明显的提示信息,若没有设置它就使用"javax.servlet.context.tempdir"作为key来获取临时存储目录
         *   Defaulting to javax.servlet.context.tempdir
         */
        File f = (File)ServletActionContext.getServletContext().getAttribute("javax.servlet.context.tempdir");
        System.out.println("Struts2文件上传临时目录设置: ***************" + f.getAbsolutePath() +"\n"
                + f.getCanonicalPath() + "\n"
                + f.getPath() + "\n");
        /*
         * 1.明确java Application应用程序的"user.dir"
         *   与java 服务器中的程序的"user.dir"
         * 2.实际开发中使用相对路径,常用classpath作为相对路径
         *  ClassLoader.getResource(classpath);
         */
        String path2 = System.getProperty("user.dir");
        System.out.println("user.dir: " + path2);

        //开始上传文件(文件拷贝)
        FileOutputStream fos = null;
        FileInputStream fis = null;
        try {
            fos=new FileOutputStream(path);
            fis=new FileInputStream(filesrc);//与文件建立输入流
            byte[] buf=new byte[2048];
            int flag=fis.read(buf);
            while(flag!=-1){
                fos.write(buf);
                fos.flush();
                flag=fis.read(buf);
            }
        }finally{
            //关闭流
            fos.close();
            fis.close();
        }

        return "success";
    }




    public File getFilesrc() {
        return filesrc;
    }

    public void setFilesrc(File filesrc) {
        this.filesrc = filesrc;
    }



    public String getFilesrcFileName() {
        return filesrcFileName;
    }


    public void setFilesrcFileName(String filesrcFileName) {
        this.filesrcFileName = filesrcFileName;
    }


    public String getFilesrcContontType() {
        return filesrcContontType;
    }


    public void setFilesrcContontType(String filesrcContontType) {
        this.filesrcContontType = filesrcContontType;
    }


    public String getUploadDir() {
        return uploadDir;
    }

    public void setUploadDir(String uploadDir) {
        this.uploadDir = uploadDir;
    }


}

****************************三、配置文件****************************
    1.struts.xml 配置文件 >>>>>>>

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
    <!-- 国际化信息用于此的目的是:当发生上传错误时,用于显示.properties中的信息-->
    <constant name="struts.custom.i18n.resources" value="testmessages_zh_CN.properties"></constant>
    <!-- 常量bean,设置最大上传量 -->
    <constant name="struts.multipart.maxSize" value="4194304"></constant>
    <include file="upload.xml" />
    <package name="default" namespace="/" extends="struts-default">


    </package>

</struts>


2.upload.xml配置文件 >>>>>>

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>

    <package name="upload" namespace="/upload" extends="struts-default">
       <action name="uplo" class="com.cs.action.UploadAction">
        <!-- 注入,将Upload的成员变量uploadDir赋值为"/upload"  -->
        <param name="uploadDir">/upload</param>

        <!-- 上传前给拦截器处理一下,使用的是struts-default.xml中的fileUpload拦截器 -->
        <interceptor-ref name="fileUpload">
                <param name="maximumSize">4194304</param><!-- 限制上传文件大小 -->
                <param name="allowedExtensions">.jpg,.ppt,.doc</param><!-- 限制文件格式 -->
        </interceptor-ref>

        <!-- 添加默认拦截器defaultStack,上面已经配置了fileUpload拦截器重复了,
          这个例子中,只使用到了三个拦截器:
            1.FileUploadInterceptor
            2.StaticParametersInterceptor
            3.ParametersInterceptor
        <interceptor-ref name="defaultStack"></interceptor-ref>
         -->
        <!-- 以下二个拦截器在此例中可以替代拦截器栈defaultStack -->
        <interceptor-ref name="staticParams"></interceptor-ref> 
        <interceptor-ref name="params"></interceptor-ref>

        <result name="success">/success.jsp</result>
        <result name="input">/error.jsp</result><!-- 通过input视图返回错误页面 -->

       </action>

    </package>


 3.testmessages_zh_CN.properties 配置文件  >>>>>>
     struts.messages.error.file.too.large=\u4E0A\u4F20\u7684\u6587\u4EF6\u8D85\u8FC7\u6307\u5B9A\u5927\u5C0F
struts.messages.error.file.extension.not.allowed=\u4E0A\u4F20\u7684\u6587\u4EF6\u683C\u5F0F\u4E0D\u6B63\u786E

</struts>



--->>>>>thanks
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值