代碼生成器

代碼生成器

1. 模板技術

  • velocity:默認模板後綴vm
  • freemarker:默認模板後綴ftl

1.1 模板技術輸出數據

數據(通常從數據庫來)+模板(自定義)= 輸出文本(目標文件)。

1.2 velocity的模板技術功能點

  1. 動態頁面靜態化:xxx.html
  2. 在後臺準備數據,在前臺準備模板,通過IO把數據與模板合併,真正的生成一個html頁面出來。
  3. 用作發送郵件、短信模板。
  4. 代碼生成器(今天要完成的代碼生成器)。

2. velocity技術

2.1 pom依賴

<!-- 代碼生成器模版技術 -->
<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity</artifactId>
    <version>1.6</version>
</dependency>

2.2 入門程序

  1. 程序代碼
@Test
public void test() throws Exception {
    //創建模本應用上下文
    VelocityContext context = new VelocityContext();
    //填充數據
    context.put("msg","Hello World!");
    //加載模板
    Template template = Velocity.getTemplate("template/new.html","UTF-8");
    //封裝文本(目標文件)的位置
    FileWriter writer = new FileWriter(new File("template/new_1.html"));
    //將數據寫到模板中
    template.merge(context,writer);
    writer.close();
}
  1. 模板
<html>
<meta charset="UTF-8">
<title></title>
<body>
<h1 style="color: red">${msg}</h1>
</body>
</html>

3.EasyCode插件

​ 主要通過自定義模板(基於velocity)來生成各種代碼。通常用於生成Entity(domain)、Dao、Service、Controller。如果你動手能力強還可以用於生成HTML、JS、PHP等代碼,理論上來說只要是與數據有關的代碼都是可以生成的。

5.1 直接在plugins中安裝Easy Code即可。

5.2 配置數據庫

  1. idea面板右邊點擊database配置數據庫;
  2. 注意要選擇與當前項目對應的數據。

5.3 配置模板

5.3.1 domain模板

##引入宏定義
$!define
##使用宏定義設置回調(保存位置與文件後綴)
#save("/main/java/com/yogie/domain", ".java")
##使用宏定義設置包後綴
#setPackageSuffix("domain")
##使用全局變量實現默認包導入
$!autoImport
import javax.persistence.*;
##使用宏定義實現類註釋信息
#tableComment("實體類")
@Entity
@Table(name = "$!{tableInfo.obj.name}")
public class $!{tableInfo.name} extends BaseDomain{
#foreach($column in $tableInfo.otherColumn)
    #if(${column.comment})//${column.comment}#end
    private $!{tool.getClsNameByFullName($column.type)} $!{column.name};
#end
#foreach($column in $tableInfo.otherColumn)
##使用宏定義實現get,set方法
    #getSetMethod($column)
#end
}

5.3.2 query模板

