当前位置: 首页 > news >正文

物流项目第九期(MongoDB的应用之作业范围)

本项目专栏:

物流项目_Auc23的博客-CSDN博客

建议先看这期:

MongoDB入门之Java的使用-CSDN博客

需求分析 

在项目中,会有两个作业范围,分别是机构作业范围和快递员作业范围,这两个作业范围的逻辑是一致的,就是在地图中进行画出范围,就是其作业范围。

实现分析 

对于作业范围是一个由多个坐标点组成的多边形,并且必须是闭合的多边形,这个就比较适合用MongoDB来存储。

现在想一个实际需求,用户小王下了订单,如何找到属于该服务范围内的快递员呢?这个就需要使用MongoDB的$geoIntersects查询操作,其原理就是查找小王的位置坐标点与哪个多边形有交叉,这个就是为其服务的快递员。

ServiceScopeEntity

/*** 服务范围实体*/
@Data
@Document("sl_service_scope")
public class ServiceScopeEntity {@Id@JsonIgnoreprivate ObjectId id;/*** 业务id,可以是机构或快递员*/@Indexedprivate Long bid;/*** 类型 {@link com.sl.ms.scope.enums.ServiceTypeEnum}*/@Indexedprivate Integer type;/*** 多边形范围,是闭合的范围,开始经纬度与结束经纬度必须一样* x: 经度,y:纬度*/@GeoSpatialIndexed(type = GeoSpatialIndexType.GEO_2DSPHERE)private GeoJsonPolygon polygon;private Long created; //创建时间private Long updated; //更新时间
}
/*** 服务类型枚举*/
public enum ServiceTypeEnum {ORGAN(1, "机构"),COURIER(2, "快递员");/*** 类型编码*/private final Integer code;/*** 类型值*/private final String value;ServiceTypeEnum(Integer code, String value) {this.code = code;this.value = value;}public Integer getCode() {return code;}public String getValue() {return value;}public static ServiceTypeEnum codeOf(Integer code) {return EnumUtil.getBy(ServiceTypeEnum::getCode, code);}
}

ScopeService

在ScopeService中主要定义了如下方法:

  • 新增或更新服务范围
  • 根据主键id删除数据
  • 根据业务id和类型删除数据
  • 根据主键查询数据
  • 根据业务id和类型查询数据
  • 根据坐标点查询所属的服务对象
  • 根据详细地址查询所属的服务对象

/*** 服务范围Service*/
public interface ScopeService {/*** 新增或更新服务范围** @param bid     业务id* @param type    类型* @param polygon 多边形坐标点* @return 是否成功*/Boolean saveOrUpdate(Long bid, ServiceTypeEnum type, GeoJsonPolygon polygon);/*** 根据主键id删除数据** @param id 主键* @return 是否成功*/Boolean delete(String id);/*** 根据业务id和类型删除数据** @param bid  业务id* @param type 类型* @return 是否成功*/Boolean delete(Long bid, ServiceTypeEnum type);/*** 根据主键查询数据** @param id 主键* @return 服务范围数据*/ServiceScopeEntity queryById(String id);/*** 根据业务id和类型查询数据** @param bid  业务id* @param type 类型* @return 服务范围数据*/ServiceScopeEntity queryByBidAndType(Long bid, ServiceTypeEnum type);/*** 根据坐标点查询所属的服务对象** @param type  类型* @param point 坐标点* @return 服务范围数据*/List<ServiceScopeEntity> queryListByPoint(ServiceTypeEnum type, GeoJsonPoint point);/*** 根据详细地址查询所属的服务对象** @param type    类型* @param address 详细地址,如:北京市昌平区金燕龙办公楼传智教育总部* @return 服务范围数据*/List<ServiceScopeEntity> queryListByPoint(ServiceTypeEnum type, String address);
}

 ScopeController

