C++(Qt)-GIS开发-QGraphicsView显示在线瓦片地图

news2024/11/16 21:49:22

C++(Qt)-GIS开发-QGraphicsView显示在线瓦片地图

文章目录

  • C++(Qt)-GIS开发-QGraphicsView显示在线瓦片地图
    • 1、概述
    • 2、实现效果
    • 3、主要代码
    • 4、源码地址

更多精彩内容
👉个人内容分类汇总 👈
👉GIS开发 👈

1、概述

  1. 支持加载显示在线瓦片地图(墨卡托投影);
  2. 瓦片切片规则以左上角为原点(谷歌、高德、ArcGis等),不支持百度瓦片规则;
  3. 支持显示瓦片网格、编号信息。
  4. 支持鼠标滚轮缩放切换地图层级。
  5. 支持鼠标拖拽。
  6. 支持显示瓦片编号、瓦片网格;
  7. 支持在线程池中快速下载在线瓦片;
  8. 以北纬85.05,西经-180为坐标原点【绝对像素坐标】。
  9. 默认支持下载显示多格式高德、Bing、ArcGis瓦片地图。
  10. 支持x/y/z、x/z/y、z/y/x任意顺序格式、quadKey格式的url。

开发环境说明

  • 系统:Windows11、Ubuntu20.04
  • Qt版本:Qt 5.14.2
  • 编译器:MSVC2017-64、GCC/G++64

2、实现效果

在这里插入图片描述

