福州大学软件工程实践个人编程作业
| 这个作业属于哪个课程 | 软件工程 https://edu.cnblogs.com/campus/fzu/SE2020 |
|---|---|
| 这个作业要求在哪里 | https://edu.cnblogs.com/campus/fzu/SE2020/homework/11167 |
| 这个作业的目标 | 对第一次个人编程作业进行总结 |
| 学号 | 081800216 |
| 使用语言 | Java |
一、PSP表格
| PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| Planning | 计划 | ||
| Estimate | 估计这个任务需要多少时间 | 15 | 20 |
| Development | 开发 | ||
| Analysis | 需求分析 (包括学习新技术) | 360 | 360 |
| Design Spec | 生成设计文档 | 30 | 30 |
| Design Review | 设计复审 | 30 | 30 |
| Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 60 | 60 |
| Design | 具体设计 | 120 | 120 |
| Coding | 具体编码 | 480 | 600 |
| Code Review | 代码复审 | 120 | 140 |
| Test | 测试(自我测试,修改代码,提交修改) | 120 | 180 |
| Reporting | 报告 | ||
| Test Report | 测试报告 | 25 | 30 |
| Size Measurement | 计算工作量 | 25 | 30 |
| Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 120 | 360 |
| 合计 | 1505 | 1960 |
二、解题思路描述
-
刚看到题目是一脸懵逼的(转专业过来的哪里见过这场面),慢慢读懂题意后大概明白是要对一个 JSON 文件进行处理,记录需要的4种信息类型,并计数输出。
-
既然是对 JSON 文件进行处理,但是又不懂 JSON 是啥于是就去各大网站上(CSDN、菜鸟教程等)找相关资料。稍微了解了一下 JSON 文件大概就是一个 key-value 的集合(大概)
-
在大致了解了 JSON 之后,就有了初步思路,就是决定用同样是 key-value 的 Map 容器来存放我需要的信息。在这之前最关键的就是 Java 如何处理 JSON 文件。
-
在着手开始敲代码之前有两个重要的问题要解决:
-
Java 如何处理文件(读、写等)
-
Java 如何对 JSON 文件进行处理
-
-
再查询各种资料,以及问了问大佬(这个是最关键的)之后,找到了一个由阿里提供的一个 Java 库:
Fastjson,来处理 JSON 文件。用FileUtiles工具类对文件进行读写。 -
然后对
Fastjson和FileUtiles一顿学习之后(指看博客)就开始敲代码。大致思路就是建立3个 Map 用于存储需要的类型和值,然后输出 Map -> JSON 文件,然后根据不同的命令在不同的 JSON 文件中查找。
三、设计实现过程
代码组织以及关键函数
Main 类
以下是对 Main 类中函数的说明
-
main:处理命令行输入的指令,调用不同的函数 -
JSONFilesToMap:对 JSOM 文件进行处理,存入3个 Map 容器中 -
OutputFile: 将 Map 文件输出成 JSON 文件 -
getDifferentEvents: 进行不同事件的计数 -
findInType1、findInType2、findInType3:分别是根据不同的命令在 3 个不同的 JSON 文件中查找需要的值
readFile 类
readLines : 读一个文件夹下的所有 JSON 的路径并将路径存入 List<String>中
numOfEvent 类
其中有 4 个属性值,分别用于记录对应的 4 种事件
关键函数流程图
JSONFilesToMap函数

