软件开发架构师

大数据项目之_15_电信客服分析平台_05_数据展示+定时任务+项目总结

大数据 132 2019-03-22 23:36

3.4、数据展示3.4.1、环境准备3.4.2、编写代码3.4.3、最终预览3.5、定时任务四、项目总结


3.4、数据展示

  令人兴奋的时刻马上到了,接下来我们需要将某人按照不同维度查询出来的结果,展示到 web 页面上。
数据展示模块流程图:

3.4.1、环境准备

1) idea 新建 module 或项目:ct_web
pom.xml 配置文件:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.china</groupId>
    <artifactId>ct_web</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>ct_web Maven Webapp</name>
    <!-- FIXME change it to the project's website -->
    <url>http://www.example.com</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.27</version>
        </dependency>

        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.2.1</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>4.3.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>4.3.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.3.3.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.0</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.10</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.2.4</version>
        </dependency>
    </dependencies>

    <build>
        <finalName>ct_web</finalName>
        <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
            <plugins>
                <plugin>
                    <artifactId>maven-clean-plugin</artifactId>
                    <version>3.1.0</version>
                </plugin>
                <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
                <plugin>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.0</version>
                </plugin>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.22.1</version>
                    <configuration>
                        <skipTests>true</skipTests>
                    </configuration>
                </plugin>
                <plugin>
                    <artifactId>maven-war-plugin</artifactId>
                    <version>3.2.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-install-plugin</artifactId>
                    <version>2.5.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-deploy-plugin</artifactId>
                    <version>2.8.2</version>
                </plugin>
                <!-- idea 专业版不需要此配置,idea 社区版需要配置
                <plugin>
                    <groupId>org.apache.tomcat.maven</groupId>
                    <artifactId>tomcat7-maven-plugin</artifactId>
                    <version>2.2</version>
                    <configuration>
                        <path>/</path>
                        <port>8080</port>
                        <uriEncoding>UTF-8</uriEncoding>
                    </configuration>
                </plugin>
                -->

            </plugins>
        </pluginManagement>
    </build>
</project>

2) 创建包结构,根包:com.china

3) 类表

4) web目录结构,web部分的根目录:webapp

5) resources 目录下创建 spring 相关配置文件
dbconfig.properties 用于存放数据库连接配置

jdbc.user=root
jdbc.password=123456
jdbc.jdbcUrl=jdbc:mysql://hadoop102:3306/db_telecom?userUnicode=true&characterEncoding=UTF-8
jdbc.driverClass=com.mysql.jdbc.Driver

applicationContext.xml 用于 Spring 和 SpringMVC 配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
       http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"
>


    <!-- 加载配置文件 -->
    <context:property-placeholder location="classpath:dbconfig.properties"/>

    <!-- 配置连接池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="user" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="jdbcUrl" value="${jdbc.jdbcUrl}"/>
        <property name="driverClass" value="${jdbc.driverClass}"/>
    </bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <constructor-arg name="dataSource" value="#{dataSource}"></constructor-arg>
    </bean>

    <bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate">
        <constructor-arg name="dataSource" value="#{dataSource}"></constructor-arg>
    </bean>

    <!-- 配置包扫描 -->
    <context:component-scan base-package="com.china.controller"></context:component-scan>
    <context:component-scan base-package="com.china.dao"></context:component-scan>

    <!-- 配置视图解析器-->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

    <!-- 配置静态资源映射,也可以配置在 web.xml 中 -->
    <!--<mvc:annotation-driven />-->
    <!--<mvc:default-servlet-handler />-->
    <!--<mvc:resources location="/images/" mapping="/images/**"/>-->
    <!--<mvc:resources location="/js/" mapping="/js/**"/>-->
    <!--<mvc:resources location="/css/" mapping="/css/**"/>-->
</beans>

