2.5.2.2 可视化项目(数据Echart可视化显示)

可视化项目案例(数据Echart可视化显示)



四、行业信息模块

4.1 行业需求描述

从多个维度统计行业信息

  1. 统计各个城市招聘人数,以饼状图方式展示个城市人数比例
  2. 统计热门行业信息,以柱状图的方式展示前10个热门行业的招聘人数
  3. 统计销售行业、服务业、生产制造行业招聘情况,使用面积图参考招聘这3个行业情况。

4.2 表结构分析

在这里插入图片描述

4.3.统计各个城市招聘人数

1) 统计各个城市招聘人数需求分析
统计各个城市招聘人数,以饼状图方式展示个城市人数比例
在这里插入图片描述
2) 统计各城市招聘接口
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
后端代码实现
IndustryController

package com.lagou.service.impl;

import com.lagou.common.ServerResponse;
import com.lagou.service.IIndustryService;
import com.lagou.vo.ConverterVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Map;

@Service("iIndustryService")
public class IIndustryServiceImpl implements IIndustryService {
    
    

    @Autowired
    private IdustryMapper mapper;

    /**
     * 统计各个城市招聘情况
     * @return
     */
    @Override
    public ServerResponse<Map<String, Object>> countCityData() {
    
    
        //1.查询各个城市招聘情况 , 创建一个对象封装查询的数据 list
        List<ConverterVo> cityPositionList = mapper.countCityPosition();

        //2.创建一个Map<String,Object> 存放总数据
        Map<String , Object> map = new HashMap<>();

        //3.创建3个List集合  cityNamesList 存放城市名称  ; thridList 前三名城市数据  dataList 存放是个城市数据
        List<String> cityNamesList = new ArrayList<>();
        List<ConverterVo> thridList = new ArrayList<>();
        List<ConverterVo> dataList = new ArrayList<>();

        //4.循环list ,给cityNamesList   thridList  dataList  封装数据
        for (ConverterVo converterVo : cityPositionList) {
    
    
            //设置城市名称
            cityNamesList.add(converterVo.getName());
            //设置thridList
            if(thridList.size() < 3 ){
    
    
                thridList.add(converterVo);
            }
            //设置dataList
            dataList.add(converterVo);
        }

        //5.把3个list的数据村道map中
        map.put("cityNamesList",cityNamesList);
        map.put("thridList",thridList);
        map.put("dataList",dataList);

        //6.把map中的数据放到serverresponse中返回
        return ServerResponse.createBySuccessData(map);
    }
}

IIndustryService

package com.lagou.service;

import com.lagou.common.ServerResponse;

import java.util.Map;

public interface IIndustryService {
    
    

    /**
     * 统计各城市招聘人数
     * @return
     */
    ServerResponse<Map<String, Object>> countCityData();
}

IndustryServiceImpl

package com.lagou.service.impl;

import com.lagou.common.ServerResponse;
import com.lagou.service.IIndustryService;
import com.lagou.vo.ConverterVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Map;

@Service("iIndustryService")
public class IndustryServiceImpl implements IIndustryService {
    
    

    @Autowired
    private IdustryMapper mapper;

    /**
     * 统计各个城市招聘情况
     * @return
     */
    @Override
    public ServerResponse<Map<String, Object>> countCityData() {
    
    
        //1.查询各个城市招聘情况 , 创建一个对象封装查询的数据 list
        List<ConverterVo> cityPositionList = mapper.countCityPosition();

        //2.创建一个Map<String,Object> 存放总数据
        Map<String , Object> map = new HashMap<>();

        //3.创建3个List集合  cityNamesList 存放城市名称  ; thridList 前三名城市数据  dataList 存放是个城市数据
        List<String> cityNamesList = new ArrayList<>();
        List<ConverterVo> thridList = new ArrayList<>();
        List<ConverterVo> dataList = new ArrayList<>();

        //4.循环list ,给cityNamesList   thridList  dataList  封装数据
        for (ConverterVo converterVo : cityPositionList) {
    
    
            //设置城市名称
            cityNamesList.add(converterVo.getName());
            //设置thridList
            if(thridList.size() < 3 ){
    
    
                thridList.add(converterVo);
            }
            //设置dataList
            dataList.add(converterVo);
        }

        //5.把3个list的数据村道map中
        map.put("cityNamesList",cityNamesList);
        map.put("thridList",thridList);
        map.put("dataList",dataList);

        //6.把map中的数据放到serverresponse中返回
        return ServerResponse.createBySuccessData(map);
    }
}

ConverterVo ,目的封装查询的数据 list

package com.lagou.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data //get、set
@AllArgsConstructor //有参构造
@NoArgsConstructor  //无参构造
public class ConverterVo {
    
    
    private String name;
    private String value;
}

IdustryMapper

package com.lagou.mapper;

import com.lagou.vo.ConverterVo;

import java.util.List;

public interface IdustryMapper {
    
    

    /**
     * 统计各个城市招聘情况
     * @return
     */
    public List<ConverterVo> countCityPosition();
}

IdustryMapper.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="com.lagou.mapper.IdustryMapper">

    <!--  1.统计各个城市招聘人数情况 top10 -->
    <select id="countCityPosition" resultType="ConverterVo">
        SELECT position_city as name ,COUNT(*) as value FROM position_info_v2
        WHERE position_city != ''
        GROUP BY position_city  ORDER BY value DESC
        LIMIT 10
    </select>

