网页五子棋——通用模块

目录

项目创建

通用功能模块

错误码

自定义异常类

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);
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Springboot_实战

项目开发 lombok使用 自动为实体类提供get、set、toString方法 引入依赖 实体类上添加注解 统一响应结果 注意要写get、set方法&#xff1b;下面是错误的&#xff0c;因此要加上Data注解 一个注册的接口的示例 Controller层 Service层 Mapper层 参数校验 但是同样存在一…

C++智能指针原理和使用(续)

文章目录 智能指针的原理auto_ptr和unique_ptr的模拟实现boostshared_ptr&#xff08;重点&#xff09;拷贝赋值shared_ptr底层实现的代码 智能指针的使用定制删除器shared_ptrunique_ptr 模拟实现定制删除器shared_ptr和weak_ptrshared_ptr循环引用问题(重点)weak_ptr shared_…

LLM:GPT 系列

阅读原文&#xff1a; LLM&#xff1a;Qwen 系列 GPT&#xff08;Generative Pre-trained Transformer&#xff09;是生成式预训练语言模型&#xff0c;基于 Transformer 架构&#xff0c;专注于通过自回归的方式生成自然语言文本&#xff0c;即给定一个输入序列 x { x 1 , …

ollama+langchain+deepseek本机跑通大模型

一、部署deepseek Ollama&#xff0c;这是是一个开源的大语言模型平台&#xff0c;它允许用户在本地环境中运行、创建和共享大型语言模型。Ollama提供了丰富的功能和特性&#xff0c;使得用户可以在自己的计算机上轻松地部署和运行大型语言模型。官网&#xff1a;https://ollam…

同步buck型降压DCDC电路设计

参考资料&#xff1a; 嵌入式-硬件-DCDC&#xff08;BUCK&#xff09;电路分析_dcdc buck-CSDN博客 1、基本原理 上图左是异步BUCK&#xff0c;右图是同步BUCK。右边使用元件较多&#xff0c;但是效率高&#xff0c;发热小。同样输出功率的前提下&#xff0c;虽然右边元件多&…

数据挖掘智能Agent

&#x1f917; CodeGenie - 智能编程助手 数据处理和分析对于数据分析工作人员来说&#xff0c;往往既复杂又令人头疼&#xff0c;需要耗费大量精力进行重复性工作。为了解决这一问题&#xff0c;我们开发了一款集成了自然语言处理和代码生成功能的智能编程助手——CodeGenie。…

人工智能之自然语言处理技术演进

自然语言处理技术演进 自然语言处理&#xff08;Natural Language Processing&#xff0c;NLP&#xff09;是人工智能的重要分支&#xff0c;旨在使计算机能够理解、生成和处理人类语言。近年来&#xff0c;NLP技术经历了从规则驱动到数据驱动的革命性演进&#xff0c;尤其是在…

保姆级GitHub大文件(100mb-2gb)上传教程

GLF&#xff08;Git Large File Storage&#xff09;安装使用 使用GitHub desktop上传大于100mb的文件时报错 The following files are over 100MB. lf you commit these files, you will no longer beable to push this repository to GitHub.com.term.rarWe recommend you a…

Spring Boot(7)Spring Boot 注解全解析:深入理解与应用

搞个引言 在现代 Java 开发中&#xff0c;Spring Boot 凭借其便捷性和高效性成为了众多开发者的首选框架。而注解作为 Spring Boot 的核心特性之一&#xff0c;极大地简化了开发过程&#xff0c;提高了代码的可读性和可维护性。本文将深入探讨 Spring Boot 中几种重要的注解&a…

【在idea中配置两个不同端口,同时运行两个相同的主程序springboot】

step1&#xff1a; step2&#xff1a; step3&#xff1a;指定端口号&#xff0c;点击apply 经过以上步骤后&#xff0c;idea下面就会出现service选项 启动两个springboot就完成了&#xff08;我的启动失败是因为redis没有启动&#xff0c;springboot没有连接到redis报错&a…

基于Flask的全国婚姻关系数据可视化分析系统的设计与实现

【FLask】基于Flask的全国婚姻关系数据可视化分析系统的设计与实现&#xff08;完整系统源码开发笔记详细部署教程&#xff09;✅ 目录 一、项目简介二、项目界面展示三、项目视频展示 一、项目简介 该系统采用Python作为后端开发语言&#xff0c;结合Flask后端框架和Bootstra…

基于Kotlin中Flow扩展重试方法

最近项目中统一采用Kotlin的Flow来重构了网络请求相关代码。 目前的场景是&#xff0c;接口在请求的时候需要一个accessToken值&#xff0c;因为此值会过期或者不存在&#xff0c;需要刷新&#xff0c;因此最终方案是在使用Flow请求的时候先获取accessToken值然后再进行接口请求…

达梦 跟踪日志诊断

目录标题 参考连接**性能诊断&#xff1a;跟踪日志诊断****总结** 参考连接 性能诊断 -> 跟踪日志诊断 性能诊断&#xff1a;跟踪日志诊断 备份现有的日志配置文件 在修改文件之前&#xff0c;建议先备份原始文件&#xff0c;以防万一需要恢复。 cp /opt/dmdbms/dmdata/DA…

RFID智能仓储管理系统:助力仓储数字化升级

​在现代物流与仓储管理中&#xff0c;RFID智能仓储管理系统凭借其高效、精准的特点&#xff0c;已成为企业提升仓库运作效率的重要工具。结合RFID仓库管理、RFID库存管理及智能仓储管理系统等技术&#xff0c;RFID智能仓储解决方案能够实现仓储全流程的自动化与智能化&#xf…

AI 编程私有化部署,在使用 cline 时,可能无法避免私隐的泄漏问题

摘录&#xff1a;Cline Privacy Policy https://github.com/cline/cline/blob/main/docs/PRIVACY.md Key Points Cline operates entirely client-side as a VS Code extensionNo code or data is collected, stored, or transmitted to Clines servers 问题是&#xff1a…

【进阶】MySQL高级篇超详讲解!!!

Mysql服务器内部架构&#xff08;了解&#xff09; 连接层 负责客户端的链接&#xff0c;验证账号密码等授权认证 服务层 对sql进行解析&#xff0c;优化&#xff0c;调用函数&#xff0c;如果是查询操作&#xff0c;有没有缓存等操作。 引擎层 是真正负责数据存储和提取…

【学术投稿-第四届智能电网和绿色能源国际学术会议(ICSGGE 2025)】CSS基本选择器详解:掌握基础,轻松布局网页

可线上 官网&#xff1a;www.icsgge.org 时间&#xff1a;2025年2月28-3月2日 目录 前言 一、基本选择器简介 1. 元素选择器&#xff08;Type Selector&#xff09; 基本语法 示例 注意事项 2. 类选择器&#xff08;Class Selector&#xff09; 基本语法 示例 注意…

编程题-字母异位词分组(中等-重点)

题目&#xff1a; 给你一个字符串数组&#xff0c;请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。 解法一&#xff08;for循环遍历-时间复杂度超限&#xff09;&#xff1a; 由于互为字母异位词的…

Spring Boot整合DeepSeek实现AI对话(API调用和本地部署)

本篇文章会分基于DeepSeek开放平台上的API&#xff0c;以及本地私有化部署DeepSeek R1模型两种方式来整合使用。 本地化私有部署可以参考这篇博文 全面认识了解DeepSeek利用ollama在本地部署、使用和体验deepseek-r1大模型 Spring版本选择 根据Spring官网的描述 Spring AI是一…

阿里云IOT消息处理

文章主要讲述了阿里云IOT平台如何处理设备上报的消息、如何将消息路由到不同的处理逻辑、如何进行消息转发与转换等操作。 一、接收IOT消息 1.创建订阅 2.案列代码 官网案例代码&#xff1a;如何将AMQP JMS客户端接入物联网平台接收消息_物联网平台(IoT)-阿里云帮助中心 代码…