软件工程实践第二次作业——个人实战

221900312黄子龙 学生 2022-03-05 12:49:54
这个作业属于哪个课程2022软工实践-W班
这个作业要求在哪里软件工程实践第二次作业——个人实战
这个作业的目标完成对冬奥会的赛事数据的收集,并实现一个能够对国家排名及奖牌个数统计的控制台程序。
其他参考文献

目录

  • Gitcode项目地址
  • PSP表格
  • 解题思路描述
  • 问题1:对冬奥会的赛事数据的收集(该爬取行为仅用于学习)
  • 问题2 :如何输出排行榜和每日日赛程
  • 接口设计和实现过程
  • 关键代码展示
  • 性能改进
  • 单元测试
  • 异常处理
  • 心得体会

Gitcode项目地址

仓库地址

PSP表格

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

解题思路描述

问题1:对冬奥会的赛事数据的收集(该爬取行为仅用于学习)

发起http请求数据的JSON格式接口进行获取。

步骤:发送请求,请求后台的JS文件或某些接口来返回数据。
查看调试工具的控制台,看是否有日志输出。
通过浏览器审查元素可以看到里面包含了文章表体以及链接地址,知道了这些就可以利用API接口来帮我们完成解析了,截图如下

img

img

img

发送get请求获取后台数据,其中,将返回回来的字符串解析成json对象用到了google的Gson.jar包,用到了其中JsonParser的parse方法。代码截图如下

img

参考资料:
java发起http请求获取返回的Json对象
2018年俄罗斯世界杯之Java数据爬虫(一)
java发送http的get、post请求

问题2 :如何输出排行榜和每日日赛程

用到java.io.BufferedReader和java.io.BufferedWriter类来读写文件。
输出排行榜到txt:Show_Total();{接受输入的文件名,读取对应json文件后,然后写入output.txt}
输出每日日赛程到txt:Show_Day();{接受输入的文件名,读取对应json文件后,然后写入output.txt}

接口设计和实现过程

接口设计

Lib.java:主要处理输入指令是否正确,判断日期和处理字符串数据等。具体有 :
      outFile():接收input文件名输出output文件
      cleanOutput():写文件时先将原内容清空
      isRightDay():判断日期是否合法
      isRightFirst():判断指令是否合法
      checkPathSpaces():处理绝对路径可能存在空格的情况
      cleanLine():去除输出txt末尾换行字符

TotalData.java:输出总榜功能。具体有 :
/**
* 存排行榜数据到指定的txt文件
*
* @param filename txt文件名
*/
public static void Show_Total(String filename, Map<String,String> map)

DayData.java:输出赛程功能。具体有 :
/**
* 存某日赛程数据到指定的txt文件
*
* @param s 日期
* @param filename txt文件名
*/
public static void Show_Day(String s, String filename, Map<String,String> map)

OlympicSearch.java:程序入口,读取命令行参数,为OlympicDataSet类提供命令行参数

流程图:

img

关键代码展示