6) WEB-INF 目录下创建 web 相关配置
web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">


    <display-name>ct_wed</display-name>

    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

    <!-- 配置springmvc的前端控制器 -->
    <servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <!-- /表示拦截所有请求,但不拦截jsp,/*表示拦截所有请求 -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!-- 配置解决post乱码的过滤器 -->
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 配置静态资源映射,也可以配置在 applicationContext.xml 中 -->
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.jpg</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.js</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>default</servlet-name>
        <url-pattern>*.css</url-pattern>
    </servlet-mapping>
</web-app>

7) 拷贝 js 框架到 js 目录下
js 框架名称:

echarts.min.js
jquery-3.2.0.min.js

3.4.2、编写代码

思路:
  a) 首先测试数据通顺以及完整性,写一个查询联系人的测试用例。
  b) 测试通过后,通过输入手机号码以及时间参数,查询指定维度的数据,并以图表展示。

代码:
1) 新建类:CallLog

package com.china.bean;

/**
 * 封装从Mysql中取出来的数据
 *
 * @author chenmingjun
 * 2019-03-21 18:38
 */

public class CallLog {

    private String id_contact_date;

    private int id_dimension_contact;

    private int id_dimension_date;

    private int call_sum;

    private int call_duration_sum;

    private String telephone;

    private String name;

    private int year;

    private int month;

    private int day;

    public String getId_contact_date() {
        return id_contact_date;
    }

    public void setId_contact_date(String id_contact_date) {
        this.id_contact_date = id_contact_date;
    }

    public int getId_dimension_contact() {
        return id_dimension_contact;
    }

    public void setId_dimension_contact(int id_dimension_contact) {
        this.id_dimension_contact = id_dimension_contact;
    }

    public int getId_dimension_date() {
        return id_dimension_date;
    }

    public void setId_dimension_date(int id_dimension_date) {
        this.id_dimension_date = id_dimension_date;
    }

    public int getCall_sum() {
        return call_sum;
    }

    public void setCall_sum(int call_sum) {
        this.call_sum = call_sum;
    }

    public int getCall_duration_sum() {
        return call_duration_sum;
    }

    public void setCall_duration_sum(int call_duration_sum) {
        this.call_duration_sum = call_duration_sum;
    }

    public String getTelephone() {
        return telephone;
    }

    public void setTelephone(String telephone) {
        this.telephone = telephone;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    public int getMonth() {
        return month;
    }

    public void setMonth(int month) {
        this.month = month;
    }

    public int getDay() {
        return day;
    }

    public void setDay(int day) {
        this.day = day;
    }

    @Override
    public String toString() {
        return "CallLog{" +
                "id_contact_date='" + id_contact_date + '\'' +
                ", id_dimension_contact=" + id_dimension_contact +
                ", id_dimension_date=" + id_dimension_date +
                ", call_sum=" + call_sum +
                ", call_duration_sum=" + call_duration_sum +
                ", telephone='" + telephone + '\'' +
                ", name='" + name + '\'' +
                ", year=" + year +
                ", month=" + month +
                ", day=" + day +
                '}';
    }
}

2) 新建类:Contact

package com.china.bean;

/**
 * @author chenmingjun
 * 2019-03-22 0:17
 */

public class Contact {

    private int id;

    private String telephone;

    private String name;

    public Contact() {
    }

    public Contact(int id, String telephone, String name) {
        this.id = id;
        this.telephone = telephone;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getTelephone() {
        return telephone;
    }

    public void setTelephone(String telephone) {
        this.telephone = telephone;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Contact{" +
                "id=" + id +
                ", telephone='" + telephone + '\'' +
                ", name='" + name + '\'' +
                '}';
    }
}

3) 新建类:QueryInfo

package com.china.bean;

/**
 * 封装用于用户传递过来的数据
 *
 * @author chenmingjun
 * 2019-03-21 18:43
 */

public class QueryInfo {

    private String telephone;

    private String year;

    private String month;

    private String day;

    public QueryInfo() {
    }

    public QueryInfo(String telephone, String year, String month, String day) {
        this.telephone = telephone;
        this.year = year;
        this.month = month;
        this.day = day;
    }

    public String getTelephone() {
        return telephone;
    }

    public void setTelephone(String telephone) {
        this.telephone = telephone;
    }

    public String getYear() {
        return year;
    }

    public void setYear(String year) {
        this.year = year;
    }

    public String getMonth() {
        return month;
    }

    public void setMonth(String month) {
        this.month = month;
    }

