JSP+Servlet网盘系统实战:从环境搭建到权限控制

发布时间:2026/10/1 5:45:35
JSP+Servlet网盘系统实战:从环境搭建到权限控制 简介这是一套面向Java Web初学者与课程设计需求的网盘系统源码采用JSPServlet技术栈后端以MySQL存储数据适合作为毕业设计、课程作业或自学练手项目。项目实现了用户管理、文件上传下载、关注关系等核心模块代码结构清晰难度适中便于理解MVC分层与过滤器机制。压缩包共123个文件约2.28MB其中22个jsp页面负责视图展示20个java源文件与20个class文件构成业务逻辑另有css、js及图片字体等静态资源以及jar依赖、properties配置和xml描述文件整体目录完整导入后按文档配置环境即可运行。目前已有116人学习关注说明其具备一定的参考价值。读者可获得一套可直接运行的完整项目用于对照学习Servlet请求处理、过滤器权限控制、DAO数据访问等实现思路也可在此基础上二次开发快速完成自己的网盘类应用。1. 从一堆 .class 文件说起这套 JSPServlet 网盘系统到底能跑出什么拿到这个压缩包第一眼看到的不是源码而是一串.class文件UserFileDao.class、UserServlet.class、UploadServlet.class、DownloadServlet.class、LoginFilter.class……很多人会愣一下——这是编译产物不是源码。但恰恰是这一点说明这套 JSPServlet 网盘系统是「本地编译过、能直接跑」的状态而不是那种丢给你一堆报错的半成品。它解决的核心问题很明确用最传统的 JavaWeb 技术栈把「用户注册登录 → 上传文件 → 文件列表 → 下载 → 关注/权限控制」这条网盘主链路完整走通数据库用 MySQL 存元数据Servlet 做控制层JSP 做展示层Filter 做登录拦截和下载鉴权。适合谁正在做 JavaWeb 课程设计、毕设选题落在「基于 JSP 的网盘/文件管理」方向、或者想拿一个能跑的传统 MVC 项目对照理解 Servlet 生命周期和 Filter 链的人。如果你只想要 SpringBoot 那套注解式开发这套东西会让你觉得「怎么这么多 web.xml 和手动转发」但它能让你看清一个请求从浏览器到数据库再回到页面的完整路径。2. 环境落地Tomcat、MySQL 与项目导入的完整链路2.1 为什么这套项目必须用 Tomcat 而不是内嵌容器这套资源的技术栈是 JSP Servlet MySQL没有 SpringBoot 的内嵌 Tomcat所以你不能像跑 SpringBoot 那样java -jar一把梭。JSP 需要 Servlet 容器编译成 Servlet 再执行Tomcat 是最常见的选择。常见做法是 Tomcat 8.5 或 9.0JDK 用 8 或 11MySQL 用 5.7 或 8.0。这里有个选型理由Tomcat 9 对应 Servlet 4.0Tomcat 8.5 对应 Servlet 3.1这套项目的web.xml版本和 Filter 写法在两者上都能跑但如果你用 Tomcat 10包名从javax.servlet变成jakarta.servlet所有 Servlet 和 Filter 的 import 都会报错这是第一个大坑。所以别追新Tomcat 9 是稳妥线。MySQL 这边项目里大概率有一张user表、一张file表、可能还有follow表。你需要先建库字符集用utf8mb4排序规则utf8mb4_general_ci否则中文文件名会乱码。数据库连接信息通常在src下的db.properties或某个DBUtil类里改之前先全局搜jdbc:mysql。2.2 导入 IDEA 并配置 Artifact 的实操步骤把压缩包解压后目录结构一般是src、WebContent或web、WebContent/WEB-INF/lib。用 IDEA 导入时选「Existing Sources」或直接 Open 项目根目录然后手动配置 Facet。# 先确认 JDK 和 Tomcat 版本 java -version # 输出应为 1.8.x 或 11.x # 查看 Tomcat 目录下的 lib 是否有 servlet-api.jar ls $CATALINA_HOME/lib/servlet-api.jar上面两条命令是动手前的自检JDK 版本决定编译级别servlet-api.jar存在说明 Tomcat 装完整了。接下来在 IDEA 里File → Project Structure → Modules把src标记为 SourcesWebContent标记为 Web Resource DirectoryWEB-INF/web.xml指向正确路径。Libraries里添加WebContent/WEB-INF/lib下所有 jar以及 Tomcat 的servlet-api.jar、jsp-api.jar。Artifacts里新建Web Application: Exploded输出目录默认即可。Run → Edit Configurations加一个 Tomcat LocalDeployment 选刚才的 ArtifactApplication context 设成/netdisk或/。参数说明Application context 决定访问路径如果设成/netdisk浏览器就要访问http://localhost:8080/netdisk/login.jsp设成/则直接http://localhost:8080/login.jsp。很多人导入后 404九成是 Artifact 没配或 context 写错。2.3 数据库初始化与连接池配置项目里如果有c3p0-config.xml或druid.properties说明用了连接池如果只是DriverManager.getConnection那就是直连。直连在并发上传时容易耗尽连接常见做法是换成 Druid 或 HikariCP但为了先跑通直连也能用。-- 建库建表的最小示例字段名以项目实际为准 CREATE DATABASE netdisk DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE netdisk; CREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE file ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL, filename VARCHAR(255) NOT NULL, filepath VARCHAR(500) NOT NULL, upload_time DATETIME DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES user(id) );这段 SQL 的逻辑是user表存账号file表存文件元数据filepath存服务器上的真实路径而不是文件内容本身这是网盘系统的标准做法——数据库只记「谁在什么时候传了什么文件、放在哪」文件实体落在磁盘目录。参数上注意filename用VARCHAR(255)是因为中文文件名按 utf8mb4 算255 字符足够filepath给 500 是防止深层目录拼接后超长。执行完把连接信息填回项目配置文件启动 Tomcat看到登录页就算环境通了。3. Servlet 与 Filter 协作登录、上传、下载的请求链路拆解3.1 LoginFilter 与 DownloadFilter 的拦截顺序这套项目里有两个 Filter 特别关键LoginFilter和DownloadFilter。LoginFilter拦的是「没登录不能看文件列表」DownloadFilter拦的是「没权限不能下载别人的文件」。Filter 的执行顺序由web.xml里filter-mapping的声明顺序决定或者用WebFilter时按类名排序这点很玄学建议在web.xml里显式写死。!-- web.xml 中 Filter 声明顺序决定执行顺序 -- filter filter-nameLoginFilter/filter-name filter-classcom.netdisk.filter.LoginFilter/filter-class /filter filter-mapping filter-nameLoginFilter/filter-name url-pattern/user/*/url-pattern url-pattern/file/*/url-pattern /filter-mapping filter filter-nameDownloadFilter/filter-name filter-classcom.netdisk.filter.DownloadFilter/filter-class /filter filter-mapping filter-nameDownloadFilter/filter-name url-pattern/download/url-pattern /filter-mapping逻辑说明LoginFilter映射到/user/*和/file/*意味着访问用户中心和文件操作前先检查 session 里有没有user对象DownloadFilter只映射/download在下载前多一层「这个文件是不是你的或你有没有关注分享者」的判断。参数上url-pattern的粒度要控制好映射太宽会把登录页也拦了导致死循环重定向。常见做法是放行/login、/register、静态资源。3.2 UploadServlet 的文件落盘与重名处理UploadServlet是这套系统的核心写入点。它接收multipart/form-data解析出文件名和字节流然后写到服务器某个目录再把路径写进file表。// UploadServlet 核心逻辑示意 WebServlet(/upload) public class UploadServlet extends HttpServlet { protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 1. 获取上传目录通常配置在 web.xml 或常量类 String saveDir getServletContext().getRealPath(/uploads); File dir new File(saveDir); if (!dir.exists()) dir.mkdirs(); // 2. 解析文件名处理重名 String originalName req.getParameter(filename); String ext originalName.substring(originalName.lastIndexOf(.)); String storedName UUID.randomUUID().toString() ext; // 3. 写文件 Part part req.getPart(file); part.write(saveDir File.separator storedName); // 4. 写数据库 User user (User) req.getSession().getAttribute(user); new UserFileDao().insert(user.getId(), originalName, storedName); } }逻辑说明第 1 步用getRealPath拿到的是部署目录下的路径重启 Tomcat 后如果重新部署这个目录可能被清空所以生产环境要配外部目录。第 2 步用 UUID 重命名是为了避免同名文件互相覆盖原始文件名单独存数据库用于展示。第 3 步part.write是 Servlet 3.0 的 API前提是MultipartConfig注解或web.xml里配了multipart-config否则getPart返回 null。参数上UUID.randomUUID()碰撞概率极低但如果你要保留扩展名注意lastIndexOf(.)在文件名没有点时返回 -1会抛异常加个判断。3.3 DownloadServlet 的流式输出与断点续传边界DownloadServlet负责把文件从磁盘读出来写回响应流。最简版本是设置Content-Disposition和Content-Type然后Files.copy。WebServlet(/download) public class DownloadServlet extends HttpServlet { protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String fileId req.getParameter(id); UserFile uf new UserFileDao().findById(Integer.parseInt(fileId)); if (uf null) { resp.sendError(404); return; } File file new File(getServletContext().getRealPath(/uploads), uf.getStoredName()); resp.setContentType(application/octet-stream); resp.setHeader(Content-Disposition, attachment; filename URLEncoder.encode(uf.getFilename(), UTF-8)); resp.setContentLengthLong(file.length()); try (InputStream in new FileInputStream(file); OutputStream out resp.getOutputStream()) { byte[] buf new byte[8192]; int len; while ((len in.read(buf)) ! -1) { out.write(buf, 0, len); } } } }逻辑说明Content-Disposition里的文件名必须 URL 编码否则中文名在浏览器下载时会变成乱码或截断。setContentLengthLong告诉浏览器文件大小这样下载进度条才准。缓冲区 8192 字节是常见值太小频繁 IO太大占内存。断点续传这套代码没实现如果客户端发Range头服务器会忽略并返回完整文件大文件下载体验差但作为课程设计够用。想加断点续传需要解析Range头、设置206 Partial Content、用RandomAccessFile定位这是进阶方向。4. 避坑与排查从 404 到中文乱码的五个血泪现场4.1 启动后 404日志里连 Servlet 都没加载现象Tomcat 启动无报错访问login.jsp能开但提交表单后 404。原因web.xml里servlet-mapping的url-pattern和表单action不一致或者WebServlet注解没生效web.xml的metadata-completetrue会忽略注解。解决先看 Tomcat 启动日志有没有Servlet [xxx] initialized没有就是没注册再核对action路径注意 context path 是否重复。4.2 上传大文件报FileSizeLimitExceededException现象传小文件正常传几十 MB 就抛异常。原因MultipartConfig默认maxFileSize是 -1不限但如果你在web.xml里配了multipart-config且设了max-file-size就会触发。另外 Tomcat 的maxSwallowSize和连接器maxPostSize也会限制。解决在MultipartConfig(maxFileSize 104857600)显式设大同时检查server.xml的 Connector 有没有maxPostSize00 表示不限。4.3 中文文件名下载后变成%E4%B8%AD%E6%96%87现象下载下来的文件名是一串百分号编码。原因Content-Disposition里直接放了未编码的中文或者用了URLEncoder.encode但浏览器不认。解决用URLEncoder.encode(filename, UTF-8).replace(, %20)或者按 RFC 5987 写filename*UTF-8格式。不同浏览器行为不一致这是经典玄学建议两种都带上。4.4 MySQL 连接报Public Key Retrieval is not allowed现象MySQL 8.0 下连接失败提示公钥检索不允许。原因MySQL 8 默认用caching_sha2_password认证插件旧版 JDBC 驱动不兼容。解决连接串加allowPublicKeyRetrievaltrueuseSSLfalse或者把用户认证插件改成mysql_native_password。注意useSSLfalse只是本地开发图省事生产环境要配证书。4.5 Filter 里重定向后请求又被拦一次现象未登录访问受保护页面LoginFilter重定向到login.jsp结果login.jsp也被拦无限重定向。原因url-pattern映射了/*或包含了登录页路径。解决在 Filter 里判断请求 URI如果是login.jsp、login、register、静态资源后缀直接chain.doFilter放行。这个判断要写在重定向之前。5. 进阶技巧用 UserFollowDao 做文件分享与权限校验的闭环UserFollowDao这个类名透露了一个信息这套网盘不只是「自己传自己下」还有「关注」关系可能是关注某个用户后能看他的分享文件。这就把权限模型从「文件属于谁」扩展到了「谁关注了谁」。我一般会这样设计校验逻辑下载请求进来先查文件归属如果file.user_id session.user.id直接放行否则查follow表看当前用户有没有关注文件所有者且文件是否标记为「公开分享」。两个条件都满足才允许下载否则返回 403。// DownloadFilter 中的权限判断片段 int fileOwnerId userFile.getUserId(); int currentUserId ((User) req.getSession().getAttribute(user)).getId(); if (fileOwnerId ! currentUserId) { boolean isFollowing new UserFollowDao() .exists(currentUserId, fileOwnerId); boolean isShared userFile.getIsShared() 1; if (!isFollowing || !isShared) { resp.sendError(HttpServletResponse.SC_FORBIDDEN); return; } } chain.doFilter(req, resp);逻辑说明exists方法查follow表里有没有(follower_id, followee_id)这条记录isShared是file表的一个标志位。参数上注意isShared用tinyint(1)存Java 里映射成int或boolean都行但 JDBC 读出来可能是0/1别直接当boolean用。这个闭环做完你的网盘就从「单用户文件柜」变成了「带社交属性的分享系统」毕设答辩时这是加分项。验证方法注册两个账号 A 和 BA 上传文件并设为分享B 不关注 A 时下载应 403B 关注 A 后再下载应成功A 取消分享后 B 再下载又变 403。这三步走通说明 Filter 链和 DAO 查询都对上了。从那以后我每次拿到这种传统 JavaWeb 项目都强制先跑一遍「注册→登录→上传→列表→下载→越权下载」这条主链路再去看代码。因为环境问题和权限漏洞永远是在跑通之后才会暴露。希望帮到你。本文还有配套的精品资源点击获取