软件工程实践第二次作业

221900228_叶小杰 学生 2022-03-01 21:35:18
这个作业属于哪个课程 2022年福大-软件工程;软件工程实践-W班
这个作业要求在哪里 软件工程实践第二次作业——个人实战
这个作业的目标读写文件
网页爬取
json解析
cmd运行
单元测试
性能测试与改进
其他参考文献Maven镜像(下载jar包用的)

本次作业的爬虫行为仅用于教学,并无恶意


目录

  • Gitcode项目地址
  • PSP表格
  • 解题思路描述
  • 1、如何实现cmd命令中的输入输出?
  • 2、如何对input文件进行判断区分?
  • 3、如何实现对Json数据的获取和解析?
  • 接口设计和实现过程
  • 1、接口设计
  • 2、实现过程
  • 关键代码展示
  • 1、指令获取与判断
  • 2、指令执行
  • 3、网络数据获取
  • 性能改进
  • 1、改进方法
  • 2、改进效果
  • 单元测试
  • 异常处理
  • 心得体会


Gitcode项目地址

地址:PersonalProject-Java


PSP表格

PSPPersonal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划
• Estimate• 估计这个任务需要多少时间1010
Development开发
• Analysis• 需求分析 (包括学习新技术)180240
• Design Spec• 生成设计文档3020
• Design Review• 设计复审2020
• Coding Standard• 代码规范 (为目前的开发制定合适的规范)2030
• Design• 具体设计3030
• Coding• 具体编码300420
• Code Review• 代码复审30180
• Test• 测试(自我测试,修改代码,提交修改)30120
Reporting报告
• Test Repor• 测试报告2030
• Size Measurement• 计算工作量1010
• Postmortem & Process Improvement Plan• 事后总结, 并提出过程改进计划2020
合计7001130

本次作业实际用时与预期不符主要在于需求的变化导致分析时间增长、编码时间的增长,除此之外代码复审和测试也是比预期高,主要原因在于自己是第一次接触实际开发的测试。

解题思路描述

1、如何实现cmd命令中的输入输出?

自己平时都是使用idea运行java项目,这次突然说要cmd就能运行,原以为就在命令台中使用cd跳到对应的目录下再使用命令java+java文件名+参数启动入口类或者使用编译+运行指令就能运行,结果遇到了不少的问题。

最主要的问题还是下面这种情况:

找不到程序包

在同学和助教的帮助下也知道了解决方法:
1、首先将项目生成为jar包。idea生成并导出jar包的方法
2、找到自己项目的jar包位置。
3、用指令运行jar包。
最终效果如图:

输出符合预期

2、如何对input文件进行判断区分?

首先想到的是split截取每一行的指令,再对每一行再分别用split进行截取每一个空格隔开的字符,然后对各类可能的输出进行分类判断。
1、无输出,跳过
2、输出奖牌榜
3、输出对应日期的赛程
4、输出N/A
5、输出Error

这里的区分需要

3、如何实现对Json数据的获取和解析?

(1)先去冬奥网址查看可以发起请求的地址,copy过来后再对条件判断修改实现自定义条件
去官网后按f12或者右键--->‘检查’;然后点击‘网络’,找到对应的地址

在这里插入图片描述

(2)再调用请求的方法获取Json数据
(3)再对Json数据进行解析(需要导包)即可


接口设计和实现过程

1、接口设计

(1)数据模块

通过data软件包存放数据模块,目前仅含Information接口,便于数据(如网页爬取的地址)的存放与重复使用的。

(2)功能模块

Lib类,用于存放各个单一功能的函数

(3)对象模块

通过models软件包存放各个类对象,目前含CountryInfo类和MatchInfor类,方便Json解析后对数据的输入输出

2、实现过程

(1)入口类OlympicSearch

函数功能
executeInput处理输入指令跳转到对应接口

(2)功能类Lib

函数功能
getTotalContent根据json数据获取返回total数据
getScheduleContent根据json数据获取返回schedule数据
getNetTotal获取网址内部数据并封装返回json对应的String数据
readFile、writeFile读取、写入文件
isRightDate判断字符串是否为0202~0215

(3)对象类
|函数| 功能|
|--|--|
| CountryInfo | 参数为Json对象,获取json对象内部中自己需要的属性|
|getCountryInfos|根据要求格式获取内容|


关键代码展示

1、指令获取与判断

情况处理
空行无输出,跳过
1、total写入奖牌榜
2、schedule+有效日期写入对应日期的赛程
3、schedule+无效日期
schedule+...(...代表两个及以上)
写入N/A
4、其他写入Error
public static ArrayList<String> executeInput(String inputCmd, String toFile) {
        ArrayList<String> cmdList=new ArrayList<>();//有效的指令
        String[] cmds=inputCmd.split("\n");//获取cmd指令
        Lib.writeFile("",toFile,false);//文件清空
        for (String oneCmd:cmds) {
            String[] oneCmdInfo=oneCmd.split(" ");
            //判断指令、执行指令
            if (oneCmdInfo.length==1) {
                if (oneCmdInfo[0].equals("total")) { //情况1:total,输出
                    ...
                }
                else if (oneCmdInfo[0].equals("schedule")){//情况3: N/A
                   ...
                }
                else if (!oneCmdInfo[0].equals("")) //非法,Error
                   ...
            }
            else
                if (oneCmdInfo[0].equals("schedule")) {
                    if (!Lib.isRightDate(oneCmdInfo[1])||oneCmdInfo.length!=2) //情况2:schedule ****不存在
                       ...
                    else {//情况3:schedule ****存在
                      ...
                    }
                }
                else ...//非法,Error
        }
        return cmdList;
    }

