在我们一般的SpringBoot项目中,由于使用了MybatisPlus或者JPA,很多增删改查都是定一个空的Mapper或者Dao就可以实现的,我这里比较懒,参考lombok的原理实现自动生成Dao代码
首先注解处理器的项目必须是单独的一个项目。
我们创建一个Maven项目
添加Google的类库 auto-service
官方示例说明
package foo.bar;
import javax.annotation.processing.Processor;
@AutoService(Processor.class)
final class MyProcessor implements Processor {
// …
}
AutoService会自动在build/classes输入目录下生成文件META-INF/services/javax.annotation.processing.Processor,文件的内容如下
foo.bar.MyProcessor
在javax.annotation.processing.Processor的情况下,如果一个jar中包含metadata文件,并且在javac的classpath下,javac会自动加载这个jar,同时包含它的普通注解编译环境。
定义一个注解
package com.yuxuan66.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author Sir丶雨轩
* @since 2021/6/24
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.CLASS)
public @interface Dao {
}
定义一个处理器
package com.yuxuan66.processor;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import com.google.auto.service.AutoService;
import com.google.common.primitives.Chars;
import com.yuxuan66.annotation.Dao;
import org.beetl.core.Configuration;
import org.beetl.core.GroupTemplate;
import org.beetl.core.Template;
import org.beetl.core.resource.ClasspathResourceLoader;
import org.beetl.core.resource.StringTemplateResourceLoader;
import sun.nio.ch.IOUtil;
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
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.IOException;
import java.io.InputStream;
import java.io.Writer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;
/**
* @author Sir丶雨轩
* @since 2021/6/24
*/
@AutoService(Processor.class)
public class DaoProcessor extends AbstractProcessor {
private Types mTypeUtils;
private Elements mElementUtils;
private Filer mFiler;
private Messager messager;
@Override
public Set<String> getSupportedAnnotationTypes() {
Set<String> annotations = new LinkedHashSet<>();
//把我们自己定义的注解添加进去
annotations.add(Dao.class.getCanonicalName());
return annotations;
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
mTypeUtils = processingEnv.getTypeUtils();
mElementUtils = processingEnv.getElementUtils();
mFiler = processingEnv.getFiler();
messager = processingEnv.getMessager();
}
private void error(Element e, String msg, Object... args) {
messager.printMessage(Diagnostic.Kind.ERROR, String.format(msg, args), e);
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
for (Element annotatedElement : roundEnv.getElementsAnnotatedWith(Dao.class)) {
if (annotatedElement.getKind() != ElementKind.CLASS) {
error(annotatedElement, "Only classes can be annotated with @%s", Dao.class.getSimpleName());
return true;
}
// //解析,并生成代码
try {
analysisAnnotated(annotatedElement);
} catch (IOException e) {
e.printStackTrace();
}
}
return false;
}
private void analysisAnnotated(Element classElement) throws IOException {
Dao annotation = classElement.getAnnotation(Dao.class);
InputStream inputStream = this.getClass().getResourceAsStream("/template/Dao.btl");
String daoContent = IoUtil.read(Objects.requireNonNull(inputStream), StandardCharsets.UTF_8);
// 获取注解所在的包,把Dao生成到原始包中,或者按照需求生成在对应的包中
String packageName = mElementUtils.getPackageOf(classElement).getQualifiedName().toString();
daoContent = daoContent.replaceAll("#date", DateUtil.format(new Date(),"yyyy/MM/dd"));
daoContent = daoContent.replaceAll("#package",packageName);
daoContent = daoContent.replaceAll("#className",classElement.getSimpleName().toString());
try {
JavaFileObject source = mFiler.createSourceFile(packageName + "." + classElement.getSimpleName() + "Dao");
Writer writer = source.openWriter();
writer.write(daoContent);
writer.flush();
writer.close();
} catch (IOException ignored) {
}
}
}
由于功能比较简单,仅需要简单替换几个字符串即可,所以我们直接字符串串替换就可以了,如果有复杂的需求可以使用模板引擎解析
我们的模板
package #package;
import #package.#className;
import com.yuxuan66.support.basic.jpa.BasicDao;
/**
* Basic-Admin Automatic Generation
* @author Sir丶雨轩
* @since #date
*/
public interface #classNameDao extends BasicDao<#className> {
}
然后我们需要使用的项目直接在Maven中引用即可,生成出来的Dao、Mapper就像自己创建的一样,也可以被Spring管理,生成的代码会在这里显示
评论区