</mapper>

3)前后台联调
编写页面recruitment.html
a.引入echats.js文件

<script src="dist/js/echarts.min.js"></script>

b.创建一个div展示区域

<div class="panel-body"> 
	<div id="main" style="height: 700px"></div> 
</div>

c.前台发送异步ajax请求

<script>
	//1.创建echats对象
	var myChart = echarts.init(document.getElementById("main"));

	//2.发送ajax请求 获取后台的数据
	$.post("/lg_visualization/industry/countCityPosition.do",function(data){
     
     
		//3.在回调函数中设置option
		myChart.setOption({
     
     
			tooltip: {
     
          //提示组件
				trigger: 'item',  //触发类型:  item 如果是散点图 饼图
				formatter: '{a} <br/>{b}: {c} ({d}%)'  //代表提示悬浮窗的格式  {a} {b} {c} 分别代表系列名  数据名 数值
			},
			legend: {
     
        //图例组件
				orient: 'vertical',  //代表布局方式  vertical 水平布局
				left: 10,   //图例举例容器左边10像素
				data: data.data.cityNamesList
			},
			series: [  //系列列表
				{
     
     
					name: '各个城市招聘人数',  //系列名称
					type: 'pie',             //图表类型  pie饼图
					selectedMode: 'single',  //选中模式 : single 选择单个
					radius: [0, '30%'],      //代表图表的半径

					label: {
     
             //饼图标签上的信息
						position: 'inner'   // 饼图扇区内部展示信息
					},
					labelLine: {
     
        //标签视觉的引导线
						show: false   //关闭视觉引导线
					},
					data: data.data.thridList   //内部饼图的数据
				},
				{
     
     
					name: '各个城市招聘人数',
					type: 'pie',
					radius: ['40%', '55%'],  //外层的饼图
					label: {
     
     
						formatter: '{a|{a}}{abg|}\n{hr|}\n  {b|{b}:}{c}  {per|{d}%}  ',
						backgroundColor: '#eee',
						borderColor: '#aaa',
						borderWidth: 1,
						borderRadius: 4,
						rich: {
     
         //自定义富文本样式
							a: {
     
     
								color: '#999',
								lineHeight: 22,
								align: 'center'
							},
							hr: {
     
     
								borderColor: '#aaa',
								width: '100%',
								borderWidth: 0.5,
								height: 0
							},
							b: {
     
     
								fontSize: 16,
								lineHeight: 33
							},
							per: {
     
     
								color: '#eee',
								backgroundColor: '#334455',
								padding: [2, 4],
								borderRadius: 2
							}
						}
					},
					data: data.data.dataList  //外层饼图的数据
				}
			]
		})
	},"json");
</script>

4.4.热门行业统计

1)热门行业统计需求分析
同一个各个行业招聘人数top10 ,显示柱状图,具体如下:
在这里插入图片描述
2) 热门行业招聘信息接口

  • 请求路径:industryTop.do
  • 请求方法:post
  • 请求接口

http://localhost:8080/lg_visualization/industry/industryTop.do
在这里插入图片描述
在这里插入图片描述
后台代码实现
IndustryController

/**
     * 2.热门行业top10
     */
    @RequestMapping(value = "industryTop.do",method = RequestMethod.POST)
    @ResponseBody
    public ServerResponse<Map<String,Object>> getIndustryTop(){
    
    
        ServerResponse<Map<String,Object>> response =  iIndustryService.getIndustryTop10();
        return response;
    }

IIndustryService

/**
     * 2.热门行业top10
     */
    ServerResponse<Map<String, Object>> getIndustryTop10();

IndustryServiceImpl

/**
     * 2.热门行业top10
     */
    @Override
    public ServerResponse<Map<String, Object>> getIndustryTop10() {
    
    
        //1.查询最热门的10个行业  List<IndustryVo>
        List<IndustryVo> list =  mapper.countIndustryTop();

        //2.创建map 封装所有数据
        Map<String,Object> map = new HashMap<>();

        //3.创建两个list  namesList 放行业名称   countList 行业数量
        List<String> industryNames = new ArrayList<>();
        List<Long> countList = new ArrayList<>();

        //4.循环给list设置数据
        for (IndustryVo industryVo : list) {
    
    
            industryNames.add(industryVo.getPositionName());
            countList.add(industryVo.getNum());
        }

        //5.list存在map中
        map.put("names",industryNames);
        map.put("count",countList);

        //6.map放到ServerResponse
        return ServerResponse.createBySuccessData(map);
    }

IdustryMapper

/**
     * 2.热门行业top10
     */
    List<IndustryVo> countIndustryTop();

IdustryMapper.xml

<!-- 2.统计热门行业top10   -->
    <select id="countIndustryTop" resultType="IndustryVo">
        SELECT DISTINCT position_type_name  positionName, SUM(position_num)  AS num
        FROM position_type_info_v2
        GROUP BY position_type_name ORDER BY num DESC LIMIT 10;
    </select>
  1. 前后台联调
    编写页面industryTop.html
    a.引入echats.js文件
<script src="dist/js/echarts.min.js"></script>

b.创建一个div展示区域

<div class="panel-body"> 
<div id="main" style="height: 700px"></div> 
</div>

