欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

springboot項(xiàng)目中整合高德地圖的實(shí)踐

 更新時(shí)間:2025年06月16日 16:14:32   作者:上官簫羽  
這篇文章主要介紹了springboot項(xiàng)目中整合高德地圖的實(shí)踐,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

一:高德開放平臺(tái)的使用

高德開放平臺(tái) | 高德地圖API

注冊高德地圖賬號(hào)

認(rèn)證填寫個(gè)人信息:

認(rèn)證方式選擇“個(gè)人認(rèn)證開發(fā)者”即可,然后完善信息

認(rèn)證成功之后,再次進(jìn)入控制臺(tái),創(chuàng)建關(guān)于地圖的應(yīng)用

創(chuàng)建Key(yml文件需要使用):

以上步驟便可以完成高德地圖的申請和key的創(chuàng)建。

開始Springboot的創(chuàng)建(就不從0到一的創(chuàng)建了)

二:創(chuàng)建數(shù)據(jù)庫(我是用的是MySQL)

建表語句:

CREATE TABLE `location_record` (
  `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
  `ip` VARCHAR(50) DEFAULT NULL COMMENT '客戶端IP地址',
  `longitude` DOUBLE(10,6) NOT NULL COMMENT '經(jīng)度坐標(biāo),精確到小數(shù)點(diǎn)后6位',
  `latitude` DOUBLE(10,6) NOT NULL COMMENT '緯度坐標(biāo),精確到小數(shù)點(diǎn)后6位',
  `address` VARCHAR(255) DEFAULT NULL COMMENT '詳細(xì)地址信息',
  `formatted_address` VARCHAR(255) DEFAULT NULL COMMENT '格式化后的完整地址',
  `city` VARCHAR(100) DEFAULT NULL COMMENT '所在城市名稱',
  `province` VARCHAR(100) DEFAULT NULL COMMENT '所在省份名稱',
  `district` VARCHAR(100) DEFAULT NULL COMMENT '新增:所在區(qū)縣名稱',
  `street` VARCHAR(100) DEFAULT NULL COMMENT '新增:街道信息',
  `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '記錄創(chuàng)建時(shí)間',
  `update_time` DATETIME DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '記錄更新時(shí)間',
  PRIMARY KEY (`id`),
  KEY `idx_location` (`longitude`,`latitude`),
  KEY `idx_create_time` (`create_time`)
) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='地理位置信息記錄表';

表中樣式:

三:Springboot所需的依賴(根據(jù)你的需求再去增加刪除依賴)

dependencies>
    <!-- FastJSON -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.76</version>
    </dependency>
    
    <!-- OkHttp -->
    <dependency>
        <groupId>com.squareup.okhttp3</groupId>
        <artifactId>okhttp</artifactId>
        <version>4.12.0</version>
    </dependency>


    <dependency>
         <groupId>com.alibaba</groupId>
         <artifactId>druid-spring-boot-starter</artifactId>
         <version> 1.2.23</version>
    </dependency>
    <dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>8.0.33</version>
    </dependency>
     <dependency>
          <groupId>com.baomidou</groupId>
          <artifactId>mybatis-plus-boot-starter</artifactId>
           <version>3.5.6</version>
      </dependency>

    <!-- Spring Boot Starter Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>2.6.13</version>
    </dependency>
    
    <!-- Apache HttpClient -->
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.13</version>
    </dependency>

    <!-- Spring Boot Configuration Processor -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <version>2.6.13</version>
        <optional>true</optional>
    </dependency>

    <!-- Lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.26</version>
    </dependency>
</dependencies>

四:yml文件的配置

server:
  port: 8096

spring:
  amap:
    key: "你的高德地圖key值"
    version: 2.0
    geocode-url: https://restapi.amap.com/v3/geocode/geo
    ip-url: https://restapi.amap.com/v3/ip
    regeo-url: https://restapi.amap.com/v3/geocode/regeo

  datasource: # 數(shù)據(jù)源配置
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/你所建表對應(yīng)的數(shù)據(jù)庫?serverTimezone=Asia/Shanghai&useSSL=false
    username: root
    password: root
    type: com.alibaba.druid.pool.DruidDataSource

