分享

基于SSH的HDFS文件web管理系统

fc013 发表于 2016-6-5 18:03:33 [显示全部楼层] 只看大图 回帖奖励 阅读模式 关闭右栏 3 12419

问题导读:

1.怎样利用hdfs管理文件?
2.hdfs中怎样检索文件夹?
3.怎样读取序列文件?




1. 软件版本 &部署:
maven:3.3.9,jdk:1.7 ,Struts2:2.3.24.1,hibernate:4.3.6,spring:4.2.5,MySQL:5.1.34,Junit:4,Myeclipse:2014;
Hadoop2.6.4

源码下载地址: https://github.com/fansy1990/ssh_v3/releases


项目部署:

1) 修改src/main/resource 下的jdbc.properties 中对应的数据库配置,为本地配置;

并在hdfsuser中添加两条记录:

下载 (5).png

2) 修改src/main/resource 下的Hadoop.properties 为本地机器配置;

其中 :hdfs.ssh.client.host=192.168.0.80 、hdfs.ssh.client.port=22 配置为何fs.defaultFS同样的ip即可,端口是指Linux远程连接的端口,一般默认是22;

3) 需要把maven的依赖加入到项目部署的web-info/lib下面:

下载 (6).png

4) 查看项目部署路径:

下载 (7).png

5)把项目直接deploy到tomcat中,浏览器直接访问http://localhost:8080/v3即可;

2. 系统功能界面&核心代码实现:


项目使用Maven构建Hadoop相关依赖以及ssh(Linux远程连接)依赖,其pom.xml如下:

[mw_shl_code=html,true]<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>

        <groupId>ssh</groupId>
        <artifactId>v2</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <packaging>jar</packaging>

        <name>v2</name>
        <url>http://maven.apache.org</url>

        <properties>
                <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
                <spring.version>4.2.5.RELEASE</spring.version>
                <struts2.version>2.3.24.1</struts2.version>
                <hibernate.version>4.3.6.Final</hibernate.version>
                <dbcp.version>1.4</dbcp.version>
                <mysql.version>5.1.34</mysql.version>
                <junit.version>4.11</junit.version>
                <json.version>1.1.36</json.version>
                <hadoop.version>2.6.4</hadoop.version>
                <ssh2-version>262</ssh2-version>

        </properties>

        <dependencies>
        <!--  添加ssh2 java相关maven -->
                <dependency>
                        <groupId>ch.ethz.ganymed</groupId>
                        <artifactId>ganymed-ssh2</artifactId>
                        <version>${ssh2-version}</version>
                </dependency>

                <dependency>
                        <groupId>com.alibaba</groupId>
                        <artifactId>fastjson</artifactId>
                        <version>${json.version}</version>
                </dependency>
                <dependency>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-context</artifactId>
                        <version>${spring.version}</version>
                </dependency>
                <dependency>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-web</artifactId>
                        <version>${spring.version}</version>
                </dependency>
                <dependency>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-test</artifactId>
                        <version>${spring.version}</version>
                </dependency>

                <dependency>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-aspects</artifactId>
                        <version>${spring.version}</version>
                </dependency>
                <dependency>
                        <groupId>commons-dbcp</groupId>
                        <artifactId>commons-dbcp</artifactId>
                        <version>${dbcp.version}</version>
                </dependency>
                <dependency>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                        <version>${mysql.version}</version>
                </dependency>
                <dependency>
                        <groupId>org.springframework</groupId>
                        <artifactId>spring-orm</artifactId>
                        <version>${spring.version}</version>
                </dependency>
                <dependency>
                        <groupId>org.hibernate</groupId>
                        <artifactId>hibernate-core</artifactId>
                        <version>${hibernate.version}</version>
                </dependency>
                <dependency>
                        <groupId>org.apache.struts</groupId>
                        <artifactId>struts2-core</artifactId>
                        <version>${struts2.version}</version>
                </dependency>
                <dependency>
                        <groupId>org.apache.struts</groupId>
                        <artifactId>struts2-spring-plugin</artifactId>
                        <version>${struts2.version}</version>
                </dependency>
                <dependency>
                        <groupId>org.apache.struts</groupId>
                        <artifactId>struts2-junit-plugin</artifactId>
                        <version>${struts2.version}</version>
                </dependency>
                <dependency>
                        <groupId>javax.servlet</groupId>
                        <artifactId>javax.servlet-api</artifactId>
                        <version>3.0.1</version>
                        <scope>provided</scope>
                </dependency>
                <dependency>
                        <groupId>junit</groupId>
                        <artifactId>junit</artifactId>
                        <version>${junit.version}</version>
                        <scope>test</scope>
                </dependency>

                <!-- 添加hadoop支持 -->
                <dependency>
                        <groupId>org.apache.hadoop</groupId>
                        <artifactId>hadoop-hdfs</artifactId>
                        <version>${hadoop.version}</version>
                        <exclusions>
                                <exclusion>
                                        <groupId>javax.servlet</groupId>
                                        <artifactId>servlet-api</artifactId>
                                </exclusion>
                        </exclusions>
                </dependency>
                <dependency>
                        <groupId>org.apache.hadoop</groupId>
                        <artifactId>hadoop-auth</artifactId>
                        <version>${hadoop.version}</version>
                </dependency>
                <dependency>
                        <groupId>org.apache.hadoop</groupId>
                        <artifactId>hadoop-common</artifactId>
                        <version>${hadoop.version}</version>
                        <exclusions>
                                <exclusion>
                                        <groupId>javax.servlet</groupId>
                                        <artifactId>servlet-api</artifactId>
                                </exclusion>
                        </exclusions>
                </dependency>
                <dependency>
                        <groupId>org.apache.hadoop</groupId>
                        <artifactId>hadoop-mapreduce-client-core</artifactId>
                        <version>${hadoop.version}</version>
                </dependency>
                <dependency>
                        <groupId>org.apache.hadoop</groupId>
                        <artifactId>hadoop-mapreduce-client-common</artifactId>
                        <version>${hadoop.version}</version>
                </dependency>
                <dependency>
                        <groupId>org.apache.hadoop</groupId>
                        <artifactId>hadoop-mapreduce-client-jobclient</artifactId>
                        <version>${hadoop.version}</version>
                </dependency>

        </dependencies>
