
简介面向计算机相关专业学生与开发者的Hadoop百度云盘项目包含完整源代码与文档说明标签聚焦Hadoop与大数据适合作为毕业设计、课程设计或大数据学习进阶的实战参考。资源包共2000个文件约77.11MB其中前端页面与静态资源数量可观涵盖HTML、CSS、JavaScript及大量PNG图片后端逻辑由JSP、Java配合Jar依赖实现同时附带数据库文件、配置属性和说明文档整体结构清晰便于按模块检索和二次开发。目前已有535人学习或下载。代码经过完整测试并成功运行作者答辩平均分达96分且可私聊远程教学适合需要快速上手或希望借鉴完整项目流程的读者。下载后建议先阅读README文件能更高效地理解项目启动、配置与部署方法。1. 为什么用 Hadoop 做百度云盘一个能跑通的毕设级 HDFS 网盘最近拆了一套基于 Hadoop 的百度云盘毕设项目前端是 Bootstrap EasyUI后端是 Java Web文件存储直接落在 HDFS 上。它没有上 Spring Cloud 那套重型框架靠 Servlet HDFS API 就把上传、下载、目录管理、文件预览整条链路跑通了。这套代码的核心逻辑很直白浏览器把文件交给后端后端调 Hadoop FileSystem 接口把文件写进分布式文件系统用户看到的“网盘目录”其实就是 HDFS 里的路径映射。对正在做大数据的课程设计、毕设题的人来说它最大的价值不是代码本身多复杂而是把“Hadoop 到底能干什么”用一个看得见摸得着的 Web 界面讲清楚了。如果你正打算做网盘、文件管理、大数据存储方向的毕设这篇笔记把架构、部署和坑都捋一遍。2. 环境准备与选型伪分布式 Hadoop Eclipse 工程导入2.1 为什么选 HDFS 做“网盘”存储层网盘这个东西本质上是“把本地文件挪到远程存储”而 Hadoop 里的 HDFS 就是分布式文件系统天生适合干这件事。传统做法是把文件存到服务器本地磁盘、或者存 MySQL 的 BLOB 字段但这两种方案在大数据课程设计里都不够“有说法”。HDFS 的多个副本机制天然对应网盘里的“文件安全”block 分块存储对应“大文件分片上传”这套映射关系在答辩汇报里特别好讲。从代码结构来看这套项目把文件操作全部封装在一个 FileOperate 类里通过 FileSystem.get(conf) 拿到 HDFS 客户端实例。伪分布式环境下配置一个副本跑通流程完全没问题。如果换成三节点集群改个 replication 参数就有容错效果这就是后面第 6 章要说的升级路径。项目里前端用了 EasyUI 的 datagrid、tree、dialog 组件配合 bootstrap.css 做美化和布局页面是典型的后台管理风格。syExtIcon.css 里放的是图标字体ace.min.css 是代码编辑器组件看起来还兼容了在线查看源代码文件的功能。这些前端文件分布在 WebContent 目录下对应 Eclipse WTP 动态 Web 项目的标准结构。2.2 伪分布式 Hadoop 安装与核心配置在跑这套代码之前先把 Hadoop 装好。这里以 Hadoop 2.x/3.x 伪分布式为例装完后要改三个配置文件core-site.xml、hdfs-site.xml、mapred-site.xml。伪分布式只用一个进程模拟分布式环境NameNode 和 DataNode 跑在同一台机器上。core-site.xml 里最重要的是 fs.defaultFS它决定了 HDFS 的访问入口。如果这里写的端口和代码里不一致后面所有上传下载都会失败。!-- core-site.xml -- configuration property namefs.defaultFS/name valuehdfs://localhost:9000/value /property property namehadoop.tmp.dir/name value/home/hadoop/data/tmp/value /property /configuration!-- hdfs-site.xml -- configuration property namedfs.replication/name value1/value /property property namedfs.namenode.name.dir/name value/home/hadoop/data/name/value /property property namedfs.datanode.data.dir/name value/home/hadoop/data/data/value /property /configurationhdfs-site.xml 里 dfs.replication 在伪分布式必须设成 1。很多新手在这里跟着集群教程配成 3结果 DataNode 只有一个节点副本永远写不满NameNode 一直报 “There are X missing blocks”。hadoop.tmp.dir 如果保留默认值重启机器后临时数据会被系统清理掉再次启动会发现 NameNode 起不来血泪教训。配置完先执行 hdfs namenode -format 格式化然后 start-dfs.sh 启动。启动后用 jps 检查进程NameNode、DataNode、SecondaryNameNode 三个进程必须同时存在。jps # 期望输出类似 # 12345 NameNode # 23456 DataNode # 34567 SecondaryNameNode如果缺 DataNode多半是刚才格式化后 datanode 的 data 目录和 namenode 的 name 目录里 clusterID 不一致需要把 data 目录删掉重新格式化。这个坑几乎每届学生都会踩到。2.3 项目导入 Eclipse 与 JDK、编码、依赖三件套这个项目是 Eclipse WTP 工程有 org.eclipse.wst.common.component 文件导入时选 “Existing Projects into Workspace”直接指向解压目录就行。导入后先做三件事检查 JDK 编译级别、检查字符集、检查 Hadoop 依赖 JAR 是否齐全。JDK 版本建议 1.8。Hadoop 2.x 对 JDK 9 以上的兼容性不算好反射调用的某些类会有非法访问警告。如果机器上装的是 JDK 11看到报错先别慌多数和 javax.xml.bind 缺失有关改成 JDK 8 基本能绕过去。字符集方面记得把 workspace 的编码改成 UTF-8。这个项目里有中文文件名上传、中文路径目录创建如果编码是 GBK传到 HDFS 上再读回来就是乱码Linux 上显示一串问号。依赖方面确认 lib 目录下有 hadoop-common、hadoop-hdfs、hadoop-client 这几个核心包。如果缺了从 Hadoop 安装目录的 share/hadoop/common 和 share/hadoop/hdfs 里拷出来。第一步先不要让 IDE 自动帮你找直接手动 Build Path 加进去这种老项目的依赖关系 IDE 自动识别反而容易乱。2.4 文档说明与包结构走读解压后先打开 README.md里面一般会写清楚项目运行步骤。src 目录下面主要包结构是 dao、servlet、util、bean核心类集中在包/目录职责dao数据库访问操作 user 表和 file_record 表servlet前端请求入口上传、下载、目录管理的控制层utilHadoop FileSystem 工具类、字符串处理bean用户、文件记录、目录信息的 JavaBeanWebContent前端页面JSP EasyUI Bootstrapsql数据库初始化脚本建表语句这套包结构是标准的 Servlet 三层写法没有引入 Spring因此追踪代码链路时非常直观浏览器请求 → Servlet → DAO → HDFS API。对毕设阶段来说这种“看得见每一行调用”的结构比 SSM 框架更适合答辩讲解。3. 核心模块实现上传、下载、目录树的 HDFS 操作怎么落代码3.1 登录与 Session 会话管理网站的登录逻辑没有引入 Redis而是用 Servlet Session MySQL 用户表完成的。用户表字段很少大概就是 id、username、password、reg_time。密码做了 MD5 加密存储不过没用加盐这个安全级别在毕设里够用但如果是真实商用肯定不够。登录成功后把用户对象丢进 Session后续上传下载都从 Session 里取当前用户然后拼装用户专属的 HDFS 目录。这里有个值得借鉴的设计每个用户的文件根目录不同类似 /user/zhangsan/避免所有用户挤在同一个根目录下互相看到。代码里大概长这样// UserServlet.java 中的登录逻辑 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String username req.getParameter(username); String password MD5Util.md5(req.getParameter(password)); User user userDao.findByUsernameAndPassword(username, password); if (user ! null) { req.getSession().setAttribute(loginUser, user); resp.sendRedirect(index.jsp); } else { req.setAttribute(msg, 用户名或密码错误); req.getRequestDispatcher(login.jsp).forward(req, resp); } }loginUser 存在 Session 里后续所有 servlet 通过 request.getSession().getAttribute(“loginUser”) 拿到用户 ID再拼出 HDFS 路径。这里注意密码必须先加密再传入 DAO 查询如果拿明文去查一旦数据库泄露就是批量裸奔。3.2 文件上传Web 表单接文件写进 HDFS上传是整个项目最核心的模块。前端用 EasyUI 的 form 组件带 file 字段后端 Servlet 通过 request.getPart 或 FileUpload 组件接文件。拿到上传的流之后构建目标 HDFS 路径调 FileSystem.copyFromLocalFile 或 create 方法写入。以下是 UploadServlet 里核心代码的简化版本// UploadServlet.java 文件上传核心片段 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding(UTF-8); User loginUser (User) req.getSession().getAttribute(loginUser); String currentPath req.getParameter(currentPath); // 当前 HDFS 目录 Part part req.getPart(file); String fileName getFileName(part); // 从 part 头解析原始文件名 // 目标目录/user/{username}/{currentPath} String hdfsPath /user/ loginUser.getUsername() / currentPath; Configuration conf new Configuration(); conf.set(fs.defaultFS, hdfs://localhost:9000); FileSystem fs FileSystem.get(conf); Path dest new Path(hdfsPath / fileName); try (InputStream in part.getInputStream()) { fs.create(dest, new Progressable() { Override public void progress() { // 这里回调可以用来计算上传进度平时也可以不写 } }); // 实际写数据 FSDataOutputStream out fs.create(dest); IOUtils.copyBytes(in, out, 4096, true); } resp.sendRedirect(fileList.jsp?path URLEncoder.encode(currentPath, UTF-8)); }重点说明两个细节getFileName(part) 不能直接拿浏览器文件名因为 IE 和 Chrome 的 Content-Disposition 头格式不一样需要 split 之后再解码。HDFS 路径里的 currentPath 要防止 “../” 这种路径穿越写法否则用户能跳到别的目录我在这个项目基础上改进时加了路径白名单校验不允许包含 .. 和空字符串。IOUtils.copyBytes 是 Hadoop 自带工具类参数 4096 是缓冲区大小true 表示自动关闭流。用 copyBytes 而不是逐行 read/write既能减少代码量也避免忘记关闭 FSDataOutputStream 导致的文件写入不完整。3.3 文件下载与在线预览下载的逻辑正好反过来把 HDFS 上的文件流取出来通过 HttpServletResponse 的输出流写回浏览器同时设置 Content-Disposition 让浏览器弹出下载框。// DownloadServlet.java 文件下载核心片段 protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String filePath req.getParameter(filePath); // 完整 HDFS 路径 Configuration conf new Configuration(); conf.set(fs.defaultFS, hdfs://localhost:9000); FileSystem fs FileSystem.get(conf); Path path new Path(filePath); if (!fs.exists(path)) { resp.setStatus(404); resp.getWriter().write(文件不存在); return; } FSDataInputStream in fs.open(path); String fileName path.getName(); String encodedName URLEncoder.encode(fileName, UTF-8) .replaceAll(\\, %20); resp.setContentType(application/octet-stream); resp.setHeader(Content-Disposition, attachment;filename*UTF-8 encodedName); OutputStream out resp.getOutputStream(); IOUtils.copyBytes(in, out, 4096, true); }注意 Content-Disposition 里的文件名编码如果直接写 filenamefileName中文文件名在 Chrome 里会变成下划线或问号。应该用 RFC 5987 的 filename* 写法配合 URLEncoder 编码才能让中文文件名正常下载。这个坑在演示给老师看的时候特别容易出现一个名为 “项目报告.docx” 的文件下载下来变成 “________.docx”观感极差。3.4 目录树与文件列表目录树是 EasyUI 的 tree 组件后端返回 JSON 数据格式是 [{“id”:1,“text”:“/user/zhangsan/”, “children”:[…]}]。对应后端逻辑遍历 HDFS 目录结构将 FileStatus 数组转换成 JSON。// FileListServlet.java 目录列表核心片段 FileSystem fs FileSystem.get(conf); Path rootPath new Path(/user/ username / currentPath); FileStatus[] statuses fs.listStatus(rootPath); JSONArray arr new JSONArray(); for (FileStatus status : statuses) { JSONObject obj new JSONObject(); if (status.isDirectory()) { obj.put(isDir, true); obj.put(text, status.getPath().getName()); obj.put(children, new JSONArray()); } else { obj.put(isDir, false); obj.put(text, status.getPath().getName() ( formatSize(status.getLen()) )); } obj.put(path, status.getPath().toString()); arr.add(obj); } resp.setCharacterEncoding(UTF-8); resp.setContentType(application/json); resp.getWriter().write(arr.toJSONString());formatSize 要处理的情况包括 B、KB、MB、GB 逐级换算。很多项目在这里直接除以 1024 保留两位小数算出来的结果在文件大时勉强能看文件小时显示成 “0.00 KB”老师看到印象分会打折。4. 部署运行全流程从 Eclipse 启动到浏览器端端到端验证4.1 启动顺序先 HDFS 再 Tomcat整个项目启动顺序有严格要求必须先启动 Hadoop 相关进程再启动 Tomcat。如果 Tomcat 先启动项目里的 Servlet 在初始化时尝试连接 HDFS 可能会抛 ConnectException等 HDFS 起来后不重启 Tomcat 往往恢复不了因为 FileSystem 客户端缓存了失败的连接状态。# 第一步启动 HDFS start-dfs.sh # 第二步确认进程全部就位 jps # 第三步再启动 TomcatEclipse 里右键项目 Run As → Run on Server service tomcat start如果用的是 Eclipse 内嵌 Tomcat一定注意 Server 的配置路径不要冲突。我曾经遇到过 Tomcat 启动显示成功但访问页面 404排查了半天发现是 Eclipse 里配置的 Web 模块根路径是 /baiduyun而访问时输入的是 localhost:8080/少了一层路径。4.2 数据库初始化与连接配置项目用的是 MySQL之前要先建库建表。安装包里的 sql 目录下应该有一个 baiduyun.sql用 source 命令导入即可。-- baiduyun.sql 核心表结构简版 CREATE DATABASE IF NOT EXISTS baiduyun DEFAULT CHARSET utf8; USE baiduyun; CREATE TABLE sys_user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) UNIQUE NOT NULL, password VARCHAR(100) NOT NULL, reg_time DATETIME DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE file_record ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL, file_name VARCHAR(255) NOT NULL, file_size BIGINT DEFAULT 0, hdfs_path VARCHAR(500) NOT NULL, upload_time DATETIME DEFAULT CURRENT_TIMESTAMP, download_count INT DEFAULT 0 );JDBC 连接配置在 util 包里一般是 JdbcUtil.java 或 db.properties。要确认数据库 URL、用户名、密码四件套都改成本机的数据库端口如果不是 3306 也要同步修改。很多同学拆包后只知道代码跑不起来没意识到是数据库账号密码不对日志只报 ClassNotFoundException 或者 Access denied。4.3 功能验证路径一次完整的上传下载巡检启动完成后不要只点几个页面就说“跑通了”。按下面这条路径走一遍确认没漏功能步骤操作预期结果1注册一个新账号能注册成功密码写入 MD5 值2用新账号登录跳转 index.jsp不报错3新建一级目录 “test”目录出现在树里4在 test 下再建二级目录 “sub”树结构展开有两层5上传一个 20MB 的 zip 文件上传进度走完刷新后文件出现在列表里6上传一个中文文件名 docx文件名显示正常无乱码7点击下载刚上传的 zip下载成功大小一致8删除 sub 目录树节点消失HDFS 里对应路径被删这个流程有 8 步覆盖了增、删、查、传、下五个核心动作。如果其中某一步失败大概率能定位到具体模块而不是一句“项目跑不起来”的模糊话。4.4 日志怎么看Tomcat 日志在 logs/catalina.outEclipse 里直接看 Console 窗口。Hadoop 的错误经常会先出现在 HDFS 服务端日志里然后才会在 Tomcat 侧抛 IOException。最常见的报错是org.apache.hadoop.ipc.RemoteException: File /user/test/xxx.dat could only be replicated to 0 nodes, instead of 1这个报错意味着 DataNode 没起来或者 NameNode 处于安全模式。执行 hdfs dfsadmin -safemode leave 退出安全模式或者查看 DataNode 日志确认节点状态。很多时候表面上报的是文件写入失败实际原因是磁盘空间不够或者目录权限不对。hadoop fs -df -h 看一下 HDFS 剩余空间df -h 看本地磁盘两种空间都满了数据节点会自动下线。5. 避坑与排查五个最容易让人翻车的点全是血泪经验5.1 坑一HDFS 端口不一致上传接口一直报 ConnectException现象点击上传按钮后控制台报错日志显示 java.net.ConnectException: Connection refused看堆栈里有 org.apache.hadoop.ipc.Client。原因core-site.xml 里 fs.defaultFS 配了 hdfs://localhost:9000但 Servlet 代码里写死的是 hdfs://localhost:8020。伪分布式安装时默认端口是 9000老版本的 Hadoop 有时是 8020两边对不上就连接失败。解决把代码里的 fs.defaultFS 的端口改成和 core-site.xml 一致。注意一共要改两处一处是各 Servlet 里 new Configuration() 之后的 conf.set另一处是可能存在的 HadoopUtil 工具类统一用一个常量管理端口避免到处写死。5.2 坑二Windows 下运行报 Hadoop WINUTILS.EXE 找不到现象项目在 Eclipse 里启动后访问上传页面日志弹出 “Failed to locate the winutils binary in the hadoop binary path”上传直接失败。原因Windows 下 Hadoop FileSystem 客户端需要一个本地库模拟 Linux 权限校验项目里没有配置 hadoop.home.dir找不到 bin 下的 winutils.exe。解决下载对应版本的 hadoop-common-bin放到一个非中文路径下然后启动 JVM 参数里加 -Dhadoop.home.dirD:/software/hadoop-common-bin或者直接在代码里 System.setProperty(hadoop.home.dir, “D:/software/hadoop-common-bin”)。建议用 JVM 参数方式因为代码方式每次进 System.setProperty 也容易和其他初始化冲突。5.3 坑三上传大文件提示 FileSystem 已关闭现象连续上传几个大文件第一次成功第二次报 java.io.IOException: Filesystem closed。原因项目里可能用了一个单例 FileSystem 实例某个流程结束时调用了 fs.close()。Hadoop 的 FileSystem 实例是线程安全的但调过一次 close 后整个实例作废后续任何操作都会抛 Filesystem closed。解决不要在每次操作结束后调用 fs.close()。正确做法是在整个应用生命周期里复用 FileSystem用 try-with-resources 只关闭流不要关 FileSystem 本身。如果非要在各 Servlet 中获取 FileSystem也尽量写成 FileSystem.get(conf)靠 Hadoop 内部缓存机制复用同一个客户端实例。5.4 坑四上传中文目录名后文件列表里显示乱码现象Linux 服务器上通过页面新建目录 “测试资料”页面树节点变成 “æµè¯èµæ”上传中文文件后 HDFS 里也是乱码。原因后端把 ISO-8859-1 编码的字节流当成 UTF-8 处理或者反过来。Tomcat 默认请求编码不是 UTF-8Servlet 里没有调用 req.setCharacterEncoding(“UTF-8”)的话中文参数在 getParameter 时已经变了形。解决每个 Servlet 的 doGet/doPost 第一行加 req.setCharacterEncoding(UTF-8)并设置 resp.setContentType(text/html; charsetUTF-8)。同时给 Tomcat 的 server.xml 里 Connector 加上 URIEncodingUTF-8 属性。如果之前乱码数据已经写入 HDFS用 dfs -rm -r 删掉重新建。5.5 坑五伪分布式启动后浏览 HDFS 界面Live Nodes 为 0现象访问 localhost:9870看到 Live Nodes 是 0文件系统所有读写都失败。原因NameNode 起来但 DataNode 没起来大概率是 datanode 的 clusterID 和 namenode 不一致。每次执行 hdfs namenode -format 会在 name 目录生成新 clusterID但如果 data 目录里还残留旧的 clusterIDDataNode 启动时会校验失败。解决把 hadoop.tmp.dir 下整个 data 目录删掉然后重新格式化。注意格式化之前先把进程全部停掉start-dfs.sh 和 stop-all.sh 各执行一次清干净再重启。这个操作我做过不下十次每次都提醒自己要确认 dfs.datanode.data.dir 路径下没有旧数据。6. 集群迁移与验收清单从伪分布式到三节点的平滑切换6.1 三节点集群迁移配置和代码要改哪些地方这套代码的 HDFS 地址是写在各 Servlet 的 Configuration 里迁移到集群时不需要大规模改动业务代码只需要把 fs.defaultFS 指向集群 NameNode 的主机名或负载均衡地址。假设三台节点master、slave1、slave2master 跑 NameNodeslave1 和 slave2 跑 DataNode。core-site.xml 改成property namefs.defaultFS/name valuehdfs://master:9000/value /propertyhdfs-site.xml 里 dfs.replication 改成 2 或 3。如果三节点都存数据建议副本数设 2兼顾容量和数据安全设 3 的话每份文件占用三倍空间。同时要在每个 DataNode 节点上配置 dfs.hosts 和 dfs.hosts.exclude 文件不然节点自动加入集群不受控。代码层改动只有一个地方需要把 servlet 里硬编码的 localhost 全部替换成 master 主机名。更好的做法是在 util 包里加一个常量类写 static final String HDFS_URI hdfs://master:9000然后在各 Servlet 中引用这个常量后续再迁移直接改一处。6.2 用上传下载压测确认 HDFS 吞吐是否正常集群搭好后用 Hadoop 自带的 dfs 命令做一轮基础吞吐测试# 测试写入 128MB 文件 hadoop jar /opt/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-3.3.6-tests.jar TestDFSIO -write -nrFiles 10 -fileSize 128MB # 测试读取 hadoop jar /opt/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-3.3.6-tests.jar TestDFSIO -read -nrFiles 10 -fileSize 128MB写吞吐一般能达到磁盘 RAID 的 70% 以上算正常读吞吐通常略高于写。如果写吞吐很低问题大概率在网络检查是否有网卡 bonding 没配好或者万兆网卡没生效。然后回到 Web 页面做一次端到端验证上传一个 500MB 的大文件记录从点击上传到进度条走完的时间。三节点集群应该比伪分布式快不少因为多个 DataNode 并行写入。如果上传反而更慢检查副本数是否过大或者有没有个别节点网络有问题拖慢整个写入。6.3 一份可复用的验收清单不管伪分布式还是集群最终提交前把这份清单过一遍检查项期望结果常见失败jps 进程完整性NameNode/DataNode 齐全SecondaryNameNode 缺失导致 checkpooint 警告HDFS Web UI 可访问master:9870 显示 Live Nodes 符合预期防火墙没开外部访问不了单文件上传中文文件名文件名正常显示大小一致编码没设 UTF-8乱码目录创建/删除/改名操作后树组件刷新正常EasyUI 缓存未清除看到旧数据大文件下载下载后 md5 与本地一致流未关闭导致文件截断用户隔离user1 看不到 user2 的文件HDFS 权限未开启互相可见最后说一件我自己的糗事每次做完这种 Hadoop 网盘项目都会踩到同一个点把代码里的 fs.defaultFS 从 localhost 切到 master 时忘记同步改 pom.xml 里依赖的 hadoop 版本号。结果客户端和服务端版本不一致HDFS 协议协商报错查了一下午才找到是 protobuf 版本冲突。从那以后我每次配置文件的任何改动都强制走一遍 hdfs dfs -ls / 验证连通性确认没问题再启动 Tomcat。希望这套笔记能把你的部署时间从一周压缩到一天真正把精力留在业务功能和答辩准备上祝顺利。本文还有配套的精品资源点击获取