Compare commits

...

No commits in common. "master" and "feature/v0.0.4" have entirely different histories.

1942 changed files with 11279 additions and 153793 deletions

2
.gitignore vendored
View File

@ -1,5 +1,5 @@
.* .*
!.gitignore !.gitignore
!.gitkeep
*.iml *.iml
target/ target/
bin/

View File

@ -1,13 +0,0 @@
## 该问题是怎么引起的?
## 重现步骤
## 报错信息

View File

@ -1,15 +0,0 @@
## 该Pull Request关联的Issue
## 修改描述
## 测试用例
## 修复效果的截屏

View File

@ -1 +1 @@
# Tigon # Tigon

View File

@ -13,13 +13,11 @@
<parent> <parent>
<groupId>me.chyxion.tigon</groupId> <groupId>me.chyxion.tigon</groupId>
<artifactId>tigon</artifactId> <artifactId>tigon</artifactId>
<version>0.0.1-SNAPSHOT</version> <version>${revision}</version>
<relativePath>../</relativePath>
</parent> </parent>
<properties> <properties>
<spring-boot.run.main-class>me.chyxion.tigon.codegen.TigonCodeGen</spring-boot.run.main-class> <spring-boot.run.main-class>me.chyxion.tigon.codegen.TigonCodeGen</spring-boot.run.main-class>
<mainClass>me.chyxion.tigon.codegen.TigonCodeGen</mainClass>
</properties> </properties>
<dependencies> <dependencies>
@ -31,10 +29,18 @@
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId> <artifactId>spring-context-support</artifactId>
</dependency> </dependency>
<dependency>
<groupId>me.chyxion.tigon</groupId>
<artifactId>tigon-common</artifactId>
</dependency>
<dependency> <dependency>
<groupId>me.chyxion.tigon</groupId> <groupId>me.chyxion.tigon</groupId>
<artifactId>tigon-extjs</artifactId> <artifactId>tigon-extjs</artifactId>
</dependency> </dependency>
<dependency>
<groupId>me.chyxion.tigon</groupId>
<artifactId>tigon-web-controller</artifactId>
</dependency>
<dependency> <dependency>
<groupId>me.chyxion.tigon</groupId> <groupId>me.chyxion.tigon</groupId>
<artifactId>tigon-web</artifactId> <artifactId>tigon-web</artifactId>
@ -48,7 +54,6 @@
<artifactId>commons-io</artifactId> <artifactId>commons-io</artifactId>
<version>2.6</version> <version>2.6</version>
</dependency> </dependency>
<!-- mybatis -->
<dependency> <dependency>
<groupId>me.chyxion.tigon</groupId> <groupId>me.chyxion.tigon</groupId>
<artifactId>tigon-mybatis</artifactId> <artifactId>tigon-mybatis</artifactId>
@ -68,12 +73,21 @@
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<!-- /mybatis -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>provided</scope> <scope>provided</scope>
</dependency> </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> </dependencies>
<build> <build>
@ -84,7 +98,6 @@
<artifactId>spring-boot-maven-plugin</artifactId> <artifactId>spring-boot-maven-plugin</artifactId>
<configuration> <configuration>
<skip>false</skip> <skip>false</skip>
<fork>true</fork>
</configuration> </configuration>
</plugin> </plugin>
</plugins> </plugins>

View File

@ -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/");
}
}

View File

@ -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;
}

View File

@ -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<>();
}

View File

@ -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;
}

View File

@ -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);
}
}

View File

@ -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";
}

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -2,7 +2,7 @@ package me.chyxion.tigon.codegen.service;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import me.chyxion.tigon.codegen.controller.CodeGenController.GenForm; import me.chyxion.tigon.codegen.controller.SiteController.GenForm;
/** /**
* @version 0.0.1 * @version 0.0.1
@ -14,19 +14,17 @@ import me.chyxion.tigon.codegen.controller.CodeGenController.GenForm;
public interface CodeGenService { public interface CodeGenService {
/** /**
* process code generation * process code generation
* @param module
* @param model * @param model
* @param cols * @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 * list generated items
* @return items list * @return items list
*/ */
List<?> list(); List<Map<String, Object>> list();
/** /**
* list tables * list tables
@ -38,5 +36,5 @@ public interface CodeGenService {
* delete items * delete items
* @param items * @param items
*/ */
void delete(List<?> items, boolean dropTable); void delete(List<Map<String, Object>> items, boolean dropTable);
} }

View File

@ -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;
}
}

View File

