目录
第4章 行业信息模块
1.行业需求描述
从多个维度统计行业信息
1. 统计各个城市招聘人数,以饼状图方式展示个城市人数比例
2. 统计热门行业信息,以柱状图的方式展示前10个热门行业的招聘人数
3. 统计销售行业、服务业、生产制造行业招聘情况,使用面积图参考招聘这3个行业情况。
2.表结构分析
position_type_info_v2 职位类型信息表
position_info_v2 职位信息表
3.统计各个城市招聘人数
3.1 统计各个城市招聘人数需求分析
统计各个城市招聘人数,以饼状图方式展示个城市人数比例
3.2 统计各城市招聘接口
请求路径:countCityPosition
请求方法:post
请求接口 : http://localhost:8080/lg_visualization/industry/countCityPosition.do
请求参数
无
响应参数
成功响应数据
{
"status": 0,
"data": {
"thridList": [
{
"name": "北京",
"value": "255"
},
{
"name": "广州",
"value": "201"
},
{
"name": "杭州",
"value": "190"
}],
"dataList": [
{
"name": "北京",
"value": "255"
},
{
"name": "广州",
"value": "201"
},
{
"name": "杭州",
"value": "190"
},
{
"name": "深圳",
"value": "162"
},
{
"name": "天津",
"value": "150"
},
{
"name": "上海",
"value": "121"
},
{
"name": "南京",
"value": "116"
},
{
"name": "济南",
"value": "107"
},
{
"name": "成都",
"value": "95"
},
{
"name": "武汉",
"value": "94"
}],
"cityNamesList": [
"北京",
"广州",
"杭州",
"深圳",
"天津",
"上海",
"南京",
"济南",
"成都",
"武汉"
]
}
}
SQL
-- 统计各个城市职位的数量, 最终找到前十名
SELECT position_city, COUNT(*) cityPositionNum FROM position_info_v2
WHERE position_city != ''
GROUP BY position_city ORDER BY cityPositionNum DESC
LIMIT 10;
Controller
package com.lagou.controller;
@Controller
@RequestMapping("/industry")
public class IndustryController {
@Autowired
private IIdustryService iIdustryService;
/**
* 1.统计个各个城市招聘人数情况
* @return
*/
@RequestMapping("countCityPosition.do")
@ResponseBody
public ServerResponse<Map<String,Object>> countCityNums(){
ServerResponse<Map<String,Object>> response = iIdustryService.countCityData();
return response;
}
}
Service
package com.lagou.service;
public interface IIdustryService {
/**
* 1.统计各个城市招聘人数
* @return
*/
public ServerResponse<Map<String, Object>> countCityData() ;
}
package com.lagou.service.impl;
@Service
public class IdustryServiceImpl implements IIdustryService {
@Autowired
private IdustryMapper mapper;
/**
* 统计各个城市招聘情况
* @return
*/
@Override
public ServerResponse<Map<String, Object>> countCityData() {
//1.查询各个城市招聘情况 , 创建一个对象封装查询的数据 list
// ConverterVo属于转换对象, 存放数据库查询结果视图中的对象
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
package com.lagou.vo;
/**
* 转换对象: 把数据库中封装好的数据, 转换成 name:xx value:xxx
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ConverterVo {
private String name;
private String value;
}
Mapper
package com.lagou.mapper;
public interface IdustryMapper {
/**
* 统计各个城市招聘情况
* @return
*/
public List<ConverterVo> countCityPosition() ;
}
<?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 -->
<!-- 下面的position_city, COUNT(*) 要起别名, 才能适配Vo对象中的属性 -->
<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.3 前后台联调
编写页面recruitment.html
1)引入echats.js文件
<script src="dist/js/echarts.min.js"></script>
2)创建一个div展示区域
<div id="main" style="height: 700px"></div>
3)前台发送异步ajax请求
<script>
//1.创建echats对象
var myChart = echarts.init(document.getElementById("main"));
//2.发送ajax请求 获取后台的数据
$.post("/lg_visualization/industry/countCityPosition.do",function(data){
//3.在回调函数中设置option, 其中内容复制于echarts网站
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 ,显示柱状图,具体如下:
4.2 热门行业招聘信息接口
请求路径:industryTop.do
请求方法:post
请求接口: http://localhost:8080/lg_visualization/industry/industryTop.do
请求参数
无
响应参数
{
"status": 0,
"data": {
"names": [
"销售",
"技术",
"运营",
"教育培训",
"服务业",
"设计",
"人事/财务/行政",
"生产制造",
"传媒",
"房地产/建筑"
],
"count": [
538522,
533074,
367759,
338040,
290336,
261589,
258828,
211471,
165769,
160022
]
}
}
SQL
-- 统计热门行业top10 行业名称, 招聘数量
SELECT DISTINCT position_type_name, SUM(position_num) AS num
FROM position_type_info_v2
GROUP BY position_type_name ORDER BY num DESC
LIMIT 10;
Controller
package com.lagou.controller;
@Controller
@RequestMapping("/industry")
public class IndustryController {
@Autowired
private IIdustryService iIdustryService;
/**
* 2.热门行业top10
*/
@RequestMapping(value = "industryTop.do",method = RequestMethod.POST)
@ResponseBody
public ServerResponse<Map<String,Object>> getIndustryTop(){
ServerResponse<Map<String,Object>> response = iIdustryService.getIndustryTop10();
return response;
}
}
Service
package com.lagou.service;
public interface IIdustryService {
/**
* 2.热门行业top10
*/
ServerResponse<Map<String, Object>> getIndustryTop10();
}
package com.lagou.service.impl;
@Service
public class IdustryServiceImpl implements IIdustryService {
@Autowired
private IdustryMapper mapper;
/**
* 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);
}
}
IndustryVo
package com.lagou.vo;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class IndustryVo {
private String positionName; //行业名称
private long num; //行业招聘数量
//TODO
}
Mapper
package com.lagou.mapper;
public interface IdustryMapper {
List<IndustryVo> countIndustryTop();
}
<?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">
<!-- 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>
</mapper>
4.3 前后台联调
编写页面industryTop.html
1)引入echats.js文件
<script src="dist/js/echarts.min.js"></script>
2)创建一个div展示区域
<div class="panel-body">
<div id="main" style="height: 700px"></div>
</div>
3)前台发送异步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>
5.热门行业招聘对比统计
5.1 热门行业招聘对比统计需求分析
使用面积图展示销售业、服务业、生产制造业的招聘数量图表
5.2 热门行业招聘对比统计接口
请求路径:industryCompare.do
请求方法:post
请求接口 : http://localhost:8080/lg_visualization/industry/industryCompare.do
请求参数
无
响应参数
成功响应数据
{
"status": 0,
"data": {
"dateTime": [
"2020-06-04",
"2020-06-05",
"2020-06-06",
"2020-06-07",
"2020-06-08",
"2020-06-09"
],
"industryNameList": [
"销售",
"服务业",
"生产制造"
],
"server": [
20963,
66650,
76178,
72691,
52483,
1371
],
"sell": [
39908,
114492,
132010,
155163,
92080,
4869
],
"pro": [
15965,
49549,
52494,
56354,
36934,
175
]
}
}
SQL
-- 统计三个行业(销售, 服务, 生产制造) 在2020-6-4到2020-6-9 招聘人数情况
SELECT position_type_name NAME, SUM(position_num) num, DATE_FORMAT(update_time, '%Y-%m-%d') AS theDay
FROM position_type_info_v2
WHERE position_type_name = '销售'
AND `update_time` >= '2020-6-4' AND `update_time` <= '2020-6-9'
GROUP BY theDay;
SELECT position_type_name NAME, SUM(position_num) num, DATE_FORMAT(update_time, '%Y-%m-%d') AS theDay
FROM position_type_info_v2
WHERE position_type_name = '服务业'
AND `update_time` >= '2020-6-4' AND `update_time` <= '2020-6-9'
GROUP BY theDay;
SELECT position_type_name NAME, SUM(position_num) num, DATE_FORMAT(update_time, '%Y-%m-%d') AS theDay
FROM position_type_info_v2
WHERE position_type_name = '生产制造'
AND `update_time` >= '2020-6-4' AND `update_time` <= '2020-6-9'
GROUP BY theDay;
Controller
package com.lagou.controller;
@Controller
@RequestMapping("/industry")
public class IndustryController {
@Autowired
private IIdustryService iIdustryService;
/**
* 3.热门行业对比图
*/
@RequestMapping(value = "industryCompare.do",method = RequestMethod.POST)
@ResponseBody
public ServerResponse<Map<String,Object>> getIndustryCompare(){
ServerResponse<Map<String,Object>> response = iIdustryService.industryCompare();
return response;
}
}
Service
package com.lagou.service;
public interface IIdustryService {
/**
* 3.热门行业招聘对比图
* @return
*/
ServerResponse<Map<String, Object>> industryCompare();
}
package com.lagou.service.impl;
@Service
public class IdustryServiceImpl implements IIdustryService {
@Autowired
private IdustryMapper mapper;
/**
* 统计 热门行业(销售 服务业 生产制造) 在2020-6-4 到2020-6-9 招聘信息对比
* @return
*/
@Override
public ServerResponse<Map<String, Object>> industryCompare() {
//1.创建Map集合,封装最终的数据
Map<String,Object> map = new HashMap<>();
//3.循环行业
// 行业定义成常量
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);
}
}
Const
package com.lagou.common;
public class Const {
// 传递参数给SQL
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:23: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"};
}
IndustryVo
package com.lagou.vo;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class IndustryVo {
private String positionName; //行业名称
private long num; //行业招聘数量
@JsonFormat(pattern = "yyyy-MM-dd")
private Date theDay;
}
Mapper
package com.lagou.mapper;
public interface IdustryMapper {
/**
* 统计热门行业对比
* @param industryName
* @param startDate
* @param endDate
* @return
*/
// 多个参数传递, 用@Param注解
List<IndustryVo> getIndustryData(@Param("industryName") String industryName,
@Param("startDate") String startDate,
@Param("endDate") String endDate);
}
<?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">
<!-- 3.统计热门行业对比情况 -->
<!--下面的 > 是大于号 < 是小于号-->
<select id="getIndustryData" resultType="IndustryVo">
SELECT position_type_name positionName, SUM(position_num) num , DATE_FORMAT(update_time,'%Y-%m-%d') AS theDay
FROM position_type_info_v2
WHERE position_type_name = #{industryName}
AND update_time >= #{startDate}
AND update_time <= #{endDate}
GROUP BY theDay
</select>
</mapper>
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 各个学历下的岗位统计需求分析
通过柱状图和饼状图统计公司需要的就业人员学历情况,及各个学历占比情况
2 统计学历对应岗位接口
请求路径:eduCount .do
请求方法:post
请求接口 : http://localhost:8080/lg_visualization/edu/eduCount.do
请求参数
无
响应参数
成功响应数据
{
"status": 0,
"data": {
"names": [
"中专/中技",
"初中及以下",
"大专",
"本科",
"硕士",
"高中"
],
"countNum": [
204,
30,
1273,
1021,
21,
267
],
"eduData": [
{
"name": "中专/中技",
"value": "204"
},
{
"name": "初中及以下",
"value": "30"
},
{
"name": "大专",
"value": "1273"
},
{
"name": "本科",
"value": "1021"
},
{
"name": "硕士",
"value": "21"
},
{
"name": "高中",
"value": "267"
}
]
}
}
SQL
-- 统计不同学历下发布了多少岗位
SELECT edu, COUNT(*)
FROM position_info_v2
WHERE edu IN ('中专/中技', '初中及以下', '博士', '大专', '本科', '硕士', '高中')
GROUP BY edu;
Controller
package com.lagou.controller;
@Controller
@RequestMapping("/edu")
public class EduController {
@Autowired
private IEduService service;
/**
* 获取不同学历下的岗位数量
*/
@RequestMapping("/eduCount")
@ResponseBody
public ServerResponse<Map<String,Object>> getEduCount(){
ServerResponse<Map<String,Object>> response = service.getEduData();
return response;
}
}
Service
package com.lagou.service;
public interface IEduService {
/**
* 统计不同学历下的岗位数量
* @return
*/
ServerResponse<Map<String, Object>> getEduData();
}
package com.lagou.service.impl;
@Service
public class IdustryServiceImpl implements IIdustryService {
@Autowired
private IdustryMapper 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);
}
}
ConverterVo
package com.lagou.vo;
/**
* 转换对象: 把数据库中封装好的数据, 转换成 name:xx value:xxx
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ConverterVo {
private String name;
private String value;
}
Mapper
package com.lagou.mapper;
public interface EduMapper {
/**
* 统计不同学历下的岗位
* @return
*/
List<ConverterVo> getEdu();
}
<?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>
3 前后台联调
编写页面edu.html
1)创建一个div展示区域
<div id="main1" style="height: 700px"></div>
<div id="main2" style="height: 700px"></div>
2)前台发送异步ajax请求
<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.全国各省招聘需求分析
以地图的方式展示每个省份的招聘人数
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": 29
},
{
"name": "辽宁",
"value": 80
},
{
"name": "内蒙古",
"value": 15
},
{
"name": "宁夏",
"value": 17
},
{
"name": "新疆",
"value": 18
},
{
"name": "青海",
"value": 6
},
{
"name": "甘肃",
"value": 15
},
{
"name": "陕西",
"value": 65
},
{
"name": "河北",
"value": 144
},
{
"name": "河南",
"value": 142
},
{
"name": "山东",
"value": 369
},
{
"name": "山西",
"value": 54
},
{
"name": "湖北",
"value": 102
},
{
"name": "湖南",
"value": 101
},
{
"name": "安徽",
"value": 162
},
{
"name": "江苏",
"value": 315
},
{
"name": "浙江",
"value": 300
},
{
"name": "江西",
"value": 56
},
{
"name": "广东",
"value": 617
},
{
"name": "广西",
"value": 84
},
{
"name": "福建",
"value": 187
},
{
"name": "四川",
"value": 155
},
{
"name": "云南",
"value": 24
},
{
"name": "贵州",
"value": 12
},
{
"name": "西藏",
"value": 1
},
{
"name": "海南",
"value": 13
},
{
"name": "香港",
"value": 0
},
{
"name": "澳门",
"value": 0
},
{
"name": "台湾",
"value": 0
}
]
}
将各个市的招聘人数汇总为个省招聘人数
java
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;
@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;
}
}
ProvinceVo
package com.lagou.vo;
/**
* 省的视图对象
* 作用1: 查找数据库的时候,数据映射
* 作用2: 把省份 对应的招聘人数,返回给前台 long 招聘人数
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ProvinceVo {
@JsonIgnore // 序列化给前台, 加了该注解的字段, 自动忽略
private int pid; //省编号
private String name; //省名称
private long value; //该省份的招聘人数
@JsonIgnore
private List<CityVo> city; // 省中的市
}
CityVo
package com.lagou.vo;
/**
* 城市的视图对象
*
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CityVo {
private int cid; //城市的id
private String cName; //城市名称
private long num; //城市招聘数量
}
Service
package com.lagou.service;
public interface ICountryMapService {
/**
* 统计各个省份的招聘人数
* @return
*/
ServerResponse<List<ProvinceVo>> getMapData();
}
package com.lagou.service.impl;
@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);
}
}
Mapper
package com.lagou.mapper;
public interface CountryMapMapper {
/**
* 通过省份的城市
* @return
*/
List<ProvinceVo> queryProvinceCity();
/**
* 通过各个城市的招聘数量
* @return
*/
List<CityVo> queryCityNum();
}
<?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属性表示, 属性和字段名相同时, 下面可以不进行该映射配置 -->
<resultMap id="provinceResultMap" type="ProvinceVo" autoMapping="true" >
<!-- 主键映射 -->
<id column="ProvinceID" property="pid"></id>
<!-- 普通字段映射 -->
<result column="name" property="name"/>
<!-- 映射集合数据类型 -->
<collection property="city" javaType="list" ofType="CityVo" autoMapping="true">
<!-- 主键映射 -->
<id column="CityID" property="cid" />
</collection>
</resultMap>
<!-- 1.城市有多少个招聘岗位-->
<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>
<!-- 2.查询省份有多少个城市 -->
<!-- 一对多查询, 所以要手动映射 -->
<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>
</mapper>
Converter
package com.lagou.common;
/**
* 转换器类
*/
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
// cityList.for 可以直接获取该集合的增强循环
for (CityVo cityVo : cityList) {
//判断有些省的名称不要是 北京 上海 还有天津 重庆...
if(provinceVoName.equals("北京") && cityVo.getCName().equals("北京")){
//给北京设置招聘人数
provinceVo.setValue(cityVo.getNum());
// 省市名都是 北京 时, 直接跳出到flag进行下一个省的循环
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;
}
}
3. 前后台联调
编写页面map.html
1)创建一个div展示区域
<div id="main" style="width: 800px; height: 700px; margin-left: 300px" ></div>
2)前台发送异步ajax请求
<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>
4.首页大屏展示图表
实现方式:
创建bigSreen.html ,在该页面使用iframe引入 recruitment2.html map2.html industryCompare2.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>
第7章 项目部署
1.nginx介绍及使用
1.1 什么是nginx?
Nginx是一款轻量级的 Web服务器 , 反向代理服务器 及 电子邮件代理服务器 。
优点:
1. 占用内存少,并发能力强.
2. Nginx专为性能优化而开发, 在高连接并发的情况下,能够支持高达 50,000 个并发连接数的响应.
3. Nginx支持热部署, 可以在不间断服务的情况下,对软件版本进行升级.
1.2 应用场景
1. http服务器: Nginx是一个http服务可以独立提供http服务。可以做网页静态服务器。
2. 虚拟主机: 可以实现在一台服务器虚拟出多个网站。例如个人网站使用的虚拟主机。
3. 反向代理,负载均衡 : 当网站的访问量达到一定程度后,单台服务器不能满足用户的请求时,需要用多台服务器集群可以使用nginx做反向代理。并且多台服务器可以平均分担负载,不会因为某台服务器负载高宕机而某台服务器闲置的情况。
1.3 Nginx安装
下载nginx, 官方网站:http://nginx.org/en/download.html
我们使用的版本是1.17.8版本。
Nginx在Linux下安装,只提供了源代码,所以我们需要进行编译.
安装环境配置
1.因为Nginx是C语言编写的,所以需要配置C语言编译环境 (一定要在联网状态下安装)
需要安装gcc的环境。执行命令:
yum install gcc-c++
2.第三方的开发包, 在编译之前需要安装这些第三方包。
PCRE
nginx的http模块使用pcre来解析正则表达式,所以需要在linux上安装pcre库
安装命令:
yum install -y pcre pcre-devel
zlib
nginx使用zlib对http包的内容进行gzip,所以需要在linux上安装zlib库。
安装命令:
yum install -y zlib zlib-devel
openssl
OpenSSL 是一个强大的安全套接字层密码库,nginx不仅支持http协议,还支持https,所以需要在linux安装openssl库。
安装命令:
yum install -y openssl openssl-devel
安装Nginx 步骤
1. 将Nginx的源码包上传到 Linux
2. 解压Nginx
tar -xvf nginx-1.17.8.tar
1. 进入到解压之后的目录 nginx-1.17.8
1. 创建一个临时目录
mkdir /var/temp/nginx/client -p
2. 执行命令 configure,生成 Mikefile 文件
./configure \
--prefix=/usr/local/nginx \
--pid-path=/var/run/nginx/nginx.pid \
--lock-path=/var/lock/nginx.lock \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--with-http_gzip_static_module \
--http-client-body-temp-path=/var/temp/nginx/client \
--http-proxy-temp-path=/var/temp/nginx/proxy \
--http-fastcgi-temp-path=/var/temp/nginx/fastcgi \
--http-uwsgi-temp-path=/var/temp/nginx/uwsgi \
--http-scgi-temp-path=/var/temp/nginx/scgi
执行命令后, 生成了MakeFile文件
执行make命令,进行编译
make
安装
make install
启动并访问 Nginx
1. 进入到nginx 安装目录
cd /usr/local/nginx/
1. 进入到 sbin目录,执行 nginx 命令
./nginx 启动
./nginx -s stop 关闭
./nginx -s reload 重启
ps aux | grep nginx 查看进程
1. 通过浏览器进行访问 ,默认端口 80 (注意:是否关闭防火墙。)
1.4 配置虚拟主机
虚拟主机指的是,在一台服务器中,我们使用Nginx,来配置多个网站.
如何区分不同的网站:
1. 端口不同
2. 域名不同
通过端口区分不同的虚拟主机
Nginx配置文件
1.Nginx配置文件的位置
cd /usr/local/nginx/conf
nginx.conf 就是Nginx的配置文件
2.Nginx核心配置文件说明
worker_processes 1; #work的进程数,默认为1
#配置 影响nginx服务器与用户的网络连接
events {
worker_connections 1024; #单个work 最大并发连接数
}
# http块是配置最频繁的部分 可以嵌套多个server,配置代理,缓存,日志定义等绝大多数功能
http {
# 引入mime类型定义文件
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65; # 超时时间
#server 配置虚拟主机的相关参数 可以有多个,一个server就是一个虚拟主机
server {
# 监听的端口
listen 80;
#监听地址
server_name localhost;
# 默认请求配置
location / {
root html; # 默认网站根目录
index index.html index.htm; # 欢迎页
}
# 错误提示页面
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
使用Notpad,连接Linux
使用notepad++来连接linux,好处是使用notepad++来编辑linux中文件的批量文字,会比直接在linux中操作方便快捷很多.
1. Notepad 插件中安装NppFTP
1. 选择设置
1. 配置连接信息
1. 连接
配置nginx.conf
1. 使用Notpad 在nginx.conf 中添加一个 新的server
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
}
# 配置新的server
server {
listen 81; # 修改端口
server_name localhost;
location / {
root html81; # 重新制定一个目录
index index.html index.htm;
}
}
}
1. 复制一份 html目录
cp -r html html81
1. 重新加载配置文件
sbin/nginx -s reload
1. 访问
http://192.168.80.100 访问第一个server
http://192.168.81.100:81/ 访问第二个server
通过域名区分不同的虚拟主机
配置域名映射
1. 本地测试可以修改hosts文件。修改window的hosts文件:(C:\Windows\System32\drivers\etc)
可以配置域名和ip的映射关系,如果hosts文件中配置了域名和ip的对应关系,不需要走dns服务器。
配置一下nginx的映射
182.168.80.100 www.ng.com
在window系统中配置host文件
192.168.80.100 www.taobao.com
192.168.80.100 www.jd.com
配置nginx.conf
#通过域名区分虚拟主机
server {
listen 80;
server_name www.taobao.com;
location / {
root taobao;
index taobao.html;
}
}
server {
listen 80;
server_name www.jd.com;
location / {
root jd;
index jd.html;
}
}
修改一下index.html 中,刷新
sbin/nginx -s reload
访问
虽然只有一台服务器,但是这台服务器上运行着多个网站,访问不同的域名 就可访问到不同的网站内容
1.5 反向代理
正向代理
比如我们国内访问谷歌,直接访问访问不到,我们可以通过一个正向代理服务器,先将请求发送到到代理服,代理服务器能够访问谷歌,这样由代理去谷歌取到返回数据,再返回给我们,这样我们就能访问谷歌了'
Nginx实现反向代理
Nginx作为反向代理服务器安装在服务端,Nginx的功能就是把请求转发给后面的应用服务器.
配置步骤
第一步:简单的使用2个tomcat实例模拟两台http服务器,分别将tomcat的端口改为8080和8081
第二步:启动两个tomcat。
./bin/startup.sh
访问两个tomcat
http://192.168.52.100:8080/
http://192.168.52.100:8081/
第三步:反向代理服务器的配置
#反向代理配置
#upstream中的server是真正处理请求的应用服务器地址
upstream lagou1{
#用server定义HTTP地址
server 192.168.80.100:8080;
}
server {
listen 80;
server_name www.lagou1.com;
location / {
# 利用 proxy_ pass可以将请求代理到upstream命名的HTTP服务
proxy_pass http://lagou1; #转发到的地址
index index.html index.htm;
}
}
upstream lagou2{
#用server定义HTTP地址
server 192.168.80.100:8081;
}
server {
listen 80;
server_name www.lagou2.com;
location / {
proxy_pass http://lagou2;
index index.html index.htm;
}
}
第四步:nginx重新加载配置文件
nginx -s reload
第五步:配置域名, 在hosts文件中添加域名和ip的映射关系
192.168.80.100 www.lagou1.com
192.168.80.100 www.lagou2.com
通过浏览器输入域名, 访问Nginx代理服务器, Nginx根据域名将请求转发给对应的目标服务器,作为用户我们看到的是服务器的响应结果页面,在整个过程中目标服务器相对于客户端是不可见的,服务端向外暴露的就是Nginx的地址.
1.6 负载均衡
什么是负载均衡
当一个请求发送过来的时候,Nginx作为反向代理服务器,会根据请求找到后面的目标服务器去处理请求,这就是反向代理. 那么, 如果目标服务器有多台的话,找哪一个服务器去处理当前请求呢 ? 这个合理分配请求到服务器的过程就叫做负载均衡.
为什么用负载均衡
当系统面临大量用户访问,负载过高的时候,通常会使用增加服务器数量来进行横向扩展, 负载均衡主要是为了分担访问量,将请求合理分发给不同的服务器, 避免临时的网络堵塞
负载均衡策略
轮询
默认策略, 每个请求按照时间顺序逐一分配到不同的服务器,如果某一个服务器下线,能自动剔除
配置方式
负载均衡
#配置负载均衡
upstream lagouedu{
# 用server定义 HTTP地址
server 192.168.80.100:8080;
server 192.168.80.100:8081;
}
server {
listen 80;
server_name www.lagouedu.com;
location / {
# 利用 proxy_ pass可以将请求代理到upstream命名的HTTP服务
proxy_pass http://lagouedu;
index index.html;
}
}
weight
可以根据服务器的实际情况调整服务器权重。权重越高分配的请求越多,权重越低,请求越少。默认是都是1.
#负载均衡
upstream lagouServer{
# 用server定义 HTTP地址
server 192.168.52.100:8080 weight=1;
server 192.168.52.100:8081 weight=10;
}
2.发布web项目
1.项目打包
2.发布web项目到tomcat下
复制到linux中tomcat1 和tomcat2的webapps目录下
启动tomcat1 tomcat2
[root@centos7-1 bin]# ./startup.sh && tail -100f ../logs/catalina.out
3.配置nginx负载均衡
upstream vis{
# 用server定义 HTTP地址
server 192.168.80.100:8080;
server 192.168.80.100:8081;
}
server {
listen 80;
server_name www.vis.com;
location / {
# 利用 proxy_ pass可以将请求代理到upstream命名的HTTP服务
proxy_pass http://vis;
index login.html ;
}
}