FileUpLoad

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package cn.toher.DataImport;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.lang.StringUtils;

/**
 *
 * @author Toher
 */
@WebServlet(name = "FileUpLoad", urlPatterns = {"/FileUpLoad"})
public class FileUpLoad extends HttpServlet {

    private final String uploadLoation = "uploadfile"; //保存的文件夹名称

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        request.setCharacterEncoding("utf-8");  //设置编码

        //获取用户UserNo作用于文件夹创建
        String UserNo = "";
        if (StringUtils.isBlank(UserNo)) {
            UserNo = request.getParameter("userNo");
        }
        //设置项目访问路径
        String ContextPath = request.getContextPath();
        String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + ContextPath + "/";
        
        PrintWriter Printout = response.getWriter();
        //获得磁盘文件条目工厂  
        DiskFileItemFactory factory = new DiskFileItemFactory();
        //获取文件需要上传到的路径
        String path = request.getSession().getServletContext().getRealPath("/") + uploadLoation + File.separator + UserNo;
       
        File pathFile = new File(path);
        //文件以及路径是否存在
        if (!pathFile.exists()) {
            //文件夹 
            pathFile.mkdirs();
        }
        //创建一个文件上传处理器
        factory.setRepository(new File(path));
        //设置 缓存的大小,当上传文件的容量超过该缓存时,直接放到 暂时存储室  
        factory.setSizeThreshold(1024 * 1024);
        //高水平的API文件上传处理  
        ServletFileUpload upload = new ServletFileUpload(factory);