3、主要代码

  • geturl.h

    #ifndef GETURL_H
    #define GETURL_H
    
    #include "mapStruct.h"
    #include <qfuture.h>
    #include <qset.h>
    #include <QObject>
    
    class GetUrlInterface : public QObject
    {
        Q_OBJECT
    public:
        static GetUrlInterface* getInterface()
        {
            static GetUrlInterface interface;
            return &interface;
        }
    
    signals:
        void update(ImageInfo info);             // 传出下载的瓦片图信息
        void updateTitle(int x, int y, int z);   // 传出下载的瓦片编号
    
        void showRect(QRect rect);   // 设置显示像素范围
        void setLevel(int level);    // 设置瓦片层级
    };
    
    class GetUrl : public QObject
    {
        Q_OBJECT
    public:
        explicit GetUrl(QObject* parent = nullptr);
        ~GetUrl();
    
        void setUrl(QString url);   // 设置获取瓦片地图的源地址
        void getImg(QRect rect, int level);
        void showRect(QRect rect);
        void setLevel(int level);   // 设置瓦片层级
    
    private:
        void getTitle(QRect rect, int level);    // 获取所有需要下载的瓦片地图编号
        void getUrl();                           // 获取用于请求瓦片地图的信息
        void clear();                            // 清空内容
        void quit();                             // 退出下载
        void updateTitle(int x, int y, int z);   // 传出下载的瓦片编号
    
    private:
        QThread* m_thread = nullptr;
        QFuture<void> m_future;
        QRect m_rect;      // 显示瓦片地图像素范围
        int m_level = 5;   // 瓦片地图层级
        QString m_url;
        QSet<quint64> m_exist;        // 已经存在的瓦片地图编号
        QVector<ImageInfo> m_infos;   // 需要下载的瓦片地图信息
    };
    
    #endif   // GETURL_H
    
    
  • geturl.cpp

    /********************************************************************
     * 文件名: geturl.cpp
     * 时间:   2024-05-19 14:29:30
     * 开发者:  mhf
     * 邮箱:   1603291350@qq.com
     * 说明:   瓦片地图网络请求类
     * ******************************************************************/
    #include "geturl.h"
    #include "bingformula.h"
    #include <qnetworkaccessmanager.h>
    #include <qnetworkreply.h>
    #include <QDebug>
    #include <QSet>
    #include <QtConcurrent>
    
    GetUrl::GetUrl(QObject* parent)
        : QObject{parent}
    {
        m_thread = new QThread;
        this->moveToThread(m_thread);
        m_thread->start();
    
        m_rect.setTopLeft(Bing::latLongToPixelXY(64.16, 56.115, m_level));
        m_rect.setBottomRight(Bing::latLongToPixelXY(148.66, 9.34, m_level));
        connect(GetUrlInterface::getInterface(), &GetUrlInterface::updateTitle, this, &GetUrl::updateTitle);
        connect(GetUrlInterface::getInterface(), &GetUrlInterface::showRect, this, &GetUrl::showRect);
        connect(GetUrlInterface::getInterface(), &GetUrlInterface::setLevel, this, &GetUrl::setLevel);
    }
    
    GetUrl::~GetUrl()
    {
        quit();
        clear();
    
        m_thread->quit();
        m_thread->wait();
        delete m_thread;
    }
    
    /**
     * @brief     设置瓦片地图源地址
     * @param url
     */
    void GetUrl::setUrl(QString url)
    {
        if (url.isEmpty())
            return;
    
        quit();   // 退出下载后再清空数组,防止数据竞争
        clear();
        m_exist.clear();   // 清空已下载列表
        m_url = url;
        getImg(m_rect, m_level);   // 使用默认范围、层级更新地图
    }
    
    /**
     * @brief       下载瓦片
     * @param info
     * @return
     */
    void httpGet(ImageInfo info)
    {
        QNetworkAccessManager manager;
        QSharedPointer<QNetworkReply> reply(manager.get(QNetworkRequest(QUrl(info.url))));
        // 等待返回
        QEventLoop loop;
        QObject::connect(reply.data(), &QNetworkReply::finished, &loop, &QEventLoop::quit);   // 等待获取完成
        QTimer::singleShot(5000, &loop, &QEventLoop::quit);                                   // 等待超时
        loop.exec();
    
        if (reply->error() == QNetworkReply::NoError)
        {
            QByteArray buf = reply->readAll();
            if (!buf.isEmpty())
            {
                info.img.loadFromData(buf);
                if (!info.img.isNull())
                {
                    emit GetUrlInterface::getInterface() -> update(info);
                    emit GetUrlInterface::getInterface() -> updateTitle(info.x, info.y, info.z);
                    return;
                }
            }
        }
    
        info.count++;
        if (info.count < 3)
        {
            httpGet(info);   // 下载失败重新下载
            return;
        }
        else
        {
            qWarning() << "下载失败:" << reply->errorString();
        }
    }
    
    /**
     * @brief       获取瓦片地图
     * @param rect  瓦片地图的像素范围
     * @param level 瓦片地图的级别
     */
    void GetUrl::getImg(QRect rect, int level)
    {
        if (rect.isEmpty())
            return;
        if (level > 22 || level < 0)
            return;
        m_rect = rect;
        m_level = level;
    
        if (m_future.isRunning())   // 判断是否在运行
        {
            m_future.cancel();   // 取消下载
        }
        clear();   // 清空待下载列表
    
        getTitle(rect, level);   // 获取所有需要加载的瓦片编号
        qInfo() << "获取瓦片数:" << m_infos.count();
        getUrl();                                         // 将瓦片编号转为url
        m_future = QtConcurrent::map(m_infos, httpGet);   // 在线程池中下载瓦片图
    }
    
    /**
     * @brief      设置获取瓦片地图的像素范围
     * @param rect
     */
    void GetUrl::showRect(QRect rect)
    {
        if (rect.isEmpty())
            return;
        getImg(rect, m_level);
    }
    
    /**
     * @brief       通过设置显示瓦片层级别完成缩放显示
     * @param level
     */
    void GetUrl::setLevel(int level)
    {
        if ((level < 0) || (level > 23))
        {
            return;
        }
        if (m_level != level)
        {
            m_exist.clear();   // 清空已下载列表
        }
        m_level = level;
    }
    
    /**
     * @brief       获取瓦片编号
     * @param rect
     * @param level
     */
    void GetUrl::getTitle(QRect rect, int level)
    {
        QPoint tl = Bing::pixelXYToTileXY(rect.topLeft());
        QPoint br = Bing::pixelXYToTileXY(rect.bottomRight());
    
        quint64 value = 0;
        ImageInfo info;
        info.z = level;
    
        int max = qPow(2, level);   // 最大瓦片编号
        for (int x = tl.x(); x <= br.x(); x++)
        {
            if (x < 0)
                continue;
            if (x >= max)
                break;
            info.x = x;
            for (int y = tl.y(); y <= br.y(); y++)
            {
                if (y < 0)
                    continue;
                if (y >= max)
                    break;
                value = ((quint64) level << 48) + (x << 24) + y;
    
                if (!m_exist.contains(value))
                {
                    info.y = y;
                    m_infos.append(info);
                }
            }
        }
    }
    
    /**
     * @brief 获取用于请求瓦片地图的信息
     */
    void GetUrl::getUrl()
    {
        if (m_url.contains("{x}"))   // XYZ格式
        {
            QString url = m_url;
            url.replace("{x}", "%1");
            url.replace("{y}", "%2");
            url.replace("{z}", "%3");
            for (int i = 0; i < m_infos.count(); i++)
            {
                m_infos[i].url = url.arg(m_infos[i].x).arg(m_infos[i].y).arg(m_infos[i].z);
            }
        }
        else if (m_url.contains("{q}"))   // Bing的quadKey格式
        {
            QString url = m_url;
            url.replace("{q}", "%1");
            QPoint point;
            for (int i = 0; i < m_infos.count(); i++)
            {
                point.setX(m_infos[i].x);
                point.setY(m_infos[i].y);
                QString quadKey = Bing::tileXYToQuadKey(point, m_infos[i].z);   // 将xy转为quadkey
                m_infos[i].url = url.arg(quadKey);
            }
        }
        else
        {
            qDebug() << "url格式未定义";
        }
    }
    
    /**
     * @brief 清空内容
     */
    void GetUrl::clear()
    {
        QVector<ImageInfo> info;
        m_infos.swap(info);
    }
    
    /**
     * @brief 退出下载
     */
    void GetUrl::quit()
    {
        if (m_future.isRunning())   // 判断是否在运行
        {
            m_future.cancel();            // 取消下载
            m_future.waitForFinished();   // 等待退出
        }
    }
    
    /**
     * @brief     将下载成功的瓦片编号添加进已下载列表,已经下载的瓦片在后续不进行下载
     * @param x
     * @param y
     * @param z
     */
    void GetUrl::updateTitle(int x, int y, int z)
    {
        quint64 value = (quint64(z) << 48) + (x << 24) + y;
        m_exist.insert(value);
    }
    
    
  • mapgraphicsview.h文件

    #ifndef MAPGRAPHICSVIEW_H
    #define MAPGRAPHICSVIEW_H
    
    #include "graphicsitemgroup.h"
    #include "mapStruct.h"
    #include <QGraphicsView>
    
    class MapGraphicsView : public QGraphicsView
    {
        Q_OBJECT
    public:
        explicit MapGraphicsView(QWidget* parent = nullptr);
        ~MapGraphicsView() override;
    
        void setRect(int level);
        void drawImg(const ImageInfo& info);
        void clear();
    
    signals:
        void updateImage(const ImageInfo& info);   // 添加瓦片图
        void showRect(QRect rect);
        void mousePos(QPoint pos);
    
    protected:
        void mousePressEvent(QMouseEvent* event) override;
        void mouseReleaseEvent(QMouseEvent* event) override;
        void wheelEvent(QWheelEvent* event) override;
        void resizeEvent(QResizeEvent* event) override;
        void showEvent(QShowEvent* event) override;
    
    private:
        void getShowRect();   // 获取显示范围
    
    private:
        QGraphicsScene* m_scene = nullptr;
        int m_level = 5;           // 当前显示瓦片等级
        bool m_moveView = false;   // 鼠标移动显示视图
        QPointF m_pos;
        QPointF m_scenePos;
        QHash<quint16, GraphicsItemGroup*> m_itemGroup;   // 瓦片图元组
    };
    
    #endif   // MAPGRAPHICSVIEW_H
    
    
  • mapgraphicsview.cpp文件

    #include "mapgraphicsview.h"
    
    #include "bingformula.h"
    #include "geturl.h"
    #include <qthread.h>
    #include <QDebug>
    #include <QFont>
    #include <QGraphicsItem>
    #include <QMouseEvent>
    #include <QScrollBar>
    #include <QWheelEvent>
    #include <QtMath>
    
    MapGraphicsView::MapGraphicsView(QWidget* parent)
        : QGraphicsView(parent)
    {
        m_scene = new QGraphicsScene();
        this->setScene(m_scene);
        this->setDragMode(QGraphicsView::ScrollHandDrag);   // 鼠标拖拽
    
        // 窗口左上角初始显示位置(中国)
        m_scenePos.setX(5700);
        m_scenePos.setY(2700);
        //    this->setMouseTracking(true);                       // 开启鼠标追踪
    
        connect(GetUrlInterface::getInterface(), &GetUrlInterface::update, this, &MapGraphicsView::drawImg);
    }
    
    MapGraphicsView::~MapGraphicsView() {}
    
    void MapGraphicsView::setRect(int level)
    {
        int w = int(qPow(2, level) * 256);
        QRect rect(0, 0, w, w);
        m_scene->setSceneRect(rect);
    
        // 将显示位置移动到缩放之前的位置
        this->horizontalScrollBar()->setValue(qRound(m_scenePos.x() - m_pos.x()));
        this->verticalScrollBar()->setValue(qRound(m_scenePos.y() - m_pos.y()));
    }
    
    /**
     * @brief       绘制瓦片图
     * @param info
     */
    void MapGraphicsView::drawImg(const ImageInfo& info)
    {
        if (!m_itemGroup.contains(info.z))   // 如果图层不存在则添加
        {
            auto* item = new GraphicsItemGroup();
            m_itemGroup.insert(info.z, item);
            m_scene->addItem(item);
        }
    
        GraphicsItemGroup* itemGroup = m_itemGroup.value(info.z);
        if (itemGroup)
        {
            itemGroup->addImage(info);
        }
    }
    
    /**
     * @brief 清空所有瓦片
     */
    void MapGraphicsView::clear()
    {
        auto* itemGroup = m_itemGroup.value(m_level);
        if (itemGroup)
        {
            delete itemGroup;
            m_itemGroup.remove(m_level);
            m_level = 0;
        }
    }
    
    void MapGraphicsView::mousePressEvent(QMouseEvent* event)
    {
        QGraphicsView::mousePressEvent(event);
    
        if (event->buttons() & Qt::LeftButton)
        {
            m_moveView = true;
        }
    }
    
    /**
     * @brief          鼠标释放
     * @param event
     */
    void MapGraphicsView::mouseReleaseEvent(QMouseEvent* event)
    {
        QGraphicsView::mouseReleaseEvent(event);
    
        if (m_moveView)   // 在鼠标左键释放时获取新的瓦片地图
        {
            emit mousePos(this->mapToScene(event->pos()).toPoint());
            getShowRect();
            m_moveView = false;
        }
    }
    
    /**
     * @brief        鼠标滚轮缩放
     * @param event
     */
    void MapGraphicsView::wheelEvent(QWheelEvent* event)
    {
        m_pos = event->pos();                          // 鼠标相对于窗口左上角的坐标
        m_scenePos = this->mapToScene(event->pos());   // 鼠标在场景中的坐标
        if (event->angleDelta().y() > 0)
        {
            m_scenePos = m_scenePos * 2;   // 放大
            m_level++;
        }
        else
        {
            m_scenePos = m_scenePos / 2;   // 缩小
            m_level--;
        }
        m_level = qBound(0, m_level, 22);                            // 限制缩放层级
        setRect(m_level);                                            // 设置缩放后的视图大小
        emit GetUrlInterface::getInterface() -> setLevel(m_level);   // 设置缩放级别
        getShowRect();
    
        // 隐藏缩放前所有图层
        for (auto itemG : m_itemGroup)
        {
            itemG->hide();
        }
    
        if (m_itemGroup.contains(m_level))   // 如果图层存在则显示
        {
            GraphicsItemGroup* itemGroup = m_itemGroup.value(m_level);
            itemGroup->show();
        }
        else   // 如果不存在则添加
        {
            auto* item = new GraphicsItemGroup();
            m_itemGroup.insert(m_level, item);
            m_scene->addItem(item);
        }
    }
    
    /**
     * @brief       窗口大小变化后获取显示新的地图
     * @param event
     */
    void MapGraphicsView::resizeEvent(QResizeEvent* event)
    {
        QGraphicsView::resizeEvent(event);
        //    getShowRect();
    }
    
    /**
     * @brief       窗口显示时设置显示瓦片的视图位置
     * @param event
     */
    void MapGraphicsView::showEvent(QShowEvent* event)
    {
        QGraphicsView::showEvent(event);
        setRect(m_level);
    }
    
    /**
     * @brief 获取当前场景的显示范围(场景坐标系)
     */
    void MapGraphicsView::getShowRect()
    {
        QRect rect;
        int w = int(qPow(2, m_level) * 256);   // 最大范围
        QPoint tl = this->mapToScene(0, 0).toPoint();
        QPoint br = this->mapToScene(this->width(), this->height()).toPoint();
        rect.setX(qMax(tl.x(), 0));
        rect.setY(qMax(tl.y(), 0));
        rect.setRight(qMin(br.x(), w));
        rect.setBottom(qMin(br.y(), w));
        emit GetUrlInterface::getInterface() -> showRect(rect);
    }
    
    