# mybatis-plus配置,也可以不加,只是為了顯示SQL,Springboot都自動(dòng)配置好了
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

五:所需要的類

  • AmapConfig:
package com.qfedu.config;


import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Data
@Configuration
@ConfigurationProperties(prefix = "spring.amap")
public class AmapConfig {
    private String key;                   // 對應(yīng)配置中的 key
    private String securityJsCode;        // 對應(yīng) security-js-code
    private String version = "2.0";       // 默認(rèn)版本號(hào)
    private String geocodeUrl;            // 對應(yīng) geocode.url
    private String ipUrl;                 // 對應(yīng) ip.url
    private String regeoUrl;              // 對應(yīng) regeo.url
}
  • WebMvcConfig(因?yàn)槲业捻?xiàng)目中配置了攔截器,所以需要這樣一個(gè)類)
package com.qfedu.config;

import com.qfedu.common.core.interceptor.LoginInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Bean
    public LoginInterceptor loginInterceptor() {
        return new LoginInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns(
                        "/api/amap/**",
                        "/api/location/**"  // 新增排除location相關(guān)路徑
                );
    }
}
  • HttpUtils:
package com.qfedu.utils;

import com.sun.deploy.net.URLEncoder;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class HttpUtil {
    public static String doGet(String url) throws IOException {
        if (url == null || url.trim().isEmpty()) {
            throw new IllegalArgumentException("URL不能為空");
        }

        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet(url);

        // 設(shè)置請求頭
        httpGet.setHeader("Accept", "application/json");
        httpGet.setHeader("Content-Type", "application/json");

        try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode != 200) {
                throw new IOException("HTTP請求失敗,狀態(tài)碼: " + statusCode + ", URL: " + url);
            }

            HttpEntity entity = response.getEntity();
            if (entity == null) {
                throw new IOException("響應(yīng)體為空");
            }

            return EntityUtils.toString(entity, StandardCharsets.UTF_8);
        } finally {
            httpClient.close();
        }
    }

    public static String encodeUrlParam(String param) {
        try {
            return URLEncoder.encode(param, StandardCharsets.UTF_8.name());
        } catch (Exception e) {
            return param;
        }
    }
}
  • 返回值R類:(我的R類沒有使用泛型)
package com.qfedu.common.core.common;

public class R {
    /**
     * code,指狀態(tài)碼,
     * 隨意定,20000 是正確,40000 錯(cuò)誤
     * 50000 請求超時(shí)
     * 60000 沒有權(quán)限
     * msg,指信息描述
     * data,返回的數(shù)據(jù)
     */
    private int code;
    private String msg;
    private Object data;


    public static R ok() {
        R r = new R();
        r.setCode(200);
        r.setMsg("成功");
        return r;
    }

    public static R ok(Object data) {
        R r = new R();
        r.setCode(200);
        r.setMsg("成功");
        r.setData(data);
        return r;
    }


    public static R fail() {
        R r = new R();
        r.setCode(500);
        r.setMsg("失敗");
        return r;
    }

    public static R fail(String msg) {
        R r = new R();
        r.setCode(500);
        r.setMsg(msg);
        return r;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }


}
  • 免登錄自定義注解:
package com.qfedu.common.core.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 以夢為馬,以汗為泉,不忘初心,不負(fù)韶華
 *
 * @author ${上官簫宇}
 * @version 1.0
 * @data 2025/6/3 16:08
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)//注解運(yùn)行時(shí)生效
public @interface NoLogin {
}
  • 攔截器:
package com.qfedu.common.core.interceptor;


import com.qfedu.common.core.annotation.NoLogin;
import com.qfedu.common.core.constants.CommonConstants;
import com.qfedu.common.core.utils.JwtUtils;
import com.qfedu.common.core.utils.UserUtils;
import io.jsonwebtoken.Claims;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

/**
 * ---Do First---
 *
 * @author:wellseasun
 * @date:2025/5/22 下午 8:30
 * @desc:
 */
public class LoginInterceptor implements HandlerInterceptor {
    // preHandle:執(zhí)行時(shí)機(jī):訪問接口前
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // handler表示處理某個(gè)請求的處理器對象,
        // 如果是類級(jí)別的攔截器,則handler為類對象,如果是方法級(jí)別的攔截器,則handler為方法對象

        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
            boolean annotationPresent = method.isAnnotationPresent(NoLogin.class);
            if (annotationPresent) {
                // 如果使用了注解,直接放行
                return true;
            } else {
                // 沒有使用注解,需要從請求頭中獲取名為LOGIN_TOKEN的token
                String token = request.getHeader(CommonConstants.LOGIN_TOKEN);
                if (token == null || token.isEmpty()) {
                    throw new RuntimeException("請重新登錄");
                }
                try {
                    JwtUtils jwtUtils = new JwtUtils();
                    Claims claims = jwtUtils.parseJWT(token);
                    UserUtils.setUid((Integer) claims.get("uid"));
                } catch (Exception e) {
                    throw e;
                }
            }
        }
        return true;
    }



}

沒錯(cuò),下面就是層級(jí)關(guān)系

  • mapper:
package com.qfedu.mapper;


import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.qfedu.common.core.entity.LocationRecord;

public interface LocationRecordMapper extends BaseMapper<LocationRecord> {
}
  • service:
package com.qfedu.service;

import com.alibaba.fastjson.JSONObject;
import com.qfedu.common.core.entity.LocationRecord;


public interface AmapService {
    /**
     * IP定位
     * @param ip IP地址
     * @return 定位結(jié)果
     */
    JSONObject ipLocation(String ip);

    /**
     * 逆地理編碼
     * @param longitude 經(jīng)度
     * @param latitude 緯度
     * @return 地址信息
     */
    JSONObject regeoLocation(Double longitude, Double latitude);

    /**
     * 地理編碼
     * @param address 地址
     * @return 經(jīng)緯度信息
     */
    JSONObject geoLocation(String address);

    /**
     * 保存定位記錄
     * @param record 定位記錄
     * @return 是否成功
     */
    boolean saveLocationRecord(LocationRecord record);
}
  • service實(shí)現(xiàn)類:
package com.qfedu.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qfedu.common.core.entity.LocationRecord;
import com.qfedu.config.AmapConfig;
import com.qfedu.mapper.LocationRecordMapper;
import com.qfedu.service.AmapService;
import com.qfedu.utils.HttpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;

/**
 * 高德地圖服務(wù)實(shí)現(xiàn)類
 * 提供IP定位、地理編碼、逆地理編碼等核心功能
 */
