Java根据经纬度获取两点之间的距离,最近在实现类似于钉钉打卡签到的需求,因为对精度要求不是很高,所以可以通过一个球面距离的公式来求两点距离,这里将地球当成一个球体,实际上地球是一个不规则的球体,所以这个实现方法只能适用一些精度要求不高的需求,如果要高精度,可以用第三方的api去实现。
实现思路
- 先新增一个配置页面,调用百度地图,保存好经纬度数据到数据库表,同时也保存距离
- 手机打卡获取当前位置的经纬度数据,通过接口对比,计算两点距离是否在配置的打卡范围内
代码实现
写一个实体类,传入经纬度信息
package cn.nzp.ems.ecb.server.common;import lombok.Data;@Data
public class PositionParam {private String positionlng; //坐标经度private String positionlat; //坐标纬度}
写一个工具类,EARTH_RADII
为地球半径的估值
package cn.server.common;public class GPSUtil {// 圆周率private static final Double PI = Math.PI;private static final Double PK = 180 / PI;private static final Double EARTH_RADII = 6370996.81;/*** 计算两个百度地图坐标实际距离:米** @param sourcePosition* @param targetPosition* @return*/public static double getDistanceByCoordinate(PositionParam sourcePosition, PositionParam targetPosition) {double o_lat = Double.valueOf(sourcePosition.getPositionlat());double o_lng = Double.valueOf(sourcePosition.getPositionlng());double d_lat = Double.valueOf(targetPosition.getPositionlat());double d_lng = Double.valueOf(targetPosition.getPositionlng());double t1 = Math.cos(o_lat / PK) * Math.cos(o_lng / PK) * Math.cos(d_lat / PK) * Math.cos(d_lng / PK);double t2 = Math.cos(o_lat / PK) * Math.sin(o_lng / PK) * Math.cos(d_lat / PK) * Math.sin(d_lng / PK);double t3 = Math.sin(o_lat / PK) * Math.sin(d_lat / PK);double tt = Math.acos(t1 + t2 + t3);return EARTH_RADII * tt;}}
接口判断是否在签到范围内
public ResultResponse<Integer> checkInGpsRange(QueryDto queryDto) {ResultResponse<Integer> resultResponse = ResultResponse.getSuccessfulResultResponse(AppConsts.NO_IN_GPS_RANGE);// 获取配置gps签到范围数据List<GpsAddress> gpsAddressList = Optional.ofNullable(gpsAddressMapper.listGpsAddressByConfigId(queryDto.getId())).orElse(Lists.newArrayList());for (GpsAddress gpsAddress : gpsAddressList) {if (Objects.isNull(gpsAddress.getRangeNum())) {continue;}// 主要复制经纬度信息,sourceParam是手机打卡时候,前端传过来的PositionParam sourceParam = BeanUtil.copyProperties(queryDto, PositionParam.class);// 这个是数据库保存的打卡范围,经纬度信息PositionParam targetParam = BeanUtil.copyProperties(gpsAddress, PositionParam.class);// 判断是否在签到范围内double difference = GPSUtil.getDistanceByCoordinate(sourceParam, targetParam);// 在签到范围内if (difference < gpsAddress.getRangeNum()) {resultResponse.setData(AppConsts.IN_GPS_RANGE);return resultResponse;}}return resultResponse;}
ps,这个是通过Java实现的简单例子,只能适用于不是特别精准的情况,要特别精准,请用第三方api,比如百度的,https://lbsyun.baidu.com/