4、源码地址

  • github
  • gitee

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2090639.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

TD学习笔记————中级教程总结(NEW)

目录 Instance功能讲解 问题&#xff1a; 报错All ops must generate the same number of instances (have the same length Replicator功能讲解 问题&#xff1a; 视频分辨率过大 Cannot find function named:onValueChange Instance功能讲解 数据通道的长度要一致 N…

redroid搭建云手机学习笔记(一)

参考链接 通过Redroid搭建自己的云手机 docker安装 docker官网目前打不开了&#xff0c;通过官网安装的方式无法实现&#xff0c;这里需要借助镜像网站来实现docker的安装 参考链接&#xff1a;https://developer.aliyun.com/mirror/docker-ce # step 1: 安装必要的一些系统…

Dockerfile 实例

删除不需要的镜像&#xff1a;示例&#xff1a;通配符可用 [rootdocker ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE <none> <none> 580260c93725 2 hours ago 4.27MB <none&…

基于python的足球比赛数据及可视化 python 足球预测

Python 足球可视化分析是使用 Python 编程语言来进行足球比赛数据分析&#xff0c;并将结果呈现为可视化图形的过程。Python 作为一种高效灵活的编程语言&#xff0c;可以用于数据处理和分析&#xff0c;同时也有丰富的可视化库。 足球比赛数据可以从各种数据来源获取&#xf…

使用 AI进行绘画初体验

大家好啊&#xff0c;我是董董灿。 AI 绘画的效果是真的不错&#xff0c;最近在查找AI相关技术文章时&#xff0c;总是会时不时的发现一些好玩的 AI 应用&#xff0c;而且大多数都是免费的。 今天就给大家介绍如何使用 MidJourney 来完成 AI 绘画的网站。 MidJourney 本身是…

解决 Linux 上的 SSH 登录缓慢问题

如果您必须等待很长时间才能看到 SSH 密码提示&#xff0c;则可能存在多种问题。要解决 SSH 登录缓慢的根本原因&#xff0c;您可以运行带有 -vvv 选项的 ssh 命令&#xff0c;该命令将向您显示 SSH 登录期间幕后发生的情况。 $ ssh -vvv user<ssh-server>以下是 SSH 登…

Windows bat脚本学习六(十六进制与十进制互转)

一、十六进制转十进制 十六进制数转十进制数相对比较简单&#xff0c;可以直接通过0x来实现。 见如下代码&#xff1a; echo off chcp 65001set taaset /a hex0x%t% echo data%hex%pause 结果&#xff1a; 二、十进制转十六进制 这个转化比较麻烦&#xff0c;没有简便的方式转…

前端面试题每日一练,测测你对JavaScript对象继承和 Object.entries() 的理解

今天的挑战题目涉及到JavaScript中的原型链 (prototype chain) 和 Object.entries() 方法的使用。我们将通过一个对象继承的例子来探索如何使用 Object.entries() 获取对象的自身可枚举属性&#xff0c;并进行处理。让我们一起分析这段代码&#xff0c;看看它会输出什么以及为什…

微服务CI/CD实践(四)Jenkins部署及环境配置

微服务CI/CD实践系列&#xff1a; 微服务CI/CD实践&#xff08;一&#xff09;环境准备及虚拟机创建 微服务CI/CD实践&#xff08;二&#xff09;服务器先决准备 微服务CI/CD实践&#xff08;三&#xff09;gitlab部署及nexus3部署 微服务CI/CD实践&#xff08;四&#xff09…

ClickHouse的安装教程

ClickHouse的安装教程 文章目录 ClickHouse的安装教程写在前面准备工作关闭防火墙CentOS 取消打开文件数限制安装依赖CentOS 取消 SELINUX 单机安装在 **node01** 的/opt/software 下创建 clickhouse 目录将下载的文件上传到 node01 的 /opt/software/clickhouse 目录下将安装文…

MFC工控项目实例之九选择下拉菜单主界面文本框显示菜单名

承接专栏《MFC工控项目实例之八选择下拉菜单添加打钩图标》 1、在主界面添加一个组合框和一个静态文本框。 2、在SEAL_PRESSUREDlg.cpp文件中添加代码 BOOL CSEAL_PRESSUREDlg::OnInitDialog() {CDialog::OnInitDialog(); ... GetDlgItem(IDC_STATIC_TYPNAME)->SetFont(&a…

通用大模型应用研究重点六:AgentOS

智能体&#xff1a;一个能够自主感知环境、做出决策并执行行动的系统。具备规划思考能力、记忆能力以及使用工具函数的能力&#xff0c;能自主完成给定任务的计算机程序。 智能体的关键组成部分包括&#xff1a; 规划&#xff08;Planning&#xff09;&#xff1a;智能体能够将…

(二)、软硬件全开源智能手表,可全面高精度采集生命体征数据,进行健康检测。(HealthyPi Move)

HealthyPi Move是一款开放式硬件设备&#xff0c;可让您高精度地跟踪所有生命体征。它不仅仅是另一款带有心率监测器的智能手表&#xff0c;它还是手腕上的完整生命体征监测和记录设备&#xff0c;可以测量心电图(ECG)、光电容积脉搏波 (PPG)、SpO₂、血压(基于手指)、EDA/GSR、…

Clobotics 计算机视觉场景存储实践:多云架构、 POSIX 全兼容、低运维的统一存储

Clobotics 是一家将计算机视觉和机器学习技术应用于风电以及零售行业的企业。在风电行业&#xff0c;Clobotics 利用无人机对风力发电机叶片进行检查&#xff0c;显著降低了对人工作业的依赖。在零售领域&#xff0c;公司通过分析捕获的包装商品图像来提供基于实时数据的洞察&a…

Java-数据结构-ArrayLis与线性表 (๑╹◡╹)ノ“““

目录&#xff1a; 一、List的简单的介绍&#xff1a; 二、线性表&#xff1a; 三、顺序表&#xff1a; 1、基本代码&#xff1a; 2、操作代码&#xff1a; display()方法&#xff1a; add(int data)方法&#xff1a; add(int pos,int data)方法&#xff1a; contains(i…

大模型企业应用落地系列》基于大模型的对话式推荐系统》对话推荐系统技术架构

注&#xff1a;此文章内容均节选自充电了么创始人&#xff0c;CEO兼CTO陈敬雷老师的新书《自然语言处理原理与实战》&#xff08;人工智能科学与技术丛书&#xff09;【陈敬雷编著】【清华大学出版社】 文章目录 大模型企业应用落地系列全貌基于大模型的对话式推荐系统》技术架…

SpringWeb后端开发-登录认证

Author&#xff1a;Dawn_T17&#x1f965; 目录 登录功能 基础登录 登录校验 一、会话技术 1.基于 Cookie 和 Session 的传统会话技术(传统) 2.基于 Token 的会话技术&#xff08;如 JWT&#xff09;(主流)​ JWT 二、过滤器&#xff08;Filter&#xff09; 具体代…

《JavaEE进阶》----1.<JavaEE进阶可以学到什么>

本篇博客会讲到 一、JavaEE进阶学习内容&#xff1a; 1.框架的学习&#xff1a;Spring、Spring Boot、Spring MVC、MyBatis 2.大项目实践 3.源码阅读 二、JavaEE简介 B/S架构web开发流程 web前端开发&#xff08;了解&#xff09; web后端开发&#xff08;重点&#xff09; 三、…

properties文件提示未引用

问题描述 以前用的好好的项目,今天突然打开就发现idea不识别spring配置信息显示未引用,如果config代码中引入的配置却可以高亮显示,然后输入spring相关的配置,文件是没有提示的。经过研究发现是spring相关的插件被关闭了。效果如下 解决方法 启用三个插件spring Boot,Sp…

Idea发布springboot项目无法识别到webapp下面的静态资源

问题&#xff1a; Idea发布springboot项目无法识别到webapp下面的静态资源 访问报错404 解决办法&#xff1a; 修改之后重新构建&#xff0c;访问成功