spring-boot-starter大力出奇迹
一、前言
上篇文章我们已经聊了SpringBoot的启动过程中的各类扩展点,那么从http://start.spring.io上我们生成的demo项目中,到目前就剩下了maven工程的pom.xml
还没有进行探索了,那么本文我们就来看看这里面到底都有啥,把大力出奇迹的常见spring-boot-starter来聊一聊,以便更好地使用SpringBoot.
二、SpringBoot项目的pom.xml文件解析
首先,我们还是按照一贯的作风,先上源码,再解析:
<?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
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.hafiz</groupId>
<artifactId>springboot-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springboot-demo</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.13.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
我们可以看到所有的结构都是我们熟悉的。首先映入眼帘的是:<parent></parent>
标签,熟悉Maven的朋友都知道,这个标签用来定义要继承的父pom的信息,它用来定义SpringBoot项目可能用到的依赖和插件声明以及一些资源文件声明,这样我们就可以在自己的SpringBoot项目中用到这些依赖或者插件的时候直接饮用,而不用指定版本号,正如我们上面看到的spring-boot-starter-web
、spring-boot-starter-test
依赖以及spring-boot-maven-plugin
插件一样,父pom.xml的源码如下:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.13.RELEASE</version>
<relativePath>../../spring-boot-dependencies</relativePath>
</parent>
<artifactId>spring-boot-starter-parent</artifactId>
<packaging>pom</packaging>
<name>Spring Boot Starter Parent</name>
<description>Parent pom providing dependency and plugin management for applications
built with Maven</description>
<url>http://projects.spring.io/spring-boot/</url>
<organization>
<name>Pivotal Software, Inc.</name>
<url>http://www.spring.io</url>
</organization>
<properties>
<java.version>1.6</java.version>
<resource.delimiter>@</resource.delimiter> <!-- delimiter that doesn't clash with Spring ${} placeholders -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<!-- Turn on filtering by default for application properties -->
<resources>
<resource>
<directory>${basedir}/src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/application*.yml</include>
<include>**/application*.yaml</include>
<include>**/application*.properties</include>
</includes>
</resource>
<resource>
<directory>${basedir}/src/main/resources</directory>
<excludes>
<exclude>**/application*.yml</exclude>
<exclude>**/application*.yaml</exclude>
<exclude>**/application*.properties</exclude>
</excludes>
</resource>
</resources>
<pluginManagement>
<plugins>
<!-- Apply more sensible defaults for user projects -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>${start-class}</mainClass>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<includes>
<include>**/*Tests.java</include>
<include>**/*Test.java</include>
</includes>
<excludes>
<exclude>**/Abstract*.java</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
<archive>
<manifest>
<mainClass>${start-class}</mainClass>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<configuration>
<mainClass>${start-class}</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
<configuration>
<delimiters>
<delimiter>${resource.delimiter}</delimiter>
</delimiters>
<useDefaultDelimiters>false</useDefaultDelimiters>
</configuration>
</plugin>
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>revision</goal>
</goals>
</execution>
</executions>
<configuration>
<verbose>true</verbose>
<dateFormat>yyyy-MM-dd'T'HH:mm:ssZ</dateFormat>
<generateGitPropertiesFile>true</generateGitPropertiesFile>
<generateGitPropertiesFilename>${project.build.outputDirectory}/git.properties</generateGitPropertiesFilename>
</configuration>
</plugin>
<!-- Support our own plugin -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>${start-class}</mainClass>
</configuration>
</plugin>
<!-- Support shade packaging (if the user does not want to use our plugin) -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.5.13.RELEASE</version>
</dependency>
</dependencies>
<configuration>
<keepDependenciesWithProvidedScope>true</keepDependenciesWithProvidedScope>
<createDependencyReducedPom>true</createDependencyReducedPom>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.handlers</resource>
</transformer>
<transformer implementation="org.springframework.boot.maven.PropertiesMergingResourceTransformer">
<resource>META-INF/spring.factories</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.schemas</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>${start-class}</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
但是我们发现,该父pom文件还有自己的父pom,作用类似,不再详解,感兴趣的可以自己去翻阅源码。那么这样看来我们自己的SpringBoot项目中的pom.xml
文件就剩下显眼的两个依赖以及一个插件了(没有指定版本号的原因前面已经解释了),那我们接下来就来聊一聊这些非常重要的spring-boot-starter依赖。
三、不可或缺的spring-boot-starter
我们从前面就知道了,SpringBoot能够如此方便便捷,其实都是得益于这些“开箱即用”的依赖模块,那SpringBoot设计者约定这些“开箱即用”的依赖模块的命名都以spring-boot-starter-
开始,并且这些模块都位于org.springframework.boot
包或者命名空间下面。我们也可以模仿者来实现自己的自动配置依赖模块,也已spring-boot-starter-
开头,是不是就很"正宗"呢?(虽然SpringBoot官方不建议我们这样做,以免跟官方提供的混淆,但是其实我们使用自己的groupId,这样命名应该不是啥问题)。
这些starter其实都有约定好的默认配置,但是它也允许我们调整这些默认配置,以便完成定制化的需求,我们可以改变默认配置的常见方式有以下几种:
- 命令行参数(Command Line Args)
- 系统环境变量(Environment Variables)
- 位于文件系统中的配置文件
- 位于classpath中的配置文件
- 固化到代码中的配置项
这几种方式从上到下优先级从高到低排列,高优先级的配置会覆盖优先级低的配置。还有就是不管位于文件系统还是classpath中的配置文件,SpringBoot应用默认的文件名称都是application.properties
,可以放在当前项目的根目录下或者名称为config的子目录下。
SpringBoot其实提供了很多这样的模块,我们就挑几个我们常用的这样的模块来解析,其他的大家就举一反三。以达到在工作和开发中灵活运用这些spring-boot-starter模块的效果。
1. spring-boot-starter-logging以及应用日志
如果我们在maven依赖中添加了spring-boot-starter-logging
:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
那也就意味着我们的SpringBoot应用自动使用logback作为日志框架,在启动的时候,由org.springframework.boot.logging.LoggingApplicationListener
根据情况初始化并使用。默认情况下,SpringBoot已经给我们提供好了很多默认的日志配置,我们只需要将spring-boot-starter-logging
作为依赖加入到你的SpringBoot应用就可以了,但是如果我们要对这些默认配置进行定制,可以有两种方式进行:
遵守logback的约定,在classpath中使用定制化的logback.xml配置文件。
在文件系统中任意一个地方提供自己的logback.xml配置文件,然后通过如下配置来
application.properties
中指定我们日志系统配置文件位置:logging.config=/{your config file location}}/logback.xml
如果我们已经习惯了log4j或log4j2,那我们只需要把spring-boot-starter-logging
换成如下的starter就好。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j</artifactId>
</dependency>
或
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
2. 用于快速构建web应用的spring-boot-starter-web
现如今,我们在工作中大部分实际用的还是SpringMVC开发的web应用,SpringBoot当然贴心的为我们开发了一个web项目模块,让我们更加方便的开发web应用。maven依赖如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
这样我们就可以得到一个可以直接执行的Web应用,然后我们运行mvn spring-boot:run
,就能直接启动一个基于嵌入式tomcat容器的Web应用了,然后就可以像这篇文章中定义controller来供用户访问了。但是呢,这简单的表象之下,其实却隐藏着很多约定,我们要把这些潜规则了解清楚才能更好地应用spring-boot-starter-web
。
2.1 项目结构的“潜规则”
传统的Java Web项目中,我们的静态文件以及页面模板都是放在src/main/webapp
目录下,但是在SpringBoot应用中,这些文件被统一放在src/main/resources
相应的子目录下:
src/main/resources/static
目录用于存放各种静态资源,如:js、css、image等。src/main/resources/template
目录用于存放模板文件。
细心地我们会发现SpringBoot的web应用已经变成了jar包而再是war包,如果我们还是希望以war包的形式发布也是可以的。
2.2 SpringMVC框架层面的约定及定制
spring-boot-starter-web
默认将为我们自动配置如下一些SpringMVC必要的组件:
- ViewResolver,如:
ContentNegotiatingViewResolver
和BeanNameViewResolver
。 - Converter,如:
GenericConverter
和Formatter
等bean被注册到IoC容器。 - 默认添加一系列
HttpMessageConverter
用于支持对Web请求和相应的类型转换。 - 自动配置和注册
MessageCodesResolver
。 - 其他必要组件…
2.3 嵌入式Web容器的约定和定制
我们知道spring-boot-starter-web
默认把嵌入式tomcat作为web容器来对外提供HTTP服务,默认使用8080端口对外监听和提供服务。这里我们可能会有两个疑问:
我们不想使用默认的嵌入式tomcat容器怎么办?
很简单,我们只需要引入
spring-boot-starter-jetty
或spring-boot-starter-undertow
依赖就能替代默认嵌入式tomcat容器了。我们想要把启动后提供服务的端口改掉怎么办?
我们可以通过在配置文件中修改启动端口就可以了,如:
server.port=9000
其实,spring-boot-starter-web
提供了很多以server.
作为前缀的配置以用来修改嵌入式容器的配置,如:
server.port
server.address
server.ssl.*
server.tomcat.*
那若这些还满足不了你,SpringBoot甚至都允许我们直接对嵌入式Web容器实例进行定制化,我们通过向IoC容器中注册一个EmbeddedServletContainerCustomizer
类型的组件来实现:
package com.hafiz.springbootdemo;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
/**
* @author hafiz.zhang
* @description: 自定义内嵌容器配置
* @date Created in 2018/6/10 12:09.
*/
public class DemoEmbeddedTomcatCustomizer implements EmbeddedServletContainerCustomizer {
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
container.setPort(9111);
container.setContextPath("/demo");
// ...
}
}
如果还要再深入的定制,那就需要实现对应内嵌容器的Factory并注册到IoC容器:
- TomcatEmbeddedServletContainerFactory
- JettyEmbeddedServletContainerFactory
- UndertowEmbeddedServletContainerFactory
但是,我们几乎没有可能需要这样的定制化,也不建议这样的定制化,使用SpringBoot默认的spring-boot-starter-web
提供的配置项列表已经很简单、很完整了。
3. 用于数据访问的spring-boot-starter-jdbc
我们知道,现实中大多数的Java应用都需要访问数据库,那SpringBoot肯定不会放过这个组件,它会很贴心的为我们自动配置好相应的数据访问工具。我们只需要在pom.xml
中添加以下依赖就好了:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
这样,在我们没有配置任何DataSource的情况下,SpringBoot会默认为我们自动配置一个基于嵌入式数据的DataSource,这种自动配置适合于测试场景,生产环境不适合。大多数情况下,我们都会自己配置DataSource实例,或通过自动配置模块提供的配置参数对DataSource实例配置自定义的参数。
若我们的SpringBoot应用只依赖一个数据库,那我们直接使用自动配置模块提供的配置参数最方便快捷:
spring.datasource.url=jdbc:mysql://{db host}:{db port}/{db name}
spring.datasource.username={db user name}
spring.datasource.password={db password}
有的小伙伴说了:那我自己配置一个DataSource行不行?答案是当然可以,SpringBoot会很智能的优先选择使用我们自己配置的这个DataSource,但是感觉多此一举!你要知道,SpringBoot除了自动帮我们配置DataSource以外,还自动帮我们配置了相应的JdbcTemplate
以及DataSourceTransactionManager
等相关的组件,我们只需要在需要使用的地方直接使用@Autowired
注解引用就好了。
那SpringBoot是不是一直贴心呢?很明显不是的,如果我们的单个项目需要依赖和访问多个数据库,这个时候就不行了,就算是我们在ApplicationContext中配置了多个DataSource实例来访问多个数据库:
@Bean
public DataSource dataSource1() throws Throwable {
DruidDataSource ds = new DruidDataSource();
ds.setUrl(...);
ds.setUsername(...);
ds.setPassword(...);
// set other db setting
return ds;
}
@Bean
public DataSource dataSource2() throws Throwable {
DruidDataSource ds = new DruidDataSource();
ds.setUrl(...);
ds.setUsername(...);
ds.setPassword(...);
// set other db setting
return ds;
}
启动项目时,你就会发现如下的异常:
No qualifying bean of type [javax.sql.DataSource] is defined: expected single matching bean but found 2...
那怎么解决这个问题呢?有两种方式:
在SpringBoot的启动类上“动手脚”
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class
})
public class DemoSpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(DemoSpringBootApplication.class, args);
}
}这也就是说我们需要排除掉SpringBoot默认的DataSource的相关的自动配置。
使用
@primary
注解那我们既要配置两个数据源,又要使用SpringBoot默认的DataSource,这时我们就可以为我们配置的两个DataSource中的任意一个使用
@primary
注解就可以了。@Bean
@Primary
public DataSource dataSource1() throws Throwable {
DruidDataSource ds = new DruidDataSource();
ds.setUrl(...);
ds.setUsername(...);
ds.setPassword(...);
// set other db setting
return ds;
}
@Bean
public DataSource dataSource2() throws Throwable {
DruidDataSource ds = new DruidDataSource();
ds.setUrl(...);
ds.setUsername(...);
ds.setPassword(...);
// set other db setting
return ds;
}除此之外,SpringBoot还提供了很多其他数据源访问相关的自动配置模块,如:
spring-boot-starter-jpa
、spring-boot-starter-mongodb
等。
四、总结
除了本文我们介绍的常用的三个spring-boot-starter以外,SpringBoot还提供了很多别的starter,包括spring-boot-starter-aop
、spring-boot-starter-security
、spring-boot-starter-actuator
等等。我们通过本文举一反三,可以做到用的时候得心应手。棒!给自己一个赞~
spring-boot-starter大力出奇迹的更多相关文章
- Spring Boot (一): Spring Boot starter自定义
前些日子在公司接触了spring boot和spring cloud,有感于其大大简化了spring的配置过程,十分方便使用者快速构建项目,而且拥有丰富的starter供开发者使用.但是由于其自动化配 ...
- 手把手教你定制标准Spring Boot starter,真的很清晰
写在前面 我们每次构建一个 Spring 应用程序时,我们都不希望从头开始实现具有「横切关注点」的内容:相反,我们希望一次性实现这些功能,并根据需要将它们包含到任何我们要构建的应用程序中 横切关注点 ...
- 从零开始开发一个Spring Boot Starter
一.Spring Boot Starter简介 Starter是Spring Boot中的一个非常重要的概念,Starter相当于模块,它能将模块所需的依赖整合起来并对模块内的Bean根据环境( 条件 ...
- 最详细的自定义Spring Boot Starter开发教程
1. 前言 随着Spring的日渐臃肿,为了简化配置.开箱即用.快速集成,Spring Boot 横空出世. 目前已经成为 Java 目前最火热的框架了.平常我们用Spring Boot开发web应用 ...
- 手把手教你手写一个最简单的 Spring Boot Starter
欢迎关注微信公众号:「Java之言」技术文章持续更新,请持续关注...... 第一时间学习最新技术文章 领取最新技术学习资料视频 最新互联网资讯和面试经验 何为 Starter ? 想必大家都使用过 ...
- Spring Boot Starter 介绍
http://www.baeldung.com/spring-boot-starters 作者:baeldung 译者:http://oopsguy.com 1.概述 依赖管理是任何复杂项目的关键部分 ...
- spring -boot s-tarter 详解
Starter POMs是可以包含到应用中的一个方便的依赖关系描述符集合.你可以获取所有Spring及相关技术的一站式服务,而不需要翻阅示例代码,拷贝粘贴大量的依赖描述符.例如,如果你想使用Sprin ...
- SpringBoot 之Spring Boot Starter依赖包及作用
Spring Boot 之Spring Boot Starter依赖包及作用 spring-boot-starter 这是Spring Boot的核心启动器,包含了自动配置.日志和YAML. spri ...
- Spring boot starter pom的依赖关系说明
Spring Boot 通过starter依赖为项目的依赖管理提供帮助.starter依赖起始就是特殊的maven依赖,利用了传递依赖解析,把常用库聚合在一起,组成了几个为特定功能而定制的依赖. sp ...
- Spring Boot Starter列表
转自:http://blog.sina.com.cn/s/blog_798f713f0102wiy5.html Spring Boot Starter 基本的一共有43种,具体如下: 1)spring ...
随机推荐
- 【机器学习】支持向量机(SVM)的优化算法——序列最小优化算法(SMO)概述
SMO算法是一一种启发式算法,它的基本思路是如果所有变量的解的条件都满足最优化问题的KKT条件,那么这个最优化问题的解就得到了.因为KKT条件是该优化问题的充分必要条件. 整个SMO算法包括两个部分: ...
- dubbo入门学习 一SOA
SOA是什么?SOA全英文是Service-Oriented Architecture,中文意思是中文面向服务编程,是一种思想,一种方法论,一种分布式的服务架构(具体可以百度). 用途:SOA解决多服 ...
- 获取window.location.href中传的值,并且转换成json数据使用
做个记录保存一下,以免以后再次用到忘记了. function locVal(){ var url=window.location.href; if (url.indexOf('?')==-1)retu ...
- pyc文件
1.pyc文件 是python预编译后的字节码文件,并不是机器码.2.PyCodeObject 是Python编译器真正编译成的结果: 当python程序运行时,编译的结果是保存在PyCodeObje ...
- appium:运行脚本时,报404的解决办法
对于报404的错,不要怀疑,在环境正常的情况下,一定是你的端口被占用了. 就用:查看端口:netstat -aon|findstr 5037 查看进程:tasklist /fi "PID e ...
- 【ORA-12516 TNS监听程序找不到符合协议堆栈要求的可用处理程序】
服务器上某个数据库出现' ORA-12516: TNS: 监听程序找不到符合协议堆栈要求的可用处理程'错误,要解决该问题首先查看一下数据库现有的进程数,是否已经达到参数processes的大小. 取得 ...
- @RequestParam与@PathVariable
@PathVariable 带占位符的 URL 是 Spring3.0 新增的功能,该功能在SpringMVC 向 REST 目标挺进发展过程中具有里程碑的意义 通过 @PathVariable 可以 ...
- Day04 (黑客成长日记) 集合记录
集合 集合:是可变的数据类型 ,它里面的数据类型必须是不可变的数据类型,无序,不重复,不同于字典,他有元素,没有键值对(编码不常用) li = set([1,2,3]) li = {'alex','w ...
- python 递归实现汉诺塔算法
def move(n,a,b,c): if (n == 1): print ( "第 ", n ," 步: 将盘子由 " ,a ," 移动到 &quo ...
- 用mplayer从视频中按周期提取帧
使用方法:extract file time step folder time 设置时间长度 step 设置周期 均以秒(s)为单位 贡献:1. 从视频文件中周期性提取图片:2. Windows下批处 ...