@Service
public class AmapServiceImpl extends ServiceImpl<LocationRecordMapper, LocationRecord>
        implements AmapService {

    private static final Logger logger = LoggerFactory.getLogger(AmapServiceImpl.class);

    @Autowired
    private AmapConfig amapConfig; // 高德配置參數(shù)(key/url等)

    /**
     * 初始化時(shí)打印配置信息(調(diào)試用)
     */
    @PostConstruct
    public void init() {
        logger.info("高德地圖配置加載: key={}, ipUrl={}, geoUrl={}, regeoUrl={}",
                amapConfig.getKey(),
                amapConfig.getIpUrl(),
                amapConfig.getGeocodeUrl(),
                amapConfig.getRegeoUrl());
    }

    // ==================== 核心服務(wù)方法 ====================

    /**
     * IP定位服務(wù)
     * @param ip 需要查詢的IP地址
     * @return 包含定位結(jié)果的JSON對象(status=1成功,0失?。?
     */
    @Override
    public JSONObject ipLocation(String ip) {
        // 參數(shù)校驗(yàn)
        if (!StringUtils.hasText(ip)) {
            return createErrorResponse("IP地址不能為空");
        }

        try {
            // 配置校驗(yàn)
            validateConfig(amapConfig.getKey(), amapConfig.getIpUrl());

            // 構(gòu)建請求URL(示例:https://restapi.amap.com/v3/ip?key=xxx&ip=8.8.8.8)
            String url = String.format("%s?key=%s&ip=%s",
                    amapConfig.getIpUrl().trim(),
                    amapConfig.getKey().trim(),
                    HttpUtil.encodeUrlParam(ip));

            validateUrl(url); // URL格式校驗(yàn)
            logger.info("請求高德IP定位API: {}", url);

            // 發(fā)送HTTP請求并解析響應(yīng)
            String response = HttpUtil.doGet(url);
            logger.debug("高德IP定位API響應(yīng): {}", response);

            return parseResponse(response);
        } catch (Exception e) {
            logger.error("IP定位失敗, IP: " + ip, e);
            return createErrorResponse("IP定位失敗: " + e.getMessage());
        }
    }

    /**
     * 逆地理編碼服務(wù)(坐標(biāo)→地址)
     * @param longitude 經(jīng)度
     * @param latitude 緯度
     * @return 包含地址信息的JSON響應(yīng)
     */
    @Override
    public JSONObject regeoLocation(Double longitude, Double latitude) {
        if (longitude == null || latitude == null) {
            return createErrorResponse("經(jīng)緯度不能為空");
        }

        try {
            validateConfig(amapConfig.getKey(), null); // 僅校驗(yàn)Key

            // 構(gòu)建請求URL(示例:https://restapi.amap.com/v3/geocode/regeo?key=xxx&location=116.4,39.9)
            String location = longitude + "," + latitude;
            String url = String.format("%s?key=%s&location=%s",
                    amapConfig.getRegeoUrl(),
                    amapConfig.getKey(),
                    HttpUtil.encodeUrlParam(location));

            logger.debug("請求高德逆地理編碼API: {}", url);
            String response = HttpUtil.doGet(url);
            logger.debug("高德逆地理編碼API響應(yīng): {}", response);

            return parseResponse(response);
        } catch (Exception e) {
            logger.error("逆地理編碼失敗, 位置: " + longitude + "," + latitude, e);
            return createErrorResponse("逆地理編碼失敗: " + getErrorMessage(e));
        }
    }

    /**
     * 地理編碼服務(wù)(地址→坐標(biāo))
     * @param address 結(jié)構(gòu)化地址(如"北京市海淀區(qū)中關(guān)村大街1號(hào)")
     * @return 包含經(jīng)緯度的JSON響應(yīng)
     */
    @Override
    public JSONObject geoLocation(String address) {
        if (!StringUtils.hasText(address)) {
            return createErrorResponse("地址不能為空");
        }

        try {
            validateConfig(amapConfig.getKey(), null); // 僅校驗(yàn)Key

            // 構(gòu)建請求URL(示例:https://restapi.amap.com/v3/geocode/geo?key=xxx&address=北京)
            String url = String.format("%s?key=%s&address=%s",
                    amapConfig.getGeocodeUrl(),
                    amapConfig.getKey(),
                    HttpUtil.encodeUrlParam(address));

            logger.debug("請求高德地理編碼API: {}", url);
            String response = HttpUtil.doGet(url);
            logger.debug("高德地理編碼API響應(yīng): {}", response);

            return parseResponse(response);
        } catch (Exception e) {
            logger.error("地理編碼失敗, 地址: " + address, e);
            return createErrorResponse("地理編碼失敗: " + getErrorMessage(e));
        }
    }

    /**
     * 保存定位記錄到數(shù)據(jù)庫
     * @param record 定位記錄實(shí)體
     * @return 是否保存成功
     */
    @Override
    public boolean saveLocationRecord(LocationRecord record) {
        try {
            return this.save(record); // 調(diào)用MyBatis-Plus的save方法
        } catch (Exception e) {
            logger.error("保存定位記錄失敗", e);
            return false;
        }
    }

    // ==================== 內(nèi)部工具方法 ====================

    /**
     * 校驗(yàn)高德配置參數(shù)
     * @param key 高德API Key
     * @param url 需要校驗(yàn)的API地址(可選)
     * @throws IllegalStateException 當(dāng)配置不合法時(shí)拋出
     */
    private void validateConfig(String key, String url) {
        if (amapConfig == null || !StringUtils.hasText(key)) {
            throw new IllegalStateException("高德地圖配置未正確初始化");
        }
        if (url != null && !StringUtils.hasText(url)) {
            throw new IllegalStateException("高德API地址未配置");
        }
    }

    /**
     * 校驗(yàn)URL合法性
     * @param url 待校驗(yàn)的URL
     * @throws IllegalArgumentException 當(dāng)URL非法時(shí)拋出
     */
    private void validateUrl(String url) {
        if (!url.startsWith("http")) {
            throw new IllegalArgumentException("無效的API URL: " + url);
        }
    }

    /**
     * 解析高德API響應(yīng)
     * @param response 原始JSON字符串
     * @return 解析后的JSONObject
     */
    private JSONObject parseResponse(String response) {
        if (!StringUtils.hasText(response)) {
            return createErrorResponse("空響應(yīng)");
        }
        try {
            JSONObject result = JSON.parseObject(response);
            return result != null ? result : createErrorResponse("響應(yīng)解析失敗");
        } catch (Exception e) {
            logger.error("解析高德API響應(yīng)失敗", e);
            return createErrorResponse("響應(yīng)解析失敗: " + e.getMessage());
        }
    }

    /**
     * 創(chuàng)建錯(cuò)誤響應(yīng)
     * @param message 錯(cuò)誤信息
     * @return 標(biāo)準(zhǔn)化錯(cuò)誤JSON(status=0)
     */
    private JSONObject createErrorResponse(String message) {
        JSONObject result = new JSONObject();
        result.put("status", "0"); // 高德標(biāo)準(zhǔn)錯(cuò)誤碼
        result.put("info", message);
        return result;
    }

    /**
     * 提取異常信息(避免null)
     */
    private String getErrorMessage(Exception e) {
        return e.getMessage() != null ? e.getMessage() : "未知錯(cuò)誤";
    }
}
  • controller:
package com.qfedu.controller;

import com.alibaba.fastjson.JSONObject;
import com.qfedu.common.core.annotation.NoLogin;
import com.qfedu.common.core.common.R;
import com.qfedu.common.core.entity.LocationRecord;
import com.qfedu.service.AmapService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;

/**
 * 高德地圖定位服務(wù)控制器
 * 提供IP定位、逆地理編碼、地理編碼三大核心功能
 */
@RestController
@RequestMapping("/api/location")
public class LocationController {

    @Autowired
    private AmapService amapService; // 高德地圖服務(wù)接口

    /**
     * IP定位接口
     * @param ip 需要定位的IP地址(如8.8.8.8)
     * @return 標(biāo)準(zhǔn)化響應(yīng)R<JSONObject>,包含定位結(jié)果或錯(cuò)誤信息
     */
    @GetMapping("/ip")
    @NoLogin
    public R locateByIp(@RequestParam String ip) {
        // 調(diào)用高德IP定位服務(wù)
        JSONObject result = amapService.ipLocation(ip);

        // 校驗(yàn)高德API返回狀態(tài)碼(1=成功)
        if (result != null && "1".equals(result.getString("status"))) {
            saveLocationRecord(ip, result); // 持久化定位記錄
            return R.ok(result); // 返回成功響應(yīng)
        }
        // 失敗時(shí)返回錯(cuò)誤信息(優(yōu)先使用高德返回的info字段)
        return R.fail(result != null ? result.getString("info") : "IP定位服務(wù)不可用");
    }

    /**
     * 逆地理編碼接口(坐標(biāo)→地址)
     * @param longitude 經(jīng)度(如116.404)
     * @param latitude 緯度(如39.915)
     * @return 包含地址信息的標(biāo)準(zhǔn)化響應(yīng)
     */
    @GetMapping("/regeo")
    @NoLogin
    public R regeo(
            @RequestParam Double longitude,
            @RequestParam Double latitude) {
        JSONObject result = amapService.regeoLocation(longitude, latitude);
        if (result != null && "1".equals(result.getString("status"))) {
            saveLocationRecord(null, longitude, latitude, result); // IP傳null
            return R.ok(result);
        }
        return R.fail(result != null ? result.getString("info") : "逆地理編碼服務(wù)不可用");
    }

    /**
     * 地理編碼接口(地址→坐標(biāo))
     * @param address 結(jié)構(gòu)化地址(如"北京市海淀區(qū)中關(guān)村大街1號(hào)")
     * @return 包含經(jīng)緯度的標(biāo)準(zhǔn)化響應(yīng)
     */
    @GetMapping("/geo")
    @NoLogin
    public R geo(@RequestParam String address) {
        JSONObject result = amapService.geoLocation(address);
        if (result != null && "1".equals(result.getString("status"))) {
            return R.ok(result); // 地理編碼不保存記錄
        }
        return R.fail(result != null ? result.getString("info") : "地理編碼服務(wù)不可用");
    }