    public String getDay() {
        return day;
    }

    public void setDay(String day) {
        this.day = day;
    }

    @Override
    public String toString() {
        return "QueryInfo{" +
                "telephone='" + telephone + '\'' +
                ", year='" + year + '\'' +
                ", month='" + month + '\'' +
                ", day='" + day + '\'' +
                '}';
    }
}

4) 新建类:CallLogDao

package com.china.dao;

import com.china.bean.CallLog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Repository;

import java.util.HashMap;
import java.util.List;

/**
 * @author chenmingjun
 * 2019-03-21 18:48
 */


@Repository
public class CallLogDao {

    // 自动装载
    @Autowired
    private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

    public List<CallLog> getCallLogList(HashMap<String, String> paramsMap) {

        // 按照年统计:统计某个用户,1年12个月的所有的数据(不精确到天)
        String sql = "SELECT `name`, `telephone`, `call_sum`, `call_duration_sum`, `year`, `month`, `day` FROM `tb_dimension_date` t4 INNER JOIN ( SELECT `id_dimension_date`, `call_sum`, `call_duration_sum`, `telephone`, `name` FROM `tb_call` t2 INNER JOIN ( SELECT `id`, `telephone`, `name` FROM `tb_dimension_contacts` WHERE `telephone` = :telephone ) t1 ON t2.id_dimension_contact = t1.id ) t3 ON t4.id = t3.id_dimension_date WHERE (`year` = :year AND `month` != :month AND `day` = :day) ORDER BY `year`, `month`;";

        BeanPropertyRowMapper<CallLog> beanPropertyRowMapper = new BeanPropertyRowMapper<>(CallLog.class);
        List<CallLog> list = namedParameterJdbcTemplate.query(sql, paramsMap, beanPropertyRowMapper);

        return list;
    }
}

5) 新建类:ContactDao

package com.china.dao;

import com.china.bean.Contact;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.stereotype.Repository;

import java.util.HashMap;
import java.util.List;

/**
 * @author chenmingjun
 * 2019-03-22 0:19
 */

@Repository
public class ContactDAO {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

    public List<Contact> getContacts() {
        String sql = "SELECT `id`, `telephone`, `name` FROM `tb_dimension_contacts`;";
        BeanPropertyRowMapper<Contact> contactBeanPropertyRowMapper = new BeanPropertyRowMapper<>(Contact.class);
        List<Contact> contactList = jdbcTemplate.query(sql, contactBeanPropertyRowMapper);
        return contactList;
    }

    public List<Contact> getContactWithId(HashMap<String, String> hashMap) {
        String sql = "SELECT `id`, `telephone`, `name` FROM `tb_dimension_contacts` WHERE `id` = :id;";
        BeanPropertyRowMapper<Contact> contactBeanPropertyRowMapper = new BeanPropertyRowMapper<>(Contact.class);
        List<Contact> contactList = namedParameterJdbcTemplate.query(sql, hashMap, contactBeanPropertyRowMapper);
        return contactList;
    }
}

6) 新建类:CallLogController

package com.china.controller;

import com.china.bean.CallLog;
import com.china.bean.Contact;
import com.china.bean.QueryInfo;
import com.china.dao.CallLogDao;
import com.china.dao.ContactDAO;
import com.google.gson.Gson;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import java.util.HashMap;
import java.util.List;

/**
 * @author chenmingjun
 * 2019-03-21 20:53
 */


@Controller
public class CallLogController {

    @RequestMapping("/queryContact")
    public ModelAndView query(Contact contact) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        ContactDAO contactDAO = applicationContext.getBean(ContactDAO.class);

        HashMap<String, String> paramMap = new HashMap<>();
        paramMap.put("id", String.valueOf(contact.getId()));

        List<Contact> contactList = contactDAO.getContactWithId(paramMap);

        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("jsp/queryContact");
        modelAndView.addObject("contacts", contactList);