/**
 * 存某日赛程数据到指定的txt文件
 *
 * @param s        日期
 * @param filename txt文件名
 */
 public static void showDay(String s, String filename, Map<String, String> map) {

        try {
            File f = new File(filename);
            OutputStreamWriter write = new OutputStreamWriter(new FileOutputStream(f, true), "utf-8");
            BufferedWriter bw = new BufferedWriter(write);
            //判断map对象是否缓存,若有直接读map中的数据。没有就读json文件并存到map。
            if (!map.containsKey(s)) {
                StringBuffer stringBuffer = new StringBuffer();
                JsonParser jsonParser = new JsonParser();
                JsonObject jsonObject = (JsonObject) jsonParser.parse(new FileReader("src/data/schedule/" + s + ".json"));
                JsonArray jsonObject2 = jsonObject.get("matchList").getAsJsonArray();
                //stringBuffer循环追加字符串
                for (int i = 0; i < jsonObject2.size(); i++) {
                    JsonObject jsonObject1 = jsonObject2.get(i).getAsJsonObject();
                    stringBuffer.append("time:" + jsonObject1.get("startdatecn").getAsString().substring(11, 16) + "\n");
                    stringBuffer.append("sport:" + jsonObject1.get("itemcodename").getAsString() + "\n");
                    if (jsonObject1.get("homename").getAsString().equals("")) {
                        stringBuffer.append("name:" + jsonObject1.get("title").getAsString() + "\n");
                    } else {
                        stringBuffer.append("name:" + jsonObject1.get("title").getAsString() + " " + jsonObject1.get("homename").getAsString() + "VS" + jsonObject1.get("awayname").getAsString() + "\n");
                    }
                    stringBuffer.append("venue:" + jsonObject1.get("venuename").getAsString() + "\n");
                    stringBuffer.append("-----" + "\n");
                }
                //写入文件和存到map
                bw.write(stringBuffer.toString());
                map.put(s, stringBuffer.toString());
                bw.close();
            } else {
                bw.write(map.get(s));
                bw.close();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

/**
     * 存排行榜数据到指定的txt文件
     *
     * @param filename txt文件名
     */
    public static void showTotal(String filename, Map<String, String> map) {

        try {
            File f = new File(filename);
            OutputStreamWriter write = new OutputStreamWriter(new FileOutputStream(f, true), "utf-8");
            BufferedWriter bw = new BufferedWriter(write);
            if (!map.containsKey("total")) {
                StringBuffer stringBuffer = new StringBuffer();
                JsonParser jsonParser = new JsonParser();
                JsonObject jsonObject = (JsonObject) jsonParser.parse(new FileReader("src/data/total.json"));
                JsonArray jsonObject2 = jsonObject.get("medalsList").getAsJsonArray();
                for (int i = 0; i < jsonObject2.size(); i++) {
                    JsonObject jsonObject1 = jsonObject2.get(i).getAsJsonObject();
                    bw.append("rank" + jsonObject1.get("rank").getAsInt() + ":" + jsonObject1.get("countryid").getAsString() + "\n");
                    bw.append("gold:" + jsonObject1.get("gold").getAsInt() + "\n");
                    bw.append("silver:" + jsonObject1.get("silver").getAsInt() + "\n");
                    bw.append("bronze:" + jsonObject1.get("bronze").getAsInt() + "\n");
                    bw.append("total:" + jsonObject1.get("count").getAsInt() + "\n");
                    bw.append("-----" + "\n");
                    bw.write(stringBuffer.toString());
                    map.put("total", stringBuffer.toString());
                }
                bw.close();
            } else {
                bw.write(map.get("total"));
                bw.close();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 判断日期是否合法
     *
     * @param s
     * @return
     */
    public static boolean isRightDay(String s) {
        if (s.length() != 4) {
            return false;
        } else {
            String s1 = s.substring(0, 1);
            String s2 = s.substring(1, 4);
            if (s1.equals("0")) {
                if (Integer.valueOf(s2) >= 202 && Integer.valueOf(s2) <= 220) {
                    return true;
                } else {
                    return false;
                }

            } else {
                return false;
            }
        }
    }
 /**
     * 判断指令是否合法
     *
     * @param s
     * @param filename 输出文件名
     * @return
     */
    public static boolean isRightFirst(String s, String filename) {
        String[] str = s.split("\\s+");
        //取第一个单词判断是否是正确指令
        if (str[0].equals("total") || str[0].equals("schedule")) {
            if (str[0].equals("total")) {
                return true;     //是正确total指令
            } else if (isRightDay(str[1])) {
                return true;     //是正确schedule指令
            } else {    //是正确schedule指令,但日期不正确,写入N/A
                try {
                    File f = new File(filename);
                    if (!f.exists()) {
                        f.createNewFile();
                    }
                    OutputStreamWriter write = new OutputStreamWriter(new FileOutputStream(f, true), "utf-8");
                    BufferedWriter bw = new BufferedWriter(write);
                    bw.write("N/A" + "\n");
                    bw.write("-----" + "\n");
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return false;
            }
        } else {   //不是正确指令,写入Error
            try {
                File f = new File(filename);
                if (!f.exists()) {
                    f.createNewFile();
                }
                OutputStreamWriter write = new OutputStreamWriter(new FileOutputStream(f, true), "utf-8");
                BufferedWriter bw = new BufferedWriter(write);
                bw.write("Error" + "\n");
                bw.write("-----" + "\n");
                bw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return false;
        }
    }
  /**
     * 处理input文件输出output文件
     *
     * @param in 输入文件名
     * @param ou 输出文件名
     */
    public static void outFile(String in, String ou, Map<String, String> map) {
        try {
            String s;
            LineNumberReader br = new LineNumberReader(new FileReader(in));
            //按行读取input.txt
            for (s = br.readLine(); s != null; s = br.readLine()) {
               s=s.trim();
                //若空白行跳过
                if ("".equals(s)) {
                    s = br.readLine();
                }
                if (isRightFirst(s, ou)) {  //判断指令正确与否
                    if (s.equals("total")) {
                        TotalData.showTotal(ou, map);  //执行总榜写入
                    } else {
                        String[] str = s.split("\\s+");
                        DayData.showDay(str[1], ou, map);  //执行赛程写入
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

性能改进

执行循环5000次
用下方计算程序运行耗时时间

    long startTime = System.currentTimeMillis();    //获取开始时间
    long endTime = System.currentTimeMillis();    //获取结束时间
    System.out.println("程序运行时间:" + (endTime - startTime) + "ms");    //输出程序运行时间

改进措施:用Map<String, String> map 来缓存已经写入的字符串,下次再写入时就不用再读json文件。
改进前截图:

img

img

改进后截图:

img

img

单元测试

 public void testMain() throws IOException {
        long startTime = System.currentTimeMillis();    //获取开始时间
        OlympicSearch.main(new String[]{"test/input.txt", "test/output.txt"});
        String s1, s2;
        s1 = Files.readString(Path.of("test/output.txt"));
        s2 = Files.readString(Path.of("test/2.txt"));
        assertEquals(s2, s1);
        long endTime = System.currentTimeMillis();    //获取结束时间
        System.out.println("程序运行时间:" + (endTime - startTime) + "ms");    //输出程序运行时间
    }

    public void testShowTotal() throws IOException {
        TotalData.showTotal("test/Total1.txt", new HashMap<>());
        String s1, s2;
        LineNumberReader br1 = new LineNumberReader(new FileReader("test/Total1.txt"));
        LineNumberReader br2 = new LineNumberReader(new FileReader("test/1.txt"));
        for (s1 = br1.readLine(), s2 = br2.readLine(); s1 != null && s2 != null; s1 = br1.readLine(), s2 = br2.readLine()) {
            assertEquals(s1, s2);
        }
    }

覆盖率:

img

异常处理

catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

心得体会

1.边查边写,效率很慢,列出若干问题,再去学习相关技术,会更快一点。
2.加深对Java的IO的掌握和流操作的基本规律:明确数据源和数据汇,目的是明确使用输入流还是输出流。明确操作的数据是否是纯文本数据。是否需要进行字节流和字符流的转换。是否需要使用缓存。
3.性能优化 用JProfiler做性能分析 ,用空间换时间的策略 ,来提高程序的运行速度

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

142

社区成员

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

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