c.前台发送异步ajax请求

<script>
		//1.创建echarts对象
		var mychart = echarts.init(document.getElementById("main"));

		//2.发送ajax请求
		$.post("/lg_visualization/industry/industryTop.do",function(data){
     
     
			//3.在回调函数中设置 option
			mychart.setOption({
     
     
				tooltip: {
     
         //提示组件
					trigger: 'axis',  //如果是柱状图或折线图触发
					axisPointer: {
     
         //坐标轴指示配置项
						type: 'shadow'  // 默认值 line    shadow 阴影指示器
					}
				},
				grid: {
     
          //直角坐标系网络 ,网络中绘制折线图  柱状图 ...
					left: '3%',   //组件举例左侧容器举例
					right: '4%',
					bottom: '3%',
					containLabel: true //grid 区域是否有坐标轴的刻度
				},
				xAxis: {
     
     
					type: 'value',  //数值轴
					boundaryGap: [0, 0.01]
				},
				yAxis: {
     
     
					type: 'category', //类目轴
					data: data.data.names
				},
				series: [
					{
     
     
						name: '招聘数量',
						type: 'bar',  //柱状图
						data: data.data.count,
						label: {
     
       //图形上添加文字标签
							show:true , //是否在标签上展示
							position: 'insideRight' //标签数据展示位置
						}
					}
				]
			});
		},"json")



	</script>

4.5 热门行业招聘对比统计

4.5.1 热门行业招聘对比统计需求分析

使用面积图展示销售业、服务业、生产制造业的招聘数量图表
在这里插入图片描述

4.5.2 热门行业招聘对比统计接口

请求路径:industryCompare.do
请求方法:post
请求接口:
http://localhost:8080/lg_visualization/industry/industryCompare.do
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
后台代码实现
IndustryController

/**
     * 3.热门行业对比图
     */
    @RequestMapping(value = "industryCompare.do",method = RequestMethod.POST)
    @ResponseBody
    public ServerResponse<Map<String,Object>> getIndustryCompare(){
    
    
        ServerResponse<Map<String,Object>> response = iIndustryService.getIndustryCompare();
        return response;
    }

IIndustryService

ServerResponse<Map<String, Object>> getIndustryCompare();

Const

package com.lagou.common;

public class Const {
    
    
    public static final String[] INDUSTRY = {
    
    "销售","服务业","生产制造"};
    public static final String START_DATE = "2020-06-04 00:00:00";
    public static final String END_DATE = "2020-06-09 23:59:59";
    public static final String[] DATE_TIME = {
    
    "2020-06-04","2020-06-05","2020-06-06","2020-06-07","2020-06-08","2020-06-09"};
}

IndustryServiceImpl

/**
     * 3.热门行业对比图
     * 统计 热门行业(销售 服务业 生产制造) 在2020-6-4 到2020-6-9 招聘信息对比
     */
    @Override
    public ServerResponse<Map<String, Object>> getIndustryCompare() {
    
    
        //1.创建一个MAP集合,封装所有数据
        Map<String,Object> map = new HashMap<>();

        //2.循环行业
        for (String industryName: Const.INDUSTRY
             ) {
    
    
            //创建List<Long> 存放行业每天的招聘情况
            List<Long> countNumList = new ArrayList<>();
            List<IndustryVo> dataList = mapper.getIndustryData(industryName,Const.START_DATE,Const.END_DATE);

            //4.循环dataList ,目的是给countNumList 设置数据
            for (IndustryVo industryVo :dataList
                 ) {
    
    
                countNumList.add(industryVo.getNum());
            }

            //5.判断行业,给MAP设置值
            if(industryName.equals(Const.INDUSTRY[0])){
    
    
                map.put("sell",countNumList);
            }else if(industryName.equals(Const.INDUSTRY[1])){
    
    
                map.put("server",countNumList);
            }else if(industryName.equals(Const.INDUSTRY[2])){
    
    
                map.put("pro",countNumList);
            }

            map.put("dateTime",Const.DATE_TIME);
            map.put("industryNameList",Const.INDUSTRY)


        }
        return ServerResponse.createBySuccessData(map);
    }

IdustryMapper

/**
     * 3.热门行业对比图
     */
    List<IndustryVo> getIndustryData(@Param("industryName") String industryName,@Param("startDate") String startDate,@Param("endDate") String endDate);

IdustryMapper.xml
这里需要注意 >= 用 & gt;= ;<= 用 & lt;=

<!-- 3.热门行业对比图 -->
    <select id="getIndustryData" resultType="IndustryVo">
        SELECT position_type_name AS positionName, SUM(position_num) AS num , DATE_FORMAT(update_time,'%Y-%m-%d') AS theDay
        FROM position_type_info_v2
        WHERE position_type_name = #{industryName}
        AND update_time &gt;= #{startDate} AND update_time &lt;= #{endDate}
        GROUP BY theDay;
    </select>

4.5.3 前后台联调

编写页面industry.html
1)创建一个div展示区域

<div class="panel-body"> 
	<div id="main" style="height: 670px"></div> 
	</div>

2)前台发送异步ajax请求