/*** 服务范围*/
@Api(tags = "服务范围")
@RestController
@RequestMapping("scopes")
@Validated
public class ScopeController {@Resourceprivate ScopeService scopeService;/*** 新增或更新服务服务范围** @return REST标准响应*/@ApiOperation(value = "新增/更新", notes = "新增或更新服务服务范围")@PostMappingpublic ResponseEntity<Void> saveScope(@RequestBody ServiceScopeDTO serviceScopeDTO) {ServiceScopeEntity serviceScopeEntity = EntityUtils.toEntity(serviceScopeDTO);Long bid = serviceScopeEntity.getBid();ServiceTypeEnum type = ServiceTypeEnum.codeOf(serviceScopeEntity.getType());Boolean result = this.scopeService.saveOrUpdate(bid, type, serviceScopeEntity.getPolygon());if (result) {return ResponseEntityUtils.ok();}return ResponseEntityUtils.error();}/*** 删除服务范围** @param bid  业务id* @param type 类型* @return REST标准响应*/@ApiImplicitParams({@ApiImplicitParam(name = "bid", value = "业务id,可以是机构或快递员", dataTypeClass = Long.class),@ApiImplicitParam(name = "type", value = "类型,1-机构,2-快递员", dataTypeClass = Integer.class)})@ApiOperation(value = "删除", notes = "删除服务范围")@DeleteMapping("{bid}/{type}")public ResponseEntity<Void> delete(@NotNull(message = "bid不能为空") @PathVariable("bid") Long bid,@NotNull(message = "type不能为空") @PathVariable("type") Integer type) {Boolean result = this.scopeService.delete(bid, ServiceTypeEnum.codeOf(type));if (result) {return ResponseEntityUtils.ok();}return ResponseEntityUtils.error();}/*** 查询服务范围** @param bid  业务id* @param type 类型* @return 服务范围数据*/@ApiImplicitParams({@ApiImplicitParam(name = "bid", value = "业务id,可以是机构或快递员", dataTypeClass = Long.class),@ApiImplicitParam(name = "type", value = "类型,1-机构,2-快递员", dataTypeClass = Integer.class)})@ApiOperation(value = "查询", notes = "查询服务范围")@GetMapping("{bid}/{type}")public ResponseEntity<ServiceScopeDTO> queryServiceScope(@NotNull(message = "bid不能为空") @PathVariable("bid") Long bid,@NotNull(message = "type不能为空") @PathVariable("type") Integer type) {ServiceScopeEntity serviceScopeEntity = this.scopeService.queryByBidAndType(bid, ServiceTypeEnum.codeOf(type));return ResponseEntityUtils.ok(EntityUtils.toDTO(serviceScopeEntity));}/*** 地址查询服务范围** @param type    类型,1-机构,2-快递员* @param address 详细地址,如:北京市昌平区金燕龙办公楼传智教育总部* @return 服务范围数据列表*/@ApiImplicitParams({@ApiImplicitParam(name = "type", value = "类型,1-机构,2-快递员", dataTypeClass = Integer.class),@ApiImplicitParam(name = "address", value = "详细地址,如:北京市昌平区金燕龙办公楼传智教育总部", dataTypeClass = String.class)})@ApiOperation(value = "地址查询服务范围", notes = "地址查询服务范围")@GetMapping("address")public ResponseEntity<List<ServiceScopeDTO>> queryListByAddress(@NotNull(message = "type不能为空") @RequestParam("type") Integer type,@NotNull(message = "address不能为空") @RequestParam("address") String address) {List<ServiceScopeEntity> serviceScopeEntityList = this.scopeService.queryListByPoint(ServiceTypeEnum.codeOf(type), address);return ResponseEntityUtils.ok(EntityUtils.toDTOList(serviceScopeEntityList));}/*** 位置查询服务范围** @param type      类型,1-机构,2-快递员* @param longitude 经度* @param latitude  纬度* @return 服务范围数据列表*/@ApiImplicitParams({@ApiImplicitParam(name = "type", value = "类型,1-机构,2-快递员", dataTypeClass = Integer.class),@ApiImplicitParam(name = "longitude", value = "经度", dataTypeClass = Double.class),@ApiImplicitParam(name = "latitude", value = "纬度", dataTypeClass = Double.class)})@ApiOperation(value = "位置查询服务范围", notes = "位置查询服务范围")@GetMapping("location")public ResponseEntity<List<ServiceScopeDTO>> queryListByAddress(@NotNull(message = "type不能为空") @RequestParam("type") Integer type,@NotNull(message = "longitude不能为空") @RequestParam("longitude") Double longitude,@NotNull(message = "latitude不能为空") @RequestParam("latitude") Double latitude) {List<ServiceScopeEntity> serviceScopeEntityList = this.scopeService.queryListByPoint(ServiceTypeEnum.codeOf(type), new GeoJsonPoint(longitude, latitude));return ResponseEntityUtils.ok(EntityUtils.toDTOList(serviceScopeEntityList));}
}

实现接口


