前几天工作之余,同事让我写一个Maven插件,因为项目很多很杂,我们公司又没有专业的数据库字典管理工具,都是我们开发人员用Excel整理一个数据字典给我们现场实施人员,每次增加新功能或该需求,增加表和修改数据时,对Excel形式数据字典维护有点。。。,此文不是讲如何维护Excel而是手写maven插件,对于我需要的功能用Maven插件来实现太简单了。
那就开始。
这里只介绍用IDEA的做法,当然其他工具也可以,只是我这边用的是IDEA。
首先我们先建个mavn项目如图:
这里就是为什么我选着IDEA因为IDEA有现成的工具
然后就是填写GroupId和Version
再然后就是完成
打开项目
已经有了现成的例子了,我们就在它给的例子上做修改。
参考maven官网添加依赖以及插件
<!-- plugin API and plugin-tools -->
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>3.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.1.6</version>
</dependency>
<!-- 用于获取jpa注解生成对应的excel-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.2.4.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<version>3.5.1</version>
</plugin>
</plugins>
</build>
配置算是结束了
先建类注解和属性注解两个注解类
类注解
/**
* @author zhuyao
* @description 类注解获取表名
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableName {
/**
* 名称
* @return
*/
String name() default "";
/**
* 信息
* @return
*/
String message();
}
/**
* @author zhuyao
* @description 属性注解用于获取表字段意思
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldName {
/**
* 名称
* @return
*/
String name() default "";
/**
* 信息
* @return
*/
String message();
}
然后上逻辑代码
/**
* @author zhuyao
*/
@Mojo(name = "tableToExcelMaven")//这里到引用插件的时候需要用到
public class TableToExcelMavenMojo extends AbstractMojo {
/**
* 扫描包
*/
@Parameter(property = "scanPackage",defaultValue = "")
private String scanPackage;
/**
* 项目源码包路径
*/
@Parameter(defaultValue = "${project.compileClasspathElements}", readonly = true)
private String[] compileClasspathElements;
/**
* 项目的artifactId
*/
@Parameter(defaultValue = "${project.artifactId}", readonly = true)
private String artifactId;
private URLClassLoader loader;
public void execute() {
String file = compileClasspathElements[0].replace("classes","");
String classPath = compileClasspathElements[0];
String libPath = compileClasspathElements[0].replace("classes",artifactId+"/WEB-INF/lib");
String basePackage = compileClasspathElements[0]+"/"+scanPackage.replaceAll("\\.","/");
try {
String libDir = (new URL("file",null,new File(libPath).getCanonicalPath()+File.separator)).toString();
String baseDir = (new URL("file",null,new File(classPath).getCanonicalPath()+File.separator)).toString();
File libDirFile = new File(libDir.replaceAll("file",""));
URLStreamHandler us = null;
List<URL> libs = new ArrayList<URL>();
if (null!=libDirFile.listFiles()){
for (File jar : libDirFile.listFiles()) {
libs.add(new URL(null,libDir+jar.getName(),us));
}
}
libs.add(new URL(null,baseDir,us));
loader = new URLClassLoader(libs.toArray(new URL[libs.size()]),Thread.currentThread().getContextClassLoader());
File dir = new File(basePackage);
List<Class<?>> classes = new ArrayList<Class<?>>();
scanner(classes,dir,classPath);
List<List<Object>> objectList = new ArrayList<List<Object>>();
for (Class<?> aClass : classes) {
if ((aClass.getAnnotation(TableName.class) != null) || (aClass.getAnnotation(Table.class) != null) || (aClass.getAnnotation(Entity.class)!=null)) {
List<Object> list1 = new ArrayList<Object>();
List<Object> list2 = new ArrayList<Object>();
List<Object> list3 = new ArrayList<Object>();
list1.add("表字段");
if ((aClass.getAnnotation(TableName.class) != null) && isNotEmpty(aClass.getAnnotation(TableName.class).name())){
list1.add(aClass.getAnnotation(TableName.class).name());
}else if ((aClass.getAnnotation(Table.class) != null) && isNotEmpty(aClass.getAnnotation(Table.class).name())){
list1.add(aClass.getAnnotation(Table.class).name());
} else {
list1.add(aClass.getSimpleName().toLowerCase());
}
list2.add("字段意思");
if ((aClass.getAnnotation(TableName.class) != null) && isNotEmpty(aClass.getAnnotation(TableName.class).message())){
list2.add(aClass.getAnnotation(TableName.class).message());
} else {
list2.add("未写注释");
}
list3.add("");
Field[] declaredFields = aClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
if ((declaredField.getAnnotation(FieldName.class) != null) || (declaredField.getAnnotation(Column.class) != null)) {
if ((declaredField.getAnnotation(FieldName.class) != null) && isNotEmpty(declaredField.getAnnotation(FieldName.class).name())){
list1.add(declaredField.getAnnotation(FieldName.class).name());
}else if ((declaredField.getAnnotation(Column.class) != null) && isNotEmpty(declaredField.getAnnotation(Column.class).name())){
list1.add(declaredField.getAnnotation(Column.class).name());
}else {
list1.add(apply(declaredField.getName()));
}
if ((declaredField.getAnnotation(FieldName.class) != null)&& isNotEmpty(declaredField.getAnnotation(FieldName.class).message())){
list2.add(declaredField.getAnnotation(FieldName.class).message());
} else {
list2.add("未写注释");
}
}else {
list1.add(apply(declaredField.getName()));
list2.add("未写注释");
}
}
objectList.add(list1);
objectList.add(list2);
objectList.add(list3);
}
OutputStream out = new FileOutputStream(file + "/table.xlsx");
new ExcelWriterBuilder().excelType(ExcelTypeEnum.XLSX)
.file(out)
.sheet(1,"表").table(1)
.doWrite(objectList);
out.close();
}
} catch (IOException e){
e.fillInStackTrace();
}
}
private void scanner(List<Class<?>> classes,File dir,String classPath){
File[] files = dir.listFiles();
for (File file : files) {
if (file.isDirectory()){
scanner(classes,file,classPath);
}else {
if (!file.getName().endsWith(".class")){
continue;
}
String path = file.getPath();
String className = getClassName(path,classPath);
try {
classes.add(Class.forName(className,true,loader));
} catch (ClassNotFoundException e){
e.printStackTrace();
continue;
}
}
}
}
private String getClassName(String path,String classPath){
classPath = (classPath==null?"":classPath);
String classDir = path.replaceAll("\\\\", "/")
.replaceAll(classPath.replaceAll("\\\\", "/"), "")
.replaceAll("/", ".")
.replaceAll("\\.class", "");
String className = classDir.substring(1, classDir.length());
return className;
}
/**
* jpa源码中的实体类如何转成数据库字段
* @param name
* @return
*/
private static String apply(String name) {
if (name == null) {
return null;
} else {
StringBuilder builder = new StringBuilder(name.replace('.', '_'));
for(int i = 1; i < builder.length() - 1; ++i) {
if (isUnderscoreRequired(builder.charAt(i - 1), builder.charAt(i), builder.charAt(i + 1))) {
builder.insert(i++, '_');
}
}
return builder.toString().toLowerCase();
}
}
private static boolean isUnderscoreRequired(char before, char current, char after) {
return Character.isLowerCase(before) && Character.isUpperCase(current) && Character.isLowerCase(after);
}
}
到这项目需要的maven插件已经算是结束了,现在就是把它打包到中央仓库,如果你不分享给其他用只要把它放到自己的本地仓库就行了,mvn install
现在我们测试下
在项目中引入jar包和插件
<dependencies>
<dependency>
<groupId>xin.zhuyao</groupId>
<artifactId>table-to-excel-maven</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>xin.zhuyao</groupId>
<artifactId>table-to-excel-maven</artifactId>
<version>1.0-SNAPSHOT</version>
<configuration>
<!--扫描包-->
<scanPackage>xin.zhuyao.wechat_article</scanPackage>
</configuration>
<executions>
<execution>
<id>tableToExcelMaven</id>
<phase>prepare-package</phase>
<goals>
<!--这个就是Mojo的name-->
<goal>tableToExcelMaven</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
这个插件是在打包时执行
这个项目用的是spring-data-jpa写的所以没有添加我的注解也是可以生产表格的。
现在我加上注解
打包后的得到道德excel是
这就出来了,也就是每次你在修改添加数据库实体类的时候添加注解就可以了,每次都会生成新的。是不是很神奇。其实maven插件还有更多用处,跟多方法,你可以去官网查查:http://maven.apache.org/plugins/
上面的项目地址在:https://github.com/zywaiting/table-to-excel-maven
学习永远是自己的事,别人说了再多,自己不动手也是学不到太多东西,maven插件官网已给,项目地址已给,剩下的就靠你自己了,其实我写的连这个知识点的九牛一毛都不算,在写这篇文章时我才发现,自己真的太渺小了。
(完)