</project>
[/mw_shl_code]

2.1 登录&注册

登录界面:

下载 (9).png 下载 (8).png

在登录界面可以直接跳转到注册界面,注册中的邮箱是唯一值,即用户名可以一样,但是邮箱不能一样;用户注册默认拥有的权限是Authority.USER,也即是在数据库中存储的是1,这个权限在后面有用;

用户登录后,进入系统界面:

下载 (10).png

在右上是系统登录用户名以及帮助信息(目前只包含注销功能);右边是导航,包含系统所有功能;

2.2 目录目前目录相关功能:目录浏览、目录检索是类似的,目录检索的功能包含目录浏览;

目录检索:
下载 (11).png

点击abc,直接可以进入到abc的目录;同时,目录也会有相应的变化

下载 (12).png

同时可以进行,目录的文件名、所有者进行过滤:

下载 (13).png

可以返回上一级,以及返回根目录;

这里的分页使用的方式是,直接查询该目录下所有的文件及文件夹,然后根据分页的当前页以及每页个数进行截取,所以这里的效率是比较低的;

后台代码:

[mw_shl_code=java,true]/**
         * 检索文件夹 先检查权限
         *
         * @return
         * @throws IOException
         * @throws IllegalArgumentException
         * @throws FileNotFoundException
         */
        public void searchFolder() throws FileNotFoundException,
                        IllegalArgumentException, IOException {

                List<HdfsResponseProperties> files = this.hdfsService.searchFolder(
                                hdfsFile.getFolder(), hdfsFile.getName(), hdfsFile.getNameOp(),
                                hdfsFile.getOwner(), hdfsFile.getOwnerOp());
                Map<String, Object> jsonMap = new HashMap<String, Object>();
                jsonMap.put("total", files.size());
                jsonMap.put("rows", getProperFiles(files, page, rows));
                Utils.write2PrintWriter(JSON.toJSONString(jsonMap));
                return;
        }[/mw_shl_code]

这里看到从service得到所有的数据后,调用了getProperFiles方法:

[mw_shl_code=java,true]private List<HdfsResponseProperties> getProperFiles(List<HdfsResponseProperties> files,
                        int page, int rows) {

                return files.subList((page-1)*rows, page*rows>files.size()?files.size():page*rows);
        }[/mw_shl_code]

在service中的方法是获取所有数据的,如下:

[mw_shl_code=java,true]public List<HdfsResponseProperties> searchFolder(String folder,
                        String name, String nameOp, String owner, String ownerOp)
                        throws FileNotFoundException, IllegalArgumentException, IOException {
                List<HdfsResponseProperties> files = new ArrayList<>();
                FileSystem fs = HadoopUtils.getFs();
                FileStatus[] filesStatus = fs.listStatus(new Path(folder));
                for (FileStatus file : filesStatus) {
                        if (!checkName(file.getPath().getName(), name, nameOp))
                                continue; // 名字没有检查通过,则下一个
                        if (!checkName(file.getOwner(), owner, ownerOp))
                                continue; // owner没有检查通过,则下一个
                        files.add(Utils.getDataFromLocatedFileStatus(file));
                }

                return files;
        }[/mw_shl_code]

目录删除

目录删除分为递归和非递归,当然一般如果要删除的话就是递归删除,如果目录下面还有其他目录,那么非递归删除,就会报错:

下载 (14).png

2.3 文件文件查看:

在目录检索中,如果点击的是非目录,就会有相应的提示:

下载 (15).png

所以针对文件,可以使用文件查看功能,目前支持文本文件和使用内置的key、value生成的序列文件读取

下载 (16).png

序列化文件读取及支持的内置键值对类型:

[mw_shl_code=java,true]/**
         * 读取序列文件
         *
         * @param fileName
         * @param records
         * @return
         * @throws IOException
         */
        public static String readSeq(String fileName, int records)
                        throws IOException {
                Configuration conf = getConf();
                SequenceFile.Reader reader = null;
                StringBuffer buffer = new StringBuffer();
                try {
                        reader = new SequenceFile.Reader(conf, Reader.file(new Path(
                                        fileName)), Reader.bufferSize(4096), Reader.start(0));
                        Writable dkey = (Writable) ReflectionUtils.newInstance(
                                        reader.getKeyClass(), conf);
                        Writable dvalue = (Writable) ReflectionUtils.newInstance(
                                        reader.getValueClass(), conf);
                        while (reader.next(dkey, dvalue) && records-- > 0) {// 循环读取文件
                                buffer.append(getValue(dkey)).append("\t")
                                                .append(getValue(dvalue)).append("<br>");
                        }
                } catch (Exception e) {
                        e.printStackTrace();
                        throw e;
                } finally {
                        IOUtils.closeStream(reader);
                }
                return buffer.toString();
        }

        /**
         * 获得writable 的实际值
         *
         * @param writable
         * @return
         */
        private static String getValue(Writable writable) {
                if (writable instanceof Text) {
                        return writable.toString();
                }
                if (writable instanceof LongWritable) {
                        return String.valueOf(((LongWritable) writable).get());
                }
                if (writable instanceof IntWritable) {
                        return String.valueOf(((IntWritable) writable).get());
                }
                if (writable instanceof ShortWritable) {
                        return String.valueOf(((ShortWritable) writable).get());
                }

                if (writable instanceof DoubleWritable) {
                        return String.valueOf(((DoubleWritable) writable).get());
                }
                if (writable instanceof BooleanWritable) {
                        return String.valueOf(((BooleanWritable) writable).get());
                }
                return null;
        }[/mw_shl_code]

文件上传:

文件上传可以直接上传客户端文件到HDFS上:

下载 (17).png


2.4 权限管理

这里的权限管理不是指的hdfsuser数据库中的权限,这里先说下hdfsuser中的authority是用来干嘛的,这个是指如果用户拥有Authority.Administrator权限,即authority=0,那么就可以打开权限管理页面:(其他用户不可以打开此页面)

下载 (18).png

tomcat启动的时候,绑定的HDFS账号权限默认使用root,也就是任何用户在操作HDFS时,使用的都是root账号,这也就是意味着,在进行目录及文件相关操作时,进行的权限检查使用的是root账号。比如在进行文件上传时,上传的文件其用户显示的就是root。如果绑定其他用户,比如hadoop,那么显示的就是hadoop账号(上传的文件的所有者);