@Slf4j
@Service
public class ScopeServiceImpl implements ScopeService {@Resourceprivate MongoTemplate mongoTemplate;@Resourceprivate EagleMapTemplate eagleMapTemplate;@Overridepublic Boolean saveOrUpdate(Long bid, ServiceTypeEnum type, GeoJsonPolygon polygon) {Query query = Query.query(Criteria.where("bid").is(bid).and("type").is(type.getCode())); //构造查询条件ServiceScopeEntity serviceScopeEntity = this.mongoTemplate.findOne(query, ServiceScopeEntity.class);if (ObjectUtil.isEmpty(serviceScopeEntity)) {//新增serviceScopeEntity = new ServiceScopeEntity();serviceScopeEntity.setBid(bid);serviceScopeEntity.setType(type.getCode());serviceScopeEntity.setPolygon(polygon);serviceScopeEntity.setCreated(System.currentTimeMillis());serviceScopeEntity.setUpdated(serviceScopeEntity.getCreated());} else {//更新serviceScopeEntity.setPolygon(polygon);serviceScopeEntity.setUpdated(System.currentTimeMillis());}try {this.mongoTemplate.save(serviceScopeEntity);return true;} catch (Exception e) {log.error("新增/更新服务范围数据失败! bid = {}, type = {}, points = {}", bid, type, polygon.getPoints(), e);}return false;}@Overridepublic Boolean delete(String id) {Query query = Query.query(Criteria.where("id").is(new ObjectId(id))); //构造查询条件return this.mongoTemplate.remove(query, ServiceScopeEntity.class).getDeletedCount() > 0;}@Overridepublic Boolean delete(Long bid, ServiceTypeEnum type) {Query query = Query.query(Criteria.where("bid").is(bid).and("type").is(type.getCode())); //构造查询条件return this.mongoTemplate.remove(query, ServiceScopeEntity.class).getDeletedCount() > 0;}@Overridepublic ServiceScopeEntity queryById(String id) {return this.mongoTemplate.findById(new ObjectId(id), ServiceScopeEntity.class);}@Overridepublic ServiceScopeEntity queryByBidAndType(Long bid, ServiceTypeEnum type) {Query query = Query.query(Criteria.where("bid").is(bid).and("type").is(type.getCode())); //构造查询条件return this.mongoTemplate.findOne(query, ServiceScopeEntity.class);}@Overridepublic List<ServiceScopeEntity> queryListByPoint(ServiceTypeEnum type, GeoJsonPoint point) {Query query = Query.query(Criteria.where("polygon").intersects(point).and("type").is(type.getCode()));return this.mongoTemplate.find(query, ServiceScopeEntity.class);}@Overridepublic List<ServiceScopeEntity> queryListByPoint(ServiceTypeEnum type, String address) {//根据详细地址查询坐标GeoResult geoResult = this.eagleMapTemplate.opsForBase().geoCode(ProviderEnum.AMAP, address, null);Coordinate coordinate = geoResult.getLocation();return this.queryListByPoint(type, new GeoJsonPoint(coordinate.getLongitude(), coordinate.getLatitude()));}
}

测试

package com.sl.ms.scope.service;import com.sl.ms.scope.entity.ServiceScopeEntity;
import com.sl.ms.scope.enums.ServiceTypeEnum;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.geo.Point;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import org.springframework.data.mongodb.core.geo.GeoJsonPolygon;import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;@SpringBootTest
public class ScopeServiceTest {@Resourceprivate ScopeService scopeService;@Testvoid saveOrUpdate() {List<Point> pointList = Arrays.asList(new Point(116.340064,40.061245),new Point(116.347081,40.061836),new Point(116.34751,40.05842),new Point(116.342446,40.058092),new Point(116.340064,40.061245));Boolean result = this.scopeService.saveOrUpdate(2L, ServiceTypeEnum.ORGAN, new GeoJsonPolygon(pointList));System.out.println(result);}@Testvoid testQueryListByPoint() {GeoJsonPoint point = new GeoJsonPoint(116.344828,40.05911);List<ServiceScopeEntity> serviceScopeEntities = this.scopeService.queryListByPoint(ServiceTypeEnum.ORGAN, point);serviceScopeEntities.forEach(serviceScopeEntity -> System.out.println(serviceScopeEntity));}@Testvoid testQueryListByPoint2() {String address = "北京市昌平区金燕龙办公楼";List<ServiceScopeEntity> serviceScopeEntities = this.scopeService.queryListByPoint(ServiceTypeEnum.ORGAN, address);serviceScopeEntities.forEach(serviceScopeEntity -> System.out.println(serviceScopeEntity));}
}

相关文章:

  • 【unity游戏开发——编辑器扩展】EditorUtility编辑器工具类实现如文件操作、进度条、弹窗等操作
  • STM32学习笔记---时钟树
  • 《基于AIGC的智能化多栈开发新模式》研究报告重磅发布! ——AI重塑软件工程,多栈开发引领未来
  • PHP+MySQL开发语言 在线下单订水送水小程序源码及搭建指南
  • Kruskal算法剖析与py/cpp/Java语言实现
  • python 小工具,获取 github 仓库信息
  • openFuyao开源发布,建设多样化算力集群开源软件生态
  • vue或者前端适配makedown推荐开源依赖
  • [科研实践] VS Code (Copilot) + Overleaf (使用 Overleaf Workshop 插件)
  • C++之string题目练习
  • P1923 【深基9.例4】求第 k 小的数
  • 2025年中国电商618年中大促策略分析:存量博弈与生态重构
  • 【设计模式】简单工厂模式,工厂模式,抽象工厂模式,单例,代理,go案例区分总结
  • GO语言进阶:掌握进程OS操作与高效编码数据转换
  • 使用 Frida 增强 FART:实现更强大的 Android 脱壳能力
  • 漫画Android:View是怎么绘制出来的?
  • k8s Headless Service
  • 阿里云服务器SSH远程登陆输错密码次数过多导致本地IP禁止登陆,网站和Linux宝塔面板无法访问,但是网站在其他网络访问一切正常
  • LLama-Factory使用教程-2025最新版
  • LLaDa——基于 Diffusion 的大语言模型 打平 LLama 3
  • 淘宝下载安装/贵州萝岗seo整站优化
  • 百度做网站的联系人/内蒙古最新消息
  • 教做幼儿菜谱菜的网站/大数据培训班需要多少钱
  • webp 做网站/今日新闻摘抄二十条
  • 网站页面划分/佛山网站优化排名推广
  • 住房和城乡建设部网站安全分会/检测网站是否安全