Skip to content

Instantly share code, notes, and snippets.

@oakhole
Last active August 29, 2015 14:04
Show Gist options
  • Save oakhole/362ed77cf143885d6a24 to your computer and use it in GitHub Desktop.
Save oakhole/362ed77cf143885d6a24 to your computer and use it in GitHub Desktop.
基于freemarker代码生成,根据个人需要修改模板
/*
* Copyright (c) 2013-2014. Powered by http://oakhole.com .
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ${packageName}.web;
import ${packageName}.entity.${ClassName};
import ${packageName}.service.${ClassName}Service;
import com.oakhole.utils.Servlets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.Map;
/**
* @author ${author}
* @since ${since}
*/
@Controller
@RequestMapping("/${className}")
public class ${ClassName}Controller {
private static Logger logger = LoggerFactory.getLogger(${ClassName}Service.class);
@Autowired
private ${ClassName}Service ${className}Service;
@RequiresPermissions("${className}:view")
@RequestMapping(value = {"", "list"})
public String index(HttpServletRequest request, Model model) {
Map<String, Object> searchParams = Servlets.getParametersStartingWith(request, "search_");
model.addAttribute("${className}s", this.${className}Service.findAll(searchParams));
return "${className}/index";
}
@RequiresPermissions("${className}:edit")
@RequestMapping(value = "create", method = RequestMethod.GET)
public String create() {
return "${className}/create";
}
@RequiresPermissions("${className}:edit")
@RequestMapping(value = "create", method = RequestMethod.POST)
public String create(@RequestParam ${ClassName} ${className}, RedirectAttributes redirectAttributes) {
this.${className}Service.save(${className});
redirectAttributes.addFlashAttribute("message", "添加成功");
return "redirect:/${className}";
}
@RequiresPermissions("${className}:view")
@RequestMapping(value = "show/{id}")
public String show(@PathVariable("id") Long id, Model model) {
model.addAttribute("${className}", ${className}Service.get(id));
return "${className}/show";
}
@RequiresPermissions("${className}:edit")
@RequestMapping(value = "update/{id}", method = RequestMethod.GET)
public String update(@PathVariable("id") Long id, Model model) {
model.addAttribute("${className}", ${className}Service.get(id));
return "${className}/update";
}
@RequiresPermissions("${className}:edit")
@RequestMapping(value = "update", method = RequestMethod.POST)
public String update(@Valid @ModelAttribute(value = "${className}") ${ClassName} ${className}, RedirectAttributes redirectAttributes) {
this.${className}Service.save(${className});
redirectAttributes.addFlashAttribute("message", "更新成功");
return "redirect:/${className}";
}
@RequiresPermissions("${className}:edit")
@RequestMapping(value = "delete/{id}")
public String delete(@PathVariable Long id, @Valid @ModelAttribute(value = "${className}") ${ClassName} ${className}, RedirectAttributes redirectAttributes) {
this.${className}Service.remove(${className});
redirectAttributes.addFlashAttribute("message", "删除成功");
return "redirect:/${className}";
}
@ModelAttribute
public void get${ClassName}(@RequestParam(value = "id", defaultValue = "-1") Long id, Model model) {
if (id != -1) {
model.addAttribute("${className}", this.${className}Service.get(id));
}
}
}
/*
* Copyright (c) 2013-2014. Powered by http://oakhole.com .
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ${packageName}.dao;
import ${packageName}.entity.${ClassName};
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.PagingAndSortingRepository;
/**
* @author ${author}
* @since ${since}
*/
public interface ${ClassName}Dao extends PagingAndSortingRepository<${ClassName},Long>,JpaSpecificationExecutor<${ClassName}> {
}
/*
* Copyright (c) 2013-2014. Powered by http://oakhole.com .
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.oakhole.generate;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.io.Files;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.dozer.util.DefaultClassLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.DefaultResourceLoader;
import javax.persistence.Entity;
import java.beans.Encoder;
import java.io.*;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 代码生成, 获取entity信息,生成 dao、service、controller、restApi、formView、listView;
*/
public class Generate {
private static Logger logger = LoggerFactory.getLogger(Generate.class);
// freemarker 配置信息
private Configuration configuration;
public Generate(String templatePath) {
this.configuration = new Configuration();
try {
configuration.setDirectoryForTemplateLoading(new File(templatePath));
} catch (IOException e) {
e.printStackTrace();
}
configuration.setDefaultEncoding("utf-8");
configuration.setObjectWrapper(new DefaultObjectWrapper());
}
public static void main(String[] args) {
Generate generate = new Generate("/Users/Oakhole/Documents/Java/journal/modules/generate/src/main/resources/template");
generate.generate("/Users/Oakhole/Desktop", "com.oakhole");
}
/**
* 处理数据与模板
*
* @param basicPackage
*/
public void generate(String basicPath, String basicPackage) {
String file_separator = File.separator;
try {
Set<Class<?>> entities = autoScan(basicPackage);
for (Class entity : entities) {
Map<String, Object> dataModel = getDataModel(entity);
// 处理 Dao
String daoPath = basicPath + file_separator
+ (dataModel.get("packageName") + ".dao." + dataModel.get("ClassName"))
.replace(".", file_separator) + "Dao.java";
File daoFile = new File(daoPath);
if (!daoFile.exists()) {
if (!daoFile.getParentFile().exists()) {
daoFile.getParentFile().mkdirs();
}
daoFile.createNewFile();
}
Template daoTemplate = configuration.getTemplate("dao.ftl");
daoTemplate.process(dataModel, new FileWriter(daoPath));
logger.info("Dao.create: {}", daoPath);
// 处理 Service
String servicePath = basicPath + file_separator
+ (dataModel.get("packageName") + ".service." + dataModel.get("ClassName"))
.replace(".", file_separator) + "Service.java";
File serviceFile = new File(servicePath);
if (!serviceFile.exists()) {
if (!serviceFile.getParentFile().exists()) {
serviceFile.getParentFile().mkdirs();
}
serviceFile.createNewFile();
}
Template serviceTemplate = configuration.getTemplate("service.ftl");
serviceTemplate.process(dataModel, new FileWriter(servicePath));
logger.info("Service.create: {}", servicePath);
// 处理 Controller
String controllerPath = basicPath + file_separator
+ (dataModel.get("packageName") + ".web." + dataModel.get("ClassName"))
.replace(".", file_separator) + "Controller.java";
File controllerFile = new File(controllerPath);
if (!controllerFile.exists()) {
if (!controllerFile.getParentFile().exists()) {
controllerFile.getParentFile().mkdirs();
}
controllerFile.createNewFile();
}
Template controllerTemplate = configuration.getTemplate("controller.ftl");
controllerTemplate.process(dataModel, new FileWriter(controllerPath));
logger.info("Controller.create: {}", controllerPath);
}
} catch (IOException e) {
e.printStackTrace();
} catch (TemplateException e) {
e.printStackTrace();
}
}
/**
* 由object得到该类的定义
* @param object
* @return
*/
private Map<String, Object> getDataModel(Class object) {
Map<String,Object> dataModel = Maps.newHashMap();
// Step 1: 基础信息
dataModel.put("author", "Oakhole");
dataModel.put("since", "1.0");
// Step 2: 加载实体类获取packageName、className等信息
String packageName = object.getPackage().getName();
// 去除最后Entity结尾,便于区分
packageName = packageName.substring(0, packageName.lastIndexOf("."));
// 只留尾部名称
String className = object.getName();
className = className.substring(className.lastIndexOf(".") + 1, className.length());
// Step 3: 赋值
dataModel.put("packageName", packageName);
dataModel.put("ClassName", className);
dataModel.put("className", StringUtils.uncapitalize(className));
return dataModel;
}
/**
* 自动扫描包下的@Entity
* @param packageToScan
* @return
* @throws IOException
*/
private Set<Class<?>> autoScan(String packageToScan) throws IOException {
Set<Class<?>> entities = Sets.newConcurrentHashSet();
Enumeration<URL> dirs = Thread.currentThread().getContextClassLoader().getResources(packageToScan
.replace('.','/'));
while (dirs.hasMoreElements()) {
URL url = dirs.nextElement();
// 判断是否为文件,且有@Entity注解
if ("file".endsWith(url.getProtocol())) {
String filePath = URLDecoder.decode(url.getFile(), "utf-8");
fetchEntities(packageToScan, filePath,entities);
}
}
return entities;
}
/**
* 递归读取包下的Entity类
* @param filePath
* @param entities
*/
private void fetchEntities(String packageName, String filePath, Set<Class<?>> entities) {
// 定义package
File file = new File(filePath);
if (!file.exists() || !file.isDirectory()) {
logger.warn("{} neither exists nor the directory .",filePath);
return;
}
// 读取package下所有class文件
File[] subFiles = file.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.isDirectory() || pathname.getName().endsWith(".class");
}
});
for (File subFile : subFiles) {
// 如果是目录,则递归读取,如果是class文件,则判断是否为实体类
if (subFile.isDirectory()) {
fetchEntities(packageName + "." + subFile.getName(), subFile.getAbsolutePath(), entities);
}else {
// 加载后判断,使用当前线程类加载器加载
String className = subFile.getName().substring(0, subFile.getName().length() - 6);
try {
Class object = Thread.currentThread().getContextClassLoader().loadClass(packageName + "." + className);
if (object.getAnnotation(Entity.class) != null) {
entities.add(object);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
/********************* Getter & Setter *********************/
}
/*
* Copyright (c) 2013-2014. Powered by http://oakhole.com .
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ${packageName}.service;
import ${packageName}.dao.${ClassName}Dao;
import ${packageName}.entity.${ClassName};
import com.oakhole.core.uitls.DynamicSpecifications;
import com.oakhole.core.uitls.SearchFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.javasimon.aop.Monitored;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import javax.transaction.Transactional;
import java.util.List;
import java.util.Map;
/**
* @author ${author}
* @since ${since}
*/
@Service
@Transactional
@Monitored
public class ${ClassName}Service {
private static Logger logger = LoggerFactory.getLogger(${ClassName}Service.class);
@Autowired
private ${ClassName} ${className}Dao;
public void create(${ClassName} ${className}) {
this.${className}Dao.save(${className});
}
public ${ClassName} get(Long id) {
return this.${className}Dao.findOne(id);
}
public void update(${ClassName} ${className}) {
this.${className}Dao.save(${className});
}
public void remove(${ClassName} ${className}) {
${className}.setDeleted(true);
this.${className}Dao.save(${className});
}
public List<${ClassName}> findAll(Map<String, Object> searchParams) {
Map<String, SearchFilter> filters = SearchFilter.parse(searchParams);
Specification<${ClassName}> spec = DynamicSpecifications.bySearchFilter(filters.values(), ${ClassName}.class);
return this.${className}Dao.findAll(spec);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment