虚拟文件存储开发求助:文件上传后的数据库存储与视图展示
解决方案:文件存储到数据库 + 文件列表展示操作
针对你遇到的两个问题,我会一步步帮你修改现有代码来解决:
一、将文件名和文件路径保存到数据库
当前你的文件上传和表单数据提交是分开执行的(文件选择后立即Ajax上传,表单提交时只保存其他字段),这会导致文件和文档元数据无法关联。我们需要调整流程,在表单提交时同时处理文件上传和数据保存,并将文件信息存入数据库。
1. 修改前端代码(合并文件与表单提交逻辑)
首先移除原来独立的文件上传Ajax,改为监听表单提交事件,用Ajax统一提交所有字段和文件:
<div class="modal-body"> @using (Html.BeginForm("SaveRecord", "NgarkoDokument", FormMethod.Post, new { enctype = "multipart/form-data", id = "documentForm" })) { <!-- 原有的表单内容保持不变 --> <div class="row" id="ruaj"> <button title="Ruaj dokumentin" type="submit" class="btn btn-success">Ruaj</button> </div> } </div> <script type="text/javascript"> $(document).ready(function () { // 监听表单提交 $("#documentForm").submit(function(e) { e.preventDefault(); // 阻止默认跳转 var formData = new FormData(this); // 自动包含所有表单字段和文件 $.ajax({ type: "POST", url: this.action, data: formData, dataType: 'json', contentType: false, processData: false, success: function (response) { response.success ? (alert('Dokumenti u ruajt me sukses!'), $('#yourModalId').modal('hide')) : alert('Gabim gjatë ruajtjes: ' + response.message); }, error: () => alert('Gabim në komunikimin me serverin!') }); }); // 保持原有的文件列表展示函数 function updateList() { const input = document.getElementById('file'); const output = document.getElementById('fileList'); output.innerHTML = ''; for (let i = 0; i < input.files.length; ++i) { output.innerHTML += `<p>${input.files.item(i).name}</p>`; } } }); </script>
2. 更新模型与Controller方法
首先确保Dokumenti实体包含文件相关字段:
public class Dokumenti { public int ID { get; set; } public string Emer { get; set; } public string EmriFile { get; set; } // 存储文件名 public string PathFile { get; set; } // 存储文件相对路径 // 关联字段 public int Vendndodhja_FizikeID { get; set; } public int Fusha_IndeksimitID { get; set; } public virtual Vendndodhja_Fizike Vendndodhja_Fizike { get; set; } public virtual Fusha_Indeksimit Fusha_Indeksimit { get; set; } }
然后修改SaveRecord方法,统一处理文件上传和数据保存:
[HttpPost] public JsonResult SaveRecord(NgarkoDokument model) { try { // 1. 保存物理位置数据 var vendndodhja = new Vendndodhja_Fizike { Zyra = model.Vendndodhja_fizike.Zyra, Rafti = model.Vendndodhja_fizike.Rafti, Nr_Kutise = model.Vendndodhja_fizike.Nr_Kutise }; db.Vendndodhja_Fizike.Add(vendndodhja); db.SaveChanges(); // 2. 保存索引字段数据 var indeksimi = new Fusha_Indeksimit { Emri_Indeksimit = model.Fusha_Indeksimit.Emri_Indeksimit }; db.Fusha_Indeksimit.Add(indeksimi); db.SaveChanges(); // 3. 处理文件并保存文档记录 for (int i = 0; i < Request.Files.Count; i++) { var file = Request.Files[i]; if (file.ContentLength <= 0) continue; // 生成唯一文件名避免覆盖 var uniqueFileName = $"{Guid.NewGuid()}_{Path.GetFileName(file.FileName)}"; var relativePath = $"~/App_Data/File/{uniqueFileName}"; var physicalPath = Server.MapPath(relativePath); file.SaveAs(physicalPath); // 保存到数据库 var dok = new Dokumenti { Emer = model.Dokumenti.Emer, EmriFile = uniqueFileName, PathFile = relativePath, Vendndodhja_FizikeID = vendndodhja.ID, Fusha_IndeksimitID = indeksimi.ID }; db.Dokumenti.Add(dok); } db.SaveChanges(); return Json(new { success = true }); } catch(Exception ex) { return Json(new { success = false, message = ex.Message }); } }
二、在视图中展示文件并支持操作
接下来我们在Dokument视图中展示所有文件,并添加查看、下载、删除功能。
1. 修改Dokument控制器方法,查询关联数据
public ActionResult Dokument() { var dokumentet = db.Dokumenti .Include(d => d.Vendndodhja_Fizike) .Include(d => d.Fusha_Indeksimit) .ToList(); return View(dokumentet); }
2. 渲染文件列表视图(强类型视图,模型为List<Dokumenti>)
@model List<Dokumenti> <h2>Lista e Dokumenteve</h2> <table class="table table-striped"> <thead> <tr> <th>Emri i Dokumentit</th> <th>Emri i File</th> <th>Zyra</th> <th>Kutia</th> <th>Rafti</th> <th>Indeksimi</th> <th>Operacione</th> </tr> </thead> <tbody> @foreach (var dok in Model) { <tr> <td>@dok.Emer</td> <td>@dok.EmriFile</td> <td>@dok.Vendndodhja_Fizike.Zyra</td> <td>@dok.Vendndodhja_Fizike.Nr_Kutise</td> <td>@dok.Vendndodhja_Fizike.Rafti</td> <td>@dok.Fusha_Indeksimit.Emri_Indeksimit</td> <td> <a href="@Url.Action("ViewFile", "NgarkoDokument", new { id = dok.ID })" target="_blank" class="btn btn-sm btn-primary">Shiko</a> <a href="@Url.Action("DownloadFile", "NgarkoDokument", new { id = dok.ID })" class="btn btn-sm btn-success">Shkarko</a> <button onclick="deleteDocument(@dok.ID)" class="btn btn-sm btn-danger">Fshi</button> </td> </tr> } </tbody> </table> <script type="text/javascript"> function deleteDocument(documentId) { if(confirm('A jeni i sigurt që doni të fshini këtë dokument?')) { $.ajax({ type: "POST", url: '@Url.Action("DeleteDocument", "NgarkoDokument")', data: { id: documentId }, success: function(response) { response.success ? (alert('Dokumenti u fshi me sukses!'), location.reload()) : alert('Gabim gjatë fshirjes: ' + response.message); } }); } } </script>
3. 添加Controller操作方法(查看、下载、删除)
// 预览文件(支持浏览器可直接渲染的格式:图片、PDF、文本等) public ActionResult ViewFile(int id) { var dok = db.Dokumenti.Find(id); if(dok == null) return HttpNotFound(); var physicalPath = Server.MapPath(dok.PathFile); var contentType = MimeMapping.GetMimeMapping(physicalPath); return File(physicalPath, contentType); } // 下载文件 public ActionResult DownloadFile(int id) { var dok = db.Dokumenti.Find(id); if(dok == null) return HttpNotFound(); var physicalPath = Server.MapPath(dok.PathFile); return File(physicalPath, MimeMapping.GetMimeMapping(physicalPath), dok.EmriFile); } // 删除文件与数据库记录 [HttpPost] public JsonResult DeleteDocument(int id) { try { var dok = db.Dokumenti.Find(id); if(dok == null) return Json(new { success = false, message = "Dokumenti nuk u gjet!" }); // 删除服务器文件 var physicalPath = Server.MapPath(dok.PathFile); if(System.IO.File.Exists(physicalPath)) System.IO.File.Delete(physicalPath); // 删除数据库记录 db.Dokumenti.Remove(dok); db.SaveChanges(); return Json(new { success = true }); } catch(Exception ex) { return Json(new { success = false, message = ex.Message }); } }
额外优化建议
- 文件类型/大小限制:在Controller中添加校验,比如限制仅上传PDF/Word/图片,单个文件不超过10MB。
- 错误提示优化:用前端弹窗组件代替alert,提升用户体验。
- 分页功能:如果文件数量多,添加分页查询,避免页面加载过慢。
内容的提问来源于stack exchange,提问作者kris7i
相关产品推荐
相关产品推荐

