Java-避免创建空的子类&;接口或生成Java源代码模板
我正在使用Java-避免创建空的子类&;接口或生成Java源代码模板,java,spring,inheritance,code-generation,mybatis,Java,Spring,Inheritance,Code Generation,Mybatis,我正在使用Spring和Mybatis开发一个java web项目 在dao级别,我定义了一个超级类和一个超级接口,实现了所有常用方法。 因此,当在dao级别为特定模型创建子类或接口时,我只需要实现超级dao类&接口,并将类体和接口体留空。 子dao级别的类和接口有一半以上始终是空的 (空dao类和接口示例:) RoleDao.java package core.dao; import core.dao.base.BaseDao; import core.model.Role; publi
Spring
和Mybatis
开发一个java web项目在dao级别,我定义了一个超级类和一个超级接口,实现了所有常用方法。
因此,当在dao级别为特定模型创建子类或接口时,我只需要实现超级dao类&接口,并将类体和接口体留空。 子dao级别的类和接口有一半以上始终是空的
(空dao类和接口示例:) RoleDao.java
package core.dao;
import core.dao.base.BaseDao;
import core.model.Role;
public interface RoleDao extends BaseDao<Role> {
}
package core.dao.impl;
import org.springframework.stereotype.Repository;
import core.dao.RoleDao;
import core.dao.base.BaseDaoImpl;
import core.model.Role;
@Repository
public class RoleDaoImpl extends BaseDaoImpl<Role> implements RoleDao {
}
package core.dao;
导入core.dao.base.BaseDao;
导入core.model.Role;
公共接口RoleDao扩展了BaseDao{
}
RoleDaoImpl.java
package core.dao;
import core.dao.base.BaseDao;
import core.model.Role;
public interface RoleDao extends BaseDao<Role> {
}
package core.dao.impl;
import org.springframework.stereotype.Repository;
import core.dao.RoleDao;
import core.dao.base.BaseDaoImpl;
import core.model.Role;
@Repository
public class RoleDaoImpl extends BaseDaoImpl<Role> implements RoleDao {
}
package core.dao.impl;
导入org.springframework.stereotype.Repository;
导入core.dao.RoleDao;
导入core.dao.base.BaseDaoImpl;
导入core.model.Role;
@存储库
公共类RoleDaoImpl扩展BaseDaoImpl实现RoleDao{
}
我的问题是: 有没有一个好方法可以避免编写这些空类和接口,同时仍然可以使用它们 我正在考虑使用
代码生成器
来生成这些类文件,或者使用Java反射
在运行时根据需要创建此类类和接口,但尚未详细介绍
@更新 在不创建源代码的情况下实现目标似乎不太灵活,因此我决定为JavaWeb项目编写一些简单的java源代码生成器 一个叫做
codemodel
的工具非常适合这样做,它是由Sun开发的,我想现在是Oracle所有
而且,我自己用我为生成java源代码而编写的代码给出了答案。大约一个月前,我问自己同样的问题:) 看来我们有了一种解决方案,因为您使用的是Spring库。正如我读到的: 而不是使用 SqlSessionDaoSupport或SqlSessionTemplate,Mybatis Spring提供 代理工厂:MapperFactoryBean。这个类允许您注入数据 映射器接口直接连接到您的服务bean中。使用映射器时 你只是简单地称呼他们,就像你一直称呼你的DAO一样,但是你 不需要编写任何DAO实现,因为MyBatis Spring将 为您创建一个代理 这里有一个例子,也有一个例子
我希望它能给您一些启示,因为重构您的整个系统以受益于这样好的功能可能是不可行的。我们项目中使用QueryDSL和JPA的类的存储库类只有一个接口,而没有实现。但是,它并没有回答是否可以基于实体类直接生成这些存储库的问题,尽管这类似于创建
QEntity
类以用于QueryDSL
@NoRepositoryBean
public interface BaseRepository<T, ID extends Serializable> extends JpaRepository<T, ID>, QueryDslPredicateExecutor<T> {
}
@Repository
public interface DummyDataRepository extends BaseRepository<DummyData, Long> {
}
@NoRepositoryBean
公共接口BaseRepository扩展了JpaRepository、QueryDSL谓词执行器{
}
@存储库
公共接口DummyDataRepository扩展了BaseRepository{
}
我刚刚为我的项目编写了一个简单的代码生成器
它只是一个类,可以在一次执行中为一个或多个模型生成模型/dao/服务/操作级别的代码模板
依赖性:
它使用codemodel
和apachecommons io
lib,是一个spring
+springMVC
项目
如何使用它:
它在我的项目中导入一些基类/接口,生成的类从中扩展/实现,因此您可能无法直接运行它。但是您可以将它们创建为空类/接口,或者从genSourceXxx()函数中删除它们
CodeGenerator.java:
package my.project.util;
import my.project.dao.base.BaseDao;
import my.project.dao.base.BaseDaoImpl;
import my.project.model.base.BaseIdModel;
import my.project.service.base.BaseService;
import my.project.service.base.BaseServiceImpl;
import my.project.web.action.base.BaseAction;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashMap;
import java.util.Map;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.DirectoryFileFilter;
import org.apache.commons.io.filefilter.FileFileFilter;
import org.apache.commons.io.filefilter.FileFilterUtils;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import com.sun.codemodel.ClassType;
import com.sun.codemodel.JClass;
import com.sun.codemodel.JClassAlreadyExistsException;
import com.sun.codemodel.JCodeModel;
import com.sun.codemodel.JDefinedClass;
import com.sun.codemodel.JFieldVar;
import com.sun.codemodel.JMethod;
import com.sun.codemodel.JMod;
/**
* code generator
*
* @author eric
* @date Apr 10, 2015 3:32:57 PM
*/
public class CodeGenerator {
// location of source folder
public static final String tmpSourceFolderBaseLocation = "/tmp/java_code/"; // tmp location for generated code,
public static final String actualSourceFolderBaseLocation = "/mnt/star/workplace/eclipse_j2ee_workplace/project-name/source/java/"; // actual source folder,
// package
public static final String packageSeparator = ".";
public static final String basePackage = "my.project";
public static final String modelPackage = "model";
public static final String daoPackage = "dao";
public static final String daoImplPackage = "dao.impl";
public static final String servicePackage = "service";
public static final String serviceImplPackage = "service.impl";
public static final String actionPackage = "web.action";
// source file path
public static final String pkgPathSeparator = File.separator;
public static final String sourceSuffix = ".java";
public static final String basePkgPath = "my/project";
public static final String modelPkgPath = "model";
public static final String daoPkgPath = "dao";
public static final String daoImplPkgPath = "dao" + pkgPathSeparator + "impl";
public static final String servicePkgPath = "service";
public static final String serviceImplPkgPath = "service" + pkgPathSeparator + "impl";
public static final String actionPkgPath = "web" + pkgPathSeparator + "action";
// naming
public static final String daoSuffix = "Dao";
public static final String daoImplSuffix = "DaoImpl";
public static final String serviceSuffix = "Service";
public static final String serviceImplSuffix = "ServiceImpl";
public static final String actionSuffix = "Action";
// compiler for generated source code,
public static final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
// classloader for compiled class,
public static final ClassLoader cl = genCl(tmpSourceFolderBaseLocation);
/**
* compile a source file,
*
* @param sourcePath
* @throws MalformedURLException
*/
public static void compileSource(String sourcePath) throws MalformedURLException {
// set this so that won't get compile error,
System.setProperty("java.class.path", System.getProperty("java.class.path") + File.pathSeparator + tmpSourceFolderBaseLocation);
compiler.run(null, null, null, sourcePath);
}
/**
* generate a classloader,
*
* @param path
* @return
* @throws MalformedURLException
*/
public static ClassLoader genCl(String path) {
ClassLoader cl = null;
try {
cl = new URLClassLoader(new URL[] { new File(path).toURI().toURL() });
} catch (MalformedURLException e) {
e.printStackTrace();
}
return cl;
}
/**
* <p>
* Generate source for model.
* </p>
*
* @param modelName
* @throws IOException
* @throws JClassAlreadyExistsException
*/
public static void genSourceModel(String modelName) throws IOException, JClassAlreadyExistsException {
String modelFullName = genFullName(modelPackage, modelName);
JCodeModel cm = new JCodeModel();
// define type,
JDefinedClass dc = cm._class(modelFullName, ClassType.CLASS);
// extends
dc._extends(BaseIdModel.class);
// id
JFieldVar idField = dc.field(JMod.PRIVATE, Integer.class, "id"); // field
// id - getter method
JMethod getIdMethod = dc.method(JMod.PUBLIC, Integer.class, "getId");
getIdMethod.body()._return(idField);
getIdMethod.annotate(cm.ref(Override.class)); // annotation - override
// generate source code,
cm.build(new File(tmpSourceFolderBaseLocation));
// compile
compileSource(genFullPath(modelPkgPath, modelName));
}
public static void genSourceDao(String modelName) throws JClassAlreadyExistsException, ClassNotFoundException, IOException {
String daoFullName = genFullName(daoPackage, modelName, daoSuffix);
String modelFullName = genFullName(modelPackage, modelName);
JCodeModel cm = new JCodeModel();
// define type,
JDefinedClass dc = cm._class(daoFullName, ClassType.INTERFACE);
// extends
JClass superClazz = cm.ref(BaseDao.class).narrow(cl.loadClass(modelFullName));
dc._extends(superClazz);
// generate source code,
cm.build(new File(tmpSourceFolderBaseLocation));
// compile
compileSource(genFullPath(daoPkgPath, modelName, daoSuffix));
}
public static void genSourceDaoImpl(String modelName) throws JClassAlreadyExistsException, ClassNotFoundException, IOException {
String daoImplFullName = genFullName(daoImplPackage, modelName, daoImplSuffix);
String daoFullName = genFullName(daoPackage, modelName, daoSuffix);
String modelFullName = genFullName(modelPackage, modelName);
JCodeModel cm = new JCodeModel();
// define type,
JDefinedClass dc = cm._class(daoImplFullName, ClassType.CLASS);
dc.annotate(Repository.class);
// extends
JClass superClazz = cm.ref(BaseDaoImpl.class).narrow(cl.loadClass(modelFullName));
dc._extends(superClazz);
// implements
dc._implements(cl.loadClass(daoFullName));
// generate source code,
cm.build(new File(tmpSourceFolderBaseLocation));
// compile
compileSource(genFullPath(daoImplPkgPath, modelName, daoImplSuffix));
}
public static void genSourceService(String modelName) throws JClassAlreadyExistsException, ClassNotFoundException, IOException {
String serviceFullName = genFullName(servicePackage, modelName, serviceSuffix);
JCodeModel cm = new JCodeModel();
// define type,
JDefinedClass dc = cm._class(serviceFullName, ClassType.INTERFACE);
// extends
dc._extends(BaseService.class);
// generate source code,
cm.build(new File(tmpSourceFolderBaseLocation));
// compile
compileSource(genFullPath(servicePkgPath, modelName, serviceSuffix));
}
public static void genSourceServiceImpl(String modelName, boolean serviceTransaction) throws JClassAlreadyExistsException, ClassNotFoundException,
IOException {
String serviceImplFullName = genFullName(serviceImplPackage, modelName, serviceImplSuffix);
String serviceFullName = genFullName(servicePackage, modelName, serviceSuffix);
JCodeModel cm = new JCodeModel();
// define type,
JDefinedClass dc = cm._class(serviceImplFullName, ClassType.CLASS);
// annotation
dc.annotate(Service.class);
if (serviceTransaction) {
dc.annotate(Transactional.class);
}
// extends
dc._extends(BaseServiceImpl.class);
// implements
dc._implements(cl.loadClass(serviceFullName));
// generate source code,
cm.build(new File(tmpSourceFolderBaseLocation));
// compile
compileSource(genFullPath(serviceImplPkgPath, modelName, serviceImplSuffix));
}
public static void genSourceAction(String modelName) throws JClassAlreadyExistsException, ClassNotFoundException, IOException {
genSourceAction(modelName, null);
}
/**
* generate action,
*
* @param modelName
* @param rootMappingPath
* root mapping path, if null or empty then don't have this annotation,
* @throws JClassAlreadyExistsException
* @throws ClassNotFoundException
* @throws IOException
*/
public static void genSourceAction(String modelName, String rootMappingPath) throws JClassAlreadyExistsException, ClassNotFoundException, IOException {
String actionFullName = genFullName(actionPackage, modelName, actionSuffix);
JCodeModel cm = new JCodeModel();
// define type,
JDefinedClass dc = cm._class(actionFullName, ClassType.CLASS);
// annotation
dc.annotate(Controller.class);
if (StringUtils.isNotBlank(rootMappingPath)) {
dc.annotate(cm.ref(RequestMapping.class)).param("value", rootMappingPath);
}
// extends
dc._extends(BaseAction.class);
// generate source code,
cm.build(new File(tmpSourceFolderBaseLocation));
// compile
compileSource(genFullPath(actionPkgPath, modelName, actionSuffix));
}
/**
* <p>
* generate a serial java source code base on a single model, don't include service level,
* </p>
* <p>
* Warning: this will override existing code, so, be careful!
* </p>
*
* @param modelName
*/
public static void genStack(String modelName) {
genStack(modelName, false, false, null);
}
/**
* <p>
* generate a serial java source code base on a single model.
* </p>
* <p>
* Warning: this will override existing code, so, be careful!
* </p>
*
* @param modelName
* @param includeService
* specify whether include service level,
* @param serviceTransaction
* whether add transaction annotation to service impl class,
* @param actionRootMappingPath
* root mapping path, if null or empty then don't have this annotation,
*/
public static void genStack(String modelName, boolean includeService, boolean serviceTransaction, String actionRootMappingPath) {
try {
initTmp(); // clean or create folder,
// generate code - start
genSourceModel(modelName);
genSourceDao(modelName);
genSourceDaoImpl(modelName);
if (includeService) {
genSourceService(modelName);
genSourceServiceImpl(modelName, serviceTransaction);
}
genSourceAction(modelName, actionRootMappingPath);
// generate code - end
merge(); // copy,
initTmp(); // clean, so that won't have duplicated class,
} catch (IOException | JClassAlreadyExistsException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* <p>
* batch generate.
* </p>
* <p>
* Warning: this will override existing code, so, be careful!
* </p>
*
* @param models
* map of "modelName : actionRootMappingPath"
* @param includeService
* specify whether include service level,
* @param serviceTransaction
* whether add transaction annotation to service impl class,
*/
public static void genStackBatch(Map<String, String> models, boolean includeService, boolean serviceTransaction) {
for (String modelName : models.keySet()) {
genStack(modelName, includeService, serviceTransaction, models.get(modelName));
}
}
/**
* generate class fullname,
*
* @param subPackage
* @param modelName
* @return
*/
public static String genFullName(String subPackage, String modelName) {
return genFullName(subPackage, modelName, "");
}
/**
* generate class fullname,
*
* @param subPackage
* @param modelName
* @param suffix
* @return
*/
public static String genFullName(String subPackage, String modelName, String suffix) {
return new StringBuilder().append(basePackage).append(packageSeparator).append(subPackage).append(packageSeparator).append(modelName).append(suffix)
.toString();
}
/**
* generate source file path,
*
* @param subPkgPath
* @param modelName
* @return
*/
public static String genFullPath(String subPkgPath, String modelName) {
return genFullPath(subPkgPath, modelName, "");
}
/**
* generate source file path,
*
* @param subPkgPath
* @param modelName
* @param suffix
* @return
*/
public static String genFullPath(String subPkgPath, String modelName, String suffix) {
return new StringBuilder().append(tmpSourceFolderBaseLocation).append(basePkgPath).append(pkgPathSeparator).append(subPkgPath).append(pkgPathSeparator)
.append(modelName).append(suffix).append(sourceSuffix).toString();
}
/**
* clean tmp location,
*
* @throws IOException
*/
public static void initTmp() throws IOException {
File tmp = new File(tmpSourceFolderBaseLocation);
if (!tmp.exists()) { // create if not exists,
tmp.mkdirs();
} else { // clean if exists,
FileUtils.cleanDirectory(tmp);
}
}
/**
* <p>
* move generated code into source folder,
* </p>
* <p>
* Warning: this will override existing code, so, be careful!
* </p>
*/
public static void merge() {
File originalFile = new File(tmpSourceFolderBaseLocation + basePkgPath);
File targetFile = new File(actualSourceFolderBaseLocation + basePkgPath);
try {
// filter - java file,
IOFileFilter javaSuffixFilter = FileFilterUtils.suffixFileFilter(".java");
IOFileFilter javaFiles = FileFilterUtils.and(FileFileFilter.FILE, javaSuffixFilter);
// filter - dir or java file,
FileFilter filter = FileFilterUtils.or(DirectoryFileFilter.DIRECTORY, javaFiles);
FileUtils.copyDirectory(originalFile, targetFile, filter);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
// String modelName = "LoginHistory";
// String actionRootMappingPath = "/loginHistory";
// genStack(modelName, true, false, actionRootMappingPath);
Map<String, String> models = new HashMap<String, String>();
models.put("AdminAccount", "/adminAccount");
models.put("CustomerAccount", "/customerAccount");
models.put("Role", "/role");
genStackBatch(models, true, true);
}
}
包my.project.util;
导入my.project.dao.base.BaseDao;
导入my.project.dao.base.BaseDaoImpl;
导入my.project.model.base.BaseIdModel;
导入my.project.service.base.BaseService;
导入my.project.service.base.BaseServiceImpl;
导入my.project.web.action.base.BaseAction;
导入java.io.File;
导入java.io.FileFilter;
导入java.io.IOException;
导入java.net.MalformedURLException;
导入java.net.URL;
导入java.net.URLClassLoader;
导入java.util.HashMap;
导入java.util.Map;
导入javax.tools.JavaCompiler;
导入javax.tools.ToolProvider;
导入org.apache.commons.io.FileUtils;
导入org.apache.commons.io.filefilter.DirectoryFileFilter;
导入org.apache.commons.io.filefilter.filefilter;
导入org.apache.commons.io.filefilter.FileFilterUtils;
导入org.apache.commons.io.filefilter.IOFileFilter;
导入org.apache.commons.lang3.StringUtils;
导入org.springframework.stereotype.Controller;
导入org.springframework.stereotype.Repository;
导入org.springframework.stereotype.Service;
导入org.springframework.transaction.annotation.Transactional;
导入org.springframework.web.bind.annotation.RequestMapping;
导入com.sun.codemodel.ClassType;
导入com.sun.codemodel.JClass;
导入com.sun.codemodel.JClassAlreadyExistsException;
导入com.sun.codemodel.JCodeModel;
导入com.sun.codemodel.JDefinedClass;
导入com.sun.codemodel.JFieldVar;
导入com.sun.codemodel.JMethod;
导入com.sun.codemodel.JMod;
/**
*代码生成器
*
*@作者埃里克
*@日期2015年4月10日下午3:32:57
*/
公共类代码生成器{
//源文件夹的位置
公共静态最终字符串tmpSourceFolderBaseLocation=“/tmp/java_code/”;//生成代码的tmp位置,
public static final String actualSourceFolderBaseLocation=“/mnt/star/workplace/eclipse\u j2ee\u workplace/project name/source/java/”;//实际源文件夹,
//包装
公共静态最终字符串包separator=“.”;
公共静态最终字符串basePackage=“my.project”;
公共静态最终字符串模型包