第3章——SSM整合

news2025/6/7 21:58:20

一、整合持久层框架MyBatis

1.准备数据库表及数据

创建数据库:springboot

使用IDEA工具自带的mysql插件来完成表的创建和数据的准备:



创建表

表创建成功后,为表准备数据,如下:

2.创建SpringBoot项目

使用脚手架创建Spring Boot项目

引入mysql驱动以及mybatis的启动器

依赖如下:

<!--mybatis的启动器-->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>3.0.3</version>
</dependency>
<!--mysql的驱动依赖-->
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

注意,之前也提到过:

Spring Boot官方提供的启动器的名字规则:spring-boot-starter-xxx

第三方(非Spring Boot官方)提供的启动器的名字规则:xxx-spring-boot-starter

3.编写数据源配置

前面提到过,Spring Boot配置统一可以编写到application.properties中,配置如下:

以上的配置属于连接池的配置,连接池使用的是Spring Boot默认的连接池:HikariCP

4.编写实体类Vip

package org.example1.bean;

public class Vip {
    private Long id;
    private String name;
    private String cardNumber; // 数据库字段 card_number
    private String birth;

    public Vip(Long id, String name, String cardNumber, String birth) {
        this.id = id;
        this.name = name;
        this.cardNumber = cardNumber;
        this.birth = birth;
    }

    public Vip() {
    }

    public Vip(String name, String cardNumber, String birth) {
        this.name = name;
        this.cardNumber = cardNumber;
        this.birth = birth;
    }

    @Override
    public String toString() {
        return "Vip{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", cardNumber='" + cardNumber + '\'' +
                ", birth='" + birth + '\'' +
                '}';
    }

    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 getCardNumber() {
        return cardNumber;
    }

    public void setCardNumber(String cardNumber) {
        this.cardNumber = cardNumber;
    }

    public String getBirth() {
        return birth;
    }

    public void setBirth(String birth) {
        this.birth = birth;
    }
}

以上代码可以使用第三方库Lombok进行改造,后面再说。

5.编写Mapper接口

创建repository包,在该包下新建VipMapper接口,代码如下:

package org.example1.repository;



import org.example1.bean.Vip;

import java.util.List;

public interface VipMapper {
    /**
     * 保存会员信息
     * @param vip 会员信息
     * @return 1表示保存成功。
     */
    int insert(Vip vip);

    /**
     * 获取所有会员信息
     * @return 会员列表
     */
    List<Vip> selectAll();
}

6.编写Mapper接口的XML配置文件

在`resources`目录下新建`mapper`目录,将来的`mapper.xml`配置文件放在这个目录下。

安装`MyBatisX`插件,该插件可以根据我们编写的`VipMapper`接口自动生成mapper的XML配置文件。

然后在`VipMapper`接口上:alt+enter

接下来,你会看到Mapper接口中方法报错了,可以在错误的位置上使用`alt+enter`,选择`Generate statement`:

接下来就是编写SQL语句了,最终VipMapper.xml文件的配置如下:

7.添加Mapper的扫描

在Spring Boot的入口程序上添加如下的注解,来完成`VipMapper`接口的扫描:

8.编写service

接口

package org.example1.service;
import org.example1.bean.Vip;
import java.util.List;
public interface VipService {

    /**
     * 保存会员信息
     * @param vip  会员信息
     * @return true表示成功,false表示失败
     */
    boolean save(Vip vip);

    /**
     * 查看会员列表
     * @return 会员列表
     */
    List<Vip> findAll();

}

package org.example1.service.impl;

import org.example1.bean.Vip;
import org.example1.repository.VipMapper;
import org.example1.service.VipService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class VipServiceImpl implements VipService {

    @Autowired
    private VipMapper vipMapper;

    @Override
    public boolean save(Vip vip) {
        return vipMapper.insert(vip) == 1;
    }

    @Override
    public List<Vip> findAll() {
        return vipMapper.selectAll();
    }
}

9.告诉MyBatis框架MapperXML文件的位置

在`application.properties`配置文件中进行如下配置:

10.测试整合MyBatis是否成功

在Spring Boot主入口程序中获取Spring上下文对象ApplicationContext,从Spring容器中获取VipService对象,然后调用相关方法进行测试:


测试结果中可以看到cardNumber属性没有赋值成功,原因是:表中的字段名叫做card_number,和实体类Vip的属性名cardNumber对应不上。解决办法两个:

  • 第一种方式:查询语句使用as关键字起别名,让查询结果列名和实体类的属性名对应上。

再次测试:

  • 第二种方式:通过配置自动映射

application.properties配置文件中进行如下配置:

mybatis.configuration.map-underscore-to-camel-case=true

map-underscore-to-camel-case 是一个配置项,主要用于处理数据库字段名与Java对象属性名之间的命名差异。在许多数据库中,字段名通常使用下划线(_)分隔单词,例如 first_name 或 last_name。而在Java代码中,变量名通常使用驼峰式命名法(camel case),如 firstName 和 lastName。

当使用MyBatis作为ORM框架时,默认情况下它会将SQL查询结果映射到Java对象的属性上。如果数据库中的字段名与Java对象的属性名不一致,那么就需要手动为每个字段指定相应的属性名,或者使用某种方式来自动转换这些名称。

map-underscore-to-camel-case 这个配置项的作用就是在查询结果映射到Java对象时,自动将下划线分隔的字段名转换成驼峰式命名法。这样可以减少手动映射的工作量,并提高代码的可读性和可维护性。

mapper的xml文件中的sql语句仍然使用*的方式:

测试结果如下:

二、 Lombok库

Lombok 是一个 Java 库,它可以通过注解的方式减少 Java 代码中的样板代码。Lombok 自动为你生成构造函数、getter、setter、equals、hashCode、toString 方法等,从而避免了手动编写这些重复性的代码。这不仅减少了出错的机会,还让代码看起来更加简洁。

Lombok只是一个编译阶段的库,能够帮我们自动补充代码,在Java程序运行阶段并不起作用。(因此Lombok库并不会影响Java程序的执行效率)

例如我们有这样一个java源文件`User.java`,代码如下:

@Data
public class User{
    private String name;
}

以上代码在程序的编译阶段,Lombok库会将User.java文件编译生成这样的User.class字节码文件:

public class com.powernode.lomboktest.model.User {
  public com.powernode.lomboktest.model.User();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public java.lang.String getName();
    Code:
       0: aload_0
       1: getfield      #7                  // Field name:Ljava/lang/String;
       4: areturn

  public void setName(java.lang.String);
    Code:
       0: aload_0
       1: aload_1
       2: putfield      #7                  // Field name:Ljava/lang/String;
       5: return

  public boolean equals(java.lang.Object);
    Code:
       0: aload_1
       1: aload_0
       2: if_acmpne     7
       5: iconst_1
       6: ireturn
       7: aload_1
       8: instanceof    #8                  // class com/powernode/lomboktest/model/User
      11: ifne          16
      14: iconst_0
      15: ireturn
      16: aload_1
      17: checkcast     #8                  // class com/powernode/lomboktest/model/User
      20: astore_2
      21: aload_2
      22: aload_0
      23: invokevirtual #13                 // Method canEqual:(Ljava/lang/Object;)Z
      26: ifne          31
      29: iconst_0
      30: ireturn
      31: aload_0
      32: invokevirtual #17                 // Method getName:()Ljava/lang/String;
      35: astore_3
      36: aload_2
      37: invokevirtual #17                 // Method getName:()Ljava/lang/String;
      40: astore        4
      42: aload_3
      43: ifnonnull     54
      46: aload         4
      48: ifnull        65
      51: goto          63
      54: aload_3
      55: aload         4
      57: invokevirtual #21                 // Method java/lang/Object.equals:(Ljava/lang/Object;)Z
      60: ifne          65
      63: iconst_0
      64: ireturn
      65: iconst_1
      66: ireturn

  protected boolean canEqual(java.lang.Object);
    Code:
       0: aload_1
       1: instanceof    #8                  // class com/powernode/lomboktest/model/User
       4: ireturn

  public int hashCode();
    Code:
       0: bipush        59
       2: istore_1
       3: iconst_1
       4: istore_2
       5: aload_0
       6: invokevirtual #17                 // Method getName:()Ljava/lang/String;
       9: astore_3
      10: iload_2
      11: bipush        59
      13: imul
      14: aload_3
      15: ifnonnull     23
      18: bipush        43
      20: goto          27
      23: aload_3
      24: invokevirtual #24                 // Method java/lang/Object.hashCode:()I
      27: iadd
      28: istore_2
      29: iload_2
      30: ireturn

  public java.lang.String toString();
    Code:
       0: aload_0
       1: invokevirtual #17                 // Method getName:()Ljava/lang/String;
       4: invokedynamic #28,  0             // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;
       9: areturn
}

通过字节码可以看到Lombok库的@Data注解可以帮助我们生成无参构造器settergettertoStringhashCodeequals

1.Lombok 的主要注解

@Data

  • 等价于 @ToString, @EqualsAndHashCode, @Getter@Setter, @RequiredArgsConstructor.

  • 用于生成:必要参数的构造方法、getter、setter、toString、equals 和 hashcode 方法。

@Getter / @Setter

  • 分别用于生成所有的 getter 和 setter 方法。

  • 可以作用于整个类,也可以作用于特定的字段。

@NoArgsConstructor

  • 生成一个无参构造方法。

@AllArgsConstructor

  • 生成一个包含所有实例变量的构造器。

@RequiredArgsConstructor

  • 生成包含所有被 final 修饰符修饰的实例变量的构造方法。

  • 如果没有的实例变量,则自动生成无参数构造方法。

@ToString / @EqualsAndHashCode:

  • 用于生成 toString 和 equals/hashCode 方法。
  • 这两个注解都有exclude属性,通过这个属性可以定制toString、hashCode、equals方法。


Lombok 主要注解详解及代码示例


添加依赖

在 Maven 的 pom.xml 文件中添加 Lombok 依赖:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.34</version>
    <scope>provided</scope>
</dependency>

IDEA中安装Lombok插件

高版本的IntelliJ IDEA工具默认都是绑定Lombok插件的,不需要再额外安装:

Lombok插件不是必须要安装的,为了提高开发效率以及开发者的体验,安装Lombok插件是有必要的。

也就是说安装了Lombok插件之后,编写代码的时候,才会有方法的提示功能。

2.Lombok的其他常用注解

@Value

@Builder

@Singular

@Slf4j

......

@Value

该注解会给所有属性添加final,给所有属性提供getter方法,自动生成toStringhashCodeequals

通过这个注解可以创建不可变对象。

测试程序:

可以查看一下字节码,你会发现,@Value注解的作用只会生成:全参数构造方法、getter方法、hashCode、equals、toString方法。(没有setter方法。)

@Builder

GoF23种设计模式之一:建造模式

建造模式(Builder Pattern)属于创建型设计模式。GoF23种设计模式之一。

用于解决对象创建时参数过多的问题。它通过将对象的构造过程与其表示分离,使得构造过程可以逐步完成,而不是一次性提供所有参数。建造模式的主要目的是让对象的创建过程更加清晰、灵活和可控。

简而言之,建造模式用于:

  1. 简化构造过程:通过逐步构造对象,避免构造函数参数过多。

  2. 提高可读性和可维护性:让构造过程更加清晰和有序。

  3. 增强灵活性:允许按需配置对象的不同部分。

这样可以更方便地创建复杂对象,并且使得代码更加易于理解和维护。


建造模式的代码

建造模式代码如下:

package org.example1;

// 定义一个 Person 类,用于表示一个人的信息
public class Person {
    // 一般建造模式的 bean 属性使用 final 进行修饰,确保对象的不可变性
    private final String name;
    private final int age;

    // 私有构造函数,只能通过建造器来创建 Person 对象
    private Person(String name, int age) {
        // 将传入的 name 参数赋值给当前对象的 name 属性
        this.name = name;
        // 将传入的 age 参数赋值给当前对象的 age 属性
        this.age = age;
    }

    // 获取姓名的方法
    public String getName() {
        return name;
    }

    // 获取年龄的方法
    public int getAge() {
        return age;
    }

    // 重写 toString 方法,方便打印 Person 对象的信息
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    // 通过这个公开的静态方法获取建造器对象
    public static PersonBuilder builder() {
        return new PersonBuilder();
    }

    // 静态内部类,用于构建 Person 对象
    public static class PersonBuilder {
        // 用于存储要构建的 Person 对象的姓名
        private String name;
        // 用于存储要构建的 Person 对象的年龄
        private int age;

        // 设置姓名的方法,返回当前建造器对象,以便进行链式调用
        public PersonBuilder name(String name) {
            this.name = name;
            return this;
        }

        // 设置年龄的方法,返回当前建造器对象,以便进行链式调用
        public PersonBuilder age(int age) {
            this.age = age;
            return this;
        }

        // 构建 Person 对象的方法
        public Person build() {
            return new Person(name, age);
        }
    }
}


建造模式就是可以把参数拆出来,一个一个建造?

没错,建造模式的确能够把参数拆分,逐个进行构建。下面为你详细介绍建造模式及其参数拆分构建的原理:

定义

建造模式(Builder Pattern)属于创建型设计模式,其作用是将一个复杂对象的构建和表示分离,如此一来,相同的构建过程就能创建出不同的表示。

把参数拆出来逐个构建的原理

  • 链式调用:建造模式一般会在建造器类里为每个参数提供对应的设置方法,这些方法会返回建造器自身,这样就能实现链式调用。你可以逐个调用这些方法来设置参数。
  • 封装构建逻辑:构建复杂对象时,不同参数的设置可能涉及复杂的逻辑,建造模式把这些逻辑封装在建造器类的各个方法中,用户仅需调用这些方法就能完成参数设置,而不用关心内部的具体实现。
  • 最终构建:当所有参数都设置好之后,调用建造器的 build() 方法,该方法会依据设置好的参数创建出最终的对象。

使用@Builder注解自动生成建造模式的代码

该注解可以直接帮助我们生成以上的代码。使用@Builder注解改造以上代码。

@Singular

@Singular注解是辅助@Builder注解的。

被建造的对象的属性是一个集合,这个集合属性使用@Singular注解进行标注的话,可以连续调用集合属性对应的方法完成多个元素的添加。如果没有这个注解,则无法连续调用方法完成多个元素的添加。代码如下:

先说不使用Singular的方法

运行结果:

使用@Singular注解

运行结果:

@Slf4j

Lombok 支持多种日志框架的注解,可以根据你使用的日志框架选择合适的注解。以下是 Lombok 提供的部分日志注解及其对应的日志框架:

@Log4j:

自动生成一个 org.apache.log4j.Logger 对象。

适用于 Apache Log4j 1.x 版本。

@Slf4j:

自动生成一个 org.slf4j.Logger 对象。

适用于 SLF4J(Simple Logging Facade for Java),这是一种日志门面,可以与多种实际的日志框架(如 Logback、Log4j 等)集成。

@Log4j2:

自动生成一个 org.apache.logging.log4j.Logger 对象。

适用于 Apache Log4j 2.x 版本。

使用示例

假设我们有一个类 `ExampleClass`,并且我们想要使用 SLF4J 作为日志框架,我们可以这样使用 `@Slf4j` 注解:

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class UserService {
    public void login(){
        log.info("登录验证...");
    }
    // 测试
    public static void main(String[] args) {
        UserService userService = new UserService();
        userService.login();
    }
}

在这个例子中,`log` 是一个静态成员变量,表示一个 `org.slf4j.Logger` 对象。Lombok 自动生成了这个日志对象,并且你可以直接使用它来进行日志记录。

选择合适的注解

选择哪个注解取决于你使用的日志框架。例如:

  • 如果你使用的是 SLF4J,可以选择 `@Slf4j`。
  • 如果你使用的是 Log4j 1.x,可以选择 `@Log4j`。
  •  如果你使用的是 Log4j 2.x,可以选择 `@Log4j2`。

注意事项

确保在使用这些注解之前,已经在项目中引入了相应的日志框架依赖。例如,如果你使用 SLF4J,你需要在项目中添加 SLF4J 的依赖,以及一个具体的日志实现(如 Logback)。对于其他日志框架,也需要相应地添加依赖。

示例依赖

如果你使用 Maven 项目,并且选择了 SLF4J + Logback 的组合,可以添加以下依赖:

<!--Slf4j日志规范-->
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>2.0.16</version>
</dependency>
<!--Slf4j日志实现:logback-->
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.5.11</version>
</dependency>

通过这些日志注解,你可以方便地在类中使用日志记录功能,而无需手动创建日志对象。

执行结果:

三、MyBatis逆向生成

MyBatis逆向工程:使用IDEA插件可以根据数据库表的设计逆向生成MyBatis的Mapper接口 与 MapperXML文件。

1.安装插件free mybatis tools

2.在IDEA中配置数据源

3.生成MyBatis代码放到SpringBoot项目中

在表上右键:Mybatis-Generator

代码生成后,如果在IDEA中看不到,这样做(重新从硬盘加载):

注意:生成的VipMapper接口上自动添加了@Repository注解,这个注解没用,删除即可。

4.编写mybatis相关配置

application.properties属性文件的配置:

spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springboot
spring.datasource.username=root
spring.datasource.password=123456

mybatis.mapper-locations=classpath:com/powernode/springboot/repository/*.xml
mybatis.configuration.map-underscore-to-camel-case=true

5.编写测试程序

对初始的Vip进行修改

测试

到此,Spring Boot整合MyBatis结束!

四、 整合SpringMVC(SSM整合)

SSM整合:Spring + SpringMVC + MyBatis

Spring Boot项目本身就是基于Spring框架实现的。因此SSM整合时,只需要在整合MyBatis框架之后,引入`web启动器`即可完成SSM整合。

1.使用脚手架创建SpringBoot项目

添加依赖:web启动器、mybatis启动器、mysql驱动依赖、lombok依赖

项目结构:

2.使用free mybatis tool插件逆向生成MyBatis代码

springboot数据库中的t_vip表逆向生成mybatis代码。这里不再赘述。

3.整合MyBatis

编写数据源的配置

在主入口类上添加@MapperScan注解

4.编写service

编写`VipService`接口:

public interface VipService {
    /**
     * 根据id获取会员信息
     * @param id 会员标识
     * @return 会员信息
     */
    Vip getById(Long id);
}

编写`VipServiceImpl`实现类:

5.编写controller

编写`VipController`,代码如下:

@RestController
public class VipController {
    
    @Autowired
    private VipService vipService;
    
    @GetMapping("/vip/{id}")
    public Vip detailById(@PathVariable("id") Long id){
        Vip vip = vipService.getById(id);
        return vip;
    }
}

6.启动服务器测试

执行SpringBoot项目主入口的main方法,启动Tomcat服务器:

打开浏览器访问:

到此为止,SSM框架就集成完毕了,通过这个集成也可以感觉到SpringBoot简化了SSM三大框架的集成。

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误-CSDN博客

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

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

相关文章

VTK 显示文字、图片及2D/3D图

1. 基本环境设置 首先确保你已经安装了VTK库&#xff0c;并配置好了C开发环境。 #include <vtkSmartPointer.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h> #include <vtkRenderer.h> 2. 显示文字 2D文字 #include &l…

小白如何在cursor中使用mcp服务——以使用notion的api为例

1. 首先安装node.js,在这一步的时候不要勾选不要勾选 2. 安装完之后,前往notion页面 我的创作者个人资料 | Notion 前往集成页面&#xff0c;添加新集成&#xff0c;自己输入名字&#xff0c;选择内部 新建完之后&#xff0c;进入选择只读 复制密匙 然后前往cursor页面 新建…

引领AI安全新时代 Accelerate 2025北亚巡展·北京站成功举办

6月5日&#xff0c;网络安全行业年度盛会——"Accelerate 2025北亚巡展北京站"圆满落幕&#xff01;来自智库、产业界、Fortinet管理层及技术团队的权威专家&#xff0c;与来自各行业的企业客户代表齐聚一堂&#xff0c;围绕"AI智御全球引领安全新时代"主题…

为什么说数列是特殊的函数

文章目录 前情概要函数特性特殊之处典例剖析前情概要 高三的学生几乎都听老师说过,数列是特殊的函数,那么如何理解这句话呢,无外乎需要关注两点:①函数性,②特殊性,以下举例说明,帮助各位学子理解。 函数特性 既然是按照一定的次序排列而成的一列数字,那么这些数字(…

解决uniapp开发app map组件最高层级 遮挡自定义解决底部tabbar方法

subNvue&#xff0c;是 vue 页面的原生子窗体&#xff0c;把weex渲染的原生界面当做 vue 页面的子窗体覆盖在页面上。它不是全屏页面&#xff0c;它给App平台vue页面中的层级覆盖和原生界面自定义提供了更强大和灵活的解决方案。它也不是组件&#xff0c;就是一个原生子窗体。 …

96. 2017年蓝桥杯省赛 - Excel地址(困难)- 进制转换

96. Excel地址&#xff08;进制转换&#xff09; 1. 2017年蓝桥杯省赛 - Excel地址&#xff08;困难&#xff09; 标签&#xff1a;2017 省赛 1.1 题目描述 Excel 单元格的地址表示很有趣&#xff0c;它使用字母来表示列号。 比如&#xff0c; A 表示第 1 列&#xff0c;…

PPT转图片拼贴工具 v1.0

软件介绍 这个软件的作用就是将单个PPT的每一页转换为单独的图片&#xff0c;然后将图片进行拼接起来。 但是我没有还没有解决一次性处理多个文件。 效果展示如下&#xff1a; 软件安装 软件源码 import os import re import win32com.client from PIL import Imagedef con…

【行驶证识别成表格】批量OCR行驶证识别与Excel自动化处理系统,行驶证扫描件和照片图片识别后保存为Excel表格,基于QT和华为ocr识别的实现教程

在车辆管理、物流运输、保险理赔等领域&#xff0c;经常需要处理大量的行驶证信息。传统的人工录入方式效率低、易出错&#xff0c;而使用 OCR 技术可以自动识别行驶证图片中的文字信息&#xff0c;极大提高数据处理效率。该系统可以应用于以下场景&#xff1a; 保险公司快速…

Linux--进程的状态

1.进程状态在所有系统中宏观的大致模型 1.1、进程状态与变迁 基础状态&#xff1a;涵盖创建、就绪、运行、阻塞、结束等核心状态&#xff0c;描述进程从诞生到消亡的生命周期流转&#xff0c;如创建后进入就绪&#xff0c;争抢 CPU 进入运行&#xff0c;遇 I/O 或资源等待则转…

(nice!!!)(LeetCode每日一题)2434. 使用机器人打印字典序最小的字符串(贪心+栈)

题目&#xff1a;2434. 使用机器人打印字典序最小的字符串 思路&#xff1a;贪心栈&#xff0c;时间复杂度0(n)。 字符串t其实就是栈&#xff0c;后进先出。要让p的字典序最小&#xff0c;那当然是t每次弹出的字符&#xff0c;都小于或等于“剩下未入t里的字符串的字符”&#…

008-libb64 你有多理解base64?-C++开源库108杰

正确认识二进制数据和文本数据的关系;深刻理解 base64 编码核心等式&#xff1a;256256256 64646464 经常听到——以至 AI 也会这么回答的&#xff1a;base64 编码用于将二进制数据&#xff0c;转换为文本数据。但是&#xff0c;众所周知&#xff0c;在数字电子计算机中&#…

电子电路基础2(杂乱)

电容器 容抗 滤波电路&#xff08;半波&#xff09; 全波整流 因为A点的电压比D点的电压高&#xff0c;所以D点会走向C点 电感基础 什么是电感器&#xff1f; 一种把电能转换成磁能&#xff0c;并可以将磁能存储起来的元器件。 在嵌入式开发中&#xff0c;电感主要用于动态能量…

LazyOwn RedTeam/APT 框架是第一个具有人工智能驱动的 CC 的 RedTeam 框架

一、软件介绍 文末提供程序和源码下载 LazyOwn RedTeam/APT 框架是第一个具有人工智能驱动的 C&C 的 RedTeam 框架&#xff0c;具有隐藏活动的 rootkit、与 Windows/Linux/Mac OSX 兼容的不可检测的可塑植入物&#xff0c;以及自配置后门。凭借其 Web 界面和强大的…

电脑的ip地址会自动变怎么办?原因解析和解决方法

在当今互联网时代&#xff0c;IP地址是每台联网设备的"身份证"&#xff0c;但很多用户都遇到过IP地址自动变化的情况。这种现象既可能发生在内网&#xff08;局域网&#xff09;环境中&#xff0c;也可能出现在外网&#xff08;公网&#xff09;连接中。要理解IP地址…

PDF 转 HTML5 —— HTML5 填充图形不支持 Even-Odd 奇偶规则?(第一部分)

在填充 PDF 中的图形时&#xff08;以及许多其他技术中&#xff09;&#xff0c;你可以选择使用 Even-Odd&#xff08;奇偶&#xff09; 或 Non-Zero&#xff08;非零&#xff09; 填充规则。 对于那些已经在想“你在说啥&#xff1f;”的朋友&#xff0c;别担心&#xff0c;我…

【八股消消乐】MySQL参数优化大汇总

&#x1f60a;你好&#xff0c;我是小航&#xff0c;一个正在变秃、变强的文艺倾年。 &#x1f514;本专栏《八股消消乐》旨在记录个人所背的八股文&#xff0c;包括Java/Go开发、Vue开发、系统架构、大模型开发、具身智能、机器学习、深度学习、力扣算法等相关知识点&#xff…

CSS 平铺+自动换行效果

先上效果图 样式 <template><div class"activity-questions"><h1>活动题库</h1><div v-if"loading" class"loading">加载中...</div><div v-else><div v-if"questions.length 0" clas…

微服务网关SpringCloudGateway+SaToken鉴权

目录 概念 前置知识回顾 拿到UserInfo 用于自定义权限和角色的获取逻辑 最后进行要进行 satoken 过滤器全局配置 概念 做权限认证的时候 我们首先要明确两点 我们需要的角色有几种 我们需要的权限有几种 角色 分两种 ADMIN 管理员 &#xff1a;可管理商品 CUSTIOMER 普通…

永磁同步电机控制算法--模糊PI转速控制器

一、原理介绍 在常规的PID控制系统的基础上提出了一种模糊PID以及矢量变换方法相结合的控制系统&#xff0c;经过仿真分析对比证明&#xff1a; 模糊PID控制系统能够有效的提高永磁同步电机的转速响应速度&#xff0c;降低转矩脉动&#xff0c;增强了整体控制系统的抗干扰能力…

Elasticsearch集群最大分片数设置详解:从问题到解决方案

目录 前言 1 问题背景&#xff1a;重启后设置失效 2 核心概念解析 2.1 什么是分片(Shard)&#xff1f; 2.2 cluster.max_shards_per_node的作用 2.3 默认值是多少&#xff1f; 3 参数设置的两种方式 3.2 持久性设置(persistent) 3.2 临时设置(transient) 4 问题解决方…