<script>
	//1.创建echart对象
		var mychart = echarts.init(document.getElementById("main"));

		//2.发送ajax请求
		$.post("/lg_visualization/industry/industryCompare.do",function(data){
     
     
			//3.设置option
			mychart.setOption({
     
     
				title: {
     
     
					text: '统计行业招聘对比'
				},
				tooltip: {
     
     
					trigger: 'axis',
					axisPointer: {
     
     
						type: 'cross',
						label: {
     
     
							backgroundColor: '#6a7985'
						}
					}
				},
				legend: {
     
     
					data: data.data.industryNameList
				},
				toolbox: {
     
     
					feature: {
     
     
						saveAsImage: {
     
     }
					}
				},
				grid: {
     
     
					left: '3%',
					right: '4%',
					bottom: '3%',
					containLabel: true
				},
				xAxis: [
					{
     
     
						type: 'category',
						boundaryGap: false,
						data: data.data.dateTime
					}
				],
				yAxis: [
					{
     
     
						type: 'value'
					}
				],
				series: [
					{
     
     
						name: '销售',
						type: 'line',
						stack: '总量',
						smooth : true, //是否平滑展示
						areaStyle: {
     
     },
						data: data.data.sell,
						label: {
     
       //给图形上添加文本标签
							normal :{
     
     
								show : true, //是否显示标签
								position : 'top' //数据展示的位置
							}
						}
					},
					{
     
     
						name: '服务业',
						type: 'line',
						stack: '总量',
						smooth : true, //是否平滑展示
						areaStyle: {
     
     },
						data: data.data.server,
						label: {
     
       //给图形上添加文本标签
							normal :{
     
     
								show : true, //是否显示标签
								position : 'top' //数据展示的位置
							}
						}
					},
					{
     
     
						name: '生产制造',
						type: 'line',
						stack: '总量',
						smooth : true, //是否平滑展示
						areaStyle: {
     
     },
						data: data.data.pro,
						label: {
     
       //给图形上添加文本标签
							normal :{
     
     
								show : true, //是否显示标签
								position : 'top' //数据展示的位置
							}
						}
					}
				]
			});
		},"json")

</script>

五.应聘者信息统计

5.1 各个学历下的岗位统计需求分析

通过柱状图和饼状图统计公司需要的就业人员学历情况,及各个学历占比情况
在这里插入图片描述

5.2 统计学历对应岗位接口

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
后台代码实现
EduController

package com.lagou.controller;

import com.lagou.common.ServerResponse;
import com.lagou.service.IEduService;
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 java.util.Map;

@Controller
@RequestMapping("/edu")
public class EduController {
    
    

    @Autowired
    private IEduService service;

    /**
     * 获取不同学历下的岗位数量
     */
    @RequestMapping("eduCount.do")
    @ResponseBody
    public ServerResponse<Map<String,Object>> getEduCount(){
    
    
        ServerResponse<Map<String,Object>> response = service.getEduData();
        return response;
    }
}


IEduService

package com.lagou.service;

import com.lagou.common.ServerResponse;

import java.util.Map;

public interface IEduService {
    
    
    /**
     * 统计不同学历下的岗位数量
     * @return
     */
    public ServerResponse<Map<String, Object>> getEduData();
}

EduServiceImpl

package com.lagou.service.impl;

import com.lagou.common.ServerResponse;
import com.lagou.mapper.EduMapper;
import com.lagou.service.IEduService;
import com.lagou.vo.ConverterVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class EduServiceImpl implements IEduService {
    
    

    @Autowired
    private EduMapper mapper;

    /**
     * 统计不同学历对应的岗位数量
     * @return
     */
    @Override
    public ServerResponse<Map<String, Object>> getEduData() {
    
    

        //1.创建一个Map集合存放数据
        Map<String,Object> dataMap = new HashMap<>();
        //2.查询数据库, List<ConverterVo>
        // 结果视图封装到ConverterVo中
        List<ConverterVo> list = mapper.getEdu();

        //3.创建两个List集合  namesList 存放名称集合    countList 存放不同的学历招聘个数
        // 下面的数量, 对应ConverterVo中的属性类型, 写成String类型, Mybatis会自动转换
        List<String> namesList = new ArrayList<>();
        List<String> countList = new ArrayList<>();

        //4.循环List<ConverterVo> ; 把数据给nameList countList设置
        for (ConverterVo vo : list) {
    
    
            namesList.add(vo.getName());
            countList.add(vo.getValue());
        }

        //5.把3个list存放到map
        dataMap.put("names",namesList);
        dataMap.put("countNum",countList);
        dataMap.put("eduData",list);

        //6.把map放到ServerResponse返回
        return ServerResponse.createBySuccessData(dataMap);
    }
}

EduMapper

package com.lagou.mapper;

import com.lagou.vo.ConverterVo;

import java.util.List;

public interface EduMapper {
    
    
    /**
     * 统计不同学历下的岗位
     * @return
     */
    List<ConverterVo> getEdu();
}

EduMapper.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="com.lagou.mapper.EduMapper">
    <!-- 1.统计不同学历下的岗位数量   -->
    <!--下面的 edu 和 count 必须要分别起别名, 和ConverterVo中的属性名一致, 才自动封装-->
    <select id="getEdu" resultType="ConverterVo">
        SELECT edu name, COUNT(*) value
        FROM position_info_v2
        WHERE edu IN ('中专/中技','初中及以下','博士','大专','本科','硕士','高中')
        GROUP BY edu
    </select>
</mapper>

