Compare commits

..

26 Commits

Author SHA1 Message Date
曾文豪
f27d8d1658 publish 2.0.2 2024-08-28 20:40:43 +08:00
曾文豪
ba9d0da33f remove:移除了poi模块 2024-08-28 20:39:52 +08:00
曾文豪
4690fa9f88 perf:调整登录日志,同时限制登录失败次数(10分钟内最多5次) 2024-08-28 20:35:38 +08:00
曾文豪
a9f218de89 perf:移除encrypt模块,直接集成到web模块中 2024-08-28 19:41:45 +08:00
曾文豪
55324199cd feat:枚举表增加sort排序字段 2024-08-28 19:34:03 +08:00
曾文豪
0b32559630 feat:新增接口 /comm/role/group 获取角色、职位列表 2024-08-28 19:29:45 +08:00
曾文豪
01cc4f16ad perf:调用日志可以筛选 url 2024-08-28 19:22:26 +08:00
曾文豪
2b70c8121d publish 2.0.1 2024-08-27 13:41:58 +08:00
曾文豪
fd30c5cf36 perf:key不用实现TsAuthorityHandler类 2024-08-27 13:41:00 +08:00
曾文豪
0310bd4a15 perf:更新用户职位的时候,清除缓存 2024-08-27 13:38:57 +08:00
曾文豪
80ec6d2e3d perf:操作日志实时插入 2024-08-27 13:32:15 +08:00
曾文豪
d96f17b847 perf:调用日志只保存json,xml,text格式的返回值 2024-08-27 11:08:36 +08:00
曾文豪
7648eef981 perf:hutool.version放到parent中 2024-08-26 14:28:12 +08:00
曾文豪
79087f33e4 perf:过程日志改造 2024-08-26 13:47:31 +08:00
曾文豪
d0289d38b3 publish 2.0.0.rc46 2024-08-26 13:31:03 +08:00
曾文豪
90029faa53 publish 2.0.0.rc44 2024-08-26 13:23:51 +08:00
曾文豪
ecb5aa1b29 perf:过程日志改造 2024-08-26 13:20:45 +08:00
曾文豪
1db8ef9d85 publish 2.0.0.rc42 2024-08-23 15:04:40 +08:00
曾文豪
4bcae2f8d1 perf:移除hutool-json,直接使用fastjson 2024-08-23 15:04:20 +08:00
曾文豪
9bab4cdb25 feat:jwt中的hutool-json改为fastjson 2024-08-23 14:10:47 +08:00
曾文豪
856a9f01dd feat:把hutool的jwt直接放入util中 2024-08-23 11:38:29 +08:00
曾文豪
e57cd5e1c8 publish 2.0.0.rc40 2024-08-23 11:15:48 +08:00
曾文豪
542e23ac1b publish 2.0.0.rc38 2024-08-23 11:12:16 +08:00
曾文豪
6949f50c7c publish 2.0.0.rc37 2024-08-22 17:13:29 +08:00
曾文豪
7b43ae3ce1 publish 2.0.0.rc36 2024-08-22 17:09:14 +08:00
曾文豪
8ca283ca85 perf:登录的时候清除授权信息,相当于刷新一下权限 2024-08-22 09:46:04 +08:00
110 changed files with 2999 additions and 918 deletions

BIN
.DS_Store vendored

Binary file not shown.

View File

@@ -1,3 +1,12 @@
## 2.0.0.rc46
现在导入导出都接入底层流程,无需新增接口,只需要实现接口即可。
- 过程日志不再和操作日志同时存在
- 过程日志新增params参数
- 通过实现*TsImportHandler*接口编写导入逻辑
- 通过实现*TsExportHandler*接口编写导出逻辑
## 2.0.0.rc4
- perfTsTokenConfig不在提供静态方法

34
pom.xml
View File

@@ -6,7 +6,7 @@
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-parent</artifactId>
<version>2.0.0.rc35</version>
<version>2.0.2</version>
<packaging>pom</packaging>
<name>springboot-parent</name>
<description>杭州铁晟科技有限公司基础依赖</description>
@@ -23,10 +23,8 @@
<module>springboot-login</module>
<module>springboot-web</module>
<module>springboot-util</module>
<module>springboot-poi</module>
<module>springboot-platform</module>
<module>springboot-message</module>
<module>springboot-encrypt</module>
<module>springboot-annotation</module>
<module>springboot-role</module>
</modules>
@@ -35,6 +33,8 @@
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<hutool.version>5.8.31</hutool.version>
</properties>
<developers>
@@ -58,61 +58,49 @@
<dependency>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-database</artifactId>
<version>2.0.0.rc35</version>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-login</artifactId>
<version>2.0.0.rc35</version>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-web</artifactId>
<version>2.0.0.rc35</version>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-util</artifactId>
<version>2.0.0.rc35</version>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-platform</artifactId>
<version>2.0.0.rc35</version>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-message</artifactId>
<version>2.0.0.rc35</version>
</dependency>
<dependency>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-encrypt</artifactId>
<version>2.0.0.rc35</version>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-role</artifactId>
<version>2.0.0.rc35</version>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-annotation</artifactId>
<version>2.0.0.rc35</version>
</dependency>
<dependency>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-poi</artifactId>
<version>2.0.0.rc35</version>
<version>2.0.2</version>
</dependency>
<dependency>

View File

@@ -6,11 +6,11 @@
<parent>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-parent</artifactId>
<version>2.0.0.rc35</version>
<version>2.0.2</version>
</parent>
<artifactId>springboot-ademo</artifactId>
<version>2.0.0.rc35</version>
<version>2.0.2</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>

View File

@@ -23,9 +23,8 @@ public class DemoWebConfigurer implements TieshengWebConfigurer, TsLoginConfigur
@Override
public RequestUserInfo getCurrentUserName(TokenBean tokenBean) {
RequestUserInfo info = new RequestUserInfo();
if (Objects.equals(tokenBean.getId(), "1")) {
return info;
}
info.setId(tokenBean.getId());
info.setName(tokenBean.getExtra());
return info;
}

View File

