Hadoop数据云盘项目实战:从环境搭建到HDFS文件上传下载全流程
简介这是一套面向高校计算机相关专业学生的Hadoop大数据开发实战项目资料以数据云盘系统为业务场景适合作为课程设计、期末大作业或毕业设计的参考方案也便于新手通过完整项目理解Hadoop生态的实际应用。压缩包共126个文件约58.11MB以Java后端源码为核心配合JSP页面、JavaScript脚本、CSS样式与XML配置另含jar依赖、properties配置及图片、字体等静态资源构成一套可运行的前后端项目结构。目前已有1153人学习下载具备一定的参考热度。项目代码注释较为完整文档说明覆盖部署与使用要点下载后简单配置即可运行功能涵盖文件上传、存储与管理等云盘核心模块界面美观、操作便捷。对于需要快速搭建大数据课程设计框架、梳理项目分层结构与排错思路的读者这份源码与文档能提供较完整的实现参照具有较高的实际应用与学习价值。1. 数据云盘项目到底能跑起来吗从文件清单看技术底子很多同学拿到「Hadoop大数据开发项目实战数据云盘」这类资源包第一反应是翻目录找主类结果看到file1.bmp、mvnw.cmd、bootstrap.min.css、animate.css、font-awesome.min.css、select2.css、style.css、jquery.dataTables.min.css、theme.css、bootstrap-select.min.css这一串文件心里先凉了半截——这看着像前端模板拼盘跟 Hadoop 有什么关系我拆过不少课程设计级别的云盘项目实话讲这类资源包通常是「Spring Boot 做业务层 Hadoop 做底层存储」的混合体前端用 Bootstrap 系 UI 快速搭出管理界面后端通过 HDFS Java API 把文件真正落到分布式文件系统里。它解决的核心问题是让你在一个能跑通的 Web 界面里完成文件上传、下载、列表、删除而文件实体不落在本地磁盘而是进 HDFS。适合谁正在做大数据课程设计、期末大作业需要一份「有界面、有存储、有文档」的完整参考实现且不想从零搭环境的人。但前提是你得先把 Hadoop 伪分布式或集群跑起来否则这个项目只能当静态页面看。2. 环境搭建与依赖梳理先把 Hadoop 和 Maven 的坑填平2.1 为什么选伪分布式而不是单机模式这个项目的代码里会引用FileSystem.get(URI, conf)这类 HDFS 客户端 API如果你本地 Hadoop 跑的是单机模式fs.defaultFS指向file:///上传逻辑会直接写本地磁盘云盘就失去了「分布式存储」的意义。常见做法是搭伪分布式一个 NameNode、一个 DataNode、一个 ResourceManager全部跑在同一台机器上。这样既能看到 HDFS 的目录结构又不用开三台虚拟机。我一般会建议把core-site.xml里的fs.defaultFS设成hdfs://localhost:9000hdfs-site.xml里副本数设 1否则伪分布式下副本数大于 1 会一直报「只有一个 DataNode 无法满足副本要求」的警告。2.2 从零配置 Hadoop 的关键参数假设你用的是 Hadoop 3.x项目文档里一般会写版本没写就按 3.2 处理解压后先配环境变量# 在 ~/.bashrc 或 /etc/profile 里追加 export HADOOP_HOME/opt/hadoop-3.2.4 export PATH$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin export HDFS_NAMENODE_USERroot export HDFS_DATANODE_USERroot export HDFS_SECONDARYNAMENODE_USERroot这几行里HDFS_*_USER是 Hadoop 3 新增的不配的话start-dfs.sh会直接报「USER is not defined」。接着改etc/hadoop/core-site.xmlconfiguration property namefs.defaultFS/name valuehdfs://localhost:9000/value /property property namehadoop.tmp.dir/name value/opt/hadoop-3.2.4/tmp/value /property /configurationhadoop.tmp.dir必须显式指定默认落在/tmp下机器重启后 NameNode 元数据丢失集群直接起不来这是血泪经验。hdfs-site.xml里把dfs.replication设为 1dfs.namenode.name.dir和dfs.datanode.data.dir指向你提前建好的目录。2.3 格式化与启动的顺序不能乱第一次启动前必须格式化 NameNodehdfs namenode -format看到Storage directory /opt/hadoop-3.2.4/tmp/dfs/name has been successfully formatted才算成功。然后start-dfs.sh jpsjps应该看到 NameNode、DataNode、SecondaryNameNode 三个进程。如果 DataNode 没起来八成是hadoop.tmp.dir下的dfs/data目录权限不对或者之前格式化过多次导致 clusterID 不一致把dfs/data清掉重新格式化即可。启动后用hdfs dfs -mkdir /clouddisk建一个云盘根目录后面项目里上传的文件都会落在这里。2.4 Maven 依赖与前端资源定位项目根目录有mvnw.cmd说明是 Maven Wrapper 项目Windows 下直接双击或命令行mvnw.cmd clean package就能编译不用额外装 Maven。但mvnw第一次运行会去下载 Maven 发行包网络不稳的话会卡住我一般会本地装一个 Maven 3.6然后mvn clean package -DskipTests跳过测试加速。前端那些bootstrap.min.css、jquery.dataTables.min.css、select2.css是放在src/main/resources/static下的Spring Boot 会自动映射为静态资源不需要额外配 Nginx。file1.bmp通常是测试用的上传样本别删后面验证上传功能时用得上。3. 核心功能拆解上传、下载、列表在 HDFS 上怎么落地3.1 文件上传从 MultipartFile 到 HDFS 输出流云盘最核心的动作是上传。项目里一般会有一个FileController接收前端form-data传来的文件然后转成 HDFS 的FSDataOutputStream。我拆过的类似实现核心代码大概长这样// 注入 Hadoop 配置通常从 application.yml 读取 fs.defaultFS Value(${hadoop.fs.defaultFS}) private String hdfsUri; public String upload(MultipartFile file) throws IOException { Configuration conf new Configuration(); conf.set(fs.defaultFS, hdfsUri); // 关键用 HDFS 的 URI 拿到 FileSystem 实例 FileSystem fs FileSystem.get(URI.create(hdfsUri), conf); // 目标路径/clouddisk/原始文件名 Path dest new Path(/clouddisk/ file.getOriginalFilename()); // 如果同名文件已存在默认会覆盖这里先判断 if (fs.exists(dest)) { return 文件已存在; } try (FSDataOutputStream out fs.create(dest); InputStream in file.getInputStream()) { // 用 Hadoop 自带的 IOUtils 做流拷贝比手写 buffer 稳 IOUtils.copyBytes(in, out, 4096, false); } fs.close(); return 上传成功; }逻辑说明FileSystem.get是重量级操作每次上传都新建一个实例在高并发下会拖垮 NameNode生产环境应该做成单例或连接池但课程设计级别这样写能跑通。IOUtils.copyBytes的第三个参数是缓冲区大小4096 是保守值传大文件可以调到 8192 或 16384。第四个参数false表示不自动关闭流由 try-with-resources 负责。参数方面hadoop.fs.defaultFS建议写在application.yml里方便换集群地址时不用改代码。3.2 文件下载把 HDFS 流写回 HTTP 响应下载的逻辑跟上传相反从 HDFS 读FSDataInputStream然后写进HttpServletResponse的OutputStream。这里有个容易翻车的点响应头里的Content-Disposition文件名如果包含中文不编码会乱码。GetMapping(/download) public void download(RequestParam String filename, HttpServletResponse response) throws IOException { Configuration conf new Configuration(); conf.set(fs.defaultFS, hdfsUri); FileSystem fs FileSystem.get(URI.create(hdfsUri), conf); Path src new Path(/clouddisk/ filename); if (!fs.exists(src)) { response.sendError(404, 文件不存在); return; } // 中文文件名用 URLEncoder 编码否则浏览器下载下来是乱码 String encodedName URLEncoder.encode(filename, UTF-8).replaceAll(\\, %20); response.setHeader(Content-Disposition, attachment; filename*UTF-8 encodedName); response.setContentType(application/octet-stream); try (FSDataInputStream in fs.open(src); OutputStream out response.getOutputStream()) { IOUtils.copyBytes(in, out, 4096, false); } fs.close(); }filename*UTF-8是 RFC 5987 规定的写法比单纯URLEncoder更规范。如果项目里用的是response.setHeader(Content-Disposition, attachment; filename filename)中文必乱这是最常见的坑之一。3.3 文件列表与 DataTables 分页前端用了jquery.dataTables.min.css说明列表页是 DataTables 渲染的。后端一般提供一个/list接口返回 HDFS 根目录下的文件数组GetMapping(/list) public ListMapString, Object list() throws IOException { Configuration conf new Configuration(); conf.set(fs.defaultFS, hdfsUri); FileSystem fs FileSystem.get(URI.create(hdfsUri), conf); FileStatus[] statuses fs.listStatus(new Path(/clouddisk)); ListMapString, Object result new ArrayList(); for (FileStatus status : statuses) { MapString, Object item new HashMap(); item.put(name, status.getPath().getName()); item.put(size, status.getLen()); item.put(modifyTime, status.getModificationTime()); result.add(item); } fs.close(); return result; }FileStatus里能拿到文件大小、修改时间、权限、副本数等信息前端 DataTables 拿到 JSON 后自动分页。注意getModificationTime()返回的是毫秒时间戳前端用new Date(timestamp).toLocaleString()转一下就行。如果文件数量上千listStatus会一次性拉全量建议加分页参数但课程设计级别文件不多这样写够用。4. 避坑与排查那些让项目跑不起来的常见问题4.1 上传报「Could not obtain block」或「No live nodes contain current block」现象上传小文件正常传几十兆以上的文件时卡住最后抛BlockMissingException。原因DataNode 磁盘空间不足或者dfs.datanode.du.reserved预留空间设得太大导致实际可用空间不够写一个 block。解决df -h看磁盘清理/opt/hadoop-3.2.4/tmp/dfs/data下的旧块或者把dfs.datanode.du.reserved调小默认 10G伪分布式下可以设成 1G。4.2 前端页面样式全丢只剩裸 HTML现象访问localhost:8080能看到页面结构但 Bootstrap 样式没生效按钮全是默认灰。原因Spring Boot 静态资源默认映射/static下的文件但项目里可能把 CSS 放在了webapp目录或者路径写成了绝对路径/css/bootstrap.min.css而实际文件在/static/css/下。解决检查application.yml里有没有spring.mvc.static-path-pattern配置默认是/**不用改然后确认 HTML 里引用路径是th:href{/css/bootstrap.min.css}或/css/bootstrap.min.css文件实际位置在src/main/resources/static/css/下。4.3 启动报「Port 9000 already in use」现象start-dfs.sh后 NameNode 没起来日志里写BindException: Port 9000 already in use。原因之前跑过 Hadoop 没停干净或者本地有其他服务占了 9000。解决netstat -tlnp | grep 9000找到进程号kill -9掉然后stop-dfs.sh再start-dfs.sh。如果 9000 被系统服务占用改core-site.xml里的fs.defaultFS端口为 9001同时改项目里hadoop.fs.defaultFS配置保持一致。4.4 Maven 编译报「Cannot resolve org.apache.hadoop:hadoop-client」现象mvn clean package时依赖下载失败提示找不到 Hadoop 客户端包。原因项目pom.xml里 Hadoop 版本写的是3.2.4但本地仓库没有或者镜像仓库里没有这个版本。解决确认pom.xml里hadoop.version属性值然后去 Maven 中央仓库搜一下该版本是否存在。常见做法是改成3.2.4或3.3.6这类稳定版别用3.4.0以上的新版本API 有变动项目里的FileSystem.get写法可能不兼容。4.5 下载文件时浏览器直接打开而不是弹出保存框现象点下载按钮PDF 或图片直接在浏览器里预览了没有「另存为」对话框。原因Content-Type设成了application/pdf或image/jpeg浏览器识别到可预览类型就内联打开了。解决强制设成application/octet-stream并且Content-Disposition用attachment两个条件同时满足才会触发下载。5. 进阶技巧用 Docker 快速复现环境与验证清单5.1 为什么建议用 Docker 跑 Hadoop本地装 Hadoop 最烦的是 JDK 版本、环境变量、目录权限三者互相打架。我后来习惯用 Docker 起一个伪分布式集群镜像选sequenceiq/hadoop-docker:2.7.1或自己写 Dockerfile 基于openjdk:8-jdk装 Hadoop 3.2.4。好处是环境隔离删容器就干净了不用手动清/tmp下的元数据。启动命令docker run -d --name hadoop-pseudo \ -p 9000:9000 -p 9870:9870 -p 8088:8088 \ -v /data/hadoop:/opt/hadoop-3.2.4/tmp \ sequenceiq/hadoop-docker:2.7.1-v把容器内临时目录挂到宿主机容器重启后 NameNode 元数据不丢。9870 是 Hadoop 3 的 NameNode Web UI 端口Hadoop 2 是 50070访问http://localhost:9870能看到集群概览就说明起来了。然后把项目里的hadoop.fs.defaultFS改成hdfs://localhost:9000直接跑 Spring Boot 即可。5.2 一份可复用的验证清单部署完别急着点上传按这个顺序走一遍能省掉大量排查时间检查项命令/操作预期结果NameNode 进程jps有 NameNodeDataNode 进程jps有 DataNodeHDFS 根目录hdfs dfs -ls /能列出目录云盘目录hdfs dfs -ls /clouddisk目录存在Web UI浏览器访问 9870页面正常项目编译mvn clean package -DskipTestsBUILD SUCCESS上传测试传file1.bmp返回「上传成功」HDFS 验证hdfs dfs -ls /clouddisk看到 file1.bmp下载测试点下载按钮文件内容一致这张表我每次部署类似项目都会走一遍尤其是hdfs dfs -ls /clouddisk这一步能直接确认文件是不是真进了 HDFS而不是被写到了本地某个临时目录。5.3 一个容易被忽略的细节HDFS 权限Hadoop 默认开启权限检查hdfs dfs -mkdir /clouddisk时如果当前用户不是 root可能报Permission denied。常见做法是在core-site.xml里临时关掉权限检查property namedfs.permissions.enabled/name valuefalse/value /property改完重启集群。但注意这只是课程设计阶段的便利做法真实生产环境不能关。另外项目里FileSystem.get拿到的用户身份取决于启动 JVM 的系统用户Windows 下是当前登录用户Linux 下是whoami的结果如果 HDFS 里文件属主对不上也会报权限错误用hdfs dfs -chown -R root:root /clouddisk统一属主即可。5.4 从那以后我每次部署都强制走一遍的流程我现在拿到任何 Hadoop 课程设计资源第一件事不是看代码而是先jps确认集群活着再hdfs dfs -ls /确认能连上然后才去编译项目。这个习惯是被坑出来的——有一次帮人看一个云盘项目折腾了一下午上传失败最后发现是 DataNode 根本没起来代码本身没问题。所以顺序不能反先集群后应用。希望帮到你。本文还有配套的精品资源点击获取