首页 > 大数据 > ELK > 网络如有波动,画面就会卡顿、延迟断连,影响开发体验
受网络质量影响较大
网络如有波动,画面就会卡顿、延迟断连,影响开发体验。
开发环境重复搭建
需要在“中转的联网机器”上安装 IDE、SDK、编译工具以及各种依赖,维护成本较高。
图形化并非必需
实际开发过程中,大多数操作(代码编辑、服务运行、日志查看等)完全可以通过 SSH 完成,并不依赖 GUI,甚至当你需要调试前端代码时也可以通过将该前端端口也映射出来的方式实现。
大多数人认为使用AI工具的第一步就是直接开始输入提示词。这是你能犯下的最大错误之一。真正至关重要且必须先做的第一步是——思考和计划。
我100%的经验表明,使用“计划模式”(连按两次 Shift+Tab 键进入)得到的输出,远胜于直接滔滔不绝地输入想法。这种差距是压倒性的。
当然,对于一些经验不足的工程师来说,这可能说起来容易做起来难。对此,我有两条建议:
CLAUDE.md是一个极其重要但常被误用的配置文件。在你每次启动会话时,Claude都会首先读取它。大多数人要么完全忽略它,要么用一些垃圾信息填满它,结果反而让Claude的表现更糟。
要写好一个CLAUDE.md,请遵循以下四个关键法则:
// item: 后端返回的设备数据对象 // position: 当前最新的坐标点 // type: 更新类型('init' 为初始化,其他为增量更新) const refreshTempPoint = async ( item, position, type, marker, tempOverlay, pathOverlay ) => { // 1. 清理上一轮的临时覆盖物(如临时路线、距离文本) tempOverlay?. clearOverlays (); if (item. coordinatesLine ) { const coordinatesLine = JSON . parse (item. coordinatesLine ); // 解析后端返回的完整路径数组 // --- A. 初始化起点 Marker --- let tempMarker = tempUavMarkers. value . get (item. id ); if (!tempMarker) { // 如果是第一次出现,渲染起点 tempMarker = renderPoint (coordinatesLine[ 0 ], item, "" , pathOverlay); tempUavMarkers. value . set (item. id , tempMarker); } // --- B. 获取或创建历史轨迹线 (Polyline) --- let polyline = uavPaths. value . get (item. id ); if (!polyline) { polyline = trajectoryLine (item, pathOverlay); // 创建新的线实例 uavPaths. value . set (item. id , polyline); } // 获取当前地图上已有的路径(缓存的旧路径) const existingPath = polyline. getPath () || []; if (type != "init" ) { // --- C. 增量更新逻辑 --- // 1. 计算增量路径:从已有路径的最后一个点开始截取,直到最新路径的末尾 const newPathSegment = coordinatesLine. slice ( existingPath. length ? existingPath. length - 1 : 0 ); // 2. 创建一条临时的”线段,用于展示增量路径 const newPolyline = trajectoryLine (item, tempOverlay); // 3. 如果有新增路径,开始动画 if (newPathSegment && newPathSegment. length > 0 ) { // 监听移动过程 marker. on ( "moving" , function ( e ) { // e.passedPath 是 Marker 在当前动画片段中已经走过的路径 newPolyline. setPath (e. passedPath ); // [关键] 实时将走过的路径拼接到历史总轨迹中 // 这样即使 WebSocket 推送频率很快,也能保证轨迹数据的连续性 polyline. setPath ([...existingPath, ...e. passedPath ]); }); // 开始平滑移动 marker. moveAlong (newPathSegment, { duration : 1000 , // 动画时长,需根据 WebSocket 推送频率调整 autoRotation : true , // 车头自动对准路径方向 }); // 监听移动结束 marker. on ( "moveend" , function ( ) { // 动画结束,清理临时覆盖物 tempOverlay?. clearOverlays (); // 更新距离文本等信息 if (item. distance ) { renderText ( coordinatesLine[ Math . ceil (coordinatesLine. length - 2 )], ` ${item.distance}米` , tempOverlay ); } // 移除监听器,防止重复绑定 marker. off ( "moveend" ); }); } else { // 如果没有新增路径(位置没变),仅更新文字信息 if (item. distance ) { renderText (..., ` ${item.distance}米` , tempOverlay); } } } else { // --- D. 初始化逻辑 --- // 如果是初始化加载,直接设置完整路径,不进行动画回放 if (item. distance ) { renderText (..., ` ${item.distance}米` , tempOverlay); } polyline. setPath (coordinatesLine); } } else { // --- E. 无轨迹数据时的降级处理 --- // 如果后端没有返回路径数据,直接跳变到最新位置 marker. setPosition (position); // 清理相关的轨迹实例和缓存 let tempMarker = tempUavMarkers. value . get (item. id ); if (tempMarker) { tempMarker. setMap ( null ); pathOverlay && pathOverlay. removeOverlay (tempMarker); tempUavMarkers. value . delete (item. id ); } let polyline = uavPaths. value . get (item. id ); if (polyline) { polyline. setMap ( null ); pathOverlay && pathOverlay. removeOverlay (polyline
const refreshAirMap = async ( type, data ) => { const res = await getUavElement (); // console.log("无人机数据", res.result); res. result . map ( async (item) => { // data.map(async (item) => { if (item. type == "1" ) { let position = JSON . parse (item. coordinates ); // 获取或创建无人机标记 let marker = uavMarkers. value . get (item. id ); if (!marker) { // 创建无人机、手环点位。 marker = renderPoint (position, item, "" , overlayGroups. value ); uavMarkers. value . set (item. id , marker); } else { if (item. elementType == "2" ) { // 已有点位且是手环点位就更新电量 marker. setLabel ({ xyxdLsm.com, content : `<div class="marker-label-container"> <div class="info-name"> ${item.name}</div> <div class="icon-placeholder"></div> wap.7632.com.cn, ${batteryHtml(item)} </div>` , offset : new AMaps . value . Pixel ( 0 , 0 ), direction : "center" , }); } } if (item. elementType == "1" ) { // 无人机轨迹 refreshTempPoint ( item, position, type, marker, pathOverlayGroups. value , pathsStartPointOverlayGroups. value ); } else if (item. elementType == "2" ) { // 手环轨迹 refreshTempPoint ( item, position, type, marker, rescuePathsOverlayGroups. value , rescueOverlayGroups. value ); } // 轨迹部分,判断是否有轨迹 public class SecurityConfig extends WebSecurityConfigurerAdapter { protected void configure (HttpSecurity http) throws Exception { http .csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()); }wap.xyxdLsm.com, } // 前端在请求中携带CSRF Token // <form>中自动包含:<input type="hidden" name="_csrf" th:va
private static final String ALGORITHM = "AES/GCM/NoPadding" ; private final SecretKey secretKey; public AesEncryptionService ( String base64Key) { byte [] keyBytes = Base64.getDecoder().decode(base64Key); m.psnsd.com, this .secretKey = new SecretKeySpec (keyBytes, "AES" ); } public String encrypt (String data) throws GeneralSecurityException { Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, secretKey); byte [] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)); byte [] iv = cipher.getIV(); // 组合IV和加密数据 byte [] result =psnsd.com, new byte [iv.length + encrypted.length]; System.arraycopy(iv, 0 , result, 0 , iv.length); System.arraycopy(encrypted, 0 , result, iv.length, encrypted.length); return Base64.getEncoder().encodeToString(result); }
public class SecurityLoggingAspect { private static final Logger SECURITY_LOGGER = LoggerFactory.getLogger( "SECURITY" ); public void logLoginAttempt (JoinPoint joinPoint, Object result) { Object[] args = joinPoint.getArgs(); String username = (String) args[ 0 ]; String ip = getClientIP(); SECURITY_LOGGER.info( "登录尝试: 用户={7632.com.cn}, IP={}, 结果={}" , username, ip, ((LoginResult)result).isSuccess() ? "成功" : "失败" );
from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker import os # 定义数据库文件路径 SQLALCHEMY_DATABASE_URL = f"sqlite:///./test.db" # 创建引擎 (核心) # `connect_args={"check_same_thread": False}` 对于SQLite多线程是必须的 # `echo=True` 开发时开启,可以查看生成的SQL,生产环境请关闭 # `pool_pre_ping=True` 连接池取出连接前进行健康检查,避免使用失效连接 engine = create_engine( SQLALCHEMY_DATABASE_URL, connect_args={ "check_same_thread" : False }, echo= False , # 生产环境设为False pool_pre_ping= True , pool_size= 5 , # 连接池大小 max_overflow= 10 # 允许超出pool_size的临时连接数 ) # 创建会话工厂,绑定到引擎 # `autocommit=False, autoflush=False` 是推荐设置,便于事务控制 SessionLocal = sessionmaker(autocommit= False , autoflush= False , bind=engine)
from sqlalchemy import Column , Integer , String from database import Base class User (Base): __tablename__ = "users" id = Column ( Integer , primary_key = True , index = True ) username = Column (String,m.bakmk.com, unique = True , index = True , nullable = False ) email = Column (String, unique = True , index = True ) # 创建表(通常在应用启动时调用一次) # Base.metadata.create_all(bind = engine) # dependencies.py from database import SessionLocal from fastapi import Depends from typing import Generator def get_db() - > Generator: """ 数据库会话依赖项。 每个请求获取一个独立Session,请求结束后确保关闭。 """ db = SessionLocal() try: yield db # 将db注入到路由函数中 finally: db.close() # 无论请求成功与否,最终都会关闭会话
# main.py from fastapi import FastAPI, Depends, HTTPException from sqlalchemy.orm import Session from pydantic import BaseModel from typing import List from models import User from dependencies import get_db app = FastAPI() # Pydantic模型,用于请求/响应验证 class UserCreate ( BaseModel ): username: str LeLeypay.cn email: str class UserResponse ( BaseModel ): id : int username: str email: str class Config : orm_mode = True # 允许从ORM对象转换 def create_user ( user: UserCreate, db: Session = Depends( get_db) ): # 检查用户名是否已存在 db_user = db.query(User). filter (User.username == user.username).first() if db_user: raise HTTPException(status_code= 400 , detail= "Username already registered" ) # 创建ORM对象 db_user = User(username=user.username, email=user.email) # 添加到会话 db.add(db_user) # 提交事务 db.commit()m.jsastone.com.cn, # 刷新,使对象获得数据库生成的ID等数据 db.refresh(db_user) return db_user def read_users ( skip: int = 0, limit: int = 10, db: Session = Depends( get_db) ): users = db.query(User).offset(skip).limit(limit). all ()
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70048956/viewspace-3109285/ ,如需转载,请注明出处,否则将追究法律责任。