    // 內(nèi)部工具方法

    /**
     * 從IP定位結(jié)果提取經(jīng)緯度并保存記錄
     * @param ip IP地址
     * @param result 高德API返回的完整結(jié)果
     */
    private void saveLocationRecord(String ip, JSONObject result) {
        JSONObject locationObj = result.getJSONObject("location");
        if (locationObj != null) {
            saveLocationRecord(
                    ip,
                    locationObj.getDouble("lng"), // 經(jīng)度字段
                    locationObj.getDouble("lat"), // 緯度字段
                    result
            );
        }
    }

    /**
     * 保存定位記錄到數(shù)據(jù)庫(核心方法)
     * @param ip 可能為null(當(dāng)來源是逆地理編碼時(shí))
     * @param longitude 經(jīng)度(必填)
     * @param latitude 緯度(必填)
     * @param result 高德API原始結(jié)果(用于提取地址信息)
     */
    private void saveLocationRecord(
            String ip,
            Double longitude,
            Double latitude,
            JSONObject result) {
        if (result == null) return;

        // 1. 構(gòu)建定位記錄實(shí)體
        LocationRecord record = new LocationRecord();
        record.setIp(ip); // IP可能為null
        record.setLongitude(longitude);
        record.setLatitude(latitude);

        // 2. 提取格式化地址(如"北京市海淀區(qū)中關(guān)村大街1號(hào)")
        String formattedAddress = result.getString("formatted_address");
        record.setAddress(formattedAddress);
        record.setFormattedAddress(formattedAddress);

        // 3. 提取結(jié)構(gòu)化地址組件(省、市、區(qū)等)
        JSONObject addressComponent = result.getJSONObject("addressComponent");
        if (addressComponent != null) {
            record.setProvince(addressComponent.getString("province"));
            record.setCity(addressComponent.getString("city"));
            // 可擴(kuò)展:district(區(qū))、street(街道)等字段
        }

        // 4. 設(shè)置時(shí)間戳并保存
        record.setCreateTime(new Date());
        amapService.saveLocationRecord(record); // 調(diào)用MyBatis-Plus持久化
    }
}

下面就是啟動(dòng)類:(首先不要忘記啟動(dòng)類的掃描注解,還有就是本次用到的注解

@EnableConfigurationProperties({AmapConfig.class})// 啟用AmapConfig配置類)
package com.qfedu;

import com.qfedu.config.AmapConfig;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

@SpringBootApplication
@MapperScan("com.qfedu.mapper")
@EnableConfigurationProperties({AmapConfig.class})// 啟用AmapConfig配置類

public class MicroServeAmapApplication {

    public static void main(String[] args) {
        SpringApplication.run(MicroServeAmapApplication.class, args);
    }

}

寫一個(gè)簡單的頁面展示吧

位置你們知道吧,我就不說詳細(xì)了

展示臺(tái)灣省地圖吧(中國一點(diǎn)都不能少)

下面就是展示的代碼,我只不過吧經(jīng)緯度寫成死值了,

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>高德地圖展示測試:臺(tái)灣省臺(tái)北市地圖 - 臺(tái)北101</title>
    <!-- 引入高德地圖JS API -->
    <script src="https://webapi.amap.com/maps?v=2.0&key=你的高德地圖key"></script>
    <style>
        #container {
            width: 100%;
            height: 600px;
        }
    </style>
</head>
<body>
<!-- 地圖容器 -->
<div id="container"></div>

<script>
    // 初始化地圖,中心點(diǎn)設(shè)為臺(tái)北市
    var map = new AMap.Map('container', {
        zoom: 14,          // 縮放級(jí)別
        center: [121.5654, 25.0330], // 臺(tái)北市坐標(biāo)
        viewMode: '2D'     // 2D地圖
    });

    // 添加標(biāo)記點(diǎn)(臺(tái)北101大樓)
    var marker = new AMap.Marker({
        position: [121.5654, 25.0330], // 臺(tái)北101坐標(biāo)
        map: map
    });

    // 信息窗口內(nèi)容
    var infoWindow = new AMap.InfoWindow({
        content: '<div style="padding:5px;">臺(tái)北101大樓</div>',
        offset: new AMap.Pixel(0, -30)
    });
    infoWindow.open(map, marker.getPosition());