@ -102,7 +102,7 @@ Ext.define ('Tigon.views.CodeGen', {
}], }],
store: Store.tree({ store: Store.tree({
url: 'codegen/tables', url: 'codegen/tables',
fields: ['id', 'text', 'module', 'model', 'cols', 'table'], fields: ['id', 'text', 'module', 'model', 'cols', 'table', 'tableComment'],
root_text: 'Tables' root_text: 'Tables'
}), }),
listeners: { listeners: {
@ -131,30 +131,6 @@ Ext.define ('Tigon.views.CodeGen', {
labelWidth: 86 labelWidth: 86
}, },
tbar: [{ 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!', text: 'Generate!',
iconCls: 'save', iconCls: 'save',
handler: function(btn) { handler: function(btn) {
@ -207,24 +183,29 @@ Ext.define ('Tigon.views.CodeGen', {
}, },
columns: 3, columns: 3,
items: [{ items: [{
boxLabel: 'Gen controller', boxLabel: 'Gen View',
checked: components.indexOf('view') > -1,
name: 'genView'
}, {
boxLabel: 'Gen Controller',
checked: components.indexOf('controller') > -1, checked: components.indexOf('controller') > -1,
name: 'genController' name: 'genController'
}, { }, {
boxLabel: 'Gen service', boxLabel: 'Gen Service',
checked: components.indexOf('service') > -1,
name: 'genService' name: 'genService'
}, { }, {
boxLabel: 'Gen mapper', boxLabel: 'Gen Mapper',
checked: components.indexOf('mapper') > -1, checked: components.indexOf('mapper') > -1,
name: 'genMapper' name: 'genMapper'
}, { }, {
boxLabel: 'Gen model', boxLabel: 'Gen Model',
checked: components.indexOf('model') > -1, checked: components.indexOf('model') > -1,
name: 'genModel' name: 'genModel'
}, { }, {
boxLabel: 'Gen form', boxLabel: 'Gen Form',
checked: components.indexOf('form') > -1, checked: components.indexOf('form') > -1,
name: 'genView' name: 'genForm'
}] }]
}, { }, {
xtype: 'fieldcontainer', 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', xtype: 'textfield',
name: 'model', name: 'model',
fieldLabel: 'Model name', fieldLabel: 'Model name',
value: 'ModelName',
allowBlank: false allowBlank: false
}, { },
{
xtype: 'textfield',
name: 'tableComment',
fieldLabel: 'Table Comment',
allowBlank: false
},
{
xtype: 'textfield', xtype: 'textfield',
name: 'table', name: 'table',
fieldLabel: 'Table name', fieldLabel: 'Table name',

View 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"
}
]
}

View 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>

View File

@ -7,27 +7,17 @@
<!-- Tool --> <!-- Tool -->
<bean class="me.chyxion.tigon.codegen.service.CodeGenBaseTool" /> <bean class="me.chyxion.tigon.codegen.service.CodeGenBaseTool" />
<!--Services --> <!--Services -->
<bean class="me.chyxion.tigon.codegen.service.support.CodeGenServiceSupport" /> <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 --> <!-- FreeMarker Config -->
<bean class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer" <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:defaultEncoding="utf-8"
p:preferFileSystemAccess="false"> p:preferFileSystemAccess="false">
<property name="freemarkerSettings"> <property name="freemarkerSettings">
<props> <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="output_encoding">utf-8</prop>
<prop key="locale">en_US</prop> <prop key="locale">en_US</prop>
<prop key="date_format">yyyy-MM-dd</prop> <prop key="date_format">yyyy-MM-dd</prop>
@ -50,9 +40,9 @@
<bean class="com.alibaba.druid.pool.DruidDataSource" <bean class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" init-method="init"
destroy-method="close" destroy-method="close"
p:url="jdbc:mysql://${datasource.host}:${datasource.port}/${datasource.database-name}?useUnicode=true&amp;characterEncoding=utf-8&amp;zeroDateTimeBehavior=convertToNull" p:url="${tigon.codegen.datasource.url}"
p:username="${datasource.username}" p:username="${tigon.codegen.datasource.username}"
p:password="${datasource.password}" p:password="${tigon.codegen.datasource.password}"
/> />
</constructor-arg> </constructor-arg>
</bean> </bean>

View File

@ -1,3 +1,3 @@
<#function isSelfCol col> <#function isSelfCol col>
<#return !['id', 'date_created', 'date_updated']?seq_contains(col.col)> <#return !['id', 'date_created', 'date_updated']?seq_contains(col.col)>
</#function> </#function>

View 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)));
}
}

View 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}> {
}

View File

@ -0,0 +1,4 @@
/**
* @author ${author}
* @date ${now}
*/

View 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>
}

View 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>
}

View 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));
}
}

View 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>

View File

@ -1,9 +1,10 @@
package ${pkg}.mapper; package ${mapperPkg};
import ${baseMapperFullName}; import ${baseMapperFullName};
import ${pkg}.model.${ModelName}; import ${modelPkg}.${ModelName};
<#if objDoc?has_content>
${objDoc} ${objDoc}
</#if>
public interface ${ModelName}Mapper extends ${baseMapperName}<${idType}, ${ModelName}> { public interface ${ModelName}Mapper extends ${baseMapperName}<${idType}, ${ModelName}> {
}
}