        return modelAndView;
    }

    @RequestMapping("/queryContactList")
    public ModelAndView querylist() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        ContactDAO contactDAO = applicationContext.getBean(ContactDAO.class);

        List<Contact> contactList = contactDAO.getContacts();

        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("jsp/queryContact");
        modelAndView.addObject("contacts", contactList);

        return modelAndView;
    }

    @RequestMapping("/queryCallLogList")
    public ModelAndView queryCallLog(QueryInfo queryInfo) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        CallLogDao callLogDao = applicationContext.getBean(CallLogDao.class);

        HashMap<String, String> paramMap = new HashMap<>();
        paramMap.put("telephone", String.valueOf(queryInfo.getTelephone()));
        paramMap.put("year", String.valueOf(queryInfo.getYear()));
        paramMap.put("day", String.valueOf(queryInfo.getDay()));

        List<CallLog> callLogList = callLogDao.getCallLogList(paramMap);

        Gson gson = new Gson();
        String resultList = gson.toJson(callLogList);

        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("jsp/callLogList");
        modelAndView.addObject("callLogList", resultList);

        return modelAndView;
    }

    @RequestMapping("/queryCallLogList2")
    public String queryCallLog2(Model model, QueryInfo queryInfo) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        CallLogDao callLogDao = applicationContext.getBean(CallLogDao.class);

        // 封装传过来的数据
        HashMap<String, String> paramMap = new HashMap<>();
        paramMap.put("telephone", queryInfo.getTelephone());
        paramMap.put("year", String.valueOf(queryInfo.getYear()));
        paramMap.put("month", String.valueOf(queryInfo.getMonth()));
        paramMap.put("day", String.valueOf(queryInfo.getDay()));

        List<CallLog> callLogList = callLogDao.getCallLogList(paramMap);

        StringBuilder dateString = new StringBuilder();
        StringBuilder callSumString = new StringBuilder();
        StringBuilder callDurationSumString = new StringBuilder();

        // 1月,2月,3月,4月,5月,6月,7月,8月,9月,10月,11月,12月,
        for (int i = 0; i < callLogList.size(); i++) {
            CallLog callLog = callLogList.get(i);
            if (Integer.valueOf(callLog.getMonth()) > 0) {
                dateString.append(callLog.getMonth()).append("月").append(",");
                callSumString.append(callLog.getCall_sum()).append(",");
                callDurationSumString.append(callLog.getCall_duration_sum() / 60f).append(",");
            }
        }

        dateString.deleteCharAt(dateString.length() - 1);
        callSumString.deleteCharAt(callSumString.length() - 1);
        callDurationSumString.deleteCharAt(callDurationSumString.length() - 1);

        // 封装返回去的数据
        model.addAttribute("telephone", callLogList.get(0).getTelephone());
        model.addAttribute("name", callLogList.get(0).getName());
        model.addAttribute("date", dateString.toString());
        model.addAttribute("count", callSumString.toString());
        model.addAttribute("duration", callDurationSumString.toString());

        return "jsp/callLogListEchart";
    }
}

7) 新建类:Contants
  暂时没用上,也可以用上,主要用于存放一些常量。

8) 新建:index.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>
<%
    String path = request.getContextPath();
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Show Time</title>
</head>
<body>
    <form action="/queryContact">
        id:<input type="text" name="id"/>
        telephone:<input type="text" name="telephone"/>
        <input type="submit" value="查询当前联系人"/>
    </form>

    <br/>

    <form action="/queryContactList">
        <input type="submit" value="查询所有联系人"/>
    </form>
    <br/>

    <%--<form action='<c:url value="/queryCallLogList2"/>' method="post">--%>
    <form action=/queryCallLogList2 method="post">
        telephone:<input type="text" name="telephone"/>
        year:<input type="text" name="year"/>
        month:<input type="text" name="month"/>
        day:<input type="text" name="day"/>
        <input type="submit" value="查询该联系人的通话记录"/>
    </form>
</body>
</html>

9) 新建:queryContact.jsp

<%--
  Created by IntelliJ IDEA.
  User: bruce
  Date2019/3/22
  Time: 0:25
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored = "false" %>
<html>
<head>
    <title>查询联系人</title>
</head>
<body>
    查询结果:<br/>
    <h3>${requestScope.contacts}</h3>
</body>
</html>

10) 新建:callLogList.jsp

