这个作业属于哪个课程 福州大学软件工程实践个人编程作业https://edu.cnblogs.com/campus/fzu/SE2020
这个作业要求在哪里 https://edu.cnblogs.com/campus/fzu/SE2020/homework/11167
这个作业的目标 对于第一次编程作业的经验总结
学号 081800414
使用语言 Java

PSP 表格

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划
Estimate 估计这个任务需要多少时间 24h 35h
Development 开发
Analysis 需求分析 (包括学习新技术) 600 600
Design Spec 生成设计文档 20 20
Design Review 设计复审 30 30
Coding Standard 代码规范 (为目前的开发制定合适的规范) 30 30
Design 具体设计 40 70
Coding 具体编码 400 500
Code Review 代码复审 30 40
Test 测试(自我测试,修改代码,提交修改) 120 500
Reporting 报告
Test Report 测试报告 30 50
Size Measurement 计算工作量 40 40
Postmortem & Process Improvement Plan 事后总结, 并提出过程改进计划 100 240
合计 1440 2140

解题思路与学习历程描述

​ 拿到题的一瞬间是懵逼的,完全看不懂在说什么。又是大数据又是各种命令格式的,然后往下翻到样例代码看到又是Python的,尝试看了一下结果啥也没看懂...于是下载了示例数据,发现是一种json格式的文件。观察了文件的特征后,进行查阅了资料确认了该任务是对JSON的解析,通过关键词获取所要求的信息,并进行统计。最终决定用Java编写,于是漫长的写题之路开始了。

  • 在群里看到大佬们提到gradle,在拿到题的当天上网搜寻了gradle的内容,在网上下载了gradle并配置了环境变量(配置了好久....)

  • 打开了github,学习了助教给的github使用教程。fork 并git clone了Java的repo。

  • 继续了解gradle,一段时间后打开clone 的repo发现助教已经基本配置好了....

  • 由于Java的文件io操作不是很熟悉,上网查询后,学会使用BufferedReadrreadline方法,将JSON按行读入存在ArrayList中进行后续的解析。

  • 要解析JSON,于是上网搜寻了解析JSON相关的库,最终决定使用fastJSON,下载了Jar包,发现一直import不进去。于是搜寻资料,发现maven,

  • 搜寻maven资料,了解了本地仓库,中央仓库,远程仓库,maven外部依赖及搜索顺序,maven插件 ,顺便看了一下xml文件的语法。

  • 回到项目中,经过查询了解到在build.gradle中可以配置fastjson。

    dependencies {
        testCompile group: 'junit', name: 'junit', version: '4.12'
        compile group: 'commons-cli', name: 'commons-cli', version: '1.4'
        compile group: 'commons-io', name: 'commons-io', version: '2.7'
        compile group: 'com.alibaba', name: 'fastjson', version: '1.2.73'
    }
    
  • 配置完fastjson后开始进行解析的尝试,通过fastjson的库函数轻松地将JSON字符串转换为JSON对象,然后通过JSON对象 ,获取所需要的id与event名称

  • 开始思考数据怎么存放,经过查阅与咨询林璟大佬后决定用3个Map分别对应三种查询类型。创建class Result存储4种事件的计数。

  • 编写程序,获取actorlogin(user) 与reponame(项目)后, 思考第三种情况如何表示,决定用login+name 组成新字符串ID表示每个人在项目的情况。

  • 完善程序后开始尝试遍历3个Map检查是否正确,前几次运行样例前1000行JSON程序都正常。后截取了样例程序的1000-2000行数据,遇到程序运行错误,错误提示为fastJSON syntax error,百思不得其解后,选取部分样例数据并打断点测试,找到语法错误的一行后对其进行研究。上网搜索JSON标准格式与fastJSON API文档,后发现是fastJSON转换字符串过程中的转义符号作怪,于是编写justify方法,将JSON字符串进行截取,程序再次运行成功。

  • 成功输出了3种类型的ID的对应event的统计数量,计时已经过去了17个h

  • 隔天助教群里发出测试程序。通过python运行后得知正确的输出格式并得用命令行执行程序,对原程序进行返工修改。

  • 了解命令行的使用方法,编写main函数中对应的命令行判别程序。

  • Java 执行时得将程序打包成Jar文件。于是尝试进行打包,通过查阅资料,发现Artifacts可以进行打包,尝试多次后无果遂放弃。进一步查询发现gradle自带打包功能,于是重新进行gradle的了解了,知道了gradle的applyplugins两种插件,并知道Gradle 默认会从 src/main/java 搜寻打包源码,在 src/test/java 下搜寻测试源码。并且 src/main/resources 下的所有文件按都会被打包,所有 src/test/resources 下的文件 都会被添加到类路径用以执行测试。所有文件都输出到 build 下,打包的文件输出到 build/libs 下。同时了解到Java 插件添加了众多任务。但是它们只是在需要构建项目的时候才能发挥作用。最常用的就是 build 任务,这会构建整个项目。当执行 gradle build 时,Gralde 会编译并执行单元测试,并且将 src/main/* 下面 class 和资源文件打包。于是尝试用 命令 gradle build进行打包,结果出现Could not receive a message from daemon的情况。查询并略微了解了daemon后重新进行打包,打包成功。

  • 通过命令行运行jar文件,出现错误提示,fastJSON无法获取,以为是依赖配置有问题尝试多次无果后询问助教得知 gradle build打包的jar文件是不包含依赖的,只包含项目源码.正确的包含依赖依赖的打包是用 gradle shadowjar。查询资料了解之后重新尝试打包并运行成功。

  • 运行成功后发现init后执行下一条指令是失败的,资源被释放了。于是想办法将Map数组输出成并存储起来,并在查询时读入。尝试通过fastJSON转换为JSON对象,并转换为JSON字符串存储文件时发现,JSON字符串只有String部分,Result全为空白, 在群里询问大佬后,通过对Result的get与set方法补充,同时implements Serializable接口。成功进行Map转存JSON字符串并存储。

  • 在群里的聊天记录中得知文件读取为读取文件夹下的一系列文件,之前的文件读取方式无法进行,进行修改后成功。后查询资料后发现Apache commons io库进行文件读写特别方便,学习并配置后,通过FileUtilswriteStringToFile方法快速存储了输出的3个map的json文件。(工具类库是真好用啊^)

  • 对程序进行细节修改与多次debug后成功通过4条测试,Commit到Github上也成功运行,菜鸡终于把题完整的搞出来了。泪目。

设计实现过程

代码说明

justify方法

private static String justify(String s) {
        int cnt = 0;
        int index = -1;
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == '\"') {
                cnt++;
            }
            if (cnt == 40) {
                index = i;
                break;
            }
        }
        String ans = s.substring(0, index);
        ans = ans + "\"}}";

        return ans;
    }
//读入的JSON字符串“裁剪方法”
  • justify方法将读入的JSON字符串裁剪到我们所需要的信息的位置。为什么cnt=40?因为我对着样例的数据数的hhh

main

 //命令行读入与判别
public static void main(String[] args) throws IOException {
       
        String testUser = null, testEvent = null, testRepo = null, filename = null;
        //命令行读入并判断
        if (args.length != 0) {
            if (args[0].equals("--init") || args[0].equals("-i ")) {
                filename = args[1];
                init(filename);
            } else if (args[0].equals("-u") || args[0].equals("--user")) {
                if (args.length > 2) {
                    testUser = args[1];
                    if (args[2].equals("-e") || args[2].equals("--event")) {
                        testEvent = args[3];
                        countFromUser(testUser, testEvent);
                    } else if (args[2].equals("-r") || args[2].equals("repo")) {
                        testRepo = args[3];
                        testEvent = args[5];
                        countFromUserAndRepo(testUser + testRepo, testEvent);
                    }
                }
            } else if (args[0].equals("-r") || args[0].equals("--repo")) {
                testRepo = args[1];
                testEvent = args[3];
                countFromRepo(testRepo, testEvent);
            }
        }
    }
  • main 读入命令行参数并判别init与三种查询类型

init方法

private static void init(String fileName) throws IOException {
        ArrayList<String> jsonList = new ArrayList<>();
        File dir = new File(fileName);
        //读入文件列表转存JSON于jsonList中
        File[] files = dir.listFiles(file -> file.getName().endsWith(".json"));
        try {
            for (File jsonFile : files) {
                FileReader fileReader = new FileReader(jsonFile);
                BufferedReader bf = new BufferedReader(fileReader);
                String str;
                while ((str = bf.readLine()) != null) {
                    jsonList.add(str);
                }
                bf.close();
                fileReader.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        //遍历jsonList,进行统计
        for (int i = 0; i < jsonList.size(); i++) {
            //"裁剪“
            String tmp = jsonList.get(i);
            tmp = justify(tmp);
            //获取所需信息
            JSONObject jso1 = JSON.parseObject(tmp);
            String actor = jso1.getString("actor");
            JSONObject jso2 = JSON.parseObject(actor);
            String id = jso2.getString("login");

            String repo = jso1.getString("repo");
            JSONObject jso3 = JSON.parseObject(repo);
            String repoId = jso3.getString("name");
            //创建第三种查询的ID
            String idAndRepoId = id + repoId;
            //创建3种Result并插入对应的Map
            if (!map1.containsKey(id)) {
                map1.put(id, new Result());
            }
            if (!map2.containsKey(repoId)) {
                map2.put(repoId, new Result());
            }
            if (!map3.containsKey(idAndRepoId)) {
                map3.put(idAndRepoId, new Result());
            }
            Result res = map1.get(id);
            Result repoRes = map2.get(repoId);
            Result iAndRepoRes = map3.get(idAndRepoId);
            String event = jso1.getString("type");

            if (event.equals("PushEvent")) {
                res.PushEvent++;
                repoRes.PushEvent++;
                iAndRepoRes.PushEvent++;
            } else if (event.equals("IssueCommentEvent")) {
                res.IssuesEvent++;
                repoRes.IssuesEvent++;
                iAndRepoRes.IssuesEvent++;
            } else if (event.equals("PullRequestEvent")) {
                res.PullRequestEvent++;
                repoRes.PullRequestEvent++;
                iAndRepoRes.PullRequestEvent++;
            } else if (event.equals("IssuesEvent")) {
                res.IssuesEvent++;
                repoRes.IssuesEvent++;
                iAndRepoRes.IssuesEvent++;
            } else {
                continue;
            }
            map1.put(id, res);
            map2.put(repoId, repoRes);
            map3.put(idAndRepoId, iAndRepoRes);

        }

        //map转换为JSON String
        String s1 = JSONObject.toJSONString(map1);
        String s2 = JSONObject.toJSONString(map2);
        String s3 = JSONObject.toJSONString(map3);
        // 将json写入文件
        FileUtils.writeStringToFile(new File("map1.json"), s1, "UTF-8");
        FileUtils.writeStringToFile(new File("map2.json"), s2, "UTF-8");
        FileUtils.writeStringToFile(new File("map3.json"), s3, "UTF-8");
    }

查询方法(user)

public static void countFromUser(String user, String event) throws IOException {
    String tmp = event.substring(0, 1);
    tmp = tmp.toLowerCase();
    event = tmp + event.substring(1, event.length());
    String s = FileUtils.readFileToString(new File("map1.json"), "UTF-8");
    JSONObject jsonObject = JSONObject.parseObject(s);
    JSONObject object = jsonObject.getJSONObject(user);
    if (object != null) {
        System.out.println(object.getInteger(event));
    }
}
  • 读入对应map的json文件,将JSON字符串转JSON对象并获取对应key(user)的Result。

代码规范

https://github.com/Pikapika-sk/2020-personal-java/edit/master/Java代码规范-洪司坤.md

总结

对我来说真难

好几个下午+好几个晚上。写博客的时候发现原来在这个过程中学到了很多新知识,希望我下次需要用的时候还记得哈哈哈。

可以提高的地方:搞多线程和单元测试

 posted on 2020-09-15 23:43  NefelibataLLM  阅读(312)  评论(2编辑  收藏  举报