Compare commits
No commits in common. "master" and "feature/v0.0.4" have entirely different histories.
master
...
feature/v0
2
.gitignore
vendored
@ -1,5 +1,5 @@
|
||||
.*
|
||||
!.gitignore
|
||||
!.gitkeep
|
||||
*.iml
|
||||
target/
|
||||
bin/
|
||||
|
@ -1,13 +0,0 @@
|
||||
## 该问题是怎么引起的?
|
||||
|
||||
|
||||
|
||||
## 重现步骤
|
||||
|
||||
|
||||
|
||||
## 报错信息
|
||||
|
||||
|
||||
|
||||
|
@ -1,15 +0,0 @@
|
||||
## 该Pull Request关联的Issue
|
||||
|
||||
|
||||
## 修改描述
|
||||
|
||||
|
||||
|
||||
## 测试用例
|
||||
|
||||
|
||||
|
||||
## 修复效果的截屏
|
||||
|
||||
|
||||
|
@ -13,13 +13,11 @@
|
||||
<parent>
|
||||
<groupId>me.chyxion.tigon</groupId>
|
||||
<artifactId>tigon</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<spring-boot.run.main-class>me.chyxion.tigon.codegen.TigonCodeGen</spring-boot.run.main-class>
|
||||
<mainClass>me.chyxion.tigon.codegen.TigonCodeGen</mainClass>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@ -31,10 +29,18 @@
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.chyxion.tigon</groupId>
|
||||
<artifactId>tigon-common</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.chyxion.tigon</groupId>
|
||||
<artifactId>tigon-extjs</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.chyxion.tigon</groupId>
|
||||
<artifactId>tigon-web-controller</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>me.chyxion.tigon</groupId>
|
||||
<artifactId>tigon-web</artifactId>
|
||||
@ -48,7 +54,6 @@
|
||||
<artifactId>commons-io</artifactId>
|
||||
<version>2.6</version>
|
||||
</dependency>
|
||||
<!-- mybatis -->
|
||||
<dependency>
|
||||
<groupId>me.chyxion.tigon</groupId>
|
||||
<artifactId>tigon-mybatis</artifactId>
|
||||
@ -68,12 +73,21 @@
|
||||
<artifactId>lombok</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- /mybatis -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
@ -84,7 +98,6 @@
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>false</skip>
|
||||
<fork>true</fork>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
@ -0,0 +1,37 @@
|
||||
package me.chyxion.tigon.codegen;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.context.annotation.ImportResource;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
|
||||
/**
|
||||
* @author Shaun Chyxion <br>
|
||||
* chyxion@163.com <br>
|
||||
* Jun 24, 2018 20:43:36
|
||||
*/
|
||||
@Slf4j
|
||||
@SpringBootApplication
|
||||
@ImportResource("classpath*:spring/spring-*.xml")
|
||||
public class TigonCodeGen implements WebMvcConfigurer {
|
||||
|
||||
/**
|
||||
* @param args start args
|
||||
*/
|
||||
public static void main(final String[] args) {
|
||||
log.info("Startup args [{}].", StringUtils.join(args, "\n"));
|
||||
SpringApplication.run(TigonCodeGen.class, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
|
||||
registry.addResourceHandler("/assets/**")
|
||||
.addResourceLocations("/assets/", "classpath:assets/");
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package me.chyxion.tigon.codegen.configprop;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date Apr 22, 2020 10:56:39
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class BaseClass {
|
||||
private String name;
|
||||
private String fullName;
|
||||
private boolean importRequired;
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package me.chyxion.tigon.codegen.configprop;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import java.util.Set;
|
||||
import lombok.ToString;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date Apr 27, 2020 17:10:18
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class BaseClassWithFields extends BaseClass {
|
||||
private Set<String> fields = new HashSet<>();
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package me.chyxion.tigon.codegen.configprop;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date Apr 27, 2020 17:11:11
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class BasicItem {
|
||||
private String projectDir;
|
||||
private String basePackage;
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package me.chyxion.tigon.codegen.configprop;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date Apr 22, 2020 10:42:03
|
||||
*/
|
||||
@Slf4j
|
||||
@Getter
|
||||
@Setter
|
||||
@Component
|
||||
@ToString
|
||||
@ConfigurationProperties("tigon.codegen")
|
||||
public class ConfigProperties implements InitializingBean {
|
||||
private String workDir;
|
||||
private FileDoc fileDoc = new FileDoc();
|
||||
private String[] defaultGenItems = {
|
||||
"model",
|
||||
"mapper",
|
||||
"form",
|
||||
"service",
|
||||
"controller"
|
||||
};
|
||||
private String basePackage;
|
||||
private String tablePrefix;
|
||||
private ItemModel model = new ItemModel();
|
||||
private ItemModel formCreate = new ItemModel();
|
||||
private ItemModel formUpdate = new ItemModel();
|
||||
private ItemMapper mapper = new ItemMapper();
|
||||
private Item service = new Item();
|
||||
private Item serviceImpl = new Item();
|
||||
private ItemController controller = new ItemController();
|
||||
private Item view = new Item();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
log.info("After config [{}] init.", this);
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package me.chyxion.tigon.codegen.configprop;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date Apr 26, 2020 17:58:54
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class FileDoc {
|
||||
private boolean gen = true;
|
||||
private String author = "Donghuang";
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package me.chyxion.tigon.codegen.configprop;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date Apr 22, 2020 10:57:47
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class Item extends BasicItem {
|
||||
private BaseClass baseClass = new BaseClass();
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package me.chyxion.tigon.codegen.configprop;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date Mar 16, 2021 00:02:00
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class ItemController extends Item {
|
||||
private String urlPrefix;
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package me.chyxion.tigon.codegen.configprop;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date Apr 22, 2020 10:57:47
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class ItemMapper extends Item {
|
||||
private boolean cacheEnabled;
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package me.chyxion.tigon.codegen.configprop;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date Apr 22, 2020 10:57:47
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class ItemModel extends BasicItem {
|
||||
private BaseClassWithFields baseClass = new BaseClassWithFields();
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
package me.chyxion.tigon.codegen.controller;
|
||||
|
||||
import java.util.Map;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import java.util.List;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import me.chyxion.tigon.kit.json.JsonService;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import me.chyxion.tigon.codegen.service.CodeGenService;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import me.chyxion.tigon.codegen.configprop.ConfigProperties;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
/**
|
||||
* @version 0.0.1
|
||||
* @since 0.0.1
|
||||
* @author Shaun Chyxion <br>
|
||||
* chyxion@163.com <br>
|
||||
* Oct 5, 2014 9:34:54 PM
|
||||
*/
|
||||
@Controller
|
||||
public class SiteController {
|
||||
@Autowired
|
||||
private CodeGenService service;
|
||||
@Autowired
|
||||
private ConfigProperties configProperties;
|
||||
@Autowired
|
||||
private JsonService json;
|
||||
|
||||
@RequestMapping("/")
|
||||
public ModelAndView index() {
|
||||
return new ModelAndView("views/index")
|
||||
.addObject("components",
|
||||
json.toJSONString(configProperties.getDefaultGenItems()));
|
||||
}
|
||||
|
||||
@RequestMapping("/codegen/tables")
|
||||
public List<Map<String, Object>> tables() {
|
||||
return service.tables();
|
||||
}
|
||||
|
||||
@PostMapping("/codegen")
|
||||
public void gen(@Valid GenForm form) {
|
||||
service.process(form.getModel(),
|
||||
json.parseArray(form.getColumns()), form);
|
||||
}
|
||||
|
||||
@RequestMapping("/codegen/list")
|
||||
public List<Map<String, Object>> list() {
|
||||
return service.list();
|
||||
}
|
||||
|
||||
@DeleteMapping("/codegen")
|
||||
public void delete(
|
||||
@RequestParam("items")
|
||||
String items,
|
||||
@RequestParam(value = "dropTable", defaultValue = "true")
|
||||
boolean dropTable) {
|
||||
service.delete(json.parseArray(items), dropTable);
|
||||
}
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public static class GenForm {
|
||||
@NotNull
|
||||
private String columns;
|
||||
@NotBlank
|
||||
private String model;
|
||||
@NotBlank
|
||||
private String table;
|
||||
@NotBlank
|
||||
private String tableComment;
|
||||
private boolean genView;
|
||||
private boolean genController;
|
||||
private boolean genService;
|
||||
private boolean genMapper;
|
||||
private boolean genModel;
|
||||
private boolean genForm;
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package me.chyxion.tigon.codegen.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date Apr 23, 2020 09:54:27
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class GenConfig {
|
||||
private GenItem[] items;
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package me.chyxion.tigon.codegen.model;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date Apr 22, 2020 17:44:22
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class GenItem {
|
||||
private String item;
|
||||
private String projectDir;
|
||||
private String template;
|
||||
private String result;
|
||||
|
||||
/**
|
||||
* copy this
|
||||
* @return copy
|
||||
*/
|
||||
public GenItem copy() {
|
||||
final GenItem it = new GenItem();
|
||||
it.item = item;
|
||||
it.projectDir = projectDir;
|
||||
it.template = template;
|
||||
it.result = result;
|
||||
return it;
|
||||
}
|
||||
}
|
@ -0,0 +1,231 @@
|
||||
package me.chyxion.tigon.codegen.service;
|
||||
|
||||
import lombok.val;
|
||||
import java.util.*;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import java.sql.ResultSet;
|
||||
import lombok.SneakyThrows;
|
||||
import java.io.StringReader;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.io.InputStreamReader;
|
||||
import freemarker.template.Template;
|
||||
import me.chyxion.tigon.util.WordUtils;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
import org.springframework.jdbc.core.ConnectionCallback;
|
||||
import me.chyxion.tigon.codegen.configprop.ConfigProperties;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
|
||||
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
|
||||
|
||||
/**
|
||||
* @version 0.0.1
|
||||
* @since 0.0.1
|
||||
* @author chyxion <br>
|
||||
* chyxion@163.com <br>
|
||||
* Dec 3, 2014 11:25:17 AM
|
||||
*/
|
||||
@Slf4j
|
||||
public class CodeGenBaseTool {
|
||||
|
||||
@Autowired
|
||||
private FreeMarkerConfigurer fmCfg;
|
||||
@Autowired
|
||||
private JdbcTemplate jdbcTpl;
|
||||
@Autowired
|
||||
private ConfigProperties configProps;
|
||||
@Getter
|
||||
@Setter
|
||||
private Set<String> baseCols = new HashSet<>();
|
||||
|
||||
/**
|
||||
* render FreeMarker Template
|
||||
* @param ftl
|
||||
* @param model
|
||||
* @return
|
||||
*/
|
||||
@SneakyThrows
|
||||
public String renderFtl(final String ftl, final Map<String, ?> model) {
|
||||
log.info("Render FreeMarker template [{}].", ftl);
|
||||
try (val resourceAsStream = CodeGenBaseTool.class.getResourceAsStream(ftl);
|
||||
val reader = new InputStreamReader(
|
||||
resourceAsStream,
|
||||
StandardCharsets.UTF_8)) {
|
||||
return FreeMarkerTemplateUtils.processTemplateIntoString(
|
||||
new Template(ftl, reader, fmCfg.getConfiguration()), model);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* render string FreeMarker Template
|
||||
*
|
||||
* @param strFtl
|
||||
* @param model
|
||||
* @return
|
||||
*/
|
||||
@SneakyThrows
|
||||
public String renderStrFtl(final String strFtl, final Map<String, ?> model) {
|
||||
log.info("Render string FreeMarker template [{}].", strFtl);
|
||||
try (val reader = new StringReader(strFtl)) {
|
||||
return FreeMarkerTemplateUtils.processTemplateIntoString(
|
||||
new Template(strFtl, reader, fmCfg.getConfiguration()), model);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> tables() {
|
||||
if (jdbcTpl != null) {
|
||||
return jdbcTpl.execute((ConnectionCallback<List<Map<String, Object>>>) conn -> {
|
||||
val tables = new LinkedList<Map<String, Object>>();
|
||||
ResultSet rs = null;
|
||||
try {
|
||||
val md = conn.getMetaData();
|
||||
val database = conn.getCatalog();
|
||||
rs = md.getTables(null, null, "%", new String[] {"TABLE"});
|
||||
while (rs.next()) {
|
||||
val mapTable = new HashMap<String, Object>(8);
|
||||
val table = rs.getString(3).toLowerCase();
|
||||
|
||||
mapTable.put("id", table);
|
||||
mapTable.put("text", table);
|
||||
mapTable.put("table", table);
|
||||
mapTable.put("tableComment", getTableComment(database, table));
|
||||
|
||||
final String trimPrefixTableName;
|
||||
val tablePrefix = configProps.getTablePrefix();
|
||||
if (StringUtils.isNotBlank(tablePrefix) &&
|
||||
table.startsWith(tablePrefix + "_")) {
|
||||
log.info("Table prefix [{}] found, trim.", tablePrefix);
|
||||
trimPrefixTableName = table.substring(
|
||||
tablePrefix.length() + 1);
|
||||
}
|
||||
else {
|
||||
trimPrefixTableName = table;
|
||||
}
|
||||
|
||||
mapTable.put("model", StringUtils.capitalize(
|
||||
WordUtils.convertToCamelCase(trimPrefixTableName)));
|
||||
mapTable.put("leaf", true);
|
||||
val keys = keys(md, table);
|
||||
mapTable.put("keys", keys);
|
||||
val indexes = indexes(md, table, false);
|
||||
mapTable.put("indexes", indexes);
|
||||
mapTable.put("cols", cols(md, table, keys, indexes));
|
||||
tables.add(mapTable);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
JdbcUtils.closeResultSet(rs);
|
||||
}
|
||||
return tables;
|
||||
});
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// --
|
||||
// private methods
|
||||
private List<Map<String, Object>> cols(final DatabaseMetaData md,
|
||||
final String table, Set<String> keys,
|
||||
final Set<String> indexes) {
|
||||
val cols = new LinkedList<Map<String, Object>>();
|
||||
|
||||
try (val rs = md.getColumns(null, "%", table, "%")) {
|
||||
while (rs.next()) {
|
||||
val col = new HashMap<String, Object>(16);
|
||||
val colName = rs.getString("COLUMN_NAME");
|
||||
col.put("isKey", keys.contains(colName));
|
||||
col.put("isIndex", indexes.contains(colName));
|
||||
col.put("col", colName);
|
||||
col.put("name", WordUtils.toCamel(colName));
|
||||
val size = rs.getInt("COLUMN_SIZE");
|
||||
col.put("size", size);
|
||||
String type = rs.getString("TYPE_NAME").toLowerCase();
|
||||
String javaType = "String";
|
||||
|
||||
val notNull = rs.getInt("NULLABLE") == 0;
|
||||
|
||||
if (type.endsWith("char")) {
|
||||
type = type + "(" + size + ")";
|
||||
}
|
||||
else if (type.contains("date") || type.contains("time")) {
|
||||
javaType = "Date";
|
||||
}
|
||||
else if (type.equals("bit")) {
|
||||
javaType = "Boolean";
|
||||
}
|
||||
else if (type.equals("int")) {
|
||||
javaType = "Integer";
|
||||
}
|
||||
else if (type.equals("bigint")) {
|
||||
javaType = "Long";
|
||||
}
|
||||
else if (type.contains("int")) {
|
||||
javaType = "Integer";
|
||||
}
|
||||
else if (type.equals("float")) {
|
||||
javaType = "Float";
|
||||
}
|
||||
else if (type.contains("double")) {
|
||||
javaType = "Double";
|
||||
}
|
||||
else if (type.contains("blob")) {
|
||||
javaType = "byte[]";
|
||||
}
|
||||
|
||||
col.put("sqlType", type);
|
||||
col.put("javaType", javaType);
|
||||
col.put("notNull", notNull);
|
||||
cols.add(col);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException(
|
||||
"Get table columns error caused", e);
|
||||
}
|
||||
return cols;
|
||||
}
|
||||
|
||||
private Set<String> keys(final DatabaseMetaData md, final String table) {
|
||||
val keys = new TreeSet<String>();
|
||||
try (val rs = md.getPrimaryKeys(null, null, table)) {
|
||||
while (rs.next()) {
|
||||
keys.add(rs.getString("COLUMN_NAME"));
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException(
|
||||
"Get table keys error caused", e);
|
||||
}
|
||||
// find unique indexes
|
||||
if (keys.isEmpty()) {
|
||||
return indexes(md, table, true);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
private Set<String> indexes(final DatabaseMetaData md, final String table, final boolean unique) {
|
||||
val keys = new TreeSet<String>();
|
||||
try (val rs = md.getIndexInfo(null, null, table, false, false)) {
|
||||
while (rs.next()) {
|
||||
if (unique && rs.getBoolean("NON_UNIQUE")) {
|
||||
continue;
|
||||
}
|
||||
keys.add(rs.getString("COLUMN_NAME"));
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException(
|
||||
"Get table indexes error caused", e);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
private String getTableComment(final String database, final String table) {
|
||||
return jdbcTpl.queryForObject("select table_comment from information_schema.tables where table_schema = ? and table_name = ?",
|
||||
new Object[] {database, table}, String.class);
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@ package me.chyxion.tigon.codegen.service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import me.chyxion.tigon.codegen.controller.CodeGenController.GenForm;
|
||||
import me.chyxion.tigon.codegen.controller.SiteController.GenForm;
|
||||
|
||||
/**
|
||||
* @version 0.0.1
|
||||
@ -14,19 +14,17 @@ import me.chyxion.tigon.codegen.controller.CodeGenController.GenForm;
|
||||
public interface CodeGenService {
|
||||
/**
|
||||
* process code generation
|
||||
* @param module
|
||||
* @param model
|
||||
* @param cols
|
||||
* @param table
|
||||
* @param form
|
||||
* @param form
|
||||
*/
|
||||
void process(String module, String model, List<?> cols, String table, GenForm form);
|
||||
void process(String model, List<Map<String, Object>> cols, GenForm form);
|
||||
|
||||
/**
|
||||
* list generated items
|
||||
* @return items list
|
||||
*/
|
||||
List<?> list();
|
||||
List<Map<String, Object>> list();
|
||||
|
||||
/**
|
||||
* list tables
|
||||
@ -38,5 +36,5 @@ public interface CodeGenService {
|
||||
* delete items
|
||||
* @param items
|
||||
*/
|
||||
void delete(List<?> items, boolean dropTable);
|
||||
void delete(List<Map<String, Object>> items, boolean dropTable);
|
||||
}
|
@ -0,0 +1,354 @@
|
||||
package me.chyxion.tigon.codegen.service.support;
|
||||
|
||||
import lombok.val;
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
import lombok.SneakyThrows;
|
||||
import me.chyxion.tigon.form.FC0;
|
||||
import me.chyxion.tigon.form.FU0;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import java.text.SimpleDateFormat;
|
||||
import me.chyxion.tigon.form.FormList;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import me.chyxion.tigon.mybatis.Table;
|
||||
import me.chyxion.tigon.mybatis.Search;
|
||||
import me.chyxion.tigon.util.WordUtils;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import me.chyxion.tigon.mybatis.BaseMapper;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import me.chyxion.tigon.kit.json.JsonService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import me.chyxion.tigon.codegen.model.GenItem;
|
||||
import me.chyxion.tigon.codegen.model.GenConfig;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import me.chyxion.tigon.web.test.ControllerTestTool;
|
||||
import me.chyxion.tigon.codegen.configprop.BaseClass;
|
||||
import me.chyxion.tigon.codegen.configprop.BasicItem;
|
||||
import me.chyxion.tigon.service.BaseCrudByFormService;
|
||||
import me.chyxion.tigon.codegen.service.CodeGenService;
|
||||
import me.chyxion.tigon.codegen.service.CodeGenBaseTool;
|
||||
import me.chyxion.tigon.web.controller.BaseCrudController;
|
||||
import me.chyxion.tigon.codegen.controller.SiteController;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import me.chyxion.tigon.codegen.configprop.ConfigProperties;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import me.chyxion.tigon.service.support.BaseCrudByFormServiceSupport;
|
||||
|
||||
/**
|
||||
* @version 0.0.1
|
||||
* @since 0.0.1
|
||||
* @author Shaun Chyxion <br>
|
||||
* chyxion@163.com <br>
|
||||
* Oct 6, 2014 1:10:02 PM
|
||||
*/
|
||||
@Slf4j
|
||||
public class CodeGenServiceSupport implements CodeGenService, InitializingBean {
|
||||
private static final Map<String, String> TYPE_PACKAGES =
|
||||
new HashMap<String, String>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
{
|
||||
put(Date.class.getSimpleName(), Date.class.getName());
|
||||
}
|
||||
};
|
||||
@Autowired
|
||||
private JsonService json;
|
||||
private GenConfig genConfig;
|
||||
|
||||
@Autowired
|
||||
private CodeGenBaseTool baseTool;
|
||||
@Autowired
|
||||
private ConfigProperties configProps;
|
||||
private final Map<String, Object> moduleConfig = new HashMap<>(8);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void process(String model,
|
||||
final List<Map<String, Object>> columns,
|
||||
final SiteController.GenForm form) {
|
||||
val minusJoinedModelName =
|
||||
WordUtils.convertCamelCase(model, "-").toLowerCase();
|
||||
|
||||
model = StringUtils.capitalize(model);
|
||||
val fmDataModel = new HashMap<String, Object>(20);
|
||||
fmDataModel.putAll(moduleConfig);
|
||||
fmDataModel.put("srcMainDir", "src/main/java");
|
||||
fmDataModel.put("srcTestDir", "src/test/java");
|
||||
|
||||
fmDataModel.put("genView", form.isGenView());
|
||||
fmDataModel.put("genController", form.isGenController());
|
||||
fmDataModel.put("genService", form.isGenService());
|
||||
fmDataModel.put("genMapper", form.isGenMapper());
|
||||
fmDataModel.put("genModel", form.isGenModel());
|
||||
fmDataModel.put("genForm", form.isGenForm());
|
||||
|
||||
val table = form.getTable();
|
||||
fmDataModel.put("table", table.toLowerCase());
|
||||
fmDataModel.put("notNull", false);
|
||||
fmDataModel.put("notBlank", false);
|
||||
fmDataModel.put("cacheEnabled",
|
||||
configProps.getMapper().isCacheEnabled());
|
||||
fmDataModel.put("useGeneratedKeys", false);
|
||||
|
||||
// collect col names
|
||||
String idType = null;
|
||||
val colNames = new ArrayList<String>(columns.size());
|
||||
for (val col : columns) {
|
||||
final String colName = ((String) col.get("col")).toLowerCase();
|
||||
colNames.add(colName);
|
||||
// find id type
|
||||
if ("id".equals(colName)) {
|
||||
String javaType = (String) col.get("javaType");
|
||||
if (ArrayUtils.contains(
|
||||
new String[] {"int", "long", "boolean", "double", "byte"},
|
||||
javaType)) {
|
||||
javaType = "int".equals(javaType) ?
|
||||
Integer.class.getSimpleName() :
|
||||
StringUtils.capitalize(javaType);
|
||||
}
|
||||
idType = javaType;
|
||||
}
|
||||
}
|
||||
|
||||
final String baseModelName;
|
||||
final String baseModelFullName;
|
||||
final Collection<String> modelBaseFields;
|
||||
|
||||
// custom super class
|
||||
val modelBaseClass = configProps.getModel().getBaseClass();
|
||||
val modelSuperClassName = modelBaseClass.getName();
|
||||
if (StringUtils.isNotBlank(modelSuperClassName)) {
|
||||
String modelSuperClassImportName = modelBaseClass.getFullName();
|
||||
Assert.state(StringUtils.isNotBlank(modelSuperClassImportName),
|
||||
"config 'codegen.model.super-class.import-name' required");
|
||||
baseModelName = modelSuperClassName;
|
||||
baseModelFullName = modelBaseClass.isImportRequired() ?
|
||||
modelSuperClassImportName : null;
|
||||
|
||||
modelBaseFields = configProps.getModel().getBaseClass().getFields();
|
||||
}
|
||||
else {
|
||||
log.info("No base model specified.");
|
||||
baseModelName = null;
|
||||
baseModelFullName = null;
|
||||
modelBaseFields = Collections.emptyList();
|
||||
}
|
||||
|
||||
fmDataModel.put("baseModelFullName", baseModelFullName);
|
||||
fmDataModel.put("baseModelName", baseModelName);
|
||||
|
||||
fmDataModel.put("tableAnnotationClassName", Table.class.getName());
|
||||
fmDataModel.put("tableAnnotationName", Table.class.getSimpleName());
|
||||
|
||||
val imports = new HashSet<String>();
|
||||
val colsWithoutBase = columns;
|
||||
val colIt = colsWithoutBase.iterator();
|
||||
|
||||
while (colIt.hasNext()) {
|
||||
val col = colIt.next();
|
||||
// col name
|
||||
val colName = ((String) col.get("col")).toLowerCase();
|
||||
// prop name
|
||||
val propName = (String) col.get("name");
|
||||
log.info("Process model col [{}] field.", colName, propName);
|
||||
if (!modelBaseFields.contains(propName)) {
|
||||
// for setName
|
||||
col.put("Name", StringUtils.capitalize(propName));
|
||||
if ((Boolean) col.get("notNull")) {
|
||||
if ("String".equals(col.get("javaType"))) {
|
||||
fmDataModel.put("notBlank", true);
|
||||
}
|
||||
else {
|
||||
fmDataModel.put("notNull", true);
|
||||
}
|
||||
}
|
||||
// imports
|
||||
val imp = TYPE_PACKAGES.get(col.get("javaType"));
|
||||
if (StringUtils.isNotBlank(imp)) {
|
||||
imports.add(imp);
|
||||
}
|
||||
}
|
||||
// remove base col
|
||||
else {
|
||||
log.info("Remove base col [{}].", colName);
|
||||
colIt.remove();
|
||||
}
|
||||
}
|
||||
|
||||
fmDataModel.put("idType", idType);
|
||||
fmDataModel.put("cols", colsWithoutBase);
|
||||
fmDataModel.put("fcProps", newPropsWithoutBase(colsWithoutBase,
|
||||
configProps.getFormCreate().getBaseClass().getFields()));
|
||||
fmDataModel.put("fuProps", newPropsWithoutBase(colsWithoutBase,
|
||||
configProps.getFormUpdate().getBaseClass().getFields()));
|
||||
fmDataModel.put("imports", imports);
|
||||
|
||||
fmDataModel.put("ModelName", model);
|
||||
fmDataModel.put("Model", model);
|
||||
fmDataModel.put("urlPrefix", configProps.getController().getUrlPrefix());
|
||||
fmDataModel.put("minusJoinedModelName", minusJoinedModelName);
|
||||
|
||||
// search
|
||||
fmDataModel.put("searchName", Search.class.getSimpleName());
|
||||
fmDataModel.put("searchFullName", Search.class.getName());
|
||||
|
||||
// controller
|
||||
fmDataModel.put("baseControllerName", BaseCrudController.class.getSimpleName());
|
||||
fmDataModel.put("baseControllerFullName", BaseCrudController.class.getName());
|
||||
|
||||
fmDataModel.put("FormList", FormList.class.getSimpleName());
|
||||
fmDataModel.put("formListFullName", FormList.class.getName());
|
||||
addFormSuperClass(fmDataModel);
|
||||
|
||||
// service interface
|
||||
fmDataModel.put("baseServiceName", BaseCrudByFormService.class.getSimpleName());
|
||||
fmDataModel.put("baseServiceFullName", BaseCrudByFormService.class.getName());
|
||||
// server impl
|
||||
fmDataModel.put("baseServiceSupportName", BaseCrudByFormServiceSupport.class.getSimpleName());
|
||||
fmDataModel.put("baseServiceSupportFullName", BaseCrudByFormServiceSupport.class.getName());
|
||||
|
||||
// mapper
|
||||
fmDataModel.put("baseMapperName", BaseMapper.class.getSimpleName());
|
||||
fmDataModel.put("baseMapperFullName", BaseMapper.class.getName());
|
||||
|
||||
fmDataModel.put("ctrlrTestToolName", ControllerTestTool.class.getSimpleName());
|
||||
fmDataModel.put("ctrlrTestToolFullName", ControllerTestTool.class.getName());
|
||||
// code doc
|
||||
fmDataModel.put("objDoc", doc());
|
||||
|
||||
// view
|
||||
fmDataModel.put("nameCn", form.getTableComment());
|
||||
fmDataModel.put("permName", WordUtils.convertCamelCase(model, "_").toUpperCase());
|
||||
|
||||
for (val genItem : genConfig.getItems()) {
|
||||
if ((Boolean) fmDataModel.get(
|
||||
"gen" + StringUtils.capitalize(genItem.getItem()))) {
|
||||
GenItem item = genItem.copy();
|
||||
item.setProjectDir(baseTool.renderStrFtl(item.getProjectDir(), fmDataModel));
|
||||
item.setResult(baseTool.renderStrFtl(item.getResult(), fmDataModel));
|
||||
render(item, fmDataModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public List<Map<String, Object>> list() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void delete(List<Map<String, Object>> items, boolean dropTable) {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public List<Map<String, Object>> tables() {
|
||||
return baseTool.tables();
|
||||
}
|
||||
|
||||
private String doc() {
|
||||
if (!configProps.getFileDoc().isGen()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Object Doc
|
||||
val objDocModel = new HashMap<String, Object>(4);
|
||||
objDocModel.put("author", configProps.getFileDoc().getAuthor());
|
||||
// time now
|
||||
objDocModel.put("now", new SimpleDateFormat(
|
||||
"MMM dd, yyyy HH:mm:ss").format(
|
||||
System.currentTimeMillis()));
|
||||
return baseTool.renderFtl("/templates/codegen/file-doc.ftl", objDocModel);
|
||||
}
|
||||
|
||||
private void addFormSuperClass(final Map<String, Object> fmModel) {
|
||||
val fcBaseClassNames = baseFormClass(
|
||||
configProps.getFormCreate().getBaseClass(), FC0.class);
|
||||
fmModel.put("baseFormCreateName", fcBaseClassNames.getLeft());
|
||||
fmModel.put("baseFormCreateFullName", fcBaseClassNames.getRight());
|
||||
|
||||
val fuBaseClassNames = baseFormClass(
|
||||
configProps.getFormUpdate().getBaseClass(), FU0.class);
|
||||
fmModel.put("baseFormUpdateName", fuBaseClassNames.getLeft());
|
||||
fmModel.put("baseFormUpdateFullName", fuBaseClassNames.getRight());
|
||||
}
|
||||
|
||||
private Pair<String, String> baseFormClass(final BaseClass baseClass, final Class<?> defaultFormClass) {
|
||||
val name = baseClass.getName();
|
||||
if (StringUtils.isNotBlank(name)) {
|
||||
if (baseClass.isImportRequired()) {
|
||||
final String fullName = baseClass.getFullName();
|
||||
Assert.state(StringUtils.isNotBlank(fullName),
|
||||
() -> "Form [" + name + "] full name required");
|
||||
return Pair.of(name, fullName);
|
||||
}
|
||||
return Pair.of(name, null);
|
||||
}
|
||||
return Pair.of(defaultFormClass.getSimpleName(),
|
||||
defaultFormClass.getName());
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
protected String render(final GenItem args, Map<String, ?> model) {
|
||||
log.info("Do render, args [{}].", args);
|
||||
|
||||
// write result
|
||||
val result = new File(
|
||||
new File(configProps.getWorkDir(),
|
||||
args.getProjectDir()), args.getResult());
|
||||
log.info("Write result to file [{}].", result);
|
||||
FileUtils.write(result, baseTool.renderFtl(args.getTemplate(), model),
|
||||
StandardCharsets.UTF_8);
|
||||
return args.getResult();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public void afterPropertiesSet() {
|
||||
ReflectionUtils.doWithFields(ConfigProperties.class, field -> {
|
||||
field.setAccessible(true);
|
||||
val name = field.getName();
|
||||
log.info("Super model field [{}] found.", name);
|
||||
val item = (BasicItem) ReflectionUtils.getField(field, configProps);
|
||||
moduleConfig.put(name + "ProjectDir", item.getProjectDir());
|
||||
val pkg = item.getBasePackage();
|
||||
if (StringUtils.isNotBlank(pkg)) {
|
||||
moduleConfig.put(name + "Pkg", pkg);
|
||||
moduleConfig.put(name + "PkgDir", pkg.replace('.', '/'));
|
||||
}
|
||||
}, field -> BasicItem.class.isAssignableFrom(field.getType()));
|
||||
|
||||
try (val ins = CodeGenServiceSupport.class.getResourceAsStream("/codegen.json")) {
|
||||
genConfig = json.parse(
|
||||
IOUtils.toString(ins, StandardCharsets.UTF_8), GenConfig.class);
|
||||
}
|
||||
}
|
||||
|
||||
private List<Map<String, Object>> newPropsWithoutBase(final List<Map<String, Object>> baseProps, final Collection<String> baseFields) {
|
||||
val props = new ArrayList<>(baseProps);
|
||||
val it = props.iterator();
|
||||
while (it.hasNext()) {
|
||||
if (baseFields.contains(it.next().get("name"))) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
return props;
|
||||
}
|
||||
}
|
@ -102,7 +102,7 @@ Ext.define ('Tigon.views.CodeGen', {
|
||||
}],
|
||||
store: Store.tree({
|
||||
url: 'codegen/tables',
|
||||
fields: ['id', 'text', 'module', 'model', 'cols', 'table'],
|
||||
fields: ['id', 'text', 'module', 'model', 'cols', 'table', 'tableComment'],
|
||||
root_text: 'Tables'
|
||||
}),
|
||||
listeners: {
|
||||
@ -131,30 +131,6 @@ Ext.define ('Tigon.views.CodeGen', {
|
||||
labelWidth: 86
|
||||
},
|
||||
tbar: [{
|
||||
text: 'New model',
|
||||
iconCls: 'add',
|
||||
handler: function(btn) {
|
||||
var form = btn.up('form'),
|
||||
s = form.down('grid').getStore();
|
||||
s.removeAll();
|
||||
s.add({
|
||||
name: 'id',
|
||||
javaType: 'String',
|
||||
col: 'id',
|
||||
sqlType: 'varchar(36)'
|
||||
}, {
|
||||
name: 'dateCreated',
|
||||
javaType: 'Date',
|
||||
col: 'date_created',
|
||||
sqlType: 'datetime'
|
||||
}, {
|
||||
name: 'dateUpdated',
|
||||
javaType: 'Date',
|
||||
col: 'date_updated',
|
||||
sqlType: 'datetime'
|
||||
});
|
||||
}
|
||||
}, {
|
||||
text: 'Generate!',
|
||||
iconCls: 'save',
|
||||
handler: function(btn) {
|
||||
@ -207,24 +183,29 @@ Ext.define ('Tigon.views.CodeGen', {
|
||||
},
|
||||
columns: 3,
|
||||
items: [{
|
||||
boxLabel: 'Gen controller',
|
||||
boxLabel: 'Gen View',
|
||||
checked: components.indexOf('view') > -1,
|
||||
name: 'genView'
|
||||
}, {
|
||||
boxLabel: 'Gen Controller',
|
||||
checked: components.indexOf('controller') > -1,
|
||||
name: 'genController'
|
||||
}, {
|
||||
boxLabel: 'Gen service',
|
||||
boxLabel: 'Gen Service',
|
||||
checked: components.indexOf('service') > -1,
|
||||
name: 'genService'
|
||||
}, {
|
||||
boxLabel: 'Gen mapper',
|
||||
boxLabel: 'Gen Mapper',
|
||||
checked: components.indexOf('mapper') > -1,
|
||||
name: 'genMapper'
|
||||
}, {
|
||||
boxLabel: 'Gen model',
|
||||
boxLabel: 'Gen Model',
|
||||
checked: components.indexOf('model') > -1,
|
||||
name: 'genModel'
|
||||
}, {
|
||||
boxLabel: 'Gen form',
|
||||
boxLabel: 'Gen Form',
|
||||
checked: components.indexOf('form') > -1,
|
||||
name: 'genView'
|
||||
name: 'genForm'
|
||||
}]
|
||||
}, {
|
||||
xtype: 'fieldcontainer',
|
||||
@ -387,24 +368,19 @@ Ext.define ('Tigon.views.CodeGen', {
|
||||
}
|
||||
}]
|
||||
}
|
||||
}, {
|
||||
xtype: 'textfield',
|
||||
name: 'pkg',
|
||||
fieldLabel: 'Base package',
|
||||
allowBlank: true,
|
||||
emptyText: 'Default base package (' + pkg + ').'
|
||||
}, {
|
||||
xtype: 'textfield',
|
||||
name: 'module',
|
||||
fieldLabel: 'Module',
|
||||
emptyText: 'Subpackage of base package.'
|
||||
}, {
|
||||
xtype: 'textfield',
|
||||
name: 'model',
|
||||
fieldLabel: 'Model name',
|
||||
value: 'ModelName',
|
||||
allowBlank: false
|
||||
}, {
|
||||
},
|
||||
{
|
||||
xtype: 'textfield',
|
||||
name: 'tableComment',
|
||||
fieldLabel: 'Table Comment',
|
||||
allowBlank: false
|
||||
},
|
||||
{
|
||||
xtype: 'textfield',
|
||||
name: 'table',
|
||||
fieldLabel: 'Table name',
|
100
codegen/src/main/resources/codegen.json
Normal file
@ -0,0 +1,100 @@
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"item": "model",
|
||||
"projectDir": "${modelProjectDir}",
|
||||
"template": "/templates/codegen/model.ftl",
|
||||
"result": "src/main/java/${modelPkgDir}/${Model}.java"
|
||||
},
|
||||
{
|
||||
"item": "form",
|
||||
"projectDir": "${formCreateProjectDir}",
|
||||
"template": "/templates/codegen/form-create.ftl",
|
||||
"result": "src/main/java/${formCreatePkgDir}/FormCreate${Model}.java"
|
||||
},
|
||||
{
|
||||
"item": "form",
|
||||
"projectDir": "${formUpdateProjectDir}",
|
||||
"template": "/templates/codegen/form-update.ftl",
|
||||
"result": "src/main/java/${formUpdatePkgDir}/FormUpdate${Model}.java"
|
||||
},
|
||||
{
|
||||
"item": "mapper",
|
||||
"projectDir": "${mapperProjectDir}",
|
||||
"template": "/templates/codegen/mapper.ftl",
|
||||
"result": "src/main/java/${mapperPkgDir}/${Model}Mapper.java"
|
||||
},
|
||||
{
|
||||
"item": "mapper",
|
||||
"projectDir": "${mapperProjectDir}",
|
||||
"template": "/templates/codegen/mapper-xml.ftl",
|
||||
"result": "src/main/java/${mapperPkgDir}/${Model}Mapper.xml"
|
||||
},
|
||||
{
|
||||
"item": "mapper",
|
||||
"projectDir": "${mapperProjectDir}",
|
||||
"template": "/templates/codegen/mapper-test.ftl",
|
||||
"result": "src/test/java/${mapperPkgDir}/${Model}MapperTest.java"
|
||||
},
|
||||
{
|
||||
"item": "service",
|
||||
"projectDir": "${serviceProjectDir}",
|
||||
"template": "/templates/codegen/service.ftl",
|
||||
"result": "src/main/java/${servicePkgDir}/${Model}Service.java"
|
||||
},
|
||||
{
|
||||
"item": "service",
|
||||
"projectDir": "${serviceImplProjectDir}",
|
||||
"template": "/templates/codegen/service-impl.ftl",
|
||||
"result": "src/main/java/${serviceImplPkgDir}/${Model}ServiceImpl.java"
|
||||
},
|
||||
{
|
||||
"item": "controller",
|
||||
"projectDir": "${controllerProjectDir}",
|
||||
"template": "/templates/codegen/controller.ftl",
|
||||
"result": "src/main/java/${controllerPkgDir}/${Model}Controller.java"
|
||||
},
|
||||
{
|
||||
"item": "view",
|
||||
"projectDir": "${viewProjectDir}",
|
||||
"template": "/templates/codegen/view/service.ftl",
|
||||
"result": "app/services/${minusJoinedModelName}/service.js"
|
||||
},
|
||||
{
|
||||
"item": "view",
|
||||
"projectDir": "${viewProjectDir}",
|
||||
"template": "/templates/codegen/view/route-list.ftl",
|
||||
"result": "app/routes/${minusJoinedModelName}/list.js"
|
||||
},
|
||||
{
|
||||
"item": "view",
|
||||
"projectDir": "${viewProjectDir}",
|
||||
"template": "/templates/codegen/view/route-create.ftl",
|
||||
"result": "app/routes/${minusJoinedModelName}/create.js"
|
||||
},
|
||||
{
|
||||
"item": "view",
|
||||
"projectDir": "${viewProjectDir}",
|
||||
"template": "/templates/codegen/view/route-edit.ftl",
|
||||
"result": "app/routes/${minusJoinedModelName}/edit.js"
|
||||
},
|
||||
{
|
||||
"item": "view",
|
||||
"projectDir": "${viewProjectDir}",
|
||||
"template": "/templates/codegen/view/tpl-list.ftl",
|
||||
"result": "app/templates/${minusJoinedModelName}/list.hbs"
|
||||
},
|
||||
{
|
||||
"item": "view",
|
||||
"projectDir": "${viewProjectDir}",
|
||||
"template": "/templates/codegen/view/tpl-create.ftl",
|
||||
"result": "app/templates/${minusJoinedModelName}/create.hbs"
|
||||
},
|
||||
{
|
||||
"item": "view",
|
||||
"projectDir": "${viewProjectDir}",
|
||||
"template": "/templates/codegen/view/tpl-edit.ftl",
|
||||
"result": "app/templates/${minusJoinedModelName}/edit.hbs"
|
||||
}
|
||||
]
|
||||
}
|
36
codegen/src/main/resources/logback.xml
Normal file
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration debug="true" scan="true" scanPeriod="180 seconds">>
|
||||
|
||||
<property name="log.level" value="DEBUG" />
|
||||
<property name="log.dir" value=".logs" />
|
||||
|
||||
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<withJansi>true</withJansi>
|
||||
<encoder>
|
||||
<pattern>%magenta(%d{"yyyy-MM-dd HH:mm:ss,SSS"}) [%thread] %highlight(%-5level) %cyan(%logger{15}) - %msg %n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="File" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.dir}/app.log</file>
|
||||
<encoder>
|
||||
<pattern>%d{"yyyy-MM-dd HH:mm:ss,SSS"} [%thread] %-5level %logger{15} %msg %n</pattern>
|
||||
</encoder>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${log.dir}/%d{yyyy-MM, aux}/app-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
|
||||
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<maxFileSize>32MB</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
</rollingPolicy>
|
||||
</appender>
|
||||
|
||||
<logger name="org.springframework" level="INFO" additivity="false">
|
||||
<appender-ref ref="Console" />
|
||||
<!--<appender-ref ref="File" />-->
|
||||
</logger>
|
||||
<root level="${log.level}">
|
||||
<appender-ref ref="Console" />
|
||||
<!--<appender-ref ref="File" />-->
|
||||
</root>
|
||||
</configuration>
|
||||
|
@ -7,27 +7,17 @@
|
||||
|
||||
<!-- Tool -->
|
||||
<bean class="me.chyxion.tigon.codegen.service.CodeGenBaseTool" />
|
||||
|
||||
<!--Services -->
|
||||
<bean class="me.chyxion.tigon.codegen.service.support.CodeGenServiceSupport" />
|
||||
<bean class="me.chyxion.tigon.codegen.service.support.ControllerCodeGen" />
|
||||
<bean class="me.chyxion.tigon.codegen.service.support.ControllerTestCodeGen" />
|
||||
<bean class="me.chyxion.tigon.codegen.service.support.MapperCodeGen" />
|
||||
<bean class="me.chyxion.tigon.codegen.service.support.MapperTestCodeGen" />
|
||||
<bean class="me.chyxion.tigon.codegen.service.support.MapperXmlCodeGen" />
|
||||
<bean class="me.chyxion.tigon.codegen.service.support.ModelCodeGen" />
|
||||
<bean class="me.chyxion.tigon.codegen.service.support.ServiceCodeGen" />
|
||||
<bean class="me.chyxion.tigon.codegen.service.support.TableCodeGen" />
|
||||
<bean class="me.chyxion.tigon.codegen.service.support.ViewCodeGen" />
|
||||
|
||||
<!-- FreeMarker Config -->
|
||||
<bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"
|
||||
p:templateLoaderPaths="/WEB-INF/views/, classpath:/, classpath:/webapp/views/"
|
||||
p:templateLoaderPaths="classpath:,classpath:/templates,classpath:/views"
|
||||
p:defaultEncoding="utf-8"
|
||||
p:preferFileSystemAccess="false">
|
||||
<property name="freemarkerSettings">
|
||||
<props>
|
||||
<prop key="template_update_delay">${tigon.codegen.freemarker.cache.expire:36000}</prop>
|
||||
<prop key="template_update_delay">${tigon.codegen.freemarker.cache-expire:36000}</prop>
|
||||
<prop key="output_encoding">utf-8</prop>
|
||||
<prop key="locale">en_US</prop>
|
||||
<prop key="date_format">yyyy-MM-dd</prop>
|
||||
@ -50,9 +40,9 @@
|
||||
<bean class="com.alibaba.druid.pool.DruidDataSource"
|
||||
init-method="init"
|
||||
destroy-method="close"
|
||||
p:url="jdbc:mysql://${datasource.host}:${datasource.port}/${datasource.database-name}?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull"
|
||||
p:username="${datasource.username}"
|
||||
p:password="${datasource.password}"
|
||||
p:url="${tigon.codegen.datasource.url}"
|
||||
p:username="${tigon.codegen.datasource.username}"
|
||||
p:password="${tigon.codegen.datasource.password}"
|
||||
/>
|
||||
</constructor-arg>
|
||||
</bean>
|
@ -1,3 +1,3 @@
|
||||
<#function isSelfCol col>
|
||||
<#return !['id', 'date_created', 'date_updated']?seq_contains(col.col)>
|
||||
</#function>
|
||||
</#function>
|
114
codegen/src/main/resources/templates/codegen/controller-test.ftl
Normal file
@ -0,0 +1,114 @@
|
||||
package ${controllerPkg};
|
||||
|
||||
<#list cols as prop>
|
||||
<#if prop.javaType == 'Date'>
|
||||
import java.util.Date;
|
||||
<#break>
|
||||
</#if>
|
||||
</#list>
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import ${ctrlrTestToolFullName};
|
||||
|
||||
<#if objDoc?has_content>
|
||||
${objDoc}
|
||||
</#if>
|
||||
@WebAppConfiguration
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration({
|
||||
"classpath*:spring/spring-*.xml",
|
||||
})
|
||||
public class ${ModelName}ControllerTest {
|
||||
@Autowired
|
||||
private ${ctrlrTestToolName} t;
|
||||
/**
|
||||
* test list
|
||||
*/
|
||||
@Test
|
||||
public void testList() {
|
||||
// TODO Modify Mock${ModelName}Mapper#listPage To Complete Test Logic
|
||||
final Map<String, Object> params = new HashMap<>();
|
||||
params.put("start", "0");
|
||||
params.put("limit", "10");
|
||||
t.assertSuccess(t.print(t.get("${urlPrefix!}/${minusJoinedModelName}/list")));
|
||||
}
|
||||
/**
|
||||
* test create
|
||||
*/
|
||||
@Test
|
||||
public void testCreate() {
|
||||
// TODO Modify Mock${ModelName}Mapper#insert To Complete Test Logic
|
||||
final Map<String, Object> params = new HashMap<>();
|
||||
<#list cols as prop>
|
||||
<#if prop.javaType == 'Date'>
|
||||
params.put("${prop.name}", new Date());
|
||||
<#elseif prop.javaType == 'String'>
|
||||
params.put("${prop.name}", "String Value");
|
||||
<#elseif prop.javaType == 'boolean'>
|
||||
params.put("${prop.name}", false);
|
||||
<#elseif prop.javaType == 'int'>
|
||||
params.put("${prop.name}", 1);
|
||||
<#elseif prop.javaType == 'long'>
|
||||
params.put("${prop.name}", 1L);
|
||||
<#elseif prop.javaType == 'float'>
|
||||
params.put("${prop.name}", 1.0F);
|
||||
<#elseif prop.javaType == 'double'>
|
||||
params.put("${prop.name}", 1.0D);
|
||||
</#if>
|
||||
</#list>
|
||||
t.print(t.put("${urlPrefix!}/${minusJoinedModelName}/create", params));
|
||||
}
|
||||
/**
|
||||
* test find
|
||||
*/
|
||||
@Test
|
||||
public void testFind() {
|
||||
// TODO Modify Mock${ModelName}Mapper#find to complete test logic
|
||||
final Map<String, Object> params = new HashMap<>();
|
||||
params.put("id", "1");
|
||||
t.assertSuccess(t.print(t.get("${urlPrefix!}/${minusJoinedModelName}/find", params)));
|
||||
}
|
||||
/**
|
||||
* test update
|
||||
*/
|
||||
@Test
|
||||
public void testUpdate() {
|
||||
// TODO Modify Mock${ModelName}Mapper#update to complete test logic
|
||||
final Map<String, Object> params = new HashMap<String, Object>();
|
||||
params.put("id", 1);
|
||||
<#list cols as prop>
|
||||
<#if prop.javaType == 'Date'>
|
||||
params.put("${prop.name}", new Date());
|
||||
<#elseif prop.javaType == 'String'>
|
||||
params.put("${prop.name}", "String Value Updated");
|
||||
<#elseif prop.javaType == 'boolean'>
|
||||
params.put("${prop.name}", true);
|
||||
<#elseif prop.javaType == 'int'>
|
||||
params.put("${prop.name}", 2);
|
||||
<#elseif prop.javaType == 'long'>
|
||||
params.put("${prop.name}", 2L);
|
||||
<#elseif prop.javaType == 'float'>
|
||||
params.put("${prop.name}", 2.0F);
|
||||
<#elseif prop.javaType == 'double'>
|
||||
params.put("${prop.name}", 2.0D);
|
||||
</#if>
|
||||
</#list>
|
||||
t.print(t.post("${urlPrefix!}/${minusJoinedModelName}/update", params));
|
||||
}
|
||||
/**
|
||||
* test delete one row
|
||||
*/
|
||||
@Test
|
||||
public void testDelete() {
|
||||
// TODO Modify Mock${ModelName}Mapper#delete to complete test logic
|
||||
final Map<String, Object> params = new HashMap<>();
|
||||
params.put("id", "1");
|
||||
t.assertSuccess(t.print(t.post("${urlPrefix!}/${minusJoinedModelName}/delete", params)));
|
||||
}
|
||||
}
|
22
codegen/src/main/resources/templates/codegen/controller.ftl
Normal file
@ -0,0 +1,22 @@
|
||||
package ${controllerPkg};
|
||||
|
||||
import ${modelPkg}.${ModelName};
|
||||
import ${formListFullName};
|
||||
import ${formCreatePkg}.FormCreate${ModelName};
|
||||
import ${formUpdatePkg}.FormUpdate${ModelName};
|
||||
import ${baseControllerFullName};
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
<#if objDoc?has_content>
|
||||
${objDoc}
|
||||
</#if>
|
||||
@Controller
|
||||
@RequestMapping("${urlPrefix!}/${minusJoinedModelName}")
|
||||
public class ${ModelName}Controller
|
||||
extends ${baseControllerName}<${idType},
|
||||
${ModelName},
|
||||
${FormList},
|
||||
FormCreate${ModelName},
|
||||
FormUpdate${ModelName}> {
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
/**
|
||||
* @author ${author}
|
||||
* @date ${now}
|
||||
*/
|
24
codegen/src/main/resources/templates/codegen/form-create.ftl
Normal file
@ -0,0 +1,24 @@
|
||||
package ${formCreatePkg};
|
||||
<#import "/codegen/commons.ftl" as CodeGen>
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
<#if baseFormCreateFullName?has_content>
|
||||
import ${baseFormCreateFullName};
|
||||
</#if>
|
||||
<#list imports as p>
|
||||
import ${p};
|
||||
</#list>
|
||||
|
||||
<#if objDoc?has_content>
|
||||
${objDoc}
|
||||
</#if>
|
||||
@Getter
|
||||
@Setter
|
||||
public class FormCreate${ModelName} extends ${baseFormCreateName} {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
<#list fcProps as prop>
|
||||
private ${prop.javaType} ${prop.name};
|
||||
</#list>
|
||||
}
|
24
codegen/src/main/resources/templates/codegen/form-update.ftl
Normal file
@ -0,0 +1,24 @@
|
||||
package ${formUpdatePkg};
|
||||
<#import "/codegen/commons.ftl" as CodeGen>
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
<#if baseFormUpdateFullName?has_content>
|
||||
import ${baseFormUpdateFullName};
|
||||
</#if>
|
||||
<#list imports as p>
|
||||
import ${p};
|
||||
</#list>
|
||||
|
||||
<#if objDoc?has_content>
|
||||
${objDoc}
|
||||
</#if>
|
||||
@Getter
|
||||
@Setter
|
||||
public class FormUpdate${ModelName} extends ${baseFormUpdateName} {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
<#list fuProps as prop>
|
||||
private ${prop.javaType} ${prop.name};
|
||||
</#list>
|
||||
}
|
24
codegen/src/main/resources/templates/codegen/mapper-test.ftl
Normal file
@ -0,0 +1,24 @@
|
||||
package ${mapperPkg};
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import ${searchFullName};
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests;
|
||||
|
||||
<#if objDoc?has_content>
|
||||
${objDoc}
|
||||
</#if>
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration("classpath*:spring/spring-*.xml")
|
||||
public class ${ModelName}MapperTest extends AbstractTransactionalJUnit4SpringContextTests {
|
||||
@Autowired
|
||||
private ${ModelName}Mapper mapper;
|
||||
|
||||
@Test
|
||||
public void mapperTest() {
|
||||
mapper.list(new Search().limit(8));
|
||||
}
|
||||
}
|
15
codegen/src/main/resources/templates/codegen/mapper-xml.ftl
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<#if objDoc??><#if objDoc?has_content>
|
||||
<!--
|
||||
${objDoc}
|
||||
-->
|
||||
</#if></#if>
|
||||
<!DOCTYPE mapper PUBLIC
|
||||
"-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="${mapperPkg}.${ModelName}Mapper">
|
||||
<#if cacheEnabled>
|
||||
<!-- Redis Cache -->
|
||||
<cache type="me.chyxion.tigon.mybatis.cache.RedisCache" />
|
||||
</#if>
|
||||
</mapper>
|
@ -1,9 +1,10 @@
|
||||
package ${pkg}.mapper;
|
||||
package ${mapperPkg};
|
||||
|
||||
import ${baseMapperFullName};
|
||||
import ${pkg}.model.${ModelName};
|
||||
import ${modelPkg}.${ModelName};
|
||||
|
||||
<#if objDoc?has_content>
|
||||
${objDoc}
|
||||
</#if>
|
||||
public interface ${ModelName}Mapper extends ${baseMapperName}<${idType}, ${ModelName}> {
|
||||
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
package ${pkg}.model;
|
||||
<#import "/codegen/commons.ftl" as CodeGen>
|
||||
package ${modelPkg};
|
||||
|
||||
<#import "/codegen/commons.ftl" as CodeGen>
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.FieldNameConstants;
|
||||
@ -12,22 +12,23 @@ import ${baseModelFullName};
|
||||
import ${p};
|
||||
</#list>
|
||||
|
||||
<#if objDoc?has_content>
|
||||
${objDoc}
|
||||
</#if>
|
||||
@Getter
|
||||
@Setter
|
||||
@${tableAnnotationName}("${table}")
|
||||
@FieldNameConstants(prefix = "")
|
||||
public class ${ModelName} extends ${baseModelName} {
|
||||
public class ${ModelName} <#if baseModelName?has_content>extends ${baseModelName} </#if>{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
<#--
|
||||
// Column Names
|
||||
<#list cols as prop>
|
||||
public static final String ${prop.col?upper_case} = "${prop.col}";
|
||||
</#list>
|
||||
-->
|
||||
|
||||
<#list cols as prop>
|
||||
private ${prop.javaType} ${prop.name};
|
||||
private ${prop.javaType} ${prop.name};
|
||||
</#list>
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package ${serviceImplPkg};
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import ${modelPkg}.${ModelName};
|
||||
import ${mapperPkg}.${ModelName}Mapper;
|
||||
import ${servicePkg}.${ModelName}Service;
|
||||
import ${formCreatePkg}.FormCreate${ModelName};
|
||||
import ${formUpdatePkg}.FormUpdate${ModelName};
|
||||
import ${baseServiceSupportFullName};
|
||||
|
||||
<#if objDoc?has_content>
|
||||
${objDoc}
|
||||
</#if>
|
||||
@Service
|
||||
public class ${ModelName}ServiceImpl
|
||||
extends ${baseServiceSupportName}<${idType},
|
||||
${ModelName},
|
||||
FormCreate${ModelName},
|
||||
FormUpdate${ModelName},
|
||||
${ModelName}Mapper>
|
||||
implements ${ModelName}Service {
|
||||
}
|
16
codegen/src/main/resources/templates/codegen/service.ftl
Normal file
@ -0,0 +1,16 @@
|
||||
package ${servicePkg};
|
||||
|
||||
import ${modelPkg}.${ModelName};
|
||||
import ${formCreatePkg}.FormCreate${ModelName};
|
||||
import ${formUpdatePkg}.FormUpdate${ModelName};
|
||||
import ${baseServiceFullName};
|
||||
|
||||
<#if objDoc?has_content>
|
||||
${objDoc}
|
||||
</#if>
|
||||
public interface ${ModelName}Service
|
||||
extends ${baseServiceName}<${idType},
|
||||
${ModelName},
|
||||
FormCreate${ModelName},
|
||||
FormUpdate${ModelName}> {
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
import BaseRoute from '../base';
|
||||
|
||||
export default BaseRoute.extend({
|
||||
perm: 'PERM_VIEW_${permName}_CREATE',
|
||||
breadcrumbs: [{route: '${minusJoinedModelName}.list', text: '${nameCn}列表'}, {text: '创建${nameCn}'}],
|
||||
model(params) {
|
||||
return {
|
||||
active: true
|
||||
};
|
||||
}
|
||||
});
|
@ -0,0 +1,10 @@
|
||||
import BaseEditRoute from '../base-edit';
|
||||
|
||||
export default BaseEditRoute.extend({
|
||||
perm: 'PERM_VIEW_${permName}_EDIT',
|
||||
afterModel(model) {
|
||||
this.set('breadcrumbs',
|
||||
[{route: '${minusJoinedModelName}.list', text: '${nameCn}列表'},
|
||||
{text: '编辑${nameCn}[' + model.id + ']'}]);
|
||||
}
|
||||
});
|
@ -0,0 +1,6 @@
|
||||
import BaseListRoute from '../base-list';
|
||||
|
||||
export default BaseListRoute.extend({
|
||||
perm: 'PERM_VIEW_${permName}_LIST',
|
||||
breadcrumbs: [{text: '${nameCn}列表'}]
|
||||
});
|
@ -0,0 +1,6 @@
|
||||
import Service from '../service';
|
||||
|
||||
export default Service.extend({
|
||||
modelName: '${ModelName}',
|
||||
// constraints: { }
|
||||
});
|
@ -0,0 +1,9 @@
|
||||
{{#form-content}}
|
||||
<hr />
|
||||
{{form-input name='name' label='名称'}}
|
||||
{{form-input name='account' label='账户'}}
|
||||
{{form-input name='note' label='备注'}}
|
||||
<hr />
|
||||
{{form-footer-buttons type='create'}}
|
||||
{{/form-content}}
|
||||
{{outlet}}
|
@ -0,0 +1,9 @@
|
||||
{{#form-content}}
|
||||
{{form-input type='hidden' name='id'}}
|
||||
{{form-input name='name' label='名称'}}
|
||||
{{form-input-enabled}}
|
||||
{{form-input name='note' label='备注'}}
|
||||
<hr />
|
||||
{{form-footer-buttons type='update'}}
|
||||
{{/form-content}}
|
||||
{{outlet}}
|
@ -0,0 +1,73 @@
|
||||
<div class="widget-box transparent" style="padding-top: 2px; border: 1px solid #ddd;">
|
||||
{{#grid-header}}
|
||||
{{#has-perm 'PERM_VIEW_${permName}_CREATE'}}
|
||||
<li>
|
||||
{{#link-to '${minusJoinedModelName}.create'}}
|
||||
<i class="ace-icon fa fa-plus-circle bigger-110 green"></i>
|
||||
新建${nameCn}
|
||||
{{/link-to}}
|
||||
</li>
|
||||
{{/has-perm}}
|
||||
{{/grid-header}}
|
||||
<div class="widget-body">
|
||||
<!-- #section:custom/scrollbar -->
|
||||
<div class="widget-main no-padding">
|
||||
<table class="table table-striped table-bordered table-hover dataTable">
|
||||
<thead class="thin-border-bottom">
|
||||
<tr>
|
||||
<th>
|
||||
名称
|
||||
</th>
|
||||
<th>
|
||||
<i class="ace-icon fa fa-sticky-note-o bigger-110"></i>
|
||||
备注
|
||||
</th>
|
||||
<th>
|
||||
<i class="ace-icon fa fa-exchange bigger-110 hidden-480"></i>
|
||||
{{th-filter name='active'
|
||||
text='状态'
|
||||
dialog-title='状态'
|
||||
options=(array (hash value=true text='启用')
|
||||
(hash value=false text='禁用'))
|
||||
}}
|
||||
</th>
|
||||
<th>
|
||||
<i class="ace-icon fa fa-cogs bigger-110 hidden-480"></i>
|
||||
管理
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each model.data as |it|}}
|
||||
<tr>
|
||||
<td>
|
||||
{{it.name}}
|
||||
</td>
|
||||
<td>
|
||||
{{editable-cell model=it field='note'}}
|
||||
</td>
|
||||
<td>
|
||||
{{status-cell model=it}}
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-group">
|
||||
{{#has-perm 'PERM_VIEW_${permName}_EDIT'}}
|
||||
{{status-toggle-button model=it}}
|
||||
{{edit-btn route-name='${minusJoinedModelName}.edit' model-id=it.id perm='PERM_VIEW_${permName}_EDIT'}}
|
||||
{{/has-perm}}
|
||||
{{#has-perm 'PERM_VIEW_${permName}_DELETE'}}
|
||||
{{#unless it.active}}
|
||||
{{delete-button model=it}}
|
||||
{{/unless}}
|
||||
{{/has-perm}}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{pagination-bar}}
|
||||
</div>
|
||||
</div>
|
||||
{{outlet}}
|
@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<#include "/commons/extjs-header.ftl" />
|
||||
<#include "/extjs-header.ftl" />
|
||||
<script type="text/javascript">
|
||||
/**
|
||||
* @version 1.0
|
||||
@ -25,10 +25,9 @@
|
||||
});
|
||||
Ext.create('Tigon.views.ThemesBar').show();
|
||||
});
|
||||
var pkg = '${pkg}';
|
||||
var components = ${components};
|
||||
</script>
|
||||
<title>Auto Code</title>
|
||||
<title>Tigon Code Gen</title>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
@ -0,0 +1,31 @@
|
||||
package me.chyxion.tigon.codegen.test;
|
||||
|
||||
import lombok.val;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chyxion.tigon.codegen.TigonCodeGen;
|
||||
import me.chyxion.tigon.codegen.service.CodeGenBaseTool;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date Mar 14, 2021 22:31:32
|
||||
*/
|
||||
@Slf4j
|
||||
@SpringBootTest(classes = TigonCodeGen.class)
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class TestDriver {
|
||||
|
||||
@Autowired
|
||||
private CodeGenBaseTool tool;
|
||||
|
||||
@Test
|
||||
public void runTest() {
|
||||
val tables = tool.tables();
|
||||
log.info("Tables [{}].", tables);
|
||||
}
|
||||
}
|
6
codegen/src/test/resources/application.yml
Normal file
@ -0,0 +1,6 @@
|
||||
tigon:
|
||||
codegen:
|
||||
datasource:
|
||||
password: yobr_query!
|
||||
url: jdbc:mysql://192.168.3.5/yobr-daily?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai
|
||||
username: yobr_query
|
36
codegen/src/test/resources/logback.xml
Normal file
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration debug="true">
|
||||
|
||||
<property name="log.level" value="DEBUG" />
|
||||
<property name="log.dir" value=".logs" />
|
||||
|
||||
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<withJansi>true</withJansi>
|
||||
<encoder>
|
||||
<pattern>%magenta(%d{"yyyy-MM-dd HH:mm:ss,SSS"}) [%thread] %highlight(%-5level) %cyan(%logger{15}) - %msg %n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="File" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${log.dir}/app.log</file>
|
||||
<encoder>
|
||||
<pattern>%d{"yyyy-MM-dd HH:mm:ss,SSS"} [%thread] %-5level %logger{15} %msg %n</pattern>
|
||||
</encoder>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${log.dir}/%d{yyyy-MM, aux}/app-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
|
||||
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<maxFileSize>32MB</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
</rollingPolicy>
|
||||
</appender>
|
||||
|
||||
<logger name="org.springframework" level="TRACE" additivity="false">
|
||||
<appender-ref ref="Console" />
|
||||
<appender-ref ref="File" />
|
||||
</logger>
|
||||
<root level="${log.level}">
|
||||
<appender-ref ref="Console" />
|
||||
<appender-ref ref="File" />
|
||||
</root>
|
||||
</configuration>
|
||||
|
6
codegen/src/test/resources/spring/spring-test.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
</beans>
|
1
common/README.md
Normal file
@ -0,0 +1 @@
|
||||
# Tigon Common
|
73
common/pom.xml
Normal file
@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
|
||||
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>tigon-common</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Tigon Common</name>
|
||||
<description>Tigon Common</description>
|
||||
|
||||
<parent>
|
||||
<groupId>me.chyxion.tigon</groupId>
|
||||
<artifactId>tigon</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>bson</artifactId>
|
||||
</dependency>
|
||||
<!--For Form Copy-->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<!-- For Form Validate -->
|
||||
<dependency>
|
||||
<groupId>org.hibernate.validator</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Test -->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-slf4j-impl</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
34
common/src/main/java/me/chyxion/tigon/annotation/Trim.java
Normal file
@ -0,0 +1,34 @@
|
||||
package me.chyxion.tigon.annotation;
|
||||
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* blank string format to null
|
||||
*
|
||||
* <pre>
|
||||
* null => null
|
||||
* "" => null
|
||||
* " " => null
|
||||
* "abc" => "abc"
|
||||
* " abc " => "abc"
|
||||
* </pre>
|
||||
*
|
||||
* @author Donghuang
|
||||
* @date Jun 15, 2016 11:20:48 AM
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE, ElementType.FIELD})
|
||||
public @interface Trim {
|
||||
|
||||
/**
|
||||
* blank as null
|
||||
*
|
||||
* @return blank as null if true
|
||||
*/
|
||||
boolean blankAsNull() default true;
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package me.chyxion.tigon.annotation.json;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 集合、Array空元素清理
|
||||
*
|
||||
* @author Donghuang
|
||||
* @date Apr 20, 2022 20:38:54
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE, ElementType.FIELD})
|
||||
public @interface EmptyElCleanup {
|
||||
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package me.chyxion.tigon.annotation.json;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* Deserialize JSON empty object to null
|
||||
*
|
||||
* @author Donghuang
|
||||
* @date Apr 20, 2022 20:38:54
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE, ElementType.FIELD})
|
||||
public @interface EmptyObjectToNull {
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package me.chyxion.tigon.annotation.json;
|
||||
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* JSON 反序列化回调
|
||||
*
|
||||
* @author Donghuang
|
||||
* @date Apr 21, 2022 10:17:19
|
||||
*/
|
||||
@Target({ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface PostDeserialize {
|
||||
|
||||
/**
|
||||
* 强制访问私有方法
|
||||
*
|
||||
* @return true if force access
|
||||
*/
|
||||
boolean forceAccess() default false;
|
||||
}
|
1
common/src/main/java/me/chyxion/tigon/package-info.java
Normal file
@ -0,0 +1 @@
|
||||
package me.chyxion.tigon;
|
18
common/src/test/java/me/chyxion/tigon/test/TestDriver.java
Normal file
@ -0,0 +1,18 @@
|
||||
package me.chyxion.tigon.test;
|
||||
|
||||
import org.junit.Test;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @version 0.0.1
|
||||
* @author Donghuang
|
||||
* @date May 13, 2016 10:45:07 AM
|
||||
*/
|
||||
@Slf4j
|
||||
public class TestDriver {
|
||||
|
||||
@Test
|
||||
public void run() {
|
||||
log.info("Run.");
|
||||
}
|
||||
}
|
@ -2,15 +2,15 @@
|
||||
<Configuration status="WARN">
|
||||
<Properties>
|
||||
<Property name="pattern">%-d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%t][%c{1}] %m%n</Property>
|
||||
<Property name="log.dir">.logs</Property>
|
||||
<Property name="log.dir">.log</Property>
|
||||
</Properties>
|
||||
<Appenders>
|
||||
<Console name="Console" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="${pattern}" />
|
||||
</Console>
|
||||
<RollingFile name="File"
|
||||
fileName="${log.dir}/tigon-service-support.log"
|
||||
filePattern="${log.dir}/tigon-service-support-%d{yyyy-MM-dd}-%i.log">
|
||||
fileName="${log.dir}/app.log"
|
||||
filePattern="${log.dir}/$${date:yyyy-MM}/app-%d{yyyy-MM-dd}-%i.log">
|
||||
<PatternLayout pattern="${pattern}" />
|
||||
<Policies>
|
||||
<TimeBasedTriggeringPolicy />
|
||||
@ -29,4 +29,3 @@
|
||||
</Root>
|
||||
</Loggers>
|
||||
</Configuration>
|
||||
|
3
deploy
@ -1,3 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
mvn clean deploy -DskipTests -U -DaltDeploymentRepository=snapshot::default::http://101.231.57.218:8081/nexus/content/repositories/snapshots/
|
@ -1,4 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# mvn clean deploy -DskipTests -U -Prelease -DaltDeploymentRepository=oss::default::https://oss.sonatype.org/service/local/staging/deploy/maven2/
|
||||
mvn clean deploy -DskipTests -Dmaven.javadoc.skip=true -U -Prelease -DaltDeploymentRepository=oss::default::https://oss.sonatype.org/content/repositories/snapshots
|
@ -0,0 +1 @@
|
||||
46d94f9b2e77fe81c9774dddb4c96228baf2ac7f
|
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
|
||||
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.sencha.extjs</groupId>
|
||||
<artifactId>extjs</artifactId>
|
||||
<version>4.2.1.883</version>
|
||||
<name>Sencha ExtJS</name>
|
||||
<description>Sencha ExtJS</description>
|
||||
<packaging>jar</packaging>
|
||||
</project>
|
@ -0,0 +1 @@
|
||||
267b9ac958463fd470940ad908f8a50b8e770138
|
14
extjs/local-repo/com/sencha/extjs/extjs/maven-metadata-local.xml
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<metadata>
|
||||
<groupId>com.sencha.extjs</groupId>
|
||||
<artifactId>extjs</artifactId>
|
||||
<version>4.2.1.883</version>
|
||||
|
||||
<versioning>
|
||||
<release>4.2.1.883</release>
|
||||
<versions>
|
||||
<version>4.2.1.883</version>
|
||||
</versions>
|
||||
<lastUpdated>20200503111212</lastUpdated>
|
||||
</versioning>
|
||||
</metadata>
|
@ -0,0 +1 @@
|
||||
87791c43904f064234ca9ce207ddafef
|
@ -0,0 +1 @@
|
||||
c26a74fe148ac826ac990036e1fb3a5ed5a34a1f
|
57
extjs/pom.xml
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
|
||||
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>tigon-extjs</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Tigon Ext JS</name>
|
||||
<description>Tigon Ext JS</description>
|
||||
|
||||
<parent>
|
||||
<groupId>me.chyxion.tigon</groupId>
|
||||
<artifactId>tigon</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.sencha.extjs</groupId>
|
||||
<artifactId>extjs</artifactId>
|
||||
<version>4.2.1.883</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<configuration>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>extjs-repo</id>
|
||||
<name>ExtJS</name>
|
||||
<url>file://${project.basedir}/local-repo/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
</project>
|
@ -1,6 +1,3 @@
|
||||
html {
|
||||
font-family: 'Microsoft YaHei'
|
||||
}
|
||||
/* message styles */
|
||||
#commons-message-div {
|
||||
position: absolute;
|
Before Width: | Height: | Size: 994 B After Width: | Height: | Size: 994 B |
Before Width: | Height: | Size: 703 B After Width: | Height: | Size: 703 B |
Before Width: | Height: | Size: 989 B After Width: | Height: | Size: 989 B |
Before Width: | Height: | Size: 788 B After Width: | Height: | Size: 788 B |
Before Width: | Height: | Size: 526 B After Width: | Height: | Size: 526 B |
Before Width: | Height: | Size: 771 B After Width: | Height: | Size: 771 B |
Before Width: | Height: | Size: 1016 B After Width: | Height: | Size: 1016 B |
Before Width: | Height: | Size: 663 B After Width: | Height: | Size: 663 B |
Before Width: | Height: | Size: 494 B After Width: | Height: | Size: 494 B |
Before Width: | Height: | Size: 504 B After Width: | Height: | Size: 504 B |
Before Width: | Height: | Size: 595 B After Width: | Height: | Size: 595 B |
@ -9,7 +9,6 @@
|
||||
Ext.define('Tigon.views.Grid', {
|
||||
extend:'Ext.grid.Panel',
|
||||
alias: 'widget.sgrid',
|
||||
alternateClassName: ['SpringExt.views.Grid'],
|
||||
columnLines: true,
|
||||
loadMask: true,
|
||||
required: '<span style="color:red;font-weight:bold" data-qtip="Required">*</span>',
|
@ -6,7 +6,6 @@
|
||||
* Dec 17, 2014 13:34:42
|
||||
*/
|
||||
Ext.define('Tigon.views.ThemesBar', {
|
||||
alternateClassName: ['SpringExt.views.ThemesBar'],
|
||||
show: function() {
|
||||
// toolbar
|
||||
setTimeout(function() {
|
@ -1,49 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
|
||||
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
|
||||
<artifactId>tigon-i18n</artifactId>
|
||||
<name>Tigon I18n</name>
|
||||
<description>Tigon I18n</description>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>tigon-shiro-cache</artifactId>
|
||||
<name>Tigon Shiro Cache</name>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>me.chyxion.tigon</groupId>
|
||||
<artifactId>tigon</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<!--三方依赖-->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.1</version>
|
||||
<groupId>javax.validation</groupId>
|
||||
<artifactId>validation-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate.validator</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<!-- shiro -->
|
||||
<dependency>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
<artifactId>shiro-core</artifactId>
|
||||
<version>1.3.2</version>
|
||||
</dependency>
|
||||
<!-- Test Dependencies -->
|
||||
<!--/三方依赖-->
|
||||
|
||||
<!--Provided-->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!--/Provided-->
|
||||
|
||||
<!--测试依赖-->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@ -51,5 +50,6 @@
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!--/测试依赖-->
|
||||
</dependencies>
|
||||
</project>
|
@ -0,0 +1,98 @@
|
||||
package me.chyxion.tigon.i18n.config;
|
||||
|
||||
import lombok.val;
|
||||
import java.util.*;
|
||||
import java.io.IOException;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import me.chyxion.tigon.i18n.resolver.I18n;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import me.chyxion.tigon.i18n.resolver.impl.I18nResolverImpl;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date May 13, 2022 11:26:34
|
||||
*/
|
||||
@Slf4j
|
||||
public class I18nConfiguration {
|
||||
private static final PathMatchingResourcePatternResolver resolver =
|
||||
new PathMatchingResourcePatternResolver(MethodHandles.lookup().getClass().getClassLoader());
|
||||
|
||||
private final ReloadableResourceBundleMessageSource messageSource = new MultipleMessageSource();
|
||||
{
|
||||
// 扫描出来
|
||||
messageSource.setBasenames(getMessageSourceBasenames());
|
||||
messageSource.setDefaultEncoding(StandardCharsets.UTF_8.name());
|
||||
}
|
||||
|
||||
public static class MultipleMessageSource extends ReloadableResourceBundleMessageSource {
|
||||
private static final String PROPERTIES_SUFFIX = ".properties";
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
protected PropertiesHolder refreshProperties(final String filename, final PropertiesHolder propHolder) {
|
||||
if (filename.startsWith(PathMatchingResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX)) {
|
||||
return refreshClassPathProperties(filename, propHolder);
|
||||
}
|
||||
|
||||
return super.refreshProperties(filename, propHolder);
|
||||
}
|
||||
|
||||
PropertiesHolder refreshClassPathProperties(final String filename, final PropertiesHolder propHolder) {
|
||||
val properties = new Properties();
|
||||
long lastModified = -1;
|
||||
try {
|
||||
val resources = resolver.getResources(filename + PROPERTIES_SUFFIX);
|
||||
for (val resource : resources) {
|
||||
val holder = super.refreshProperties(
|
||||
resource.getURI().toString().replace(PROPERTIES_SUFFIX, ""), propHolder);
|
||||
properties.putAll(holder.getProperties());
|
||||
if (lastModified < resource.lastModified()) {
|
||||
lastModified = resource.lastModified();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (final IOException e) {
|
||||
log.warn("Refresh class path properties error caused.", e);
|
||||
}
|
||||
|
||||
return new PropertiesHolder(properties, lastModified);
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MessageSource messageSource() {
|
||||
return messageSource;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public I18n i18nResolver(final MessageSource messageSource) {
|
||||
return new I18nResolverImpl(messageSource);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
String[] getMessageSourceBasenames() {
|
||||
val resources = resolver.getResources("classpath*:i18n/**/messages*.properties");
|
||||
if (resources != null) {
|
||||
val setBasenames = new HashSet<String>(resources.length);
|
||||
for (val resource : resources) {
|
||||
setBasenames.add(resource.getURI().toString().replaceAll(
|
||||
".*(i18n(?:/\\w+)?/messages.*)_\\w+_\\w+.properties.*", "classpath*:$1"));
|
||||
}
|
||||
log.info("I18n message source basenames [{}] scanned.", setBasenames);
|
||||
return setBasenames.toArray(new String[0]);
|
||||
}
|
||||
|
||||
// default
|
||||
log.info("No message source basenames scanned, use default [classpath:i18n/messages].");
|
||||
return new String[] {"classpath*:i18n/messages"};
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package me.chyxion.tigon.i18n.constant;
|
||||
|
||||
/**
|
||||
* 国际化消息前缀
|
||||
*
|
||||
* @author Donghuang
|
||||
* @date May 17, 2022 10:22:57
|
||||
*/
|
||||
public class I18nMsgKeyPrefix {
|
||||
|
||||
/**
|
||||
* 错误消息
|
||||
*/
|
||||
public static final String ERRMSG = "ERRMSG.";
|
||||
|
||||
/**
|
||||
* 枚举名称
|
||||
*/
|
||||
public static final String ENUM = "ENUM.";
|
||||
|
||||
/**
|
||||
* 表头
|
||||
*/
|
||||
public static final String TABLE_HEADER = "TABLE_HEADER.";
|
||||
}
|
84
i18n/src/main/java/me/chyxion/tigon/i18n/resolver/I18n.java
Normal file
@ -0,0 +1,84 @@
|
||||
package me.chyxion.tigon.i18n.resolver;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Collection;
|
||||
import org.springframework.lang.Nullable;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import me.chyxion.tigon.i18n.resolver.impl.I18nResolverImpl;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date May 13, 2022 10:41:50
|
||||
*/
|
||||
@Validated
|
||||
public interface I18n {
|
||||
|
||||
/**
|
||||
* 获取国际化文本
|
||||
*
|
||||
* @param code 国际化代码
|
||||
* @param args 占位参数
|
||||
* @return 国际化文本
|
||||
*/
|
||||
@Nullable
|
||||
static String t(@NotBlank final String code, final Object ... args) {
|
||||
return I18nResolverImpl.getStaticInstance().getI18nText(code, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取国际化文本
|
||||
*
|
||||
* @param locale 区域位置
|
||||
* @param code 国际化代码
|
||||
* @param args 占位参数
|
||||
* @return 国际化文本
|
||||
*/
|
||||
@Nullable
|
||||
static String t(@NotNull Locale locale, @NotBlank final String code, final Object ... args) {
|
||||
return I18nResolverImpl.getStaticInstance().getI18nText(locale, code, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取国际化文本
|
||||
*
|
||||
* @param code 国际化代码
|
||||
* @param args 占位参数
|
||||
* @return 国际化文本
|
||||
*/
|
||||
@Nullable
|
||||
String getI18nText(@NotBlank String code, Object ... args);
|
||||
|
||||
/**
|
||||
* 获取国际化文本
|
||||
*
|
||||
* @param code 国际化代码
|
||||
* @param args 占位参数
|
||||
* @return 国际化文本
|
||||
*/
|
||||
@Nullable
|
||||
<T> String getI18nText(@NotBlank String code, Collection<T> args);
|
||||
|
||||
/**
|
||||
* 获取国际化文本
|
||||
*
|
||||
* @param locale 区域位置
|
||||
* @param code 国际化代码
|
||||
* @param args 占位参数
|
||||
* @return 国际化文本
|
||||
*/
|
||||
@Nullable
|
||||
String getI18nText(@NotNull Locale locale, @NotBlank String code, Object ... args);
|
||||
|
||||
/**
|
||||
* 获取国际化文本
|
||||
*
|
||||
* @param locale 区域位置
|
||||
* @param code 国际化代码
|
||||
* @param args 占位参数
|
||||
* @return 国际化文本
|
||||
*/
|
||||
@Nullable
|
||||
<T> String getI18nText(@NotNull Locale locale, @NotBlank String code, Collection<T> args);
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package me.chyxion.tigon.i18n.resolver.impl;
|
||||
|
||||
import lombok.val;
|
||||
import lombok.Getter;
|
||||
import java.util.Collection;
|
||||
import java.util.Locale;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.chyxion.tigon.i18n.resolver.I18n;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.i18n.LocaleContextHolder;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date May 13, 2022 10:41:35
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class I18nResolverImpl implements I18n, InitializingBean {
|
||||
private final MessageSource messageSource;
|
||||
|
||||
@Getter
|
||||
private static I18n staticInstance;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String getI18nText(final String code, final Object ... args) {
|
||||
return getI18nText(LocaleContextHolder.getLocale(), code, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public <T> String getI18nText(final String code, final Collection<T> args) {
|
||||
return getI18nText(LocaleContextHolder.getLocale(), code, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String getI18nText(final Locale locale, final String code, final Object ... args) {
|
||||
val message = messageSource.getMessage(code, args, null, locale);
|
||||
log.debug("Get i18n text, code [{}] result [{}].", code, message);
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public <T> String getI18nText(final Locale locale, final String code, final Collection<T> args) {
|
||||
if (args != null && !args.isEmpty()) {
|
||||
return getI18nText(locale, code, args.toArray());
|
||||
}
|
||||
return getI18nText(locale, code);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
staticInstance = this;
|
||||
}
|
||||
}
|
2
i18n/src/main/resources/META-INF/spring.factories
Normal file
@ -0,0 +1,2 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
me.chyxion.tigon.i18n.config.I18nConfiguration
|
@ -0,0 +1,37 @@
|
||||
package me.chyxion.tigon.i18n.test;
|
||||
|
||||
import lombok.val;
|
||||
import me.chyxion.tigon.i18n.resolver.I18n;
|
||||
import org.junit.Test;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import org.junit.runner.RunWith;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date May 13, 2022 11:32:49
|
||||
*/
|
||||
@Slf4j
|
||||
@SpringBootTest(classes = Main.class)
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class I18nResolverTest {
|
||||
@Autowired
|
||||
private MessageSource messageSource;
|
||||
@Autowired
|
||||
private I18n i18n;
|
||||
|
||||
@Test
|
||||
public void testMessageSource() {
|
||||
val message = messageSource.getMessage("param.could.not.be.blank", new Object[] {"参数"}, Locale.CHINA);
|
||||
log.info("message [{}].", message);
|
||||
log.info("i18n text [{}].", i18n.getI18nText("param.could.not.be.blank", "请求参数"));
|
||||
log.info("i18n text2 [{}].", i18n.getI18nText("param.could.not.be.blank", Arrays.asList("请求参数")));
|
||||
log.info("i18n text3 [{}].", I18n.t("param.could.not.be.blank", Arrays.asList("请求参数")));
|
||||
log.info("format: {0} {1} {2}", 1, 2, 3);
|
||||
}
|
||||
}
|
11
i18n/src/test/java/me/chyxion/tigon/i18n/test/Main.java
Normal file
@ -0,0 +1,11 @@
|
||||
package me.chyxion.tigon.i18n.test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date May 13, 2022 11:30:53
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class Main {
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package me.chyxion.tigon.i18n.test;
|
||||
|
||||
import org.junit.Test;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author Donghuang
|
||||
* @date May 13, 2022 11:31:55
|
||||
*/
|
||||
@Slf4j
|
||||
public class TestDriver {
|
||||
|
||||
@Test
|
||||
public void testRun() {
|
||||
log.info("TRUE: {}", Boolean.TRUE.toString());
|
||||
}
|
||||
}
|
12
i18n/src/test/resources/application.yml
Normal file
@ -0,0 +1,12 @@
|
||||
# common config
|
||||
server:
|
||||
port: 7001
|
||||
|
||||
spring:
|
||||
jackson:
|
||||
default-property-inclusion: NON_NULL
|
||||
time-zone: GMT+8
|
||||
servlet:
|
||||
multipart:
|
||||
max-file-size: 128MB
|
||||
max-request-size: 128MB
|
@ -0,0 +1 @@
|
||||
bp.could.not.be.blank=BP could not be blank
|
@ -0,0 +1 @@
|
||||
bp.could.not.be.blank=BP不可以为空
|