郑根木 2 лет назад
Родитель
Сommit
540c8da753
100 измененных файлов: 6034 добавлений и 0 удалений
  1. +27
    -0
      smtweb-framework/.gitignore
  2. +34
    -0
      smtweb-framework/pom.xml
  3. +132
    -0
      smtweb-framework/sw-framework-auth/pom.xml
  4. +66
    -0
      smtweb-framework/sw-framework-auth/src/main/java/cc/smtweb/framework/auth/captcha/ImageMaker.java
  5. +21
    -0
      smtweb-framework/sw-framework-auth/src/main/java/cc/smtweb/framework/auth/spring/AuthAutoConfiguration.java
  6. +60
    -0
      smtweb-framework/sw-framework-auth/src/main/java/cc/smtweb/framework/auth/spring/cache/RealmCache.java
  7. +11
    -0
      smtweb-framework/sw-framework-auth/src/main/java/cc/smtweb/framework/auth/web/entity/LoginAckVO.java
  8. +12
    -0
      smtweb-framework/sw-framework-auth/src/main/java/cc/smtweb/framework/auth/web/entity/LoginVO.java
  9. +29
    -0
      smtweb-framework/sw-framework-auth/src/main/java/cc/smtweb/framework/auth/web/entity/MenuPO.java
  10. +28
    -0
      smtweb-framework/sw-framework-auth/src/main/java/cc/smtweb/framework/auth/web/entity/UserPO.java
  11. +89
    -0
      smtweb-framework/sw-framework-auth/src/main/java/cc/smtweb/framework/auth/web/service/AuthService.java
  12. +2
    -0
      smtweb-framework/sw-framework-auth/src/main/resources/META-INF/spring.factories
  13. Двоичные данные
      smtweb-framework/sw-framework-auth/src/main/resources/auth/courier_new_34_19.png
  14. +64
    -0
      smtweb-framework/sw-framework-auth/src/main/resources/config/application-dev.yaml
  15. +35
    -0
      smtweb-framework/sw-framework-auth/src/main/resources/config/application-prod.yaml
  16. +3
    -0
      smtweb-framework/sw-framework-auth/src/main/resources/config/application.yaml
  17. +2
    -0
      smtweb-framework/sw-framework-auth/target/classes/META-INF/spring.factories
  18. Двоичные данные
      smtweb-framework/sw-framework-auth/target/classes/auth/courier_new_34_19.png
  19. +64
    -0
      smtweb-framework/sw-framework-auth/target/classes/config/application-dev.yaml
  20. +35
    -0
      smtweb-framework/sw-framework-auth/target/classes/config/application-prod.yaml
  21. +3
    -0
      smtweb-framework/sw-framework-auth/target/classes/config/application.yaml
  22. +5
    -0
      smtweb-framework/sw-framework-auth/target/maven-archiver/pom.properties
  23. +0
    -0
      smtweb-framework/sw-framework-auth/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
  24. +9
    -0
      smtweb-framework/sw-framework-auth/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
  25. +8
    -0
      smtweb-framework/sw-framework-core/doc/TODO.mk
  26. +202
    -0
      smtweb-framework/sw-framework-core/pom.xml
  27. +11
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/CoreApplication.java
  28. +33
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/CoreApplicationStartedListener.java
  29. +33
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/CoreAutoConfiguration.java
  30. +117
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/R.java
  31. +53
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/SwException.java
  32. +9
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/SwIpAddr.java
  33. +93
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/SwMap.java
  34. +21
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwAction.java
  35. +16
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwAttr.java
  36. +22
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwBean.java
  37. +15
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwBody.java
  38. +26
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwCache.java
  39. +38
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwColumn.java
  40. +21
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwColumnForeign.java
  41. +20
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwConstruct.java
  42. +20
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwDestroy.java
  43. +16
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwHeaderParam.java
  44. +18
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwParam.java
  45. +16
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwPathParam.java
  46. +21
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwPerm.java
  47. +30
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwScheduling.java
  48. +16
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwService.java
  49. +17
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwTable.java
  50. +493
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/cache/AbstractCache.java
  51. +109
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/cache/CacheManager.java
  52. +24
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/cache/ISwCache.java
  53. +271
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/DbEngine.java
  54. +281
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/EntityDao.java
  55. +64
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/cache/EntityCache.java
  56. +45
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/cache/ModelDatabaseCache.java
  57. +90
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/cache/ModelTableCache.java
  58. +41
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/config/DbEngineConfiguration.java
  59. +43
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/config/DesignConfig.java
  60. +23
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/config/YamlPropertyLoaderFactory.java
  61. +383
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/dao/AbstractEntityDao.java
  62. +66
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/dao/EntityColumn.java
  63. +26
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/dao/EntityColumnForeign.java
  64. +98
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/impl/BaseBean.java
  65. +362
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/impl/DefaultDatabaseInfoImpl.java
  66. +62
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/impl/DefaultEntity.java
  67. +37
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/impl/IDatabaseInfo.java
  68. +134
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/jdbc/IdGenerator.java
  69. +411
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/jdbc/JdbcEngine.java
  70. +56
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/jdbc/JdbcTrans.java
  71. +39
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/jdbc/MapPropertyRowMapper.java
  72. +59
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/jdbc/SwMapPropertyRowMapper.java
  73. +129
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/sqlbuilder/AbstractSelectSqlBuilder.java
  74. +20
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/sqlbuilder/AbstractUpdateSqlBuilder.java
  75. +33
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/sqlbuilder/DeleteSqlBuilder.java
  76. +20
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/sqlbuilder/DirectSelectSqlBuilder.java
  77. +38
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/sqlbuilder/InsertSqlBuilder.java
  78. +98
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/sqlbuilder/SelectSqlBuilder.java
  79. +84
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/sqlbuilder/SqlBuilder.java
  80. +14
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/sqlbuilder/SqlFieldValue.java
  81. +15
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/sqlbuilder/SqlJoinField.java
  82. +39
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/sqlbuilder/SqlJoinTable.java
  83. +13
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/sqlbuilder/SqlWhereValue.java
  84. +55
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/sqlbuilder/UpdateSqlBuilder.java
  85. +9
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/vo/KeyValueVO.java
  86. +30
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/vo/ModelCache.java
  87. +27
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/vo/ModelCatalog.java
  88. +31
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/vo/ModelDatabase.java
  89. +38
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/vo/ModelField.java
  90. +20
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/vo/ModelIndex.java
  91. +29
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/vo/ModelProject.java
  92. +142
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/vo/ModelTable.java
  93. +33
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/vo/def/DataType.java
  94. +22
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/vo/def/FieldType.java
  95. +41
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/exception/BindBeanException.java
  96. +34
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/exception/BindParamException.java
  97. +29
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/exception/BizException.java
  98. +13
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/exception/CacheException.java
  99. +33
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/exception/DbException.java
  100. +105
    -0
      smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/exception/ExceptionMessage.java

+ 27
- 0
smtweb-framework/.gitignore Просмотреть файл

@@ -0,0 +1,27 @@
# ---> Java
# Compiled class file
*.class

# Log file
*.log

# BlueJ files
*.ctxt

# Mobile Tools for Java (J2ME)
.mtj.tmp/

# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*

.idea
*.iml

+ 34
- 0
smtweb-framework/pom.xml Просмотреть файл

@@ -0,0 +1,34 @@
<?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>cc.smtweb</groupId>
<artifactId>smtweb-framework</artifactId>
<packaging>pom</packaging>
<version>2.2.0-SNAPSHOT</version>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<skipTests>true</skipTests>
</properties>

<modules>
<module>sw-framework-core</module>
<module>sw-framework-auth</module>
<module>sw-framework-file</module>
<module>sw-framework-web</module>
<module>../smtweb-system/sw-system-bpm</module>
</modules>
</project>

+ 132
- 0
smtweb-framework/sw-framework-auth/pom.xml Просмотреть файл

@@ -0,0 +1,132 @@
<?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">
<groupId>cc.smtweb</groupId>
<artifactId>sw-framework-auth</artifactId>
<version>2.2.0-SNAPSHOT</version>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

<modelVersion>4.0.0</modelVersion>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>cc.smtweb</groupId>
<artifactId>sw-framework-core</artifactId>
<version>2.2.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.platform/junit-platform-launcher -->
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>1.6.2</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.6.2</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.6.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>5.6.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.6.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.7.RELEASE</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-all -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.10.19</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<!-- <finalName>user</finalName>-->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<phase>verify</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 用于生成jar包的plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<configuration>
<excludes>
<exclude>config/*.yaml</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
<!-- <resources>-->
<!-- <resource>-->
<!-- <filtering>true</filtering>-->
<!-- <directory>src/main/resources</directory>-->
<!-- <excludes>-->
<!-- <exclude>config/*.yaml</exclude>-->
<!-- </excludes>-->
<!-- </resource>-->
<!-- </resources>-->
</build>

<distributionManagement>
<repository>
<id>nexus-releases</id>
<name>Nexus Release Repository</name>
<url>http://47.92.149.153:7000/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>nexus-snapshots</id>
<name>Nexus Snapshot Repository</name>
<url>http://47.92.149.153:7000/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
</project>

+ 66
- 0
smtweb-framework/sw-framework-auth/src/main/java/cc/smtweb/framework/auth/captcha/ImageMaker.java Просмотреть файл

@@ -0,0 +1,66 @@
package cc.smtweb.framework.auth.captcha;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

public class ImageMaker {
private static final String signChar = "()+-*/=";

// 生成png图片
public void make() throws IOException {
int fontHeight = 34;
int width = 19;
int height = fontHeight * (62 + signChar.length());
// 创建BufferedImage对象

BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// ---------- 增加下面的代码使得背景透明 -----------------
Graphics2D g2d = image.createGraphics();
image = g2d.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
g2d.dispose();

// 画图
g2d = image.createGraphics();
g2d.setColor(new Color(0,0,0));

// 画图
Font font = new Font("Courier New", Font.BOLD, 30);
g2d.setFont(font);

System.out.println(font.getMaxCharBounds(g2d.getFontRenderContext()));

int top = 25;
for (int i = 0; i < 10; i++) {
g2d.drawString(i + "", 0, top);
top += fontHeight;
}

for (int i = 0; i < 26; i++) {
g2d.drawString((char)(i + (int)'a') + "", 0, top);
top += fontHeight;
}

for (int i = 0; i < 26; i++) {
g2d.drawString((char)(i + (int)'A') + "", 0, top);
top += fontHeight;
}

for (int i = 0; i < signChar.length(); i++) {
g2d.drawString(signChar.charAt(i) + "", 0, top);
top += fontHeight;
}

// 释放对象
g2d.dispose();

// 保存文件
ImageIO.write(image, "png", new File("/var/tmp/test.png"));
}

public static void main(String[] args) throws IOException {
new ImageMaker().make();
}
}

+ 21
- 0
smtweb-framework/sw-framework-auth/src/main/java/cc/smtweb/framework/auth/spring/AuthAutoConfiguration.java Просмотреть файл

@@ -0,0 +1,21 @@
package cc.smtweb.framework.auth.spring;

import cc.smtweb.framework.core.mvc.config.ControllerConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
* @author kevin
*/
@Configuration
@ComponentScan
public class AuthAutoConfiguration {

/** 配置自定义service扫描路径 {module}/{service}/{method} */
@Bean
public ControllerConfig authControllerConfig() {
return new ControllerConfig("auth", "cc.smtweb.framework.auth.web");
}

}

+ 60
- 0
smtweb-framework/sw-framework-auth/src/main/java/cc/smtweb/framework/auth/spring/cache/RealmCache.java Просмотреть файл

@@ -0,0 +1,60 @@
package cc.smtweb.framework.auth.spring.cache;

import cc.smtweb.framework.core.annotation.SwCache;
import cc.smtweb.framework.core.cache.AbstractCache;
import cc.smtweb.framework.core.db.jdbc.JdbcEngine;
import cc.smtweb.framework.core.mvc.realm.service.PermChecker;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;

/**
* 用户权限集合缓存器,@todo 权限部分需要重写
* @author xkliu
*/
@Log4j2
@SwCache(ident = "PERM_CHECKER", title = "用户权限")
public class RealmCache extends AbstractCache<PermChecker> {
@Autowired
private JdbcEngine dbEngine;

private static final long ENTERPRISE_ADMIN_ID = 1;

@Override
protected String getId(PermChecker bean) {
return "1";//todo
}

@Override
protected List<PermChecker> loadAll() {
return null;
}


protected PermChecker load(Long key) {
// admin
if (key == ENTERPRISE_ADMIN_ID) {
return PermChecker.build(new HashSet<>(Collections.singletonList("*")));
}

// TODO: 合并相同角色,自己到缓存里面获取
Set<String> permissions = new HashSet<>();

List<String> permList = dbEngine.queryStringList("SELECT menu_api_perm FROM sys_menu WHERE menu_id in\n" +
"(SELECT rmp_menu_id from sys_role_menu_privilege WHERE rmp_role_id in\n" +
"(SELECT role_id FROM sw_user.sys_role WHERE role_id IN" +
"(SELECT ur_role_id FROM sw_user.sys_user_role WHERE ur_user_id=?)))", key);

if (permList != null) {
for (String perm: permList) {
for (String item: perm.split(",")) {
permissions.add(item.trim());
}
}
}

return PermChecker.build(permissions);
}

}

+ 11
- 0
smtweb-framework/sw-framework-auth/src/main/java/cc/smtweb/framework/auth/web/entity/LoginAckVO.java Просмотреть файл

@@ -0,0 +1,11 @@
package cc.smtweb.framework.auth.web.entity;

import lombok.Data;

@Data
public class LoginAckVO {
private Long userId;
private String userAvatar;
private String userName;
private String token;
}

+ 12
- 0
smtweb-framework/sw-framework-auth/src/main/java/cc/smtweb/framework/auth/web/entity/LoginVO.java Просмотреть файл

@@ -0,0 +1,12 @@
package cc.smtweb.framework.auth.web.entity;

import lombok.Data;

import java.io.Serializable;

@Data
public class LoginVO implements Serializable {
private String username;

private String password;
}

+ 29
- 0
smtweb-framework/sw-framework-auth/src/main/java/cc/smtweb/framework/auth/web/entity/MenuPO.java Просмотреть файл

@@ -0,0 +1,29 @@
package cc.smtweb.framework.auth.web.entity;

import cc.smtweb.framework.core.annotation.SwColumn;
import cc.smtweb.framework.core.annotation.SwTable;
import lombok.Data;

import java.io.Serializable;

@Data
@SwTable("sw_user.sys_menu")
public class MenuPO implements Serializable {
@SwColumn(type={SwColumn.Type.ID})
private Long menuId;

@SwColumn(type={SwColumn.Type.PARENT_ID})
private Long menuParentId;

private String menuName;

private Long menuSiteId;


private String menuPermiss;

private String menuUrl;

@SwColumn(type={SwColumn.Type.ORDER})
private Integer menuSort;
}

+ 28
- 0
smtweb-framework/sw-framework-auth/src/main/java/cc/smtweb/framework/auth/web/entity/UserPO.java Просмотреть файл

@@ -0,0 +1,28 @@
package cc.smtweb.framework.auth.web.entity;

import cc.smtweb.framework.core.annotation.SwColumn;
import cc.smtweb.framework.core.annotation.SwTable;
import lombok.Data;

import java.io.Serializable;

@Data
@SwTable("sw_user.sys_user")
public class UserPO implements Serializable {
@SwColumn(type={SwColumn.Type.ID})
private Long userId;

private String userNickCode;

private String userNickName;

private Long userCreatePartyId;

private String userPwd;

private String userPhone;

private Integer userStatus;

private String userAvatar;
}

+ 89
- 0
smtweb-framework/sw-framework-auth/src/main/java/cc/smtweb/framework/auth/web/service/AuthService.java Просмотреть файл

@@ -0,0 +1,89 @@
package cc.smtweb.framework.auth.web.service;

import cc.smtweb.framework.auth.web.entity.LoginAckVO;
import cc.smtweb.framework.auth.web.entity.LoginVO;
import cc.smtweb.framework.auth.web.entity.UserPO;
import cc.smtweb.framework.core.*;
import cc.smtweb.framework.core.annotation.*;
import cc.smtweb.framework.core.session.SessionManager;
import cc.smtweb.framework.core.session.UserSession;
import cc.smtweb.framework.core.db.DbEngine;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;

@Slf4j
@SwService
public class AuthService {
@SwParam
private DbEngine dbEngine;

@SwParam
private SessionManager sessionManager;

@SwPerm(SwPerm.NONE)
public R login(@SwBody LoginVO loginPO) {
if (StringUtils.isBlank(loginPO.getUsername())) {
return R.error("账号不能为空");
}

if (StringUtils.isBlank(loginPO.getPassword())) {
return R.error("密码不能为空");
}

UserPO user = dbEngine.queryEntity("select user_id,user_nick_name,user_nick_code,user_pwd,user_create_party_id from sw_user.sys_user where user_nick_code=?", UserPO.class, loginPO.getUsername());

if (user == null) {
return R.error("账号不存在");
}

// digest:md5("goodpj" + user.userId + password)
String pass = DigestUtils.md5Hex("goodpj" + user.getUserId() + loginPO.getPassword());

if (!pass.equals(user.getUserPwd())) {
return R.error("账号或者密码出错");
}

UserSession userSession = new UserSession();
userSession.setUserId(user.getUserId());
userSession.setSiteId(user.getUserCreatePartyId());

String token = sessionManager.login(userSession);

LoginAckVO data = new LoginAckVO();

data.setUserId(user.getUserId());
data.setUserName(user.getUserNickName());
data.setUserAvatar(user.getUserAvatar());
data.setToken(token);

return R.success(data);
}

@SwPerm()
public R ping(@SwParam("msg") String msg) {
return R.success(msg);
}

@SwPerm("user:edit")
public R config(@SwParam("username") String username) {
return R.success("config: " + username);
}


/**
* 退出登录
* @return code
*/
public R logout() {
sessionManager.logout();
return R.success();
}

// defaultRun 命名的函数是默认函数
// @SwPerm(SwPerm.NONE)
// public R defaultRun(@SwPathParam String path) {
// return R.success(path).put("dao", authDao);
// }

}

+ 2
- 0
smtweb-framework/sw-framework-auth/src/main/resources/META-INF/spring.factories Просмотреть файл

@@ -0,0 +1,2 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cc.smtweb.framework.auth.spring.AuthAutoConfiguration

Двоичные данные
smtweb-framework/sw-framework-auth/src/main/resources/auth/courier_new_34_19.png Просмотреть файл

До После
Ширина: 19  |  Высота: 2346  |  Размер: 2.4 KiB

+ 64
- 0
smtweb-framework/sw-framework-auth/src/main/resources/config/application-dev.yaml Просмотреть файл

@@ -0,0 +1,64 @@
smtweb:
machine-id: 1
file:
local-path: /data/files/
host: http://127.0.0.1
url: http://127.0.0.1:8888/files/
db:
default:
rule:
prefix: _smt_
replace: smt_
server:
port: 8888
servlet:
context-path: /
feign:
hystrix:
enabled: false
logging:
level:
root: INFO
cc.smtweb: DEBUG
spring:
# 设置服务名
application:
name: smtweb_user
main:
allow-bean-definition-overriding: true
banner-mode: console
mvc:
static-path-pattern: /static/**
redis:
host: 127.0.0.1
port: 6379
password:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/smt_user?useUnicode=true&characterEncoding=utf-8&useTimezone=true&serverTimezone=CTT&allowMultiQueries=true
username: root
password: 1681860
# 连接池配置
hikari:
pool-name: HikariPool
minimum-idle: 10
maximum-pool-size: 100
connection-timeout: 60000
idle-timeout: 600000
max-lifetime: 1800000
servlet:
multipart:
max-file-size: 104857600000
max-request-size: 10485760000000
profiles:
include: role
cache:
type: caffeine
cache-names:
- core
caffeine:
spec: maximumSize=1024,expireAfterWrite=2h





+ 35
- 0
smtweb-framework/sw-framework-auth/src/main/resources/config/application-prod.yaml Просмотреть файл

@@ -0,0 +1,35 @@
sme:
machine-id: 1
file-local-path: /data/files/smart/
file-host: http://auth.smtweb.cc
file-url: ${sme.file-host}:${server.port}${server.servlet.context-path}/${sme.file-local-path}
server:
port: 10001
servlet:
context-path: /
logging:
level:
smtweb: DEBUG

spring:
main:
allow-bean-definition-overriding: true
mvc:
static-path-pattern: /static/**
redis:
host: 127.0.0.1
port: 6379
datasource:
user:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/smt_user?useUnicode=true&characterEncoding=utf-8&useTimezone=true&serverTimezone=CTT&allowMultiQueries=true
username: smt
password: smt_123456

servlet:
multipart:
max-file-size: 104857600000
max-request-size: 10485760000000




+ 3
- 0
smtweb-framework/sw-framework-auth/src/main/resources/config/application.yaml Просмотреть файл

@@ -0,0 +1,3 @@
spring:
profiles:
active: dev

+ 2
- 0
smtweb-framework/sw-framework-auth/target/classes/META-INF/spring.factories Просмотреть файл

@@ -0,0 +1,2 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cc.smtweb.framework.auth.spring.AuthAutoConfiguration

Двоичные данные
smtweb-framework/sw-framework-auth/target/classes/auth/courier_new_34_19.png Просмотреть файл

До После
Ширина: 19  |  Высота: 2346  |  Размер: 2.4 KiB

+ 64
- 0
smtweb-framework/sw-framework-auth/target/classes/config/application-dev.yaml Просмотреть файл

@@ -0,0 +1,64 @@
smtweb:
machine-id: 1
file:
local-path: /data/files/
host: http://127.0.0.1
url: http://127.0.0.1:8888/files/
db:
default:
rule:
prefix: _smt_
replace: smt_
server:
port: 8888
servlet:
context-path: /
feign:
hystrix:
enabled: false
logging:
level:
root: INFO
cc.smtweb: DEBUG
spring:
# 设置服务名
application:
name: smtweb_user
main:
allow-bean-definition-overriding: true
banner-mode: console
mvc:
static-path-pattern: /static/**
redis:
host: 127.0.0.1
port: 6379
password:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/smt_user?useUnicode=true&characterEncoding=utf-8&useTimezone=true&serverTimezone=CTT&allowMultiQueries=true
username: root
password: 1681860
# 连接池配置
hikari:
pool-name: HikariPool
minimum-idle: 10
maximum-pool-size: 100
connection-timeout: 60000
idle-timeout: 600000
max-lifetime: 1800000
servlet:
multipart:
max-file-size: 104857600000
max-request-size: 10485760000000
profiles:
include: role
cache:
type: caffeine
cache-names:
- core
caffeine:
spec: maximumSize=1024,expireAfterWrite=2h





+ 35
- 0
smtweb-framework/sw-framework-auth/target/classes/config/application-prod.yaml Просмотреть файл

@@ -0,0 +1,35 @@
sme:
machine-id: 1
file-local-path: /data/files/smart/
file-host: http://auth.smtweb.cc
file-url: ${sme.file-host}:${server.port}${server.servlet.context-path}/${sme.file-local-path}
server:
port: 10001
servlet:
context-path: /
logging:
level:
smtweb: DEBUG

spring:
main:
allow-bean-definition-overriding: true
mvc:
static-path-pattern: /static/**
redis:
host: 127.0.0.1
port: 6379
datasource:
user:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/smt_user?useUnicode=true&characterEncoding=utf-8&useTimezone=true&serverTimezone=CTT&allowMultiQueries=true
username: smt
password: smt_123456

servlet:
multipart:
max-file-size: 104857600000
max-request-size: 10485760000000




+ 3
- 0
smtweb-framework/sw-framework-auth/target/classes/config/application.yaml Просмотреть файл

@@ -0,0 +1,3 @@
spring:
profiles:
active: dev

+ 5
- 0
smtweb-framework/sw-framework-auth/target/maven-archiver/pom.properties Просмотреть файл

@@ -0,0 +1,5 @@
#Generated by Apache Maven
#Tue Nov 02 19:04:59 CST 2021
version=2.1.0-SNAPSHOT
groupId=cc.smtweb
artifactId=sw-framework-auth

+ 0
- 0
smtweb-framework/sw-framework-auth/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst Просмотреть файл


+ 9
- 0
smtweb-framework/sw-framework-auth/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst Просмотреть файл

@@ -0,0 +1,9 @@
E:\jujia\git\6.0\sw\smtweb-framework\sw-framework-auth\src\main\java\cc\smtweb\framework\auth\web\entity\LoginAckVO.java
E:\jujia\git\6.0\sw\smtweb-framework\sw-framework-auth\src\main\java\cc\smtweb\framework\auth\web\entity\UserPO.java
E:\jujia\git\6.0\sw\smtweb-framework\sw-framework-auth\src\main\java\cc\smtweb\framework\auth\spring\cache\RealmCache.java
E:\jujia\git\6.0\sw\smtweb-framework\sw-framework-auth\src\main\java\cc\smtweb\framework\auth\AuthApplication.java
E:\jujia\git\6.0\sw\smtweb-framework\sw-framework-auth\src\main\java\cc\smtweb\framework\auth\web\entity\MenuPO.java
E:\jujia\git\6.0\sw\smtweb-framework\sw-framework-auth\src\main\java\cc\smtweb\framework\auth\web\entity\LoginVO.java
E:\jujia\git\6.0\sw\smtweb-framework\sw-framework-auth\src\main\java\cc\smtweb\framework\auth\captcha\ImageMaker.java
E:\jujia\git\6.0\sw\smtweb-framework\sw-framework-auth\src\main\java\cc\smtweb\framework\auth\spring\AuthAutoConfiguration.java
E:\jujia\git\6.0\sw\smtweb-framework\sw-framework-auth\src\main\java\cc\smtweb\framework\auth\web\service\AuthService.java

+ 8
- 0
smtweb-framework/sw-framework-core/doc/TODO.mk Просмотреть файл

@@ -0,0 +1,8 @@
20210710

1. 定时器手动触发 (done)
2. 优化BeanReadUtils的TableName预先进行转换
2. updateEntity支持悲观锁,并能抛出异常
3. 缓存支持自定义 key
4. 序列号生成器
5. redis配置database(0~15) (done)

+ 202
- 0
smtweb-framework/sw-framework-core/pom.xml Просмотреть файл

@@ -0,0 +1,202 @@
<?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">
<groupId>cc.smtweb</groupId>
<artifactId>sw-framework-core</artifactId>
<version>2.2.0-SNAPSHOT</version>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

<modelVersion>4.0.0</modelVersion>

<properties>
<!-- <maven.build.timestamp.format>MMddHH</maven.build.timestamp.format>-->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<skipTests>true</skipTests>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<!-- 引入jdbc 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!--janino,经过测试,强项是动态脚本,作为表达式引擎,性能比不上jexl,暂舍弃
<dependency>
<groupId>org.codehaus.janino</groupId>
<artifactId>janino</artifactId>
<version>3.0.11</version>
</dependency>-->
<!-- Redis Lettuce -->
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>6.1.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.11.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>

<!-- 将作为Redis对象序列化器 -->
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>kryo</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-jexl3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-jexl3</artifactId>
<version>3.2.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.tika/tika-core -->
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-core</artifactId>
<version>2.1.0</version>
</dependency>
<!-- 本地缓存 -->
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
<!-- jdbc驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
<scope>compile</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.platform/junit-platform-launcher -->
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>1.6.2</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.6.2</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.6.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>5.6.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.6.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<phase>verify</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 用于生成jar包的plugin -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<excludes>
<exclude>config/*.yaml</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
<!-- <resources>-->
<!-- <resources>-->
<!-- <resource>-->
<!-- <filtering>true</filtering>-->
<!-- <directory>src/main/resources</directory>-->
<!-- <excludes>-->
<!-- <exclude>config/*.yaml</exclude>-->
<!-- </excludes>-->
<!-- </resource>-->
<!-- </resources>-->
</build>

<distributionManagement>
<repository>
<id>nexus-releases</id>
<name>Nexus Release Repository</name>
<url>http://47.92.149.153:7000/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>nexus-snapshots</id>
<name>Nexus Snapshot Repository</name>
<url>http://47.92.149.153:7000/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
</project>

+ 11
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/CoreApplication.java Просмотреть файл

@@ -0,0 +1,11 @@
package cc.smtweb.framework.core;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class CoreApplication {
public static void main(String[] args) {
SpringApplication.run(CoreApplication.class, args);
}
}

+ 33
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/CoreApplicationStartedListener.java Просмотреть файл

@@ -0,0 +1,33 @@
package cc.smtweb.framework.core;

import cc.smtweb.framework.core.cache.CacheManager;
import cc.smtweb.framework.core.mvc.controller.scan.ApplicationScanner;
import cc.smtweb.framework.core.systask.TaskStartEvent;
import cc.smtweb.framework.core.systask.WebStartedEvent;
import lombok.SneakyThrows;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;

/**
* 执行接口扫描任务
*/
@Component
public class CoreApplicationStartedListener implements ApplicationListener<ApplicationStartedEvent> {
@SneakyThrows
@Override
public void onApplicationEvent(ApplicationStartedEvent event) {
System.out.println("onApplicationEvent=============");
ConfigurableApplicationContext applicationContext = event.getApplicationContext();

applicationContext.publishEvent(new TaskStartEvent());
//包扫描
ApplicationScanner.scan(applicationContext);
//初始化缓存
CacheManager.getIntance().init();

// 通知 controller 正式使用
applicationContext.publishEvent(new WebStartedEvent());
}
}

+ 33
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/CoreAutoConfiguration.java Просмотреть файл

@@ -0,0 +1,33 @@
package cc.smtweb.framework.core;

import cc.smtweb.framework.core.db.jdbc.IdGenerator;
import cc.smtweb.framework.core.mvc.config.ControllerConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;

/**
* @author kevin
*/
@Configuration
@ComponentScan
@EnableScheduling
public class CoreAutoConfiguration {
/**
* ID生成器的分步式机器码(1-1023)
*/
@Value("${smtweb.machine-id}")
private int machineId;

@Bean
public IdGenerator idGenerator() {
return new IdGenerator(machineId);
}

@Bean
public ControllerConfig coreControllerConfig() {
return new ControllerConfig("core", "cc.smtweb.framework.core");
}
}

+ 117
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/R.java Просмотреть файл

@@ -0,0 +1,117 @@
package cc.smtweb.framework.core;

import cc.smtweb.framework.core.exception.ExceptionMessage;

import java.util.Date;

/**
* 〈返回结果集〉
*
* @author kevin
* @since 1.0.0
*/
public class R extends SwMap {
protected R() {
this(0);
}

protected R(int code) {
put("now", new Date());
put("code", code);
}

public static R success() {
return new R();
}

public static R success(Object data) {
return new R().put("data", data);
}

public static R success(String name, Object data) {
return new R().put(name, data);
}

public static R error() {
return error(ExceptionMessage.INNER_ERROR.getMsg());
}

public static R error(String msg) {
R r = new R(ExceptionMessage.INNER_ERROR.getCode());
r.put("msg", msg);
return r;
}

public static R error(int code, String msg) {
R r = new R(code);
r.put("msg", msg);
return r;
}

public static R errorf(String format, Object...args) {
R r = new R(ExceptionMessage.INNER_ERROR.getCode());
r.put("msg", String.format(format, args));
return r;
}

// public static R error(ExceptionMessage cm) {
// R r = new R(cm.getCode());
// r.put("msg", cm.getMsg());
// return r;
// }

// public static R error(ExceptionMessage cm, Throwable ex) {
// R r = new R(cm.getCode());
// r.put("msg", cm.getMsg());
// r.put("exception", ex.getMessage());
// return r;
// }

public static R error(String msg, Throwable ex) {
R r = new R(ExceptionMessage.INNER_ERROR.getCode());
r.put("msg", msg);
r.put("exception", ex.getMessage());
return r;
}

public static R error(ExceptionMessage cm, String msg) {
R r = new R(cm.getCode());
r.put("msg", msg);
return r;
}

@Override
public R put(String key, Object value) {
super.put(key, value);
return this;
}

public R putNotNull(String key, Object value) {
if (value != null) {
super.put(key, value);
}

return this;
}

public void setMessage(ExceptionMessage cm) {
this.put("code", cm.getCode());
this.put("msg", cm.getMsg());
}

public void setData(Object data) {
this.put("data", data);
}

public int readCode() {
return this.readInt("code");
}

public String readMsg() {
return this.readString("msg");
}

public boolean readSuccess() {
return this.readInt("code", -1) == 0;
}
}

+ 53
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/SwException.java Просмотреть файл

@@ -0,0 +1,53 @@
package cc.smtweb.framework.core;

import cc.smtweb.framework.core.exception.ExceptionMessage;

/**
* 〈全局异常〉
*
* @author kevin
* @since 1.0.0
*/
public class SwException extends RuntimeException {

private static final long serialVersionUID = 8096609992852791423L;

// private ExceptionMessage cm;

public SwException() {
}

public SwException(String msg) {
super(msg);
}

public SwException(int code, String msg) {
super(msg);
}

public SwException(String msg, Throwable e) {
super(msg, e);
}

public SwException(Throwable e) {
super(e.getMessage(), e);
}

public SwException(ExceptionMessage cm) {
super(cm.getMsg());
}

public SwException(ExceptionMessage cm, Throwable e) {
super(cm.getMsg(), e);
}

public SwException(ExceptionMessage cm, String msg) {
super(msg);
}


// public ExceptionMessage getCm() {
// return cm;
// }

}

+ 9
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/SwIpAddr.java Просмотреть файл

@@ -0,0 +1,9 @@
package cc.smtweb.framework.core;

import lombok.Data;

@Data
public class SwIpAddr {
private String ip;
private int port;
}

+ 93
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/SwMap.java Просмотреть файл

@@ -0,0 +1,93 @@
package cc.smtweb.framework.core;

import cc.smtweb.framework.core.util.MapUtil;

import java.util.HashMap;
import java.util.Set;

/**
* 通用map对象,用于无具体类型的传值
* @author kevin
*/
public class SwMap extends HashMap<String, Object> {
public SwMap() {}

public SwMap(int initialCapacity) {
super(initialCapacity);
}

public String readString(String name) {
return MapUtil.readString(this, name, null);
}

public String readString(String name, String defaultValue) {
return MapUtil.readString(this, name, defaultValue);
}

public Long readLong(String name) {
return MapUtil.readLong(this, name, null);
}

public Long readLong(String name, Long defaultValue) {
return MapUtil.readLong(this, name, defaultValue);
}

public Long[] readLongArray(String name) {
return MapUtil.readLongArray(this, name, null);
}

public Long[] readLongArray(String name, Long[] defaultValue) {
return MapUtil.readLongArray(this, name, defaultValue);
}

public Set<Long> readLongSet(String name) {
return MapUtil.readLongSet(this, name);
}

public Integer readInt(String name) {
return MapUtil.readInt(this, name, null);
}

public Integer readInt(String name, Integer defaultValue) {
return MapUtil.readInt(this, name, defaultValue);
}

public Float readFloat(String name) {
return MapUtil.readFloat(this, name, null);
}

public Float readFloat(String name, Float defaultValue) {
return MapUtil.readFloat(this, name, defaultValue);
}

public Double readDouble(String name) {
return MapUtil.readDouble(this, name, null);
}

public Double readDouble(String name, Double defaultValue) {
return MapUtil.readDouble(this, name, defaultValue);
}

public Boolean readBool(String name) {
return MapUtil.readBool(this, name, null);
}

public Boolean readBool(String name, Boolean defaultValue) {
return MapUtil.readBool(this, name, defaultValue);
}

@Override
public SwMap put(String name, Object value) {
if (value != null) {
super.put(name, value);
} else {
super.remove(name);
}

return this;
}

public static SwMap of(String name, Object value) {
return new SwMap().put(name, value);
}
}

+ 21
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwAction.java Просмотреть файл

@@ -0,0 +1,21 @@
package cc.smtweb.framework.core.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* 配置在@SwService中的函数,对应API请求,默认公用函数不用配置拦截器的函数,
* 也可以作为拦截实现的基类
* @author kevin
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface SwAction {
/**
* 重写API请求地址,不配置使用: 服务类地址 + “/” + 函数名
* @return API请求地址
*/
String value() default "";
}

+ 16
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwAttr.java Просмотреть файл

@@ -0,0 +1,16 @@
package cc.smtweb.framework.core.annotation;

import java.lang.annotation.*;

/**
* 参数注解,request定制的上下文内容,定制使用
* @author kevin
*
*/