View File

@ -1,6 +1,6 @@
package ${pkg}.model; package ${modelPkg};
<#import "/codegen/commons.ftl" as CodeGen>
<#import "/codegen/commons.ftl" as CodeGen>
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.experimental.FieldNameConstants; import lombok.experimental.FieldNameConstants;
@ -12,22 +12,23 @@ import ${baseModelFullName};
import ${p}; import ${p};
</#list> </#list>
<#if objDoc?has_content>
${objDoc} ${objDoc}
</#if>
@Getter @Getter
@Setter @Setter
@${tableAnnotationName}("${table}") @${tableAnnotationName}("${table}")
@FieldNameConstants(prefix = "") @FieldNameConstants(prefix = "")
public class ${ModelName} extends ${baseModelName} { public class ${ModelName} <#if baseModelName?has_content>extends ${baseModelName} </#if>{
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
<#-- <#--
// Column Names // Column Names
<#list cols as prop> <#list cols as prop>
public static final String ${prop.col?upper_case} = "${prop.col}"; public static final String ${prop.col?upper_case} = "${prop.col}";
</#list> </#list>
--> -->
<#list cols as prop> <#list cols as prop>
private ${prop.javaType} ${prop.name}; private ${prop.javaType} ${prop.name};
</#list> </#list>
}
}

View File

@ -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 {
}

View 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}> {
}

View File

@ -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
};
}
});

View File

@ -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 + ']'}]);
}
});

View File

@ -0,0 +1,6 @@
import BaseListRoute from '../base-list';
export default BaseListRoute.extend({
perm: 'PERM_VIEW_${permName}_LIST',
breadcrumbs: [{text: '${nameCn}列表'}]
});

View File

@ -0,0 +1,6 @@
import Service from '../service';
export default Service.extend({
modelName: '${ModelName}',
// constraints: { }
});

View File

@ -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}}

View File

@ -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}}

View File

@ -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}}

View File

@ -1,7 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<#include "/commons/extjs-header.ftl" /> <#include "/extjs-header.ftl" />
<script type="text/javascript"> <script type="text/javascript">
/** /**
* @version 1.0 * @version 1.0
@ -25,10 +25,9 @@
}); });
Ext.create('Tigon.views.ThemesBar').show(); Ext.create('Tigon.views.ThemesBar').show();
}); });
var pkg = '${pkg}';
var components = ${components}; var components = ${components};
</script> </script>
<title>Auto Code</title> <title>Tigon Code Gen</title>
</head> </head>
<body> <body>
</body> </body>

View File

@ -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);
}
}

View 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

View 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>

View 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
View File

@ -0,0 +1 @@
# Tigon Common

73
common/pom.xml Normal file
View 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>

View 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;
}

View File

@ -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 {
}

View File

@ -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 {
}

View File

@ -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;
}

View File

@ -0,0 +1 @@
package me.chyxion.tigon;

View 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.");
}
}

View File

@ -2,15 +2,15 @@
<Configuration status="WARN"> <Configuration status="WARN">
<Properties> <Properties>
<Property name="pattern">%-d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%t][%c{1}] %m%n</Property> <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> </Properties>
<Appenders> <Appenders>
<Console name="Console" target="SYSTEM_OUT"> <Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="${pattern}" /> <PatternLayout pattern="${pattern}" />
</Console> </Console>
<RollingFile name="File" <RollingFile name="File"
fileName="${log.dir}/tigon-service-support.log" fileName="${log.dir}/app.log"
filePattern="${log.dir}/tigon-service-support-%d{yyyy-MM-dd}-%i.log"> filePattern="${log.dir}/$${date:yyyy-MM}/app-%d{yyyy-MM-dd}-%i.log">
<PatternLayout pattern="${pattern}" /> <PatternLayout pattern="${pattern}" />
<Policies> <Policies>
<TimeBasedTriggeringPolicy /> <TimeBasedTriggeringPolicy />
@ -29,4 +29,3 @@
</Root> </Root>
</Loggers> </Loggers>
</Configuration> </Configuration>

3
deploy
View File

@ -1,3 +0,0 @@
#!/bin/bash
mvn clean deploy -DskipTests -U -DaltDeploymentRepository=snapshot::default::http://101.231.57.218:8081/nexus/content/repositories/snapshots/

View File

@ -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

View File

@ -0,0 +1 @@
46d94f9b2e77fe81c9774dddb4c96228baf2ac7f

View File

@ -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>

View File

@ -0,0 +1 @@
267b9ac958463fd470940ad908f8a50b8e770138

View 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>

View File

@ -0,0 +1 @@
87791c43904f064234ca9ce207ddafef

View File

@ -0,0 +1 @@
c26a74fe148ac826ac990036e1fb3a5ed5a34a1f

57
extjs/pom.xml vendored Normal file
View 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>

View File

@ -1,6 +1,3 @@
html {
font-family: 'Microsoft YaHei'
}
/* message styles */ /* message styles */
#commons-message-div { #commons-message-div {
position: absolute; position: absolute;

