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

网页五子棋——通用模块

目录

项目创建

通用功能模块

错误码

自定义异常类

CommonResult

jackson

加密工具


项目创建

使用 idea 创建 SpringBoot 项目,并引入相关依赖:

配置 MyBatis:

编辑 application.yml

spring:datasource: # 数据库连接配置url: jdbc:mysql://127.0.0.1:3306/gobang_system?characterEncoding=utf8&useSSL=falseusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driver
mybatis: # mybatis 配置configuration:map-underscore-to-camel-case: true #配置驼峰自动转换log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #打印sql语句

通用功能模块

通用功能模块 是在软件开发中,创建的一组通用的功能模块,以便在不同的应用场景中重用,从而提高开发效率、降低重复开发工作量,并确保系统的一致性与可维护性。通用功能模块通常具有高度的复用性,能够服务于多个系统或应用

这部分模块通常存放在项目中的 common 包下

错误码

错误码主要用于标识和处理程序运行中的各种异常情况,能够精确的指出问题所在

错误码的作用有:

明确标识错误:错误码提供了一种明确的方式来表示错误的状态,能够精确的指出问题所在

简化问题排查:通过错误码,我们可以快速的定位问题。在系统日志中会包含大量的信息,而错误码作为一种统一的标识符,可以帮助我们在日志中迅速查找特定的错误类型,提高排查效率

错误处理:客户端可以根据错误码进行特定的错误处理,而不是依赖通用的异常处理

易于维护:集中管理错误码使得它们更容易维护和更新。如,业务逻辑变化,只需要更新错误码的定义,而不需要修改每个使用它们的地方。在接口文档中,错误码也可以清晰的列出所有的错误情况,使开发者更容易立即和使用接口

调试和测试:错误码可用于自动化测试,确保特定的错误情况被正确处理

错误分类:错误码可以将错误分类为不同级别或不同类型,如 客户端错误、服务器错误、业务逻辑错误等

创建 errorcode 包:

定义错误码类型

@Data
public class ErrorCode {/*** 错误码*/private final Integer code;/*** 错误描述信息*/private final String message;public ErrorCode(Integer code, String message) {this.code = code;this.message = message;}
}

定义全局错误码

public interface GlobalErrorCodeConstants {// 成功ErrorCode SUCCESS = new ErrorCode(200, "成功");// 服务端错误ErrorCode INTERNAL_SERVER_ERROR = new ErrorCode(500, "系统异常");ErrorCode NOT_IMPLEMENTED = new ErrorCode(501, "功能未实现/未开启");ErrorCode ERROR_CONFIGURATION = new ErrorCode(502, "配置项错误");ErrorCode UNKNOWN = new ErrorCode(999, "未知错误");
}

定义 controller 层业务错误码

public interface ControllerErrorCodeConstants {}

其中的错误码信息随着后续业务代码的完成补充

定义 service 层业务错误码

public interface ServiceErrorCodeConstants {
}

其中的错误码信息随着后续业务代码的完成补充

自定义异常类

自定义异常类是为了在程序中处理特定的错误或异常情境,使得异常处理更加清晰和灵活。通过自定义异常类,可以根据业务需求定义特定的异常类型,方便捕获和处理特定的错误

创建 exception 包:

controller 层异常类

@Data
@EqualsAndHashCode(callSuper = true)
public class ControllerException extends RuntimeException {/*** controller 层错误码* @see com.example.gobang_system.common.errorcode.ControllerErrorCodeConstants*/private Integer code;/*** 错误描述信息*/private String message;/*** 无参构造方法,方便后续进行序列化*/public ControllerException() {}/*** 全参构造方法,指定 code 和 message* @param code* @param message*/public ControllerException(Integer code, String message) {this.code = code;this.message = message;}/*** 通过 errorCode 指定 code 和 message* @param errorCode*/public ControllerException(ErrorCode errorCode) {this.code = errorCode.getCode();this.message = errorCode.getMessage();}
}

service 层异常类

@Data
@EqualsAndHashCode(callSuper = true)
public class ServiceException extends RuntimeException{/*** service 层错误码* @see com.example.gobang_system.common.errorcode.ServiceErrorCodeConstants*/private Integer code;/*** 错误描述信息*/private String message;/*** 无参构造方法,方便后续进行序列化*/public ServiceException() {}/*** 全参构造方法,指定 code 和 message* @param code* @param message*/public ServiceException(Integer code, String message) {this.code = code;this.message = message;}/*** 通过 errorCode 指定 code 和 message* @param errorCode*/public ServiceException(ErrorCode errorCode) {this.code = errorCode.getCode();this.message = errorCode.getMessage();}
}

在进行序列化时需要使用无参构造方法,因此需要提供无参构造方法

那么,在进行序列化时为什么要使用无参构造方法呢?

序列化:将对象转化为字节流

反序列化:从字节流中重建对象

在序列化过程中,使用无参构造方法(即不带任何参数的构造方法)是因为序列化和反序列化涉及将对象的状态转换为字节流 并且再 将其从字节流重建回原对象

序列化过程中,java会将对象的状态(字段值)保存在 字节流 中,而反序列化是通过读取这些字节流恢复对象,当反序列化时,JVM 必须首先 创建一个新的对象实例,然后再将字节流中的数据填充到该对象的字段中。为了能够保证顺利创建对象,java需要一个 无参构造方法 来实例化对象

因此,无参构造方法是反序列化时默认的构造方法,java默认调用该构造方法创建对象实例,因为其没有任何参数,创建对象时无需传递任何参数。如果没有无参构造方法,Java 会试图使用其他构造方法来创建对象,但这些构造方法需要相应的参数传递。而反序列化时,并没有提供参数,这就导致反序列化过程失败

总而言之,无参构造方法在序列化和反序列化中的作用主要体现在以下几个方面:

1. 反序列化需要通过无参构造方法来实例化对象,因为反序列化时无法传递参数给构造方法

2. 无参构造方法保证了对象的正确创建,即使类中有其他的构造方法,也不会影响反序列化的成功

3. 无参构造方法不执行任何业务逻辑,保证了反序列化对象的一致性

 @Data 注解

@Data 是 Lombok 提供的一个常见注解,在 java 中用于简化类的代码编写。@Data 注解会为类生成一系列的常用功能代码(自动生成 getter 和 setter 方法、toString 方法等),从而减少代码冗余,提升开发效率

若我们此时运行程序,查看 target 中 的 ControllerException.class

就可以看到对应的 getter、setter 等方法

 @EqualsAndHashCode(callSuper = true)

@EqualsAndHashCode 注解也是 Lombok 中的一个注解,用于自动生成 equals() 和 hashcode() 方法。这两个方法是 Java 中非常常见且重要的方法,通常用于对象的比较和存储在基于哈希表的集合(如 HashMap、HashSet)

callSuper = true:调用父类(super)的 equals() 和 hashCode() 方法,不仅会考虑当前类中的字段,还会考虑父类中的字段,确保父类和子类的字段都参与相等性比较和哈希计算

callSuper = false(默认值):不调用父类的 equals() 和 hashCode() 方法,只考虑当前字段,不考虑父类中的字段

此外,在使用 @Data 注解时,可能会出现反编译 target 文件中并未生成对应 getter、setter 等方法的情况

可能是因为 spring 在创建项目添加 lombok 依赖时,会自动引入一个插件,将其删除即可

更多问题可参考:【SpringBug】lombok插件失效,但是没有报错信息,@Data不能生成get和set方法_lombok data get set-CSDN博客

CommonResult<T>

CommonResult<T> 作为控制层方法的返回类型,封装接口调用结果,包括成功数据、错误数据 和 状态码。它可以被 SpringBoot 框架自动转化为 JSON 或其他格式的响应体,发送给客户端

为什么要进行封装呢?

统一的返回格式:确保客户端收到的响应具有一致的结构,避免每个接口都需要自己定义状态码、消息、数据等内容

错误码和消息:提供错误码(code)错误消息(errorMessage),帮助客户端快速识别和处理错误

泛型数据返回:使用泛型 <T> 允许返回任何类型的数据,增加了返回对象的灵活性

静态方法:提供了 fail() 和 success() 静态方法,方便快速创建错误或成功的响应对象

错误码常量集成:通过 ErrorCode 和 GlobalErrorCodeConstants 使用预定义的错误码,保持错误码的一致性和可维护性

序列化:实现了 Serializable 接口,使得 CommonResult<T> 对象可以被序列化为多种格式,如 JSON 或 XML,方便网络传输

业务逻辑解耦:将业务逻辑与 API 的响应格式分离,使得后端开发人员可以专注业务逻辑实现,而不必关系如何构建响应

客户端友好:客户端开发人员可以通过统一的接口获取数据和错误信息,无需针对每个 API 编写特定的错误处理逻辑

代码实现:

@Data
public class CommonResult<T> implements Serializable {/*** 错误码* @see ErrorCode#getCode()*/private Integer code;/*** 返回数据*/private T data;/*** 错误描述信息*/private String errorMessage;/*** 业务处理成功* @param data* @return* @param <T>*/public static <T> CommonResult<T> success(T data) {CommonResult result = new CommonResult();result.code = GlobalErrorCodeConstants.SUCCESS.getCode();result.data = data;result.errorMessage = "";return result;}/*** 业务处理失败* @param errorCode* @return* @param <T>*/public static <T> CommonResult<T> fail(ErrorCode errorCode) {return fail(errorCode.getCode(), errorCode.getMessage());}/*** 业务处理失败* @param code* @param errorMessage* @return* @param <T>*/public static <T> CommonResult<T> fail(Integer code, String errorMessage) {Assert.isTrue(!GlobalErrorCodeConstants.SUCCESS.getCode().equals(code),"code = 200, 运行成功");CommonResult result = new CommonResult();result.code = code;result.errorMessage = errorMessage;return result;}
}

其中,serializable 接口是 java 提供的一个标记接口(空接口),用于指示一个类的对象可以被序列化,无需实现任何方法,定义在 java.io 包中

此外,若想在 idea 中使用断言,需要先开启断言功能,可参考:

如何开启idea中的断言功能?_idea开启断言-CSDN博客

jackson

在前后端交互的过程中,经常会使用 JSON 格式来传递数据,这也就涉及到 序列化 反序列化,此外,我们在进行日志打印时,也会涉及到序列化

因此,我们可以定义一个工具类,来专门处理 序列化

在 java 中,通常使用 ObjectMapper 来处理 Java 对象与 JSON 数据之间的转换

因此,我们首先来学习一下 ObjectMapper 的相关方法和使用

在 test 中创建一个测试类:

@SpringBootTest
public class JacksonTest {@Testvoid jacksonTest() {}
}

首先来看 object 的序列化

序列化需要使用 ObjectMapper 中的 writeValueAsString 方法:

 处理过程中可能会抛出异常,因此需要进行处理

@SpringBootTest
public class JacksonTest {@Testvoid jacksonTest() {// 创建 ObjectMapper 实例ObjectMapper objectMapper = new ObjectMapper();// 序列化CommonResult<String> result = CommonResult.success("成功"); // 创建 java 对象String str = null;try {str = objectMapper.writeValueAsString(result);System.out.println("序列化结果:" + str);} catch (JsonProcessingException e) {throw new RuntimeException(e);}}
}

我们继续看 object 的反序列化

反序列化需要使用 readValue 方法:

其中,content 是需要读取的字符串,valueType 是将要转化的 java 对象类型

        // 反序列化try {CommonResult<String> result1 = objectMapper.readValue(str, CommonResult.class);System.out.println(result1.getCode() + " " + result1.getData());} catch (JsonProcessingException e) {throw new RuntimeException(e);}

运行并观察结果:

此外,除了处理普通的 object,还可能需要处理一些复杂类型,如 集合、Map 等

例如,处理 List 类型的 序列化 和 反序列化:

List 的序列化 与 object 类型的序列化类似:

        // List 的序列化List<CommonResult<String>> commonResultList = Arrays.asList(CommonResult.success("test1"),CommonResult.success("test2"),CommonResult.success("test3"));try {str = objectMapper.writeValueAsString(commonResultList);System.out.println(str);} catch (JsonProcessingException e) {throw new RuntimeException(e);}

List 的反序列化:

在对 List 类型进行反序列化时,不能直接将 List 类型传递给 valueType,而是需要构造一个 JavaType 类型

        // List 的反序列化JavaType javaType = objectMapper.getTypeFactory().constructParametricType(List.class, CommonResult.class); // 构造参数类型try {commonResultList = objectMapper.readValue(str, javaType);for (CommonResult<String> res : commonResultList) {System.out.println(res.getData());}} catch (JsonProcessingException e) {throw new RuntimeException(e);}

运行并观察结果:

完整测试代码:

@SpringBootTest
public class JacksonTest {@Testvoid jacksonTest() {// 创建 ObjectMapper 实例ObjectMapper objectMapper = new ObjectMapper();// 序列化CommonResult<String> result = CommonResult.success("成功"); // 创建 java 对象String str = null;try {str = objectMapper.writeValueAsString(result);System.out.println("序列化结果:" + str);} catch (JsonProcessingException e) {throw new RuntimeException(e);}// 反序列化try {CommonResult<String> result1 = objectMapper.readValue(str, CommonResult.class);System.out.println(result1.getCode() + " " + result1.getData());} catch (JsonProcessingException e) {throw new RuntimeException(e);}// List 的序列化List<CommonResult<String>> commonResultList = Arrays.asList(CommonResult.success("test1"),CommonResult.success("test2"),CommonResult.success("test3"));try {str = objectMapper.writeValueAsString(commonResultList);System.out.println(str);} catch (JsonProcessingException e) {throw new RuntimeException(e);}// List 的反序列化JavaType javaType = objectMapper.getTypeFactory().constructParametricType(List.class, CommonResult.class); // 构造参数类型try {commonResultList = objectMapper.readValue(str, javaType);for (CommonResult<String> res : commonResultList) {System.out.println(res.getData());}} catch (JsonProcessingException e) {throw new RuntimeException(e);}}
}

可以发现,在使用 objectMapper 中的方式时,每次都要对异常进行处理,十分繁琐

那我们该如何简化呢?

我们来看 SpringBoot 框架中是如何实现的:

不同类型的对象序列化是基本相同的,都是使用 writeValueAsString 方法来进行序列化,因此我们主要来看反序列化:

可以看到,反序列化 Map 和 List 都调用了 tryParse 方法,并传递了两个参数:一个 lambda 表达式,一个 Exception

我们继续看 tryParse 方法:

其中,最主要的方法就是 parse.call(),通过 call() 方法,来执行定义的任务

且 tryParse 方法中对异常进行了处理:

check.isAssignableFrom(var4.getClass()) 判断抛出的异常是否是传入的 check 异常,若是,则抛出 JsonParseException 异常;若不是,则抛出 IllegalStateException 异常

可以看到,框架中通过 tryParse() 方法,巧妙地对异常进行了处理

因此,我们可以借鉴上述方法来进行实现

由于只需要使用一个 ObjectMapper 实例,因此可以创建 单例 ObjectMapper

public class JacksonUtil {private JacksonUtil() {}private final static ObjectMapper OBJECT_MAPPER;static {OBJECT_MAPPER = new ObjectMapper();}private static ObjectMapper getObjectMapper() {return OBJECT_MAPPER;}
}

实现 tryParse 方法:

    private static <T> T tryParse(Callable<T> parser, Class<? extends Exception> check) {try {return parser.call();} catch (Exception e) {if (check.isAssignableFrom(e.getClass())) {throw new JsonParseException(e);}throw new IllegalStateException(e);}}private static <T> T tryParse(Callable<T> parser) {return tryParse(parser, JsonParseException.class);}

实现序列化方法:

    /*** 序列化* @param value* @return*/public static String writeValueAsString(Object value) {return tryParse(() -> getObjectMapper().writeValueAsString(value));}

反序列化: 

    /*** 反序列化* @param content* @param valueType* @return* @param <T>*/public static <T> T readValue(String content, Class<T> valueType) {return tryParse(() -> {return getObjectMapper().readValue(content, valueType);});}/*** 反序列化 List* @param content* @param param List 中元素类型* @return*/public static <T> T readListValue(String content, Class<?> param) {JavaType javaType = getObjectMapper().getTypeFactory().constructParametricType(List.class, param);return tryParse(() -> {return getObjectMapper().readValue(content, javaType);});}

完整代码:

public class JacksonUtil {private JacksonUtil() {}private final static ObjectMapper OBJECT_MAPPER;static {OBJECT_MAPPER = new ObjectMapper();}private static ObjectMapper getObjectMapper() {return OBJECT_MAPPER;}/*** 序列化* @param value* @return*/public static String writeValueAsString(Object value) {return tryParse(() ->getObjectMapper().writeValueAsString(value));}/*** 反序列化* @param content* @param valueType* @return* @param <T>*/public static <T> T readValue(String content, Class<T> valueType) {return tryParse(() -> {return getObjectMapper().readValue(content, valueType);});}/*** 反序列化 List* @param content* @param param List 中元素类型* @return*/public static <T> T readListValue(String content, Class<?> param) {JavaType javaType = getObjectMapper().getTypeFactory().constructParametricType(List.class, param);return tryParse(() -> {return getObjectMapper().readValue(content, javaType);});}private static <T> T tryParse(Callable<T> parser, Class<? extends Exception> check) {try {return parser.call();} catch (Exception e) {if (check.isAssignableFrom(e.getClass())) {throw new JsonParseException(e);}throw new IllegalStateException(e);}}private static <T> T tryParse(Callable<T> parser) {return tryParse(parser, JsonParseException.class);}
}

进行测试:

@SpringBootTest
public class JacksonTest {@Testvoid jacksonTest() {CommonResult<String> failResult = CommonResult.fail(GlobalErrorCodeConstants.ERROR_CONFIGURATION);// 序列化String res = JacksonUtil.writeValueAsString(failResult);System.out.println(res);// 反序列化failResult = JacksonUtil.readValue(res, CommonResult.class);System.out.println(failResult.getCode() + " " + failResult.getErrorMessage());List<CommonResult<String>> commonResults = Arrays.asList(CommonResult.success("test1"),CommonResult.success("test2"),CommonResult.success("test3"));// 序列化 ListString listStr = JacksonUtil.writeValueAsString(commonResults);System.out.println(listStr);// 反序列化commonResults = JacksonUtil.readListValue(listStr, CommonResult.class);for (CommonResult<String> commonResult: commonResults) {System.out.println(commonResult.getData());}}
}

运行结果:

加密工具

在对敏感信息(如密码、手机号等)进行存储时,需要进行加密,从而保证数据的安全性,若直接明文存储,当黑客入侵数据库时,就可以轻松拿到用户的相关信息,从而造成信息泄露或财产损失

在这里,使用 md5 对用户密码进行加密

采用 判断哈希值是否一致 的方法来判断密码是否正确

详细过程可参考:密码加密及验证_加密算法识别-CSDN博客

完整代码:

public class SecurityUtil {// 密钥private static final String AES_KEY = "3416b730f0f244128200c59fd07e6249";/*** 使用 md5 对密码进行加密* @param password 输入的密码* @return 密码 + 盐值*/public static String encipherPassword(String password) {String salt = UUID.randomUUID().toString().replace("-", "");String secretPassword = DigestUtils.md5DigestAsHex((password + salt).getBytes());return secretPassword + salt;}/*** 验证用户输入的密码是否正确* @param inputPassword 用户输入密码* @param sqlPassword 数据库中存储密码* @return*/public static Boolean verifyPassword(String inputPassword, String sqlPassword) {if (!StringUtils.hasLength(inputPassword)) {return false;}if (!StringUtils.hasLength(sqlPassword) || sqlPassword.length() != 64) {return false;}String salt = sqlPassword.substring(32, 64);String secretPassword = DigestUtils.md5DigestAsHex((inputPassword + salt).getBytes());return sqlPassword.substring(0, 32).equals(secretPassword);}
}

相关文章:

网页五子棋——通用模块

目录 项目创建 通用功能模块 错误码 自定义异常类 CommonResult jackson 加密工具 项目创建 使用 idea 创建 SpringBoot 项目&#xff0c;并引入相关依赖&#xff1a; 配置 MyBatis&#xff1a; 编辑 application.yml&#xff1a; spring:datasource: # 数据库连接配…...

第6章 6.2使用ASP.NET Core 开发WebAPI ASP.NET Core Web API

6.2.1 Web API项目的搭建 进入VS&#xff0c;【创建新项目】&#xff0c;选择【ASP.NET Core Web API】模板&#xff0c;【下一步】&#xff0c;编辑项目名称及项目位置&#xff0c;【下一步】&#xff0c;选择框架&#xff0c;其他选项默认即可&#xff0c;【创建】。 进入项…...

[MFC] 使用控件

介绍如何使用控件&#xff0c;以及如何获取控件中的数值 check Box 添加点击事件&#xff0c;即选中和取消选中触发的事件 第一种方式是按照如下方式第二种方式是直接双击点击进去 void CMFCApplication1Dlg::OnBnClickedCheckSun() {// TODO: 在此添加控件通知处理程序代…...

景联文科技:以精准标注赋能AI未来,打造高质量数据基石

在人工智能蓬勃发展的时代&#xff0c;数据已成为驱动技术革新的核心燃料&#xff0c;而高质量的数据标注则是让AI模型从“感知”走向“认知”的关键桥梁。作为深耕数据服务领域的创新者&#xff0c;景联文科技始终以“精准、高效、安全”为核心理念&#xff0c;为全球AI企业提…...

2月14(信息差)

&#x1f30d;杭州&#xff1a;全球数贸港核心区建设方案拟出台 争取国家支持杭州在网络游戏管理给予更多权限 &#x1f384;Kimi深夜炸场&#xff1a;满血版多模态o1级推理模型&#xff01;OpenAI外全球首次&#xff01;Jim Fan&#xff1a;同天两款国产o1绝对不是巧合&#x…...

UE_C++ —— Metadata Specifiers

声明UClasses、UFunctions、UProperties、UEnums和UInterfaces时使用的元数据关键词&#xff0c;表示其与引擎和关卡编辑器诸多方面的互动方式&#xff1b; 当声明classe、interfaces、structs、enums、enum values、functions、or propertie时&#xff0c;可添加 Metadata Spe…...

C++ 常用的设计模式

1&#xff1a;单例模式&#xff1a;首先能想到的&#xff0c;最为重要的一个设计模式。确保一个类仅有一个实例&#xff0c;提供一个 全局访问点&#xff0c;惯用做法是屏蔽构造数访问&#xff08;设为private&#xff09;&#xff0c;通过static 权限达到间接访问调用的目的…...

web集群(LVS-DR)

LVS是Linux Virtual Server的简称&#xff0c;也就是Linux虚拟服务器, 是一个由章文嵩博士发起的自由软件项 目&#xff0c;它的官方站点是 www.linuxvirtualserver.org。现在LVS已经是 Linux标准内核的一部分&#xff0c;在 Linux2.4内核以前&#xff0c;使用LVS时必须要重新编…...

Instagram与小红书的自动化运营

Instagram与小红书的自动化运营 引言 在这个信息爆炸的时代&#xff0c;社交媒体成为了与世界互动的重要平台。在这样的背景下&#xff0c;如何高效地运营你的Instagram或小红书账户&#xff0c;成为众多内容创作者和品牌的重要课题。那么&#xff0c;自动化运营究竟是什么&a…...

从二维到三维3D工业相机如何改变机器视觉检测

从二维到三维&#xff0c;3D工业相机在机器视觉检测中带来了显著变革&#xff0c;主要体现在以下几个方面&#xff1a; 深度信息获取 二维相机&#xff1a;只能提供平面信息&#xff0c;无法获取物体的深度。 三维相机&#xff1a;通过深度信息&#xff0c;能够更精确地测量物…...

多媒体软件安全与授权新范例,用 CodeMeter 实现安全、高效的软件许可管理

背景概述 Reason Studios 成立于 1994 年&#xff0c;总部位于瑞典斯德哥尔摩&#xff0c;是全球领先的音乐制作软件开发商。凭借创新的软件产品和行业标准技术&#xff0c;如 ReWire 和 REX 文件格式&#xff0c;Reason Studios 为全球专业音乐人和业余爱好者提供了一系列高质…...

DeePseek结合PS!批量处理图片的方法教程

​ ​ 今天我们来聊聊如何利用deepseek和Photoshop&#xff08;PS&#xff09;实现图片的批量处理。 传统上&#xff0c;批量修改图片尺寸、分辨率等任务往往需要编写脚本或手动处理&#xff0c;而现在有了AI的辅助&#xff0c;我们可以轻松生成PS脚本&#xff0c;实现自动化处…...

2.14寒假作业

web&#xff1a;[SWPUCTF 2021 新生赛]PseudoProtocols 打开环境给了提示要我们找 hint.php url是给了后缀的&#xff0c;不单纯是地址&#xff0c;直接用为协议看一下目标文件&#xff0c;得到base64加密的文字 解密&#xff0c;提示我们访问一个文件 跟着思路走访问文件之后…...

【鱼眼镜头12】Scaramuzza的鱼眼相机模型实操,不依赖于具体的相机几何结构,直接从图像数据出发,因此更具灵活性。

文章目录 Scaramuzza相机模型标定效果2、原理和代码代码1、 2D映射到3D&#xff0c;函数输入为2D点坐标OCAM参数代码功能详解2、3D --> 2D 3、总结Scaramuzza 模型的核心思想Scaramuzza 模型的核心思想与 Kannala-Brandt 模型的对比Scaramuzza 模型的独特之处Scaramuzza 的意…...

(Windows | Linux)ssh访问服务器报错:no matching key exchange method found

问题现象 ssh user1192.168.1X.XX Unable to negotiate with 192.168.1X.XX port 22: no matching key exchange method found. Their offer: gss-group1-sha1-toWM5Slw5Ew8Mqkayal2g,diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,diffie-hellman-group1-…...

达梦分布式集群DPC_架构详解_yxy

达梦分布式集群DPC_架构详解 1 DPC核心架构介绍1.1 架构图1.2 DPC核心架构组件 2 多副本2.1 多副本架构图2.2 多副本示例2.3 RAFT组概念2.4 表空间与RAFT组的关系 1 DPC核心架构介绍 1.1 架构图 1.2 DPC核心架构组件 DMDPC 架构由三部分组成 SP&#xff08;SQL Processor&…...

51单片机独立按键的扩展应用

提示&#xff1a; 按键S7和S6为选择键&#xff0c;确定控制键控制那组LED指示灯。按键S5和S4为控制键&#xff0c;按键该键点亮指定的LED指示灯&#xff0c;松开后熄灭。按下S7点亮L1指示灯&#xff0c;L1点亮后&#xff0c;S6不响应操作&#xff0c;S5控制L3&#xff0c;S4控…...

浅识MQ的 Kafka、ActiveMQ、RabbitMQ、RocketMQ区别

DeepSeek回复&#xff1a; 以下是主流消息队列&#xff08;MQ&#xff09;的对比分析&#xff0c;结合核心特性、适用场景和实际案例说明&#xff1a; 一、主流MQ对比分析 维度 Kafka RabbitMQ RocketMQ ActiveMQ所属公司Apache&#xff08;LinkedIn开源&#xff09;…...

模型报错infeasible,如何查看冲突约束

在使用Gurobi求解模型时&#xff0c;如果模型不可行&#xff08;infeasible&#xff09;&#xff0c;可以通过以下步骤来查看冲突的约束或变量&#xff0c;帮助诊断问题&#xff1a; 1. 使用 computeIIS() 方法 Gurobi 提供了 computeIIS() 方法&#xff0c;用于计算不可行模…...

Golang GORM系列:GORM事务及错误处理

在数据库管理领域&#xff0c;确保数据完整性至关重要。GORM是健壮的Go对象关系映射库&#xff0c;它为开发人员提供了维护数据一致性和优雅地处理错误的基本工具。本文是掌握GORM事务和错误处理的全面指南。我们将深入研究如何使用事务来保证原子性&#xff0c;并探索有效处理…...

如何实现对 ELK 各组件的监控?试试 Metricbea

上一章基于 Filebeat 的日志收集使用Filebeat收集文件中的日志&#xff0c;而Metricbeat则是收集服务器存活性监测和系统指标的指标。 1. Filebeat和Metricbeat的区别 特性FilebeatHeartbeat作用收集和转发日志监测服务可用性数据来源服务器上的日志文件远程主机、API、服务主…...

图像处理篇---基本Python图像处理

文章目录 前言1. 图像灰度化原理Python 实现 2. 图像二值化原理&#xff1a;Python 实现 3. 图像掩膜&#xff08;Mask&#xff09;原理Python 实现 4. 腐蚀&#xff08;Erosion&#xff09;和膨胀&#xff08;Dilation&#xff09;原理Python 实现 5. 其他常用图像操作(1) 图像…...

使用PHP爬虫获取1688商品分类:实战案例指南

在电商领域&#xff0c;商品分类信息是商家进行市场调研、选品分析和竞争情报收集的重要基础。1688作为国内领先的B2B电商平台&#xff0c;提供了丰富且详细的商品分类数据。通过PHP爬虫技术&#xff0c;我们可以高效地获取这些分类信息&#xff0c;为商业决策提供有力支持。 …...

【微服务学习二】nacos服务发现与负载均衡

nacos服务发现 想要开启服务发现&#xff0c;需要在main函数上添加 EnableDiscoveryClient 注解 然后我们编写一个controller类来查询nacos中注册的所有微服务以及对应的ip端口号 Controller public class DiscoveryController {AutowiredDiscoveryClient discoveryClient;//…...

深入剖析推理模型:从DeepSeek R1看LLM推理能力构建与优化

著名 AI 研究者和博主 Sebastian Raschka 又更新博客了。原文地址&#xff1a;https://sebastianraschka.com/blog/2025/understanding-reasoning-llms.html。这一次&#xff0c;他将立足于 DeepSeek 技术报告&#xff0c;介绍用于构建推理模型的四种主要方法&#xff0c;也就是…...

有哪些滤波,原理是什么,分别在什么时候用

均值滤波&#xff08;Average Filtering&#xff09; 原理&#xff1a;通过计算像素点邻域内像素值的平均值来作为该像素点滤波后的新值。例如&#xff0c;对于一个 3x3 的邻域&#xff0c;将 9 个像素值相加然后除以 9 得到滤波后的像素值。优点&#xff1a;简单易实现&#x…...

小初高各学科教材,PDF电子版下载

链接&#xff1a;https://pan.quark.cn/s/7c2125f648e2 小初高中电子课本资料pdf合集 高中各科教材 &#xff08;部分举例&#xff09; - 语文&#xff1a;新人教版、旧人教版、苏教版等 - 数学&#xff1a;人教A版、沪教版、鄂教版等 - 英语&#xff1a;重大版、人教版…...

Kafka分区管理大师指南:扩容、均衡、迁移与限流全解析

#作者&#xff1a;孙德新 文章目录 分区分配操作(kafka-reassign-partitions.sh)1.1 分区扩容、数据均衡、迁移(kafka-reassign-partitions.sh)1.2、修改topic分区partition的副本数&#xff08;扩缩容副本&#xff09;1.3、Partition Reassign场景限流1.4、节点内副本移动到不…...

java后端开发day14--之前练习的总结和思考

1.感受 这两天学点儿新的就直接上手打代码&#xff0c;真的是累死个人。我唯一的感受就是&#xff0c;课听完了&#xff0c;代码也跟着打完了&#xff08;是的&#xff0c;跟着打的&#xff0c;没自己打&#xff09;&#xff0c;感觉自己脑袋里乱乱的&#xff0c;对代码的分区…...

[运输时间]

运输时间 真题目录: 点击去查看 E 卷 200分题型 题目描述 M(1 ≤ M ≤ 20)辆车需要在一条不能超车的单行道到达终点,起点到终点的距离为 N(1 ≤ N ≤ 400)。 速度快的车追上前车后,只能以前车的速度继续行驶,求最后一辆车到达目的地花费的时间。 注:每辆车固定间隔…...