        try {
            //可以上传多个文件,解析表单中的每一个表单项,封装成FileItem对象,以List方式返回,表单("enctype="multipart/form-data"")
            List<FileItem> list = (List<FileItem>) upload.parseRequest(request);
            String newFileName = "";
            for (FileItem item : list) {
                //获取表单的属性名字  
                String name = item.getFieldName();
                //如果获取的 表单信息是普通的 文本 信息  
                if (item.isFormField()) {
                    //获取用户具体输入的字符串 ,名字起得挺好,因为表单提交过来的是 字符串类型的  
                    String value = item.getString();
                    request.setAttribute(name, value);
                } else {
                    //获取路径名  
                    String value = item.getName();
                    String fileExt = value.substring(value.lastIndexOf(".") + 1);
                    //设置新的文件名,这里我们采用日期格式,当然我们还可以使用UUID
                    SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
                    newFileName = df.format(new Date()) + (int) (Math.random() * 1000) + "." + fileExt;

                    String uploadFolder = path + File.separator + newFileName;
                    File file = new File(uploadFolder);
//        到这一步,就开始把request中获取到的文件写入到我预先处理好的路径地址加名字的文件中,write
                    item.write(file);
                }
                /* 上传成功后,进行数据返回!*/
            }
            Printout.println("{\"code\":\"success\",\"msg\":\"/"+ uploadLoation +"/"+UserNo+"/"+ newFileName + "\"}");

        } catch (Exception e) {
            e.printStackTrace();
            Printout.println("{\"code\":\"error\",\"msg\":\"\"}");
        }
    }

    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /**
     * Handles the HTTP <code>GET</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Handles the HTTP <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Returns a short description of the servlet.
     *
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>

}

 

转载于:https://www.cnblogs.com/itchenfirst/p/7284253.html

<think> 我们被要求提供关于文件上传(fileUpload)的相关信息,包括实现方法、使用示例、遇到的问题及解决方案等。根据提供的引用内容,我们可以总结如下: 1. 引用[1]介绍了Apache Commons FileUpload组件,它是一个用于Java环境下处理文件上传的开源库,性能优异且API简单。它需要两个jar包:commons-fileupload和commons-io(作为支撑库)。 2. 引用[2]提到在上传文件时需要检查文件名和MIME类型以确保安全,可以通过FileUpload控件获取文件的MIME类型。 3. 引用[3]展示了一个使用C#的ASP.NET批量上传文件的示例代码,通过遍历HttpFileCollection来处理多个文件,并保存到服务器。 4. 引用[4]指出在文件上传过程中,由于存在分隔符(如multipart/form-data请求中的边界分隔符),可能会导致上传的文件内容出现错误(例如在文本文件中出现额外的分隔符信息)。 5. 引用[5]提到在使用Commons FileUpload时,parseRequest方法返回的List只能被iterator()遍历一次,解决方法是先将parseRequest的结果保存为List,然后可以多次获取迭代器。 根据以上信息,我们将从以下几个方面组织回答: 1. 文件上传的基本原理(使用multipart/form-data编码格式) 2. 使用Apache Commons FileUpload实现文件上传(Java) 3. 使用ASP.NET实现文件上传(C#) 4. 常见问题及解决方案(包括文件名和MIME类型检查、多次遍历上传项、文件内容错误等) 5. 安全注意事项 同时,我们将生成相关问题。 注意:由于引用内容有限,我们主要基于引用提供的信息,并补充一些必要的背景知识。 </think> ### FileUpload 技术详解 #### 一、核心原理与工作流程 文件上传基于 `multipart/form-data` 编码格式实现[^4],工作流程如下: 1. **请求解析**:服务器解析包含文件数据的 HTTP 请求 2. **数据分割**:通过分隔符(如 `------WebKitFormBoundary...`)区分表单字段和文件内容[^4] 3. **元数据提取**:获取文件名、MIME 类型等元信息[^2] 4. **内容存储**:将文件流写入服务器存储位置[^3] ```mermaid sequenceDiagram participant 浏览器 participant 服务器 浏览器->>服务器: multipart/form-data 请求 activate 服务器 服务器->>服务器: 解析请求边界 服务器->>服务器: 分离文件元数据和内容 服务器->>服务器: 验证文件类型和大小[^2][^3] 服务器->>存储: 保存文件流 服务器-->>浏览器: 返回上传结果 deactivate 服务器 ``` #### 二、主流实现方式 ##### 1. Java(Apache Commons FileUpload) ```java // 依赖:commons-fileupload + commons-io DiskFileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload upload = new ServletFileUpload(factory); List<FileItem> items = upload.parseRequest(request); // 关键步骤[^5] for (FileItem item : items) { if (!item.isFormField()) { // 文件字段 String fileName = item.getName(); String mimeType = item.getContentType(); // 获取MIME类型[^2] if (mimeType.startsWith("image/")) { // 安全校验 File file = new File(uploadPath + fileName); item.write(file); // 保存文件 } } } ``` ##### 2. ASP.NET(HttpPostedFile) ```csharp // 批量上传示例[^3] HttpFileCollection files = Request.Files; for (int i = 0; i < files.Count; i++) { HttpPostedFile file = files[i]; if (file.ContentLength > 0) { string mimeType = file.ContentType; // 验证文件类型 string safePath = Path.Combine("~/upload", Path.GetFileName(file.FileName)); file.SaveAs(Server.MapPath(safePath)); // 保存文件 } } ``` #### 三、关键问题与解决方案 | 问题类型 | 现象 | 解决方案 | |----------|------|----------| | **文件内容错误** | 上传文本含分隔符导致文件损坏[^4] | 使用二进制模式读写文件流 | | **迭代器失效** | `parseRequest().iterator()` 单次可用[^5] | 转为List存储:`List items = upload.parseRequest(request)` | | **安全风险** | 恶意文件上传 | 双重验证:<br>1. 文件头签名验证<br>2. 后缀名白名单校验[^2] | | **大文件崩溃** | 内存溢出 | 配置临时目录:<br>`factory.setRepository(new File("/tmp"))` | #### 四、安全最佳实践 1. **MIME类型验证**:对比文件头和声明类型 ```java // 真实检测JPEG文件头 byte[] header = new byte[2]; inputStream.read(header); if (header[0] != (byte)0xFF || header[1] != (byte)0xD8) { throw new InvalidFileException(); } ``` 2. **路径安全**:禁用用户输入直接作为路径 ```csharp // 安全的文件名处理 string safeName = Path.GetFileName(file.FileName).Replace("..", ""); ``` 3. **权限控制**:上传目录禁止脚本执行权限 4. **大小限制**:配置最大上传尺寸(如100MB) > **性能提示**:对于>10MB文件,启用磁盘临时存储而非内存存储[^1] #### 五、扩展应用场景 1. **断点续传**:通过 `Content-Range` 头实现分片上传 2. **云存储集成**:直传OSS/AWS S3 避免服务器带宽瓶颈 3. **病毒扫描**:上传后调用ClamAV等引擎扫描 [^1]: Apache Commons FileUpload 是高性能 Java 文件上传解决方案 [^2]: 必须验证 MIME 类型防止恶意文件上传 [^3]: ASP.NET 通过 HttpFileCollection 实现批量上传 [^4]: 分隔符处理不当会导致文件内容错误 [^5]: parseRequest() 返回的 List 可多次遍历 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值