前后台联调
编写页面edu.html
1)创建一个div展示区域

<div class="panel-body" > 
	<div id="main1" style="height: 550px"></div> 
</div>

<script>
		//1.创建2个echarts对象
		var myChart1 = echarts.init(document.getElementById("main1"));
		var myChart2 = echarts.init(document.getElementById("main2"));

		//2.发送ajax请求
		$.post("/lg_visualization/edu/eduCount.do",function(data){
     
     
			//3.回调函数中,设置两个echarts option
			myChart1.setOption({
     
     
				color: ['#3398DB'],
				tooltip: {
     
     
					trigger: 'axis',
					axisPointer: {
     
                 // 坐标轴指示器,坐标轴触发有效
						type: 'shadow'        // 默认为直线,可选为:'line' | 'shadow'
					}
				},
				grid: {
     
     
					left: '3%',
					right: '4%',
					bottom: '3%',
					containLabel: true //grid 区域是否包含坐标轴的刻度标签
				},
				xAxis: [
					{
     
     
						type: 'category',
						data: data.data.names,
						axisTick: {
     
        //配置坐标轴刻度
							alignWithLabel: true  //true 有效,保证刻度线和标签对齐
						}
					}
				],
				yAxis: [
					{
     
     
						type: 'value'
					}
				],
				series: [
					{
     
     
						name: '岗位人数',
						type: 'bar',  //柱状图
						label: {
     
          //图上添加文字
							show: true,
							position: 'inside'
						},
						barWidth: '60%',
						data: data.data.countNum
					}
				]
			});

			myChart2.setOption({
     
     
				tooltip: {
     
     
					trigger: 'item',
					formatter: '{a} <br/>{b} : {c} ({d}%)'
				},
				legend: {
     
     
					orient: 'vertical',
					left: 'left',
					data: data.data.names
				},
				series: [
					{
     
     
						name: '学历占比',
						type: 'pie',
						radius: '55%',  //代表饼图的半径
						center: ['50%', '60%'],  //饼图圆心的坐标
						data: data.data.eduData,
						emphasis: {
     
        //高亮扇区和标签的样式
							itemStyle: {
     
     
								shadowBlur: 10,
								shadowOffsetX: 0,
								shadowColor: 'rgba(0, 0, 0, 0.5)'
							}
						}
					}
				]
			});
		},"json")




	</script>

六、全国招聘信息

6.1.全国各省招聘需求分析

以地图的方式展示每个省份的招聘人数
在这里插入图片描述

6.2. 统计各全国各省招聘接口

  • 请求路径:mapData
  • 请求方法:post
  • 请求接口:http://localhost:8080/lg_visualization/map/mapData.do
  • 请求参数:无
  • 响应参数
    在这里插入图片描述
  • 成功响应数据
{
    
    
	"status":0,
	"data": [
		{
    
    
			"name": "北京",
			"value": 255
		},
		{
    
    
			"name": "上海",
			"value": 121
		},
		{
    
    
			"name": "天津",
			"value": 150
		},
		{
    
    
			"name": "重庆",
			"value": 85
		},
		{
    
    
			"name": "黑龙江",
			"value": 16
		},
		...
		{
    
    
			"name": "台湾",
			"value": 0
		}
	]
}

后台代码实现
在这里插入图片描述
在这里插入图片描述
sql

-- 1. 查询每个城市有多少招聘岗位
SELECT position_city cName, COUNT(*) num
FROM position_info_v2
WHERE position_city != ''
GROUP BY position_city
ORDER BY num DESC;
 
-- 2. 查询每个省有多少个城市
SELECT p.`ProvinceID`, p.`NAME` NAME, c.`NAME` cName
FROM Province p
LEFT JOIN City c
ON c.`ProvinceID`=p.`ProvinceID`;

Controller

package com.lagou.controller;

import com.lagou.common.ServerResponse;
import com.lagou.service.ICountryMapService;
import com.lagou.vo.ProvinceVo;
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.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;

@Controller
@RequestMapping("/map")
public class CountryMapController {
    
    
    @Autowired
    private ICountryMapService service;

    /**
     * 统计各省的招聘人数
     */
    @RequestMapping(value = "mapData.do",method = RequestMethod.POST)
    @ResponseBody
    public ServerResponse<List<ProvinceVo>>  countProvinceData(){
    
    
        ServerResponse<List<ProvinceVo>> response = service.getMapData();
        return response;
    }
}

将各个市的招聘人数汇总为个省招聘人数
a.封装省份:ProvinceVo

package com.lagou.vo;

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

/**
 * 省的视图对象
 * 作用1: 查找数据库的时候,数据映射
 * 作用2: 把省份 对应的招聘人数,返回给前台  long 招聘人数
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ProvinceVo {
    
    
    @JsonIgnore //代表pid不返回给前台,相当于@JsonIgnoreProperties(value = "{pid}")
    private int pid;  //省编号
    private String name; //省名称
    private long value; //该省份的招聘人数
    @JsonIgnore
    private List<CityVo> city;
}

b.封装城市 CityVo

package com.lagou.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 城市的视图对象
 *
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CityVo {
    
    
    private int cid;   //城市的id
    private String cName; //城市名称
    private long num;   //城市招聘数量
}

c.定义转换器类CityProvinceConverter,将CityVo中的人数累加到ProvinceVo中

package com.lagou.common;

import com.lagou.vo.CityVo;
import com.lagou.vo.ProvinceVo;

import java.util.ArrayList;
import java.util.List;

/**
 * 转换器类
 * 将CityVo中的人数累加到ProvinceVo中
 */
