服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - 现学现用,写个Maven插件用下

现学现用,写个Maven插件用下

2024-01-15 14:12Java技术指北 Java教程

上一次简单介绍了如何编写一个Maven插件,并且如何将插件的执行与Maven生命周期绑定,这样通过调用maven生命周期方法时,则会在配置的阶段按照插件的目标来执行代码。

Maven 插件实践

上一次简单介绍了如何编写一个Maven插件,并且如何将插件的执行与Maven生命周期绑定,这样通过调用maven生命周期方法时,则会在配置的阶段按照插件的目标来执行代码。

今天通过一个具体的插件来熟悉在项目中的使用。

一般公司的项目结构或者代码结构都是非常固定的,有一些框架针对这种固化的代码结构或约定的规范,在开发前会严格对项目进行模块划分,对各个模块的代码结构也会严格要求。那么我们则可以根据这种约定的规范,通过工具来自动化的生成代码,从而减少开发人员的工作量。

示例项目

比如我们的项目一般都会由多个模块组成,比如下面的示例:

DMP
    ├ system
    │ ├ account
    │   ├ entity
    │   ├ dao
    │   └ service
    │   └ web
    │ ├ role
    │   ├ ...
    │ ├ permission
    │   ├ ...    
    │ └ pom.xml
    ├ monitor
    │ ├ database
    │   ├ ...
    │ ├ disk
    │   ├ ...
    │ ├ memory
    │   ├ ...    
    │ └ pom.xml
    └ pom.xml

在上面的例子中,我们项目包括了system、monitor等多个模块,其中system模块包含了account、role、permission三个子模块, monitor模块包含了database、disk、memory三个子模块,每个子模块又包含了特定的代码结构. 这个属于我们约定的模块划分规则,那么基于这样的规则,我们完全可以通过开发一个插件来自动生成这种约定结构的空项目。

实现步骤

假设插件名称为 `module-create-maven-plugin`,将来我们会通过该插件实现
项目模块文件夹和一些通用文件的自动生成。插件大概配置如下:
<build>
   <plugins>
      <plugin>
         <groupId>com.sucls.blog.plugin</groupId>
         <artifactId>module-create-plugin</artifactId>
         <version>1.0.0</version>
         <configuration>
            <basedir>E:\\_projects\\demo\\DMP</basedir>
            <modules>
               <module>system/account</module>
               <module>system/role</module>
               <module>monitor/databse</module>
               <module>monitor/disk</module>
               <module>monitor/memory</module>
            </modules>
         </configuration>
      </plugin>
   </plugins>
</build>

根据我们预期要求,来设想插件的开发过程。

定义一个maven插件项目

创建一个maven插件项目,在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.sucls.blog.plugin</groupId>
    <artifactId>module-create-plugin</artifactId>
    <version>1.0.0</version>
    <packaging>maven-plugin</packaging>

    <dependencies>
        <dependency>
            <groupId>org.apache.maven</groupId>
            <artifactId>maven-plugin-api</artifactId>
            <version>3.8.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.maven</groupId>
            <artifactId>maven-core</artifactId>
            <version>3.8.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.maven.plugin-tools</groupId>
            <artifactId>maven-plugin-annotations</artifactId>
            <version>3.8.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.32</version>
        </dependency>
    </dependencies>
</project>

创建一个Mojo根据配置添加实现逻辑

goal的名字设计成modules,由于最终项目是基于maven构建,所以会生成pom.xml,插件中的几个参数就是为了生成pom而设计

@Mojo(name = "run")
public class ModulesCreatePlugin extends AbstractMojo {

    @Parameter(property = "basedir",defaultValue = "${project.basedir}")
    private String basedir;

    @Parameter
    private String project;

    @Parameter(property = "groupId",defaultValue = "${project.groupId}")
    private String groupId;
    @Parameter(property = "artifactId",defaultValue = "${project.artifactId}")
    private String artifactId;
    @Parameter(property = "version",defaultValue = "${project.version}")
    private String version;

    @Parameter
    private List<String> modules;


    private ModuleTemplateHelper moduleTemplateHelper;

    public ModulesCreatePlugin(){
        init();
    }

    public void init(){
        moduleTemplateHelper = new ModuleTemplateHelper();
    }

    @Override
    public void execute() throws MojoExecutionException, MojoFailureException {
        Log log = getLog();
        log.info(StringUtils.repeat("=",50));

        log.info(modules.toString());
        createModules();

        log.info(StringUtils.repeat("=",50));
    }

    private void createModules() {
        if(modules != null && modules.size() >0){
            List<File> moduleFiles = new ArrayList<>();

            modules.forEach(module -> {
                // 创建目录
                File path = new File(basedir,module);
                path.mkdirs();
                moduleFiles.add(path);
            });

            Set<String> parentModules = new HashSet<>();

            // 添加pom.xml
            for (File module : moduleFiles) {
                File parent = module.getParentFile();
                parentModules.add(parent.getName());
                // 上级pom
                if( !new File(parent,"pom.xml").exists() ){
                    moduleTemplateHelper.process("pom.ftl", new ModuleEntity(groupId,project,version, parent.getName()),parent.getAbsolutePath()+"/pom.xml");
                }
                // 追缴module
                XmlUtils.appendModule(new File(parent,"pom.xml"), module.getName());

                // 模块pom
                moduleTemplateHelper.process("jar.ftl", new ModuleEntity(groupId,parent.getName(),version,module.getName()),module.getAbsolutePath()+"/pom.xml");
                new File(module,"src/main/java").mkdirs();
                new File(module,"src/main/resources").mkdirs();
            }

            // 项目pom.xml追加module
            if(new File(basedir,"pom.xml").exists()){
                for (String parentModule : parentModules) {
                    XmlUtils.appendModule(new File(basedir,"pom.xml"), parentModule);
                }
            }
        }
    }

}

上面我们通过ModuleTemplateHelper辅助类结合freemaker框架,最后为各个模块生成对应的pom.xml文件;通过自定义的XmlUtils工具类结合JDK Documentation API,实现父级模块中modules节点的添加子module;

public class ModuleTemplateHelper {

    private Configuration configuration;

    public ModuleTemplateHelper() throws IOException {
        configuration = new Configuration(Configuration.VERSION_2_3_22);
        configuration.setTemplateLoader(new ClassTemplateLoader(this.getClass(), "/templates"));
        configuration.setDefaultEncoding("UTF-8");
    }

    public void process(String tpl, Object module, String outputPath){
        Template template = configuration.getTemplate(tpl);
        template.process(module, new FileWriter(outputPath));
    }
}
public class XmlUtils {

    static DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
    static TransformerFactory transformerFactory = TransformerFactory.newInstance();
    static DocumentBuilder documentBuilder;

    static {
        try {
            documentBuilder = documentBuilderFactory.newDocumentBuilder();
        } catch (ParserConfigurationException e) {
            throw new RuntimeException(e);
        }
    }
    

    /**
     *
     * @param pomXmlPath
     * @param moduleName
     */
    public static void appendModule(File pomXml, String moduleName) {
        try {
            Document document = documentBuilder.parse(pomXml);
            NodeList modules = document.getElementsByTagName("modules");
            Node modulesNode = null;
            if( modules.getLength()>0 ){
                modulesNode = modules.item(0);
            }
            if( modulesNode == null ){
                modulesNode = document.createElement("modules");
                document.appendChild(modulesNode);
            }
            // 追加
            Element module = document.createElement("module");
            module.setTextContent(moduleName);
            modulesNode.appendChild(module);

            // 保存
            transformerFactory.newTransformer().transform(new DOMSource(document), new StreamResult(pomXml));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

生成插件

执行下面的命令即可生成插件jar,并安装到本地仓库

mvn clean package

在项目中调用插件

在项目中引入插件,并且按照需要的模块添加配置,最后在IDEA右侧则可以看到该插件,双击运行,最终项目结构如下图:

结束语

很多技术本身不复杂,合理使用与加工则可以将我们平时工作中重复相似的工作内容进行简化,很多自动化工具亦是如此,只不过这些工作由别人完成了。通过今天的示例,主要了解如何将学到的知识具体化到工作中。

原文地址:https://mp.weixin.qq.com/s/ek9R2GGOfzgYINO4uay3hA

延伸 · 阅读

精彩推荐
  • Java教程详解Spring不同数据库异常如何抽象的

    详解Spring不同数据库异常如何抽象的

    根据spring-jdbc中的定义,所有的数据操作异常都会转换为 DataAccessException,下面这篇文章主要给大家介绍了关于Spring不同数据库异常如何抽象的相关资料,需要的...

    程序员阿牛6892021-12-22
  • Java教程Java利用POI读取、写入Excel的方法指南

    Java利用POI读取、写入Excel的方法指南

    这篇文章主要给大家介绍了关于Java利用POI读取、写入Excel的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值...

    Dreamer-19142021-07-18
  • Java教程实例讲解Java批量插入、更新数据

    实例讲解Java批量插入、更新数据

    这片文章介绍了一个Java批量添加数据,多个字段同时添加多条数据具体实例,面向的是Oracle数据库,需要的朋友可以参考下 ...

    奔跑吧吕子2902019-12-31
  • Java教程Java中的maven和gradle的比较与使用详解

    Java中的maven和gradle的比较与使用详解

    这篇文章主要介绍了maven和gradle的比较与使用,Maven使用基于XML的配置,Gradle采用了领域特定语言Groovy的配置,在Maven中要引入一个依赖,需要的朋友可以参考...

    毛毛的猫毛5672022-11-16
  • Java教程Ajax+Servlet+jsp显示搜索效果

    Ajax+Servlet+jsp显示搜索效果

    这篇文章主要为大家详细介绍了Ajax+Servlet+jsp显示搜索效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 ...

    伟雪无痕2782020-07-19
  • Java教程Java 中如何加密配置文件中的数据库账号和密码?

    Java 中如何加密配置文件中的数据库账号和密码?

    作为程序员每天的开发工作都离不开跟数据库打交道,而且我们的应用程序往往都会配置数据库的链接,那你有没有想过,任何一个能接触到我们项目代码...

    Java极客技术10852022-02-28
  • Java教程Java实现并查集

    Java实现并查集

    这篇文章主要为大家详细介绍了Java实现并查集,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 ...

    NinoSun4732020-07-05
  • Java教程Spring AspectJ AOP框架注解原理解析

    Spring AspectJ AOP框架注解原理解析

    这篇文章主要介绍了Spring AspectJ AOP框架注解原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以...

    NopSmile4632020-09-03