网页五子棋——通用模块

news2025/3/24 17:32:37

目录

项目创建

通用功能模块

错误码

自定义异常类

CommonResult

jackson

加密工具


项目创建

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

配置 MyBatis:

编辑 application.yml

spring:
  datasource: # 数据库连接配置
    url: jdbc:mysql://127.0.0.1:3306/gobang_system?characterEncoding=utf8&useSSL=false
    username: root
    password: 123456
    driver-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 {
    @Test
    void jacksonTest() {
    }
}

首先来看 object 的序列化

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

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

@SpringBootTest
public class JacksonTest {
    @Test
    void 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 {
    @Test
    void 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 {
    @Test
    void 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")
        );
        // 序列化 List
        String 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);
    }
}

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

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

相关文章

第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…

web集群(LVS-DR)

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

多媒体软件安全与授权新范例,用 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控…

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

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

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

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

【微服务学习二】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;也就是…

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

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

AIoT时代来临,物联网技术如何颠覆未来生活?

在这个万物互联的时代&#xff0c;“物联网”&#xff08;IoT&#xff09;正以前所未有的速度改变我们的生活&#xff0c;而“AIoT”则是在物联网基础上融入人工智能技术&#xff0c;赋予设备更高的智能和自主决策能力。随着5G、边缘计算和云技术的不断发展&#xff0c;物联网正…

基于SpringBoot的电影院售票管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

深度学习与人工智能:解锁未来的无限可能

在当今这个科技飞速发展的时代&#xff0c;深度学习和人工智能已不再只是科幻小说中的概念&#xff0c;它们正以惊人的速度渗透到我们生活的方方面面&#xff0c;从智能手机上的语音助手到医疗领域的疾病诊断&#xff0c;从自动驾驶汽车到金融市场的风险预测&#xff0c;其影响…