View File

Before

Width:  |  Height:  |  Size: 994 B

After

Width:  |  Height:  |  Size: 994 B

View File

Before

Width:  |  Height:  |  Size: 703 B

After

Width:  |  Height:  |  Size: 703 B

View File

Before

Width:  |  Height:  |  Size: 989 B

After

Width:  |  Height:  |  Size: 989 B

View File

Before

Width:  |  Height:  |  Size: 788 B

After

Width:  |  Height:  |  Size: 788 B

View File

Before

Width:  |  Height:  |  Size: 526 B

After

Width:  |  Height:  |  Size: 526 B

View File

Before

Width:  |  Height:  |  Size: 771 B

After

Width:  |  Height:  |  Size: 771 B

View File

Before

Width:  |  Height:  |  Size: 1016 B

After

Width:  |  Height:  |  Size: 1016 B

View File

Before

Width:  |  Height:  |  Size: 663 B

After

Width:  |  Height:  |  Size: 663 B

View File

Before

Width:  |  Height:  |  Size: 494 B

After

Width:  |  Height:  |  Size: 494 B

View File

Before

Width:  |  Height:  |  Size: 504 B

After

Width:  |  Height:  |  Size: 504 B

View File

Before

Width:  |  Height:  |  Size: 595 B

After

Width:  |  Height:  |  Size: 595 B

View File

@ -9,7 +9,6 @@
Ext.define('Tigon.views.Grid', { Ext.define('Tigon.views.Grid', {
extend:'Ext.grid.Panel', extend:'Ext.grid.Panel',
alias: 'widget.sgrid', alias: 'widget.sgrid',
alternateClassName: ['SpringExt.views.Grid'],
columnLines: true, columnLines: true,
loadMask: true, loadMask: true,
required: '<span style="color:red;font-weight:bold" data-qtip="Required">*</span>', required: '<span style="color:red;font-weight:bold" data-qtip="Required">*</span>',

View File

@ -6,7 +6,6 @@
* Dec 17, 2014 13:34:42 * Dec 17, 2014 13:34:42
*/ */
Ext.define('Tigon.views.ThemesBar', { Ext.define('Tigon.views.ThemesBar', {
alternateClassName: ['SpringExt.views.ThemesBar'],
show: function() { show: function() {
// toolbar // toolbar
setTimeout(function() { setTimeout(function() {

View File

@ -1,49 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?> <?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" 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"> 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> <modelVersion>4.0.0</modelVersion>
<artifactId>tigon-shiro-cache</artifactId>
<name>Tigon Shiro Cache</name>
<packaging>jar</packaging>
<parent> <parent>
<groupId>me.chyxion.tigon</groupId> <groupId>me.chyxion.tigon</groupId>
<artifactId>tigon</artifactId> <artifactId>tigon</artifactId>
<version>0.0.1-SNAPSHOT</version> <version>${revision}</version>
<relativePath>../</relativePath>
</parent> </parent>
<dependencies> <dependencies>
<!--三方依赖-->
<dependency> <dependency>
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId> <artifactId>spring-context</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>javax.validation</groupId>
<artifactId>commons-lang3</artifactId> <artifactId>validation-api</artifactId>
<version>3.1</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.hibernate.validator</groupId> <groupId>org.slf4j</groupId>
<artifactId>hibernate-validator</artifactId> <artifactId>slf4j-api</artifactId>
</dependency> </dependency>
<!-- shiro --> <!--/三方依赖-->
<dependency>
<groupId>org.apache.shiro</groupId> <!--Provided-->
<artifactId>shiro-core</artifactId>
<version>1.3.2</version>
</dependency>
<!-- Test Dependencies -->
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<!--/Provided-->
<!--测试依赖-->
<dependency> <dependency>
<groupId>org.springframework</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
@ -51,5 +50,6 @@
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!--/测试依赖-->
</dependencies> </dependencies>
</project> </project>

View File

@ -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"};
}
}

View File

@ -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.";
}

View 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);
}

View File

@ -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;
}
}

View File

@ -0,0 +1,2 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
me.chyxion.tigon.i18n.config.I18nConfiguration

View File

@ -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);
}
}

View 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 {
}

View File

@ -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());
}
}

View 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

View File

@ -0,0 +1 @@
bp.could.not.be.blank=BP could not be blank

View File

@ -0,0 +1 @@
bp.could.not.be.blank=BP不可以为空

Some files were not shown because too many files have changed in this diff Show More