2、指令执行

   //对有效指令进行处理
    public static void dealWithCmd(ArrayList<String> cmdList,String toFile){
        for (int i=0;i<cmdList.size();i++){
            String writeData,rightCmd=cmdList.get(i);
            if (dataMap.containsKey(rightCmd)) writeData=dataMap.get(rightCmd);
            else {
                if (rightCmd.equals("total")) {
                    String jsoncontent=Lib.getNetResponse(TOTAL_ADDRESS);
                    writeData=Lib.getTotalContent(jsoncontent);
                    dataMap.put(rightCmd,writeData);
                }else if(rightCmd.equals("Error"))
                    writeData=ERROR_INFO;
                else if(rightCmd.equals("NA"))
                    writeData=NA_INFO;
                else {
                    String jsoncontent=Lib.getNetResponse(SCHEDULE_ADDRESS.replace("mmdd",rightCmd));
                    System.out.println(rightCmd);
                    writeData=Lib.getScheduleContent(jsoncontent);
                    dataMap.put(rightCmd,writeData);
                }
            }
            if (i==cmdList.size()-1)
                Lib.writeFile(writeData,toFile,true);
            else Lib.writeFile(writeData+"\n",toFile,true);
        }
    }

3、网络数据获取

情况处理
错误地址输出“Error:Something wrong with function getNetResponse().”
返回码非200输出“The request has been rejected.”
返回码200处理返回值后返回对应的json字符串
public static String getNetResponse(String address) {
        ...
        try {
            //发送请求
            URL url=new URL(address);
            HttpURLConnection httpUrl=(HttpURLConnection)url.openConnection();
            //System.out.println(httpUrl.getResponseCode());
            if (httpUrl.getResponseCode()==200){
                //获取流
                InputStream is=httpUrl.getInputStream();
                //utf-8字符转换
                BufferedReader br=new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
                String line;
                while ((line=br.readLine())!= null)
                    sb.append(line);
                //结束、关闭
                is.close();
                br.close();
                //处理返回值
                ...
                   ...
            }else {
                System.out.println("The request has been rejected.");
            }
        }catch (IOException e){
            e.printStackTrace();
        }
        //处理返回值
        ...
        ...

性能改进

1、改进方法

影响性能因素改进方法
每次获取信息都要向网站发起一次请求,速度较慢创建一个Map,每次获取指令对应内容的时候判断是否存过对应数据,若有直接读取,若无则发起请求获取数据再存入Map

2、改进效果

使用JProfiler进行性能分析

原方法:
运行一万次的两个指令(total和schedule 0220)运行了2分54秒左右

在这里插入图片描述

使用map存放已经获取过的数据改进后:
只运行了13秒左右,不过有一点不剩很清楚的就是内存占用高了一点点而已,可能是因为原来占用率本就高的问题??

在这里插入图片描述

带着疑惑检查了下,发现map占用内存比确实不高(但不懂为什么...)

在这里插入图片描述


单元测试

个人感觉本次作业覆盖率不高的原因有以下:
1、写入无法执行到的语句
2、测试的时候没测全面

其中测试没测全主要是网页请求没测到200返回码之外的情况:

在这里插入图片描述

由于一开始不会伪造网页请求200之外的返回值,导致有些语句无法执行,选择上图中的if...else...判断删除直接执行if内部语句即可达到100%(但是这样不太好)

在这里插入图片描述

后来经过不断测试后发现这样可以返回404添加了这个地址的测试

在这里插入图片描述

添加了新测试后完成单元测试
覆盖率(第二张是因为测试的时候发现有新要求后又修改了点代码):

在这里插入图片描述


在这里插入图片描述

测试结果:

img


异常处理

异常处理
主函数参数个数错误输出"Error:Something wrong with args."
读取错误文件输出"Error:Something wrong with function readFile()."
写入错误文件输出"Error:Something wrong with function writeFile()."
网络请求返回码非200"The request has been rejected."
网络请求地址无效输出"Error:Something wrong with function getNetResponse()."

心得体会

在程序设计和实现的时候往往不是一个要求执行到底,本次作业就出现了需求的不断完善的过程,实实在在体会到了什么是乙方也在对照需求的过程中不断修正自己的代码 。
第一次接触单元测试,也通过这个单元测试修正了不少的bug
第一次接触性能测试,以前写程序代码的时候很少考虑性能,考虑性能的时候一般是写算法题的时候
本次作业顺便巩固了下java的相关知识(小组前端人员,后端最近比较少学习)


...全文
357 回复 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

142

社区成员

发帖
与我相关
我的任务
社区描述
2022年福大-软件工程;软件工程实践-W班
软件工程 高校
社区管理员
  • FZU_SE_teacherW
  • 丝雨_xrc
  • Lyu-
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