Skip to content

Commit

Permalink
1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
351768593 committed Aug 24, 2021
0 parents commit a6113b6
Show file tree
Hide file tree
Showing 12 changed files with 634 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Project exclude paths
/target/
.idea
40 changes: 40 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?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>firok.spring</groupId>
<artifactId>mvci</artifactId>
<version>1.0.0</version>
<description>An annotation processing tool to generate MVC code from JavaBean(s).</description>

<properties>
<java.version>16</java.version>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
</properties>

<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>16</source>
<target>16</target>
</configuration>
</plugin>

</plugins>
</build>

</project>
65 changes: 65 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# MVC Introspector

基于 Annotation Processing Tool 技术, 工作于编译期,
为 SpringBoot 生成一整套 MVC CRUD 结构.

## 使用方式

* 在项目中引入 MVC Introspector 依赖
*`META-INF/services/` 目录下建立文件 `javax.annotation.processing.Processor`
内容为
```text
firok.spring.mvci.MVCIntrospectProcessor
```
* 启用开发环境中的 ADT 功能
* 为数据库表创建对应的 JavaBean 实体类, 并标注 `@BeanIntrospective` 注解
* 重新编译并启动项目

### 自定义生成模板

修改 `@MVCIntrospective` 注解中的 `xxxTemplate` 值即可调整相关结构的生成模板

> 将值设为 `firok.spring.mvci.Constants.DISABLE` (`"##DISABLE##"`) 会禁用相关结构生成
> 如果不想重复写多次冗长的生成模板, 可以将模板字符串定义为静态常量, 再在注解中使用
默认的模板定义在 `firok.spring.mvci.internal.DefaultXXXTemplate` 下.

创建自定义模板时, 如下键会在结构生成时被替换:

键|含义|示例替换值
-|-|-
`##BEAN_NAME_FULL##` | 实体完整名 | `TestBean`, `TestEntity`, `BeanTest`, `EntityTest`
`##BEAN_NAME_SHORT##` | 实体简称 | `Test`
`##MAPPER_NAME##` | Mapper 名称 | `TestMapper`
`##SERVICE_NAME##` | Service 名称 | `TestService`
`##SERVICE_IMPL_NAME##` | Service Impl 名称 | `TestServiceImpl`
`##CONTROLLER_NAME##` | Controller 名称 | `TestController`
`##BEAN_PACKAGE##` | 实体位置 | `firok.spring.demo.bean`, `firok.spring.demo.entity`
`##MAPPER_PACKAGE##` | Mapper 位置 | `firok.spring.demo.mapper`
`##SERVICE_PACKAGE##` | Service 位置 | `firok.spring.demo.service`
`##SERVICE_IMPL_PACKAGE##` | Service Impl 位置 | `firok.spring.demo.service.impl`
`##CONTROLLER_PACKAGE##` | Controller 位置 | `firok.spring.demo.controller`

### 自定义生成位置和名称

修改 `@MVCIntrospective` 注解中的 `xxxPackage` 值即可调整相关结构的生成位置; 修改 `xxxName` 即可调整相关结构名称.

## 注意

**MVCI 本身** 不基于 SpringBoot 和 MybatisPlus, 但是 **MVCI 默认的结构代码模板** 基于 SpringBoot 和 MybatisPlus.
所以默认情况下需为编译环境引入相关依赖, 否则项目无法通过编译.

一个可用的依赖配置为:

```xml
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3.2</version>
</dependency>
```

此外, 您需要正确提供数据库驱动等依赖, 否则项目可能无法正常运行.

MVCI 仅于 **Java16 环境** 下经过测试. 更低 Java 版本中仍可能使用, 但是您需要手动调整 `firok.spring.mvci.MVCIntrospectProcessor` 上的 `@SupportedSourceVersion` 注解值.
24 changes: 24 additions & 0 deletions src/main/java/firok/spring/mvci/Constants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package firok.spring.mvci;

import firok.spring.mvci.internal.DefaultControllerTemplate;
import firok.spring.mvci.internal.DefaultMapperTemplate;
import firok.spring.mvci.internal.DefaultServiceImplTemplate;
import firok.spring.mvci.internal.DefaultServiceTemplate;

public final class Constants
{
public static final String DEFAULT_MAPPER_TEMPLATE = DefaultMapperTemplate.VALUE;

public static final String DEFAULT_SERVICE_TEMPLATE = DefaultServiceTemplate.VALUE;

public static final String DEFAULT_SERVICE_IMPL_TEMPLATE = DefaultServiceImplTemplate.VALUE;

public static final String DEFAULT_CONTROLLER_TEMPLATE = DefaultControllerTemplate.VALUE;

/**
* 如果标注为 DISABLE, 将不会生成指定结构
*/
public static final String DISABLE = "##DISABLE##";

public static final String DEFAULT = "##DEFAULT##";
}
118 changes: 118 additions & 0 deletions src/main/java/firok/spring/mvci/MVCIntrospectProcessor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package firok.spring.mvci;

