物流项目第十期(轨迹微服务)

news2025/6/7 16:42:43

本项目专栏:

物流项目_Auc23的博客-CSDN博客

建议先看这期:

MongoDB入门之Java的使用-CSDN博客

物流项目第九期(MongoDB的应用之作业范围)-CSDN博客

业务需求

快递员取件成功后,需要将订单转成运单,用户会比较关注目前包裹走到哪里,类似这样:

需求描述

轨迹微服务是一个独立的微服务,主要提供创建运单轨迹点、记录最新位置、查询轨迹这些服务,具体要求如下:

  • 运单创建成功后,为运单创建轨迹点数据,并且将此数据持久化,以供后续的查询
  • 司机端在运输途中,需要上报最新的位置,更新相应的运单的最新位置数据
  • 快递员端在运输途中,需要上报最新的位置,更新相应的运单的最新位置数据
  • 提供查询轨迹的接口服务
  • 为查询轨迹接口服务设置缓存
  • 用户签收后,需要关闭轨迹的更新,不再更新最新位置数据

业务流程

MQListener

@Slf4j
@Component
public class MQListener {

    @Resource
    private TrackService trackService;

    /**
     * 创建运单后创建轨迹
     *
     * @param msg 消息
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = Constants.MQ.Queues.TRACK_TRANSPORT_ORDER_CREATED),
            exchange = @Exchange(name = Constants.MQ.Exchanges.TRANSPORT_ORDER_DELAYED, type = ExchangeTypes.TOPIC, delayed = Constants.MQ.DELAYED),
            key = Constants.MQ.RoutingKeys.TRANSPORT_ORDER_CREATE
    ))
    public void listenTransportOrderCreatedMsg(String msg) {
        log.info("接收到新增运单的消息 ({})-> {}", Constants.MQ.Queues.TRACK_TRANSPORT_ORDER_CREATED, msg);
        TransportOrderMsg transportOrderMsg = JSONUtil.toBean(msg, TransportOrderMsg.class);
        this.trackService.create(transportOrderMsg.getId());
    }

    /**
     * 运单签收后完成轨迹
     *
     * @param msg 消息
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = Constants.MQ.Queues.TRACK_TRANSPORT_ORDER_UPDATE_STATUS),
            exchange = @Exchange(name = Constants.MQ.Exchanges.TRANSPORT_ORDER_DELAYED, type = ExchangeTypes.TOPIC, delayed = Constants.MQ.DELAYED),
            key = Constants.MQ.RoutingKeys.TRANSPORT_ORDER_UPDATE_STATUS_PREFIX + "RECEIVED"
    ))
    public void listenTransportOrderUpdateStatusMsg(String msg) {
        log.info("接收到更新运单状态的消息 ({})-> {}", Constants.MQ.Queues.TRACK_TRANSPORT_ORDER_UPDATE_STATUS, msg);
        TransportOrderStatusMsg transportOrderStatusMsg = JSONUtil.toBean(msg, TransportOrderStatusMsg.class);
        this.trackService.complete(transportOrderStatusMsg.getIdList());
    }
}

util

public class TrackEntityUtil {

    /**
     * 将 TrackEntity 转换为 TrackDTO
     * 主要用于接口返回或业务层使用,脱敏敏感字段并格式化数据结构
     *
     * @param trackEntity 原始实体对象(来自数据库)
     * @return 转换后的 DTO 对象(用于返回给前端或其他服务)
     */
    public static TrackDTO toDTO(TrackEntity trackEntity) {
        // 创建 CopyOptions 配置项,指定忽略某些字段的复制
        // 这里忽略了 planGeoJsonLine 和 lastPoint 字段,因为这两个字段是 GeoJSON 类型,不适合直接暴露给外部
        // ignoreNullValue 表示不复制 null 值属性,避免空值污染 DTO
        CopyOptions copyOptions = CopyOptions.create()
                .setIgnoreProperties("planGeoJsonLine", "lastPoint")
                .ignoreNullValue();

        // 使用 Hutool 的 BeanUtil.toBean 方法进行基础字段拷贝
        // 会自动将 trackEntity 中非忽略字段复制到 TrackDTO 中
        TrackDTO trackDTO = BeanUtil.toBean(trackEntity, TrackDTO.class, copyOptions);

        // 处理计划轨迹点(planGeoJsonLine):这是一个 GeoJsonLineString 类型的地理轨迹线
        GeoJsonLineString planGeoJsonLine = trackEntity.getPlanGeoJsonLine();
        if (ObjectUtil.isAllNotEmpty(planGeoJsonLine, planGeoJsonLine.getCoordinates())) {
            // 如果轨迹线及其坐标列表存在且非空,则进行转换

            // 将 GeoJsonLineString 中的坐标点列表转换为 MarkerPointDTO 列表
            List<MarkerPointDTO> coordinateList = planGeoJsonLine.getCoordinates().stream()
                    // 每个 Coordinate 点转成 MarkerPointDTO(只包含 x 和 y 坐标)
                    .map(point -> new MarkerPointDTO(point.getX(), point.getY()))
                    // 收集为 List<MarkerPointDTO>
                    .collect(Collectors.toList());

            // 设置到 DTO 的 pointList 字段中,供前端展示使用
            trackDTO.setPointList(coordinateList);
        }

        // 处理最新位置坐标(lastPoint):是一个 GeoJsonPoint 类型的点
        if (ObjectUtil.isNotEmpty(trackEntity.getLastPoint())) {
            // 如果 lastPoint 存在

            // 获取该点的经纬度信息
            GeoJsonPoint point = trackEntity.getLastPoint();
            // 转换成 MarkerPointDTO 并设置到 DTO 中
            trackDTO.setLastPoint(new MarkerPointDTO(point.getX(), point.getY()));
        }

        // 返回最终处理好的 DTO 对象
        return trackDTO;
    }

}

entity

/**
 * 轨迹数据
 *
 * @author zzj
 * @version 1.0
 */
@Data
@Document("sl_track")
public class TrackEntity {

    @Id
    @JsonIgnore
    private ObjectId id;

    /**
     * 运单id
     */
    @Indexed
    private String transportOrderId;

    /**
     * 规划的轨迹坐标点线(通过地图服务商规划出来的轨迹点)
     */
    private GeoJsonLineString planGeoJsonLine;

    /**
     * 距离,单位:米
     */
    private Double distance;

    /**
     * 最新的位置坐标,x:经度,y:纬度
     */
    private GeoJsonPoint lastPoint;

    /**
     * 状态
     */
    private TrackStatusEnum status;

    /**
     * 类型
     */
    private TrackTypeEnum type;

    /**
     * 创建时间
     */
    private Long created;

    /**
     * 更新时间
     */
    private Long updated;

}

enums

/**
 * 异常枚举
 *
 * @author zzj
 * @version 1.0
 */
public enum TrackExceptionEnum implements BaseExceptionEnum {

    TRACK_ALREADY_EXISTS(1001, "轨迹已经存在");

    private Integer code;
    private Integer status;
    private String value;

    TrackExceptionEnum(Integer code, String value) {
        this.code = code;
        this.value = value;
        this.status = 500;
    }

    TrackExceptionEnum(Integer code, Integer status, String value) {
        this.code = code;
        this.value = value;
        this.status = status;
    }

    @Override
    public Integer getCode() {
        return this.code;
    }

    @Override
    public String getValue() {
        return this.value;
    }

    @Override
    public Integer getStatus() {
        return this.status;
    }

    public static TrackExceptionEnum codeOf(Integer code) {
        return EnumUtil.getBy(TrackExceptionEnum::getCode, code);
    }
}

controller

@RestController
@Api(tags = "轨迹管理")
@RequestMapping("track")
public class TrackController {

    @Resource
    private TrackService trackService;

    @PostMapping
    @ApiOperation(value = "创建轨迹", notes = "创建轨迹,会完成路线规划")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "transportOrderId", value = "运单号", required = true)
    })
    public boolean create(@RequestParam("transportOrderId") String transportOrderId) {
        return this.trackService.create(transportOrderId);
    }

    @PutMapping("complete")
    @ApiOperation(value = "完成轨迹", notes = " 完成轨迹,修改为完成状态")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "transportOrderIds", value = "运单号列表", required = true)
    })
    public boolean complete(@RequestParam("transportOrderIds") List<String> transportOrderIds) {
        return this.trackService.complete(transportOrderIds);
    }

    /**
     * 通过运单号查询轨迹
     *
     * @param transportOrderId 运单号
     * @return 轨迹数据
     */
    @GetMapping("{transportOrderId}")
    @ApiOperation(value = "查询轨迹", notes = "通过运单号查询轨迹")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "transportOrderId", value = "运单号", required = true)
    })
    public TrackDTO queryByTransportOrderId(@PathVariable("transportOrderId") String transportOrderId) {
        TrackEntity trackEntity = this.trackService.queryByTransportOrderId(transportOrderId);
        return TrackEntityUtil.toDTO(trackEntity);
    }

    @PutMapping("upload/truck")
    @ApiOperation(value = "车辆上报位置", notes = "车辆上报位置")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "transportTaskId", value = "运输任务id", required = true),
            @ApiImplicitParam(name = "lng", value = "经度", required = true),
            @ApiImplicitParam(name = "lat", value = "纬度", required = true),
    })
    public boolean uploadFromTruck(@RequestParam("transportTaskId") Long transportTaskId,
                                   @RequestParam("lng") double lng,
                                   @RequestParam("lat") double lat) {
        return this.trackService.uploadFromTruck(transportTaskId, lng, lat);
    }

    @PutMapping("upload/courier")
    @ApiOperation(value = "快递员上报位置", notes = "快递员上报位置")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "transportOrderIds", value = "运单号列表", required = true),
            @ApiImplicitParam(name = "lng", value = "经度", required = true),
            @ApiImplicitParam(name = "lat", value = "纬度", required = true),
    })
    public boolean uploadFromCourier(@RequestParam("transportOrderIds") List<String> transportOrderIds,
                                     @RequestParam("lng") double lng,
                                     @RequestParam("lat") double lat) {
        return this.trackService.uploadFromCourier(transportOrderIds, lng, lat);
    }

}

service

/**
 * 轨迹服务
 *
 * @author zzj
 * @version 1.0
 */
public interface TrackService {


    /**
     * 创建轨迹,会完成路线规划
     *
     * @param transportOrderId 运单号
     * @return 是否成功
     */
    boolean create(String transportOrderId);

    /**
     * 完成轨迹,修改为完成状态
     *
     * @param transportOrderIds 运单号列表
     * @return 是否成功
     */
    boolean complete(List<String> transportOrderIds);

    /**
     * 通过运单号查询轨迹
     *
     * @param transportOrderId 运单号
     * @return 轨迹数据
     */
    TrackEntity queryByTransportOrderId(String transportOrderId);

    /**
     * 车辆上报位置
     *
     * @param transportTaskId 运输任务id
     * @param lng             经度
     * @param lat             纬度
     * @return 是否成功
     */
    boolean uploadFromTruck(Long transportTaskId, double lng, double lat);

    /**
     * 快递员上报位置
     *
     * @param transportOrderIds 运单号列表
     * @param lng               经度
     * @param lat               纬度
     * @return 是否成功
     */
    boolean uploadFromCourier(List<String> transportOrderIds, double lng, double lat);

}

实现接口

/**
 * TrackServiceImpl 是一个服务实现类,用于处理物流轨迹相关的业务逻辑。
 * 包括创建轨迹、更新状态、路径规划、位置上报等功能。
 */
@Service // Spring 注解,表示这是一个服务层 Bean,可被自动注入使用
public class TrackServiceImpl implements TrackService {

    /**
     * MongoDB 操作模板,用于持久化 TrackEntity 数据
     */
    @Resource
    private MongoTemplate mongoTemplate;

    /**
     * 自定义的地图服务模板(如封装了高德地图 API),用于路径规划等地理操作
     */
    @Resource
    private EagleMapTemplate eagleMapTemplate;

    /**
     * Feign 客户端,用于调用运输订单微服务接口
     */
    @Resource
    private TransportOrderFeign transportOrderFeign;

    /**
     * Feign 客户端,用于调用运输任务微服务接口
     */
    @Resource
    private TransportTaskFeign transportTaskFeign;

    /**
     * Feign 客户端,用于调用订单微服务接口
     */
    @Resource
    private OrderFeign orderFeign;

    /**
     * Feign 客户端,用于调用组织机构微服务接口
     */
    @Resource
    private OrganFeign organFeign;

    /**
     * 创建一个新的物流轨迹记录
     *
     * @param transportOrderId 运单 ID
     * @return 是否创建成功
     */
    @Override
    public boolean create(String transportOrderId) {
        // 构造查询条件:根据 transportOrderId 查询是否已有对应轨迹记录
        Query query = Query.query(Criteria.where("transportOrderId").is(transportOrderId));

        // 从 MongoDB 中查找是否存在该运单的轨迹信息
        TrackEntity trackEntity = mongoTemplate.findOne(query, TrackEntity.class);

        // 如果已经存在轨迹数据,则抛出自定义异常 TRACK_ALREADY_EXISTS
        if (ObjectUtil.isNotEmpty(trackEntity)) {
            throw new SLException(TrackExceptionEnum.TRACK_ALREADY_EXISTS);
        }

        // 创建新的轨迹实体对象
        TrackEntity track = new TrackEntity();
        track.setTransportOrderId(transportOrderId); // 设置运单 ID
        track.setStatus(TrackStatusEnum.NEW); // 设置初始状态为“新建”
        track.setCreated(System.currentTimeMillis()); // 设置创建时间戳
        track.setUpdated(track.getCreated()); // 初始更新时间等于创建时间

        // 调用方法获取计划路线 GeoJSON 线段,并设置到轨迹实体中
        track.setPlanGeoJsonLine(this.queryPlanGeoJsonLineString(transportOrderId, track));

        // 将新创建的轨迹实体保存到 MongoDB
        this.mongoTemplate.save(track);

        // 返回 true 表示创建成功
        return true;
    }

    /**
     * 获取计划路线的 GeoJsonLineString(即路径线)
     *
     * @param transportOrderId 运单 ID
     * @param track            当前轨迹实体(用于设置距离等属性)
     * @return GeoJsonLineString 表示路径线
     */
    private GeoJsonLineString queryPlanGeoJsonLineString(String transportOrderId, TrackEntity track) {
        // 通过 Feign 接口获取运输订单详情
        TransportOrderDTO transportOrderDTO = transportOrderFeign.findById(transportOrderId);

        // 获取运输线路字符串(通常是 JSON 格式的运输节点列表)
        String transportLine = transportOrderDTO.getTransportLine();

        String wayPoints = null;

        // 如果运输线路不为空
        if (StrUtil.isNotEmpty(transportLine)) {
            // 解析成 JSON 对象
            JSONObject transportLineJson = JSONUtil.parseObj(transportLine);

            // 获取节点列表 JSONArray
            JSONArray nodeList = transportLineJson.getJSONArray("nodeList");

            // 遍历每个节点,提取经纬度并格式化为 "lng,lat" 字符串
            List<String> pointList = nodeList.stream()
                    .map(obj -> {
                        JSONObject json = (JSONObject) obj;
                        double longitude = json.getDouble("longitude", 0d);
                        double latitude = json.getDouble("latitude", 0d);

                        // 如果经纬度为 0,标记为错误点
                        if (ObjectUtil.equalsAny(0d, longitude, latitude)) {
                            return "err";
                        }

                        // 正常点则格式化为字符串
                        return StrUtil.format("{},{}", longitude, latitude);
                    })
                    // 过滤掉错误点
                    .filter(o -> ObjectUtil.notEqual(o, "err"))
                    .collect(Collectors.toList());

            // 多个坐标点之间用分号拼接,作为途经点参数
            wayPoints = StrUtil.join(";", pointList);
        } else {
            // 如果没有运输线路信息,则尝试获取当前网点的经纬度作为起点

            OrganDTO organDTO = this.organFeign.queryById(transportOrderDTO.getCurrentAgencyId());
            if (ObjectUtil.isNotEmpty(organDTO)) {
                // 使用网点坐标作为途经点
                wayPoints = StrUtil.format("{},{}", organDTO.getLongitude(), organDTO.getLatitude());
            } else {
                // 理论上不会出现这种情况,如果没有就不设置途经点
            }
        }

        // 获取订单的位置信息(发货地和收货地)
        OrderLocationDTO orderLocationDTO = this.orderFeign.findOrderLocationByOrderId(transportOrderDTO.getOrderId());

        // 格式化发货地和收货地坐标
        CoordinateUtil.Coordinate origin = CoordinateUtil.format(orderLocationDTO.getSendLocation());
        CoordinateUtil.Coordinate destination = CoordinateUtil.format(orderLocationDTO.getReceiveLocation());

        // 构建请求参数 Map
        Map<String, Object> param = MapUtil.<String, Object>builder()
                .put(ObjectUtil.isNotEmpty(wayPoints), "waypoints", wayPoints) // 添加途经点(如果有的话)
                .put("show_fields", "polyline") // 请求返回 polyline 字段
                .build();

        // 调用地图服务,获取驾车路线规划结果
        String driving = this.eagleMapTemplate.opsForDirection()
                .driving(ProviderEnum.AMAP, new Coordinate(origin), new Coordinate(destination), param);

        // 如果返回为空,说明调用失败或无结果
        if (StrUtil.isEmpty(driving)) {
            return null;
        }

        // 解析返回的 JSON 数据
        JSONObject jsonObject = JSONUtil.parseObj(driving);

        // 提取总距离
        Double distance = Convert.toDouble(jsonObject.getByPath("route.paths[0].distance"), -1d);
        track.setDistance(distance); // 设置到轨迹实体中

        // 提取步骤列表
        JSONArray steps = jsonObject.getByPath("route.paths[0].steps", JSONArray.class);

        // 收集所有坐标点
        List<Point> points = new ArrayList<>();

        // 获取所有 polyline 字段值(每一步的坐标点集合)
        List<Object> polyLines = CollUtil.getFieldValues(steps, "polyline");

        for (Object polyLine : polyLines) {
            // 将 polyline 字符串拆分成多个坐标点
            List<GeoJsonPoint> list = StrUtil.split(Convert.toStr(polyLine), ';')
                    .stream().map(coordinateStr -> {
                        // 拆分为 lng 和 lat
                        double[] ds = Convert.convert(double[].class, StrUtil.splitTrim(coordinateStr, ','));
                        return new GeoJsonPoint(ds[0], ds[1]);
                    }).collect(Collectors.toList());

            // 添加到总坐标点列表中
            points.addAll(list);
        }

        // 返回构造好的 GeoJsonLineString(代表整条路径线)
        return new GeoJsonLineString(points);
    }

    /**
     * 批量完成轨迹记录(更新状态为 COMPLETE)
     *
     * @param transportOrderIds 运单 ID 列表
     * @return 是否有记录被修改
     */
    @Override
    public boolean complete(List<String> transportOrderIds) {
        // 构造查询条件:匹配 transportOrderId 在传入列表中的记录,且状态为 NEW
        Query query = Query.query(Criteria.where("transportOrderId").in(transportOrderIds));

        // 构造更新语句:将 status 更新为 COMPLETE
        Update update = Update.update("status", TrackStatusEnum.COMPLETE);

        // 执行批量更新
        UpdateResult updateResult = this.mongoTemplate.updateMulti(query, update, TrackEntity.class);

        // 如果修改了至少一条记录,返回 true
        return updateResult.getModifiedCount() > 0;
    }

    /**
     * 根据运单 ID 查询轨迹实体
     *
     * @param transportOrderId 运单 ID
     * @return 查询到的 TrackEntity 实体对象 或 null
     */
    @Override
    public TrackEntity queryByTransportOrderId(String transportOrderId) {
        // 构造查询条件:按 transportOrderId 查询
        Query query = Query.query(Criteria.where("transportOrderId").is(transportOrderId));

        // 查询唯一匹配的记录
        return this.mongoTemplate.findOne(query, TrackEntity.class);
    }

    /**
     * 司机端上报当前位置
     *
     * @param transportTaskId 运输任务 ID
     * @param lng             经度
     * @param lat             纬度
     * @return 是否上报成功
     */
    @Override
    public boolean uploadFromTruck(Long transportTaskId, double lng, double lat) {
        // 根据运输任务 ID 查询对应的运单 ID 列表
        List<String> list = this.transportTaskFeign.queryTransportOrderIdListById(transportTaskId);

        // 调用通用上传方法,类型为 DRIVER
        return upload(list, lng, lat, TrackTypeEnum.DRIVER);
    }

    /**
     * 快递员端上报当前位置
     *
     * @param transportOrderIds 运单 ID 列表
     * @param lng               经度
     * @param lat               纬度
     * @return 是否上报成功
     */
    @Override
    public boolean uploadFromCourier(List<String> transportOrderIds, double lng, double lat) {
        // 直接调用通用上传方法,类型为 COURIER
        return upload(transportOrderIds, lng, lat, TrackTypeEnum.COURIER);
    }

    /**
     * 通用位置上报逻辑
     *
     * @param transportOrderIds 运单 ID 列表
     * @param lng               经度
     * @param lat               纬度
     * @param trackTypeEnum     上报类型(DRIVER/COURIER)
     * @return 是否更新成功
     */
    private boolean upload(List<String> transportOrderIds, double lng, double lat, TrackTypeEnum trackTypeEnum) {
        // 如果运单列表为空,直接返回 false
        if (CollUtil.isEmpty(transportOrderIds)) {
            return false;
        }

        // 构造查询条件:transportOrderId 在列表中,且状态为 NEW
        Query query = Query.query(Criteria.where("transportOrderId")
                .in(transportOrderIds)
                .and("status").is(TrackStatusEnum.NEW));

        // 构造更新内容:更新 lastPoint(最新位置)、type(轨迹类型)、updated(更新时间)
        Update update = Update.update("lastPoint", new GeoJsonPoint(lng, lat))
                .set("type", trackTypeEnum)
                .set("updated", System.currentTimeMillis());

        // 执行批量更新
        UpdateResult updateResult = this.mongoTemplate.updateMulti(query, update, TrackEntity.class);

        // 返回是否成功更新(是否有记录被修改)
        return updateResult.getModifiedCount() > 0;
    }
}

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

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

相关文章

【数据库】关系数据理论--规范化

1.问题的提出 关系模式由五部分组成&#xff0c;是一个五元组&#xff1a; R(U, D, DOM, F) &#xff08;1&#xff09;关系名R是符号化的元组语义 &#xff08;2&#xff09;U为一组属性 &#xff08;3&#xff09;D为属性组U中的属性所来自的域 &#xff08;4&#xff09;DOM…

Oracle双平面适用场景讨论会议

4月28日&#xff0c;我在杭州组织召开了Oracle双平面会议讨论沙龙。在国产化数据库浪潮的今天&#xff0c;Oracle数据库作为国产数据库的应急库&#xff0c;在国产数据库发生故障或者性能下降时&#xff0c;如何更好的使用Oracle。会议主题如下&#xff1a; 1、背景与痛点速览&…

使用BERT/BiLSTM + CRF 模型进行NER进展记录~

使用代码处理数据集&#xff0c;发现了一些问题&#xff0c;以及解决办法~ 下载了一组数据集&#xff0c;数据存放在CSV中&#xff0c;GBK格式。如下&#xff1a; 首先对每一列直接进行NER抽取&#xff0c;结果非常不好&#xff1a; 几乎是乱抽取的&#xff0c;解决办法是自己创…

Web攻防-SQL注入高权限判定跨库查询文件读写DNS带外SecurePriv开关绕过

知识点&#xff1a; 1、Web攻防-SQL注入-高权限用户差异 2、Web攻防-SQL注入-跨库注入&文件读写&DNS带外 案例说明&#xff1a; 在应用中&#xff0c;数据库用户不同&#xff0c;可操作的数据库和文件读写权限不一&#xff0c;所有在注入过程中可以有更多的利用思路&a…

C语言数据结构笔记3:Union联合体+结构体取8位Bool量

本文衔接上文要求&#xff0c;新增8位bool量的获取方式。 目录 问题提出&#xff1a; Union联合体struct结构体(方式1)&#xff1a; Union联合体struct结构体(方式2)&#xff1a; BYTE方式读取&#xff1a; 问题提出&#xff1a; 在STM32单片机的编程中&#xff0c;无法定义Boo…

SAP学习笔记 - 开发22 - 前端Fiori开发 数据绑定(Jason),Data Types(数据类型)

上一章讲了Icons&#xff08;图标&#xff09;&#xff0c;Icon Explorer。 SAP学习笔记 - 开发21 - 前端Fiori开发 Icons&#xff08;图标&#xff09;&#xff0c;Icon Explorer&#xff08;图标浏览器&#xff09;-CSDN博客 本章继续讲SAP Fiori开发的知识。 目录 1&…

网络编程之TCP编程

基于 C/S &#xff1a;客户端&#xff08;client&#xff09;/服务器端&#xff08;server&#xff09; 1.流程 2. 函数接口 所有函数所需头文件&#xff1a; #include <sys/types.h> #include <sys/socket.h> 系统定义好了用来存储网络信息的结构体 ipv4通信使…

C++进阶--C++11(04)

文章目录 C进阶--C11&#xff08;04&#xff09;lambdalambda表达式语法捕捉列表lambda的应用lambda的原理 包装器functionbind 总结结语 很高兴和大家见面&#xff0c;给生活加点impetus&#xff01;&#xff01;开启今天的编程之路&#xff01;&#xff01; 今天我们进一步c…

当AI遇上防火墙:新一代智能安全解决方案全景解析

在2025年网络安全攻防升级的背景下&#xff0c;AI与防火墙的融合正重塑安全防御体系。以下三款产品通过机器学习、行为分析等技术创新&#xff0c;为企业提供智能化主动防护&#xff1a; 1. 保旺达数据安全管控平台——AI驱动的动态治理引擎‌ 智能分类分级‌&#xff1a;基于…

Spring MVC参数绑定终极手册:单多参/对象/集合/JSON/文件上传精讲

我们通过浏览器访问不同的路径&#xff0c;就是在发送不同的请求&#xff0c;在发送请求时&#xff0c;可能会带一些参数&#xff0c;本文将介绍了Spring MVC中处理不同请求参数的多种方式 一、传递单个参数 接收单个参数&#xff0c;在Spring MVC中直接用方法中的参数就可以&…

Fluence推出“Pointless计划”:五种方式参与RWA算力资产新时代

2025年6月1日&#xff0c;去中心化算力平台 Fluence 正式宣布启动“Pointless 计划”——这是其《Fluence Vision 2026》战略中四项核心举措之一&#xff0c;旨在通过贡献驱动的积分体系&#xff0c;激励更广泛的社区参与&#xff0c;为用户带来现实世界资产&#xff08;RWA&am…

innovus: ecoAddRepeater改变hier层级解决办法

我正在「拾陆楼」和朋友们讨论有趣的话题&#xff0c;你⼀起来吧&#xff1f; 拾陆楼知识星球入口 来自星球提问: 星主&#xff0c;我在A/B/C/D/E/U0这个cell后面插入一个BUFF&#xff0c;生成的名字为A/B/C/BUFF1&#xff0c;少了D/E两个层级&#xff0c;不应该是生成A/B/C/…

华为OD机试真题——硬件产品销售方案(2025A卷:100分)Java/python/JavaScript/C++/C语言/GO六种最佳实现

2025 A卷 100分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析; 并提供Java、python、JavaScript、C++、C语言、GO六种语言的最佳实现方式! 2025华为OD真题目录+全流程解析/备考攻略/经验分享 华为OD机试真题《硬件产品销售方案》: 目录…

传统业务对接AI-AI编程框架-Rasa的业务应用实战(1)--项目背景即学习初衷

我的初衷&#xff1a;我想学习AI。具体的方向是这样的&#xff1a;原本传统的平台业务去对接智能体。比如发票业务&#xff0c;发票的开具、审核、计税、回款等。根据用户在业务系统前台界面输入若干提示词 或者 语音输入简短语音信息&#xff0c;可以通过智能体给出需要处理的…

低功耗架构突破:STM32H750 与 SD NAND (存储芯片)如何延长手环续航至 14 天

低功耗架构突破&#xff1a;STM32H750 与 SD NAND &#xff08;存储芯片&#xff09;如何延长手环续航至 14 天 卓越性能强化安全高效能效图形处理优势丰富集成特性 模拟模块实时监控保障数据完整性提升安全性与可靠性测量原理采样率相关结束语 在智能皮电手环及数据存储技术不…

Linux(11)——基础IO(上)

目录 一、理解文件 二、回顾C文件的接口 &#x1f4c4; C语言文件操作函数表 ​编辑&#x1f4c4; 三个文件流 三、系统文件I/O 1️⃣open 2️⃣close 3️⃣write 4️⃣read 四、文件描述符 &#x1f4a1;用户操作文件的底层逻辑是什么&#xff1f; &#x1f4…

ABP-Book Store Application中文讲解 - Part 9: Authors: User Interface

ABP-Book Store Application中文讲解 - Part 9: Authors: User Interface TBD 1. 汇总 ABP-Book Store Application中文讲解-汇总-CSDN博客 2. 前一章 ABP-Book Store Application中文讲解 - Part 8: Authors: Application Layer-CSDN博客 项目之间的引用关系。 ​​ 目…

Hive自定义函数案例(UDF、UDAF、UDTF)

目录 前提条件 背景 概念及适用场景 UDF&#xff08;User-Defined Function&#xff09; 概念 适用场景 UDAF&#xff08;User-Defined Aggregate Function&#xff09; 概念 适用场景 UDTF&#xff08;User-Defined Table-Generating Function&#xff09; 概念 适…

【学习笔记】Circuit Tracing: Revealing Computational Graphs in Language Models

Circuit Tracing: Revealing Computational Graphs in Language Models 替代模型(Replacement Model)&#xff1a;用更多的可解释的特征来替代transformer模型的神经元。 归因图(Attribution Graph)&#xff1a;展示特征之间的相互影响&#xff0c;能够追踪模型生成输出时所采用…

STM32标准库-TIM定时器

文章目录 一、TIM定时器1.1定时器1.2定时器类型1.1.1 高级定时器1.1.2通用定时器1.1.3基本定时器 二、定时中断基本结构预分频器时器计时器时序计数器无预装时序计数器有预装时序RCC时钟树 三、定时器定时中断3.1 接线图3.2代码3.3效果&#xff1a; 四、定时器外部中断4.1接线图…