<%--
  Created by IntelliJ IDEA.
  User: bruce
  Date2019/3/22
  Time: 0:28
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored = "false" %>
<html>
<head>
    <title>显示通话记录</title>
</head>
<body>
    查询结果:<br/>
    <h3>${requestScope.callLogList}</h3>
</body>
</html>

11) 新建:callLogListEchart.jsp

<%--
  Created by IntelliJ IDEA.
  User: bruce
  Date2019/3/21
  Time: 21:09
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
    <meta http-equiv="Content-Type" , content="text/html" charset="UTF-8">
    <title>显示通话记录</title>
    <script type="text/javascript" src="../js/echarts.min.js"></script>
    <%--<script type="text/javascript" src="${pageContext.request.contextPath}/js/echarts.min.js"></script>--%>
    <%--<script type="text/javascript" src="${pageContext.request.contextPath}/jquery-3.2.0.min.js"></script>--%>
    <%--<script type="text/javascript" src="http://echarts.baidu.com/gallery/vendors/echarts/echarts-all-3.js"></script>--%>
</head>
<body style="height: 100%; margin: 0; background-color:#2B2B2B ">

<style type="text/css">
    h3 {
        font-size: 14px;
        color: #ffffff;
        display: inline;
    }
</style>
<h4 style="color: #ffffff;text-align:center">通话月单查询:${requestScope.name}</h4>
<%--<h3 style="margin-left: 70%">通话次数</h3>--%>
<%--<h3 style="margin-left: 20%">通话时长</h3>--%>
<div id="container1" style="height: 80%; width: 50%; float:left"></div>
<div id="container2" style="height: 80%; width: 50%; float:right"></div>
<script type="text/javascript">
    var telephone = "${requestScope.telephone}"
    var name = "${requestScope.name}"

    var date = "${requestScope.date}"//1月,2月,3月,xxxxx
    var count = "${requestScope.count}"

    var duration = "${requestScope.duration}"
    var pieData = converterFun(duration.split(","), date.split(","))
    callog1();
    callog2();

    function converterFun(duration, date) {
        var array = [];
        for (var i = 0; i < duration.length; i++) {
            var map = {};
            map['value'] = parseFloat(duration[i]);
            map['name'] = date[i];
            array.push(map);
        }
        return array;
    }

    function callog1() {
        var dom = document.getElementById("container1");
        var myChart = echarts.init(dom);
        myChart.showLoading();
        var option = {
            title: {
                text: '通话次数',
                textStyle: {
                    //文字颜色
                    color: '#ffffff',
                    //字体风格,'normal','italic','oblique'
                    fontStyle: 'normal',
                    //字体粗细 'normal','bold','bolder','lighter',100 | 200 | 300 | 400...
                    fontWeight: 'bold',
                    //字体系列
                    fontFamily: 'sans-serif',
                    //字体大小
                    fontSize: 13
                },
                itemGap: 12,
            },
            grid: {
                x: 80,
                y: 60,
                x2: 80,
                y2: 60,
                backgroundColor: 'rgba(0,0,0,0)',
                borderWidth: 1,
                borderColor: '#ffffff'
            },
            tooltip: {
                trigger: 'axis'
            },
            legend: {
                borderColor: '#ffffff',
                itemGap: 10,
                data: ['通话次数'],
                textStyle: {
                    color: '#ffffff'// 图例文字颜色
                }
            },
            toolbox: {
                show: false,
                feature: {
                    dataZoom: {
                        yAxisIndex: 'none'
                    },
                    dataView: {readOnly: false},
                    magicType: {type: ['line', 'bar']},
                    restore: {},
                    saveAsImage: {}
                }
            },
            xAxis: {
                data: date.split(","),
                axisLine: {
                    lineStyle: {
                        color: '#ffffff',
                        width: 2
                    }
                }
            },
            yAxis: {
                axisLine: {
                    lineStyle: {
                        color: '#ffffff',
                        width: 2
                    }
                }
            },
            series: [
                {
                    type: 'line',
                    data: count.split(","),
                    itemStyle: {
                        normal: {
                            color: '#ffca29',
                            lineStyle: {
                                color: '#ffd80d',
                                width: 2
                            }
                        }
                    },
                    markPoint: {
                        data: [
                            {type: 'max', name: '最大值'},
                            {type: 'min', name: '最小值'}
                        ]
                    },
                    markLine: {
                        data: [
                            {type: 'average', name: '平均值'}
                        ]
                    }
                }
            ]
        };
        if (option && typeof option === "object") {
            myChart.setOption(option, true);
        }
        myChart.hideLoading()
    }

    function callog2() {
        var dom = document.getElementById("container2");
        var myChart = echarts.init(dom);
        myChart.showLoading();
        var option = {
            title: {
                text: '通话时长',
                textStyle: {
                    //文字颜色
                    color: '#ffffff',
                    //字体风格,'normal','italic','oblique'
                    fontStyle: 'normal',
                    //字体粗细 'normal','bold','bolder','lighter',100 | 200 | 300 | 400...
                    fontWeight: 'bold',
                    //字体系列
                    fontFamily: 'sans-serif',
                    //字体大小
                    fontSize: 13
                },
                itemGap: 12,
            },
            tooltip: {
                trigger: 'item',
                formatter: "{a} <br/>{b} : {c} ({d}%)"
            },
            visualMap: {
                show: false,
                min: Math.min.apply(null, duration.split(",")),
                max: Math.max.apply(null, duration.split(",")),
                inRange: {
                    colorLightness: [0, 0.5]
                }
            },
            series: [
                {
                    name: '通话时长',
                    type: 'pie',
                    radius: '55%',
                    center: ['50%', '50%'],
                    data: pieData.sort(function (a, b) {
                        return a.value - b.value;
                    }),
                    roseType: 'radius',
                    label: {
                        normal: {
                            textStyle: {
                                color: 'rgba(255, 255, 255, 0.3)'
                            }
                        }
                    },
                    labelLine: {
                        normal: {
                            lineStyle: {
                                color: 'rgba(255, 255, 255, 0.3)'
                            },
                            smooth: 0.2,
                            length: 10,
                            length2: 20
                        }
                    },
                    itemStyle: {
                        normal: {
                            color: '#01c1c2',
                            shadowBlur: 200,
                            shadowColor: 'rgba(0, 0, 0, 0.5)'
                        }
                    },

                    animationType: 'scale',
                    animationEasing: 'elasticOut',
                    animationDelay: function (idx) {
                        return Math.random() * 200;
                    }
                }
            ]
        };
        if (option && typeof option === "object") {
            myChart.setOption(option, true);
        }
        myChart.hideLoading()
    }
