1. Redis使用
1.1. 应用场景
外卖,充电,地图搜索,导航
1.2. 使用redis计算距离
1.2.1. 启动redis
如图-1所示。
图-1
1.2.2. 查看redis版本
redis-cli.exe -h 192.168.64.140,如图-1所示。
图-1
Redis 3.2.8版本才支持距离计算
1.2.3. 添加充电站
https://lbs.qq.com/getPoint/,如图-1所示。
图-1
Redis官网,如图-1所示。
1.2.4. 计算距离
1.2.5. 获取周边充电站
查询协和医院周边充电站
1.2.6. 小结
1.3. 把位置信息,充电站信息放入redis
1.3.1. 需求分析
如图-1所示。
图-1
图-1
1.3.2. 分析设计
服务器启动时把数据库中的信息保存到redis中。
1.3.3. 配置redis信息
如图-1所示。
图-1
1.3.4. 服务启动时自动执行方法
package com.ruoyi.charge.config;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
public class ChargingAppliction {
/**
* 从数据库读取充电站位置信息和充电站详情写入到redis中
*/
@PostConstruct
public void readGeoStationWriteToRedis(){
}
}
1.3.5. 写充电站位置信息
package com.ruoyi.charge.config;
import com.ruoyi.charge.domain.ChargingStation;
import com.ruoyi.charge.service.IChargingStationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.List;
@Component
public class InitAppliction {
//2.1从数据库读充电站信息
@Autowired
IChargingStationService iChargingStationService;
//2.2把充电站信息写入redis
@Autowired
RedisTemplate redisTemplate;
/**
* 1,从数据库读取充电站位置信息和充电站详情写入到redis中
*/
@PostConstruct
public void readGeoStationWriteToRedis(){
//3.1,读数据库信息
List<ChargingStation>stationList = iChargingStationService.selectChargingStationList(null);
//4,把位置信息写入redis
//4.2 创建hashmap
HashMap<String, Point>geoMap = new HashMap<>();
//3.2 遍历数据库信息
for (ChargingStation chargingStation:stationList){
//4.3 把位置信息放到map中
double lng = Double.parseDouble(chargingStation.getStationLng().toString());
double lat = Double.parseDouble(chargingStation.getStationLat().toString());
Point stationPosition = new Point(lng, lat);
geoMap.put(chargingStation.getId().toString(), stationPosition);
}
//4.1查看BoundGeoOperations,point源码 point的x,y是double
//4.3把map放到redis中
redisTemplate.boundGeoOps("stationGeoZset").add(geoMap);
}
}
192.168.64.140:6379> type stationGeoZset
zset
192.168.64.140:6379> zcard stationGeoZset
(integer) 6
192.168.64.140:6379> zrange stationGeoZset0 6
1) "\"2\""
2) "\"1\""
3) "\"4\""
4) "\"6\""
5) "\"5\""
6) "\"3\""
1.3.6. 写充电站信息
//5.1 访问hash类型stationDetailList
BoundHashOperations stationDetailHash = redisTemplate.boundHashOps("stationDetailHash");
//3.2 遍历数据库信息
for (ChargingStation chargingStation:stationList){
//4.3 把位置信息放到map中
double lng = Double.parseDouble(chargingStation.getStationLng().toString());
double lat = Double.parseDouble(chargingStation.getStationLat().toString());
Point stationPosition = new Point(lng, lat);
geoMap.put(chargingStation.getId().toString(), stationPosition);
//5.2 将充电站详情保存到redis中
stationDetailHash.put(chargingStation.getId().toString(),chargingStation);
}
如图-1所示。
图-1
1.3.7. 定时更新redis信息
每隔10秒更新一下redis中地理位置和充电站信息
1.3.8. 小结
1.4. 查询周边充电站
1.4.1. 需求分析(业务场景)
如图-1所示。
图-1
1.4.2. 分析设计
时序图
1.4.3. 详细设计
1,ChargingStation类中没有距离信息,复制chargingStation产生新的实体类NearbyChargingStation,增加distance属性,setter(),getter()
2,GlobalConstant{stationGeoZset,stationHash}
3, 修改InitApplication,使用常量
4,IChargingStationService.selectNearbyStation(longitude,latitude,radius)
IChargingStationServiceImpl
5,修改ChargingStationController增加方法
1.4.4. 实现
增加Vo
拷贝ChargingStation改为NearbyChargingStation
增加distance属性
public class NearbyChargingStation extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** 主ID */
private Integer id;
private double distance;
public double getDistance() {
return distance;
}
public void setDistance(double distance) {
this.distance = distance;
}
}
创建全局常量
public class GlobalConstant {
public static final String GEO_LIST="geoList";
public static final String STATION_DETAIL_HASH="stationDetailHash";
}
修改ChargingApplicaiton
修改接口
增加方法,调整参数
/**
* 根据用户位置查询附近充电站
* @param longitude 用户位置的经度
* @param latitude 用户位置的纬度
* @param radius 查找半径
* @return 集合
*/
public List<NearbyChargingStation>selectNearbyChargingStationList(Double longitude, double latitude,double radius);
完成实现类得到geo信息
@Service
public class ChargingStationServiceImpl implements IChargingStationService
{
//1,从容器中得到redisTemplate
@Autowired
RedisTemplate redisTemplate;
@Override
public List<NearbyChargingStation>selectNearbyChargingStationList(Double longitude, double latitude,double radius) {
//2.2创建用户当前位置
Point userPosition = new Point(longitude, latitude);
//2.3创建查找半径
Distance distance = new Distance(radius, Metrics.KILOMETERS);
//2.4创建查找范围
Circle circle = new Circle(userPosition, distance);
//2.5 设置redis返回那些内容
RedisGeoCommands.GeoRadiusCommandArgs geoRadiusCommandArgs = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs();
//设置返回坐标
geoRadiusCommandArgs.includeCoordinates();
//设置返回距离
geoRadiusCommandArgs.includeDistance();
//2.1,从redis中读取用户周边充电站信息,查看BoundGeoOperations,circle,point,distance,
// metric,metric的实现类metrics,GeoRadiusCommandArgs源码
BoundGeoOperations boundGeoOperations = redisTemplate.boundGeoOps(GlobalConstant.GEO_LIST);
GeoResults<RedisGeoCommands.GeoLocation<String>>geoResults = boundGeoOperations.radius(circle, geoRadiusCommandArgs);
ArrayList<NearbyChargingStation>list = new ArrayList<>();
return list;
}
}
修改controller
@RestController
@RequestMapping("/charge/station")
public class ChargingStationController extends BaseController
{
@Autowired
private IChargingStationService chargingStationService;
@GetMapping("/nearbyList")
public AjaxResult nearbyList(double longitude,double latitude,double radius)
{
List<NearbyChargingStation>list = chargingStationService.selectNearbyChargingStationList(longitude,latitude,radius);
return AjaxResult.success(list);
}
}
浏览器中测试,如图-1所示。
图-1
代码中加断点,结果如下图所示。
得到充电站信息
@Override
public List<NearbyChargingStation>selectNearbyChargingStationList(Double longitude, double latitude,double radius) {
//2.2创建用户当前位置
Point userPosition = new Point(longitude, latitude);
//2.3创建查找半径
Distance distance = new Distance(radius, Metrics.KILOMETERS);
//2.4创建查找范围
Circle circle = new Circle(userPosition, distance);
//2.5 设置redis返回那些内容
RedisGeoCommands.GeoRadiusCommandArgs geoRadiusCommandArgs = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs();
geoRadiusCommandArgs.includeCoordinates();
geoRadiusCommandArgs.includeDistance();
//2.1,从redis中读取用户周边充电站信息,查看BoundGeoOperations,circle,point,distance,
// metric,metric的实现类metrics,GeoRadiusCommandArgs源码
BoundGeoOperations boundGeoOperations = redisTemplate.boundGeoOps(GlobalConstant.GEO_LIST);
GeoResults<RedisGeoCommands.GeoLocation<String>>geoResults = boundGeoOperations.radius(circle, geoRadiusCommandArgs);
//3根据geo中的name查询充电站详情
ArrayList<NearbyChargingStation>list = new ArrayList<>();
BoundHashOperations boundHashOperations = redisTemplate.boundHashOps(GlobalConstant.STATION_DETAIL_HASH);
//3.1得到迭代器
Iterator<GeoResult<RedisGeoCommands.GeoLocation<String>>>iterator = geoResults.iterator();
//3.2遍历迭代器
while(iterator.hasNext()){
//3.3取到stationId
GeoResult<RedisGeoCommands.GeoLocation<String>>geoResult = iterator.next();
String stationId = geoResult.getContent().getName();
//3.4取到距离
double stationDistance = geoResult.getDistance().getValue();
//3.5根据stationId取充电站详情
ChargingStation chargingStation = (ChargingStation) boundHashOperations.get(stationId);
//3.6 把nearbyChargingStation放到list中
NearbyChargingStation nearbyChargingStation = new NearbyChargingStation();
BeanUtils.copyProperties(chargingStation,nearbyChargingStation);
nearbyChargingStation.setDistance(stationDistance);
list.add(nearbyChargingStation);
}
return list;
}
1.4.5. 小结
1.5. 获取充电站详情
1.5.1. 业务场景
用户在地图上或列表上看到附近的充电站
单击充电站查看充电站详情,详情显示充电站名称,地址,收费。
充电桩是否使用信息
1.5.2. 解决方案
充电站详情放在数据库中
用户比较多,直接从数据库中果比较慢,从redis中查
业务层代码如下:
1.6. 修改充电进度接口
1.6.1. 业务场景
用户到达充电站,找到一个充电桩,扫码开始充电,手机上显示进度,停止之后,手机上显示订单详情。
1.6.2. 技术解决方案
1.6.3. 模拟设备上传充电数据
设备把充电进度发给iot平台,iot 平台再把数据发给应用层
接口
public interface IChargingBillProcessService
{
public boolean updateProgress(Integer id);
}
实现类
@Override
public boolean updateProgress(Integer id) {
ChargingBillProcess chargingBillProcess = selectChargingBillProcessById(id);
//充电度数加1
Integer capacity=chargingBillProcess.getChargingCapacity()+1;
if (capacity>=100){
capacity=1;
}
chargingBillProcess.setChargingCapacity(capacity);
//更新到数据库
updateChargingBillProcess(chargingBillProcess);
return true;
}
控制层
//由iot平台调用
@GetMapping("/uploadProgress")
public AjaxResult uploadProgress(Integer id)
{
return toAjax(chargingBillProcessService.updateProgress(id));
}
swagger测试
模拟每隔30秒上传一个数据
1.6.4. 手机端查询数据
接口/charge/process/1
@Override
public ChargingBillProcess selectChargingBillProcessById(Integer id)
{
ChargingBillProcess chargingBillProcess = chargingBillProcessMapper.selectChargingBillProcessById(id);
return chargingBillProcess;
}
如图-1所示。
图-1