大数据项目实战

第六章 数据可视化

学习目标

掌握 Sqoop 数据迁移工具的迁移工具的使用
熟悉关系型数据库 MySQL
掌握 SSM JavaEE 开发框架的整合及应用
掌握 ECharts 前端框架的使用

本篇将应用 Sqoop 将 Hive 中的表数据导出到关系型数据库 MySQL 中,方便后续进行数据可视化处理,使抽象的数据转化为图形化表示,便于非技术人员的决策和分析。


一、数据迁移

(1)创建关系型数据库

在上篇中,使用 Hive 完成数据分析过程后,分析结果数据存储在 HDFS 上(Hive 中数据用 HDFS 进行存储),为了方便后续进行数据可视化处理,需要将 HDFS 上的数据导出到关系型数据库 MySQL 中。接下来将详细讲解在MySQL 数据库中创建用于存储分析结果数据的数据表。
(1)通过 MySQL-Front 工具(图形化管理 MySQL 数据库的工具)远程连接 Hadoop001 服务器下的 MySQL 服务。
(2)通过 MySQL-Front 工具在 MySQL中创建 JobData 数据库,并指定数据库编码为 utf8。

CREATE DATABASE JobData CHARACTER SET utf8 COLLATE utf8_general_ci;

(3)在 JobData 数据库下创建需要图形化展示的职位所在城市的分布表 t_city_count。

CREATE TABLE t_city_count(
city varchar(30) DEFAULT NULL,
count int(5) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

(4)在 JobData 数据库下创建需要图形化展示的薪资分布表 t_salary_dist。

CREATE TABLE t_salary_dist(
salary varchar(30) DEFAULT NULL,
count int(5) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

(5)在 JobData 数据库下创建性需要图形化展示的福利标签统计表 t_company_count。

CREATE TABLE t_company_count(
company varchar(30) DEFAULT NULL,
count int(5) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

(6)在 JobData 数据库下创建需要图形化展示的技能标签统计表 t_kill_count。

CREATE TABLE t_kill_count(
kills varchar(30) DEFAULT NULL,
count int(5) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

至此,在 MySQL 关系型数据库中创建了用于存储 4 个不同分析结果的数据表。

(2)通过 Sqoop 实现数据迁移

通过 Sqoop 工具将 HDFS 上的数据加载到 MySQL 关系型数据库中。
(1)在安装 Sqoop 工具的节点(这里操作 Hadoop001节点)上执行 Sqoop 导出数据命令,将大数据相关职位所在城市的分布统计结果数据迁移到 MySQL 的 t_city_count 表中。

bin/sqoop export \
--connect jdbc:mysql://node01:3306/JobData?characterEncoding=UTF-8 \
--username root \
--password 123456 \
--table t_city_count \
--columns "city,count" \
--fields-terminated-by ',' \
--export-dir /user/hive/warehouse/jobdata.db/t_ods_city

(2)在安装 Sqoop 工具的节点(这里操作 Hadoop001节点)上执行 Sqoop 导出数据命令,将大数据相关职位的薪资分布结果数据迁移到 MySQL 的 t_salary_dist 表中。

bin/sqoop export \
--connect jdbc:mysql://node01:3306/JobData?characterEncoding=UTF-8 \
--username root \
--password 123456 \
--table t_salary_dist \
--columns "salary,count" \
--fields-terminated-by ',' \
--export-dir /user/hive/warehouse/jobdata.db/t_ods_salary

(3)在安装 Sqoop 工具的节点(这里操作 Hadoop001节点)上执行 Sqoop 导出数据命令,将大数据相关职位的福利标签统计结果数据迁移到 MySQL 的 t_company_count 表中。

bin/sqoop export \
--connect jdbc:mysql://node01:3306/JobData?characterEncoding=UTF-8 \
--username root \
--password 123456 \
--table t_company_count \
--columns "company,count" \
--fields-terminated-by ',' \
--export-dir /user/hive/warehouse/jobdata.db/t_ods_company

(4)在安装 Sqoop 工具的节点(这里操作 Hadoop001节点)上执行 Sqoop 导出数据命令,将大数据相关职位的技能标签统计结果数据迁移到 MySQL 的 t_kill_count 表中。

bin/sqoop export \
--connect jdbc:mysql://node01:3306/JobData?characterEncoding=UTF-8 \
--username root \
--password 123456 \
--table t_kill_count \
--columns "kills,count" \
--fields-terminated-by ',' \
--export-dir /user/hive/warehouse/jobdata.db/t_ods_kill

上述 4 个命令中指定了 MySQL 连接、MySQL 的用户名和密码、表名、表的字段、分隔符方式以及 Hive 数据在 HDFS 上的位置,执行完毕后,可以通过 MySQL-Front 工具查看对应 MySQL 数据库表的内容,以表 t_kill_count 为例,从下图中可以看出,表 t_kill_count 中有城市统计数据,说明实现了导入 Sqoop 数据的功能。

二、平台环境搭建

1、新建 Maven 项目

(1)创建一个 Maven 项目,打开 Eclipse 开发工具,在 Eclipse 主界面一次单击 File->new->Other,在弹出的窗口选择 Maven Project,单击 Next 按钮。

(2)在上一步中单击完 Next 按钮后,通过勾选就 Create a simple project 创建一个简单的 Maven 项目,在创建 Maven 项目的最终页面输入 Group Id 和 Artifact Id,并在 Packaging 中选择 war 打包方式,设置完成后单击 Finish 按钮。


(3)创建成功后,会提示“web.xml is missing and is set to true” 的错误,这是由于缺失 Web 工程的 web.xml 文件导致的,只需要通过右击项目,选择 Java EE Tools 选项,单击Generate Deployment Descriptor Stub选项便可以快速创建 web.xml 文件。

2、配置 pom.xml 文件

pom.xml 文件

<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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.itcast.jobanalysis</groupId><artifactId>job-webs</artifactId><version>0.0.1-SNAPSHOT</version><packaging>war</packaging><dependencies><dependency><groupId>org.codehaus.jettison</groupId><artifactId>jettison</artifactId><version>1.1</version></dependency><!-- Spring --><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>4.2.4.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>4.2.4.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>4.2.4.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>4.2.4.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>4.2.4.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jms</artifactId><version>4.2.4.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId><version>4.2.4.RELEASE</version></dependency><!-- Mybatis --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.2.8</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>1.2.2</version></dependency><dependency><groupId>com.github.miemiedev</groupId><artifactId>mybatis-paginator</artifactId><version>1.2.15</version></dependency><!-- MySql --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.32</version></dependency><!-- 连接池 --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.0.9</version><exclusions><exclusion><groupId>com.alibaba</groupId><artifactId>jconsole</artifactId></exclusion><exclusion><groupId>com.alibaba</groupId><artifactId>tools</artifactId></exclusion></exclusions></dependency><!-- JSP相关 --><dependency><groupId>jstl</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency><dependency><groupId>javax.servlet</groupId><artifactId>servlet-api</artifactId><version>2.5</version><scope>provided</scope></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jsp-api</artifactId><version>2.0</version><scope>provided</scope></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.4.2</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.8.4</version></dependency>
</dependencies>
<build><finalName>${project.artifactId}</finalName><resources><resource><directory>src/main/java</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>false</filtering></resource><resource><directory>src/main/resources</directory><includes><include>**/*.properties</include><include>**/*.xml</include></includes><filtering>false</filtering></resource></resources><plugins>
<!-- 指定maven编译的jdk版本,如果不指定,maven3默认用jdk 1.5--> <plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.2</version><configuration><!-- 源代码使用的JDK版本 --><source>1.8</source><!-- 需要生成的目标class文件的编译版本 --> <target>1.8</target><!-- 字符集编码 --><encoding>UTF-8</encoding></configuration></plugin><!-- 配置Tomcat插件 --><plugin><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><version>2.2</version><configuration><path>/</path><port>8080</port></configuration></plugin></plugins>
</build>
</project>

上述依赖的作用主要是构建以 SSM 框架为基础的 Java Web 工程所需的相关 jar 包。

3、项目组织结构

我们首先了解一下项目中所涉及的包文件、配置文件以及页面文件等在项目中的组织结构。

4、编辑配置文件

(1)在项目 src/main/resources->spring 文件夹下的 applicationContext.xml 文件中,编写 Spring 的配置内容。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.2.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.2.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd"><!-- 数据库连接池 --><!-- 加载配置文件 --><context:property-placeholder location="classpath:properties/db.properties" /><!-- 数据库连接池 --><bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"        destroy-method="close"><property name="url" value="${jdbc.url}" /><property name="username" value="${jdbc.username}" /><property name="password" value="${jdbc.password}" /><property name="driverClassName" value="${jdbc.driver}" /><property name="maxActive" value="10" /><property name="minIdle" value="5" /></bean>
<!-- 让spring管理sqlsessionfactory使用mybatis和spring整合包中的 --><bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"><!-- 数据库连接池 --><property name="dataSource" ref="dataSource" /><!-- 加载mybatis的全局配置文件 --><property name="configLocation" value="classpath:mybatis/mybatis-config.xml" /></bean><!-- 使用扫描包的形式来创建mapper代理对象 --><bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"><property name="basePackage" value="cn.itcast.mapper" /></bean><!-- 事务管理器 --><bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><!-- 数据源 --><property name="dataSource" ref="dataSource" /></bean><!-- 通知 --><tx:advice id="txAdvice" transaction-manager="transactionManager"><tx:attributes><!-- 传播行为 --><tx:method name="save*" propagation="REQUIRED" /><tx:method name="insert*" propagation="REQUIRED" /><tx:method name="add*" propagation="REQUIRED" /><tx:method name="create*" propagation="REQUIRED" /><tx:method name="delete*" propagation="REQUIRED" /><tx:method name="update*" propagation="REQUIRED" /><tx:method name="find*" propagation="SUPPORTS" read-only="true" /><tx:method name="select*" propagation="SUPPORTS" read-only="true" /><tx:method name="get*" propagation="SUPPORTS" read-only="true" /></tx:attributes></tx:advice><!-- 切面 --><aop:config><aop:advisor advice-ref="txAdvice" pointcut="execution(* cn.itcast.service..*.*(..))" /></aop:config><!-- 配置包扫描器,扫描所有带@Service注解的类 --><context:component-scan base-package="cn.itcast.service" />
</beans>

上述代码中,第20-21行代码用于加载数据库配置文件;第23-32行用于配置数据库连接池信息;第34-41行代码用于整合 Spring 和 MyBatis,创建 SqlSessionFactory 并指定数据源和 MyBatis 配置文件;第43-45代码用于将指定包路径下的映射器自动创建成 MapperFactoryBean;第47-51行代码拥有配置事务管理组件;第53-72行代码用于配置事务传播特性;第74-77行代码用于配置参与事务的类;第79行代码用于配置 Service 层的包扫描器。

(2)在项目 src/main/resources/->spring 文件夹下的 springmvc.xml 文件中,编写 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:context="http://www.springframework.org/schema/context"xmlns:mvc="http://www.springframework.org/schema/mvc"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.2.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-4.2.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.2.xsd"><!-- 扫描指定包路径 使路径当中的@controller注解生效 --><context:component-scan base-package="cn.itcast.controller" /><!-- mvc的注解驱动  --><mvc:annotation-driven /><!-- 视图解析器 --><beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/jsp/" /><property name="suffix" value=".jsp" /></bean><!-- 配置资源映射 --><mvc:resources location="/css/" mapping="/css/**"/><mvc:resources location="/js/" mapping="/js/**"/><mvc:resources location="/assets/" mapping="/assets/**"/><mvc:resources location="/img/" mapping="/img/**"/></beans>

上述代码中,第14行用于Spring自动扫描 base-package 对应的路径或者该路径的子包下面的 java 文件,将 @Controller 注解的类注册为 Bean; 第16行用于启用注解驱动,Spring 会自动将 Bean 注册到工厂中;第18-23行用于解析JSP页面资源;第25-29行用于访问静态资源文件。

(3)编写web.xml文件,配置Spring监听器、编码过滤器和SpringMVC的前端控制器等信息

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"><display-name>job-web</display-name><welcome-file-list><welcome-file>index.html</welcome-file><welcome-file>index.htm</welcome-file><welcome-file>index.jsp</welcome-file><welcome-file>default.html</welcome-file><welcome-file>default.htm</welcome-file><welcome-file>default.jsp</welcome-file></welcome-file-list><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring/applicationContext.xml</param-value></context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><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></filter><filter-mapping><filter-name>CharacterEncodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping><servlet><servlet-name>data-report</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring/springmvc.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>data-report</servlet-name><url-pattern>/</url-pattern></servlet-mapping><error-page><error-code>404</error-code><location>/WEB-INF/jsp/404.jsp</location></error-page>
</web-app>

上述代码中,第7-9行代码用于配置系统的首页;第11-19行代码用于配置监听加载 Spring 容器;第21-30行代码用于配置全局控制字符编码;第32-36行代码用于配置拦截的资源;第38-53行代码用于配置 Servlet 及 Servlet 映射;第55-58行代码用于配置全局错误页面。

(4)编写数据库配置参数文件 db.properties,用于项目的解耦。

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://hadoop001:3306/JobData?characterEncoding=utf-8
jdbc.username=root
jdbc.password=123456

上述代码是配置了数据库连接参数,需要注意的是 jdbc.url 参数中 MySQL 连接地址,需要根据读者具体情况填写。

(5)编写 Mybatis-Config.xml 文件,用于配置 MyBatis 相关配置,由于在 applicationContext.xml 中配置使用扫描包形式创建 Mapper 代理对象,那么在 Mybatis-Config.xml 文件中就不需要再配置 Mapper 的路径了。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
</configuration>

(6)将项目运行所需要的 css 文件、assets 文件、js 文件以及 jsp 页面需按照如下图所示的组织结构引入到项目中对应的文件夹下。项目源代码通过私聊笨猫猫获取即可(基本都是公共文件)!!!

css 文件名称 相关说明
bootstrap-reset.css、bootstrap.min.css bootstrap 前端框架
style-responsive.css、style404.css 404.jsp 样式
style.css index.jsp 样式
assets 文件名称 相关说明
font-awesome 字体样式
js 文件名称 相关说明
echarts.min.js ECharts 可视化框架
jquery-1.11.3.min.js JQuery 文件
echarts-wordcloud.js ECharts 词频插件
index.js index.jsp 页面的 JS 内容
echarts-view.js 分析结果图形化展示的 JS 内容
jsp 文件名称 相关说明
404.jsp 错误页面
index.jsp 图形化展示页面

5、实现图形化展示功能

(1)实现职位区域分布展示

【1】创建实体类
在项目的 cn.itcast.pojo 包中创建 CityPojo 实体类对象,用于封装数据库获取的城市数据,在该类中定义属于的 get()/set() 方法,并重写 toString() 方法,用于自定义输出信息。

文件 CityPojo.java

public class CityPojo {private String city;private int count;public String getCity() {return city;}public void setCity(String city) {this.city = city;}public int getCount() {return count;}public void setCount(int count) {this.count = count;}@Overridepublic String toString() {return "{\"name\":\"" + city + "\", \"value\":" + String.valueOf(count) + "}";}
}

上述代码中,实体类对象的属性值与 t_city_count 表中字段保持一致。

【2】实现 Dao 层

(1)在 cn.itcast.mapper 包下创建 DAO 层接口 CityMapper,并在接口中编写查询城市统计数据的方法。

文件 CityMapper.java

import java.util.List;
import cn.itcast.pojo.CityPojo;public interface  CityMapper {public List<CityPojo> selectCity();
}

(2)在 mapper 包下创建 MyBatis 映射文件 CityMapper.xml,并在接口中编写查询城市统计数据的方法。

文件 CityMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.itcast.mapper.CityMapper"><select id="selectCity" resultType="cn.itcast.pojo.CityPojo">select * from t_city_count ORDER BY count;</select>
</mapper>

上述代码中,编写一条 SQL 语句,用来查询 t_city_count 表中的所有数据。

【3】实现 Service 层

(1)在 cn.itcast.service 包下创建 Service 层接口 CityService ,在接口中编写一个获取城市统计数据的方法。

文件 CityService.java

public interface CityService {public String getCityData();
}

(2)在 cn.itcast.service.impl 包下创建 Service 层接口 CityServiceImpl ,在该类中实现接口中的 getCityData() 方法。

文件 CityServiceImpl.java

import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import cn.itcast.mapper.CityMapper;
import cn.itcast.pojo.CityPojo;
import cn.itcast.service.CityService;@Service
public class CityServiceImpl implements CityService {   @Autowiredprivate CityMapper mapper;@Transactionalpublic String getCityData() {List<CityPojo> lists = mapper.selectCity();List<String> resultData = new ArrayList<String>();for (CityPojo cityPojo : lists) {resultData.add(cityPojo.toString());}ObjectMapper om = new ObjectMapper();String beanJson = null;try {beanJson = om.writeValueAsString(resultData);} catch (JsonProcessingException e) {e.printStackTrace();}return beanJson;}
}

上述代码中,将查询的数据放入 resultData 集合中,这样就可以利用 Jackson 工具类中 ObjectMapper 对象的 writeValueAsString() 方法将集合转换成 JSON 格式的数据并发送给前端。

【4】实现 Controller 层

在 cn.itcast.controller 包下创建 controller 层的实现类 IndexController。

文件 IndexController.java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import cn.itcast.service.CityService;
@Controller
public class IndexController {@Autowiredprivate CityService cityService;@RequestMapping("/index")public String showIndex() {return "index";}@RequestMapping(value = "/city", produces = "application/json;charset=UTF-8")@ResponseBodypublic String getCity() {String data = cityService.getCityData();return data;}
}

上述代码中,在 getCity() 方法中通过 cityService 对象调用 getCityData() 方法将 JSON 格式数据返回给前端并定义实现城市数据可视化页面时前端请求后端获取数据的指定参数为 “/city”。

【5】实现页面展示

在 echarts-view.js 中,文件中创建 city() 方法,通过在 index.jsp(首页)的职位区域分布按钮下调用 city() 方法,实现职位区域分析的可视化展示。

文件 echarts-view.js

/*** * 获取职位全国分布数据生成饼状图*/
function city(){var JsonSeries = [];document.getElementById("dataView").className = 'general';var dataViewcharts=echarts.init(document.getElementById('dataView'));var dataViewoption = {title : {text: '职位区域分布',subtext: '',x:'center'},tooltip : {trigger: 'item',formatter: "{a} <br/>{b} : {c} ({d}%)"},legend: {orient : 'vertical',x : 'left',data:[]},toolbox: {show : true,feature : {mark : {show: true},dataView : {show: true, readOnly: false},magicType : {show: true, type: ['pie', 'funnel'],option: {funnel: {x: '25%',width: '50%',funnelAlign: 'left',max: 1548}}},restore : {show: true},saveAsImage : {show: true}}},calculable : true,series : [{name:'职位所在区域',type:'pie',radius : '55%',center: ['50%', '60%'],data:[]}]};// 异步加载数据$.get('http://localhost:8080/city').done(function(data) {data.forEach(function(element) {JsonSeries.push(JSON.parse(element)); });dataViewoption.series[0].data = JsonSeries;dataViewoption.legend.data = JsonSeries;dataViewcharts.clear();dataViewcharts.setOption(dataViewoption);});
}

上述代码中,设置 id 为“dataView” 的标签样式名为 general,并通过 echarts.init 创建实例容器;加载 ECharts 饼状图模板;通过 Ajax 异步请求获取 JSON 数据,并将 JSON 数据动态填充到饼状图模板,通过 setOption 将填充的饼状图加载到容器中实现数据可视化功能。

(2)实现薪资分布展示

【1】创建持久化类

在项目的 cn.itcast.pojo 包中创建 SalaryPojo 实体类对象,用于封装数据库获取的薪资数据,在该类中定义属于的 get()/set() 方法,并重写 toString() 方法,用于自定义输出信息。

文件 SalaryPojo.java

public class SalaryPojo {private String salary;private int count;public String getSalary() {return salary;}public void setSalary(String salary) {this.salary = salary;}public int getCount() {return count;}public void setCount(int count) {this.count = count;}  @Overridepublic String toString() {return "{\"name\":\"" + salary + "\", \"value\":" + String.valueOf(count) + "}";}
}

上述代码可以看出,实体类对象的属性值与 t_salary_dist 表中字段保持一致。

【2】实现 DAO 层

(1)在 cn.itcast.mapper 包下创建 DAO 层接口 SalaryMapper,并在接口中编写查询薪资区间分布数据的方法。

文件 SalaryMapper.java

package cn.itcast.mapper;import java.util.List;
import cn.itcast.pojo.SalaryPojo;public interface SalaryMapper {public List<SalaryPojo> selectSalary();
}

(2)在 mapper 包下创建 MyBatis 映射文件 SalaryMapper.xml,并在映射文件中编写 SQL 查询语句。

文件 SalaryMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.itcast.mapper.SalaryMapper"><select id="selectSalary" resultType="cn.itcast.pojo.SalaryPojo">select * from t_salary_dist ORDER BY salary;</select>
</mapper>

上述代码中,编写一条 SQL 语句,用来查询 t_salary_dist 表中的所有数据。

【3】实现 Service 层

(1)在 cn.itcast.service 包下创建 Service 层接口 SalaryService ,在接口中编写一个获取薪资区间分布数据的方法。

文件 SalaryService.java

public interface SalaryService {public String getSalaryData();
}

(2)在 cn.itcast.service.impl 包下创建 Service 层接口 SalaryServiceImpl ,在该类中实现接口中的 getSalaryData() 方法。

文件 SalaryServiceImpl.java

import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import cn.itcast.mapper.SalaryMapper;
import cn.itcast.pojo.SalaryPojo;
import cn.itcast.service.SalaryService;
@Service
public class SalaryServiceImpl implements SalaryService {@Autowiredprivate SalaryMapper mapper;@Transactionalpublic String getSalaryData() {List<SalaryPojo> lists = mapper.selectSalary();List<String> resultData = new ArrayList<String>();for (SalaryPojo salaryPojo : lists) {resultData.add(salaryPojo.toString());} ObjectMapper om = new ObjectMapper();String beanJson = null;try {beanJson = om.writeValueAsString(resultData);} catch (JsonProcessingException e) {e.printStackTrace();}return beanJson;}
}

上述代码中,将查询的数据放入 resultData 集合中,这样就可以利用 Jackson 工具类中 ObjectMapper 对象的 writeValueAsString() 方法将集合转换成 JSON 格式的数据并发送给前端。

【4】实现 Controller 层

在已有的 Controller 层实现 IndexController 中创建 getSalary() 方法,实现将数据库获取的薪资数据以 JSON 数据形式返回前端。

文件 IndexController.java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import cn.itcast.service.CityService;
@Controller
public class IndexController {@Autowiredprivate SalaryService salaryService;@RequestMapping(value = "/salary", produces = "application/json;charset=UTF-8")@ResponseBodypublic String getSalary() {String data = salaryService.getSalaryData();return data;}}
}

上述代码中,在 getSalary() 方法中通过 SalaryService 对象调用 getSalaryData() 方法将 JSON 格式数据返回给前端并定义实现薪资区间分布数据可视化页面时前端请求后端获取数据的指定参数为 “/salary”。

【5】实现页面展示

在已有的 echarts-view.js 中,文件中创建 salary() 方法,实现薪资区间分布数据的可视化功能。

文件 echarts-view.js

/*** * 获取工资分段数据生成柱状图*/
function salary(){document.getElementById("dataView").className = 'general';var dataViewcharts=echarts.init(document.getElementById('dataView'));var dataViewoption = {title : {text: '全国大数据职位薪资区间分布',subtext: ''},tooltip : {trigger: 'axis'},legend: {data:['薪资区间']},toolbox: {show : true,feature : {mark : {show: true},dataView : {show: true, readOnly: false},magicType : {show: true, type: ['line', 'bar']},restore : {show: true},saveAsImage : {show: true}}},calculable : true,xAxis : [{type : 'category',data : []}],yAxis : [{type : 'value'}],series : [{name:'薪资区间',type:'bar',data:[],markPoint : {data : [{type : 'max', name: '最大值'},{type : 'min', name: '最小值'}]}}]};var JsonxAxis = [];var JsonSeries = [];    // 异步加载数据$.get('http://localhost:8080/salary').done(function(data) {data.forEach(function(element) {for(var key in JSON.parse(element)){if(key == 'name'){JsonxAxis.push(JSON.parse(element)[key]);}else{JsonSeries.push(JSON.parse(element)[key]);}      }});dataViewoption.xAxis[0].data = JsonxAxis;dataViewoption.series[0].data = JsonSeries;dataViewcharts.clear();dataViewcharts.setOption(dataViewoption);});
}

上述代码中,通过判断 JSON 数据中的 Key 值,将数据中 Key 为 “name” 的值放入到 JsonxAxis 数组中,将 Key 为非 “name” 的值放入到 JsonSeries 数组中。

(3)实现福利标签词云图

【1】创建实体类
在项目的 cn.itcast.pojo 包中创建 CompanyPojo 实体类对象,用于封装数据库获取的福利标签数据,在该类中定义属于的 get()/set() 方法,并重写 toString() 方法,用于自定义输出信息。

文件 CompanyPojo.java

public class CompanyPojo {private int count;private String company;public String getCompany() {return company;}public void setCompany(String company) {this.company = company;}public int getCount() {return count;}public void setCount(int count) {this.count = count;}@Overridepublic String toString() {return "{\"name\":\"" + company + "\", \"value\":" + String.valueOf(count) + "}";}
}

上述代码中,实体类对象的属性值与 t_company_count 表中字段保持一致。

【2】实现 Dao 层

(1)在 cn.itcast.mapper 包下创建 DAO 层接口 CompanyMapper,并在接口中编写查询福利标签统计数据的方法。

文件 CompanyMapper.java

import java.util.List;
import cn.itcast.pojo.CompanyPojo;public interface CompanyMapper {public List<CompanyPojo> selectCompany();
}

(2)在 mapper 包下创建 MyBatis 映射文件 CompanytMapper.xml,并在映射文件中编写 SQL 查询语句。

文件 CompanyMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.itcast.mapper.CompanyMapper"><select id="selectCompany" resultType="cn.itcast.pojo.CompanyPojo">select * from t_company_count;</select>
</mapper>

上述代码中,编写一条 SQL 语句,用来查询 t_company_count 表中的所有数据。

【3】实现 Service 层

(1)在 cn.itcast.service 包下创建 Service 层接口 CompanyService ,在接口中编写获取福利标签统计数据的方法。

文件 CompanyService.java

public interface CompanyService {public String getCompanyData();
}

(2)在 cn.itcast.service.impl 包下创建 Service 层接口 CompanyServiceImpl ,在该类中实现接口中的 getCompanyData() 方法。

文件 CompanyServiceImpl.java

import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import cn.itcast.mapper.CompanyMapper;
import cn.itcast.pojo.CompanyPojo;
import cn.itcast.service.CompanyService;
@Service
public class CompanyServiceImpl implements CompanyService {@Autowiredprivate CompanyMapper mapper;@Transactionalpublic String getCompanyData(){List<CompanyPojo> lists = mapper.selectCompany();List<String> resultData = new ArrayList<String>();for (CompanyPojo companyPojo : lists) {resultData.add(companyPojo.toString());} ObjectMapper om = new ObjectMapper();String beanJson = null;try {beanJson = om.writeValueAsString(resultData);} catch (JsonProcessingException e) {e.printStackTrace();}return beanJson;}
}

上述代码中,将查询的数据放入 resultData 集合中,这样就可以利用 Jackson 工具类中 ObjectMapper 对象的 writeValueAsString() 方法将集合转换成 JSON 格式的数据并发送给前端。

【4】实现 Controller 层

在已有的 Controller 层实现 IndexController 中通过实现 getCompany() 方法将福利标签统计数据返回前端。

文件 IndexController.java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import cn.itcast.service.CityService;
@Controller
public class IndexController {@Autowiredprivate CompanyService companyService;@RequestMapping(value = "/company",produces = "application/json;charset=UTF-8")@ResponseBodypublic String getCompany() {String data = companyService.getCompanyData();return data;}
}

上述代码中,在 getCompany() 方法中通过 companyService 对象调用 getCompanyData() 方法将 JSON 格式数据返回给前端并定义实现福利标签数据可视化页面时前端请求后端获取数据的指定参数为 “/company”。

【5】实现页面展示

在已有的 echarts-view.js 中,文件中创建 companry() 方法,实现福利标签数据生成词云图功能。

文件 echarts-view.js

/*** * 获取福利标签数据生成词云*/
function company(){document.getElementById("dataView").className = 'general';var dataViewcharts=echarts.init(document.getElementById('dataView'));var dataViewoption = {title: {text: '福利标签分析',x: 'center',textStyle: {fontSize: 23,color:'#FFFFFF'}},tooltip: {show: true},series: [{name: '福利标签分析',type: 'wordCloud',sizeRange: [6, 66],rotationRange: [-45, 90],textPadding: 0,autoSize: {enable: true,minSize: 6},textStyle: {normal: {color: function() {return 'rgb(' + [Math.round(Math.random() * 160),Math.round(Math.random() * 160),Math.round(Math.random() * 160)].join(',') + ')';}},emphasis: {shadowBlur: 10,shadowColor: '#333'}},data: []}]};var JosnList = [];// 异步加载数据$.get('http://localhost:8080/company').done(function(data) {data.forEach(function(element) {JosnList.push(JSON.parse(element));});dataViewoption.series[0].data = JosnList;dataViewcharts.clear();dataViewcharts.setOption(dataViewoption);});
}

上述代码中,通过 Ajax 异步加载获取后端发送过来的数据,将这些数据加载到 ECharts 词云图配置参数 series 中,从而通过参数 series 配置 ECharts 词云图数据的属性 data。

(4)实现技能标签词云图

【1】创建持久化类
在项目的 cn.itcast.pojo 包中创建 KillPojo 实体类对象,用于封装数据库获取的技能标签数据,在该类中定义属于的 get()/set() 方法,并重写 toString() 方法,用于自定义输出信息。

文件 KillPojo.java

public class KillPojo {private String kills;private int count;public String getKills() {return kills;}public void setKills(String kills) {this.kills = kills;}public int getCount() {return count;}public void setCount(int count) {this.count = count;}@Overridepublic String toString() {return "{\"name\":\"" + kills + "\", \"value\":" + String.valueOf(count) + "}";}
}

上述代码中,实体类对象的属性值与 t_kill_count 表中字段保持一致。

【2】实现 Dao 层

(1)在 cn.itcast.mapper 包下创建 DAO 层接口 KillMapper,并在接口中编写查询技能标签统计数据的方法。

文件 KillMapper.java

import java.util.List;
import cn.itcast.pojo.KillPojo;public interface KillMapper {public List<KillPojo> selectKill();
}

(2)在 mapper 包下创建 MyBatis 映射文件 KillMapper.xml,并在映射文件中编写 SQL 查询语句。

文件 CompanyMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.itcast.mapper.KillMapper"><select id="selectKill" resultType="cn.itcast.pojo.KillPojo">select * from t_kill_count;</select>
</mapper>

上述代码中,编写一条 SQL 语句,用来查询 t_kill_count 表中的所有数据。

【3】实现 Service 层

(1)在 cn.itcast.service 包下创建 Service 层接口 KillService ,在接口中编写获取技能标签统计数据的方法。

文件 KillService.java

public interface KillService {public String getKillData();
}

(2)在 cn.itcast.service.impl 包下创建 Service 层接口 KillServiceImpl ,在该类中实现接口中的 getKillData() 方法。

文件 KillServiceImpl.java

import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import cn.itcast.mapper.KillMapper;
import cn.itcast.pojo.KillPojo;
import cn.itcast.service.KillService;
@Service
public class KillServiceImpl implements KillService {@Autowiredprivate KillMapper mapper;@Transactionalpublic String getKillData() {List<KillPojo> lists = mapper.selectKill();List<String> resultData = new ArrayList<String>();for (KillPojo killPojo : lists) {resultData.add(killPojo.toString());}   ObjectMapper om = new ObjectMapper();String beanJson = null;try {beanJson = om.writeValueAsString(resultData);} catch (JsonProcessingException e) {e.printStackTrace();}return beanJson;}
}

上述代码中,将数据库获取的数据放入 lists 集合中;遍历 lists 集合利用实体类中重写的 toString() 方法组合每一条数据并放入 resultData 数组集合中;利用 writeValueAsString() 方法将集合转换成 JSON 格式的数据。

【4】实现 Controller 层

在已有的 Controller 层实现 IndexController 中通过实现 getKill() 方法将技能标签统计数据返回前端。

文件 IndexController.java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import cn.itcast.service.CityService;
@Controller
public class IndexController {@Autowiredprivate KillService killService;@RequestMapping(value = "/kill",produces = "application/json;charset=UTF-8")@ResponseBodypublic String getKill() {String data = killService.getKillData();return data;}
}

上述代码中,在 getKill() 方法中通过 KillService 对象调用 getKillData() 方法将 JSON 格式数据返回给前端并定义实现技能标签数据可视化页面时前端请求后端获取数据的指定参数为 “/kill”。

【5】实现页面展示

在已有的 echarts-view.js 中,文件中创建 kill() 方法,实现技能标签数据生成词云图功能。

文件 echarts-view.js

/*** * 获取技能标签数据生成词云*/
function kill(){document.getElementById("dataView").className = 'general';var dataViewcharts=echarts.init(document.getElementById('dataView'));var dataViewoption = {title: {text: '技能标签分析',x: 'center',textStyle: {fontSize: 23,color:'#FFFFFF'}},tooltip: {show: true},series: [{name: '技能标签分析',type: 'wordCloud',sizeRange: [6, 66],rotationRange: [-45, 90],textPadding: 0,autoSize: {enable: true,minSize: 6},textStyle: {normal: {color: function() {return 'rgb(' + [Math.round(Math.random() * 160),Math.round(Math.random() * 160),Math.round(Math.random() * 160)].join(',') + ')';}},emphasis: {shadowBlur: 10,shadowColor: '#333'}},data: []}]};var JosnList = [];// 异步加载数据$.get('http://localhost:8080/kill').done(function(data) {data.forEach(function(element) {JosnList.push(JSON.parse(element));});dataViewoption.series[0].data = JosnList;dataViewcharts.clear();dataViewcharts.setOption(dataViewoption);});
}

上述代码中,通过 Ajax 异步加载获取后端发送过来的数据,将这些数据加载到 ECharts 词云图配置参数 series 中,从而通过参数 series 配置 ECharts 词云图数据的属性 data。

(5)平台可视化展示

在 Eclipse 开发工具中,右击单击 job-webs 项目,选择 Run As -> Maven build,在 Goals 文本框输入 “tomcat7:run” 启动 Tomcat 服务,待项目启动完成后,在浏览器的地址栏输入 http://localhost:8080/index.html 网址,即可打开招聘网站职位分析可视化系统主界面,通过展开左侧导航栏,单击对应的分析按钮查看展开效果。


通过观察,福利标签词云图中每个词语出现的大小,了解全国招聘大数据公司的福利主要集中在哪几个方面。

通过观察职位区域分布饼状图中各个扇区的大小,了解每个城市招聘的职位数在全国数据中所占的比例。

通过观察,薪资分布柱状图各个柱形的长度,了解全国大数据薪资区间的分布情况。

通过观察,技能标签词云图中每个词语出现的大小,了解全国招聘大数据的公司主要要求求职者需要掌握哪些技能。

至此,招聘网站职位分析可视化系统搭建完成,通过系统的可视化展示可以更加清晰地观察数据。


总结

本篇主要讲解数据可视化,使用 SSM 框架(Spring、Spring MVC 和 MyBatis)、JQuery 和 ECharts 图表库等网页开发技术对数据分析结果进行可视化展示。至此,本项目已全部完成,笨猫猫在此告一段落,我们下个新项目见!!!

大数据项目实战——基于某招聘网站进行数据采集及数据分析(六)相关推荐

  1. 大数据项目实战——基于某招聘网站进行数据采集及数据分析(四)

    大数据项目实战 第四章 数据预处理 文章目录 大数据项目实战 学习目标 一.分析预处理数据 1)salary 2)city 3)skillLabels 4)companyLabelList.posit ...

  2. 大数据项目实战教程:使用SparkSQL+Hbase+Oozie构建企业级用户画像

    大数据项目实战教程,本课程需要有大数据基础(掌握基本大数据组件应用)的人才可以学习哦!市面上全面的大数据教程较少,今天分享给大家的就是一套全面的大数据学习教程,企业级大数据项目:360度用户画像实战 ...

  3. 大数据项目(基于spark)--新冠疫情防控指挥作战平台项目

    大数据项目(基于spark)–新冠疫情防控指挥作战平台项目 文章目录 第一章 项目介绍 1.1 项目背景 1.2 项目架构 1.3 项目截图 1.4 功能模块 第二章 数据爬取 2.1 数据清单 2. ...

  4. 大数据项目实战-招聘网站职位分析

    目录 第一章:项目概述 1.1项目需求和目标 1.2预备知识 1.3项目架构设计及技术选取 1.4开发环境和开发工具 1.5项目开发流程 第二章:搭建大数据集群环境 2.1安装准备 2.2Hadoop ...

  5. 大数据项目实战——电信业务大数据分析系统

    基于大数据与hadoop的电信业务大数据分析系统 项目源代码:https://github.com/2462612540/Big_Data_Spark_Scala_hadoop/tree/master ...

  6. 大数据项目实战之数据仓库:用户行为采集平台——第4章 用户行为数据采集模块

    第4章 用户行为数据采集模块 4.1 数据通道 4.2 环境准备 4.2.1 集群所有进程查看脚本 1)在/home/atguigu/bin目录下创建脚本xcall [atguigu@hadoop10 ...

  7. python大数据项目_(价值1280)大数据项目实战之Python金融应用编程

    朱彤老师,2009年博士毕业于北京大学光华管理学院金融系,对金融.数据分析与统计有着较为深刻的理解,多年来一直持续跟踪和研究金融量化分析与数据统计相关领域的进展与发展,对概率论.随机过程及其在金融中的 ...

  8. 大数据项目实战——电商推荐系统设计

    摘要 1 项目体系架构设计 1.1系统架构设计 项目以推荐系统建设领域知名的经过修改过的中文亚马逊电商数据集作为依托,以某电商网站真实业务数据架构为基础,构建了符合实践项目的一体化的电商推荐系统,包含 ...

  9. docker-compose观察实时日志_大数据项目实战之在线教育(03实时需求) - 十一vs十一...

    第1章Spark Streaming概念 Spark Streaming 是核心Spark API的扩展,可实现实时数据的可扩展,高吞吐量,容错处理.数据可以从许多来源(如Kafka,Flume,Ki ...

  10. 大数据项目实战数仓4——总纲

    文章目录 一.数据仓库的概述 二.项目需求及架构设计 1.项目需求分析 2.项目框架 2.1技术选型 2.2系统数据流程设计 2.3框架发行版本选型 2.4服务器选型 2.5集群资源规划设计 三.相关 ...

最新文章

  1. 计算机技术在工程的应用浅论,《计算机技术在计算机应用技术中的应用浅论》...
  2. SQLServer 的存储过程与java交互
  3. logstash 过虑nginx访问日志
  4. 电脑数据存储工具----光盘驱动器
  5. 822C Hacker, pack your bags!
  6. $科大讯飞开放平台——语音听写接口的使用
  7. 关于文献汇报与撰写论文模板,我有话要讲!
  8. Layui数据表格动态cols(字段)动态变化(2)
  9. ftp中转服务器,bat实现的ftp中转
  10. esp32 esp8285 wf6000OTA升级小记
  11. linux蓝牙主从机模式代码,技术贴 丨 Android 蓝牙BLE开发Docker入门与WMS2.0实例
  12. 录制软件obs的使用方法
  13. 毕业设计 - 题目:基于深度学习的中文汉字识别 - 深度学习 卷积神经网络 机器视觉 OCR
  14. IP Catalog与Create Block Design调用软核的不同
  15. 解决浏览器主页被2345篡改
  16. python tkinter界面 多进程启动scrapy爬取百度贴吧的回复,显示爬取进度,并可以搜索回帖人,指定时间生成词云图,用pyinstaller打包成exe(七)
  17. 计算机图形学14:三维图形的投影变换
  18. 牵手·············
  19. 关机提示 ”task host window任务宿主正在执行关闭任务并且正在停止已运行的任务“我是这样解决的
  20. LCD段码液晶屏PIN脚间距

热门文章

  1. LeetCode:Confusing Number II
  2. 图神经网络和强化学习
  3. 狂神SpringBoot静态资源文件
  4. fetion-robot是基于web飞信接口的飞信机器人
  5. 超级AI买家阿里巴巴
  6. 生活随记 - 尝试与师傅沟通争取自己的权益
  7. python输出今天的日期和今天的日期时间
  8. mysql lob字段_数据库的LOB大字段的一些总结
  9. 读书感受 之 《写给年轻人的 经济学故事书》
  10. D - Plane 航空管制2 HYSBZ - 2535