public class CityProvinceConverter {
    
    
    /**
     * 作用:  cityList 中的招聘数 ===> provinceVoList 中的value值中
     * @param cityList
     * @param provinceVoList
     * @return
     */
    public static List<ProvinceVo> converter(List<CityVo> cityList, List<ProvinceVo> provinceVoList) {
    
    
        //cityList  [ {北京  255  }, {上海 300 , 杭州 100} ]

        //provinceVoList  [{浙江  0 [杭州,宁波..]} ,{浙江  0 [杭州,宁波..]}]
        //1.循环省
        flag:   for (ProvinceVo provinceVo : provinceVoList) {
    
    
            //统计每一个省的招聘数量
            long sumCount = 0;
            String provinceVoName = provinceVo.getName();
            List<CityVo> pCityList = provinceVo.getCity();
            //用来装省中的城市的名称
            List<String> pCityNameList = new ArrayList<>();
            for (CityVo cityVo : pCityList) {
    
    
                //填充城市的名称
                pCityNameList.add(cityVo.getCName());
            }

            //循环cityList
            for (CityVo cityVo : cityList) {
    
    
                //判断有些有些省的名称不要是 北京  上海  还有天津 重庆...
                if(provinceVoName.equals("北京") && cityVo.getCName().equals("北京")){
    
    
                    //给北京设置招聘人数
                    provinceVo.setValue(cityVo.getNum());
                    continue flag;
                } else if(provinceVoName.equals("上海") && cityVo.getCName().equals("上海")){
    
    
                    provinceVo.setValue(cityVo.getNum());
                    continue flag;
                } else if(provinceVoName.equals("天津") && cityVo.getCName().equals("天津")){
    
    
                    provinceVo.setValue(cityVo.getNum());
                    continue flag;
                } else if(provinceVoName.equals("重庆") && cityVo.getCName().equals("重庆")){
    
    
                    provinceVo.setValue(cityVo.getNum());
                    continue flag;
                } else {
    
    
                    //如果省份的名称集合包含城市的名字,累加sumCount 设置给provinceVo
                    if(pCityNameList.contains(cityVo.getCName())){
    
    
                        sumCount += cityVo.getNum();
                    }
                }
                provinceVo.setValue(sumCount);
            }

        }
        return provinceVoList;
    }
}

ICountryMapService

package com.lagou.service;

import com.lagou.common.ServerResponse;
import com.lagou.vo.ProvinceVo;

import java.util.List;

public interface ICountryMapService {
    
    

    /**
     * 统计各个省份的招聘人数
     * @return
     */
    ServerResponse<List<ProvinceVo>> getMapData();
}

CountryMapServiceImpl

package com.lagou.service.impl;

import com.lagou.common.CityProvinceConverter;
import com.lagou.common.ServerResponse;
import com.lagou.mapper.CountryMapMapper;
import com.lagou.service.ICountryMapService;
import com.lagou.vo.CityVo;
import com.lagou.vo.ProvinceVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 统计各个省份的招聘人数
 */
@Service
public class CountryMapServiceImpl implements ICountryMapService {
    
    

    @Autowired
    private CountryMapMapper mapper;

    /**
     * 统计各省招聘人数
     * @return
     */
    @Override
    public ServerResponse<List<ProvinceVo>> getMapData() {
    
    
        //1.查询各个省份有哪些城市  List<ProvinceVo>   没有城市, 招聘数量0
        List<ProvinceVo>  provinceVoList = mapper.queryProvinceCity();

        //2.查询每个城市招聘数量 List<CityVo>  有城市招聘数量
        List<CityVo>  cityList = mapper.queryCityNum();

        //3.调用转换类的转换方法,传递 List<ProvinceVo>  List<CityVo>  --->  CityVo中的人数累加到ProvinceVo中
        List<ProvinceVo> provinceVos = CityProvinceConverter.converter(cityList,provinceVoList);

        //4.返回ServerResponse ,把List<ProvinceVo>放到response中
        return ServerResponse.createBySuccessData(provinceVos);
    }
}

CountryMapMapper

package com.lagou.mapper;

import com.lagou.vo.CityVo;
import com.lagou.vo.ProvinceVo;

import java.util.List;

public interface CountryMapMapper {
    
    
    /**
     * 查询各个省份有哪些城市
     * @return
     */
    public List<ProvinceVo> queryProvinceCity() ;

    /**
     * 查询每个城市招聘数量
     * @return
     */
    List<CityVo> queryCityNum();
}

