You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MVC 5 C#中基于DropZone JS按文档类型限制总文件大小

MVC5 C# 结合DropZoneJS实现按文档类型限制总大小的批量PDF上传方案

一、前端实现(DropZone配置与大小校验)

1. 页面HTML结构

先在视图中添加文档类型下拉框、DropZone容器和批量提交按钮:

<div class="form-group">
    @Html.Label("文档类型", new { @class = "control-label" })
    @Html.DropDownList("LKP_DocType", null, "请选择文档类型", new { @class = "form-control", id = "docTypeDropdown" })
</div>

<div id="fileUploadZone" class="dropzone"></div>
<button id="submitBtn" class="btn btn-primary mt-3" disabled>批量上传</button>

2. DropZone JS配置与自定义逻辑

核心是维护不同文档类型的总上传大小,监听文件添加/移除事件做校验,批量提交时携带文档类型参数:

// 按文档类型存储已选文件总大小
let totalSizeByDocType = {
    1: 0, // Administrator
    2: 0, // Manager
    3: 0  // Programer
};
const MAX_TOTAL_SIZE = 5 * 1024 * 1024; // 5MB转换为字节

// 初始化DropZone
Dropzone.options.fileUploadZone = {
    url: '@Url.Action("Upload", "YourController")', // 替换为你的控制器上传方法路径
    autoProcessQueue: false, // 关闭自动上传,手动触发批量提交
    uploadMultiple: true, // 允许批量上传
    parallelUploads: 100, // 并行上传数量
    maxFilesize: 5, // 单文件最大5MB
    acceptedFiles: ".pdf", // 仅允许PDF文件
    addRemoveLinks: true, // 显示移除文件链接
    init: function() {
        const myDropzone = this;
        const submitBtn = document.getElementById("submitBtn");
        const docTypeDropdown = document.getElementById("docTypeDropdown");

        // 切换文档类型时清空当前队列,避免跨类型文件混淆
        docTypeDropdown.addEventListener("change", () => {
            myDropzone.removeAllFiles(true);
            submitBtn.disabled = true;
        });

        // 文件加入队列时校验并更新总大小
        this.on("addedfile", function(file) {
            const selectedTypeId = parseInt(docTypeDropdown.value);
            if (!selectedTypeId) {
                myDropzone.removeFile(file);
                alert("请先选择文档类型");
                return;
            }

            // 累加总大小
            totalSizeByDocType[selectedTypeId] += file.size;

            // 校验总大小是否超限
            if (totalSizeByDocType[selectedTypeId] > MAX_TOTAL_SIZE) {
                myDropzone.removeFile(file);
                totalSizeByDocType[selectedTypeId] -= file.size;
                alert(`当前文档类型总上传大小不能超过5MB,已超出限制`);
                return;
            }

            // 有文件时启用提交按钮
            submitBtn.disabled = false;
        });

        // 文件被移除时更新总大小
        this.on("removedfile", function(file) {
            const selectedTypeId = parseInt(docTypeDropdown.value);
            if (selectedTypeId) {
                totalSizeByDocType[selectedTypeId] -= file.size;
                // 队列为空时禁用提交按钮
                submitBtn.disabled = myDropzone.getQueuedFiles().length === 0;
            }
        });

        // 点击提交按钮触发批量上传
        submitBtn.addEventListener("click", () => {
            const selectedTypeId = parseInt(docTypeDropdown.value);
            if (!selectedTypeId) {
                alert("请先选择文档类型");
                return;
            }

            // 给上传请求携带文档类型参数
            myDropzone.options.params = {
                LKP_DocType: selectedTypeId
            };

            myDropzone.processQueue();
        });

        // 上传完成后重置状态
        this.on("queuecomplete", () => {
            myDropzone.removeAllFiles(true);
            submitBtn.disabled = true;
            const selectedTypeId = parseInt(docTypeDropdown.value);
            if (selectedTypeId) totalSizeByDocType[selectedTypeId] = 0;
        });
    }
};

二、后端实现(MVC5控制器上传方法)

后端需要接收文件集合和文档类型ID,同时做二次校验(防止前端限制被绕过),最后完成文件保存与关联:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;

public class YourController : Controller
{
    [HttpPost]
    public async Task<ActionResult> Upload(IEnumerable<HttpPostedFileBase> files, int LKP_DocType)
    {
        // 1. 校验文档类型合法性
        var validDocTypeIds = new List<int> { 1, 2, 3 };
        if (!validDocTypeIds.Contains(LKP_DocType))
        {
            return Json(new { success = false, message = "无效的文档类型" });
        }

        // 2. 校验总上传大小不超过5MB
        const long MaxTotalSize = 5 * 1024 * 1024;
        long totalUploadSize = files.Sum(f => f?.ContentLength ?? 0);
        if (totalUploadSize > MaxTotalSize)
        {
            return Json(new { success = false, message = "当前文档类型总上传大小不能超过5MB" });
        }

        // 3. 逐个校验文件并保存
        foreach (var file in files)
        {
            if (file == null || file.ContentLength == 0) continue;

            // 校验文件类型(MIME+扩展名双重校验更安全)
            if (file.ContentType != "application/pdf" || Path.GetExtension(file.FileName).ToLower() != ".pdf")
            {
                return Json(new { success = false, message = $"文件{file.FileName}不是合法的PDF格式" });
            }

            // 校验单文件大小
            if (file.ContentLength > MaxTotalSize)
            {
                return Json(new { success = false, message = $"文件{file.FileName}大小超过5MB限制" });
            }

            // 处理文件名重复问题(用GUID生成唯一文件名)
            string uniqueFileName = $"{Guid.NewGuid()}_{Path.GetFileName(file.FileName)}";
            string uploadPath = Path.Combine(Server.MapPath("~/Uploads"), uniqueFileName);

            // 确保上传目录存在
            Directory.CreateDirectory(Path.GetDirectoryName(uploadPath));
            // 保存文件到服务器
            file.SaveAs(uploadPath);

            // 4. 关联文档类型到数据库(示例代码,根据你的实体调整)
            // var document = new Document
            // {
            //     DocTypeId = LKP_DocType,
            //     FileName = uniqueFileName,
            //     FilePath = uploadPath,
            //     UploadTime = DateTime.Now
            // };
            // db.Documents.Add(document);
            // await db.SaveChangesAsync();
        }

        return Json(new { success = true, message = "所有文件上传成功" });
    }
}

三、关键注意事项

  • 权限配置:确保服务器上的~/Uploads目录有读写权限,否则文件保存会失败。
  • 文件名去重:用GUID拼接文件名避免覆盖已有文件,这是生产环境的必要操作。
  • 双重校验:前端校验提升用户体验,后端校验保障数据安全,不可省略后端校验。
  • 错误反馈:前端和后端都要返回清晰的错误提示,帮助用户定位问题。

内容的提问来源于stack exchange,提问作者Syed Mohsin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 17:20:36