四、代码说明
main 函数
public static void main(String[] args) {
if (args.length > 0) { // 如果输入为空则什么也不执行
if (args[0].equals("--init") || args[0].equals("-i")) {
JSONFilesToMap(args[1]);// args[1]是文件夹路径,调用此函数输出 3 个JSON文件这样就不用每次都遍历处理原 JSON 文件,而是通过查找输出的,整理过的 JSON 文件来获得对应的值
//以下是分别对应 3 个命令的查询判断
} else if (args[0].equals("--user") || args[0].equals("-u")) {
String userName = args[1];
if (args[2].equals("--event") || args[2].equals("-e")) {
String event = args[3];
event = event.substring(0, 1).toLowerCase() + event.substring(1); // 将事件单词的首字母转化成小写,否则无法查询
findInType1(userName, event);
} else {
String repoName = args[3];
String event = args[5];
event = event.substring(0, 1).toLowerCase() + event.substring(1);
findInType3(userName + repoName, event);
} } else {
String repoName = args[1];
String event = args[3];
event = event.substring(0, 1).toLowerCase() + event.substring(1);
findInType2(repoName, event);
}
}
JSONFilesToMap 函数
public static void JSONFilesToMap(String path) {
//定义3个 Map 容器,其中 numOfEvent 是自己定义的类,其中的属性值是 4 个事件的值
Map<String, numOfEvent> type1 = new HashMap<String, numOfEvent>();
Map<String, numOfEvent> type2 = new HashMap<String, numOfEvent>();
Map<String, numOfEvent> type3 = new HashMap<String, numOfEvent>();
List<File> fileList = (List<File>) FileUtils.listFiles(new File(path), new String[]{"json"}, true);//获得文件路径
fileList.forEach(readFile::readLines);
//遍历同一个文件夹下所有 JSON 文件
for (File filePath : fileList) {
List<String> list = null;
try {
list = FileUtils.readLines(filePath, "UTF-8");//将 JSON 文件按行读取并存入 List<String>list 中
} catch (IOException e) {
e.printStackTrace();
}
for (String str : Objects.requireNonNull(list)) {
// 3 个不同的 JSON 对象分别对应不同的要求
JSONObject obj = JSON.parseObject(str);
JSONObject user = obj.getJSONObject("actor");
JSONObject repo = obj.getJSONObject("repo");
String event = obj.getString("type");//事件名
String userName = user.getString("login");
String repoName = repo.getString("name");
String userAndRepoName = userName + repoName;//简单的将用户名和事件名拼接在一起当做第三个 Map 的 Key 值,用于唯一确定一个用户在一个项目中的事件
// 将需要的内容存入 Map
numOfEvent input1 = new numOfEvent();
numOfEvent input2 = new numOfEvent();
numOfEvent input3 = new numOfEvent();
if (type1.get(userName) != null)
input1 = type1.get(userName);
getDifferentEvents(input1, event);
type1.put(userName, input1);
if (type2.get(repoName) != null)
input2 = type2.get(repoName);
getDifferentEvents(input2, event);
type2.put(repoName, input2);
if (type3.get(userAndRepoName) != null)
input3 = type3.get(userAndRepoName);
getDifferentEvents(input3, event);
type3.put(userAndRepoName, input3);
}
}
//调用 OutputFile 函数将 3 个 Map 输出成 JSON 文件
OutputFile(type1, type2, type3);
}
五、困难描述
1. 不会用 Git 以及对 GitHub 不熟悉
解决办法:菜就去学嘛,看了助教在 B 站发的教学视频,自己再去找了些博客学习了一下。大概学会了如何使用 Git,以及对 GitHub 有了更多的了解,明白了什么是 fork,pr,不再是之前只会建个仓库的水平了哈哈哈。
2. 对 Java 语法不熟悉
Java 是在暑假入的门,只看了一些基础语法。后续被期末考复习打断了,加上练习又比较的少,所以忘了很多,但是想好好学下去。于是就打算边用 Java 完成这次作业边学习。
解决办法:看书+百度+别人写的博客+记笔记。前期多花了一些时间。
3. IDEA 使用 gradle 进行 build 时候报错
报错内容:Cause: zip END header not found
百度了一下大概是网络问题导致下载 gradle 的 zip 包时出了问题(大概
解决办法:
-
打开 IDEA 的设置,在搜索框输入 Gradle,如图

-
找到文件目录,打开 Gradle 的本地目录,删除本地文件,重新打开 IDEA 重新下载即可。(当然网络差的话还可能失败,暂时没有找到别的解决办法,可能得自己去找国内镜像下载配置?)
4. 不会文件操作
解决办法:查找资料,可以用 FileUtiles 工具类来简化文件操作。包括如何读取一个文件夹下的所有 JSON 文件,这个也是找了好久才明白如何去写。
5. 不会处理 JSON 文件
解决办法:查找资料,发现可以用 Fastjson 对其进行处理。
6. 无法导入 Fastjson 的 JAR 包和 commons-io 的 JAR 包
解决办法:打开 IDEA 的项目结构选项,并导入存放 JAR 的文件目录即可
这个是一开始我的解决方法,确实在本地上是可行的。但是 push 到仓库代码会报错,有更好的解决办法,具体在下一条说明。
7. push 到 GitHub 上显示包不存在

根据上一条所说,一开始导入的包只在本地上存在,仓库上是没有的,自然会显示不存在。
解决办法:找到项目文件夹中的 build.gradle 文件,添加包的依赖,如下:
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'
}
顺便说一下代码中读文件的操作是不能把自己电脑的本地路径写上去的,不然也会报错。可以通过定义一个字符串变量来代替
8. 如何打包成 jar 包并用命令行方式执行
大概敲完代码能实现基本的功能之后,发现自己根本不知道如何用命令行方式运行,也没有对其做处理。
解决办法:
-
首先重写 Main.java 使用函数封装主要功能。到这一步我才知道
public static void main(String[] args)
main 函数的参数 String[] args 就是从命令行输入的命令
-
对 args 进行判断,分别调用不同的函数
-
基本编码处理完就要将项目打包成 jar 包,具体方法是:
-
在项目文件夹下打开终端,输入 gradle shadowjar

如果成功了应该如上图所示 我之前也是一直构建不成功,原因在上一条,要在 build.gradle 里添加依赖
-
接着 cd 进 build\libs 发现有个 jar 包,就是我们打包的结果
-
在这个目录下就可以使用命令行进行一些操作了。
9. 从 Map 写入 JSON 文件失败
因为如果每次命令行调用一次都要遍历一波 JSON 文件肯定是非常耗时的,所以要在第一次调用的时候输出 3 个处理好的 JSON 文件,然后后续只要查询这 3 个就可以了。但是问题也随之而来,Map 转成 String 之后写入 JSON 文件,得到的JSON 文件中有些数据丢失了。只有 Map 的 key 值,并没有 value 值。
解决办法:因为我的 Map 是这样定义的
Map<String, numOfEvent> type1 = new HashMap<String, numOfEvent>();
其中这个 numOfEvent 是我自己写的类,但是我在类中没有 写 set,get 方法,以及实现serializable接口。自然就导致转化成 String 这一步就出问题了。只要在类中把缺的补上就可以了。
10. 命令行运行全部输出的都是null
这个 bug 我找了半天才发现,输出的 JSON 文件事件首字母都是小写

比如事件名应该是 PushEvent,但是输出却变成了 pushEvent ,这个原因我到现在也不明白,但是知道原因就好解决了。
解决办法:简单粗暴的将输入的 event 的首字母变成小写不就完了。
然后写这个总结的时候我突然想到,Java 不是有个字符串比较是可以忽略大小写的嘛!

11. 由于新语法问题,上传到仓库又失败了
在我信心满满调试完之后,准备上传到 GitHub 然后收获一个从来没拿到过的绿勾,然后又又又又又报错了。

认真看了下好像我用的 switch 语法是 Java12 的新特性,在上面跑不了?(大概
解决办法:于是我就改了回之前的 switch 语法。

然后一切就好起来了!!

写在最后
以上就是我这次编程作业遇到的一些问题啦,当然肯定不止这些,有些细碎的我就没有记录了。毕竟一开始我连 Java 语法都不太熟悉。
六、结果演示

七、代码规范链接
https://github.com/LiskarmW/2020-personal-java/blob/master/codestyle.md
八、总结

浙公网安备 33010602011771号