@Target( { ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SwAttr {
String value() default "";
}

+ 22
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwBean.java Просмотреть файл

@@ -0,0 +1,22 @@
package cc.smtweb.framework.core.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* 被该注释修饰的类提供服务,如Dao,Service等
* @author kevin
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface SwBean {
String value() default "";

/**
* 是否强行生成对象,不检查单例
* @return 是否强行生成对象
*/
boolean alwaysCreate() default false;
}

+ 15
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwBody.java Просмотреть файл

@@ -0,0 +1,15 @@
package cc.smtweb.framework.core.annotation;

import java.lang.annotation.*;

/**
* 参数注解,当编译器无法找到参数名称时,需要用该注解标明参数名称,当然你也可以用该参数标注参数别名与表单域字段名同意
* @author kevin
*
*/
@Target( { ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SwBody {
String value() default "";
}

+ 26
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwCache.java Просмотреть файл

@@ -0,0 +1,26 @@
package cc.smtweb.framework.core.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* 被该注释修饰的类提供缓存服务
*
* @author kevin
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface SwCache {
//唯一标识
String ident();
//标题,展示用
String title();
//依赖的缓存ident,多个用英文逗号分隔
String depends() default "";
//是否懒加载
boolean lazy() default false;
//失效时间,单位分钟
long timeout() default 0;
}

+ 38
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwColumn.java Просмотреть файл

@@ -0,0 +1,38 @@
package cc.smtweb.framework.core.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* 被该注释修饰的方法对应了字段名和类型
* @author kevin
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface SwColumn {
String value() default "";

/** 字段作用,前端用RefType表示 */
Type[] type() default {};

public static enum Type {
// 主键
ID,
// 上级ID,树结构需要
PARENT_ID,
// 排序字段,树结构需要
ORDER,
// 编码字段
CODE,
// 名词字段
NAME,
// 主表ID,MapToOne
MASTER_ID,
// 创建时间
CREATE_TIME,
// 更新时间
LAST_TIME,
}
}

+ 21
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwColumnForeign.java Просмотреть файл

@@ -0,0 +1,21 @@
package cc.smtweb.framework.core.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* 被该注释修饰的方法对应了外键表名和字段名,名称可选
* @author kevin
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface SwColumnForeign {
// 外键表名
String table() default "";
// ID字段名
String id() default "";
// 唯一名称字段名
String code() default "";
}

+ 20
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwConstruct.java Просмотреть файл

@@ -0,0 +1,20 @@
package cc.smtweb.framework.core.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* 通过对@SwService/@SwBean类中的函数注解,服务启动时会调用一次被注解的函数
* @author kevin
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface SwConstruct {
/**
* 销毁顺序,值越小越先创建
* @return 销毁顺序值
*/
int order() default 0;
}

+ 20
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwDestroy.java Просмотреть файл

@@ -0,0 +1,20 @@
package cc.smtweb.framework.core.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* 通过对@SwService/@SwBean类中的函数注解,服务停止时会调用一次被注解的函数
* @author kevin
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface SwDestroy {
/**
* 销毁顺序,值越大越先销毁
* @return 销毁顺序值
*/
int order() default 0;
}

+ 16
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwHeaderParam.java Просмотреть файл

@@ -0,0 +1,16 @@
package cc.smtweb.framework.core.annotation;

import java.lang.annotation.*;


/**
* 路径注解
* @author kevin
*
*/
@Target( { ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SwHeaderParam {
String value() default "";
}

+ 18
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwParam.java Просмотреть файл

@@ -0,0 +1,18 @@
package cc.smtweb.framework.core.annotation;

import java.lang.annotation.*;


/**
* 参数注解,当编译器无法找到参数名称时,需要用该注解标明参数名称,当然你也可以用该参数标注参数别名与表单域字段名同意
* @author kevin
*
*/
@Target( { ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SwParam {
String value() default "";
/** 注入类型,有多个类实现/子类时使用 */
Class<?> type() default Object.class;
}

+ 16
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwPathParam.java Просмотреть файл

@@ -0,0 +1,16 @@
package cc.smtweb.framework.core.annotation;

import java.lang.annotation.*;


/**
* 路径注解
* @author kevin
*
*/
@Target( { ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SwPathParam {
// String value() default "";
}

+ 21
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwPerm.java Просмотреть файл

@@ -0,0 +1,21 @@
package cc.smtweb.framework.core.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* 被该注释修饰的方法都会经过切面拦截校验权限,默认是需要已登录权限
* @author kevin
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface SwPerm {
/** 无权限控制的值,在函数上注解@SwPerm(SwPerm.NONE) */
static final String NONE = "*";
static final String SESSION = "";

/** 权限定义值 */
String value() default SESSION;
}

+ 30
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwScheduling.java Просмотреть файл

@@ -0,0 +1,30 @@
package cc.smtweb.framework.core.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* 通过对@SwService/@SwBean类中的函数注解,定时任务方法注解
*
* @author xkliu
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(value={ElementType.METHOD})
public @interface SwScheduling {
/**
* 时间触发条件,如果值是单数字就是用秒定时,否则就是采用linux/unux crondtab 样式
*/
String value();

/**
* 定时任务分组条件, 有值时同一分组不允许并发执行
*/
String group() default "";

/**
* 是否支持多服务同时运行
*/
boolean multiServer() default false;
}

+ 16
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwService.java Просмотреть файл

@@ -0,0 +1,16 @@
package cc.smtweb.framework.core.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* 被该注释修饰的类提供控制器服务
* @author kevin
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface SwService {
String value() default "";
}

+ 17
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/annotation/SwTable.java Просмотреть файл

@@ -0,0 +1,17 @@
package cc.smtweb.framework.core.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* 被该注释修饰的类对应了数据库表名(库+表的形式,如 sw_user.sys_user)
* @author kevin
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface SwTable {
/** 库名+表名 */
String value() default "";
}

+ 493
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/cache/AbstractCache.java Просмотреть файл

@@ -0,0 +1,493 @@
package cc.smtweb.framework.core.cache;

import cc.smtweb.framework.core.annotation.SwCache;
import cc.smtweb.framework.core.annotation.SwParam;
import cc.smtweb.framework.core.cache.ISwCache;
import cc.smtweb.framework.core.redis.RedisBroadcastEvent;
import cc.smtweb.framework.core.redis.RedisManager;
import cc.smtweb.framework.core.util.CommUtil;
import cc.smtweb.framework.core.util.kryo.KryoTool;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.github.benmanes.caffeine.cache.RemovalCause;
import com.github.benmanes.caffeine.cache.Scheduler;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.Serializable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
* 封装caffeine的抽象Cache类,实现内存缓存,并支持用redis广播进行数据缓存同步
*
* @param <> 缓存的值类
* @author zhenggm
*/
@Slf4j
public abstract class AbstractCache<T extends Serializable> implements ISwCache<String, T> {
protected final static int LS_NONE = 0;
protected final static int LS_LOADING = 1;
protected final static int LS_LOADED = 2;

private final static String split_char = "-";
//唯一标识
protected String ident;
//展示名称
protected String title;
//是否懒加载,懒加载时,将不从库loadall
protected boolean lazy;
//依赖
protected String[] depends;

//数据加载状态
private short loadStatu = LS_NONE;
private Class<T> pTypeClass = null;


private LoadingCache<String, T> cache;
private Map<String, T> cacheOrg = new ConcurrentHashMap<>();
//本地缓存对象,按List缓存,减轻redis压力
protected Map<String, Set<T>> mapListLocal = new ConcurrentHashMap<>();
//本地按其他键值缓存的对象
protected Map<String, Map<String, T>> mapMapLocal = new ConcurrentHashMap<>();

/*注册要按list缓存的信息,key=list的类别,按什么字段来缓存。IGetBeanKey为根据bean获取此bean的key
如资金科目明细项,需按资金科目缓存List。key=sc,value=class_id
*/
protected Map<String, IGetBeanKey<T>> mapListReg = new HashMap<>();
protected Map<String, IGetBeanKey<T>> mapMapReg = new HashMap<>();

public AbstractCache() {
pTypeClass = CommUtil.getParameterizedType(getClass());
}

//注册
protected void install(ScheduledExecutorService executorService) {
SwCache swCache = this.getClass().getAnnotation(SwCache.class);
if (swCache != null) {
ident = swCache.ident();
title = swCache.title();
lazy = swCache.lazy();
depends = StringUtils.split(swCache.depends(), ",");
}
final @NonNull Caffeine<Object, Object> kvCaffeine = Caffeine.newBuilder()
.scheduler(Scheduler.forScheduledExecutorService(executorService));
if (swCache.timeout() > 0) {
kvCaffeine.expireAfterAccess(swCache.timeout(), TimeUnit.MINUTES);
}
this.cache = kvCaffeine.build(this::onLoad);
}

public boolean isNotInited() {
return loadStatu == LS_NONE;
}

/**
* 注册标识,用于同步数据事件通知
*/
public String getIdent() {
return ident;
}

public String getTitle() {
return title;
}

public boolean isLazy() {
return lazy;
}

public String[] getDepends() {
return depends;
}

/**
* 初始化
* redis有,则从redis下载;
* 否则,非lazy,从数据库加载,并更新redis
*/
protected void init() {
if (RedisManager.getInstance().exists(getIdent())) {
//从缓存服务器下载到本地
syncCache();
} else if (!lazy) {
refresh();
}
}

/**
* 注册其他key的List缓存,如tree的children
*
* @param key
* @param iGetBeanKey
*/
protected void regList(String key, IGetBeanKey<T> iGetBeanKey) {
mapListReg.put(key, iGetBeanKey);
}

/**
* 注册其他key的Map缓存,如按code缓存
*
* @param key
* @param iGetBeanKey
*/

protected void regMap(String key, IGetBeanKey<T> iGetBeanKey) {
mapMapReg.put(key, iGetBeanKey);
}

//获取bean的id
protected abstract String getId(T bean);

/**
* 从redis获取全部缓存
* redis上只保留<id,Bean>,拉下来后,自行组织其他格式缓存
*/
public void syncCache() {
loadStatu = LS_LOADING;

cache.invalidateAll();
cacheOrg.clear();
mapListLocal.clear();
mapMapLocal.clear();

List<byte[]> vals = RedisManager.getInstance().hVals(getIdent());
for (byte[] v : vals) {
T bean = CommUtil.readObject(v, pTypeClass);
doUpdate(bean);
}
loadStatu = LS_LOADED;
}

/**
* 监听redis同步事件
*
* @param event
*/
public void syncCache(RedisBroadcastEvent event) {
//加载中,忽略
if (loadStatu == LS_LOADING) {
log.info("加载中,忽略本次同步通知:" + event.toString());
return;
}
switch (event.getAction()) {
case RedisBroadcastEvent.CODE_REMOVE:
doRemove(event.getKey());
break;
case RedisBroadcastEvent.CODE_CLEAR:
doClear();
break;
case RedisBroadcastEvent.CODE_CACHE_UPDATE:
T bean = RedisManager.getInstance().hGet(getIdent(), event.getKey(), pTypeClass);
if (bean != null) {
doRemove(getId(bean));
doUpdate(bean);
}
break;
case RedisBroadcastEvent.CODE_CACHE_REFRESH:
syncCache();
break;
default:
throw new IllegalStateException("Unexpected value: " + event.getAction());
}
}


/**
* 通过指定的key获取缓存对象值
*
* @param key 缓存key值
* @return 缓存对象值
*/
protected T load(String key) {
return null;
}

/**
* 从数据库加载全部,lazy模式可以不用实现
*/
protected List<T> loadAll() {
return null;
}

/**
* @param key
* @return
*/
private T onLoad(String key) {
if (lazy) {//非懒加载,不管
T result = load(key);

if (result != null) {
this.put(result);
}

return result;
}
return null;
}

/**
* 删除时,需要拿原来的对象;对象被取出后,可能被修改
*
* @param key
* @return
*/
protected T getForRemove(String key) {
return cacheOrg.get(key);
}

/**
* 本地删除缓存
*
* @param key
*/
protected void doRemove(String key) {
T bean = getForRemove(key);
if (bean != null) {
for (Map.Entry<String, IGetBeanKey<T>> entry : mapListReg.entrySet()) {
doRemoveList(entry.getKey(), getBeanKey(entry.getValue(), bean), bean);
}

for (Map.Entry<String, IGetBeanKey<T>> entry : mapMapReg.entrySet()) {
doRemoveMap(entry.getKey(), getBeanKey(entry.getValue(), bean));
}
}
cache.invalidate(key);
cacheOrg.remove(key);
}

/**
* 插入新对象
*/
protected void doUpdate(T value) {
final String key = getId(value);
cache.put(key, value);
cacheOrg.put(key, CommUtil.cloneObj(value, pTypeClass));

for (Map.Entry<String, IGetBeanKey<T>> entry : mapListReg.entrySet()) {
doUpdateList(entry.getKey(), getBeanKey(entry.getValue(), value), value);
}

for (Map.Entry<String, IGetBeanKey<T>> entry : mapMapReg.entrySet()) {
doUpdateMap(entry.getKey(), getBeanKey(entry.getValue(), value), value);
}
}

//本地调用,删除一个对象时,更新列表缓存
private void doRemoveList(String regionKey, String key, T value) {
if (StringUtils.isEmpty(key)) return;
Set<T> list = mapListLocal.get(regionKey + split_char + key);
if (list == null) {
return;
}
list.remove(value);
}

//本地调用,删除对象时,更新map缓存
private void doRemoveMap(String regionKey, String key) {
if (StringUtils.isEmpty(key)) return;
Map<String, T> map = mapMapLocal.get(regionKey);
if (map != null) {
map.remove(key);
}
}

//本地调用,更新列表缓存
private void doUpdateList(String regionKey, String key, T value) {
if (StringUtils.isEmpty(key)) return;
Set<T> list = mapListLocal.computeIfAbsent(regionKey + split_char + key, k -> new LinkedHashSet<>());
list.add(value);
}

//本地调用,更新对象时,更新map缓存
private void doUpdateMap(String regionKey, String key, T value) {
if (StringUtils.isEmpty(key)) return;
Map<String, T> map = mapMapLocal.computeIfAbsent(regionKey, k -> new HashMap<>());
map.put(key, value);
}

/**
* 外部调用,更新缓存:先删除,再更新本地缓存,更新并通知redis
*
* @param bean
*/
public final void put(T bean) {
doRemove(getId(bean));
doUpdate(bean);
if (loadStatu != LS_LOADING) {
RedisManager.getInstance().hSet(getIdent(), getId(bean), bean);
//通知redis
publishUpdate(getId(bean));
}
}

/**
* 将对象重置为修改前的值,用于取出修改后,事务提交失败
*
* @param bean
*/
public final void reset(T bean) {
final String id = getId(bean);
T b = getForRemove(id);
if (b != null) {
cache.put(id, b);
}
}

@Override
public final T get(String key) {
return cache.get(key);
}

public final T get(long key) {
return cache.get(String.valueOf(key));
}

/**
* 按其他key取bean
*
* @param rk 注册类型
* @param key
* @return
*/
protected final T localGetByKey(String rk, String key) {
Map<String, T> map = mapMapLocal.get(rk);
if (map != null) {
return map.get(key);
}
return null;
}

public final Set<T> localGetListByKey(String rk, String key) {
return mapListLocal.get(rk + split_char + key);
}

/**
* 通知redis更新:更新单个bean
*
* @param key
*/
protected final void publishUpdate(String key) {
RedisBroadcastEvent message = new RedisBroadcastEvent();
message.setIdent(getIdent());
message.setKey(key);
message.setAction(RedisBroadcastEvent.CODE_CACHE_UPDATE);
RedisManager.getInstance().publish(message);
}

/**
* 通知redis更新:删除单个bean
*
* @param key
*/
@Override
public final void publishRemove(String key) {
RedisBroadcastEvent message = new RedisBroadcastEvent();
message.setIdent(getIdent());
message.setKey(key);
message.setAction(RedisBroadcastEvent.CODE_REMOVE);
RedisManager.getInstance().publish(message);
}

/**
* 通知redis更新:清空缓存
*/
@Override
public final void publishClear() {
RedisBroadcastEvent message = new RedisBroadcastEvent();
message.setIdent(getIdent());
message.setAction(RedisBroadcastEvent.CODE_CLEAR);
RedisManager.getInstance().publish(message);
}

/**
* 通知redis更新:刷新缓存 *
*/
public final void publishRefresh() {
RedisBroadcastEvent message = new RedisBroadcastEvent();
message.setIdent(getIdent());
message.setAction(RedisBroadcastEvent.CODE_CACHE_REFRESH);
RedisManager.getInstance().publish(message);
}

/**
* 外部调用,删除单个对象
*
* @param key
*/
public void remove(String key) {
this.doRemove(key);
RedisManager.getInstance().hdel(getIdent(), key);
publishRemove(key);
}

public void remove(long key) {
remove(String.valueOf(key));
}

/**
* 本地调用,清空缓存
*/
protected void doClear() {
cache.cleanUp();
cacheOrg.clear();
mapListLocal.clear();
mapMapLocal.clear();
}

/**
* 外部调用,清空缓存:清空本地缓存,并更新redis,通知其他服务
*/
public void clear() {
doClear();
RedisManager.getInstance().del(getIdent());
publishClear();
}

/**
* 重载缓存:先清空,再重载
*/
public void refresh() {
loadStatu = LS_LOADING;
doClear();
List<T> list = loadAll();
if (list != null) {
for (T bean : list) {
doUpdate(bean);
}
}
loadStatu = LS_LOADED;
RedisManager.getInstance().hmSet(getIdent(), cacheOrg);
publishRefresh();
}

/**
* 根据接口,得到bean的缓存key
*
* @param iGetBeanKey
* @param bean
* @return
*/
protected String getBeanKey(IGetBeanKey<T> iGetBeanKey, T bean) {
return iGetBeanKey.getKey(bean);
}

public Collection<T> getAll() {
return cacheOrg.values();
}

/**
* 获取bean缓存key的接口类,用于按非id的缓存,如code等
*
* @param <T>
*/
public interface IGetBeanKey<T> {
String getKey(T bean);
}
}

+ 109
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/cache/CacheManager.java Просмотреть файл

@@ -0,0 +1,109 @@
package cc.smtweb.framework.core.cache;

import cc.smtweb.framework.core.annotation.SwTable;
import cc.smtweb.framework.core.db.cache.EntityCache;
import cc.smtweb.framework.core.db.cache.ModelTableCache;
import cc.smtweb.framework.core.db.vo.ModelTable;
import cc.smtweb.framework.core.redis.RedisBroadcastEvent;
import cc.smtweb.framework.core.util.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

/**
* 内存缓存管理器,管理lazy加载的缓存,长时间不使用会失效
*/
@Slf4j
public class CacheManager {
//所有缓存对象
private final Map<String, AbstractCache> cacheMap = new HashMap<>();
private final Map<Class, AbstractCache> cacheMapCls = new HashMap<>();
//记录顺序用
private List<AbstractCache> listCache = new ArrayList<>();
//缓存清理线程池
private final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2);

public AbstractCache getCache(String ident) {
final AbstractCache cache = cacheMap.get(ident);
if (cache != null && cache.isNotInited()) {
cache.init();
}
return cache;
}

public <T extends AbstractCache> T getCache(Class<T> clazz) {
final T cache = (T) cacheMapCls.get(clazz);
if (cache != null && cache.isNotInited()) {
cache.init();
}
return cache;
}

public static CacheManager getIntance() {
return SpringUtil.getBean(CacheManager.class);
}

// 初始化cache
public boolean install(AbstractCache cache) {
cache.install(executorService);
if (cacheMap.putIfAbsent(cache.getIdent(), cache) == null) {
cacheMapCls.put(cache.getClass(), cache);
listCache.add(cache);
return true;
}

return false;
}

/**
* 启动时的初始化及预加载
* 1、按依赖关系排序
* 2、预加载(lazy模式不从库加载)
*/
public void init() {
listCache.sort((o1, o2) -> {
//o1依赖o2
if (isContains(o1.getDepends(), o2.getIdent())) return 1;
//o2依赖o1
if (isContains(o2.getDepends(), o1.getIdent())) return -1;

return 0;//getPluginIndex(o1) - getPluginIndex(o2);
});
for (AbstractCache cache : listCache) {
cache.init();
}
//按表加载并初始化
for (ModelTable table : ModelTableCache.getInstance().getAll()) {
if (table.isNeedCache() && !cacheMap.containsKey(table.getName())) {
EntityCache cache = new EntityCache(table.getName());
cache.install(executorService);
cacheMapCls.put(cache.getClass(), cache);
cacheMap.put(table.getName(), cache);
}
}
}

private boolean isContains(String[] src, String dest) {
if (src == null || src.length == 0) return false;
for (String s : src) {
if (s.trim().equals(dest)) return true;
}
return false;
}

@EventListener
public void onRedisBroadcastEvent(RedisBroadcastEvent event) {
AbstractCache cache = getCache(event.getIdent());
if (cache == null) {
log.info("接收到不存在的缓存更新!(" + event.toString() + ")");
return;
}
cache.syncCache(event);
}
}

+ 24
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/cache/ISwCache.java Просмотреть файл

@@ -0,0 +1,24 @@
package cc.smtweb.framework.core.cache;

public interface ISwCache<K, V> {
/** 权限缓存名称 */
String REALM_CACHE = "RealmCache";

/**
* 根据键值获取缓存对象
* @param key 缓存唯一键值
* @return 缓存对象
*/
V get(K key);

/**
* 给redis发送广播消息,多服务同步删除相同key值的缓存对象
* @param key 缓存键值
*/
void publishRemove(K key);

/**
* 给redis发送广播消息,多服务同步清空相同类型的缓存对象
*/
void publishClear();
}

+ 271
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/DbEngine.java Просмотреть файл

@@ -0,0 +1,271 @@
package cc.smtweb.framework.core.db;

import cc.smtweb.framework.core.db.impl.DefaultEntity;
import cc.smtweb.framework.core.db.jdbc.IdGenerator;
import cc.smtweb.framework.core.db.jdbc.JdbcEngine;
import cc.smtweb.framework.core.util.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ResultSetExtractor;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
* 提供数据库基本操作和代理EntityDao操作,在DbEngineConfiguration中初始化
*
* @author xkliu
*/
@Slf4j
public class DbEngine extends JdbcEngine {
private String dbSchema;
private final Map<Class<?>, EntityDao<?>> daoMap = new ConcurrentHashMap<>();
private final Map<String, EntityDao<DefaultEntity>> tableDaoMap = new ConcurrentHashMap<>();

public static DbEngine getInstance() {
return SpringUtil.getBean(DbEngine.class);
}

public DbEngine(JdbcTemplate jdbcTemplate, IdGenerator idGenerator, String type) {
super(jdbcTemplate, idGenerator, type);
}

/**
* bean为Data格式,调用此方法
* @param type bean类
* @param <T>
* @return
*/
public <T> EntityDao<T> findDao(Class<T> type) {
EntityDao<T> handler = (EntityDao<T>) daoMap.get(type);

if (handler == null) {
synchronized (daoMap) {
handler = new EntityDao<>(type, this);
daoMap.put(type, handler);
}
}

return handler;
}

public EntityDao<DefaultEntity> findDao(String tableName) {
EntityDao<DefaultEntity> handler = tableDaoMap.get(type);

if (handler == null) {
synchronized (tableDaoMap) {
handler = new EntityDao<>(tableName, this);
tableDaoMap.put(tableName, handler);
}
}

return handler;
}

public String getDbSchema() {
if (dbSchema == null) {
synchronized (DbEngine.class) {
if (dbSchema == null) {
try {
final ResultSetExtractor<String> rse = new ResultSetExtractor<String>() {
@Override
public String extractData(ResultSet rs) throws SQLException {
if (rs.next()) return rs.getString(1);
throw new SQLException("未指定当前数据库,请检查您的链接!");
}
};

dbSchema = query("SELECT database()", rse);

} catch (Exception e) {
log.error("获取mysql的数据库失败", e);
return null;
}
}
}
}
return dbSchema;
}

/**
* 根据PO对象的ID值更新其余所有字段
*
* @param entity PO对象
* @param <T> PO对象类型
* @return 更新数量
*/
public <T> int updateEntity(T entity) {
return updateEntity(entity, null, null);
}

/**
* 使用ID字段更新单行数据
*
* @param entity PO值对象,对象属性是需要更新的值
* @param fields 需要更新额字段列表,逗号分隔
* @param <T> PO值对象类型
* @return 更新数量
*/
public <T> int updateEntity(T entity, String fields) {
return updateEntity(entity, fields, null);
}

/**
* 指定自定义条件更新对象
*
* @param entity PO值对象,对象属性是需要更新的值和更新条件值
* @param fields 需要更新额字段列表,逗号分隔
* @param whereFields 更新条件字段列表,逗号分隔
* @param <T> PO值对象类型
* @return 更新数量
*/
public <T> int updateEntity(T entity, String fields, String whereFields) {
EntityDao<T> dao = findDao((Class<T>) entity.getClass());
return dao.updateEntity(entity, fields, whereFields);
}

/**
* 用PO对象所有字段入单行数据
*
* @param entity PO对象
* @param <T> PO对象类型
* @return 更新数量
*/
public <T> int insertEntity(T entity) {
return insertEntity(entity, null);
}

/**
* 插入单行数据
*
* @param entity PO对象
* @param fields 逗号分隔的字段列表
* @param <T> PO对象类型
* @return 更新数量
*/
public <T> int insertEntity(T entity, String fields) {
EntityDao<T> dao = findDao((Class<T>) entity.getClass());
return dao.insertEntity(entity, fields);
}

/**
* 根据ID值删除单行数据
*
* @param entity PO对象
* @param <T> PO对象类型
* @return 删除数量
*/
public <T> int deleteEntity(T entity) {
EntityDao<T> dao = findDao((Class<T>) entity.getClass());
return dao.deleteEntity(entity);
}

/**
* 根据ID值删除单行数据
*
* @param entityType PO对象类型
* @param id 记录主建值
* @param <T> PO对象
* @return 删除数量
*/
public <T> int deleteEntity(Class<T> entityType, Long id) {
EntityDao<T> dao = findDao(entityType);
return dao.deleteEntity(id);
}

/**
* 根据ID值删除单行数据
*
* @param entityType PO对象类型
* @param whereSql Where条件SQL语句,以where开头
* @param params 条件的值,可以多个
* @param <T> PO对象
* @return 删除数量
*/
public <T> int deleteEntity(Class<T> entityType, String whereSql, Object... params) {
EntityDao<T> dao = findDao(entityType);
return dao.deleteEntity(whereSql, params);
}

/**
* 读取实体对象ID值
*
* @param entity
* @param <T>
* @return
*/
public <T> Long readEntityId(T entity) {
EntityDao<T> dao = findDao((Class<T>) entity.getClass());
return dao.readId(entity);
}

/**
* 查询单行数据,返回bean
*/
public <T> T queryEntity(Class<T> type, Long id) {
return queryEntity(type, id, null);
}

public <T> T queryEntity(Class<T> type, Long id, String fields) {
return findDao(type).queryEntity(id, fields);
}

/**
* 查询对象所有数据,返回列表
*/
public <T> List<T> query(Class<T> type) {
return query(type, null);
}

/**
* 查询对象所有数据,返回列表
*/
public <T> List<T> query(Class<T> type, String fields) {
return findDao(type).query(fields);
}

/**
* 传入where条件查询实体类别
*
* @param type 实体类型类
* @param sqlWhere sql的where语句部分,不包含from
* @param params 条件参数值
* @param <T> 实体类型
* @return
*/
public <T> List<T> queryWhere(Class<T> type, String sqlWhere, Object... params) {
return findDao(type).queryWhere(sqlWhere, params);
}

/**
* 批量插入单行数据
*
* @param entities PO对象列表
* @param <T> 实体类型
* @return 更新数量
*/
public <T> int[] batchInsertEntity(List<T> entities) {
if (entities == null || entities.isEmpty()) {
return null;
}
return findDao((Class<T>) entities.get(0).getClass()).batchInsertEntity(entities, null);
}

/**
* 批量插入单行数据
*
* @param entities PO对象列表
* @param fields 逗号分隔的字段列表
* @param <T> 实体类型
* @return 更新数量
*/
public <T> int[] batchInsertEntity(List<T> entities, String fields) {
if (entities == null || entities.isEmpty()) {
return null;
}
return findDao((Class<T>) entities.get(0).getClass()).batchInsertEntity(entities, fields);
}
}

+ 281
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/EntityDao.java Просмотреть файл

@@ -0,0 +1,281 @@
package cc.smtweb.framework.core.db;

import cc.smtweb.framework.core.db.dao.AbstractEntityDao;
import cc.smtweb.framework.core.db.dao.EntityColumn;
import cc.smtweb.framework.core.db.jdbc.JdbcEngine;
import cc.smtweb.framework.core.db.vo.def.FieldType;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;

/**
* 提供数据对象Dao操作
*
* @author xkliu
*/
public class EntityDao<T> extends AbstractEntityDao<T> {
@Getter
protected JdbcEngine jdbcEngine;

public EntityDao(Class<T> type, JdbcEngine jdbcEngine) {
super(type);
this.jdbcEngine = jdbcEngine;
}

public EntityDao(String tableName, JdbcEngine jdbcEngine) {
super(tableName);
this.jdbcEngine = jdbcEngine;
}

/**
* 获取数据库唯一id
*
* @return 返回ID值
*/
public long nextId() {
return this.jdbcEngine.nextId();
}

/**
* 根据PO对象的ID值更新其余所有字段
*
* @param entity PO对象
* @return 更新数量
*/
public int updateEntity(T entity) {
return updateEntity(entity, null, null);
}

/**
* 使用ID字段更新单行数据
*
* @param entity PO值对象,对象属性是需要更新的值
* @param fields 需要更新额字段列表,逗号分隔
* @return 更新数量
*/
public int updateEntity(T entity, String fields) {
return updateEntity(entity, fields, null);
}

/**
* 指定自定义条件更新对象
*
* @param entity PO值对象,对象属性是需要更新的值和更新条件值
* @param fields 需要更新额字段列表,逗号分隔
* @param whereFields 更新条件字段列表,逗号分隔
* @return 更新数量
*/
public int updateEntity(T entity, String fields, String whereFields) {
StringBuilder sb = new StringBuilder();
Object[] params = this.handleUpdate(entity, sb, fields, whereFields);

return jdbcEngine.update(sb.toString(), params);
}

/**
* 用PO对象所有字段入单行数据
*
* @param type PO对象字段范围的类,是entity的父类
* @param entity PO对象
* @return 更新数量
*/
public int insertEntity(Class<? super T> type, T entity) {
return insertEntity(type, entity, null);
}

/**
* 用PO对象所有字段入单行数据
*
* @param entity PO对象
* @return 更新数量
*/
public int insertEntity(T entity) {
return insertEntity(entity.getClass(), entity, null);
}

/**
* 插入单行数据
*
* @param entity PO对象
* @param fields 逗号分隔的字段列表
* @return 更新数量
*/
public int insertEntity(T entity, String fields) {
return insertEntity(entity.getClass(), entity, fields);
}

private int insertEntity(Class<?> type, T entity, String fields) {
StringBuilder sb = new StringBuilder();

Object[] params = handleInsert(entity, sb, fields);

return jdbcEngine.update(sb.toString(), params);
}

/**
* 批量插入单行数据
*
* @param entities PO对象列表
* @return 更新数量
*/
public int[] batchInsertEntity(List<T> entities) {
return batchInsertEntity(entities, null);
}

/**
* 批量插入单行数据
*
* @param entities PO对象列表
* @param fields 逗号分隔的字段列表
* @return 更新数量
*/
public int[] batchInsertEntity(List<T> entities, String fields) {
StringBuilder sql = new StringBuilder();

sql.append("insert into ").append(tableName).append("(");

List<String> listFields = adjustFields(fields, FieldType.CREATE_TIME, FieldType.LAST_TIME);
List<EntityColumn> insertColumns = new ArrayList<>(this.columns.size());

if (listFields == null) {
for (EntityColumn column : this.columns.values()) {
sql.append(column.getField().getName()).append(",");
insertColumns.add(column);
}
} else {

for (String name : listFields) {
EntityColumn column = this.columns.get(name.trim());
sql.append(column.getField().getName()).append(",");
insertColumns.add(column);
}
}

sql.setCharAt(sql.length() - 1, ')');

// values(?,?)
sql.append(" values(");
for (int i = insertColumns.size(); i > 0; i--) {
sql.append("?,");
}
sql.setCharAt(sql.length() - 1, ')');

// 参数列表
List<Object[]> listParams = new ArrayList<>(entities.size());
for (T obj : entities) {
List<Object> params = new ArrayList<>(this.columns.size());

for (EntityColumn column : this.columns.values()) {
params.add(column.readValue(obj));
}

listParams.add(params.toArray());
}

return jdbcEngine.batchUpdate(sql.toString(), listParams);
}


/**
* 根据ID值删除单行数据
*
* @param entity PO对象
* @return 删除数量
*/
public int deleteEntity(T entity) {
StringBuilder sb = new StringBuilder();

Object[] params = handleDelete(entity, sb);

return jdbcEngine.update(sb.toString(), params);
}

/**
* 根据ID值删除单行数据
*
* @param id 记录主建值
* @return 删除数量
*/
public int deleteEntity(Long id) {
StringBuilder sb = new StringBuilder();
handleDelete(sb);

return jdbcEngine.update(sb.toString(), id);
}

/**
* 根据ID值删除单行数据
*
* @param whereSql Where条件SQL语句,以where开头
* @param params 条件的值,可以多个
* @return 删除数量
*/
public int deleteEntity(String whereSql, Object... params) {
StringBuilder sb = new StringBuilder("DELETE FROM ");
sb.append(getTableName()).append(" ").append(whereSql);

return jdbcEngine.update(sb.toString(), params);
}

/**
* 读取实体对象ID值
*
* @param entity
* @return
*/
public Long readEntityId(T entity) {
return (Long) readId(entity);
}

/**
* 查询单行数据,返回bean
*/
public T queryEntity(Long id) {
return queryEntity(id, null);
}

public T queryEntity(Long id, String fields) {
StringBuilder sb = new StringBuilder();
handleSelectOne(sb, fields);

List<T> list = jdbcEngine.query(sb.toString(), type, id);

if (list != null && !list.isEmpty()) {
return list.get(0);
}

return null;
}

/**
* 查询对象所有数据,返回列表
*/
public List<T> query() {
return query(null);
}

/**
* 查询对象所有数据,返回列表
*/
public List<T> query(String fields) {
StringBuilder sb = new StringBuilder();
handleSelect(sb, fields);

return jdbcEngine.query(sb.toString(), type);
}

/**
* 查询对象所有数据,返回列表
*/
public List<T> queryWhere(String sqlWhere, Object... params) {
StringBuilder sb = new StringBuilder();
handleSelect(sb, null);
if (StringUtils.isNotEmpty(sqlWhere)) {
sb.append(" where ").append(sqlWhere);
}

return jdbcEngine.query(sb.toString(), type, params);
}
}

+ 64
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/cache/EntityCache.java Просмотреть файл

@@ -0,0 +1,64 @@
package cc.smtweb.framework.core.db.cache;

import cc.smtweb.framework.core.annotation.SwCache;
import cc.smtweb.framework.core.cache.AbstractCache;
import cc.smtweb.framework.core.db.DbEngine;
import cc.smtweb.framework.core.db.EntityDao;
import cc.smtweb.framework.core.db.impl.DefaultEntity;
import cc.smtweb.framework.core.db.vo.ModelCache;
import cc.smtweb.framework.core.db.vo.ModelTable;
import cc.smtweb.framework.core.util.CommUtil;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.Scheduler;
import org.apache.commons.lang3.StringUtils;
import org.checkerframework.checker.nullness.qual.NonNull;

import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
* Created by Akmm at 2022/2/19 17:19
*/
public class EntityCache extends AbstractCache<DefaultEntity> {
private String tableName;

public EntityCache(String tableName) {
this.tableName = tableName;
ModelTable table = ModelTableCache.getInstance().getByName(tableName);

ident = tableName;
title = table.getTitle();
lazy = false;

if (!table.isNeedCache() || CommUtil.isEmpty(table.getCaches())) return;

for (ModelCache cache : table.getCaches()) {
final IGetBeanKey<DefaultEntity> key = bean -> {
String ret = "";
for (String s : StringUtils.split(cache.getFields(), ",")) {
if (StringUtils.isNotEmpty(s)) {
ret += "_" + bean.getStr(s);
}
}
return ret;
};
if (cache.isMapType()) {
regMap(cache.getName(), key);
} else {
regList(cache.getName(), key);
}
}
}

@Override
protected String getId(DefaultEntity bean) {
return String.valueOf(bean.getEntityId());
}

@Override
protected List<DefaultEntity> loadAll() {
EntityDao<DefaultEntity> dao = DbEngine.getInstance().findDao(tableName);
return dao.query();
}
}

+ 45
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/cache/ModelDatabaseCache.java Просмотреть файл

@@ -0,0 +1,45 @@
package cc.smtweb.framework.core.db.cache;

import cc.smtweb.framework.core.annotation.SwCache;
import cc.smtweb.framework.core.cache.AbstractCache;
import cc.smtweb.framework.core.cache.CacheManager;
import cc.smtweb.framework.core.db.DbEngine;
import cc.smtweb.framework.core.db.EntityDao;
import cc.smtweb.framework.core.db.vo.ModelDatabase;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.RowMapper;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

/**
* Created by Akmm at 2022/1/12 18:34
*/
@SwCache(ident = "ASP_MODEL_DATABASE", title = "数据库")
public class ModelDatabaseCache extends AbstractCache<ModelDatabase> {
private final static String mk = "k";

public static ModelDatabaseCache getInstance() {
return CacheManager.getIntance().getCache(ModelDatabaseCache.class);
}

public ModelDatabaseCache() {
regMap(mk, ModelDatabase::getName);
}

@Override
protected String getId(ModelDatabase bean) {
return String.valueOf(bean.getId());
}

@Override
protected List<ModelDatabase> loadAll() {
EntityDao<ModelDatabase> dao = DbEngine.getInstance().findDao(ModelDatabase.class);
return dao.query();
}

public final ModelDatabase getByName(String key) {
return localGetByKey(mk, key);
}
}

+ 90
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/cache/ModelTableCache.java Просмотреть файл

@@ -0,0 +1,90 @@
package cc.smtweb.framework.core.db.cache;

import cc.smtweb.framework.core.annotation.SwCache;
import cc.smtweb.framework.core.cache.AbstractCache;
import cc.smtweb.framework.core.cache.CacheManager;
import cc.smtweb.framework.core.db.DbEngine;
import cc.smtweb.framework.core.db.vo.ModelTable;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.ResultSetExtractor;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
* Created by Akmm at 2022/1/12 18:34
*/
@SwCache(ident = "ASP_MODEL_TABLE", title = "数据库表定义")
public class ModelTableCache extends AbstractCache<ModelTable> {
private final static String mk = "k";
private final static String md = "d";

public static ModelTableCache getInstance() {
return CacheManager.getIntance().getCache(ModelTableCache.class);
}

public ModelTableCache() {
regMap(mk, k-> k.getName().toUpperCase());
regList(md, k-> String.valueOf(k.getDatabaseId()));
}

@Override
protected String getId(ModelTable bean) {
return String.valueOf(bean.getId());
}

@Override
protected List<ModelTable> loadAll() {
return DbEngine.getInstance().query("SELECT\n" +
"t.table_id,\n" +
"t.prjoect_id,\n" +
"t.catalog_id,\n" +
"t.database_id,\n" +
"t.table_extends,\n" +
"t.table_name,\n" +
"t.table_title,\n" +
"t.table_abbr,\n" +
"t.table_type,\n" +
"t.need_cache,\n" +
"t.table_content,\n" +
"t.table_create_uid,\n" +
"t.table_update_uid,\n" +
"t.table_create_at,\n" +
"t.table_update_at\n" +
"from asp_model_table t\n", new ResultSetExtractor<List<ModelTable>>() {
@Override
public List<ModelTable> extractData(ResultSet rs) throws SQLException, DataAccessException {
List<ModelTable> list = new ArrayList<>();
while (rs.next()) {
ModelTable table = new ModelTable();
list.add(table);
table.setId(rs.getLong("table_id"));
table.setDatabaseId(rs.getLong("database_id"));
table.setPrjoectId(rs.getLong("prjoect_id"));
table.setCatalogId(rs.getLong("catalog_id"));
table.setTableExtends(rs.getString("table_extends"));
table.setName(rs.getString("table_name").toUpperCase());
table.setTitle(rs.getString("table_title"));
table.setAbbr(rs.getString("table_abbr"));
table.setType(rs.getInt("table_type"));
table.setNeedCache(rs.getInt("need_cache") == 1);
table.setCreateUid(rs.getLong("table_create_uid"));
table.setCreateAt(rs.getLong("table_create_at"));
table.setUpdateAt(rs.getLong("table_update_at"));
table.setTableContent(rs.getString("table_content"));
}
return list;
}
});
}

public final ModelTable getByName(String key) {
return localGetByKey(mk, key.toUpperCase());
}
public final Set<ModelTable> getDbTables(long dbId) {
return localGetListByKey(md, String.valueOf(dbId));
}
}

+ 41
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/config/DbEngineConfiguration.java Просмотреть файл

@@ -0,0 +1,41 @@
package cc.smtweb.framework.core.db.config;

import cc.smtweb.framework.core.db.DbEngine;
import cc.smtweb.framework.core.db.jdbc.IdGenerator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;

/**
* 默认数据源
* @author xkliu
*/
@Configuration
public class DbEngineConfiguration {
@Value("${smtweb.db.type}")
private String dbType;
// @Bean
// public DataSource dataSource() {
// return DataSourceBuilder.create().build();
// }
//
// @Bean
// public NamedParameterJdbcTemplate jdbcTemplate(DataSource dataSource) {
// return new NamedParameterJdbcTemplate(dataSource);
// }

/**
* 产生数据库数据库访问对象 dbEngine
* @param jdbcTemplate Spring框架Jdbc,通过 spring.datasource 配置
* @param idGenerator ID生成器对象,思想数据库ID生成
* @return dbEngine对象
*/
@Bean
@ConfigurationProperties(prefix = "smtweb.db.default")
public DbEngine dbEngine(JdbcTemplate jdbcTemplate, IdGenerator idGenerator) {
System.out.println("create dbEngine=============");
return new DbEngine(jdbcTemplate, idGenerator, dbType);
}
}

+ 43
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/config/DesignConfig.java Просмотреть файл

@@ -0,0 +1,43 @@
package cc.smtweb.framework.core.db.config;

import cc.smtweb.framework.core.db.vo.def.DataType;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
//通过@PropertySource注解指定要读取的yaml配置文件,默认读取src\main\resources\application.yml配置
@PropertySource(value = "classpath:config/design_db.yaml", factory = YamlPropertyLoaderFactory.class)
@ConfigurationProperties(prefix = "design")
public class DesignConfig {
private List<DataType> dataTypes;

private Map<String, DataType> mapType = null;

private void adjustMap() {
if (mapType == null) {
synchronized (DesignConfig.class) {
if (mapType == null) {
Map<String, DataType> map = new HashMap<>();
for (DataType type : dataTypes) {
map.put(type.getType(), type);
}
mapType = map;
}
}
}
}

public DataType getDataType(String type) {
adjustMap();
return mapType.get(type);
}

public List<DataType> getDataTypes() {
return dataTypes;
}
}

+ 23
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/config/YamlPropertyLoaderFactory.java Просмотреть файл

@@ -0,0 +1,23 @@
package cc.smtweb.framework.core.db.config;

import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.DefaultPropertySourceFactory;
import org.springframework.core.io.support.EncodedResource;

import java.io.IOException;

/**
* 实现yaml配置文件加载工厂,以使用@PropertySource注解加载指定yaml文件的配置
*/
public class YamlPropertyLoaderFactory extends DefaultPropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {

if (null == resource) {
super.createPropertySource(name, resource);
}
return new YamlPropertySourceLoader().load(resource.getResource().getFilename(), resource.getResource()).get(0);
}

}

+ 383
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/dao/AbstractEntityDao.java Просмотреть файл

@@ -0,0 +1,383 @@
package cc.smtweb.framework.core.db.dao;

import cc.smtweb.framework.core.annotation.SwTable;
import cc.smtweb.framework.core.cache.CacheManager;
import cc.smtweb.framework.core.db.cache.ModelTableCache;
import cc.smtweb.framework.core.db.impl.BaseBean;
import cc.smtweb.framework.core.db.impl.DefaultEntity;
import cc.smtweb.framework.core.db.vo.def.FieldType;
import cc.smtweb.framework.core.db.vo.ModelField;
import cc.smtweb.framework.core.db.vo.ModelTable;
import cc.smtweb.framework.core.exception.DbException;
import cc.smtweb.framework.core.util.DateUtil;
import cc.smtweb.framework.core.util.SpringUtil;
import cc.smtweb.framework.core.util.VariableUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.ClassUtils;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.*;

/**
* 抽象的值对象数据库访问
*
* @param <T> 数据库值对象类型
*/
public abstract class AbstractEntityDao<T> {
protected ModelTable modelTable;
protected String tableName;
protected Map<String, EntityColumn> columns = new HashMap<>();
protected Class<T> type;
protected CacheManager cacheManager = SpringUtil.getBean(CacheManager.class);
// public AbstractEntityDao(String tableName) {
// this.tableName = tableName;
// }

/**
* 通过值对象类型构造值对象数据库访问
*
* @param type 值对象类型
*/
public AbstractEntityDao(Class<T> type) {
this.type = type;
// type.isAnnotationPresent(Table.class);
SwTable table = type.getAnnotation(SwTable.class);
Class<? super T> superclass = type.getSuperclass();

if (table == null && superclass != null) {
table = superclass.getAnnotation(SwTable.class);
}

if (table == null) {
throw new IllegalAccessError("not find annotation @SwTable");
}

tableName = table.value();
modelTable = ModelTableCache.getInstance().getByName(tableName);

for (ModelField field : modelTable.getFields()) {
String voFieldName = getVoFieldName(modelTable.getAbbr(), field.getName());
// 处理get method
try {
PropertyDescriptor pd = new PropertyDescriptor(voFieldName, type);
// 获得get方法
Method readMethod = pd.getReadMethod();
Method writeMethod = pd.getWriteMethod();

if (readMethod != null && writeMethod != null) {
Class<?>[] parameterTypes = writeMethod.getParameterTypes();
if (parameterTypes.length == 1 && ClassUtils.isAssignable(parameterTypes[0], readMethod.getReturnType())) {
add(field, readMethod, writeMethod);
}
}
} catch (IntrospectionException ignore) {
}
}
}

/**
* 通过值对象类型构造值对象数据库访问
*
* @param tableName 表名
*/
public AbstractEntityDao(String tableName) {
this.tableName = tableName;
this.type = (Class<T>)DefaultEntity.class;
modelTable = cacheManager.getCache(ModelTableCache.class).getByName(tableName);

for (ModelField field : modelTable.getFields()) {
add(field, null, null);
}
}

/**
* 根据字段名,得到类中的字段属性名
* @param tbAbbr 表缩写,一般是字段的前缀
* @param fieldName 字段名
* @return
*/
private String getVoFieldName(String tbAbbr, String fieldName) {
fieldName = fieldName.toLowerCase();
tbAbbr = tbAbbr.toLowerCase() + "_";
if (fieldName.startsWith(tbAbbr)) return VariableUtil.underlineToHump(fieldName.substring(tbAbbr.length()));
return VariableUtil.underlineToHump(fieldName);
}

/**
* 添加值对象的属性访问方法何注解值
*
* @param field 字段名
* @param readMethod 读值对象属性方法
* @param writeMethod 写值值对象属性方法
*/
protected void add(ModelField field, Method readMethod, Method writeMethod) {
EntityColumn beanColumn = new EntityColumn(field, readMethod, writeMethod);
columns.put(field.getName(), beanColumn);
}

protected void updateTime(T obj, FieldType type) {
ModelField field = modelTable.findFieldByType(type);
if (field == null) return;
EntityColumn col = columns.get(field.getName());
if (col != null) {
col.writeValue(obj, DateUtil.nowDateTimeLong());
}
}

/**
* 校验传入的字段,如没有创建时间和最后更改时间,则加上
*
* @param fields
* @return
*/
protected List<String> adjustFields(String fields, FieldType... types) {
if (StringUtils.isEmpty(fields)) return null;
String[] fieldNames = fields.toLowerCase().split(",");
List<String> listFields = new ArrayList<>(fieldNames.length + 2);
boolean[] includeTypes = new boolean[types.length];
for (int i = 0, len = includeTypes.length; i < len; i++) {
includeTypes[i] = false;
}

for (String name : fieldNames) {
EntityColumn column = this.columns.get(name.trim());
for (int i = 0, len = types.length; i < len; i++) {
if (types[i].name().equalsIgnoreCase(column.getField().getFieldType())) {
includeTypes[i] = true;
}
}
listFields.add(name);
}
for (int i = 0, len = types.length; i < len; i++) {
if (!includeTypes[i]) {
ModelField field = modelTable.findFieldByType(types[i]);
if (field != null) listFields.add(field.getName());
}
}
return listFields;
}

/**
* 拼接插入SQL语句
*
* @param obj 值对象
* @param sql 记录sql的字符缓存
* @param fields 逗号分割字段列表,设置为null表示使用所有字段
* @return SQL参数列表
*/
protected Object[] handleInsert(T obj, StringBuilder sql, String fields) {
List<Object> result;
List<String> listFields = adjustFields(fields, FieldType.CREATE_TIME, FieldType.LAST_TIME);
sql.append("insert into ").append(tableName).append("(");

updateTime(obj, FieldType.CREATE_TIME);
updateTime(obj, FieldType.LAST_TIME);

if (listFields == null) {
result = new ArrayList<>(this.columns.size());

for (EntityColumn column : this.columns.values()) {
result.add(column.readValue(obj));
sql.append(column.getField().getName()).append(",");
}
} else {
result = new ArrayList<>(listFields.size());

for (String name : listFields) {
EntityColumn column = this.columns.get(name.trim());
result.add(column.readValue(obj));
sql.append(column.getField().getName()).append(",");
}
}

sql.setCharAt(sql.length() - 1, ')');

// values(?,?)
sql.append(" values(");
for (int i = result.size(); i > 0; i--) {
sql.append("?,");
}
sql.setCharAt(sql.length() - 1, ')');

return result.toArray();
}

/**
* 拼接更新SQL语句
*
* @param obj 值对象
* @param sql 记录sql的字符缓存
* @param fields 逗号分割更新字段列表,设置为null表示使用所有字段
* @param whereFields 逗号分割查询字段列表,设置为null表示使用ID字段作为查询条件
* @return SQL参数列表
*/
protected Object[] handleUpdate(T obj, StringBuilder sql, String fields, String whereFields) {
EntityColumn idColumn = findIdColumn();

List<String> listFields = adjustFields(fields, FieldType.LAST_TIME);
updateTime(obj, FieldType.LAST_TIME);

sql.append("update ").append(tableName).append(" set ");
List<Object> result = new ArrayList<>();

if (listFields == null) {
for (EntityColumn column : this.columns.values()) {
if (idColumn != column) {
sql.append(column.getField().getName()).append("=?,");
}
}
sql.setCharAt(sql.length() - 1, ' ');

// 默认使用Id字段条件
result.add(idColumn.readValue(obj));

sql.append("where ").append(idColumn.getField().getName()).append("=?");
} else {

for (String name : listFields) {
name = name.trim();
EntityColumn beanColumn = getBeanColumn(name);

sql.append(name).append("=?,");
result.add(beanColumn.readValue(obj));

}

sql.setCharAt(sql.length() - 1, ' ');

if (StringUtils.isNotBlank(whereFields)) {
sql.append("where ");
boolean first = true;
for (String name : whereFields.split(",")) {
name = name.trim();
if (first) {
first = false;
} else {
sql.append(" and ");
}

sql.append(name).append("=?");
result.add(readValue(obj, name));
}
} else {
// 默认使用Id字段条件
result.add(idColumn.readValue(obj));
sql.append("where ").append(idColumn.getField().getName()).append("=?");
}
}
return result.toArray();
}

private EntityColumn findIdColumn() {
ModelField field = modelTable.findIdField();
EntityColumn idColumn = field != null ? columns.get(field.getName()) : null;
if (idColumn == null) {
throw new DbException(tableName + " not define id column");
}

return idColumn;
}

/**
* 拼接删除值对象语句
*
* @param obj 值对象
* @param sql 记录sql的字符缓存
* @return SQL参数列表
*/
protected Object[] handleDelete(T obj, StringBuilder sql) {
EntityColumn idColumn = findIdColumn();

sql.append("DELETE FROM ").append(tableName).append(" WHERE ").append(idColumn.getField()).append("=?");

return new Object[]{idColumn.readValue(obj)};
}

/**
* 拼接删除值对象语句,条件由外部设置
*
* @param sql 记录sql的字符缓存
*/
protected void handleDelete(StringBuilder sql) {
EntityColumn idColumn = findIdColumn();
sql.append("DELETE FROM ").append(tableName).append(" WHERE ").append(idColumn.getField().getName()).append("=?");
}

private Object readValue(T obj, String fieldName) {
EntityColumn beanColumn = getBeanColumn(fieldName);

return beanColumn.readValue(obj);
}

private EntityColumn getBeanColumn(String fieldName) {
EntityColumn beanColumn = this.columns.get(fieldName);

if (beanColumn == null) {
throw new DbException("not define column:" + fieldName);
}

return beanColumn;
}

/**
* 获取表名
*
* @return 表名
*/
protected String getTableName() {
return tableName;
}

/**
* 拼接查询SQL语句
*
* @param sql SQL字符缓存
* @param fields 逗号分割的查询字段列表,传入null表示全部值对象字段
*/
public void handleSelect(StringBuilder sql, String fields) {
sql.append("select ");

if (fields != null) {
sql.append(fields).append(' ');
} else {
for (String fieldName : columns.keySet()) {
sql.append(fieldName).append(',');
}
sql.setCharAt(sql.length() - 1, ' ');
}

sql.append("from ").append(tableName);
}

protected void handleSelectOne(StringBuilder sql, String fields) {
EntityColumn idColumn = findIdColumn();

sql.append("select ");

if (fields != null) {
sql.append(fields).append(' ');
} else {
for (EntityColumn field : columns.values()) {
sql.append(field.getField().getName()).append(",");
}
sql.setCharAt(sql.length() - 1, ' ');
}

sql.append("from ").append(tableName).append(" where ").append(idColumn.getField().getName()).append("=?");
}

/**
* 读取ID值
*
* @param entity
* @return
*/
public Long readId(T entity) {
EntityColumn idColumn = findIdColumn();

return (Long) idColumn.readValue(entity);
}
}


+ 66
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/dao/EntityColumn.java Просмотреть файл

@@ -0,0 +1,66 @@
package cc.smtweb.framework.core.db.dao;

import cc.smtweb.framework.core.db.impl.DefaultEntity;
import cc.smtweb.framework.core.db.vo.ModelField;
import cc.smtweb.framework.core.exception.DbException;
import lombok.Getter;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
* 值对象字段处理类
* @author xkliu
*/
@Getter
public class EntityColumn {
private ModelField field;
private final Method readMethod;
private final Method writeMethod;

/**
* 构建值对象字段
* @param field 字段名
* @param readMethod 读值方法
* @param writeMethod 写值方法
*/
public EntityColumn(ModelField field, Method readMethod, Method writeMethod) {
this.field = field;
this.readMethod = readMethod;
this.writeMethod = writeMethod;
}

/**
* 从对象中读取字段对应的属性值
* @param obj 值对象
* @return 属性值
*/
public Object readValue(Object obj) {
if (readMethod != null) {
try {
return readMethod.invoke(obj);
} catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
throw new DbException(e);
}
} else {
return ((DefaultEntity)obj).get(field.getName());
}
}

/**
* 写入值到对象字段对象属性
* @param obj 值对象
* @param value 属性值
*/
public void writeValue(Object obj, Object value) {
if (readMethod != null) {
try {
writeMethod.invoke(obj, value);
} catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
throw new DbException(e);
}
} else {
((DefaultEntity)obj).put(field.getName(), value);
}
}
}

+ 26
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/dao/EntityColumnForeign.java Просмотреть файл

@@ -0,0 +1,26 @@
package cc.smtweb.framework.core.db.dao;

import lombok.Getter;

/**
* 字段外键属性
* @author admin
*/
@Getter
public class EntityColumnForeign {
private final String table;
private final String id;
private final String name;

/**
* 构造字段外键属性
* @param table 外键表名
* @param id 外键ID字段名
* @param name 外键名称字段名
*/
public EntityColumnForeign(String table, String id, String name) {
this.table = table;
this.id = id;
this.name = name;
}
}

+ 98
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/impl/BaseBean.java Просмотреть файл

@@ -0,0 +1,98 @@
package cc.smtweb.framework.core.db.impl;

import cc.smtweb.framework.core.util.JsonUtil;
import cc.smtweb.framework.core.util.NumberUtil;
import com.fasterxml.jackson.databind.JsonNode;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
* Created by Akmm at 2016-02-23 9:31
* bean基类,基于Map,
*/
public class BaseBean implements Serializable {
protected Map<String, Object> data = new HashMap<>();

public Map<String, Object> getData() {
return data;
}

public void setData(Map<String, Object> data) {
this.data = data;
}

@Override
public BaseBean clone() throws CloneNotSupportedException {
BaseBean bean = (BaseBean) super.clone();
bean.data = new HashMap<>();
bean.getData().putAll(this.data);
return bean;
}

public boolean isEmpty() {
return data.isEmpty();
}

public String getStr(String fieldName) {
return getStr(fieldName, "");
}

public String getStr(String fieldName, String defValue) {
Object o = data.get(fieldName);
return o != null ? o.toString() : defValue;
}

public double getDouble(String fieldName) {
return getDouble(fieldName, 0.0);
}

public double getDouble(String fieldName, double defValue) {
Object o = data.get(fieldName);
if (o == null) return defValue;
if (o instanceof Number) return ((Number) o).doubleValue();
return NumberUtil.getDoubleIgnoreErr(o.toString());
}

public int getInt(String fieldName) {
Object o = data.get(fieldName);
if (o == null) return 0;
if (o instanceof Number) return ((Number) o).intValue();
return NumberUtil.getIntIgnoreErr(o.toString());
}

public long getLong(String fieldName) {
Object o = data.get(fieldName);
if (o == null) return 0L;
if (o instanceof Number) return ((Number) o).longValue();
return NumberUtil.getLongIgnoreErr(o.toString());
}

public boolean getBool(String fieldName) {
Object o = data.get(fieldName);
if (o == null) return false;
String v = o.toString();
return "1".equals(v) || "t".equalsIgnoreCase(v) || "true".equalsIgnoreCase(v);
}

public void put(String fieldName, Object value) {
this.data.put(fieldName, value);
}

public void setBool(String fieldName, boolean value) {
this.data.put(fieldName, value ? 1 : 0);
}

public Object get(String fieldName) {
return this.data.get(fieldName);
}

public void readFromJson(String json){
Map map = JsonUtil.parseMap(json);
if (map != null) {
data.putAll(map);
}
}
}

+ 362
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/impl/DefaultDatabaseInfoImpl.java Просмотреть файл

@@ -0,0 +1,362 @@
package cc.smtweb.framework.core.db.impl;

import cc.smtweb.framework.core.db.DbEngine;
import cc.smtweb.framework.core.util.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.ConnectionCallback;
import org.springframework.jdbc.support.JdbcUtils;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import java.util.function.Function;

/**
* Created with IntelliJ IDEA.
* User: AKhh
* Date: 12-12-21 下午10:14
* 获取连接的数据库相关信息,from ofbiz
*/
@Slf4j
public class DefaultDatabaseInfoImpl implements IDatabaseInfo {
private static final String MODULE = DefaultDatabaseInfoImpl.class.getName();
private DbEngine dbEngine = SpringUtil.getBean(DbEngine.class);

@SuppressWarnings("unchecked")
public void printDatabaseInfo() {
dbEngine.doConn(connection -> {
try {
DatabaseMetaData dbData = connection.getMetaData();
// 数据库信息
try {
log.debug("Database Product Name is " + dbData.getDatabaseProductName(), MODULE);
log.debug("Database Product Version is " + dbData.getDatabaseProductVersion(), MODULE);
} catch (SQLException sqle) {
log.debug("Unable to get Database name & version information", MODULE);
}
// JDBC Driver Info
try {
log.debug("Database Driver Name is " + dbData.getDriverName(), MODULE);
log.debug("Database Driver Version is " + dbData.getDriverVersion(), MODULE);
} catch (SQLException sqle) {
log.debug("Unable to get Driver name & version information", MODULE);
}
// Db/Driver support settings
try {
log.debug("Database Setting/Support Information (those with a * should be true):", MODULE);
log.debug("- supports transactions [" + dbData.supportsTransactions() + "]*", MODULE);
log.debug("- isolation None [" + dbData.supportsTransactionIsolationLevel(Connection.TRANSACTION_NONE) + "]", MODULE);
log.debug("- isolation ReadCommitted [" + dbData.supportsTransactionIsolationLevel(Connection.TRANSACTION_READ_COMMITTED) + "]", MODULE);
log.debug("- isolation ReadUncommitted[" + dbData.supportsTransactionIsolationLevel(Connection.TRANSACTION_READ_UNCOMMITTED) + "]", MODULE);
log.debug("- isolation RepeatableRead [" + dbData.supportsTransactionIsolationLevel(Connection.TRANSACTION_REPEATABLE_READ) + "]", MODULE);
log.debug("- isolation Serializable [" + dbData.supportsTransactionIsolationLevel(Connection.TRANSACTION_SERIALIZABLE) + "]", MODULE);
log.debug("- is case sensitive [" + dbData.supportsMixedCaseIdentifiers() + "]", MODULE);
log.debug("- stores LowerCase [" + dbData.storesLowerCaseIdentifiers() + "]", MODULE);
log.debug("- stores MixedCase [" + dbData.storesMixedCaseIdentifiers() + "]", MODULE);
log.debug("- stores UpperCase [" + dbData.storesUpperCaseIdentifiers() + "]", MODULE);
log.debug("- max table name length [" + dbData.getMaxTableNameLength() + "]", MODULE);
log.debug("- max column name length [" + dbData.getMaxColumnNameLength() + "]", MODULE);
log.debug("- max schema name length [" + dbData.getMaxSchemaNameLength() + "]", MODULE);
log.debug("- concurrent connections [" + dbData.getMaxConnections() + "]", MODULE);
log.debug("- concurrent statements [" + dbData.getMaxStatements() + "]", MODULE);
log.debug("- ANSI SQL92 Entry [" + dbData.supportsANSI92EntryLevelSQL() + "]", MODULE);
log.debug("- ANSI SQL92 Itermediate [" + dbData.supportsANSI92IntermediateSQL() + "]", MODULE);
log.debug("- ANSI SQL92 Full [" + dbData.supportsANSI92FullSQL() + "]", MODULE);
log.debug("- ODBC SQL Grammar Core [" + dbData.supportsCoreSQLGrammar() + "]", MODULE);
log.debug("- ODBC SQL Grammar Extended[" + dbData.supportsExtendedSQLGrammar() + "]", MODULE);
log.debug("- ODBC SQL Grammar Minimum [" + dbData.supportsMinimumSQLGrammar() + "]", MODULE);
log.debug("- outer joins [" + dbData.supportsOuterJoins() + "]*", MODULE);
log.debug("- limited outer joins [" + dbData.supportsLimitedOuterJoins() + "]", MODULE);
log.debug("- full outer joins [" + dbData.supportsFullOuterJoins() + "]", MODULE);
log.debug("- group by [" + dbData.supportsGroupBy() + "]*", MODULE);
log.debug("- group by not in select [" + dbData.supportsGroupByUnrelated() + "]", MODULE);
log.debug("- column aliasing [" + dbData.supportsColumnAliasing() + "]", MODULE);
log.debug("- order by not in select [" + dbData.supportsOrderByUnrelated() + "]", MODULE);
// this doesn't work in HSQLDB, other databases? Debug.logInfo("- named parameters [" + dbData.supportsNamedParameters() + "]", MODULE);
log.debug("- alter table add column [" + dbData.supportsAlterTableWithAddColumn() + "]*", MODULE);
log.debug("- non-nullable column [" + dbData.supportsNonNullableColumns() + "]*", MODULE);
} catch (Exception e) {
log.error("Unable to get misc. support/setting information", e);
}
} catch (SQLException e) {
log.error(e.getMessage(), e);
}
return null;
});
}

//需要考虑分库的情况
@SuppressWarnings("unchecked")
public Map<String, TableCheckInfo> getTables() {
final Map<String, TableCheckInfo> tables = new TreeMap<>();
dbEngine.doConn(new Function<Connection, Object>() {
@Override
public Object apply(Connection connection) {
try {
DatabaseMetaData dbData = connection.getMetaData();
if (dbData == null) {
return null;
}
System.out.println("获取数据库表信息...............................");
boolean needsUpperCase = false;
try {
needsUpperCase = dbData.storesLowerCaseIdentifiers() || dbData.storesMixedCaseIdentifiers();
} catch (SQLException sqle) {
String message = "Error getting identifier case information... Error was:" + sqle.toString();
log.error(message, MODULE);
}
String lookupSchemaName = null;
if (dbData.supportsSchemasInTableDefinitions()) {
lookupSchemaName = dbData.getUserName();
}
if (dbEngine.isMysql()) {//非oracle才需要
String dbName = dbEngine.getDbSchema();
/*Set<String> list = .getInstance().getModelReader().getListSchema();
if (list != null && !list.isEmpty()) {
for (String catalog : list) {
getTableSet(dbData, dbName + "_" + catalog, needsUpperCase, lookupSchemaName);
}
}*/
//当前库都要去读
getTableSet(dbData, dbName, needsUpperCase, lookupSchemaName);
} else {
//当前库都要去读
getTableSet(dbData, null, needsUpperCase, lookupSchemaName);
}
} catch (SQLException e) {
log.error(e.getMessage(), e);
}
return null;
}

private void getTableSet(DatabaseMetaData dbData, String catalog, boolean needsUpperCase, String lookupSchemaName) {
ResultSet tableSet = null;
try {
String[] types = {"TABLE"/*,"VIEW", "ALIAS", "SYNONYM"*/};
tableSet = dbData.getTables(catalog, lookupSchemaName, null, types);
while (tableSet.next()) {
String tableName = tableSet.getString("TABLE_NAME");
// for those databases which do not return the schema name with the table name (pgsql 7.3)
//boolean appendSchemaName = false;
if (needsUpperCase && tableName != null) {
tableName = tableName.toUpperCase();
}
//if (appendSchemaName) {
// tableName = String.format("%s.%s", lookupSchemaName, tableName);
//}
String tableType = tableSet.getString("TABLE_TYPE");
// only allow certain table types
if (tableType != null &&
!"TABLE".equalsIgnoreCase(tableType) &&
!"BASE TABLE".equalsIgnoreCase(tableType) &&
!"VIEW".equalsIgnoreCase(tableType) &&
!"ALIAS".equalsIgnoreCase(tableType) &&
!"SYNONYM".equalsIgnoreCase(tableType)) {
continue;
}
try (ResultSet pkSet = dbData.getPrimaryKeys(catalog, lookupSchemaName, tableName)) {
String s = "";
while (pkSet.next()) {
s += "," + pkSet.getString(4);
}
TableCheckInfo table = new TableCheckInfo();
table.tableName = tableName;
table.catalog = catalog;
if (StringUtils.isNotEmpty(s)) {
table.pk = s.substring(1);
}
tables.put(tableName, table);
}
}
} catch (SQLException sqle) {
String message = "Error getting next table information... Error was:" + sqle.toString();
log.error(message, MODULE);
} finally {
JdbcUtils.closeResultSet(tableSet);
}
}
});
return tables;
}

@SuppressWarnings("unchecked")
//获取列信息
public Map<String, List<ColumnCheckInfo>> getColumnInfo(final Map<String, TableCheckInfo> dbTables) {
// if there are no tableNames, don't even try to get the columns
final Map<String, List<ColumnCheckInfo>> colInfo = new HashMap<>();
if (dbTables.size() == 0) {
return colInfo;
}
dbEngine.doConn(new Function<Connection, Object>() {
@Override
public Object apply(Connection connection) {
try {
DatabaseMetaData dbData = connection.getMetaData();
boolean needsUpperCase = false;
try {
needsUpperCase = dbData.storesLowerCaseIdentifiers() || dbData.storesMixedCaseIdentifiers();
} catch (SQLException sqle) {
String message = "Error getting identifier case information... Error was:" + sqle.toString();
log.error(message, MODULE);
}

String lookupSchemaName = null;
if (dbData.supportsSchemasInTableDefinitions()) {
lookupSchemaName = dbData.getUserName();
}

if (dbEngine.isMysql()) {//非oracle才需要
String dbName = dbEngine.getDbSchema();
/*Set<String> list = ModelConfigUtil.getInstance().getModelReader().getListSchema();
if (list != null && !list.isEmpty()) {
for (String catalog : list) {
getColumnInfo(dbData, dbName + "_" + catalog, needsUpperCase, lookupSchemaName);
}
}*/
}

getColumnInfo(dbData, null, needsUpperCase, lookupSchemaName);
} catch (SQLException e) {
log.error(e.getMessage(), e);
}
return null;
}

private void getColumnInfo(DatabaseMetaData dbData, String catalog, boolean needsUpperCase, String lookupSchemaName) {
ResultSet rsCols = null;
try {
rsCols = dbData.getColumns(catalog, lookupSchemaName, null, null);
while (rsCols.next()) {
ColumnCheckInfo ccInfo = new ColumnCheckInfo();

ccInfo.tableName = rsCols.getString("TABLE_NAME");
// for those databases which do not return the schema name with the table name (pgsql 7.3)
//boolean appendSchemaName = false;
// AKzz : 不在表名前加用户名.
//if (ccInfo.tableName != null && lookupSchemaName != null && !ccInfo.tableName.startsWith(lookupSchemaName)) {
// appendSchemaName = true;
//}
if (needsUpperCase && ccInfo.tableName != null) {
ccInfo.tableName = ccInfo.tableName.toUpperCase();
}
//if (appendSchemaName) {
// ccInfo.tableName = lookupSchemaName + "." + ccInfo.tableName;
//}
// ignore the column info if the table name is not in the list we are concerned with
if (!dbTables.containsKey(ccInfo.tableName)) {
continue;
}
ccInfo.columnName = rsCols.getString("COLUMN_NAME");
if (needsUpperCase && ccInfo.columnName != null) {
ccInfo.columnName = ccInfo.columnName.toUpperCase();
}
// NOTE: this may need a toUpperCase in some cases, keep an eye on it
ccInfo.typeName = rsCols.getString("TYPE_NAME");
ccInfo.columnSize = rsCols.getInt("COLUMN_SIZE");
ccInfo.decimalDigits = rsCols.getInt("DECIMAL_DIGITS");
// NOTE: this may need a toUpperCase in some cases, keep an eye on it
ccInfo.isNullable = rsCols.getString("IS_NULLABLE");
List<ColumnCheckInfo> tableColInfo = colInfo.get(ccInfo.tableName);
if (tableColInfo == null) {
tableColInfo = new ArrayList<>();
colInfo.put(ccInfo.tableName, tableColInfo);
}
tableColInfo.add(ccInfo);
}
} catch (SQLException sqle) {
String message = "Error getting table fields information... Error was:" + sqle.toString();
log.error(message, MODULE);
} finally {
JdbcUtils.closeResultSet(rsCols);
}
}
});
return colInfo;
}

@SuppressWarnings("unchecked")
//获取索引
public Map<String, Map<String, Set<String>>> getIndexInfo(final Collection<TableCheckInfo> tableNames, final boolean include_nounique) {
final Map<String, Map<String, Set<String>>> indexInfo = new HashMap<>();
if (!tableNames.isEmpty()) {
for (TableCheckInfo c : tableNames) {
indexInfo.put(c.tableName, new HashMap<>());
}
dbEngine.doConn(connection -> {
try {
DatabaseMetaData dbData = connection.getMetaData();
boolean needsUpperCase = false;
try {
needsUpperCase = dbData.storesLowerCaseIdentifiers() || dbData.storesMixedCaseIdentifiers();
} catch (SQLException sqle) {
String message = "Error getting identifier case information... Error was:" + sqle.toString();
log.error(message, MODULE);
}

// int totalIndices = 0;
String lookupSchemaName = null;
if (dbData.supportsSchemasInTableDefinitions()) {
lookupSchemaName = dbData.getUserName();
}

for (TableCheckInfo curTableName : tableNames) {
ResultSet rsCols = null;
try {
// false for unique, we don't really use unique indexes
// true for approximate, don't really care if stats are up-to-date
rsCols = dbData.getIndexInfo(curTableName.catalog, lookupSchemaName, curTableName.tableName, !include_nounique, true);
while (rsCols != null && rsCols.next()) {
// NOTE: The code in this block may look funny, but it is designed so that the wrapping loop can be removed
// skip all index info for statistics
if (rsCols.getShort("TYPE") == DatabaseMetaData.tableIndexStatistic) continue;
//HACK: for now skip all "unique" indexes since our foreign key indices are not unique, but the primary key ones are
//原来的方法: 只取了NON_UNIQUE == true的索引.
//if (!rsCols.getBoolean ("NON_UNIQUE")) continue;
boolean unique = rsCols.getBoolean("NON_UNIQUE");

//for (int x = 1; x<=rsCols.getMetaData().getColumnCount();x++){
// System.out.println(rsCols.getMetaData().getColumnName(x) + " = " + rsCols.getString(x));
//}

//System.out.println("INDEX_NAME=" + rsCols.getString("INDEX_NAME") + " --- "+ "COLUMN_NAME=" + rsCols.getString("COLUMN_NAME") );

//改动, 可以取所有的索引.
if (include_nounique) {
// 要取nouniqune的
} else {
// 不取nouniqune的,
if (!unique) continue;
}
String tableName = rsCols.getString("TABLE_NAME");
if (needsUpperCase && tableName != null) {
tableName = tableName.toUpperCase();
}

String indexName = rsCols.getString("INDEX_NAME");
if (needsUpperCase && indexName != null) {
indexName = indexName.toUpperCase();
}
Map<String, Set<String>> tableIndexList = indexInfo.computeIfAbsent(tableName, k -> new HashMap<>());
Set<String> set = tableIndexList.computeIfAbsent(indexName, k -> new LinkedHashSet<>());
// totalIndices++;
set.add(rsCols.getString("COLUMN_NAME"));
}
} catch (Exception e) {
log.debug("Error getting index info using lookupSchemaName " + lookupSchemaName, e);
} finally {
JdbcUtils.closeResultSet(rsCols);
}
}
} catch (SQLException e) {
log.error(e.getMessage(), e);
}
return null;
});
}
return indexInfo;
}
}

+ 62
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/impl/DefaultEntity.java Просмотреть файл

@@ -0,0 +1,62 @@
package cc.smtweb.framework.core.db.impl;

import cc.smtweb.framework.core.db.cache.ModelTableCache;
import cc.smtweb.framework.core.db.vo.ModelField;
import cc.smtweb.framework.core.db.vo.ModelTable;
import org.apache.commons.lang3.StringUtils;

import java.io.Serializable;

/**
* Created by Akmm at 14-1-2 上午11:19
* 实体bean抽象类
*/
public class DefaultEntity extends BaseBean implements Serializable, Cloneable {
//表名
private String tableName;

public DefaultEntity(String tableName) {
this.tableName = tableName;
}

public ModelTable getModelTable() {
return ModelTableCache.getInstance().getByName(tableName);
}

//根据实体定义,设默认值
public void init() {
ModelTable entity = getModelTable();
if (entity == null) return;
String pkField = getPkFieldName();
for (ModelField field : entity.getFields()) {
if (data.containsKey(field.getName())) continue;//有值了,不能动
if (field.getName().equalsIgnoreCase(pkField)) continue;//是pk,不要初始化
String s = field.getDefaultValue();
if (StringUtils.isNotEmpty(s)) put(field.getName(), s);
}
}

/** 主键字段 */
public String getPkFieldName() {
return getModelTable().getIdField();
}

public long getEntityId() {
return getLong(getPkFieldName());
}

public void setEntityId(long id) {
data.put(getPkFieldName(), id);
}

public boolean isNew() {
return getEntityId() <= 0L;
}

@Override
public DefaultEntity clone() throws CloneNotSupportedException {
DefaultEntity bean = (DefaultEntity) super.clone();
bean.getData().remove(getPkFieldName());
return bean;
}
}

+ 37
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/impl/IDatabaseInfo.java Просмотреть файл

@@ -0,0 +1,37 @@
package cc.smtweb.framework.core.db.impl;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
* Created with IntelliJ IDEA.
* User: AKhh
* Date: 12-12-21 下午10:13
* To change this template use File | Settings | File Templates.
*/
public interface IDatabaseInfo {
void printDatabaseInfo();

Map<String, TableCheckInfo> getTables();

Map<String, List<ColumnCheckInfo>> getColumnInfo(Map<String, TableCheckInfo> dbTables);

Map<String, Map<String, Set<String>>> getIndexInfo(Collection<TableCheckInfo> tableNames, boolean include_nounique);

public static class TableCheckInfo {
public String tableName;
public String catalog;
public String pk;
}

public static class ColumnCheckInfo {
public String tableName;
public String columnName;
public String typeName;
public int columnSize;
public int decimalDigits;
public String isNullable; // Y|N or "" = ie nobody knows
}
}

+ 134
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/jdbc/IdGenerator.java Просмотреть файл

@@ -0,0 +1,134 @@
package cc.smtweb.framework.core.db.jdbc;

/**
* 主键生成器。
*/
//public class IdGenerator {
// private AtomicLong key;
//
// public IdGenerator() {
// this(0);
// }
//
// /**
// *
// * @param seed 集群服务id,用于集群产生的数据不重复(0~255)
// */
// public IdGenerator(int seed) {
// long now = System.currentTimeMillis();
//
// if(seed > 0xFF){
// seed = 0xFF;
// }
//
// if(seed <= 0){
// seed = 1;
// }
//
// key = new AtomicLong(now | (((long) seed) << 48));
// }
//
// public long nextCode() {
// return key.incrementAndGet();
// }
//}

/**
* tweeter的snowflake
* time—42bits,精确到ms,那就意味着其可以表示长达(2^42-1)/(1000360024*365)=139.5年
* (a) id构成: 42位的时间前缀 + 10位的节点标识 + 12位的sequence避免并发的数字(12位不够用时强制得到新的时间前缀)
* 注意这里进行了小改动: snowkflake是5位的datacenter加5位的机器id; 这里变成使用10位的机器id
* (b) 对系统时间的依赖性非常强,需关闭ntp的时间同步功能。当检测到ntp时间调整后,将会拒绝分配id
* @author xkliu
*/
public class IdGenerator {
/**
* 起始的时间戳 epoch 2017-1-1
*/
private final static long EPOCH_STMP = 1483200000000L;

/**
* 每一部分占用的位数
*/
//序列号占用的位数
private final static long SEQUENCE_BIT = 12;
//机器标识占用的位数
private final static long MACHINE_BIT = 10;

/**
* 每一部分的最大值
*/
private final static long MAX_MACHINE_NUM = ~(-1L << MACHINE_BIT);
private final static long MAX_SEQUENCE = ~(-1L << SEQUENCE_BIT);

/**
* 每一部分向左的位移
*/
private final static long MACHINE_LEFT = SEQUENCE_BIT;
private final static long TIMESTMP_LEFT = SEQUENCE_BIT + MACHINE_BIT;

// private long datacenterId; //数据中心
// 机器标识
private long machineIdShift;
// 序列号
private long sequence = 0L;
// 上一次时间戳
private long lastStmp = -1L;

// 0 ~ 1023
public IdGenerator(long machineId) {
if (machineId > MAX_MACHINE_NUM || machineId < 0) {
throw new IllegalArgumentException("machineId " + machineId + " can't be greater than " + MAX_MACHINE_NUM + " or less than 0");
}

this.machineIdShift = machineId << MACHINE_LEFT;
}

/**
* 产生下一个ID
*
* @return ID值
*/
public synchronized long nextId() {
long currStmp = getNewStamp();
if (currStmp < lastStmp) {
throw new RuntimeException("Clock moved backwards. Refusing to generate id");
}

if (currStmp == lastStmp) {
//相同毫秒内,序列号自增
sequence = (sequence + 1) & MAX_SEQUENCE;
//同一毫秒的序列数已经达到最大
if (sequence == 0L) {
currStmp = getNextMill();
}
} else {
//不同毫秒内,序列号置为0
sequence = 0L;
}

lastStmp = currStmp;

// 时间戳部分 + 机器标识部分 + 序列号部分
return (currStmp - EPOCH_STMP) << TIMESTMP_LEFT
| machineIdShift
| sequence;
}

private long getNextMill() {
long mill = getNewStamp();
while (mill <= lastStmp) {
mill = getNewStamp();
}
return mill;
}

private long getNewStamp() {
return System.currentTimeMillis();
}

// 根据ID值反向计算时间戳
public static long queryTimestamp(long id) {
return (id >>> TIMESTMP_LEFT) + EPOCH_STMP;
}
}

+ 411
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/jdbc/JdbcEngine.java Просмотреть файл

@@ -0,0 +1,411 @@
package cc.smtweb.framework.core.db.jdbc;

import cc.smtweb.framework.core.SwMap;
import cc.smtweb.framework.core.exception.DbException;
import cc.smtweb.framework.core.util.JsonUtil;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;

/**
* JDBC访问类,包装了spring jdbcTemplate对象
*/
public class JdbcEngine {
private final static String DB_TYPE_MYSQL = "mysql";

private JdbcTemplate jdbcTemplate;
private DataSourceTransactionManager dataSourceTransactionManager;
private IdGenerator idGenerator;

protected String type;

public JdbcEngine(JdbcTemplate jdbcTemplate, IdGenerator idGenerator, String type) {
this.jdbcTemplate = jdbcTemplate;
this.dataSourceTransactionManager = new DataSourceTransactionManager(jdbcTemplate.getDataSource());
this.idGenerator = idGenerator;
this.type = type;
}

public boolean isMysql() {
return DB_TYPE_MYSQL.equalsIgnoreCase(type);
}

/**
* 获取数据库唯一id
*
* @return 返回ID值
*/
public long nextId() {
return this.idGenerator.nextId();
}

/**
* 查询单行数据
*
* @param sql 查询SQL
* @param rowHandler ResultSet处理器
* @param <T> 返回得对象类型
* @return 返回单个对象数据
*/
public <T> T queryEntity(String sql, final ResultSetExtractor<T> rowHandler) {
return jdbcTemplate.query(sql, rowHandler);
}

/**
* 查询单行数据
*
* @param sql 查询SQL
* @param rowHandler ResultSet处理器
* @param params SQL参数
* @param <T> 返回得对象类型
* @return 返回单个对象数据
*/
public <T> T queryEntity(String sql, final ResultSetExtractor<T> rowHandler, Object... params) {
return jdbcTemplate.query(sql, rowHandler, params);
}

/**
* 通过回调函数查询SQL,返回列表或者对象数据
*/
public <T> T query(String sql, ResultSetExtractor<T> rse, Object... params) {
return jdbcTemplate.query(sql, rse, params);
}

/**
* 查询SQL,返回列表数据
*/
public <T> List<T> query(String sql, RowMapper<T> rowMapper) {
return jdbcTemplate.query(sql, rowMapper);
}

/**
* 查询SQL,返回列表数据
*/
public <T> List<T> query(String sql, RowMapper<T> rowMapper, Object... params) {
return jdbcTemplate.query(sql, rowMapper, params);
}

/**
* 翻页查询
*/
public <T> List<T> pagedQuery(String sql, RowMapper<T> rowMapper, int start, int limit, Object... params) {
return jdbcTemplate.query(sql + " LIMIT " + start + "," + limit, rowMapper, params);
}

/**
* 执行更新SQL
*/
public int update(String sql) {
return jdbcTemplate.update(sql);
}

/**
* 执行更新SQL
*/
public int update(String sql, Object... params) {
return jdbcTemplate.update(sql, params);
}

/**
* 执行更新语句直到无更新数据或者达到最大修改记录数
*
* @param sql 需要执行的SQL语句
* @param limit 每次更新的条数
* @param count 最大更新次数
* @param params 执行参数
* @return 返回更新的数据数量
*/
public int pagedUpdate(String sql, int limit, int count, Object... params) {
int result = 0;
for (int i = 0, ret = 1; i < count && ret > 0; i++) {
ret = jdbcTemplate.update(sql + " LIMIT " + limit, params);
if (ret > 0) {
result += ret;
}
}

return result;
}

/**
* 查询字符list
*
* @param sql 查询SQL
* @param params 查询SQL参数
* @return 字符list
*/
public List<String> queryStringList(String sql, Object... params) {
return jdbcTemplate.query(sql, (resultSet, i) -> resultSet.getString(1), params);
}

/**
* 查询字符set
*
* @param sql 查询SQL
* @param params 查询SQL参数
* @return 字符set
*/
public Set<String> queryStringSet(String sql, Object... params) {
return jdbcTemplate.query(sql, (resultSet) -> {
Set<String> result = new HashSet<>();
while (resultSet.next()) {
String value = resultSet.getString(1);
if (value != null) {
result.add(value);
}
}

return result;
}, params);
}

/**
* 查询字符
*
* @param sql 查询SQL
* @param params 查询SQL参数
* @return 字符
*/
public String queryString(String sql, Object... params) {
List<String> list = jdbcTemplate.query(sql, (resultSet, i) -> resultSet.getString(1), params);
if (list != null && !list.isEmpty()) {
return list.get(0);
}

return null;
}

/**
* 查询值为JSON格式,转换为对象返回
*
* @param sql 查询SQL
* @param clazz 对象类
* @param params 查询SQL参数
* @param <T> 对象类型
* @return JSON格式,转换为对象返回
*/
public <T> T queryJson(String sql, Class<T> clazz, Object... params) {
List<String> list = jdbcTemplate.query(sql, (resultSet, i) -> resultSet.getString(1), params);
if (list != null && !list.isEmpty()) {
String s = list.get(0);
if (StringUtils.isNotBlank(s)) {
return JsonUtil.parse(s, clazz);
} else {
try {
return clazz.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new DbException(e);
}
}
}

return null;
}

/**
* 查询Long对象
*
* @param sql 查询SQL
* @param params 查询SQL参数
* @return Long对象
*/
public Long queryLong(String sql, Object... params) {
List<Long> list = jdbcTemplate.query(sql, (resultSet, i) -> resultSet.getLong(1), params);
if (list != null && !list.isEmpty()) {
return list.get(0);
}

return null;
}

/**
* 查询List<Long>对象
*
* @param sql 查询SQL
* @param params 查询SQL参数
* @return List<Long>对象
*/
public List<Long> queryLongList(String sql, Object... params) {
return jdbcTemplate.query(sql, (resultSet, i) -> resultSet.getLong(1), params);
}

/**
* 查询Set<Long>对象
*
* @param sql 查询SQL
* @param params 查询SQL参数
* @return Set<Long>对象
*/
public Set<Long> queryLongSet(String sql, Object... params) {
return jdbcTemplate.query(sql, (resultSet) -> {
Set<Long> result = new HashSet<>();
while (resultSet.next()) {
long value = resultSet.getLong(1);
if (!resultSet.wasNull()) {
result.add(value);
}
}

return result;
}, params);
}

/**
* 查询Integer对象
*
* @param sql 查询SQL
* @param params 查询SQL参数
* @return Integer对象
*/
public Integer queryInt(String sql, Object... params) {
List<Integer> list = jdbcTemplate.query(sql, (resultSet, i) -> resultSet.getInt(1), params);
if (list != null && !list.isEmpty()) {
return list.get(0);
}

return null;
}

/**
* 执行批量更新语句
*
* @param sql SQL语句
* @param params 数组参数列表
* @return 执行结果数组
*/
public int[] batchUpdate(String sql, List<Object[]> params) {
return jdbcTemplate.batchUpdate(sql, params);
}

/**
* 启动事务,需要用try(DbTrans dbTrans=dbEngine.openTrans())来处理异常后自动回滚事务,如果手工提交事务DbTaans.commit()
*
* @return 事务对象
*/
public JdbcTrans openTrans() {
return new JdbcTrans(this.dataSourceTransactionManager);
}

/**
* 在回调函数中执行事务,返回的true就提交事务,否则回滚事务
*
* @param extractor 回调方法
* @return 事务是否成功,如果异常会也会事务回滚后再抛出异常
*/
public boolean doTrans(Supplier<Boolean> extractor) {
try (JdbcTrans jdbcTrans = openTrans()) {
boolean result = extractor.get();
if (result) {
jdbcTrans.commit();
return true;
}
}

return false;
}

/**
* 获取原始数据库连接执行命令
*
* @return 数据库连接
*/
public <T> T doConn(Function<Connection, T> extractor) {
DataSource ds = Objects.requireNonNull(this.jdbcTemplate.getDataSource());

try (Connection conn = ds.getConnection()) {
return extractor.apply(conn);
} catch (SQLException e) {
throw new DbException(e);
}
}

/**
* 查询单行数据,返回bean
*/
public <T> T queryEntity(String sql, Class<T> type) {
List<T> list = jdbcTemplate.query(sql, createRowMapper(type));

if (list != null && !list.isEmpty()) {
return list.get(0);
}

return null;
}

/**
* 查询单行数据,返回bean
*/
public <T> T queryEntity(String sql, Class<T> type, Object... params) {
List<T> list = query(sql, createRowMapper(type), params);

if (list != null && !list.isEmpty()) {
return list.get(0);
}

return null;
}

/**
* 通过回调函数查询SQL,返回列表或者对象数据
*/
public <T> T query(String sql, ResultSetExtractor<T> rse) {
return jdbcTemplate.query(sql, rse);
}

/**
* 查询SQL,返回列表数据
*/
public <T> List<T> query(String sql, Class<T> type) {
return jdbcTemplate.query(sql, createRowMapper(type));
}

/**
* 查询SQL,返回列表数据
*/
public <T> List<T> query(String sql, Class<T> type, Object... params) {
return jdbcTemplate.query(sql, createRowMapper(type), params);
}

/**
* 翻页查询
*/
public <T> List<T> pagedQuery(String sql, Class<T> type, int start, int limit) {
return jdbcTemplate.query(sql + " LIMIT " + start + "," + limit, createRowMapper(type));
}

private <T> RowMapper<T> createRowMapper(Class<T> type) {
RowMapper<T> rowMapper;
if (java.util.Map.class.isAssignableFrom(type)) {
if (SwMap.class.equals(type)) {
rowMapper = new SwMapPropertyRowMapper<>(type);
} else {
rowMapper = new MapPropertyRowMapper<>(type);
}
} else {
rowMapper = new BeanPropertyRowMapper<>(type);
}
return rowMapper;
}

/**
* 翻页查询
*/
public <T> List<T> pagedQuery(String sql, Class<T> type, int start, int limit, Object... params) {
return jdbcTemplate.query(sql + " LIMIT " + start + "," + limit, createRowMapper(type), params);
}
}

+ 56
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/jdbc/JdbcTrans.java Просмотреть файл

@@ -0,0 +1,56 @@
package cc.smtweb.framework.core.db.jdbc;

import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

/**
* JDBC事务处理类,可以在try中使用自动结束事务
* @author xkliu
*/
public class JdbcTrans implements AutoCloseable {
private DataSourceTransactionManager transactionManager;
private TransactionStatus status;

/**
* 构造事务执行
* @param transactionManager spring事务管理对象
*/
public JdbcTrans(DataSourceTransactionManager transactionManager) {
this.transactionManager = transactionManager;
// 事务定义类
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
// 返回事务对象
this.status = transactionManager.getTransaction(def);
}

/**
* 回滚事务
*/
public void rollback() {
if (status != null) {
transactionManager.rollback(status);
status = null;
}
}

/**
* 提交事务
*/
public void commit() {
if (status != null) {
transactionManager.commit(status);
status = null;
}
}

/**
* 实现自动关闭,回滚方式结束事务
*/
@Override
public void close() {
this.rollback();
}
}

+ 39
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/jdbc/MapPropertyRowMapper.java Просмотреть файл

@@ -0,0 +1,39 @@
package cc.smtweb.framework.core.db.jdbc;

import org.springframework.beans.BeanUtils;
import org.springframework.jdbc.core.RowMapper;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

/**
* ORM映射处理器,实现spring jdbcTemplate的行集映射器
* @author xkliu
*/
public class MapPropertyRowMapper<T> implements RowMapper<T> {
private Class<T> mappedClass;

public MapPropertyRowMapper(Class<T> mappedClass) {
this.mappedClass = mappedClass;
}

@Override
public T mapRow(ResultSet resultSet, int i) throws SQLException {
T mappedObject = BeanUtils.instantiateClass(this.mappedClass);
java.util.Map map = (java.util.Map)mappedObject;

ResultSetMetaData rsmd = resultSet.getMetaData();
int columnCount = rsmd.getColumnCount();

for(int index = 1; index <= columnCount; ++index) {
Object value = resultSet.getObject(index);

if (value != null) {
map.put(rsmd.getColumnLabel(index), value);
}
}

return mappedObject;
}
}

+ 59
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/jdbc/SwMapPropertyRowMapper.java Просмотреть файл

@@ -0,0 +1,59 @@
package cc.smtweb.framework.core.db.jdbc;

import cc.smtweb.framework.core.SwMap;
import org.springframework.jdbc.core.RowMapper;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

/**
* ORM映射处理器,实现spring jdbcTemplate的行集映射器,对下划线进行小驼峰命名转化
* @author xkliu
*/
public class SwMapPropertyRowMapper<T> implements RowMapper<T> {
public SwMapPropertyRowMapper(Class<T> mappedClass) {
}

@Override
public T mapRow(ResultSet resultSet, int i) throws SQLException {
SwMap map = new SwMap();

ResultSetMetaData rsmd = resultSet.getMetaData();
int columnCount = rsmd.getColumnCount();

for(int index = 1; index <= columnCount; ++index) {
Object value = resultSet.getObject(index);

if (value != null) {
String columnLabel = rsmd.getColumnLabel(index);
map.put(toCamelCase(columnLabel), value);
}
}

return (T)map;
}

private String toCamelCase(String columnLabel) {
int len = columnLabel.length();
StringBuilder sb = new StringBuilder(len);
int lowCase = 1;
for (int i = 0; i < len; i++) {
char ch = columnLabel.charAt(i);
if (ch == '_') {
lowCase = 2;
} else {
if (lowCase == 1) {
ch = Character.toLowerCase(ch);
lowCase = 0;
} else if (lowCase == 2) {
ch = Character.toUpperCase(ch);
lowCase = 0;
}
sb.append(ch);
}
}

return sb.toString();
}
}

+ 129
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/sqlbuilder/AbstractSelectSqlBuilder.java Просмотреть файл

@@ -0,0 +1,129 @@
package cc.smtweb.framework.core.db.sqlbuilder;

import cc.smtweb.framework.core.db.DbEngine;
import cc.smtweb.framework.core.db.jdbc.JdbcEngine;

import java.util.ArrayList;
import java.util.List;
import java.util.function.BiFunction;

public class AbstractSelectSqlBuilder extends SqlBuilder<AbstractSelectSqlBuilder> {
private List<String> orderBy;

protected void makeFields(StringBuilder sb) {
}

protected Object[] makeParams(StringBuilder sb) {
makeFields(sb);

if (wheres != null) {
List<Object> params = new ArrayList<>(wheres.size());

if (wheres.size() > 0) {
String logicOp = " AND ";
boolean addLoginOp = false;

for (int i = 0; i < wheres.size(); i++) {
SqlWhereValue whereValue = wheres.get(i);

if (i == 0) {
sb.append(" WHERE ");
}

if (whereValue.getName() == null) {
Object value = whereValue.getValue();

if ("(".equals(value)) {
if (i > 0) {
sb.append(logicOp);
}
addLoginOp = false;
}

sb.append(value);
logicOp = whereValue.getOp();
} else {
if (addLoginOp) {
sb.append(logicOp);
} else {
addLoginOp = true;
}

sb.append(whereValue.getName()).append(whereValue.getOp()).append('?');
params.add(whereValue.getValue());
}
}
}

if (orderBy != null) {
for (int i = 0; i < orderBy.size(); i++) {
if (i == 0) {
sb.append(" ORDER BY ");
} else {
sb.append(",");
}

sb.append(orderBy.get(i));
}
}

return params.toArray(new Object[params.size()]);
}

return null;
}

@Override
public AbstractSelectSqlBuilder addOrderBy(String orderByField) {
if (this.orderBy == null) {
this.orderBy = new ArrayList<>();
}

this.orderBy.add(orderByField);

return this;
}

public <T> List<T> query(DbEngine dbEngine, Class<T> clazz) {
return exec((sql, params) -> dbEngine.query(sql, clazz, params));
}

public <T> T queryEntity(DbEngine dbEngine, Class<T> clazz) {
return exec((sql, params) -> dbEngine.queryEntity(sql, clazz, params));

// StringBuilder sb = new StringBuilder("select ");
//
// Object[] params = makeParams(sb);
//
// return dbEngine.queryEntity(sb.toString(), clazz, params);
}

public <T> T exec(BiFunction<String, Object[], T> execute) {
StringBuilder sb = new StringBuilder("select ");

Object[] params = makeParams(sb);

return execute.apply(sb.toString(), params);
}

public <T> List<T> pagedQuery(DbEngine dbEngine, Class<T> clazz, int start, int limit) {
return exec((sql, params) -> dbEngine.pagedQuery(sql, clazz, start, limit, params));
// StringBuilder sb = new StringBuilder("select ");
//
// Object[] params = makeParams(sb);
//
// return dbEngine.pagedQuery(sb.toString(), clazz, start, limit, params);
}

public int queryInt(JdbcEngine dbEngine) {
return exec(dbEngine::queryInt);
}

public SqlJoinTable addJoinTable(String dbName, String tableName, String tableAlias) {
return null;
}

public SqlJoinTable findJoinTable(String dbName, String tableName) {
return null;
}
}

+ 20
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/sqlbuilder/AbstractUpdateSqlBuilder.java Просмотреть файл

@@ -0,0 +1,20 @@
package cc.smtweb.framework.core.db.sqlbuilder;

import cc.smtweb.framework.core.db.jdbc.JdbcEngine;

public abstract class AbstractUpdateSqlBuilder<T extends AbstractUpdateSqlBuilder> extends SqlBuilder<T> {
// 无效的更新值,用以占位表示不组装值到params对象里面
public static final Object VALUE_INVALID = new SqlFieldValue("", "");

public boolean isEmpty() {
return fields.isEmpty();
}

public abstract int update(JdbcEngine dbEngine);

public void updateMap(java.util.Map<String, Object> map) {
for (SqlFieldValue field: fields) {
map.put(field.getName(), field.getValue());
}
}
}

+ 33
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/sqlbuilder/DeleteSqlBuilder.java Просмотреть файл

@@ -0,0 +1,33 @@
package cc.smtweb.framework.core.db.sqlbuilder;

import cc.smtweb.framework.core.db.jdbc.JdbcEngine;

public class DeleteSqlBuilder extends AbstractUpdateSqlBuilder<DeleteSqlBuilder> {
private String tableName;

DeleteSqlBuilder(String tableName) {
this.tableName = tableName;
}

@Override
public int update(JdbcEngine dbEngine) {
int fieldSize = wheres.size();
Object[] params = new Object[fieldSize];

StringBuilder sb = new StringBuilder("delete from ");

sb.append(tableName).append(" where ");

int index = 0;
for (SqlWhereValue whereValue: wheres) {
if (index > 0){
sb.append(" and ");
}
sb.append(whereValue.getName()).append("=?");
params[index] = whereValue.getValue();
index++;
}

return dbEngine.update(sb.toString(), params);
}
}

+ 20
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/sqlbuilder/DirectSelectSqlBuilder.java Просмотреть файл

@@ -0,0 +1,20 @@
package cc.smtweb.framework.core.db.sqlbuilder;

import java.util.function.BiFunction;

public class DirectSelectSqlBuilder extends AbstractSelectSqlBuilder {
private String sql;

DirectSelectSqlBuilder(String sql) {
this.sql = sql;
}

@Override
public <T> T exec(BiFunction<String, Object[], T> execute) {
StringBuilder sb = new StringBuilder(sql);

Object[] params = makeParams(sb);

return execute.apply(sb.toString(), params);
}
}

+ 38
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/sqlbuilder/InsertSqlBuilder.java Просмотреть файл

@@ -0,0 +1,38 @@
package cc.smtweb.framework.core.db.sqlbuilder;

import cc.smtweb.framework.core.db.jdbc.JdbcEngine;

public class InsertSqlBuilder extends AbstractUpdateSqlBuilder<InsertSqlBuilder> {
private String tableName;

InsertSqlBuilder(String tableName) {
this.tableName = tableName;
}

@Override
public int update(JdbcEngine dbEngine) {
int fieldSize = fields.size();
Object[] params = new Object[fieldSize];

StringBuilder sb = new StringBuilder("insert into ");
sb.append(tableName).append('(');

for (int i = 0; i < fieldSize; i++) {
SqlFieldValue field = fields.get(i);
sb.append(field.getName()).append(',');
params[i] = field.getValue();
}

sb.setCharAt(sb.length() - 1, ')');

sb.append(" values(");

for (int i = 0; i < fieldSize; i++) {
sb.append("?,");
}

sb.setCharAt(sb.length() - 1, ')');

return dbEngine.update(sb.toString(), params);
}
}

+ 98
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/sqlbuilder/SelectSqlBuilder.java Просмотреть файл

@@ -0,0 +1,98 @@
package cc.smtweb.framework.core.db.sqlbuilder;

import cc.smtweb.framework.core.db.DbEngine;
import cc.smtweb.framework.core.db.jdbc.JdbcEngine;

import java.util.ArrayList;
import java.util.List;
import java.util.function.BiFunction;

public class SelectSqlBuilder extends AbstractSelectSqlBuilder {
private String tableName;
private List<SqlJoinTable> joinTables;

SelectSqlBuilder(String tableName) {
this.tableName = tableName;
}

// @Override
// public <T> List<T> query(DbEngine dbEngine, Class<T> clazz) {
// StringBuilder sb = new StringBuilder("select ");
//
// Object[] params = makeParams(sb);
//
// if (params != null) {
// return dbEngine.query(sb.toString(), clazz, params);
// } else {
// return dbEngine.query(sb.toString(), clazz);
// }
// }

@Override
protected void makeFields(StringBuilder sb) {
for (SqlFieldValue field: fields) {
sb.append(field.getName()).append(",");
}

sb.setCharAt(sb.length() - 1, ' ');
sb.append("FROM ").append(tableName);

if (joinTables != null) {
for (SqlJoinTable joinTable: joinTables) {
sb.append(joinTable.joinSql()).append(joinTable.getDbName()).append('.').append(joinTable.getTableName())
.append(' ').append(joinTable.getTableAlias()).append(" ON(");

boolean first = true;
for (SqlJoinField joinField: joinTable.getFields()) {
if (first) {
first = false;
} else {
sb.append(" AND ");
}

sb.append(joinField.getKeyField()).append("=").append(joinField.getValueField());
}

sb.append(')');
}
}
}

@Override
public <T> T exec(BiFunction<String, Object[], T> execute) {
StringBuilder sb = new StringBuilder("select ");

Object[] params = makeParams(sb);

return execute.apply(sb.toString(), params);
}

@Override
public SqlJoinTable addJoinTable(String dbName, String tableName, String tableAlias) {
if (joinTables == null) {
joinTables = new ArrayList<>();
}

SqlJoinTable joinTable = new SqlJoinTable();
joinTable.setDbName(dbName);
joinTable.setTableName(tableName);
joinTable.setTableAlias(tableAlias);

joinTables.add(joinTable);

return joinTable;
}

@Override
public SqlJoinTable findJoinTable(String dbName, String tableName) {
if (joinTables != null) {
for (SqlJoinTable table: joinTables) {
if (dbName.equals(table.getDbName()) && tableName.equals(table.getTableName())) {
return table;
}
}
}

return null;
}
}

+ 84
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/sqlbuilder/SqlBuilder.java Просмотреть файл

@@ -0,0 +1,84 @@
package cc.smtweb.framework.core.db.sqlbuilder;

import java.util.ArrayList;
import java.util.List;

/**
* SQL语句建造器
* @author admin
* @param <T> 建造器类型
*/
public abstract class SqlBuilder<T extends SqlBuilder> {
protected List<SqlFieldValue> fields = new ArrayList<>();
protected List<SqlWhereValue> wheres;

SqlBuilder() {
}

public static InsertSqlBuilder createInsert(String tableName) {
return new InsertSqlBuilder(tableName);
}
public static UpdateSqlBuilder createUpdate(String tableName) {
return new UpdateSqlBuilder(tableName);
}
public static SelectSqlBuilder createSelect(String tableName) {
return new SelectSqlBuilder(tableName);
}
public static DeleteSqlBuilder createDelete(String tableName) {
return new DeleteSqlBuilder(tableName);
}

public static InsertSqlBuilder createInsert(String dbName, String tableName) {
return new InsertSqlBuilder(dbName + "." + tableName);
}

public static UpdateSqlBuilder createUpdate(String dbName, String tableName) {
return new UpdateSqlBuilder(dbName + "." + tableName);
}

public static AbstractSelectSqlBuilder createSelect(String dbName, String tableName) {
return new SelectSqlBuilder(dbName + "." + tableName);
}

public static AbstractSelectSqlBuilder createDirectSelect(String sql) {
return new DirectSelectSqlBuilder(sql);
}

public static DeleteSqlBuilder createDelete(String dbName, String tableName) {
return new DeleteSqlBuilder(dbName + "." + tableName);
}

public T add(String fieldName) {
fields.add(new SqlFieldValue(fieldName, null));
return (T)this;
}

public T add(String fieldName, Object fieldValue) {
fields.add(new SqlFieldValue(fieldName, fieldValue));
return (T)this;
}

public T addWhere(String fieldName, Object fieldValue, String op) {
if (wheres == null) {
wheres = new ArrayList<>();
}
wheres.add(new SqlWhereValue(fieldName, fieldValue, op));
return (T)this;
}

public T addWhere(String fieldName, Object fieldValue) {
return addWhere(fieldName, fieldValue, "=");
}

public T addWhereOrBegin() {
return addWhere(null, "(", " or ");
}

public T addWhereOrEnd() {
return addWhere(null, ")", " and ");
}

public T addOrderBy(String orderBy) {
return (T)this;
}
}

+ 14
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/sqlbuilder/SqlFieldValue.java Просмотреть файл

@@ -0,0 +1,14 @@
package cc.smtweb.framework.core.db.sqlbuilder;

import lombok.Getter;

@Getter
class SqlFieldValue {
private final String name;
private final Object value;

public SqlFieldValue(String name, Object value) {
this.name = name;
this.value = value;
}
}

+ 15
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/sqlbuilder/SqlJoinField.java Просмотреть файл

@@ -0,0 +1,15 @@
package cc.smtweb.framework.core.db.sqlbuilder;

import lombok.Data;
import lombok.Getter;

@Getter
public class SqlJoinField {
private String keyField;
private String valueField;

public SqlJoinField(String keyField, String valueField) {
this.keyField = keyField;
this.valueField = valueField;
}
}

+ 39
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/sqlbuilder/SqlJoinTable.java Просмотреть файл

@@ -0,0 +1,39 @@
package cc.smtweb.framework.core.db.sqlbuilder;

import lombok.Data;

import java.util.ArrayList;
import java.util.List;

/**
* SelectSqlBuilder使用的查询关联表
* @author xkliu
*/
@Data
public class SqlJoinTable {
public static final int LEFT_JOIN = 1;
public static final int RIGHT_JOIN = 2;
public static final int INNER_JOIN = 3;
public static final int FULL_JOIN = 4;

private int joinType = LEFT_JOIN;
private String dbName;
private String tableName;
private String tableAlias;

private List<SqlJoinField> fields = new ArrayList<>();

public void add(String keyField, String valueField) {
fields.add(new SqlJoinField(keyField, valueField));
}

public String joinSql() {
switch (joinType) {
default:
case LEFT_JOIN: return " LEFT JOIN ";
case RIGHT_JOIN: return " RIGHT JOIN ";
case INNER_JOIN: return " INNER JOIN ";
case FULL_JOIN: return " FULL JOIN ";
}
}
}

+ 13
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/sqlbuilder/SqlWhereValue.java Просмотреть файл

@@ -0,0 +1,13 @@
package cc.smtweb.framework.core.db.sqlbuilder;

import lombok.Getter;

class SqlWhereValue extends SqlFieldValue {
@Getter
private String op;

public SqlWhereValue(String name, Object value, String op) {
super(name, value);
this.op = op;
}
}

+ 55
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/sqlbuilder/UpdateSqlBuilder.java Просмотреть файл

@@ -0,0 +1,55 @@
package cc.smtweb.framework.core.db.sqlbuilder;

import cc.smtweb.framework.core.db.jdbc.JdbcEngine;

import java.util.ArrayList;
import java.util.List;

public class UpdateSqlBuilder extends AbstractUpdateSqlBuilder<UpdateSqlBuilder> {
private String tableName;

UpdateSqlBuilder(String tableName) {
this.tableName = tableName;
}

@Override
public int update(JdbcEngine dbEngine) {
int fieldSize = fields.size() + wheres.size();
List<Object> params = new ArrayList<>(fieldSize);
// Object[] params = new Object[fieldSize];

StringBuilder sb = new StringBuilder("update ");

sb.append(tableName).append(" set ");

// int index = 0;
for (SqlFieldValue field: fields) {
if (field.getValue() == VALUE_INVALID) {
sb.append(field.getName());
} else {
sb.append(field.getName()).append("=?,");
params.add(field.getValue());
}
// params[index] = field.getValue();
// index++;
}

sb.setCharAt(sb.length() - 1, ' ');
sb.append("where ");

boolean first = true;
for (SqlWhereValue whereValue: wheres) {
if (first) {
first = false;
} else {
sb.append(" and ");
}
sb.append(whereValue.getName()).append("=?");
params.add(whereValue.getValue());
// params[index]
// index++;
}

return dbEngine.update(sb.toString(), params.toArray());
}
}

+ 9
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/vo/KeyValueVO.java Просмотреть файл

@@ -0,0 +1,9 @@
package cc.smtweb.framework.core.db.vo;

import lombok.Data;

@Data
public class KeyValueVO {
private String key;
private String value;
}

+ 30
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/vo/ModelCache.java Просмотреть файл

@@ -0,0 +1,30 @@
package cc.smtweb.framework.core.db.vo;

import lombok.Data;

import java.util.List;

/**
* 表缓存信息定义:{"name":"tn","title":"按表名","fields":"table_name","type":"M"}
* Created by Akmm at 2022/2/21 16:22
*/
@Data
public class ModelCache {
//按map缓存
public static String CACHE_TYPE_MAP = "M";
//按list缓存
public static String CACHE_TYPE_LIST = "L";

//缓存名,根据此名称去获取缓存信息 getByKey的参数
private String name;
//缓存中文名,给人看的
private String title;
//字段,多个字段,键值以下划线分隔
private String fields;
//缓存类别:list/map
private String type;

public boolean isMapType() {
return CACHE_TYPE_MAP.equalsIgnoreCase(type);
}
}

+ 27
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/vo/ModelCatalog.java Просмотреть файл

@@ -0,0 +1,27 @@
package cc.smtweb.framework.core.db.vo;

import lombok.Data;

import java.io.Serializable;

/**
* 目录
*/
@Data
public class ModelCatalog implements Serializable {
private long id;
private long parentId;
//项目id
private long prjId;
//目录编码及名称
private String code;
private String name;
//创建者
private Long createUid;
//创建时间
private Long createTime;
//最后更新人
private Long updateUid;
//更新时间
private Long updateTime;
}

+ 31
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/vo/ModelDatabase.java Просмотреть файл

@@ -0,0 +1,31 @@
package cc.smtweb.framework.core.db.vo;

import cc.smtweb.framework.core.annotation.SwTable;
import lombok.Data;

import java.io.Serializable;
import java.util.Map;

@Data
@SwTable(value = "ASP_MODEL_DATABASE")
public class ModelDatabase implements Serializable {
private long id;
//项目id
private long prjId;
// 库名
private String name;
//中文标题
private String title;
//状态:0-启用 1-停用
private int status;
//版本
private int version;
//创建者
private Long createUid;
//创建时间
private Long createTime;
//最后更新人
private Long updateUid;
//更新时间
private Long updateTime;
}

+ 38
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/vo/ModelField.java Просмотреть файл

@@ -0,0 +1,38 @@
package cc.smtweb.framework.core.db.vo;

import cc.smtweb.framework.core.db.vo.def.DataType;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;

import java.util.List;

/**
* 字段定义
* {name:"字段名,如id",fieldType:"字段类型,如编码字段", dataType:"数据类型,如ID/CODE/NAME等", null:"0-空/1-非空", default: "默认值", title:"中文名",link:"外键关联表",editor:"控件类型:TEXT/TextArea/NUMBER/COMBO"}
*/
@Data
public class ModelField {
private String name;
private String title;
private String remark;
//字段类型,如编码字段,参见FieldTypeDef
private String fieldType;
/**
* 数据类型,参见DataType
*/
private String dataType;
/**
* '禁止为空'
*/
@JsonProperty("null")
private int notNull;
/**
* '默认值'
*/
@JsonProperty("default")
private String defaultValue;
//外键关联表
private String link;
//控件类型:TEXT/TextArea/NUMBER/COMBO
private String editor;
}

+ 20
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/vo/ModelIndex.java Просмотреть файл

@@ -0,0 +1,20 @@
package cc.smtweb.framework.core.db.vo;

import lombok.Data;

import java.util.ArrayList;
import java.util.List;

/**
* 索引定义 {name:"索引名称,如idx_t1", fields:"字段,如f1,f2", type="索引类别:P-主键 I-一般索引 U-唯一索引"}
*/
@Data
public class ModelIndex {
public static final String TYPE_PRIMARY = "P";
public static final String TYPE_INDEX = "I";
public static final String TYPE_UNIQUE = "U";

private String type;
private String name;
private String fields;
}

+ 29
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/vo/ModelProject.java Просмотреть файл

@@ -0,0 +1,29 @@
package cc.smtweb.framework.core.db.vo;

import lombok.Data;

import java.io.Serializable;

/**
* 项目
*/
@Data
public class ModelProject implements Serializable {
private long id;
// 项目名称
private String name;
//依赖项目
private String depends;
//状态:0-启用 1-停用
private int status;
//备注
private String desc;
//创建者
private Long createUid;
//创建时间
private Long createTime;
//最后更新人
private Long updateUid;
//更新时间
private Long updateTime;
}

+ 142
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/vo/ModelTable.java Просмотреть файл

@@ -0,0 +1,142 @@
package cc.smtweb.framework.core.db.vo;

import cc.smtweb.framework.core.annotation.SwTable;
import cc.smtweb.framework.core.db.vo.def.FieldType;
import cc.smtweb.framework.core.util.JsonUtil;
import lombok.Data;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

@Data
@SwTable(value="ASP_MODEL_TABLE")
public class ModelTable implements Serializable {
private long id;
//所属数据库id及名称
private long databaseId;
//项目id
private long prjoectId;
//目录id
private long catalogId;
//库表名
private String name;
//中文名
private String title;
//缩写
private String abbr;
//继承的表
private String tableExtends;
//类型 0-普通表,1 树型表 2 编码表 9-虚拟抽象表 11 视图'
private int type;
//表定义
private String tableContent;
//是否需要缓存
private boolean needCache;
//创建者
private Long createUid;
//创建时间
private Long createAt;
//最后更新人
private Long updateUid;
//更新时间
private Long updateAt;

/*冗余*/
private String idField;
private String dbName;

private List<ModelField> fields = new ArrayList<>();
private List<ModelIndex> indexes = new ArrayList<>();
private List<ModelCache> caches = new ArrayList<>();

public ModelField findField(String fieldName) {
if (fieldName != null && fields != null) {
for (ModelField modelField : fields) {
if (fieldName.equals(modelField.getName())) {
return modelField;
}
}
}

return null;
}

public String fullName() {
return dbName + '.' + name;
}

public void addIndex(ModelIndex modelIndex) {
indexes.add(modelIndex);
}

public ModelIndex findIndexByName(String indexName) {
for (ModelIndex modelIndex : indexes) {
if (indexName.equals(modelIndex.getName())) {
return modelIndex;
}
}

return null;
}

public ModelIndex findPrimaryIndex() {
for (ModelIndex modelIndex : indexes) {
if (ModelIndex.TYPE_PRIMARY.equalsIgnoreCase(modelIndex.getType())) {
return modelIndex;
}
}

return null;
}

public ModelField findFieldByName(String name) {
if (name != null) {
for (ModelField value : fields) {
if (name.equalsIgnoreCase(value.getName())) {
return value;
}
}
}

return null;
}

public ModelField findFieldByType(FieldType type) {
if (type != null) {
for (ModelField value : fields) {
if (type.name().equalsIgnoreCase(value.getFieldType())) {
return value;
}
}
}

return null;
}

public ModelField findIdField() {
ModelIndex index = findPrimaryIndex();
if (index != null) {
return findField(index.getFields());
}

return null;
}

public void setTableContent(String tableContent) {
this.tableContent = tableContent;
//读取表定义信息
ModelTable bean = JsonUtil.parse(tableContent, ModelTable.class);
if (bean == null) {
return;
}
this.fields = bean.fields;
this.indexes = bean.indexes;
this.caches = bean.caches;

ModelIndex i = findPrimaryIndex();
if (i != null) {
this.idField = i.getFields();
}
}
}

+ 33
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/vo/def/DataType.java Просмотреть файл

@@ -0,0 +1,33 @@
package cc.smtweb.framework.core.db.vo.def;

import lombok.Data;

/**
* 数据类型定义,参见design_db.yaml配置
*/
@Data
public class DataType {
/*{type: "id", name: "ID", sql-type: "bigint", java-type: "long", widget: "fz-field-long", defaultValue: "0"}
- {type: "code", name: "编码", sql-type: "varchar", java-type: "string", data-length: 32, widget: "fz-field-string", defaultValue: ""}
- {type: "name", name: "名字", sql-type: "varchar", java-type: "string", data-length: 100, widget: "fz-field-string", defaultValue: ""}
- {type: "remark", name: "备注", sql-type: "varchar", data-length: 255, java-type: "string", widget: "fz-field-string", defaultValue: ""}
- {type: "text", name: "大文本", sql-type: "text", java-type: "string", widget: "fz-field-string", defaultValue: ""}
- {type: "currency", name: "货币", sql-type: "bigint", java-type: "long", widget: "fz-field-long", defaultValue: "0"}
- {type: "datetime", name: "时间日期", sql-type: "bigint", java-type: "long", widget: "fz-field-datetime", defaultValue: "0"}
- {type: "date", name: "日期", sql-type: "int", java-type: "int", widget: "fz-field-date", defaultValue: "0"}
- {type: "time", name: "时间", sql-type: "int", java-type: "int", widget: "fz-field-time", defaultValue: "0"}
- {type: "int", name: "整型", sql-type: "int", java-type: "int", widget: "fz-field-int", defaultValue: "0"}
- {type: "smallint", name: "短整型", sql-type: "smallint", java-type: "short", widget: "fz-field-int", defaultValue: "0"}
- {type: "bool", name: "布尔型", sql-type: "tinyint", java-type: "boolean", widget: "fz-field-bool", defaultValue: "0"}*/
public static final String TYPE_STR = "varchar";
public static final String TYPE_BOOL = "bool";
public static final String TYPE_DATETIME = "datetime";
public static final String TYPE_DATE = "date";

private String type;
private String name;
private String sqlType;
private int dataLength;
private String javaType;
private String defaultValue;
}

+ 22
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/db/vo/def/FieldType.java Просмотреть файл

@@ -0,0 +1,22 @@
package cc.smtweb.framework.core.db.vo.def;

/**
* Created by Akmm at 2022/2/9 10:01
* 字段业务类别
*/
public enum FieldType {
// 主键
ID,
// 上级ID,树结构需要
PARENT_ID,
// 排序字段,树结构需要
ORDER,
// 编码字段
CODE,
// 名词字段
NAME,
// 创建时间
CREATE_TIME,
// 更新时间
LAST_TIME
}

+ 41
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/exception/BindBeanException.java Просмотреть файл

@@ -0,0 +1,41 @@
package cc.smtweb.framework.core.exception;

import cc.smtweb.framework.core.SwException;

/**
* bean绑定错误
* @author kevin
* @since 2010-9-14 上午11:17:43
*
*/
public class BindBeanException extends SwException {

/**
*
*/
private static final long serialVersionUID = 1L;
private static String msg = "绑定bean异常:Context中已经存在这个bean: ";

public BindBeanException() {
super();
// TODO Auto-generated constructor stub
}

public BindBeanException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
}

public BindBeanException(String message) {
super(msg+message);
// TODO Auto-generated constructor stub
}

public BindBeanException(Throwable cause) {
super(cause);
// TODO Auto-generated constructor stub
}

}

+ 34
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/exception/BindParamException.java Просмотреть файл

@@ -0,0 +1,34 @@
package cc.smtweb.framework.core.exception;

import cc.smtweb.framework.core.SwException;

import java.text.ParseException;

public class BindParamException extends SwException {
/**
*
*/
private static final long serialVersionUID = 1L;
private String paramName;

public String getParamName() {
return paramName;
}

public BindParamException(String message, String paramName) {
this(message, null, paramName);
}

public BindParamException(Exception e, String paramName) {
this(e.getMessage(), e, paramName);
}

public BindParamException(String message, Exception e, String paramName) {
super("[" + paramName + "]" + message, e);
this.paramName = paramName;
}

public BindParamException(ParseException e) {
super(e);
}
}

+ 29
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/exception/BizException.java Просмотреть файл

@@ -0,0 +1,29 @@
package cc.smtweb.framework.core.exception;

/**
* 业务异常
* @author kevin
*
*/
public class BizException extends RuntimeException {
/**
*
*/
private static final long serialVersionUID = 1L;

public BizException() {
super();
}

public BizException(String message, Throwable cause) {
super(message, cause);
}

public BizException(String message) {
super(message);
}

public BizException(Throwable cause) {
super(cause.getMessage(), cause);
}
}

+ 13
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/exception/CacheException.java Просмотреть файл

@@ -0,0 +1,13 @@
package cc.smtweb.framework.core.exception;

import cc.smtweb.framework.core.SwException;

public class CacheException extends SwException {
public CacheException(String message) {
super(message);
}

public CacheException(Throwable e) {
super(e);
}
}

+ 33
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/exception/DbException.java Просмотреть файл

@@ -0,0 +1,33 @@
package cc.smtweb.framework.core.exception;

import cc.smtweb.framework.core.SwException;

/**
* bean绑定错误
* @author kevin
* @since 2010-9-14 上午11:17:43
*
*/
public class DbException extends RuntimeException {

/**
*
*/
private static final long serialVersionUID = 1L;

public DbException() {
super();
}

public DbException(String message, Throwable cause) {
super(message, cause);
}

public DbException(String message) {
super(message);
}

public DbException(Throwable cause) {
super(cause.getMessage(), cause);
}
}

+ 105
- 0
smtweb-framework/sw-framework-core/src/main/java/cc/smtweb/framework/core/exception/ExceptionMessage.java Просмотреть файл

@@ -0,0 +1,105 @@
package cc.smtweb.framework.core.exception;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.apache.commons.lang3.StringUtils;

import java.util.Set;

/**
* 错误码 JDK version used: <JDK1.8>
*
* @author kevin
* @version v1.0
*/
@Setter
@Getter
@ToString
public class ExceptionMessage {
private int code;

private String msg;

private ExceptionMessage(int code, String msg) {
this.code = code;
this.msg = msg;
}

// 401
public static ExceptionMessage NO_AUTH_ERROR = new ExceptionMessage(401, "登录失效!");

// 403
public static ExceptionMessage FORBIDDEN_ERROR = new ExceptionMessage(403, "没有访问权限!");

// 404
public static ExceptionMessage NOT_FOUND_ERROR = new ExceptionMessage(404, "没有找到需要资源!");

// 通用异常
public static ExceptionMessage INNER_ERROR = new ExceptionMessage(100100, "内部服务错误,请稍后再试!");

// 参数错误
public static ExceptionMessage PARAM_ERROR = new ExceptionMessage(100101, "参数校验失败!");

// 数据库访问异常
public static ExceptionMessage DB_ERROR = new ExceptionMessage(100102, "数据库访问失败!");

// 外部网络访问异常
public static ExceptionMessage NETWORK_ERROR = new ExceptionMessage(100103, "外部网络访问失败!");

// 字符转换异常
public static ExceptionMessage UNSUPPORTED_ENCODING_ERROR = new ExceptionMessage(100104, "字符编码失败!");

// 没有登录
public static ExceptionMessage NO_LOGIN_ERROR = new ExceptionMessage(100105, "用户没有登录!");

// 没有登录
public static ExceptionMessage CAPTCHA_ERROR = new ExceptionMessage(100106, "验证码错误!");

// 用户不存在
public static ExceptionMessage USER_ERROR = new ExceptionMessage(100107, "手机号或密码错误,请重新输入!");

// 用户被禁
public static ExceptionMessage USER_FORBIDED = new ExceptionMessage(100108, "用户被禁!");

// 密码错误
public static ExceptionMessage PASSWORD_ERROR = new ExceptionMessage(100109, "密码错误,请重新输入!");

// 文件上传失败
public static ExceptionMessage FILE_UPLOAD_ERROR = new ExceptionMessage(100110, "文件上传失败!");

// 文件不存在
public static ExceptionMessage FILE_NOT_EXIST = new ExceptionMessage(100111, "文件不存在!");

// 树形层级只有6级
public static ExceptionMessage TREE_HIERARCHY_ERROR = new ExceptionMessage(100112, "树形层级过多!");

// 手机号被使用了
public static ExceptionMessage PHONE_ERROR = new ExceptionMessage(100113, "手机号被使用了!");

// 手机号不存在
public static ExceptionMessage PHONE_EXISTS_ERROR = new ExceptionMessage(100114, "手机号不存在!");

// 消息发送要延迟
public static ExceptionMessage SM_SEND_NEED_DELAY = new ExceptionMessage(100115, "验证码有效时间");

// 身份不能确认
public static ExceptionMessage IDENTITY_ERROR = new ExceptionMessage(100116, "请选择登录身份!");

// 身份不能确认
public static ExceptionMessage USER_PERMISSION_CHANGE = new ExceptionMessage(100117, "权限变更,请选择退出重新登录!");

// 数据发生变更
public static ExceptionMessage DATA_CHANGE_ERROR = new ExceptionMessage(100118, "数据发生变更,请刷新后重试!");

// 数据发生变更
public static ExceptionMessage SM_SEND_ERROR = new ExceptionMessage(100119, "验证码发生失败!");

// 敏感词
public static ExceptionMessage XSS_ERROR = new ExceptionMessage(100120, "含有敏感词,请检查。");

// 树形层级数量太多
public static ExceptionMessage TREE_NUMBER_ERROR = new ExceptionMessage(100121, "树形该层节点过多!");

public static ExceptionMessage APP_ID_NOT_EXISTS = new ExceptionMessage(100122, "不存在的应用ID");
}

Некоторые файлы не были показаны из-за большого количества измененных файлов

Загрузка…
Отмена
Сохранить