Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java-避免创建空的子类&;接口或生成Java源代码模板_Java_Spring_Inheritance_Code Generation_Mybatis - Fatal编程技术网

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”;
公共静态最终字符串模型包