Spring Boot 学习记录笔记【 三 】

Spring Boot中统一记录请求、响应及异常日志的方法 通过自定义可以同时记录请求和响应日志。if (!try {// 可以添加更多信息注册DispatcherServlet:在配置类中注册自定义的。@Bean。 阅读详情

Spring Boot 学习记录笔记【 三 】

封装入参和出参

封装入参和出参,目的是因为我们的实体类,存放的字段有些是我们不需要返回或者返回的字段实体类里面并没有,这个时候我们就需要进行删除和添加,如果我们单独封装入参和出参就能解决,当然也有别的办法进行解决,还是因人而异,只为记录。觉得有用就点个赞吧!!!

  1. 首先封装了一个统一的返回公用类,格式统一,方便前后端调试。
package com.zcf.monitor.resp;

/**
 * 通用返回类
 * @param <T>
 */
public class CommonResp<T> {

    /**
     * 业务上的成功或失败
     */
    private boolean success = true;

    /**
     * 返回信息
     */
    private String message;

    /**
     * 返回泛型数据,自定义类型
     */
    private T content;

    public boolean getSuccess() {
        return success;
    }

    public void setSuccess(boolean success) {
        this.success = success;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public T getContent() {
        return content;
    }

    public void setContent(T content) {
        this.content = content;
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("ResponseDto{");
        sb.append("success=").append(success);
        sb.append(", message='").append(message).append('\'');
        sb.append(", content=").append(content);
        sb.append('}');
        return sb.toString();
    }

}

修改前
在这里插入图片描述
在这里插入图片描述
修改后
在这里插入图片描述
在这里插入图片描述
可以看出来,修改前返回的是List,修改后返回的是CommonResp返回类,里面包含了返回状态success,返回信息内容message 可以带上一句话,返回content 里面包含了List,这个content 是一个泛型数据,可以自定义类型。

  1. 我定义了一个TestResp类
    在这里插入图片描述
    从这一次的返回结果和上面的返回结果进行对比,我们可以看出,Test表里面password字段并没有返回,这就是我在定义TestResp类的时候,没有添加password字段。
package com.zcf.monitor.resp.query;

import java.util.StringJoiner;

public class TestResp {
    private Long id;

    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return new StringJoiner(", ", TestResp.class.getSimpleName() + "[", "]")
                .add("id=" + id)
                .add("name='" + name + "'")
                .toString();
    }
}

在这里插入图片描述
在这里插入图片描述
可以看出,把返回的List 转换成List ,我们可以在返回的 TestResp 类里面根据实际需要添加和删除我们需要的字段。注意:TestResp 类 和 Test 类 可以一样,也可以不一样。出参就是这样,那入参也是同样的道理。

package com.zcf.monitor.req.save;

import java.util.StringJoiner;

public class TestReq {
    private Long id;

    private String name;

    private String password;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return new StringJoiner(", ", TestReq.class.getSimpleName() + "[", "]")
                .add("id=" + id)
                .add("name='" + name + "'")
                .add("password='" + password + "'")
                .toString();
    }
}

在这里插入图片描述
在这里插入图片描述

分页

在这里插入图片描述
看这个请求就是查询第1页,每页3条数据,返回结果就是总条数12条,展示3条数据。这就是分页的效果。由此,修改了查询代码,添加了分页进来。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
从SQL日志可以看出,分页查询一共执行了两条sql,第一条是查询了一共有多少条数据,第二条是查询了第1页,每页3条的数据。
里面用到了TestQueryReq 类、PageResp 类,我们来看一下。

package com.zcf.monitor.req.query;

import com.zcf.monitor.req.PageReq;

import java.util.StringJoiner;

public class TestQueryReq extends PageReq {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return new StringJoiner(", ", TestQueryReq.class.getSimpleName() + "[", "]")
                .add("name='" + name + "'")
                .toString();
    }
}

TestQueryReq 类主要是查询使用,可以看出,我的查询条件是name,分页主要用到是继承的PageReq 类

package com.zcf.monitor.req;

import javax.validation.constraints.Max;
import javax.validation.constraints.NotNull;

/**
 * 分页
 */
public class PageReq {

    @NotNull(message = "【页码】不能为空")
    private int page;

    @NotNull(message = "【每页条数】不能为空")
    @Max(value = 1000,message = "【每页条数】不能超过1000")
    private int size;

    public int getPage() {
        return page;
    }

    public void setPage(int page) {
        this.page = page;
    }

    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
    }

    @Override
    public String toString() {
        return "PageReq{" +
                "page=" + page +
                ", size=" + size +
                '}';
    }

}

PageReq 类就是作为分页的入参类,page表示当前页,size表示每页条数。此类一般都作为公用的父类,被其他类所继承使用。

package com.zcf.monitor.resp;

import java.util.List;

/**
 * 分页返回
 * @param <T>
 */
public class PageResp<T> {

    private long total;

    private List<T> list;

    public long getTotal() {
        return total;
    }

    public void setTotal(long total) {
        this.total = total;
    }

    public List<T> getList() {
        return list;
    }

    public void setList(List<T> list) {
        this.list = list;
    }

    @Override
    public String toString() {
        return "PageResp{" +
                "total=" + total +
                ", list=" + list +
                '}';
    }
}

PageResp 类是作为分页返回数据的一个类,一般是只返回总条数和分页的List数据,因为这个类可能会被很多List<实体类>使用,用到了 T 作为泛型使用。

工具类

之前新增的时候使用到一个snowFlake.nextId(),这是一个雪花算法的工具类,可以生成一组18位的雪花ID。

package com.zcf.monitor.utils;

import org.springframework.stereotype.Component;
import java.text.ParseException;

/**
 * Twitter的分布式自增ID雪花算法
 **/
@Component
public class SnowFlake {

    /**
     * 起始的时间戳
     */
    private final static long START_STMP = 1609459200000L; // 2021-01-01 00:00:00

    /**
     * 每一部分占用的位数
     */
    private final static long SEQUENCE_BIT = 12; //序列号占用的位数
    private final static long MACHINE_BIT = 5;   //机器标识占用的位数
    private final static long DATACENTER_BIT = 5;//数据中心占用的位数

    /**
     * 每一部分的最大值
     */
    private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT);
    private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);
    private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);

    /**
     * 每一部分向左的位移
     */
    private final static long MACHINE_LEFT = SEQUENCE_BIT;
    private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
    private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;

    private long datacenterId = 1;  //数据中心
    private long machineId = 1;     //机器标识
    private long sequence = 0L; //序列号
    private long lastStmp = -1L;//上一次时间戳

    public SnowFlake() {
    }

    public SnowFlake(long datacenterId, long machineId) {
        if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {
            throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0");
        }
        if (machineId > MAX_MACHINE_NUM || machineId < 0) {
            throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");
        }
        this.datacenterId = datacenterId;
        this.machineId = machineId;
    }

    /**
     * 产生下一个ID
     *
     * @return
     */
    public synchronized long nextId() {
        long currStmp = getNewstmp();
        if (currStmp < lastStmp) {
            throw new RuntimeException("Clock moved backwards.  Refusing to generate id");
        }

        if (currStmp == lastStmp) {
            //相同毫秒内,序列号自增
            sequence = (sequence + 1) & MAX_SEQUENCE;
            //同一毫秒的序列数已经达到最大
            if (sequence == 0L) {
                currStmp = getNextMill();
            }
        } else {
            //不同毫秒内,序列号置为0
            sequence = 0L;
        }

        lastStmp = currStmp;

        return (currStmp - START_STMP) << TIMESTMP_LEFT //时间戳部分
                | datacenterId << DATACENTER_LEFT       //数据中心部分
                | machineId << MACHINE_LEFT             //机器标识部分
                | sequence;                             //序列号部分
    }

    private long getNextMill() {
        long mill = getNewstmp();
        while (mill <= lastStmp) {
            mill = getNewstmp();
        }
        return mill;
    }

    private long getNewstmp() {
        return System.currentTimeMillis();
    }
    
}

CopyUtil 类是一个复制的工具类,当然也可以使用for循环替代。里面包含了单体复制和列表复制,简化了我们的代码编写。

package com.zcf.monitor.utils;

import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * 复制工具类
 */
public class CopyUtil {

    /**
     * 单体复制
     */
    public static <T> T copy(Object source, Class<T> clazz) {
        if (source == null) {
            return null;
        }
        T obj = null;
        try {
            obj = clazz.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        BeanUtils.copyProperties(source, obj);
        return obj;
    }

    /**
     * 列表复制
     */
    public static <T> List<T> copyList(List source, Class<T> clazz) {
        List<T> target = new ArrayList<>();
        if (!CollectionUtils.isEmpty(source)){
            for (Object c: source) {
                T obj = copy(c, clazz);
                target.add(obj);
            }
        }
        return target;
    }

}

SpringBootAOP的使用

配置AOP,我们在之前pom.xml 添加了AOP的依赖。打印接口耗时、请求参数、返回参数

package com.zcf.monitor.aspect;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.support.spring.PropertyPreFilters;
import com.zcf.monitor.utils.RequestContext;
import com.zcf.monitor.utils.SnowFlake;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

@Aspect //切面
@Component
public class LogAspect {

    private final static Logger LOG = LoggerFactory.getLogger(LogAspect.class);

    @Resource
    private SnowFlake snowFlake;

    /** 定义一个切点 */
    @Pointcut("execution(public * com.zcf.*.controller..*Controller.*(..))")
    public void controllerPointcut() {}

    //前置通知
    @Before("controllerPointcut()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {

        // 增加日志流水号
        MDC.put("LOG_ID", String.valueOf(snowFlake.nextId()));

        // 开始打印请求日志
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        Signature signature = joinPoint.getSignature();
        String name = signature.getName();

        // 打印请求信息
        LOG.info("------------- 开始 -------------");
        LOG.info("请求地址: {} {}", request.getRequestURL().toString(), request.getMethod());
        LOG.info("类名方法: {}.{}", signature.getDeclaringTypeName(), name);
        LOG.info("远程地址: {}", request.getRemoteAddr());

        RequestContext.setRemoteAddr(getRemoteIp(request));

        // 打印请求参数
        Object[] args = joinPoint.getArgs();
        // LOG.info("请求参数: {}", JSONObject.toJSONString(args));

        Object[] arguments  = new Object[args.length];
        for (int i = 0; i < args.length; i++) {
            if (args[i] instanceof ServletRequest
                    || args[i] instanceof ServletResponse
                    || args[i] instanceof MultipartFile) {
                continue;
            }
            arguments[i] = args[i];
        }
        // 排除字段,敏感字段或太长的字段不显示
        String[] excludeProperties = {"password", "file"};
        PropertyPreFilters filters = new PropertyPreFilters();
        PropertyPreFilters.MySimplePropertyPreFilter excludefilter = filters.addFilter();
        excludefilter.addExcludes(excludeProperties);
        LOG.info("请求参数: {}", JSONObject.toJSONString(arguments, excludefilter));
    }

    // 环绕通知
    @Around("controllerPointcut()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = proceedingJoinPoint.proceed();
        // 排除字段,敏感字段或太长的字段不显示
        String[] excludeProperties = {"password", "file"};
        PropertyPreFilters filters = new PropertyPreFilters();
        PropertyPreFilters.MySimplePropertyPreFilter excludefilter = filters.addFilter();
        excludefilter.addExcludes(excludeProperties);
        LOG.info("返回结果: {}", JSONObject.toJSONString(result, excludefilter));
        LOG.info("------------- 结束 耗时:{} ms -------------", System.currentTimeMillis() - startTime);
        return result;
    }
    
}

在这里插入图片描述
在这里插入图片描述
从上面两个控制台的显示看出来,打印出请求地址,类名方法,远程地址,请求参数,以及执行一条分页查询,耗时时间。使用MDC.put,可以为logback增加自定义参数,绿色的是日志流水号,为今后查找报错能快速定位。

结尾

到这里,Spring Boot 项目封装了入参和出参,添加了分页,工具类,还继承了SpringBootAOP的使用,文章是记录自己的学习笔记,或多或少都有问题和遗漏,欢迎留言,一起进步。继续更新Spring Boot 学习记录笔记【 四 】

Spring Boot学习记录(一):Spring Boot 基础 SpringBoot是一个简化Spring应用开发的框架,提供了快速创建独立项目、嵌入式服务器、自动配置等特性。本文介绍了开发环境准备(JDK17+、Maven3.3+、IDEA)、创建第一个SpringBoot应用的完整流程(包括Maven配置、控制器编写、接口测试),重点解析了核心机制,还演示了项目打包部署方法,并指导使用Spring Initializer快速初始化项目结构。文中包含具体代码示例和配置说明,适合SpringBoot初学者快速入门。 阅读详情

相关推荐

Spring Boot 学习之路 -- 基础认知

Spring Boot 是在 Spring 的基础上发展而来的全新的开源框架。它是由 Pivotal 团队开发的。开发 Spring Boot 的主要动机是简化部署 Spring 应用程序的配置过程。也就是说,使用 Spring Boot 能够以更简单的、更灵活的方式开发 Spring 应用程序。▪️ Spring Boot 的代码非常少。Spring 的注解驱动编程避免了大量的配置工作,并且 Spring Boot 可以自动创建各种工厂类,程序开发人员直接通过依赖注入就可以获取各类对象。

Fucking Android & Compose & Harmony & Spring Boot ... 1650

Spring Boot学习笔记(知识点总结)

Spring Boot是一个基于Spring框架的全新项目,旨在帮助开发者更轻松地创建基于Spring的应用程序。它简化了Spring应用程序的初始化和开发过程,使得开发者能够更快速地构建独立、生产级别的应用程序。Spring Boot通过提供默认配置和一系列快捷特性,如自动配置、起步依赖、内置Web服务器等,来降低项目搭建的复杂性。同时,它还集成了大量常用的第三方库配置,使得这些库在Spring Boot应用中几乎可以零配置地开箱即用。

m0_55810383的博客 1408

Spring全家桶笔记:Spring+Spring Boot+Spring Cloud+Spring MVC

最近小编整理了一下一线架构师的Spring全家桶笔记:Spring+Spring Boot+Spring Cloud+Spring MVC,分享给大家一起学习一下~ 注意:有需要免费领取一线架构师的Spring全家桶笔记的朋友,可以点击【学习】免费领取,不要错过哦~ 01 Spring Spring是一个轻量级控制反转(IoC)和面向切面(AOP)的容器框架。Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而,S...

ITjianshuzhai的博客 834

SpringBoot学习笔记整理

SpringBoot学习笔记整理

weixin_56380175的博客 457

Spring Boot系列十三 Spring Boot集成RabbitMQ

1. 概述之前我有一系列关于RabbitMQ文章介绍了RabbitMQ的用法,本篇我们介绍如何在Spring Boot中集成RabbitMQ。本篇主要内容如下: 在Spring boot中消息的发送和接收的两种方式的demo 配置使用MessageConverter对消息序列化 2. Demo工程公共部分介绍工程名称:rabbitmq需要在我们的工程中的pom.xml引入新jar <!-- spri

不积跬步无以至千里; 不积小流无以成江海 1万+

Java Spring Boot 全面学习指南

通过系统学习官方文档、经典书籍与实战课程,结合开源项目实践,能够快速掌握 Spring Boot 的核心能力。

记录点滴 1928

springBoot学习笔记(完结)

Spring是为了解决企业级应用开发的复杂性而创建的,简化开发。为了降低Java开发的复杂性,Spring采用了以下4种关键策略:1、基于POJO的轻量级和最小侵入性编程,所有东西都是bean;2、通过IOC,依赖注入(DI)和面向接口实现松耦合;3、基于切面(AOP)和惯例进行声明式编程;4、通过切面和模版减少样式代码,RedisTemplate,xxxTemplate;什么是SpringBoot呢,就是一个javaweb的开发框架,和SpringMVC类似,对比其他javaweb框架的好处,官方说是简化

weixin_52798101的博客 4526

学习Spring Boot,应该从哪里开始学起

学习Spring Boot,应该从哪里开始学起记住,学习是一个持续的过程,不要害怕遇到困难和挑战。通过不断的实践和探索,你会逐渐掌握Spring Boot的精髓。

cesske的博客 1757

SpringBoot学习日记

SpringBoot学习日记

yushuzuishuai的博客 455

Spring Boot基础学习笔记01:Spring Boot入门程序

1. 了解Spring Boot框架的优点; 2. 掌握使用Maven方式构建Spring Boot项目; 3. 掌握使用Spring Initializr方式构建Spring Boot项目

howard2005的专栏 2087

2020年Spring学习笔记目录

一、Spring框架 Spring框架学习笔记01:初探Spring——采用Spring配置文件管理Bean Spring框架学习笔记02:初探Spring——利用组件注解符精简Spring配置文件 Spring框架学习笔记03:初探Spring——利用注解配置类取代Spring配置文件 Spring框架学习笔记04:初探Spring——采用Java配置类管理Bean Spring框架学习笔记05:Spring AOP基础 Spring框架学习笔记06:Spring JdbcTemplate入门 Spri

howard2005的专栏 4170

学习记录十六 ---- spring boot

springboot学习

young_man2的博客 237

Windows版本Carla(含RoadRunner插件)源码安装+RoadRunner地图导入

通过跳转浏览器账号密码登录github,不要选择Fine-grained personal access tokens,在git clone时会显示非授权,也不要使用Windows凭据!核心指令:编译PythonAPI–make PythonAPI,,编译Server–make launch,封装”游戏“–make package。完成安装后,在已安装->2022版本右侧->更多->导入配置,选择配置文件(需将配置文件内容更新为手册内容,如下图)->详细信息,更新。不要修改版本,执行上面指令即可!

winnizap的博客 1467

Spring boot学习记录

需求:使用Spring boot开发一个web应用,浏览器发起请求 /hello 后,给浏览器返回字符串 “hello world”。浏览器中输入:http://localhost:8080/hello创建一个请求处理类:HelloController浏览器中访问。

lu2925028830的博客 945

PIC单片机应用开发实践教程(二): 新建工程

File---New ProjectMicrochip Embedded --- Standalone Project 选择所用MCU对应型号 点击 Finish 后,工程就建好了 至止,我们的一个新工程就建完成了!

qq_57798018的博客 2889

手把手教你搭建离线语音助手:FunASR+DeepSeek+TTS保姆级教程

本文详细介绍了如何利用FunASR、DeepSeek和TTS技术搭建离线语音助手系统。从环境配置、模型部署到唤醒词检测优化、语音识别与语义理解联调,再到语音合成与系统集成,提供全链路实战教程。特别适合智能家居控制、企业内部知识问答等需要数据隔离的场景,实现高响应、低延迟的离线语音交互体验。

weixin_30316097的博客 476

Spring-Boot学习笔记

这个笔记是在自己学习的过程中根据实际用到的和学到的整理出来的,可能会有缺失,错误等,主要是给激励自己学习,遇到写不下去的情况给自己一个参考,请各位大佬发现问题提出问题时能嘴下留情,也希望多提建议,谢谢。本笔记长期更新(更新日期2024年9月21日)

2403_86693263的博客 4538

STM32CubeMX HAL实战:JY901S串口数据解析与姿态解算

本文详细介绍了如何使用STM32CubeMX HAL库实现JY901S六轴姿态传感器的串口数据解析与姿态解算。从基础硬件连接到USART3配置,再到数据接收状态机实现和传感器校准方法,最后深入讲解互补滤波与Mahony滤波算法在姿态解算中的应用。通过实战代码演示,帮助开发者快速掌握无人机、机器人等项目中关键姿态数据处理技术。

weixin_28703489的博客 432

Spring Boot实战学习笔记(三)

本文为学习Spring Boot实战的学习笔记,学习了一遍,但是好记性不如烂笔头,所以文章记录下来。图书购买地址为: https://item.jd.com/11894632.html.Spring Boot实战学习笔记1Spring Boot实战学习笔记2Spring Boot实战学习笔记3Spring Boot实战学习笔记4Spring Boot实战学习笔记51.Spring 基础2.Spri...

殘遛的博客 1005

使用VS Code创建第一个Flutter工程

你可以使用任意文本编辑器结合命令行工具来开发Flutter应用。然而,我们推荐使用本文介绍的编辑器插件以获取更好的开发体验。这些插件提供了代码补全、代码高亮、widget辅助编辑等功能,以及为项目的运行和调试提供支持。推荐的开发工具有VS Code、Android Studio、IntelliJ。本文将重点介绍如何使用VS Code进行Flutter应用开发。

2501_91373349的博客 2129

Windows系统下AutoDock 4.2.6安装避坑指南(附MGLTools配置技巧)

本文详细介绍了在Windows系统下安装和配置AutoDock 4.2.6的完整流程,特别针对分子对接研究中常见的软件安装问题提供了解决方案。从环境准备、分步安装到常见报错处理,涵盖MGLTools配置技巧、工作目录设置和环境变量优化,帮助科研人员快速搭建稳定的分子对接平台。

weixin_29234239的博客 313

Spring Boot 学习笔记

Spring Boot 是由 Pivotal 团队开发的开源 Java 基础框架,用于简化 Spring 应用的开发过程。通过 Spring Boot,开发者可以轻松创建独立、生产级的 Spring 应用,而无需繁琐的配置和部署步骤。Spring Boot 内嵌了 Tomcat、Jetty 等主流 Web 容器,支持自动配置和依赖管理,极大地提高了开发效率。Spring Boot 是一个功能强大且易于使用的框架,通过简化配置和依赖管理,极大地提高了开发效率。

m0_72686196的博客 1051

【深度学习新浪潮】OpenClaw跟机器人行业有哪些很好的研究结合点?

OpenClaw正通过"AI大脑+机器人肢体"的深度融合,重新定义机器人与人类的交互方式和自主操作能力。近期ROSClaw框架发布、人形机器人集成和空间计算试验等进展,标志着OpenClaw已从概念验证阶段进入实际应用落地期,为机器人行业带来了自然语言控制普及化具身智能平民化和跨平台开发标准化三大变革机遇。

专注:太空算力、AI infra、异构调度、大模型成本工程 229

JAVA 后端(Spring Boot)开发学习笔记记录

spring boot 多模块开发学习笔记

m0_62454335的博客 1134

【Halcon-1D测量】measure_pairs 函数功能(用于提取垂直于矩形/环形弧主轴的直边对)

HALCON算子measure_pairs是1D测量模块的基础工具,专用于提取垂直于矩形/环形弧主轴的直边对。该算子通过振幅阈值和灰度过渡规则(如positive/negative)进行边对分组,支持_strongest后缀选择最强边缘避免误配对。输出包含边缘坐标、振幅及内外间距(IntraDistance/InterDistance)。关键限制包括仅适用于直边、Sigma需≤0.5×测量长度,且忽略图像域。相比模糊版本算子,它更适用于边缘清晰的简单场景(如电子元件间距测量)。典型应用需配合gen_meas

weixin_45590420的博客 305

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

上一篇: Spring Boot 学习记录笔记【 二 】
下一篇: 如何查询网络出口IP
perfei焓
博客等级 码龄8年 32粉丝 28原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值