当前位置: 首页 > news >正文

Java调用Pytorch实现以图搜图(附源码)

Java调用Pytorch实现以图搜图

设计技术栈:
1、ElasticSearch环境;
2、Python运行环境(如果事先没有pytorch模型时,可以用python脚本创建模型);

1、运行效果

在这里插入图片描述

2、创建模型(有则可以跳过)

vi script.py

import torch
import torch.nn as nn
import torchvision.models as modelsclass ImageFeatureExtractor(nn.Module):def __init__(self):super(ImageFeatureExtractor, self).__init__()self.resnet = models.resnet50(pretrained=True)#最终输出维度1024的向量,下文elastic search要设置dims为1024self.resnet.fc = nn.Linear(2048, 1024)def forward(self, x):x = self.resnet(x)return xif __name__ == '__main__':model = ImageFeatureExtractor()model.eval()#根据模型随便创建一个输入input = torch.rand([1, 3, 224, 224])output = model(input)#以这种方式保存script = torch.jit.trace(model, input)script.save("model.pt")

2、java项目pom.xml

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>provided</scope></dependency><dependency><groupId>ai.djl.pytorch</groupId><artifactId>pytorch-engine</artifactId><version>0.19.0</version></dependency><dependency><groupId>ai.djl.pytorch</groupId><artifactId>pytorch-native-cpu</artifactId><version>1.10.0</version><scope>runtime</scope></dependency><dependency><groupId>ai.djl.pytorch</groupId><artifactId>pytorch-jni</artifactId><version>1.10.0-0.19.0</version></dependency><dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId></dependency></dependencies>

3、ES创建文档

PUT /isi
{"mappings": {"properties": {"vector": {"type": "dense_vector","dims": 1024},"url" : {"type" : "keyword"},"user_id": {"type": "keyword"}}}
}

4、编写java代码调用模型

ORCUtil.java

package com.topprismcloud.rtm;import ai.djl.Device;
import ai.djl.Model;
import ai.djl.inference.Predictor;
import ai.djl.modality.cv.Image;
import ai.djl.modality.cv.ImageFactory;
import ai.djl.modality.cv.transform.Normalize;
import ai.djl.modality.cv.transform.Resize;
import ai.djl.modality.cv.transform.ToTensor;
import ai.djl.modality.cv.util.NDImageUtils;
import ai.djl.ndarray.NDArray;
import ai.djl.ndarray.NDList;
import ai.djl.ndarray.NDManager;
import ai.djl.translate.Transform;
import ai.djl.translate.Translator;
import ai.djl.translate.TranslatorContext;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.ScriptQueryBuilder;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.xcontent.XContentType;import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URL;
import java.nio.file.Paths;
import java.util.*;public class ORCUtil {private static final String INDEX = "isi";private static final int IMAGE_SIZE = 224;private static Model model; // 模型private static Predictor<Image, float[]> predictor; // predictor.predict(input)相当于python中model(input)static {try {model = Model.newInstance("model");// 这里的model.pt是上面代码展示的那种方式保存的model.load(ORCUtil.class.getClassLoader().getResourceAsStream("model.pt"));Transform resize = new Resize(IMAGE_SIZE);Transform toTensor = new ToTensor();Transform normalize = new Normalize(new float[] { 0.485f, 0.456f, 0.406f },new float[] { 0.229f, 0.224f, 0.225f });// Translator处理输入Image转为tensor、输出转为float[]Translator<Image, float[]> translator = new Translator<Image, float[]>() {@Overridepublic NDList processInput(TranslatorContext ctx, Image input) throws Exception {NDManager ndManager = ctx.getNDManager();System.out.println("input: " + input.getWidth() + ", " + input.getHeight());NDArray transform = normalize.transform(toTensor.transform(resize.transform(input.toNDArray(ndManager))));System.out.println(transform.getShape());NDList list = new NDList();list.add(transform);return list;}@Overridepublic float[] processOutput(TranslatorContext ctx, NDList ndList) throws Exception {return ndList.get(0).toFloatArray();}};predictor = new Predictor<>(model, translator, Device.cpu(), true);} catch (Exception e) {e.printStackTrace();}}public static void upload() throws Exception {HttpHost host=new HttpHost("14.20.30.16", 9200, HttpHost.DEFAULT_SCHEME_NAME);RestClientBuilder builder=RestClient.builder(host);CredentialsProvider credentialsProvider = new BasicCredentialsProvider();credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("elastic", "123456"));builder.setHttpClientConfigCallback(f -> f.setDefaultCredentialsProvider(credentialsProvider));RestHighLevelClient client = new RestHighLevelClient( builder);// 批量上传请求BulkRequest bulkRequest = new BulkRequest(INDEX);File file = new File("D:\\001ENV\\nginx-1.24.0\\html\\resource\\new");for (File listFile : file.listFiles()) {
//			float[] vector = predictor.predict(ImageFactory.getInstance()
//					.fromInputStream(Test.class.getClassLoader().getResourceAsStream("new/" + listFile.getName())));float[] vector = predictor.predict(ImageFactory.getInstance().fromInputStream(new FileInputStream(listFile)));// 构建文档Map<String, Object> jsonMap = new HashMap<>();jsonMap.put("url", "/resource/"+listFile.getName());jsonMap.put("vector", vector);jsonMap.put("user_id", "user123");IndexRequest request = new IndexRequest(INDEX).source(jsonMap, XContentType.JSON);bulkRequest.add(request);}client.bulk(bulkRequest, RequestOptions.DEFAULT);client.close();}// 接收待搜索图片的inputstream,搜索与其相似的图片public static List<SearchResult> search(InputStream input) throws Throwable {float[] vector = predictor.predict(ImageFactory.getInstance().fromInputStream(input));System.out.println(Arrays.toString(vector));// 展示k个结果int k = 100;// 连接Elasticsearch服务器RestHighLevelClient client = new RestHighLevelClient(RestClient.builder(new HttpHost("14.20.30.16", 9200, "http")));SearchRequest searchRequest = new SearchRequest(INDEX);Script script = new Script(ScriptType.INLINE, "painless", "cosineSimilarity(params.queryVector, doc['vector'])",Collections.singletonMap("queryVector", vector));FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(QueryBuilders.matchAllQuery(), ScoreFunctionBuilders.scriptFunction(script));SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();searchSourceBuilder.query(functionScoreQueryBuilder).fetchSource(null, "vector") // 不返回vector字段,太多了没用还耗时.size(k);searchRequest.source(searchSourceBuilder);SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);SearchHits hits = searchResponse.getHits();List<SearchResult> list = new ArrayList<>();for (SearchHit hit : hits) {// 处理搜索结果System.out.println(hit.toString());SearchResult result = new SearchResult((String) hit.getSourceAsMap().get("url"), hit.getScore());list.add(result);}client.close();return list;}public static void main(String[] args) throws Throwable {ORCUtil.upload();System.out.println("hao");}
}

SearchController.java

package com.topprismcloud.rtm;import java.util.List;import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;@RestController
@CrossOrigin
public class SearchController {@PostMapping("search")public ResponseEntity search(MultipartFile file) {try {List<SearchResult> list = ORCUtil.search(file.getInputStream());return ResponseEntity.ok(list);} catch (Throwable e) {return ResponseEntity.status(400).body(null);}}
}

SearchResult.java

package com.topprismcloud.rtm;import lombok.AllArgsConstructor;
import lombok.Data;@Data
@AllArgsConstructor
public class SearchResult {private String url;private Float score;
}

5、前端

index.html

<!DOCTYPE html>
<html lang="zh"><head><meta charset="UTF-8"><title>以图搜图</title><style>body {background: url("/img/bg.jpg");background-attachment: fixed;background-size: 100% 100%;}body>div {width: 1000px;margin: 50px auto;padding: 10px 20px;border: 1px solid lightgray;border-radius: 20px;box-sizing: border-box;background: rgba(255, 255, 255, 0.7);}.upload {display: inline-block;width: 300px;height: 280px;border: 1px dashed lightcoral;vertical-align: top;}.upload .cover {width: 200px;height: 200px;margin: 10px 50px;border: 1px solid black;box-sizing: border-box;text-align: center;line-height: 200px;position: relative;}.upload img {width: 198px;height: 198px;position: absolute;left: 0;top: 0;}.upload input {margin-left: 50px;}.upload button {width: 80px;height: 30px;margin-left: 110px;}.result-block {display: inline-block;margin-left: 40px;border: 1px solid lightgray;border-radius: 10px;min-height: 500px;width: 600px;}.result-block h1 {text-align: center;margin-top: 100px;}.result {padding: 10px;cursor: pointer;display: inline-block;}.result:hover {background: rgb(240, 240, 240);}.result p {width: 110px;overflow: hidden;white-space: nowrap;text-overflow: ellipsis;}.result img {width: 160px;height: 160px;}.result .prob {color: rgb(37, 147, 60)}</style><script src="js/jquery-3.6.0.js"></script>
</head><body><div><div class="upload"><div class="cover">请选择图片<img id="image" src="" /></div><input id="file" type="file"></div><div class="result-block"><h1>请选择图片</h1></div></div><ul id="box"></ul><script>var file = $('#file')file.change(function () {let f = this.files[0]let index = f.name.lastIndexOf('.')let fileText = f.name.substring(index, f.name.length)let ext = fileText.toLowerCase() //文件类型console.log(ext)if (ext != '.png' && ext != '.jpg' && ext != '.jpeg') {alert('系统仅支持 JPG、PNG、JPEG 格式的图片,请您调整格式后重新上传')return}$('.result-block').empty().append($('<h1>正在识别中...</h1>'))$("#image").attr("src", getObjectURL(f));let formData = new FormData()formData.append('file', f)$.ajax({url: 'http://10.1.2.240:8081/search',method: 'post',data: formData,processData: false,contentType: false,success: res => {console.log('shibie', res)$('.result-block').empty()for (let item of res) {console.log(item)let html = `<div class="result"><img src="${item.url}"/><div style="display: inline-block;vertical-align: top"><p class="prob">得分:${item.score.toFixed(4)}</p></div></div>`$('.result-block').append($(html))}}})});$('#button').click(function (e) {var file = $('#file')[0].files[0] //单个console.log(file)})function getObjectURL(file) {var url = null;if (window.createObjcectURL != undefined) {url = window.createOjcectURL(file);} else if (window.URL != undefined) {url = window.URL.createObjectURL(file);} else if (window.webkitURL != undefined) {url = window.webkitURL.createObjectURL(file);}return url;}function detect() {}</script>
</body></html>

6、打包后的源代码

以图搜图Java+html源代码

相关参考文章:Java调用Pytorch模型进行图像识别

相关文章:

Java调用Pytorch实现以图搜图(附源码)

Java调用Pytorch实现以图搜图 设计技术栈&#xff1a; 1、ElasticSearch环境&#xff1b; 2、Python运行环境&#xff08;如果事先没有pytorch模型时&#xff0c;可以用python脚本创建模型&#xff09;&#xff1b; 1、运行效果 2、创建模型&#xff08;有则可以跳过&#xf…...

【EasyX】实时时钟

目录 实时时钟1. 绘制静态秒针2. 秒针的转动3. 根据实际时间转动4. 添加时针和分针5. 添加表盘刻度 实时时钟 本博客介绍利用EasyX实现一个实时钟表的小程序&#xff0c;同时学习时间函数的使用。 本文源码可从github获取 1. 绘制静态秒针 第一步定义钟表的中心坐标center&a…...

基于XC7Z100的PCIe采集卡(GMSL FMC采集卡)

GMSL 图像采集卡 特性 ● PCIe Gen2.0 X8 总线&#xff1b; ● 支持V4L2调用&#xff1b; ● 1路CAN接口&#xff1b; ● 6路/12路 GMSL1/2摄像头输入&#xff0c;最高可达8MP&#xff1b; ● 2路可定义相机同步触发输入/输出&#xff1b; 优势 ● 采用PCIe主卡与FMC子…...

Kibana:使用 Kibana 自带数据进行可视化(一)

在今天的练习中&#xff0c;我们将使用 Kibana 自带的数据来进行一些可视化的展示。希望对刚开始使用 Kibana 的用户有所帮助。 前提条件 如果你还没有安装好自己的 Elastic Stack&#xff0c;你可以参考如下的视频来开启 Elastic Stack 并进行下面的练习。你可以开通阿里云检…...

MySQL数据库基础 07

第七章 单行函数 1. 函数的理解1.1 什么是函数1.2 不同DBMS函数的差异1.3 MySQL的内置函数及分类 2. 数值函数2.1 基本函数2.2 角度与弧度互换函数2.3 三角函数2.4 指数与对数2.5 进制间的转换 3. 字符串函数4. 日期和时间函数4.1 获取日期、时间 4.2 日期与时间戳的转换 4.3 获…...

JVM | JVM垃圾回收

JVM | JVM垃圾回收 1、堆空间的基本结构2、内存分配和回收原则2.1、对象优先在 Eden 区分配2.2、大对象直接进入老年代2.3、长期存活的对象将进入老年代2.4、主要进行 gc 的区域2.5、空间分配担保3、死亡对象判断方法3.1、引用计数法3.2、可达性分析算法3.3、引用类型总结3.4、…...

avive零头撸矿

Avive 是一个透明的、自下而上替代自上而下的多元网络&#xff0c;旨在克服当前生态系统的局限性&#xff0c;实现去中心化社会。 aVive&#xff1a;一个基于 SBT 和市场的 deSoc&#xff0c;它使 dapps 能够与分散的位置 oracle 和 SBT 关系进行互操作。您的主权社交网络元宇宙…...

openGauss5.0之学习环境 Docker安装

文章目录 0.前言1. 准备软硬件安装环境1.1 软硬件环境要求1.2 修改操作系统配置1.2.1 关闭操作系统防火墙 1.3 设置字符集参数1.4 设置时区和时间&#xff08;可选&#xff09;关闭swap交换内存1.5 关闭RemoveIPC1.6 关闭HISTORY记录 2. 容器安装2. 1支持的架构和操作系统版本2…...

数据可视化大屏人员停留系统的开发实录(默认加载条件筛选、单击加载、自动刷新加载、异步加载数据)

项目需求 录入进入房间的相关数据&#xff1b;从进入时间开始计时&#xff0c;计算滞留房间的时间&#xff1b;定时刷新数据&#xff0c;超过30分钟的人数&#xff0c;进行红色告警&#xff1b; 实现流程 为了完整地实现上述需求&#xff0c;我们可以按照以下步骤开发&#…...

【Linux】-关于调试器gdb的介绍和使用

作者&#xff1a;小树苗渴望变成参天大树 作者宣言&#xff1a;认真写好每一篇博客 作者gitee:gitee 如 果 你 喜 欢 作 者 的 文 章 &#xff0c;就 给 作 者 点 点 关 注 吧&#xff01; 文章目录 前言一、Linux中的debug和release二、gdb的使用**1.进入调试****2.显示代码*…...

项目开发经验

hadoop 1.namenode中有专门的工作线程池用于处理与datanode的心跳信号 dfs.namenode.handler.count20 * log2(Clust 2.编辑日志存储路径 dfs.namenode.edits.dir 设置与镜像文件存储路径 dfs.namenode分开存放&#xff0c;可以达到提高并发 3.yarn参数调优&#xff0c;单个服…...

STM32——05-按键、时钟控制、中断复位 点亮LED灯

如何点亮一颗LED灯 编程实现点灯 常用的 GPIO HAL 库函数&#xff1a; void HAL_GPIO_Init ( GPIO_TypeDef * GPIOx , GPIO_InitTypeDef * GPIO_Init ); void HAL_GPIO_WritePin ( GPIO_TypeDef * GPIOx , uint16_t GPIO_Pin , GPIO_PinState PinState ); void HAL_GPIO_Togg…...

VBA下载二进制文件,文本读写

这里使用了vba如下两个对象&#xff1a; Microsoft.XMLHTTP&#xff1a;文件读写&#xff0c;可读写二进制&#xff0c;可指定编码,对于utf-8编码文本文件使用FSO的TextStream对象打开&#xff0c;读取到的内容可能会出现乱码&#xff0c;可以使用该对象打开;前期绑定添加引用…...

MongoDB结合Robo 3T 1.4.3的简单操作

MongoDB的简单操作结合Robo 3T 1.4.3工具进行查询。 常用的正则表达式 /* 29 */ 正则表达式 /\* [0-9]* \*/ "_id" : ObjectId("5f3d05cdfd2aa9a8a7"), 正则表达式 \"([^\"]*_id)\".*, 使用方法&#xff1a;查询结果去掉注释和不需要…...

【学习笔记】[AGC048D] Pocky Game

这是一个非平等博弈。但是只要求你判断胜负&#xff0c;本身也不是一道结论题&#xff0c;所以可以用 D P DP DP来解决。 结论&#xff1a;第一堆石子剩的越多&#xff0c;先手玩家获胜的概率越大。这直接引出了一个非常感性的结论&#xff1a;每次取石子时要么取一堆&#xf…...

Qgis中进行Shp和Excel属性连接实现百强县公共预算空间分析

前言 在之前的博文中&#xff0c;将2022的全国百强县一般公共预算收入的数据下载到了本地&#xff0c;博客原文地址&#xff1a;一种使用Java的快速将Web中表格转换成Excel的方法。对于不关注时空位置关系的一般分析&#xff0c;到此也就基本够用了。但是&#xff0c;如果站在全…...

ES6 新增的循环方法

在 ES6&#xff08;ECMAScript 2015&#xff09;中&#xff0c;新增了一些循环方法&#xff0c;这些方法可以帮助我们更方便地遍历数组、字符串、Set、Map 等数据结构。本文将介绍一些常用的 ES6 循环方法。 for…of 循环 for…of 循环是一种遍历可迭代对象的方法&#xff0c…...

移动端事件300ms延迟解决

有移动端与PC端的项目开发&#xff0c;那么移动端和PC端开发上是存在差异的&#xff0c;比如 click 事件的300ms 延迟&#xff0c;即移动Web页面上的click事件响应都要慢上300ms&#xff0c;移动设备访问Web页面时往往需要 “双击” 或者 “捏开” 来放大页面看清页面的具体内容…...

NRF52832的DFU

开发环境&#xff1a; Winsodw&#xff1a;10 nRF5_SDK&#xff1a;17.1.0 1 工具安装 1.1 gcc-arm-none-eabi Downloads | GNU Arm Embedded Toolchain Downloads – Arm Developer 下载“gcc-arm-none-eabi-10.3-2021.10-win32.exe”&#xff0c;接提示安装。注意安装完…...

开源WebRTC库放大器模式在采集桌面图像时遇到的DPI缩放与内存泄漏问题排查

目录 1、在非100%的显示比例下放大器采集到的桌面图像不全问题 1.1、通过manifest文件禁止系统对软件进行缩放 1.2、调用SetThreadDpiAwarenessContext函数&#xff0c;禁止系统对目标线程中的窗口进行缩放 1.3、使用winver命令查看Windows的年月版本 2、使用放大器模式遇…...

嵌入式系统调试技术:从JTAG到多核同步的实战指南

1. 嵌入式系统调试技术概述在嵌入式系统开发过程中&#xff0c;调试环节往往占据整个开发周期的40%-60%时间。与通用计算机系统不同&#xff0c;嵌入式系统通常运行在资源受限的环境中&#xff0c;缺乏标准输入输出设备&#xff0c;这使得调试工作更具挑战性。我曾参与过多个工…...

AI技能文件管理工具agent-skills-lint:多助手环境下的统一质检方案

1. 项目概述&#xff1a;为什么我们需要一个AI技能文件“质检员”如果你和我一样&#xff0c;同时在使用Claude Code、Cursor、Aider这些AI编程助手&#xff0c;那你一定遇到过这个烦人的问题&#xff1a;每个助手都有自己的“技能”&#xff08;Skills&#xff09;系统&#x…...

保姆级教程:彻底解决CondaHTTPError网络连接失败(附.condarc文件完整配置流程)

深度解析CondaHTTPError&#xff1a;从网络诊断到.condarc文件全配置指南 遇到CondaHTTPError: HTTP 000 CONNECTION FAILED错误时&#xff0c;很多开发者会感到束手无策。这个问题通常出现在国内网络环境下&#xff0c;尤其是公司内网、校园网或使用某些代理服务后。本文将带你…...

MATLAB 2018a/2023b实测:Libsvm安装后如何用自带数据集快速验证与跑通第一个模型

MATLAB 2018a/2023b实战&#xff1a;Libsvm安装后快速验证与模型跑通全流程 当你第一次在MATLAB中成功安装Libsvm后&#xff0c;那种兴奋感可能很快会被"接下来该做什么"的迷茫所取代。别担心&#xff0c;这篇文章将带你用Libsvm自带的heart_scale数据集&#xff0c;…...

大核小核架构的演进:从DVFS到异构计算,应对先进制程挑战

1. 项目概述&#xff1a;大核小核架构的十字路口在移动计算和嵌入式领域&#xff0c;ARM的“大核小核”&#xff08;big.LITTLE&#xff09;架构在过去十年里几乎成了高性能低功耗的代名词。从智能手机到平板电脑&#xff0c;再到如今的物联网边缘设备&#xff0c;这套将高性能…...

规则驱动流程引擎:告别if-else,构建灵活业务自动化核心

1. 项目概述&#xff1a;一个规则驱动的流程引擎最近在梳理一些业务自动化需求时&#xff0c;我又把目光投向了规则引擎和流程编排这个老话题。无论是电商的风控审核、金融的信贷审批&#xff0c;还是内容平台的自动化运营&#xff0c;我们总在重复一个模式&#xff1a;定义一堆…...

从HIP4082到IR2184:直流电机H桥驱动芯片怎么选?一份给硬件工程师的对比清单(含成本、功耗、设计复杂度)

从HIP4082到IR2184&#xff1a;直流电机H桥驱动芯片的工程选型指南 在小型机器人、电动工具或自动化设备的开发中&#xff0c;电机驱动电路的设计往往是硬件工程师面临的核心挑战之一。面对市场上琳琅满目的驱动芯片&#xff0c;如何在性能、成本和可靠性之间找到最佳平衡点&am…...

保姆级教程:用易语言和大漠插件给游戏做字库,实现自动化文字识别(附模块源码)

零基础实战&#xff1a;易语言与大漠插件游戏字库制作全指南 游戏自动化开发中&#xff0c;文字识别是绕不开的核心技术。想象一下&#xff0c;当你的程序能自动读取任务提示、NPC对话或物品名称时&#xff0c;整个自动化流程就拥有了"眼睛"。本文将彻底拆解大漠插件…...

SAP-ABAP:ABAP Development Tools(ADT)安装配置学习分享教程(四篇连载)第四篇:ADT连接故障排查与环境迁移教程

ABAP Development Tools&#xff08;ADT&#xff09;安装配置学习分享教程&#xff08;四篇连载&#xff09; 第四篇&#xff1a;ADT连接故障排查与环境迁移教程 ADT连不上SAP后端&#xff1f;刚刚还好好的系统突然报错了&#xff1f;换了新电脑要重建整个开发环境&#xff1f…...

5分钟掌握ExplorerPatcher:Windows界面定制终极指南

5分钟掌握ExplorerPatcher&#xff1a;Windows界面定制终极指南 【免费下载链接】ExplorerPatcher This project aims to enhance the working environment on Windows 项目地址: https://gitcode.com/GitHub_Trending/ex/ExplorerPatcher 还在为Windows 11的新界面感到…...