手把手教你调用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"
    }
  }
}
posted @ 2025-05-26 21:33  雨花阁  阅读(126)  评论(0)    收藏  举报