Merge branch 'dev-V0.4.5' of https://gitee.com/iotkit-open-source/iotkit-parent into dev-V0.4.5
commit
488c526055
|
@ -23,7 +23,6 @@ hs_err_pid*
|
|||
.idea
|
||||
target
|
||||
*.iml
|
||||
log
|
||||
data/elasticsearch
|
||||
.init
|
||||
*.db
|
||||
|
|
|
@ -79,19 +79,19 @@ Vertx event-bus(内置)、RocketMQ,通过扩展模块可接入其它任意
|
|||
|
||||
##### 关系数据库切换为mysql方法(其它数据库同理)
|
||||
|
||||
1、将iot-rdb-data-service/pom.xml中的mysql驱动注释放开
|
||||
1、将iot-data-serviceImpl-rdb/pom.xml中的mysql驱动注释放开
|
||||
|
||||
2、启动时指定active: --spring.profiles.active=mysql
|
||||
|
||||
##### 时序数据库切换为TDengein方法
|
||||
|
||||
1、注释掉iot-standalone/pom.xml中的 iot-es-temporal-service,并打开iot-td-temporal-service的注释
|
||||
1、注释掉iot-standalone/pom.xml中的 iot-temporal-serviceImpl-es,并打开iot-td-temporal-service的注释
|
||||
|
||||
2、application.xml中注释掉elasticsearch配置,并打开td-datasource配置
|
||||
|
||||
##### 消息总线切换为RocketMq方法
|
||||
|
||||
1、注释掉iot-standalone/pom.xml中的 iot-vertx-event-bus,并打开iot-message-rocketmq的注释
|
||||
1、注释掉iot-standalone/pom.xml中的 iot-message-event-bus,并打开iot-message-rocketmq的注释
|
||||
|
||||
2、application.xml中打开rocketmq配置
|
||||
|
||||
|
|
Binary file not shown.
|
@ -1,7 +1,5 @@
|
|||
var mid=1;
|
||||
|
||||
var access_token="";
|
||||
|
||||
function getMid(){
|
||||
mid++;
|
||||
if(mid>10000){
|
||||
|
@ -9,58 +7,94 @@ function getMid(){
|
|||
}
|
||||
return mid;
|
||||
};
|
||||
function getPingData(data){
|
||||
var ping={
|
||||
productKey:"",
|
||||
deviceName:"",
|
||||
function getPkDn(deviceKey){
|
||||
var arr=deviceKey.split("_");
|
||||
return {
|
||||
pk:arr[1],
|
||||
dn:deviceKey
|
||||
};
|
||||
}
|
||||
function register(data){
|
||||
var device=getPkDn(data.data.deviceName)
|
||||
var subDevicesList=data.data.subDevices
|
||||
var subDevices=[]
|
||||
if(subDevicesList!=undefined&&subDevicesList.length>0){
|
||||
apiTool.log("device:"+subDevicesList);
|
||||
for (var i = 0; i < subDevicesList.length; i++) {
|
||||
var deviceKey=subDevicesList[i]
|
||||
var subDevice=getPkDn(deviceKey)
|
||||
subDevices.push({
|
||||
productKey:subDevice.pk,
|
||||
deviceName:subDevice.dn,
|
||||
model:''
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var reply=
|
||||
{
|
||||
productKey:device.pk,
|
||||
deviceName:device.dn,
|
||||
mid:"0",
|
||||
content:{
|
||||
id:getMid(),
|
||||
type:data
|
||||
id:data.id,
|
||||
type:data.type,
|
||||
result:'success'
|
||||
}
|
||||
};
|
||||
var data={
|
||||
productKey:device.pk,
|
||||
deviceName:device.dn
|
||||
}
|
||||
if(subDevices.length>0){
|
||||
data['subDevices']=subDevices
|
||||
}
|
||||
apiTool.log("subDevices:"+JSON.stringify(data));
|
||||
return {
|
||||
type:"action",
|
||||
data:{
|
||||
productKey:"",
|
||||
deviceName:"",
|
||||
state:""
|
||||
},
|
||||
type:"register",
|
||||
data:data,
|
||||
action:{
|
||||
type:"ack",
|
||||
content:JSON.stringify(ping)
|
||||
}
|
||||
content:JSON.stringify(reply)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function online(data){
|
||||
apiTool.log("data:"+JSON.stringify(data));
|
||||
var device=getPkDn(data.data.deviceName)
|
||||
return {
|
||||
type:"state",
|
||||
data:{
|
||||
productKey:device.pk,
|
||||
deviceName:device.dn,
|
||||
state:data.type
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function offline(data){
|
||||
var device=getPkDn(data.deviceKey)
|
||||
return {
|
||||
type:"state",
|
||||
data:{
|
||||
productKey:device.pk,
|
||||
deviceName:device.dn,
|
||||
state:data.type
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
//必须提供onReceive方法
|
||||
this.onReceive=function(head,type,payload){
|
||||
var data=JSON.parse(payload)
|
||||
if(data.type=="auth_required"){
|
||||
var auth={
|
||||
productKey:"",
|
||||
deviceName:"",
|
||||
content:{
|
||||
type:"auth",
|
||||
access_token:access_token
|
||||
}
|
||||
};
|
||||
return {
|
||||
type:"action",
|
||||
data:{
|
||||
productKey:"",
|
||||
deviceName:"",
|
||||
state:""
|
||||
},
|
||||
action:{
|
||||
type:"ack",
|
||||
content:JSON.stringify(auth)
|
||||
}
|
||||
}
|
||||
}else if(data.type=="auth_ok"){
|
||||
return getPingData(data.heartBeatData);
|
||||
}else if(data.type=="pong"){
|
||||
apiTool.log("receive pong!");
|
||||
}else if("ping"==type){
|
||||
return getPingData(data.heartBeatData);
|
||||
if(data.type=="register"){
|
||||
apiTool.log("data:"+payload);
|
||||
return register(data)
|
||||
}else if(data.type=="online"){
|
||||
return online(data);
|
||||
}else if(data.type=="offline"){
|
||||
return offline(data);
|
||||
}
|
||||
return {
|
||||
productKey:"",
|
||||
|
@ -70,3 +104,7 @@ this.onReceive=function(head,type,payload){
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.onRegistered=function (data,status) {
|
||||
apiTool.log("onRegistered调用");
|
||||
}
|
Binary file not shown.
|
@ -1,7 +1,7 @@
|
|||
var mid=1;
|
||||
|
||||
var gatewayPk="BRD3x4fkKxkaxXFt"
|
||||
var smartMeterPk="PjmkANSTDt85bZPj"
|
||||
var smartMeterPk="PwMfpXmp4ZWkGahn"
|
||||
|
||||
function getMid(){
|
||||
mid++;
|
||||
|
|
|
@ -1,74 +0,0 @@
|
|||
var pidPkMap={
|
||||
"H5Z31yKBmy":"3ptfx2dRescPAwTn",
|
||||
"xOCy76jn6k":"jzC6eQGRse6hDZPB"
|
||||
}
|
||||
|
||||
this.onReceive=function(method,path,header,params,body){
|
||||
var type=header["Content-Type"];
|
||||
if(type=="application/json"){
|
||||
var msg=JSON.parse(body.msg);
|
||||
var productId=msg.productId;
|
||||
var deviceName=msg.deviceName;
|
||||
var messageType=msg.messageType;
|
||||
var data=msg.data;
|
||||
var pk=pidPkMap[productId];
|
||||
if(!pk){
|
||||
return {
|
||||
url:"",
|
||||
header:{
|
||||
contentType:"application/json"
|
||||
},
|
||||
content:"error"
|
||||
}
|
||||
}
|
||||
|
||||
if(messageType=="lifeCycle"){
|
||||
//登录、登出
|
||||
var online=data.status=="online";
|
||||
deviceBehaviour.deviceStateChange(pk,deviceName,online);
|
||||
}else if(messageType=="notify"){
|
||||
//设备消息
|
||||
//消息类型
|
||||
var notifyType=msg.notifyType;
|
||||
if(notifyType=="property"){
|
||||
//属性上报
|
||||
var propertyData={};
|
||||
for(var p in data.params){
|
||||
propertyData[p]=data.params[p].value;
|
||||
}
|
||||
deviceBehaviour.reportMessage(JSON.stringify({
|
||||
mid:data.id,
|
||||
productKey:pk,
|
||||
deviceName:deviceName,
|
||||
type:"property",
|
||||
identifier:"report",
|
||||
data:propertyData
|
||||
}));
|
||||
}else if(notifyType=="event"){
|
||||
//事件上报
|
||||
var identifier="";
|
||||
var paramData={};
|
||||
for(var p in data.params){
|
||||
identifier=p;
|
||||
paramData=data.params[p];
|
||||
}
|
||||
|
||||
deviceBehaviour.reportMessage(JSON.stringify({
|
||||
mid:data.id,
|
||||
productKey:pk,
|
||||
deviceName:deviceName,
|
||||
type:"event",
|
||||
identifier:identifier,
|
||||
data:paramData.value
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
url:"",
|
||||
header:{
|
||||
contentType:"application/json"
|
||||
},
|
||||
content:JSON.stringify(params.msg)
|
||||
}
|
||||
};
|
Binary file not shown.
|
@ -43,5 +43,10 @@
|
|||
"id": "FreshAir",
|
||||
"name": "新风",
|
||||
"createAt": 1681444312184
|
||||
},
|
||||
{
|
||||
"id": "SmartMeter",
|
||||
"name": "智能电表",
|
||||
"createAt": 1681444312184
|
||||
}
|
||||
]
|
|
@ -0,0 +1,23 @@
|
|||
[
|
||||
{
|
||||
"id": "fa1c5eaa-de6e-48b6-805e-8f091c7bb831",
|
||||
"code": "DingTalk",
|
||||
"title": "钉钉",
|
||||
"icon": "http://www.baidu.com",
|
||||
"createAt": 1683816661690
|
||||
},
|
||||
{
|
||||
"id": "fa1c5eaa-de6e-48b6-805e-8f091c7bb832",
|
||||
"code": "QyWechat",
|
||||
"title": "企业微信",
|
||||
"icon": "http://www.baidu.com",
|
||||
"createAt": 1683816661690
|
||||
},
|
||||
{
|
||||
"id": "fa1c5eaa-de6e-48b6-805e-8f091c7bb833",
|
||||
"code": "Email",
|
||||
"title": "邮箱",
|
||||
"icon": "http://www.baidu.com",
|
||||
"createAt": 1683816661690
|
||||
}
|
||||
]
|
|
@ -984,8 +984,8 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"id": "a5fnnx3ksu7n2n0f",
|
||||
"productKey": "a5fnnx3ksu7n2n0f",
|
||||
"id": "bGdZt8ffBETtsirm",
|
||||
"productKey": "bGdZt8ffBETtsirm",
|
||||
"model": {
|
||||
"properties": [
|
||||
{
|
||||
|
@ -1115,8 +1115,8 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"id": "PjmkANSTDt85bZPj",
|
||||
"productKey": "PjmkANSTDt85bZPj",
|
||||
"id": "PwMfpXmp4ZWkGahn",
|
||||
"productKey": "PwMfpXmp4ZWkGahn",
|
||||
"model": {
|
||||
"properties": [
|
||||
{
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
# **提交规范**
|
||||
|
||||
## **例子**
|
||||
|
||||
```
|
||||
feat(miniprogram):新增自开奖页面
|
||||
|
||||
新增活动页面,但是产品还有需求遗漏,待完善
|
||||
- 新增内容1
|
||||
- 新增内容2
|
||||
```
|
||||
|
||||
```
|
||||
fix(miniprogram):活动页面设置渠道后,自动添加渠道文字类型判断错误
|
||||
```
|
||||
|
||||
|
||||
|
||||
## **Commit message 格式**
|
||||
|
||||
为了方便使用,我们避免了过于复杂的规定,格式较为简单且不限制中英文:
|
||||
|
||||
|
||||
|
||||
```
|
||||
<type>(<scope>): <subject>
|
||||
// 空一行
|
||||
<body>
|
||||
// 空一行
|
||||
|
||||
// 注意冒号 : 后有空格
|
||||
// 如 feat(miniprogram): 增加了小程序模板消息相关功能
|
||||
```
|
||||
|
||||
大致分为两个个部分:
|
||||
|
||||
1. 标题行: 包括` <type>(<scope>): <subject>`
|
||||
2. 主题内容: 描述了为什么修改,做了什么修改,以及开发思路等
|
||||
|
||||
| | 说明 | 必填 |
|
||||
| ------- | ---------------------- | ------ |
|
||||
| type | 修改类型 | 必填 |
|
||||
| scope | 作用范围 | 非必填 |
|
||||
| subject | 对commit的简单描述 | 必填 |
|
||||
| body | 本次 commit 的详细描述 | 非必填 |
|
||||
|
||||
### **1.type**
|
||||
|
||||
```
|
||||
feat:新功能(feature)
|
||||
fix:修补bug
|
||||
docs:文档(documentation)
|
||||
style: 格式(不影响代码运行的变动)
|
||||
refactor:重构(即不是新增功能,也不是修改bug的代码变动)
|
||||
test:增加测试
|
||||
chore:构建过程或辅助工具的变动
|
||||
```
|
||||
|
||||
如果type为feat和fix,则该 commit 将肯定出现在 Change log 之中。其他情况(docs、chore、style、refactor、test)由你决定,要不要放入 Change log,建议是不要。
|
||||
|
||||
### **2.scope**
|
||||
|
||||
scope用于说明 commit 影响的范围,比如数据层、控制层、视图层等等,视项目不同而不同。
|
||||
|
||||
### **3. subject**
|
||||
|
||||
subject是 commit 目的的简短描述,不超过50个字符。
|
||||
|
||||
```
|
||||
以动词开头,使用第一人称现在时,比如change,而不是changed或changes
|
||||
第一个字母小写
|
||||
结尾不加句号(.)
|
||||
```
|
||||
|
||||
### **4. body**
|
||||
|
||||
Body 部分是对本次 commit 的详细描述,可以分成多行。描述为什么修改, 做了什么样的修改, 以及开发的思路等等
|
|
@ -1,59 +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">
|
||||
<parent>
|
||||
<artifactId>iotkit-parent</artifactId>
|
||||
<groupId>cc.iotkit</groupId>
|
||||
<version>0.4.3-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>iot-auth-server</artifactId>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-oauth2</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-dao-redis-jackson</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.ejlchina</groupId>
|
||||
<artifactId>okhttps</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cc.iotkit</groupId>
|
||||
<artifactId>iot-data-service</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -1 +0,0 @@
|
|||
此模块为认证服务,提供oauth2认证界面和接口
|
|
@ -1,138 +0,0 @@
|
|||
/*
|
||||
* +----------------------------------------------------------------------
|
||||
* | Copyright (c) 奇特物联 2021-2022 All rights reserved.
|
||||
* +----------------------------------------------------------------------
|
||||
* | Licensed 未经许可不能去掉「奇特物联」相关版权
|
||||
* +----------------------------------------------------------------------
|
||||
* | Author: xw2sy@163.com
|
||||
* +----------------------------------------------------------------------
|
||||
*/
|
||||
package cc.iotkit.oauth.controller;
|
||||
|
||||
import cc.iotkit.common.Constants;
|
||||
import cc.iotkit.common.utils.CodecUtil;
|
||||
import cc.iotkit.common.utils.ReflectUtil;
|
||||
import cc.iotkit.data.IOauthClientData;
|
||||
import cc.iotkit.data.IUserInfoData;
|
||||
import cc.iotkit.model.OauthClient;
|
||||
import cc.iotkit.model.UserInfo;
|
||||
import cc.iotkit.oauth.vo.UserInfoVo;
|
||||
import cc.iotkit.utils.SoMap;
|
||||
import cn.dev33.satoken.stp.SaLoginConfig;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
import com.ejlchina.okhttps.OkHttps;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.cglib.beans.BeanMap;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.view.RedirectView;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/oauth2")
|
||||
public class AuthClientController {
|
||||
|
||||
@Value("${oauth2.auth-server-url}")
|
||||
private String serverUrl;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("oauthClientDataCache")
|
||||
private IOauthClientData oauthClientData;
|
||||
@Autowired
|
||||
@Qualifier("userInfoDataCache")
|
||||
private IUserInfoData userInfoData;
|
||||
|
||||
/**
|
||||
* 根据Code码进行登录,获取 Access-Token 和 用户信息
|
||||
*/
|
||||
@RequestMapping("/codeLogin")
|
||||
public SaResult codeLogin(String code, String clientId) {
|
||||
OauthClient oauthClient = oauthClientData.findByClientId(clientId);
|
||||
if (oauthClient == null) {
|
||||
return SaResult.error("clientId does not exist");
|
||||
}
|
||||
String clientSecret = oauthClient.getClientSecret();
|
||||
|
||||
// 调用Server端接口,获取 Access-Token 以及其他信息
|
||||
String str = OkHttps.sync(serverUrl + "/oauth2/token")
|
||||
.addBodyPara("grant_type", "authorization_code")
|
||||
.addBodyPara("code", code)
|
||||
.addBodyPara("client_id", clientId)
|
||||
.addBodyPara("client_secret", clientSecret)
|
||||
.post()
|
||||
.getBody()
|
||||
.toString();
|
||||
SoMap so = SoMap.getSoMap().setJsonString(str);
|
||||
log.info("get token by code result:{}", so);
|
||||
// 存在code,不是token结构
|
||||
if (so.getInt("code") != 0) {
|
||||
return SaResult.error(so.getString("msg"));
|
||||
}
|
||||
|
||||
// 根据openid获取其对应的userId
|
||||
String uid = getUserIdByOpenid(so.getString("openid"));
|
||||
String access_token = so.getString("access_token");
|
||||
UserInfoVo userVo = getUserInfo(uid);
|
||||
BeanMap beanMap = BeanMap.create(userVo);
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
beanMap.forEach((key, value) -> {
|
||||
data.put(key.toString(), value);
|
||||
});
|
||||
data.put("access_token", access_token);
|
||||
|
||||
// 返回相关参数
|
||||
StpUtil.login(uid, SaLoginConfig.setToken(access_token));
|
||||
return SaResult.data(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注销登录
|
||||
*/
|
||||
@RequestMapping("/logout")
|
||||
public RedirectView logout(String accessToken, String redirect_uri) {
|
||||
//先注销client中cookie的token
|
||||
StpUtil.logout();
|
||||
//再注销web页面使用的token
|
||||
StpUtil.logoutByTokenValue(accessToken);
|
||||
|
||||
return new RedirectView(redirect_uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录验证
|
||||
*/
|
||||
@GetMapping("/checkLogin")
|
||||
public SaResult checkLogin() {
|
||||
try {
|
||||
String uid = StpUtil.getLoginId().toString();
|
||||
UserInfoVo userVo = getUserInfo(uid);
|
||||
return SaResult.ok().setData(userVo);
|
||||
} catch (Throwable e) {
|
||||
return SaResult.error("no login");
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private String getUserIdByOpenid(String openid) {
|
||||
String clientIdLoginId = CodecUtil.aesDecrypt(openid, Constants.ACCOUNT_SECRET);
|
||||
return clientIdLoginId.split(":")[1];
|
||||
}
|
||||
|
||||
private UserInfoVo getUserInfo(String uid) {
|
||||
UserInfo userInfo = userInfoData.findById(uid);
|
||||
UserInfoVo userVo = new UserInfoVo();
|
||||
ReflectUtil.copyNoNulls(userInfo, userVo);
|
||||
return userVo;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,99 +0,0 @@
|
|||
/*
|
||||
* +----------------------------------------------------------------------
|
||||
* | Copyright (c) 奇特物联 2021-2022 All rights reserved.
|
||||
* +----------------------------------------------------------------------
|
||||
* | Licensed 未经许可不能去掉「奇特物联」相关版权
|
||||
* +----------------------------------------------------------------------
|
||||
* | Author: xw2sy@163.com
|
||||
* +----------------------------------------------------------------------
|
||||
*/
|
||||
package cc.iotkit.oauth.controller;
|
||||
|
||||
import cc.iotkit.common.utils.JsonUtil;
|
||||
import cc.iotkit.data.IUserInfoData;
|
||||
import cc.iotkit.model.UserInfo;
|
||||
import cc.iotkit.oauth.service.TokenRequestHandler;
|
||||
import cc.iotkit.utils.AuthUtil;
|
||||
import cn.dev33.satoken.oauth2.config.SaOAuth2Config;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
public class AuthServerController {
|
||||
|
||||
@Autowired
|
||||
private IUserInfoData userInfoData;
|
||||
|
||||
/**
|
||||
* 处理所有OAuth相关请求
|
||||
*/
|
||||
@RequestMapping("/oauth2/*")
|
||||
public Object request(HttpServletRequest request) {
|
||||
Object result = TokenRequestHandler.serverRequest();
|
||||
log.info("oauth path:{},result:{}", request.getRequestURI(), JsonUtil.toJsonString(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sa-OAuth2 自定义配置
|
||||
*/
|
||||
@Autowired
|
||||
public void setSaOAuth2Config(SaOAuth2Config cfg) {
|
||||
cfg.
|
||||
// 未登录的视图
|
||||
setNotLoginView(() -> new ModelAndView("login.html")).
|
||||
// 登录处理函数
|
||||
setDoLoginHandle((name, pwd) -> {
|
||||
try {
|
||||
UserInfo userInfo = userInfoData.findByUid(name);
|
||||
if (userInfo != null) {
|
||||
String secret = userInfo.getSecret();
|
||||
if (AuthUtil.checkPwd(pwd, secret)) {
|
||||
StpUtil.login(userInfo.getId(), "PC");
|
||||
return SaResult.ok();
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
return SaResult.error("账号名或密码错误");
|
||||
}
|
||||
return SaResult.error("账号名或密码错误");
|
||||
}).
|
||||
// 授权确认视图
|
||||
setConfirmView((clientId, scope) -> {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("clientId", clientId);
|
||||
map.put("scope", scope);
|
||||
return new ModelAndView("confirm.html", map);
|
||||
})
|
||||
;
|
||||
|
||||
//开启密码授权、刷新token和client授权模式
|
||||
cfg.setIsPassword(true);
|
||||
cfg.setIsNewRefresh(true);
|
||||
cfg.setIsClient(true);
|
||||
}
|
||||
|
||||
// 全局异常拦截
|
||||
@ExceptionHandler
|
||||
public SaResult handlerException(Exception e) {
|
||||
e.printStackTrace();
|
||||
return SaResult.error(e.getMessage());
|
||||
}
|
||||
|
||||
@RequestMapping("/oauth2/userinfo")
|
||||
public SaResult userinfo() {
|
||||
return SaResult.ok();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
* +----------------------------------------------------------------------
|
||||
* | Copyright (c) 奇特物联 2021-2022 All rights reserved.
|
||||
* +----------------------------------------------------------------------
|
||||
* | Licensed 未经许可不能去掉「奇特物联」相关版权
|
||||
* +----------------------------------------------------------------------
|
||||
* | Author: xw2sy@163.com
|
||||
* +----------------------------------------------------------------------
|
||||
*/
|
||||
package cc.iotkit.oauth.service;
|
||||
|
||||
import cc.iotkit.common.Constants;
|
||||
import cc.iotkit.common.utils.CodecUtil;
|
||||
import cc.iotkit.data.IOauthClientData;
|
||||
import cc.iotkit.model.OauthClient;
|
||||
import cn.dev33.satoken.oauth2.logic.SaOAuth2Template;
|
||||
import cn.dev33.satoken.oauth2.model.SaClientModel;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class SaOAuth2TemplateImpl extends SaOAuth2Template {
|
||||
|
||||
@Autowired
|
||||
@Qualifier("oauthClientDataCache")
|
||||
private IOauthClientData oauthClientData;
|
||||
|
||||
// 根据 id 获取 Client 信息
|
||||
@Override
|
||||
public SaClientModel getClientModel(String clientId) {
|
||||
OauthClient client = oauthClientData.findByClientId(clientId);
|
||||
if (client == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new SaClientModel()
|
||||
.setClientId(client.getClientId())
|
||||
.setClientSecret(client.getClientSecret())
|
||||
.setAllowUrl(client.getAllowUrl())
|
||||
.setContractScope("userinfo")
|
||||
.setIsAutoMode(true);
|
||||
}
|
||||
|
||||
// 根据ClientId 和 LoginId 获取openid
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public String getOpenid(String clientId, Object loginId) {
|
||||
// 此为模拟数据,真实环境需要从数据库查询
|
||||
return CodecUtil.aesEncrypt(clientId + ":" + loginId, Constants.ACCOUNT_SECRET);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String randomAccessToken(String clientId, Object loginId, String scope) {
|
||||
return StpUtil.createLoginSession(loginId);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* +----------------------------------------------------------------------
|
||||
* | Copyright (c) 奇特物联 2021-2022 All rights reserved.
|
||||
* +----------------------------------------------------------------------
|
||||
* | Licensed 未经许可不能去掉「奇特物联」相关版权
|
||||
* +----------------------------------------------------------------------
|
||||
* | Author: xw2sy@163.com
|
||||
* +----------------------------------------------------------------------
|
||||
*/
|
||||
package cc.iotkit.oauth.service;
|
||||
|
||||
import cc.iotkit.data.IUserInfoData;
|
||||
import cc.iotkit.model.UserInfo;
|
||||
import cn.dev33.satoken.stp.StpInterface;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class StpInterfaceImpl implements StpInterface {
|
||||
|
||||
@Autowired
|
||||
@Qualifier("userInfoDataCache")
|
||||
private IUserInfoData userInfoData;
|
||||
|
||||
/**
|
||||
* 返回一个账号所拥有的权限码集合
|
||||
*/
|
||||
@Override
|
||||
public List<String> getPermissionList(Object loginId, String loginType) {
|
||||
UserInfo userInfo = userInfoData.findById(loginId.toString());
|
||||
return userInfo.getPermissions();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回一个账号所拥有的角色标识集合 (权限与角色可分开校验)
|
||||
*/
|
||||
@Override
|
||||
public List<String> getRoleList(Object loginId, String loginType) {
|
||||
UserInfo userInfo = userInfoData.findById(loginId.toString());
|
||||
return userInfo.getRoles();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,124 +0,0 @@
|
|||
/*
|
||||
* +----------------------------------------------------------------------
|
||||
* | Copyright (c) 奇特物联 2021-2022 All rights reserved.
|
||||
* +----------------------------------------------------------------------
|
||||
* | Licensed 未经许可不能去掉「奇特物联」相关版权
|
||||
* +----------------------------------------------------------------------
|
||||
* | Author: xw2sy@163.com
|
||||
* +----------------------------------------------------------------------
|
||||
*/
|
||||
package cc.iotkit.oauth.service;
|
||||
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.context.model.SaRequest;
|
||||
import cn.dev33.satoken.context.model.SaResponse;
|
||||
import cn.dev33.satoken.oauth2.SaOAuth2Manager;
|
||||
import cn.dev33.satoken.oauth2.config.SaOAuth2Config;
|
||||
import cn.dev33.satoken.oauth2.exception.SaOAuth2Exception;
|
||||
import cn.dev33.satoken.oauth2.logic.SaOAuth2Consts;
|
||||
import cn.dev33.satoken.oauth2.logic.SaOAuth2Handle;
|
||||
import cn.dev33.satoken.oauth2.logic.SaOAuth2Util;
|
||||
import cn.dev33.satoken.oauth2.model.AccessTokenModel;
|
||||
import cn.dev33.satoken.oauth2.model.ClientTokenModel;
|
||||
import cn.dev33.satoken.oauth2.model.RequestAuthModel;
|
||||
import cn.dev33.satoken.oauth2.model.SaClientModel;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
|
||||
public class TokenRequestHandler {
|
||||
|
||||
public static Object serverRequest() {
|
||||
SaRequest req = SaHolder.getRequest();
|
||||
SaResponse res = SaHolder.getResponse();
|
||||
SaOAuth2Config cfg = SaOAuth2Manager.getConfig();
|
||||
SaClientModel cm;
|
||||
if (req.isPath(SaOAuth2Consts.Api.authorize) && req.isParam(SaOAuth2Consts.Param.response_type, SaOAuth2Consts.ResponseType.code)) {
|
||||
cm = SaOAuth2Handle.currClientModel();
|
||||
if (!cfg.getIsCode() || !cm.isCode && !cm.isAutoMode) {
|
||||
throw new SaOAuth2Exception("暂未开放的授权模式");
|
||||
} else {
|
||||
return SaOAuth2Handle.authorize(req, res, cfg);
|
||||
}
|
||||
} else if (req.isPath(SaOAuth2Consts.Api.token) && req.isParam(SaOAuth2Consts.Param.grant_type, SaOAuth2Consts.GrantType.authorization_code)) {
|
||||
return token(req, res, cfg);
|
||||
} else if (req.isPath(SaOAuth2Consts.Api.token) && req.isParam(SaOAuth2Consts.Param.grant_type, SaOAuth2Consts.GrantType.refresh_token)) {
|
||||
return refreshToken(req);
|
||||
} else if (req.isPath(SaOAuth2Consts.Api.revoke)) {
|
||||
return SaOAuth2Handle.revokeToken(req);
|
||||
} else if (req.isPath(SaOAuth2Consts.Api.doLogin)) {
|
||||
return SaOAuth2Handle.doLogin(req, res, cfg);
|
||||
} else if (req.isPath(SaOAuth2Consts.Api.doConfirm)) {
|
||||
return SaOAuth2Handle.doConfirm(req);
|
||||
} else if (req.isPath(SaOAuth2Consts.Api.authorize) && req.isParam(SaOAuth2Consts.Param.response_type, SaOAuth2Consts.ResponseType.token)) {
|
||||
cm = SaOAuth2Handle.currClientModel();
|
||||
if (!cfg.getIsImplicit() || !cm.isImplicit && !cm.isAutoMode) {
|
||||
throw new SaOAuth2Exception("暂未开放的授权模式");
|
||||
} else {
|
||||
return SaOAuth2Handle.authorize(req, res, cfg);
|
||||
}
|
||||
} else if (req.isPath(SaOAuth2Consts.Api.token) && req.isParam(SaOAuth2Consts.Param.grant_type, SaOAuth2Consts.GrantType.password)) {
|
||||
cm = SaOAuth2Handle.currClientModel();
|
||||
if (!cfg.getIsPassword() || !cm.isPassword && !cm.isAutoMode) {
|
||||
throw new SaOAuth2Exception("暂未开放的授权模式");
|
||||
} else {
|
||||
return password(req, res, cfg);
|
||||
}
|
||||
} else if (req.isPath(SaOAuth2Consts.Api.token) && req.isParam(SaOAuth2Consts.Param.grant_type, SaOAuth2Consts.GrantType.client_credentials)) {
|
||||
cm = SaOAuth2Handle.currClientModel();
|
||||
if (!cfg.getIsClient() || !cm.isClient && !cm.isAutoMode) {
|
||||
throw new SaOAuth2Exception("暂未开放的授权模式");
|
||||
} else {
|
||||
return clientToken(req, res, cfg);
|
||||
}
|
||||
} else {
|
||||
return "{\"msg\": \"not handle\"}";
|
||||
}
|
||||
}
|
||||
|
||||
public static Object token(SaRequest req, SaResponse res, SaOAuth2Config cfg) {
|
||||
String code = req.getParamNotNull(SaOAuth2Consts.Param.code);
|
||||
String clientId = req.getParamNotNull(SaOAuth2Consts.Param.client_id);
|
||||
String clientSecret = req.getParamNotNull(SaOAuth2Consts.Param.client_secret);
|
||||
String redirectUri = req.getParam(SaOAuth2Consts.Param.redirect_uri);
|
||||
SaOAuth2Util.checkGainTokenParam(code, clientId, clientSecret, redirectUri);
|
||||
AccessTokenModel token = SaOAuth2Util.generateAccessToken(code);
|
||||
return token.toLineMap();
|
||||
}
|
||||
|
||||
public static Object refreshToken(SaRequest req) {
|
||||
String clientId = req.getParamNotNull(SaOAuth2Consts.Param.client_id);
|
||||
String clientSecret = req.getParamNotNull(SaOAuth2Consts.Param.client_secret);
|
||||
String refreshToken = req.getParamNotNull(SaOAuth2Consts.Param.refresh_token);
|
||||
SaOAuth2Util.checkRefreshTokenParam(clientId, clientSecret, refreshToken);
|
||||
return SaOAuth2Util.refreshAccessToken(refreshToken).toLineMap();
|
||||
}
|
||||
|
||||
public static Object password(SaRequest req, SaResponse res, SaOAuth2Config cfg) {
|
||||
String username = req.getParamNotNull(SaOAuth2Consts.Param.username);
|
||||
String password = req.getParamNotNull(SaOAuth2Consts.Param.password);
|
||||
String clientId = req.getParamNotNull(SaOAuth2Consts.Param.client_id);
|
||||
String scope = req.getParam(SaOAuth2Consts.Param.scope, "");
|
||||
SaOAuth2Util.checkContract(clientId, scope);
|
||||
SaHolder.getStorage().set(StpUtil.stpLogic.splicingKeyJustCreatedSave(), "no-token");
|
||||
Object retObj = cfg.getDoLoginHandle().apply(username, password);
|
||||
if (!StpUtil.isLogin()) {
|
||||
return retObj;
|
||||
} else {
|
||||
RequestAuthModel ra = new RequestAuthModel();
|
||||
ra.clientId = clientId;
|
||||
ra.loginId = StpUtil.getLoginId();
|
||||
ra.scope = scope;
|
||||
AccessTokenModel at = SaOAuth2Util.generateAccessToken(ra, true);
|
||||
return at.toLineMap();
|
||||
}
|
||||
}
|
||||
|
||||
public static Object clientToken(SaRequest req, SaResponse res, SaOAuth2Config cfg) {
|
||||
String clientId = req.getParamNotNull(SaOAuth2Consts.Param.client_id);
|
||||
String clientSecret = req.getParamNotNull(SaOAuth2Consts.Param.client_secret);
|
||||
String scope = req.getParam(SaOAuth2Consts.Param.scope);
|
||||
SaOAuth2Util.checkContract(clientId, scope);
|
||||
SaOAuth2Util.checkClientSecret(clientId, clientSecret);
|
||||
ClientTokenModel ct = SaOAuth2Util.generateClientToken(clientId, scope);
|
||||
return ct.toLineMap();
|
||||
}
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
/*
|
||||
* +----------------------------------------------------------------------
|
||||
* | Copyright (c) 奇特物联 2021-2022 All rights reserved.
|
||||
* +----------------------------------------------------------------------
|
||||
* | Licensed 未经许可不能去掉「奇特物联」相关版权
|
||||
* +----------------------------------------------------------------------
|
||||
* | Author: xw2sy@163.com
|
||||
* +----------------------------------------------------------------------
|
||||
*/
|
||||
package cc.iotkit.oauth.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
public class UserInfoVo {
|
||||
|
||||
/**
|
||||
* 用户账号
|
||||
*/
|
||||
private String uid;
|
||||
|
||||
/**
|
||||
* 用户昵称
|
||||
*/
|
||||
private String nickName;
|
||||
|
||||
/**
|
||||
* 性别 0-未知 1-male,2-female
|
||||
*/
|
||||
private Integer gender;
|
||||
|
||||
/**
|
||||
* 头像地址
|
||||
*/
|
||||
private String avatarUrl;
|
||||
|
||||
private String email;
|
||||
|
||||
private String address;
|
||||
|
||||
/**
|
||||
* 当前家庭Id
|
||||
*/
|
||||
private String currHomeId;
|
||||
|
||||
/**
|
||||
* 用户类型
|
||||
* 0:平台用户
|
||||
* 1:终端用户
|
||||
*/
|
||||
private Integer type;
|
||||
|
||||
/**
|
||||
* 角色
|
||||
*/
|
||||
private List<String> roles = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 权限
|
||||
*/
|
||||
private List<String> permissions = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 用户使用的平台
|
||||
* 见:Constants.THIRD_PLATFORM
|
||||
*/
|
||||
private List<String> usePlatforms = new ArrayList<>();
|
||||
|
||||
|
||||
}
|
|
@ -1,837 +0,0 @@
|
|||
/*
|
||||
* +----------------------------------------------------------------------
|
||||
* | Copyright (c) 奇特物联 2021-2022 All rights reserved.
|
||||
* +----------------------------------------------------------------------
|
||||
* | Licensed 未经许可不能去掉「奇特物联」相关版权
|
||||
* +----------------------------------------------------------------------
|
||||
* | Author: xw2sy@163.com
|
||||
* +----------------------------------------------------------------------
|
||||
*/
|
||||
package cc.iotkit.utils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import cc.iotkit.common.utils.JsonUtil;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
/**
|
||||
* Map< String, Object> 是最常用的一种Map类型,但是它写着麻烦
|
||||
* <p>所以特封装此类,继承Map,进行一些扩展,可以让Map更灵活使用
|
||||
* <p>最新:2020-12-10 新增部分构造方法
|
||||
*
|
||||
* @author kong
|
||||
*/
|
||||
public class SoMap extends LinkedHashMap<String, Object> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public SoMap() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 以下元素会在isNull函数中被判定为Null,
|
||||
*/
|
||||
public static final Object[] NULL_ELEMENT_ARRAY = {null, ""};
|
||||
public static final List<Object> NULL_ELEMENT_LIST;
|
||||
|
||||
static {
|
||||
NULL_ELEMENT_LIST = Arrays.asList(NULL_ELEMENT_ARRAY);
|
||||
}
|
||||
|
||||
// ============================= 读值 =============================
|
||||
|
||||
/**
|
||||
* 获取一个值
|
||||
*/
|
||||
@Override
|
||||
public Object get(Object key) {
|
||||
if ("this".equals(key)) {
|
||||
return this;
|
||||
}
|
||||
return super.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果为空,则返回默认值
|
||||
*/
|
||||
public Object get(Object key, Object defaultValue) {
|
||||
Object value = get(key);
|
||||
if (valueIsNull(value)) {
|
||||
return defaultValue;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转为String并返回
|
||||
*/
|
||||
public String getString(String key) {
|
||||
Object value = get(key);
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
return String.valueOf(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果为空,则返回默认值
|
||||
*/
|
||||
public String getString(String key, String defaultValue) {
|
||||
Object value = get(key);
|
||||
if (valueIsNull(value)) {
|
||||
return defaultValue;
|
||||
}
|
||||
return String.valueOf(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转为int并返回
|
||||
*/
|
||||
public int getInt(String key) {
|
||||
Object value = get(key);
|
||||
if (valueIsNull(value)) {
|
||||
return 0;
|
||||
}
|
||||
return Integer.parseInt(String.valueOf(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* 转为int并返回,同时指定默认值
|
||||
*/
|
||||
public int getInt(String key, int defaultValue) {
|
||||
Object value = get(key);
|
||||
if (valueIsNull(value)) {
|
||||
return defaultValue;
|
||||
}
|
||||
return Integer.parseInt(String.valueOf(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* 转为long并返回
|
||||
*/
|
||||
public long getLong(String key) {
|
||||
Object value = get(key);
|
||||
if (valueIsNull(value)) {
|
||||
return 0;
|
||||
}
|
||||
return Long.parseLong(String.valueOf(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* 转为double并返回
|
||||
*/
|
||||
public double getDouble(String key) {
|
||||
Object value = get(key);
|
||||
if (valueIsNull(value)) {
|
||||
return 0.0;
|
||||
}
|
||||
return Double.parseDouble(String.valueOf(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* 转为boolean并返回
|
||||
*/
|
||||
public boolean getBoolean(String key) {
|
||||
Object value = get(key);
|
||||
if (valueIsNull(value)) {
|
||||
return false;
|
||||
}
|
||||
return Boolean.parseBoolean(String.valueOf(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* 转为Date并返回,根据自定义格式
|
||||
*/
|
||||
public Date getDateByFormat(String key, String format) {
|
||||
try {
|
||||
return new SimpleDateFormat(format).parse(getString(key));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转为Date并返回,根据格式: yyyy-MM-dd
|
||||
*/
|
||||
public Date getDate(String key) {
|
||||
return getDateByFormat(key, "yyyy-MM-dd");
|
||||
}
|
||||
|
||||
/**
|
||||
* 转为Date并返回,根据格式: yyyy-MM-dd HH:mm:ss
|
||||
*/
|
||||
public Date getDateTime(String key) {
|
||||
return getDateByFormat(key, "yyyy-MM-dd HH:mm:ss");
|
||||
}
|
||||
|
||||
/**
|
||||
* 转为Map并返回
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public SoMap getMap(String key) {
|
||||
Object value = get(key);
|
||||
if (value == null) {
|
||||
return SoMap.getSoMap();
|
||||
}
|
||||
if (value instanceof Map) {
|
||||
return SoMap.getSoMap((Map) value);
|
||||
}
|
||||
if (value instanceof String) {
|
||||
return SoMap.getSoMap().setJsonString((String) value);
|
||||
}
|
||||
throw new RuntimeException("值无法转化为SoMap: " + value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取集合(必须原先就是个集合,否则会创建个新集合并返回)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<Object> getList(String key) {
|
||||
Object value = get(key);
|
||||
List<Object> list;
|
||||
if (value == null || value.equals("")) {
|
||||
list = new ArrayList<>();
|
||||
} else if (value instanceof List) {
|
||||
list = (List<Object>) value;
|
||||
} else {
|
||||
list = new ArrayList<>();
|
||||
list.add(value);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取集合 (指定泛型类型)
|
||||
*/
|
||||
public <T> List<T> getList(String key, Class<T> cs) {
|
||||
List<Object> list = getList(key);
|
||||
List<T> list2 = new ArrayList<T>();
|
||||
for (Object obj : list) {
|
||||
T objC = getValueByClass(obj, cs);
|
||||
list2.add(objC);
|
||||
}
|
||||
return list2;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取集合(逗号分隔式),(指定类型)
|
||||
*/
|
||||
public <T> List<T> getListByComma(String key, Class<T> cs) {
|
||||
String listStr = getString(key);
|
||||
if (listStr == null || listStr.equals("")) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
// 开始转化
|
||||
String[] arr = listStr.split(",");
|
||||
List<T> list = new ArrayList<T>();
|
||||
for (String str : arr) {
|
||||
if (cs == int.class || cs == Integer.class || cs == long.class || cs == Long.class) {
|
||||
str = str.trim();
|
||||
}
|
||||
T objC = getValueByClass(str, cs);
|
||||
list.add(objC);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据指定类型从map中取值,返回实体对象
|
||||
*/
|
||||
public <T> T getModel(Class<T> cs) {
|
||||
try {
|
||||
return getModelByObject(cs.newInstance());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从map中取值,塞到一个对象中
|
||||
*/
|
||||
public <T> T getModelByObject(T obj) {
|
||||
// 获取类型
|
||||
Class<?> cs = obj.getClass();
|
||||
// 循环复制
|
||||
for (Field field : cs.getDeclaredFields()) {
|
||||
try {
|
||||
// 获取对象
|
||||
Object value = this.get(field.getName());
|
||||
if (value == null) {
|
||||
continue;
|
||||
}
|
||||
field.setAccessible(true);
|
||||
Object valueConvert = getValueByClass(value, field.getType());
|
||||
field.set(obj, valueConvert);
|
||||
} catch (IllegalArgumentException | IllegalAccessException e) {
|
||||
throw new RuntimeException("属性取值出错:" + field.getName(), e);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将指定值转化为指定类型并返回
|
||||
*
|
||||
* @param obj
|
||||
* @param cs
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getValueByClass(Object obj, Class<T> cs) {
|
||||
String obj2 = String.valueOf(obj);
|
||||
Object obj3;
|
||||
if (cs.equals(String.class)) {
|
||||
obj3 = obj2;
|
||||
} else if (cs.equals(int.class) || cs.equals(Integer.class)) {
|
||||
obj3 = Integer.valueOf(obj2);
|
||||
} else if (cs.equals(long.class) || cs.equals(Long.class)) {
|
||||
obj3 = Long.valueOf(obj2);
|
||||
} else if (cs.equals(short.class) || cs.equals(Short.class)) {
|
||||
obj3 = Short.valueOf(obj2);
|
||||
} else if (cs.equals(byte.class) || cs.equals(Byte.class)) {
|
||||
obj3 = Byte.valueOf(obj2);
|
||||
} else if (cs.equals(float.class) || cs.equals(Float.class)) {
|
||||
obj3 = Float.valueOf(obj2);
|
||||
} else if (cs.equals(double.class) || cs.equals(Double.class)) {
|
||||
obj3 = Double.valueOf(obj2);
|
||||
} else if (cs.equals(boolean.class) || cs.equals(Boolean.class)) {
|
||||
obj3 = Boolean.valueOf(obj2);
|
||||
} else {
|
||||
obj3 = (T) obj;
|
||||
}
|
||||
return (T) obj3;
|
||||
}
|
||||
|
||||
|
||||
// ============================= 写值 =============================
|
||||
|
||||
/**
|
||||
* 给指定key添加一个默认值(只有在这个key原来无值的情况先才会set进去)
|
||||
*/
|
||||
public void setDefaultValue(String key, Object defaultValue) {
|
||||
if (isNull(key)) {
|
||||
set(key, defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set一个值,连缀风格
|
||||
*/
|
||||
public SoMap set(String key, Object value) {
|
||||
// 防止敏感key
|
||||
if (key.toLowerCase().equals("this")) {
|
||||
return this;
|
||||
}
|
||||
put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将一个Map塞进SoMap
|
||||
*/
|
||||
public SoMap setMap(Map<String, ?> map) {
|
||||
if (map != null) {
|
||||
for (String key : map.keySet()) {
|
||||
this.set(key, map.get(key));
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将一个对象解析塞进SoMap
|
||||
*/
|
||||
public SoMap setModel(Object model) {
|
||||
if (model == null) {
|
||||
return this;
|
||||
}
|
||||
Field[] fields = model.getClass().getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
try {
|
||||
field.setAccessible(true);
|
||||
boolean isStatic = Modifier.isStatic(field.getModifiers());
|
||||
if (!isStatic) {
|
||||
this.set(field.getName(), field.get(model));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将json字符串解析后塞进SoMap
|
||||
*/
|
||||
public SoMap setJsonString(String jsonString) {
|
||||
return this.setMap(JsonUtil.parse(jsonString, Map.class));
|
||||
}
|
||||
|
||||
|
||||
// ============================= 删值 =============================
|
||||
|
||||
/**
|
||||
* delete一个值,连缀风格
|
||||
*/
|
||||
public SoMap delete(String key) {
|
||||
remove(key);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理所有value为null的字段
|
||||
*/
|
||||
public SoMap clearNull() {
|
||||
Iterator<String> iterator = this.keySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
String key = iterator.next();
|
||||
if (this.isNull(key)) {
|
||||
iterator.remove();
|
||||
this.remove(key);
|
||||
}
|
||||
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理指定key
|
||||
*/
|
||||
public SoMap clearIn(String... keys) {
|
||||
List<String> keys2 = Arrays.asList(keys);
|
||||
Iterator<String> iterator = this.keySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
String key = iterator.next();
|
||||
if (keys2.contains(key)) {
|
||||
iterator.remove();
|
||||
this.remove(key);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理掉不在列表中的key
|
||||
*/
|
||||
public SoMap clearNotIn(String... keys) {
|
||||
List<String> keys2 = Arrays.asList(keys);
|
||||
Iterator<String> iterator = this.keySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
String key = iterator.next();
|
||||
if (!keys2.contains(key)) {
|
||||
iterator.remove();
|
||||
this.remove(key);
|
||||
}
|
||||
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理掉所有key
|
||||
*/
|
||||
public SoMap clearAll() {
|
||||
clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
// ============================= 快速构建 =============================
|
||||
|
||||
/**
|
||||
* 构建一个SoMap并返回
|
||||
*/
|
||||
public static SoMap getSoMap() {
|
||||
return new SoMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建一个SoMap并返回
|
||||
*/
|
||||
public static SoMap getSoMap(String key, Object value) {
|
||||
return new SoMap().set(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建一个SoMap并返回
|
||||
*/
|
||||
public static SoMap getSoMap(Map<String, ?> map) {
|
||||
return new SoMap().setMap(map);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将一个对象集合解析成为SoMap
|
||||
*/
|
||||
public static SoMap getSoMapByModel(Object model) {
|
||||
return SoMap.getSoMap().setModel(model);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将一个对象集合解析成为SoMap集合
|
||||
*/
|
||||
public static List<SoMap> getSoMapByList(List<?> list) {
|
||||
List<SoMap> listMap = new ArrayList<>();
|
||||
for (Object model : list) {
|
||||
listMap.add(getSoMapByModel(model));
|
||||
}
|
||||
return listMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 克隆指定key,返回一个新的SoMap
|
||||
*/
|
||||
public SoMap cloneKeys(String... keys) {
|
||||
SoMap so = new SoMap();
|
||||
for (String key : keys) {
|
||||
so.set(key, this.get(key));
|
||||
}
|
||||
return so;
|
||||
}
|
||||
|
||||
/**
|
||||
* 克隆所有key,返回一个新的SoMap
|
||||
*/
|
||||
public SoMap cloneSoMap() {
|
||||
SoMap so = new SoMap();
|
||||
for (String key : this.keySet()) {
|
||||
so.set(key, this.get(key));
|
||||
}
|
||||
return so;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将所有key转为大写
|
||||
*/
|
||||
public SoMap toUpperCase() {
|
||||
SoMap so = new SoMap();
|
||||
for (String key : this.keySet()) {
|
||||
so.set(key.toUpperCase(), this.get(key));
|
||||
}
|
||||
this.clearAll().setMap(so);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将所有key转为小写
|
||||
*/
|
||||
public SoMap toLowerCase() {
|
||||
SoMap so = new SoMap();
|
||||
for (String key : this.keySet()) {
|
||||
so.set(key.toLowerCase(), this.get(key));
|
||||
}
|
||||
this.clearAll().setMap(so);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将所有key中下划线转为中划线模式 (kebab-case风格)
|
||||
*/
|
||||
public SoMap toKebabCase() {
|
||||
SoMap so = new SoMap();
|
||||
for (String key : this.keySet()) {
|
||||
so.set(wordEachKebabCase(key), this.get(key));
|
||||
}
|
||||
this.clearAll().setMap(so);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将所有key中下划线转为小驼峰模式
|
||||
*/
|
||||
public SoMap toHumpCase() {
|
||||
SoMap so = new SoMap();
|
||||
for (String key : this.keySet()) {
|
||||
so.set(wordEachBigFs(key), this.get(key));
|
||||
}
|
||||
this.clearAll().setMap(so);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将所有key中小驼峰转为下划线模式
|
||||
*/
|
||||
public SoMap humpToLineCase() {
|
||||
SoMap so = new SoMap();
|
||||
for (String key : this.keySet()) {
|
||||
so.set(wordHumpToLine(key), this.get(key));
|
||||
}
|
||||
this.clearAll().setMap(so);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
// ============================= 辅助方法 =============================
|
||||
|
||||
|
||||
/**
|
||||
* 指定key是否为null,判定标准为 NULL_ELEMENT_ARRAY 中的元素
|
||||
*/
|
||||
public boolean isNull(String key) {
|
||||
return valueIsNull(get(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定key列表中是否包含value为null的元素,只要有一个为null,就会返回true
|
||||
*/
|
||||
public boolean isContainNull(String... keys) {
|
||||
for (String key : keys) {
|
||||
if (this.isNull(key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 与isNull()相反
|
||||
*/
|
||||
public boolean isNotNull(String key) {
|
||||
return !isNull(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定key的value是否为null,作用同isNotNull()
|
||||
*/
|
||||
public boolean has(String key) {
|
||||
return !isNull(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定value在此SoMap的判断标准中是否为null
|
||||
*/
|
||||
public boolean valueIsNull(Object value) {
|
||||
return NULL_ELEMENT_LIST.contains(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证指定key不为空,为空则抛出异常
|
||||
*/
|
||||
public SoMap checkNull(String... keys) {
|
||||
for (String key : keys) {
|
||||
if (this.isNull(key)) {
|
||||
throw new RuntimeException("参数" + key + "不能为空");
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
static Pattern patternNumber = Pattern.compile("[0-9]*");
|
||||
|
||||
/**
|
||||
* 指定key是否为数字
|
||||
*/
|
||||
public boolean isNumber(String key) {
|
||||
String value = getString(key);
|
||||
if (value == null) {
|
||||
return false;
|
||||
}
|
||||
return patternNumber.matcher(value).matches();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 转为JSON字符串
|
||||
*/
|
||||
public String toJsonString() {
|
||||
return JsonUtil.toJsonString(this);
|
||||
}
|
||||
|
||||
// ============================= web辅助 =============================
|
||||
|
||||
/**
|
||||
* 返回当前request请求的的所有参数
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static SoMap getRequestSoMap() {
|
||||
// 大善人SpringMVC提供的封装
|
||||
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
if (servletRequestAttributes == null) {
|
||||
throw new RuntimeException("当前线程非JavaWeb环境");
|
||||
}
|
||||
// 当前request
|
||||
HttpServletRequest request = servletRequestAttributes.getRequest();
|
||||
if (request.getAttribute("currentSoMap") == null || !(request.getAttribute("currentSoMap") instanceof SoMap)) {
|
||||
initRequestSoMap(request);
|
||||
}
|
||||
return (SoMap) request.getAttribute("currentSoMap");
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化当前request的 SoMap
|
||||
*/
|
||||
private static void initRequestSoMap(HttpServletRequest request) {
|
||||
SoMap soMap = new SoMap();
|
||||
Map<String, String[]> parameterMap = request.getParameterMap(); // 获取所有参数
|
||||
for (String key : parameterMap.keySet()) {
|
||||
try {
|
||||
String[] values = parameterMap.get(key); // 获得values
|
||||
if (values.length == 1) {
|
||||
soMap.set(key, values[0]);
|
||||
} else {
|
||||
soMap.set(key, Arrays.asList(values));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
request.setAttribute("currentSoMap", soMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证返回当前线程是否为JavaWeb环境
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static boolean isJavaWeb() {
|
||||
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();// 大善人SpringMVC提供的封装
|
||||
if (servletRequestAttributes == null) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// ============================= 常见key (以下key经常用,所以封装以下,方便写代码) =============================
|
||||
|
||||
/**
|
||||
* get 当前页
|
||||
*/
|
||||
public int getKeyPageNo() {
|
||||
int pageNo = getInt("pageNo", 1);
|
||||
if (pageNo <= 0) {
|
||||
pageNo = 1;
|
||||
}
|
||||
return pageNo;
|
||||
}
|
||||
|
||||
/**
|
||||
* get 页大小
|
||||
*/
|
||||
public int getKeyPageSize() {
|
||||
int pageSize = getInt("pageSize", 10);
|
||||
if (pageSize <= 0 || pageSize > 1000) {
|
||||
pageSize = 10;
|
||||
}
|
||||
return pageSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* get 排序方式
|
||||
*/
|
||||
public int getKeySortType() {
|
||||
return getInt("sortType");
|
||||
}
|
||||
|
||||
|
||||
// ============================= 工具方法 =============================
|
||||
|
||||
|
||||
/**
|
||||
* 将一个一维集合转换为树形集合
|
||||
*
|
||||
* @param list 集合
|
||||
* @param idKey id标识key
|
||||
* @param parentIdKey 父id标识key
|
||||
* @param childListKey 子节点标识key
|
||||
* @return 转换后的tree集合
|
||||
*/
|
||||
public static List<SoMap> listToTree(List<SoMap> list, String idKey, String parentIdKey, String childListKey) {
|
||||
// 声明新的集合,存储tree形数据
|
||||
List<SoMap> newTreeList = new ArrayList<>();
|
||||
// 声明hash-Map,方便查找数据
|
||||
SoMap hash = new SoMap();
|
||||
// 将数组转为Object的形式,key为数组中的id
|
||||
for (SoMap json : list) {
|
||||
hash.put(json.getString(idKey), json);
|
||||
}
|
||||
// 遍历结果集
|
||||
for (SoMap soMap : list) {
|
||||
// 单条记录
|
||||
// 在hash中取出key为单条记录中pid的值
|
||||
SoMap hashVp = (SoMap) hash.get(soMap.get(parentIdKey, "").toString());
|
||||
// 如果记录的pid存在,则说明它有父节点,将她添加到孩子节点的集合中
|
||||
if (hashVp != null) {
|
||||
// 检查是否有child属性,有则添加,没有则新建
|
||||
if (hashVp.get(childListKey) != null) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<SoMap> ch = (List<SoMap>) hashVp.get(childListKey);
|
||||
ch.add(soMap);
|
||||
hashVp.put(childListKey, ch);
|
||||
} else {
|
||||
List<SoMap> ch = new ArrayList<SoMap>();
|
||||
ch.add(soMap);
|
||||
hashVp.put(childListKey, ch);
|
||||
}
|
||||
} else {
|
||||
newTreeList.add(soMap);
|
||||
}
|
||||
}
|
||||
return newTreeList;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 指定字符串的字符串下划线转大写模式
|
||||
*/
|
||||
private static String wordEachBig(String str) {
|
||||
StringBuilder newStr = new StringBuilder();
|
||||
for (String s : str.split("_")) {
|
||||
newStr.append(wordFirstBig(s));
|
||||
}
|
||||
return newStr.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回下划线转小驼峰形式
|
||||
*/
|
||||
private static String wordEachBigFs(String str) {
|
||||
return wordFirstSmall(wordEachBig(str));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定单词首字母大写
|
||||
*/
|
||||
private static String wordFirstBig(String str) {
|
||||
return str.substring(0, 1).toUpperCase() + str.substring(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定单词首字母小写
|
||||
*/
|
||||
private static String wordFirstSmall(String str) {
|
||||
return str.substring(0, 1).toLowerCase() + str.substring(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下划线转中划线
|
||||
*/
|
||||
private static String wordEachKebabCase(String str) {
|
||||
return str.replaceAll("_", "-");
|
||||
}
|
||||
|
||||
/**
|
||||
* 驼峰转下划线
|
||||
*/
|
||||
private static String wordHumpToLine(String str) {
|
||||
return str.replaceAll("[A-Z]", "_$0").toLowerCase();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,149 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>奇特物联认证授权</title>
|
||||
<style type="text/css">
|
||||
body{
|
||||
min-height: 500px;
|
||||
background: linear-gradient( 270deg, rgb(46 124 255) 0%, rgb(52 3 65) 100% );
|
||||
}
|
||||
.bgimg{
|
||||
position:absolute;
|
||||
width:100%;
|
||||
height:100%;
|
||||
}
|
||||
.bgimg::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 60%;
|
||||
overflow: hidden;
|
||||
height: 80%;
|
||||
-webkit-mask-box-image: url("data:image/svg+xml,%3Csvg width='1200' height='770' xmlns='http://www.w3.org/2000/svg' fill='none'%3E%3Cg%3E%3Cpath id='svg_1' d='M58.4 47.77C104.6 59.51 135.26 67.37 162.11 78.04C188.97 88.72 226.33 102.69 265.92 123.55C305.51 144.4 366.96 167.09 441.43 121.52C515.9 75.95 546.48 61.01 577.69 46.27C608.9 31.53 625.86 23.69 680.26 12.28C734.65 0.87 837.29 10.7 867.29 21.8C897.29 32.9 935.51 51.9 962.21 95.45C988.9 139.01 972.91 177.36 951.37 221.39C929.83 265.43 883.49 306 890.44 337.33C897.4 368.66 974.73 412.18 974.73 411.47C974.73 412.18 1066.36 457.62 1106.36 491.06C1146.36 524.5 1178.8 563.36 1184.03 579.63C1189.26 595.9 1200.4 622.49 1181.55 676.88C1162.71 731.26 1127.16 764.32 1115.31 778.64C1103.45 792.96 5.34 783.61 4.32 784.63C3.3 785.65 -172.34 2.38 1.13 35.04L58.4 47.77L58.4 47.77Z' fill='%23409eff'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
||||
background: #2e72f08f;
|
||||
transition: all .3s ease;
|
||||
}
|
||||
.bgimg::after {
|
||||
content: "";
|
||||
width: 150px;
|
||||
height: 300px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
-webkit-mask-box-image: url("data:image/svg+xml,%3Csvg width='150' height='300' xmlns='http://www.w3.org/2000/svg' fill='none'%3E%3Cg%3E%3Cpath id='svg_1' d='M-0.56 -0.28C41.94 36.17 67.73 18.94 93.33 33.96C118.93 48.98 107.58 73.56 101.94 89.76C96.29 105.96 50.09 217.83 47.87 231.18C45.64 244.52 46.02 255.2 64.4 270.05C82.79 284.91 121.99 292.31 111.98 289.81C101.97 287.32 153.96 301.48 151.83 299.9C149.69 298.32 149.98 -1.36 149.71 -1.18C149.98 -1.36 -43.06 -36.74 -0.56 -0.28L-0.56 -0.28Z' fill='%23409eff'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
||||
background: #330b4e8c;
|
||||
transition: all .3s ease;
|
||||
}
|
||||
|
||||
*{margin: 0px; padding: 0px;}
|
||||
.login-box{
|
||||
position: absolute;
|
||||
right: 100px;
|
||||
width: 400px;
|
||||
height: 400px;
|
||||
margin: 20vh auto;
|
||||
padding: 30px 50px;
|
||||
background-color: #fff;
|
||||
overflow: inherit;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.login-box .title{color:#333;font-size:22px;text-align:center;margin:20px 20px}
|
||||
.login-box button{padding: 5px 15px; cursor: pointer; }
|
||||
|
||||
#loginImg{
|
||||
-webkit-animation:bounce 3s 1s infinite linear normal;
|
||||
-moz-animation:bounce 3s 1s infinite linear normal;}
|
||||
@-webkit-keyframes bounce{
|
||||
40%{-webkit-transform:translateY(-20px)}
|
||||
60%{-webkit-transform:translateY(-10px)}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="bgimg">
|
||||
<div style="position:absolute;top:40px;left:100px;font-size:30px;color:#FFF">©奇特物联</div>
|
||||
<img id="loginImg" src="http://iotkit-img.oss-cn-shenzhen.aliyuncs.com/product/KdJYpTp5ywNhmrmC/cover.png?Expires=1970997977&OSSAccessKeyId=LTAI5t8UFEH5eGrBUS5zSiof&Signature=0YV5y27iIYYL5XQ2qMeBV%2FloYFU%3D" style="position: absolute;left:100px;bottom: -20px;"/>
|
||||
</div>
|
||||
<div class="login-box">
|
||||
<div class="title">授权确认</div> <br>
|
||||
<div>
|
||||
正在确认授权...
|
||||
</div>
|
||||
<div id="divFailed"></div>
|
||||
</div>
|
||||
<script src="https://unpkg.zhimg.com/jquery@3.4.1/dist/jquery.min.js"></script>
|
||||
<script>window.jQuery || alert('当前页面CDN服务商已宕机,请将所有js包更换为本地依赖')</script>
|
||||
<script type="text/javascript">
|
||||
// 同意授权
|
||||
function yes() {
|
||||
$.ajax({
|
||||
url: '/oauth2/doConfirm',
|
||||
data: {
|
||||
client_id: getParam('client_id'),
|
||||
scope: getParam('scope')
|
||||
},
|
||||
dataType: 'json',
|
||||
success: function(res) {
|
||||
if(res.code == 200) {
|
||||
location.reload(true);
|
||||
} else {
|
||||
// 重定向至授权失败URL
|
||||
$("#divFailed").text('授权失败!');
|
||||
}
|
||||
},
|
||||
error: function(e) {
|
||||
console.log('error');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 拒绝授权
|
||||
function no() {
|
||||
var url = joinParam(getParam('redirect_uri'), "handle=refuse&msg=用户拒绝了授权");
|
||||
location.href = url;
|
||||
}
|
||||
|
||||
// 从url中查询到指定名称的参数值
|
||||
function getParam(name, defaultValue){
|
||||
var query = window.location.search.substring(1);
|
||||
var vars = query.split("&");
|
||||
for (var i=0;i<vars.length;i++) {
|
||||
var pair = vars[i].split("=");
|
||||
if(pair[0] == name){return pair[1];}
|
||||
}
|
||||
return(defaultValue == undefined ? null : defaultValue);
|
||||
}
|
||||
|
||||
// 在url上拼接上kv参数并返回
|
||||
function joinParam(url, parameStr) {
|
||||
if(parameStr == null || parameStr.length == 0) {
|
||||
return url;
|
||||
}
|
||||
var index = url.indexOf('?');
|
||||
// ? 不存在
|
||||
if(index == -1) {
|
||||
return url + '?' + parameStr;
|
||||
}
|
||||
// ? 是最后一位
|
||||
if(index == url.length - 1) {
|
||||
return url + parameStr;
|
||||
}
|
||||
// ? 是其中一位
|
||||
if(index > -1 && index < url.length - 1) {
|
||||
// 如果最后一位是 不是&, 且 parameStr 第一位不是 &, 就增送一个 &
|
||||
if(url.lastIndexOf('&') != url.length - 1 && parameStrindexOf('&') != 0) {
|
||||
return url + '&' + parameStr;
|
||||
} else {
|
||||
return url + parameStr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
yes();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,154 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>奇特物联登录授权</title>
|
||||
<style type="text/css">
|
||||
body{
|
||||
min-height: 500px;
|
||||
background: linear-gradient( 270deg, rgb(46 124 255) 0%, rgb(52 3 65) 100% );
|
||||
}
|
||||
.bgimg{
|
||||
position:absolute;
|
||||
width:100%;
|
||||
height:100%;
|
||||
}
|
||||
.bgimg::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 60%;
|
||||
overflow: hidden;
|
||||
height: 80%;
|
||||
-webkit-mask-box-image: url("data:image/svg+xml,%3Csvg width='1200' height='770' xmlns='http://www.w3.org/2000/svg' fill='none'%3E%3Cg%3E%3Cpath id='svg_1' d='M58.4 47.77C104.6 59.51 135.26 67.37 162.11 78.04C188.97 88.72 226.33 102.69 265.92 123.55C305.51 144.4 366.96 167.09 441.43 121.52C515.9 75.95 546.48 61.01 577.69 46.27C608.9 31.53 625.86 23.69 680.26 12.28C734.65 0.87 837.29 10.7 867.29 21.8C897.29 32.9 935.51 51.9 962.21 95.45C988.9 139.01 972.91 177.36 951.37 221.39C929.83 265.43 883.49 306 890.44 337.33C897.4 368.66 974.73 412.18 974.73 411.47C974.73 412.18 1066.36 457.62 1106.36 491.06C1146.36 524.5 1178.8 563.36 1184.03 579.63C1189.26 595.9 1200.4 622.49 1181.55 676.88C1162.71 731.26 1127.16 764.32 1115.31 778.64C1103.45 792.96 5.34 783.61 4.32 784.63C3.3 785.65 -172.34 2.38 1.13 35.04L58.4 47.77L58.4 47.77Z' fill='%23409eff'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
||||
background: #2e72f08f;
|
||||
transition: all .3s ease;
|
||||
}
|
||||
.bgimg::after {
|
||||
content: "";
|
||||
width: 150px;
|
||||
height: 300px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
-webkit-mask-box-image: url("data:image/svg+xml,%3Csvg width='150' height='300' xmlns='http://www.w3.org/2000/svg' fill='none'%3E%3Cg%3E%3Cpath id='svg_1' d='M-0.56 -0.28C41.94 36.17 67.73 18.94 93.33 33.96C118.93 48.98 107.58 73.56 101.94 89.76C96.29 105.96 50.09 217.83 47.87 231.18C45.64 244.52 46.02 255.2 64.4 270.05C82.79 284.91 121.99 292.31 111.98 289.81C101.97 287.32 153.96 301.48 151.83 299.9C149.69 298.32 149.98 -1.36 149.71 -1.18C149.98 -1.36 -43.06 -36.74 -0.56 -0.28L-0.56 -0.28Z' fill='%23409eff'%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
|
||||
background: #330b4e8c;
|
||||
transition: all .3s ease;
|
||||
}
|
||||
|
||||
*{margin: 0px; padding: 0px;}
|
||||
.login-box{
|
||||
position: absolute;
|
||||
right: 100px;
|
||||
width: 400px;
|
||||
height: 400px;
|
||||
margin: 20vh auto;
|
||||
padding: 30px 50px;
|
||||
background-color: #fff;
|
||||
overflow: inherit;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.login-box .title{color:#333;font-size:22px;text-align:center;margin:20px 20px}
|
||||
.login-box .form{list-style:none; padding:20px 20px;}
|
||||
.login-box li{
|
||||
padding:10px 10px;
|
||||
line-height:30px;
|
||||
text-align:center;
|
||||
}
|
||||
.login-box input{
|
||||
width:100%;
|
||||
line-height: 30px;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #999;
|
||||
padding:5px 10px;
|
||||
}
|
||||
.login-box button{
|
||||
padding: 5px 15px;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
line-height:30px;
|
||||
border: 1px solid #5e77ff;
|
||||
background-color: #5e77ff;
|
||||
color: #fff;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.login-box button:hover{
|
||||
background-color: #2746f1;
|
||||
}
|
||||
.login-box .tip{
|
||||
margin-top:20px;
|
||||
color:#666;
|
||||
}
|
||||
.tip.error{
|
||||
color:red;
|
||||
}
|
||||
#loginImg{
|
||||
-webkit-animation:bounce 3s 1s infinite linear normal;
|
||||
-moz-animation:bounce 3s 1s infinite linear normal;}
|
||||
@-webkit-keyframes bounce{
|
||||
40%{-webkit-transform:translateY(-20px)}
|
||||
60%{-webkit-transform:translateY(-10px)}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="bgimg">
|
||||
<div style="position:absolute;top:40px;left:100px;font-size:30px;color:#FFF">©奇特物联</div>
|
||||
<img id="loginImg" src="http://iotkit-img.oss-cn-shenzhen.aliyuncs.com/product/KdJYpTp5ywNhmrmC/cover.png?Expires=1970997977&OSSAccessKeyId=LTAI5t8UFEH5eGrBUS5zSiof&Signature=0YV5y27iIYYL5XQ2qMeBV%2FloYFU%3D" style="position: absolute;left:100px;bottom: -20px;"/>
|
||||
</div>
|
||||
<div class="login-box">
|
||||
<div class="title">登录授权</div>
|
||||
<ul class="form">
|
||||
<li>
|
||||
<input name="name" placeholder="请输入账号"/>
|
||||
</li>
|
||||
<li>
|
||||
<input name="pwd" type="password" placeholder="请输入密码" /> <br>
|
||||
</li>
|
||||
<li>
|
||||
<button onclick="doLogin()">登录</button>
|
||||
</li>
|
||||
<li class="tip" id="liTip"></li>
|
||||
<li style="color:#aaa;">
|
||||
Copyright © 2021 - 2022 奇特物联
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<script src="https://unpkg.zhimg.com/jquery@3.4.1/dist/jquery.min.js"></script>
|
||||
<script>window.jQuery || alert('当前页面CDN服务商已宕机,请将所有js包更换为本地依赖')</script>
|
||||
<script type="text/javascript">
|
||||
// 登录方法
|
||||
function doLogin() {
|
||||
var name=$.trim($('[name=name]').val());
|
||||
var pwd=$.trim($('[name=pwd]').val());
|
||||
if(!name || !pwd){
|
||||
$("#liTip").addClass("error").text("账号或密码不能为空!");
|
||||
}
|
||||
$.ajax({
|
||||
url: '/oauth2/doLogin',
|
||||
data: {
|
||||
name: name,
|
||||
pwd: pwd
|
||||
},
|
||||
dataType: 'json',
|
||||
success: function(res) {
|
||||
if(res.code == 200) {
|
||||
$("#liTip").removeClass("error").text("登录成功!");
|
||||
setTimeout(function() {
|
||||
location.reload(true);
|
||||
}, 800);
|
||||
} else {
|
||||
$("#liTip").addClass("error").text(res.msg);
|
||||
}
|
||||
},
|
||||
error: function(e) {
|
||||
console.log('error');
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,13 +0,0 @@
|
|||
import cc.iotkit.utils.AuthUtil;
|
||||
import org.junit.Test;
|
||||
|
||||
public class GenPwdSecret {
|
||||
|
||||
@Test
|
||||
public void gen() throws Exception {
|
||||
//生成密码加密内容
|
||||
String secret = AuthUtil.enCryptPwd("iotkitadmin");
|
||||
System.out.println(secret);
|
||||
System.out.println(AuthUtil.checkPwd("guest123", secret));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
<?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>
|
||||
<artifactId>iot-common</artifactId>
|
||||
<groupId>cc.iotkit</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>iot-common-core</artifactId>
|
||||
|
||||
<description>
|
||||
此模块为通用业务逻辑或工具类
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk15on</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- JSON工具类 -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-beanutils</groupId>
|
||||
<artifactId>commons-beanutils</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring框架基本的核心工具 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--常用工具类 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-http</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-extra</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-json</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.github.linpeilie</groupId>
|
||||
<artifactId>mapstruct-plus-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.validation</groupId>
|
||||
<artifactId>jakarta.validation-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.lionsoul</groupId>
|
||||
<artifactId>ip2region</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,45 @@
|
|||
package cc.iotkit.common.api;
|
||||
|
||||
import cc.iotkit.common.utils.MapstructUtils;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Entity基类
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Data
|
||||
public class BaseDto {
|
||||
|
||||
/**
|
||||
* 创建部门
|
||||
*/
|
||||
|
||||
private Long createDept;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Date updateTime;
|
||||
|
||||
public <T> T to(Class<T> tClass) {
|
||||
return MapstructUtils.convert(this, tClass);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
package cc.iotkit.common.api;
|
||||
|
||||
import cc.iotkit.common.utils.MapstructUtils;
|
||||
import cc.iotkit.common.utils.SnowflakeIdGeneratorUtil;
|
||||
import jakarta.validation.constraints.Max;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.util.Map;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author: Longjun.Tu
|
||||
* @description:
|
||||
* @date:created in 2023/5/10 23:15
|
||||
* @modificed by:
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
public class PageRequest<T> extends Request<T> implements Serializable {
|
||||
|
||||
/**
|
||||
* 分页大小
|
||||
*/
|
||||
@Min(1)
|
||||
@NotNull
|
||||
private Integer pageSize;
|
||||
|
||||
/**
|
||||
* 当前页数
|
||||
*/
|
||||
@Min(1)
|
||||
@Max(100)
|
||||
@NotNull
|
||||
private Integer pageNum;
|
||||
|
||||
/**
|
||||
* 排序 key为排序字段名 value为排序方向方向desc或者asc
|
||||
*/
|
||||
private Map<String,String> sortMap;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 当前记录起始索引 默认值
|
||||
*/
|
||||
public static final int DEFAULT_PAGE_NUM = 1;
|
||||
|
||||
/**
|
||||
* 每页显示记录数 默认值
|
||||
*/
|
||||
public static final int DEFAULT_PAGE_SIZE = 20;
|
||||
|
||||
|
||||
public static <T> PageRequest<T> of(T data) {
|
||||
PageRequest<T> pageRequest = new PageRequest<>();
|
||||
pageRequest.setPageSize(DEFAULT_PAGE_SIZE);
|
||||
pageRequest.setPageNum(DEFAULT_PAGE_NUM);
|
||||
pageRequest.setData(data);
|
||||
pageRequest.setRequestId(String.valueOf(SnowflakeIdGeneratorUtil.getInstanceSnowflake().nextId()));
|
||||
return pageRequest;
|
||||
}
|
||||
|
||||
public static <DTO> PageRequest<DTO> request2PageRequest(Request<DTO> request) {
|
||||
PageRequest<DTO> pageRequest = new PageRequest<>();
|
||||
pageRequest.setData(request.getData());
|
||||
pageRequest.setPageNum(DEFAULT_PAGE_NUM);
|
||||
pageRequest.setPageSize(DEFAULT_PAGE_SIZE);
|
||||
pageRequest.setRequestId(request.getRequestId());
|
||||
return pageRequest;
|
||||
}
|
||||
|
||||
public <DTO> PageRequest<DTO> to(Class<DTO> dtoClass) {
|
||||
DTO dto = MapstructUtils.convert(getData(), dtoClass);
|
||||
PageRequest<DTO> pageRequest = new PageRequest<>();
|
||||
pageRequest.setData(dto);
|
||||
pageRequest.setPageNum(this.getPageNum());
|
||||
pageRequest.setPageSize(this.getPageSize());
|
||||
pageRequest.setRequestId(this.getRequestId());
|
||||
pageRequest.setSortMap(this.getSortMap());
|
||||
return pageRequest;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package cc.iotkit.common.api;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author: Longjun.Tu
|
||||
* @description:
|
||||
* @date:created in 2023/5/10 23:16
|
||||
* @modificed by:
|
||||
*/
|
||||
@Data
|
||||
public class PageRequestEmpty {
|
||||
private Integer pageNum = 1;
|
||||
private Integer pageSize = 20;
|
||||
}
|
|
@ -7,8 +7,9 @@
|
|||
* | Author: xw2sy@163.com
|
||||
* +----------------------------------------------------------------------
|
||||
*/
|
||||
package cc.iotkit.model;
|
||||
package cc.iotkit.common.api;
|
||||
|
||||
import cc.iotkit.common.utils.MapstructUtils;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
@ -24,4 +25,7 @@ public class Paging<T> {
|
|||
|
||||
private List<T> data;
|
||||
|
||||
public <VO> Paging<VO> to(Class<VO> voClass) {
|
||||
return MapstructUtils.convert(this, voClass);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package cc.iotkit.common.api;
|
||||
|
||||
import cc.iotkit.common.utils.SnowflakeIdGeneratorUtil;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author: Longjun.Tu
|
||||
* @description:
|
||||
* @date:created in 2023/5/10 23:14
|
||||
* @modificed by:
|
||||
*/
|
||||
@Data
|
||||
public class Request<T> extends RequestEmpty implements Serializable {
|
||||
|
||||
@Valid
|
||||
@NotNull
|
||||
private T data;
|
||||
|
||||
public static <T> Request<T> of(T data) {
|
||||
Request<T> request = new Request<>();
|
||||
request.setData(data);
|
||||
request.setRequestId(String.valueOf(SnowflakeIdGeneratorUtil.getInstanceSnowflake().nextId()));
|
||||
return request;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package cc.iotkit.common.api;
|
||||
|
||||
import cc.iotkit.common.utils.SnowflakeIdGeneratorUtil;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author: Longjun.Tu
|
||||
* @description:
|
||||
* @date:created in 2023/5/10 23:12
|
||||
* @modificed by:
|
||||
*/
|
||||
@Data
|
||||
public class RequestEmpty implements Serializable {
|
||||
|
||||
@NotBlank
|
||||
private String requestId;
|
||||
|
||||
public static RequestEmpty of() {
|
||||
RequestEmpty request = new RequestEmpty();
|
||||
request.setRequestId(String.valueOf(SnowflakeIdGeneratorUtil.getInstanceSnowflake().nextId()));
|
||||
return request;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package cc.iotkit.common.api;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class Response {
|
||||
private int code;
|
||||
private String message;
|
||||
private Object data;
|
||||
private long timestamp;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package cc.iotkit.common.constant;
|
||||
|
||||
/**
|
||||
* 缓存的key 常量
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
public interface CacheConstants {
|
||||
|
||||
/**
|
||||
* 在线用户 redis key
|
||||
*/
|
||||
String ONLINE_TOKEN_KEY = "online_tokens:";
|
||||
|
||||
/**
|
||||
* 参数管理 cache key
|
||||
*/
|
||||
String SYS_CONFIG_KEY = "sys_config:";
|
||||
|
||||
/**
|
||||
* 字典管理 cache key
|
||||
*/
|
||||
String SYS_DICT_KEY = "sys_dict:";
|
||||
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package cc.iotkit.common.constant;
|
||||
|
||||
/**
|
||||
* 缓存组名称常量
|
||||
* <p>
|
||||
* key 格式为 cacheNames#ttl#maxIdleTime#maxSize
|
||||
* <p>
|
||||
* ttl 过期时间 如果设置为0则不过期 默认为0
|
||||
* maxIdleTime 最大空闲时间 根据LRU算法清理空闲数据 如果设置为0则不检测 默认为0
|
||||
* maxSize 组最大长度 根据LRU算法清理溢出数据 如果设置为0则无限长 默认为0
|
||||
* <p>
|
||||
* 例子: test#60s、test#0#60s、test#0#1m#1000、test#1h#0#500
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
public interface CacheNames {
|
||||
|
||||
/**
|
||||
* 演示案例
|
||||
*/
|
||||
String DEMO_CACHE = "demo:cache#60s#10m#20";
|
||||
|
||||
/**
|
||||
* 系统配置
|
||||
*/
|
||||
String SYS_CONFIG = "sys_config";
|
||||
|
||||
/**
|
||||
* 数据字典
|
||||
*/
|
||||
String SYS_DICT = "sys_dict";
|
||||
|
||||
/**
|
||||
* 租户
|
||||
*/
|
||||
String SYS_TENANT = GlobalConstants.GLOBAL_REDIS_KEY + "sys_tenant#30d";
|
||||
|
||||
/**
|
||||
* 用户账户
|
||||
*/
|
||||
String SYS_USER_NAME = "sys_user_name#30d";
|
||||
|
||||
/**
|
||||
* 部门
|
||||
*/
|
||||
String SYS_DEPT = "sys_dept#30d";
|
||||
|
||||
/**
|
||||
* OSS内容
|
||||
*/
|
||||
String SYS_OSS = "sys_oss#30d";
|
||||
|
||||
/**
|
||||
* OSS配置
|
||||
*/
|
||||
String SYS_OSS_CONFIG = "sys_oss_config";
|
||||
|
||||
/**
|
||||
* 在线用户
|
||||
*/
|
||||
String ONLINE_TOKEN = "online_tokens";
|
||||
|
||||
}
|
|
@ -1,16 +1,83 @@
|
|||
/*
|
||||
* +----------------------------------------------------------------------
|
||||
* | Copyright (c) 奇特物联 2021-2022 All rights reserved.
|
||||
* +----------------------------------------------------------------------
|
||||
* | Licensed 未经许可不能去掉「奇特物联」相关版权
|
||||
* +----------------------------------------------------------------------
|
||||
* | Author: xw2sy@163.com
|
||||
* +----------------------------------------------------------------------
|
||||
*/
|
||||
package cc.iotkit.common;
|
||||
package cc.iotkit.common.constant;
|
||||
|
||||
/**
|
||||
* 通用常量信息
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public interface Constants {
|
||||
|
||||
/**
|
||||
* UTF-8 字符集
|
||||
*/
|
||||
String UTF8 = "UTF-8";
|
||||
|
||||
/**
|
||||
* GBK 字符集
|
||||
*/
|
||||
String GBK = "GBK";
|
||||
|
||||
/**
|
||||
* www主域
|
||||
*/
|
||||
String WWW = "www.";
|
||||
|
||||
/**
|
||||
* http请求
|
||||
*/
|
||||
String HTTP = "http://";
|
||||
|
||||
/**
|
||||
* https请求
|
||||
*/
|
||||
String HTTPS = "https://";
|
||||
|
||||
/**
|
||||
* 通用成功标识
|
||||
*/
|
||||
String SUCCESS = "0";
|
||||
|
||||
/**
|
||||
* 通用失败标识
|
||||
*/
|
||||
String FAIL = "1";
|
||||
|
||||
/**
|
||||
* 登录成功
|
||||
*/
|
||||
String LOGIN_SUCCESS = "Success";
|
||||
|
||||
/**
|
||||
* 注销
|
||||
*/
|
||||
String LOGOUT = "Logout";
|
||||
|
||||
/**
|
||||
* 注册
|
||||
*/
|
||||
String REGISTER = "Register";
|
||||
|
||||
/**
|
||||
* 登录失败
|
||||
*/
|
||||
String LOGIN_FAIL = "Error";
|
||||
|
||||
/**
|
||||
* 验证码有效期(分钟)
|
||||
*/
|
||||
Integer CAPTCHA_EXPIRATION = 2;
|
||||
|
||||
/**
|
||||
* 令牌
|
||||
*/
|
||||
String TOKEN = "token";
|
||||
|
||||
/**
|
||||
* 顶级部门id
|
||||
*/
|
||||
Long TOP_PARENT_ID = 0L;
|
||||
|
||||
|
||||
String PRODUCT_SECRET = "xdkKUymrEGSCYWswqCvSPyRSFvH5j7CU";
|
||||
|
||||
String ACCOUNT_SECRET = "3n1z33kzvpgz1foijpkepyd3e8tw84us";
|
||||
|
@ -224,3 +291,4 @@ public interface Constants {
|
|||
String DEVICE_SUBSCRIBE_TOPIC = "^/sys/.+/.+/c/#$";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
package cc.iotkit.common.constant;
|
||||
|
||||
/**
|
||||
* 全局的key常量 (业务无关的key)
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
public interface GlobalConstants {
|
||||
|
||||
/**
|
||||
* 全局 redis key (业务无关的key)
|
||||
*/
|
||||
String GLOBAL_REDIS_KEY = "global:";
|
||||
|
||||
/**
|
||||
* 验证码 redis key
|
||||
*/
|
||||
String CAPTCHA_CODE_KEY = GLOBAL_REDIS_KEY + "captcha_codes:";
|
||||
|
||||
/**
|
||||
* 防重提交 redis key
|
||||
*/
|
||||
String REPEAT_SUBMIT_KEY = GLOBAL_REDIS_KEY + "repeat_submit:";
|
||||
|
||||
/**
|
||||
* 限流 redis key
|
||||
*/
|
||||
String RATE_LIMIT_KEY = GLOBAL_REDIS_KEY + "rate_limit:";
|
||||
|
||||
/**
|
||||
* 登录账户密码错误次数 redis key
|
||||
*/
|
||||
String PWD_ERR_CNT_KEY = GLOBAL_REDIS_KEY + "pwd_err_cnt:";
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package cc.iotkit.common.constant;
|
||||
|
||||
/**
|
||||
* 返回状态码
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
public interface HttpStatus {
|
||||
/**
|
||||
* 操作成功
|
||||
*/
|
||||
int SUCCESS = 200;
|
||||
|
||||
/**
|
||||
* 对象创建成功
|
||||
*/
|
||||
int CREATED = 201;
|
||||
|
||||
/**
|
||||
* 请求已经被接受
|
||||
*/
|
||||
int ACCEPTED = 202;
|
||||
|
||||
/**
|
||||
* 操作已经执行成功,但是没有返回数据
|
||||
*/
|
||||
int NO_CONTENT = 204;
|
||||
|
||||
/**
|
||||
* 资源已被移除
|
||||
*/
|
||||
int MOVED_PERM = 301;
|
||||
|
||||
/**
|
||||
* 重定向
|
||||
*/
|
||||
int SEE_OTHER = 303;
|
||||
|
||||
/**
|
||||
* 资源没有被修改
|
||||
*/
|
||||
int NOT_MODIFIED = 304;
|
||||
|
||||
/**
|
||||
* 参数列表错误(缺少,格式不匹配)
|
||||
*/
|
||||
int BAD_REQUEST = 400;
|
||||
|
||||
/**
|
||||
* 未授权
|
||||
*/
|
||||
int UNAUTHORIZED = 401;
|
||||
|
||||
/**
|
||||
* 访问受限,授权过期
|
||||
*/
|
||||
int FORBIDDEN = 403;
|
||||
|
||||
/**
|
||||
* 资源,服务未找到
|
||||
*/
|
||||
int NOT_FOUND = 404;
|
||||
|
||||
/**
|
||||
* 不允许的http方法
|
||||
*/
|
||||
int BAD_METHOD = 405;
|
||||
|
||||
/**
|
||||
* 资源冲突,或者资源被锁
|
||||
*/
|
||||
int CONFLICT = 409;
|
||||
|
||||
/**
|
||||
* 不支持的数据,媒体类型
|
||||
*/
|
||||
int UNSUPPORTED_TYPE = 415;
|
||||
|
||||
/**
|
||||
* 系统内部错误
|
||||
*/
|
||||
int ERROR = 500;
|
||||
|
||||
/**
|
||||
* 接口未实现
|
||||
*/
|
||||
int NOT_IMPLEMENTED = 501;
|
||||
|
||||
/**
|
||||
* 系统警告消息
|
||||
*/
|
||||
int WARN = 601;
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package cc.iotkit.common.constant;
|
||||
|
||||
/**
|
||||
* 租户常量信息
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
public interface TenantConstants {
|
||||
|
||||
/**
|
||||
* 租户正常状态
|
||||
*/
|
||||
String NORMAL = "0";
|
||||
|
||||
/**
|
||||
* 租户封禁状态
|
||||
*/
|
||||
String DISABLE = "1";
|
||||
|
||||
/**
|
||||
* 超级管理员ID
|
||||
*/
|
||||
Long SUPER_ADMIN_ID = 1L;
|
||||
|
||||
/**
|
||||
* 超级管理员角色 roleKey
|
||||
*/
|
||||
String SUPER_ADMIN_ROLE_KEY = "superadmin";
|
||||
|
||||
/**
|
||||
* 租户管理员角色 roleKey
|
||||
*/
|
||||
String TENANT_ADMIN_ROLE_KEY = "admin";
|
||||
|
||||
/**
|
||||
* 租户管理员角色名称
|
||||
*/
|
||||
String TENANT_ADMIN_ROLE_NAME = "管理员";
|
||||
|
||||
/**
|
||||
* 默认租户ID
|
||||
*/
|
||||
String DEFAULT_TENANT_ID = "000000";
|
||||
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
package cc.iotkit.common.constant;
|
||||
|
||||
/**
|
||||
* 用户常量信息
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public interface UserConstants {
|
||||
|
||||
/**
|
||||
* 平台内系统用户的唯一标志
|
||||
*/
|
||||
String SYS_USER = "SYS_USER";
|
||||
|
||||
/**
|
||||
* 正常状态
|
||||
*/
|
||||
String NORMAL = "0";
|
||||
|
||||
/**
|
||||
* 异常状态
|
||||
*/
|
||||
String EXCEPTION = "1";
|
||||
|
||||
/**
|
||||
* 用户正常状态
|
||||
*/
|
||||
String USER_NORMAL = "0";
|
||||
|
||||
/**
|
||||
* 用户封禁状态
|
||||
*/
|
||||
String USER_DISABLE = "1";
|
||||
|
||||
/**
|
||||
* 角色正常状态
|
||||
*/
|
||||
String ROLE_NORMAL = "0";
|
||||
|
||||
/**
|
||||
* 角色封禁状态
|
||||
*/
|
||||
String ROLE_DISABLE = "1";
|
||||
|
||||
/**
|
||||
* 部门正常状态
|
||||
*/
|
||||
String DEPT_NORMAL = "0";
|
||||
|
||||
/**
|
||||
* 部门停用状态
|
||||
*/
|
||||
String DEPT_DISABLE = "1";
|
||||
|
||||
/**
|
||||
* 字典正常状态
|
||||
*/
|
||||
String DICT_NORMAL = "0";
|
||||
|
||||
/**
|
||||
* 是否为系统默认(是)
|
||||
*/
|
||||
String YES = "Y";
|
||||
|
||||
/**
|
||||
* 是否菜单外链(是)
|
||||
*/
|
||||
String YES_FRAME = "0";
|
||||
|
||||
/**
|
||||
* 是否菜单外链(否)
|
||||
*/
|
||||
String NO_FRAME = "1";
|
||||
|
||||
/**
|
||||
* 菜单正常状态
|
||||
*/
|
||||
String MENU_NORMAL = "0";
|
||||
|
||||
/**
|
||||
* 菜单停用状态
|
||||
*/
|
||||
String MENU_DISABLE = "1";
|
||||
|
||||
/**
|
||||
* 菜单类型(目录)
|
||||
*/
|
||||
String TYPE_DIR = "M";
|
||||
|
||||
/**
|
||||
* 菜单类型(菜单)
|
||||
*/
|
||||
String TYPE_MENU = "C";
|
||||
|
||||
/**
|
||||
* 菜单类型(按钮)
|
||||
*/
|
||||
String TYPE_BUTTON = "F";
|
||||
|
||||
/**
|
||||
* Layout组件标识
|
||||
*/
|
||||
String LAYOUT = "Layout";
|
||||
|
||||
/**
|
||||
* ParentView组件标识
|
||||
*/
|
||||
String PARENT_VIEW = "ParentView";
|
||||
|
||||
/**
|
||||
* InnerLink组件标识
|
||||
*/
|
||||
String INNER_LINK = "InnerLink";
|
||||
|
||||
/**
|
||||
* 用户名长度限制
|
||||
*/
|
||||
int USERNAME_MIN_LENGTH = 2;
|
||||
int USERNAME_MAX_LENGTH = 20;
|
||||
|
||||
/**
|
||||
* 密码长度限制
|
||||
*/
|
||||
int PASSWORD_MIN_LENGTH = 5;
|
||||
int PASSWORD_MAX_LENGTH = 20;
|
||||
|
||||
/**
|
||||
* 超级管理员ID
|
||||
*/
|
||||
Long SUPER_ADMIN_ID = 1L;
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package cc.iotkit.common.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
* 针对一套 用户体系
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum DeviceType {
|
||||
|
||||
/**
|
||||
* pc端
|
||||
*/
|
||||
PC("pc"),
|
||||
|
||||
/**
|
||||
* app端
|
||||
*/
|
||||
APP("app"),
|
||||
|
||||
/**
|
||||
* 小程序端
|
||||
*/
|
||||
XCX("xcx");
|
||||
|
||||
private final String device;
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
package cc.iotkit.common.enums;
|
||||
|
||||
/**
|
||||
* @author :tfd
|
||||
* 异常枚举类
|
||||
*/
|
||||
public enum ErrCode implements IEnum {
|
||||
/**
|
||||
* 系统通用异常段
|
||||
*/
|
||||
PARAMS_EXCEPTION(10000001, "参数异常"),
|
||||
SYSTEM_EXCEPTION(10000002, "系统异常"),
|
||||
UNKNOWN_EXCEPTION(10000003, "未知异常"),
|
||||
SYSTEM_ERROR(10000004, "服务器内部错误"),
|
||||
METHOD_NOT_ALLOWED(10000005, "请求方法不支持"),
|
||||
NOT_FOUND(10000006, "请求资源不存在"),
|
||||
FORBIDDEN(10000007, "请求被拒绝"),
|
||||
UNAUTHORIZED_EXCEPTION(10000008, "未授权访问"),
|
||||
UNSUPPORTED_OPERATION_EXCEPTION(10000009, "方法未实现"),
|
||||
DATA_NOT_EXIST(10000010, "数据不存在"),
|
||||
|
||||
/**
|
||||
* 组件通用异常段
|
||||
*/
|
||||
GET_COMPONENT_INSTANCE_ERROR(00000000, "获取通讯组件实例失败"),
|
||||
GET_COMPONENT_SCRIPT_ERROR(00000000, "获取通讯组件脚本失败"),
|
||||
GET_CONVERT_ERROR(00000000, "获取转换器失败"),
|
||||
GET_SPI_COMPONENT_ERROR(00000000, "获取组件CLASS失败"),
|
||||
GET_SPI_CONVERT_ERROR(00000000, "获取转换器CLASS失败"),
|
||||
COMPONENT_NOT_FOUND(00000000, "通讯组件不存在"),
|
||||
SEND_DESTINATION_NOT_FOUND(00000000, "发送目标不存在"),
|
||||
MSG_CONVERT_ERROR(00000000, "消息转换失败"),
|
||||
DEVICE_REGISTER_ERROR(00000000, "设备注册失败"),
|
||||
COMPONENT_ID_BLANK(00000000, "通讯组件ID为空"),
|
||||
COMPONENT_JAR_NOT_FOUND(00000000, "通讯组件JAR包为空"),
|
||||
COMPONENT_ALREADY(00000000, "通讯组件已经存在"),
|
||||
SAVE_COMPONENT_SCRIPT_ERROR(00000000, "保存通讯组件脚本失败"),
|
||||
SAVE_CONVERT_SCRIPT_ERROR(00000000, "保存转换器脚本失败"),
|
||||
ADD_COMPONENT_ERROR(00000000, "添加通讯组件失败"),
|
||||
ADD_CONVERT_ERROR(00000000, "添加转换器失败"),
|
||||
CONVERT_NOT_FOUND(00000000, "转换器不存在"),
|
||||
DELETE_CONVERT_ERROR(00000000, "删除转换器失败"),
|
||||
DELETE_COMPONENT_ERROR(00000000, "删除通讯组件失败"),
|
||||
PRODUCT_SECRET_ERROR(00000000, "产品密钥错误"),
|
||||
COMPONENT_START_ERROR(00000000, "通讯组件启动失败"),
|
||||
INIT_PRODUCER_ERROR(00000000, "初始化MQ生产者失败"),
|
||||
SEND_MSG_ERROR(00000000, "发送消息失败"),
|
||||
|
||||
|
||||
/**
|
||||
* 业务通用异常段
|
||||
*/
|
||||
TASK_NOT_SUPPORT_RENEW(00000000, "任务不支持续订"),
|
||||
GROUP_ALREADY(00000000, "分组已经存在"),
|
||||
GROUP_NOT_FOUND(00000000, "分组不存在"),
|
||||
PRODUCT_NOT_FOUND(00000000, "产品不存在"),
|
||||
DEVICE_NOT_FOUND(00000000, "设备不存在"),
|
||||
DEVICE_OFFLINE(00000000, "设备已离线"),
|
||||
DEVICE_ALREADY(00000000, "设备已存在"),
|
||||
MODEL_ALREADY(00000000, "型号已存在"),
|
||||
MODEL_SCRIPT_NOT_FOUND(00000000, "产品型号脚本不存在"),
|
||||
PRODUCT_MODEL_NOT_FOUND(00000000, "产品型号不存在"),
|
||||
FILE_NOT_FOUND(00000000, "文件不存在"),
|
||||
RULE_NOT_FOUND(00000000, "规则不存在"),
|
||||
RULE_ALREADY_RUNNING(00000000, "规则已运行"),
|
||||
SEND_REQUEST_ERROR(00000000, "发送请求失败"),
|
||||
TASK_NOT_FOUND(00000000, "任务不存在"),
|
||||
RENEW_TASK_ERROR(00000000, "重启任务失败"),
|
||||
HOME_NOT_FOUND(00000000, "家庭不存在"),
|
||||
CURRENT_HOME_NOT_FOUND(00000000, "当前家庭不存在"),
|
||||
SPACE_NOT_FOUND(00000000, "空间不存在"),
|
||||
SPACE_DEVICE_NOT_FOUND(00000000, "空间设备不存在"),
|
||||
DATA_BLANK(00000000, "数据为空"),
|
||||
DATA_LENGTH_ERROR(00000000, "数据长度错误"),
|
||||
DATA_FORMAT_ERROR(00000000, "数据格式错误"),
|
||||
USER_NOT_FOUND(00000000, "用户不存在"),
|
||||
RESET_PWD_ERROR(00000000, "重置密码失败"),
|
||||
UPDATE_PWD_ERROR(00000000, "修改密码失败"),
|
||||
PWD_ERROR(00000000, "密码错误"),
|
||||
STATE_ERROR(00000000, "状态错误"),
|
||||
RECORD_NOT_FOUND(00000000, "记录不存在"),
|
||||
ADD_PLATFORM_USER_ERROR(00000000, "添加平台用户失败"),
|
||||
UPLOAD_FILE_ERROR(00000000, "上传文件失败");
|
||||
|
||||
|
||||
private int code;
|
||||
private String message;
|
||||
|
||||
ErrCode(int code, String message) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getKey() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return this.message;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package cc.iotkit.common.enums;
|
||||
|
||||
public interface IEnum {
|
||||
/**
|
||||
* 获取枚举的key
|
||||
*/
|
||||
Integer getKey();
|
||||
|
||||
/**
|
||||
* 获取枚举的下标
|
||||
*/
|
||||
String getValue();
|
||||
|
||||
/**
|
||||
* 将参数反序列化为枚举
|
||||
*
|
||||
* @param param 当前值
|
||||
* @param clazz 枚举类型
|
||||
*/
|
||||
static <T extends Enum<T> & IEnum> T parse(Integer param, Class<T> clazz) {
|
||||
if (param == null || clazz == null) {
|
||||
return null;
|
||||
}
|
||||
T[] enums = clazz.getEnumConstants();
|
||||
for (T t : enums) {
|
||||
Integer key = t.getKey();
|
||||
if (key.equals(param)) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package cc.iotkit.common.enums;
|
||||
|
||||
import cc.iotkit.common.utils.StringUtils;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 设备类型
|
||||
* 针对多套 用户体系
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum UserType {
|
||||
|
||||
/**
|
||||
* pc端
|
||||
*/
|
||||
SYS_USER("sys_user"),
|
||||
|
||||
/**
|
||||
* app端
|
||||
*/
|
||||
APP_USER("app_user");
|
||||
|
||||
private final String userType;
|
||||
|
||||
public static UserType getUserType(String str) {
|
||||
for (UserType value : values()) {
|
||||
if (StringUtils.contains(str, value.getUserType())) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("'UserType' not found By " + str);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* +----------------------------------------------------------------------
|
||||
* | Copyright (c) 奇特物联 2021-2022 All rights reserved.
|
||||
* +----------------------------------------------------------------------
|
||||
* | Licensed 未经许可不能去掉「奇特物联」相关版权
|
||||
* +----------------------------------------------------------------------
|
||||
* | Author: xw2sy@163.com
|
||||
* +----------------------------------------------------------------------
|
||||
*/
|
||||
package cc.iotkit.common.exception;
|
||||
|
||||
import cc.iotkit.common.enums.ErrCode;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class BizException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* 所属模块
|
||||
*/
|
||||
private String module;
|
||||
|
||||
/**
|
||||
* 错误码
|
||||
*/
|
||||
private Integer code;
|
||||
|
||||
/**
|
||||
* 错误消息
|
||||
*/
|
||||
private String message;
|
||||
|
||||
public BizException(String message) {
|
||||
super(message);
|
||||
this.code = ErrCode.SYSTEM_EXCEPTION.getKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一异常消息处理
|
||||
*
|
||||
* @param errCode 异常枚举值
|
||||
*/
|
||||
public BizException(ErrCode errCode) {
|
||||
this.message = errCode.getValue();
|
||||
this.code = errCode.getKey();
|
||||
}
|
||||
|
||||
public BizException(ErrCode errCode, Throwable cause) {
|
||||
super(cause);
|
||||
this.message = errCode.getValue();
|
||||
}
|
||||
|
||||
public BizException(ErrCode errCode, String message) {
|
||||
this.message = message;
|
||||
this.code = errCode.getKey();
|
||||
}
|
||||
|
||||
public BizException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public BizException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package cc.iotkit.common.exception;
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 视图异常
|
||||
*
|
||||
* @author sjg
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
public class ViewException extends RuntimeException {
|
||||
|
||||
public static final int CODE_FAILED = 0;
|
||||
public static final int CODE_WARN = 1;
|
||||
|
||||
private int code;
|
||||
private String message;
|
||||
private Object data;
|
||||
|
||||
public ViewException() {
|
||||
}
|
||||
|
||||
public ViewException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ViewException(int code, String message) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public ViewException(int code, String message, Object data) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
this.data = data;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package cc.iotkit.common.service;
|
||||
|
||||
/**
|
||||
* 通用 参数配置服务
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
public interface ConfigService {
|
||||
|
||||
/**
|
||||
* 根据参数 key 获取参数值
|
||||
*
|
||||
* @param configKey 参数 key
|
||||
* @return 参数值
|
||||
*/
|
||||
String getConfigValue(String configKey);
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package cc.iotkit.common.service;
|
||||
|
||||
/**
|
||||
* 通用 部门服务
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
public interface DeptService {
|
||||
|
||||
/**
|
||||
* 通过部门ID查询部门名称
|
||||
*
|
||||
* @param deptIds 部门ID串逗号分隔
|
||||
* @return 部门名称串逗号分隔
|
||||
*/
|
||||
String selectDeptNameByIds(String deptIds);
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package cc.iotkit.common.service;
|
||||
|
||||
/**
|
||||
* 通用 字典服务
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
public interface DictService {
|
||||
|
||||
/**
|
||||
* 分隔符
|
||||
*/
|
||||
String SEPARATOR = ",";
|
||||
|
||||
/**
|
||||
* 根据字典类型和字典值获取字典标签
|
||||
*
|
||||
* @param dictType 字典类型
|
||||
* @param dictValue 字典值
|
||||
* @return 字典标签
|
||||
*/
|
||||
default String getDictLabel(String dictType, String dictValue) {
|
||||
return getDictLabel(dictType, dictValue, SEPARATOR);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据字典类型和字典标签获取字典值
|
||||
*
|
||||
* @param dictType 字典类型
|
||||
* @param dictLabel 字典标签
|
||||
* @return 字典值
|
||||
*/
|
||||
default String getDictValue(String dictType, String dictLabel) {
|
||||
return getDictValue(dictType, dictLabel, SEPARATOR);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据字典类型和字典值获取字典标签
|
||||
*
|
||||
* @param dictType 字典类型
|
||||
* @param dictValue 字典值
|
||||
* @param separator 分隔符
|
||||
* @return 字典标签
|
||||
*/
|
||||
String getDictLabel(String dictType, String dictValue, String separator);
|
||||
|
||||
/**
|
||||
* 根据字典类型和字典标签获取字典值
|
||||
*
|
||||
* @param dictType 字典类型
|
||||
* @param dictLabel 字典标签
|
||||
* @param separator 分隔符
|
||||
* @return 字典值
|
||||
*/
|
||||
String getDictValue(String dictType, String dictLabel, String separator);
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package cc.iotkit.common.service;
|
||||
|
||||
/**
|
||||
* 通用 OSS服务
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
public interface OssService {
|
||||
|
||||
/**
|
||||
* 通过ossId查询对应的url
|
||||
*
|
||||
* @param ossIds ossId串逗号分隔
|
||||
* @return url串逗号分隔
|
||||
*/
|
||||
String selectUrlByIds(String ossIds);
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package cc.iotkit.common.service;
|
||||
|
||||
/**
|
||||
* 通用 用户服务
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
public interface UserService {
|
||||
|
||||
/**
|
||||
* 通过用户ID查询用户账户
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 用户账户
|
||||
*/
|
||||
String selectUserNameById(Long userId);
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package cc.iotkit.common.undefined;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 用户登录对象
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
|
||||
@Data
|
||||
public class LoginBody {
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
@NotBlank(message = "{tenant.number.not.blank}")
|
||||
private String tenantId;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
@NotBlank(message = "{user.username.not.blank}")
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 用户密码
|
||||
*/
|
||||
@NotBlank(message = "{user.password.not.blank}")
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 验证码
|
||||
*/
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* 唯一标识
|
||||
*/
|
||||
private String uuid;
|
||||
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
package cc.iotkit.common.undefined;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 登录用户身份权限
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class LoginUser implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
private String tenantId;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 部门名
|
||||
*/
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 用户唯一标识
|
||||
*/
|
||||
private String token;
|
||||
|
||||
/**
|
||||
* 用户类型
|
||||
*/
|
||||
private String userType;
|
||||
|
||||
/**
|
||||
* 登录时间
|
||||
*/
|
||||
private Long loginTime;
|
||||
|
||||
/**
|
||||
* 过期时间
|
||||
*/
|
||||
private Long expireTime;
|
||||
|
||||
/**
|
||||
* 登录IP地址
|
||||
*/
|
||||
private String ipaddr;
|
||||
|
||||
/**
|
||||
* 登录地点
|
||||
*/
|
||||
private String loginLocation;
|
||||
|
||||
/**
|
||||
* 浏览器类型
|
||||
*/
|
||||
private String browser;
|
||||
|
||||
/**
|
||||
* 操作系统
|
||||
*/
|
||||
private String os;
|
||||
|
||||
/**
|
||||
* 菜单权限
|
||||
*/
|
||||
private Set<String> menuPermission;
|
||||
|
||||
/**
|
||||
* 角色权限
|
||||
*/
|
||||
private Set<String> rolePermission;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 角色对象
|
||||
*/
|
||||
private List<RoleDTO> roles;
|
||||
|
||||
/**
|
||||
* 数据权限 当前角色ID
|
||||
*/
|
||||
private Long roleId;
|
||||
|
||||
/**
|
||||
* 获取登录id
|
||||
*/
|
||||
public String getLoginId() {
|
||||
if (userType == null) {
|
||||
throw new IllegalArgumentException("用户类型不能为空");
|
||||
}
|
||||
if (userId == null) {
|
||||
throw new IllegalArgumentException("用户ID不能为空");
|
||||
}
|
||||
return userType + ":" + userId;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package cc.iotkit.common.undefined;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 用户注册对象
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class RegisterBody extends LoginBody {
|
||||
|
||||
private String userType;
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package cc.iotkit.common.undefined;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 角色
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class RoleDTO implements Serializable {
|
||||
|
||||
/**
|
||||
* 角色ID
|
||||
*/
|
||||
private Long roleId;
|
||||
|
||||
/**
|
||||
* 角色名称
|
||||
*/
|
||||
private String roleName;
|
||||
|
||||
/**
|
||||
* 角色权限
|
||||
*/
|
||||
private String roleKey;
|
||||
|
||||
/**
|
||||
* 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限)
|
||||
*/
|
||||
private String dataScope;
|
||||
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package cc.iotkit.common.undefined;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 当前在线会话
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class UserOnlineDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 会话编号
|
||||
*/
|
||||
private String tokenId;
|
||||
|
||||
/**
|
||||
* 部门名称
|
||||
*/
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 用户名称
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 登录IP地址
|
||||
*/
|
||||
private String ipaddr;
|
||||
|
||||
/**
|
||||
* 登录地址
|
||||
*/
|
||||
private String loginLocation;
|
||||
|
||||
/**
|
||||
* 浏览器类型
|
||||
*/
|
||||
private String browser;
|
||||
|
||||
/**
|
||||
* 操作系统
|
||||
*/
|
||||
private String os;
|
||||
|
||||
/**
|
||||
* 登录时间
|
||||
*/
|
||||
private Long loginTime;
|
||||
|
||||
}
|
|
@ -7,8 +7,10 @@
|
|||
* | Author: xw2sy@163.com
|
||||
* +----------------------------------------------------------------------
|
||||
*/
|
||||
package cc.iotkit.common;
|
||||
package cc.iotkit.common.utils;
|
||||
|
||||
import cc.iotkit.common.enums.ErrCode;
|
||||
import cc.iotkit.common.exception.BizException;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
|
@ -65,13 +67,13 @@ public class ComponentClassLoader {
|
|||
public static <T> T getComponent(String name, File jarFile) throws Exception {
|
||||
String className = addUrl(name, jarFile);
|
||||
if (StringUtils.isBlank(className)) {
|
||||
throw new RuntimeException("component class does not exist");
|
||||
throw new BizException(ErrCode.GET_SPI_COMPONENT_ERROR);
|
||||
}
|
||||
Class<T> componentClass = findClass(name, className);
|
||||
return componentClass.getDeclaredConstructor().newInstance();
|
||||
}
|
||||
|
||||
public static <T> T getConverter(String name, File jarFile) throws Exception {
|
||||
public static <T> T getConverter(String name) throws Exception {
|
||||
URLClassLoader classLoader = classLoaders.get(name);
|
||||
InputStream is = classLoader.getResourceAsStream("convert.spi");
|
||||
if (is == null) {
|
||||
|
@ -81,7 +83,7 @@ public class ComponentClassLoader {
|
|||
//多行只取第1行,并处理空格
|
||||
String[] lines = IOUtils.toString(is, StandardCharsets.UTF_8).split("\\s");
|
||||
if (lines.length == 0) {
|
||||
throw new RuntimeException("convert class does not exist");
|
||||
throw new BizException(ErrCode.GET_SPI_CONVERT_ERROR);
|
||||
}
|
||||
String className = lines[0].trim();
|
||||
Class<T> converterClass = findClass(name, className);
|
|
@ -0,0 +1,164 @@
|
|||
package cc.iotkit.common.utils;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.commons.lang3.time.DateFormatUtils;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.*;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 时间工具类
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
|
||||
|
||||
public static final String YYYY = "yyyy";
|
||||
|
||||
public static final String YYYY_MM = "yyyy-MM";
|
||||
|
||||
public static final String YYYY_MM_DD = "yyyy-MM-dd";
|
||||
|
||||
public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
|
||||
|
||||
public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
private static final String[] PARSE_PATTERNS = {
|
||||
"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
|
||||
"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
|
||||
"yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
|
||||
|
||||
/**
|
||||
* 获取当前Date型日期
|
||||
*
|
||||
* @return Date() 当前日期
|
||||
*/
|
||||
public static Date getNowDate() {
|
||||
return new Date();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前日期, 默认格式为yyyy-MM-dd
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public static String getDate() {
|
||||
return dateTimeNow(YYYY_MM_DD);
|
||||
}
|
||||
|
||||
public static String getTime() {
|
||||
return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
|
||||
}
|
||||
|
||||
public static String dateTimeNow() {
|
||||
return dateTimeNow(YYYYMMDDHHMMSS);
|
||||
}
|
||||
|
||||
public static String dateTimeNow(final String format) {
|
||||
return parseDateToStr(format, new Date());
|
||||
}
|
||||
|
||||
public static String dateTime(final Date date) {
|
||||
return parseDateToStr(YYYY_MM_DD, date);
|
||||
}
|
||||
|
||||
public static String parseDateToStr(final String format, final Date date) {
|
||||
return new SimpleDateFormat(format).format(date);
|
||||
}
|
||||
|
||||
public static Date dateTime(final String format, final String ts) {
|
||||
try {
|
||||
return new SimpleDateFormat(format).parse(ts);
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期路径 即年/月/日 如2018/08/08
|
||||
*/
|
||||
public static String datePath() {
|
||||
Date now = new Date();
|
||||
return DateFormatUtils.format(now, "yyyy/MM/dd");
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期路径 即年/月/日 如20180808
|
||||
*/
|
||||
public static String dateTime() {
|
||||
Date now = new Date();
|
||||
return DateFormatUtils.format(now, "yyyyMMdd");
|
||||
}
|
||||
|
||||
/**
|
||||
* 日期型字符串转化为日期 格式
|
||||
*/
|
||||
public static Date parseDate(Object str) {
|
||||
if (str == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return parseDate(str.toString(), PARSE_PATTERNS);
|
||||
} catch (ParseException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取服务器启动时间
|
||||
*/
|
||||
public static Date getServerStartDate() {
|
||||
long time = ManagementFactory.getRuntimeMXBean().getStartTime();
|
||||
return new Date(time);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算相差天数
|
||||
*/
|
||||
public static int differentDaysByMillisecond(Date date1, Date date2) {
|
||||
return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算两个时间差
|
||||
*/
|
||||
public static String getDatePoor(Date endDate, Date nowDate) {
|
||||
long nd = 1000 * 24 * 60 * 60;
|
||||
long nh = 1000 * 60 * 60;
|
||||
long nm = 1000 * 60;
|
||||
// long ns = 1000;
|
||||
// 获得两个时间的毫秒时间差异
|
||||
long diff = endDate.getTime() - nowDate.getTime();
|
||||
// 计算差多少天
|
||||
long day = diff / nd;
|
||||
// 计算差多少小时
|
||||
long hour = diff % nd / nh;
|
||||
// 计算差多少分钟
|
||||
long min = diff % nd % nh / nm;
|
||||
// 计算差多少秒//输出结果
|
||||
// long sec = diff % nd % nh % nm / ns;
|
||||
return day + "天" + hour + "小时" + min + "分钟";
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加 LocalDateTime ==> Date
|
||||
*/
|
||||
public static Date toDate(LocalDateTime temporalAccessor) {
|
||||
ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault());
|
||||
return Date.from(zdt.toInstant());
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加 LocalDate ==> Date
|
||||
*/
|
||||
public static Date toDate(LocalDate temporalAccessor) {
|
||||
LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0));
|
||||
ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
|
||||
return Date.from(zdt.toInstant());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
package cc.iotkit.common.utils;
|
||||
|
||||
import cn.hutool.core.lang.Dict;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* JSON 工具类
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class JsonUtils {
|
||||
|
||||
private static final ObjectMapper OBJECT_MAPPER = SpringUtils.getBean(ObjectMapper.class);
|
||||
|
||||
public static ObjectMapper getObjectMapper() {
|
||||
return OBJECT_MAPPER;
|
||||
}
|
||||
|
||||
public static String toJsonString(Object object) {
|
||||
if (ObjectUtil.isNull(object)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return OBJECT_MAPPER.writeValueAsString(object);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T parseObject(String text, Class<T> clazz) {
|
||||
if (StringUtils.isEmpty(text)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return OBJECT_MAPPER.readValue(text, clazz);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T parseObject(byte[] bytes, Class<T> clazz) {
|
||||
if (ArrayUtil.isEmpty(bytes)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return OBJECT_MAPPER.readValue(bytes, clazz);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T parseObject(String text, TypeReference<T> typeReference) {
|
||||
if (StringUtils.isBlank(text)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return OBJECT_MAPPER.readValue(text, typeReference);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static Dict parseMap(String text) {
|
||||
if (StringUtils.isBlank(text)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructType(Dict.class));
|
||||
} catch (MismatchedInputException e) {
|
||||
// 类型不匹配说明不是json
|
||||
return null;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Dict> parseArrayMap(String text) {
|
||||
if (StringUtils.isBlank(text)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, Dict.class));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> List<T> parseArray(String text, Class<T> clazz) {
|
||||
if (StringUtils.isEmpty(text)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
try {
|
||||
return OBJECT_MAPPER.readValue(text, OBJECT_MAPPER.getTypeFactory().constructCollectionType(List.class, clazz));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
package cc.iotkit.common.utils;
|
||||
|
||||
import cc.iotkit.common.api.Paging;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import io.github.linpeilie.Converter;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Mapstruct 工具类
|
||||
* <p>参考文档:<a href="https://mapstruct.plus/guide/quick-start">mapstruct-plus</a></p>
|
||||
*
|
||||
* @author Michelle.Chung
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class MapstructUtils {
|
||||
|
||||
private final static Converter CONVERTER = SpringUtils.getBean(Converter.class);
|
||||
|
||||
/**
|
||||
* 将 T 类型对象,转换为 desc 类型的对象并返回
|
||||
*
|
||||
* @param source 数据来源实体
|
||||
* @param desc 描述对象 转换后的对象
|
||||
* @return desc
|
||||
*/
|
||||
public static <T, V> V convert(T source, Class<V> desc) {
|
||||
Assert.notNull(source, "source is null");
|
||||
Assert.notNull(desc, "desc is null");
|
||||
return CONVERTER.convert(source, desc);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 T 类型对象,按照配置的映射字段规则,给 desc 类型的对象赋值并返回 desc 对象
|
||||
*
|
||||
* @param source 数据来源实体
|
||||
* @param desc 转换后的对象
|
||||
* @return desc
|
||||
*/
|
||||
public static <T, V> V convert(T source, V desc) {
|
||||
if (ObjectUtil.isNull(source)) {
|
||||
return null;
|
||||
}
|
||||
if (ObjectUtil.isNull(desc)) {
|
||||
return null;
|
||||
}
|
||||
return CONVERTER.convert(source, desc);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 T 类型的集合,转换为 desc 类型的集合并返回
|
||||
*
|
||||
* @param sourceList 数据来源实体列表
|
||||
* @param desc 描述对象 转换后的对象
|
||||
* @return desc
|
||||
*/
|
||||
public static <T, V> List<V> convert(List<T> sourceList, Class<V> desc) {
|
||||
if (ObjectUtil.isNull(sourceList)) {
|
||||
return null;
|
||||
}
|
||||
if (CollUtil.isEmpty(sourceList)) {
|
||||
return CollUtil.newArrayList();
|
||||
}
|
||||
return CONVERTER.convert(sourceList, desc);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 Map 转换为 beanClass 类型的集合并返回
|
||||
*
|
||||
* @param map 数据来源
|
||||
* @param beanClass bean类
|
||||
* @return bean对象
|
||||
*/
|
||||
public static <T> T convert(Map<String, Object> map, Class<T> beanClass) {
|
||||
if (MapUtil.isEmpty(map)) {
|
||||
return null;
|
||||
}
|
||||
if (ObjectUtil.isNull(beanClass)) {
|
||||
return null;
|
||||
}
|
||||
return CONVERTER.convert(map, beanClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换分页对象
|
||||
*
|
||||
* @param source 数据来源
|
||||
* @param desc 描述对象 转换后的对象
|
||||
* @return desc
|
||||
*/
|
||||
public static <T, V> Paging<V> convert(Paging<T> source, Class<V> desc) {
|
||||
if (ObjectUtil.isNull(source)) {
|
||||
return null;
|
||||
}
|
||||
if (CollUtil.isEmpty(source.getData())) {
|
||||
return new Paging<>(0, new ArrayList<>());
|
||||
}
|
||||
return new Paging<>(source.getTotal(), CONVERTER.convert(source.getData(), desc));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package cc.iotkit.common.utils;
|
||||
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class ReflectUtils extends ReflectUtil {
|
||||
|
||||
private static final String SETTER_PREFIX = "set";
|
||||
|
||||
private static final String GETTER_PREFIX = "get";
|
||||
|
||||
/**
|
||||
* 调用Getter方法.
|
||||
* 支持多级,如:对象名.对象名.方法
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <E> E invokeGetter(Object obj, String propertyName) {
|
||||
Object object = obj;
|
||||
for (String name : StringUtils.split(propertyName, ".")) {
|
||||
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name);
|
||||
object = invoke(object, getterMethodName);
|
||||
}
|
||||
return (E) object;
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用Setter方法, 仅匹配方法名。
|
||||
* 支持多级,如:对象名.对象名.方法
|
||||
*/
|
||||
public static <E> void invokeSetter(Object obj, String propertyName, E value) {
|
||||
Object object = obj;
|
||||
String[] names = StringUtils.split(propertyName, ".");
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
if (i < names.length - 1) {
|
||||
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
|
||||
object = invoke(object, getterMethodName);
|
||||
} else {
|
||||
String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
|
||||
Method method = getMethodByName(object.getClass(), setterMethodName);
|
||||
invoke(object, method, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
package cc.iotkit.common.utils;
|
||||
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.net.SocketException;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author: Longjun.Tu
|
||||
* @description:
|
||||
* @date:created in 2023/5/18 10:20
|
||||
* @modificed by:
|
||||
*/
|
||||
public class SnowflakeIdGeneratorUtil {
|
||||
|
||||
/**
|
||||
* 起始的时间戳
|
||||
*/
|
||||
private final static long START_STMP = 1577808000000L;
|
||||
|
||||
/**
|
||||
* 每一部分占用的位数
|
||||
*/
|
||||
private final static long SEQUENCE_BIT = 12; //序列号占用的位数
|
||||
private final static long MACHINE_BIT = 5; //机器标识占用的位数
|
||||
private final static long DATACENTER_BIT = 5;//数据中心占用的位数
|
||||
|
||||
/**
|
||||
* 每一部分的最大值
|
||||
*/
|
||||
private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT);
|
||||
private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);
|
||||
private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);
|
||||
|
||||
/**
|
||||
* 每一部分向左的位移
|
||||
*/
|
||||
private final static long MACHINE_LEFT = SEQUENCE_BIT;
|
||||
private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
|
||||
private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;
|
||||
|
||||
private long datacenterId; //数据中心
|
||||
private long machineId; //机器标识
|
||||
private long sequence = 0L; //序列号
|
||||
private long lastStmp = -1L;//上一次时间戳
|
||||
|
||||
private static volatile SnowflakeIdGeneratorUtil snowflake = null;
|
||||
private static Object lock = new Object();
|
||||
|
||||
public SnowflakeIdGeneratorUtil(long datacenterId, long machineId) {
|
||||
if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {
|
||||
throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0");
|
||||
}
|
||||
if (machineId > MAX_MACHINE_NUM || machineId < 0) {
|
||||
throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");
|
||||
}
|
||||
this.datacenterId = datacenterId;
|
||||
this.machineId = machineId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单列
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static SnowflakeIdGeneratorUtil getInstanceSnowflake() {
|
||||
if (snowflake == null) {
|
||||
synchronized (lock) {
|
||||
if(snowflake == null){
|
||||
long workerId;
|
||||
long dataCenterId = getRandom();
|
||||
try {
|
||||
//第一次使用获取mac地址的
|
||||
workerId = getWorkerId();
|
||||
} catch (Exception e) {
|
||||
workerId = getRandom();
|
||||
}
|
||||
snowflake = new SnowflakeIdGeneratorUtil(dataCenterId, workerId);
|
||||
}
|
||||
}
|
||||
}
|
||||
return snowflake;
|
||||
}
|
||||
|
||||
/**
|
||||
* 产生下一个ID
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public synchronized long nextId() {
|
||||
long currStmp = getNewstmp();
|
||||
if (currStmp < lastStmp) {
|
||||
throw new RuntimeException("Clock moved backwards. Refusing to generate id");
|
||||
}
|
||||
|
||||
if (currStmp == lastStmp) {
|
||||
//相同毫秒内,序列号自增
|
||||
sequence = (sequence + 1) & MAX_SEQUENCE;
|
||||
//同一毫秒的序列数已经达到最大
|
||||
if (sequence == 0L) {
|
||||
currStmp = getNextMill();
|
||||
}
|
||||
} else {
|
||||
//不同毫秒内,序列号置为0
|
||||
sequence = 0L;
|
||||
}
|
||||
|
||||
lastStmp = currStmp;
|
||||
|
||||
return (currStmp - START_STMP) << TIMESTMP_LEFT //时间戳部分
|
||||
| datacenterId << DATACENTER_LEFT //数据中心部分
|
||||
| machineId << MACHINE_LEFT //机器标识部分
|
||||
| sequence; //序列号部分
|
||||
}
|
||||
|
||||
private long getNextMill() {
|
||||
long mill = getNewstmp();
|
||||
while (mill <= lastStmp) {
|
||||
mill = getNewstmp();
|
||||
}
|
||||
return mill;
|
||||
}
|
||||
|
||||
private long getNewstmp() {
|
||||
return System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成1-31之间的随机数
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private static long getRandom() {
|
||||
int max = (int) (MAX_MACHINE_NUM);
|
||||
int min = 1;
|
||||
Random random = new Random();
|
||||
long result = random.nextInt(max - min) + min;
|
||||
return result;
|
||||
}
|
||||
|
||||
private static long getWorkerId() throws SocketException, UnknownHostException, NullPointerException {
|
||||
@SuppressWarnings("unused")
|
||||
InetAddress ip = InetAddress.getLocalHost();
|
||||
|
||||
NetworkInterface network = null;
|
||||
Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces();
|
||||
while (en.hasMoreElements()) {
|
||||
NetworkInterface nint = en.nextElement();
|
||||
if (!nint.isLoopback() && nint.getHardwareAddress() != null) {
|
||||
network = nint;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (network == null) {
|
||||
throw new NullPointerException("network is null");
|
||||
}
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
byte[] mac = network.getHardwareAddress();
|
||||
long id = ((0x000000FF & (long) mac[mac.length - 1]) | (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 11;
|
||||
if (id > MAX_MACHINE_NUM) {
|
||||
return getRandom();
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Set<Long> idList = new HashSet<>();
|
||||
long start = System.currentTimeMillis();
|
||||
for (int i = 0; i < 1000000; i++) {
|
||||
long id = SnowflakeIdGeneratorUtil.getInstanceSnowflake().nextId();
|
||||
idList.add(id);
|
||||
// System.out.println("id="+id);
|
||||
}
|
||||
// System.out.println(idList.size());
|
||||
// System.out.println(System.currentTimeMillis() - start);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package cc.iotkit.common.utils;
|
||||
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import org.springframework.aop.framework.AopContext;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* spring工具类
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Component
|
||||
public final class SpringUtils extends SpringUtil {
|
||||
|
||||
/**
|
||||
* 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
|
||||
*/
|
||||
public static boolean containsBean(String name) {
|
||||
return getBeanFactory().containsBean(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断以给定名字注册的bean定义是一个singleton还是一个prototype。
|
||||
* 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
|
||||
*/
|
||||
public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
|
||||
return getBeanFactory().isSingleton(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Class 注册对象的类型
|
||||
*/
|
||||
public static Class<?> getType(String name) throws NoSuchBeanDefinitionException {
|
||||
return getBeanFactory().getType(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果给定的bean名字在bean定义中有别名,则返回这些别名
|
||||
*/
|
||||
public static String[] getAliases(String name) throws NoSuchBeanDefinitionException {
|
||||
return getBeanFactory().getAliases(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取aop代理对象
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getAopProxy(T invoker) {
|
||||
return (T) AopContext.currentProxy();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取spring上下文
|
||||
*/
|
||||
public static ApplicationContext context() {
|
||||
return getApplicationContext();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,254 @@
|
|||
package cc.iotkit.common.utils;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* stream 流工具类
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class StreamUtils {
|
||||
|
||||
/**
|
||||
* 将collection过滤
|
||||
*
|
||||
* @param collection 需要转化的集合
|
||||
* @param function 过滤方法
|
||||
* @return 过滤后的list
|
||||
*/
|
||||
public static <E> List<E> filter(Collection<E> collection, Predicate<E> function) {
|
||||
if (CollUtil.isEmpty(collection)) {
|
||||
return CollUtil.newArrayList();
|
||||
}
|
||||
// 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
|
||||
return collection.stream().filter(function).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将collection拼接
|
||||
*
|
||||
* @param collection 需要转化的集合
|
||||
* @param function 拼接方法
|
||||
* @return 拼接后的list
|
||||
*/
|
||||
public static <E> String join(Collection<E> collection, Function<E, String> function) {
|
||||
return join(collection, function, StringUtils.SEPARATOR);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将collection拼接
|
||||
*
|
||||
* @param collection 需要转化的集合
|
||||
* @param function 拼接方法
|
||||
* @param delimiter 拼接符
|
||||
* @return 拼接后的list
|
||||
*/
|
||||
public static <E> String join(Collection<E> collection, Function<E, String> function, CharSequence delimiter) {
|
||||
if (CollUtil.isEmpty(collection)) {
|
||||
return StringUtils.EMPTY;
|
||||
}
|
||||
return collection.stream().map(function).filter(Objects::nonNull).collect(Collectors.joining(delimiter));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将collection排序
|
||||
*
|
||||
* @param collection 需要转化的集合
|
||||
* @param comparing 排序方法
|
||||
* @return 排序后的list
|
||||
*/
|
||||
public static <E> List<E> sorted(Collection<E> collection, Comparator<E> comparing) {
|
||||
if (CollUtil.isEmpty(collection)) {
|
||||
return CollUtil.newArrayList();
|
||||
}
|
||||
// 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
|
||||
return collection.stream().sorted(comparing).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将collection转化为类型不变的map<br>
|
||||
* <B>{@code Collection<V> ----> Map<K,V>}</B>
|
||||
*
|
||||
* @param collection 需要转化的集合
|
||||
* @param key V类型转化为K类型的lambda方法
|
||||
* @param <V> collection中的泛型
|
||||
* @param <K> map中的key类型
|
||||
* @return 转化后的map
|
||||
*/
|
||||
public static <V, K> Map<K, V> toIdentityMap(Collection<V> collection, Function<V, K> key) {
|
||||
if (CollUtil.isEmpty(collection)) {
|
||||
return MapUtil.newHashMap();
|
||||
}
|
||||
return collection.stream().collect(Collectors.toMap(key, Function.identity(), (l, r) -> l));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将Collection转化为map(value类型与collection的泛型不同)<br>
|
||||
* <B>{@code Collection<E> -----> Map<K,V> }</B>
|
||||
*
|
||||
* @param collection 需要转化的集合
|
||||
* @param key E类型转化为K类型的lambda方法
|
||||
* @param value E类型转化为V类型的lambda方法
|
||||
* @param <E> collection中的泛型
|
||||
* @param <K> map中的key类型
|
||||
* @param <V> map中的value类型
|
||||
* @return 转化后的map
|
||||
*/
|
||||
public static <E, K, V> Map<K, V> toMap(Collection<E> collection, Function<E, K> key, Function<E, V> value) {
|
||||
if (CollUtil.isEmpty(collection)) {
|
||||
return MapUtil.newHashMap();
|
||||
}
|
||||
return collection.stream().collect(Collectors.toMap(key, value, (l, r) -> l));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将collection按照规则(比如有相同的班级id)分类成map<br>
|
||||
* <B>{@code Collection<E> -------> Map<K,List<E>> } </B>
|
||||
*
|
||||
* @param collection 需要分类的集合
|
||||
* @param key 分类的规则
|
||||
* @param <E> collection中的泛型
|
||||
* @param <K> map中的key类型
|
||||
* @return 分类后的map
|
||||
*/
|
||||
public static <E, K> Map<K, List<E>> groupByKey(Collection<E> collection, Function<E, K> key) {
|
||||
if (CollUtil.isEmpty(collection)) {
|
||||
return MapUtil.newHashMap();
|
||||
}
|
||||
return collection
|
||||
.stream()
|
||||
.collect(Collectors.groupingBy(key, LinkedHashMap::new, Collectors.toList()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将collection按照两个规则(比如有相同的年级id,班级id)分类成双层map<br>
|
||||
* <B>{@code Collection<E> ---> Map<T,Map<U,List<E>>> } </B>
|
||||
*
|
||||
* @param collection 需要分类的集合
|
||||
* @param key1 第一个分类的规则
|
||||
* @param key2 第二个分类的规则
|
||||
* @param <E> 集合元素类型
|
||||
* @param <K> 第一个map中的key类型
|
||||
* @param <U> 第二个map中的key类型
|
||||
* @return 分类后的map
|
||||
*/
|
||||
public static <E, K, U> Map<K, Map<U, List<E>>> groupBy2Key(Collection<E> collection, Function<E, K> key1, Function<E, U> key2) {
|
||||
if (CollUtil.isEmpty(collection)) {
|
||||
return MapUtil.newHashMap();
|
||||
}
|
||||
return collection
|
||||
.stream()
|
||||
.collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.groupingBy(key2, LinkedHashMap::new, Collectors.toList())));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将collection按照两个规则(比如有相同的年级id,班级id)分类成双层map<br>
|
||||
* <B>{@code Collection<E> ---> Map<T,Map<U,E>> } </B>
|
||||
*
|
||||
* @param collection 需要分类的集合
|
||||
* @param key1 第一个分类的规则
|
||||
* @param key2 第二个分类的规则
|
||||
* @param <T> 第一个map中的key类型
|
||||
* @param <U> 第二个map中的key类型
|
||||
* @param <E> collection中的泛型
|
||||
* @return 分类后的map
|
||||
*/
|
||||
public static <E, T, U> Map<T, Map<U, E>> group2Map(Collection<E> collection, Function<E, T> key1, Function<E, U> key2) {
|
||||
if (CollUtil.isEmpty(collection) || key1 == null || key2 == null) {
|
||||
return MapUtil.newHashMap();
|
||||
}
|
||||
return collection
|
||||
.stream()
|
||||
.collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.toMap(key2, Function.identity(), (l, r) -> l)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将collection转化为List集合,但是两者的泛型不同<br>
|
||||
* <B>{@code Collection<E> ------> List<T> } </B>
|
||||
*
|
||||
* @param collection 需要转化的集合
|
||||
* @param function collection中的泛型转化为list泛型的lambda表达式
|
||||
* @param <E> collection中的泛型
|
||||
* @param <T> List中的泛型
|
||||
* @return 转化后的list
|
||||
*/
|
||||
public static <E, T> List<T> toList(Collection<E> collection, Function<E, T> function) {
|
||||
if (CollUtil.isEmpty(collection)) {
|
||||
return CollUtil.newArrayList();
|
||||
}
|
||||
return collection
|
||||
.stream()
|
||||
.map(function)
|
||||
.filter(Objects::nonNull)
|
||||
// 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将collection转化为Set集合,但是两者的泛型不同<br>
|
||||
* <B>{@code Collection<E> ------> Set<T> } </B>
|
||||
*
|
||||
* @param collection 需要转化的集合
|
||||
* @param function collection中的泛型转化为set泛型的lambda表达式
|
||||
* @param <E> collection中的泛型
|
||||
* @param <T> Set中的泛型
|
||||
* @return 转化后的Set
|
||||
*/
|
||||
public static <E, T> Set<T> toSet(Collection<E> collection, Function<E, T> function) {
|
||||
if (CollUtil.isEmpty(collection) || function == null) {
|
||||
return CollUtil.newHashSet();
|
||||
}
|
||||
return collection
|
||||
.stream()
|
||||
.map(function)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 合并两个相同key类型的map
|
||||
*
|
||||
* @param map1 第一个需要合并的 map
|
||||
* @param map2 第二个需要合并的 map
|
||||
* @param merge 合并的lambda,将key value1 value2合并成最终的类型,注意value可能为空的情况
|
||||
* @param <K> map中的key类型
|
||||
* @param <X> 第一个 map的value类型
|
||||
* @param <Y> 第二个 map的value类型
|
||||
* @param <V> 最终map的value类型
|
||||
* @return 合并后的map
|
||||
*/
|
||||
public static <K, X, Y, V> Map<K, V> merge(Map<K, X> map1, Map<K, Y> map2, BiFunction<X, Y, V> merge) {
|
||||
if (MapUtil.isEmpty(map1) && MapUtil.isEmpty(map2)) {
|
||||
return MapUtil.newHashMap();
|
||||
} else if (MapUtil.isEmpty(map1)) {
|
||||
map1 = MapUtil.newHashMap();
|
||||
} else if (MapUtil.isEmpty(map2)) {
|
||||
map2 = MapUtil.newHashMap();
|
||||
}
|
||||
Set<K> key = new HashSet<>();
|
||||
key.addAll(map1.keySet());
|
||||
key.addAll(map2.keySet());
|
||||
Map<K, V> map = new HashMap<>();
|
||||
for (K t : key) {
|
||||
X x = map1.get(t);
|
||||
Y y = map2.get(t);
|
||||
V z = merge.apply(x, y);
|
||||
if (z != null) {
|
||||
map.put(t, z);
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,321 @@
|
|||
package cc.iotkit.common.utils;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.lang.Validator;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 字符串工具类
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class StringUtils extends org.apache.commons.lang3.StringUtils {
|
||||
|
||||
public static final String SEPARATOR = ",";
|
||||
|
||||
/**
|
||||
* 获取参数不为空值
|
||||
*
|
||||
* @param str defaultValue 要判断的value
|
||||
* @return value 返回值
|
||||
*/
|
||||
public static String blankToDefault(String str, String defaultValue) {
|
||||
return StrUtil.blankToDefault(str, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* * 判断一个字符串是否为空串
|
||||
*
|
||||
* @param str String
|
||||
* @return true:为空 false:非空
|
||||
*/
|
||||
public static boolean isEmpty(String str) {
|
||||
return StrUtil.isEmpty(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* * 判断一个字符串是否为非空串
|
||||
*
|
||||
* @param str String
|
||||
* @return true:非空串 false:空串
|
||||
*/
|
||||
public static boolean isNotEmpty(String str) {
|
||||
return !isEmpty(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* 去空格
|
||||
*/
|
||||
public static String trim(String str) {
|
||||
return StrUtil.trim(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* 截取字符串
|
||||
*
|
||||
* @param str 字符串
|
||||
* @param start 开始
|
||||
* @return 结果
|
||||
*/
|
||||
public static String substring(final String str, int start) {
|
||||
return substring(str, start, str.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* 截取字符串
|
||||
*
|
||||
* @param str 字符串
|
||||
* @param start 开始
|
||||
* @param end 结束
|
||||
* @return 结果
|
||||
*/
|
||||
public static String substring(final String str, int start, int end) {
|
||||
return StrUtil.sub(str, start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化文本, {} 表示占位符<br>
|
||||
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
|
||||
* 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
|
||||
* 例:<br>
|
||||
* 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br>
|
||||
* 转义{}: format("this is \\{} for {}", "a", "b") -> this is {} for a<br>
|
||||
* 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
|
||||
*
|
||||
* @param template 文本模板,被替换的部分用 {} 表示
|
||||
* @param params 参数值
|
||||
* @return 格式化后的文本
|
||||
*/
|
||||
public static String format(String template, Object... params) {
|
||||
return StrUtil.format(template, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为http(s)://开头
|
||||
*
|
||||
* @param link 链接
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean ishttp(String link) {
|
||||
return Validator.isUrl(link);
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串转set
|
||||
*
|
||||
* @param str 字符串
|
||||
* @param sep 分隔符
|
||||
* @return set集合
|
||||
*/
|
||||
public static Set<String> str2Set(String str, String sep) {
|
||||
return new HashSet<>(str2List(str, sep, true, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串转list
|
||||
*
|
||||
* @param str 字符串
|
||||
* @param sep 分隔符
|
||||
* @param filterBlank 过滤纯空白
|
||||
* @param trim 去掉首尾空白
|
||||
* @return list集合
|
||||
*/
|
||||
public static List<String> str2List(String str, String sep, boolean filterBlank, boolean trim) {
|
||||
List<String> list = new ArrayList<>();
|
||||
if (isEmpty(str)) {
|
||||
return list;
|
||||
}
|
||||
|
||||
// 过滤空白字符串
|
||||
if (filterBlank && isBlank(str)) {
|
||||
return list;
|
||||
}
|
||||
String[] split = str.split(sep);
|
||||
for (String string : split) {
|
||||
if (filterBlank && isBlank(string)) {
|
||||
continue;
|
||||
}
|
||||
if (trim) {
|
||||
string = trim(string);
|
||||
}
|
||||
list.add(string);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写
|
||||
*
|
||||
* @param cs 指定字符串
|
||||
* @param searchCharSequences 需要检查的字符串数组
|
||||
* @return 是否包含任意一个字符串
|
||||
*/
|
||||
public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences) {
|
||||
return StrUtil.containsAnyIgnoreCase(cs, searchCharSequences);
|
||||
}
|
||||
|
||||
/**
|
||||
* 驼峰转下划线命名
|
||||
*/
|
||||
public static String toUnderScoreCase(String str) {
|
||||
return StrUtil.toUnderlineCase(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否包含字符串
|
||||
*
|
||||
* @param str 验证字符串
|
||||
* @param strs 字符串组
|
||||
* @return 包含返回true
|
||||
*/
|
||||
public static boolean inStringIgnoreCase(String str, String... strs) {
|
||||
return StrUtil.equalsAnyIgnoreCase(str, strs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld
|
||||
*
|
||||
* @param name 转换前的下划线大写方式命名的字符串
|
||||
* @return 转换后的驼峰式命名的字符串
|
||||
*/
|
||||
public static String convertToCamelCase(String name) {
|
||||
return StrUtil.upperFirst(StrUtil.toCamelCase(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* 驼峰式命名法 例如:user_name->userName
|
||||
*/
|
||||
public static String toCamelCase(String s) {
|
||||
return StrUtil.toCamelCase(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
|
||||
*
|
||||
* @param str 指定字符串
|
||||
* @param strs 需要检查的字符串数组
|
||||
* @return 是否匹配
|
||||
*/
|
||||
public static boolean matches(String str, List<String> strs) {
|
||||
if (isEmpty(str) || CollUtil.isEmpty(strs)) {
|
||||
return false;
|
||||
}
|
||||
for (String pattern : strs) {
|
||||
if (isMatch(pattern, str)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断url是否与规则配置:
|
||||
* ? 表示单个字符;
|
||||
* * 表示一层路径内的任意字符串,不可跨层级;
|
||||
* ** 表示任意层路径;
|
||||
*
|
||||
* @param pattern 匹配规则
|
||||
* @param url 需要匹配的url
|
||||
*/
|
||||
public static boolean isMatch(String pattern, String url) {
|
||||
AntPathMatcher matcher = new AntPathMatcher();
|
||||
return matcher.match(pattern, url);
|
||||
}
|
||||
|
||||
/**
|
||||
* 数字左边补齐0,使之达到指定长度。注意,如果数字转换为字符串后,长度大于size,则只保留 最后size个字符。
|
||||
*
|
||||
* @param num 数字对象
|
||||
* @param size 字符串指定长度
|
||||
* @return 返回数字的字符串格式,该字符串为指定长度。
|
||||
*/
|
||||
public static String padl(final Number num, final int size) {
|
||||
return padl(num.toString(), size, '0');
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串左补齐。如果原始字符串s长度大于size,则只保留最后size个字符。
|
||||
*
|
||||
* @param s 原始字符串
|
||||
* @param size 字符串指定长度
|
||||
* @param c 用于补齐的字符
|
||||
* @return 返回指定长度的字符串,由原字符串左补齐或截取得到。
|
||||
*/
|
||||
public static String padl(final String s, final int size, final char c) {
|
||||
final StringBuilder sb = new StringBuilder(size);
|
||||
if (s != null) {
|
||||
final int len = s.length();
|
||||
if (s.length() <= size) {
|
||||
sb.append(String.valueOf(c).repeat(size - len));
|
||||
sb.append(s);
|
||||
} else {
|
||||
return s.substring(len - size, len);
|
||||
}
|
||||
} else {
|
||||
sb.append(String.valueOf(c).repeat(Math.max(0, size)));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 切分字符串(分隔符默认逗号)
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @return 分割后的数据列表
|
||||
*/
|
||||
public static List<String> splitList(String str) {
|
||||
return splitTo(str, Convert::toStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 切分字符串
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符
|
||||
* @return 分割后的数据列表
|
||||
*/
|
||||
public static List<String> splitList(String str, String separator) {
|
||||
return splitTo(str, separator, Convert::toStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 切分字符串自定义转换(分隔符默认逗号)
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param mapper 自定义转换
|
||||
* @return 分割后的数据列表
|
||||
*/
|
||||
public static <T> List<T> splitTo(String str, Function<? super Object, T> mapper) {
|
||||
return splitTo(str, SEPARATOR, mapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 切分字符串自定义转换
|
||||
*
|
||||
* @param str 被切分的字符串
|
||||
* @param separator 分隔符
|
||||
* @param mapper 自定义转换
|
||||
* @return 分割后的数据列表
|
||||
*/
|
||||
public static <T> List<T> splitTo(String str, String separator, Function<? super Object, T> mapper) {
|
||||
if (isBlank(str)) {
|
||||
return new ArrayList<>(0);
|
||||
}
|
||||
return StrUtil.split(str, separator)
|
||||
.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(mapper)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package cc.iotkit.common.utils;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.tree.Tree;
|
||||
import cn.hutool.core.lang.tree.TreeNodeConfig;
|
||||
import cn.hutool.core.lang.tree.TreeUtil;
|
||||
import cn.hutool.core.lang.tree.parser.NodeParser;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 扩展 hutool TreeUtil 封装系统树构建
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class TreeBuildUtils extends TreeUtil {
|
||||
|
||||
/**
|
||||
* 根据前端定制差异化字段
|
||||
*/
|
||||
public static final TreeNodeConfig DEFAULT_CONFIG = TreeNodeConfig.DEFAULT_CONFIG.setNameKey("label");
|
||||
|
||||
public static <T, K> List<Tree<K>> build(List<T> list, NodeParser<T, K> nodeParser) {
|
||||
if (CollUtil.isEmpty(list)) {
|
||||
return null;
|
||||
}
|
||||
K k = ReflectUtils.invokeGetter(list.get(0), "parentId");
|
||||
return TreeUtil.build(list, k, DEFAULT_CONFIG, nodeParser);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package cc.iotkit.common.utils;
|
||||
|
||||
import jakarta.validation.ConstraintViolation;
|
||||
import jakarta.validation.ConstraintViolationException;
|
||||
import jakarta.validation.Validator;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Validator 校验框架工具
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class ValidatorUtils {
|
||||
|
||||
private static final Validator VALID = SpringUtils.getBean(Validator.class);
|
||||
|
||||
public static <T> void validate(T object, Class<?>... groups) {
|
||||
Set<ConstraintViolation<T>> validate = VALID.validate(object, groups);
|
||||
if (!validate.isEmpty()) {
|
||||
throw new ConstraintViolationException("参数校验异常", validate);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -7,12 +7,11 @@
|
|||
* | Author: xw2sy@163.com
|
||||
* +----------------------------------------------------------------------
|
||||
*/
|
||||
package cc.iotkit.manager.utils;
|
||||
package cc.iotkit.common.utils;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.bouncycastle.util.Arrays;
|
||||
import org.bouncycastle.util.encoders.Base64;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
|
@ -26,6 +25,7 @@ import java.net.URL;
|
|||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.Key;
|
||||
import java.security.Security;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 微信小程序工具类
|
|
@ -0,0 +1,20 @@
|
|||
package cc.iotkit.common.utils.file;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* 文件处理工具类
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class FileUtils extends FileUtil {
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package cc.iotkit.common.utils.file;
|
||||
|
||||
/**
|
||||
* 媒体类型工具类
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class MimeTypeUtils {
|
||||
public static final String IMAGE_PNG = "image/png";
|
||||
|
||||
public static final String IMAGE_JPG = "image/jpg";
|
||||
|
||||
public static final String IMAGE_JPEG = "image/jpeg";
|
||||
|
||||
public static final String IMAGE_BMP = "image/bmp";
|
||||
|
||||
public static final String IMAGE_GIF = "image/gif";
|
||||
|
||||
public static final String[] IMAGE_EXTENSION = {"bmp", "gif", "jpg", "jpeg", "png"};
|
||||
|
||||
public static final String[] FLASH_EXTENSION = {"swf", "flv"};
|
||||
|
||||
public static final String[] MEDIA_EXTENSION = {"swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg",
|
||||
"asf", "rm", "rmvb"};
|
||||
|
||||
public static final String[] VIDEO_EXTENSION = {"mp4", "avi", "rmvb"};
|
||||
|
||||
public static final String[] DEFAULT_ALLOWED_EXTENSION = {
|
||||
// 图片
|
||||
"bmp", "gif", "jpg", "jpeg", "png",
|
||||
// word excel powerpoint
|
||||
"doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt",
|
||||
// 压缩文件
|
||||
"rar", "zip", "gz", "bz2",
|
||||
// 视频格式
|
||||
"mp4", "avi", "rmvb",
|
||||
// pdf
|
||||
"pdf"};
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package cc.iotkit.common.utils.ip;
|
||||
|
||||
import cc.iotkit.common.utils.StringUtils;
|
||||
import cn.hutool.core.net.NetUtil;
|
||||
import cn.hutool.http.HtmlUtil;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 获取地址类
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
@Slf4j
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class AddressUtils {
|
||||
|
||||
// 未知地址
|
||||
public static final String UNKNOWN = "XX XX";
|
||||
|
||||
public static String getRealAddressByIP(String ip) {
|
||||
if (StringUtils.isBlank(ip)) {
|
||||
return UNKNOWN;
|
||||
}
|
||||
// 内网不查询
|
||||
ip = "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : HtmlUtil.cleanHtmlTag(ip);
|
||||
if (NetUtil.isInnerIP(ip)) {
|
||||
return "内网IP";
|
||||
}
|
||||
return RegionUtils.getCityInfo(ip);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package cc.iotkit.common.utils.ip;
|
||||
|
||||
import cc.iotkit.common.exception.BizException;
|
||||
import cc.iotkit.common.utils.file.FileUtils;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.io.resource.ClassPathResource;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.lionsoul.ip2region.xdb.Searcher;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* 根据ip地址定位工具类,离线方式
|
||||
* 参考地址:<a href="https://gitee.com/lionsoul/ip2region/tree/master/binding/java">集成 ip2region 实现离线IP地址定位库</a>
|
||||
*
|
||||
* @author lishuyan
|
||||
*/
|
||||
@Slf4j
|
||||
public class RegionUtils {
|
||||
|
||||
private static final Searcher SEARCHER;
|
||||
|
||||
static {
|
||||
String fileName = "/ip2region.xdb";
|
||||
File existFile = FileUtils.file(FileUtil.getTmpDir() + FileUtil.FILE_SEPARATOR + fileName);
|
||||
if (!FileUtils.exist(existFile)) {
|
||||
ClassPathResource fileStream = new ClassPathResource(fileName);
|
||||
if (ObjectUtil.isEmpty(fileStream.getStream())) {
|
||||
throw new BizException("RegionUtils初始化失败,原因:IP地址库数据不存在!");
|
||||
}
|
||||
FileUtils.writeFromStream(fileStream.getStream(), existFile);
|
||||
}
|
||||
|
||||
String dbPath = existFile.getPath();
|
||||
|
||||
// 1、从 dbPath 加载整个 xdb 到内存。
|
||||
byte[] cBuff;
|
||||
try {
|
||||
cBuff = Searcher.loadContentFromFile(dbPath);
|
||||
} catch (Exception e) {
|
||||
throw new BizException("RegionUtils初始化失败,原因:从ip2region.xdb文件加载内容失败!" + e.getMessage());
|
||||
}
|
||||
// 2、使用上述的 cBuff 创建一个完全基于内存的查询对象。
|
||||
try {
|
||||
SEARCHER = Searcher.newWithBuffer(cBuff);
|
||||
} catch (Exception e) {
|
||||
throw new BizException("RegionUtils初始化失败,原因:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据IP地址离线获取城市
|
||||
*/
|
||||
public static String getCityInfo(String ip) {
|
||||
try {
|
||||
ip = ip.trim();
|
||||
// 3、执行查询
|
||||
String region = SEARCHER.search(ip);
|
||||
return region.replace("0|", "").replace("|0", "");
|
||||
} catch (Exception e) {
|
||||
log.error("IP地址离线获取城市异常 {}", ip);
|
||||
return "未知";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package cc.iotkit.common.validate;
|
||||
|
||||
/**
|
||||
* 校验分组 add
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
public interface AddGroup {
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package cc.iotkit.common.validate;
|
||||
|
||||
/**
|
||||
* 校验分组 delete
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
public interface DeleteGroup {
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package cc.iotkit.common.validate;
|
||||
|
||||
/**
|
||||
* 校验分组 edit
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
public interface EditGroup {
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package cc.iotkit.common.validate;
|
||||
|
||||
/**
|
||||
* 校验分组 query
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
public interface QueryGroup {
|
||||
}
|
24
iot-data/iot-model/pom.xml → iot-common/iot-common-dao/iot-common-model/pom.xml
Executable file → Normal file
24
iot-data/iot-model/pom.xml → iot-common/iot-common-dao/iot-common-model/pom.xml
Executable file → Normal file
|
@ -3,14 +3,14 @@
|
|||
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">
|
||||
<parent>
|
||||
<artifactId>iot-data</artifactId>
|
||||
<artifactId>iot-common-dao</artifactId>
|
||||
<groupId>cc.iotkit</groupId>
|
||||
<version>0.4.3-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<version>0.4.3-SNAPSHOT</version>
|
||||
<version>${revision}</version>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>iot-model</artifactId>
|
||||
<artifactId>iot-common-model</artifactId>
|
||||
|
||||
<dependencies>
|
||||
|
||||
|
@ -27,8 +27,22 @@
|
|||
|
||||
<dependency>
|
||||
<groupId>cc.iotkit</groupId>
|
||||
<artifactId>iot-common</artifactId>
|
||||
<artifactId>iot-common-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,47 @@
|
|||
package cc.iotkit.model;
|
||||
|
||||
import cc.iotkit.common.utils.MapstructUtils;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Entity基类
|
||||
*
|
||||
* @author Lion Li
|
||||
*/
|
||||
|
||||
@Data
|
||||
public class BaseModel implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 创建部门
|
||||
*/
|
||||
private Long createDept;
|
||||
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private Long createBy;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新者
|
||||
*/
|
||||
private Long updateBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Date updateTime;
|
||||
|
||||
public <T> T to(Class<T> tClass) {
|
||||
return MapstructUtils.convert(this, tClass);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package cc.iotkit.model;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 租户基类
|
||||
*
|
||||
* @author Michelle.Chung
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class TenantModel extends BaseModel {
|
||||
|
||||
/**
|
||||
* 租户编号
|
||||
*/
|
||||
private String tenantId;
|
||||
|
||||
}
|
|
@ -23,8 +23,6 @@ import lombok.NoArgsConstructor;
|
|||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class AlertConfig implements Owned<String> {
|
||||
public static final String TYPE_EMAIL="email";
|
||||
public static final String TYPE_DINGDING_ROBOT="dingding_robot";
|
||||
|
||||
private String id;
|
||||
|
||||
|
@ -34,30 +32,38 @@ public class AlertConfig implements Owned<String> {
|
|||
private String uid;
|
||||
|
||||
/**
|
||||
* 告警器类型
|
||||
* 告警名称
|
||||
*/
|
||||
private String type;
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 告警配置标题
|
||||
* 告警严重度
|
||||
*/
|
||||
private String title;
|
||||
private String level;
|
||||
|
||||
/**
|
||||
* 告警器参数配置
|
||||
* 关联规则引擎ID
|
||||
*/
|
||||
private String config;
|
||||
private String ruleInfoId;
|
||||
|
||||
/**
|
||||
* 告警内容模板
|
||||
* 关联消息转发模板ID
|
||||
*/
|
||||
private String template;
|
||||
private String messageTemplateId;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 是否启用
|
||||
*/
|
||||
private boolean enable;
|
||||
private Boolean enable;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Long createAt;
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* +----------------------------------------------------------------------
|
||||
* | Copyright (c) 奇特物联 2021-2022 All rights reserved.
|
||||
* +----------------------------------------------------------------------
|
||||
* | Licensed 未经许可不能去掉「奇特物联」相关版权
|
||||
* +----------------------------------------------------------------------
|
||||
* | Author: xw2sy@163.com
|
||||
* +----------------------------------------------------------------------
|
||||
*/
|
||||
package cc.iotkit.model.alert;
|
||||
|
||||
import cc.iotkit.model.Owned;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 告警配置
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class AlertRecord implements Owned<String> {
|
||||
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 配置所属用户
|
||||
*/
|
||||
private String uid;
|
||||
|
||||
/**
|
||||
* 告警名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 告警严重度(1-5)
|
||||
*/
|
||||
private String level;
|
||||
|
||||
/**
|
||||
* 告警时间
|
||||
*/
|
||||
private Long alertTime;
|
||||
|
||||
/**
|
||||
* 告警详情
|
||||
*/
|
||||
private String details;
|
||||
|
||||
/**
|
||||
* 是否已读
|
||||
*/
|
||||
private Boolean read;
|
||||
|
||||
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue