maven系列目标:从入门开始开始掌握一个高级开发所需要的maven技能。

这是maven系列第10篇。

整个maven系列的内容前后是有依赖的,如果之前没有接触过maven,建议从第一篇看起,本文尾部有maven完整系列的连接。

Maven默认提供了很多插件,功能也非常强大,但是如果我们想自己开发一些插件,比如自定义一款自动打包并且发布到服务器然后重启服务器的插件;或者定义一款插件自动打包自动运行打包好的构件。各种好玩的东西只要你能想到,都可以通过maven插件去完成,不过我们需要先了解如何自定义maven插件。

必备知识

  1. Maven系列第6篇:生命周期和插件详解,高手必备!

本篇环境

  1. jdk1.8

  2. maven3.6.2

  3. idea

本章内容

  1. 自定义插件详细步骤

  2. 自定义插件参数的使用

  3. 自定义插件前缀的使用

  4. 手动实现打包之后自动运行的插件

自定义插件详细步骤

maven中的插件是有很多目标(goal)组成的,开发插件,实际上就是去编写插件中目标的具体代码。每个目标对应一个java类,这个类在maven中叫做MOJO,maven提供了一个Mojo的接口,我们开发插件也就是去实现这个接口的方法,这个接口是:

org.apache.maven.plugin.Mojo

接口有3个方法:

  1. void execute() throws MojoExecutionException, MojoFailureException;
  2. void setLog( Log log );
  3. Log getLog();
  • execute:这个方法比较重要,目标的主要代码就在这个方法中实现,当使用mvn命令调用插件的目标的时候,最后具体调用的就是这个方法。

  • setLog:注入一个标准的Maven日志记录器,允许这个Mojo向用户传递事件和反馈

  • getLog:获取注入的日志记录器

说一下上面这个Log,这是一日志接口,里面定义了很多方法,主要用户向交互者输出日志,比如我们运行mvn clean,会输出很多提示信息,这些输出的信息就是通过Log来输出的。

Mojo接口有个默认的抽象类:

org.apache.maven.plugin.AbstractMojo

这个类中把Mojo接口中的setLoggetLog实现了,而execute方法没有实现,交给继承者去实现,这个类中Log默认可以向控制台输出日志信息,maven中自带的插件都继承这个类,一般情况下我们开发插件目标可以直接继承这个类,然后实现execute方法就可以了。

实现一个插件的具体步骤

1、 创建一个maven构件,这个构件的packaging比较特殊,必须为maven-plugin,表示这个构件是一个插件类型,如下:

pom.xml中的packageing元素必须如下值:

<packaging>maven-plugin</packaging>
2、导入maven插件依赖:
  1. <dependency>
  2. <groupId>org.apache.maven</groupId>
  3. <artifactId>maven-plugin-api</artifactId>
  4. <version>3.0</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.apache.maven.plugin-tools</groupId>
  8. <artifactId>maven-plugin-annotations</artifactId>
  9. <version>3.4</version>
  10. <scope>provided</scope>
  11. </dependency>
3、创建一个目标类,需要继承org.apache.maven.plugin.AbstractMojo
4、目标类中添加注解@Mojo注解:
@org.apache.maven.plugins.annotations.Mojo(name="目标名称")

注意@Mojo注解用来标注这个类是一个目标类,maven对插件进行构建的时候会根据这个注解来找到这个插件的目标,这个注解中还有其他参数,后面在详细介绍。

5、在目标类的execute方法中实现具体的逻辑
6、安装插件到本地仓库:插件的pom.xml所在目录执行下面命令
mvn clean install

或者可以部署到私服仓库,部署方式和其他构件的方式一样,这个具体去看前面文章的私服的文章。

7、让使用者去使用插件

案例1

下面我们来实现我们第一个插件,插件构件信息:

  1. <groupId>com.javacode2018</groupId>
  2. <artifactId>demo1-maven-plugin</artifactId>
  3. <version>1.0-SNAPSHOT</version>
  4. <packaging>maven-plugin</packaging>

创建一个目标类demo1,调用这个目标的时候,希望他能够输出:

hello my first maven plugin!
创建一个maven项目

打开idea,点击File->New->Project,如下图:

选择Maven,如下图:

点击上图中的Next,如下图,输入项目坐标信息:

点击上图中的Next,如下图,输入Project namemaven-chat10

点击上图中的Finish,完成创建,如下图:

配置一下idea的maven环境,点击File->Settings,如下图:

删除下面2个无用的文件夹:

创建插件模块`demo1-maven-plugin`

这次用idea创建一个插件模块demo1-maven-plugin,具体过程如下。

在刚才的maven-chat10项目窗口中,点击File->Project Structure,如下图:

也可以使用快捷键Ctrl+Alt+Shift+S打开

选择上图找你的Modules,如下图:

点击+,如下图:

选择上图中的New Module,如下图:

选择上图左侧的Maven,如下图:

点击上图中的Next,如下图:

Add as module to设置为maven-chat10,如下图:

上图中输入坐标信息,如下图:

点击上图中的Next,默认如下图:

修改上图中Module namedemo1-maven-plugin,如下图:

点击上图的Finish,如下图:

点击上图中的OK按钮,完成创建工作,目前项目结构如下图:

设置demo1-maven-plugin/pom.xml中packaging的值为maven-plugin,如下
<packaging>maven-plugin</packaging>
demo1-maven-plugin/pom.xml引入插件需要的依赖
  1. <dependency>
  2. <groupId>org.apache.maven</groupId>
  3. <artifactId>maven-plugin-api</artifactId>
  4. <version>3.0</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.apache.maven.plugin-tools</groupId>
  8. <artifactId>maven-plugin-annotations</artifactId>
  9. <version>3.4</version>
  10. <scope>provided</scope>
  11. </dependency>

最后demo1-maven-plugin/pom.xml内容如下

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <modelVersion>4.0.0</modelVersion>
  6. <groupId>com.javacode2018</groupId>
  7. <artifactId>demo1-maven-plugin</artifactId>
  8. <version>1.0-SNAPSHOT</version>
  9. <!-- 插件必须为maven-plugin这个类型 -->
  10. <packaging>maven-plugin</packaging>
  11. <properties>
  12. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  13. <!-- 配置maven编译的时候采用的编译器版本 -->
  14. <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
  15. <!-- 指定源代码是什么版本的,如果源码和这个版本不符将报错,maven中执行编译的时候会用到这个配置,默认是1.5,这个相当于javac命令后面的-source参数 -->
  16. <maven.compiler.source>1.8</maven.compiler.source>
  17. <!-- 该命令用于指定生成的class文件将保证和哪个版本的虚拟机进行兼容,maven中执行编译的时候会用到这个配置,默认是1.5,这个相当于javac命令后面的-target参数 -->
  18. <maven.compiler.target>1.8</maven.compiler.target>
  19. </properties>
  20. <dependencies>
  21. <!-- maven插件依赖 start -->
  22. <dependency>
  23. <groupId>org.apache.maven</groupId>
  24. <artifactId>maven-plugin-api</artifactId>
  25. <version>3.0</version>
  26. </dependency>
  27. <dependency>
  28. <groupId>org.apache.maven.plugin-tools</groupId>
  29. <artifactId>maven-plugin-annotations</artifactId>
  30. <version>3.4</version>
  31. <scope>provided</scope>
  32. </dependency>
  33. <!-- maven插件依赖 end -->
  34. </dependencies>
  35. <build>
  36. <plugins>
  37. <plugin>
  38. <groupId>org.apache.maven.plugins</groupId>
  39. <artifactId>maven-plugin-plugin</artifactId>
  40. <version>3.4</version>
  41. </plugin>
  42. </plugins>
  43. </build>
  44. </project>
创建目标类

demo-maven-plugin中创建的目标类com.javacode2018.Demo1Mojo,需要继承org.apache.maven.plugin.AbstractMojo,需要实现@Mojo注解,如下:

  1. package com.javacode2018;
  2. import org.apache.maven.plugin.AbstractMojo;
  3. import org.apache.maven.plugin.MojoExecutionException;
  4. import org.apache.maven.plugin.MojoFailureException;
  5. import org.apache.maven.plugins.annotations.Mojo;
  6. /**
  7.  * 工作10年的前阿里P7分享Java、算法、数据库方面的技术干货!坚信用技术改变命运,让家人过上更体面的生活!喜欢的请关注公众号:路人甲Java
  8.  */
  9. @Mojo(name = "demo1")
  10. public class Demo1Mojo extends AbstractMojo {
  11. public void execute() throws MojoExecutionException, MojoFailureException {
  12. }
  13. }

注意上面注解@Mojo(name = "demo1"),name使用来标注目标的名称为demo1

实现目标类的execute方法

我们在execute方法中输出一句话

this.getLog().info("hello my first maven plugin!");

目前execute方法代码如下:

  1. public void execute() throws MojoExecutionException, MojoFailureException {
  2. this.getLog().info("hello my first maven plugin!");
  3. }
安装插件到本地仓库

maven-chat10/pom.xml目录执行下面命令:

mvn clean install -pl :demo1-maven-plugin

注意上面命令和在demo1-maven-plugin/pom中执行mvn clean install效果是一样的,只是这个地方使用了maven裁剪的功能,对这块命令不熟悉的可以看:Maven系列第8篇:大型Maven项目,快速按需任意构建,必备神技能!

上面命令效果如下:

  1. D:\code\IdeaProjects\maven-chat10>mvn clean install -pl :demo1-maven-plugin
  2. [INFO] Scanning for projects...
  3. [INFO]
  4. [INFO] ----------------< com.javacode2018:demo1-maven-plugin >-----------------
  5. [INFO] Building demo1-maven-plugin 1.0-SNAPSHOT
  6. [INFO] ----------------------------[ maven-plugin ]----------------------------
  7. [INFO]
  8. [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ demo1-maven-plugin ---
  9. [INFO] Deleting D:\code\IdeaProjects\maven-chat10\demo1-maven-plugin\target
  10. [INFO]
  11. [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ demo1-maven-plugin ---
  12. [INFO] Using 'UTF-8' encoding to copy filtered resources.
  13. [INFO] Copying 0 resource
  14. [INFO]
  15. [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ demo1-maven-plugin ---
  16. [INFO] Changes detected - recompiling the module!
  17. [INFO] Compiling 1 source file to D:\code\IdeaProjects\maven-chat10\demo1-maven-plugin\target\classes
  18. [INFO]
  19. [INFO] --- maven-plugin-plugin:3.4:descriptor (default-descriptor) @ demo1-maven-plugin ---
  20. [INFO] Using 'UTF-8' encoding to read mojo metadata.
  21. [INFO] Mojo extractor with id: java-javadoc found 0 mojo descriptors.
  22. [INFO] Mojo extractor with id: java-annotations found 1 mojo descriptors.
  23. [INFO]
  24. [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ demo1-maven-plugin ---
  25. [INFO] Using 'UTF-8' encoding to copy filtered resources.
  26. [INFO] skip non existing resourceDirectory D:\code\IdeaProjects\maven-chat10\demo1-maven-plugin\src\test\resources
  27. [INFO]
  28. [INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ demo1-maven-plugin ---
  29. [INFO] Nothing to compile - all classes are up to date
  30. [INFO]
  31. [INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ demo1-maven-plugin ---
  32. [INFO] No tests to run.
  33. [INFO]
  34. [INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ demo1-maven-plugin ---
  35. [INFO] Building jar: D:\code\IdeaProjects\maven-chat10\demo1-maven-plugin\target\demo1-maven-plugin-1.0-SNAPSHOT.jar
  36. [INFO]
  37. [INFO] --- maven-plugin-plugin:3.4:addPluginArtifactMetadata (default-addPluginArtifactMetadata) @ demo1-maven-plugin ---
  38. [INFO]
  39. [INFO] --- maven-install-plugin:2.4:install (default-install) @ demo1-maven-plugin ---
  40. [INFO] Installing D:\code\IdeaProjects\maven-chat10\demo1-maven-plugin\target\demo1-maven-plugin-1.0-SNAPSHOT.jar to C:\Users\Think\.m2\repository\com\javacode2018\demo1-maven-plugin\1.0-SNAPSHOT\demo1-maven-plugin-1.0-SNAPSHOT.jar
  41. [INFO] Installing D:\code\IdeaProjects\maven-chat10\demo1-maven-plugin\pom.xml to C:\Users\Think\.m2\repository\com\javacode2018\demo1-maven-plugin\1.0-SNAPSHOT\demo1-maven-plugin-1.0-SNAPSHOT.pom
  42. [INFO] ------------------------------------------------------------------------
  43. [INFO] BUILD SUCCESS
  44. [INFO] ------------------------------------------------------------------------
  45. [INFO] Total time:  5.402 s
  46. [INFO] Finished at: 2019-11-26T15:21:26+08:00
  47. [INFO] ------------------------------------------------------------------------
验证插件,调用插件的demo1目标看效果

maven-chat10/pom.xml所在目录执行:

mvn com.javacode2018:demo1-maven-plugin:demo1

效果如下:

  1. D:\code\IdeaProjects\maven-chat10>mvn com.javacode2018:demo1-maven-plugin:demo1
  2. [INFO] Scanning for projects...
  3. [INFO] ------------------------------------------------------------------------
  4. [INFO] Reactor Build Order:
  5. [INFO]
  6. [INFO] demo1-maven-plugin                                        [maven-plugin]
  7. [INFO] maven-chat10                                                       [pom]
  8. [INFO]
  9. [INFO] ----------------< com.javacode2018:demo1-maven-plugin >-----------------
  10. [INFO] Building demo1-maven-plugin 1.0-SNAPSHOT                           [1/2]
  11. [INFO] ----------------------------[ maven-plugin ]----------------------------
  12. [INFO]
  13. [INFO] --- demo1-maven-plugin:1.0-SNAPSHOT:demo1 (default-cli) @ demo1-maven-plugin ---
  14. [INFO] hello my first maven plugin!
  15. [INFO]
  16. [INFO] -------------------< com.javacode2018:maven-chat10 >--------------------
  17. [INFO] Building maven-chat10 1.0-SNAPSHOT                                 [2/2]
  18. [INFO] --------------------------------[ pom ]---------------------------------
  19. [INFO]
  20. [INFO] --- demo1-maven-plugin:1.0-SNAPSHOT:demo1 (default-cli) @ maven-chat10 ---
  21. [INFO] hello my first maven plugin!
  22. [INFO] ------------------------------------------------------------------------
  23. [INFO] Reactor Summary for maven-chat10 1.0-SNAPSHOT:
  24. [INFO]
  25. [INFO] demo1-maven-plugin ................................. SUCCESS [  0.358 s]
  26. [INFO] maven-chat10 ....................................... SUCCESS [  0.042 s]
  27. [INFO] ------------------------------------------------------------------------
  28. [INFO] BUILD SUCCESS
  29. [INFO] ------------------------------------------------------------------------
  30. [INFO] Total time:  0.656 s
  31. [INFO] Finished at: 2019-11-26T13:49:30+08:00

上面输出的东西比较多,我们主要看一下有这样的一句输出,如下:

[INFO] hello my first maven plugin!

上面这个输出就是我们在execute方法中输出的内容。

目标中参数的使用

上面我们介绍了开发一个插件目标详细的实现过程,然后写了一个简单的案例,比较简单。不过自定义的Mojo如果没有参数,那么这个Mojo基本上也实现不了什么复杂的功能,下面我们来看一下Mojo中如何使用参数。

需要先在mojo中定义参数

定义参数就像在mojo中创建一个实例变量并添加适当的注释一样简单。下面列出了一个简单mojo的参数示例:

  1. /**
  2.  * 要显示的问候语。
  3.  */
  4. @Parameter( property = "sayhi.greeting", defaultValue = "Hello World!" )
  5. private String greeting;

@Parameter注解之前的部分是参数的描述,这个注解将变量标识为mojo参数。注解的defaultValue参数定义变量的默认值,此值maven的属性值,例如“${project.version}”(更多信息可以看上一篇文章中的 target="_blank">maven属性部分),property参数可用于通过引用用户通过-D选项设置的系统属性,即通过从命令行配置mojo参数,如mvn ... -Dsayhi.greeting=路人甲Java可以将路人甲Java的值传递给greeting参数,这个注解还有几个属性大家有兴趣的可以自己去研究一下。

在pom.xml配置参数的值

  1. <plugin>
  2. <groupId>com.javacode2018</groupId>
  3. <artifactId>demo1-maven-plugin</artifactId>
  4. <version>1.0-SNAPSHOT</version>
  5. <configuration>
  6. <greeting>欢迎您和【路人甲Java】一起学习Maven技术!</greeting>
  7. </configuration>
  8. </plugin>

上面设置的是一个string类型的greeting参数的值,还有其他很多类型定义以及使用,我们也来看一下。

Boolean参数

  1. /**
  2. * My boolean.
  3. */
  4. @Parameter
  5. private boolean myBoolean;
<myBoolean>true</myBoolean>

数字类型参数

数字类型包含:byte, Byte, int, Integer, long, Long, short, Short,读取配置时,XML文件中的文本将使用适当类的integer.parseInt()或valueOf()方法转换为整数值,这意味着字符串必须是有效的十进制整数值,仅由数字0到9组成,前面有一个可选的-表示负值。例子:

  1. /**
  2. * My Integer.
  3. */
  4. @Parameter
  5. private Integer myInteger;
<myInteger>10</myInteger>

File类型参数

读取配置时,XML文件中的文本用作所需文件或目录的路径。如果路径是相对的(不是以/或C:之类的驱动器号开头),则路径是相对于包含POM的目录的。例子:

  1. /**
  2. * My File.
  3. */
  4. @Parameter
  5. private File myFile;
<myFile>c:\temp</myFile>

枚举类型参数

  1. public enum Color {
  2. GREEN,
  3. RED,
  4. BLUE
  5. }
  6. /**
  7. * My Enum
  8. */
  9. @Parameter
  10. private Color myColor;
<myColor>GREEN</myColor>

数组类型参数

  1. /**
  2. * My Array.
  3. */
  4. @Parameter
  5. private String[] myArray;
  1. <myArray>
  2. <param>value1</param>
  3. <param>value2</param>
  4. </myArray>

Collections类型参数

  1. /**
  2. * My List.
  3. */
  4. @Parameter
  5. private List myList;
  1. <myList>
  2. <param>value1</param>
  3. <param>value2</param>
  4. </myList>

Maps类型参数

  1. /**
  2. * My Map.
  3. */
  4. @Parameter
  5. private Map myMap;
  1. <myMap>
  2. <key1>value1</key1>
  3. <key2>value2</key2>
  4. </myMap>

Properties类型参数

java.util.Properties的类型

  1. /**
  2. * My Properties.
  3. */
  4. @Parameter
  5. private Properties myProperties;
  1. <myProperties>
  2. <property>
  3. <name>propertyName1</name>
  4. <value>propertyValue1</value>
  5. <property>
  6. <property>
  7. <name>propertyName2</name>
  8. <value>propertyValue2</value>
  9. <property>
  10. </myProperties>

自定义类型参数

  1. /**
  2. * My Object.
  3. */
  4. @Parameter
  5. private MyObject myObject;
  1. <myObject>
  2. <myField>test</myField>
  3. </myObject>

案例2

修改案例代码

我们将上面各种类型的参数都放到Demo1Mojo中,Demo1Mojo类如下:

  1. package com.javacode2018;
  2. import org.apache.maven.plugin.AbstractMojo;
  3. import org.apache.maven.plugin.MojoExecutionException;
  4. import org.apache.maven.plugin.MojoFailureException;
  5. import org.apache.maven.plugins.annotations.Mojo;
  6. import org.apache.maven.plugins.annotations.Parameter;
  7. import java.io.File;
  8. import java.lang.reflect.Field;
  9. import java.util.Arrays;
  10. import java.util.List;
  11. import java.util.Map;
  12. import java.util.Properties;
  13. /**
  14.  * 工作10年的前阿里P7分享Java、算法、数据库方面的技术干货!坚信用技术改变命运,让家人过上更体面的生活!喜欢的请关注公众号:路人甲Java
  15.  */
  16. @Mojo(name = "demo1")
  17. public class Demo1Mojo extends AbstractMojo {
  18. /**
  19.      * 要显示的问候语。
  20.      */
  21. @Parameter(property = "sayhi.greeting", defaultValue = "Hello World!")
  22. private String greeting;
  23. /**
  24.      * My boolean.
  25.      */
  26. @Parameter
  27. private boolean myBoolean;
  28. /**
  29.      * My Integer.
  30.      */
  31. @Parameter
  32. private Integer myInteger;
  33. /**
  34.      * My File.
  35.      */
  36. @Parameter
  37. private File myFile;
  38. public enum Color {
  39. GREEN,
  40. RED,
  41. BLUE
  42. }
  43. /**
  44.      * My Enum
  45.      */
  46. @Parameter
  47. private Color myColor;
  48. /**
  49.      * My Array.
  50.      */
  51. @Parameter
  52. private String[] myArray;
  53. /**
  54.      * My List.
  55.      */
  56. @Parameter
  57. private List myList;
  58. /**
  59.      * My Map.
  60.      */
  61. @Parameter
  62. private Map myMap;
  63. /**
  64.      * My Properties.
  65.      */
  66. @Parameter
  67. private Properties myProperties;
  68. public static class Person {
  69. private String name;
  70. private int age;
  71. public String getName() {
  72. return name;
  73. }
  74. public void setName(String name) {
  75. this.name = name;
  76. }
  77. public int getAge() {
  78. return age;
  79. }
  80. public void setAge(int age) {
  81. this.age = age;
  82. }
  83. @Override
  84. public String toString() {
  85. return "Person{" +
  86. "name='" + name + '\'' +
  87. ", age=" + age +
  88. '}';
  89. }
  90. }
  91. @Parameter
  92. private Person person;
  93. public void execute() throws MojoExecutionException, MojoFailureException {
  94. this.getLog().info("hello my first maven plugin!");
  95. Field[] declaredFields = Demo1Mojo.class.getDeclaredFields();
  96. Arrays.stream(declaredFields).forEach(f -> {
  97. if (f.isAccessible()) {
  98. f.setAccessible(true);
  99. }
  100. try {
  101. this.getLog().info(f.getName() + ":" + f.get(this));
  102. } catch (IllegalAccessException e) {
  103. this.getLog().warn(e);
  104. }
  105. });
  106. }
  107. }
将`demo1-maven-plugin`安装到本地仓库

maven-chat10/pom.xml所在目录运行:

mvn clean install -pl :demo1-maven-plugin
创建测试模块`demo1-maven-plugin-test`

使用idea创建,过程和demo1-maven-plugin过程类似,可以直接参考,创建好了,如下:

修改demo1-mavein-plugin-test/pom.xml文件,加入下面内容:

  1. <build>
  2. <plugins>
  3. <plugin>
  4. <groupId>com.javacode2018</groupId>
  5. <artifactId>demo1-maven-plugin</artifactId>
  6. <version>1.0-SNAPSHOT</version>
  7. <executions>
  8. <execution>
  9. <id>demo1 plugin test</id>
  10. <phase>pre-clean</phase>
  11. <goals>
  12. <goal>demo1</goal>
  13. </goals>
  14. <configuration>
  15. <myBoolean>true</myBoolean>
  16. <myInteger>30</myInteger>
  17. <myFile>${project.basedir}</myFile>
  18. <myColor>BLUE</myColor>
  19. <myArray>
  20. <array>maven</array>
  21. <array>spring</array>
  22. <array>mybatis</array>
  23. <array>springboot</array>
  24. <array>springcloud</array>
  25. </myArray>
  26. <myList>
  27. <list>30</list>
  28. <list>35</list>
  29. </myList>
  30. <myMap>
  31. <name>路人甲Java</name>
  32. <age>30</age>
  33. </myMap>
  34. <myProperties>
  35. <property>
  36. <name>name</name>
  37. <value>javacode2018</value>
  38. </property>
  39. <property>
  40. <name>age</name>
  41. <value>30</value>
  42. </property>
  43. </myProperties>
  44. <person>
  45. <name>路人甲Java</name>
  46. <age>32</age>
  47. </person>
  48. </configuration>
  49. </execution>
  50. </executions>
  51. </plugin>
  52. </plugins>
  53. </build>

上面是将生命周期的pre-clean阶段绑定插件demo1-maven-plugindemo1目标,并且设置了demo1目标所需要的所有参数的值。

验证效果

maven-chat10/pom.xml所在目录执行:

  1. D:\code\IdeaProjects\maven-chat10>mvn pre-clean -pl :demo1-maven-plugin-test -Dsayhi.greeting="欢迎和【路人甲Java】一起学习Maven!"
  2. [INFO] Scanning for projects...
  3. [INFO]
  4. [INFO] --------------< com.javacode2018:demo1-maven-plugin-test >--------------
  5. [INFO] Building demo1-maven-plugin-test 1.0-SNAPSHOT
  6. [INFO] --------------------------------[ jar ]---------------------------------
  7. [INFO]
  8. [INFO] --- demo1-maven-plugin:1.0-SNAPSHOT:demo1 (demo1 plugin test) @ demo1-maven-plugin-test ---
  9. [INFO] hello my first maven plugin!
  10. [INFO] greeting:欢迎和【路人甲Java】一起学习Maven!
  11. [INFO] myBoolean:true
  12. [INFO] myInteger:30
  13. [INFO] myFile:D:\code\IdeaProjects\maven-chat10\demo1-maven-plugin-test
  14. [INFO] myColor:BLUE
  15. [INFO] myArray:[Ljava.lang.String;@7bf9b098
  16. [INFO] myList:[30, 35]
  17. [INFO] myMap:{age=30, name=路人甲Java}
  18. [INFO] myProperties:{age=30, name=javacode2018}
  19. [INFO] person:Person{name='路人甲Java', age=32}
  20. [INFO] ------------------------------------------------------------------------
  21. [INFO] BUILD SUCCESS
  22. [INFO] ------------------------------------------------------------------------
  23. [INFO] Total time:  0.517 s
  24. [INFO] Finished at: 2019-11-26T15:42:53+08:00
  25. [INFO] ------------------------------------------------------------------------

插件前缀

在案例1中,我们使用下面命令调用的插件:

mvn com.javacode2018:demo1-maven-plugin:demo1

这种是采用下面这种格式:

mvn 插件groupId:插件artifactId[:插件版本]:插件目标名称

命令中插件版本是可以省略的,maven会自动找到这个插件最新的版本运行,不过最好我们不要省略版本号,每个版本的插件功能可能不一样,为了保证任何情况下运行效果的一致性,强烈建议指定版本号。

上面执行插件需要插件的坐标信息,一长串比较麻烦,maven也为了我们使用插件方便,提供了插件前缀来帮我们解决这个问题。

自定义插件前缀的使用

设置自定义插件的artifactId

自定义插件的artifactId满足下面的格式:

xxx-maven-plugin

如果采用这种格式的maven会自动将xxx指定为插件的前缀,其他格式也可以,不过此处我们只说这种格式,这个是最常用的格式。

如我们上面的demo1-maven-plugin插件,他的前缀就是demo1

当我们配置了插件前缀,可以插件前缀来调用插件的目标了,命令如下:

mvn 插件前缀:插件目标

maven是如何通过插件前缀找到具体的插件的呢?

maven默认会在仓库"org.apache.maven.plugins" 和 "org.codehaus.mojo"2个位置查找插件,比如:

mvn clean:help

这个是调用maven-clean-plugin插件的help目标,maven-clean-plugin的前缀就是clean,他的groupIdorg.apache.maven.plugins,所以能够直接找到。

但是我们自己定义的插件,如果也让maven能够找到,需要下面的配置。

在`~/.m2/settings.xml`中配置自定义插件组

pluginGroups中加入自定义的插件组groupId,如:

<pluginGroup>com.javacode2018</pluginGroup>

这样当我们通过前缀调用插件的时候,maven除了会在2个默认的组中查找,还会在这些自定义的插件组中找,一般情况下我们自定义的插件通常使用同样的groupId

使用插件前缀调用插件
mvn 插件前缀:插件目标

案例3

~/.m2/settings.xml中加入下面配置:

<pluginGroup>com.javacode2018</pluginGroup>

maven-chat10/pom.xml所在目录执行:

mvn demo1:demo1 -pl demo1-maven-plugin-test

效果如下:

  1. D:\code\IdeaProjects\maven-chat10>mvn demo1:demo1 -pl demo1-maven-plugin-test
  2. [INFO] Scanning for projects...
  3. [INFO]
  4. [INFO] --------------< com.javacode2018:demo1-maven-plugin-test >--------------
  5. [INFO] Building demo1-maven-plugin-test 1.0-SNAPSHOT
  6. [INFO] --------------------------------[ jar ]---------------------------------
  7. [INFO]
  8. [INFO] --- demo1-maven-plugin:1.0-SNAPSHOT:demo1 (default-cli) @ demo1-maven-plugin-test ---
  9. [INFO] hello my first maven plugin!
  10. [INFO] greeting:Hello World!
  11. [INFO] myBoolean:false
  12. [INFO] myInteger:null
  13. [INFO] myFile:null
  14. [INFO] myColor:null
  15. [INFO] myArray:null
  16. [INFO] myList:null
  17. [INFO] myMap:null
  18. [INFO] myProperties:null
  19. [INFO] person:null
  20. [INFO] ------------------------------------------------------------------------
  21. [INFO] BUILD SUCCESS
  22. [INFO] ------------------------------------------------------------------------
  23. [INFO] Total time:  0.786 s
  24. [INFO] Finished at: 2019-11-26T16:10:41+08:00
  25. [INFO] ------------------------------------------------------------------------

上面直接通过插件的前缀来调用插件的功能了,是不是很爽!

手动实现打包之后自动运行的插件

实现思路

1、将目标构件打包为可以执行jar包到target目录

maven中将构件打包为可以执行的jar的插件,maven已经帮我们提供了,如下:

  1. <plugin>
  2. <groupId>org.apache.maven.plugins</groupId>
  3. <artifactId>maven-shade-plugin</artifactId>
  4. <version>3.2.1</version>
  5. <executions>
  6. <execution>
  7. <phase>package</phase>
  8. <goals>
  9. <goal>shade</goal>
  10. </goals>
  11. <configuration>
  12. <transformers>
  13. <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
  14. <mainClass>启动类完整路径</mainClass>
  15. </transformer>
  16. </transformers>
  17. </configuration>
  18. </execution>
  19. </executions>
  20. </plugin>

上面使用到了maven官方提供的一个打包的插件,可以将构件打包为可以直接运行的jar包。

2、自定义一个插件,然后执行上面打包好的插件

插件中需要通过java命令调用打包好的jar包,然后运行。

具体实现如下

创建自定义目标类

demo1-maven-plugin中创建一个插件目标类,如下:

  1. package com.javacode2018;
  2. import org.apache.maven.plugin.AbstractMojo;
  3. import org.apache.maven.plugin.MojoExecutionException;
  4. import org.apache.maven.plugin.MojoFailureException;
  5. import org.apache.maven.plugins.annotations.Execute;
  6. import org.apache.maven.plugins.annotations.LifecyclePhase;
  7. import org.apache.maven.plugins.annotations.Mojo;
  8. import org.apache.maven.plugins.annotations.Parameter;
  9. import java.io.BufferedReader;
  10. import java.io.IOException;
  11. import java.io.InputStreamReader;
  12. /**
  13.  * 工作10年的前阿里P7分享Java、算法、数据库方面的技术干货!坚信用技术改变命运,让家人过上更体面的生活!喜欢的请关注公众号:路人甲Java
  14.  */
  15. @Mojo(name = "run", defaultPhase = LifecyclePhase.PACKAGE)
  16. @Execute(phase = LifecyclePhase.PACKAGE)
  17. public class RunMojo extends AbstractMojo {
  18. /**
  19.      * 打包好的构件的路径
  20.      */
  21. @Parameter(defaultValue = "${project.build.directory}\\${project.artifactId}-${project.version}.jar")
  22. private String jarPath;
  23. @Override
  24. public void execute() throws MojoExecutionException, MojoFailureException {
  25. try {
  26. this.getLog().info("Started:" + this.jarPath);
  27. ProcessBuilder builder = new ProcessBuilder("java", "-jar", this.jarPath);
  28. final Process process = builder.start();
  29. new Thread(() -> {
  30. BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
  31. try {
  32. String s;
  33. while ((s = reader.readLine()) != null) {
  34. System.out.println(s);
  35. }
  36. } catch (IOException e) {
  37. e.printStackTrace();
  38. }
  39. }).start();
  40. Runtime.getRuntime().addShutdownHook(new Thread() {
  41. @Override
  42. public void run() {
  43. RunMojo.this.getLog().info("Destroying...");
  44. process.destroy();
  45. RunMojo.this.getLog().info("Shutdown hook finished.");
  46. }
  47. });
  48. process.waitFor();
  49. this.getLog().info("Finished.");
  50. } catch (Exception e) {
  51. this.getLog().warn(e);
  52. }
  53. }
  54. }

上面这个插件目标的名称为run

注意这个类上面多了一个注解@Execute,这个注解可以配置这个目标执行之前可以先执行的生命周期的阶段或者需要先执行的插件目标

上面配置的是phase = LifecyclePhase.PACKAGE,也就是说当我们运行上面run目标的时候,会先执行构件的package阶段,也就是先执行项目的打包阶段,打包完成之后才会执行run目标。

安装插件到本地仓库

maven-chat10/pom.xml所在目录运行:

mvn clean install -pl :demo1-maven-plugin
创建测试模块`demo1-maven-plugin-run`

使用idea创建,过程和demo1-maven-plugin过程类似,可以直接参考,创建好了,如下:

创建`com.javacode2018.Demo`类

在demo1-maven-plugin-run\src\main\java创建下面类:

  1. package com.javacode2018;
  2. import java.util.Calendar;
  3. import java.util.concurrent.TimeUnit;
  4. /**
  5.  * 工作10年的前阿里P7分享Java、算法、数据库方面的技术干货!坚信用技术改变命运,让家人过上更体面的生活!喜欢的请关注公众号:路人甲Java
  6.  */
  7. public class Demo1 {
  8. public static void main(String[] args) throws InterruptedException {
  9. for (int i = 0; i < 1000; i++) {
  10. System.out.println(Calendar.getInstance().getTime() + ":" + i);
  11. TimeUnit.SECONDS.sleep(1);
  12. }
  13. }
  14. }
修改`demo1-maven-plugin-run/pom.xml`,如下
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <modelVersion>4.0.0</modelVersion>
  6. <groupId>com.javacode2018</groupId>
  7. <artifactId>demo1-maven-plugin-run</artifactId>
  8. <version>1.0-SNAPSHOT</version>
  9. <properties>
  10. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  11. <!-- 配置maven编译的时候采用的编译器版本 -->
  12. <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
  13. <!-- 指定源代码是什么版本的,如果源码和这个版本不符将报错,maven中执行编译的时候会用到这个配置,默认是1.5,这个相当于javac命令后面的-source参数 -->
  14. <maven.compiler.source>1.8</maven.compiler.source>
  15. <!-- 该命令用于指定生成的class文件将保证和哪个版本的虚拟机进行兼容,maven中执行编译的时候会用到这个配置,默认是1.5,这个相当于javac命令后面的-target参数 -->
  16. <maven.compiler.target>1.8</maven.compiler.target>
  17. </properties>
  18. <build>
  19. <plugins>
  20. <plugin>
  21. <groupId>org.apache.maven.plugins</groupId>
  22. <artifactId>maven-shade-plugin</artifactId>
  23. <version>3.2.1</version>
  24. <executions>
  25. <execution>
  26. <phase>package</phase>
  27. <goals>
  28. <goal>shade</goal>
  29. </goals>
  30. <configuration>
  31. <transformers>
  32. <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
  33. <mainClass>com.javacode2018.Demo1</mainClass>
  34. </transformer>
  35. </transformers>
  36. </configuration>
  37. </execution>
  38. </executions>
  39. </plugin>
  40. </plugins>
  41. </build>
  42. </project>
验证效果见证奇迹的时刻

maven-chat10/pom.xml所在目录执行下面的命令:

mvn clean demo1:run -pl demo1-maven-plugin-run

输出如下:

  1. D:\code\IdeaProjects\maven-chat10>mvn clean demo1:run -pl demo1-maven-plugin-run
  2. [INFO] Scanning for projects...
  3. [INFO]
  4. [INFO] --------------< com.javacode2018:demo1-maven-plugin-run >---------------
  5. [INFO] Building demo1-maven-plugin-run 1.0-SNAPSHOT
  6. [INFO] --------------------------------[ jar ]---------------------------------
  7. [INFO]
  8. [INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ demo1-maven-plugin-run ---
  9. [INFO] Deleting D:\code\IdeaProjects\maven-chat10\demo1-maven-plugin-run\target
  10. [INFO]
  11. [INFO] >>> demo1-maven-plugin:1.0-SNAPSHOT:run (default-cli) > package @ demo1-maven-plugin-run >>>
  12. [INFO]
  13. [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ demo1-maven-plugin-run ---
  14. [INFO] Using 'UTF-8' encoding to copy filtered resources.
  15. [INFO] Copying 0 resource
  16. [INFO]
  17. [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ demo1-maven-plugin-run ---
  18. [INFO] Changes detected - recompiling the module!
  19. [INFO] Compiling 1 source file to D:\code\IdeaProjects\maven-chat10\demo1-maven-plugin-run\target\classes
  20. [INFO]
  21. [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ demo1-maven-plugin-run ---
  22. [INFO] Using 'UTF-8' encoding to copy filtered resources.
  23. [INFO] skip non existing resourceDirectory D:\code\IdeaProjects\maven-chat10\demo1-maven-plugin-run\src\test\resources
  24. [INFO]
  25. [INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ demo1-maven-plugin-run ---
  26. [INFO] Nothing to compile - all classes are up to date
  27. [INFO]
  28. [INFO] --- maven-surefire-plugin:2.12.4:test (default-test) @ demo1-maven-plugin-run ---
  29. [INFO] No tests to run.
  30. [INFO]
  31. [INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ demo1-maven-plugin-run ---
  32. [INFO] Building jar: D:\code\IdeaProjects\maven-chat10\demo1-maven-plugin-run\target\demo1-maven-plugin-run-1.0-SNAPSHOT.jar
  33. [INFO]
  34. [INFO] --- maven-shade-plugin:3.2.1:shade (default) @ demo1-maven-plugin-run ---
  35. [INFO] Replacing original artifact with shaded artifact.
  36. [INFO] Replacing D:\code\IdeaProjects\maven-chat10\demo1-maven-plugin-run\target\demo1-maven-plugin-run-1.0-SNAPSHOT.jar with D:\code\IdeaProjects\maven-chat10\demo1-maven-plugin-run\target\demo1-maven-plugin-run-1.0-SNAPSHOT-shaded.jar
  37. [INFO]
  38. [INFO] <<< demo1-maven-plugin:1.0-SNAPSHOT:run (default-cli) < package @ demo1-maven-plugin-run <<<
  39. [INFO]
  40. [INFO]
  41. [INFO] --- demo1-maven-plugin:1.0-SNAPSHOT:run (default-cli) @ demo1-maven-plugin-run ---
  42. [INFO] Started:D:\code\IdeaProjects\maven-chat10\demo1-maven-plugin-run\target\demo1-maven-plugin-run-1.0-SNAPSHOT.jar
  43. Tue Nov 26 17:24:47 CST 2019:0
  44. Tue Nov 26 17:24:48 CST 2019:1
  45. Tue Nov 26 17:24:49 CST 2019:2
  46. Tue Nov 26 17:24:50 CST 2019:3
  47. Tue Nov 26 17:24:51 CST 2019:4
  48. Tue Nov 26 17:24:52 CST 2019:5
  49. Tue Nov 26 17:24:53 CST 2019:6
  50. Tue Nov 26 17:24:54 CST 2019:7
  51. Tue Nov 26 17:24:55 CST 2019:8
  52. Tue Nov 26 17:24:56 CST 2019:9
  53. Tue Nov 26 17:24:57 CST 2019:10
  54. Tue Nov 26 17:24:58 CST 2019:11
  55. Tue Nov 26 17:24:59 CST 2019:12
  56. Tue Nov 26 17:25:00 CST 2019:13

是不是打包+运行很简单,一行命令就搞定了。

后面我们需要学的springboot中也是一个maven命令就可以启动springboot项目,这个原理和我们上面的类似,是spring官方他们自己开发了一款maven插件,可以直接运行springboot项目,后面学习springboot的时候,我们会详细介绍。

总结

本文的内容起到一个抛砖引玉的作用,大家如果有兴趣,可以去写很多更好的maven插件玩玩,maven默认提供了很多优秀的插件,大家可以去看他们的源码,借鉴他们的设计思路,开发出自己喜欢的插件使用,有问题的可以加我微信【itsoku】或者留言交流!

maven系列到此已经结束了,10篇如果都能够坚持看完,大家已经成为一等一的高手了。

后面将进行mybatis、springboot、springcloud系列,所有系列的目标都是让大家掌握从入门到高级开发所需要的所有技能。

Maven系列目录

  1. Maven系列:第1篇:Maven未出世前,我们那些痛苦的经历!

  2. Maven系列第2篇:安装、配置、mvn运行过程详解

  3. Maven系列第3篇:详解maven解决依赖问题

  4. Maven系列第4篇:仓库详解

  5. Maven系列第5篇:私服详解

  6. Maven系列第6篇:生命周期和插件详解,高手必备!

  7. Maven系列第7篇:聚合、继承、单继承问题详解,必备技能!

  8. Maven系列第8篇:大型Maven项目,快速按需任意构建,必备神技能!

  9. Maven系列第9篇:多环境构建,作为核心开发,这个玩不转有点说不过去!

更多好文章

  1. java高并发系列(共34篇)

  2. mysql高手系列(共27篇)

  3. 聊聊db和缓存一致性常见的实现方式

  4. 接口幂等性这么重要,它是什么?怎么实现?

感谢大家的阅读,也欢迎您把这篇文章分享给更多的朋友一起阅读!谢谢!

路人甲java

▲长按图片识别二维码关注

路人甲Java:工作10年的前阿里P7分享Java、算法、数据库方面的技术干货!坚信用技术改变命运,让家人过上更体面的生活!

文章知识点与官方知识档案匹配,可进一步学习相关知识
Java技能树Java概览Maven基础14061 人正在系统学习中 来源:https://itsoku.blog.csdn.net/article/details/103268188


http://www.taodudu.cc/news/show-2101220.html

相关文章:

  • 走过电竞之路的程序员
  • 传奇物品在地上显示,红字,自动拾取文件
  • 完美世界服务器维护多久,完美世界服务端启动和维护
  • Spring Boot 接入 Dubbo 指导文档
  • 传奇服务器怎么修改升级武器成功,四次升级武器成功
  • 怎么修改服务器玩家等级级上限,GOM引擎等级限制了极限怎么办?传奇服务端突破等级限制的方法...
  • 射雕zero找不到服务器,神秘领域《射雕ZERO》未揭秘场景盘点
  • 面试感悟----一名3年工作经验的程序员应该具备的技能
  • 网络暴利行业,天龙私服赚千万是不是梦想?
  • IIS使用十大原则
  • 项目管理--maven浅析《四》之私服(Nexus)
  • 如果命运是一条孤独的河流,谁会是你的灵魂摆渡人
  • 私服脚本制作教程......
  • 网页游戏服务器的源代码武者无敌_仅百元搭建盗版游戏框架,牟利上百万元……私服游戏地下产业链的“生意经”...
  • 网页游戏服务器的源代码武者无敌_周志宏:私服游戏 别拿法律当儿戏
  • 沙巴克服务器占用,传奇私服服务端里最完整的攻沙传送教程,直接飞皇宫和影之道方法...
  • 马云私服
  • Camera_Hal3_User_Manual
  • PostgreSQL usermanual翻译暂停20200420
  • 【RDMA】文档和教程和相关知识
  • Sentaurus入门(1):工艺仿真
  • NXP S32G2开发
  • Android studio导入项目报错Please refer to the user guide chapter on the daemon at http://gradle.org/docs/2
  • 阿里大佬手把手教你用jmeter做压力测试(详图)
  • Davinci Configurator之User Config File配置功能
  • vim user-manual的笔记 Chapter1
  • NXP:I2C总线技术规范和用户手册(中文版)(一)
  • guide, manual, tutorial之间的区别
  • OsiriX User Manual - 3D Curved MPR(曲面重建)
  • VideoEdit+ User Manual

MAVEN专题之十、设计你自己的maven插件【高手必备】相关推荐

  1. 【无线网络技术专题(十)】企业无线网络规划设计与交付流程

    无线专题共12篇,本文为第十篇(点击标题跳转历史文章): 无线专题(一):无线网络的前世今生 无线专题(二):Wi-Fi6与5G之战 无线专题(三):无线网络是通过空气传输数据吗? 无线专题(四):你 ...

  2. 专题开发十二:JEECG微云快速开发平台-基础用户权限

      专题开发十二:JEECG微云快速开发平台-基础用户权限 11.3.4自定义按钮权限 Jeecg中,目前按钮权限设置,是通过对平台自己封装的按钮标签(<t:dgFunOpt等)进行设置.而在开 ...

  3. 专题开发十二:JEECG微云高速开发平台-基础用户权限

      专题开发十二:JEECG微云高速开发平台-基础用户权限 11.3.4自己定义button权限 Jeecg中.眼下button权限设置,是通过对平台自己封装的button标签(<t:dgFun ...

  4. Maven学习总结(十)——使用Maven编译项目gbk的不可映射问题

    2019独角兽企业重金招聘Python工程师标准>>> Maven学习总结(十)--使用Maven编译项目gbk的不可映射问题 一.问题描述 今天在MyEclipse中使用Maven ...

  5. 十二、阿里云 maven 配置

    十二.阿里云 maven 配置 在 maven 目录下的 conf/setting.xml 中找到 mirrors 添加如下内容,对所有使用改 maven 打包的项目生效 <mirror> ...

  6. MAVEN专题之五、私服详解

    maven系列目标:从入门开始开始掌握一个高级开发所需要的maven技能. 这是maven系列第5篇. 整个maven系列的内容前后是有依赖的,如果之前没有接触过maven,建议从第一篇看起,本文尾部 ...

  7. Maven学习(十四)profile标签

    Maven学习(十四)profile标签 1.profile概述 ①单词释义 ②项目的不同运行环境 ②默认profile 2.profile配置 ①外部视角:配置文件 ②内部实现:具体标签 [1]pr ...

  8. 【隐私计算笔谈】MPC系列专题(十五):三方复制秘密分享

    [隐私计算笔谈]MPC系列专题(十五):三方复制秘密分享 文章目录 [隐私计算笔谈]MPC系列专题(十五):三方复制秘密分享 三方复制秘密分享 [隐私计算笔谈]MPC系列专题(一):安全多方计算应用场 ...

  9. STemWin专题-控件设计

    STemWin图形化界面设计专题 STemWin-控件设计 如果你是个小白,你即将对STemWin这方面进行一个开发,你需要先初始化一些东西,就是所谓的学前准备工作,也是对软件的一个基本配置. 软件的 ...

  10. 百度hao123-游戏专题头部Banner设计-百度UE讲堂-专题视频课程

    百度hao123-游戏专题头部Banner设计-301人已学习 课程介绍         本课程详细讲解了运营Banner设计的思路和方法,包括字体设计,特效制作,背景处理等 课程收益     掌握b ...

最新文章

  1. Windbg、dump分析类资源链接
  2. BZOJ4590: [Shoi2015]自动刷题机
  3. 剑指Offer - 面试题60. n个骰子的点数(动态规划)
  4. 什么是Apache Spark?这篇文章带你从零基础学起
  5. 粒子群优化算法(1)
  6. python怎么读取excel-python对Excel的读取
  7. 一、网络知识 1.计算机网络原理
  8. 训练好caffemodel后,提取人脸图片的特征向量
  9. MVC/POJO/POJI/DAO/DTO/VO
  10. UMTS移动通信技术
  11. H3C 路由器中VLAN隔离
  12. 计算机硬件的五大逻辑部分,计算机硬件系统主要由五个部分组成?
  13. js原型、原型链、原型链继承详解
  14. Excel报表的导出
  15. 41家大公司年度福利比较 大公司福利档案揭秘
  16. Robust Consistent Video Depth Estimation_具有鲁棒一致性的视频深度估计
  17. 爱江山更爱美人服务器维护,爱江山更爱美人,不花钱的升级攻略
  18. RNA核糖核酸修饰RNA-HiLyte FluorTM 405荧光染料|RNA-HiLyte FluorTM 405
  19. XShell安装报错1605或1608
  20. 关于近视眼手术网友的评价

热门文章

  1. 2021级南航计算机专硕829备考记录
  2. bayer raw RGB raw
  3. ROS安装超详细保姆级教程
  4. ROS安装教程(ubuntu16.04安装ROS Kinetic)
  5. “国潮” MCU厂商列表
  6. python爬虫入门实例
  7. 年会将近,如何用Excel做个抽奖界面?
  8. 五分钟带你玩转rabbitmq(八)【真实案例】消息消费失败如何处理?
  9. VS-RK3399 and VS-RK3288 Audio 开发指南
  10. 梅小雨20190919-5 代码规范,结对