Spring框架-入门(IOC,DI)

news2024/11/20 12:24:24

文章目录

  • Spring框架
    • 简介
    • 创建Spring项目
    • 理解IOC和DI:
      • IOC控制反转
        • 示例
          • pom.xml
          • Person.java
          • applicationContext.xml
          • PersonTest.java
      • DI依赖注入
        • 传统的方式
          • GreetingService.java
          • GreetingServiceImpl.java
          • GreetingTest.java
        • 使用DI依赖注入
          • GreetingService.java
          • GreetingServiceImpl.java
          • AppConfig.java
          • AppTest.java

Spring框架

spring官网;https://spring.io/

简介

Spring框架是一个开源的Java应用程序框架,它提供了一种全面的编程和配置模型,可用于构建现代化的基于Java的企业级应用程序。

Spring框架提供的核心功能包括控制反转(IoC)、依赖注入(DI)、面向切面编程(AOP)、数据访问、事务管理、Web应用程序开发等方面。它可以与其他技术和框架无缝集成,如Hibernate、MyBatis、Struts、Servlet API,SpringMVC等。

使用Spring框架可以简化Java应用程序的开发过程,减少代码量,提高代码的可重用性和可维护性。它也提供了各种扩展和插件,以满足特定场景下的需求。

Spring框架的设计思想是基于松耦合、可扩展和可重用的原则,使得Java开发者可以更专注于业务逻辑的实现,而不必关注底层技术的细节。它已成为Java企业级应用程序开发中最流行和广泛使用的框架之一。

创建Spring项目

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

pom.xml

<?xml version="1.0" encoding="UTF-8"?> <!-- xml声明,指定版本和编码 -->
<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
         http://maven.apache.org/xsd/maven-4.0.0.xsd"><!-- pom文件的根元素 -->

    <!-- 指定pom模型的版本 -->
    <modelVersion>4.0.0</modelVersion>

    <!-- 项目所属组织或公司的唯一标识符 -->
    <groupId>com.sin</groupId>
    <!-- 项目的唯一标识符 -->
    <artifactId>spring_demo</artifactId>
    <!-- 项目的版本号 -->
    <version>1.0-SNAPSHOT</version>

    <!-- 固定项目依赖版本 -->
    <properties>
        <!-- 指定源代码的字符编码 -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <!-- 指定使用的Spring框架版本 -->
        <spring.version>5.3.13</spring.version>
    </properties>

    <dependencies>
        <!-- spring-core库的依赖 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- spring-context库的依赖 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- spring-beans库的依赖 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
    </dependencies>
</project>

理解IOC和DI:

在传统的程序

User.java

package com.sin.pojo;

/**
 * @createTime 2023/12/29 16:22
 * @createAuthor SIN
 * @use
 */
public class User {
    private int id;
    private String name;


    public void setId(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

UserDao.java

package com.sin.Dao;

import com.sin.pojo.User;

/**
 * @createTime 2023/12/29 16:22
 * @createAuthor SIN
 * @use
 */
public class UserDao {
    public User getUser(int userId) {
        // 模拟从数据库中获取用户信息的逻辑
        // 这里假设直接返回一个User对象
        User user = new User();
        user.setId(userId);
        user.setName("张三");
        return user;
    }
}

UserService.java

package com.sin.service;

import com.sin.Dao.UserDao;
import com.sin.pojo.User;

/**
 * @createTime 2023/12/29 16:21
 * @createAuthor SIN
 * @use
 */
public class UserService {

    private UserDao userDao;

    public UserService() {
        userDao = new UserDao();
    }

    /**
     * 该方法允许外部设置UserDao对象,这种方式称之为依赖注入
     *
     * @param userDao
     */
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void getUserInfo(int userId) {
        // 通过UserDao获取用户信息
        User user = userDao.getUser(userId);
        // 处理用户信息
        System.out.println("用户ID: " + user.getId());
        System.out.println("用户姓名: " + user.getName());
    }
}

在这里插入图片描述

在编写过程中发现:

  1. 需要获取数据时,需要创建UserSercie对象,每次创建UserService对象都会创建出一新的UserDao对象,这样做会导致内存的浪费,因为我们可能只需要一个UserDao对象,而不是每次都创建一个新的对象。
  2. 这种实现方式还存在对象生命周期的问题。如果UserService对象被销毁了,那么与之关联的UserDao对象也将被销毁,这可能会导致数据丢失或其他意想不到的问题。
  3. 高耦合性:UserServiceUserDao之间的关系非常紧密,UserService需要知道如何创建UserDao对象,并且需要在方法中直接调用UserDao的方法。这样做会使得代码高度耦合,难以维护。
  4. 代码重复:如果有多个类需要使用UserDao对象进行数据访问,那么就需要在每个类中都写出类似的代码,这将导致大量重复的代码,增加了代码的冗余。
  5. 可测试性差:在单元测试时,我们希望能够对UserService进行测试,而不是测试UserDao的实现。但是,由于UserService依赖于UserDao,因此需要在测试中实例化UserDao对象并设置到UserService中,这就使得测试变得困难。
  6. 不易扩展:如果我们需要更改UserDao的实现方式,比如从数据库中获取用户信息改为从Web服务中获取,那么就需要修改UserService的代码,这样做会使得代码更加脆弱,不易扩展。

这些问题可以通过使用IOC容器和DI框架来解决。在Spring框架中,我们可以通过配置文件或注解来告诉Spring容器如何创建对象并管理对象之间的依赖关系。Spring容器会在需要时自动创建对象,并确保每个对象只被创建一次,并且可以在整个应用程序中共享。这样做不仅可以提高应用程序的性能,还可以减少内存消耗和对象生命周期的问题。

在这里插入图片描述

IOC控制反转

控制反转(Inversion of Control,简称IoC)是一种软件设计原则,也是面向对象编程中的一种设计模式。它的核心思想是将对象的创建和依赖关系的管理交给容器来完成,而不是由对象自身来创建和管理其依赖的对象。

传统的程序设计中,对象之间的依赖关系常常通过对象自身来创建和管理。例如,在一个类中直接使用new关键字来创建其他类的实例,这样就导致了类与类之间的紧耦合,使得代码难以维护、扩展和测试。

而采用IoC的方式,对象之间的依赖关系被反转了。具体来说,IoC通过引入一个容在这里插入图片描述
器(如Spring框架的ApplicationContext),容器负责创建对象并管理对象之间的依赖关系。在IoC容器中,我们可以配置对象的创建方式、依赖关系以及其他属性,然后由容器来实例化对象,并将所需的依赖注入到对象中。

IoC的优点包括:

  1. 解耦:IoC可以降低对象之间的耦合度,使得代码更加灵活、可维护和可扩展。

  2. 便于测试:由于依赖关系由容器管理,我们可以很容易地对对象进行单元测试,而不需要真正地创建依赖对象。

  3. 可以更好地支持面向接口编程:通过IoC容器可以轻松地切换不同的实现类,从而支持面向接口编程的设计原则。

  4. 提高了代码的可读性和可维护性:通过配置文件或注解来管理对象的创建和依赖关系,使得代码的逻辑更加清晰、易于理解和维护。

示例
pom.xml
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.13</version>
</dependency>

spring-context是Spring的核心模块之一,提供了Spring应用程序上下文的基础设施支持,也是Spring框架中最重要的部分之一。它负责管理Spring应用程序中所有bean的声明周期,并提供了依赖注入和面向切面编程等重要的特性。

主要提供的功能:

  1. ApplicationContext接口:这是Spring应用程序上下文的核心接口,定义了获取bean、注册bean、发布事件等操作的API。
  2. BeanFactory接口:定义了Spring IoC容器的基本功能,这是Spring应用程序上下文的基础。
  3. AOP支持:Spring提供了强大的AOP支持,可以在应用程序中轻松实现面向切面编程。
  4. 事件处理:Spring提供了事件机制,允许应用程序中的各个组件之间进行通信和协作。
  5. SpEL表达式语言:Spring提供了一种表达式语言,允许开发者使用类似于EL的语法来处理复杂的表达式和逻辑。
  6. 数据绑定:Spring提供了一种灵活的数据绑定机制,可以将请求参数、属性文件、XML文档等各种数据源与Java对象进行绑定。
Person.java
package com.sin.pojo;

/**
 * @createTime 2024/1/2 8:44
 * @createAuthor SIN
 * @use
 */
public class Person {

    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
applicationContext.xml

注意:文件位置必须在src/main/resources目录下。这是默认的资源目录,Spring会自动将其包含在类路径中。

<?xml version="1.0" encoding="UTF-8"?><!-- XML声明,xml版本和编码格式 -->

<!-- spring配置文件起点  -->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--
        创建一个bean
            id : bean名称
            class :SpringBean对应的Java对象
    -->
    <bean id="person" class="com.sin.pojo.Person">
        <!-- 对bean的属性进行赋值 -->
        <property name="name" value="张三"/>
        <property name="age" value="18"/>
    </bean>


</beans>

bean : 是指Spring容器管理的Java对象,是Spring框架的核心概念之一。在Spring中Bean是应用程序的基本构建模块,代表着一个可重用的组件,它可以是任何普通的Java对象,也可以是由Spring容易创建和管理的特殊对象。这些对象可以通过Spring容器进行创建,配置和管理,从而实现依赖注入和面向切面编程等功能。

为什么使用Spring配置文件来赋值?

可以将应用程序中各个组件之间的依赖关系和属性值都统一管理,从而实现松耦合的设计和高度可配置性。

PersonTest.java
package com.sin.pojo;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @createTime 2024/1/2 8:48
 * @createAuthor SIN
 * @use 通过Spring容器获取并使用一个被管理的Bean
 */
public class PersonTest {

    public static void main(String[] args) {
        /**
         * 创建ApplicationContext对象,
         * ApplicationContext : 是Spring的顶层接口,用于表示整个应用程序的上下文环境
         * ClassPathXmlApplicationContext :通过指定文件来获取spring容器
         */
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        /**
         * 从容器中获取指定bean
         * getBean :返回类型为Object,我们需要将其为具体类型,
         */
        Person person = (Person) applicationContext.getBean("person");
        System.out.println(person);
    }
}

流程图
请添加图片描述

在整个过程中发现不用创建Person对象了,不需要new Person();减少了内存空间的占用。整个过程将对象的创建交给Spring来管理。

DI依赖注入

依赖注入(Dependency Injection,简称DI)是控制反转(IoC)的一个具体实现方式。它是指通过外部将对象的依赖关系注入到对象中,而不是由对象自身来创建和管理依赖的对象。

在传统的程序设计中,对象通常需要自己创建和管理其所依赖的其他对象。这种方式导致了对象之间的紧耦合,使得代码难以测试、扩展和维护。而采用依赖注入,我们将对象的依赖关系交给容器来管理,对象只需声明自己需要哪些依赖,容器则负责将相应的依赖注入到对象中。

依赖注入可以通过以下几种方式实现:

  1. 构造函数注入(Constructor Injection):通过对象的构造函数来传递依赖。在对象创建时,容器会根据构造函数的参数类型来自动注入所需的依赖。

  2. Setter方法注入(Setter Injection):通过对象的setter方法来注入依赖。容器会调用对象的setter方法,并将相应的依赖作为参数传入。

  3. 接口注入(Interface Injection):通过对象实现一个特定的接口,该接口定义了注入依赖的方法。容器会在对象创建后,调用接口方法并注入相应的依赖。

依赖注入的优点包括:

  1. 解耦:通过将对象的依赖关系交给容器管理,实现了对象之间的解耦,使得代码更加灵活、可维护和可扩展。

  2. 可测试性:由于对象的依赖关系由容器注入,我们可以很容易地使用模拟对象来进行单元测试,而不需要真实的依赖对象。

  3. 灵活性:依赖注入使得切换和替换不同的依赖实现变得容易,从而支持面向接口编程和可插拔的架构设计。

传统的方式
GreetingService.java
package com.sin.service;

/**
 * @createTime 2024/1/2 10:52
 * @createAuthor SIN
 * @use
 */
public interface GreetingService {

    public void sayHello();
}
GreetingServiceImpl.java
package com.sin.service.impl;

import com.sin.service.GreetingService;

import java.awt.*;

/**
 * @createTime 2024/1/2 10:52
 * @createAuthor SIN
 * @use
 */
public class GreetingServiceImpl implements GreetingService {

    @Override
    public void sayHello() {
        System.out.println("hello,world!");
    }
}
GreetingTest.java
package com.sin.test;

import com.sin.service.impl.GreetingServiceImpl;
import org.junit.Test;

/**
 * @createTime 2024/1/2 10:53
 * @createAuthor SIN
 * @use
 */
public class GreetingTest {

    @Test
    public void testGreeting(){
        GreetingServiceImpl greetingService = new GreetingServiceImpl();

        greetingService.sayHello();
    }
}
使用DI依赖注入
GreetingService.java
package com.sin.service;

/**
 * @createTime 2024/1/2 10:52
 * @createAuthor SIN
 * @use
 */
public interface GreetingService {

    public void sayHello();
}
GreetingServiceImpl.java
package com.sin.service.impl;

import com.sin.service.GreetingService;

import java.awt.*;

/**
 * @createTime 2024/1/2 10:52
 * @createAuthor SIN
 * @use
 */
public class GreetingServiceImpl implements GreetingService {

    @Override
    public void sayHello() {
        System.out.println("hello,world!");
    }
}
AppConfig.java
package com.sin.config;

import com.sin.service.GreetingService;
import com.sin.service.impl.GreetingServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @createTime 2024/1/2 10:56
 * @createAuthor SIN
 * @use
 */
@Configuration // 标记为一个配置类,该类将提供Bean的定义和配置,
public class AppConfig {

    /**
     * 定义一个Bean,方法名getGreetingService将作为Bean的名称,默认为方法名(也可以通过name属性指定其他名称)。
     * @return 创建GreetingServiceImpl对象, 该对象将被Spring容器管理,
     */
    @Bean
    public GreetingService getGreetingService() {
        return new GreetingServiceImpl();
    }
}

AppTest.java
package com.sin.test;

import com.sin.config.AppConfig;
import com.sin.service.GreetingService;
import com.sin.service.impl.GreetingServiceImpl;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @createTime 2024/1/2 10:57
 * @createAuthor SIN
 * @use
 */
public class AppTest {

    @Test
    public void test(){
        /**
         * 创建spring容器并加载配置类
         * new AnnotationConfigApplicationContext(AppConfig.class)创建对象时加载配置类
         */
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        // 获取依赖注入的Bean
        // 通过bean名称来获取
        GreetingService greetingService1 =(GreetingService) context.getBean("getGreetingService");
        // 通过bean类型来获取
        GreetingService greetingService2 =context.getBean(GreetingService.class);


        // 使用依赖注入的Bean
        greetingService1.sayHello();
        greetingService2.sayHello();

    }
}

AnnotationConfigApplicationContext是一个基于注解配置方式的Spring容器,它负责加载配置类、注册和管理Bean的定义、提供依赖注入功能以及管理Bean的生命周期。

在这里插入图片描述

两种方式都可以用来获取Spring容器中的Bean,如果知道Bean的名称就可以使用Bean的名称作为参数来获取。如果只知道Bean的类型,则使用类型作为参数来获取。

流程图

请添加图片描述

总结:如果不使用Spring框架的依赖注入,需要手动创建和管理对象,这可能会导致代码冗余和可维护性的问题。但对于简单的应用程序,手动创建对象可能是可行的。

使用Spring框架的依赖注入,发现朱需要创建一次GreetingServiceImpl对象,就可以多次使用。通过声明式配置,简化了对象的创建和组装过程,降低了代码复杂度。Spring容器又可以管理依赖对象的生命周期,避免了内存泄漏的问题,大大减轻了JVM的压力。

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

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

相关文章

关于系统设计的一些思考

0.前言 当我们站在系统设计的起点&#xff0c;面对一个新的需求&#xff0c;我们该如何开始呢&#xff1f;这是许多处于系统分析与设计领域的新手常常思考的问题。有些人可能会误以为&#xff0c;只要掌握了诸如面向对象、统一建模语言、设计模式、微服务、Serverless、Servic…

电脑视频剪辑软件哪个好用

电脑视频剪辑软件是当今创作者不可或缺的工具之一&#xff0c;它们能够帮助我们在电脑上对视频进行编辑、剪辑、特效添加等操作&#xff0c;使我们的作品更加专业、精美。然而&#xff0c;在众多的视频剪辑软件中&#xff0c;该选择哪一个呢&#xff1f;本文将为你推荐2款非常好…

全网最细,接口+接口自动化测试面试题汇总(附回答)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、我们测试的接口…

vite 如何设置 pwa,让网页类似 app 那样运行,使用插件 vite-plugin-pwa

vite 如何设置 pwa&#xff0c;让网页类似 app 那样运行&#xff0c;使用插件 vite-plugin-pwa 一、概述 情况还是那么个情况&#xff0c;还是原来的项目 vue2 改为 vitetsvue3 遇到的问题&#xff0c;今天这个问题是如何 在 Vite 环境下设置 PWA。 PWA 就是网页应用可以像 a…

驱动芯片,预计未来几年将达到605亿美元的规模

驱动芯片是指驱动显示屏幕幕的芯片&#xff0c;其应用广泛&#xff0c;主要用于电脑、手机、电视、平板电脑和汽车等设备。全球驱动芯片市场分析&#xff1a; 据市场研究预测&#xff0c;未来几年内&#xff0c;全球驱动芯片市场将保持稳定增长&#xff0c;并达到605亿美元的规…

【萤火虫系列教程】2/5-Adobe Firefly 文字​生成​图像

文字​生成​图像 登录账号后&#xff0c;在主页点击文字生成图像的【生成】按钮&#xff0c;进入到文字生成图像 查看图像 在文字生成图像页面&#xff0c;可以看到别人生成的图像。 点击某个图像&#xff0c;就可以进入图像详情&#xff0c;可以看到文字描述。 生成图像 我…

电子化学品,预计2025年会增长到4302亿美元

电子化学品市场是一个庞大的细分市场&#xff0c;它包括了广泛的化学品种类&#xff0c;如涂料、塑料、精细化学品、农药和医药等。这个市场的发展相当迅速&#xff0c;下面我们将从全球市场和中国市场两个方面对其发展趋势进行分析。全球市场分析&#xff1a; 从全球市场的角度…

谷达冠楠:抖店创业初期需要注意哪些

随着互联网的发展&#xff0c;越来越多的人选择通过开设网店来实现创业梦想。而在众多的电商平台中&#xff0c;抖音小店因其独特的社交属性和巨大的流量优势&#xff0c;成为了许多人的首选。然而&#xff0c;抖店创业并非一帆风顺&#xff0c;初期需要注意的问题也不少。以下…

OHC堆外内存

JVM内存模型 先复习一波JVM的内存模型&#xff0c;线程共享的区域为堆、方法区|永久代&#xff0c;线程不共享的区域为栈、程序计数器。 对象创建的整体流程可以用一图描述 内存逃逸 逃逸分析是指分析指针动态范围的方法&#xff0c;它同编译器优化原理的指针分析和外形分析相…

小微企业是如何使用CRM辅助业务的?CRM功能汇总

小企业的成长取决于客户&#xff0c;因此实施有效的CRM管理系统至关重要。曾有数据机构调查发现&#xff0c;每支出1美元用于CRM&#xff0c;您的CRM将带来8、71美元的回报。难怪越来越多的企业实施CRM&#xff0c;因为它带来了高投资回报率。对小企业来说&#xff0c;CRM应该具…

pytorch08:学习率调整策略

目录 一、为什么要调整学习率&#xff1f;1.1 class _LRScheduler 二、pytorch的六种学习率调整策略2.1 StepLR2.2 MultiStepLR2.3 ExponentialLR2.4 CosineAnnealingLR2.5 ReduceLRonPlateau2.6 LambdaLR 三、学习率调整小结四、学习率初始化 一、为什么要调整学习率&#xff…

怎么查询网络出口IP

怎么查询自己的网络的出口IP 背景 一般跟第三方服务进行接口数据交互的时候&#xff0c;对方都会让我们提供调用接口的网络的出口IP&#xff0c;对方会把该IP地址加到对方的白名单中。这样我们才能有权限进行接口的访问。 解决办法 下面介绍三种常用的查询网络出口IP的办法…

DevOps(10)

目录 56.Docker的架构&#xff1f; 57.Docker镜像相关操作有哪些&#xff1f; 58.Docker容器相关操作有哪些&#xff1f; ​编辑59.如何查看Docker容器的日志&#xff1f; 60.如何启动Docker容器&#xff1f;参数含义&#xff1f; 61.如何进入Docker后台模式&#xff1f;有…

基于Java SSM框架实现旅游资源网站系统项目【项目源码+论文说明】

基于java的SSM框架实现旅游资源网站系统演示 摘要 本论文主要论述了如何使用JAVA语言开发一个旅游资源网站 &#xff0c;本系统将严格按照软件开发流程进行各个阶段的工作&#xff0c;采用B/S架构&#xff0c;面向对象编程思想进行项目开发。在引言中&#xff0c;作者将论述旅…

Redis:原理+项目实战——Redis实战2(Redis实现短信登录(原理剖析+代码优化))

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位大四、研0学生&#xff0c;正在努力准备大四暑假的实习 &#x1f30c;上期文章&#xff1a;Redis&#xff1a;原理项目实战——Redis实战1&#xff08;session实现短信登录&#xff08;并剖析问题&#xff09;&#xff09…

Ambiq推出语音增强人工智能以消除物联网应用中的噪声

超低功耗半导体解决方案供应商Ambiq推出了其最新产品——神经网络语音增强器 (NNSE)&#xff0c;并已将该方案加入到neuralSPOT的&#xff08;开源模型&#xff09;Model Zoo中。这一高度优化过的AI模型可以高效实时地将背景噪声从设备对话中去除&#xff0c;从而在嘈杂的环境中…

基于Kettle开发的web版数据集成开源工具(data-integration)-应用篇

目录 &#x1f4da;第一章 基本流程梳理&#x1f4d7;页面基本操作&#x1f4d7;对应后台服务流程 &#x1f4da;第二章 二开思路&#x1f4d7;前端&#x1f4d7;后端 &#x1f53c;上一集&#xff1a;基于Kettle开发的web版数据集成开源工具(data-integration)-介绍篇 *️⃣主…

对话小仙炖副总裁张勇:内容价值将成为直播电商的核心趋势和竞争力

“ 激活中医典籍里的智慧&#xff0c;坚持内容化之路&#xff0c;服务好消费者。” 整理 | 飞族 编辑 | 渔舟 出品&#xff5c;极新&#xff06;北京电子商务协会 随着直播电商的影响力越来越大&#xff0c;对品牌而言&#xff0c;直播不仅是一种单纯的卖货渠道&#xff0c;…

Open3D聚类算法

按照官网的例子使用聚类&#xff0c;发现结果是全黑的。 经过多次测试发现 eps3.3, min_points1这里是关键 min_points必须等于1否则无效果 import time import open3d as o3d; import numpy as np; import matplotlib.pyplot as plt#坐标 mesh_coord_frame o3d.geometry.Tria…

力扣题:高精度运算-1.3

力扣题-1.3 [力扣刷题攻略] Re&#xff1a;从零开始的力扣刷题生活 力扣题1&#xff1a;43. 字符串相乘 解题思想&#xff1a;类似计算时采用的竖式乘法。首先取得num2的低位&#xff0c;并补齐对应的0&#xff0c;然后与num1进行相乘&#xff0c;然后进行字符串的相加操作。…