此页面在管理员输入HDFS用户名和密码后需要先进行“验证”,然后才能“更新”;

验证:会使用ssh(Linux远程连接)测试此用户是否可以连接 hdfs.ssh.client.host 这个机器;

[mw_shl_code=java,true]/**
         * 权限验证
         */
        public void authCheck() {
                Map<String, Object> map = new HashMap<>();
                // 进行ssh权限验证
                boolean hasHdfsLoginAuth = Utils.canLogin(hadoopUserName,
                                hadoopPassword);
                ActionContext context = ActionContext.getContext();
                Map session = context.getSession();
                if (!hasHdfsLoginAuth) {
                        map.put("flag", "false");
                        map.put("msg", "HDFS用户名或密码错误!");
                        session.put("authCheck", "false");// 用于验证 ,更新数据库时

                } else {
                        map.put("flag", "true");
                        session.put("authCheck", "true");
                        session.put("tmpHadoopUserName", hadoopUserName);// 临时存储,防止验证和更新使用的是不一样的用户名
                        session.put("tmpHadoopPassword", hadoopPassword);// 临时存储,防止验证和更新使用的是不一样的密码
                }
                Utils.write2PrintWriter(JSON.toJSONString(map));
                return;
        }[/mw_shl_code]

[mw_shl_code=java,true]/**
         * ssh远程是否可登录
         *
         * @param hdfsUserName
         * @param hdfsPassword
         * @return
         */
        public static boolean canLogin(String hdfsUserName, String hdfsPassword) {
                // hdfsPassword 解密
                // TODO 未完成
                // ssh远程检查用户名和密码

                String hostname = HadoopUtils.getPropertyValue("hdfs.ssh.client.host");
                int port = Integer.parseInt(HadoopUtils
                                .getPropertyValue("hdfs.ssh.client.port"));
                try {
                        Connection conn = new Connection(hostname, port);
                        conn.connect();

                        boolean isAuthenticated = conn.authenticateWithPassword(
                                        hdfsUserName, hdfsPassword);
                        return isAuthenticated;
                } catch (Exception e) {
                        e.printStackTrace();
                        return false;
                }

        }[/mw_shl_code]

更新:会先检查“验证”的状态,如果没有验证,那么就不能更新,更新操作会refresh session中的值,同时会更新HDFS的FileSystem;

[mw_shl_code=java,true]/**
         * 更新 绑定的hadoop用户密码
         * @param username
         * @param password
         */
        public static void updateHadoopUserNamePassword(String username,String password){
                if(username!=null){
                        hadoopUserName= username;
                }else{
                        hadoopUserName="null";
                }
                if(password!=null){
                        setHadoopPassword(password);
                }else{
                        setHadoopPassword("null") ;
                }
                initFs();// 重新初始化
        }[/mw_shl_code]

3. 总结:

1)本系统较多使用的其实还是easyui,js及spring、hibernate、Struts的技术,关于hadoop的相关操作,只是FileSystem的一些API的使用;
2)权限管理,本来是想一个用户配置一个HDFS相关的账号,但是查看了FileSystem的api,感觉绑定的账号只能一个,针对不同的账号来回切换太麻烦了,所以就直接采用一个,然后使用管理员来更新;
3)系统还存在一些bug,比如文件查看,如果读取的数据编码格式有问题,那么也是显示不出来的,同时前台没有任何提示;
4)目录检索功能还可以把目录新增、目录删除、文件查看等功能进行整合,全部放到一个页面;
5)文件上传的进度条并不是真实反映上传进度的(这个上传受限于HDFS的相关API,并没有获取上传进度的API供参考调用);







已有(3)人评论

跳转到指定楼层
小伙425 发表于 2016-6-6 09:09:21
不错不错 学习了
回复

使用道具 举报

NIITYZU 发表于 2016-6-6 17:10:30
你好,请问一下,你这边是不是向Hadoop集群发送Hadoop 指令达到页面化管理的目的?
回复

使用道具 举报

975616465 发表于 2016-7-7 09:53:05
能不能把用到的jar包也共享下啊,部署后老报错,估计ssh的jar包版本不对
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条