CountryMapMapper.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="com.lagou.mapper.CountryMapMapper">

    <!-- 身份城市一对多关系映射 -->
    <!-- autoMapping="true" 作用是属性和字段名相同时, 下面可以不进行该映射配置 -->
    <resultMap id="provinceResultMap" type="ProvinceVo" autoMapping="true">
        <!-- 主键映射      -->
        <id column="ProvinceID" property="pid"/>
        <!-- 普通字段映射  autoMapping="true"时,下面属性名和字段名相同,可以省略    -->
        <result column="name" property="name"/>
        <!-- 映射集合数据类型       -->
        <collection property="city" javaType="list"  ofType="CityVo" autoMapping="true">
            <!-- 主键映射  -->
            <id column="CityID" property="cid" />
        </collection>

    </resultMap>

    <!--  1.查询省份有多少个城市  -->
    <select id="queryProvinceCity" resultMap="provinceResultMap">
        SELECT p.ProvinceID , p.Name  NAME , c.NAME cName
        FROM Province p
        LEFT JOIN City c
        ON c.ProvinceID = p.ProvinceID
    </select>

    <!--  2.城市有多少个招聘岗位-->
    <select id="queryCityNum" resultType="CityVo">
        SELECT position_city cName ,COUNT(*) num
        FROM position_info_v2
        WHERE position_city != ''
        GROUP BY position_city  ORDER BY num DESC
    </select>

</mapper>

前后台联调
编写页面map.html
1)创建一个div展示区域

<div class="panel-wrapper collapse in" >
	<!--图表区域-->
	<div id="main" style="width: 800px; height: 700px; margin-left: 300px" ></div>
</div>

<script>
	var myChart = echarts.init(document.getElementById('main'));
	//执行图表的配置和数据
	var titleName = "2020年全国各个城市招聘数量";
	var mapName = "china";

	$.post("/lg_visualization/map/mapData.do",function(data){
     
     
		myChart.setOption({
     
     
			title: {
     
     
				text: titleName,
				x: 'center',
				textStyle: {
     
     
					fontSize: 24
				}
			},
			tooltip: {
     
         //提示框组件
				trigger: "item",  //数据项图形触发,主要在散点图,饼图等无类目轴的图表中使用
				//提示框浮层内容格式器,支持字符串模板和回调函数两种形式。
				formatter: function (params) {
     
     
					return params.name + "招聘人数:" + params.value + "人";
				}
			},
			toolbox: {
     
     
				feature: {
     
        //各工具配置项
					saveAsImage: {
     
     }  //保存为图片
				}
			},
			visualMap: {
     
       //是视觉映射组件
				show: true,  //是否显示 visualMap-piecewise 组件
				left: "left",//visualMap 组件离容器左侧的距离
				top: "bottom",   //visualMap 组件离容器上侧的距离
				seriesIndex: [0],  //指定取哪个系列的数据,即哪个系列的
				type: "piecewise",  //分段型视觉映射组件
				pieces: [ //分段式视觉映射组件的每一段的范围
					{
     
     ge : 30000},  //设置大于10000人数
					{
     
     ge :10000 , lte: 29999}, //设置人数1000-9999
					{
     
     ge :  5000, lte : 9999} ,
					{
     
     ge : 1000 , lte :  4999},
					{
     
     ge : 0 , lte : 999}
				],
				inRange : {
     
      //定义 在选中范围中 的视觉元素
					color : ['rgb(168,188,180)','rgb(141,188,180)', 'rgb(200,200,160)' , 'rgb(249,207,178)' , 'rgb(254,57,101)']
				},
				textStyle: {
     
     
					color: "#000000"
				}
			},
			geo: {
     
       //地理坐标系组件
				show: true,  //是否显示地理坐标系组件
				map: mapName,  //地图类型。
				label: {
     
      //图形上的文本标签,可用于说明图形的一些数据信息
					normal: {
     
     
						show: true,
						fontSize: 12
					},
					emphasis: {
     
     
						show: true
					}
				},
				roam: false, //是否开启鼠标缩放和平移漫游。默认不开启
				itemStyle : {
     
     
					normal: {
     
      //普通状态下样式
						areaColor: "#FFFFFF",
						borderColor: "#666666",
					},
					emphasis: {
     
      //高亮状态下的多边形和标签样式。
						areaColor: "#0099CC"  //地图区域的颜色。
					}
				}
			},
			series: [
				{
     
     
					type: "map",
					map: mapName,
					geoIndex: 0, // geoIndex 指定一个 geo 组件
					animation: false,  //是否开启动画。
					data:data.data
				},
			]
		})
	})

</script>

6.3.首页大屏展示图表

在这里插入图片描述
实现方式:
创建bigSreen.html ,在该页面使用iframe引入 recruitment.html , map.html , industryCompare.html
下面是bigSreen.html 代码细节
在这里插入图片描述
bigSreen.html
在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
	<title>Elmer I Fast build Admin dashboard for any platform</title>
	<meta name="description" content="Elmer is a Dashboard & Admin Site Responsive Template by hencework." />
	<meta name="keywords" content="admin, admin dashboard, admin template, cms, crm, Elmer Admin, Elmeradmin, premium admin templates, responsive admin, sass, panel, software, ui, dwh, web app, application" />
	<meta name="author" content="hencework"/>

	<!-- Morris Charts CSS -->
    <link href="vendors/bower_components/morris.js/morris.css" rel="stylesheet" type="text/css"/>
	<!-- Calendar CSS -->
	<link href="vendors/bower_components/fullcalendar/dist/fullcalendar.css" rel="stylesheet" type="text/css"/>
	<!-- bootstrap-select CSS -->
	<link href="vendors/bower_components/bootstrap-select/dist/css/bootstrap-select.min.css" rel="stylesheet" type="text/css"/>
	<!-- switchery CSS -->
	<link href="vendors/bower_components/switchery/dist/switchery.min.css" rel="stylesheet" type="text/css"/>
	<!-- Data table CSS -->
	<link href="vendors/bower_components/datatables/media/css/jquery.dataTables.min.css" rel="stylesheet" type="text/css"/>
	<!-- Custom CSS -->
	<link href="dist/css/style.css" rel="stylesheet" type="text/css">
