Compare commits

...

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

1942 changed files with 153779 additions and 11265 deletions

2
.gitignore vendored
View File

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

13
ISSUE_TEMPLATE.zh-CN.md Normal file
View File

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

View File

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

View File

@ -1,37 +0,0 @@
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

@ -1,18 +0,0 @@
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

@ -1,18 +0,0 @@
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

@ -1,17 +0,0 @@
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

@ -1,49 +0,0 @@
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

@ -1,17 +0,0 @@
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

@ -1,16 +0,0 @@
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

@ -1,16 +0,0 @@
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

@ -1,16 +0,0 @@
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

@ -1,16 +0,0 @@
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

@ -1,87 +0,0 @@
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

@ -1,16 +0,0 @@
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

@ -1,32 +0,0 @@
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

@ -1,231 +0,0 @@
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

@ -1,354 +0,0 @@
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

@ -1,100 +0,0 @@
{
"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

@ -1,36 +0,0 @@
<?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

@ -1,114 +0,0 @@
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

@ -1,22 +0,0 @@
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

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

View File

@ -1,24 +0,0 @@
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

@ -1,24 +0,0 @@
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

@ -1,24 +0,0 @@
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

@ -1,15 +0,0 @@
<?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,22 +0,0 @@
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

@ -1,16 +0,0 @@
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

@ -1,11 +0,0 @@
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

@ -1,10 +0,0 @@
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

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

View File

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

View File

@ -1,9 +0,0 @@
{{#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

@ -1,9 +0,0 @@
{{#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

@ -1,73 +0,0 @@
<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,31 +0,0 @@
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

@ -1,6 +0,0 @@
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

@ -1,36 +0,0 @@
<?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

@ -1,6 +0,0 @@
<?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>

View File

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

View File

@ -1,73 +0,0 @@
<?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

@ -1,34 +0,0 @@
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

@ -1,16 +0,0 @@
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

@ -1,16 +0,0 @@
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

@ -1,24 +0,0 @@
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

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

View File

@ -1,18 +0,0 @@
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.");
}
}

3
deploy Executable file
View File

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

4
deploy_oss Executable file
View File

@ -0,0 +1,4 @@
#!/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

@ -1 +0,0 @@
46d94f9b2e77fe81c9774dddb4c96228baf2ac7f

View File

@ -1,13 +0,0 @@
<?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

@ -1 +0,0 @@
267b9ac958463fd470940ad908f8a50b8e770138

View File

@ -1,14 +0,0 @@
<?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

@ -1 +0,0 @@
87791c43904f064234ca9ce207ddafef

View File

@ -1 +0,0 @@
c26a74fe148ac826ac990036e1fb3a5ed5a34a1f

57
extjs/pom.xml vendored
View File

@ -1,57 +0,0 @@
<?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,98 +0,0 @@
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

@ -1,25 +0,0 @@
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

@ -1,84 +0,0 @@
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

@ -1,71 +0,0 @@
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

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

View File

@ -1,37 +0,0 @@
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

@ -1,11 +0,0 @@
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

@ -1,17 +0,0 @@
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

@ -1,12 +0,0 @@
# 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

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

View File

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

View File

@ -1,3 +0,0 @@
javax.validation.constraints.NotEmpty.message=could not be empty
param.could.not.be.blank={0}不可以为空
errmsg.500=Oh, shit!

View File

@ -1,4 +0,0 @@
javax.validation.constraints.NotEmpty.message=不能为空
javax.validation.constraints.NotBlank.message=不可以为空
param.could.not.be.blank={0}不允许为空
errmsg.500=卧槽!

View File

@ -1 +0,0 @@
uc.could.not.be.blank=UC could not be blank

View File

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

View File

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="true" scan="true" scanPeriod="42 seconds">>
<property name="log.dir" value="${LOG_DIR:-.logs}"/>
<property name="log.level" value="${LOG_LEVEL:-DEBUG}"/>
<appender name="Console" class="ch.qos.logback.core.ConsoleAppender">
<withJansi>true</withJansi>
<encoder>
<pattern>%magenta(%d{"yyyy-MM-dd HH:mm:ss,SSS"}) [%thread][%X{traceId}] %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][%X{traceId}] %-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="${log.level}" 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

@ -1,28 +0,0 @@
#!/bin/bash
# get real path of softlink
get_real_path() {
local f="$1"
while [ -h "$f" ]; do
ls=`ls -ld "$f"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
f="$link"
else
f=`dirname "$f"`/"$link"
fi
done
echo "$f"
}
prg_path=$(get_real_path "$0")
echo "Script path [$prg_path]"
# Service Home
pushd $(dirname "$prg_path") > /dev/null
WORK_DIR=$(pwd)
echo "Work dir [$WORK_DIR]"
mvn -T 4C -DskipTests clean flatten:flatten source:jar install
popd > /dev/null

View File

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

View File

@ -1,77 +0,0 @@
<?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">
<artifactId>tigon-kit</artifactId>
<name>Tigon Kit</name>
<description>Tigon Kit</description>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>me.chyxion.tigon</groupId>
<artifactId>tigon</artifactId>
<version>${revision}</version>
</parent>
<dependencies>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<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.mongodb</groupId>
<artifactId>bson</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>me.chyxion.tigon</groupId>
<artifactId>tigon-common</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -1,62 +0,0 @@
package me.chyxion.tigon.kit.bean;
import java.util.Map;
import java.util.List;
import java.util.Collection;
import javax.validation.constraints.NotNull;
import org.springframework.validation.annotation.Validated;
/**
* @author Donghuang
* @date Jun 02, 2021 15:18:17
*/
@Validated
public interface BeanService {
/**
* Object to map
*
* @param object object
* @return map
*/
Map<String, Object> toMap(Object object);
/**
* convert type
*
* @param obj object
* @param type Type-erased type to parameterize
* @param paramClasses Type parameters to apply
* @param <T> type
* @return convert result
*/
<T> T convert(Object obj, @NotNull Class<T> type, Class<?> ... paramClasses);
/**
* convert list type
*
* @param list list
* @param elementType Type-erased type to parameterize
* @param paramClasses Type parameters to apply
* @param <T> type
* @return convert result
*/
<T> List<T> convert(Collection<?> list, @NotNull Class<T> elementType, Class<?> ... paramClasses);
/**
* assign value
*
* @param to to object
* @param from from object
* @return assign result
*/
<T> T assign(T to, Object from);
/**
* copy object
*
* @param from from object
* @return assign result
*/
<T> T copy(T from);
}

View File

@ -1,32 +0,0 @@
package me.chyxion.tigon.kit.config;
import lombok.extern.slf4j.Slf4j;
import me.chyxion.tigon.kit.json.JsonService;
import me.chyxion.tigon.kit.sequence.IdSequence;
import me.chyxion.tigon.kit.json.impl.JacksonImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import me.chyxion.tigon.kit.sequence.impl.IdSequenceImpl;
import org.springframework.beans.factory.annotation.Autowired;
/**
* @author Donghuang
* @date Jul 08, 2021 11:11:32
*/
@Slf4j
public class TigonKitConfiguration {
@Bean
public JsonService jsonService(
@Autowired(required = false)
final ObjectMapper objectMapper) {
return new JacksonImpl(objectMapper != null ?
objectMapper.copy() : new ObjectMapper());
}
@Bean
public IdSequence idSequence() {
return new IdSequenceImpl();
}
}

View File

@ -1,105 +0,0 @@
package me.chyxion.tigon.kit.json;
import java.util.Map;
import java.util.List;
import me.chyxion.tigon.kit.bean.BeanService;
import com.fasterxml.jackson.databind.ObjectMapper;
import me.chyxion.tigon.kit.json.impl.JacksonImpl;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* @author Donghuang
* @date May 22, 2021 16:01:20
*/
public interface JsonService extends BeanService {
/**
* get object mapper
* @return object mapper
*/
ObjectMapper getObjectMapper();
/**
* parse json
*
* @param data json data
* @param type result type
* @param <T> result type
* @return result object
*/
<T> T parse(@NotBlank String data, Class<T> type);
/**
* parse json object
*
* @param data data
* @return map result
*/
Map<String, Object> parseObject(@NotBlank String data);
/**
* parse json array
*
* @param data json data
* @return json array list
*/
List<Map<String, Object>> parseArray(@NotBlank String data);
/**
* parse json array
*
* @param data json data
* @param elementType Type-erased type to parameterize
* @param paramClasses Type parameters to apply
* @param <T> element type
* @return json array list
*/
<T> List<T> parseArray(@NotBlank String data, @NotNull Class<T> elementType, Class<?> ... paramClasses);
/**
* object to json string
*
* @param object object
* @return json string
*/
String toJSONString(Object object);
/**
* object to json string
*
* @param object object
* @param pretty pretty format
* @return json string
*/
String toJSONString(Object object, boolean pretty);
/**
* 检查对象是否为{}或者null
*
* @param object object
* @return true if object is empty
*/
boolean isEmpty(Object object);
/**
* 检查对象是否不为{}或者null
*
* @param object object
* @return true if object is not empty
*/
default boolean isNotEmpty(Object object) {
return !isEmpty(object);
}
/**
* static get JsonService
*
* @return JsonService
*/
static JsonService getInstance() {
return JacksonImpl.getInstance();
}
}

View File

@ -1,21 +0,0 @@
package me.chyxion.tigon.kit.json.annotation;
import java.lang.annotation.*;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import me.chyxion.tigon.kit.json.serializer.FinanceValueSerializer;
/**
* 财务数据JSON序列化格式化保留2位小数
*
* @author Donghuang
* @date Apr 24, 2022 10:09:17
*/
@Documented
@JacksonAnnotationsInside
@Retention(RetentionPolicy.RUNTIME)
@JsonSerialize(using = FinanceValueSerializer.class)
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.TYPE, ElementType.PARAMETER})
public @interface FinanceValue {
}

View File

@ -1,20 +0,0 @@
package me.chyxion.tigon.kit.json.deserializer;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.introspect.AnnotatedClass;
/**
* @author Donghuang
* @date Apr 21, 2022 15:33:32
*/
interface DeserializeModifier {
/**
* modify json deserialized result
* @param parser json parser
* @param classInfo class info
* @param object object
* @return object
*/
Object modify(JsonParser parser, AnnotatedClass classInfo, Object object);
}

View File

@ -1,104 +0,0 @@
package me.chyxion.tigon.kit.json.deserializer;
import lombok.val;
import java.io.IOException;
import lombok.extern.slf4j.Slf4j;
import java.util.stream.StreamSupport;
import me.chyxion.tigon.annotation.Trim;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.core.JsonParser;
import me.chyxion.tigon.annotation.json.EmptyElCleanup;
import me.chyxion.tigon.annotation.json.EmptyObjectToNull;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
import com.fasterxml.jackson.databind.deser.std.DelegatingDeserializer;
/**
* @author Donghuang
* @date Apr 20, 2022 21:12:10
*/
@Slf4j
public class DeserializeModifierDelegatingDeserializer extends DelegatingDeserializer {
private final BeanDescription beanDescription;
private static final Class<?>[] ANNOTATION = new Class<?>[] {
Trim.class,
EmptyObjectToNull.class,
EmptyElCleanup.class,
};
private static final DeserializeModifier[] MODIFIERS = new DeserializeModifier[] {
new TrimDeserializeModifier(),
new EmptyElCleanupDeserializeModifier(),
new EmptyObjectToNullDeserializeModifier()
};
/**
* Factory method to return a Module with this deserializer suitable for insertion into an ObjectMapper
*
* @return a SimpleModule.
*/
public static Module getSimpleModule() {
log.info("Registering EmptyObjectToNullDelegatingDeserializer");
return new SimpleModule().setDeserializerModifier(new BeanDeserializerModifier() {
@Override
public JsonDeserializer<?> modifyDeserializer(final DeserializationConfig config,
final BeanDescription beanDescription,
final JsonDeserializer<?> originalDeserializer) {
val classInfo = beanDescription.getClassInfo();
if (hasAnnotation(classInfo)) {
log.debug("Bean description {} @EmptyObjectToNull found.", classInfo);
return new DeserializeModifierDelegatingDeserializer(originalDeserializer, beanDescription);
}
if (StreamSupport.stream(classInfo.fields().spliterator(), true).
anyMatch(field -> hasAnnotation(field))) {
log.debug("Bean description field {} @EmptyObjectToNull found.", classInfo);
return new DeserializeModifierDelegatingDeserializer(originalDeserializer, beanDescription);
}
return originalDeserializer;
}
});
}
private DeserializeModifierDelegatingDeserializer(final JsonDeserializer<?> delegate, final BeanDescription beanDescription) {
super(delegate);
this.beanDescription = beanDescription;
}
/**
* {@inheritDoc}
*/
@Override
protected JsonDeserializer<?> newDelegatingInstance(final JsonDeserializer<?> newDelegatee) {
return new DeserializeModifierDelegatingDeserializer(newDelegatee, beanDescription);
}
/**
* {@inheritDoc}
*/
@Override
public Object deserialize(final JsonParser p, final DeserializationContext ctxt) throws IOException {
val obj = super.deserialize(p, ctxt);
val classInfo = beanDescription.getClassInfo();
for (val modifier : MODIFIERS) {
modifier.modify(p, classInfo, obj);
}
return obj;
}
static boolean hasAnnotation(final Annotated annotated) {
for (val annotation : ANNOTATION) {
if (annotated.hasAnnotation(annotation)) {
return true;
}
}
return false;
}
}

View File

@ -1,108 +0,0 @@
package me.chyxion.tigon.kit.json.deserializer;
import lombok.val;
import java.util.List;
import java.util.ArrayList;
import java.util.Collection;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import lombok.extern.slf4j.Slf4j;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.core.JsonParser;
import me.chyxion.tigon.annotation.json.EmptyElCleanup;
import org.springframework.util.ReflectionUtils;
import com.fasterxml.jackson.databind.introspect.AnnotatedClass;
/**
* @author Donghuang
* @date Apr 20, 2022 21:12:10
*/
@Slf4j
class EmptyElCleanupDeserializeModifier implements DeserializeModifier {
/**
* {@inheritDoc}
*/
@Override
public Object modify(final JsonParser parser, final AnnotatedClass classInfo, final Object obj) {
if (classInfo.hasAnnotation(EmptyElCleanup.class)) {
log.debug("@EmptyElCleanup found on class [{}].", classInfo.getAnnotated());
classInfo.fields().forEach(field ->
emptyElementCleanup((ObjectMapper) parser.getCodec(), obj, field.getAnnotated()));
return obj;
}
classInfo.fields().forEach(field -> {
if (field.hasAnnotation(EmptyElCleanup.class)) {
log.debug("@EmptyElCleanup found on field [{}] of class [{}].", field.getName(), classInfo.getAnnotated());
emptyElementCleanup((ObjectMapper) parser.getCodec(), obj, field.getAnnotated());
}
});
return obj;
}
void emptyElementCleanup(final ObjectMapper objectMapper,
final Object object,
final Field field) {
ReflectionUtils.makeAccessible(field);
val value = ReflectionUtils.getField(field, object);
if (value != null) {
if (value instanceof Collection) {
val it = ((Collection) value).iterator();
while (it.hasNext()) {
val el = it.next();
if (isNullOrEmpty(objectMapper, el)) {
it.remove();
}
}
return;
}
val fieldType = field.getType();
if (fieldType.isArray()) {
val length = Array.getLength(value);
if (length > 0) {
val newList = new ArrayList<>(length);
for (int i = 0; i < length; ++i) {
val el = Array.get(value, i);
if (!isNullOrEmpty(objectMapper, el)) {
newList.add(el);
}
}
ReflectionUtils.setField(field, object,
listToArray(newList, fieldType.getComponentType()));
}
}
}
}
boolean isNullOrEmpty(final ObjectMapper objectMapper, final Object object) {
if (object == null) {
return true;
}
val jsonNode = objectMapper.valueToTree(object);
if (jsonNode.isValueNode()) {
return false;
}
return jsonNode.isEmpty();
}
Object listToArray(final List<?> list, final Class<?> elType) {
val array = Array.newInstance(elType, list.size());
int i = 0;
for (val e : list) {
Array.set(array, i++, e);
}
return array;
}
}

View File

@ -1,61 +0,0 @@
package me.chyxion.tigon.kit.json.deserializer;
import lombok.val;
import java.lang.reflect.Field;
import lombok.extern.slf4j.Slf4j;
import com.fasterxml.jackson.core.JsonParser;
import me.chyxion.tigon.annotation.json.EmptyObjectToNull;
import org.springframework.util.ReflectionUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.introspect.AnnotatedClass;
/**
* @author Donghuang
* @date Apr 20, 2022 21:12:10
*/
@Slf4j
class EmptyObjectToNullDeserializeModifier implements DeserializeModifier {
/**
* {@inheritDoc}
*/
@Override
public Object modify(final JsonParser parser, final AnnotatedClass classInfo, final Object obj) {
if (classInfo.hasAnnotation(EmptyObjectToNull.class)) {
log.debug("@EmptyObjectToNull found on class [{}].", classInfo.getAnnotated());
classInfo.fields().forEach(field ->
setEmptyFieldNull((ObjectMapper) parser.getCodec(), obj, field.getAnnotated()));
return obj;
}
classInfo.fields().forEach(field -> {
if (field.hasAnnotation(EmptyObjectToNull.class)) {
log.debug("@EmptyObjectToNull found on field [{}] of class [{}].", field.getName(), classInfo.getAnnotated());
setEmptyFieldNull((ObjectMapper) parser.getCodec(), obj, field.getAnnotated());
}
});
return obj;
}
void setEmptyFieldNull(final ObjectMapper objectMapper, final Object object, final Field field) {
ReflectionUtils.makeAccessible(field);
val value = ReflectionUtils.getField(field, object);
if (value != null) {
if (isEmpty(objectMapper, value)) {
ReflectionUtils.setField(field, object, null);
}
}
}
boolean isEmpty(final ObjectMapper objectMapper, final Object object) {
val jsonNode = objectMapper.valueToTree(object);
if (jsonNode.isValueNode()) {
return false;
}
return jsonNode.isEmpty();
}
}

View File

@ -1,93 +0,0 @@
package me.chyxion.tigon.kit.json.deserializer;
import lombok.val;
import java.io.IOException;
import lombok.extern.slf4j.Slf4j;
import java.util.stream.StreamSupport;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.core.JsonParser;
import me.chyxion.tigon.annotation.json.PostDeserialize;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
import com.fasterxml.jackson.databind.deser.std.DelegatingDeserializer;
/**
* @author Donghuang
* @date Apr 20, 2022 21:12:10
*/
@Slf4j
public class PostDeserializeDelegatingDeserializer extends DelegatingDeserializer {
private final BeanDescription beanDescription;
/**
* Factory method to return a Module with this deserializer suitable for insertion into an ObjectMapper
*
* @return a SimpleModule.
*/
public static Module getSimpleModule() {
log.info("Registering JacksonPostHookDeserializer");
return new SimpleModule().setDeserializerModifier(new BeanDeserializerModifier() {
@Override
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config,
BeanDescription beanDescription,
JsonDeserializer<?> originalDeserializer) {
val classInfo = beanDescription.getClassInfo();
if (StreamSupport.stream(classInfo.memberMethods().spliterator(), true).
anyMatch(m -> m.hasAnnotation(PostDeserialize.class))) {
log.debug("BeanDescription {} ", classInfo);
return new PostDeserializeDelegatingDeserializer(originalDeserializer, beanDescription);
}
else {
return originalDeserializer;
}
}
});
}
/**
* {@inheritDoc}
*/
private PostDeserializeDelegatingDeserializer(JsonDeserializer<?> delegate, BeanDescription beanDescription) {
super(delegate);
this.beanDescription = beanDescription;
}
/**
* {@inheritDoc}
*/
@Override
protected JsonDeserializer<?> newDelegatingInstance(final JsonDeserializer<?> newDelegatee) {
return new PostDeserializeDelegatingDeserializer(newDelegatee, beanDescription);
}
/**
* {@inheritDoc}
*/
@Override
public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
val obj = super.deserialize(p, ctxt);
beanDescription.getClassInfo().memberMethods().forEach(method -> {
if (method.hasAnnotation(PostDeserialize.class)) {
log.debug("Invoking method {} on {} ", method.getName(), beanDescription.getBeanClass());
try {
if (method.getAnnotation(PostDeserialize.class).forceAccess()) {
log.debug("Modifying access for {}", method);
method.fixAccess(true);
}
method.callOn(obj);
}
catch (Exception e) {
log.error("Caught exception calling method", e);
throw new RuntimeException("Failed to call @JsonPostDeserialize annotated method in class " +
beanDescription.getClassInfo().getName(), e);
}
}
});
return obj;
}
}

View File

@ -1,76 +0,0 @@
package me.chyxion.tigon.kit.json.deserializer;
import lombok.val;
import java.lang.reflect.Field;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import me.chyxion.tigon.annotation.Trim;
import com.fasterxml.jackson.core.JsonParser;
import org.springframework.util.ReflectionUtils;
import com.fasterxml.jackson.databind.introspect.AnnotatedClass;
/**
* @author Donghuang
* @date Apr 20, 2022 21:12:10
*/
@Slf4j
class TrimDeserializeModifier implements DeserializeModifier {
/**
* {@inheritDoc}
*/
@Override
public Object modify(final JsonParser p, final AnnotatedClass classInfo, final Object obj) {
if (classInfo.hasAnnotation(Trim.class)) {
log.debug("@Trim found on class [{}].", classInfo.getAnnotated());
classInfo.fields().forEach(field ->
trimFieldValue(obj,
field.getAnnotated(),
classInfo.getAnnotation(Trim.class).blankAsNull()));
return obj;
}
classInfo.fields().forEach(field -> {
if (field.hasAnnotation(Trim.class)) {
log.debug("@Trim found on field [{}] of class [{}].", field.getName(), classInfo.getAnnotated());
trimFieldValue(obj,
field.getAnnotated(),
field.getAnnotation(Trim.class).blankAsNull());
}
});
return obj;
}
void trimFieldValue(final Object object, final Field field, final boolean blankAsNull) {
ReflectionUtils.makeAccessible(field);
val value = ReflectionUtils.getField(field, object);
if (value == null) {
return;
}
if (value instanceof String) {
val newVal = blankAsNull ?
StringUtils.trimToNull((String) value) :
StringUtils.trim((String) value);
if (newVal == null) {
ReflectionUtils.setField(field, object, null);
return;
}
if (!newVal.equals(value)) {
ReflectionUtils.setField(field, object, newVal);
}
return;
}
val fieldType = field.getType();
if (field.isAnnotationPresent(Trim.class) &&
!fieldType.isAnnotationPresent(Trim.class)) {
ReflectionUtils.doWithFields(fieldType, subField -> trimFieldValue(value, subField, blankAsNull));
}
}
}

View File

@ -1,191 +0,0 @@
package me.chyxion.tigon.kit.json.impl;
import lombok.val;
import java.util.*;
import lombok.Getter;
import lombok.SneakyThrows;
import me.chyxion.tigon.kit.json.JsonService;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.annotation.JsonInclude;
import org.springframework.beans.factory.InitializingBean;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.DeserializationFeature;
import me.chyxion.tigon.kit.json.deserializer.PostDeserializeDelegatingDeserializer;
import me.chyxion.tigon.kit.json.deserializer.DeserializeModifierDelegatingDeserializer;
/**
* @author Donghuang
* @date Sep 26, 2019 19:21:14
*/
public class JacksonImpl implements JsonService, InitializingBean {
@Getter
private final ObjectMapper objectMapper;
@Getter
private static JsonService instance;
public JacksonImpl(final ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
this.objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true);
// Enable assign NULL
this.objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
this.objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
this.objectMapper.registerModule(DeserializeModifierDelegatingDeserializer.getSimpleModule());
this.objectMapper.registerModule(PostDeserializeDelegatingDeserializer.getSimpleModule());
}
/**
* {@inheritDoc}
*/
@Override
@SneakyThrows
public <T> T parse(final String data, final Class<T> type) {
return objectMapper.readValue(data, type);
}
/**
* {@inheritDoc}
*/
@Override
@SneakyThrows
@SuppressWarnings("unchecked")
public Map<String, Object> parseObject(final String data) {
val typeFactory = objectMapper.getTypeFactory();
val mapJavaType = typeFactory.constructParametricType(Map.class, String.class, Object.class);
return objectMapper.readValue(data, mapJavaType);
}
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings({"unchecked"})
public List<Map<String, Object>> parseArray(final String data) {
return (List) parseArray(data, Map.class, String.class, Object.class);
}
/**
* {@inheritDoc}
*/
@Override
@SneakyThrows
public <T> List<T> parseArray(final String data, final Class<T> elementType, final Class<?> ... paramClasses) {
val typeFactory = objectMapper.getTypeFactory();
if (paramClasses != null && paramClasses.length > 0) {
val elJavaType = typeFactory.constructParametricType(elementType, paramClasses);
return objectMapper.readValue(data, typeFactory.constructCollectionType(List.class, elJavaType));
}
return objectMapper.readValue(data, typeFactory.constructCollectionType(List.class, elementType));
}
/**
* {@inheritDoc}
*/
@Override
@SneakyThrows
public String toJSONString(final Object object) {
return objectMapper.writeValueAsString(object);
}
/**
* {@inheritDoc}
*/
@Override
@SneakyThrows
public String toJSONString(final Object object, final boolean pretty) {
return pretty ? objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(object)
: toJSONString(object);
}
/**
* {@inheritDoc}
*/
@Override
public boolean isEmpty(final Object object) {
if (object == null) {
return true;
}
val jsonNode = objectMapper.valueToTree(object);
if (jsonNode.isValueNode()) {
return false;
}
return jsonNode.isEmpty();
}
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings("unchecked")
public Map<String, Object> toMap(final Object object) {
return objectMapper.convertValue(object, Map.class);
}
/**
* {@inheritDoc}
*/
@Override
public <T> T convert(final Object obj, final Class<T> type, final Class<?> ... paramClasses) {
if (obj == null) {
return null;
}
if (paramClasses != null && paramClasses.length > 0) {
val javaType = objectMapper.getTypeFactory().constructParametricType(type, paramClasses);
return objectMapper.convertValue(obj, javaType);
}
return objectMapper.convertValue(obj, type);
}
/**
* {@inheritDoc}
*/
@Override
public <T> List<T> convert(final Collection<?> list, final Class<T> elementType, final Class<?> ... paramClasses) {
if (list == null || list.isEmpty()) {
return Collections.emptyList();
}
if (paramClasses != null && paramClasses.length > 0) {
val typeFactory = objectMapper.getTypeFactory();
val elJavaType = typeFactory.constructParametricType(elementType, paramClasses);
return objectMapper.convertValue(list, typeFactory.constructCollectionType(List.class, elJavaType));
}
return (List<T>) convert((Object) list, List.class, elementType);
}
/**
* {@inheritDoc}
*/
@Override
public <T> T copy(T from) {
return (T) objectMapper.convertValue(from, from.getClass());
}
/**
* {@inheritDoc}
*/
@Override
@SneakyThrows
public Object assign(final Object to, final Object from) {
val jsonNode = objectMapper.valueToTree(from);
return objectMapper.readerForUpdating(to).readValue(jsonNode);
}
/**
* {@inheritDoc}
*/
@Override
public void afterPropertiesSet() {
instance = this;
}
}

View File

@ -1,32 +0,0 @@
package me.chyxion.tigon.kit.json.serializer;
import java.io.IOException;
import java.text.DecimalFormat;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
/**
* @author Donghuang
* @date Apr 24, 2022 09:58:02
*/
public class FinanceValueSerializer extends JsonSerializer<Number> {
/**
* {@inheritDoc}
*/
@Override
public void serialize(final Number value,
final JsonGenerator gen,
final SerializerProvider serializers) throws IOException {
if (value == null) {
//write the word 'null' if there's no value available
gen.writeNull();
return;
}
// "###,###,##0.00";
gen.writeString(new DecimalFormat("0.00").format(value));
}
}

View File

@ -1,30 +0,0 @@
package me.chyxion.tigon.kit.sequence;
/**
* @author Donghuang
* @date Jul 08, 2021 10:55:39
*/
public interface IdSequence {
/**
* get sequence
*
* @return id
*/
String get();
/**
* get uuid
*
* @return uuid
*/
String uuid();
/**
* get uuid
*
* @param lowerCase lower case
* @return uuid
*/
String uuid(boolean lowerCase);
}

View File

@ -1,40 +0,0 @@
package me.chyxion.tigon.kit.sequence.impl;
import lombok.val;
import java.util.UUID;
import org.bson.types.ObjectId;
import me.chyxion.tigon.kit.sequence.IdSequence;
/**
* @author Donghuang
* @date Jul 08, 2021 10:55:45
*/
public class IdSequenceImpl implements IdSequence {
/**
* {@inheritDoc}
*/
@Override
public String get() {
return ObjectId.get().toHexString();
}
/**
* {@inheritDoc}
*/
@Override
public String uuid() {
return uuid(false);
}
/**
* {@inheritDoc}
*/
@Override
public String uuid(final boolean lowerCase) {
val uuid = UUID.randomUUID();
val strUuid = Long.toHexString(uuid.getMostSignificantBits())
+ Long.toHexString(uuid.getLeastSignificantBits());
return lowerCase ? strUuid : strUuid.toUpperCase();
}
}

View File

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

View File

@ -1,201 +0,0 @@
package me.chyxion.tigon.kit;
import me.chyxion.tigon.kit.json.annotation.FinanceValue;
import lombok.*;
import me.chyxion.tigon.kit.model.UserCtrlrReq;
import org.junit.Test;
import java.math.BigDecimal;
import java.util.*;
import org.junit.runner.RunWith;
import lombok.extern.slf4j.Slf4j;
import me.chyxion.tigon.kit.json.JsonService;
import me.chyxion.tigon.kit.model.UserServReq;
import org.springframework.beans.factory.annotation.Value;
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, 2021 16:37:08
*/
@Slf4j
@SpringBootTest(classes = TestDriver.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class JsonServiceTest {
@Autowired
private JsonService jsonService;
@Test
public void testConvert() {
val userCtrlrReq = new UserCtrlrReq();
userCtrlrReq.setName("donghuang");
userCtrlrReq.setGender("male");
userCtrlrReq.setDeleted(true);
log.info("Result1 [{}].", jsonService.toJSONString(userCtrlrReq));
val convert = jsonService.convert(userCtrlrReq, UserServReq.class);
log.info("Result [{}].", convert);
}
@Test
public void testGetInstance() {
val userCtrlrReq = new UserCtrlrReq();
userCtrlrReq.setName("donghuang");
userCtrlrReq.setGender("male");
userCtrlrReq.setDeleted(true);
val jsonService = JsonService.getInstance();
log.info("Result1 [{}].", jsonService.toJSONString(userCtrlrReq));
val convert = jsonService.convert(userCtrlrReq, UserServReq.class);
log.info("Result [{}].", convert);
}
@Test
public void testCopy() {
val userCtrlrReq = new UserCtrlrReq();
userCtrlrReq.setName("donghuang");
userCtrlrReq.setGender("male");
userCtrlrReq.setDeleted(true);
val convert = jsonService.copy(userCtrlrReq);
log.info("Copy result [{}].", convert);
}
@Test
public void testAssign() {
val userCtrlrReq = new UserCtrlrReq();
userCtrlrReq.setName("donghuang");
// userCtrlrReq.setGender("male");
userCtrlrReq.setDeleted(false);
val user1 = new UserServReq();
user1.setName("donghuang");
user1.setGender("male");
user1.setIsDeleted(true);
log.info("Result1 [{}].", user1);
log.info("Result2 [{}].", jsonService.assign(user1, userCtrlrReq));
}
@Test
public void testConvert1() {
val convert = jsonService.convert("1", Integer.class);
log.info("Result [{}].", convert);
}
@Test
public void testConvert2() {
val convert = jsonService.convert("1", Integer.class);
log.info("Result [{}].", convert);
log.info("Result [{}].", jsonService.convert("MALE", Gender.class));
}
public enum Gender {
MALE,
FEMALE
}
@Value("${value1:${value2:#{null}}}")
private String value;
@Test
public void testValue() {
log.info("Value: {}", value);
}
@Test
public void testIsEmpty() {
log.info("Value: {}", jsonService.isEmpty(new Object()));
log.info("Value: {}", jsonService.isEmpty(new HashMap<>()));
log.info("Value: {}", jsonService.isEmpty(new HashMap<String, String>(){{put("foo", "bar");}}));
log.info("Value: {}", jsonService.isEmpty(new ArrayList<>()));
log.info("Value: {}", jsonService.isEmpty("123"));
log.info("Value: {}", jsonService.isEmpty(123));
}
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
static class Model1 {
private Date date;
}
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
static class Model2 {
private Long date;
}
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
static class Model3 {
private List<String> data;
private List<Model1> modelList;
}
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
static class Model4 {
private List<Long> data;
private List<Model2> modelList;
}
@Test
public void testConvert3() {
log.info("Model2: {}", jsonService.convert(new Model1(new Date()), Model2.class));
log.info("Model1: {}", jsonService.convert(new Model2(System.currentTimeMillis()), Model1.class));
List<Integer> intList1 = jsonService.convert(Arrays.asList("1", "2", "3"), Integer.class);
log.info("List: {}", intList1);
List<List> intList2 = jsonService.convert(
Arrays.asList(Arrays.asList("1"), Arrays.asList("2"), Arrays.asList("3")),
List.class, Integer.class);
log.info("List: {}", intList2);
val model4 = jsonService.convert(
new Model3(Arrays.asList("1"), Arrays.asList(new Model1(new Date()))), Model4.class);
log.info("Model4: {}", model4);
}
@Getter
@Setter
@ToString
static class FinanceValueModel {
@FinanceValue
private BigDecimal value1;
@FinanceValue
private Long value2;
@FinanceValue
private Double value3;
}
@Test
public void testFinanceValue() {
val model = new FinanceValueModel();
model.setValue1(new BigDecimal(1000));
model.setValue2(1000L);
model.setValue3(99.99);
log.info("FinanceValue: {}", jsonService.toJSONString(model));
}
@Test
public void testParseArray() {
val data = jsonService.parseArray("[{\"key\":\"value\"}]");
log.info("Parse array: {}", data);
val array2 = jsonService.parseArray("[1, 2, 3]", Long.class);
log.info("Parse array: {}", array2);
}
}

View File

@ -1,14 +0,0 @@
package me.chyxion.tigon.kit;
import org.springframework.context.annotation.ImportResource;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author Donghuang
* @date May 13, 2021 16:38:34
*/
@SpringBootApplication
@ImportResource("classpath*:spring/spring-*.xml")
public class TestDriver {
}

View File

@ -1,19 +0,0 @@
package me.chyxion.tigon.kit.model;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serializable;
/**
* @author Donghuang
* @date May 13, 2021 16:45:28
*/
@Setter
@Getter
@ToString
public class UserCtrlrReq implements Serializable {
private String name;
private String gender;
private Boolean deleted;
}

View File

@ -1,21 +0,0 @@
package me.chyxion.tigon.kit.model;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* @author Donghuang
* @date May 13, 2021 16:46:07
*/
@Setter
@Getter
@ToString
public class UserServReq implements Serializable {
private String name;
private String gender;
@JsonProperty("deleted")
private Boolean isDeleted;
}

View File

@ -1,6 +0,0 @@
spring:
jackson:
default-property-inclusion: ALWAYS
# value2: value2
# value1: value1

View File

@ -1,16 +0,0 @@
<?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">
<bean class="com.fasterxml.jackson.databind.ObjectMapper">
<property name="dateFormat">
<bean class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy-MM-dd'T'HH:mm:ssXXX" />
</bean>
</property>
<property name="timeZone" value="GMT+8" />
<property name="serializationInclusion" value="NON_NULL" />
</bean>
</beans>

View File

@ -1 +0,0 @@
#tigon-base-model

View File

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

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