##引入宏定義
$!define
##使用宏定義設置回調(保存位置與文件後綴)
#save("/main/java/com/yogie/query", ".java")
##使用宏定義設置包後綴
#setPackageSuffix("query")
##設置文件名
$!callback.setFileName($tool.append($!{tableInfo.name},"Query", ".java"))
##使用全局變量實現默認包導入
$!autoImport
import com.github.wenhao.jpa.Specifications;
import com.yogie.domain.$!{tableInfo.name};
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.jpa.domain.Specification;
##使用宏定義實現類註釋信息
#tableComment("實體類")
public class $!{tableInfo.name}Query extends BaseQuery {
    //查詢條件需要的字段
    private String name;
    /**
     * 創建query查詢條件
     */
    @Override
    public Specification createSpec() {
        /**
         * Specifications:是com.github.wenhao.jpa插件的類
         */
        Specification<$!{tableInfo.name}> spec = Specifications.<$!{tableInfo.name}>and()
                .like(StringUtils.isNotBlank(name), "name", "%" + name + "%")
                .build();
        return spec;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

5.3.2 repository模板

##引入宏定義
$!define
##使用宏定義設置回調(保存位置與文件後綴)
#save("/main/java/com/yogie/repository", ".java")
##使用宏定義設置包後綴
#setPackageSuffix("repository")
##設置文件名
$!callback.setFileName($tool.append($!{tableInfo.name},"Repository", ".java"))
##使用全局變量實現默認包導入
$!autoImport
import com.yogie.domain.$!{tableInfo.name};
##使用宏定義實現類註釋信息
#tableComment("實體類")
public interface $!{tableInfo.name}Repository extends BaseRepository<$!{tableInfo.name},Long>{
}

5.3.2 service模板

##引入宏定義
$!define
##使用宏定義設置回調(保存位置與文件後綴)
#save("/main/java/com/yogie/service", ".java")
##使用宏定義設置包後綴
#setPackageSuffix("service")
##設置文件名
$!callback.setFileName($tool.append("I",$!{tableInfo.name},"Service", ".java"))
##使用全局變量實現默認包導入
$!autoImport
import com.yogie.domain.$!{tableInfo.name};
##使用宏定義實現類註釋信息
#tableComment("實體類")
public interface I$!{tableInfo.name}Service extends IBaseService<$!{tableInfo.name},Long> {
}

5.3.2 serviceimpl模板

##引入宏定義
$!define
##使用宏定義設置回調(保存位置與文件後綴)
#save("/main/java/com/yogie/service/impl", ".java")
##使用宏定義設置包後綴
#setPackageSuffix("service.impl")
##設置文件名
$!callback.setFileName($tool.append($!{tableInfo.name},"ServiceImpl", ".java"))
##使用全局變量實現默認包導入
$!autoImport
import com.yogie.domain.$!{tableInfo.name};
import com.yogie.repository.$!{tableInfo.name}Repository;
import com.yogie.service.I$!{tableInfo.name}Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
##使用宏定義實現類註釋信息
#tableComment("實體類")
@Service
public class $!{tableInfo.name}ServiceImpl extends BaseServiceImpl<$!{tableInfo.name},Long> implements I$!{tableInfo.name}Service {
    @Autowired
    private $!{tableInfo.name}Repository $!{tableInfo.obj.name}Repository;
}

5.3.2 controller模板

##引入宏定義
$!define

##使用宏定義設置回調(保存位置與文件後綴)
#save("/main/java/com/yogie/web/controller", ".java")

##使用宏定義設置包後綴
#setPackageSuffix("web.controller")

##設置文件名
$!callback.setFileName($tool.append($!{tableInfo.name},"Controller", ".java"))

##使用全局變量實現默認包導入
$!autoImport
import com.yogie.common.JsonResult;
import com.yogie.common.UIPage;
import com.yogie.domain.$!{tableInfo.name};
import com.yogie.query.$!{tableInfo.name}Query;
import com.yogie.service.I$!{tableInfo.name}Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;

##使用宏定義實現類註釋信息
#tableComment("實體類")
@Controller
@RequestMapping("/$!{tableInfo.obj.name}")
public class $!{tableInfo.name}Controller {
    @Autowired
    private I$!{tableInfo.name}Service $!{tableInfo.obj.name}Service;
    
    @RequestMapping("/index")
    public String index() {
        return "$!{tableInfo.obj.name}/$!{tableInfo.obj.name}";
    }
    
    @RequestMapping("/findAll")
    @ResponseBody
    public List<$!{tableInfo.name}> findAll() {
        return $!{tableInfo.obj.name}Service.findAll();
    }
    
    @RequestMapping("/findPage")
    @ResponseBody
    public UIPage<$!{tableInfo.name}> findPage($!{tableInfo.name}Query baseQuery) {
        Page page = $!{tableInfo.obj.name}Service.findPageByQuery(baseQuery);
        return new UIPage(page);
    }

    @RequestMapping("/delete")
    @ResponseBody
    public JsonResult delete(Long id) {
        try {
            $!{tableInfo.obj.name}Service.delete(id);
            return new JsonResult();
        } catch (Exception e) {
            e.printStackTrace();
            return new JsonResult(false, e.getMessage());
        }
    }

    /**
     * 設計這個方法是爲了解決在修改實體對象的時候會產生數據丟失的問題。
     * springmvc的@ModelAttribute註解會在每個controller的每個方法前面執行
     */
    @ModelAttribute("edit$!{tableInfo.name}")
    public $!{tableInfo.name} beforeEdit(Long id, String cmd) {
        if (id != null && "_update".equals(cmd)) {
            $!{tableInfo.name} $!{tableInfo.obj.name} = $!{tableInfo.obj.name}Service.findOne(id);
            /**
             * 這個方法的設計是爲了解決當前臺修改部門的時候,調教修改的時候會報錯:n to n
             * 這個錯誤的原因是:當修改部門的時候,實際上是修改的$!{tableInfo.obj.name}對應的持久化對象的department持久化對象的oid
             * 解決辦法就是:直接將員工關聯的department對象設置爲null
             * 然後springmvc會根據前臺的department.id自動創建一個非持久的department對象
             */
            //$!{tableInfo.obj.name}.setDepartment(null);
            return $!{tableInfo.obj.name};
        }
        return null;
    }

    /**
     * 當在進行修改的時候,修改實體的時候會產生數據丟失現象
     * @param $!{tableInfo.obj.name}
     * @return
     */
    @RequestMapping("/update")
    @ResponseBody
    public JsonResult update(@ModelAttribute("edit$!{tableInfo.name}") $!{tableInfo.name} $!{tableInfo.obj.name}) {
        try {
            $!{tableInfo.obj.name}Service.save($!{tableInfo.obj.name});
            return new JsonResult();
        } catch (Exception e) {
            e.printStackTrace();
            return new JsonResult(false, e.getMessage());
        }
    }
    @RequestMapping("/save")
    @ResponseBody
    public JsonResult save($!{tableInfo.name} $!{tableInfo.obj.name}) {
        try {
            $!{tableInfo.obj.name}Service.save($!{tableInfo.obj.name});
            return new JsonResult();
        } catch (Exception e) {
            e.printStackTrace();
            return new JsonResult(false, e.getMessage());
        }
    }
}

5.3.2 test模板

##引入宏定義
$!define
##使用宏定義設置回調(保存位置與文件後綴)
#save("/test/java/com/yogie/repository", ".java")
##使用宏定義設置包後綴
#setPackageSuffix("repository")
##設置文件名
$!callback.setFileName($tool.append($!{tableInfo.name},"RepositoryTest",".java"))
##使用全局變量實現默認包導入
$!autoImport
import com.github.wenhao.jpa.Specifications;
import com.yogie.domain.$!{tableInfo.name};
import com.yogie.query.$!{tableInfo.name}Query;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.persistence.criteria.*;
import java.util.List;

##使用宏定義實現類註釋信息
#tableComment("測試類")
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class $!{tableInfo.name}RepositoryTest {
    @Autowired
    private $!{tableInfo.name}Repository $!{tableInfo.obj.name}Repository;

    @Test
    public void testAdd() {
        $!{tableInfo.name} $!{tableInfo.obj.name} = new $!{tableInfo.name}();
        //添加set方法
        
        $!{tableInfo.obj.name}Repository.save($!{tableInfo.obj.name});
    }
}

5.3.2 jsp模板

##引入宏定義
$!define
##使用宏定義設置回調(保存位置與文件後綴)
#save("/main/webapp/WEB-INF/views/$!{tableInfo.obj.name}", ".jsp")
##設置文件名
$!callback.setFileName($tool.append($!{tableInfo.obj.name}, ".jsp"))

<%--
  User: $!author
  Date: $!currTime
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
    <title>$!{tableInfo.obj.name}.jsp</title>
    <%@include file="../head.jsp" %>
    <%--自定義的js要在head.jsp後引入,因爲head.jsp中有jquery的引入,自定義的js如果要使用jquey,就需要之後引入--%>
    <script src="/js/model/$!{tableInfo.obj.name}.js"></script>
    <%--引入easyui擴展庫--%>
    <link rel="stylesheet" href="http://www.easyui-extlib.com/Content/icons/icon-standard.css" />
    <link rel="stylesheet" href="http://www.easyui-extlib.com/Scripts/jquery-easyui-extensions/datagrid/jeasyui.extensions.datagrid.css" />
    <script src="http://www.easyui-extlib.com/Scripts/jquery-easyui-extensions/menu/jeasyui.extensions.menu.js"></script>
    <script src="http://www.easyui-extlib.com//Scripts/jquery-easyui-extensions/datagrid/jeasyui.extensions.datagrid.getColumnInfo.js"></script>
    <script src="http://www.easyui-extlib.com/Scripts/jquery-easyui-extensions/datagrid/jeasyui.extensions.datagrid.columnToggle.js"></script>
    <style>
        #editForm table tr td{
            padding: 3px;
        }
        .datagrid-row-selected{
            background-color:#0092DC;
        }
    </style>
</head>
<body oncontextmenu="doNothing()">
<table id="$!{tableInfo.obj.name}Grid" class="easyui-datagrid" fit="true"
       data-options="url:'/$!{tableInfo.obj.name}/findPage',fitColumns:true,
       singleSelect:false,checkOnSelect:true,onRowContextMenu:showMenu,
       pagination:true,toolbar:'#gridTolls',enableHeaderClickMenu:'true'">
    <thead>
        <tr>
            <th data-options="field:'',checkbox:true,width:50,checkbox:true" align="center"></th>
            #foreach($column in $tableInfo.otherColumn)
                #if(${column.comment})//${column.comment}#end
                <th data-options="field:'$!{column.name}',width:100" align="center">$!{column.name}</th>
            #end
        </tr>
    </thead>
</table>
<%--datagrid頂部工具欄--%>
<div id="gridTolls" style="padding:5px;height:auto">
    <%--操作按鈕--%>
    <div style="margin-bottom:5px">
        <a href="#" data-method="add" class="easyui-linkbutton" iconCls="icon-add" plain="true">添加</a>
        <a href="#" data-method="update" class="easyui-linkbutton" iconCls="icon-edit" plain="true">修改</a>
        <a href="#" data-method="del" class="easyui-linkbutton" iconCls="icon-remove" plain="true">刪除</a>
    </div>
    <%--搜索部分--%>
    <form id="searchForm">
        名稱: <input name="name" class="easyui-textbox" style="width:80px">
        <a data-method="search" href="#" class="easyui-linkbutton" iconCls="icon-search">查詢</a>
    </form>
</div>
<%--對話框--%>
<div id="$!{tableInfo.obj.name}Dialog" class="easyui-dialog" style="width:345px;padding-left: 35px;padding-right: 35px;padding-top: 15px;"
     data-options="title:'編輯功能',buttons:'#editBtn',modal:true,closed:true">
    <form id="editForm" method="post">
        <%--當修改的時候,把id傳到後臺--%>
        <input id="$!{tableInfo.obj.name}Id" type="hidden" name="id">
        <table>
        #foreach($column in $tableInfo.otherColumn)
        #if(${column.comment})//${column.comment}#end
        <tr>
            <td>
                <label>$!{column.name}:</label>
            </td>
            <td>
                <input class="easyui-validatebox" type="text" name="$!{column.name}"
                      data-options="required:true"/>
            </td>
        </tr>
        #end
        </table>
    </form>
</div>
<div id="editBtn">
    <a data-method="save" href="#" class="easyui-linkbutton">保存</a>
    <a data-method="close" href="#" class="easyui-linkbutton">關閉</a>
</div>
<div id="gridMenu" class="easyui-menu" style="width:80px;">
    <div data-options="iconCls:'icon-add'">添加</div>
    <div data-options="iconCls:'icon-edit'">修改</div>
    <div data-options="iconCls:'icon-remove'">刪除</div>
</div>
</body>
</html>

5.3.2 js模板

## 引入宏定義
$!define
## 使用宏定義設置回調(保存位置與文件後綴)
#save("/main/webapp/js/model", ".js")
## 設置文件名
$!callback.setFileName($tool.append($!{tableInfo.obj.name}, ".js"))
/**
 * User: $!author
 * Date: $!currTime
**/
//阻止瀏覽器原有的右鍵菜單彈出
function doNothing() {
    window.event.returnValue = false;
    return false;
}

function deptFormat(value, row, index) {
    return value ? value.name : "";
}

function imgFormat(value, row, index) {
    return `<img src='${value}' alt='無圖片' width="50px" height="50px"/>`;
}

function showMenu(e, index, row) {
    //選中這個行
    $("#$!{tableInfo.obj.name}Grid").datagrid("selectRow", index);
    //第0個位置的面板不支持相應功能
    e.preventDefault();
    $('#gridMenu').menu('show', {
        left: e.pageX,
        top: e.pageY,
        onClick: function (item) {
            switch (item.text) {
                case "添加" : {
                    mymethod.add();
                }
                    ;
                    break;
                case "修改" : {
                    mymethod.update();
                }
                    ;
                    break;
                case "刪除" : {
                    mymethod.del();
                }
                    ;
                    break;
            }
        }
    });
}

$(function () {

    /*爲每一個帶有data-method屬性的a標籤綁定click事件*/
    $("a[data-method]").on("click", function () {
        /*獲取方法的名稱*/
        let methodName = $(this).data("method");
        /*調用方法*/
        window.mymethod[methodName]();
    });

    /*拿到常用的組件*/
    let $!{tableInfo.obj.name}Grid = $("#$!{tableInfo.obj.name}Grid");
    let searchForm = $("#searchForm");
    let $!{tableInfo.obj.name}Dialog = $("#$!{tableInfo.obj.name}Dialog");
    let editForm = $("#editForm");

    /*方法的定義*/
    mymethod = {
        add() {
            $("*[data-edit]").show();
            $("*[data-edit] input").validatebox("enable");
            //先清空
            editForm.form("clear");
            $!{tableInfo.obj.name}Dialog.dialog("center").dialog("open");
        },
        del() {//多行刪除
            /*let row = $!{tableInfo.obj.name}Grid.datagrid("getSelected");*/
            let rows = $!{tableInfo.obj.name}Grid.datagrid("getSelections");
            //如果用戶沒有選中行
            if (!rows) {
                $.messager.alert("警告", "請至少選中一行數據再刪除!", "warning");
                return;
            } else {
                /*如果已經選中,提示是否確認進行刪除操作*/
                $.messager.confirm('確認', `您確認想要刪除這${rows.length}條記錄嗎?`, function (r) {
                    if (r) {
                        for (let i = 0; i < rows.length; i++) {
                            $.get('/$!{tableInfo.obj.name}/delete', {id: rows[i].id}, function (result) {
                                if (result.success) {
                                    $!{tableInfo.obj.name}Grid.datagrid("reload");
                                } else {
                                    $.messager.alert("錯誤", "刪除失敗,原因:+" + result.msg, "error")
                                }
                                //關閉對話框
                                mymethod.close();
                            });
                        }
                    }
                });
            }
        },
        save() {
            let url = "/$!{tableInfo.obj.name}/save";
            let $$!{tableInfo.obj.name}Id = $("#$!{tableInfo.obj.name}Id").val();
            if ($$!{tableInfo.obj.name}Id) {
                url = "/$!{tableInfo.obj.name}/update?cmd=_update";
            }
            editForm.form('submit', {
                url: url,
                //提交之前的操作
                onSubmit: function () {
                    return $(this).form('validate');
                },
                //提交完成後,接收後臺返回的數據,並操作
                success: function (data) {
                    let result = JSON.parse(data);
                    if (result.success) {
                        //如果保存成功,就重新加載數據
                        $!{tableInfo.obj.name}Grid.datagrid("reload");
                    } else {
                        //沒有保存成功的話,就提示用戶
                        $.messager.alert('錯誤', `保存失敗,原因是:${result.msg}`, 'error');
                    }
                    mymethod.close();
                }
            });
        },
        update() {
            let row = $!{tableInfo.obj.name}Grid.datagrid("getSelected");
            //如果用戶沒有選中行
            if (!row) {
                $.messager.alert("警告", "請選中一行數據再修改!", "warning");
                return;
            } else {
                editForm.form("clear");
                //禁用密碼框,並讓其失效
                $("*[data-edit]").hide();
                $("*[data-edit] input").validatebox("disable");
                //解決部門不能回顯的問題
                if (row.department) {
                    //row對象增加一個department.id的屬性
                    row['department.id'] = row.department.id;
                }
                //數據回顯
                editForm.form("load", row);
                $!{tableInfo.obj.name}Dialog.dialog("center").dialog("open");
            }
        },
        search() {
            /**
             * serializeObject是easyui/plugin/jquery.jdirk.js下的方法,
             * 功能就是拿到一個form表單中的所有數據,(根據name屬性)封裝成json對象
             */
            let params = searchForm.serializeObject();
            $!{tableInfo.obj.name}Grid.datagrid("load", params);/*重新加載數據(重新發送請求)*/
        },
        close() {
            $!{tableInfo.obj.name}Dialog.dialog("close");
        }
    };

    /**
     * 雙擊單元格的時候,直接編輯該單元格的字段的內容
     */
    $!{tableInfo.obj.name}Grid.datagrid({
        onDblClickCell:function (index, field, value) {
            $!{tableInfo.obj.name}Grid.datagrid('beginEdit', index);
            let ed = $!{tableInfo.obj.name}Grid.datagrid('getEditor', {index:index,field:field});
            $(ed.target).focus();
        }
    });

    //綁定相應的事件 : 與右鍵菜單衝突
    $(window).keydown(function (event) {
        switch (event.keyCode) {
            case 46:
                mymethod.del();
                break;
            case 13:
                mymethod.update();
                break;
            case 9:
                mymethod.add();
                break;
        }
    });
    //綁定相應的事件 : 與右鍵菜單衝突
    /*$("body").bind('keydown', 'del', window.mymethod.del);
    $(document).bind('keydown', 'Shift+1', window.mymethod.add);
    $(document).bind('keydown', 'Shift+2', window.mymethod.update);*/
});

5.4 生成目標文件

當配置好模板後,點擊面板右邊的Database -> 選擇對應的數據庫 -> 選擇表 -> 右鍵 -> EasyCode -> Generate Code -> 設置正確的package(包名),path(路徑)然後選擇Template(模板) -> 點擊ok即可

5.5 導出模板

File -> Export settings ->只選擇EasyCodeSetting導出即可。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章