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

自定义基座实时采集uniapp日志

自定义基座实时采集uniapp日志

打测试包给远端现场(测试/客户)实际测试时也能实时看到日志了,也有代码行数显示。
收集的日志

流程设计

重写console.log方法
Websocket
Websocket
uniapp收集日志
通过插件或Native.js传输
安卓基座接收
后台服务接收保存
前端html页面渲染

uniapp收集代码

重写console方法

通过条件编译,在app使用环境重写日志打印方法

 // #ifdef APP-PLUS=function(...args){console.log = function (...args) {try {_this.$plugins.getUtils("consoleLog", {'level': 'log', 'args': args})} catch (e) {console.info('console.log 打印失败', e);}}console.error = function (...args) {try {_this.$plugins.getUtils("consoleLog", {'level': 'error', 'args': args})} catch (e) {console.info('console.error 打印失败', e);}}console.warn = function (...args) {try {_this.$plugins.getUtils("consoleLog", {'level': 'warn', 'args': args})} catch (e) {console.info('console.warn 打印失败', e);}}// #endif

发送给安卓层

/*** 快捷调用安卓工具类方法* this.$plugins.getUtils('method',{userId:'test'})* @param {Object} method* @param {Object} jsonObject* @param {Object} successCallback* @param {Object} errorCallback* @return {String} 原始字符串,如果是json化返回的就是一个json字符串 不是对象!!!*/
getUtils: function(method, jsonObject, successCallback, errorCallback) {try {var success = typeof successCallback !== 'function' ? null : function(args) {successCallback(args);},fail = typeof errorCallback !== 'function' ? null : function(code) {errorCallback(code);};var callbackID = plus.bridge.callbackId(success, fail);return plus.bridge.exec(_BARCODE, "getUtils", [callbackID, method, jsonObject]);} catch (e) {console.error(e)errorCallback(e)}},//初始化方法,一般是登录后调用
_this.$plugins.getUtils("initConsoleLog", {'userId': _this.GLOBAL.$USER_INFO.user_iidd})

安卓自定义基座收集日志

跳转方法

/*** 工具类获取** @param pWebview* @param array* @return*/public void getUtils(IWebview pWebview, JSONArray array) {Log.i("getUtils", "工具类获取" + array.toString());String result = null;String CallBackID = array.optString(0);try {//方法String method = array.optString(1);JSONObject json = new JSONObject(array.optString(2));result = this.utilMethood(method, json, pWebview);} catch (Exception e) {e.printStackTrace();JSUtil.execCallback(pWebview, CallBackID, e.getMessage(), JSUtil.ERROR, false);}Log.i("getUtils", "工具类返回信息:\n" + result);JSUtil.execCallback(pWebview, CallBackID, result, JSUtil.OK, true);}

初始化日志信息方法

/*** WebSocket调试信息推送客户端*/
private PushConsoleWebSocketClient pushConsoleWebSocketClient = null;/*** 初始化推送*/
public static boolean pushLogInit = false;/*** 调试日志地址*/
public static String LOG_WS_URL = "ws://127.0.0.1:5080/weblog/uniapplogv2/";/*** 调试id*/
public static String LOG_WS_USERID = null;/*** 初始化日志信息** @param params* @param pWebview* @return*/
private String initConsoleLog(JSONObject params, IWebview pWebview) {LOG_WS_USERID = params.optString("userId");Log.i(TAG, "uniapp层初始化日志信息: " + LOG_WS_USERID);if (null != LOG_WS_USERID && !"".equals(LOG_WS_USERID)) {try {new Thread(new Runnable() {@Overridepublic void run() {try {pushConsoleWebSocketClient = PushConsoleWebSocketClient.builder(LOG_WS_URL, "系统名称", LOG_WS_USERID);pushConsoleWebSocketClient.connect();pushLogInit = true;} catch (Exception e) {e.printStackTrace();}}}).start();} catch (Exception e) {Log.e(TAG, "initConsoleLog: 初始化调试信息推送服务异常", e);}}return ResultUtil.ok("日志初始化完毕");
}

推送日志调试信息方法

/*** 推送日志信息到调试页面** @param log   日志内容* @param level 日志等级*/
private void pushLogToCache(String level, JSONArray log) {Thread thread = new Thread(new Runnable() {@Overridepublic void run() {try {com.alibaba.fastjson.JSONObject params = new com.alibaba.fastjson.JSONObject();params.put("code", "push");params.put("sys", pushConsoleWebSocketClient.getSys());params.put("userId", pushConsoleWebSocketClient.getUserId());params.put("level", level);params.put("timestamp", System.currentTimeMillis());params.put("time", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()));try {params.put("log", parseUniappConsoleLog(log));} catch (Exception e) {params.put("log", log);}pushConsoleWebSocketClient.send(params.toString());} catch (Exception e) {e.printStackTrace();}}});thread.start();
//        executorService.submit(thread);
}

安装自定义基座

安卓WebSocket客户端

安卓WebSocket客户端推送负责将调试日志推送给后端

gradle依赖

//WebSocket连接
implementation 'org.java-websocket:Java-WebSocket:1.5.3'

import android.util.Log;import com.inspur.mobilefsp.plugins.WfmPlugin;import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.json.JSONObject;import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.Charset;/*** WebSocket客户端类,用于与服务器建立WebSocket连接并处理消息。* 该类实现了WebSocketClient接口,并提供了连接、消息处理和错误处理的功能。** @author 淡梦如烟* @date 20250211*/
public class PushConsoleWebSocketClient extends WebSocketClient {/*** 日志标签,用于标识日志输出的来源*/public final static String TAG = "PushLogClient";/*** WebSocket服务器的URL*/private String url;/*** 系统名称*/private String sys;/*** 用户ID*/private String userId;/*** 构造函数,初始化WebSocket客户端** @param serverUrl WebSocket服务器的URL* @param sys       系统名称* @param userId    用户ID* @throws URISyntaxException 如果提供的URL格式不正确*/public PushConsoleWebSocketClient(String serverUrl, String urlParams, String sys, String userId) throws URISyntaxException {super(new URI(serverUrl + urlParams));this.url = serverUrl;this.sys = sys;this.userId = userId;}/*** 建造者生成客户端** @param serverUrl* @param sys* @param userId* @return*/public static PushConsoleWebSocketClient builder(String serverUrl, String sys, String userId) {try {//自定义参数,自行实现JSONObject json = new JSONObject();json.put("code", "pushStart");json.put("userId", userId);json.put("sys", sys);JSONObject password = new JSONObject();password.put("userId", userId);password.put("timestamp", System.currentTimeMillis());//aes加密 ,自行实现或者用第三方包String encode = QEncodeUtil.aesEncrypt(json.toString(), "aes秘钥2");encode = URLEncoder.encode(encode, "UTF-8");//百分号不能作为参数encode = encode.replaceAll("%", "BaiFenHao");String url = serverUrl + encode;Log.e(TAG, "builder: websocket地址:" + url);PushConsoleWebSocketClient pushConsoleWebSocketClient = new PushConsoleWebSocketClient(serverUrl, encode, sys, userId);return pushConsoleWebSocketClient;} catch (Exception e) {throw new RuntimeException(e);}}/*** 获取WebSocket服务器的URL** @return WebSocket服务器的URL*/public String getUrl() {return url;}/*** 获取系统名称** @return 系统名称*/public String getSys() {return sys;}/*** 获取用户ID** @return 用户ID*/public String getUserId() {return userId;}/*** 当WebSocket连接成功建立时调用** @param handshake 握手信息*/@Overridepublic void onOpen(ServerHandshake handshake) {// WebSocket连接已成功建立// 在此执行任何必要的操作Log.i(TAG, "onOpen: " + handshake.getHttpStatus());WfmPlugin.pushLogInit = true;}/*** 当接收到来自服务器的消息时调用** @param message 收到的消息内容*/@Overridepublic void onMessage(String message) {// 处理来自服务器的传入消息Log.i(TAG, "onMessage: " + message);}/*** 当WebSocket连接关闭时调用** @param code   关闭状态码* @param reason 关闭原因* @param remote 是否由远程服务器关闭*/@Overridepublic void onClose(int code, String reason, boolean remote) {Log.e(TAG, "onClose: code[" + code + "];remote[" + remote + "];url[" + this.url + "];reason:" + reason);// WebSocket连接已关闭// 在此执行任何必要的清理操作
//        this.reconnectAfterMillis(100L);}/*** 重连锁*/private static boolean reConnectLock = false;/*** 延迟重连** @param millis*/public void reconnectAfterMillis(Long millis) {try {if (reConnectLock) {return;}reConnectLock = true;new Thread(new Runnable() {@Overridepublic void run() {try {// 尝试在5秒后重新连接Thread.sleep(millis);reconnect();} catch (Exception e) {e.printStackTrace();} finally {reConnectLock = false;}}}).start();} catch (Exception e) {e.printStackTrace();reConnectLock = false;} finally {}}/*** 当WebSocket连接期间发生错误时调用** @param ex 发生的异常*/@Overridepublic void onError(Exception ex) {Log.e(TAG, "onError: ", ex);// 处理WebSocket连接期间发生的任何错误
//        this.reconnectAfterMillis(5000L);}
}

后台代码

springboot接受日志和推送日志

package com.faker.weblog.websocket;import cn.hutool.core.net.URLDecoder;
import com.alibaba.fastjson2.JSONObject;
import com.faker.weblog.model.dto.PushUniappLogDto;
import com.faker.weblog.util.Toolkit;
import com.faker.weblog.wrapper.WrapMapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;@Lazy
@Component
@Slf4j
@ServerEndpoint("/uniapplogv2/{id}")
@Api(value = "websocket日志接受和推送uniapp日志工具")
public class UniappLogWebHandleV2 {@ApiModelProperty(value = "客户端id")private String id;@ApiModelProperty(value = "是否初始化", example = "true")private boolean initialized = false;@ApiModelProperty(value = "是否接受日志消息", example = "true")private boolean isPullLogs = false;@ApiModelProperty(value = "系统名称", example = "fakerSys")private String sys;@ApiModelProperty(value = "用户id", example = "test")private String userId;/*** 日志列表*/private static ConcurrentHashMap<String, ConcurrentHashMap<String, List<String>>> logListMap = new ConcurrentHashMap<>();/*** 获取日志列表** @return*/public ConcurrentHashMap<String, ConcurrentHashMap<String, List<String>>> getlogListMap() {return logListMap;}/*** 清理日志列表*/public static void cleanLogListMap() {logListMap.clear();}/*** concurrent包的线程安全Map,用来存放每个客户端对应的MyWebSocket对象。*/private static ConcurrentHashMap<String, UniappLogWebHandleV2> webSocketMap = new ConcurrentHashMap<String, UniappLogWebHandleV2>();/*** websocket的session*/private Session session;/*** 获取session** @return*/public Session getSession() {return this.session;}/*** 新的WebSocket请求开启*/@OnOpenpublic void onOpen(Session session, @PathParam("id") String id) {log.info("新的WebSocket请求开启:" + id);try {String decode = id.replaceAll("BaiFenHao", "%");decode = URLDecoder.decode(decode, Charset.forName("UTF-8"));String aesJson = com.faker.dba.util.QEncodeUtil.aesDecrypt(decode, "aes秘钥2");JSONObject jsonObject = JSONObject.parseObject(aesJson);String userId = jsonObject.getString("userId");String password = jsonObject.getString("password");String sign = jsonObject.getString("sign");if (jsonObject.get("isPullLogs") != null) {this.isPullLogs = jsonObject.getBoolean("isPullLogs");}this.sys = jsonObject.getString("sys");this.userId = userId;this.session = session;//鉴权方法,自行实现this.validate(userId, sign, password);this.id = id;webSocketMap.put(id, this);String code = jsonObject.getString("code");if ("pushStart".equalsIgnoreCase(code)) {//app推送方法if (thisLististMap == null) {thisLististMap = new ConcurrentHashMap<>();logListMap.put(this.sys, thisLististMap);}List<String> logList = thisLististMap.get(this.userId);if (logList == null) {logList = new ArrayList<>();thisLististMap.put(this.userId, logList);}} else if ("webStart".equalsIgnoreCase(code)) {//pc端查看日志方法this.isPullLogs = true;this.sys = jsonObject.getString("watchSys");this.userId = jsonObject.getString("watchUserId");ConcurrentHashMap<String, List<String>> thisLististMap = logListMap.get(this.sys);if (thisLististMap != null) {List<String> logList = thisLististMap.get(this.userId);if (logList != null) {for (String log : logList) {try {session.getBasicRemote().sendText(log);} catch (IOException e) {e.printStackTrace();}}}}}} catch (Exception e) {log.error("鉴权错误:" + id, e);}}/*** WebSocket 请求关闭*/@OnClosepublic void onClose() {// 从set中删除log.info("WebSocket请求关闭:" + id);webSocketMap.remove(id);}/*** 发生异常*/@OnErrorpublic void onErro(Throwable throwable) {throwable.printStackTrace();}/*** 收到客户端消息后调用的方法** @param message 客户端发送过来的消息*/@OnMessagepublic void onMessage(String message, Session session) throws IOException {log.debug("websocket来自客户端的消息:{}", message);JSONObject jsonObject = JSONObject.parseObject(message);String code = jsonObject.getString("code");if (this.initialized) {if ("push".equalsIgnoreCase(code)) {PushUniappLogDto params = JSONObject.parseObject(message, PushUniappLogDto.class);if (Toolkit.isNullOrEmpty(params.getSys())) {log.warn("系统名称不能为空");return;}if (Toolkit.isNullOrEmpty(params.getUserId())) {log.warn("用户id不能为空");return;}if (Toolkit.isNullOrEmpty(params.getLevel())) {log.warn("日志等级不能为空");return;}if (Toolkit.isNullOrEmpty(params.getLog()) || "[]".equals(params.getLog())) {log.warn("日志信息不能为空");return;}this.sendLogs(JSONObject.toJSONString(params));}} else {log.warn("[" + this.sys + "][" + this.userId + "]未初始化" + this.initialized);}}/*** token鉴权** @param userId* @param sign* @param password* @throws IOException*/public void validate(String userId, String sign, String password) throws IOException {if (Toolkit.isNotNull(userId) && Toolkit.isNotNull(sign)) {//校验userId和密码 这里简化为校验userId和时间戳的aes加密信息,校验通过初始化连接try {String aesJson = com.faker.dba.util.QEncodeUtil.aesDecrypt(sign, "aes秘钥1");JSONObject aesJsonObject = JSONObject.parseObject(aesJson);if (aesJsonObject.get("userId") == null || aesJsonObject.get("timestamp") == null) {session.getBasicRemote().sendText("加密信息校验错误,已记录!" + "<br>" + aesJson + "<br>");session.close();}if (userId.equals(aesJsonObject.getString("userId"))) {if (aesJsonObject.getLong("timestamp") > System.currentTimeMillis() - 1000 * 60 * 5|| aesJsonObject.getLong("timestamp") < System.currentTimeMillis() + 1000 * 60 * 5) {this.initialized = true;session.getBasicRemote().sendText(JSONObject.toJSONString(WrapMapper.ok("签名[" + sign + "]正确,已记录!")));} else {session.getBasicRemote().sendText(JSONObject.toJSONString(WrapMapper.error("签名[" + sign + "]已过期,已记录!")));session.close();}} else {session.getBasicRemote().sendText(JSONObject.toJSONString(WrapMapper.error("签名[" + sign + "]错误,已记录!")));session.close();}} catch (Exception e) {log.error("加密信息[" + password + "]校验错误", e);session.getBasicRemote().sendText(JSONObject.toJSONString(WrapMapper.error("加密信息校验错误,已记录!" + "<br>" + e.getMessage())));session.close();}} else if (Toolkit.isNotNull(userId) && Toolkit.isNotNull(password)) {//todo 校验登录密码} else {log.error("登录信息错误[" + userId + "][" + password + "][" + sign + "]");session.getBasicRemote().sendText(JSONObject.toJSONString(WrapMapper.error("登录信息错误,已记录!")));session.close();}}/*** 向客户端发送消息** @param message*/public void sendLogs(String message) {ConcurrentHashMap<String, List<String>> thisLististMap = logListMap.get(this.sys);if (thisLististMap == null) {thisLististMap = new ConcurrentHashMap<>();}List<String> logList = thisLististMap.get(this.userId);if (logList == null) {logList = new ArrayList<>();}logList.add(message);//日志暂存最新的100条if (logList.size() > 100) {logList.remove(0);}this.sendToUser(message);}/*** 向指定客户端发送消息** @param message*/private void sendToUser(String message) {for (UniappLogWebHandleV2 webSocket : webSocketMap.values()) {if (webSocket.isInitialized() && webSocket.isPullLogs() && webSocket.getSys().equals(this.sys) && webSocket.getUserId().equals(this.userId)) {log.debug("【websocket消息】广播消息, message={}", message);try {Session session = webSocket.getSession();session.getBasicRemote().sendText(message);} catch (Exception e) {log.error("【websocket消息】广播消息, message={}", message);}}}}/*** 向所有客户端发送消息** @param message*/public void sendToAll(String message) {for (UniappLogWebHandleV2 webSocket : webSocketMap.values()) {if (!webSocket.isInitialized()) {continue;}log.debug("【websocket消息】广播消息, message={}", message);try {Session session = webSocket.getSession();session.getBasicRemote().sendText(message);} catch (Exception e) {log.error("【websocket消息】广播消息, message={}", message);}}}public String getId() {return id;}public String getSys() {return sys;}public String getUserId() {return userId;}public boolean isInitialized() {return initialized;}public boolean isPullLogs() {return isPullLogs;}
}

html页面渲染日志

const id = JSON.stringify({code: 'webStart',userId: userToken.userId,sign: userToken.token,isPullLogs: true,watchSys: $('#sys').val(),watchUserId: $('#userId').val()
})
//aes加密
const aes = aesEncrypt(id)
//替换百分号
const url = encodeURIComponent(aes).replaceAll('%', 'BaiFenHao')
console.log('[信息]传输协议秘钥', id, aes, url)
// 指定websocket路径
var wsUrl = 'ws://' + location.host + '/weblog/uniapplogv2/' + url;try {if (null != websocket && undefined != websocket) {websocket.close();}
} catch (e) {console.warn(e)
}
websocket = new WebSocket(wsUrl);
websocket.onmessage = function (event) {// 接收服务端的实时日志并添加到HTML页面中$("#log-container div").append(showColorLog(event.data));$("#log-container div").append('<br/>')if (localStorage.autoJump == '是') {// 滚动条滚动到最低部$("#log-container").scrollTop($("#log-container div").height() - $("#log-container").height());}
};
websocket.onopen = function (event) {reloadLock = false;
}websocket.onerror = function (error) {console.log('onerror', error)// $("#log-container div").append('<br/><br/>连接已断开...    5秒后尝试重新连接........ <br/><br/>');// setTimeout(reloadWebSocket(), 5000)
}
websocket.onclose = function (event) {console.log('onclose', event)$("#log-container div").append('<br/><br/>连接已关闭...    5秒后尝试重新连接........ <br/><br/>');setTimeout(reloadWebSocket, 5000)
}

总结

给远程调试提供方便,websocket推送消耗较少,也是有序推送,完善好重连机制比post提交更方便查看。

相关文章:

自定义基座实时采集uniapp日志

自定义基座实时采集uniapp日志 打测试包给远端现场(测试/客户)实际测试时也能实时看到日志了&#xff0c;也有代码行数显示。 流程设计 #mermaid-svg-1I5W9r1DU4xUsaTF {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid…...

【java】方法:遍历/求最大值/判断是否存在

1.遍历 public class ArrayTraversal {// 定义一个静态方法用于遍历数组并在一行上显示元素public static void printArray(int[] arr) {for (int num:arr) {// 打印数组元素&#xff0c;不换行System.out.print(num" ");}// 遍历结束后换行System.out.println();}p…...

【ISO 14229-1:2023 UDS诊断全量测试用例清单系列:第六节】

ISO 14229-1:2023 UDS诊断服务测试用例全解析&#xff08;ReadDataByIdentifier0x22服务&#xff09; 作者&#xff1a;车端域控测试工程师 发布日期&#xff1a;2025年2月13日 关键词&#xff1a;UDS诊断协议、0x22服务、ReadDataByIdentifier、DID读取、ECU测试 一、服务功能…...

dedecms 开放重定向漏洞(附脚本)(CVE-2024-57241)

免责申明: 本文所描述的漏洞及其复现步骤仅供网络安全研究与教育目的使用。任何人不得将本文提供的信息用于非法目的或未经授权的系统测试。作者不对任何由于使用本文信息而导致的直接或间接损害承担责任。如涉及侵权,请及时与我们联系,我们将尽快处理并删除相关内容。 0x0…...

AI知识库 - Cherry Studio

1 引言&#xff1a; 最近 DeepSeek 很火啊&#xff0c;想必大家都知道&#xff0c;DeepSeek 这个开源的模型出来后&#xff0c;因其高质量能力和R1 的思维链引发了大家本地部署的热潮。我也不例外&#xff0c;本地部署了一个 14B 的模型&#xff0c;然后把&#xff0c;感觉傻傻…...

20250213 隨筆 雪花算法

雪花算法&#xff08;Snowflake Algorithm&#xff09; 雪花算法&#xff08;Snowflake&#xff09; 是 Twitter 在 2010 年開發的一種 分布式唯一 ID 生成算法&#xff0c;它可以在 高併發場景下快速生成全局唯一的 64-bit 長整型 ID&#xff0c;且不依賴資料庫&#xff0c;具…...

(前端基础)HTML(一)

前提 W3C:World Wide Web Consortium&#xff08;万维网联盟&#xff09; Web技术领域最权威和具有影响力的国际中立性技术标准机构 其中标准包括&#xff1a;机构化标准语言&#xff08;HTML、XML&#xff09; 表现标准语言&#xff08;CSS&#xff09; 行为标准&#xf…...

pdf.js默认显示侧边栏和默认手形工具

文章目录 默认显示侧边栏(切换侧栏)默认手形工具(手型工具) 大部分的都是在viewer.mjs中的const defaultOptions 变量设置默认值,可以使用数字也可以使用他们对应的变量枚举值 默认显示侧边栏(切换侧栏) 在viewer.mjs中找到defaultOptions,大概在732行,或则搜索sidebarViewOn…...

学习总结三十三

括号序列 如果它是一个右括号&#xff0c;考察它与它左侧离它最近的未匹配的的左括号。如果该括号与之对应&#xff08;即小括号匹配小括号&#xff0c;中括号匹配中括号&#xff09;&#xff0c;则将二者配对。简单理解&#xff0c;找到一个右括号&#xff0c;向左找一个左括号…...

微信小程序 - 组件

组件通信事件 父传子 父组件如果需要向子组件传递指定属性的数据&#xff0c;在 WXML 中需要使用数据绑定的方式 与普通的 WXML 模板类似&#xff0c;使用数据绑定&#xff0c;这样就可以向子组件的属性传递动态数据。 父组件如果需要向子组件传递数据&#xff0c;只需要两…...

如何在Ubuntu中切换多个PHP版本

在Ubuntu环境下实现PHP版本的灵活切换&#xff0c;是众多开发者与系统管理员的重要技能之一。下面&#xff0c;我们将深入探讨如何在Ubuntu系统中安装、配置及管理多个PHP版本&#xff0c;确保您的开发环境随心所欲地适应各类项目需求。 开始前的准备 确保您的Ubuntu系统保持…...

解决DeepSeek服务器繁忙问题

目录 解决DeepSeek服务器繁忙问题 一、用户端即时优化方案 二、高级技术方案 三、替代方案与平替工具&#xff08;最推荐简单好用&#xff09; 四、系统层建议与官方动态 用加速器本地部署DeepSeek 使用加速器本地部署DeepSeek的完整指南 一、核心原理与工具选择 二、…...

Huatuo热更新--安装HybridCLR

1.自行安装unity编辑器 支持2019.4.x、2020.3.x、2021.3.x、2022.3.x 中任一版本。推荐安装2019.4.40、2020.3.26、2021.3.x、2022.3.x版本。 根据你打包的目标平台&#xff0c;安装过程中选择必要模块。如果打包Android或iOS&#xff0c;直接选择相应模块即可。如果你想打包…...

flink cdc2.2.1同步postgresql表

目录 简要说明前置条件maven依赖样例代码 简要说明 在flink1.14.4 和 flink cdc2.2.1下&#xff0c;采用flink sql方式&#xff0c;postgresql同步表数据&#xff0c;本文采用的是上传jar包&#xff0c;利用flink REST api的方式进行sql执行。 前置条件 1.开启logical 确保你…...

Golang协程调度模型MPG

深入解析Golang协程调度模型MPG&#xff1a;原理、实践与性能优化 一、为什么需要MPG模型&#xff1f; 在传统操作系统调度中&#xff0c;线程作为CPU调度的基本单位存在两个根本性挑战&#xff1a;1&#xff09;内核线程上下文切换成本高昂&#xff08;约1-5μs&#xff09;…...

纪念日倒数日项目的实现-【纪念时刻-时光集】

纪念日/倒数日项目的实现## 一个练手的小项目&#xff0c;uniappnodemysql七牛云。 在如今快节奏的生活里&#xff0c;大家都忙忙碌碌&#xff0c;那些具有特殊意义的日子一不小心就容易被遗忘。今天&#xff0c;想给各位分享一个“纪念日”项目。 【纪念时刻-时光集】 一…...

WPF的MVVMLight框架

在NuGet中引入该库&#xff1a; MVVMLight框架中的命令模式的使用&#xff1a; <StackPanel><TextBox Text"{Binding Name}"/><TextBox Text"{Binding Title}"/><Button Content"点我" Command"{Binding ShowCommand…...

DeepSeek从入门到精通(清华大学)

​ DeepSeek是一款融合自然语言处理与深度学习技术的全能型AI助手&#xff0c;具备知识问答、数据分析、编程辅助、创意生成等多项核心能力。作为多模态智能系统&#xff0c;它不仅支持文本交互&#xff0c;还可处理文件、图像、代码等多种格式输入&#xff0c;其知识库更新至2…...

【DeepSeek】DeepSeek R1 本地windows部署(Ollama+Docker+OpenWebUI)

1、背景&#xff1a; 2025年1月&#xff0c;DeepSeek 正式发布 DeepSeek-R1 推理大模型。DeepSeek-R1 因其成本价格低廉&#xff0c;性能卓越&#xff0c;在 AI 行业引起了广泛关注。DeepSeek 提供了多种使用方式&#xff0c;满足不同用户的需求和场景。本地部署在数据安全、性…...

windows平台上 oracle简单操作手册

一 环境描述 Oracle 11g单机环境 二 基本操作 2.1 数据库的启动与停止 启动: C:\Users\Administrator>sqlplus / as sysdba SQL*Plus: Release 11.2.0.4.0 Production on 星期五 7月 31 12:19:51 2020 Copyright (c) 1982, 2013, Oracle. All rights reserved. 连接到:…...

【弹性计算】弹性计算的技术架构

弹性计算的技术架构 1.工作原理2.总体架构3.控制面4.数据面5.物理设施层 虽然弹性计算的产品种类越来越多&#xff0c;但不同产品的技术架构大同小异。下面以当前最主流的产品形态 —— 云服务器为例&#xff0c;探查其背后的技术秘密。 1.工作原理 云服务器通常以虚拟机的方…...

RAG(检索增强生成)落地:基于阿里云opensearch视线智能问答机器人与企业知识库

文章目录 一、环境准备二、阿里云opensearch准备1、产品文档2、准备我们的数据3、上传文件 三、对接1、对接文本问答 一、环境准备 # 准备python环境 conda create -n opensearch conda activate opensearch# 安装必要的包 pip install alibabacloud_tea_util pip install ali…...

【踩坑】pytorch模型导出部署onnx问题记录

问题1&#xff1a;repeat_interleave 无法转译 具体报错为&#xff1a; TypeError: torch._C.Value object is not iterable (Occurred when translating repeat_interleave).原因是我的模型代码中有&#xff1a; batch_indices torch.repeat_interleave(torch.arange(can…...

利用prompt技术结合大模型对目标B/S架构软件系统进行测试

利用prompt技术结合大模型对目标B/S架构软件系统进行测试,可参考以下步骤和方法: 测试需求理解与prompt设计 明确测试点:梳理B/S架构软件系统的功能需求、非功能需求(如性能、安全性、兼容性等),确定具体的测试点,如用户登录功能、数据查询功能、系统响应时间要求等。设…...

DeepSeek vs ChatGPT:AI对决中的赢家是……人类吗?

DeepSeek vs ChatGPT&#xff1a;AI对决中的赢家是……人类吗&#xff1f; 文章目录 DeepSeek vs ChatGPT&#xff1a;AI对决中的赢家是……人类吗&#xff1f;一、引言1. 背景2. 问题 二、DeepSeek vs ChatGPT&#xff1a;谁更胜一筹&#xff1f;2.1 语言生成能力评测对比场景…...

基于ollama搭建本地deepseek大模型服务

基于ollama搭建本地deepseek大模型服务 简介准备工作系统要求ollama的安装ollama 模型ollama 安装流程ollama 如何运行大模型前端部署注意事项简介 本指南旨在帮助初学者在本地环境中设置和运行DeepSeek大模型服务。本文将使用Ollama平台来简化这一过程,确保即使是新手也能顺…...

elementUI rules 判断 el-cascader控件修改值未生效

今天修改一个前端项目&#xff0c;增加一个多选字段&#xff0c;使用的是el-cascader控件&#xff0c;因页面是通过引用子页面组件形式使用&#xff0c;出现一个点选后再勾选原有值&#xff0c;输入框内不展示或取消后的也未正常隐藏&#xff0c;如果勾选的值是全新的则其他已选…...

讯方·智汇云校华为授权培训机构的介绍

官方授权 华为授权培训服务伙伴&#xff08;Huawei Authorized Learning Partner&#xff0c;简称HALP&#xff09;是获得华为授权&#xff0c;面向公众&#xff08;主要为华为企业业务的伙伴/客户&#xff09;提供与华为产品和技术相关的培训服务&#xff0c;培养华为产业链所…...

力扣-二叉树-257 二叉树的所有路径

思路 除去根节点&#xff0c;每一层添加->val&#xff0c;然后使用前序遍历的顺序 代码 class Solution { public:vector<string> res;void getTreePaths(string s, TreeNode* root){s "->";s to_string(root->val);if(root->left nullptr &…...

DeepSeek4j 已开源,支持思维链,自定义参数,Spring Boot Starter 轻松集成,快速入门!建议收藏

DeepSeek4j Spring Boot Starter 快速入门 简介 DeepSeek4j 是一个专为 Spring Boot 设计的 AI 能力集成启动器&#xff0c;可快速接入 DeepSeek 大模型服务。通过简洁的配置和易用的 API&#xff0c;开发者可轻松实现对话交互功能。 环境要求 JDK 8Spring Boot 2.7Maven/Gr…...