結對第二次作業——某次疫情統計可視化的實現


這個作業屬於哪個課程
https://edu.cnblogs.com/campus/fzu/2020SpringW/
這個作業要求在哪里
https://edu.cnblogs.com/campus/fzu/2020SpringW/homework/10456
結對學號
221701429 221701438
這個作業的目標
疫情統計可視化的原型
作業正文
....
其他參考文獻
....

一、Github 倉庫地址和代碼規范鏈接

二、成品演示

  • 地圖上方提供日歷,可以選取不同日期查看截止該日全國疫情情況
    conv_ops

  • 統計數據在地圖上方,只顯示到助教提供的靜態文件最后一個日期
    相同感染人數區間的省份可以通過左下方鼠標停留或點擊
    conv_ops

  • 全國疫情折線圖在地圖下方,可選擇顯示或隱藏確診,疑似,治愈,死亡四條折線
    折線上的點顯示當前日期的疫情數據
    conv_ops

  • 地圖上點擊不同省份會跳轉到該省份疫情數據的折線圖
    conv_ops

三、結對討論過程描述

  • 作業發布當天晚上,由於技術不足無法實現實時數據更新,我們決定用javeEE課上學的JSP框架和數據庫完成本次作業
    聊天1
    聊天2

四、描述設計實現過程

221701429-前端

  • 作業題目有提示用echarts設計圖表,就跟着學了echarts的教程,下載了文件,
在前端用jsp的方式實現頁面,在頁面中加入script,添加圖表,設置圖表的類型和參數,就能夠顯示出來了。
數據部分則是通過Servlet的http請求獲取的,把數據庫中的表的數據實例化成Province后,通過req.setAttribute的方式傳遞參數。
在地圖上設置了點擊事件,將params加到url上傳遞給Servlet判斷,點擊后跳轉到具體省份的疫情的功能就實現了。

前端

221701438-后端

  • 與前端交流后,確定我的主要任務是對log文件夾下的日志進行處理,再將日志中數據寫入數據庫,完善疫情數據的讀取和存儲。
結合之前所學,我將每個省份的疫情情況封裝在Province類,把助教提供的靜態日志內容讀取出來,存儲在ArrayList<Province>
再用正則匹配將每個省的疫情數據提取並寫入數據庫,然后完善數據庫的存取。

后端

五、關鍵代碼

  • Jsp頁面通過http請求獲得Servlet傳的數據,用div的方式顯示出來,在css中更改樣式使得四塊橫向排版。
<div id="virusSummary">
    <%
        int totalip = (int) request.getAttribute("totalip");
        int totalsp = (int) request.getAttribute("totalsp");
        int totalcure = (int) request.getAttribute("totalcure");
        int totaldead = (int) request.getAttribute("totaldead");
    %>
    <div id="ip">
        <div class="name">確診</div>
        <div class="data"><%=totalip%></div>
    </div>
    <div id="sp">
        <div class="name">疑似</div>
        <div class="data"><%=totalsp%></div>
    </div>
    <div id="cure">
        <div class="name">治愈</div>
        <div class="data"><%=totalcure%></div>
    </div>
    <div id="dead">
        <div class="name">死亡</div>
        <div class="data"><%=totaldead%></div>
    </div>
</div>
  • 這是用echarts實現疫情地圖的script,tooltip改變數據提示框的輸出格式,visualMap改變確診人數區間對應的顏色提示,series里data部分填入http請求得到的確診人數數據,然后顯示到地圖上。再添加一個function點擊事件,點擊省份后跳轉到該省份的疫情折線圖的頁面。
<div id="chinaMap"></div>
<script type="text/javascript">
    var myChart = echarts.init(document.getElementById('chinaMap'));
        myChart.setOption({
            // 數據提示框
            tooltip: {
                trigger: 'item', // item放到數據區域觸發
                formatter: '地區:{b}<br/>確診:{c}' // 提示數據格式br表示換行,地圖 : {a}(系列名稱),{b}(區域名稱),{c}(合並數值), {d}(無)
            },
            // 工具欄
            /*toolbox: {
                show: true,
                orient: 'horizontal',
                left: 'right',
                feature: {
                    dataView: {readOnly: false},
                    restore: {},
                    saveAsImage: {}
                }
            },*/

            // 使用透明度來區分疫情嚴重情況
            visualMap: {
                type: 'piecewise',
                pieces: [
                    {gt: 1500, color: 'darkred'},
                    {gt: 1000, lte: 1500, color: 'red', colorAlpha: 1},
                    {gt: 500, lte: 1000, color: 'red', colorAlpha: 0.8},
                    {gt: 300, lte: 500, color: 'red', colorAlpha: 0.6},
                    {gt: 100, lte: 300, color: 'red', colorAlpha: 0.4},
                    {gt: 50, lte: 100, color: 'red', colorAlpha: 0.3},
                    {gt: 0, lte: 50, color: 'red', colorAlpha: 0.2},
                    {lte: 0, color: 'white'}
                ],
            },


            // 具體數據
            series: [
                {
                    name: '各省確診病例', // 系列名稱
                    type: 'map', // 系列類型,地圖
                    map: 'china', // 要使用的地圖,即上面注冊的地圖名稱
                    //roam: true, // 開啟鼠標縮放和平移漫游
                    label: { // 圖形上的文本標簽,地圖默認顯示數據名
                        show: true,
                        formatter: '{b}', // b是數據名,c是數據值
                        fontSize: 12
                    },
                    data:[
                        <%
                        int Ip;
                        for(int i = 0; i < ProvinceName.provinceSize; i++){
                            //ip = 0;
                            Ip = (int) request.getAttribute(ProvinceName.provinceName[i] + "Ip");
                        %>
                        {name: "<%=ProvinceName.provinceName[i]%>", value: "<%=Ip%>"},
                        <%}%>
                    ]
                }
            ]
        });

    //點擊省份后跳轉到具體疫情的頁面
    myChart.on("click",function (params) {
        window.location.href = "Servlet?flag=2&name="+params.name;
    },true)
</script>
  • 該部分顯示的是全國四種人數的折線圖,用echarts定制的折線圖樣式,將獲取的日期作為xAxis的數據、四種人數作為每個點的值,實現折線圖。點擊省份進入具體頁面的折線圖與之類似。
<div id="lineChart" style="width: 800px;height:400px; position: center; background-color: #ffffff; padding-top: 40px"></div>
<script type="text/javascript">

    var name = "全國";
    // 基於准備好的dom,初始化echarts實例
    var Chart = echarts.init(document.getElementById('lineChart'),'infographic');

    Chart.setOption({
        //設置標題
        title: {
            text: name + '疫情趨勢'
        },
        //數據提示框
        tooltip: {
            trigger: 'axis',
        },
        legend: {
            data: ['確診','疑似','治愈','死亡']
        },
        xAxis: {
            data:[<%
              List<Province> country = (List<Province>) request.getAttribute("country");
              String date;
              int ip,totalIp = 0;
              int sp,totalSp = 0;
              int cure,totalCure = 0;
              int dead,totalDead = 0;
              for(Province province : country){
                  date = province.getDate();
              %>
                "<%=date%>",
                <%}%>]
        },
        yAxis: {},
        series: [
            {
                name: '確診',
                type: 'line',
                data:[<%
                  for(Province province : country){
                      ip = province.getIp();
                      totalIp += ip;
                  %>
                    <%=totalIp%>,
                    <%}%>]
            },
            {
                name: '疑似',
                type: 'line',
                data:[<%
                  for(Province province : country){
                      sp = province.getSp();
                      totalSp += sp;
                  %>
                    <%=totalSp%>,
                    <%}%>]
            },
            {
                name: '治愈',
                type: 'line',
                data:[<%
                  for(Province province : country){
                      cure = province.getCure();
                      totalCure += cure;
                  %>
                    <%=totalCure%>,
                    <%}%>]
            },
            {
                name: '死亡',
                type: 'line',
                data:[<%
                  for(Province province : country){
                      dead = province.getDead();
                      totalDead += dead;
                  %>
                    <%=totalDead%>,
                    <%}%>]
            }
        ]
    },true)
</script>
  • Servlet控制前后端數據交互,調用對象類實例化,將參數通過http請求發送給下一個頁面,通過url附帶參數的形式,在Servlet中獲取參數並判斷選擇進入的頁面。