</script>
</body>
</html>

3.4.3、最终预览

前端界面:

查询人通话时长与通话次数统计大概如下所示,统一展示:

3.5、定时任务

  新的数据每天都会产生,所以我们每天都需要更新离线的分析结果,所以此时我们可以用各种各样的定时任务调度工具来完成此操作。此例我们使用 crontab 来执行该操作。

1) 编写任务脚本:analysis.sh

#!/bin/bash
/opt/module/hadoop-2.7.2/bin/yarn jar ./ct_analysis-1.0-SNAPSHOT.jar com.china.analysis.runner.CountDurationRunner -libjars /opt/module/flume/job/ct/lib/mysql-connector-java-5.1.27-bin.jar

2) 制定 crontab 任务

# .------------------------------------------minute(0~59)
# | .----------------------------------------hours(0~23)
# | | .--------------------------------------day of month(1~31)
# | | | .------------------------------------month(1~12)
# | | | | .----------------------------------day of week(0~6)
# | | | | | .--------------------------------command
# | | | | | |
# | | | | | |
0 0 * * * /opt/module/flume/job/ct/analysis.sh

3) 考虑数据处理手段是否安全
  a、定时任务统计结果是否会重复
  b、定时任务处理的数据是否全面

四、项目总结

重新总结梳理整个项目流程和方法论。
  1、实现月查询(某个月每一天的数据展示:重新编写 sql 语句即可实现)。
  2、用户亲密度展示。
  3、考虑 Hive 实现。
  4、用户按照时间区间,查找所有的通话数据。

文章评论