</head>

<body>
	<!--Preloader-->
	<div class="preloader-it">
		<div class="la-anim-1"></div>
	</div>
	<!--/Preloader-->
    <div class="wrapper  theme-1-active pimary-color-blue" id="app">
        <!-- Main Content -->
				<!-- Row -->
				<div class="row">
					<div class="col-lg-6 col-md-12 col-sm-12 col-xs-12">
						<div class="panel panel-default card-view panel-refresh">
							<div class="refresh-container">
								<div class="la-anim-1"></div>
							</div>
							<div class="panel-heading">
								<div class="pull-left">
									<h6 class="panel-title txt-dark">各个城市招聘统计</h6>
								</div>
								<div class="pull-right">
									<a href="#" class="pull-left inline-block refresh mr-15">
										<i class="zmdi zmdi-replay"></i>
									</a>
								</div>
								<div class="clearfix"></div>
							</div>
							<div class="panel-wrapper collapse in">
								<div class="panel-body">
									<!-- 1.引入recruitment2 各个城市招聘信息 -->
									<iframe src="recruitment2.html" style="width: 600px;height: 378px" scrolling="no"></iframe>

								</div>
							</div>
						</div>
					</div>
					<div class="col-lg-6 col-md-12 col-sm-12 col-xs-12">
						<div class="panel panel-default card-view panel-refresh">
							<div class="refresh-container">
								<div class="la-anim-1"></div>
							</div>
							<div class="panel-heading">
								<div class="pull-left">
									<h6 class="panel-title txt-dark">全国各省招聘人数统计</h6>
								</div>
								<div class="pull-right">
									<a href="#" class="pull-left inline-block refresh mr-15">
										<i class="zmdi zmdi-replay"></i>
									</a>
								</div>
								<div class="clearfix"></div>
							</div>
							<div class="panel-wrapper collapse in">
								<div class="panel-body">
									<!-- 2.引入各个城市招聘地图 -->
									<iframe src="map2.html" style="width: 600px;height: 378px" scrolling="no"></iframe>

								</div>
							</div>
						</div>
					</div>
				</div>
				<!-- /Row -->

				<!-- Row -->
				<div class="row">
					<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
						<!-- 3.引入热门行业对比 -->
						<iframe src="industryCompare2.html" style="width: 1350px;height: 280px" scrolling="no"></iframe>

					</div>
				</div>
				<!-- /Row -->
        <!-- /Main Content -->

    </div>
    <!-- /#wrapper -->
	<!-- JavaScript -->
    <!-- jQuery -->
    <script src="vendors/bower_components/jquery/dist/jquery.min.js"></script>
    <!-- Bootstrap Core JavaScript -->
    <script src="vendors/bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
	<!-- Calender JavaScripts -->
	<script src="vendors/bower_components/moment/min/moment.min.js"></script>
	<script src="vendors/jquery-ui.min.js"></script>
	<script src="vendors/bower_components/fullcalendar/dist/fullcalendar.min.js"></script>
	<script src="dist/js/fullcalendar-data.js"></script>
	<!-- Progressbar Animation JavaScript -->
	<script src="vendors/bower_components/waypoints/lib/jquery.waypoints.min.js"></script>
	<script src="vendors/bower_components/jquery.counterup/jquery.counterup.min.js"></script>
	<!-- Data table JavaScript -->
	<script src="vendors/bower_components/datatables/media/js/jquery.dataTables.min.js"></script>
	<!-- Slimscroll JavaScript -->
	<script src="dist/js/jquery.slimscroll.js"></script>
	<!-- ChartJS JavaScript -->
	<script src="vendors/chart.js/Chart.min.js"></script>
	<!-- Fancy Dropdown JS -->
	<script src="dist/js/dropdown-bootstrap-extended.js"></script>
	<!-- Sparkline JavaScript -->
	<script src="vendors/jquery.sparkline/dist/jquery.sparkline.min.js"></script>
	<script src="vendors/bower_components/jquery.easy-pie-chart/dist/jquery.easypiechart.min.js"></script>
	<!-- Morris Charts JavaScript -->
    <script src="vendors/bower_components/raphael/raphael.min.js"></script>
    <script src="vendors/bower_components/morris.js/morris.min.js"></script>
    <script src="dist/js/morris-data.js"></script>
	<!-- Owl JavaScript -->
	<script src="vendors/bower_components/owl.carousel/dist/owl.carousel.min.js"></script>
	<!-- Bootstrap Select JavaScript -->
	<script src="vendors/bower_components/bootstrap-select/dist/js/bootstrap-select.min.js"></script>
	<!-- Switchery JavaScript -->
	<script src="vendors/bower_components/switchery/dist/switchery.min.js"></script>
	<!-- Init JavaScript -->
	<script src="dist/js/init.js"></script>
	<script src="dist/js/widgets-data.js"></script>
</body>

</html>

猜你喜欢

转载自blog.csdn.net/weixin_47134119/article/details/112075586