最近公司新開一個(gè)項(xiàng)目,很多基本的dao和service層代碼都重復(fù)遗遵,所以打算寫個(gè)簡(jiǎn)單的代碼生成器直接生成逸嘀,
免得一個(gè)一個(gè)復(fù)制麻煩车要。但是在使用Velocity的時(shí)候發(fā)現(xiàn)獲取模板信息有點(diǎn)繁瑣,需要修改配置崭倘。索性自己寫個(gè)
簡(jiǎn)單實(shí)用的自己用用翼岁,在此也做個(gè)記錄,有興趣的也可以看看司光,實(shí)現(xiàn)思路很簡(jiǎn)單琅坡。
- 代碼如下:
/**
* 測(cè)試
* Created by GN on 2016/11/27.
*/
public class GnTest {
@Test
public void testGn() throws IOException {
GnContext gnContext = new GnContext();
gnContext.put("domain","User");
gnContext.put("lowerDomain","user");
String path = "E:\\WorkSpace\\Idea\\ztx\\gn-cc\\src\\main\\resources\\DaoImpl.java";
Template template = GnUtil.getTemplate(path);
String target = "G:\\DaoImpl.java";
File file = new File(target);
template.merge(gnContext,file);
}
}
/**
* 定義模板插入值
* Created by GN on 2016/11/27.
*/
public class GnContext {
/**
* 存儲(chǔ)模板值
*/
private Map<String, String> context = new HashMap<>();
public GnContext() {
}
public GnContext(Map<String, String> context) {
this.context = context;
}
public void put(String key, String value) {
context.put(key, value);
}
public String get(String key) {
return context.get(key);
}
}
/**
* Created by GN on 2016/11/27.
*/
public abstract class GnUtil {
/**
* 獲取模板信息
* @param filePath 模板路徑
* @return
*/
public static Template getTemplate(String filePath) throws IOException {
if (!StringUtil.hasLength(filePath)){
throw new IllegalArgumentException("模板路徑不能為空");
}
File file = new File(filePath);
if (!file.isFile() || !file.exists()){
throw new IllegalArgumentException("無(wú)法找到指定文件:"+filePath);
}
return new Template(file);
}
}
/**
* 模板處理
* Created by GN on 2016/11/27.
*/
public class Template {
private static final String TAG_PREFIX = "${";
private static final String TAG_POSTFIX = "}";
/**
* 模板信息
*/
private BufferedReader reader;
private File file;
/**
* 模板標(biāo)簽,eg:${domain}:key=domain,value=${domain}
*/
private Map<String, String> tag = new HashMap<>();
public Template(File file) throws IOException {
this.file = file;
//初始化模板輸入流
initReader();
}
private void initReader() {
if (file == null) {
throw new IllegalArgumentException("獲取模板失敗");
}
try {
InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(file), "UTF-8");
this.reader = new BufferedReader(inputStreamReader);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
/**
* 處理標(biāo)簽到tag中
*
* @param text
*/
private void initTag(String text) {
if (!StringUtil.hasLength(text)) {
return;
}
String tagFlag = getTagFlag(text);
String tagText = getTagText(text);
this.tag.put(tagText, tagFlag);
//遞歸解析一行中的多個(gè)標(biāo)簽
int prefix = text.indexOf(TAG_PREFIX);
String subText = text.substring(prefix + 2 + tagText.length());
if (hasTag(subText)) {
initTag(subText);
}
}
/**
* 獲取標(biāo)簽,${domain}
*
* @param text
* @return
*/
private String getTagFlag(String text) {
int prefix = text.indexOf(TAG_PREFIX);
int postfix = text.indexOf(TAG_POSTFIX);
return text.substring(prefix, postfix + 1);
}
/**
* 獲取標(biāo)簽中的內(nèi)容,${domain} --> domain
*
* @param text
* @return
*/
private String getTagText(String text) {
String tagFlag = getTagFlag(text);
return tagFlag.substring(2, tagFlag.length() - 1);
}
/**
* 判斷文本中是否含有標(biāo)簽
*
* @param text
* @return
*/
private boolean hasTag(String text) {
if (!StringUtil.hasLength(text)) {
return Boolean.FALSE;
}
return text.indexOf(TAG_PREFIX) > 0 && text.indexOf(TAG_POSTFIX) > 0;
}
/**
* 生成模板
*
* @param context 模板值定義
* @param target 目標(biāo)生成文件
*/
public void merge(GnContext context, File target) throws IOException {
if (reader == null) {
throw new IllegalArgumentException("讀取模板失敗");
}
if (context == null) {
throw new IllegalArgumentException("獲取GnContext失敗");
}
if (target == null) {
throw new IllegalArgumentException("獲取輸出流失敗");
}
String temp;
FileWriter writer = new FileWriter(target, true);
while ((temp = reader.readLine()) != null) {
if (hasTag(temp)) {
//解析出所有的標(biāo)簽
List<String> tagTextList = findTagTextList(temp);
if (!tagTextList.isEmpty()) {
for (String text : tagTextList) {
String value = context.get(text);
if (StringUtil.hasLength(value)){
temp = temp.replace(TAG_PREFIX + text + TAG_POSTFIX, value);
}
}
}
}
writer.write(temp + "\n");
writer.flush();
}
writer.close();
}
/**
* 獲取文本中的標(biāo)簽
*
* @param lineText
* @return
*/
private List<String> findTagTextList(String lineText) {
List<String> tagTextList = new ArrayList<>();
if (StringUtil.hasLength(lineText) && hasTag(lineText)) {
String tmp = lineText;
while (hasTag(tmp)) {
String tagText = findTagText(tmp);
if (!tagTextList.contains(tagText)) {
tagTextList.add(tagText);
}
int begin = tmp.indexOf(tagText);
tmp = tmp.substring(begin + tagText.length()+1);
}
}
return tagTextList;
}
/**
* 獲取文本中的單個(gè)標(biāo)簽
*
* @param text
* @return
*/
private String findTagText(String text) {
if (!StringUtil.hasLength(text)) {
return null;
}
return getTagText(text);
}
}
- 一下為測(cè)試使用模板 :
/**
* Created by GNon 2016/9/8.
*/
@Service
@Transactional
public class ${domain}ServiceImpl implements I${domain}Service {
@Autowired
private ${domain}Dao dao;
@Override
public void save(${domain} ${lowerDomain}) {
dao.save(${lowerDomain});
}
@Override
public void update(${domain} ${lowerDomain}) {
dao.update(${lowerDomain});
}
@Override
public void delete(Serializable id) {
dao.delete(id);
}
@Override
public ${domain} findById(Serializable id) {
return dao.findById(id);
}
@Override
public List<${domain}> findAll() {
return dao.findAll();
}
@Override
public PageData findListByPage(PageData pageData) {
return dao.findListByPage(pageData);
}
}
- 以下是通過(guò)上述代碼實(shí)現(xiàn)的簡(jiǎn)單生成器
/**
* 代碼生成器
* Created by GN on 2016/11/28.
*/
public class GnCreator {
/**
* 實(shí)體
*/
private List<String> domains = new ArrayList<>();
/**
* 模板基礎(chǔ)路徑
*/
private String baseTemplatePath = "E:\\WorkSpace\\demo\\src\\main\\resources\\";
/**
* 生成文件保存基本路徑
*/
private String baseSavePath = "E:\\WorkSpace\\demosrc\\main\\java\\com\\gn\\demo\\";
/**
* 模板
*/
private List<String> templates = new ArrayList<>();
private final String DAOIMPL = "Dao.java";
private final String SERVICE = "Service.java";
private final String SERVICEIMPL = "ServiceImpl.java";
public GnCreator() {
//初始化生成器信息
//初始化實(shí)體集合
String[] domainList = {"User"}; //如果實(shí)體很多谴仙,可以通過(guò)注解掃描的方式去獲取迂求,不用一個(gè)一個(gè)的去寫
List<String> asList = Arrays.asList(domainList);
domains.addAll(asList);
//初始化模板
templates.add(DAOIMPL);
templates.add(SERVICE);
templates.add(SERVICEIMPL);
}
public void create() throws IOException {
System.out.println("代碼生成器開始執(zhí)行>>>>>>>>>>>>>>>>>>>>");
for (String domain : domains) {
System.out.println("開始生成實(shí)體【"+domain+"】代碼...............");
//模板值定義
GnContext gnContext = new GnContext();
gnContext.put("domain",domain);
gnContext.put("lowerDomain",domain.toLowerCase());
//根據(jù)模板生成代碼
for (String tp : templates) {
String templatePath = baseTemplatePath+tp;
Template template = GnUtil.getTemplate(templatePath);
//根據(jù)不同的模板保存到不同的目錄
String targetFilePath = "";
String targetFileName = "";
if (tp.equals(DAOIMPL)){
targetFilePath = baseSavePath+"dao\\impl\\";
targetFileName = domain+DAOIMPL;
}else if (tp.equals(SERVICE)){
targetFilePath = baseSavePath+"service\\";
targetFileName = "I"+domain+SERVICE;
}else if (tp.equals(SERVICEIMPL)){
targetFilePath = baseSavePath + "service\\impl\\";
targetFileName = domain+SERVICEIMPL;
}
//判斷目錄是否存在,如果不存在則創(chuàng)建
File file = new File(targetFilePath);
if (!file.exists()){
file.mkdirs();
}
File targetFile = new File(targetFilePath+targetFileName);
template.merge(gnContext,targetFile);
}
System.out.println("生成實(shí)體【"+domain+"】代碼完成...............");
}
System.out.println("代碼生成器執(zhí)行完畢>>>>>>>>>>>>>>>>>>>>>>>>");
}
}
- 以上為所有代碼晃跺,僅為適用自己的需求揩局,如果能幫助到其他人更好,說(shuō)下簡(jiǎn)單思路:
代碼主要實(shí)現(xiàn)功能是獲取模板中的 ${domain} ,然后通過(guò)替換的方式把傳入的 GnContext 所對(duì)應(yīng)的值掀虎,最終實(shí)現(xiàn)代碼生成凌盯。替換一處我用的是直接查詢替換,如果你愿意也可以用正則表達(dá)式去處理烹玉,這樣也許會(huì)簡(jiǎn)潔很多驰怎。