@@ -1,37 +1,39 @@
package com.tiesheng.demo.controller;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.io.FileUtil;
import cn.hutool.log.LogFactory;
import cn.hutool.poi.excel.ExcelUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tiesheng.annotation.role.RoleAuthority;
import com.tiesheng.annotation.token.TokenIgnore;
import com.tiesheng.database.config.DbBackupConfig;
import com.tiesheng.demo.pojos.JsonTest;
import com.tiesheng.demo.pojos.PoiBean;
import com.tiesheng.demo.pojos.TestFile;
import com.tiesheng.platform.config.ding.PlatformDingConfig;
import com.tiesheng.platform.config.ding.bean.DingUserInfo;
import com.tiesheng.util.config.EncryptConfig;
import com.tiesheng.util.config.GlobalConfig;
import com.tiesheng.util.config.Ip2regionConfig;
import com.tiesheng.util.config.TsTokenConfig;
import com.tiesheng.util.exception.ApiException;
import com.tiesheng.util.pojos.ApiResp;
import com.tiesheng.util.pojos.FileUploadPath;
import com.tiesheng.util.service.TsCacheService;
import com.tiesheng.util.service.http.OkHttpUtil;
import com.tiesheng.web.service.CoreLogService;
import com.tiesheng.web.util.ProcessImportConsumer;
import okhttp3.Request;
import okhttp3.Response;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
@@ -70,7 +72,16 @@ public class TestController {
@RequestMapping("/redirect")
@TokenIgnore
@RoleAuthority("redirect")
public ApiResp<String> redirect(HttpServletResponse response) {
public ApiResp<JsonTest> redirect(@RequestBody JsonTest dto, HttpServletResponse response) {
JsonTest jsonTest = new JsonTest();
jsonTest.setNow(DateUtil.date());
jsonTest.setNow1(DateUtil.date());
String jsonString = JSON.toJSONString(jsonTest);
LogFactory.get().info(jsonString);
LogFactory.get().info(JSON.toJSONString(dto));
// ArrayList<String> strings = CollUtil.newArrayList("11111", "22222");
// coreLogService.addProcess("fdfd", strings, new ProcessImportConsumer<String>() {
@@ -92,7 +103,7 @@ public class TestController {
// tsTokenConfig.validToken("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NzYwMDY4NzUsImlkIjoiMSIsImVudmlyb25tZW50VHlwZSI6Im1vYmlsZSIsInNlcnZpY2UiOiJjb250ZXN0LXJlc2VydmUiLCJleHRyYSI6IiJ9.nsfxEFpCNHC7eNCS5DJXdu1VDdnHrTjSfgrozND70Lc", true);
// globalConfig.redirect("mobile", "/test", response);
return ApiResp.respOK("");
return ApiResp.respOK(jsonTest);
}
@@ -148,16 +159,6 @@ public class TestController {
return ApiResp.respOK(search);
}
@RequestMapping("desensitize")
@TokenIgnore
public ApiResp<List<TestFile>> desensitize() {
TestFile file = new TestFile("11111");
file.setTest("111111");
TestFile file1 = new TestFile("22222");
file1.setTest("22222");
return ApiResp.respOK(CollUtil.newArrayList(file, file1));
}
@RequestMapping("passwd")
@TokenIgnore
@@ -195,18 +196,31 @@ public class TestController {
return ApiResp.respOK("");
}
@RequestMapping("poiTool")
@GetMapping("getwxacode")
@TokenIgnore
public ApiResp<String> poiTool() {
TimeInterval timeInterval = new TimeInterval();
FileUploadPath file = FileUploadPath.file("/upload/test.xlsx");
ExcelUtil.getReader(new File(file.getAbsolutePath())).read();
System.out.println("timeInterval: " + timeInterval.interval());
return ApiResp.respOK("");
public ApiResp<String> getwxacode() {
String id = "test_1111111";
FileUploadPath path = FileUploadPath.random("png");
JSONObject paramJson = new JSONObject();
paramJson.put("page", "pages/login/index");
paramJson.put("scene", "no=" + id);
paramJson.put("env_version", "develop");
paramJson.put("width", 430);
paramJson.put("is_hyaline", false);
paramJson.put("auto_color", false);
FileUploadPath file = FileUploadPath.file(id + ".png");
try {
Request request = OkHttpUtil.ofPost("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" +
"83_7xqG36kdgwuf8zzWLY3jtz7bg4ucziN-0oxbE0X9zBzwbjZ4S4Ss2RM9uHeSIcRp2K-wEp6MLzWhqo2AXj0Jpzd6IiJdUsRxqdHPvEWqAdOgt83vzZwdDf7tZBkGNGeAFASZS",
paramJson);
Response execute1 = OkHttpUtil.ofHttpClient().build().newCall(request).execute();
FileUtil.writeFromStream(execute1.body().byteStream(), file.getAbsolutePath());
execute1.close();
} catch (Exception e) {
throw new ApiException("每分钟最多生成5000个二维码请稍后再试");
}
return ApiResp.respOK(path.getHttpPath());
}
}

View File

@@ -0,0 +1,60 @@
package com.tiesheng.demo.pojos;
import com.alibaba.fastjson.annotation.JSONField;
import java.util.Date;
public class JsonTest {
private Date now;
@JSONField(format = "yyyy-MM-dd")
private Date now1;
private String no;
private String name;
private JsonTest child;
///////////////////////////////////////////////////////////////////////////
// setter\getter
///////////////////////////////////////////////////////////////////////////
public Date getNow() {
return now;
}
public void setNow(Date now) {
this.now = now;
}
public Date getNow1() {
return now1;
}
public void setNow1(Date now1) {
this.now1 = now1;
}
public String getNo() {
return no;
}
public void setNo(String no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public JsonTest getChild() {
return child;
}
public void setChild(JsonTest child) {
this.child = child;
}
}

View File

@@ -1,21 +0,0 @@
package com.tiesheng.demo.pojos;
import com.tiesheng.poi.pojos.PoiWriteBase;
public class TestFile extends TestParent implements PoiWriteBase {
private String name;
public TestFile(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@@ -1,33 +0,0 @@
package com.tiesheng.demo.pojos;
import com.tiesheng.annotation.desensitize.Desensitize;
import com.tiesheng.poi.pojos.PoiWriteBase;
public class TestParent implements PoiWriteBase {
private String id;
@Desensitize()
private String test;
///////////////////////////////////////////////////////////////////////////
// setter、getter
///////////////////////////////////////////////////////////////////////////
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTest() {
return test;
}
public void setTest(String test) {
this.test = test;
}
}

View File

@@ -1,8 +1,7 @@
package com.tiesheng.demo.service;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.tiesheng.message.config.aliyun.AliyunSmsHandler;
import com.tiesheng.message.config.aliyun.AliyunTempParam;
import org.springframework.stereotype.Service;
@@ -15,16 +14,17 @@ public class DemoSmsHandler implements AliyunSmsHandler {
@Override
public AliyunTempParam handler(JSONObject obj) {
String action = obj.getStr("action");
String action = obj.getString("action");
AliyunTempParam param = new AliyunTempParam();
param.setSignName("智慧校园");
if (Objects.equals(action, "sms-visitor-invite")) {
param.setTemplateCode("SMS_276125463");
param.setTemplateParam(JSONUtil.createObj()
.putOpt("date", DateUtil.today())
);
JSONObject object = new JSONObject();
object.put("date", DateUtil.today());
param.setTemplateParam(object);
}
return param;

View File

@@ -0,0 +1,39 @@
package com.tiesheng.demo.service;
import cn.hutool.core.collection.CollUtil;
import com.tiesheng.util.pojos.TokenBean;
import com.tiesheng.web.pojos.imex.ImportDealDTO;
import com.tiesheng.web.service.imex.TsImportHandler;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserImportHandler implements TsImportHandler<String> {
@Override
public List<String> ready(ImportDealDTO dto, TokenBean token) {
return CollUtil.newArrayList("11111");
}
@Override
public String getTemplateUrl() {
return "/template/xsxxzx_teacher_leader.xlsx";
}
@Override
public String getAction() {
return "user_import";
}
@Override
public int batchHandler(List<String> list) {
return 0;
}
@Override
public String getResultFile() {
return "";
}
}

View File

@@ -7,8 +7,9 @@ spring:
url: jdbc:mysql://47.96.30.85:3306/com_tiesheng_web?useSSL=false&useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&queryTimeout=5400&allowMultiQueries=true&serverTimezone=GMT%2B8
username: com_tiesheng_web
password: 4Xo$XheGFc
# redis:
# url: redis://kyF0zUL3011111@47.96.30.85:6234
redis:
url: redis://kyF0zUL3011111@47.96.30.85:6234
database: 1
platform:
ding:

View File

@@ -0,0 +1,42 @@
package com.tiesheng.demo;
import cn.hutool.core.date.DateUtil;
import cn.hutool.log.LogFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONPath;
import com.tiesheng.demo.pojos.JsonTest;
import com.tiesheng.login.pojos.RequestUserInfo;
public class MainTest {
public static void main(String[] args) {
MainTest test = new MainTest();
test.testJsonSelf();
}
private void testJsonSelf() {
RequestUserInfo info = new RequestUserInfo();
info.setId("1");
info.setName("name");
info.setData(info);
String jsonStr = JSON.toJSONString(info);
LogFactory.get().info(jsonStr);
}
private void testJsonPath() {
JsonTest jsonTest = new JsonTest();
jsonTest.setNo("1111");
jsonTest.setName("1111");
jsonTest.setNow(DateUtil.date());
jsonTest.setChild(jsonTest);
JSONPath jsonPath = JSONPath.compile("child.no");
String eval = jsonPath.eval(jsonTest, String.class);
LogFactory.get().info(eval);
}
}

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-parent</artifactId>
<version>2.0.0.rc35</version>
<version>2.0.2</version>
</parent>
<artifactId>springboot-annotation</artifactId>

View File

@@ -1,16 +0,0 @@
package com.tiesheng.annotation.desensitize;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* @author hao
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface Desensitize {
int prefix() default 1;
int suffix() default 1;
}

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-parent</artifactId>
<version>2.0.0.rc35</version>
<version>2.0.2</version>
</parent>
<artifactId>springboot-database</artifactId>

Binary file not shown.

View File

@@ -1,40 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-parent</artifactId>
<version>2.0.0.rc35</version>
</parent>
<artifactId>springboot-encrypt</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-util</artifactId>
</dependency>
<dependency>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-annotation</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,10 +0,0 @@
package com.tiesheng.encrypt;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan({
"com.tiesheng.encrypt.**.*",
})
public class EncryptAutoConfigurer {
}

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-parent</artifactId>
<version>2.0.0.rc35</version>
<version>2.0.2</version>
</parent>
<artifactId>springboot-login</artifactId>

View File

@@ -65,7 +65,7 @@ public class LoginController {
@OperationIgnore
public void uniqueIndex(UniqueIndexDTO dto, HttpServletResponse response) {
if (tsTokenConfig.isValidLoginSign() && !dto.validSign()) {
corePlatformUniqueService.onSignError(response);
corePlatformUniqueService.redirect(null, dto.getTo(), dto.getExtra(), response);
return;
}
@@ -86,7 +86,7 @@ public class LoginController {
public ApiResp<String> uniqueIndex(@RequestBody UniqueIndexDTO dto) {
TokenBean tokenBean = corePlatformUniqueService.login(new DoLoginInfo("web_unique_index",
dto.getNo(), dto.getPlatform(), dto.getInfo()));
if (tokenBean == null || StrUtil.isEmpty(tokenBean.getId())) {
if (!TsTokenConfig.validToken(tokenBean)) {
throw new ApiException("登录失败");
}
return ApiResp.respOK(tokenBean.toToken());
@@ -219,7 +219,7 @@ public class LoginController {
WxminiLoginVo loginVo = new WxminiLoginVo();
loginVo.setOpenid(openid);
if (tokenBean != null) {
if (TsTokenConfig.validToken(tokenBean)) {
loginVo.setToken(tokenBean.toToken());
}
return ApiResp.respOK(loginVo);

View File

@@ -2,6 +2,17 @@ package com.tiesheng.login.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.tiesheng.login.pojos.dao.CoreLogLogin;
import org.apache.ibatis.annotations.Param;
public interface CoreLogLoginMapper extends BaseMapper<CoreLogLogin> {
/**
* 获取登录失败的次数
*
* @param ip
* @return
*/
int getLoginErrorTimes(@Param("ip") String ip);
}

View File

@@ -1,5 +1,9 @@
package com.tiesheng.login.pojos;
import com.tiesheng.util.ServletKit;
import javax.servlet.http.HttpServletRequest;
public class DoLoginInfo {
private String appId;
@@ -7,12 +11,17 @@ public class DoLoginInfo {
private String platform;
private String info;
private String extra;
private String loginIp;
public DoLoginInfo(String appId, String unique, String platform, String info) {
this.appId = appId;
this.unique = unique;
this.platform = platform;
this.info = info;
// 设置IP
HttpServletRequest request = ServletKit.getRequest();
this.loginIp = ServletKit.getClientIP(request);
}
///////////////////////////////////////////////////////////////////////////
@@ -58,4 +67,12 @@ public class DoLoginInfo {
public void setExtra(String extra) {
this.extra = extra;
}
public String getLoginIp() {
return loginIp;
}
public void setLoginIp(String loginIp) {
this.loginIp = loginIp;
}
}

View File

@@ -16,13 +16,13 @@ public class CoreLogLogin extends DaoBase {
private String userId;
/**
* 用户id
* 用户姓名
*/
@TableField(value = "user_name")
private String userName;
/**
* ip
* 登录方式
*/
@TableField(value = "platform")
private String platform;
@@ -39,6 +39,18 @@ public class CoreLogLogin extends DaoBase {
@TableField(value = "address")
private String address;
/**
* 登录结果,0否1是
*/
@TableField(value = "`result`")
private Integer result;
/**
* 请求参数
*/
@TableField(value = "params")
private String params;
/**
* 获取用户id
*
@@ -57,18 +69,38 @@ public class CoreLogLogin extends DaoBase {
this.userId = userId;
}
/**
* 获取用户姓名
*
* @return user_name - 用户姓名
*/
public String getUserName() {
return userName;
}
/**
* 设置用户姓名
*
* @param userName 用户姓名
*/
public void setUserName(String userName) {
this.userName = userName;
}
/**
* 获取登录方式
*
* @return platform - 登录方式
*/
public String getPlatform() {
return platform;
}
/**
* 设置登录方式
*
* @param platform 登录方式
*/
public void setPlatform(String platform) {
this.platform = platform;
}
@@ -108,4 +140,40 @@ public class CoreLogLogin extends DaoBase {
public void setAddress(String address) {
this.address = address;
}
/**
* 获取登录结果,0否1是
*
* @return result - 登录结果,0否1是
*/
public Integer getResult() {
return result;
}
/**
* 设置登录结果,0否1是
*
* @param result 登录结果,0否1是
*/
public void setResult(Integer result) {
this.result = result;
}
/**
* 获取请求参数
*
* @return params - 请求参数
*/
public String getParams() {
return params;
}
/**
* 设置请求参数
*
* @param params 请求参数
*/
public void setParams(String params) {
this.params = params;
}
}

View File

@@ -1,22 +1,24 @@
package com.tiesheng.login.service;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.alibaba.fastjson.JSON;
import com.tiesheng.login.mapper.CoreLogLoginMapper;
import com.tiesheng.login.mapper.CorePlatformUniqueMapper;
import com.tiesheng.login.pojos.DoLoginInfo;
import com.tiesheng.login.pojos.RequestUserInfo;
import com.tiesheng.login.pojos.dao.CoreLogLogin;
import com.tiesheng.login.pojos.dao.CorePlatformUnique;
import com.tiesheng.util.ServletKit;
import com.tiesheng.util.config.Ip2regionConfig;
import com.tiesheng.util.config.TsTokenConfig;
import com.tiesheng.util.exception.ApiException;
import com.tiesheng.util.pojos.TokenBean;
import com.tiesheng.util.service.TsCacheService;
import com.tiesheng.util.service.TsServiceBase;
import com.tiesheng.util.service.role.TsAuthorityHandler;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Objects;
@@ -37,6 +39,11 @@ public class CorePlatformUniqueService extends TsServiceBase<CorePlatformUniqueM
@Transactional(rollbackFor = Exception.class)
public TokenBean login(DoLoginInfo loginInfo) {
int loginErrorTimes = coreLogLoginMapper.getLoginErrorTimes(loginInfo.getLoginIp());
if (loginErrorTimes > 4) {
throw new ApiException("登录失败已达5次请10分钟后再试");
}
CorePlatformUnique platformUnique = getOneByColumn("unique_id", loginInfo.getUnique());
if (platformUnique == null) {
platformUnique = new CorePlatformUnique();
@@ -47,21 +54,33 @@ public class CorePlatformUniqueService extends TsServiceBase<CorePlatformUniqueM
platformUnique.setInfo(loginInfo.getInfo());
saveOrUpdate(platformUnique);
String oldUserId = platformUnique.getUserId();
TokenBean tokenBean = tsLoginConfigurer.login(platformUnique);
if (tokenBean != null) {
TokenBean tokenBean = null;
String errorMsg = null;
try {
tokenBean = tsLoginConfigurer.login(platformUnique);
} catch (Exception e) {
errorMsg = e.getMessage();
}
// 添加登录日志
addLoginLog(platformUnique, tokenBean);
if (TsTokenConfig.validToken(tokenBean)) {
// 清除授权信息
TsCacheService.of().remove(StrUtil.format(TsAuthorityHandler.CACHE_AUTHORITY,
tokenBean.getRoleId(), tokenBean.getId()));
// 更新唯一值
String oldUserId = platformUnique.getUserId();
if (!StrUtil.isEmpty(tokenBean.getId()) &&
!Objects.equals(oldUserId, tokenBean.getId())) {
platformUnique.setUserId(tokenBean.getId());
saveOrUpdate(platformUnique);
}
}
addLoginLog(tokenBean, loginInfo);
if (StrUtil.isNotEmpty(errorMsg)) {
throw new ApiException(errorMsg);
}
return tokenBean;
@@ -74,40 +93,37 @@ public class CorePlatformUniqueService extends TsServiceBase<CorePlatformUniqueM
* @param bean
*/
public void redirect(TokenBean bean, String to, String extra, HttpServletResponse response) {
tsLoginConfigurer.redirect(bean, to, extra, response);
if (TsTokenConfig.validToken(bean)) {
tsLoginConfigurer.redirect(bean, to, extra, response);
} else {
tsLoginConfigurer.onLoginError(to, response);
}
}
/**
* 签名错误的时候
*/
public void onSignError(HttpServletResponse response) {
tsLoginConfigurer.onSignError(response);
}
///////////////////////////////////////////////////////////////////////////
// 登录日志
///////////////////////////////////////////////////////////////////////////
/**
* 添加登录日志
*
* @param platformUnique
* @param tokenBean
* @param info
*/
public void addLoginLog(CorePlatformUnique platformUnique, TokenBean tokenBean) {
HttpServletRequest request = ServletKit.getRequest();
String ip = ServletUtil.getClientIP(request);
public void addLoginLog(TokenBean tokenBean, DoLoginInfo info) {
CoreLogLogin login = new CoreLogLogin();
login.setUserId(tokenBean.getId());
login.setPlatform(platformUnique.getPlatform());
login.setPlatform(info.getPlatform());
login.setParams(JSON.toJSONString(info));
RequestUserInfo requestUserInfo = tsLoginConfigurer.getCachedUserInfo(tokenBean, true);
login.setUserName(requestUserInfo.getName());
if (TsTokenConfig.validToken(tokenBean)) {
RequestUserInfo requestUserInfo = tsLoginConfigurer.getCachedUserInfo(tokenBean, true);
login.setUserId(tokenBean.getId());
login.setUserName(requestUserInfo.getName());
login.setResult(1);
} else {
login.setUserName(info.getUnique());
login.setResult(0);
}
login.setIp(ip);
login.setIp(info.getLoginIp());
login.setAddress(ip2regionConfig.search(login.getIp()));
coreLogLoginMapper.insert(login);
}

View File

@@ -1,9 +1,9 @@
package com.tiesheng.login.service;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.tiesheng.login.pojos.RequestUserInfo;
import com.tiesheng.login.pojos.dao.CorePlatformUnique;
import com.tiesheng.util.ServletKit;
import com.tiesheng.util.config.TsTokenConfig;
import com.tiesheng.util.pojos.TokenBean;
import com.tiesheng.util.service.TsCacheService;
@@ -34,10 +34,10 @@ public interface TsLoginConfigurer {
/**
* 签名错误的时候
* 登录失败的时候
*/
default void onSignError(HttpServletResponse response) {
ServletUtil.write(response, "404", "text");
default void onLoginError(String to,HttpServletResponse response) {
ServletKit.write(response, "404", "text");
}

View File

@@ -13,9 +13,20 @@
<result column="platform" jdbcType="VARCHAR" property="platform" />
<result column="ip" jdbcType="VARCHAR" property="ip" />
<result column="address" jdbcType="VARCHAR" property="address" />
<result column="result" jdbcType="INTEGER" property="result" />
<result column="params" jdbcType="LONGVARCHAR" property="params" />
</resultMap>
<sql id="Base_Column_List">
<!--@mbg.generated-->
id, create_time, update_time, is_deleted, user_id, user_name, platform, ip, address
id, create_time, update_time, is_deleted, user_id, user_name, platform, ip, address,
`result`, params
</sql>
<select id="getLoginErrorTimes" resultType="int">
select count(1)
from core_log_login
where ip = #{ip}
and create_time > date_add(now(), interval -10 minute)
</select>
</mapper>

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-parent</artifactId>
<version>2.0.0.rc35</version>
<version>2.0.2</version>
</parent>
<artifactId>springboot-message</artifactId>

View File

@@ -1,6 +1,6 @@
package com.tiesheng.message.config.aliyun;
import cn.hutool.json.JSONObject;
import com.alibaba.fastjson.JSONObject;
public interface AliyunSmsHandler {

View File

@@ -5,8 +5,8 @@ import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tiesheng.message.service.TsMessageSender;
import com.tiesheng.util.exception.ApiException;
import com.tiesheng.util.pojos.ApiResp;
@@ -103,10 +103,10 @@ public class AliyunSmsSender implements TsMessageSender {
try {
respBody = OkHttpUtil.get(ENDPOINT + "?Signature=" + signature + sortQueryStringTmp);
} catch (Exception e) {
respBody = JSONUtil.createObj()
.putOpt("Code", "Error")
.putOpt("Message", "消息通道异常")
.toString();
JSONObject object = new JSONObject();
object.put("Code", "Error");
object.put("Message", "消息通道异常");
respBody = object.toJSONString();
}
return respBody;
}
@@ -130,9 +130,9 @@ public class AliyunSmsSender implements TsMessageSender {
queryMap.put("TemplateParam", tempParam.getTemplateParam().toString());
}
JSONObject respObj = JSONUtil.parseObj(request("SendSms", queryMap));
if (!Objects.equals(respObj.getStr("Code"), "OK")) {
return ApiResp.resp130(respObj.getStr("Message"));
JSONObject respObj = JSON.parseObject(request("SendSms", queryMap));
if (!Objects.equals(respObj.getString("Code"), "OK")) {
return ApiResp.resp130(respObj.getString("Message"));
}
return ApiResp.respOK("");

View File

@@ -1,6 +1,6 @@
package com.tiesheng.message.config.aliyun;
import cn.hutool.json.JSONObject;
import com.alibaba.fastjson.JSONObject;
public class AliyunTempParam {

View File

@@ -1,7 +1,7 @@
package com.tiesheng.message.service;
import cn.hutool.json.JSONObject;
import com.alibaba.fastjson.JSONObject;
import com.tiesheng.util.pojos.ApiResp;
/**

View File

@@ -3,7 +3,7 @@ package com.tiesheng.message.service;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.alibaba.fastjson.JSONObject;
import com.tiesheng.message.pojos.UserChannel;
import com.tiesheng.util.pojos.ApiResp;
import org.springframework.beans.factory.annotation.Autowired;

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-parent</artifactId>
<version>2.0.0.rc35</version>
<version>2.0.2</version>
</parent>
<artifactId>springboot-platform</artifactId>

View File

@@ -1,12 +1,12 @@
package com.tiesheng.platform.config.ding;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.LogFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.tiesheng.platform.config.ding.bean.*;
import com.tiesheng.util.exception.ApiException;
import com.tiesheng.util.service.TsCacheService;
@@ -80,7 +80,7 @@ public class PlatformDingConfig {
Response response = OkHttpUtil.ofHttpClient().build().newCall(request).execute();
if (response.isSuccessful() && response.body() != null) {
String rawBody = response.body().string();
DingResponse<T> bean = JSONUtil.toBean(rawBody, typeReference, true);
DingResponse<T> bean = JSON.parseObject(rawBody, typeReference);
bean.setRawBody(rawBody);
return bean;
} else {
@@ -116,8 +116,8 @@ public class PlatformDingConfig {
query.put("appkey", dingConfigBean.getAppKey());
query.put("appsecret", dingConfigBean.getAppSecret());
String response = OkHttpUtil.get("https://oapi.dingtalk.com/gettoken", query);
JSONObject respJson = JSONUtil.parseObj(response);
accessToken = respJson.getStr("access_token");
JSONObject respJson = JSON.parseObject(response);
accessToken = respJson.getString("access_token");
TsCacheService.of().put(CACHE_ACCESS_TOKEN + dingConfigBean.getAppKey(),
accessToken, respJson.getLong("expires_in"));
@@ -174,8 +174,12 @@ public class PlatformDingConfig {
* @see <a href="https://open.dingtalk.com/document/isvapp-server/obtain-the-userid-of-a-user-by-using-the-log-free"></a>
*/
public DingUserSimple getUserIdByCode(String service, String code) {
JSONObject object = new JSONObject();
object.put("code", code);
DingResponse<DingUserSimple> resp = doRequest(service, "https://oapi.dingtalk.com/topapi/v2/user/getuserinfo",
JSONUtil.createObj().putOpt("code", code), new TypeReference<DingResponse<DingUserSimple>>() {
object, new TypeReference<DingResponse<DingUserSimple>>() {
});
return resp.getResult();
}
@@ -192,9 +196,13 @@ public class PlatformDingConfig {
public DingUserInfo topapiV2UserGet(String service, String ddUserId) {
DingConfigBean dingConfigBean = getConfigBean(service);
JSONObject object = new JSONObject();
object.put("userid", ddUserId);
DingUserInfo userInfo = doRequest(service, "https://oapi.dingtalk.com/topapi/v2/user/get",
JSONUtil.createObj().putOpt("userid", ddUserId), new TypeReference<DingResponse<DingUserInfo>>() {
object, new TypeReference<DingResponse<DingUserInfo>>() {
}).getResult();
// 设置一下job_number
userInfo.setJobNumber(userInfo.getJobNumber());
userInfo.setAppId(dingConfigBean.getAppKey());
@@ -214,8 +222,11 @@ public class PlatformDingConfig {
return new ArrayList<>();
}
JSONObject object = new JSONObject();
object.put("dept_id", deptId);
return doRequest(service, "https://oapi.dingtalk.com/topapi/v2/department/listsub",
JSONUtil.createObj().putOpt("dept_id", deptId), new TypeReference<DingResponse<List<DingDeptVo>>>() {
object, new TypeReference<DingResponse<List<DingDeptVo>>>() {
}).getResult();
}
@@ -232,9 +243,13 @@ public class PlatformDingConfig {
return DingUserListVo.fail();
}
JSONObject object = new JSONObject();
object.put("dept_id", deptId);
object.put("cursor", cursor);
object.put("size", 100);
return doRequest(service, "https://oapi.dingtalk.com/topapi/v2/user/list",
JSONUtil.createObj().putOpt("dept_id", deptId).putOpt("cursor", cursor).putOpt("size", 100),
new TypeReference<DingResponse<DingUserListVo>>() {
object, new TypeReference<DingResponse<DingUserListVo>>() {
}).getResult();
}
@@ -293,24 +308,28 @@ public class PlatformDingConfig {
DingConfigBean configBean = getConfigBean(service);
JSONObject msg = new JSONObject();
if (StrUtil.isEmpty(actionUrl)) {
msg.set("msgtype", "markdown");
msg.set("markdown", JSONUtil.createObj()
.set("title", title).set("text", markdown)
);
JSONObject markdownObj = new JSONObject();
markdownObj.put("title", title);
markdownObj.put("text", markdown);
msg.put("msgtype", "markdown");
msg.put("markdown", markdownObj);
} else {
msg.set("msgtype", "action_card");
msg.set("action_card", JSONUtil.createObj()
.set("title", title).set("markdown", markdown)
.set("single_title", "点击查看").set("single_url", actionUrl)
);
JSONObject actionCard = new JSONObject();
actionCard.put("title", title);
actionCard.put("markdown", markdown);
actionCard.put("single_title", "点击查看");
actionCard.put("single_url", actionUrl);
msg.put("msgtype", "action_card");
msg.put("action_card", actionCard);
}
JSONObject body = new JSONObject();
body.putOpt("agent_id", configBean.getAgentId());
body.putOpt("userid_list", CollUtil.join(userIds, ","));
body.putOpt("msg", msg);
body.put("agent_id", configBean.getAgentId());
body.put("userid_list", CollUtil.join(userIds, ","));
body.put("msg", msg);
return doRequest(service, "https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2", body,
new TypeReference<DingResponse<String>>() {
});

View File

@@ -1,6 +1,7 @@
package com.tiesheng.platform.config.ding.bean;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONPath;
import java.util.Objects;
@@ -41,7 +42,8 @@ public class DingResponse<T> {
* @return
*/
public <E> E getRawValue(String path, Class<E> tClass) {
return JSONUtil.parse(getRawBody()).getByPath(path, tClass);
JSONPath jsonPath = JSONPath.compile(path);
return jsonPath.eval(JSON.parseObject(getRawBody()), tClass);
}
///////////////////////////////////////////////////////////////////////////

View File

@@ -2,8 +2,8 @@ package com.tiesheng.platform.config.wxmini;
import cn.hutool.core.map.MapUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tiesheng.platform.config.wxmp.bean.WxConfigBean;
import com.tiesheng.util.exception.ApiException;
import com.tiesheng.util.service.http.OkHttpUtil;
@@ -56,8 +56,8 @@ public class PlatformWxminiConfig {
+ "&secret=" + configBean.getAppSecret()
+ "&js_code=" + code + "&grant_type=authorization_code");
JSONObject object = JSONUtil.parseObj(body);
return object.getStr("openid");
JSONObject object = JSON.parseObject(body);
return object.getString("openid");
}
/**
@@ -72,8 +72,8 @@ public class PlatformWxminiConfig {
+ "?grant_type=client_credential&appid=" + configBean.getAppId()
+ "&secret=" + configBean.getAppSecret());
JSONObject object = JSONUtil.parseObj(body);
return object.getStr("access_token");
JSONObject object = JSON.parseObject(body);
return object.getString("access_token");
}

View File

@@ -4,9 +4,9 @@ package com.tiesheng.platform.config.wxmp;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.LogFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tiesheng.platform.config.wxmp.bean.WxConfigBean;
import com.tiesheng.platform.config.wxmp.bean.WxJsapiSignature;
import com.tiesheng.platform.config.wxmp.bean.WxOAuth2AccessToken;
@@ -70,8 +70,8 @@ public class PlatformWxmpConfig {
query.put("appid", configBean.getAppId());
query.put("secret", configBean.getAppSecret());
String response = OkHttpUtil.get("https://api.weixin.qq.com/cgi-bin/token", query);
JSONObject respJson = JSONUtil.parseObj(response);
accessToken = respJson.getStr("access_token");
JSONObject respJson = JSON.parseObject(response);
accessToken = respJson.getString("access_token");
TsCacheService.of().put(CACHE_ACCESS_TOKEN + configBean.getAppId(), accessToken,
respJson.getLong("expires_in"));
}
@@ -93,8 +93,8 @@ public class PlatformWxmpConfig {
query.put("type", "jsapi");
String response = OkHttpUtil.get("https://api.weixin.qq.com/cgi-bin/ticket/getticket", query);
LogFactory.get().info("getJsapiTicket: " + response);
JSONObject respJson = JSONUtil.parseObj(response);
jsapiTicket = respJson.getStr("ticket");
JSONObject respJson = JSON.parseObject(response);
jsapiTicket = respJson.getString("ticket");
TsCacheService.of().put(CACHE_JSAPI_TICKET + configBean.getAppId(), jsapiTicket,
respJson.getLong("expires_in"));
}

View File

@@ -1,7 +1,7 @@
package com.tiesheng.platform.config.wxmp.bean;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.tiesheng.util.service.http.OkHttpUtil;
/**
@@ -15,11 +15,11 @@ public class WxOAuth2AccessToken {
public static WxOAuth2AccessToken create(String appId, String secret, String code) {
String response = OkHttpUtil.get("https://api.weixin.qq.com/sns/oauth2/access_token" +
"?appid=" + appId + "&secret=" + secret + "&code=" + code + "&grant_type=authorization_code");
JSONObject respJson = JSONUtil.parseObj(response);
JSONObject respJson = JSON.parseObject(response);
WxOAuth2AccessToken oAuth2AccessToken = new WxOAuth2AccessToken();
oAuth2AccessToken.setOpenid(respJson.getStr("openid"));
oAuth2AccessToken.setAccessToken(respJson.getStr("access_token"));
oAuth2AccessToken.setOpenid(respJson.getString("openid"));
oAuth2AccessToken.setAccessToken(respJson.getString("access_token"));
return oAuth2AccessToken;
}

View File

@@ -1,6 +1,6 @@
package com.tiesheng.platform.config.wxmp.bean;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.tiesheng.util.service.http.OkHttpUtil;
/**
@@ -33,7 +33,7 @@ public class WxUserInfo {
String s = OkHttpUtil.get("https://api.weixin.qq.com/sns/userinfo"
+ "?access_token=" + oAuth2AccessToken.getAccessToken()
+ "&openid=" + oAuth2AccessToken.getOpenid() + "&lang=zh_CN");
return JSONUtil.toBean(s, WxUserInfo.class);
return JSON.parseObject(s, WxUserInfo.class);
}

Binary file not shown.

View File

@@ -1,34 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-parent</artifactId>
<version>2.0.0.rc35</version>
</parent>
<artifactId>springboot-poi</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-util</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,8 +0,0 @@
package com.tiesheng.poi.pojos;
/**
* @author hao
*/
public interface PoiReadBase {
}

View File

@@ -1,19 +0,0 @@
package com.tiesheng.poi.pojos;
import com.alibaba.excel.annotation.write.style.*;
import com.alibaba.excel.enums.poi.HorizontalAlignmentEnum;
import com.alibaba.excel.enums.poi.VerticalAlignmentEnum;
/**
* @author hao
*/
@HeadRowHeight(24)
@HeadFontStyle(fontHeightInPoints = 13)
@HeadStyle(horizontalAlignment = HorizontalAlignmentEnum.LEFT)
@ContentRowHeight(20)
@ContentFontStyle(fontHeightInPoints = 12)
@ContentStyle(verticalAlignment = VerticalAlignmentEnum.CENTER)
@ColumnWidth(20)
public interface PoiWriteBase {
}

View File

@@ -1,23 +0,0 @@
package com.tiesheng.poi.util;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.listener.ReadListener;
import com.tiesheng.poi.pojos.PoiReadBase;
import java.io.File;
public class PoiReadUtil {
/**
* 读取文件
*
* @param file
* @param readListener
* @return
*/
public static <T extends PoiReadBase> void read(File file, Class<T> tClass, ReadListener<T> readListener) {
EasyExcel.read(file, tClass, readListener).autoTrim(true).headRowNumber(1).sheet().doRead();
}
}

View File

@@ -1,38 +0,0 @@
package com.tiesheng.poi.util;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.annotation.write.style.*;
import com.alibaba.excel.enums.poi.HorizontalAlignmentEnum;
import com.alibaba.excel.enums.poi.VerticalAlignmentEnum;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.tiesheng.poi.pojos.PoiWriteBase;
import java.util.List;
/**
* @author hao
*/
@HeadRowHeight(24)
@HeadFontStyle(fontHeightInPoints = 13)
@HeadStyle(horizontalAlignment = HorizontalAlignmentEnum.LEFT)
@ContentRowHeight(20)
@ContentFontStyle(fontHeightInPoints = 12)
@ContentStyle(verticalAlignment = VerticalAlignmentEnum.CENTER)
@ColumnWidth(20)
public class PoiWriteUtil {
/**
* 导出数据
*
* @param list
* @return
*/
public static <T extends PoiWriteBase> boolean export(List<T> list, Class<T> tClass, String absPath, String sheetName) {
EasyExcel.write(absPath, tClass).excelType(ExcelTypeEnum.XLSX)
.sheet(sheetName)
.doWrite(list);
return true;
}
}

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-parent</artifactId>
<version>2.0.0.rc35</version>
<version>2.0.2</version>
</parent>
<artifactId>springboot-role</artifactId>

View File

@@ -3,10 +3,13 @@ package com.tiesheng.role.controller;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tiesheng.role.pojos.dao.CoreRoleAuthority;
import com.tiesheng.role.pojos.dao.CoreRoleGroup;
import com.tiesheng.role.pojos.dao.CoreRoleServer;
import com.tiesheng.role.pojos.dto.OwnerMenuDTO;
import com.tiesheng.role.pojos.dto.OwnerPointDTO;
import com.tiesheng.role.pojos.vo.GroupTypeDTO;
import com.tiesheng.role.pojos.vo.ServiceMenuVO;
import com.tiesheng.role.service.CoreRoleService;
import com.tiesheng.util.pojos.ApiResp;
@@ -101,4 +104,24 @@ public class CommRoleController {
}
/**
* 角色、职位列表
*
* @return
*/
@GetMapping("/group")
public ApiResp<List<CoreRoleGroup>> groupPage(@Valid GroupTypeDTO dto) {
QueryWrapper<CoreRoleGroup> queryWrapper = new QueryWrapper<CoreRoleGroup>()
.eq("is_deleted", 0)
.eq(StrUtil.isNotEmpty(dto.getType()), "type", dto.getType())
.orderByAsc("sort");
dto.likeColumns(queryWrapper, "name");
Page<CoreRoleGroup> page = dto.pageObj();
coreRoleService.page(page, queryWrapper);
return ApiResp.respOK(page.getRecords(), page.getTotal());
}
}

View File

@@ -1,15 +1,12 @@
package com.tiesheng.role.service;
import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tiesheng.annotation.role.RoleAuthority;
import com.tiesheng.role.mapper.*;
import com.tiesheng.role.pojos.dao.CoreRoleAuthority;
import com.tiesheng.role.pojos.dao.CoreRoleGroup;
@@ -22,21 +19,15 @@ import com.tiesheng.util.exception.ApiException;
import com.tiesheng.util.service.TsCacheService;
import com.tiesheng.util.service.TsServiceBase;
import com.tiesheng.util.service.role.TsAuthorityHandler;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;
@Service
public class CoreRoleService extends TsServiceBase<CoreRoleGroupMapper, CoreRoleGroup>
implements ApplicationListener<ContextRefreshedEvent> {
public class CoreRoleService extends TsServiceBase<CoreRoleGroupMapper, CoreRoleGroup> {
@Resource
CoreRoleUserMapper coreRoleUserMapper;
@@ -46,8 +37,7 @@ public class CoreRoleService extends TsServiceBase<CoreRoleGroupMapper, CoreRole
CoreRoleAuthorityMapper coreRoleAuthorityMapper;
@Resource
CoreRoleServerMapper coreRoleServerMapper;
@Resource
TsAuthorityHandler tsAuthorityHandler;
public CoreRoleServerMapper getServerMapper() {
return coreRoleServerMapper;
@@ -134,7 +124,7 @@ public class CoreRoleService extends TsServiceBase<CoreRoleGroupMapper, CoreRole
coreRoleGroupRx.setType("bind");
list.add(coreRoleGroupRx);
List<String> deps = JSONUtil.toList(authority.getDeps(), String.class);
List<String> deps = JSON.parseArray(authority.getDeps(), String.class);
for (String dep : deps) {
CoreRoleGroupRx depRx = new CoreRoleGroupRx();
depRx.setGroupId(roleGroup.getId());
@@ -164,7 +154,7 @@ public class CoreRoleService extends TsServiceBase<CoreRoleGroupMapper, CoreRole
coreRoleUserMapper.insert(roleUser);
}
onRoleChange(roleUser.getTypeId(), roleUser.getUserId());
onRoleChange("", roleUser.getUserId());
}
@@ -181,7 +171,7 @@ public class CoreRoleService extends TsServiceBase<CoreRoleGroupMapper, CoreRole
coreRoleUser.setIsDeleted(1);
coreRoleUserMapper.updateById(coreRoleUser);
onRoleChange(coreRoleUser.getTypeId(), coreRoleUser.getUserId());
onRoleChange("", coreRoleUser.getUserId());
}
@@ -189,8 +179,13 @@ public class CoreRoleService extends TsServiceBase<CoreRoleGroupMapper, CoreRole
* 当授权发生变化时
*/
public void onRoleChange(String roleId, String userId) {
TsCacheService.of().keys(StrUtil.format(TsAuthorityHandler.CACHE_HAS_AUTHORITY,
roleId, userId)).forEach(key -> TsCacheService.of().remove(key));
if (StrUtil.isEmpty(roleId)) {
TsCacheService.of().keys(StrUtil.replace(TsAuthorityHandler.CACHE_AUTHORITY,
":{}", "")).forEach(key -> TsCacheService.of().remove(key));
} else {
TsCacheService.of().keys(StrUtil.format(TsAuthorityHandler.CACHE_AUTHORITY,
roleId, userId)).forEach(key -> TsCacheService.of().remove(key));
}
}
@@ -248,36 +243,4 @@ public class CoreRoleService extends TsServiceBase<CoreRoleGroupMapper, CoreRole
.collect(Collectors.toList());
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
ApplicationContext applicationContext = event.getApplicationContext();
Map<String, Object> beansOfType = applicationContext.getBeansWithAnnotation(RoleAuthority.class);
String version = DateUtil.format(new Date(), "yyyyMMddHHmmss");
for (Map.Entry<String, Object> entry : beansOfType.entrySet()) {
Class<?> targetClass = AopUtils.getTargetClass(entry.getValue());
RoleAuthority menu = targetClass.getAnnotation(RoleAuthority.class);
List<RoleAuthority> points = new ArrayList<>();
Method[] methods = targetClass.getDeclaredMethods();
for (Method method : methods) {
RoleAuthority methodAuthority = AnnotationUtil.getAnnotation(method, RoleAuthority.class);
if (methodAuthority != null) {
points.add(methodAuthority);
}
}
tsAuthorityHandler.addRoleAuthority(version, menu, points);
}
coreRoleAuthorityMapper.delete(new QueryWrapper<CoreRoleAuthority>()
.ne("version", version)
.eq("source", "auto")
);
}
}

View File

@@ -1,7 +1,8 @@
package com.tiesheng.role.service;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tiesheng.annotation.role.RoleAuthority;
import com.tiesheng.role.mapper.CoreRoleAuthorityMapper;
import com.tiesheng.role.mapper.CoreRoleUserMapper;
@@ -75,7 +76,7 @@ public class RoleAuthorityHandler implements TsAuthorityHandler {
menuAuthority.setPlatform(menuPlatform);
menuAuthority.setVersion(version);
menuAuthority.setSource("auto");
menuAuthority.setDeps(JSONUtil.toJsonStr(menu.deps()));
menuAuthority.setDeps(JSON.toJSONString(menu.deps()));
menuAuthority.setId(StrUtil.join("_", menuAuthority.getService(), menuAuthority.getNo()));
list.add(menuAuthority);
@@ -90,7 +91,7 @@ public class RoleAuthorityHandler implements TsAuthorityHandler {
point.setParent(menuAuthority.getId());
point.setVersion(version);
point.setSource("auto");
point.setDeps(JSONUtil.toJsonStr(authority.deps()));
point.setDeps(JSON.toJSONString(authority.deps()));
point.setPlatform(StrUtil.emptyToDefault(authority.platform(), menuPlatform));
point.setId(StrUtil.join("_", point.getService(), point.getNo()));
list.add(point);
@@ -107,4 +108,13 @@ public class RoleAuthorityHandler implements TsAuthorityHandler {
return list.stream().map(CoreRoleAuthority::getNo).distinct().collect(Collectors.toList());
}
@Override
public void onCreateAfter(String version) {
coreRoleAuthorityMapper.delete(new QueryWrapper<CoreRoleAuthority>()
.ne("version", version)
.eq("service", globalConfig.getService())
.eq("source", "auto")
);
}
}

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-parent</artifactId>
<version>2.0.0.rc35</version>
<version>2.0.2</version>
</parent>
<artifactId>springboot-util</artifactId>
@@ -32,15 +32,44 @@
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-bom</artifactId>
<version>5.8.16</version>
<type>pom</type>
<exclusions>
<exclusion>
<groupId>cn.hutool</groupId>
<artifactId>hutool-http</artifactId>
</exclusion>
</exclusions>
<artifactId>hutool-core</artifactId>
<version>${hutool.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-cache</artifactId>
<version>${hutool.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-captcha</artifactId>
<version>${hutool.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-log</artifactId>
<version>${hutool.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-crypto</artifactId>
<version>${hutool.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-extra</artifactId>
<version>${hutool.version}</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-db</artifactId>
<version>${hutool.version}</version>
</dependency>
<dependency>

View File

@@ -4,10 +4,8 @@ package com.tiesheng.util;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import java.util.Map;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
public class CharacterUtils {
@@ -24,19 +22,24 @@ public class CharacterUtils {
/**
* 移除特殊字符
*
* @param o 类
* @param o
* @param searchStr 规则
*/
public static void removeSymbol(Object o, String searchStr) {
JSONObject object = JSONUtil.parseObj(o, false);
for (Map.Entry<String, Object> entry : object) {
if (ObjectUtil.isEmpty(entry.getValue()) || StrUtil.equals("null", String.valueOf(entry.getValue()))) {
entry.setValue("");
JSONObject object = JSON.parseObject(JSON.toJSONString(o));
for (String key : object.keySet()) {
if (StrUtil.isEmpty(key)) {
continue;
}
if (StrUtil.isNotEmpty(entry.getKey())) {
entry.setValue(StrUtil.trim(StrUtil.replace(entry.getValue().toString(), searchStr, "")));
Object value = object.get(key);
if (ObjectUtil.isEmpty(value) || StrUtil.equals("null", String.valueOf(value))) {
object.put(key, "");
continue;
}
String replace = StrUtil.replace(String.valueOf(value), searchStr, "");
object.put(key, StrUtil.trim(replace));
}
BeanUtil.copyProperties(object, o);
}

View File

@@ -1,50 +0,0 @@
package com.tiesheng.util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.tiesheng.util.config.DesensitizeValueFilter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class CommonUtil {
/**
* FastJson配置
*
* @return
*/
public static FastJsonConfig fastJsonConfig() {
FastJsonConfig config = new FastJsonConfig();
config.setSerializerFeatures(SerializerFeature.WriteMapNullValue,
SerializerFeature.WriteNullStringAsEmpty,
SerializerFeature.WriteEnumUsingName,
SerializerFeature.DisableCircularReferenceDetect
);
config.setDateFormat("yyyy-MM-dd HH:mm:ss");
config.setSerializeFilters(new DesensitizeValueFilter());
return config;
}
/**
* 格式化数据
*
* @param value
* @return
* @throws IOException
*/
public static String writeJsonString(Object value) throws IOException {
FastJsonConfig fastJsonConfig = fastJsonConfig();
ByteArrayOutputStream outnew = new ByteArrayOutputStream();
JSON.writeJSONStringWithFastJsonConfig(outnew, fastJsonConfig.getCharset(),
value, fastJsonConfig.getSerializeConfig(),
fastJsonConfig.getSerializeFilters(),
fastJsonConfig.getDateFormat(), JSON.DEFAULT_GENERATE_FEATURE,
fastJsonConfig.getSerializerFeatures());
return outnew.toString();
}
}

View File

@@ -1,37 +0,0 @@
package com.tiesheng.util.config;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.serializer.ValueFilter;
import com.tiesheng.annotation.desensitize.Desensitize;
import java.lang.reflect.Field;
/**
* 脱敏过滤类
*
* @author hao
*/
public class DesensitizeValueFilter implements ValueFilter {
@Override
public Object process(Object object, String name, Object value) {
if (ObjectUtil.isEmpty(value) || !(value instanceof String)) {
return value;
}
Field field = ReflectUtil.getField(object.getClass(), name);
if (ObjectUtil.isEmpty(field)) {
return value;
}
Desensitize desensitize = field.getAnnotation(Desensitize.class);
if (String.class != field.getType() || ObjectUtil.isEmpty(desensitize)) {
return value;
}
String originVal = String.valueOf(value);
return StrUtil.hide(originVal, desensitize.prefix(),
StrUtil.length(originVal) - desensitize.suffix());
}
}

View File

@@ -1,15 +1,12 @@
package com.tiesheng.util.config;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.symmetric.SM4;
import com.tiesheng.util.ServletKit;
import com.tiesheng.util.exception.ApiException;
import com.tiesheng.util.service.TsCacheService;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@@ -104,12 +101,6 @@ public class EncryptConfig {
String salt = decrypt(encrypted).substring(0, saltSize);
String inputEncrypted = passwdCreate(inputPasswd, salt);
if (!StrUtil.equals(inputEncrypted, encrypted)) {
String clientIp = "passwdVerify_" + ServletKit.getClientIP();
int num = NumberUtil.parseInt(TsCacheService.of().get(clientIp, -1));
if (num > 5) {
throw new ApiException("登录失败已达6次请10分钟后再试");
}
TsCacheService.of().put(clientIp, String.valueOf(num + 1), 10 * 60);
throw new ApiException("账号或密码错误");
}
}

View File

@@ -6,6 +6,8 @@ import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.log.LogFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.tiesheng.util.exception.ApiException;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@@ -26,6 +28,18 @@ import java.util.List;
@ConfigurationProperties(prefix = "tiesheng.global")
public class GlobalConfig {
static {
JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
// FASTJSON 设置全局序列化配置
JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.WriteMapNullValue.getMask();
JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.WriteNullStringAsEmpty.getMask();
JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.WriteEnumUsingName.getMask();
JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.WriteDateUseDateFormat.getMask();
JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.DisableCircularReferenceDetect.getMask();
}
private String host;
private String service;
private String version;

View File

@@ -4,10 +4,10 @@ package com.tiesheng.util.config;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTValidator;
import com.alibaba.fastjson.JSON;
import com.tiesheng.util.exception.ApiException;
import com.tiesheng.util.jwt.JWT;
import com.tiesheng.util.jwt.JWTValidator;
import com.tiesheng.util.pojos.TokenBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@@ -66,6 +66,16 @@ public class TsTokenConfig {
return validToken(token, thrExp);
}
/**
* token是否有效
*
* @param token
* @return
*/
public static boolean validToken(TokenBean token) {
return token != null && StrUtil.isNotEmpty(token.getId());
}
/**
* 验证token
@@ -81,7 +91,7 @@ public class TsTokenConfig {
try {
JWT decode = JWT.of(token);
JWTValidator.of(decode).validateDate();
tokenBean = JSONUtil.toBean(decode.getPayloads(), TokenBean.class);
tokenBean = JSON.toJavaObject(decode.getPayloads(), TokenBean.class);
} catch (Exception ignored) {
}

View File

@@ -0,0 +1,95 @@
package com.tiesheng.util.jwt;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import java.io.Serializable;
import java.nio.charset.Charset;
import java.util.Map;
/**
* Claims 认证简单的JSONObject包装
*
* @author looly
* @since 5.7.0
*/
public class Claims implements Serializable {
private static final long serialVersionUID = 1L;
private JSONObject claimJSON;
/**
* 增加Claims属性如果属性值为{@code null},则移除这个属性
*
* @param name 属性名
* @param value 属性值
*/
protected void setClaim(String name, Object value) {
init();
Assert.notNull(name, "Name must be not null!");
if (value == null) {
claimJSON.remove(name);
return;
}
claimJSON.put(name, value);
}
/**
* 加入多个Claims属性
*
* @param headerClaims 多个Claims属性
*/
protected void putAll(Map<String, ?> headerClaims) {
if (MapUtil.isNotEmpty(headerClaims)) {
for (Map.Entry<String, ?> entry : headerClaims.entrySet()) {
setClaim(entry.getKey(), entry.getValue());
}
}
}
/**
* 获取指定名称属性
*
* @param name 名称
* @return 属性
*/
public Object getClaim(String name) {
init();
return this.claimJSON.get(name);
}
/**
* 获取Claims的JSON字符串形式
*
* @return JSON字符串
*/
public JSONObject getClaimsJson() {
init();
return this.claimJSON;
}
/**
* 解析JWT JSON
*
* @param tokenPart JWT JSON
* @param charset 编码
*/
public void parse(String tokenPart, Charset charset) {
this.claimJSON = JSON.parseObject(Base64.decodeStr(tokenPart, charset));
}
@Override
public String toString() {
init();
return this.claimJSON.toString();
}
private void init() {
if (null == this.claimJSON) {
this.claimJSON = new JSONObject();
}
}
}

View File

@@ -0,0 +1,433 @@
package com.tiesheng.util.jwt;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.exceptions.ValidateException;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.tiesheng.util.jwt.signers.AlgorithmUtil;
import com.tiesheng.util.jwt.signers.JWTSigner;
import com.tiesheng.util.jwt.signers.JWTSignerUtil;
import com.tiesheng.util.jwt.signers.NoneJWTSigner;
import java.nio.charset.Charset;
import java.security.Key;
import java.security.KeyPair;
import java.util.List;
import java.util.Map;
/**
* JSON Web Token (JWT)基于JSON的开放标准(RFC 7519)用于在网络应用环境间传递声明。<br>
* <p>
* 结构header.payload.signature
* <ul>
* <li>header主要声明了JWT的签名算法</li>
* <li>payload主要承载了各种声明并传递明文数据</li>
* <li>signature拥有该部分的JWT被称为JWS也就是签了名的JWS</li>
* </ul>
*
* <p>
* 详细介绍见https://www.jianshu.com/p/576dbf44b2ae
* </p>
*
* @author looly
* @since 5.7.0
*/
public class JWT implements RegisteredPayload<JWT> {
private final JWTHeader header;
private final JWTPayload payload;
private Charset charset;
private JWTSigner signer;
private List<String> tokens;
/**
* 创建空的JWT对象
*
* @return JWT
*/
public static JWT create() {
return new JWT();
}
/**
* 创建并解析JWT对象
*
* @param token JWT Token字符串格式为xxxx.yyyy.zzzz
* @return JWT
*/
public static JWT of(String token) {
return new JWT(token);
}
/**
* 构造
*/
public JWT() {
this.header = new JWTHeader();
this.payload = new JWTPayload();
this.charset = CharsetUtil.CHARSET_UTF_8;
}
/**
* 构造
*
* @param token JWT Token字符串格式为xxxx.yyyy.zzzz
*/
public JWT(String token) {
this();
parse(token);
}
/**
* 解析JWT内容
*
* @param token JWT Token字符串格式为xxxx.yyyy.zzzz
* @return this
*/
public JWT parse(String token) {
Assert.notBlank(token, "Token String must be not blank!");
final List<String> tokens = splitToken(token);
this.tokens = tokens;
this.header.parse(tokens.get(0), this.charset);
this.payload.parse(tokens.get(1), this.charset);
return this;
}
/**
* 设置编码
*
* @param charset 编码
* @return this
*/
public JWT setCharset(Charset charset) {
this.charset = charset;
return this;
}
/**
* 设置密钥如果头部指定了算法直接使用否则默认算法是HS256(HmacSHA256)
*
* @param key 密钥
* @return this
*/
public JWT setKey(byte[] key) {
// 检查头信息中是否有算法信息
final String claim = (String) this.header.getClaim(JWTHeader.ALGORITHM);
if (StrUtil.isNotBlank(claim)) {
return setSigner(JWTSignerUtil.createSigner(claim, key));
}
return setSigner(JWTSignerUtil.hs256(key));
}
/**
* 设置签名算法
*
* @param algorithmId 签名算法ID如HS256
* @param key 密钥
* @return this
*/
public JWT setSigner(String algorithmId, byte[] key) {
return setSigner(JWTSignerUtil.createSigner(algorithmId, key));
}
/**
* 设置签名算法
*
* @param algorithmId 签名算法ID如HS256
* @param key 密钥
* @return this
* @since 5.7.2
*/
public JWT setSigner(String algorithmId, Key key) {
return setSigner(JWTSignerUtil.createSigner(algorithmId, key));
}
/**
* 设置非对称签名算法
*
* @param algorithmId 签名算法ID如HS256
* @param keyPair 密钥对
* @return this
* @since 5.7.2
*/
public JWT setSigner(String algorithmId, KeyPair keyPair) {
return setSigner(JWTSignerUtil.createSigner(algorithmId, keyPair));
}
/**
* 设置签名算法
*
* @param signer 签名算法
* @return this
*/
public JWT setSigner(JWTSigner signer) {
this.signer = signer;
return this;
}
/**
* 获取JWT算法签名器
*
* @return JWT算法签名器
*/
public JWTSigner getSigner() {
return this.signer;
}
/**
* 获取所有头信息
*
* @return 头信息
*/
public JSONObject getHeaders() {
return this.header.getClaimsJson();
}
/**
* 获取头
*
* @return 头信息
* @since 5.7.2
*/
public JWTHeader getHeader() {
return this.header;
}
/**
* 获取头信息
*
* @param name 头信息名称
* @return 头信息
*/
public Object getHeader(String name) {
return this.header.getClaim(name);
}
/**
* 获取算法ID(alg)头信息
*
* @return 算法头信息
* @see JWTHeader#ALGORITHM
*/
public String getAlgorithm() {
return (String) this.header.getClaim(JWTHeader.ALGORITHM);
}
/**
* 设置JWT头信息
*
* @param name 头名
* @param value 头
* @return this
*/
public JWT setHeader(String name, Object value) {
this.header.setClaim(name, value);
return this;
}
/**
* 增加JWT头信息
*
* @param headers 头信息
* @return this
*/
public JWT addHeaders(Map<String, ?> headers) {
this.header.addHeaders(headers);
return this;
}
/**
* 获取所有载荷信息
*
* @return 载荷信息
*/
public JSONObject getPayloads() {
return this.payload.getClaimsJson();
}
/**
* 获取载荷对象
*
* @return 载荷信息
* @since 5.7.2
*/
public JWTPayload getPayload() {
return this.payload;
}
/**
* 获取载荷信息
*
* @param name 载荷信息名称
* @return 载荷信息
*/
public Object getPayload(String name) {
return getPayload().getClaim(name);
}
/**
* 设置JWT载荷信息
*
* @param name 载荷名
* @param value 头
* @return this
*/
@Override
public JWT setPayload(String name, Object value) {
this.payload.setClaim(name, value);
return this;
}
/**
* 增加JWT载荷信息
*
* @param payloads 载荷信息
* @return this
*/
public JWT addPayloads(Map<String, ?> payloads) {
this.payload.addPayloads(payloads);
return this;
}
/**
* 签名生成JWT字符串
*
* @return JWT字符串
*/
public String sign() {
return sign(true);
}
/**
* 签名生成JWT字符串
*
* @param addTypeIfNot 如果'typ'头不存在,是否赋值默认值
* @return JWT字符串
* @since 5.8.24
*/
public String sign(boolean addTypeIfNot) {
return sign(this.signer, addTypeIfNot);
}
/**
* 签名生成JWT字符串
*
* @param signer JWT签名器
* @return JWT字符串
*/
public String sign(JWTSigner signer) {
return sign(signer, true);
}
/**
* 签名生成JWT字符串
*
* @param signer JWT签名器
* @param addTypeIfNot 如果'typ'头不存在,是否赋值默认值
* @return JWT字符串
* @since 5.8.24
*/
public String sign(JWTSigner signer, boolean addTypeIfNot) {
Assert.notNull(signer, () -> new JWTException("No Signer provided!"));
// 检查tye信息
if (addTypeIfNot) {
final String type = (String) this.header.getClaim(JWTHeader.TYPE);
if (StrUtil.isBlank(type)) {
this.header.setClaim(JWTHeader.TYPE, "JWT");
}
}
// 检查头信息中是否有算法信息
final String algorithm = (String) this.header.getClaim(JWTHeader.ALGORITHM);
if (StrUtil.isBlank(algorithm)) {
this.header.setClaim(JWTHeader.ALGORITHM,
AlgorithmUtil.getId(signer.getAlgorithm()));
}
final String headerBase64 = Base64.encodeUrlSafe(this.header.toString(), charset);
final String payloadBase64 = Base64.encodeUrlSafe(this.payload.toString(), charset);
final String sign = signer.sign(headerBase64, payloadBase64);
return StrUtil.format("{}.{}.{}", headerBase64, payloadBase64, sign);
}
/**
* 验证JWT Token是否有效
*
* @return 是否有效
*/
public boolean verify() {
return verify(this.signer);
}
/**
* 验证JWT是否有效验证包括
*
* <ul>
* <li>Token是否正确</li>
* <li>{@link JWTPayload#NOT_BEFORE}:生效时间不能晚于当前时间</li>
* <li>{@link JWTPayload#EXPIRES_AT}:失效时间不能早于当前时间</li>
* <li>{@link JWTPayload#ISSUED_AT} 签发时间不能晚于当前时间</li>
* </ul>
*
* @param leeway 容忍空间,单位:秒。当不能晚于当前时间时,向后容忍;不能早于向前容忍。
* @return 是否有效
* @see JWTValidator
* @since 5.7.4
*/
public boolean validate(long leeway) {
if (false == verify()) {
return false;
}
// 校验时间字段
try {
JWTValidator.of(this).validateDate(DateUtil.date(), leeway);
} catch (ValidateException e) {
return false;
}
return true;
}
/**
* 验证JWT Token是否有效
*
* @param signer 签名器(签名算法)
* @return 是否有效
*/
public boolean verify(JWTSigner signer) {
if (null == signer) {
// 如果无签名器提供默认认为是无签名JWT信息
signer = NoneJWTSigner.NONE;
}
final List<String> tokens = this.tokens;
if (CollUtil.isEmpty(tokens)) {
throw new JWTException("No token to verify!");
}
return signer.verify(tokens.get(0), tokens.get(1), tokens.get(2));
}
/**
* 将JWT字符串拆分为3部分无加密算法则最后一部分是""
*
* @param token JWT Token
* @return 三部分内容
*/
private static List<String> splitToken(String token) {
final List<String> tokens = StrUtil.split(token, CharUtil.DOT);
if (3 != tokens.size()) {
throw new JWTException("The token was expected 3 parts, but got {}.", tokens.size());
}
return tokens;
}
}

View File

@@ -0,0 +1,38 @@
package com.tiesheng.util.jwt;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.StrUtil;
/**
* JWT异常
*
* @author looly
* @since 5.7.0
*/
public class JWTException extends RuntimeException {
private static final long serialVersionUID = 1L;
public JWTException(Throwable e) {
super(ExceptionUtil.getMessage(e), e);
}
public JWTException(String message) {
super(message);
}
public JWTException(String messageTemplate, Object... params) {
super(StrUtil.format(messageTemplate, params));
}
public JWTException(String message, Throwable cause) {
super(message, cause);
}
public JWTException(String message, Throwable throwable, boolean enableSuppression, boolean writableStackTrace) {
super(message, throwable, enableSuppression, writableStackTrace);
}
public JWTException(Throwable throwable, String messageTemplate, Object... params) {
super(StrUtil.format(messageTemplate, params), throwable);
}
}

View File

@@ -0,0 +1,58 @@
package com.tiesheng.util.jwt;
import java.util.Map;
/**
* JWT头部信息
*
* @author looly
* @since 5.7.0
*/
public class JWTHeader extends Claims {
private static final long serialVersionUID = 1L;
//Header names
/**
* 加密算法通常为HMAC SHA256HS256
*/
public static String ALGORITHM = "alg";
/**
* 声明类型一般为jwt
*/
public static String TYPE = "typ";
/**
* 内容类型content type
*/
public static String CONTENT_TYPE = "cty";
/**
* jwk的ID编号
*/
public static String KEY_ID = "kid";
/**
* 构造,初始化默认(typ=JWT)
*/
public JWTHeader() {}
/**
* 增加“kid”头信息
*
* @param keyId kid
* @return this
*/
public JWTHeader setKeyId(String keyId) {
setClaim(KEY_ID, keyId);
return this;
}
/**
* 增加自定义JWT认证头
*
* @param headerClaims 头信息
* @return this
*/
public JWTHeader addHeaders(Map<String, ?> headerClaims) {
putAll(headerClaims);
return this;
}
}

View File

@@ -0,0 +1,39 @@
package com.tiesheng.util.jwt;
import java.util.Map;
/**
* JWT载荷信息<br>
* 载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分:
*
* <ul>
* <li>标准中注册的声明</li>
* <li>公共的声明</li>
* <li>私有的声明</li>
* </ul>
* <p>
* 详细介绍见https://www.jianshu.com/p/576dbf44b2ae
*
* @author looly
* @since 5.7.0
*/
public class JWTPayload extends Claims implements RegisteredPayload<JWTPayload>{
private static final long serialVersionUID = 1L;
/**
* 增加自定义JWT认证载荷信息
*
* @param payloadClaims 载荷信息
* @return this
*/
public JWTPayload addPayloads(Map<String, ?> payloadClaims) {
putAll(payloadClaims);
return this;
}
@Override
public JWTPayload setPayload(String name, Object value) {
setClaim(name, value);
return this;
}
}

View File

@@ -0,0 +1,257 @@
package com.tiesheng.util.jwt;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.exceptions.ValidateException;
import cn.hutool.core.util.StrUtil;
import com.tiesheng.util.jwt.signers.JWTSigner;
import com.tiesheng.util.jwt.signers.NoneJWTSigner;
import java.util.Date;
/**
* JWT数据校验器用于校验包括
* <ul>
* <li>算法是否一致</li>
* <li>算法签名是否正确</li>
* <li>字段值是否有效(例如时间未过期等)</li>
* </ul>
*
* @author looly
* @since 5.7.2
*/
public class JWTValidator {
private final JWT jwt;
/**
* 创建JWT验证器
*
* @param token JWT Token
* @return JWTValidator
*/
public static JWTValidator of(String token) {
return new JWTValidator(JWT.of(token));
}
/**
* 创建JWT验证器
*
* @param jwt JWT对象
* @return JWTValidator
*/
public static JWTValidator of(JWT jwt) {
return new JWTValidator(jwt);
}
/**
* 构造
*
* @param jwt JWT对象
*/
public JWTValidator(JWT jwt) {
this.jwt = jwt;
}
/**
* 验证算法使用JWT对象自带的{@link JWTSigner}
*
* @return this
* @throws ValidateException 验证失败的异常
*/
public JWTValidator validateAlgorithm() throws ValidateException {
return validateAlgorithm(null);
}
/**
* 验证算法,使用自定义的{@link JWTSigner}
*
* @param signer 用于验证算法的签名器
* @return this
* @throws ValidateException 验证失败的异常
*/
public JWTValidator validateAlgorithm(JWTSigner signer) throws ValidateException {
validateAlgorithm(this.jwt, signer);
return this;
}
/**
* 检查JWT的以下三两个时间
*
* <ul>
* <li>{@link JWTPayload#NOT_BEFORE}:被检查时间必须晚于生效时间</li>
* <li>{@link JWTPayload#EXPIRES_AT}:被检查时间必须早于失效时间</li>
* <li>{@link JWTPayload#ISSUED_AT}:签发时间必须早于失效时间</li>
* </ul>
* <p>
* 如果某个时间没有设置,则不检查(表示无限制)
*
* @return this
* @throws ValidateException 验证失败的异常
* @since 5.7.3
*/
public JWTValidator validateDate() throws ValidateException {
return validateDate(DateUtil.beginOfSecond(DateUtil.date()));
}
/**
* 检查JWT的以下三两个时间
*
* <ul>
* <li>{@link JWTPayload#NOT_BEFORE}:生效时间不能晚于当前时间</li>
* <li>{@link JWTPayload#EXPIRES_AT}:失效时间不能早于当前时间</li>
* <li>{@link JWTPayload#ISSUED_AT} 签发时间不能晚于当前时间</li>
* </ul>
* <p>
* 如果某个时间没有设置,则不检查(表示无限制)
*
* @param dateToCheck 被检查的时间,一般为当前时间
* @return this
* @throws ValidateException 验证失败的异常
*/
public JWTValidator validateDate(Date dateToCheck) throws ValidateException {
validateDate(this.jwt.getPayload(), dateToCheck, 0L);
return this;
}
/**
* 检查JWT的以下三两个时间
*
* <ul>
* <li>{@link JWTPayload#NOT_BEFORE}:生效时间不能晚于当前时间</li>
* <li>{@link JWTPayload#EXPIRES_AT}:失效时间不能早于当前时间</li>
* <li>{@link JWTPayload#ISSUED_AT} 签发时间不能晚于当前时间</li>
* </ul>
* <p>
* 如果某个时间没有设置,则不检查(表示无限制)
*
* @param dateToCheck 被检查的时间,一般为当前时间
* @param leeway 容忍空间,单位:秒。当不能晚于当前时间时,向后容忍;不能早于向前容忍。
* @return this
* @throws ValidateException 验证失败的异常
*/
public JWTValidator validateDate(Date dateToCheck, long leeway) throws ValidateException {
validateDate(this.jwt.getPayload(), dateToCheck, leeway);
return this;
}
/**
* 验证算法
*
* @param jwt {@link JWT}对象
* @param signer 用于验证的签名器
* @throws ValidateException 验证异常
*/
private static void validateAlgorithm(JWT jwt, JWTSigner signer) throws ValidateException {
final String algorithmId = jwt.getAlgorithm();
if (null == signer) {
signer = jwt.getSigner();
}
if (StrUtil.isEmpty(algorithmId)) {
// 可能无签名
if (null == signer || signer instanceof NoneJWTSigner) {
return;
}
throw new ValidateException("No algorithm defined in header!");
}
if (null == signer) {
throw new IllegalArgumentException("No Signer for validate algorithm!");
}
final String algorithmIdInSigner = signer.getAlgorithmId();
if (false == StrUtil.equals(algorithmId, algorithmIdInSigner)) {
throw new ValidateException("Algorithm [{}] defined in header doesn't match to [{}]!"
, algorithmId, algorithmIdInSigner);
}
// 通过算法验证签名是否正确
if (false == jwt.verify(signer)) {
throw new ValidateException("Signature verification failed!");
}
}
/**
* 检查JWT的以下三两个时间
*
* <ul>
* <li>{@link JWTPayload#NOT_BEFORE}:生效时间不能晚于当前时间</li>
* <li>{@link JWTPayload#EXPIRES_AT}:失效时间不能早于当前时间</li>
* <li>{@link JWTPayload#ISSUED_AT} 签发时间不能晚于当前时间</li>
* </ul>
* <p>
* 如果某个时间没有设置,则不检查(表示无限制)
*
* @param payload {@link JWTPayload}
* @param now 当前时间
* @param leeway 容忍空间,单位:秒。当不能晚于当前时间时,向后容忍;不能早于向前容忍。
* @throws ValidateException 验证异常
*/
private static void validateDate(JWTPayload payload, Date now, long leeway) throws ValidateException {
if (null == now) {
// 默认当前时间
now = DateUtil.date();
// truncate millis
now.setTime(now.getTime() / 1000 * 1000);
}
// 检查生效时间(生效时间不能晚于当前时间)
final Date notBefore = payload.getClaimsJson().getDate(JWTPayload.NOT_BEFORE);
validateNotAfter(JWTPayload.NOT_BEFORE, notBefore, now, leeway);
// 检查失效时间(失效时间不能早于当前时间)
final Date expiresAt = payload.getClaimsJson().getDate(JWTPayload.EXPIRES_AT);
validateNotBefore(JWTPayload.EXPIRES_AT, expiresAt, now, leeway);
// 检查签发时间(签发时间不能晚于当前时间)
final Date issueAt = payload.getClaimsJson().getDate(JWTPayload.ISSUED_AT);
validateNotAfter(JWTPayload.ISSUED_AT, issueAt, now, leeway);
}
/**
* 验证指定字段的时间不能晚于当前时间<br>
* 被检查的日期不存在则跳过
*
* @param fieldName 字段名
* @param dateToCheck 被检查的字段日期
* @param now 当前时间
* @param leeway 容忍空间,单位:秒。向后容忍
* @throws ValidateException 验证异常
*/
private static void validateNotAfter(String fieldName, Date dateToCheck, Date now, long leeway) throws ValidateException {
if (null == dateToCheck) {
return;
}
if(leeway > 0){
now = DateUtil.date(now.getTime() + leeway * 1000);
}
if (dateToCheck.after(now)) {
throw new ValidateException("'{}':[{}] is after now:[{}]",
fieldName, DateUtil.date(dateToCheck), DateUtil.date(now));
}
}
/**
* 验证指定字段的时间不能早于当前时间<br>
* 被检查的日期不存在则跳过
*
* @param fieldName 字段名
* @param dateToCheck 被检查的字段日期
* @param now 当前时间
* @param leeway 容忍空间,单位:秒。。向前容忍
* @throws ValidateException 验证异常
*/
@SuppressWarnings("SameParameterValue")
private static void validateNotBefore(String fieldName, Date dateToCheck, Date now, long leeway) throws ValidateException {
if (null == dateToCheck) {
return;
}
if(leeway > 0){
now = DateUtil.date(now.getTime() - leeway * 1000);
}
if (dateToCheck.before(now)) {
throw new ValidateException("'{}':[{}] is before now:[{}]",
fieldName, DateUtil.date(dateToCheck), DateUtil.date(now));
}
}
}

View File

@@ -0,0 +1,122 @@
package com.tiesheng.util.jwt;
import java.util.Date;
/**
* 注册的标准载荷Payload声明
*
* @param <T> 实现此接口的类的类型
* @author looly
* @since 5.7.2
*/
public interface RegisteredPayload<T extends RegisteredPayload<T>> {
/**
* jwt签发者
*/
String ISSUER = "iss";
/**
* jwt所面向的用户
*/
String SUBJECT = "sub";
/**
* 接收jwt的一方
*/
String AUDIENCE = "aud";
/**
* jwt的过期时间这个过期时间必须要大于签发时间
*/
String EXPIRES_AT = "exp";
/**
* 生效时间定义在什么时间之前该jwt都是不可用的.
*/
String NOT_BEFORE = "nbf";
/**
* jwt的签发时间
*/
String ISSUED_AT = "iat";
/**
* jwt的唯一身份标识主要用来作为一次性token,从而回避重放攻击。
*/
String JWT_ID = "jti";
/**
* 设置 jwt签发者("iss")的Payload值
*
* @param issuer jwt签发者
* @return this
*/
default T setIssuer(String issuer) {
return setPayload(ISSUER, issuer);
}
/**
* 设置jwt所面向的用户("sub")的Payload值
*
* @param subject jwt所面向的用户
* @return this
*/
default T setSubject(String subject) {
return setPayload(SUBJECT, subject);
}
/**
* 设置接收jwt的一方("aud")的Payload值
*
* @param audience 接收jwt的一方
* @return this
*/
default T setAudience(String... audience) {
return setPayload(AUDIENCE, audience);
}
/**
* 设置jwt的过期时间("exp")的Payload值这个过期时间必须要大于签发时间
*
* @param expiresAt jwt的过期时间
* @return this
* @see #setIssuedAt(Date)
*/
default T setExpiresAt(Date expiresAt) {
return setPayload(EXPIRES_AT, expiresAt);
}
/**
* 设置不可用时间点界限("nbf")的Payload值
*
* @param notBefore 不可用时间点界限在这个时间点之前jwt不可用
* @return this
*/
default T setNotBefore(Date notBefore) {
return setPayload(NOT_BEFORE, notBefore);
}
/**
* 设置jwt的签发时间("iat")
*
* @param issuedAt 签发时间
* @return this
*/
default T setIssuedAt(Date issuedAt) {
return setPayload(ISSUED_AT, issuedAt);
}
/**
* 设置jwt的唯一身份标识("jti")
*
* @param jwtId 唯一身份标识
* @return this
*/
default T setJWTId(String jwtId) {
return setPayload(JWT_ID, jwtId);
}
/**
* 设置Payload值
*
* @param name payload名
* @param value payload值
* @return this
*/
T setPayload(String name, Object value);
}

View File

@@ -0,0 +1,89 @@
package com.tiesheng.util.jwt.signers;
import cn.hutool.core.map.BiMap;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.asymmetric.SignAlgorithm;
import cn.hutool.crypto.digest.HmacAlgorithm;
import java.util.HashMap;
/**
* 算法工具类算法和JWT算法ID对应表
*
* @author looly
* @since 5.7.0
*/
public class AlgorithmUtil {
private static final BiMap<String, String> map;
static {
map = new BiMap<>(new HashMap<>());
map.put("HS256", HmacAlgorithm.HmacSHA256.getValue());
map.put("HS384", HmacAlgorithm.HmacSHA384.getValue());
map.put("HS512", HmacAlgorithm.HmacSHA512.getValue());
map.put("HMD5", HmacAlgorithm.HmacMD5.getValue());
map.put("HSHA1", HmacAlgorithm.HmacSHA1.getValue());
map.put("SM4CMAC", HmacAlgorithm.SM4CMAC.getValue());
map.put("RS256", SignAlgorithm.SHA256withRSA.getValue());
map.put("RS384", SignAlgorithm.SHA384withRSA.getValue());
map.put("RS512", SignAlgorithm.SHA512withRSA.getValue());
map.put("ES256", SignAlgorithm.SHA256withECDSA.getValue());
map.put("ES384", SignAlgorithm.SHA384withECDSA.getValue());
map.put("ES512", SignAlgorithm.SHA512withECDSA.getValue());
map.put("PS256", SignAlgorithm.SHA256withRSA_PSS.getValue());
map.put("PS384", SignAlgorithm.SHA384withRSA_PSS.getValue());
map.put("PS512", SignAlgorithm.SHA512withRSA_PSS.getValue());
map.put("RMD2", SignAlgorithm.MD2withRSA.getValue());
map.put("RMD5", SignAlgorithm.MD5withRSA.getValue());
map.put("RSHA1", SignAlgorithm.SHA1withRSA.getValue());
map.put("DNONE", SignAlgorithm.NONEwithDSA.getValue());
map.put("DSHA1", SignAlgorithm.SHA1withDSA.getValue());
map.put("ENONE", SignAlgorithm.NONEwithECDSA.getValue());
map.put("ESHA1", SignAlgorithm.SHA1withECDSA.getValue());
}
/**
* 获取算法用户传入算法ID返回算法名传入算法名返回本身
* @param idOrAlgorithm 算法ID或算法名
* @return 算法名
*/
public static String getAlgorithm(String idOrAlgorithm){
return ObjectUtil.defaultIfNull(getAlgorithmById(idOrAlgorithm), idOrAlgorithm);
}
/**
* 获取算法ID用户传入算法名返回ID传入算法ID返回本身
* @param idOrAlgorithm 算法ID或算法名
* @return 算法ID
*/
public static String getId(String idOrAlgorithm){
return ObjectUtil.defaultIfNull(getIdByAlgorithm(idOrAlgorithm), idOrAlgorithm);
}
/**
* 根据JWT算法ID获取算法
*
* @param id JWT算法ID
* @return 算法
*/
private static String getAlgorithmById(String id) {
return map.get(id.toUpperCase());
}
/**
* 根据算法获取JWT算法ID
*
* @param algorithm 算法
* @return JWT算法ID
*/
private static String getIdByAlgorithm(String algorithm) {
return map.getKey(algorithm);
}
}

View File

@@ -0,0 +1,97 @@
package com.tiesheng.util.jwt.signers;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.asymmetric.Sign;
import java.nio.charset.Charset;
import java.security.Key;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
/**
* 非对称加密JWT签名封装
*
* @author looly
* @since 5.7.0
*/
public class AsymmetricJWTSigner implements JWTSigner {
private Charset charset = CharsetUtil.CHARSET_UTF_8;
private final Sign sign;
/**
* 构造
*
* @param algorithm 算法字符串表示
* @param key 公钥{@link PublicKey}或私钥{@link PrivateKey},公钥用于验证签名,私钥用于产生签名
*/
public AsymmetricJWTSigner(String algorithm, Key key) {
final PublicKey publicKey = key instanceof PublicKey ? (PublicKey) key : null;
final PrivateKey privateKey = key instanceof PrivateKey ? (PrivateKey) key : null;
this.sign = new Sign(algorithm, privateKey, publicKey);
}
/**
* 构造
*
* @param algorithm 算法字符串表示
* @param keyPair 密钥对
*/
public AsymmetricJWTSigner(String algorithm, KeyPair keyPair) {
this.sign = new Sign(algorithm, keyPair);
}
/**
* 设置编码
*
* @param charset 编码
* @return 编码
*/
public AsymmetricJWTSigner setCharset(Charset charset) {
this.charset = charset;
return this;
}
@Override
public String sign(String headerBase64, String payloadBase64) {
final String dataStr = StrUtil.format("{}.{}", headerBase64, payloadBase64);
return Base64.encodeUrlSafe(sign(StrUtil.bytes(dataStr, charset)));
}
/**
* 签名字符串数据
*
* @param data 数据
* @return 签名
*/
protected byte[] sign(byte[] data) {
return sign.sign(data);
}
@Override
public boolean verify(String headerBase64, String payloadBase64, String signBase64) {
return verify(
StrUtil.bytes(StrUtil.format("{}.{}", headerBase64, payloadBase64), charset),
Base64.decode(signBase64));
}
/**
* 验签数据
*
* @param data 数据
* @param signed 签名
* @return 是否通过
*/
protected boolean verify(byte[] data, byte[] signed) {
return sign.verify(data, signed);
}
@Override
public String getAlgorithm() {
return this.sign.getSignature().getAlgorithm();
}
}

View File

@@ -0,0 +1,182 @@
package com.tiesheng.util.jwt.signers;
import com.tiesheng.util.jwt.JWTException;
import java.security.Key;
import java.security.KeyPair;
/**
* 椭圆曲线Elliptic Curve的JWT签名器。<br>
* 按照https://datatracker.ietf.org/doc/html/rfc7518#section-3.4,<br>
* Elliptic Curve Digital Signature Algorithm (ECDSA)算法签名需要转换DER格式为pair (R, S)
*
* @author looly
* @since 5.8.21
*/
public class EllipticCurveJWTSigner extends AsymmetricJWTSigner {
/**
* 构造
*
* @param algorithm 算法
* @param key 密钥
*/
public EllipticCurveJWTSigner(String algorithm, Key key) {
super(algorithm, key);
}
/**
* 构造
*
* @param algorithm 算法
* @param keyPair 密钥对
*/
public EllipticCurveJWTSigner(String algorithm, KeyPair keyPair) {
super(algorithm, keyPair);
}
@Override
protected byte[] sign(final byte[] data) {
// https://datatracker.ietf.org/doc/html/rfc7518#section-3.4
return derToConcat(super.sign(data), getSignatureByteArrayLength(getAlgorithm()));
}
@Override
protected boolean verify(final byte[] data, final byte[] signed) {
// https://datatracker.ietf.org/doc/html/rfc7518#section-3.4
return super.verify(data, concatToDER(signed));
}
/**
* 获取签名长度
* @param alg 算法
* @return 长度
* @throws JWTException JWT异常
*/
private static int getSignatureByteArrayLength(final String alg) throws JWTException {
switch (alg) {
case "ES256":
case "SHA256withECDSA":
return 64;
case "ES384":
case "SHA384withECDSA":
return 96;
case "ES512":
case "SHA512withECDSA":
return 132;
default:
throw new JWTException("Unsupported Algorithm: {}", alg);
}
}
private static byte[] derToConcat(final byte[] derSignature, int outputLength) throws JWTException {
if (derSignature.length < 8 || derSignature[0] != 48) {
throw new JWTException("Invalid ECDSA signature format");
}
final int offset;
if (derSignature[1] > 0) {
offset = 2;
} else if (derSignature[1] == (byte) 0x81) {
offset = 3;
} else {
throw new JWTException("Invalid ECDSA signature format");
}
final byte rLength = derSignature[offset + 1];
int i = rLength;
while ((i > 0) && (derSignature[(offset + 2 + rLength) - i] == 0)) {
i--;
}
final byte sLength = derSignature[offset + 2 + rLength + 1];
int j = sLength;
while ((j > 0) && (derSignature[(offset + 2 + rLength + 2 + sLength) - j] == 0)) {
j--;
}
int rawLen = Math.max(i, j);
rawLen = Math.max(rawLen, outputLength / 2);
if ((derSignature[offset - 1] & 0xff) != derSignature.length - offset
|| (derSignature[offset - 1] & 0xff) != 2 + rLength + 2 + sLength
|| derSignature[offset] != 2
|| derSignature[offset + 2 + rLength] != 2) {
throw new JWTException("Invalid ECDSA signature format");
}
final byte[] concatSignature = new byte[2 * rawLen];
System.arraycopy(derSignature, (offset + 2 + rLength) - i, concatSignature, rawLen - i, i);
System.arraycopy(derSignature, (offset + 2 + rLength + 2 + sLength) - j, concatSignature, 2 * rawLen - j, j);
return concatSignature;
}
private static byte[] concatToDER(byte[] jwsSignature) throws ArrayIndexOutOfBoundsException {
int rawLen = jwsSignature.length / 2;
int i = rawLen;
while ((i > 0) && (jwsSignature[rawLen - i] == 0)) {
i--;
}
int j = i;
if (jwsSignature[rawLen - i] < 0) {
j += 1;
}
int k = rawLen;
while ((k > 0) && (jwsSignature[2 * rawLen - k] == 0)) {
k--;
}
int l = k;
if (jwsSignature[2 * rawLen - k] < 0) {
l += 1;
}
int len = 2 + j + 2 + l;
if (len > 255) {
throw new JWTException("Invalid ECDSA signature format");
}
int offset;
final byte[] derSignature;
if (len < 128) {
derSignature = new byte[2 + 2 + j + 2 + l];
offset = 1;
} else {
derSignature = new byte[3 + 2 + j + 2 + l];
derSignature[1] = (byte) 0x81;
offset = 2;
}
derSignature[0] = 48;
derSignature[offset++] = (byte) len;
derSignature[offset++] = 2;
derSignature[offset++] = (byte) j;
System.arraycopy(jwsSignature, rawLen - i, derSignature, (offset + j) - i, i);
offset += j;
derSignature[offset++] = 2;
derSignature[offset++] = (byte) l;
System.arraycopy(jwsSignature, 2 * rawLen - k, derSignature, (offset + l) - k, k);
return derSignature;
}
}

View File

@@ -0,0 +1,69 @@
package com.tiesheng.util.jwt.signers;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.HMac;
import java.nio.charset.Charset;
import java.security.Key;
/**
* HMac算法签名实现
*
* @author looly
* @since 5.7.0
*/
public class HMacJWTSigner implements JWTSigner {
private Charset charset = CharsetUtil.CHARSET_UTF_8;
private final HMac hMac;
/**
* 构造
*
* @param algorithm HMAC签名算法
* @param key 密钥
*/
public HMacJWTSigner(String algorithm, byte[] key) {
this.hMac = new HMac(algorithm, key);
}
/**
* 构造
*
* @param algorithm HMAC签名算法
* @param key 密钥
*/
public HMacJWTSigner(String algorithm, Key key) {
this.hMac = new HMac(algorithm, key);
}
/**
* 设置编码
*
* @param charset 编码
* @return 编码
*/
public HMacJWTSigner setCharset(Charset charset) {
this.charset = charset;
return this;
}
@Override
public String sign(String headerBase64, String payloadBase64) {
return hMac.digestBase64(StrUtil.format("{}.{}", headerBase64, payloadBase64), charset, true);
}
@Override
public boolean verify(String headerBase64, String payloadBase64, String signBase64) {
final String sign = sign(headerBase64, payloadBase64);
return hMac.verify(
StrUtil.bytes(sign, charset),
StrUtil.bytes(signBase64, charset));
}
@Override
public String getAlgorithm() {
return this.hMac.getAlgorithm();
}
}

View File

@@ -0,0 +1,45 @@
package com.tiesheng.util.jwt.signers;
/**
* JWT签名接口封装通过实现此接口完成不同算法的签名功能
*
* @author looly
*/
public interface JWTSigner {
/**
* 签名
*
* @param headerBase64 JWT头的JSON字符串的Base64表示
* @param payloadBase64 JWT载荷的JSON字符串Base64表示
* @return 签名结果Base64即JWT的第三部分
*/
String sign(String headerBase64, String payloadBase64);
/**
* 验签
*
* @param headerBase64 JWT头的JSON字符串Base64表示
* @param payloadBase64 JWT载荷的JSON字符串Base64表示
* @param signBase64 被验证的签名Base64表示
* @return 签名是否一致
*/
boolean verify(String headerBase64, String payloadBase64, String signBase64);
/**
* 获取算法
*
* @return 算法
*/
String getAlgorithm();
/**
* 获取算法ID即算法的简写形式如HS256
*
* @return 算法ID
* @since 5.7.2
*/
default String getAlgorithmId() {
return AlgorithmUtil.getId(getAlgorithm());
}
}

View File

@@ -0,0 +1,288 @@
package com.tiesheng.util.jwt.signers;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ReUtil;
import java.security.Key;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
/**
* JWT签名器工具类
*
* @author looly
* @since 5.7.0
*/
public class JWTSignerUtil {
/**
* 无签名
*
* @return 无签名的签名器
*/
public static JWTSigner none() {
return NoneJWTSigner.NONE;
}
//------------------------------------------------------------------------- HSxxx
/**
* HS256(HmacSHA256)签名器
*
* @param key 密钥
* @return 签名器
*/
public static JWTSigner hs256(byte[] key) {
return createSigner("HS256", key);
}
/**
* HS384(HmacSHA384)签名器
*
* @param key 密钥
* @return 签名器
*/
public static JWTSigner hs384(byte[] key) {
return createSigner("HS384", key);
}
/**
* HS512(HmacSHA512)签名器
*
* @param key 密钥
* @return 签名器
*/
public static JWTSigner hs512(byte[] key) {
return createSigner("HS512", key);
}
//------------------------------------------------------------------------- RSxxx
/**
* RS256(SHA256withRSA)签名器
*
* @param key 密钥
* @return 签名器
*/
public static JWTSigner rs256(Key key) {
return createSigner("RS256", key);
}
/**
* RS384(SHA384withRSA)签名器
*
* @param key 密钥
* @return 签名器
*/
public static JWTSigner rs384(Key key) {
return createSigner("RS384", key);
}
/**
* RS512(SHA512withRSA)签名器
*
* @param key 密钥
* @return 签名器
*/
public static JWTSigner rs512(Key key) {
return createSigner("RS512", key);
}
//------------------------------------------------------------------------- ESxxx
/**
* ES256(SHA256withECDSA)签名器
*
* @param key 密钥
* @return 签名器
*/
public static JWTSigner es256(Key key) {
return createSigner("ES256", key);
}
/**
* ES384(SHA383withECDSA)签名器
*
* @param key 密钥
* @return 签名器
*/
public static JWTSigner es384(Key key) {
return createSigner("ES384", key);
}
/**
* ES512(SHA512withECDSA)签名器
*
* @param key 密钥
* @return 签名器
*/
public static JWTSigner es512(Key key) {
return createSigner("ES512", key);
}
/**
* HMD5(HmacMD5)签名器
*
* @param key 密钥
* @return 签名器
*/
public static JWTSigner hmd5(Key key) {
return createSigner("HMD5",key);
}
/**
* HSHA1(HmacSHA1)签名器
*
* @param key 密钥
* @return 签名器
*/
public static JWTSigner hsha1(Key key) {
return createSigner("HSHA1",key);
}
/**
* SM4CMAC(SM4CMAC)签名器
*
* @param key 密钥
* @return 签名器
*/
public static JWTSigner sm4cmac(Key key) {
return createSigner("SM4CMAC",key);
}
/**
* RMD2(MD2withRSA)签名器
*
* @param key 密钥
* @return 签名器
*/
public static JWTSigner rmd2(Key key) {
return createSigner("RMD2",key);
}
/**
* RMD5(MD5withRSA)签名器
*
* @param key 密钥
* @return 签名器
*/
public static JWTSigner rmd5(Key key) {
return createSigner("RMD5",key);
}
/**
* RSHA1(SHA1withRSA)签名器
*
* @param key 密钥
* @return 签名器
*/
public static JWTSigner rsha1(Key key) {
return createSigner("RSHA1",key);
}
/**
* DNONE(NONEwithDSA)签名器
*
* @param key 密钥
* @return 签名器
*/
public static JWTSigner dnone(Key key) {
return createSigner("DNONE",key);
}
/**
* DSHA1(SHA1withDSA)签名器
*
* @param key 密钥
* @return 签名器
*/
public static JWTSigner dsha1(Key key) {
return createSigner("DSHA1",key);
}
/**
* ENONE(NONEwithECDSA)签名器
*
* @param key 密钥
* @return 签名器
*/
public static JWTSigner enone(Key key) {
return createSigner("ENONE",key);
}
/**
* ESHA1(SHA1withECDSA)签名器
*
* @param key 密钥
* @return 签名器
*/
public static JWTSigner esha1(Key key) {
return createSigner("ESHA1",key);
}
/**
* 创建签名器
*
* @param algorithmId 算法ID见{@link AlgorithmUtil}
* @param key 密钥
* @return 签名器
*/
public static JWTSigner createSigner(String algorithmId, byte[] key) {
Assert.notNull(key, "Signer key must be not null!");
if (null == algorithmId || NoneJWTSigner.ID_NONE.equals(algorithmId)) {
return none();
}
return new HMacJWTSigner(AlgorithmUtil.getAlgorithm(algorithmId), key);
}
/**
* 创建签名器
*
* @param algorithmId 算法ID见{@link AlgorithmUtil}
* @param keyPair 密钥对
* @return 签名器
*/
public static JWTSigner createSigner(String algorithmId, KeyPair keyPair) {
Assert.notNull(keyPair, "Signer key pair must be not null!");
if (null == algorithmId || NoneJWTSigner.ID_NONE.equals(algorithmId)) {
return none();
}
// issue3205@Github
if(ReUtil.isMatch("es\\d{3}", algorithmId.toLowerCase())){
return new EllipticCurveJWTSigner(AlgorithmUtil.getAlgorithm(algorithmId), keyPair);
}
return new AsymmetricJWTSigner(AlgorithmUtil.getAlgorithm(algorithmId), keyPair);
}
/**
* 创建签名器
*
* @param algorithmId 算法ID见{@link AlgorithmUtil}
* @param key 密钥
* @return 签名器
*/
public static JWTSigner createSigner(String algorithmId, Key key) {
Assert.notNull(key, "Signer key must be not null!");
if (null == algorithmId || NoneJWTSigner.ID_NONE.equals(algorithmId)) {
return NoneJWTSigner.NONE;
}
if (key instanceof PrivateKey || key instanceof PublicKey) {
// issue3205@Github
if(ReUtil.isMatch("ES\\d{3}", algorithmId)){
return new EllipticCurveJWTSigner(algorithmId, key);
}
return new AsymmetricJWTSigner(AlgorithmUtil.getAlgorithm(algorithmId), key);
}
return new HMacJWTSigner(AlgorithmUtil.getAlgorithm(algorithmId), key);
}
}

View File

@@ -0,0 +1,31 @@
package com.tiesheng.util.jwt.signers;
import cn.hutool.core.util.StrUtil;
/**
* 无需签名的JWT签名器
*
* @author looly
* @since 5.7.0
*/
public class NoneJWTSigner implements JWTSigner {
public static final String ID_NONE = "none";
public static NoneJWTSigner NONE = new NoneJWTSigner();
@Override
public String sign(String headerBase64, String payloadBase64) {
return StrUtil.EMPTY;
}
@Override
public boolean verify(String headerBase64, String payloadBase64, String signBase64) {
return StrUtil.isEmpty(signBase64);
}
@Override
public String getAlgorithm() {
return ID_NONE;
}
}

View File

@@ -3,8 +3,8 @@ package com.tiesheng.util.pojos;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.jwt.JWT;
import com.tiesheng.util.config.TsTokenConfig;
import com.tiesheng.util.jwt.JWT;
/**
* @author hao

View File

@@ -3,7 +3,7 @@ package com.tiesheng.util.service;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.tiesheng.util.ServletKit;
import com.tiesheng.util.exception.ApiException;
import com.tiesheng.util.service.cache.TsCacheHandler;
@@ -36,7 +36,7 @@ public class TsCacheService {
}
public void putObj(String key, Object value, long seconds) {
tsCacheHandler.put(key, JSONUtil.toJsonStr(value), seconds);
tsCacheHandler.put(key, JSON.toJSONString(value), seconds);
}
public String get(String key) {
@@ -58,7 +58,7 @@ public class TsCacheService {
* @return
*/
public <T> T getObj(String key, Class<T> tClass, long seconds) {
return JSONUtil.toBean(get(key, seconds), tClass, true);
return JSON.parseObject(get(key, seconds), tClass);
}
public void remove(String key) {
@@ -68,11 +68,11 @@ public class TsCacheService {
/**
* 获取key
*
* @param pattern
* @param prefix
* @return
*/
public Set<String> keys(String pattern) {
return tsCacheHandler.keys(pattern);
public Set<String> keys(String prefix) {
return tsCacheHandler.keys(prefix);
}

View File

@@ -1,5 +1,6 @@
package com.tiesheng.util.service.cache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
@@ -13,7 +14,7 @@ import java.util.concurrent.TimeUnit;
@ConditionalOnProperty("spring.redis.url")
public class TsCacheRedisHandler implements TsCacheHandler {
@Resource
@Autowired
RedisTemplate<String, String> redisTemplate;

View File

@@ -4,7 +4,7 @@ import cn.hutool.core.io.FileUtil;
import cn.hutool.core.net.url.UrlQuery;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.alibaba.fastjson.JSONObject;
import okhttp3.*;
import java.io.File;

View File

@@ -9,7 +9,7 @@ import java.util.List;
@Service
public interface TsAuthorityHandler {
String CACHE_HAS_AUTHORITY = "CACHE:HAS_AUTHORITY:{}:{}";
String CACHE_AUTHORITY = "CACHE:AUTHORITY:{}:{}";
/**
@@ -30,4 +30,12 @@ public interface TsAuthorityHandler {
*/
List<String> getAuthorities(TokenBean tokenBean);
/**
* 创建结束后
*
* @param version
*/
void onCreateAfter(String version);
}

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-parent</artifactId>
<version>2.0.0.rc35</version>
<version>2.0.2</version>
</parent>
<artifactId>springboot-web</artifactId>
@@ -49,11 +49,6 @@
<artifactId>springboot-database</artifactId>
</dependency>
<dependency>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-poi</artifactId>
</dependency>
<dependency>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-login</artifactId>
@@ -64,11 +59,6 @@
<artifactId>springboot-message</artifactId>
</dependency>
<dependency>
<groupId>com.tiesheng.springboot-parent</groupId>
<artifactId>springboot-encrypt</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,7 +1,6 @@
package com.tiesheng.web;
import com.tiesheng.database.DatabaseAutoConfigurer;
import com.tiesheng.encrypt.EncryptAutoConfigurer;
import com.tiesheng.message.MessageAutoConfigurer;
import com.tiesheng.platform.PlatformAutoConfigurer;
import com.tiesheng.util.UtilAutoConfigurer;
@@ -21,7 +20,6 @@ import java.lang.annotation.*;
MessageAutoConfigurer.class,
WebAutoConfigurer.class,
DatabaseAutoConfigurer.class,
EncryptAutoConfigurer.class,
PlatformAutoConfigurer.class,
})
public @interface EnableTieshengWeb {

View File

@@ -1,9 +1,9 @@
package com.tiesheng.encrypt.config;
package com.tiesheng.web.config.encrypt;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.tiesheng.util.config.EncryptConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
@@ -66,7 +66,7 @@ public class DecryptRequestBodyAdvice implements RequestBodyAdvice {
DecryptHttpInputMessage(HttpInputMessage inputMessage, EncryptConfig encryptConfig) throws Exception {
this.headers = inputMessage.getHeaders();
String bodyStr = IoUtil.read(inputMessage.getBody(), CharsetUtil.CHARSET_UTF_8);
String encryptData = JSONUtil.parseObj(bodyStr).getStr("encryptData");
String encryptData = JSON.parseObject(bodyStr).getString("encryptData");
if (!StrUtil.isEmpty(encryptData)) {
String decrypt = encryptConfig.decrypt(encryptData);
this.body = IoUtil.toStream(decrypt, Charset.defaultCharset());

View File

@@ -1,8 +1,8 @@
package com.tiesheng.encrypt.config;
package com.tiesheng.web.config.encrypt;
import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.log.LogFactory;
import com.tiesheng.util.CommonUtil;
import com.alibaba.fastjson.JSON;
import com.tiesheng.util.config.EncryptConfig;
import com.tiesheng.util.pojos.ApiResp;
import org.springframework.beans.factory.annotation.Autowired;
@@ -42,7 +42,7 @@ public class EncryptResponseBodyAdvice implements ResponseBodyAdvice<ApiResp> {
}
body.setEncrypt(true);
body.setData(encryptConfig.encrypt(CommonUtil.writeJsonString(data)));
body.setData(encryptConfig.encrypt(JSON.toJSONString(data)));
return body;
} catch (Exception var17) {
LogFactory.get().info("加密数据异常", var17);

View File

@@ -2,12 +2,13 @@ package com.tiesheng.web.config.exception;
import cn.hutool.core.exceptions.ValidateException;
import cn.hutool.extra.spring.SpringUtil;
import com.tiesheng.web.service.TieshengWebConfigurer;
import com.tiesheng.util.exception.ApiException;
import com.tiesheng.util.exception.ApiRespEnum;
import com.tiesheng.util.pojos.ApiResp;
import com.tiesheng.web.service.TieshengWebConfigurer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.servlet.MultipartProperties;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
@@ -55,6 +56,9 @@ public class SpringExceptionHandler {
}
return ApiResp.respCust(ApiRespEnum.BadRequest.getCode(), msg);
}
if (e instanceof HttpMessageNotReadableException) {
return ApiResp.respCust(ApiRespEnum.BadRequest.getCode(), "参数格式不正确");
}
if (e instanceof MethodArgumentTypeMismatchException) {
return ApiResp.respCust(ApiRespEnum.BadRequest.getCode(), "请求参数不合法");
}

View File

@@ -1,7 +1,8 @@
package com.tiesheng.web.config.json;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import com.tiesheng.util.CommonUtil;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -25,12 +26,15 @@ public class FastJsonMessageConverter {
@Bean
public HttpMessageConverters fastJsonHttpMessageConverters() {
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
fastConverter.setFastJsonConfig(CommonUtil.fastJsonConfig());
fastConverter.setDefaultCharset(StandardCharsets.UTF_8);
FastJsonConfig config = new FastJsonConfig();
config.setDateFormat(JSON.DEFFAULT_DATE_FORMAT);
List<MediaType> mediaTypes = new ArrayList<>();
mediaTypes.add(MediaType.APPLICATION_JSON);
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
fastConverter.setFastJsonConfig(config);
fastConverter.setDefaultCharset(StandardCharsets.UTF_8);
fastConverter.setSupportedMediaTypes(mediaTypes);
return new HttpMessageConverters(fastConverter);

View File

@@ -56,7 +56,7 @@ public class RoleAuthorityAspect {
HttpServletRequest request = ServletKit.getRequest();
TokenBean tokenBean = tsTokenConfig.validToken(request, true);
String cacheKey = StrUtil.format(TsAuthorityHandler.CACHE_HAS_AUTHORITY, tokenBean.getRoleId(), tokenBean.getId());
String cacheKey = StrUtil.format(TsAuthorityHandler.CACHE_AUTHORITY, tokenBean.getRoleId(), tokenBean.getId());
List<String> authorityList = StrUtil.split(TsCacheService.of().get(cacheKey), ";")
.stream().filter(StrUtil::isNotEmpty).collect(Collectors.toList());
if (CollUtil.isEmpty(authorityList)) {

View File

@@ -0,0 +1,58 @@
package com.tiesheng.web.config.role;
import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.date.DateUtil;
import com.tiesheng.annotation.role.RoleAuthority;
import com.tiesheng.util.service.role.TsAuthorityHandler;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Service;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Service
public class RoleAuthorityCreator implements ApplicationListener<ContextRefreshedEvent> {
@Autowired(required = false)
TsAuthorityHandler tsAuthorityHandler;
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if (tsAuthorityHandler == null) {
return;
}
ApplicationContext applicationContext = event.getApplicationContext();
Map<String, Object> beansOfType = applicationContext.getBeansWithAnnotation(RoleAuthority.class);
String version = DateUtil.format(new Date(), "yyyyMMddHHmmss");
for (Map.Entry<String, Object> entry : beansOfType.entrySet()) {
Class<?> targetClass = AopUtils.getTargetClass(entry.getValue());
RoleAuthority menu = targetClass.getAnnotation(RoleAuthority.class);
List<RoleAuthority> points = new ArrayList<>();
Method[] methods = targetClass.getDeclaredMethods();
for (Method method : methods) {
RoleAuthority methodAuthority = AnnotationUtil.getAnnotation(method, RoleAuthority.class);
if (methodAuthority != null) {
points.add(methodAuthority);
}
}
tsAuthorityHandler.addRoleAuthority(version, menu, points);
}
tsAuthorityHandler.onCreateAfter(version);
}
}

View File

@@ -1,34 +0,0 @@
package com.tiesheng.web.config.template;
import com.tiesheng.web.pojos.dto.TemplateDealDTO;
import org.springframework.stereotype.Service;
@Service
public class TieshengTemplateHandler implements ToolTemplateHandler {
@Override
public String handler(TemplateDealDTO dto) {
return "";
}
@Override
public String getTemplateUrl() {
return "";
}
@Override
public Object getParms(Object params) {
return "";
}
@Override
public String getAction() {
return "";
}
@Override
public int getSort() {
return 0;
}
}

View File

@@ -1,54 +0,0 @@
package com.tiesheng.web.config.template;
import cn.hutool.core.util.StrUtil;
import com.tiesheng.web.pojos.dto.TemplateDealDTO;
import org.springframework.stereotype.Service;
@Service
public interface ToolTemplateHandler {
/**
* 处理对象
*
* @param dto
* @return
*/
String handler(TemplateDealDTO dto);
/**
* 获取模版地址
*
* @return
*/
String getTemplateUrl();
Object getParms(Object params);
/**
* 动作说明(唯一)
*
* @return
*/
String getAction();
/**
* 排序如果action相同只会使用sort大的来处理
*
* @return
*/
int getSort();
/**
* 获取模版ID
*
* @return
*/
default String getTeamplateId() {
return StrUtil.format("{}_{}", getAction(), getSort());
}
}

View File

@@ -62,6 +62,7 @@ public class CommWebController {
QueryWrapper<CoreConfigEnum> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("is_deleted", 0);
queryWrapper.eq("type", dto.getType());
queryWrapper.orderByAsc("type", "sort");
List<CoreConfigEnum> selectList = coreConfigService.getEnumMapper().selectList(queryWrapper);
return ApiResp.respOK(selectList);

View File

@@ -4,19 +4,33 @@ package com.tiesheng.web.controller.comm;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.tiesheng.annotation.operation.OperationIgnore;
import com.tiesheng.annotation.token.TokenIgnore;
import com.tiesheng.util.service.TsCacheService;
import com.tiesheng.web.config.template.ToolTemplateHandler;
import com.tiesheng.web.pojos.dto.*;
import com.tiesheng.web.pojos.vo.TemplateInfoVO;
import com.tiesheng.web.pojos.vo.PicVerifyVo;
import com.tiesheng.web.service.FileUploadService;
import com.tiesheng.util.exception.ApiException;
import com.tiesheng.util.pojos.ApiResp;
import com.tiesheng.util.pojos.TokenBean;
import com.tiesheng.util.service.TsCacheService;
import com.tiesheng.web.pojos.dao.CoreLogProcess;
import com.tiesheng.web.pojos.dto.ChunkCheckDTO;
import com.tiesheng.web.pojos.dto.ChunkMergeDTO;
import com.tiesheng.web.pojos.dto.ChunkStartDTO;
import com.tiesheng.web.pojos.dto.ImageCodeDTO;
import com.tiesheng.web.pojos.imex.ExportDealDTO;
import com.tiesheng.web.pojos.imex.ImportDealDTO;
import com.tiesheng.web.pojos.imex.ImportInfoDTO;
import com.tiesheng.web.pojos.imex.ImportInfoVO;
import com.tiesheng.web.pojos.vo.PicVerifyVo;
import com.tiesheng.web.service.CoreLogService;
import com.tiesheng.web.service.FileUploadService;
import com.tiesheng.web.service.imex.TsExportHandler;
import com.tiesheng.web.service.imex.TsImportHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.Valid;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@@ -35,7 +49,11 @@ public class ToolController {
@Autowired
FileUploadService fileUploadService;
@Autowired
List<ToolTemplateHandler> templateHandlerList;
List<TsImportHandler> importHandlers;
@Autowired
List<TsExportHandler> exportHandlers;
@Autowired
CoreLogService coreLogService;
/**
@@ -124,40 +142,102 @@ public class ToolController {
}
@TokenIgnore
@GetMapping("/template/info")
public ApiResp<TemplateInfoVO> templateInfo(TemplateInfoDTO dto) {
///////////////////////////////////////////////////////////////////////////
// import
///////////////////////////////////////////////////////////////////////////
List<ToolTemplateHandler> collect = templateHandlerList.stream()
.filter(it -> Objects.equals(it.getAction(), dto.getAction()))
.sorted((it, it2) -> it2.getSort() - it.getSort())
.collect(Collectors.toList());
if (CollUtil.isEmpty(collect)) {
throw new ApiException("没有找到对应的模版");
@TokenIgnore
@GetMapping("/imex/info")
public ApiResp<ImportInfoVO> importInfo(@Valid ImportInfoDTO dto) {
ImportInfoVO template = new ImportInfoVO();
if (Objects.equals(dto.getType(), "import")) {
List<TsImportHandler> collect = importHandlers.stream()
.filter(it -> Objects.equals(it.getAction(), dto.getAction()))
.sorted((it, it2) -> it2.getSort() - it.getSort())
.collect(Collectors.toList());
if (CollUtil.isNotEmpty(collect)) {
TsImportHandler toolTemplateHandler = collect.get(0);
template.setTemplateUrl(toolTemplateHandler.getTemplateUrl());
template.setImexId(toolTemplateHandler.getImexId());
}
} else if (Objects.equals(dto.getType(), "export")) {
List<TsExportHandler> collect = exportHandlers.stream()
.filter(it -> Objects.equals(it.getAction(), dto.getAction()))
.sorted((it, it2) -> it2.getSort() - it.getSort())
.collect(Collectors.toList());
if (CollUtil.isNotEmpty(collect)) {
TsExportHandler toolTemplateHandler = collect.get(0);
template.setImexId(toolTemplateHandler.getImexId());
}
}
ToolTemplateHandler toolTemplateHandler = collect.get(0);
TemplateInfoVO template = new TemplateInfoVO();
template.setTemplateUrl(toolTemplateHandler.getTemplateUrl());
template.setParams(toolTemplateHandler.getParms(dto.getParams()));
template.setTemplateId(toolTemplateHandler.getTeamplateId());
if (StrUtil.isEmpty(template.getImexId())) {
throw new ApiException("没有找到对应的模版");
}
return ApiResp.respOK(template);
}
@TokenIgnore
@PostMapping("/template/deal")
public ApiResp<String> templateDeal(@RequestBody TemplateDealDTO dto) {
List<ToolTemplateHandler> collect = templateHandlerList.stream().
filter(it -> Objects.equals(it.getTeamplateId(), dto.getTemplateId()))
@TokenIgnore
@OperationIgnore
@PostMapping("/import/deal")
public ApiResp<String> importDeal(@RequestBody @Valid ImportDealDTO dto, TokenBean token) {
List<TsImportHandler> collect = importHandlers.stream().
filter(it -> Objects.equals(it.getImexId(), dto.getImexId()))
.collect(Collectors.toList());
if (CollUtil.isEmpty(collect)) {
throw new ApiException("模版ID不存在");
throw new ApiException("导入ID不存在");
}
return ApiResp.respOK(collect.get(0).handler(dto));
TsImportHandler tsImportHandler = collect.get(0);
tsImportHandler.validToken(token);
List read = tsImportHandler.ready(dto, token);
if (CollUtil.isEmpty(read)) {
throw new ApiException("没有数据可以导入");
}
CoreLogProcess coreLogProcess = coreLogService.addProcess(tsImportHandler.getImexId(), read, tsImportHandler);
coreLogProcess.setParams(JSON.toJSONString(dto));
coreLogService.getCoreLogProcessMapper().updateById(coreLogProcess);
return ApiResp.respOK(coreLogProcess.getId());
}
///////////////////////////////////////////////////////////////////////////
// export
///////////////////////////////////////////////////////////////////////////
@TokenIgnore
@OperationIgnore
@PostMapping("/export/deal")
public ApiResp<String> exportDeal(@RequestBody @Valid ExportDealDTO dto, TokenBean token) {
List<TsExportHandler> collect = exportHandlers.stream().
filter(it -> Objects.equals(it.getImexId(), dto.getImexId()))
.collect(Collectors.toList());
if (CollUtil.isEmpty(collect)) {
throw new ApiException("导出ID不存在");
}
TsExportHandler tsExportHandler = collect.get(0);
tsExportHandler.validToken(token);
List read = tsExportHandler.ready(dto, token);
if (CollUtil.isEmpty(read)) {
throw new ApiException("没有数据可以导出");
}
CoreLogProcess coreLogProcess = coreLogService.addProcess(tsExportHandler.getImexId(), read, tsExportHandler);
coreLogProcess.setType("export");
coreLogProcess.setParams(JSON.toJSONString(dto));
coreLogService.getCoreLogProcessMapper().updateById(coreLogProcess);
return ApiResp.respOK(coreLogProcess.getId());
}
}

View File

@@ -41,6 +41,7 @@ public class ConfigEnumController {
if (!StrUtil.isEmpty(dto.getType())) {
queryWrapper.eq("type", dto.getType());
}
queryWrapper.orderByAsc("type", "sort");
List<CoreConfigEnum> selectList = coreConfigService.getEnumMapper().selectList(queryWrapper);
return ApiResp.respOK(selectList);

View File

@@ -41,7 +41,7 @@ public class LogApiController {
if (!StrUtil.isEmpty(result)) {
queryWrapper.eq("result", result);
}
dto.likeColumns(queryWrapper, "type", "content");
dto.likeColumns(queryWrapper, "type", "url", "content");
queryWrapper.orderByDesc("create_time");
Page<CoreLogApi> page = dto.pageObj();

View File

@@ -5,8 +5,8 @@ import com.baomidou.mybatisplus.annotation.TableName;
import com.tiesheng.util.pojos.DaoBase;
/**
* 配置-枚举
*/
* 配置-枚举
*/
@TableName(value = "core_config_enum")
public class CoreConfigEnum extends DaoBase {
/**
@@ -21,6 +21,12 @@ public class CoreConfigEnum extends DaoBase {
@TableField(value = "`name`")
private String name;
/**
* 排序
*/
@TableField(value = "sort")
private Integer sort;
/**
* 备注
*/
@@ -69,6 +75,24 @@ public class CoreConfigEnum extends DaoBase {
this.name = name;
}
/**
* 获取排序
*
* @return sort - 排序
*/
public Integer getSort() {
return sort;
}
/**
* 设置排序
*
* @param sort 排序
*/
public void setSort(Integer sort) {
this.sort = sort;
}
/**
* 获取备注
*

View File

@@ -48,14 +48,8 @@ public class CoreLogProcess extends DaoBase {
/**
* 失败的文件
*/
@TableField(value = "fail_file")
private String failFile;
/**
* 异常说明
*/
@TableField(value = "error")
private String error;
@TableField(value = "result_file")
private String resultFile;
/**
* 进度
@@ -63,6 +57,12 @@ public class CoreLogProcess extends DaoBase {
@TableField(value = "`process`")
private Integer process;
/**
* 异常说明
*/
@TableField(value = "params")
private String params;
/**
* 获取标题
*
@@ -174,37 +174,19 @@ public class CoreLogProcess extends DaoBase {
/**
* 获取失败的文件
*
* @return fail_file - 失败的文件
* @return result_file - 失败的文件
*/
public String getFailFile() {
return failFile;
public String getResultFile() {
return resultFile;
}
/**
* 设置失败的文件
*
* @param failFile 失败的文件
* @param resultFile 失败的文件
*/
public void setFailFile(String failFile) {
this.failFile = failFile;
}
/**
* 获取异常说明
*
* @return error - 异常说明
*/
public String getError() {
return error;
}
/**
* 设置异常说明
*
* @param error 异常说明
*/
public void setError(String error) {
this.error = error;
public void setResultFile(String resultFile) {
this.resultFile = resultFile;
}
/**
@@ -224,4 +206,22 @@ public class CoreLogProcess extends DaoBase {
public void setProcess(Integer process) {
this.process = process;
}
/**
* 获取异常说明
*
* @return params - 异常说明
*/
public String getParams() {
return params;
}
/**
* 设置异常说明
*
* @param params 异常说明
*/
public void setParams(String params) {
this.params = params;
}
}

View File

@@ -0,0 +1,33 @@
package com.tiesheng.web.pojos.imex;
import com.alibaba.fastjson.JSONObject;
import javax.validation.constraints.NotEmpty;
public class ExportDealDTO {
@NotEmpty(message = "模版ID")
private String imexId;
private JSONObject params;
///////////////////////////////////////////////////////////////////////////
// setter\getter
///////////////////////////////////////////////////////////////////////////
public String getImexId() {
return imexId;
}
public void setImexId(String imexId) {
this.imexId = imexId;
}
public JSONObject getParams() {
return params;
}
public void setParams(JSONObject params) {
this.params = params;
}
}

View File

@@ -1,25 +1,27 @@
package com.tiesheng.web.pojos.dto;
package com.tiesheng.web.pojos.imex;
import com.alibaba.fastjson.JSONObject;
import javax.validation.constraints.NotEmpty;
public class TemplateDealDTO {
public class ImportDealDTO {
@NotEmpty(message = "模版ID")
private String templateId;
private String imexId;
@NotEmpty(message = "文件路径必填")
private String file;
private Object params;
private JSONObject params;
///////////////////////////////////////////////////////////////////////////
// setter\getter
///////////////////////////////////////////////////////////////////////////
public String getTemplateId() {
return templateId;
public String getImexId() {
return imexId;
}
public void setTemplateId(String templateId) {
this.templateId = templateId;
public void setImexId(String imexId) {
this.imexId = imexId;
}
public String getFile() {
@@ -30,11 +32,11 @@ public class TemplateDealDTO {
this.file = file;
}
public Object getParams() {
public JSONObject getParams() {
return params;
}
public void setParams(Object params) {
public void setParams(JSONObject params) {
this.params = params;
}
}

View File

@@ -1,10 +1,15 @@
package com.tiesheng.web.pojos.dto;
package com.tiesheng.web.pojos.imex;
public class TemplateInfoDTO {
import javax.validation.constraints.NotEmpty;
public class ImportInfoDTO {
@NotEmpty(message = "操作必须存在")
private String action;
private Object params;
@NotEmpty(message = "类型必须存在")
private String type;
///////////////////////////////////////////////////////////////////////////
// setter\getter
@@ -18,11 +23,11 @@ public class TemplateInfoDTO {
this.action = action;
}
public Object getParams() {
return params;
public String getType() {
return type;
}
public void setParams(Object params) {
this.params = params;
public void setType(String type) {
this.type = type;
}
}

View File

@@ -0,0 +1,29 @@
package com.tiesheng.web.pojos.imex;
public class ImportInfoVO {
private String imexId;
private String templateUrl;
///////////////////////////////////////////////////////////////////////////
// setter\getter
///////////////////////////////////////////////////////////////////////////
public String getImexId() {
return imexId;
}
public void setImexId(String imexId) {
this.imexId = imexId;
}
public String getTemplateUrl() {
return templateUrl;
}
public void setTemplateUrl(String templateUrl) {
this.templateUrl = templateUrl;
}
}

View File

@@ -5,7 +5,7 @@ package com.tiesheng.web.pojos.vo;
*/
public class ProcessDetailVo {
private String title;
private String id;
private Integer total;
@@ -15,13 +15,17 @@ public class ProcessDetailVo {
private Integer process;
private String type;
private Integer status;
private String failFile;
private String resultFile;
private String error;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Integer getStatus() {
return status;
@@ -31,14 +35,6 @@ public class ProcessDetailVo {
this.status = status;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Integer getTotal() {
return total;
}
@@ -63,20 +59,12 @@ public class ProcessDetailVo {
this.failNum = failNum;
}
public String getType() {
return type;
public String getResultFile() {
return resultFile;
}
public void setType(String type) {
this.type = type;
}
public String getFailFile() {
return failFile;
}
public void setFailFile(String failFile) {
this.failFile = failFile;
public void setResultFile(String resultFile) {
this.resultFile = resultFile;
}
public Integer getProcess() {
@@ -87,11 +75,4 @@ public class ProcessDetailVo {
this.process = process;
}
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
}

View File

@@ -1,37 +0,0 @@
package com.tiesheng.web.pojos.vo;
public class TemplateInfoVO {
private String templateId;
private String templateUrl;
private Object params;
///////////////////////////////////////////////////////////////////////////
// setter\getter
///////////////////////////////////////////////////////////////////////////
public String getTemplateId() {
return templateId;
}
public void setTemplateId(String templateId) {
this.templateId = templateId;
}
public String getTemplateUrl() {
return templateUrl;
}
public void setTemplateUrl(String templateUrl) {
this.templateUrl = templateUrl;
}
public Object getParams() {
return params;
}
public void setParams(Object params) {
this.params = params;
}
}

View File

@@ -5,7 +5,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tiesheng.login.mapper.CoreLogLoginMapper;
import com.tiesheng.login.pojos.RequestUserInfo;
@@ -23,7 +23,6 @@ import com.tiesheng.web.util.ProcessSyncConsumer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
/**
@@ -32,11 +31,6 @@ import java.util.List;
@Service
public class CoreLogService extends TsServiceBase<CoreLogOperationMapper, CoreLogOperation> {
/**
* 日志缓存
*/
private static final List<CoreLogOperation> cacheOperations = new ArrayList<>();
@Autowired
TieshengWebConfigurer tieshengWebConfigurer;
@Autowired
@@ -79,33 +73,24 @@ public class CoreLogService extends TsServiceBase<CoreLogOperationMapper, CoreLo
coreLogProcess.setSuccessNum(0);
coreLogProcess.setFailNum(0);
coreLogProcess.setProcess(0);
coreLogProcess.setError("");
coreLogProcess.setParams("");
coreLogProcessMapper.insert(coreLogProcess);
ThreadUtil.execute(() -> {
List<Exception> errorList = new ArrayList<>();
CollUtil.split(list, 100).forEach((it) -> {
int accept = 0;
try {
accept = consumer.accept(it);
} catch (Exception e) {
errorList.add(e);
}
int accept = consumer.batchHandler(it);
coreLogProcess.setProcess(coreLogProcess.getProcess() + it.size());
coreLogProcess.setSuccessNum(coreLogProcess.getSuccessNum() + accept);
coreLogProcess.setFailNum(coreLogProcess.getFailNum() + it.size() - accept);
coreLogProcess.setError(JSONUtil.toJsonStr(errorList));
coreLogProcessMapper.updateById(coreLogProcess);
});
// 执行结束
coreLogProcess.setFailFile(consumer.getFailFile());
coreLogProcess.setResultFile(consumer.getResultFile());
coreLogProcess.setStatus(1);
coreLogProcess.setError(JSONUtil.toJsonStr(errorList));
coreLogProcessMapper.updateById(coreLogProcess);
});
return coreLogProcess;
}
@@ -126,29 +111,24 @@ public class CoreLogService extends TsServiceBase<CoreLogOperationMapper, CoreLo
coreLogProcess.setFailNum(0);
coreLogProcess.setTotal(0);
coreLogProcess.setProcess(0);
coreLogProcess.setError("");
coreLogProcessMapper.insert(coreLogProcess);
ThreadUtil.execute(() -> {
int pageSize = 1000;
int pageNum = 1, lastCount = pageSize;
List<Exception> errorList = new ArrayList<>();
while (lastCount == pageSize) {
try {
lastCount = consumer.accept(pageNum, pageSize);
coreLogProcess.setTotal(coreLogProcess.getTotal() + lastCount);
coreLogProcess.setProcess(coreLogProcess.getTotal());
coreLogProcess.setError(JSONUtil.toJsonStr(errorList));
coreLogProcess.setSuccessNum(coreLogProcess.getSuccessNum() + lastCount);
} catch (Exception e) {
errorList.add(e);
} catch (Exception ignored) {
}
coreLogProcessMapper.updateById(coreLogProcess);
pageNum++;
}
// 执行结束
coreLogProcess.setError(JSONUtil.toJsonStr(errorList));
coreLogProcess.setStatus(1);
coreLogProcessMapper.updateById(coreLogProcess);
});
@@ -192,16 +172,9 @@ public class CoreLogService extends TsServiceBase<CoreLogOperationMapper, CoreLo
operation.setTitle(title);
operation.setSubject(subject);
if (params != null) {
operation.setParams(JSONUtil.toJsonStr(params));
}
synchronized (CoreLogOperation.class) {
cacheOperations.add(operation);
if (cacheOperations.size() >= 100) {
getBaseMapper().batchInsert(cacheOperations);
cacheOperations.clear();
}
operation.setParams(JSON.toJSONString(params));
}
save(operation);
}

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