Java研学-SpringBoot(四)

news2024/11/27 11:10:11

六 SpringBoot 项目搭建

1 创建项目

  spring2.X版本在2023年11月24日停止维护,而Spring3.X版本不支持JDK8,JDK11,最低支持JDK17,目前阿里云还是支持创建Spring2.X版本的项目
创建项目
选择所需模块

2 修改所需依赖版本 – pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.3.RELEASE</version>
        <relativePath/>
    </parent>
    <groupId>cn.tj</groupId>
    <artifactId>play_boot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>play_boot</name>
    <description>play_boot</description>
    <properties>
        <java.version>8</java.version>
    </properties>
    <dependencies>
        <!-- spring boot Web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- spring boot Test-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

3 配置数据库连接池

 ① 添加依赖

<!--此处不需设置版本,父工程已经规定好了-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

 ② application.properties 文件配置4要素 – 小改(可在对应的DataSourceProperties文件中获取配置前缀)

# 不同版本对应不同的路径
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql:///play_boot?serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root

 ③ 测试 此时会报NoSuchBeanDefinitionException错误,springboot实际上并没有帮我们创建这个Bean对象,这是因为@ConditionalOnClass 注解没有找到必需的类 javax.transaction.TransactionManager,此时将事务注解添加即可

// 错误信息
// @ConditionalOnClass did not find required class 'javax.transaction.TransactionManager' (OnClassCondition)
@SpringBootTest
class Play_bootApplicationTests {
    @Autowired
    private DataSource dataSource;
    @Test
    void testLoad(){
    	// Hikari连接池是springboot自带的,接下来要配置Druid 连接池
    	// HikariDataSource (null) 此时值不为null,只是显示为null(表示此刻没有配置)
        System.out.println(dataSource);
    }
}

 ④ 导入事务依赖,上面的测试可正常运行

<!-- Spring JDBCTX -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

 ⑤ 配置 Druid 连接池,添加依赖即可,Spring Boot 的自动配置中含有 DataSourceAutoConfiguration 配置类,会先检查容器中是否已经有连接池对象,有就用,没有则会使用默认的连接池(Hikari),此时通过 dataSource.getClass() 方法即可获取当前的连接池对象,com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceWrapper,springboot会自动帮我们装配DataSource 对象

<!-- druid -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.21</version>
</dependency>

4 集成 MyBatis

  集成 MyBatis 所需要的SqlSessionFactory 在springboot中会自动装配,而SqlSessionFactory 所需要的数据源,已经配置完了,此时需要配置的是实体类的别名(mapper映射文件编译后在同一文件夹中,故不需要配置)
 ① 导入依赖

<!-- Mybatis 集成到 SpringBoot 中的依赖 -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.1</version>
</dependency>

 ② application.properties 中配置实体类别名

mybatis.type-aliases-package=cn.tj.play_boot.domain

 ③ 测试 SqlSessionFactory 是否成功创建

@SpringBootTest
class Play_bootApplicationTests {
    @Autowired
    private DataSource dataSource;
    @Autowired
    private SqlSessionFactory sqlSessionFactory;
    @Test
    void testLoad(){
        //System.out.println(dataSource.getClass());
        System.out.println(sqlSessionFactory);
        // org.apache.ibatis.session.defaults.DefaultSqlSessionFactory@799ed4e8
    }
}

 ④ 配置Mapper对象,扫描 Mapper 接口只要在配置类上贴个注解 @MapperScan 并指定扫描的包路径即可生成所有的mapper实体类。

@SpringBootApplication
@MapperScan("cn.tj.play_boot.mapper")
public class Play_bootApplication {
    public static void main(String[] args) {
        SpringApplication.run(Play_bootApplication.class, args);
    }
}

 ⑤ 测试时报错 The server time zone 数据库连接池连接失败短时间内会多次链接,这个错误出现的原因是没有设置时区

@SpringBootTest
class Play_bootApplicationTests {
    @Autowired
    private DataSource dataSource;
    @Autowired
    private SqlSessionFactory sqlSessionFactory;
    @Autowired
    private DepartmentMapper departmentMapper;
    @Test
    void testLoad(){
        //System.out.println(dataSource.getClass());
        //System.out.println(sqlSessionFactory);
        System.out.println(departmentMapper.selectAll());
    }
}

 ⑥ application.properties 中配置日志,设定日志级别

logging.level.cn.tj.play_boot.mapper=trace

 ⑦ 配置事务,导入事务依赖后,于service层贴上@Service注解,主启动类的注解就会找到他(service层的方法上含有事务注解@Transactional),直接测试即可

@SpringBootTest
class Play_bootApplicationTests {
    @Autowired
    private DataSource dataSource;
    @Autowired
    private SqlSessionFactory sqlSessionFactory;
    @Autowired
    private DepartmentMapper departmentMapper;
    @Autowired
    private DepartmentService departmentService;
    @Test
    void testLoad(){
        //System.out.println(dataSource.getClass());
        //System.out.println(sqlSessionFactory);
        //System.out.println(departmentMapper.selectAll());
        System.out.println(departmentService.listAll());
        // 查看对象类型真实对象说明没加事务,代理对象说明加事务了
        System.out.println(departmentService.getClass());
        // class cn.tj.play_boot.service.impl.DepartmentServiceImpl$$EnhancerBySpringCGLIB$$418bef25
        // 该类型为代理对象,说明加事务了
        // class cn.tj.play_boot.service.impl.DepartmentServiceImpl
        // 该类型为真实对象,没加事务
        // class com.sun.proxy.$Proxy61 此为JDK动态代理对象
    }
}

 ⑧ application.properties 中配置代理对象,可将代理对象设置为JDK动态代理,默认为CGLIB动态代理

# 默认为true,改为false即可更换为JDK动态代理
spring.aop.proxy-target-class=false

 ⑨ 数据库以及实体类

# 数据库
CREATE TABLE `department` (
  `id` bigint(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT NULL,
  `sn` varchar(50) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=808 DEFAULT CHARSET=utf8;
// 实体类
@Data
public class Department {
    private Long id;
    private String name;
    private String sn;
}
// mapper接口
public interface DepartmentMapper {
    /*删除*/
    int deleteByPrimaryKey(Long id);
    /*增加*/
    int insert(Department record);
    /*根据id查询*/
    Department selectByPrimaryKey(Long id);
    /*查询所有*/
    List<Department> selectAll();
    /*修改*/
    int updateByPrimaryKey(Department record);
    /*查询总条数*/
    public int selectForCount(QueryObject qo);
    /*分页查询*/
    public List<Department> selectForList(QueryObject qo);
}
<!--mapper.xml-->
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="cn.tj.play_boot.mapper.DepartmentMapper" >
  <resultMap id="BaseResultMap" type="cn.tj.play_boot.domain.Department" >
    <id column="id" property="id" jdbcType="BIGINT" />
    <result column="name" property="name" jdbcType="VARCHAR" />
    <result column="sn" property="sn" jdbcType="VARCHAR" />
  </resultMap>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Long" >
    delete from department
    where id = #{id,jdbcType=BIGINT}
  </delete>
  <insert id="insert" parameterType="cn.tj.play_boot.domain.Department" useGeneratedKeys="true" keyProperty="id" >
    insert into department (name, sn)
    values (#{name,jdbcType=VARCHAR}, #{sn,jdbcType=VARCHAR})
  </insert>
  <update id="updateByPrimaryKey" parameterType="cn.tj.play_boot.domain.Department" >
    update department
    set name = #{name,jdbcType=VARCHAR},
      sn = #{sn,jdbcType=VARCHAR}
    where id = #{id,jdbcType=BIGINT}
  </update>
  <select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.Long" >
    select id, name, sn
    from department
    where id = #{id,jdbcType=BIGINT}
  </select>
  <select id="selectAll" resultMap="BaseResultMap" >
    select id, name, sn
    from department
  </select>
  <!--查询总条数-->
  <select id="selectForCount" resultType="int">
    SELECT count(*) from department
  </select>
  <!--分页查询部门-->
  <select id="selectForList" resultMap="BaseResultMap">
    SELECT * from  department limit #{start},#{pageSize}
  </select>
</mapper>

 ⑩ service层

// 接口
public interface DepartmentService {
    void delete(Long id);
    void save(Department department);
    Department get(Long id);
    List<Department> listAll();
    void update(Department department);
    /*分页查询*/
    PageResult<Department> query(QueryObject qo);
}
// 实现类
@Service
public class DepartmentServiceImpl implements DepartmentService {
    /*注入mapper*/
    @Autowired
    private DepartmentMapper departmentMapper;
    @Override
    public void delete(Long id) {
       departmentMapper.deleteByPrimaryKey(id);
    }
    // 事务注解
    @Transactional
    @Override
    public void save(Department department) {
       departmentMapper.insert(department);
    }
    @Override
    public Department get(Long id) {
        Department department = departmentMapper.selectByPrimaryKey(id);
        return department;
    }
    @Override
    public List<Department> listAll() {
        List<Department> departmentList = departmentMapper.selectAll();
        return departmentList;
    }
    @Override
    public void update(Department department) {
       departmentMapper.updateByPrimaryKey(department);
    }
    /*分页查询*/
    @Override
    public PageResult<Department> query(QueryObject qo) {
        //查询总条数
        int totalCount = departmentMapper.selectForCount(qo);
        if (totalCount==0){
            return new PageResult<>(qo.getCurrentPage(),qo.getPageSize(),0, Collections.emptyList());
        }
        //分页查询部门
        List<Department> departmentList = departmentMapper.selectForList(qo);
        //创建返回的分页对象
        PageResult<Department> pageResult=new PageResult<>(qo.getCurrentPage(),
                qo.getPageSize(),totalCount,departmentList);
        return pageResult;
    }
}

 小结
  springboot对持久层(1.2.3)及业务层(4.5.6)的优化
  1.自动配置DataSource对象,配置4要素同时导入指定连接池依赖(starter启动器)即可自动替换所需要的连接池对象
  2.自动配置SqlSessionFactory对象,配置指定实体类别名既可
  3.通过MapperScan注解优化Mapper对象,指定好具体路径可自动生成Mapper接口代理类
  4.不再扫描业务层对象
  5.不再配置事物管理器对象
  6.不再配置事务解析器对象

5 集成 Web

 ① 导入所需依赖

<!-- spring boot web 启动器(之前已添加了) -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

 ② application.properties 文件中修改端口号(浏览器端口默认80,地址中可省略书写端口号)

server.port=80

 ③ 于resources目录下创建static目录用来存放静态资源(原来位于webapp目录下的static目录),于resources目录下创建的templates模板目录用来存放模板(原来位于webapp目录下的WEB-INF目录中的views目录,类似WEB-INF不能直接访问),static相当于webapp这意味着路径中不需要输入static,但针对于静态资源需要放行的特点,以后拦截器要排除/static/**的路径,在application.properties中做了以下配置后,路径中就需要输入static了

// 告诉springboot访问静态资源路径以后都需要以/static/**开头 
// 所有以 /static/ 开头的 URL 都会被映射到静态资源目录
spring.mvc.static-path-pattern=/static/**

6 集成Thymeleaf

 ① 导入所需依赖

<!-- 引入 Thymeleaf 依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

 ② application.properties 文件中,配置Thymeleaf前缀(默认路径找templates目录,可省略)后缀(默认.html,可省略)model(默认HTML,可省略),编码集(默认UTF-8,可省略),缓存默认为true需要设置为false(开发阶段不建议打开缓存)

# 前缀
spring.thymeleaf.prefix=classpath:/templates/

# 后缀
spring.thymeleaf.suffix=.html

# model
spring.thymeleaf.mode=HTML

# model
spring.thymeleaf.mode=HTML

# 编码集
spring.thymeleaf.encoding=UTF-8

# 缓存
spring.thymeleaf.cache=false

 ③ controller层

@Controller
@RequestMapping("department")
public class DepartmentController {
    /*注入业务逻辑层对象*/
    @Autowired
    private DepartmentService departmentService;
    /*查询部门*/
    @RequestMapping("selectAll")
    public String selectAll(Model model){
        List<Department> departmentList = departmentService.listAll();
        model.addAttribute("departmentList",departmentList);
        return "department/list";
    }
    /*跳转到增加或修改页面*/
    @RequestMapping("input")
    public String input(Long id,Model model){
        /*根据id判断是否做修改*/
        if (id!=null){
            //根据id查询
            Department department = departmentService.get(id);
            //将部门对象存储到作用域
            model.addAttribute("department",department);
        }
        return "department/input";
    }
    /*保存增加或修改*/
    @RequestMapping("saveOrUpdate")
    public String saveOrUpdate(Department department){
        if (department.getId()!=null){
            //执行修改操作
            departmentService.update(department);
        }else {
            //执行增加操作
            departmentService.save(department);
        }
        //跳转查询
        return "redirect:/department/listAll";
    }
    /*删除部门*/
    @RequestMapping("delete")
    public String delete(Long id){
        departmentService.delete(id);
        return "redirect:/department/listAll";
    }
    /*分页查询部门*/
    @RequestMapping("listAll")
    public String listAll(Model model,
                          @RequestParam(value = "currentPage",required = false,defaultValue = "1") Integer currentPage,
                          @RequestParam(value = "pageSize",required = false,defaultValue = "2") Integer pageSize
                          /*参数value对应  required为false表示可以不传此参数  defaultValue表示不传参数时的默认值为何值*/
    ){
        QueryObject qo=new QueryObject();
        qo.setCurrentPage(currentPage);
        qo.setPageSize(pageSize);
        PageResult<Department> pageResult = departmentService.query(qo);
        model.addAttribute("pageResult",pageResult);
        return "department/list";
    }
}

 ④ html模板,访问http://localhost/department/input?id=801即可查询对应的部门信息(801为数据库中数据的id)

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>部门新增或者修改</title>
</head>
<body>
<h3>部门编辑</h3>
<form action="/department/saveOrUpdate" method="post">
    <input type="hidden" name="id" th:value="${department?.id}">
    <input type="text" name="name" placeholder="名称" th:value="${department.name}"><br/>
    <input type="text" name="sn" placeholder="缩写" th:value="${department.sn}"><br/>
    <input type="submit" value="提交">
</form>
</body>
</html>

 小结
  springboot对控制层的优化
  1.前端文件存放位置更明确
  2.不需再写扫描控制层
  3.不需再写静态资源处理
  4.不需再写MVC注解解析器
  5.thymeleaf集成优化,小改即可
  6.前端控制器不用自行配置了,路径默认为/

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

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

相关文章

从0开始打架基于VUE的前端项目

准备与版本 安装nodejs(v20.11.1)安装vue脚手架(@vue/cli 5.0.8) ,参考(https://cli.vuejs.org/zh/)vue版本(2.7.16),vue2的最后一个版本初始化项目 创建一个git项目(可以去gitee/github上创建),注意创建一个空项目创建项目vue create mvp-admin-vue-ui删除自己创建的gi…

如何制作Word模板并用Java导出自定义的内容

1前言 在做项目时会按照指定模板导出word文档,本文讲解分析需求后,制作word模板、修改模板内容,最终通过Java代码实现按照模板自定义内容的导出。 2制作word模板 2.1 新建word文档 新建word文档,根据需求进行编写模板内容,调整行间距和段落格式后将指定替换位置留空。…

50 基于 provide/inject 属性的模型视图不同步问题

前言 这是一个之前 2023年12月月底碰到的一个问题 这个问题还是 比较复杂, 呵呵 这个在当时 看来 我甚至觉得 我可能搞不定这个问题 但是 当时出现了一些 其他的可以临时解决这个问题的方式, 因此 当时就没有深究 然后 过了两天 重新复现了一下 问题, 重新看了一下 这个问题…

2023年第十四届蓝桥杯大赛软件类省赛C/C++研究生组真题(代码完整题解)

C题-翻转⭐ 标签:贪心 简述:如果 S 中存在子串 101 或者 010,就可以将其分别变为 111 和 000,操作可以无限重复。最少翻转多少次可以把 S 变成和 T 一样。 链接: 翻转 思路:要求步骤最少->S每个位置最多修改一次->从头开始遍历不匹配就翻转->翻转不了就-1 …

CVE-2023-38408漏洞修复 - 升级openssl和openssh

CVE-2023-38408 OpenSSH 代码问题漏洞修复 - 升级openssl和openssh ※ 重要说明&#xff1a; 1、升级后会导致无法用ssh远程登录&#xff0c;提示“Permission denied, please try again.” 2、解决方案请查看本章节【三、解决升级后无法用ssh远程登录】 目录 CVE-2023-38408 O…

集合(ArrayList,HashMap,HashSet)详解+ entrySet的应用

集合 例题引入——直线题意分析根据下面的参考代码&#xff0c;自己模仿的参考代码&#xff08;加一点点我的小tips&#xff09; 1.java集合引入2.为什么要使用集合&#xff1f;3.List、Set、Queue和Map的区别4.ListList——ArrayList&#xff08;&#xff01;&#xff01;实用…

武汉星起航:跨境电商获各大企业鼎力支持,共筑繁荣生态

随着全球化和数字化的深入发展&#xff0c;跨境电商行业逐渐成为连接国内外市场的重要桥梁。在这一进程中&#xff0c;各大企业纷纷加大对跨境电商行业的支持力度&#xff0c;通过投资、合作与创新&#xff0c;共同推动行业的繁荣与发展。武汉星起航将探讨各大企业对跨境电商行…

图片标注编辑平台搭建系列教程(6)——fabric渲染原理

原理 fabric的渲染步骤大致如下&#xff1a; 渲染前都设置背景图然后调用ctx.save()&#xff0c;存储画布的绘制状态参数然后调用每个object自身的渲染方法最后调用ctx.restore()&#xff0c;恢复画布的保存状态后处理&#xff0c;例如控制框的渲染等 值得注意的是&#xff0…

Verilog语法之case语句学习

case分支语句是一种实现多路分支控制的分支语句。与使用if-else条件分支语句相比&#xff0c;采用case分支语句来实现多路控制会变得更加的方便直观。 case分支语句通常用于对微处理器指令译码功能的描述以及对有限状态机的描述。Case分支语句有“case”、“casez”、“casex”…

使用pdf表单域填充pdf内容

需要引用如下包 <dependency><groupId>com.itextpdf</groupId><artifactId>itext-core</artifactId><version>8.0.3</version><type>pom</type></dependency>1、预先准备一个pdf模板&#xff0c;并在指定位置添加…

C/C++语言实现简易通讯录 [含文件操作,循环双链表]

文章目录 C/C语言实现简易通讯录概要基本功能运行截图展示主要代码展示 &#x1f396; 博主的CSDN主页&#xff1a;Ryan.Alaskan Malamute &#x1f4dc; 博主的代码仓库主页 [ Gitee ]&#xff1a;ryanala [GitHub]&#xff1a; Ryan-Ala C/C语言实现简易通讯录 ⚠⚠⚠ …

Android 开发投屏软件

一、背景 作为Android开发总会有给他人share自己APP情况&#xff0c;一般在线会议投屏&#xff0c;总是需要在手机上安装对应会议软件特别麻烦~ 二、投屏 Android Studio已经自带了投屏能力&#xff0c;可以在电脑端直接控制手机&#xff0c;同步起来非常方便简单 打开步骤 …

【Kubernetes】K8s 中的 Pod 驱逐

K8s 中的 Pod 驱逐 1.Pod 被驱逐的原因&#xff1a;抢占和节点压力2.抢占式驱逐2.1 Pod 调度2.1.1 过滤2.1.2 计分 2.2 Pod 优先级2.3 优先级示例 3.节点压力驱逐3.1 服务质量等级3.1.1 Guaranteed3.1.2 Burstable3.1.3 BestEffort 4.其他类型的驱逐4.1 API 发起的驱逐&#xf…

[机器学习]练习-KNN算法

1&#xff0e;&#x1d458;近邻法是基本且简单的分类与回归方法。&#x1d458;近邻法的基本做法是&#xff1a;对给定的训练实例点和输入实例点&#xff0c;首先确定输入实例点的&#x1d458;个最近邻训练实例点&#xff0c;然后利用这&#x1d458;个训练实例点的类的多数来…

代码随想录算法训练营三刷 day38 | 动态规划之 509. 斐波那契数 70. 爬楼梯 746. 使用最小花费爬楼梯

三刷day38 509. 斐波那契数1 确定dp数组以及下标的含义2 确定递推公式3 dp数组如何初始化4 确定遍历顺序5 举例推导dp数组 70. 爬楼梯1 确定dp数组以及下标的含义2 确定递推公式3 dp数组如何初始化4 确定遍历顺序5 举例推导dp数组 746. 使用最小花费爬楼梯1 确定dp数组以及下标…

Disruptor

前言 大家好&#xff0c;我是jiantaoyab&#xff0c;这是我作为学习笔记总结应用篇最后一篇&#xff0c;本章大量的参考了别的博主的文章。 我们今天一起来看一个开源项目 Disruptor。看看我们怎么利用 CPU 和高速缓存的硬件特性&#xff0c;来设计一个对于性能有极限追求的系…

vlan间单臂路由

【项目实践4】 --vlan间单臂路由 一、实验背景 实验的目的是在一个有限的网络环境中实现VLAN间的通信。网络环境包括两个交换机和一个路由器&#xff0c;交换机之间通过Trunk链路相连&#xff0c;路由器则连接到这两个交换机的Trunk端口上。 二、案例分析 在网络工程中&#…

python批量转化pdf图片为jpg图片

1.把pdf图片批量转为jpg&#xff1b;需要注意的是&#xff0c;需要先安装poppler这个软件&#xff0c;具体安装教程放在下面代码中了 2.代码 #poppler安装教程参考&#xff1a;https://blog.csdn.net/wy01415/article/details/110257130 #windows上poppler下载链接&#xff1a…

只出现一次的数字 II

题目链接 只出现一次的数字 II 题目描述 注意点 nums中&#xff0c;除某个元素仅出现一次外&#xff0c;其余每个元素都恰出现三次设计并实现线性时间复杂度的算法且使用常数级空间来解决此问题 解答思路 本题与只出现一次的数字的数字类似&#xff0c;区别是重复的数字会…