import firok.spring.mvci.internal.IntrospectContext;

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
import java.io.Writer;
import java.util.Set;

import static firok.spring.mvci.Constants.DISABLE;

@SupportedAnnotationTypes("firok.spring.mvci.MVCIntrospective")
@SupportedSourceVersion(SourceVersion.RELEASE_16)
public class MVCIntrospectProcessor extends AbstractProcessor
{
private Types typeUtils;
private Elements elementUtils;
private Filer filer;
private Messager messager;
private void printNote(Object obj)
{
messager.printMessage(Diagnostic.Kind.NOTE,"[MVCI] " + obj);
}
private void printWarning(Object obj)
{
messager.printMessage(Diagnostic.Kind.WARNING,"[MVCI] " + obj);
}
private void printError(Object obj)
{
messager.printMessage(Diagnostic.Kind.ERROR,"[MVCI] " + obj);
}

public MVCIntrospectProcessor()
{ }

@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
typeUtils = processingEnv.getTypeUtils();
elementUtils = processingEnv.getElementUtils();
filer = processingEnv.getFiler();
messager = processingEnv.getMessager();

messager.printMessage(Diagnostic.Kind.NOTE,"MVC Introspector ADT 初始化完成");
}

private void genJavaSource(String location,String content) throws Exception
{
JavaFileObject jfo = filer.createSourceFile(location);
try(Writer jw = jfo.openWriter())
{
jw.write(content);
}
}

@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)
{
Set<? extends Element> setElements = roundEnv.getElementsAnnotatedWith(MVCIntrospective.class);
printNote("读取并处理 MVC 结构");
for(Element ele : setElements)
{
if(ele instanceof TypeElement te)
{
var anno = ele.getAnnotation(MVCIntrospective.class);
var context = new IntrospectContext(te,anno);

try
{
String content; // content to generate
String qn; // qualified name
GEN_MAPPER:
{
if(DISABLE.equals(anno.mapperTemplate())) break GEN_MAPPER;
content = context.pipeline(anno.mapperTemplate());
qn = context.mapperPackage + "." + context.mapperName;
genJavaSource(qn,content);
}
GEN_SERVICE:
{
if(DISABLE.equals(anno.serviceTemplate())) break GEN_SERVICE;
content = context.pipeline(anno.serviceTemplate());
qn = context.servicePackage + "." + context.serviceName;
genJavaSource(qn,content);
}
GEN_SERVICE_IMPL:
{
if(DISABLE.equals(anno.serviceImplTemplate())) break GEN_SERVICE_IMPL;
content = context.pipeline(anno.serviceImplTemplate());
qn = context.serviceImplPackage + "." + context.serviceImplName;
genJavaSource(qn,content);
}
GEN_CONTROLLER:
{
if(DISABLE.equals(anno.controllerTemplate())) break GEN_CONTROLLER;
content = context.pipeline(anno.controllerTemplate());
qn = context.controllerPackage + "." + context.controllerName;
genJavaSource(qn,content);
}
}
catch (Exception e)
{
printError("为 [%s] 生成结构失败: %s".formatted(context.beanNameFull,e.getLocalizedMessage()));
}

printNote("为 [%s] 生成结构成功".formatted(context.beanNameFull));
}
}

return true;
}
}
54 changes: 54 additions & 0 deletions src/main/java/firok/spring/mvci/MVCIntrospective.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package firok.spring.mvci;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import static firok.spring.mvci.Constants.*;

/**
* 标记在 JavaBean 上
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MVCIntrospective
{
/* == 实体信息 == */

String beanPackage() default DEFAULT;

String beanNameFull() default DEFAULT;

String beanNameShort() default DEFAULT;

/* == 结构名称 == */

String mapperName() default DEFAULT;

String serviceName() default DEFAULT;

String serviceImplName() default DEFAULT;

String controllerName() default DEFAULT;

/* == 结构模板 == */

String mapperTemplate() default DEFAULT_MAPPER_TEMPLATE;

String serviceTemplate() default DEFAULT_SERVICE_TEMPLATE;

String serviceImplTemplate() default DEFAULT_SERVICE_IMPL_TEMPLATE;

String controllerTemplate() default DEFAULT_CONTROLLER_TEMPLATE;

/* == 结构位置 == */

String mapperPackage() default DEFAULT;

String servicePackage() default DEFAULT;

String serviceImplPackage() default DEFAULT;

String controllerPackage() default DEFAULT;
}
Loading

0 comments on commit a6113b6

Please sign in to comment.