
本文介绍如何将 spring boot 控制器中基于 url 参数的经纬度范围查询,改造为接收结构化 json 请求体(如两个地理点 p1/p2),并安全、准确地执行数据库范围过滤。
本文介绍如何将 spring boot 控制器中基于 url 参数的经纬度范围查询,改造为接收结构化 json 请求体(如两个地理点 p1/p2),并安全、准确地执行数据库范围过滤。
在实际地理服务开发中,前端常需以更语义化、可扩展的方式传递空间查询条件(例如矩形区域的两个对角顶点)。原 @RequestParam 方式虽简单,但难以表达嵌套结构(如 "p1": {"lat": 46.6, "lng": 15.4}),且不符合 RESTful API 设计规范——复杂查询参数应通过 @RequestBody 以 JSON 形式提交,而非拼接在 URL 中。
✅ 正确做法:定义 DTO 并使用 @RequestBody
首先,创建一个清晰、可验证的请求数据传输对象(DTO):
public class LocationSearchRequest {
private Coordinate p1;
private Coordinate p2;
private Location.LocationType type;
private Integer limit = 10; // 默认值保持一致
// getters and setters...
public static class Coordinate {
private Double lat;
private Double lng;
// getters and setters...
}
}接着,在 Controller 中改用 @RequestBody 接收该结构:
@GetMapping("/locations/search")
public ResponseEntity<List<Location>> searchLocations(@RequestBody LocationSearchRequest request) {
// 安全校验:确保 p1 和 p2 非空
if (request.getP1() == null || request.getP2() == null) {
return ResponseEntity.badRequest().build();
}
double minLat = Math.min(request.getP1().getLat(), request.getP2().getLat());
double maxLat = Math.max(request.getP1().getLat(), request.getP2().getLat());
double minLng = Math.min(request.getP1().getLng(), request.getP2().getLng());
double maxLng = Math.max(request.getP1().getLng(), request.getP2().getLng());
Pageable pageable = PageRequest.of(0, request.getLimit() != null ? request.getLimit() : 10);
List<Location> locations = locationRepository.findByLatBetweenAndLngBetweenAndTypeOrderByTypeDesc(
minLat, maxLat, minLng, maxLng, request.getType(), pageable
);
return ResponseEntity.ok(locations);
}? 前端调用示例(JSON Body)
请求 URL:POST /api/locations/search(注意:改为 POST 更符合语义,因含非幂等/较重负载的查询)
Content-Type:application/json
{
"p1": { "lat": 46.6, "lng": 15.4 },
"p2": { "lat": 48.8, "lng": 17.5 },
"type": "premium",
"limit": 3
}⚠️ 注意事项:
- 禁止使用 @GetMapping + @RequestBody:虽然 Spring 支持,但 GET 请求携带 body 违反 HTTP 规范,部分代理或客户端可能丢弃 body;推荐统一改为 @PostMapping。
- 边界校验不可省略:必须检查 p1/p2 是否为空,并确保 lat ∈ [-90, 90]、lng ∈ [-180, 180],建议在 DTO 上添加 @Valid 与 @Min/@Max 注解。
- 数据库索引优化:为 lat 和 lng 字段建立复合索引(如 INDEX idx_lat_lng (lat, lng))可显著提升 BETWEEN 查询性能。
- 地理精度考量:上述逻辑适用于轴对齐矩形(AABB),若需真实地理围栏(如球面距离、多边形),应切换至 PostGIS 或 MongoDB GeoJSON 查询。
✅ 总结
将经纬度范围查询从 @RequestParam 迁移至 @RequestBody DTO,不仅提升了 API 的可读性与可维护性,也为后续支持更复杂的空间查询(如圆形半径、GeoHash、WKT 多边形)打下坚实基础。关键在于:用类型安全的 Java 对象承载结构化输入,用明确的 HTTP 方法语义表达操作意图,再辅以严谨的数据校验与数据库优化。

















