美文网首页深度好文互联网科技程序员
Java之利用Freemarker模板引擎实现代码生成器,提高效

Java之利用Freemarker模板引擎实现代码生成器,提高效

作者: 阿_毅 | 来源:发表于2017-05-06 11:03 被阅读1993次

    开心一笑

    【1.你以为我会眼睁睁的看着你去送死?我会闭着眼睛。2.给你讲个故事,从前有个笨蛋,他非常笨,别人问他问题他只会回答“没有”,这个故事你听过吗?】

    提出问题

    如何利用 Java + Freemarker 实现代码生成器???

    唯美图片

    解决问题

    ** 前言 **

    做业务开发的时候,经常要根据建立好的数据库表,生成相关的 Model , DTO , Service, Controller , DAO 等等。包括基本的增删改查。而这些细活往往比较简单且没有挑战性,纯粹苦力活。因此,根据公司的框架,开发一个代码生成器是很有必要的。

    这里:
    假如你有一定的java基础;
    假如你熟悉freemarker模板引擎;
    假如你熟悉MVC框架;
    假如你熟悉Spring Data 框架

    ** 技术选型 **

    由于代码生成器是要生成很多文件的,包 Test.java , TestDTO.java ,TestController.java , TestServiceImpl.java , ITestService.java , TestDAO.java 等等这些文件。所有考虑用 freemarker 强大的模板引擎,制作相关的模板。

    ** 实现思路 **

    首先,假如在数据库中有一张表 ay_test.

    CREATE TABLE "public"."ay_test" (
        "id" varchar(32) COLLATE "default" NOT NULL,
        "name" varchar(10) COLLATE "default",
        "birth_date" timestamp(6),
        "remark" text COLLATE "default",
        CONSTRAINT "ay_test_pkey" PRIMARY KEY ("id")
    )
    

    我们首先要获取数据库的连接,这里我只贴出相关的代码。

    private final String URL = "jdbc:postgresql://192.168.3.160:10655/cibpm";
    private final String USER = "postgres";
    private final String PASSWORD = "888888";
    private final String DRIVER = "org.postgresql.Driver";
    
    public Connection getConnection() throws Exception{
        Class.forName(DRIVER);
        Connection connection= DriverManager.getConnection(URL, USER, PASSWORD);
        return connection;
    }
    

    获取数据库表的元数据

    private final String changeTableName = replaceUnderLineAndUpperCase(tableName);
    
    Connection connection = getConnection();
    DatabaseMetaData databaseMetaData = connection.getMetaData();
    ResultSet resultSet = databaseMetaData.getColumns(null,"%", tableName,"%");
    

    最后根据元数据获取表字段,注释等等,生成相关的文件

    代码实现

    Java代码实现

    package com.evada.inno.pm.code.generate.util;
    import com.evada.inno.pm.code.generate.model.ColumnClass;
    
    import freemarker.template.Template;
    import org.apache.commons.lang3.StringUtils;
    
    import java.io.*;
    import java.sql.Connection;
    import java.sql.DatabaseMetaData;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * 描述:代码生成器
     * Created by Ay on 2017/5/1.
     */
    public class CodeGenerateUtils {
    
        private final String AUTHOR = "Ay";
        private final String CURRENT_DATE = "2017/05/03";
        private final String tableName = "tm_project_quality_problem";
        private final String packageName = "com.evada.pm.process.manage";
        private final String tableAnnotation = "质量问题";
        private final String URL = "jdbc:postgresql://192.168.3.160:10655/cibpm";
        private final String USER = "postgres";
        private final String PASSWORD = "888888";
        private final String DRIVER = "org.postgresql.Driver";
        private final String diskPath = "D://";
        private final String changeTableName = replaceUnderLineAndUpperCase(tableName);
    
        public Connection getConnection() throws Exception{
            Class.forName(DRIVER);
            Connection connection= DriverManager.getConnection(URL, USER, PASSWORD);
            return connection;
        }
    
        public static void main(String[] args) throws Exception{
            CodeGenerateUtils codeGenerateUtils = new CodeGenerateUtils();
            codeGenerateUtils.generate();
        }
    
        public void generate() throws Exception{
            try {
                Connection connection = getConnection();
                DatabaseMetaData databaseMetaData = connection.getMetaData();
                ResultSet resultSet = databaseMetaData.getColumns(null,"%", tableName,"%");
                //生成Mapper文件
                generateMapperFile(resultSet);
                //生成Dao文件
                generateDaoFile(resultSet);
                //生成Repository文件
                generateRepositoryFile(resultSet);
                //生成服务层接口文件
                generateServiceInterfaceFile(resultSet);
                //生成服务实现层文件
                generateServiceImplFile(resultSet);
                //生成Controller层文件
                generateControllerFile(resultSet);
                //生成DTO文件
                generateDTOFile(resultSet);
                //生成Model文件
                generateModelFile(resultSet);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }finally{
    
            }
        }
    
        private void generateModelFile(ResultSet resultSet) throws Exception{
    
            final String suffix = ".java";
            final String path = diskPath + changeTableName + suffix;
            final String templateName = "Model.ftl";
            File mapperFile = new File(path);
            List<ColumnClass> columnClassList = new ArrayList<>();
            ColumnClass columnClass = null;
            while(resultSet.next()){
                //id字段略过
                if(resultSet.getString("COLUMN_NAME").equals("id")) continue;
                columnClass = new ColumnClass();
                //获取字段名称
                columnClass.setColumnName(resultSet.getString("COLUMN_NAME"));
                //获取字段类型
                columnClass.setColumnType(resultSet.getString("TYPE_NAME"));
                //转换字段名称,如 sys_name 变成 SysName
                columnClass.setChangeColumnName(replaceUnderLineAndUpperCase(resultSet.getString("COLUMN_NAME")));
                //字段在数据库的注释
                columnClass.setColumnComment(resultSet.getString("REMARKS"));
                columnClassList.add(columnClass);
            }
            Map<String,Object> dataMap = new HashMap<>();
            dataMap.put("model_column",columnClassList);
            generateFileByTemplate(templateName,mapperFile,dataMap);
    
        }
    
        private void generateDTOFile(ResultSet resultSet) throws Exception{
            final String suffix = "DTO.java";
            final String path = "D://" + changeTableName + suffix;
            final String templateName = "DTO.ftl";
            File mapperFile = new File(path);
            Map<String,Object> dataMap = new HashMap<>();
            generateFileByTemplate(templateName,mapperFile,dataMap);
        }
    
        private void generateControllerFile(ResultSet resultSet) throws Exception{
            final String suffix = "Controller.java";
            final String path = diskPath + changeTableName + suffix;
            final String templateName = "Controller.ftl";
            File mapperFile = new File(path);
            Map<String,Object> dataMap = new HashMap<>();
            generateFileByTemplate(templateName,mapperFile,dataMap);
        }
    
        private void generateServiceImplFile(ResultSet resultSet) throws Exception{
            final String suffix = "ServiceImpl.java";
            final String path = diskPath + changeTableName + suffix;
            final String templateName = "ServiceImpl.ftl";
            File mapperFile = new File(path);
            Map<String,Object> dataMap = new HashMap<>();
            generateFileByTemplate(templateName,mapperFile,dataMap);
        }
    
        private void generateServiceInterfaceFile(ResultSet resultSet) throws Exception{
            final String prefix = "I";
            final String suffix = "Service.java";
            final String path = diskPath + prefix + changeTableName + suffix;
            final String templateName = "ServiceInterface.ftl";
            File mapperFile = new File(path);
            Map<String,Object> dataMap = new HashMap<>();
            generateFileByTemplate(templateName,mapperFile,dataMap);
        }
    
        private void generateRepositoryFile(ResultSet resultSet) throws Exception{
            final String suffix = "Repository.java";
            final String path = diskPath + changeTableName + suffix;
            final String templateName = "Repository.ftl";
            File mapperFile = new File(path);
            Map<String,Object> dataMap = new HashMap<>();
            generateFileByTemplate(templateName,mapperFile,dataMap);
        }
    
        private void generateDaoFile(ResultSet resultSet) throws Exception{
            final String suffix = "DAO.java";
            final String path = diskPath + changeTableName + suffix;
            final String templateName = "DAO.ftl";
            File mapperFile = new File(path);
            Map<String,Object> dataMap = new HashMap<>();
            generateFileByTemplate(templateName,mapperFile,dataMap);
    
        }
    
        private void generateMapperFile(ResultSet resultSet) throws Exception{
            final String suffix = "Mapper.xml";
            final String path = diskPath + changeTableName + suffix;
            final String templateName = "Mapper.ftl";
            File mapperFile = new File(path);
            Map<String,Object> dataMap = new HashMap<>();
            generateFileByTemplate(templateName,mapperFile,dataMap);
    
        }
    
        private void generateFileByTemplate(final String templateName,File file,Map<String,Object> dataMap) throws Exception{
            Template template = FreeMarkerTemplateUtils.getTemplate(templateName);
            FileOutputStream fos = new FileOutputStream(file);
            dataMap.put("table_name_small",tableName);
            dataMap.put("table_name",changeTableName);
            dataMap.put("author",AUTHOR);
            dataMap.put("date",CURRENT_DATE);
            dataMap.put("package_name",packageName);
            dataMap.put("table_annotation",tableAnnotation);
            Writer out = new BufferedWriter(new OutputStreamWriter(fos, "utf-8"),10240);
            template.process(dataMap,out);
        }
    
        public String replaceUnderLineAndUpperCase(String str){
            StringBuffer sb = new StringBuffer();
            sb.append(str);
            int count = sb.indexOf("_");
            while(count!=0){
                int num = sb.indexOf("_",count);
                count = num + 1;
                if(num != -1){
                    char ss = sb.charAt(count);
                    char ia = (char) (ss - 32);
                    sb.replace(count , count + 1,ia + "");
                }
            }
            String result = sb.toString().replaceAll("_","");
            return StringUtils.capitalize(result);
        }
    
    }
    
    FreeMarkerTemplateUtils工具类

    FreeMarkerTemplateUtils工具类用来配置模板所在的路径

    package com.evada.inno.pm.code.generate.util;
    
    import com.evada.inno.core.exception.BusinessException;
    import freemarker.cache.ClassTemplateLoader;
    import freemarker.cache.NullCacheStorage;
    import freemarker.template.Configuration;
    import freemarker.template.Template;
    import freemarker.template.TemplateExceptionHandler;
    
    import java.io.IOException;
    
    /**
     * Created by Ay on 2016/7/27.
     */
    public class FreeMarkerTemplateUtils {
    
        private FreeMarkerTemplateUtils(){}
        private static final Configuration CONFIGURATION = new Configuration(Configuration.VERSION_2_3_22);
    
        static{
            //这里比较重要,用来指定加载模板所在的路径
            CONFIGURATION.setTemplateLoader(new ClassTemplateLoader(FreeMarkerTemplateUtils.class, "/templates"));
            CONFIGURATION.setDefaultEncoding("UTF-8");
            CONFIGURATION.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
            CONFIGURATION.setCacheStorage(NullCacheStorage.INSTANCE);
        }
    
        public static Template getTemplate(String templateName) throws IOException {
            try {
                return CONFIGURATION.getTemplate(templateName);
            } catch (IOException e) {
                throw e;
            }
        }
    
        public static void clearCache() {
            CONFIGURATION.clearTemplateCache();
        }
    }
    
    实体类 ColumnClass

    ColumnClass 用来封装 数据库表元数据的信息,如字段名称,字段类型,字段注释等等。

    package com.evada.inno.pm.code.generate.model;
    
    /**
     * 数据库字段封装类
     * Created by Ay on 2017/5/3.
     */
    public class ColumnClass {
    
        /** 数据库字段名称 **/
        private String columnName;
        /** 数据库字段类型 **/
        private String columnType;
        /** 数据库字段首字母小写且去掉下划线字符串 **/
        private String changeColumnName;
        /** 数据库字段注释 **/
        private String columnComment;
    
        public String getColumnComment() {
            return columnComment;
        }
    
        public void setColumnComment(String columnComment) {
            this.columnComment = columnComment;
        }
    
        public String getColumnName() {
            return columnName;
        }
    
        public void setColumnName(String columnName) {
            this.columnName = columnName;
        }
    
        public String getColumnType() {
            return columnType;
        }
    
        public void setColumnType(String columnType) {
            this.columnType = columnType;
        }
    
        public String getChangeColumnName() {
            return changeColumnName;
        }
    
        public void setChangeColumnName(String changeColumnName) {
            this.changeColumnName = changeColumnName;
        }
    }
    

    freemarker 模板文件

    Freemarker的模板文件,后缀都是以ftl结尾的。

    Model.ftl模型模板

    Model.ftl可以生成字段的属性,并且可以生成字段属性对应的 set 和 get 方法,包括字段在数据库中对应的注释,以及一些该引入的包和类注释。

    package ${package_name}.model;
    import com.evada.inno.common.domain.BaseModel;
    import com.evada.inno.common.listener.ICreateListenable;
    import com.evada.inno.common.listener.IDeleteListenable;
    import com.evada.inno.common.listener.IModifyListenable;
    import org.hibernate.annotations.Where;
    import javax.persistence.*;
    import java.util.Date;
    
    /**
    * 描述:${table_annotation}模型
    * @author ${author}
    * @date ${date}
    */
    @Entity
    @Table(name="${table_name_small}")
    @Where(clause = "status > '0'")
    @Inheritance(strategy= InheritanceType.SINGLE_TABLE)
    public class ${table_name} extends BaseModel implements ICreateListenable,IModifyListenable,IDeleteListenable {
    
        <#if model_column?exists>
            <#list model_column as model>
        /**
        *${model.columnComment!}
        */
        <#if (model.columnType = 'varchar' || model.columnType = 'text')>
        @Column(name = "${model.columnName}",columnDefinition = "VARCHAR")
        private String ${model.changeColumnName?uncap_first};
    
        </#if>
        <#if model.columnType = 'timestamp' >
        @Column(name = "${model.columnName}",columnDefinition = "TIMESTAMP")
        private Date ${model.changeColumnName?uncap_first};
    
        </#if>
            </#list>
        </#if>
    
    <#if model_column?exists>
    <#list model_column as model>
    <#if (model.columnType = 'varchar' || model.columnType = 'text')>
        public String get${model.changeColumnName}() {
            return this.${model.changeColumnName?uncap_first};
        }
    
        public void set${model.changeColumnName}(String ${model.changeColumnName?uncap_first}) {
            this.${model.changeColumnName?uncap_first} = ${model.changeColumnName?uncap_first};
        }
    
    </#if>
    <#if model.columnType = 'timestamp' >
        public Date get${model.changeColumnName}() {
            return this.${model.changeColumnName?uncap_first};
        }
    
        public void set${model.changeColumnName}(Date ${model.changeColumnName?uncap_first}) {
            this.${model.changeColumnName?uncap_first} = ${model.changeColumnName?uncap_first};
        }
    
    </#if>
    </#list>
    </#if>
    
    }
    
    DTO.ftl模板

    DTO.ftl 文件用来生产 DTO 值对象,该对象继承 Model.ftl 文件中的对象。

    package ${package_name}.dto;
    
    import ${package_name}.model.${table_name};
    
    /**
    * 描述:${table_annotation}DTO
    * @author ${author}
    * @date ${date}
    */
    public class ${table_name}DTO extends ${table_name}{
    
    }
    
    Service.ftl模板

    Service.ftl 模板用来生成服务层实现类,在模板中已经添加了增 ,删,改,查等方法,同时可以注入DAO和repository 到service中,一旦文件生成,就不需要我们去写了,很方便,提高开发的效率。

    package ${package_name}.service.impl;
    import com.evada.inno.core.service.impl.BaseServiceImpl;
    import ${package_name}.model.${table_name};
    import ${package_name}.repository.${table_name}Repository;
    import ${package_name}.service.I${table_name}Service;
    import ${package_name}.repository.mybatis.${table_name}DAO;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    import ${package_name}.dto.${table_name}DTO;
    import org.apache.commons.beanutils.BeanUtils;
    import com.evada.inno.core.enums.StatusEnum;
    
    /**
    * 描述:${table_annotation} 服务实现层
    * @author ${author}
    * @date ${date}
    */
    @Service
    public class ${table_name}ServiceImpl extends BaseServiceImpl<${table_name}, String> implements I${table_name}Service {
    
        @Autowired
        private ${table_name}DAO ${table_name?uncap_first}DAO;
    
        @Autowired
        private ${table_name}Repository ${table_name?uncap_first}Repository;
    
        @Override
        public ${table_name}DTO findDTOById(String id) throws Exception {
            ${table_name}DTO ${table_name?uncap_first}DTO = ${table_name?uncap_first}DAO.findDTOById(id);
            return ${table_name?uncap_first}DTO;
        }
    
        @Override
        public ${table_name}DTO create${table_name}(${table_name}DTO ${table_name?uncap_first}DTO) throws Exception {
            ${table_name} ${table_name?uncap_first} = new ${table_name}();
            BeanUtils.copyProperties(${table_name?uncap_first},${table_name?uncap_first}DTO);
            ${table_name?uncap_first}.setStatus(StatusEnum.ENABLE.toString());
            ${table_name?uncap_first} = ${table_name?uncap_first}Repository.saveAndFlush(${table_name?uncap_first});
            return this.findDTOById(${table_name?uncap_first}.getId());
        }
    
        @Override
        public ${table_name}DTO update${table_name}(${table_name}DTO ${table_name?uncap_first}DTO)throws Exception {
            ${table_name} ${table_name?uncap_first} = new ${table_name}();
            BeanUtils.copyProperties(${table_name?uncap_first},${table_name?uncap_first}DTO);
            ${table_name?uncap_first} = ${table_name?uncap_first}Repository.saveAndFlush(${table_name?uncap_first});
            return this.findDTOById(${table_name?uncap_first}.getId());
        }
    
    Interface.ftl 模板

    Interface.ftl 用来生成服务层接口,接口中定义了增,删,改,查等接口。

    package ${package_name}.service;
    import com.evada.inno.core.service.IBaseService;
    import ${package_name}.model.${table_name};
    import ${package_name}.dto.${table_name}DTO;
    /**
    * 描述:${table_annotation} 服务实现层接口
    * @author ${author}
    * @date ${date}
    */
    public interface I${table_name}Service extends IBaseService<${table_name},String> {
    
        /**
        * 描述:根据Id获取DTO
        * @param id
        */
        ${table_name}DTO findDTOById(String id)throws Exception;
    
        ${table_name}DTO create${table_name}(${table_name}DTO ${table_name?uncap_first}DTO) throws Exception;
    
        void delete${table_name}(String id) throws Exception;
    
        ${table_name}DTO update${table_name}(${table_name}DTO ${table_name?uncap_first}DTO) throws Exception;
    
    }
    
    Respontory.ftl 模板

    Respontory.ftl 用来生成 Repository 文件,这一块是 Spring Data的内容,可能不同的公司,使用的框架不一样。

    package ${package_name}.repository;
    import com.evada.inno.core.repository.BaseJpaRepository;
    import ${package_name}.model.${table_name};
    
    /**
    * 描述:${table_annotation} Repository接口
    * @author ${author}
    * @date ${date}
    */
    public interface ${table_name}Repository extends BaseJpaRepository<${table_name}, String> {
    
    
    
    }
    
    Mappter.ftl 模板

    Mappter.ftl 用来生成 MyBatis 使用到的 mappter 文件,在文件中,定义了查询的sql语句。

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
    <mapper namespace="${package_name}.repository.mybatis.${table_name}DAO">
    
        <resultMap id="${table_name}DTOResultMap" type="${package_name}.dto.${table_name}DTO"></resultMap>
    
        <sql id="findDtoSql">
            select * from (
            select * from  ${table_name_small} temp
            ) t
        </sql>
    
        <select id="findDTOById" parameterType="String" resultMap="${table_name}DTOResultMap">
            <include refid="findDtoSql"></include>
            <where>
                and t.id = ${r'#{id}'}
            </where>
        </select>
    
        <select id="find${table_name}Page" parameterType="${package_name}.dto.${table_name}DTO" resultMap="${table_name}DTOResultMap">
            <include refid="findDtoSql" />
            <where>
    
            </where>
        </select>
    
    </mapper>
    
    Controller.ftl 模板

    Controller.ftl 文件用来生成控制层类,类中已经帮我们生成了,增,删,改,查等路由。同时可以注入接口道控制层中。

    package ${package_name}.controller;
    import com.evada.inno.core.annotation.Rest;
    import ${package_name}.service.I${table_name}Service;
    import ${package_name}.model.${table_name};
    import ${package_name}.dto.${table_name}DTO;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.http.MediaType;
    import com.evada.inno.common.domain.ResultData;
    import com.evada.inno.core.util.AssertUtils;
    
    /**
    * 描述:${table_annotation}控制层
    * @author ${author}
    * @date ${date}
    */
    @Rest(${table_name}.class)
    public class ${table_name}Controller {
    
        @Autowired
        private I${table_name}Service ${table_name?uncap_first}Service;
    
        /**
        * 描述:根据Id 查询
        * @param id  ${table_annotation}id
        */
        @RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
        public ResultData findById(@PathVariable("id") String id)throws Exception {
            ${table_name}DTO ${table_name?uncap_first}DTO = ${table_name?uncap_first}Service.findDTOById(id);
            AssertUtils.checkResourceFound(${table_name?uncap_first}DTO);
            return new ResultData(${table_name}DTO.class, ${table_name?uncap_first}DTO);
        }
    
        /**
        * 描述:创建${table_annotation}
        * @param ${table_name?uncap_first}DTO  ${table_annotation}DTO
        */
        @RequestMapping(value = "", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
        public ResultData create(@RequestBody ${table_name}DTO ${table_name?uncap_first}DTO) throws Exception {
            return new ResultData(${table_name}.class,${table_name?uncap_first}Service.create${table_name}(${table_name?uncap_first}DTO));
        }
    
        /**
        * 描述:删除${table_annotation}
        * @param id ${table_annotation}id
        */
        @RequestMapping(value = "/{id}/bulk", method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
        public void deleteById(@PathVariable("id") String id) throws Exception {
            ${table_name?uncap_first}Service.deleteById(id);
        }
    
        /**
        * 描述:更新${table_annotation}
        * @param id ${table_annotation}id
        */
        @RequestMapping(value = "/{id}", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
        public ResultData update${table_name}(@PathVariable("id") String id,@RequestBody ${table_name}DTO ${table_name?uncap_first}DTO) throws Exception {
            ${table_name?uncap_first}DTO.setId(id);
            return new ResultData(${table_name}.class,${table_name?uncap_first}Service.update${table_name}(${table_name?uncap_first}DTO));
        }
    
    }
    

    通过上面的代码生成,我们就可以把生成的文件复制到相关的目录,重新启动系统,这样,基本的增,删,改,查就实现了。

    读书感悟

    来自东野圭吾《信》

    • “大多数人都想置身于远离罪犯的地方。和犯罪者,特别是犯下抢劫杀人这样恶心犯罪的人,哪怕是间接的关系也不想有。因为稍微有点什么关系,没准也会被卷入莫名其妙的事情中去。排斥犯罪者或是与其近似的人,是非常正当的行为,也可以说是正当防卫的本能。”
    • 犯罪者必须要有这样的思想准备,就是自己犯罪的同时也抹杀了自己亲属在社会上的存在。
    • 所谓偏见,就是不平等看待,其产生的根源就在于人的自私本性。这里的不平等看待,其实可以视为一种处理各种社会关系时的态度平衡缺失,而总是向有利于自己的一方倾斜,除非不同的立场之间不存在厉害冲突。一般情况下,人都是首先从自己的角度来看问题,而不会力图站在他人的立场来考量,完全意义上的中立是不可能的,由己及人是必然的思维定势,偏见遂自然而生。

    经典故事

    【一只小青蛙厌倦了常年生活的小水沟——水沟的水越来越少,它已经没有什么食物了。小青蛙每天都不停地蹦,想要逃离这个地方。而它的同伴整日懒洋洋地蹲在浑浊的水洼里,说:“现在不是还饿不死
    吗?你着什么急?”终于有一天,小青蛙纵身一跃,跳进了旁边的一个大河塘,那里面有很多好吃的,它可以自由游弋。小青蛙呱呱地呼唤自己的伙伴:“你快过来吧,这边简直是天堂!”但是它的同伴说:“我在这里已经习惯了,我从小就生活在这里,懒得动了!” 不久,水沟里的水干了,小青蛙的同伴活活饿死了。】

    大神文章

    【1】Freemarker官网
    【2】可用于企业级开发的JAVA代码生成器
    【3】 一个java代码生成器的简单实现

    其他

    如果有带给你一丝丝小快乐,就让快乐继续传递下去,欢迎点赞、顶、欢迎留下宝贵的意见、多谢支持!

    相关文章

      网友评论

      • 赵文斌:楼主能提供相关的项目示例,谢谢楼主

      本文标题:Java之利用Freemarker模板引擎实现代码生成器,提高效

      本文链接:https://www.haomeiwen.com/subject/jwpetxtx.html