String flag = req.getParameter("flag");
ProvinceDAO provinceDAO =new ProvinceDAOImpl();
//flag=2時跳轉到第二個頁面
if(flag != null && flag.equals("2")){
    String name = req.getParameter("name");
    provinceDAO =new ProvinceDAOImpl();
    List<Province> local = provinceDAO.list(name,true);//獲取當地每天數據
    int ip = 0,sp = 0,cure = 0,dead = 0;
    //累加當地每天的數據
    for (Province province : local) {
        ip += province.getIp();
        sp += province.getSp();
        cure += province.getCure();
        dead += province.getDead();
    }
    req.setAttribute("name",name);
    req.setAttribute("totalip",ip);
    req.setAttribute("totalsp",sp);
    req.setAttribute("totalcure",cure);
    req.setAttribute("totaldead",dead);
    req.setAttribute("local",local);
    req.getRequestDispatcher("concreteInfectStatistic.jsp").forward(req,resp);
}
//否則跳轉到第一個頁面
else{
    provinceDAO =new ProvinceDAOImpl();
    List<Province> country = provinceDAO.list("全國",true);//獲取全國每天數據
    //List<Province> all = provinceDAO.list();//獲取各省份每天的數據
    int ip = 0,sp = 0,cure = 0,dead = 0;
    //累加全國每天的數據
    for (Province province : country) {
        ip += province.getIp();
        sp += province.getSp();
        cure += province.getCure();
        dead += province.getDead();
    }

    String name;
    int eachIp;
    //查找每個省份的每天的確診數據累加到一個數值上
    for(int i = 0; i < ProvinceName.provinceSize; i++) {
        name = ProvinceName.provinceName[i];
        eachIp = 0;
        List<Province> each = provinceDAO.list(name, true);//按省份名獲取省份每天數據
        for(Province province : each){
            eachIp += province.getIp();
        }
        req.setAttribute(name+"Ip",eachIp);
    }
    req.setAttribute("totalip",ip);
    req.setAttribute("totalsp",sp);
    req.setAttribute("totalcure",cure);
    req.setAttribute("totaldead",dead);
    req.setAttribute("country",country);


    req.getRequestDispatcher("chinaMap.jsp").forward(req,resp);
}
  • 讀取目錄下指定日期前的所有日志內容
 public static String[] readFile(String path,String date) throws ParseException, IOException {
        List allFilePath = getFileName(path,date);
        String[] allContent = new String[allFilePath.size()];
        for (int i = 0; i < allFilePath.size(); i++){
            File file = new File(String.valueOf(allFilePath.get(i)));
            StringBuilder result = new StringBuilder();
            // 構造一個BufferedReader類來讀取文件
            BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file),"UTF-8"));
            String s;
            // 使用readLine方法,一次讀一行,並忽略注釋行
            while ((s = br.readLine()) != null && !s.startsWith("//")) {
                result.append(System.lineSeparator() + s);
            }
            br.close();
            allContent[i] = result.toString();
        }
        return allContent;
    }
  • 將正則匹配處理完的數據填入數據庫
 public static void connectMysql() throws IOException, ParseException {
        for (int i=0; i<date.length; i++){
            String[] allContent = readFile("src/infectstatistic/log",date[i]);
            ArrayList<Province> province = RegularMatch.match(allContent);
            ListAdd(province, date[i]);
        }
    }

六、《構建之法閱讀心得》、心路歷程和收獲及對隊友的評價

閱讀心得

  • 構建之法第四章提到兩人合作開發,我和隊友采用的是前后端分離的,按照作業要求使用Git分支,建立一條dev分支,讓隊友和自己在dev分支上開發,開發結束后再合並到main分支。第一次接觸這樣的結對編程,感到新穎的同時也很陌生,相信在以后的實踐中對這種合作開發會有更多經驗。
  • 第五章講述軟件團隊模式和開發流程,至於團隊模式和團隊的開發模式的關系,我個人的理解是一群人在一起做軟件開發,總是要一些方式方法。而這里團隊模式就是這一群人的定性,團隊的開發模式則是這群人使用的方法的定性。

心路歷程

221701429
  • 剛開始以為實現地圖會很難,但是知道了echarts之后發現也沒有那么難實現,
    就是設置圖表格式和傳入數據的事情,折線圖也是一個意思。收獲也是挺多的,
    第一次寫前端頁面,一直設置不好,沒辦法做出自己想要的樣子,甚是苦惱,
    但時間問題也只能作罷,美名其曰“精簡”。
    這次結對作業鍛煉了我們的合作開發能力,對技術上的也好、配合上的也好,
    都有很大的提升,對GitHub的使用也更熟練了一些,總的來說是一件好事。
    成長總是要經歷一些挫折的,這也是我的感受。
221701438
  • 第一次看到這次作業感覺非常難,畢竟自己很少接觸前后端分離的開發模式,
    與隊友討論完也認清自己的任務,代碼雖然不多,但是小BUG還是很多,
    因為自己能力不足,很多時候還是在查文檔和看大佬代碼中學習。
    本次結對作業采用了全新的結對開發模式,剛上手不是很熟悉,
    在查找很多資料后逐漸掌握,這也算學到一種新的技能。

對隊友的評價

221701429
  • 他是個靠譜的隊友,能一起合作是我的榮幸,他的部分我完全不用擔心,
    都能做好,對前端的部分也能提出一些建議,是個有實力有配合的隊友。
221701438
  • 我的隊友代碼規范,對本次作業的看法很多很棒,能給后端很清晰的開發思路。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM