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

ocpp-远程启动(RemoteStartTransaction)、远程停止(RemoteStopTransaction)

目录

1、介绍

2、远程启动-RemoteStartTransaction

3、远程停止-RemoteStopTransaction

4、代码

4.1 OcppRechongFeign

4.2 CmdController

4.3 CmdService

4.4 RemoteStartTransactionReq

4.5 接收报文-DataAnalysisController

4.6 接收报文实现类-DataAnalysisService

4.7 StartTransactionReq

4.8 StartTransactionConfig

4.9 AuthorizeConfig

4.10 IdTagInfo

4.11 DateUtil


1、介绍

         远程启动与停止一般是在小程序或者App端发起;

         启动的支付方式可以用余额支付、优惠劵支付、微信支付、支付宝支付等等,当前主流的支付方式;

        启动时创建充电桩-枪对应的充电记录信息;

2、远程启动-RemoteStartTransaction

@Autowired
OcppRechongFeign ocppRechongFeign;

/**
* 开始充电
*
* @param map 充电订单的信息
* @return
*/
public ReturnData startRecharge(Map<String, Object> map, String AppId,Object userId) {

        ReturnData returnData = new ReturnData();

        log.info("startRecharge=参数{}", JSON.toJSONString(map));

        returnData = ocppRechongFeign.startRecharge();

}

3、远程停止-RemoteStopTransaction

/**
* 结束充电
*
* @param map
* @return
*/
public ReturnData endRecharge(Map<String, Object> map) {
ReturnData returnData = new ReturnData();
try {
log.info("测试小程序结束充电");

// 订单号
Object orderNumber = map.get("orderNumber");
log.info("订单编号"+orderNumber);
}
// 调用结束充电
log.info("调用结束充电");
returnData = ocppRechongFeign.equEndRecharge(map);
if (returnData.isResult()==true){
  // 自己的业务处理
}
log.info("结果======"+JSON.toJSONString(returnData));
return returnData;
} catch (Exception e) {
log.error("结束充电异常", e);
returnData.setCode("111111");
returnData.setResult(false);
returnData.setMsg("结束充电失败" + e.getMessage());
}
return returnData;
}

4、代码

4.1 OcppRechongFeign

public interface OcppRechongFeign {

/**
* 开始充电
* @param map
* @return
*/
@PostMapping("/cmd/equStartRecharge.jk")
ReturnData startRecharge(@RequestBody Map<String,Object> map);

/**
* 停止充电
* @param map
* @return
*/
@PostMapping("/cmd/equEndRecharge.jk")
ReturnData equEndRecharge(@RequestBody Map<String,Object> map);

}

4.2 CmdController

@RestController
@Slf4j
@RequestMapping("cmd")

public class CmdController {

/**
* 开始充电
* @param map
* @return
*/
@RequestMapping("equStartRecharge.jk")
public ReturnData equStartRecharge(@RequestBody Map<String,Object> map){
    log.info("接收到的参数{}", JSON.toJSONString(map));
    ReturnData returnData=cmdService.equStartRecharge(map);
    return returnData;
}
/**
* 停止充电
* @param map
* @return
*/
@RequestMapping("equEndRecharge.jk")
public ReturnData equEndRecharge(@RequestBody Map<String ,Object> map){
    log.info("停止充电接收到的参数{}", JSON.toJSONString(map));
    ReturnData returnData=cmdService.equEndRecharge(map);
    return returnData;
}

}

4.3 CmdService

@Slf4j
@Service
public class CmdService {

/**
* 开始充电
* @param
* @return

* [2,"4f08e280-b5b2-4197-82ef-f10a1f351fcb","RemoteStartTransaction",{"connectorId":1,"idTag":"C35CEA09"}]
*/
public ReturnData equStartRecharge(Map<String,Object> map){
ReturnData returnData=new ReturnData();
try {
String orderId=map.get("id")+"";
// 设备sn
String sn=map.get("equSn")+"";
// 抢号
String socketNo=map.get("socketNo")+"";
//充电编号
String chargingNumber=map.get("chargingNumber")+"";
String ocppChargingNumber=String.valueOf(map.get("ocppChargingNumber"));
// String ip=map.get("ip")+"";
JSONObject resultJSONObj=new JSONObject();
String cmdStr="";
ArrayList arrayList=new ArrayList();
arrayList.add(2);
String msgId=UuidUtil.get32UUID();
arrayList.add(msgId);
String actiion="RemoteStartTransaction";
arrayList.add(actiion);
RemoteStartTransactionReq remoteStartTransactionReq =new RemoteStartTransactionReq();
// 抢号
remoteStartTransactionReq.setConnectorId(Integer.parseInt(socketNo));
// 自动生成的卡号
remoteStartTransactionReq.setIdTag(ocppChargingNumber);
// 卡号
// remoteStartTransactionReq.setIdTag("43AA3CA6");

arrayList.add(remoteStartTransactionReq);
cmdStr=JSON.toJSONString(arrayList);
resultJSONObj.put("ip",ip);
resultJSONObj.put("data",cmdStr);
log.info("开始充电发的报文{}",cmdStr);

// 发送报文
nettyFeign.A4OutMessage(resultJSONObj.toJSONString());
returnData.setResult(true);
}catch (Exception e){
log.error("开始充电异常{}",e.getMessage());
e.printStackTrace();
returnData.setResult(false);
returnData.setMsg(e.getMessage());
}
return returnData;
}

/**
* 停止充电
* @param
* @return
*/
public ReturnData equEndRecharge(Map<String ,Object> map){
ReturnData returnData=new ReturnData();
try {
log.info("结束充电==========");

Long msgId=getRandom.nextNumber(2,"equEndRecharge");//消息ID
// String msgIdStr=HaxUtils.addZore(msgId+"",4);
// [2,"28f7d946-c019-4071-8800-8e07426836f2","RemoteStopTransaction",{"transactionId":12023}]
String cmdStr="";
ArrayList arrayList=new ArrayList();
arrayList.add(2);
// arrayList.add(OrderUtil.getOrderId());
String msgIdStr=UuidUtil.get32UUID();
arrayList.add(msgIdStr);
String actiion="RemoteStopTransaction";
arrayList.add(actiion);
// 订单编号
String orderId=map.get("id")+"";
RemoteStopTransaction remoteStopTransaction =new RemoteStopTransaction();
remoteStopTransaction.setTransactionId(Integer.parseInt(orderId));
redis.setex("sendData"+msgId,20,JSON.toJSONString(remoteStopTransaction));

arrayList.add(remoteStopTransaction);
cmdStr=JSON.toJSONString(arrayList);
log.info("停止充电发的报文{}",cmdStr);
// 业务逻辑处理
if (ip==null){
log.info("结束充电,结算订单,ip不存在,设备未连接");
returnData.setResult(false);
returnData.setMsg("设备未连接");
}else {
//结束充电
log.info("操作执行结束充电");
JSONObject resultJSONObj=new JSONObject();
resultJSONObj.put("ip",ip);
resultJSONObj.put("data",cmdStr);
MqttPushClient.publish(BusinessType.topIc,JSON.toJSONString(resultJSONObj));

boolean end=false;
}
returnData.setResult(end);
if (end){
returnData.setMsg("成功结束充电");
}else {
returnData.setMsg("结束充电失败");
}
}
}catch (Exception e){
log.error("结束充电异常{}",e.getMessage());
e.printStackTrace();
returnData.setMsg(e.getMessage()+"");
}
return returnData;
}

}

4.4 RemoteStartTransactionReq

import lombok.Data;
/**
* 远程启动充电 6.33. RemoteStartTransaction.req
*/
@Data
public class RemoteStartTransactionReq {
    private Integer connectorId; //可选。要启动事务的连接器的编号。连接器Id应为>值0
    private String idTag;// 必填。收费点在启动事务处理时必须使用的标识符
}

4.5 接收报文-DataAnalysisController

/**
* ocpp协议
*/
@Slf4j
@RestController
@RequestMapping("ocpp")
public class DataAnalysisController {
  @Autowired
  DataAnalysisService zhenwankejiDataAnalysisService;
  @RequestMapping("/dataAnalysis")
  public ReturnData dataAnalysis(@RequestBody String body){
     ReturnData returnData=zhenwankejiDataAnalysisService.dataAnalysisService(body);
     return returnData;
 }
}

4.6 接收报文实现类-DataAnalysisService

@Slf4j
@Service
public class DataAnalysisService {

public ReturnData dataAnalysisService(String body) {
 ReturnData returnData = new ReturnData();
try {
Cache redis=Redis.use();
String inputStr = "";
JSONObject inputJson = JSON.parseObject(body);
inputStr = inputJson.getString("data");
String ip = inputJson.getString("ip");
log.info("ocpp收到的上报信息报文{}", inputStr);
if(null!=inputStr && !"".equals(inputStr)){
// 获取消息状态
JSONArray jsonArray=JSON.parseArray(inputStr);
String msgType=jsonArray.getString(0);//消息类型
//消息ID
String msgId=jsonArray.getString(1); //消息ID
JSONObject actionJSON=new JSONObject();
String action="";
String sendData="";
if (jsonArray.size()==4){
action=jsonArray.getString(2);//action类型
//加密标识
actionJSON=jsonArray.getJSONObject(3);
}else if (jsonArray.size()==3){
actionJSON=jsonArray.getJSONObject(2);
action=redis.get("action"+msgId);
sendData=redis.get("sendData"+msgId);
if (sendData!=null){
log.info("下发的消息信息:{}"+sendData);
}
}
//帧类型标识
String cmd=action;
log.info("ocpp-cmd命令{}",cmd);
String data =actionJSON.toJSONString();
log.info("消息体{}", data);
String des3="";
if(null!=cmd && !"".equals(cmd)){
switch (cmd) {

// 开始充电事务
case "RemoteStartTransaction":
returnData = RemoteStartTransaction(data,msgId,msgType,action,
sendData,ip,body);
break;

// 充电桩事务开启
case "StartTransaction":
returnData = StartTransaction(data,msgType,msgId,action,ip,body);
break;

// 停止
case "StopTransaction":
returnData=stopTransaction(data,msgId,msgType,body);


}
if (returnData.isResult()) {//需要返回
  JSONObject resultJsonObj = new JSONObject();
  resultJsonObj.put("ip", inputJson.getString("ip"));
  resultJsonObj.put("data", (returnData.getData()));
  MqttPushClient.publish(BusinessType.topIc,JSON.toJSONString(resultJsonObj));
}
}else{
  returnData=defaultInfos(data,msgId,msgType,ip,action,body);
}
}
} catch (Exception e) {
  log.error("ocpp设备上报报文解析异常",e);
  returnData.setResult(false);
  returnData.setCode("111111");
  returnData.setMsg("ocpp设备上报报文解析异常"+e.getLocalizedMessage());
}
  return returnData;
}

}

/**
* 开始充电事务
* 启动充点电返回
* @param data
* @param msgId
* @param msgType
* @param action
* @param sendData
* @return
*/
public ReturnData RemoteStartTransaction(String data,String msgId,
String msgType,String action,
String sendData,String ip,String body){
ReturnData returnData=new ReturnData();
try {
RemoteStartTransactionReq req= JSON.parseObject(sendData,RemoteStartTransactionReq.class);
JSONObject jsonObject=JSON.parseObject(data);
String status=jsonObject.getString("status");
if(OcppStatus.PREPARING.getCode().equals(status)){
  returnData.setResult(true);
}
// 未插枪
else if(OcppStatus.AVALIABLE.getCode().equals(status)){
  returnData.setResult(false);
  returnData.setMsg("请先插枪");
}else if(OcppStatus.CHARGING.getCode().equals(status)){
  returnData.setResult(false);
  returnData.setMsg("请先插枪");
}else if(OcppStatus.ACCEPTED.getCode().equals(status)){
  returnData.setResult(false);
  returnData.setMsg("请先插枪");
}
}catch (Exception e){
  log.error("收到充电点反馈,并且开启事务异常",e);
  returnData.setResult(false);
}
return returnData;
}

/**
* 充电桩事务开启
* 开始充电事务 data,msgType,msgId,action
* @param data
* @param msgType
* @param msgId
* @param action
* @return
*/
public ReturnData StartTransaction(String data, String msgType,String msgId,String action,String ip,String body) {
ReturnData returnData = new ReturnData();
try {
// [2,"QyVbJb28BEZfws6C","StartTransaction",{"connectorId":1,"idTag":"43AA3CA6","meterStart":0,"timestamp":"2023-08-14T05:54:03Z"}]
log.info("充电桩开启充电事务{}",data);
StartTransactionReq startTransactionReq=JSON.parseObject(data,StartTransactionReq.class);
String idTag=startTransactionReq.getIdTag();
// 抢号
int connectorId=startTransactionReq.getConnectorId();

log.info("idTag{} :",idTag);
StartTransactionConfig config=new StartTransactionConfig();
config.setTransactionId(transactionId);
IdTagInfo info=new IdTagInfo();
info.setStatus("Accepted");
config.setIdTagInfo(info);

List resultList=new ArrayList();
resultList.add(Integer.parseInt(msgType)+1);
resultList.add(msgId);
resultList.add(config);
log.info("开始事务配置数据:{}",JSON.toJSONString(resultList));
returnData.setData(JSON.toJSONString(resultList));
returnData.setResult(true);
return returnData;
}
returnData.setData("发起充电失败");
returnData.setResult(false);
return returnData;
}catch (Exception e){
log.error("开始充电事务异常{}",e);
returnData.setResult(false);
}
return returnData;
}

4.7 StartTransactionReq

/**
* 开启充电事务
*/
@Data
public class StartTransactionReq {

private Integer connectorId;//充电枪号

private String idTag; //id标识

private Integer meterStart=0; // 这包含了事务开始时连接器的表值,单位为Wh。

private String timestamp;//时间戳

}

/**
* 停止
* 停止操作
* @param data
* @param msgType
* @param msgId
* @return
*/
@Transactional
public ReturnData stopTransaction(String data,String msgId,String msgType,String body) {
ReturnData returnData=new ReturnData();
try {
IdTagInfo info=new IdTagInfo();
info.setStatus("Accepted");

// 时间推迟60分钟
Date endDate=DateUtil.getAfterMinute(new Date(),60);

// 转换为utc格式
String utcStr=DateUtil.localToUTC(endDate);
info.setExpiryDate(utcStr);
List resultList=new ArrayList();
resultList.add(Integer.parseInt(msgType)+1);
resultList.add(msgId);
AuthorizeConfig authorizeConfig=new AuthorizeConfig();
authorizeConfig.setIdTagInfo(info);
resultList.add(authorizeConfig);

returnData.setResult(true);
log.info("停止返回信息:{}",JSON.toJSONString(resultList));
String json=new ObjectMapper().writeValueAsString(resultList);
returnData.setData(json);
returnData=stopOrderInfo(JSON.parseObject(data),returnData,body);
}catch (Exception e){
log.error("停止点反馈,并且开启事务异常",e);
returnData.setResult(false);
}
return returnData;
}

4.8 StartTransactionConfig

/**
* 开始充电事务
*/

@Data
public class StartTransactionConfig {

// idtag信息
// private IdTagInfo info;
private IdTagInfo idTagInfo;

//中央平台控制的事务ID
private Integer transactionId;


}

4.9 AuthorizeConfig

import lombok.Data;

/**
* 授权配置
*/
@Data
public class AuthorizeConfig {

private IdTagInfo idTagInfo;
}

4.10 IdTagInfo

/**
*
* 授权token回复详细信息
*/
@Data
public class IdTagInfo {
// Accepted 允许使用可充电的标识符
// Blocked 标识符已被阻止。不允许充电。
// Expired 标识符已过期。不允许充电。
// Invalid 标识符未知。不允许充电。
// ConcurrentTx 标识符已涉及到另一个事务中,并且不允许有多个事务。(仅与StartTransaction.req相关。)
private String status;
// 这其中包含idTag应该从授权缓存中删除的日期。
private String expiryDate;
//private IdToken idToken;//父级标识符。
}

4.11 DateUtil

/**
* 得到 n分钟后的时间
*
* @param date
* @param minute
* @return
*/
public static Date getAfterMinute(Date date, Integer minute) {

long time = date.getTime();

time += minute * 1000 * 60;//在当前系统时间的基础上往后加minute分钟
return new Date(time);
}

/**
*
* <p>Description: 本地时间转化为UTC时间</p>
* @param localDate
* @return
* @author wgs
* @date 2018年10月19日 下午2:23:43
*
*/
public static String localToUTC(Date localDate) {
long localTimeInMillis=localDate.getTime();
/** long时间转换成Calendar */
Calendar calendar= Calendar.getInstance();
calendar.setTimeInMillis(localTimeInMillis);
/** 取得时间偏移量 */
int zoneOffset = calendar.get(java.util.Calendar.ZONE_OFFSET);
/** 取得夏令时差 */
int dstOffset = calendar.get(java.util.Calendar.DST_OFFSET);
/** 从本地时间里扣除这些差量,即可以取得UTC时间*/
calendar.add(java.util.Calendar.MILLISECOND, -(zoneOffset + dstOffset));
/** 取得的时间就是UTC标准时间 */
Date utcDate=new Date(calendar.getTimeInMillis());
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
String timeStr=df.format(utcDate);
return timeStr;
}

相关文章:

ocpp-远程启动(RemoteStartTransaction)、远程停止(RemoteStopTransaction)

目录 1、介绍 2、远程启动-RemoteStartTransaction 3、远程停止-RemoteStopTransaction 4、代码 4.1 OcppRechongFeign 4.2 CmdController 4.3 CmdService 4.4 RemoteStartTransactionReq 4.5 接收报文-DataAnalysisController 4.6 接收报文实现类-DataAnalysisServi…...

【网络安全】安全的系统配置

系统配置是网络安全的重要组成部分。一个不安全的系统配置可能会使网络暴露在攻击者面前&#xff0c;而一个安全的系统配置可以有效地防止攻击者的入侵。在本文中&#xff0c;我们将详细介绍如何配置一个安全的系统&#xff0c;包括操作系统配置&#xff0c;网络服务配置&#…...

conda使用一般步骤

Terminal&#xff1a;conda create --name myenv python3.7 如果环境不行的话 1.source /opt/anaconda3/bin/activate 2.可能是没有源 vim ~/.condarc将需要的源装上 conda clean -i将原先的源删除 3.然后再conda create即可 4.需要激活环境 conda activate numpy 5.pycharm配置…...

如何做好需求收集?方法和步骤

需求收集是理解你想要构建什么以及为什么要构建它的过程。需求收集通常被视为开发软件应用&#xff0c;或开发硬件产品的一部分。其重要性不言而喻。据调查显示50%以上产品在市场上失败的原因&#xff0c;是由于忽视了用户需求。 一、需求收集为什么会困难&#xff1f; 困扰项…...

SpringBoo整合WebSocket实战演练——Java入职十三天

前言 本文将介绍如何在Spring Boot应用程序中使用WebSocket实现服务端向客户端推送消息。Spring Boot和WebSocket的整合实现服务端向客户端推送消息,使得客户端能够实时接收并处理服务器发来的信息。WebSocket协议是一种双向通信的网络协议,使得客户端和服务器能够建立持久连…...

众佰诚:抖音小店的体验分什么时候更新

随着移动互联网的发展&#xff0c;越来越多的电商平台开始涌现&#xff0c;其中抖音小店作为一种新型的电商模式&#xff0c;受到了许多用户的欢迎。然而&#xff0c;对于抖音小店的体验分更新时间&#xff0c;很多用户并不是很清楚。本文将对此进行详细的解答。 首先&#xff…...

详解cv2.addWeighted函数【使用 OpenCV 添加(混合)两个图像-Python版本】

文章目录 简介函数原型代码示例参考资料 简介 有的时候我们需要将两张图片在alpha通道进行混合&#xff0c;比如深度学习数据集增强方式MixUp。OpenCV的addWeighted提供了相关操作&#xff0c;此篇博客将详细介绍这个函数&#xff0c;并给出代码示例。&#x1f680;&#x1f6…...

单链表经典OJ题:反转链表

题目&#xff1a; 给你单链表的头节点 head &#xff0c;i请你反转链表&#xff0c;并返回反转后的链表。 图例&#xff1a; 分析&#xff1a; 根据链表的特征&#xff0c;反转链表的本质便是改变节点内部的指针方向。 将原先指向下一个节点的指针进行修改&#xff0c;将其的…...

软考高级信息系统项目管理师系列论文六:论信息系统项目的人力资源管理

软考高级信息系统项目管理师系列论文六:论信息系统项目的人力资源管理 一、人力资源管理相关知识二、摘要三、正文四、总结一、人力资源管理相关知识 软考高级信息系统项目管理师系列之十七:项目人力资源管理二、摘要 2021年7 月,我参加了╳╳市物价局发起的“智慧物价”信息…...

Kubeadm部署k8s集群

目录 主机准备 主机配置 修改主机名&#xff08;三个节点分别执行&#xff09; 配置hosts&#xff08;所有节点&#xff09; 关闭防火墙、selinux、swap、dnsmasq(所有节点) 安装依赖包&#xff08;所有节点&#xff09; 系统参数设置(所有节点) 时间同步(所有节点) 配…...

YOLOv7改进:新机制,扩展DCNv3,基于DCNv2优化 | CVPR2023 InternImage

💡💡💡本文属于原创独家改进:DCNv3优势:1) 共享投射权重;2) 引入多组机制;3)采样点调制标量归一化; DCNv3 | 亲测在多个数据集实现暴力涨点; 收录: YOLOv7高阶自研专栏介绍: http://t.csdnimg.cn/tYI0c ✨✨✨前沿最新计算机顶会复现 🚀🚀🚀YOL…...

SMAP(Soil Moisture Active and Passive)数据下载

SMAP&#xff08;Soil Moisture Active and Passive&#xff09;数据下载 打开网站先注册登录用户 然后打开SMAP下载的网站 点击HTTPS File System进入下载页面 然后点击HDF文件下载 下载之后在HDF View里面预览...

【Huawei S5700交换机】产品介绍

产品特点 S5700系列以太网交换机&#xff0c;是华为公司为满足大带宽接入和以太多业务汇聚而推出的新一代绿色节能的全千兆高性能以太交换机。它基于新一代高性能硬件和华为公司统一的VRP&#xff08;Versatile Routing Platform&#xff09;平台&#xff0c;具备大容量、高可…...

华为Atlas 200I DK A2开发者套件--基础使用配置

文章目录 前言一、快速开始二、通过路由器联网三、USB相机总结 前言 Atlas 200I DK A2基础使用配置方法。准备好键鼠、显示器、网线、USB拓展器。 一、快速开始 下载最新官方Windows版本昇腾开发者套件一键制卡工具&#xff1a; https://ascend-repo.obs.cn-east-2.myhuaweic…...

C++DAY47

头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QPushButton> #include <QLabel> #include <QLineEdit> #include <QDebug>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public…...

四边形不等式

区间dp问题&#xff0c;状态转移方程&#xff1a; dp[i][j] min( dp[i][k] dp[k1][j] w[i][j] ) //w[i][j]是从i到j的&#xff0c;一个定值 不随k改变&#xff0c;而且w的值只和i j有关&#xff0c;是它们的二元函数。 其中i<k<j ,初始值dp[i][i]已知。 含义&#x…...

Jmeter(四):请求默认值元件应用,正则表达式提取器元件讲解

Jmeter请求默认值元件应用 HTTP请求默认值 在公司内部进行测试的时候&#xff0c;一般测试环境访问的接口地址&#xff08;服务器名称 或IP&#xff09;、端口、协议一般都是不变的&#xff0c;但http请求取样器每个请求都要求写一遍 这些信息&#xff0c;在实际HTTP请求取样…...

LCR 001. 两数相除

剑指Offer通关 力扣搜索LCR即为剑指Offer的所有题目。 LCR 001. 两数相除 快速乘 解析&#xff1a; 题目规定只能用32位整数&#xff0c;所以取值范围在-2^31 ~ 2^31 - 1 之间。这里的特殊情况为什么不考虑被除数和除数为最大值&#xff1f;因为后面会将所有的数都转为负数…...

LeCun和Bengio“吵”起来了,人工智能是“潘多拉魔盒”吗?

作者 | 谢年年 上周末&#xff0c;深度学习领域最有影响力的三巨头之二Yann LeCun和Yoshua Bengio就AI的潜在风险和安全问题引发了一场激烈辩论&#xff0c;人工智能是“潘多拉魔盒”吗&#xff1f;这场辩论引来众多AI知名人士围观。 LeCun在Facebook上发起了这场辩论&#xff…...

电子期刊制作宝典,让你成为专业行家

电子期刊作为一种新兴的媒体形式&#xff0c;越来越受到人们的喜爱。它不仅方便快捷&#xff0c;而且可以随时随地阅读&#xff0c;不受时间和空间的限制。那么&#xff0c;如何制作一份高质量的电子期刊呢&#xff1f; 1.首先打开FLBOOK电子杂志平台 2.然后点击模板选择电子期…...

新手教程使用curl命令一分钟测试Taotoken的OpenAI兼容API

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 新手教程&#xff1a;使用curl命令一分钟测试Taotoken的OpenAI兼容API 本文面向刚获取Taotoken API Key的开发者&#xff0c;目标是…...

C8051Fxx系列MCU的Bootloader与ISP功能开发指南

1. C8051Fxx系列MCU的Bootloader与ISP功能概述在嵌入式系统开发中&#xff0c;C8051Fxx系列微控制器因其高性能和丰富的外设资源被广泛应用于工业控制、消费电子等领域。Bootloader&#xff08;引导加载程序&#xff09;和ISP&#xff08;在系统编程&#xff09;功能是这类MCU开…...

慕尼黑电子展深度攻略:从技术侦察到资源对接的实战指南

1. 展会项目概述与核心价值解析又到了一年一度的行业盛会密集期&#xff0c;对于身处电子、嵌入式、物联网这些硬科技赛道的从业者来说&#xff0c;参加一场高质量的线下展会&#xff0c;其价值远不止是“逛一逛”那么简单。它更像是一次集中的行业体检、一次高效的技术社交和一…...

RocketMQ 源码解析——Controller 高可用切换架构

延伸阅读&#xff1a;&#x1f50d;「RocketMQ 中文社区」 持续更新源码解析/最佳实践&#xff0c;提供 RocketMQ 专家 AI 答疑服务 一、原理及核心概念浅述 1.1 核心架构 1.2 核心概念 controller&#xff1a;负责管理broker间的主备关系&#xff0c;可以挂在namesrv中&…...

【BUUCTF】【WEB】ReadlezPHP

考点&#xff1a;打开题目&#xff0c;发现页面有点阴森&#xff1a;右键没有任何反应&#xff0c;那就右上角三个点&#xff1a;更多工具->开发者工具OK没有任何线索&#xff0c;那就用bp看看。拉倒最下面&#xff0c;发现右下角一个文件./time.php?source这可能是一个线索…...

RT-Thread Studio自定义工程路径踩坑记:解决‘Error retrieving output from the rttconfig server’报错

RT-Thread Studio自定义工程路径踩坑指南&#xff1a;从报错到原理的深度解析 第一次在RT-Thread Studio中尝试将项目放在D盘的自定义文件夹时&#xff0c;那个刺眼的红色报错框让我愣了几秒——"Error retrieving output from the rttconfig server"。控制台里密密麻…...

Spring Boot条件装配原理

Spring Boot条件装配原理 引言 条件装配是Spring Boot自动配置的核心机制&#xff0c;通过Conditional及其派生注解&#xff0c;Spring能够根据当前环境、classpath、配置属性等因素智能地决定是否创建某个Bean。本文将深入剖析条件装配的实现原理、各种条件注解的使用方法以及…...

Yokogawa ADV551数字输出模块

Yokogawa ADV551 数字输出模块是横河 CENTUM VP/CS 3000 系统的核心输出组件&#xff0c;具备以下 15 条特点&#xff1a;提供 32 路独立数字量输出通道。额定电压 24V DC&#xff0c;每通道负载能力充足。输出类型为电流吸收型&#xff08;Current Sink&#xff09;。支持状态…...

【软考高级架构】论文范文19——论软件系统架构风格

论软件系统架构风格 摘要 软件系统架构风格是描述系统结构和行为的抽象模式,为不同应用领域提供了经过验证的设计方案。合理选择与组合架构风格能够有效指导系统分解、组件划分和交互设计,从而提升系统的可维护性、可扩展性和性能等质量属性。本文以笔者主导的某大型制造企…...

别再给Claude送钱了!7个硬核技巧让Token消耗爆降80%,我亲测有效

文章目录前言1. 杀鸡不用牛刀&#xff1a;根据任务复杂度切换模型&#xff0c;别用导弹打蚊子2. 把CLAUDE.md当“项目宪法”&#xff0c;别当“信息垃圾场”3. 把脏活累活交给Subagent&#xff0c;但别滥用4. 精准打击&#xff01;明确指定文件和行号&#xff0c;别让Claude大海…...