手把手教你调用api获取设备的位置信息
1:注册高德开发者账号
访问高德开放平台:https://lbs.amap.com
点击右上角"注册",选择「开发者」身份
完成手机验证和邮箱激活
2:创建应用
登录后进入控制台:https://console.amap.com
在「应用管理」菜单点击「创建新应用」
填写应用信息:
应用名称:设备管理系统(示例)
应用类型:企业应用
行业类型:物流运输(根据实际选择)
3:添加Web服务Key
创建应用后点击「添加Key」``
填写Key配置:
Key名称:BackendServiceKey
服务平台:Web服务 # 这是后端调用的关键选项
域名白名单:留空(开发阶段)或填写生产环境域名
4:获取API_KEY
提交后可在Key列表中看到生成的Key
格式示例:d2a5d2e4e5b8c4d8a7b3c6d9e1f2a5d3
5:Spring Boot配置API_KEY
推荐配置方式(application.yml):
amap:
api-key: your_api_key_here
geocode-url: https://restapi.amap.com/v3/geocode/regeo
6.1:具体代码
package com.example.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "amap")
public class AmapProperties {
private String apiKey;
private String geocodeUrl;
public String getApiKey() { return apiKey; }
public void setApiKey(String apiKey) { this.apiKey = apiKey; }
public String getGeocodeUrl() { return geocodeUrl; }
public void setGeocodeUrl(String geocodeUrl) { this.geocodeUrl = geocodeUrl; }
}
6.2:具体代码
package com.example.controller;
import com.example.dto.GeoResponse;
import com.example.service.LocationService;
import jakarta.validation.constraints.DecimalMax;
import jakarta.validation.constraints.DecimalMin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class LocationController {
private final LocationService locationService;
@Autowired
public LocationController(LocationService locationService) {
this.locationService = locationService;
}
@GetMapping(value = "/api/location", produces = MediaType.APPLICATION_JSON_VALUE)
public GeoResponse getLocation(
@RequestParam @DecimalMin("73.66") @DecimalMax("135.05") String longitude,
@RequestParam @DecimalMin("3.86") @DecimalMax("53.55") String latitude) {
GeoResponse response = locationService.getLocation(longitude, latitude);
System.out.println("Service返回对象: " + response); // 使用toString()
return response;
}
}
6.3:具体代码
package com.example.dto;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class BusinessAreaListDeserializer extends JsonDeserializer<List<GeoResponse.BusinessArea>> {
@Override
public List<GeoResponse.BusinessArea> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
JsonNode node = p.getCodec().readTree(p);
List<GeoResponse.BusinessArea> businessAreas = new ArrayList<>();
if (node.isArray()) {
for (JsonNode element : node) {
// 跳过空数组(如[[]])
if (element.isArray() && element.isEmpty()) {
continue;
}
// 解析有效对象
if (element.isObject()) {
GeoResponse.BusinessArea area = p.getCodec().treeToValue(element, GeoResponse.BusinessArea.class);
businessAreas.add(area);
}
}
}
return businessAreas;
}
}
6.4:具体代码
点击查看代码
package com.example.dto;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true)
public class GeoResponse {
private String status;
private String info;
private String infocode;
private Regeocode regeocode;
// 无参构造
public GeoResponse() {}
// 全参构造
public GeoResponse(String status, String info, String infocode, Regeocode regeocode) {
this.status = status;
this.info = info;
this.infocode = infocode;
this.regeocode = regeocode;
}
// Getter/Setter
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public String getInfo() { return info; }
public void setInfo(String info) { this.info = info; }
public String getInfocode() { return infocode; }
public void setInfocode(String infocode) { this.infocode = infocode; }
public Regeocode getRegeocode() { return regeocode; }
public void setRegeocode(Regeocode regeocode) { this.regeocode = regeocode; }
@Override
public String toString() {
return "GeoResponse{" +
"status='" + status + '\'' +
", info='" + info + '\'' +
", infocode='" + infocode + '\'' +
", regeocode=" + (regeocode != null ? regeocode.toString() : "null") +
'}';
}
@JsonIgnoreProperties(ignoreUnknown = true)
public static class Regeocode {
@JsonProperty("formatted_address")
private String formattedAddress;
@JsonProperty("addressComponent")
private AddressComponent addressComponent;
public Regeocode() {}
public String getFormattedAddress() { return formattedAddress; }
public void setFormattedAddress(String formattedAddress) { this.formattedAddress = formattedAddress; }
public AddressComponent getAddressComponent() { return addressComponent; }
public void setAddressComponent(AddressComponent addressComponent) { this.addressComponent = addressComponent; }
@Override
public String toString() {
return "Regeocode{" +
"formattedAddress='" + formattedAddress + '\'' +
", addressComponent=" + (addressComponent != null ? addressComponent.toString() : "null") +
'}';
}
}
@JsonIgnoreProperties(ignoreUnknown = true)
public static class AddressComponent {
private String province;
@JsonProperty("city")
@JsonDeserialize(using = StringOrArrayDeserializer.class)
private String city;
private String district;
private String adcode;
private String towncode;
private String country;
private String township;
private String citycode;
@JsonProperty("streetNumber")
private StreetNumber streetNumber;
@JsonProperty("businessAreas")
@JsonDeserialize(using = BusinessAreaListDeserializer.class)
private List<BusinessArea> businessAreas;
@JsonProperty("building")
private Building building;
@JsonProperty("neighborhood")
private Neighborhood neighborhood;
public AddressComponent() {}
// Getter/Setter
public String getProvince() { return province; }
public void setProvince(String province) { this.province = province; }
public String getCity() { return city; }
public void setCity(String city) { this.city = city; }
public String getDistrict() { return district; }
public void setDistrict(String district) { this.district = district; }
public String getAdcode() { return adcode; }
public void setAdcode(String adcode) { this.adcode = adcode; }
public String getTowncode() { return towncode; }
public void setTowncode(String towncode) { this.towncode = towncode; }
public String getCountry() { return country; }
public void setCountry(String country) { this.country = country; }
public String getTownship() { return township; }
public void setTownship(String township) { this.township = township; }
public String getCitycode() { return citycode; }
public void setCitycode(String citycode) { this.citycode = citycode; }
public StreetNumber getStreetNumber() { return streetNumber; }
public void setStreetNumber(StreetNumber streetNumber) { this.streetNumber = streetNumber; }
public List<BusinessArea> getBusinessAreas() { return businessAreas; }
public void setBusinessAreas(List<BusinessArea> businessAreas) { this.businessAreas = businessAreas; }
public Building getBuilding() { return building; }
public void setBuilding(Building building) { this.building = building; }
public Neighborhood getNeighborhood() { return neighborhood; }
public void setNeighborhood(Neighborhood neighborhood) { this.neighborhood = neighborhood; }
@Override
public String toString() {
return "AddressComponent{" +
"province='" + province + '\'' +
", city='" + city + '\'' +
", district='" + district + '\'' +
", adcode='" + adcode + '\'' +
", towncode='" + towncode + '\'' +
", country='" + country + '\'' +
", township='" + township + '\'' +
", citycode='" + citycode + '\'' +
", streetNumber=" + (streetNumber != null ? streetNumber.toString() : "null") +
", businessAreas=" + businessAreas +
", building=" + (building != null ? building.toString() : "null") +
", neighborhood=" + (neighborhood != null ? neighborhood.toString() : "null") +
'}';
}
}
// 其他嵌套类实现(StreetNumber、BusinessArea等)...
@JsonIgnoreProperties(ignoreUnknown = true)
public static class StreetNumber {
private String number;
private String location;
private String direction;
private String distance;
private String street;
public StreetNumber() {}
// Getter/Setter
public String getNumber() { return number; }
public void setNumber(String number) { this.number = number; }
public String getLocation() { return location; }
public void setLocation(String location) { this.location = location; }
public String getDirection() { return direction; }
public void setDirection(String direction) { this.direction = direction; }
public String getDistance() { return distance; }
public void setDistance(String distance) { this.distance = distance; }
public String getStreet() { return street; }
public void setStreet(String street) { this.street = street; }
@Override
public String toString() {
return "StreetNumber{" +
"number='" + number + '\'' +
", location='" + location + '\'' +
", direction='" + direction + '\'' +
", distance='" + distance + '\'' +
", street='" + street + '\'' +
'}';
}
}
@JsonIgnoreProperties(ignoreUnknown = true)
public static class BusinessArea {
private String location;
@JsonDeserialize(using = StringOrArrayDeserializer.class)
private String name;
private String id;
public BusinessArea() {}
// Getter/Setter
public String getLocation() { return location; }
public void setLocation(String location) { this.location = location; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getId() { return id; }
public void setId(String id) { this.id = id; }
@Override
public String toString() {
return "BusinessArea{" +
"location='" + location + '\'' +
", name='" + name + '\'' +
", id='" + id + '\'' +
'}';
}
}
@JsonIgnoreProperties(ignoreUnknown = true)
public static class Building {
@JsonDeserialize(using = StringOrArrayDeserializer.class)
private String name;
@JsonDeserialize(using = StringOrArrayDeserializer.class)// 改为String类型
private String type;
public Building() {}
// Getter/Setter
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
@Override
public String toString() {
return "Building{" +
"name='" + name + '\'' +
", type='" + type + '\'' +
'}';
}
}
@JsonIgnoreProperties(ignoreUnknown = true)
public static class Neighborhood {
@JsonDeserialize(using = StringOrArrayDeserializer.class) // 处理字符串或数组
private String name;
@JsonDeserialize(using = StringOrArrayDeserializer.class) // 处理字符串或数组
private String type;
public Neighborhood() {}
// Getter/Setter
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
@Override
public String toString() {
return "Neighborhood{" +
"name='" + name + '\'' +
", type='" + type + '\'' +
'}';
}
}
}
6.5具体代码
点击查看代码
```plaintext
package com.example.dto;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonNode;
import java.io.IOException;
public class StringOrArrayDeserializer extends JsonDeserializer<String> {
private final boolean returnFirstElement; // 控制是否取数组首元素
public StringOrArrayDeserializer() {
this(true); // 默认取首元素(兼容原逻辑)
}
public StringOrArrayDeserializer(boolean returnFirstElement) {
this.returnFirstElement = returnFirstElement;
}
@Override
public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
JsonNode node = p.getCodec().readTree(p);
if (node.isArray()) {
if (returnFirstElement && node.size() > 0) {
return node.get(0).asText(); // 取第一个元素
}
return null; // 空数组或配置不取首元素时返回null
} else if (node.isTextual()) {
return node.asText();
}
return null;
}
}
6.6具体代码
点击查看代码
```plaintext
package com.example.service;
import com.example.config.AmapProperties;
import com.example.dto.GeoResponse;
import com.example.util.CoordinateConverter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
@Service
public class LocationService {
private final RestTemplate restTemplate;
private final AmapProperties amapProperties;
@Autowired
public LocationService(RestTemplate restTemplate, AmapProperties amapProperties) {
this.restTemplate = restTemplate;
this.amapProperties = amapProperties;
}
public GeoResponse getLocation(String longitude, String latitude) {
// 转换为double类型
double lng = Double.parseDouble(longitude);
double lat = Double.parseDouble(latitude);
// 坐标转换(WGS-84 -> GCJ-02)
double[] converted = CoordinateConverter.wgs84ToGcj02(lng, lat);
String convertedLng = String.format("%.6f", converted[0]);
String convertedLat = String.format("%.6f", converted[1]);
// 使用转换后的坐标构造请求URL
String url = String.format("%s?key=%s&location=%s,%s&extensions=all",
amapProperties.getGeocodeUrl(),
amapProperties.getApiKey(),
convertedLng, // 使用转换后的经度
convertedLat // 使用转换后的纬度
);
try {
String rawResponse = restTemplate.getForObject(url, String.class);
System.out.println("转换后坐标: " + convertedLng + "," + convertedLat);
System.out.println("原始API响应: " + rawResponse);
// 使用ObjectMapper手动反序列化
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(rawResponse, GeoResponse.class);
} catch (HttpClientErrorException | JsonProcessingException e) {
System.err.println("请求失败: " + e.getMessage());
return new GeoResponse();
}
}
}
6.7具体代码
点击查看代码
```plaintext
package com.example.util;
public class CoordinateConverter {
private static final double PI = 3.1415926535897932384626;
private static final double a = 6378245.0;
private static final double ee = 0.00669342162296594323;
public static double[] wgs84ToGcj02(double lng, double lat) {
if (outOfChina(lng, lat)) {
return new double[]{lng, lat};
}
double dLat = transformLat(lng - 105.0, lat - 35.0);
double dLng = transformLng(lng - 105.0, lat - 35.0);
double radLat = lat / 180.0 * PI;
double magic = Math.sin(radLat);
magic = 1 - ee * magic * magic;
double sqrtMagic = Math.sqrt(magic);
dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI);
dLng = (dLng * 180.0) / (a / sqrtMagic * Math.cos(radLat) * PI);
double mgLat = lat + dLat;
double mgLng = lng + dLng;
return new double[]{mgLng, mgLat};
}
private static boolean outOfChina(double lng, double lat) {
if (lng < 72.004 || lng > 137.8347) {
return true;
}
return lat < 0.8293 || lat > 55.8271;
}
private static double transformLat(double x, double y) {
double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(y * PI) + 40.0 * Math.sin(y / 3.0 * PI)) * 2.0 / 3.0;
ret += (160.0 * Math.sin(y / 12.0 * PI) + 320 * Math.sin(y * PI / 30.0)) * 2.0 / 3.0;
return ret;
}
private static double transformLng(double x, double y) {
double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(x * PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(x * PI) + 40.0 * Math.sin(x / 3.0 * PI)) * 2.0 / 3.0;
ret += (150.0 * Math.sin(x / 12.0 * PI) + 300.0 * Math.sin(x / 30.0 * PI)) * 2.0 / 3.0;
return ret;
}
}
使用Postman测试请求
GET http://localhost:8080/api/location?longitude=116.481488&latitude=39.990464
预期响应结构:
{
"status": 1,
"info": "OK",
"infocode": "10000",
"regeocode": {
"formatted_address": "北京市朝阳区望京街道方恒国际中心B座",
"addressComponent": {
"province": "北京市",
"city": "",
"district": "朝阳区",
"adcode": "110105",
"towncode": "110105026000",
"country": "中国",
"township": "望京街道",
"citycode": "010"
}
}
}
浙公网安备 33010602011771号