SpringBoot整合Hadoop,完成雲網盤部分實例

作者這裏使用的是IntelliJ IDEA2017,創建SpringBoot項目的工作以及一些簡單的整合由於網上也有很多資料,這裏就不做贅述,
只談一些比較關鍵的配置。
本項目採用的是SpringBoot 1.5.3.RELEASE這個版本。

1.pom文件依賴版本示例:
        <!-- 版本配置 -->
    <junit.version>4.12</junit.version>
    <mysql-connector.version>5.1.46</mysql-connector.version>
    <mybatis-spring-boot-starter.version>1.3.1</mybatis-spring-boot-starter.version>
    <mybatis-plus.verison>2.1.9</mybatis-plus.verison>
    <mybatis-plus-boot-starter.version>2.1.9</mybatis-plus-boot-starter.version>
    <alibaba.druid.version>1.1.9</alibaba.druid.version>
    <commons-lang3.version>3.5</commons-lang3.version>
    <slf4j-api.version>1.7.25</slf4j-api.version>
    <logback.version>1.2.3</logback.version>
    <log4j.version>1.2.9</log4j.version>
    <fastxml.jackson.version>2.8.10</fastxml.jackson.version>
    <commons-codec.version>1.9</commons-codec.version>
    <commons-io.version>2.5</commons-io.version>
    <hibernate-validator.version>5.3.6.Final</hibernate-validator.version>
    <asm.version>3.3.1</asm.version>
    <cglib-nodep.version>3.2.5</cglib-nodep.version>
    <commons-beanutils.version>1.9.3</commons-beanutils.version>
    <fastjson.version>1.2.32</fastjson.version>
    <springfox-swagger.version>2.8.0</springfox-swagger.version>
    <spring-data-redis.version>1.8.3.RELEASE</spring-data-redis.version>
    <shiro.version>1.4.0-RC2</shiro.version>
    <poi.version>3.9</poi.version>
    <mybatis.version>3.4.4</mybatis.version>
    <velocity.version>2.0</velocity.version>
    <velocity.engine.version>1.7</velocity.engine.version>
    <freemarker.version>2.3.28</freemarker.version>
    <tomcat-servlet-api.version>7.0.77</tomcat-servlet-api.version>
    <jstl-api.version>1.2-rev-1</jstl-api.version>
    <jstl-impl.version>1.2</jstl-impl.version>
    <joda-time.version>2.9.3</joda-time.version>
    <kaptcha.version>0.0.9</kaptcha.version>

2.SpringBoot整合Hadoop,在application.yml配置 ,hadoop集羣的搭建請參考作者的其它文章。
spring:
  hadoop:
    config:
      fs:
        defaultFS: hdfs://192.168.2.213:8020 #你的hdfs的路徑
    fsshell:
      enabled: true #開啓fsshell支持
   mvc:
      view:
        prefix: /templates/
        suffix: .ftl
      static-path-pattern: /static/**
  datasource:
        url: jdbc:mysql://localhost:3306/hadoop?useUnicode=true&characterEncoding=utf-8&useSSL=false #配置數據庫爲mysql
        username: root
        password: hwf123456
        # 使用druid數據源
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.jdbc.Driver
        filters: stat
        maxActive: 20
        initialSize: 1
        maxWait: 60000
        minIdle: 1
        timeBetweenEvictionRunsMillis: 60000
        minEvictableIdleTimeMillis: 300000
        validationQuery: select 'x'
        testWhileIdle: true
        testOnBorrow: false
        testOnReturn: false
        poolPreparedStatements: true
        maxOpenPreparedStatements: 20
mybatis: 
      #MyBatis的配置
      mapper-locations: classpath:mapping/*.xml
      type-aliases-package: com.hdvon.domain
      configuration:
        location: classpath:mybatis-config.xml
        map-underscore-to-camel-case: true
server:
  port: 8082

3.這個時候就可以在service裏面直接注入FsShell,去做一些簡單的操作。
    @Autowired
    FsShell shell;
 
 比如說,這裏只舉幾個栗子:
 (1)返回hdfs路徑下的文件信息:
   public List<HdfsFile> listPaths(String path) throws Exception{
        Collection<FileStatus> fileStatuses = shell.lsr(path);

        List<HdfsFile> fileList = new ArrayList<>();

        for(FileStatus fs: fileStatuses){
            boolean isDirectory = fs.isDirectory();

            if (!isDirectory){
                Path hdfsPath = fs.getPath();
                String name = hdfsPath.getName();
                String uri = hdfsPath.toUri().getPath();

                String owner = fs.getOwner();
                long blockSize = fs.getBlockSize();

                HdfsFile file = new HdfsFile();
                file.setFileOwner(owner);
                file.setFileName(name);
                file.setBlockSize(blockSize);
                file.setFilePath(uri);

                fileList.add(file);
            }
        }
        return fileList;
    }
  (2)創建hdfs目錄
    public RestResult mkDir(String path){
        try {
            shell.mkdir(path);
        } catch (Exception e){
            e.printStackTrace();
            return RestResult.ERROR("創建hdfs目錄失敗" , e);
        }
        return RestResult.SUCCESS("創建hdfs目錄成功" , null);
    }
   (3)上傳文件
     public RestResult putFile(String srcPath , String destPath){
        try {
            shell.put(srcPath , destPath);
        } catch (Exception e){
            e.printStackTrace();
            return RestResult.ERROR("上傳文件失敗" , e);
        }
        return RestResult.SUCCESS("上傳文件成功" , null);
     } 
    (4)下載文件
     public RestResult getFile(String srcPath , String destPath){
        try {
            shell.get(srcPath , destPath);
        } catch (Exception e){
            e.printStackTrace();
            return RestResult.ERROR("下載文件失敗" , e);
        }
        return RestResult.SUCCESS("下載文件成功" , null);
     }
  

4.除了用FsShell,另外一種也是很常用的,沒錯^_^,就是FileSystem,因爲FileSystem需要一個
Configuration,所以我們在SpringBoot裏面需要創建一個實例出來。

@org.springframework.context.annotation.Configuration
public class HdfsRepository {

    @Bean
    public Configuration getConfiguration(){
        Configuration configuration = new Configuration();
        return configuration;
    }

}

這個時候我們就可以在service裏面注入Configuration,然後獲取FileSystem。
比如說:
  (1)獲取hdfs當前路徑下不是目錄的文件
   public List<HdfsFile> getFiles(String path){
      try {
          FileSystem fs = FileSystem.get(configuration);
          RemoteIterator<LocatedFileStatus> fileStatusRemoteIterator = fs.listFiles(new Path(path) , false);

          List<HdfsFile> files = new ArrayList<>();

          while (fileStatusRemoteIterator.hasNext()){
              LocatedFileStatus fileStatus = fileStatusRemoteIterator.next();
              Path path1 = fileStatus.getPath();
              long blockSize = fileStatus.getBlockSize();
              String name = path1.getName();
              String uriPath =  path1.toUri().getPath();
              String owner = fileStatus.getOwner();

              HdfsFile file = new HdfsFile();
              file.setFilePath(uriPath);
              file.setBlockSize(blockSize);
              file.setFileName(name);
              file.setFileOwner(owner);

              files.add(file);
          }
          return files;
      } catch (Exception e){
          e.printStackTrace();
          return null;
      }
    }
   (2)查詢當前路徑下所有的目錄
    public List<HdfsFile> getDirectory(String path){
       try{
           FileSystem fs = FileSystem.get(configuration);
           FileStatus[] fileStatuses = fs.listStatus(new Path(path));

           List<HdfsFile> files = new ArrayList<>();
           for (FileStatus fileStatus : fileStatuses){
               if (fileStatus.isDirectory()){

                   Path path1 = fileStatus.getPath();

                   String name = path1.getName();
                   String uriPath =  path1.toUri().getPath();
                   long blockSize = fileStatus.getBlockSize();
                   String owner = fileStatus.getOwner();

                   HdfsFile file = new HdfsFile();
                   file.setFilePath(uriPath);
                   file.setBlockSize(blockSize);
                   file.setFileName(name);
                   file.setFileOwner(owner);
                   files.add(file);
               }
           }

           return files;
       } catch (Exception e){
           e.printStackTrace();
           return null;
       }
    }
   (4)上傳文件
     public Boolean uploadFile(String srcPath , String destPath){
       try{
           FileSystem fs = FileSystem.get(configuration);
           fs.copyFromLocalFile(new Path(srcPath) , new Path(destPath));
       } catch (Exception e){
           e.printStackTrace();
           return false;
       }
       return true;
     }
   (5)使用流上傳文件
      public Boolean uploadFile2(InputStream inStream , String hdfsPath){
        FSDataOutputStream fos = null;
        try{
            FileSystem fs = FileSystem.get(configuration);
            fos =  fs.create(new Path(hdfsPath));
            IOUtils.copyBytes(inStream , fos , 4078);
        } catch (Exception e){
            e.printStackTrace();
            return false;
        } finally {
            IOUtils.closeStream(fos);
        }
        return true;
     }
    (6)使用流下載文件
      public Boolean downLoadFile(String localPath , String hdfsPath){
        FSDataInputStream fis = null;
        FileOutputStream fos = null;
        try{
            FileSystem fs = FileSystem.get(configuration);
            fis = fs.open(new Path(hdfsPath));
            fos = new FileOutputStream(localPath);
            IOUtils.copyBytes(fis ,fos , 4078);
        } catch (Exception e){
            e.printStackTrace();
            return false;
        } finally {
            IOUtils.closeStream(fos);
            IOUtils.closeStream(fis);
        }
        return true;
     }
    (7)寫文件
      public Boolean writeFile(String inpath , String outpath){
        FSDataOutputStream fos = null;
        FSDataInputStream fis = null;
        try{
            FileSystem fs = FileSystem.get(configuration);
            fos = fs.create(new Path(outpath));
            fis = fs.open(new Path(inpath));
            IOUtils.copyBytes(fis , fos , 1024);
        } catch (Exception e){
            e.printStackTrace();
            return false;
        } finally {
            IOUtils.closeStream(fis);
            IOUtils.closeStream(fos);
        }
        return true;
     }
    (8)修改文件名
      public boolean renameFile(String oldPath, String newPath){
        try{
            FileSystem fs = FileSystem.get(configuration);
            boolean flag = fs.rename(new Path(oldPath) , new Path(newPath));
            return flag;
        } catch (Exception e){
            e.printStackTrace();
            return false;
      }
    (9)移動hdfs上面的文件
      public boolean moveFile(String oldPath, String newPath){
        FSDataInputStream fdis = null;
        FSDataOutputStream fos = null;
        try{
            FileSystem fs = FileSystem.get(configuration);
            fdis = fs.open(new Path(oldPath));
            fos = fs.create(new Path(newPath));

            IOUtils.copyBytes(fdis , fos , 4096);
            fs.delete(new Path(oldPath) , true);
        } catch (Exception e){
            e.printStackTrace();
            return false;
        } finally {
            IOUtils.closeStream(fos);
            IOUtils.closeStream(fdis);
        }
        return true;
     }
    (10)hdfs移動目錄,請小夥伴們注意咯:FileStatus只能讀到當前一級文件或者目錄,所以需要遞歸遍歷才能讀到所有的子文件
      public boolean moveDir(String oldPath, String newPath){
        FSDataInputStream fdis = null;
        FSDataOutputStream fos = null;
        try{
            FileSystem fs = FileSystem.get(configuration);
            Path pathdir = new Path(oldPath);
            FileStatus[] fileStatuses = fs.listStatus(pathdir);

            String basePath = newPath+"/";
            //創建基礎目錄
            fs.mkdirs(new Path(basePath));

            for (FileStatus fileStatus : fileStatuses){
                recuerFile(fdis , fos , fs, fileStatus , basePath);
            }
            fs.delete(new Path(oldPath) , true);
        } catch (Exception e){
            e.printStackTrace();
            return false;
        } finally {
            IOUtils.closeStream(fos);
            IOUtils.closeStream(fdis);
        }
        return true;
     }

     public void recuerFile(FSDataInputStream fdis, FSDataOutputStream fos , FileSystem fs , FileStatus fileStatus , String basePath) {
        try{
            boolean dir = fileStatus.isDirectory();

            FileStatus[] fileStatuses = fs.listStatus(fileStatus.getPath());
            Path path = fileStatus.getPath();
            String fileName = path.getName();

            if (dir){
                fs.mkdirs(new Path(basePath+fileName));

                basePath = basePath+"/"+fileName+"/"; //因爲當前遍歷到的是一個目錄 , basePath又要改成當前目錄的路徑,之後的文件寫入這個新的目錄

                for (FileStatus fileStatus1 : fileStatuses){
                    recuerFile(fdis , fos , fs, fileStatus1 , basePath);
                }
            } else {
                fdis = fs.open(path);
                fos = fs.create(new Path(basePath+fileName));
                IOUtils.copyBytes(fdis , fos , 4096);
            }
        } catch (Exception e){
            e.printStackTrace();
        }
    }

   (11)hdfs移動目錄 ,使用callback減少業務代碼入侵我們的方法!!
      1.首先創建一個回調接口Callback。裏面就只有一個方法 void call(T obj);
      2.移動目錄的邏輯
      public boolean moveDir0(String oldPath, String newPath){
        try{
            FileSystem fs = FileSystem.get(configuration);
            Path pathdir = new Path(oldPath);
            FileStatus[] fileStatuses = fs.listStatus(pathdir);

            final String basePath = newPath+"/";

            //創建基礎目錄
            fs.mkdirs(new Path(basePath));
            for (FileStatus fileStatus : fileStatuses){
            //遞歸調用回調之後的業務
                recuerFile0(fs, fileStatus, new Callback<FileStatus>() {

                    String common_path = basePath;

                    @Override
                    public void call(FileStatus fileStatus) {
                        boolean dir = fileStatus.isDirectory();
                        Path path = fileStatus.getPath();
                        String fileName = path.getName();
                        FSDataInputStream fis = null;
                        FSDataOutputStream fos = null;

                        try{
                            if (dir){
                                fs.mkdirs(new Path(common_path+path.toUri().getPath()));
                            } else {
                                fis = fs.open(path);
                                fos = fs.create(new Path(common_path+path.toUri().getPath()));
                                IOUtils.copyBytes(fis , fos , 4096);
                            }
                        } catch (Exception e){
                            e.printStackTrace();
                        } finally {
                            IOUtils.closeStream(fos);
                            IOUtils.closeStream(fis);
                        }
                    }
                });
            }
            fs.delete(new Path(oldPath) , true);
        } catch (Exception e){
            e.printStackTrace();
            return false;
        }
        return true;
     }
     3.遞歸方法改版,刪掉業務代碼,就很清楚了^_^
      public void recuerFile0(FileSystem fs , FileStatus fileStatus , Callback callback) {
        try{
            boolean dir = fileStatus.isDirectory();
            callback.call(fileStatus);
            if (dir){
                FileStatus[] fileStatuses = fs.listStatus(fileStatus.getPath());
                for (FileStatus fileStatus1 : fileStatuses){
                    recuerFile0(fs, fileStatus1 ,callback);
                }
            }
        } catch (Exception e){
            e.printStackTrace();
        }
     }
    (12)hdfs刪除文件,如果是用hdfs的API的話,默認刪除的文件不會放入到回收站,需要自己去實現這個功能!!!
      public boolean deleteFile(String path){
       try{
           FileSystem fs = FileSystem.get(configuration);
           boolean flag =  fs.delete(new Path(path) , true);
           return flag;
       } catch (Exception e){
           e.printStackTrace();
           return false;
       }
     }
    (13)刪除文件,並且將文件放入到回收站
      public boolean deleteFile2Trash(String path){
        try{
            Trash trash = new Trash(configuration);
            boolean tflag = trash.moveToTrash(new Path(path));
            return tflag;
        } catch (Exception e){
            e.printStackTrace();
            return false;
        }
      }

當然整合的時候如果出現權限的問題,請參考作者的另外一篇博客:https://blog.csdn.net/huwenfeng111111/article/details/82799558
搭建hadoop集羣請參考作者的:https://blog.csdn.net/huwenfeng111111/article/details/82985544

最後,歡迎熱愛技術的小夥伴加入我們的聊天羣qq:715115302 ,大家一起交流^_^

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章