</script>
</body>
</html>

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 面向?qū)ο蠛兔嫦蜻^程的區(qū)別(動(dòng)力節(jié)點(diǎn)java學(xué)院整理)

    面向?qū)ο蠛兔嫦蜻^程的區(qū)別(動(dòng)力節(jié)點(diǎn)java學(xué)院整理)

    很多朋友不清楚面向?qū)ο蠛兔嫦蜻^程有什么區(qū)別,接下來小編給大家整理了關(guān)于面向?qū)ο蠛兔嫦蜻^程的區(qū)別講解,感興趣的朋友可以參考下
    2017-04-04
  • SpringBoot+Redis+Lua分布式限流的實(shí)現(xiàn)

    SpringBoot+Redis+Lua分布式限流的實(shí)現(xiàn)

    本文主要介紹了SpringBoot+Redis+Lua分布式限流的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • Springboot項(xiàng)目啟動(dòng)成功后可通過五種方式繼續(xù)執(zhí)行

    Springboot項(xiàng)目啟動(dòng)成功后可通過五種方式繼續(xù)執(zhí)行

    本文主要介紹了Springboot項(xiàng)目啟動(dòng)成功后可通過五種方式繼續(xù)執(zhí)行,主要包括CommandLineRunner接口,ApplicationRunner接口,ApplicationListener接口,@PostConstruct注解,InitalizingBean接口,感興趣的可以了解一下
    2023-12-12
  • SpringBoot項(xiàng)目啟動(dòng)數(shù)據(jù)加載內(nèi)存的三種方法

    SpringBoot項(xiàng)目啟動(dòng)數(shù)據(jù)加載內(nèi)存的三種方法

    一般來說,SpringBoot工程環(huán)境配置放在properties文件中,啟動(dòng)的時(shí)候?qū)⒐こ讨械膒roperties/yaml文件的配置項(xiàng)加載到內(nèi)存中,本文給大家介紹了SpringBoot項(xiàng)目啟動(dòng)數(shù)據(jù)加載內(nèi)存中的三種方法,需要的朋友可以參考下
    2024-04-04
  • Java如何實(shí)現(xiàn)對稱加密

    Java如何實(shí)現(xiàn)對稱加密

    這篇文章主要介紹了Java如何實(shí)現(xiàn)對稱加密問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • java爬取并下載酷狗TOP500歌曲的方法

    java爬取并下載酷狗TOP500歌曲的方法

    這篇文章主要介紹了java爬取并下載酷狗TOP500歌曲的方法,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2019-01-01
  • java中JsonObject與JsonArray轉(zhuǎn)換方法實(shí)例

    java中JsonObject與JsonArray轉(zhuǎn)換方法實(shí)例

    在項(xiàng)目日常開發(fā)中常常會(huì)遇到JSONArray和JSONObject的轉(zhuǎn)換,很多公司剛?cè)肼毜男∶刃聲?huì)卡在這里,下面這篇文章主要給大家介紹了關(guān)于java中JsonObject與JsonArray轉(zhuǎn)換方法的相關(guān)資料,需要的朋友可以參考下
    2023-04-04
  • Java 集合去重的三種方法

    Java 集合去重的三種方法

    本主要介紹了Java 集合去重的三種方法,包含HashSet,Stream API和手動(dòng)遍歷并使用Map三種,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-07-07
  • java獲取properties屬性文件示例

    java獲取properties屬性文件示例

    Properties類表示了一個(gè)持久的屬性集。Properties可保存在流中或從流中加載。屬性列表中每個(gè)鍵及其對應(yīng)值都是一個(gè)字符串。本文使用java讀取這些屬性,看下面詳細(xì)介紹吧
    2014-01-01
  • Spring AOP里的靜態(tài)代理和動(dòng)態(tài)代理用法詳解

    Spring AOP里的靜態(tài)代理和動(dòng)態(tài)代理用法詳解

    這篇文章主要介紹了 Spring AOP里的靜態(tài)代理和動(dòng)態(tài)代理用法詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07

最新評論