fix: 码全代码添加
This commit is contained in:
38
template/cvbp/cvbp-public/.gitignore
vendored
Normal file
38
template/cvbp/cvbp-public/.gitignore
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea/modules.xml
|
||||
.idea/jarRepositories.xml
|
||||
.idea/compiler.xml
|
||||
.idea/libraries/
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### Eclipse ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
### Mac OS ###
|
||||
.DS_Store
|
||||
38
template/cvbp/cvbp-public/cvbp-auth-core/.gitignore
vendored
Normal file
38
template/cvbp/cvbp-public/cvbp-auth-core/.gitignore
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea/modules.xml
|
||||
.idea/jarRepositories.xml
|
||||
.idea/compiler.xml
|
||||
.idea/libraries/
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### Eclipse ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
### Mac OS ###
|
||||
.DS_Store
|
||||
60
template/cvbp/cvbp-public/cvbp-auth-core/pom.xml
Normal file
60
template/cvbp/cvbp-public/cvbp-auth-core/pom.xml
Normal file
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
-->
|
||||
|
||||
<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>
|
||||
<groupId>com.codvision</groupId>
|
||||
<artifactId>cvbp-public</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>cvbp-auth-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.codvision</groupId>
|
||||
<artifactId>cvbp-common-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.codvision</groupId>
|
||||
<artifactId>cvbp-common-feign</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.codvision</groupId>
|
||||
<artifactId>cvbp-cache-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-undertow</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.codvision.authcore.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 权限注解
|
||||
*
|
||||
* @author lingee
|
||||
* @date 2023/7/28
|
||||
*/
|
||||
@Target({ElementType.TYPE, ElementType.METHOD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface RequiresPermissions {
|
||||
|
||||
String value() default "";
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.codvision.authcore.bean;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 组织信息
|
||||
* </p>
|
||||
*
|
||||
* @author lingee
|
||||
* @since 2023-11-10
|
||||
*/
|
||||
@Data
|
||||
@ApiModel(value = "Org", description = "组织信息")
|
||||
public class OrgBean implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("组织id")
|
||||
private Integer oid;
|
||||
|
||||
@ApiModelProperty("名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty("全称")
|
||||
private String fullname;
|
||||
|
||||
@ApiModelProperty("类型")
|
||||
private Integer type;
|
||||
|
||||
@ApiModelProperty("等级")
|
||||
private Short level;
|
||||
|
||||
@ApiModelProperty("父组织编码")
|
||||
private Integer poid;
|
||||
|
||||
private String geom;
|
||||
|
||||
@ApiModelProperty("排序")
|
||||
private Integer orderby;
|
||||
|
||||
@ApiModelProperty("组织路径")
|
||||
private String path;
|
||||
|
||||
@ApiModelProperty("边界数据")
|
||||
private String wkt;
|
||||
|
||||
@ApiModelProperty("组织id路径")
|
||||
private String oidPath;
|
||||
|
||||
private String refOid;
|
||||
|
||||
private String geoJson;
|
||||
|
||||
@ApiModelProperty("备注")
|
||||
private String remark;
|
||||
|
||||
private String refCode;
|
||||
|
||||
@ApiModelProperty("行政区域id")
|
||||
private Integer districtOid;
|
||||
|
||||
@ApiModelProperty("删除标记,1:已删除,0:正常")
|
||||
private Short delFlag;
|
||||
|
||||
@ApiModelProperty("逻辑删除辅助字段")
|
||||
private Integer delKey;
|
||||
|
||||
@ApiModelProperty("专有钉钉部门code")
|
||||
private String zzdOrgCode;
|
||||
|
||||
@ApiModelProperty("创建时间")
|
||||
private Date createTime;
|
||||
|
||||
@ApiModelProperty("更新时间")
|
||||
private Date updateTime;
|
||||
|
||||
@ApiModelProperty("行政区划编码")
|
||||
private String districtCode;
|
||||
|
||||
@ApiModelProperty("组织属性id")
|
||||
private Integer orgPropertyId;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.codvision.authcore.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 分页数据
|
||||
*
|
||||
* @author lingee
|
||||
* @date 2023/9/21
|
||||
*/
|
||||
@Data
|
||||
public class PageData<T> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -6577523148643960799L;
|
||||
|
||||
/**
|
||||
* 总数
|
||||
*/
|
||||
private int total = 0;
|
||||
|
||||
/**
|
||||
* 当前页
|
||||
*/
|
||||
private int page = 1;
|
||||
|
||||
/**
|
||||
* 页大小
|
||||
*/
|
||||
private int size = 20;
|
||||
|
||||
/**
|
||||
* 数据
|
||||
*/
|
||||
private List<T> list;
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.codvision.authcore.bean;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 系统菜单展示信息
|
||||
* </p>
|
||||
*
|
||||
* @author lingee
|
||||
* @since 2023-11-09
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ApiModel(value = "SysMenuVO", description = "系统菜单展示信息")
|
||||
public class SysMenuBean implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("ID")
|
||||
private Integer id;
|
||||
|
||||
@ApiModelProperty("菜单名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty("菜单父id")
|
||||
private Integer pid;
|
||||
|
||||
@ApiModelProperty("菜单权限标识")
|
||||
private String permission;
|
||||
|
||||
@ApiModelProperty("前端路由标识路径")
|
||||
private String url;
|
||||
|
||||
@ApiModelProperty("类型")
|
||||
private Short type;
|
||||
|
||||
@ApiModelProperty("排序值")
|
||||
private Short sortOrder;
|
||||
|
||||
@ApiModelProperty("创建时间")
|
||||
private Date createTime;
|
||||
|
||||
@ApiModelProperty("更新时间")
|
||||
private Date updateTime;
|
||||
|
||||
@ApiModelProperty("删除标记,1:已删除,0:正常")
|
||||
private Short delFlag;
|
||||
|
||||
@ApiModelProperty("逻辑删除辅助字段")
|
||||
private Integer delKey;
|
||||
|
||||
@ApiModelProperty("菜单图标")
|
||||
private String icon;
|
||||
|
||||
@ApiModelProperty("是否隐藏")
|
||||
private Boolean isHidden;
|
||||
|
||||
@ApiModelProperty("组件地址")
|
||||
private String component;
|
||||
|
||||
@ApiModelProperty("布局是否可见")
|
||||
private Boolean layout;
|
||||
|
||||
@ApiModelProperty("跳转地址")
|
||||
private String redirect;
|
||||
|
||||
@ApiModelProperty("目标地址")
|
||||
private String target;
|
||||
|
||||
@ApiModelProperty("所属分类")
|
||||
private String category;
|
||||
|
||||
@ApiModelProperty("是否默认")
|
||||
private Boolean isDefault;
|
||||
|
||||
@ApiModelProperty("菜单路径")
|
||||
private String pathName;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.codvision.authcore.bean;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 系统角色展示信息
|
||||
* </p>
|
||||
*
|
||||
* @author lingee
|
||||
* @since 2023-11-09
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ApiModel(value = "SysRoleVO", description = "系统角色展示信息")
|
||||
public class SysRoleBean implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("ID")
|
||||
private Integer id;
|
||||
|
||||
@ApiModelProperty("角色名称")
|
||||
private String roleName;
|
||||
|
||||
@ApiModelProperty("角色标识")
|
||||
private String roleCode;
|
||||
|
||||
@ApiModelProperty("角色描述")
|
||||
private String roleDesc;
|
||||
|
||||
@ApiModelProperty("数据权限类型")
|
||||
private Short dsType;
|
||||
|
||||
@ApiModelProperty("数据权限作用范围")
|
||||
private Short dsScope;
|
||||
|
||||
@ApiModelProperty("删除标记,1:已删除,0:正常")
|
||||
private Short delFlag;
|
||||
|
||||
@ApiModelProperty("逻辑删除辅助字段")
|
||||
private Short delKey;
|
||||
|
||||
@ApiModelProperty("创建时间")
|
||||
private Date createTime;
|
||||
|
||||
@ApiModelProperty("更新时间")
|
||||
private Date updateTime;
|
||||
|
||||
@ApiModelProperty("是否默认")
|
||||
private Short isDefault;
|
||||
|
||||
@ApiModelProperty("父角色id")
|
||||
private Integer pId;
|
||||
|
||||
@ApiModelProperty("角色等级")
|
||||
private Short level;
|
||||
|
||||
@ApiModelProperty("角色的菜单")
|
||||
private List<SysMenuBean> roleMenus;
|
||||
|
||||
@ApiModelProperty("角色的子角色")
|
||||
private List<SysRoleBean> child = new ArrayList<>();
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.codvision.authcore.bean;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 系统用户展示信息
|
||||
* </p>
|
||||
*
|
||||
* @author lingee
|
||||
* @since 2023-11-09
|
||||
*/
|
||||
@Data
|
||||
@ApiModel(value = "SysUserBean", description = "系统用户展示信息")
|
||||
public class SysUserBean implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String token;
|
||||
|
||||
@ApiModelProperty("ID")
|
||||
private Long id;
|
||||
|
||||
@ApiModelProperty("用户登陆名")
|
||||
private String loginName;
|
||||
|
||||
@ApiModelProperty("登陆密码")
|
||||
private String password;
|
||||
|
||||
@ApiModelProperty("用户真实姓名")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty("用户联系方式")
|
||||
private String mobile;
|
||||
|
||||
@ApiModelProperty("拓展字段:昵称")
|
||||
private String nickname;
|
||||
|
||||
@ApiModelProperty("拓展字段:头像")
|
||||
private String avatarUrl;
|
||||
|
||||
@ApiModelProperty("拓展字段:邮箱")
|
||||
private String email;
|
||||
|
||||
@ApiModelProperty("浙政钉ID")
|
||||
private String zzdId;
|
||||
|
||||
@ApiModelProperty("微信服务号openID")
|
||||
private String wxMpOpenid;
|
||||
|
||||
@ApiModelProperty("删除标记,1:已删除,0:正常")
|
||||
private Short delFlag;
|
||||
|
||||
@ApiModelProperty("逻辑删除辅助字段")
|
||||
private Short delKey;
|
||||
|
||||
@ApiModelProperty("备注")
|
||||
private String remark;
|
||||
|
||||
@ApiModelProperty("创建时间")
|
||||
private Date createTime;
|
||||
|
||||
@ApiModelProperty("更新时间")
|
||||
private Date updateTime;
|
||||
|
||||
@ApiModelProperty("最近一次密码更新的时间")
|
||||
private Date pwdLastUpdatedTime;
|
||||
|
||||
@ApiModelProperty("普通钉钉userid")
|
||||
private String dingTalkUid;
|
||||
|
||||
@ApiModelProperty("微信unionId")
|
||||
private String wxUnionid;
|
||||
|
||||
@ApiModelProperty("微信小程序openID")
|
||||
private String wxMaOpenid;
|
||||
|
||||
@ApiModelProperty("三方同步来的用户唯一id")
|
||||
private String syncId;
|
||||
|
||||
@ApiModelProperty("当前组织OID")
|
||||
private Integer activeOid;
|
||||
|
||||
@ApiModelProperty("当前组织父级OID")
|
||||
private Integer activePoid;
|
||||
|
||||
@ApiModelProperty("当前组织名称")
|
||||
private String activeOrgName;
|
||||
|
||||
@ApiModelProperty("当前组织路径")
|
||||
private String activeOrgPath;
|
||||
|
||||
@ApiModelProperty("当前角色ID")
|
||||
private Integer activeRoleId;
|
||||
|
||||
@ApiModelProperty("当前角色名称")
|
||||
private String activeRoleName;
|
||||
|
||||
@ApiModelProperty("当前角色编码")
|
||||
private String activeRoleCode;
|
||||
|
||||
@ApiModelProperty("关联信息(组织与角色)")
|
||||
private List<UserAssociatedInfoBean> associatedInfos;
|
||||
|
||||
@ApiModelProperty("是否已禁用")
|
||||
private Boolean isForbidden;
|
||||
|
||||
@ApiModelProperty(value = "状态:0未读,1已读")
|
||||
private Integer readStatus;
|
||||
|
||||
@ApiModelProperty(value = "通知消息是否撤回:0否,1是")
|
||||
private Integer flagDel;
|
||||
|
||||
@ApiModelProperty("组织角色")
|
||||
private UserOrgRoleBean activeOrgRole;
|
||||
|
||||
@ApiModelProperty("组织角色列表")
|
||||
private List<UserOrgRoleBean> orgRoles;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.codvision.authcore.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 系统角色展示信息
|
||||
* </p>
|
||||
*
|
||||
* @author lingee
|
||||
* @since 2023-11-09
|
||||
*/
|
||||
@Data
|
||||
public class UserAssociatedInfoBean implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -2558572689076752915L;
|
||||
|
||||
private Integer oid;
|
||||
|
||||
private String orgName;
|
||||
private String orgPath;
|
||||
private Integer orgLevel;
|
||||
|
||||
private Integer roleId;
|
||||
private String roleName;
|
||||
private Integer roleLevel;
|
||||
private String roleCode;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.codvision.authcore.bean;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 组织用户关联信息展示信息
|
||||
* </p>
|
||||
*
|
||||
* @author lingee
|
||||
* @since 2023-11-10
|
||||
*/
|
||||
@Data
|
||||
@ApiModel(value = "UserOrgRoleVO", description = "组织用户关联信息展示信息")
|
||||
public class UserOrgRoleBean implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("用户UID")
|
||||
private Integer uid;
|
||||
|
||||
@ApiModelProperty("组织OID")
|
||||
private Integer oid;
|
||||
|
||||
@ApiModelProperty("角色ID")
|
||||
private Integer roleId;
|
||||
|
||||
@ApiModelProperty("是否开启")
|
||||
private Short flagEnabled;
|
||||
|
||||
@ApiModelProperty("排序字段")
|
||||
private Integer orderby;
|
||||
|
||||
@ApiModelProperty("角色编码")
|
||||
private String roleCode;
|
||||
|
||||
@ApiModelProperty("更新时间")
|
||||
private Date updateTime;
|
||||
|
||||
@ApiModelProperty("组织信息")
|
||||
private OrgBean org;
|
||||
|
||||
@ApiModelProperty("角色信息")
|
||||
private SysRoleBean role;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.codvision.authcore.config;
|
||||
|
||||
import com.codvision.authcore.interceptor.AuthInterceptor;
|
||||
import com.codvision.authcore.service.IAuthService;
|
||||
import com.codvision.authcore.service.impl.AuthService;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 认证配置类
|
||||
*
|
||||
* @author lingee
|
||||
* @date 2023/7/19
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnProperty(value = "cvbp.auth.enabled", havingValue = "true", matchIfMissing = true)
|
||||
public class AuthConfig implements WebMvcConfigurer {
|
||||
|
||||
@Resource
|
||||
private AuthProperties authProperties;
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(authInterceptor())
|
||||
.excludePathPatterns("/v1/sysUser/login",
|
||||
"/v1/sysUser/verifyCode",
|
||||
"/v1/sysUser/loginByMobile",
|
||||
"/v1/sysUser/loginSignature",
|
||||
"/v1/manager/sysConfig/getListByKeys",
|
||||
"/v1/manager/sysFile/preview/**",
|
||||
"/v1/manager/sysFile/download/**",
|
||||
"/v1/manager/website/addRecord",
|
||||
"/customCaptcha/get",
|
||||
"/captcha/get",
|
||||
"/captcha/check",
|
||||
"/backend/**",
|
||||
"/**/error",
|
||||
"/**/doc.*",
|
||||
"/**/swagger-ui.*",
|
||||
"/swagger-resources/**",
|
||||
"/**/webjars/**",
|
||||
"/favicon.ico",
|
||||
"/**/v2/api-docs/**")
|
||||
.addPathPatterns(authProperties.getIncludes());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "authCenterConfig")
|
||||
public IAuthService authService() {
|
||||
return new AuthService();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public AuthInterceptor authInterceptor() {
|
||||
return new AuthInterceptor();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.codvision.authcore.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 认证配置属性
|
||||
*
|
||||
* @author lingee
|
||||
* @date 2023/7/25
|
||||
*/
|
||||
@Data
|
||||
@Configuration
|
||||
@ConfigurationProperties("cvbp.auth")
|
||||
public class AuthProperties {
|
||||
|
||||
/**
|
||||
* 未授权登录跳转地址
|
||||
*/
|
||||
public String authRedirectUrl = "";
|
||||
|
||||
/**
|
||||
* 是否开启
|
||||
*/
|
||||
public Boolean enabled = true;
|
||||
|
||||
/**
|
||||
* 登录地址
|
||||
*/
|
||||
private String host = "";
|
||||
|
||||
/**
|
||||
* token名称
|
||||
*/
|
||||
private String tokenName = "Authorization";
|
||||
|
||||
/**
|
||||
* cookie名称
|
||||
*/
|
||||
private String cookieName = "Authorization";
|
||||
|
||||
/**
|
||||
* 排除地址
|
||||
*/
|
||||
private String excludes = "";
|
||||
|
||||
/**
|
||||
* 拦截地址
|
||||
*/
|
||||
private String includes = "/**";
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.codvision.authcore.constants;
|
||||
|
||||
/**
|
||||
* 认证模块常量类
|
||||
*
|
||||
* @author lingee
|
||||
* @date 2023/11/22
|
||||
*/
|
||||
public final class AuthCoreConstant {
|
||||
|
||||
/**
|
||||
* 用户信息缓存
|
||||
*/
|
||||
public static final String LOGIN_USER_EXPIRE_PREFIX = "user:auth:";
|
||||
|
||||
/**
|
||||
* 用户权限缓存
|
||||
*/
|
||||
public static final String LOGIN_USER_PERMISSION_EXPIRE_PREFIX = "user:permission:";
|
||||
|
||||
/**
|
||||
* 页面嵌入标识
|
||||
*/
|
||||
public static final String IframeDownFlag = "iframeDown";
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.codvision.authcore.interceptor;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.codvision.authcore.annotation.RequiresPermissions;
|
||||
import com.codvision.authcore.bean.SysMenuBean;
|
||||
import com.codvision.authcore.bean.SysUserBean;
|
||||
import com.codvision.authcore.config.AuthProperties;
|
||||
import com.codvision.authcore.constants.AuthCoreConstant;
|
||||
import com.codvision.authcore.service.IAuthService;
|
||||
import com.codvision.authcore.util.RequestUtil;
|
||||
import com.codvision.commoncore.exception.AuthException;
|
||||
import com.codvision.commoncore.exception.PermissionException;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 认证拦截器
|
||||
*
|
||||
* @author lingee
|
||||
* @date 2023/8/3
|
||||
*/
|
||||
public class AuthInterceptor implements HandlerInterceptor {
|
||||
|
||||
@Resource
|
||||
private AuthProperties authProperties;
|
||||
|
||||
@Resource
|
||||
private IAuthService authService;
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
|
||||
final String path = request.getServletPath();
|
||||
|
||||
if (RequestUtil.isExcludedUri(path, authProperties.getExcludes())) {
|
||||
return true;
|
||||
}
|
||||
final String token = authService.getAuthToken(request);
|
||||
Optional.ofNullable(token).orElseThrow(() -> new AuthException(10002));
|
||||
|
||||
SysUserBean sysUser = authService.getCurrentUserInfo(token);
|
||||
Optional.ofNullable(sysUser).orElseThrow(() -> new AuthException(10002));
|
||||
|
||||
if (handler.getClass().isAssignableFrom(HandlerMethod.class)) {
|
||||
RequiresPermissions permissions = getRequiresPermissions((HandlerMethod) handler);
|
||||
if (ObjectUtil.isEmpty(permissions)) {
|
||||
return true;
|
||||
}
|
||||
String code = permissions.value();
|
||||
if (StrUtil.isNotBlank(code)) {
|
||||
Optional.ofNullable(sysUser.getActiveRoleId()).orElseThrow(() -> new PermissionException("当前用户无授权角色"));
|
||||
|
||||
List<SysMenuBean> sysMenus = authService.getMenuList(token);
|
||||
if (CollectionUtils.isEmpty(sysMenus)) {
|
||||
throw new PermissionException("当前用户无菜单权限");
|
||||
}
|
||||
if (sysMenus.stream().filter(x -> code.equals(x.getPermission())).count() == 0) {
|
||||
throw new PermissionException("当前用户无访问权限");
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取hander上的RequiresPermissions注解
|
||||
*
|
||||
* @param handler 处理对象
|
||||
* @return 注解
|
||||
*/
|
||||
private RequiresPermissions getRequiresPermissions(HandlerMethod handler) {
|
||||
RequiresPermissions requiresPermissions = handler.getMethodAnnotation(RequiresPermissions.class);
|
||||
if (ObjectUtils.isEmpty(requiresPermissions)) {
|
||||
requiresPermissions = AnnotatedElementUtils.getMergedAnnotation(handler.getBean().getClass(), RequiresPermissions.class);
|
||||
}
|
||||
return requiresPermissions;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 统一认证模块
|
||||
*
|
||||
* @author lingee
|
||||
* @date 2023/7/17
|
||||
*/
|
||||
package com.codvision.authcore;
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.codvision.authcore.remote;
|
||||
|
||||
import com.codvision.authcore.bean.PageData;
|
||||
import com.codvision.authcore.bean.SysMenuBean;
|
||||
import com.codvision.authcore.bean.SysUserBean;
|
||||
import com.codvision.authcore.remote.fallback.RemoteAuthServiceFallback;
|
||||
import com.codvision.commoncore.common.ResponseEntity;
|
||||
import com.codvision.commonfeign.config.OpenFeignConfig;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
/**
|
||||
* 认证服务远程调用
|
||||
*
|
||||
* @author lingee
|
||||
* @date 2023/7/18
|
||||
*/
|
||||
@FeignClient(name = "remote-auth-sevice", url = "${cvbp.auth.host}", fallback = RemoteAuthServiceFallback.class,
|
||||
configuration = OpenFeignConfig.class)
|
||||
public interface RemoteAuthService {
|
||||
|
||||
/**
|
||||
* 获取当前登录用户信息
|
||||
*
|
||||
* @param token token
|
||||
* @return 用户信息
|
||||
*/
|
||||
@PostMapping("/sysUser/getUserInfo")
|
||||
ResponseEntity<SysUserBean> getUserInfo(@RequestHeader(value = "Authorization") String token);
|
||||
|
||||
/**
|
||||
* 获取权限菜单列表
|
||||
*
|
||||
* @param page 当前页
|
||||
* @param size 页面大小lø
|
||||
* @return 菜单列表
|
||||
*/
|
||||
@PostMapping("/findAll")
|
||||
ResponseEntity<PageData<SysMenuBean>> getUserMenus(@RequestHeader(value = "Authorization") String token,
|
||||
@RequestParam(value = "page", required = false, defaultValue = "1") int page,
|
||||
@RequestParam(value = "size", required = false, defaultValue = "1000") int size);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.codvision.authcore.remote.fallback;
|
||||
|
||||
import com.codvision.authcore.bean.PageData;
|
||||
import com.codvision.authcore.bean.SysMenuBean;
|
||||
import com.codvision.authcore.bean.SysUserBean;
|
||||
import com.codvision.authcore.remote.RemoteAuthService;
|
||||
import com.codvision.commoncore.common.ResponseEntity;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 认证服务调用反馈
|
||||
*
|
||||
* @author lingee
|
||||
* @date 2023/7/19
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class RemoteAuthServiceFallback implements RemoteAuthService {
|
||||
|
||||
|
||||
private ResponseEntity failResponse() {
|
||||
ResponseEntity response = new ResponseEntity();
|
||||
response.error(990000).message("认证服务调用失败");
|
||||
log.error(response.getMessage());
|
||||
return response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<SysUserBean> getUserInfo(String token) {
|
||||
return failResponse();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResponseEntity<PageData<SysMenuBean>> getUserMenus(String token, int page, int size) {
|
||||
return failResponse();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.codvision.authcore.service;
|
||||
|
||||
import com.codvision.authcore.bean.SysMenuBean;
|
||||
import com.codvision.authcore.bean.SysUserBean;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 认证接口
|
||||
*
|
||||
* @author lingee
|
||||
* @date 2023/7/18
|
||||
*/
|
||||
public interface IAuthService {
|
||||
|
||||
/**
|
||||
* 获取当前登录用户信息
|
||||
*
|
||||
* @param token token
|
||||
* @return 用户
|
||||
*/
|
||||
SysUserBean getCurrentUserInfo(String token);
|
||||
|
||||
/**
|
||||
* 获取上下文的token信息
|
||||
*
|
||||
* @param request 请求
|
||||
* @return token
|
||||
*/
|
||||
String getAuthToken(HttpServletRequest request);
|
||||
|
||||
/**
|
||||
* 获取菜单列表
|
||||
*
|
||||
* @param token token
|
||||
* @return 菜单列表
|
||||
*/
|
||||
List<SysMenuBean> getMenuList(String token);
|
||||
|
||||
/**
|
||||
* 根据用户名密码登录
|
||||
*
|
||||
* @param username 用户名
|
||||
* @param password 密码
|
||||
* @return 登录用户信息
|
||||
*/
|
||||
SysUserBean loginByUsernameAndPassword(String username, String password);
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.codvision.authcore.service.impl;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.codvision.authcore.bean.PageData;
|
||||
import com.codvision.authcore.bean.SysMenuBean;
|
||||
import com.codvision.authcore.bean.SysUserBean;
|
||||
import com.codvision.authcore.config.AuthProperties;
|
||||
import com.codvision.authcore.remote.RemoteAuthService;
|
||||
import com.codvision.authcore.service.IAuthService;
|
||||
import com.codvision.authcore.util.RequestUtil;
|
||||
import com.codvision.cachecore.utils.RedisUtil;
|
||||
import com.codvision.commoncore.common.ResponseEntity;
|
||||
import com.codvision.commoncore.utils.ResponseUtil;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
|
||||
import static com.codvision.authcore.constants.AuthCoreConstant.IframeDownFlag;
|
||||
import static com.codvision.authcore.constants.AuthCoreConstant.LOGIN_USER_EXPIRE_PREFIX;
|
||||
|
||||
/**
|
||||
* 认证服务
|
||||
*
|
||||
* @author lingee
|
||||
* @date 2023/7/17
|
||||
*/
|
||||
public class AuthService implements IAuthService {
|
||||
|
||||
@Resource
|
||||
private RemoteAuthService remoteAuthService;
|
||||
|
||||
@Resource
|
||||
private AuthProperties authProperties;
|
||||
|
||||
@Override
|
||||
public SysUserBean getCurrentUserInfo(String token) {
|
||||
String key = LOGIN_USER_EXPIRE_PREFIX + token;
|
||||
if (RedisUtil.hasKey(key)) {
|
||||
SysUserBean sysUser = RedisUtil.get(key);
|
||||
if (ObjectUtil.isNotEmpty(sysUser)) {
|
||||
return sysUser;
|
||||
}
|
||||
}
|
||||
|
||||
ResponseEntity<SysUserBean> response = remoteAuthService.getUserInfo(token);
|
||||
if (!ResponseUtil.isSuccess(response)) {
|
||||
return null;
|
||||
}
|
||||
SysUserBean sysUser = response.getData();
|
||||
RedisUtil.set(key, sysUser);
|
||||
return sysUser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthToken(HttpServletRequest request) {
|
||||
String tokenName = authProperties.getTokenName();
|
||||
String cookieName = authProperties.getCookieName();
|
||||
String token = request.getParameter(tokenName);
|
||||
|
||||
if (StrUtil.isNotBlank(token)) {
|
||||
return token;
|
||||
}
|
||||
|
||||
token = RequestUtil.getFromCookie(request, cookieName);
|
||||
if (StrUtil.isNotBlank(token)) {
|
||||
return token;
|
||||
}
|
||||
|
||||
token = request.getHeader(tokenName);
|
||||
if (StrUtil.isNotBlank(token)) {
|
||||
return token;
|
||||
}
|
||||
|
||||
final String iframeDown = request.getParameter(IframeDownFlag);
|
||||
if (StrUtil.isNotBlank(iframeDown)) {
|
||||
token = request.getParameter(tokenName);
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SysMenuBean> getMenuList(String token) {
|
||||
ResponseEntity<PageData<SysMenuBean>> response = remoteAuthService.getUserMenus(token, 1, 10000);
|
||||
if (!ResponseUtil.isSuccess(response)) {
|
||||
return null;
|
||||
}
|
||||
PageData<SysMenuBean> data = response.getData();
|
||||
return data.getList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SysUserBean loginByUsernameAndPassword(String username, String password) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.codvision.authcore.util;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import com.codvision.authcore.bean.SysUserBean;
|
||||
import com.codvision.authcore.service.IAuthService;
|
||||
import com.codvision.commoncore.exception.AuthException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 认证工具类
|
||||
*
|
||||
* @author lingee
|
||||
* @date 2023/7/18
|
||||
*/
|
||||
public class AuthUtil {
|
||||
|
||||
/**
|
||||
* 获取token
|
||||
*
|
||||
* @return token
|
||||
*/
|
||||
public static String getToken() {
|
||||
ApplicationContext context = SpringUtil.getApplicationContext();
|
||||
if (!context.containsBean("authService")) {
|
||||
return null;
|
||||
}
|
||||
IAuthService authService = SpringUtil.getBean(IAuthService.class);
|
||||
return authService.getAuthToken(RequestUtil.getRequest());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取当前登录用户信息
|
||||
*
|
||||
* @return 用户信息
|
||||
*/
|
||||
public static SysUserBean getCurrentUser() {
|
||||
ApplicationContext context = SpringUtil.getApplicationContext();
|
||||
if (!context.containsBean("authService")) {
|
||||
return new SysUserBean();
|
||||
}
|
||||
IAuthService authService = SpringUtil.getBean(IAuthService.class);
|
||||
String token = authService.getAuthToken(RequestUtil.getRequest());
|
||||
Optional.ofNullable(token).orElseThrow(() -> new AuthException(10002));
|
||||
SysUserBean sysUser = authService.getCurrentUserInfo(token);
|
||||
Optional.ofNullable(sysUser).orElseThrow(() -> new AuthException(10002));
|
||||
return sysUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否已登录
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static boolean isLogin() {
|
||||
ApplicationContext context = SpringUtil.getApplicationContext();
|
||||
if (!context.containsBean("authService")) {
|
||||
return false;
|
||||
}
|
||||
IAuthService authService = SpringUtil.getBean(IAuthService.class);
|
||||
String token = authService.getAuthToken(RequestUtil.getRequest());
|
||||
if (StrUtil.isBlank(token)) {
|
||||
return false;
|
||||
}
|
||||
SysUserBean sysUser = authService.getCurrentUserInfo(token);
|
||||
if (ObjectUtil.isEmpty(sysUser)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
package com.codvision.authcore.util;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.PathMatcher;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 请求工具类
|
||||
*
|
||||
* @author lingee
|
||||
* @date 2023/7/18
|
||||
*/
|
||||
public class RequestUtil {
|
||||
|
||||
public static final String ClientIp = "client-ip";
|
||||
|
||||
public static String getIp() {
|
||||
final HttpServletRequest httpServletRequest = getRequest();
|
||||
if (httpServletRequest == null) {
|
||||
return null;
|
||||
}
|
||||
return getIp(httpServletRequest);
|
||||
}
|
||||
|
||||
public static String getFromHead(String name) {
|
||||
if (StrUtil.isBlank(name)) {
|
||||
return null;
|
||||
}
|
||||
final HttpServletRequest httpServletRequest = getRequest();
|
||||
if (httpServletRequest == null) {
|
||||
return null;
|
||||
}
|
||||
return httpServletRequest.getHeader(name);
|
||||
}
|
||||
|
||||
public static String getFromCookie(HttpServletRequest request, String cookieName) {
|
||||
Cookie cookie = ServletUtil.getCookie(request, cookieName);
|
||||
if (cookie != null) {
|
||||
return cookie.getValue();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String getIp(HttpServletRequest httpServletRequest) {
|
||||
String ip = httpServletRequest.getHeader(ClientIp);
|
||||
if (StrUtil.isBlank(ip)) {
|
||||
ip = ServletUtil.getClientIP(httpServletRequest);
|
||||
}
|
||||
return ip;
|
||||
}
|
||||
|
||||
public static String getRequestPath() {
|
||||
final HttpServletRequest httpServletRequest = getRequest();
|
||||
if (httpServletRequest == null) {
|
||||
return null;
|
||||
}
|
||||
return httpServletRequest.getServletPath();
|
||||
}
|
||||
|
||||
public static String getContextPath() {
|
||||
final HttpServletRequest request = getRequest();
|
||||
if (request == null) {
|
||||
return "/";
|
||||
}
|
||||
return request.getContextPath();
|
||||
}
|
||||
|
||||
public static HttpServletRequest getRequest() {
|
||||
RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
|
||||
if (attrs == null) {
|
||||
return null;
|
||||
}
|
||||
final ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) attrs;
|
||||
return servletRequestAttributes.getRequest();
|
||||
}
|
||||
|
||||
private static String getStrFromRequest(final String key) {
|
||||
final Object v = getObject(key);
|
||||
if (v == null) {
|
||||
return null;
|
||||
}
|
||||
return Objects.toString(v);
|
||||
}
|
||||
|
||||
public static <T> T getObject(final String key) {
|
||||
RequestAttributes attrs = RequestContextHolder.getRequestAttributes();
|
||||
if (attrs == null) {
|
||||
return null;
|
||||
}
|
||||
Object obj = attrs.getAttribute(key, RequestAttributes.SCOPE_REQUEST);
|
||||
if (obj == null) {
|
||||
return null;
|
||||
}
|
||||
return (T) obj;
|
||||
}
|
||||
|
||||
public static <T> void setObject(final HttpServletRequest request, final String key, final T obj) {
|
||||
request.setAttribute(key, obj);
|
||||
}
|
||||
|
||||
public static boolean isExcludedUri(String uri, String excludedUris) {
|
||||
if (StringUtils.isBlank(uri) || StringUtils.isBlank(excludedUris)) {
|
||||
return false;
|
||||
}
|
||||
PathMatcher matcher = new AntPathMatcher();
|
||||
for (String ex : excludedUris.split(",")) {
|
||||
uri = uri.trim();
|
||||
ex = ex.trim();
|
||||
if (matcher.match(ex.toLowerCase(), uri.toLowerCase())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.codvision.authcore.config.AuthConfig,\
|
||||
com.codvision.authcore.config.AuthProperties
|
||||
38
template/cvbp/cvbp-public/cvbp-cache-core/.gitignore
vendored
Normal file
38
template/cvbp/cvbp-public/cvbp-cache-core/.gitignore
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea/modules.xml
|
||||
.idea/jarRepositories.xml
|
||||
.idea/compiler.xml
|
||||
.idea/libraries/
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### Eclipse ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
### Mac OS ###
|
||||
.DS_Store
|
||||
69
template/cvbp/cvbp-public/cvbp-cache-core/pom.xml
Normal file
69
template/cvbp/cvbp-public/cvbp-cache-core/pom.xml
Normal file
@@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
-->
|
||||
|
||||
<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>
|
||||
<groupId>com.codvision</groupId>
|
||||
<artifactId>cvbp-public</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>cvbp-cache-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>io.lettuce</groupId>
|
||||
<artifactId>lettuce-core</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>redis.clients</groupId>
|
||||
<artifactId>jedis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.redisson</groupId>
|
||||
<artifactId>redisson</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<groupId>org.slf4j</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-crypto</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-extra</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.codvision.cachecore.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 缓存属性配置
|
||||
*
|
||||
* @author lingee
|
||||
* @date 2023/7/26
|
||||
*/
|
||||
@Data
|
||||
@Configuration
|
||||
@ConfigurationProperties("cvbp.cache")
|
||||
public class CacheProperties {
|
||||
|
||||
/**
|
||||
* 缓存
|
||||
*/
|
||||
private Boolean enabled = false;
|
||||
|
||||
/**
|
||||
* 缓存类型
|
||||
*/
|
||||
private String type = "redis";
|
||||
|
||||
/**
|
||||
* 缓存超时时间(单位:秒)
|
||||
*/
|
||||
private Long timeout = 3600 * 24L;
|
||||
|
||||
/**
|
||||
* redisson是否开启
|
||||
*/
|
||||
private Boolean redisson = false;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
package com.codvision.cachecore.config;
|
||||
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import cn.hutool.crypto.digest.DigestUtil;
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.MapperFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.redisson.Redisson;
|
||||
import org.redisson.api.RedissonClient;
|
||||
import org.redisson.config.ClusterServersConfig;
|
||||
import org.redisson.config.Config;
|
||||
import org.redisson.config.SentinelServersConfig;
|
||||
import org.redisson.config.SingleServerConfig;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.annotation.CachingConfigurerSupport;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.cache.interceptor.CacheErrorHandler;
|
||||
import org.springframework.cache.interceptor.KeyGenerator;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.data.redis.cache.RedisCacheConfiguration;
|
||||
import org.springframework.data.redis.cache.RedisCacheManager;
|
||||
import org.springframework.data.redis.cache.RedisCacheWriter;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.RedisSerializationContext;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 自定义redis配置
|
||||
*
|
||||
* @author lingee
|
||||
* @since 2023/7/26
|
||||
*/
|
||||
@Slf4j
|
||||
@EnableCaching
|
||||
@Configuration
|
||||
@ConditionalOnExpression(value = "${cvbp.cache.enabled:true}")
|
||||
@ConditionalOnProperty(value = "cvbp.cache.type", havingValue = "redis")
|
||||
public class RedisConfig extends CachingConfigurerSupport {
|
||||
|
||||
private static final String REDIS_PREFIX = "redis://";
|
||||
|
||||
@Resource
|
||||
private CacheProperties cacheProperties;
|
||||
|
||||
@Resource
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
/**
|
||||
* 缓存json序列化配置
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private Jackson2JsonRedisSerializer jackson2JsonRedisSerializer() {
|
||||
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
||||
objectMapper.configure(MapperFeature.USE_ANNOTATIONS, false);
|
||||
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
|
||||
|
||||
//此项必须配置,否则会报java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to XXX
|
||||
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL,
|
||||
JsonTypeInfo.As.PROPERTY);
|
||||
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
|
||||
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
|
||||
return jackson2JsonRedisSerializer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当有多个管理器的时候,必须使用该注解在一个管理器上注释:表示该管理器为默认的管理器
|
||||
*
|
||||
* @param connectionFactory 链接工厂
|
||||
* @return 缓存
|
||||
*/
|
||||
@Bean
|
||||
@Primary
|
||||
public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
|
||||
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
|
||||
|
||||
RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
|
||||
.entryTtl(Duration.ofSeconds(cacheProperties.getTimeout()))
|
||||
.disableCachingNullValues()
|
||||
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
|
||||
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer()));
|
||||
|
||||
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory);
|
||||
RedisCacheManager cacheManager = new RedisCacheManager(redisCacheWriter, cacheConfiguration);
|
||||
return cacheManager;
|
||||
}
|
||||
|
||||
@Bean(destroyMethod = "shutdown")
|
||||
@ConditionalOnProperty(value = "cvbp.cache.redisson", havingValue = "true")
|
||||
public RedissonClient redisson(RedisProperties redisProperties) {
|
||||
Config config = new Config();
|
||||
if (redisProperties.getSentinel() != null && !redisProperties.getSentinel().getNodes().isEmpty()) {
|
||||
// 哨兵模式
|
||||
SentinelServersConfig sentinelServersConfig = config.useSentinelServers();
|
||||
sentinelServersConfig.setMasterName(redisProperties.getSentinel().getMaster());
|
||||
List<String> sentinelAddress = new ArrayList<>();
|
||||
for (String node : redisProperties.getCluster().getNodes()) {
|
||||
sentinelAddress.add(REDIS_PREFIX + node);
|
||||
}
|
||||
sentinelServersConfig.setSentinelAddresses(sentinelAddress);
|
||||
if (CharSequenceUtil.isNotEmpty(redisProperties.getSentinel().getPassword())) {
|
||||
sentinelServersConfig.setSentinelPassword(redisProperties.getSentinel().getPassword());
|
||||
}
|
||||
} else if (redisProperties.getCluster() != null && !redisProperties.getCluster().getNodes().isEmpty()) {
|
||||
// 集群模式
|
||||
ClusterServersConfig clusterServersConfig = config.useClusterServers();
|
||||
List<String> clusterNodes = new ArrayList<>();
|
||||
for (String node : redisProperties.getCluster().getNodes()) {
|
||||
clusterNodes.add(REDIS_PREFIX + node);
|
||||
}
|
||||
clusterServersConfig.setNodeAddresses(clusterNodes);
|
||||
if (CharSequenceUtil.isNotEmpty(redisProperties.getPassword())) {
|
||||
clusterServersConfig.setPassword(redisProperties.getPassword());
|
||||
}
|
||||
} else {
|
||||
SingleServerConfig singleServerConfig = config.useSingleServer();
|
||||
singleServerConfig.setAddress(REDIS_PREFIX + redisProperties.getHost() + ":" + redisProperties.getPort());
|
||||
if (CharSequenceUtil.isNotEmpty(redisProperties.getPassword())) {
|
||||
singleServerConfig.setPassword(redisProperties.getPassword());
|
||||
}
|
||||
singleServerConfig.setPingConnectionInterval(1000);
|
||||
}
|
||||
|
||||
return Redisson.create(config);
|
||||
}
|
||||
|
||||
@Primary
|
||||
@Bean(name = "redisTemplate")
|
||||
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
|
||||
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
|
||||
redisTemplate.setConnectionFactory(connectionFactory);
|
||||
// 使用Jackson2JsonRedisSerialize 替换默认序列化(默认采用的是JDK序列化)
|
||||
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
|
||||
ObjectMapper om = new ObjectMapper();
|
||||
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
||||
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
|
||||
jackson2JsonRedisSerializer.setObjectMapper(om);
|
||||
// redisTemplate.setKeySerializer(jackson2JsonRedisSerializer);
|
||||
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
|
||||
// redisTemplate.setHashKeySerializer(jackson2JsonRedisSerializer);
|
||||
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
|
||||
|
||||
//key的序列化采用StringRedisSerializer
|
||||
redisTemplate.setKeySerializer(new StringRedisSerializer());
|
||||
redisTemplate.setHashKeySerializer(jackson2JsonRedisSerializer);
|
||||
return redisTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义缓存key生成策略,默认将使用该策略
|
||||
*/
|
||||
@Bean(name = "cacheKeyGenerator")
|
||||
@Override
|
||||
public KeyGenerator keyGenerator() {
|
||||
return (target, method, params) -> {
|
||||
Map<String, Object> container = new HashMap<>(3);
|
||||
Class<?> targetClassClass = target.getClass();
|
||||
//类地址
|
||||
container.put("class", targetClassClass.toGenericString());
|
||||
//方法名称
|
||||
container.put("methodName", method.getName());
|
||||
//包名称
|
||||
container.put("package", targetClassClass.getPackage());
|
||||
//参数列表
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
container.put(String.valueOf(i), params[i]);
|
||||
}
|
||||
//转为JSON字符串
|
||||
String jsonString;
|
||||
try {
|
||||
jsonString = objectMapper.writeValueAsString(container);
|
||||
} catch (JsonProcessingException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
//做SHA256 Hash计算,得到一个SHA256摘要作为Key
|
||||
return DigestUtil.sha256Hex(jsonString);
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
public CacheErrorHandler errorHandler() {
|
||||
//异常处理,当Redis发生异常时,打印日志,但是程序正常走
|
||||
log.info("初始化 -> [{}]", "Redis CacheErrorHandler");
|
||||
return new CacheErrorHandler() {
|
||||
@Override
|
||||
public void handleCacheGetError(RuntimeException e, Cache cache, Object key) {
|
||||
log.error("Redis occur handleCacheGetError:key -> [{}]", key, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCachePutError(RuntimeException e, Cache cache, Object key, Object value) {
|
||||
log.error("Redis occur handleCachePutError:key -> [{}];value -> [{}]", key, value, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCacheEvictError(RuntimeException e, Cache cache, Object key) {
|
||||
log.error("Redis occur handleCacheEvictError:key -> [{}]", key, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCacheClearError(RuntimeException e, Cache cache) {
|
||||
log.error("Redis occur handleCacheClearError:", e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 缓存模块
|
||||
*
|
||||
* @author lingee
|
||||
* @date 2023/7/26
|
||||
*/
|
||||
package com.codvision.cachecore;
|
||||
@@ -0,0 +1,718 @@
|
||||
package com.codvision.cachecore.utils;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import com.codvision.cachecore.config.CacheProperties;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import org.springframework.data.redis.connection.RedisConnection;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.core.*;
|
||||
import org.springframework.data.redis.core.script.DefaultRedisScript;
|
||||
import org.springframework.data.redis.core.script.RedisScript;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 缓存工具类
|
||||
*
|
||||
* @author lingee
|
||||
* @date 2023/7/27
|
||||
*/
|
||||
@UtilityClass
|
||||
public class RedisUtil {
|
||||
|
||||
private static final Long SUCCESS = 1L;
|
||||
|
||||
/**
|
||||
* 指定缓存失效时间
|
||||
*
|
||||
* @param key 键
|
||||
* @param time 时间(秒)
|
||||
*/
|
||||
public boolean expire(String key, long time) {
|
||||
RedisTemplate<Object, Object> redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
Optional.ofNullable(redisTemplate)
|
||||
.filter(template -> time > 0)
|
||||
.ifPresent(template -> template.expire(key, time, TimeUnit.SECONDS));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定缓存失效时间
|
||||
*
|
||||
* @param key 键
|
||||
* @param time 时间
|
||||
* @param timeUnit 时间单位
|
||||
*/
|
||||
public boolean expire(String key, long time, TimeUnit timeUnit) {
|
||||
RedisTemplate<Object, Object> redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
Optional.ofNullable(redisTemplate)
|
||||
.filter(template -> time > 0)
|
||||
.ifPresent(template -> template.expire(key, time, timeUnit));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据 key 获取过期时间
|
||||
*
|
||||
* @param key 键 不能为null
|
||||
* @return 时间(秒) 返回0代表为永久有效
|
||||
*/
|
||||
public long getExpire(Object key) {
|
||||
RedisTemplate<Object, Object> redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
return Optional.ofNullable(redisTemplate)
|
||||
.map(template -> template.getExpire(key, TimeUnit.SECONDS))
|
||||
.orElse(-1L);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找匹配key
|
||||
*
|
||||
* @param pattern key
|
||||
* @return /
|
||||
*/
|
||||
public List<String> scan(String pattern) {
|
||||
RedisTemplate<Object, Object> redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
ScanOptions options = ScanOptions.scanOptions().match(pattern).build();
|
||||
return Optional.ofNullable(redisTemplate).map(template -> {
|
||||
RedisConnectionFactory factory = template.getConnectionFactory();
|
||||
RedisConnection rc = Objects.requireNonNull(factory).getConnection();
|
||||
Cursor<byte[]> cursor = rc.scan(options);
|
||||
List<String> result = new ArrayList<>();
|
||||
while (cursor.hasNext()) {
|
||||
result.add(new String(cursor.next()));
|
||||
}
|
||||
RedisConnectionUtils.releaseConnection(rc, factory);
|
||||
return result;
|
||||
}).orElse(Collections.emptyList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询 key
|
||||
*
|
||||
* @param patternKey key
|
||||
* @param page 页码
|
||||
* @param size 每页数目
|
||||
* @return /
|
||||
*/
|
||||
public List<String> findKeysForPage(String patternKey, int page, int size) {
|
||||
RedisTemplate redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
ScanOptions options = ScanOptions.scanOptions().match(patternKey).build();
|
||||
RedisConnectionFactory factory = redisTemplate.getConnectionFactory();
|
||||
RedisConnection rc = Objects.requireNonNull(factory).getConnection();
|
||||
Cursor<byte[]> cursor = rc.scan(options);
|
||||
List<String> result = new ArrayList<>(size);
|
||||
int tmpIndex = 0;
|
||||
int fromIndex = page * size;
|
||||
int toIndex = page * size + size;
|
||||
while (cursor.hasNext()) {
|
||||
if (tmpIndex >= fromIndex && tmpIndex < toIndex) {
|
||||
result.add(new String(cursor.next()));
|
||||
tmpIndex++;
|
||||
continue;
|
||||
}
|
||||
// 获取到满足条件的数据后,就可以退出了
|
||||
if (tmpIndex >= toIndex) {
|
||||
break;
|
||||
}
|
||||
tmpIndex++;
|
||||
cursor.next();
|
||||
}
|
||||
RedisConnectionUtils.releaseConnection(rc, factory);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断key是否存在
|
||||
*
|
||||
* @param key 键
|
||||
* @return true 存在 false不存在
|
||||
*/
|
||||
public boolean hasKey(String key) {
|
||||
RedisTemplate<Object, Object> redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
return Optional.ofNullable(redisTemplate).map(template -> template.hasKey(key)).orElse(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
*
|
||||
* @param keys 可以传一个值 或多个
|
||||
*/
|
||||
public void del(String... keys) {
|
||||
RedisTemplate<Object, Object> redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
for (String key : keys) {
|
||||
if (hasKey(key)) {
|
||||
redisTemplate.delete(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取锁
|
||||
*
|
||||
* @param lockKey 锁key
|
||||
* @param value value
|
||||
* @param expireTime:单位-秒
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean getLock(String lockKey, String value, int expireTime) {
|
||||
RedisTemplate<Object, Object> redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
return Optional.ofNullable(redisTemplate)
|
||||
.map(template -> template.opsForValue().setIfAbsent(lockKey, value, expireTime, TimeUnit.SECONDS))
|
||||
.orElse(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放锁
|
||||
*
|
||||
* @param lockKey 锁key
|
||||
* @param value value
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean releaseLock(String lockKey, String value) {
|
||||
RedisTemplate<Object, Object> redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
|
||||
RedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);
|
||||
return Optional.ofNullable(redisTemplate.execute(redisScript, Collections.singletonList(lockKey), value))
|
||||
.map(Convert::toLong)
|
||||
.filter(SUCCESS::equals)
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
// ============================String=============================
|
||||
|
||||
/**
|
||||
* 普通缓存获取
|
||||
*
|
||||
* @param key 键
|
||||
* @return 值
|
||||
*/
|
||||
public <T> T get(String key) {
|
||||
RedisTemplate<String, T> redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
return redisTemplate.opsForValue().get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量获取
|
||||
*
|
||||
* @param keys
|
||||
* @return
|
||||
*/
|
||||
public <T> List<T> multiGet(List<String> keys) {
|
||||
RedisTemplate<String, T> redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
return redisTemplate.opsForValue().multiGet(keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* 普通缓存放入
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @return true成功 false失败
|
||||
*/
|
||||
public boolean set(String key, Object value) {
|
||||
CacheProperties cacheProperties = SpringUtil.getBean(CacheProperties.class);
|
||||
RedisTemplate<Object, Object> redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
Optional.ofNullable(redisTemplate).map(template -> {
|
||||
template.opsForValue().set(key, value, cacheProperties.getTimeout(), TimeUnit.SECONDS);
|
||||
return true;
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 普通缓存放入
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @return true成功 false失败
|
||||
*/
|
||||
public boolean increment(String key, long value) {
|
||||
CacheProperties cacheProperties = SpringUtil.getBean(CacheProperties.class);
|
||||
RedisTemplate<Object, Object> redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
Optional.ofNullable(redisTemplate).map(template -> {
|
||||
template.opsForValue().increment(key, value);
|
||||
return true;
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 普通缓存放入并设置时间
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
|
||||
* @return true成功 false 失败
|
||||
*/
|
||||
public boolean set(String key, Object value, long time) {
|
||||
RedisTemplate<Object, Object> redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
return Optional.ofNullable(redisTemplate).map(template -> {
|
||||
if (time > 0) {
|
||||
template.opsForValue().set(key, value, time, TimeUnit.SECONDS);
|
||||
} else {
|
||||
template.opsForValue().set(key, value);
|
||||
}
|
||||
return true;
|
||||
}).orElse(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 普通缓存放入并设置时间
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @param time 时间
|
||||
* @param timeUnit 类型
|
||||
* @return true成功 false 失败
|
||||
*/
|
||||
public <T> boolean set(String key, T value, long time, TimeUnit timeUnit) {
|
||||
RedisTemplate<String, T> redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
Optional.ofNullable(redisTemplate).map(template -> {
|
||||
if (time > 0) {
|
||||
template.opsForValue().set(key, value, time, timeUnit);
|
||||
} else {
|
||||
template.opsForValue().set(key, value);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
// ================================Map=================================
|
||||
|
||||
/**
|
||||
* HashGet
|
||||
*
|
||||
* @param key 键 不能为null
|
||||
* @param hashKey 项 不能为null
|
||||
* @return 值
|
||||
*/
|
||||
public <HK, HV> HV hget(String key, HK hashKey) {
|
||||
RedisTemplate<String, HV> redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
return redisTemplate.<HK, HV>opsForHash().get(key, hashKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取hashKey对应的所有键值
|
||||
*
|
||||
* @param key 键
|
||||
* @return 对应的多个键值
|
||||
*/
|
||||
public <HK, HV> Map<HK, HV> hmget(String key) {
|
||||
RedisTemplate<String, HV> redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
return redisTemplate.<HK, HV>opsForHash().entries(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* HashSet
|
||||
*
|
||||
* @param key 键
|
||||
* @param map 对应多个键值
|
||||
* @return true 成功 false 失败
|
||||
*/
|
||||
public boolean hmset(String key, Map<?, ?> map) {
|
||||
RedisTemplate<Object, Object> redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
Optional.ofNullable(redisTemplate).map(template -> {
|
||||
template.opsForHash().putAll(key, map);
|
||||
return true;
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* HashSet 并设置时间
|
||||
*
|
||||
* @param key 键
|
||||
* @param map 对应多个键值
|
||||
* @param time 时间(秒)
|
||||
* @return true成功 false失败
|
||||
*/
|
||||
public boolean hmset(String key, Map<?, ?> map, long time) {
|
||||
RedisTemplate<Object, Object> redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
Optional.ofNullable(redisTemplate).map(template -> {
|
||||
template.opsForHash().putAll(key, map);
|
||||
if (time > 0) {
|
||||
template.expire(key, time, TimeUnit.SECONDS);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 向一张hash表中放入数据,如果不存在将创建
|
||||
*
|
||||
* @param key 键
|
||||
* @param item 项
|
||||
* @param value 值
|
||||
* @return true 成功 false失败
|
||||
*/
|
||||
public boolean hset(String key, Object item, Object value) {
|
||||
RedisTemplate<Object, Object> redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
return Optional.ofNullable(redisTemplate).map(template -> {
|
||||
template.opsForHash().put(key, item, value);
|
||||
return true;
|
||||
}).orElse(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 向一张hash表中放入数据,如果不存在将创建
|
||||
*
|
||||
* @param key 键
|
||||
* @param item 项
|
||||
* @param value 值
|
||||
* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
|
||||
* @return true 成功 false失败
|
||||
*/
|
||||
public boolean hset(String key, Object item, Object value, long time) {
|
||||
RedisTemplate<Object, Object> redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
return Optional.ofNullable(redisTemplate).map(template -> {
|
||||
template.opsForHash().put(key, item, value);
|
||||
if (time > 0) {
|
||||
template.expire(key, time, TimeUnit.SECONDS);
|
||||
}
|
||||
return true;
|
||||
}).orElse(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除hash表中的值
|
||||
*
|
||||
* @param key 键 不能为null
|
||||
* @param item 项 可以使多个 不能为null
|
||||
*/
|
||||
public void hdel(String key, Object... item) {
|
||||
RedisTemplate redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
redisTemplate.opsForHash().delete(key, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断hash表中是否有该项的值
|
||||
*
|
||||
* @param key 键 不能为null
|
||||
* @param item 项 不能为null
|
||||
* @return true 存在 false不存在
|
||||
*/
|
||||
public boolean hHasKey(String key, String item) {
|
||||
RedisTemplate redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
return redisTemplate.opsForHash().hasKey(key, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* hash递增 如果不存在,就会创建一个 并把新增后的值返回
|
||||
*
|
||||
* @param key 键
|
||||
* @param item 项
|
||||
* @param by 要增加几(大于0)
|
||||
* @return
|
||||
*/
|
||||
public double hincr(String key, String item, double by) {
|
||||
RedisTemplate redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
return redisTemplate.opsForHash().increment(key, item, by);
|
||||
}
|
||||
|
||||
/**
|
||||
* hash递减
|
||||
*
|
||||
* @param key 键
|
||||
* @param item 项
|
||||
* @param by 要减少记(小于0)
|
||||
* @return
|
||||
*/
|
||||
public double hdecr(String key, String item, double by) {
|
||||
RedisTemplate redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
return redisTemplate.opsForHash().increment(key, item, -by);
|
||||
}
|
||||
|
||||
// ============================set=============================
|
||||
|
||||
/**
|
||||
* 根据key获取Set中的所有值
|
||||
*
|
||||
* @param key 键
|
||||
* @return
|
||||
*/
|
||||
public <T> Set<T> sGet(String key) {
|
||||
RedisTemplate<String, T> redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
return redisTemplate.opsForSet().members(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据value从一个set中查询,是否存在
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @return true 存在 false不存在
|
||||
*/
|
||||
public boolean sHasKey(String key, Object value) {
|
||||
RedisTemplate redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
return redisTemplate.opsForSet().isMember(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将数据放入set缓存
|
||||
*
|
||||
* @param key 键
|
||||
* @param values 值 可以是多个
|
||||
* @return 成功个数
|
||||
*/
|
||||
public long sSet(String key, Object... values) {
|
||||
RedisTemplate redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
return redisTemplate.opsForSet().add(key, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将set数据放入缓存
|
||||
*
|
||||
* @param key 键
|
||||
* @param time 时间(秒)
|
||||
* @param values 值 可以是多个
|
||||
* @return 成功个数
|
||||
*/
|
||||
public long sSetAndTime(String key, long time, Object... values) {
|
||||
RedisTemplate redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
Long count = redisTemplate.opsForSet().add(key, values);
|
||||
if (time > 0) {
|
||||
expire(key, time);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取set缓存的长度
|
||||
*
|
||||
* @param key 键
|
||||
* @return
|
||||
*/
|
||||
public long sGetSetSize(String key) {
|
||||
RedisTemplate redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
return redisTemplate.opsForSet().size(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除值为value的
|
||||
*
|
||||
* @param key 键
|
||||
* @param values 值 可以是多个
|
||||
* @return 移除的个数
|
||||
*/
|
||||
public long setRemove(String key, Object... values) {
|
||||
RedisTemplate redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
Long count = redisTemplate.opsForSet().remove(key, values);
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获集合key1和集合key2的差集元素
|
||||
*
|
||||
* @param key 键
|
||||
* @return
|
||||
*/
|
||||
public <T> Set<T> sDifference(String key, String otherKey) {
|
||||
RedisTemplate<String, T> redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
return redisTemplate.opsForSet().difference(key, otherKey);
|
||||
}
|
||||
|
||||
// ===============================list=================================
|
||||
|
||||
/**
|
||||
* 获取list缓存的内容
|
||||
*
|
||||
* @param key 键
|
||||
* @param start 开始
|
||||
* @param end 结束 0 到 -1代表所有值
|
||||
* @return
|
||||
*/
|
||||
public <T> List<T> lGet(String key, long start, long end) {
|
||||
RedisTemplate<String, T> redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
return redisTemplate.opsForList().range(key, start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取list缓存的长度
|
||||
*
|
||||
* @param key 键
|
||||
* @return
|
||||
*/
|
||||
public long lGetListSize(String key) {
|
||||
RedisTemplate redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
return redisTemplate.opsForList().size(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过索引 获取list中的值
|
||||
*
|
||||
* @param key 键
|
||||
* @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
|
||||
* @return
|
||||
*/
|
||||
public Object lGetIndex(String key, long index) {
|
||||
RedisTemplate redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
return redisTemplate.opsForList().index(key, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将list放入缓存
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @return
|
||||
*/
|
||||
public boolean lSet(String key, Object value) {
|
||||
RedisTemplate redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
redisTemplate.opsForList().rightPush(key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将list放入缓存
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @param time 时间(秒)
|
||||
* @return
|
||||
*/
|
||||
public boolean lSet(String key, Object value, long time) {
|
||||
RedisTemplate<Object, Object> redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
redisTemplate.opsForList().rightPush(key, value);
|
||||
if (time > 0) {
|
||||
Optional.ofNullable(redisTemplate).ifPresent(template -> template.expire(key, time, TimeUnit.SECONDS));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将list放入缓存
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @return
|
||||
*/
|
||||
public boolean lSet(String key, List<Object> value) {
|
||||
RedisTemplate redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
redisTemplate.opsForList().rightPushAll(key, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将list放入缓存
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @param time 时间(秒)
|
||||
* @return
|
||||
*/
|
||||
public boolean lSet(String key, List<Object> value, long time) {
|
||||
RedisTemplate redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
redisTemplate.opsForList().rightPushAll(key, value);
|
||||
if (time > 0) {
|
||||
expire(key, time);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据索引修改list中的某条数据
|
||||
*
|
||||
* @param key 键
|
||||
* @param index 索引
|
||||
* @param value 值
|
||||
* @return /
|
||||
*/
|
||||
public boolean lUpdateIndex(String key, long index, Object value) {
|
||||
RedisTemplate redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
redisTemplate.opsForList().set(key, index, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除N个值为value
|
||||
*
|
||||
* @param key 键
|
||||
* @param count 移除多少个
|
||||
* @param value 值
|
||||
* @return 移除的个数
|
||||
*/
|
||||
public long lRemove(String key, long count, Object value) {
|
||||
RedisTemplate redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
return redisTemplate.opsForList().remove(key, count, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将zSet数据放入缓存
|
||||
*
|
||||
* @param key
|
||||
* @param time
|
||||
* @param tuples
|
||||
* @return
|
||||
*/
|
||||
public long zSetAndTime(String key, long time, Set<ZSetOperations.TypedTuple<Object>> tuples) {
|
||||
RedisTemplate redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
Long count = redisTemplate.opsForZSet().add(key, tuples);
|
||||
if (time > 0) {
|
||||
expire(key, time);
|
||||
}
|
||||
return count;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorted set:有序集合获取
|
||||
*
|
||||
* @param key
|
||||
* @param min
|
||||
* @param max
|
||||
* @return
|
||||
*/
|
||||
public Set<Object> zRangeByScore(String key, double min, double max) {
|
||||
RedisTemplate redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
|
||||
return zset.rangeByScore(key, min, max);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorted set:有序集合获取 正序
|
||||
*
|
||||
* @param key
|
||||
* @param start
|
||||
* @param end
|
||||
* @return
|
||||
*/
|
||||
public Set<Object> zRange(String key, long start, long end) {
|
||||
RedisTemplate redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
|
||||
return zset.range(key, start, end);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorted set:有序集合获取 倒叙
|
||||
*
|
||||
* @param key
|
||||
* @param start
|
||||
* @param end
|
||||
* @return
|
||||
*/
|
||||
public Set<Object> zReverseRange(String key, long start, long end) {
|
||||
RedisTemplate redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
|
||||
return zset.reverseRange(key, start, end);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取zSet缓存的长度
|
||||
*
|
||||
* @param key 键
|
||||
* @return
|
||||
*/
|
||||
public long zGetSetSize(String key) {
|
||||
RedisTemplate redisTemplate = SpringUtil.getBean("redisTemplate");
|
||||
return redisTemplate.opsForZSet().size(key);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.codvision.cachecore.config.RedisConfig,\
|
||||
com.codvision.cachecore.config.CacheProperties
|
||||
38
template/cvbp/cvbp-public/cvbp-common-core/.gitignore
vendored
Normal file
38
template/cvbp/cvbp-public/cvbp-common-core/.gitignore
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea/modules.xml
|
||||
.idea/jarRepositories.xml
|
||||
.idea/compiler.xml
|
||||
.idea/libraries/
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### Eclipse ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
### Mac OS ###
|
||||
.DS_Store
|
||||
91
template/cvbp/cvbp-public/cvbp-common-core/pom.xml
Normal file
91
template/cvbp/cvbp-public/cvbp-common-core/pom.xml
Normal file
@@ -0,0 +1,91 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
-->
|
||||
|
||||
<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>
|
||||
<groupId>com.codvision</groupId>
|
||||
<artifactId>cvbp-public</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>cvbp-common-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-crypto</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-extra</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-json</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.poi</groupId>
|
||||
<artifactId>poi-ooxml</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>easyexcel</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.servlet</groupId>
|
||||
<artifactId>jakarta.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.codvision.commoncore.bean;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author codvision
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class CoordinatePoint {
|
||||
|
||||
Double lng;
|
||||
|
||||
Double lat;
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
package com.codvision.commoncore.common;
|
||||
|
||||
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class ExpiryMap<K, V> implements Map<K, V> {
|
||||
|
||||
private boolean isRefresh = false;
|
||||
private ScheduledExecutorService scheduledExecutorService;
|
||||
private static final ConcurrentHashMap WORK_MAP = new ConcurrentHashMap();
|
||||
private static final ConcurrentHashMap<Object, Long> EXPIRY_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
public ExpiryMap() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ExpiryMap(boolean isRefresh) {
|
||||
this.isRefresh = isRefresh;
|
||||
startClearKey();
|
||||
}
|
||||
|
||||
public void closeMap() {
|
||||
scheduledExecutorService.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* 定时清除失效key
|
||||
*/
|
||||
public void startClearKey() {
|
||||
scheduledExecutorService = new ScheduledThreadPoolExecutor(1, new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build());
|
||||
scheduledExecutorService.scheduleAtFixedRate(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
System.out.println("===" + Thread.currentThread().getName() + "===");
|
||||
removeInvalidKeys();
|
||||
}
|
||||
}
|
||||
, 0, 3600, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private static void removeInvalidKeys() {
|
||||
EXPIRY_MAP.keySet().forEach(key -> {
|
||||
if (EXPIRY_MAP.get(key) < System.currentTimeMillis()) {
|
||||
EXPIRY_MAP.remove(key);
|
||||
WORK_MAP.remove(key);
|
||||
}
|
||||
});
|
||||
System.gc();
|
||||
}
|
||||
|
||||
/**
|
||||
* put方法,需要设置key 的有效期!单位为:毫秒
|
||||
*
|
||||
* @param key
|
||||
* @param value
|
||||
* @param expiry key的有效期,单位:毫秒
|
||||
* @return
|
||||
*/
|
||||
public V put(K key, V value, long expiry) {
|
||||
if (!containsKey(key) || isRefresh) {//更新value,只有需要刷新时间时才需要操作expiryMap
|
||||
EXPIRY_MAP.put(key, System.currentTimeMillis() + expiry);
|
||||
}
|
||||
WORK_MAP.put(key, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return keySet().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
if (key != null && EXPIRY_MAP.containsKey(key)) {
|
||||
boolean flag = EXPIRY_MAP.get(key) > System.currentTimeMillis();
|
||||
return flag;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
Collection values = WORK_MAP.values();
|
||||
if (values != null) {
|
||||
return values.contains(value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
if (containsKey(key)) {
|
||||
return (V) WORK_MAP.get(key);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
throw new RuntimeException("此方法已废弃!请加上key失效时间");
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
boolean containKey = containsKey(key);
|
||||
EXPIRY_MAP.remove(key);
|
||||
if (containKey) {
|
||||
return (V) WORK_MAP.remove(key);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public void putAll(Map<? extends K, ? extends V> m) {
|
||||
throw new RuntimeException("此方法已废弃!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
EXPIRY_MAP.clear();
|
||||
WORK_MAP.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
removeInvalidKeys();
|
||||
return WORK_MAP.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
removeInvalidKeys();
|
||||
return WORK_MAP.values();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Entry<K, V>> entrySet() {
|
||||
removeInvalidKeys();
|
||||
return WORK_MAP.entrySet();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
//ExpiryMap emap=new ExpiryMap();
|
||||
ExpiryMap emap = new ExpiryMap(true);
|
||||
emap.put("key1", "value1", 2 * 1000);
|
||||
emap.put("key2", "value2", 5 * 1000);
|
||||
emap.put("key3", "value3", 15 * 1000);
|
||||
System.out.println(emap.size());
|
||||
try {
|
||||
Thread.sleep(10 * 1000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.out.println(emap.size());
|
||||
System.out.println(emap.keySet());
|
||||
System.out.println(emap.values());
|
||||
System.out.println(emap.entrySet());
|
||||
emap.put("key4", "value4", 8 * 1000);
|
||||
System.out.println(emap.size());
|
||||
try {
|
||||
Thread.sleep(10 * 1000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.out.println(emap.size());
|
||||
System.out.println(emap.keySet());
|
||||
System.out.println(emap.values());
|
||||
System.out.println(emap.entrySet());
|
||||
|
||||
emap.closeMap();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
package com.codvision.commoncore.common;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
|
||||
/**
|
||||
* @author codvision
|
||||
*/
|
||||
@ApiModel(description = "返回响应数据")
|
||||
public class ResponseEntity<T> {
|
||||
|
||||
@ApiModelProperty(value = "编码")
|
||||
private int code = 200;
|
||||
|
||||
@ApiModelProperty(value = "基本信息")
|
||||
private String message = "成功";
|
||||
|
||||
@ApiModelProperty(value = "返回对象")
|
||||
private T data;
|
||||
|
||||
|
||||
private static final HashMap<Integer, String> ERROR_CODE = new HashMap<Integer, String>() {
|
||||
{
|
||||
put(100, "暂无数据");
|
||||
put(200, "成功");
|
||||
put(10000, "通用错误");
|
||||
///用户类
|
||||
put(10001, "用户名或密码错误");
|
||||
put(10002, "登录状态已过期");
|
||||
put(10003, "注册用户已存在");
|
||||
put(10004, "账号已被锁定,请在一小时后重试");
|
||||
|
||||
///操作权限类
|
||||
put(20001, "无操作权限");
|
||||
///参数类
|
||||
put(30001, "非法参数");
|
||||
put(30002, "缺少必要参数");
|
||||
put(30003, "文件内容为空");
|
||||
put(30004, "不支持的文件格式");
|
||||
put(30005, "获取参数失败");
|
||||
////数据操作类
|
||||
put(40001, "添加数据失败");
|
||||
put(40002, "更新数据失败");
|
||||
put(40003, "删除数据失败");
|
||||
put(50001, "不存在的对象");
|
||||
put(50002, "文件上传超过最大限制!");
|
||||
put(50003, "文件上传失败!");
|
||||
|
||||
put(110000, "获取用户失败或用户不存在!");
|
||||
put(100001, "钉钉获取用户信息失败,请稍后再试");
|
||||
put(110002, "小程序授权获取手机号失败");
|
||||
|
||||
put(990000, "系统错误");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public ResponseEntity() {
|
||||
}
|
||||
|
||||
public ResponseEntity(T data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public ResponseEntity setCode(int code) {
|
||||
this.code = code;
|
||||
if (ERROR_CODE.containsKey(code)) {
|
||||
setMessage(ERROR_CODE.get(code));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public T getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public ResponseEntity setData(T data) {
|
||||
this.data = data;
|
||||
return this;
|
||||
}
|
||||
|
||||
public static <T> ResponseEntity<T> def(Class<T> clazz) {
|
||||
return new ResponseEntity<>();
|
||||
}
|
||||
|
||||
public ResponseEntity<T> ok() {
|
||||
setCode(200);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ResponseEntity<T> error(int code) {
|
||||
setCode(code);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ResponseEntity<T> error(int code, String message) {
|
||||
setCode(code);
|
||||
setMessage(message);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ResponseEntity<T> message(String message) {
|
||||
setMessage(message);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ResponseEntity<T> data(T data) {
|
||||
setData(data);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ResponseEntity<T> back(int code, String message, T data) {
|
||||
setCode(code);
|
||||
setMessage(message);
|
||||
setData(data);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.codvision.commoncore.enums;
|
||||
|
||||
/**
|
||||
* @author codvision
|
||||
*/
|
||||
|
||||
public enum NetworkData {
|
||||
|
||||
/**
|
||||
* 月的天数
|
||||
*/
|
||||
MONTH(30, "月"),
|
||||
/**
|
||||
* 周的天数
|
||||
*/
|
||||
WEEK(7, "周"),
|
||||
|
||||
/**
|
||||
* NET_WORK_ID
|
||||
*/
|
||||
NET_WORK_ID(0, "0:0:0:0:0:0:0:1"),
|
||||
|
||||
/**
|
||||
* 成功
|
||||
*/
|
||||
OK(200, "ok");
|
||||
|
||||
private final int code;
|
||||
private final String desc;
|
||||
|
||||
NetworkData(int code, String desc) {
|
||||
this.code = code;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.codvision.commoncore.enums;
|
||||
|
||||
/**
|
||||
* where 条件操作符号
|
||||
*
|
||||
* @author lingee
|
||||
* @date 2022/5/9
|
||||
*/
|
||||
public enum SqlOperator {
|
||||
/**
|
||||
* like
|
||||
*/
|
||||
LIKE("LIKE"),
|
||||
/**
|
||||
* =
|
||||
*/
|
||||
EQ("="),
|
||||
/**
|
||||
* 不等于
|
||||
*/
|
||||
NE("<>"),
|
||||
/**
|
||||
* 大于
|
||||
*/
|
||||
GT(">"),
|
||||
/**
|
||||
* 大于等于
|
||||
*/
|
||||
GE(">="),
|
||||
/**
|
||||
* 小于
|
||||
*/
|
||||
LT("<"),
|
||||
/**
|
||||
* 小于等于
|
||||
*/
|
||||
LE("<="),
|
||||
/**
|
||||
* 为空
|
||||
*/
|
||||
IS_NULL("IS NULL"),
|
||||
/**
|
||||
* 不为空
|
||||
*/
|
||||
IS_NOT_NULL("IS NOT NULL"),
|
||||
/**
|
||||
* 范围查找
|
||||
*/
|
||||
BETWEEN("BETWEEN"),
|
||||
/**
|
||||
* 多数据查找
|
||||
*/
|
||||
IN("IN");
|
||||
|
||||
private final String operator;
|
||||
|
||||
SqlOperator(String operator) {
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
public String getOperator() {
|
||||
return operator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.codvision.commoncore.enums;
|
||||
|
||||
/**
|
||||
* TrueOrFalse
|
||||
*
|
||||
* @author lingee
|
||||
* @since 2024/4/29
|
||||
*/
|
||||
public enum TrueOrFalse {
|
||||
|
||||
FALSE("0", 0, false),
|
||||
|
||||
TRUE("1", 1, true);
|
||||
private final String key;
|
||||
private final int intVal;
|
||||
private final boolean val;
|
||||
|
||||
TrueOrFalse(String key, int intVal, boolean val) {
|
||||
this.key = key;
|
||||
this.intVal = intVal;
|
||||
this.val = val;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public int getIntVal() {
|
||||
return intVal;
|
||||
}
|
||||
|
||||
public boolean isVal() {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.codvision.commoncore.exception;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 认证异常
|
||||
*
|
||||
* @author hxl
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class AuthException extends RuntimeException {
|
||||
|
||||
private Integer code;
|
||||
|
||||
private String message;
|
||||
|
||||
public AuthException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public AuthException(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public AuthException(String message) {
|
||||
super(message);
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public AuthException(int code, String message) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.codvision.commoncore.exception;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 业务异常
|
||||
*
|
||||
* @author hxl
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class BusinessException extends RuntimeException {
|
||||
|
||||
private Integer code;
|
||||
private String message;
|
||||
|
||||
public BusinessException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public BusinessException(String message) {
|
||||
super(message);
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public BusinessException(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public BusinessException(int code, String message) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.codvision.commoncore.exception;
|
||||
|
||||
/**
|
||||
* @Author huxb
|
||||
* @description:
|
||||
* @create 2023/2/7 16:16
|
||||
*/
|
||||
public class IdempotentException extends RuntimeException {
|
||||
public IdempotentException() {
|
||||
}
|
||||
|
||||
public IdempotentException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.codvision.commoncore.exception;
|
||||
|
||||
/**
|
||||
* @Author huxb
|
||||
* @description:
|
||||
* @create 2022/11/22 10:28
|
||||
*/
|
||||
public class LimitException extends RuntimeException{
|
||||
public LimitException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public LimitException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.codvision.commoncore.exception;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* 权限异常
|
||||
*
|
||||
* @author hxl
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class PermissionException extends RuntimeException {
|
||||
|
||||
private Integer code;
|
||||
|
||||
private String message;
|
||||
|
||||
public PermissionException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public PermissionException(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public PermissionException(String message) {
|
||||
super(message);
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public PermissionException(int code, String message) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 公共模块
|
||||
*
|
||||
* @author lingee
|
||||
* @date 2023/7/14
|
||||
*/
|
||||
package com.codvision.commoncore;
|
||||
@@ -0,0 +1,139 @@
|
||||
package com.codvision.commoncore.utils;
|
||||
|
||||
import javax.crypto.*;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.management.openmbean.InvalidKeyException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* @author zjm
|
||||
* @version V1.0
|
||||
* @Package com.codvision.xlwzl.util
|
||||
* @date 2020/7/3 10:59
|
||||
* @Copyright © 2017-2020 杭州码全科技有限公司
|
||||
* @Description 使用ECB模式加密
|
||||
*/
|
||||
public class AES {
|
||||
/**
|
||||
* 偏移量字符串必须是16位 当模式是CBC的时候必须设置偏移量
|
||||
*/
|
||||
private static final String iv = "0123456789ABCDEF";
|
||||
private static final String Algorithm = "AES";
|
||||
/**
|
||||
* 算法/模式/补码方式
|
||||
*/
|
||||
private static final String AlgorithmProvider = "AES/ECB/PKCS5Padding";
|
||||
|
||||
public static byte[] generatorKey() throws NoSuchAlgorithmException {
|
||||
KeyGenerator keyGenerator = KeyGenerator.getInstance(Algorithm);
|
||||
//默认128,获得无政策权限后可为192或256
|
||||
keyGenerator.init(256);
|
||||
SecretKey secretKey = keyGenerator.generateKey();
|
||||
return secretKey.getEncoded();
|
||||
}
|
||||
|
||||
public static IvParameterSpec getIv() throws UnsupportedEncodingException {
|
||||
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
|
||||
System.out.println("偏移量:" + byteToHexString(ivParameterSpec.getIV()));
|
||||
return ivParameterSpec;
|
||||
}
|
||||
|
||||
public static byte[] encrypt(String src) throws NoSuchPaddingException, NoSuchAlgorithmException, java.security.InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException {
|
||||
return encrypt(src, "codvision@2020YH".getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
public static byte[] encrypt(String src, byte[] key) throws NoSuchPaddingException, NoSuchAlgorithmException, java.security.InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
|
||||
SecretKey secretKey = new SecretKeySpec(key, Algorithm);
|
||||
//IvParameterSpec ivParameterSpec = getIv();
|
||||
Cipher cipher = Cipher.getInstance(AlgorithmProvider);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
|
||||
byte[] cipherBytes = cipher.doFinal(src.getBytes(StandardCharsets.UTF_8));
|
||||
return cipherBytes;
|
||||
}
|
||||
|
||||
public static String decrypt(String src) throws Exception {
|
||||
return decrypt(src, "codvision@2020YH".getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
public static String decrypt(String src, byte[] key) throws Exception {
|
||||
SecretKey secretKey = new SecretKeySpec(key, Algorithm);
|
||||
|
||||
//IvParameterSpec ivParameterSpec = getIv();
|
||||
Cipher cipher = Cipher.getInstance(AlgorithmProvider);
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKey);
|
||||
byte[] hexBytes = hexStringToBytes(src);
|
||||
byte[] plainBytes = cipher.doFinal(hexBytes);
|
||||
return new String(plainBytes, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将byte转换为16进制字符串
|
||||
*
|
||||
* @param src
|
||||
* @return
|
||||
*/
|
||||
public static String byteToHexString(byte[] src) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < src.length; i++) {
|
||||
int v = src[i] & 0xff;
|
||||
String hv = Integer.toHexString(v);
|
||||
if (hv.length() < 2) {
|
||||
sb.append("0");
|
||||
}
|
||||
sb.append(hv);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 将16进制字符串装换为byte数组
|
||||
*
|
||||
* @param hexString
|
||||
* @return
|
||||
*/
|
||||
public static byte[] hexStringToBytes(String hexString) {
|
||||
hexString = hexString.toUpperCase();
|
||||
int length = hexString.length() / 2;
|
||||
char[] hexChars = hexString.toCharArray();
|
||||
byte[] b = new byte[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
int pos = i * 2;
|
||||
b[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
private static byte charToByte(char c) {
|
||||
return (byte) "0123456789ABCDEF".indexOf(c);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
// byte key[] = generatorKey();
|
||||
// 密钥必须是16的倍数
|
||||
String src = "6ea40c84b3fe7c6c3033e59bd59643a3";
|
||||
System.out.println("原字符串:" + src);
|
||||
|
||||
String enc = byteToHexString(encrypt(src));
|
||||
System.out.println("加密:" + enc);
|
||||
System.out.println("解密:" + decrypt(enc));
|
||||
} catch (InvalidKeyException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchPaddingException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
e.printStackTrace();
|
||||
} catch (BadPaddingException e) {
|
||||
e.printStackTrace();
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.codvision.commoncore.utils;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.util.HexUtil;
|
||||
import cn.hutool.crypto.CryptoException;
|
||||
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* @author hxl
|
||||
*/
|
||||
public class AesUtil {
|
||||
/**
|
||||
* Cipher负责完成加密或解密工作
|
||||
*/
|
||||
private Cipher cipher;
|
||||
/**
|
||||
* 密钥
|
||||
*/
|
||||
private SecretKey secretKey;
|
||||
|
||||
/**
|
||||
* @param key 密钥 转为为字节后:支持三种密钥长度:128、192、256位
|
||||
*/
|
||||
public AesUtil(String key) {
|
||||
this(new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), SymmetricAlgorithm.AES.getValue()));
|
||||
}
|
||||
|
||||
public AesUtil(SecretKey secretKey) {
|
||||
try {
|
||||
this.cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||
} catch (Exception e) {
|
||||
throw new CryptoException(e);
|
||||
}
|
||||
this.secretKey = secretKey;
|
||||
}
|
||||
|
||||
public byte[] encrypt(byte[] data) {
|
||||
try {
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(new byte[cipher.getBlockSize()]));
|
||||
return cipher.doFinal(data);
|
||||
} catch (Exception e) {
|
||||
throw new CryptoException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] decrypt(byte[] data) {
|
||||
try {
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(new byte[cipher.getBlockSize()]));
|
||||
return cipher.doFinal(data);
|
||||
} catch (Exception e) {
|
||||
throw new CryptoException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public String encryptHex(byte[] data) {
|
||||
return HexUtil.encodeHexStr(encrypt(data));
|
||||
}
|
||||
|
||||
public byte[] decryptHex(String data) {
|
||||
return decrypt(HexUtil.decodeHex(data));
|
||||
}
|
||||
|
||||
public String encryptBase64(byte[] data) {
|
||||
return Base64.encode(encrypt(data));
|
||||
}
|
||||
|
||||
public byte[] decryptBase64(String data) {
|
||||
return decrypt(Base64.decode(data));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.codvision.commoncore.utils;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @Author huxb
|
||||
* @description: 随机生成appKey,appSecret
|
||||
* @create 2021/12/21 16:44
|
||||
*/
|
||||
public class AppUtils {
|
||||
|
||||
//生成 app_secret 密钥
|
||||
private final static String SERVER_NAME = "maquan_codvision";
|
||||
private final static String[] chars = new String[]{"a", "b", "c", "d", "e", "f",
|
||||
"g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
|
||||
"t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5",
|
||||
"6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I",
|
||||
"J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
|
||||
"W", "X", "Y", "Z"};
|
||||
|
||||
/**
|
||||
* 短8位UUID思想其实借鉴微博短域名的生成方式,但是其重复概率过高,而且每次生成4个,需要随即选取一个。
|
||||
* 本算法利用62个可打印字符,通过随机生成32位UUID,由于UUID都为十六进制,所以将UUID分成8组,每4个为一组,然后通过模62操作,结果作为索引取出字符,
|
||||
* 这样重复率大大降低。
|
||||
* 经测试,在生成一千万个数据也没有出现重复,完全满足大部分需求。
|
||||
*/
|
||||
public static String getAppId() {
|
||||
StringBuffer shortBuffer = new StringBuffer();
|
||||
String uuid = UUID.randomUUID().toString().replace("-", "");
|
||||
for (int i = 0; i < 8; i++) {
|
||||
String str = uuid.substring(i * 4, i * 4 + 4);
|
||||
int x = Integer.parseInt(str, 16);
|
||||
shortBuffer.append(chars[x % 0x3E]);
|
||||
}
|
||||
return shortBuffer.toString();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过appId和内置关键词生成APP Secret
|
||||
*/
|
||||
public static String getAppSecret(String appId) {
|
||||
try {
|
||||
String[] array = new String[]{appId, SERVER_NAME};
|
||||
StringBuffer sb = new StringBuffer();
|
||||
// 字符串排序
|
||||
Arrays.sort(array);
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
sb.append(array[i]);
|
||||
}
|
||||
String str = sb.toString();
|
||||
MessageDigest md = MessageDigest.getInstance("SHA-1");
|
||||
md.update(str.getBytes());
|
||||
byte[] digest = md.digest();
|
||||
|
||||
StringBuffer hexstr = new StringBuffer();
|
||||
String shaHex = "";
|
||||
for (int i = 0; i < digest.length; i++) {
|
||||
shaHex = Integer.toHexString(digest[i] & 0xFF);
|
||||
if (shaHex.length() < 2) {
|
||||
hexstr.append(0);
|
||||
}
|
||||
hexstr.append(shaHex);
|
||||
}
|
||||
return hexstr.toString();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
package com.codvision.commoncore.utils;
|
||||
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 对象工具类
|
||||
*
|
||||
* @author lingee
|
||||
* @since 2023-7-20
|
||||
*/
|
||||
public class BeanUtil extends cn.hutool.core.bean.BeanUtil {
|
||||
|
||||
/**
|
||||
* 获取属性名数组
|
||||
*
|
||||
* @param o 获取字段的对象
|
||||
* @return 返回各个字段
|
||||
*/
|
||||
public static Field[] getFields(Object o) {
|
||||
Field[] fields = o.getClass().getDeclaredFields();
|
||||
Field[] superFields = o.getClass().getSuperclass().getDeclaredFields();
|
||||
Field[] allFields = new Field[fields.length + superFields.length];
|
||||
int index = 0;
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
if ("serialVersionUID".equals(fields[i].getName())) {
|
||||
continue;
|
||||
}
|
||||
Field field = fields[i];
|
||||
if (ObjectUtil.isNotEmpty(field)) {
|
||||
allFields[index] = field;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
for (int i = 0; i < superFields.length; i++) {
|
||||
if ("id".equals(superFields[i].getName())
|
||||
|| "serialVersionUID".equals(superFields[i].getName())) {
|
||||
continue;
|
||||
}
|
||||
Field field = superFields[i];
|
||||
if (ObjectUtil.isNotEmpty(field)) {
|
||||
allFields[index] = field;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return allFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取属性名数组
|
||||
*
|
||||
* @param o 获取字段的对象
|
||||
* @return 返回各个字段
|
||||
*/
|
||||
public static String[] getFieldName(Object o) {
|
||||
Field[] fields = o.getClass().getDeclaredFields();
|
||||
Field[] superFields = o.getClass().getSuperclass().getDeclaredFields();
|
||||
String[] fieldNames = new String[fields.length + superFields.length];
|
||||
int index = 0;
|
||||
for (int i = 0; i < fields.length; i++) {
|
||||
fieldNames[index] = fields[i].getName();
|
||||
index++;
|
||||
}
|
||||
for (int i = 0; i < superFields.length; i++) {
|
||||
if ("id".equals(superFields[i].getName())) {
|
||||
continue;
|
||||
}
|
||||
fieldNames[index] = superFields[i].getName();
|
||||
index++;
|
||||
}
|
||||
return fieldNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据属性名获取属性值
|
||||
*
|
||||
* @param fieldName 属性名
|
||||
* @param o 对象
|
||||
* @return 属性值
|
||||
*/
|
||||
public static Object getFieldValueByName(String fieldName, Object o) {
|
||||
try {
|
||||
String firstLetter = fieldName.substring(0, 1).toUpperCase();
|
||||
String getter = "get" + firstLetter + fieldName.substring(1);
|
||||
Method method = o.getClass().getMethod(getter, new Class[]{});
|
||||
Object value = method.invoke(o, new Object[]{});
|
||||
return value;
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将对象转换为key value
|
||||
* A=a&B=b&C=c 格式
|
||||
*
|
||||
* @param object 对象
|
||||
* @return 格式化结果
|
||||
*/
|
||||
public static String formatKeyValuePair(Object object) {
|
||||
//准备接受的字符串
|
||||
StringBuilder stringBuffer = new StringBuilder();
|
||||
//获取对象字段
|
||||
String[] fieldNames = BeanUtil.getFieldName(object);
|
||||
//遍历所有属性
|
||||
for (int j = 0; j < fieldNames.length; j++) {
|
||||
//不是第一个并且不是最后一个,拼接&
|
||||
if (j != 0) {
|
||||
stringBuffer.append("&");
|
||||
}
|
||||
//获取属性的名字
|
||||
String key = fieldNames[j];
|
||||
//获取值
|
||||
Object value = BeanUtil.getFieldValueByName(key, object);
|
||||
assert value != null;
|
||||
stringBuffer.append(key).append("=").append(value.toString());
|
||||
}
|
||||
return stringBuffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* key value键值对 转换为 对象
|
||||
* A=a&B=b&C=c 格式 转换为对象
|
||||
*
|
||||
* @param str 对象字符串
|
||||
* @param t 范型
|
||||
* @param <T> 范型
|
||||
* @return 格式化结果
|
||||
*/
|
||||
public static <T> T formatKeyValuePair(String str, T t) {
|
||||
//填写对参数键值对
|
||||
String[] params = str.split("&");
|
||||
|
||||
//获取对象字段
|
||||
String[] fieldNames = BeanUtil.getFieldName(t);
|
||||
|
||||
try {
|
||||
//循环每个参数
|
||||
for (String param : params) {
|
||||
String[] keyValues = param.split("=");
|
||||
for (int i = 0; i < fieldNames.length; i++) {
|
||||
if (fieldNames[i].equals(keyValues[0])) {
|
||||
Field f = t.getClass().getDeclaredField(fieldNames[i]);
|
||||
f.setAccessible(true);
|
||||
//长度为2 才转换,否则不转
|
||||
if (keyValues.length == 2) {
|
||||
f.set(t, keyValues[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.codvision.commoncore.utils;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
/**
|
||||
* 强密码校验:包含数字、大小写字母和特殊符号,长度要求8-15位且不与用户名相同
|
||||
* @author hxl
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public class CheckPwdUtil {
|
||||
|
||||
// 数字
|
||||
public static final String REG_NUMBER = ".*\\d+.*";
|
||||
// 小写字母
|
||||
public static final String REG_UPPERCASE = ".*[A-Z]+.*";
|
||||
// 大写字母
|
||||
public static final String REG_LOWERCASE = ".*[a-z]+.*";
|
||||
// 特殊符号(~!@#$%^&*()_+|<>,.?/:;'[]{}\)
|
||||
public static final String REG_SYMBOL = ".*[~!@#$%^&*()_+|<>,.?/:;'\\[\\]{}\"]+.*";
|
||||
|
||||
|
||||
public static boolean checkPasswordRule(String username, String password) {
|
||||
if (StringUtils.isBlank(password) || password.length() < 8 || password.length() > 15) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
if (password.matches(REG_NUMBER)) { i++; }
|
||||
if (password.matches(REG_LOWERCASE)) { i++; }
|
||||
if (password.matches(REG_UPPERCASE)) { i++; }
|
||||
if (password.matches(REG_SYMBOL)) { i++; }
|
||||
|
||||
boolean contains = password.equals(username);
|
||||
if (i < 4 || contains) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
package com.codvision.commoncore.utils;
|
||||
|
||||
|
||||
import com.codvision.commoncore.bean.CoordinatePoint;
|
||||
|
||||
/**
|
||||
* 坐标工具类
|
||||
*
|
||||
* @author codvision
|
||||
*/
|
||||
public class CoordinateUtil {
|
||||
|
||||
public static final String BAIDU_LBS_TYPE = "bd09ll";
|
||||
|
||||
public static double pi = 3.1415926535897932384626;
|
||||
public static double a = 6378245.0;
|
||||
public static double ee = 0.00669342162296594323;
|
||||
|
||||
/**
|
||||
* 84 to 火星坐标系 (GCJ-02)
|
||||
*
|
||||
* @param lat
|
||||
* @param lon
|
||||
* @return
|
||||
*/
|
||||
public static CoordinatePoint wgs84ToGcj02(double lon, double lat) {
|
||||
if (outOfChina(lon, lat)) {
|
||||
return null;
|
||||
}
|
||||
double dLat = transformLat(lon - 105.0, lat - 35.0);
|
||||
double dLon = transformLon(lon - 105.0, lat - 35.0);
|
||||
double radLat = lat / 180.0 * pi;
|
||||
double magic = Math.sin(radLat);
|
||||
magic = 1 - ee * magic * magic;
|
||||
double sqrtMagic = Math.sqrt(magic);
|
||||
dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
|
||||
dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
|
||||
double mgLat = lat + dLat;
|
||||
double mgLon = lon + dLon;
|
||||
return new CoordinatePoint(mgLon, mgLat);
|
||||
}
|
||||
|
||||
/**
|
||||
* * 火星坐标系 (GCJ-02) to 84 * * @param lon * @param lat * @return
|
||||
*/
|
||||
public static CoordinatePoint gcj02ToWgs84(double lon, double lat) {
|
||||
CoordinatePoint gps = transform(lon, lat);
|
||||
double lontitude = lon * 2 - gps.getLng();
|
||||
double latitude = lat * 2 - gps.getLat();
|
||||
return new CoordinatePoint(lontitude, latitude);
|
||||
}
|
||||
|
||||
/**
|
||||
* 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换算法 将 GCJ-02 坐标转换成 BD-09 坐标
|
||||
*
|
||||
* @param ggLat
|
||||
* @param ggLat
|
||||
*/
|
||||
public static CoordinatePoint gcj02ToBd09(double ggLng, double ggLat) {
|
||||
double x = ggLng, y = ggLat;
|
||||
double z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * pi);
|
||||
double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * pi);
|
||||
double bdLng = z * Math.cos(theta) + 0.0065;
|
||||
double bdLat = z * Math.sin(theta) + 0.006;
|
||||
return new CoordinatePoint(bdLng, bdLat);
|
||||
}
|
||||
|
||||
/**
|
||||
* * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换算法 * * 将 BD-09 坐标转换成GCJ-02 坐标 * * @param
|
||||
* bd_lat * @param bd_lon * @return
|
||||
*/
|
||||
public static CoordinatePoint bd09ToGcj02(double bdLng, double bdLat) {
|
||||
double x = bdLng - 0.0065, y = bdLat - 0.006;
|
||||
double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * pi);
|
||||
double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * pi);
|
||||
double ggLng = z * Math.cos(theta);
|
||||
double ggLat = z * Math.sin(theta);
|
||||
return new CoordinatePoint(ggLng, ggLat);
|
||||
}
|
||||
|
||||
/**
|
||||
* (BD-09)-->84
|
||||
*
|
||||
* @param bdLng
|
||||
* @param bdLat
|
||||
* @return
|
||||
*/
|
||||
public static CoordinatePoint bd09ToWgs84(double bdLng, double bdLat) {
|
||||
|
||||
CoordinatePoint gcj02 = bd09ToGcj02(bdLng, bdLat);
|
||||
CoordinatePoint map84 = gcj02ToWgs84(gcj02.getLng(),
|
||||
gcj02.getLat());
|
||||
return map84;
|
||||
|
||||
}
|
||||
|
||||
public static boolean outOfChina(double lon, double lat) {
|
||||
if (lon < 72.004 || lon > 137.8347) {
|
||||
return true;
|
||||
}
|
||||
return lat < 0.8293 || lat > 55.8271;
|
||||
}
|
||||
|
||||
public static CoordinatePoint transform(double lon, double lat) {
|
||||
if (outOfChina(lon, lat)) {
|
||||
return new CoordinatePoint(lat, lon);
|
||||
}
|
||||
double dLat = transformLat(lon - 105.0, lat - 35.0);
|
||||
double dLon = transformLon(lon - 105.0, lat - 35.0);
|
||||
double radLat = lat / 180.0 * pi;
|
||||
double magic = Math.sin(radLat);
|
||||
magic = 1 - ee * magic * magic;
|
||||
double sqrtMagic = Math.sqrt(magic);
|
||||
dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
|
||||
dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
|
||||
double mgLat = lat + dLat;
|
||||
double mgLon = lon + dLon;
|
||||
return new CoordinatePoint(mgLon, mgLat);
|
||||
}
|
||||
|
||||
public static double transformLat(double x, double y) {
|
||||
double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y
|
||||
+ 0.2 * Math.sqrt(Math.abs(x));
|
||||
ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
|
||||
ret += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0;
|
||||
ret += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static double transformLon(double x, double y) {
|
||||
double ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1
|
||||
* Math.sqrt(Math.abs(x));
|
||||
ret += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
|
||||
ret += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0;
|
||||
ret += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0
|
||||
* pi)) * 2.0 / 3.0;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,564 @@
|
||||
package com.codvision.commoncore.utils;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author codvision
|
||||
*/
|
||||
public class DateUtil extends cn.hutool.core.date.DateUtil {
|
||||
public static final String STANDARD_FORMAT = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
public static final String STANDARD_DATE_FORMAT = "yyyy-MM-dd";
|
||||
|
||||
public static final String STANDARD_DATE_NO_UNDERLINE_FORMAT = "yyyyMMdd";
|
||||
|
||||
public static final String FULL_DATE = "yyyyMMddHHmmss";
|
||||
|
||||
|
||||
public static Date getSomeWeekAgoDate(Date date, int weeks) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(date);
|
||||
calendar.add(Calendar.WEEK_OF_YEAR, -weeks);
|
||||
Date someWeeksAgo = calendar.getTime();
|
||||
return someWeeksAgo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取N个月前日期
|
||||
*
|
||||
* @param date
|
||||
* @param month
|
||||
* @return
|
||||
*/
|
||||
public static Date getSomeMonthAgoDate(Date date, int month) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(date);
|
||||
calendar.add(Calendar.MONTH, -month);
|
||||
Date someMonthAgo = calendar.getTime();
|
||||
return someMonthAgo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取N年前日期
|
||||
*
|
||||
* @param date
|
||||
* @return
|
||||
*/
|
||||
public static Date getSomeYearAgoDate(Date date, int year) {
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(date);
|
||||
calendar.add(Calendar.YEAR, -year);
|
||||
Date someYearAgo = calendar.getTime();
|
||||
return someYearAgo;
|
||||
}
|
||||
|
||||
public static String strToStr(String strDate) {
|
||||
Date date = new Date();
|
||||
try {
|
||||
//先按照原格式转换为时间
|
||||
date = new SimpleDateFormat("yyyyMMddHHmmss").parse(strDate);
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
//再将时间转换为对应格式字符串
|
||||
String str = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date);
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据系统时间返回一串无符号字符串
|
||||
*/
|
||||
public static String toString(Date date) {
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
|
||||
return simpleDateFormat.format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据系统时间返回一串无符号字符串
|
||||
*/
|
||||
public static String monthToString(Date date) {
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMM");
|
||||
return simpleDateFormat.format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据系统时间返回一串无符号字符串
|
||||
*/
|
||||
public static String dayToString(Date date) {
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
|
||||
return simpleDateFormat.format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据系统时间返回一串无符号字符串
|
||||
*/
|
||||
public static String toStringFor16(Date date, String value) {
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
|
||||
String data = simpleDateFormat.format(date);
|
||||
Random rome = new Random();
|
||||
int last = rome.nextInt(90000000) + 10000000;
|
||||
return value + data + last;
|
||||
}
|
||||
|
||||
public static Date toDate(String date) {
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
try {
|
||||
return simpleDateFormat.parse(date);
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将一个字符串转换成日期格式
|
||||
*
|
||||
* @param date 字符串日期
|
||||
* @param pattern 日期格式
|
||||
* @return date
|
||||
*/
|
||||
public static Date toDate(String date, String pattern) {
|
||||
if ("".equals("" + date)) {
|
||||
return null;
|
||||
}
|
||||
if (pattern == null) {
|
||||
pattern = STANDARD_DATE_FORMAT;
|
||||
}
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(pattern, Locale.ENGLISH);
|
||||
Date newDate = new Date();
|
||||
try {
|
||||
newDate = sdf.parse(date);
|
||||
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return newDate;
|
||||
}
|
||||
|
||||
|
||||
public static String sdf(Date date) {
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
return simpleDateFormat.format(date);
|
||||
}
|
||||
|
||||
public static String getMonthBeginTime() {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.add(Calendar.MONTH, 0);
|
||||
//设置为1号,当前日期既为本月第一天
|
||||
c.set(Calendar.DAY_OF_MONTH, 1);
|
||||
return sdf.format(c.getTime());
|
||||
}
|
||||
|
||||
|
||||
public static String getMonthEndTime() {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.add(Calendar.MONTH, 0);
|
||||
c.set(Calendar.DAY_OF_MONTH, c.getActualMaximum(Calendar.DAY_OF_MONTH));
|
||||
return sdf.format(c.getTime());
|
||||
}
|
||||
|
||||
public static String getMonthBeginTimeOfLastYear() {
|
||||
|
||||
Calendar c = Calendar.getInstance();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
|
||||
c.add(Calendar.MONTH, 0);
|
||||
c.add(Calendar.YEAR, -1);
|
||||
//设置为1号,当前日期既为本月第一天
|
||||
c.set(Calendar.DAY_OF_MONTH, 1);
|
||||
return sdf.format(c.getTime());
|
||||
}
|
||||
|
||||
|
||||
public static String getMonthEndTimeOfLastYear() {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.add(Calendar.MONTH, 0);
|
||||
c.add(Calendar.YEAR, -1);
|
||||
c.set(Calendar.DAY_OF_MONTH, c.getActualMaximum(Calendar.DAY_OF_MONTH));
|
||||
return sdf.format(c.getTime());
|
||||
}
|
||||
|
||||
|
||||
public static String getToday() {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
return sdf.format(new Date());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获得昨天日期:yyyy-MM-dd HH:mm:ss
|
||||
*/
|
||||
public static String getYesterdayBeginTime() {
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.add(Calendar.DATE, -1);
|
||||
SimpleDateFormat startSdf = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
|
||||
return startSdf.format(c.getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得昨天日期:yyyy-MM-dd HH:mm:ss
|
||||
*/
|
||||
public static String getYesterdayEndTime() {
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.add(Calendar.DATE, -1);
|
||||
SimpleDateFormat startSdf = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
|
||||
return startSdf.format(c.getTime());
|
||||
}
|
||||
|
||||
public static String getTodayBeginTime() {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
|
||||
return sdf.format(new Date());
|
||||
}
|
||||
|
||||
|
||||
public static String getTodayEndTime() {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
|
||||
return sdf.format(new Date());
|
||||
}
|
||||
|
||||
public static String getNowDateTime() {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
return sdf.format(new Date());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得明天日期:yyyy-MM-dd HH:mm:ss
|
||||
*/
|
||||
public static String getTomorrowBeginTime() {
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.add(Calendar.DATE, 1);
|
||||
SimpleDateFormat startSdf = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
|
||||
return startSdf.format(c.getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得明天日期:yyyy-MM-dd HH:mm:ss
|
||||
*/
|
||||
public static String getTomorrowEndTime() {
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.add(Calendar.DATE, 1);
|
||||
SimpleDateFormat startSdf = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
|
||||
return startSdf.format(c.getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得明天日期:yyyy-MM-dd time
|
||||
*/
|
||||
public static String getTomorrowTime(String time) {
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.add(Calendar.DATE, 1);
|
||||
SimpleDateFormat startSdf = new SimpleDateFormat(String.format("yyyy-MM-dd %s", time));
|
||||
return startSdf.format(c.getTime());
|
||||
}
|
||||
|
||||
|
||||
public static String getYearBeginTime() {
|
||||
Calendar c = Calendar.getInstance();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-01-01 00:00:00");
|
||||
return sdf.format(c.getTime());
|
||||
}
|
||||
|
||||
|
||||
public static String getYearEndTime() {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-12-31 23:59:59");
|
||||
Calendar c = Calendar.getInstance();
|
||||
return sdf.format(c.getTime());
|
||||
}
|
||||
|
||||
public static String getYearBeginTimeOfLastYear() {
|
||||
|
||||
Calendar c = Calendar.getInstance();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-01-01 00:00:00");
|
||||
c.add(Calendar.YEAR, -1);
|
||||
return sdf.format(c.getTime());
|
||||
}
|
||||
|
||||
|
||||
public static String getYearEndTimeOfLastYear() {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-12-31 23:59:59");
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.add(Calendar.YEAR, -1);
|
||||
return sdf.format(c.getTime());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 默认当天
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static Map<String, Integer> getWeekOfMonth() {
|
||||
return DateUtil.getWeekOfMonth(DateUtil.getToday());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 当前时间所属周,一周占用两个月的情况下属于上个月
|
||||
*
|
||||
* @param time
|
||||
* @return
|
||||
*/
|
||||
public static Map<String, Integer> getWeekOfMonth(String time) {
|
||||
//Calendar周日为一周的第一天
|
||||
//1.当月的1号为周日:
|
||||
//日期是否为周日 是,周数-1 第一个周日属于上个月最后一周
|
||||
//2.当月的1号为周一:
|
||||
//日期是否为周日 是,周数-1
|
||||
//3.当月的1号为周二--六:
|
||||
//日期是否为周日 是,周数-2 否,周数-1 为0属于上个月最后一周
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
int resultYear;
|
||||
int resultMonth;
|
||||
int resultWeekOfMonth;
|
||||
Map<String, Integer> resultMap = new HashMap<>(16);
|
||||
try {
|
||||
Date parse = sdf.parse(time);
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(parse);
|
||||
int year = calendar.get(Calendar.YEAR);
|
||||
int month = calendar.get(Calendar.MONTH);
|
||||
int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
|
||||
int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
|
||||
int weekOfMonth = calendar.get(Calendar.WEEK_OF_MONTH);
|
||||
resultYear = year;
|
||||
resultMonth = month + 1;
|
||||
|
||||
Calendar monthCalendar = Calendar.getInstance();
|
||||
monthCalendar.set(Calendar.YEAR, year);
|
||||
monthCalendar.set(Calendar.MONTH, month);
|
||||
monthCalendar.set(Calendar.DAY_OF_MONTH, 1);
|
||||
int monthDayOfWeek = monthCalendar.get(Calendar.DAY_OF_WEEK);
|
||||
|
||||
if (monthDayOfWeek == Calendar.SUNDAY) {
|
||||
if (dayOfWeek == Calendar.SUNDAY) {
|
||||
if (dayOfMonth == 1) {
|
||||
if (month == 0) {
|
||||
resultWeekOfMonth = getLastWeekOfMonth(year - 1, 11);
|
||||
resultYear = year - 1;
|
||||
resultMonth = 12;
|
||||
} else {
|
||||
resultWeekOfMonth = getLastWeekOfMonth(year, month - 1);
|
||||
resultMonth = month;
|
||||
}
|
||||
} else {
|
||||
resultWeekOfMonth = weekOfMonth - 1;
|
||||
}
|
||||
} else {
|
||||
resultWeekOfMonth = weekOfMonth;
|
||||
}
|
||||
} else if (monthDayOfWeek == Calendar.MONDAY) {
|
||||
if (dayOfWeek == Calendar.SUNDAY) {
|
||||
resultWeekOfMonth = weekOfMonth - 1;
|
||||
} else {
|
||||
resultWeekOfMonth = weekOfMonth;
|
||||
}
|
||||
} else {
|
||||
if (dayOfWeek == Calendar.SUNDAY) {
|
||||
resultWeekOfMonth = weekOfMonth - 2;
|
||||
} else {
|
||||
resultWeekOfMonth = weekOfMonth - 1;
|
||||
}
|
||||
if (resultWeekOfMonth == 0) {
|
||||
if (month == 0) {
|
||||
resultWeekOfMonth = getLastWeekOfMonth(year - 1, 11);
|
||||
resultYear = year - 1;
|
||||
resultMonth = 12;
|
||||
} else {
|
||||
resultWeekOfMonth = getLastWeekOfMonth(year, month - 1);
|
||||
resultMonth = month;
|
||||
}
|
||||
}
|
||||
}
|
||||
resultMap.put("year", resultYear);
|
||||
resultMap.put("month", resultMonth);
|
||||
resultMap.put("weekOfMonth", resultWeekOfMonth);
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 按月度获取当月最后一周是第几周
|
||||
*
|
||||
* @param year
|
||||
* @param month
|
||||
* @return
|
||||
*/
|
||||
private static int getLastWeekOfMonth(int year, int month) {
|
||||
int result;
|
||||
//当月1号
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.set(Calendar.YEAR, year);
|
||||
calendar.set(Calendar.MONTH, month);
|
||||
calendar.set(Calendar.DAY_OF_MONTH, 1);
|
||||
|
||||
//当月最后一天
|
||||
Calendar lastDayOfMonth = Calendar.getInstance();
|
||||
lastDayOfMonth.set(Calendar.YEAR, year);
|
||||
lastDayOfMonth.set(Calendar.MONTH, month);
|
||||
lastDayOfMonth.set(Calendar.DAY_OF_MONTH, 1);
|
||||
lastDayOfMonth.roll(Calendar.DAY_OF_MONTH, -1);
|
||||
|
||||
//
|
||||
int lastWeekOfMonth = lastDayOfMonth.get(Calendar.WEEK_OF_MONTH);
|
||||
//
|
||||
int lastDayOfWeek = lastDayOfMonth.get(Calendar.DAY_OF_WEEK);
|
||||
//当月1号是周几
|
||||
int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
|
||||
//如果1号是周日或周一,那么这个月的所有除了周日的日期用Calendar获取的周数与需要的周数是一致的;
|
||||
if (dayOfWeek == Calendar.SUNDAY || dayOfWeek == Calendar.MONDAY) {
|
||||
//如果最后一天是周日需要的周数要-1
|
||||
if (lastDayOfWeek == Calendar.SUNDAY) {
|
||||
result = lastWeekOfMonth - 1;
|
||||
} else {
|
||||
result = lastWeekOfMonth;
|
||||
}
|
||||
} else {//1号是周二,三,四,五,六的情况下,这个月的所有除了周日的日期用Calendar获取的周数-1后与需要的周数是一致的;
|
||||
//是周日的日期需要-2
|
||||
if (lastDayOfWeek == Calendar.SUNDAY) {
|
||||
result = lastWeekOfMonth - 2;
|
||||
} else {
|
||||
result = lastWeekOfMonth - 1;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String getWeekBeginTime() {
|
||||
Date date = new Date();
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(date);
|
||||
int dayofweek = cal.get(Calendar.DAY_OF_WEEK);
|
||||
if (dayofweek == 1) {
|
||||
dayofweek += 7;
|
||||
}
|
||||
cal.add(Calendar.DATE, 2 - dayofweek);
|
||||
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd 00:00:00");
|
||||
return sdf.format(cal.getTime());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取本周的结束时间
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static String getWeekEndTime() {
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTime(new Date());
|
||||
int dayofweek = cal.get(Calendar.DAY_OF_WEEK);
|
||||
if (dayofweek == 1) {
|
||||
dayofweek += 7;
|
||||
}
|
||||
cal.add(Calendar.DATE, 2 - dayofweek);
|
||||
|
||||
cal.setTime(cal.getTime());
|
||||
cal.add(Calendar.DAY_OF_WEEK, 6);
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd 23:59:59");
|
||||
return sdf.format(cal.getTime());
|
||||
}
|
||||
|
||||
public static String getSomeHoursAgo(int hours) {
|
||||
Date date = new Date(System.currentTimeMillis() - hours * 3600 * 1000L);
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
return sdf.format(date);
|
||||
}
|
||||
|
||||
public static String getSomeHoursLater(int hours) {
|
||||
Date date = new Date(System.currentTimeMillis() + hours * 3600 * 1000L);
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
return sdf.format(date);
|
||||
}
|
||||
|
||||
|
||||
public static String getSomeDaysAgo(int days) {
|
||||
Date date = new Date(System.currentTimeMillis() - days * 86400 * 1000L);
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
return sdf.format(date);
|
||||
}
|
||||
|
||||
public static String getSomeDaysLater(int days) {
|
||||
Date date = new Date(System.currentTimeMillis() + days * 86400 * 1000L);
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
return sdf.format(date);
|
||||
}
|
||||
|
||||
public static long getHourLeftMilliseconds() {
|
||||
Date now = new Date();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:59:59");
|
||||
try {
|
||||
Date end = sdf.parse(sdf2.format(now));
|
||||
|
||||
return end.getTime() - now.getTime();
|
||||
} catch (Exception ex) {
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long getDayLeftMilliseconds() {
|
||||
Date now = new Date();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
String endTime = getTodayEndTime();
|
||||
try {
|
||||
Date end = sdf.parse(endTime);
|
||||
return end.getTime() - now.getTime();
|
||||
} catch (Exception ex) {
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long getWeekLeftMilliseconds() {
|
||||
Date now = new Date();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
String endTime = getWeekEndTime();
|
||||
try {
|
||||
Date end = sdf.parse(endTime);
|
||||
return end.getTime() - now.getTime();
|
||||
} catch (Exception ex) {
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long getMonthLeftMilliseconds() {
|
||||
Date now = new Date();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
String endTime = getMonthEndTime();
|
||||
try {
|
||||
Date end = sdf.parse(endTime);
|
||||
return end.getTime() - now.getTime();
|
||||
} catch (Exception ex) {
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
public static long getYearLeftMilliseconds() {
|
||||
Date now = new Date();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
String endTime = getYearEndTime();
|
||||
try {
|
||||
Date end = sdf.parse(endTime);
|
||||
return end.getTime() - now.getTime();
|
||||
} catch (Exception ex) {
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.codvision.commoncore.utils;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.crypto.Mode;
|
||||
import cn.hutool.crypto.Padding;
|
||||
import cn.hutool.crypto.symmetric.AES;
|
||||
import com.codvision.commoncore.exception.BusinessException;
|
||||
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* 登陆密码解密
|
||||
*
|
||||
* @author hxl
|
||||
*/
|
||||
public class DecPwdUtil {
|
||||
|
||||
/**
|
||||
* AES数据块长度为128位,IV(偏移量)长度需要为16个字符(ECB模式不用IV)
|
||||
* 密钥(SECRET_KEY)根据指定密钥位数分别为16、24、32个字符,IV与密钥超过长度则截取,不足则在末尾填充'\0'补足
|
||||
*/
|
||||
private static final String SECRET_KEY = "8237909036518327";
|
||||
private static final String IV = "4a3f824766747c27";
|
||||
|
||||
public static String encryptAes(String password) {
|
||||
AES aes = new AES(Mode.CBC, Padding.ZeroPadding, new SecretKeySpec(SECRET_KEY.getBytes(), "AES"), new IvParameterSpec(IV.getBytes()));
|
||||
try {
|
||||
return Base64.encode(aes.encrypt(password, StandardCharsets.UTF_8));
|
||||
} catch (Exception e) {
|
||||
throw new BusinessException(30001, "密码加密失败!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static String decryptAes(String password) {
|
||||
AES aes = new AES(Mode.CBC, Padding.ZeroPadding, new SecretKeySpec(SECRET_KEY.getBytes(), "AES"), new IvParameterSpec(IV.getBytes()));
|
||||
try {
|
||||
byte[] decrypt = aes.decrypt(Base64.decode(password.getBytes(StandardCharsets.UTF_8)));
|
||||
return new String(decrypt, StandardCharsets.UTF_8);
|
||||
} catch (Exception e) {
|
||||
throw new BusinessException(30001, "密码解密失败!");
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(encryptAes("Jcpt@2023"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
package com.codvision.commoncore.utils;
|
||||
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Formatter;
|
||||
|
||||
/**
|
||||
* 加解密工具类
|
||||
*
|
||||
* @author codvision
|
||||
*/
|
||||
public class Encryption {
|
||||
private static final String chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
private static final int scale = 62;
|
||||
|
||||
/**
|
||||
* 进行加密
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String encoding(String password) {
|
||||
String md5 = "";
|
||||
try {
|
||||
// 创建一个md5算法对象
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
byte[] messageByte = ("Codvision" + password).getBytes(StandardCharsets.UTF_8);
|
||||
// 获得MD5字节数组,16*8=128位
|
||||
byte[] md5Byte = md.digest(messageByte);
|
||||
// 转换为16进制字符串
|
||||
md5 = bytesToHex(md5Byte);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return md5;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 二进制转十六进制
|
||||
*
|
||||
* @param bytes
|
||||
* @return
|
||||
*/
|
||||
public static String bytesToHex(byte[] bytes) {
|
||||
StringBuffer hexStr = new StringBuffer();
|
||||
int num;
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
num = bytes[i];
|
||||
if (num < 0) {
|
||||
num += 256;
|
||||
}
|
||||
if (num < 16) {
|
||||
hexStr.append("0");
|
||||
}
|
||||
hexStr.append(Integer.toHexString(num));
|
||||
}
|
||||
return hexStr.toString().toUpperCase();
|
||||
}
|
||||
|
||||
|
||||
public static String getSign(String jsTicket, String nonceStr, long timeStamp, String url) throws Exception {
|
||||
|
||||
String planTex = "jsapi_ticket=" + jsTicket + "&noncestr=" + nonceStr + "×tamp=" + timeStamp + "&url=" + url;
|
||||
MessageDigest crypt = null;
|
||||
try {
|
||||
crypt = MessageDigest.getInstance("SHA-1");
|
||||
crypt.reset();
|
||||
crypt.update(planTex.getBytes(StandardCharsets.UTF_8));
|
||||
return byteToHex(crypt.digest());
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new Exception(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将bytes类型的数据转化为16进制类型
|
||||
*
|
||||
* @param digest
|
||||
* @return
|
||||
*/
|
||||
private static String byteToHex(byte[] digest) {
|
||||
Formatter formatter = new Formatter();
|
||||
for (byte b : digest) {
|
||||
formatter.format("%02x", Byte.valueOf(b));
|
||||
}
|
||||
String result = formatter.toString();
|
||||
formatter.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 10进制转62进制
|
||||
*
|
||||
* @param num
|
||||
* @return
|
||||
*/
|
||||
public static String encode(int num) {
|
||||
java.util.Random random = new java.util.Random();
|
||||
StringBuffer sbf = new StringBuffer();
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int a = random.nextInt(10);
|
||||
sbf.append(a);
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int remainder = 0;
|
||||
while (num > scale - 1) {
|
||||
/**
|
||||
* 对 scale 进行求余,然后将余数追加至 sb 中,由于是从末位开始追加的,因此最后需要反转(reverse)字符串
|
||||
*/
|
||||
remainder = Long.valueOf(num % scale).intValue();
|
||||
sb.append(chars.charAt(remainder));
|
||||
|
||||
num = num / scale;
|
||||
}
|
||||
|
||||
sb.append(chars.charAt(Long.valueOf(num).intValue()));
|
||||
String value = sb.reverse().toString() + sbf;
|
||||
return value;
|
||||
}
|
||||
|
||||
public static int decode(String str) {
|
||||
str = str.substring(0, str.length() - 4);
|
||||
int num = 0;
|
||||
int index = 0;
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
/**
|
||||
* 查找字符的索引位置
|
||||
*/
|
||||
index = chars.indexOf(str.charAt(i));
|
||||
/**
|
||||
* 索引位置代表字符的数值
|
||||
*/
|
||||
num += (long) (index * (Math.pow(scale, str.length() - i - 1)));
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,346 @@
|
||||
package com.codvision.commoncore.utils;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.http.HttpEntityEnclosingRequest;
|
||||
import org.apache.http.HttpHost;
|
||||
import org.apache.http.HttpRequest;
|
||||
import org.apache.http.NoHttpResponseException;
|
||||
import org.apache.http.client.HttpRequestRetryHandler;
|
||||
import org.apache.http.client.config.RequestConfig;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.protocol.HttpClientContext;
|
||||
import org.apache.http.client.utils.URIBuilder;
|
||||
import org.apache.http.config.Registry;
|
||||
import org.apache.http.config.RegistryBuilder;
|
||||
import org.apache.http.conn.routing.HttpRoute;
|
||||
import org.apache.http.conn.socket.ConnectionSocketFactory;
|
||||
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
|
||||
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
|
||||
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
|
||||
import javax.net.ssl.*;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.URI;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* HttpClientUtils
|
||||
*
|
||||
* @author Bulbasaur
|
||||
* @since 2021/7/9 1:40 上午
|
||||
*/
|
||||
@Slf4j
|
||||
public class HttpClientUtils {
|
||||
|
||||
/**
|
||||
* org.apache.http.impl.client.CloseableHttpClient
|
||||
*/
|
||||
private static CloseableHttpClient httpClient = null;
|
||||
|
||||
private static CloseableHttpClient httpsClient = null;
|
||||
|
||||
//这里就直接默认固定了,因为以下三个参数在新建的method中仍然可以重新配置并被覆盖.
|
||||
/**
|
||||
* ms毫秒,从池中获取链接超时时间
|
||||
*/
|
||||
static final int CONNECTION_REQUEST_TIMEOUT = 30000;
|
||||
/**
|
||||
* ms毫秒,建立链接超时时间
|
||||
*/
|
||||
static final int CONNECT_TIMEOUT = 60000;
|
||||
/**
|
||||
* ms毫秒,读取超时时间
|
||||
*/
|
||||
static final int SOCKET_TIMEOUT = 60000;
|
||||
|
||||
/**
|
||||
* 总配置,主要涉及是以下两个参数,如果要作调整没有用到properties会比较后麻烦,但鉴于一经粘贴,随处可用的特点,就不再做依赖性配置化处理了.
|
||||
* 而且这个参数同一家公司基本不会变动.
|
||||
* 最大总并发,很重要的参数
|
||||
*/
|
||||
static final int MAX_TOTAL = 500;
|
||||
/**
|
||||
* 每路并发,很重要的参数
|
||||
*/
|
||||
static final int MAX_PER_ROUTE = 100;
|
||||
|
||||
/**
|
||||
* 正常情况这里应该配成MAP或LIST
|
||||
* 细化配置参数,用来对每路参数做精细化处理,可以管控各ip的流量,比如默认配置请求baidu:80端口最大100个并发链接,
|
||||
* 每个细化配置之ip(不重要,在特殊场景很有用)
|
||||
*/
|
||||
static final String DETAIL_HOST_NAME = "http://www.baidu.com";
|
||||
|
||||
/**
|
||||
* 每个细化配置之port(不重要,在特殊场景很有用)
|
||||
*/
|
||||
static final int DETAIL_PORT = 80;
|
||||
/**
|
||||
* 每个细化配置之最大并发数(不重要,在特殊场景很有用)
|
||||
*/
|
||||
static final int DETAIL_MAX_PER_ROUTE = 100;
|
||||
|
||||
private synchronized static CloseableHttpClient getHttpClient() {
|
||||
if (null == httpClient) {
|
||||
httpClient = initHttp();
|
||||
}
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
private synchronized static CloseableHttpClient getHttpsClient() {
|
||||
if (null == httpsClient) {
|
||||
httpsClient = initHttps();
|
||||
}
|
||||
return httpsClient;
|
||||
}
|
||||
|
||||
//绕过证书
|
||||
public static CloseableHttpClient initHttps() {
|
||||
try {
|
||||
SSLContext ctx = SSLContext.getInstance("TLS");
|
||||
X509TrustManager tm = new X509TrustManager() {
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] arg0,
|
||||
String arg1) throws CertificateException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] arg0,
|
||||
String arg1) throws CertificateException {
|
||||
}
|
||||
};
|
||||
ctx.init(null, new TrustManager[]{tm}, null);
|
||||
SSLConnectionSocketFactory ssf = new SSLConnectionSocketFactory(
|
||||
ctx, NoopHostnameVerifier.INSTANCE);
|
||||
httpsClient = HttpClients.custom()
|
||||
.setSSLSocketFactory(ssf).build();
|
||||
return httpsClient;
|
||||
} catch (Exception e) {
|
||||
return HttpClients.createDefault();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 链接池初始化 这里最重要的一点理解就是. 让CloseableHttpClient 一直活在池的世界里, 但是HttpPost却一直用完就消掉.
|
||||
* 这样可以让链接一直保持着.
|
||||
*/
|
||||
private static CloseableHttpClient initHttp() {
|
||||
CloseableHttpClient newHotpoint;
|
||||
|
||||
//设置连接池
|
||||
ConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory();
|
||||
LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory.getSocketFactory();
|
||||
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create().register("http", plainsf).register("https", sslsf).build();
|
||||
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
|
||||
//将最大连接数增加
|
||||
cm.setMaxTotal(MAX_TOTAL);
|
||||
//将每个路由基础的连接增加
|
||||
cm.setDefaultMaxPerRoute(MAX_PER_ROUTE);
|
||||
|
||||
//细化配置开始,其实这里用Map或List的for循环来配置每个链接,在特殊场景很有用.
|
||||
//将每个路由基础的连接做特殊化配置,一般用不着
|
||||
HttpHost httpHost = new HttpHost(DETAIL_HOST_NAME, DETAIL_PORT);
|
||||
//将目标主机的最大连接数增加
|
||||
cm.setMaxPerRoute(new HttpRoute(httpHost), DETAIL_MAX_PER_ROUTE);
|
||||
//细化配置结束
|
||||
|
||||
//请求重试处理
|
||||
HttpRequestRetryHandler httpRequestRetryHandler = (exception, executionCount, context) -> {
|
||||
if (executionCount >= 2) {//如果已经重试了2次,就放弃
|
||||
return false;
|
||||
}
|
||||
if (exception instanceof NoHttpResponseException) {//如果服务器丢掉了连接,那么就重试
|
||||
return true;
|
||||
}
|
||||
if (exception instanceof SSLHandshakeException) {//不要重试SSL握手异常
|
||||
return false;
|
||||
}
|
||||
if (exception instanceof InterruptedIOException) {//超时
|
||||
return false;
|
||||
}
|
||||
if (exception instanceof UnknownHostException) {//目标服务器不可达
|
||||
return false;
|
||||
}
|
||||
if (exception instanceof SSLException) {//SSL握手异常
|
||||
return false;
|
||||
}
|
||||
|
||||
HttpClientContext clientContext = HttpClientContext.adapt(context);
|
||||
HttpRequest request = clientContext.getRequest();
|
||||
//如果请求是幂等的,就再次尝试
|
||||
return !(request instanceof HttpEntityEnclosingRequest);
|
||||
};
|
||||
|
||||
//配置请求的超时设置
|
||||
RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT).setConnectTimeout(CONNECT_TIMEOUT).setSocketTimeout(SOCKET_TIMEOUT).build();
|
||||
newHotpoint = HttpClients.custom().setConnectionManager(cm).setDefaultRequestConfig(requestConfig).setRetryHandler(httpRequestRetryHandler).build();
|
||||
return newHotpoint;
|
||||
}
|
||||
|
||||
public static String doGet(String url, Map<String, Object> param) {
|
||||
//httpClient
|
||||
CloseableHttpClient httpClient;
|
||||
if (url.startsWith("https://")) {
|
||||
httpClient = getHttpsClient();
|
||||
} else {
|
||||
httpClient = getHttpClient();
|
||||
}
|
||||
|
||||
String resultString = "";
|
||||
CloseableHttpResponse response = null;
|
||||
try {
|
||||
//创建uri
|
||||
URIBuilder builder = new URIBuilder(url);
|
||||
if (param != null) {
|
||||
for (String key : param.keySet()) {
|
||||
builder.addParameter(key, (String) param.get(key));
|
||||
}
|
||||
}
|
||||
URI uri = builder.build();
|
||||
|
||||
//创建http GET请求
|
||||
HttpGet httpGet = new HttpGet(uri);
|
||||
log.info(httpGet.toString());
|
||||
//执行请求
|
||||
response = httpClient.execute(httpGet);
|
||||
//判断返回状态是否为200
|
||||
if (response.getStatusLine().getStatusCode() == 200) {
|
||||
resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
|
||||
log.info(resultString);
|
||||
} else {
|
||||
log.error(url + "请求失败:" + response);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(url + "get请求错误:", e);
|
||||
throw new RuntimeException(e.getMessage());
|
||||
} finally {
|
||||
try {
|
||||
if (response != null) {
|
||||
response.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("Get错误", e);
|
||||
throw new RuntimeException(e.getMessage());
|
||||
}
|
||||
}
|
||||
return resultString;
|
||||
}
|
||||
|
||||
public static String doPost(String url, Map<String, String> headers, String body) {
|
||||
//httpClient
|
||||
CloseableHttpClient httpClient;
|
||||
if (url.startsWith("https://")) {
|
||||
httpClient = getHttpsClient();
|
||||
} else {
|
||||
httpClient = getHttpClient();
|
||||
}
|
||||
|
||||
String resultString = "";
|
||||
CloseableHttpResponse response = null;
|
||||
try {
|
||||
//创建http GET请求
|
||||
HttpPost httpPost = new HttpPost(url);
|
||||
log.info(httpPost.toString());
|
||||
httpPost.addHeader("Content-Type", "application/json;charset=utf-8");
|
||||
if (CollectionUtil.isNotEmpty(headers)) {
|
||||
for (Map.Entry<String, String> entry : headers.entrySet()) {
|
||||
httpPost.addHeader(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
StringEntity stringEntity = new StringEntity(body, "UTF-8");
|
||||
httpPost.setEntity(stringEntity);
|
||||
//执行请求
|
||||
response = httpClient.execute(httpPost);
|
||||
//判断返回状态是否为200
|
||||
if (response.getStatusLine().getStatusCode() == 200) {
|
||||
resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
|
||||
log.info(resultString);
|
||||
} else {
|
||||
log.error(url + "请求失败:" + response);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(url + "post请求错误:", e);
|
||||
throw new RuntimeException(e.getMessage());
|
||||
} finally {
|
||||
try {
|
||||
if (response != null) {
|
||||
response.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("Post错误", e);
|
||||
throw new RuntimeException(e.getMessage());
|
||||
}
|
||||
}
|
||||
return resultString;
|
||||
}
|
||||
|
||||
public static String doPost(String url, Map<String, String> headers, Map<String, String> params) {
|
||||
//httpClient
|
||||
CloseableHttpClient httpClient;
|
||||
if (url.startsWith("https://")) {
|
||||
httpClient = getHttpsClient();
|
||||
} else {
|
||||
httpClient = getHttpClient();
|
||||
}
|
||||
|
||||
String resultString = "";
|
||||
CloseableHttpResponse response = null;
|
||||
try {
|
||||
//创建uri
|
||||
URIBuilder builder = new URIBuilder(url);
|
||||
if (params != null) {
|
||||
for (String key : params.keySet()) {
|
||||
builder.addParameter(key, (String) params.get(key));
|
||||
}
|
||||
}
|
||||
URI uri = builder.build();
|
||||
HttpPost httpPost = new HttpPost(uri);
|
||||
log.info(httpPost.toString());
|
||||
if (CollectionUtil.isNotEmpty(headers)) {
|
||||
for (Map.Entry<String, String> entry : headers.entrySet()) {
|
||||
httpPost.addHeader(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
//执行请求
|
||||
response = httpClient.execute(httpPost);
|
||||
//判断返回状态是否为200
|
||||
if (response.getStatusLine().getStatusCode() == 200) {
|
||||
resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
|
||||
log.info(resultString);
|
||||
} else {
|
||||
log.error(url + "请求失败:" + response);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(url + "post请求错误:", e);
|
||||
throw new RuntimeException(e.getMessage());
|
||||
} finally {
|
||||
try {
|
||||
if (response != null) {
|
||||
response.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("Post错误", e);
|
||||
throw new RuntimeException(e.getMessage());
|
||||
}
|
||||
}
|
||||
return resultString;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,339 @@
|
||||
package com.codvision.commoncore.utils;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 身份证号码的格式:610821-20061222-612-X 由18位数字组成:前6位为地址码,第7至14位为出生日期码,第15至17位为顺序码,
|
||||
* 第18位为校验码。检验码分别是0-10共11个数字,当检验码为“10”时,为了保证公民身份证号码18位,所以用“X”表示。虽然校验码为“X”不能更换,但若需全用数字表示,只需将18位公民身份号码转换成15位居民身份证号码,去掉第7至8位和最后1位3个数码。
|
||||
* 当今的身份证号码有15位和18位之分。1985年我国实行居民身份证制度,当时签发的身份证号码是15位的,1999年签发的身份证由于年份的扩展(由两位变为四位)和末尾加了效验码,就成了18位。
|
||||
* (1)前1、2位数字表示:所在省份的代码;
|
||||
* (2)第3、4位数字表示:所在城市的代码;
|
||||
* (3)第5、6位数字表示:所在区县的代码;
|
||||
* (4)第7~14位数字表示:出生年、月、日;
|
||||
* (5)第15、16位数字表示:所在地的派出所的代码;
|
||||
* (6)第17位数字表示性别:奇数表示男性,偶数表示女性
|
||||
* (7)第18位数字是校检码:根据一定算法生成
|
||||
*
|
||||
* @author codvision
|
||||
*/
|
||||
public class IdCardUtil {
|
||||
|
||||
/**
|
||||
* 身份证有效
|
||||
*/
|
||||
public static final String VALIDITY = "该身份证有效!";
|
||||
/**
|
||||
* 位数不足
|
||||
*/
|
||||
public static final String LACKDIGITS = "身份证号码长度应该为15位或18位。请检查是否有多余的空格";
|
||||
/**
|
||||
* 最后一位应为数字
|
||||
*/
|
||||
public static final String LASTOFNUMBER = "身份证15位号码都应为数字 ; 18位号码除最后一位外,都应为数字。";
|
||||
/**
|
||||
* 出生日期无效
|
||||
*/
|
||||
public static final String INVALIDBIRTH = "身份证出生日期无效。";
|
||||
/**
|
||||
* 生日不在有效范围
|
||||
*/
|
||||
public static final String INVALIDSCOPE = "身份证生日不在有效范围。";
|
||||
/**
|
||||
* 月份无效
|
||||
*/
|
||||
public static final String INVALIDMONTH = "身份证月份无效";
|
||||
/**
|
||||
* 日期无效
|
||||
*/
|
||||
public static final String INVALIDDAY = "身份证日期无效";
|
||||
/**
|
||||
* 身份证地区编码错误
|
||||
*/
|
||||
public static final String CODINGERROR = "身份证地区编码错误。";
|
||||
/**
|
||||
* 身份证校验码无效
|
||||
*/
|
||||
public static final String INVALIDCALIBRATION = "身份证校验码无效,不是合法的身份证号码";
|
||||
|
||||
private static final Pattern pattern = Pattern.compile("[0-9]*");
|
||||
private static final Pattern idCardPattern = Pattern.compile("^((\\d{2}(([02468][048])|([13579][26]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])))))|(\\d{2}(([02468][1235679])|([13579][01345789]))[\\-\\/\\s]?((((0?[13578])|(1[02]))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\\-\\/\\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\\-\\/\\s]?((0?[1-9])|(1[0-9])|(2[0-8]))))))?$");
|
||||
|
||||
public static Integer getCardSex(String cardCode) {
|
||||
int sex = 0;
|
||||
if (StringUtils.isNotEmpty(cardCode)) {
|
||||
if (cardCode.length() == 18) {
|
||||
if (Integer.parseInt(cardCode.substring(16).substring(0, 1)) % 2 == 0) {
|
||||
sex = 2;
|
||||
} else {
|
||||
sex = 1;
|
||||
}
|
||||
} else if (cardCode.length() == 15) {
|
||||
if (Integer.parseInt(cardCode.substring(14, 15)) % 2 == 0) {
|
||||
sex = 2;
|
||||
} else {
|
||||
sex = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return sex;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检验身份证号码是否符合规范
|
||||
*
|
||||
* @param idStr 身份证号码
|
||||
* @return 错误信息或成功信息
|
||||
*/
|
||||
public static String cardCodeVerifySimple(String idStr) {
|
||||
//记录错误信息
|
||||
String tipInfo = VALIDITY;
|
||||
String ai = "";
|
||||
idStr = idStr.trim();
|
||||
// 判断号码的长度 15位或18位
|
||||
if (idStr.length() != 15 && idStr.length() != 18) {
|
||||
tipInfo = LACKDIGITS;
|
||||
return tipInfo;
|
||||
}
|
||||
|
||||
// 18位身份证前17位位数字,如果是15位的身份证则所有号码都为数字
|
||||
if (idStr.length() == 18) {
|
||||
ai = idStr.substring(0, 17);
|
||||
} else if (idStr.length() == 15) {
|
||||
ai = idStr.substring(0, 6) + "19" + idStr.substring(6, 15);
|
||||
}
|
||||
if (isNumeric(ai) == false) {
|
||||
tipInfo = LASTOFNUMBER;
|
||||
return tipInfo;
|
||||
}
|
||||
|
||||
// 判断出生年月是否有效
|
||||
//年份
|
||||
String strYear = ai.substring(6, 10);
|
||||
// 月份
|
||||
String strMonth = ai.substring(10, 12);
|
||||
// 日期
|
||||
String strDay = ai.substring(12, 14);
|
||||
if (isDate(strYear + "-" + strMonth + "-" + strDay) == false) {
|
||||
tipInfo = INVALIDBIRTH;
|
||||
return tipInfo;
|
||||
}
|
||||
GregorianCalendar gc = new GregorianCalendar();
|
||||
SimpleDateFormat s = new SimpleDateFormat("yyyy-MM-dd");
|
||||
try {
|
||||
if ((gc.get(Calendar.YEAR) - Integer.parseInt(strYear)) > 150
|
||||
|| (gc.getTime().getTime() - s.parse(strYear + "-" + strMonth + "-" + strDay).getTime()) < 0) {
|
||||
tipInfo = INVALIDSCOPE;
|
||||
return tipInfo;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (Integer.parseInt(strMonth) > 12 || Integer.parseInt(strMonth) == 0) {
|
||||
tipInfo = INVALIDMONTH;
|
||||
return tipInfo;
|
||||
}
|
||||
if (Integer.parseInt(strDay) > 31 || Integer.parseInt(strDay) == 0) {
|
||||
tipInfo = INVALIDDAY;
|
||||
return tipInfo;
|
||||
}
|
||||
|
||||
// 判断地区码是否有效
|
||||
Hashtable<String, String> areacode = getAreaCode();
|
||||
// 如果身份证前两位的地区码不在Hashtable,则地区码有误
|
||||
if (areacode.get(ai.substring(0, 2)) == null) {
|
||||
tipInfo = CODINGERROR;
|
||||
return tipInfo;
|
||||
}
|
||||
|
||||
if (isVarifyCode(ai, idStr) == false) {
|
||||
tipInfo = INVALIDCALIBRATION;
|
||||
return tipInfo;
|
||||
}
|
||||
|
||||
return tipInfo;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据身份证的号码算出当前身份证持有者的性别和年龄 18位身份证
|
||||
*
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static Map<String, Object> getCarInfo18W(String cardCode)
|
||||
throws Exception {
|
||||
Map<String, Object> map = new HashMap<String, Object>(16);
|
||||
// 得到年份
|
||||
String year = cardCode.substring(6).substring(0, 4);
|
||||
// 得到月份
|
||||
String yue = cardCode.substring(10).substring(0, 2);
|
||||
String sex;
|
||||
// 判断性别
|
||||
if (Integer.parseInt(cardCode.substring(16).substring(0, 1)) % 2 == 0) {
|
||||
sex = "女";
|
||||
} else {
|
||||
sex = "男";
|
||||
}
|
||||
// 得到当前的系统时间
|
||||
Date date = new Date();
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
|
||||
// 当前年份
|
||||
String fyear = format.format(date).substring(0, 4);
|
||||
// 月份
|
||||
String fyue = format.format(date).substring(5, 7);
|
||||
int age = 0;
|
||||
// 当前月份大于用户出身的月份表示已过生
|
||||
if (Integer.parseInt(yue) <= Integer.parseInt(fyue)) {
|
||||
age = Integer.parseInt(fyear) - Integer.parseInt(year) + 1;
|
||||
// 当前用户还没过生
|
||||
} else {
|
||||
age = Integer.parseInt(fyear) - Integer.parseInt(year);
|
||||
}
|
||||
map.put("sex", sex);
|
||||
map.put("age", age);
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 15位身份证的验证
|
||||
*
|
||||
* @param
|
||||
* @throws Exception
|
||||
*/
|
||||
public static Map<String, Object> getCarInfo15W(String card)
|
||||
throws Exception {
|
||||
Map<String, Object> map = new HashMap<String, Object>(16);
|
||||
// 年份
|
||||
String uyear = "19" + card.substring(6, 8);
|
||||
// 月份
|
||||
String uyue = card.substring(8, 10);
|
||||
// 用户的性别
|
||||
String usex = card.substring(14, 15);
|
||||
String sex;
|
||||
if (Integer.parseInt(usex) % 2 == 0) {
|
||||
sex = "女";
|
||||
} else {
|
||||
sex = "男";
|
||||
}
|
||||
// 得到当前的系统时间
|
||||
Date date = new Date();
|
||||
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
|
||||
// 当前年份
|
||||
String fyear = format.format(date).substring(0, 4);
|
||||
// 月份
|
||||
String fyue = format.format(date).substring(5, 7);
|
||||
int age = 0;
|
||||
// 当前月份大于用户出身的月份表示已过生
|
||||
if (Integer.parseInt(uyue) <= Integer.parseInt(fyue)) {
|
||||
age = Integer.parseInt(fyear) - Integer.parseInt(uyear) + 1;
|
||||
// 当前用户还没过生
|
||||
} else {
|
||||
age = Integer.parseInt(fyear) - Integer.parseInt(uyear);
|
||||
}
|
||||
map.put("sex", sex);
|
||||
map.put("age", age);
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断第18位校验码是否正确 第18位校验码的计算方式:
|
||||
* 1. 对前17位数字本体码加权求和 公式为:S = Sum(Ai * Wi), i =
|
||||
* 0, ... , 16 其中Ai表示第i个位置上的身份证号码数字值,Wi表示第i位置上的加权因子,其各位对应的值依次为: 7 9 10 5 8 4
|
||||
* 2 1 6 3 7 9 10 5 8 4 2
|
||||
* 2. 用11对计算结果取模 Y = mod(S, 11)
|
||||
* 3. 根据模的值得到对应的校验码
|
||||
* 对应关系为: Y值: 0 1 2 3 4 5 6 7 8 9 10 校验码: 1 0 X 9 8 7 6 5 4 3 2
|
||||
*/
|
||||
private static boolean isVarifyCode(String ai, String idStr) {
|
||||
String[] varifyCode = {"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"};
|
||||
String[] wi = {"7", "9", "10", "5", "8", "4", "2", "1", "6", "3", "7", "9", "10", "5", "8", "4", "2"};
|
||||
int sum = 0;
|
||||
for (int i = 0; i < 17; i++) {
|
||||
sum = sum + Integer.parseInt(String.valueOf(ai.charAt(i))) * Integer.parseInt(wi[i]);
|
||||
}
|
||||
int modValue = sum % 11;
|
||||
String strVerifyCode = varifyCode[modValue];
|
||||
ai = ai + strVerifyCode;
|
||||
if (idStr.length() == 18) {
|
||||
return ai.equals(idStr) != false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将所有地址编码保存在一个Hashtable中
|
||||
*
|
||||
* @return Hashtable 对象
|
||||
*/
|
||||
|
||||
private static Hashtable<String, String> getAreaCode() {
|
||||
Hashtable<String, String> hashtable = new Hashtable<String, String>();
|
||||
hashtable.put("11", "北京");
|
||||
hashtable.put("12", "天津");
|
||||
hashtable.put("13", "河北");
|
||||
hashtable.put("14", "山西");
|
||||
hashtable.put("15", "内蒙古");
|
||||
hashtable.put("21", "辽宁");
|
||||
hashtable.put("22", "吉林");
|
||||
hashtable.put("23", "黑龙江");
|
||||
hashtable.put("31", "上海");
|
||||
hashtable.put("32", "江苏");
|
||||
hashtable.put("33", "浙江");
|
||||
hashtable.put("34", "安徽");
|
||||
hashtable.put("35", "福建");
|
||||
hashtable.put("36", "江西");
|
||||
hashtable.put("37", "山东");
|
||||
hashtable.put("41", "河南");
|
||||
hashtable.put("42", "湖北");
|
||||
hashtable.put("43", "湖南");
|
||||
hashtable.put("44", "广东");
|
||||
hashtable.put("45", "广西");
|
||||
hashtable.put("46", "海南");
|
||||
hashtable.put("50", "重庆");
|
||||
hashtable.put("51", "四川");
|
||||
hashtable.put("52", "贵州");
|
||||
hashtable.put("53", "云南");
|
||||
hashtable.put("54", "西藏");
|
||||
hashtable.put("61", "陕西");
|
||||
hashtable.put("62", "甘肃");
|
||||
hashtable.put("63", "青海");
|
||||
hashtable.put("64", "宁夏");
|
||||
hashtable.put("65", "新疆");
|
||||
hashtable.put("71", "台湾");
|
||||
hashtable.put("81", "香港");
|
||||
hashtable.put("82", "澳门");
|
||||
hashtable.put("91", "国外");
|
||||
return hashtable;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断字符串是否为数字,0-9重复0次或者多次
|
||||
*
|
||||
* @param strnum
|
||||
* @return true, 符合; false, 不符合。
|
||||
*/
|
||||
private static boolean isNumeric(String strnum) {
|
||||
|
||||
Matcher isNum = pattern.matcher(strnum);
|
||||
return isNum.matches();
|
||||
}
|
||||
|
||||
/**
|
||||
* 功能:判断字符串出生日期是否符合正则表达式:包括年月日,闰年、平年和每月31天、30天和闰月的28天或者29天
|
||||
*
|
||||
* @param strDate
|
||||
* @return true, 符合; false, 不符合。
|
||||
*/
|
||||
public static boolean isDate(String strDate) {
|
||||
Matcher m = idCardPattern.matcher(strDate);
|
||||
return m.matches();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.codvision.commoncore.utils;
|
||||
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.util.HexUtil;
|
||||
import cn.hutool.crypto.CryptoException;
|
||||
import cn.hutool.crypto.KeyUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import cn.hutool.crypto.asymmetric.SignAlgorithm;
|
||||
|
||||
import java.security.*;
|
||||
|
||||
/**
|
||||
* @author hxl
|
||||
*/
|
||||
public class LySign {
|
||||
|
||||
/**
|
||||
* 算法
|
||||
*/
|
||||
protected String algorithm;
|
||||
|
||||
protected String algorithmAfterWith;
|
||||
/**
|
||||
* 公钥
|
||||
*/
|
||||
protected PublicKey publicKey;
|
||||
/**
|
||||
* 私钥
|
||||
*/
|
||||
protected PrivateKey privateKey;
|
||||
|
||||
/**
|
||||
* 签名,用于签名和验证
|
||||
*/
|
||||
protected Signature signature;
|
||||
|
||||
public LySign(SignAlgorithm algorithmE, byte[] privateKey, byte[] publicKey) {
|
||||
this.algorithm = algorithmE.getValue();
|
||||
this.algorithmAfterWith = KeyUtil.getAlgorithmAfterWith(this.algorithm);
|
||||
this.privateKey = SecureUtil.generatePrivateKey(this.algorithmAfterWith, privateKey);
|
||||
this.publicKey = SecureUtil.generatePublicKey(this.algorithmAfterWith, publicKey);
|
||||
try {
|
||||
this.signature = Signature.getInstance(algorithm);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new CryptoException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static LySign of(SignAlgorithm algorithm, String privateKey, String publicKey, boolean hexStr) {
|
||||
byte[] privateBytes;
|
||||
byte[] publicBytes;
|
||||
if (hexStr) {
|
||||
privateBytes = HexUtil.decodeHex(privateKey);
|
||||
publicBytes = HexUtil.decodeHex(publicKey);
|
||||
} else {
|
||||
privateBytes = Base64.decode(privateKey);
|
||||
publicBytes = Base64.decode(publicKey);
|
||||
}
|
||||
return new LySign(algorithm, privateBytes, publicBytes);
|
||||
}
|
||||
|
||||
public String sign(String data) {
|
||||
try {
|
||||
signature.initSign(privateKey);
|
||||
signature.update(data.getBytes());
|
||||
byte[] sign = signature.sign();
|
||||
return HexUtil.encodeHexStr(sign, false);
|
||||
} catch (InvalidKeyException | SignatureException e) {
|
||||
throw new CryptoException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean verify(String data, String sign) {
|
||||
try {
|
||||
signature.initVerify(publicKey);
|
||||
signature.update(data.getBytes());
|
||||
return signature.verify(HexUtil.decodeHex(sign));
|
||||
} catch (InvalidKeyException | SignatureException e) {
|
||||
throw new CryptoException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
package com.codvision.commoncore.utils;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* @author zjm
|
||||
* @version V1.0
|
||||
* @Package com.codvision.serverboot.util
|
||||
* @date 2020/3/4 10:00
|
||||
* @Copyright © 2017-2020 杭州码全科技有限公司
|
||||
*/
|
||||
public class Md5Utils {
|
||||
|
||||
/**
|
||||
* md5加密
|
||||
*
|
||||
* @param message 内容
|
||||
* @return 摘要
|
||||
*/
|
||||
public static String md5Encode(String message) {
|
||||
String temp = "";
|
||||
try {
|
||||
MessageDigest md5Digest = MessageDigest.getInstance("MD5");
|
||||
byte[] d = md5Digest.digest(message.getBytes());
|
||||
temp = converByteToHexString(d);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 转换byte到16进制
|
||||
*
|
||||
* @param b 要转换的byte
|
||||
* @return 16进制对应的字符
|
||||
*/
|
||||
private static String converByteToHexString(byte[] b) {
|
||||
String result = "";
|
||||
for (int i = 1; i < b.length; i++) {
|
||||
int temp = b[i] & 0xff;
|
||||
String tempHex = Integer.toHexString(temp);
|
||||
if (tempHex.length() < 2) {
|
||||
|
||||
result += "" + tempHex;
|
||||
} else {
|
||||
result += tempHex;
|
||||
}
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取摘要
|
||||
*
|
||||
* @param str 内容
|
||||
* @return 摘要
|
||||
*/
|
||||
public static String getMd5(String str) {
|
||||
try {
|
||||
// 生成一个MD5加密计算摘要
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
// 计算md5函数
|
||||
md.update(str.getBytes());
|
||||
String md5 = new BigInteger(1, md.digest()).toString(16);
|
||||
return fillMd5(md5);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("MD5加密错误:" + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 填充摘要
|
||||
*
|
||||
* @param md5 摘要
|
||||
* @return 填充后的摘要
|
||||
*/
|
||||
public static String fillMd5(String md5) {
|
||||
return md5.length() == 32 ? md5 : fillMd5("0" + md5);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 使用指定哈希算法计算摘要信息
|
||||
*
|
||||
* @param content 内容
|
||||
* @param algorithm 哈希算法
|
||||
* @return 内容摘要
|
||||
*/
|
||||
public static String getMd5Digest(String content, String algorithm) {
|
||||
try {
|
||||
MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
|
||||
messageDigest.update(content.getBytes(StandardCharsets.UTF_8));
|
||||
return bytesToHexString(messageDigest.digest());
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字节数组转换成16进制字符串
|
||||
*
|
||||
* @param bytes 即将转换的数据
|
||||
* @return 16进制字符串
|
||||
*/
|
||||
private static String bytesToHexString(byte[] bytes) {
|
||||
StringBuffer sb = new StringBuffer(bytes.length);
|
||||
String temp = null;
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
temp = Integer.toHexString(0xFF & bytes[i]);
|
||||
if (temp.length() < 2) {
|
||||
sb.append(0);
|
||||
}
|
||||
sb.append(temp);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String md532Encode(String s) {
|
||||
try {
|
||||
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||
byte[] bytes = md.digest(s.getBytes(StandardCharsets.UTF_8));
|
||||
return toHex(bytes);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String toHex(byte[] bytes) {
|
||||
|
||||
final char[] HEX_DIGITS = "0123456789abcdef".toCharArray();
|
||||
StringBuilder ret = new StringBuilder(bytes.length * 2);
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
ret.append(HEX_DIGITS[(bytes[i] >> 4) & 0x0f]);
|
||||
ret.append(HEX_DIGITS[bytes[i] & 0x0f]);
|
||||
}
|
||||
return ret.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.codvision.commoncore.utils;
|
||||
|
||||
import com.codvision.commoncore.enums.NetworkData;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 网络工具类
|
||||
* Created by mrhe on 2018/2/17.
|
||||
*/
|
||||
public class NetworkUtils {
|
||||
|
||||
/**
|
||||
* 获取请求主机IP地址,如果通过代理进来,则透过防火墙获取真实IP地址;
|
||||
*
|
||||
* @param request
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public static String getIpAddress(HttpServletRequest request) throws IOException {
|
||||
// 获取请求主机IP地址,如果通过代理进来,则透过防火墙获取真实IP地址
|
||||
|
||||
String ip = request.getHeader("X-Forwarded-For");
|
||||
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("Proxy-Client-IP");
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("WL-Proxy-Client-IP");
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("HTTP_CLIENT_IP");
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
|
||||
}
|
||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
|
||||
ip = request.getRemoteAddr();
|
||||
}
|
||||
} else if (ip.length() > 15) {
|
||||
String[] ips = ip.split(",");
|
||||
for (int index = 0; index < ips.length; index++) {
|
||||
String strIp = ips[index];
|
||||
if (!("unknown".equalsIgnoreCase(strIp))) {
|
||||
ip = strIp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ip.equals(NetworkData.NET_WORK_ID.getDesc()) ? "127.0.0.1" : ip;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.codvision.commoncore.utils;
|
||||
|
||||
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author zjm
|
||||
* @version V1.0
|
||||
* @Package com.codvision.serverboot.util
|
||||
* @date 2020/3/4 9:48
|
||||
* @Copyright © 2017-2020 杭州码全科技有限公司
|
||||
*/
|
||||
public class ParamUtil {
|
||||
|
||||
public static boolean isKeyExist(Map<String, Object> params, String key) {
|
||||
return isKeyExist(params, key, true);
|
||||
}
|
||||
|
||||
public static boolean isKeyExist(Map<String, Object> params, String key, boolean ignoreEmptyValue) {
|
||||
if (ignoreEmptyValue) {
|
||||
return params.containsKey(key) && null != params.get(key) && StringUtils.isNotEmpty(params.get(key).toString());
|
||||
} else {
|
||||
return params.containsKey(key) && null != params.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
public static Map<String, String> objectToMap(Object obj) throws IllegalAccessException {
|
||||
Map<String, String> map = new HashMap<String, String>(16);
|
||||
Class<?> clazz = obj.getClass();
|
||||
for (Field field : clazz.getDeclaredFields()) {
|
||||
field.setAccessible(true);
|
||||
String fieldName = field.getName();
|
||||
if (!(ObjectUtils.isEmpty(field.get(obj)))) {
|
||||
Object value = field.get(obj);
|
||||
map.put(fieldName, String.valueOf(value));
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.codvision.commoncore.utils;
|
||||
|
||||
|
||||
import com.codvision.commoncore.common.ResponseEntity;
|
||||
import com.codvision.commoncore.exception.BusinessException;
|
||||
import lombok.NonNull;
|
||||
|
||||
/**
|
||||
* @author hxl
|
||||
*/
|
||||
public final class Preconditions {
|
||||
|
||||
/**
|
||||
* @param expression 布尔表达式
|
||||
* @param code 自定义响应状态码
|
||||
* @param errorMsg 检查失败时使用的异常消息
|
||||
* @throws BusinessException if {@code expression} is false
|
||||
*/
|
||||
public static void checkArgument(boolean expression, int code, @NonNull Object errorMsg) {
|
||||
if (!expression) {
|
||||
throw new BusinessException(code, String.valueOf(errorMsg));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean expression, @NonNull Object errorMsg) {
|
||||
if (!expression) {
|
||||
throw new BusinessException(String.valueOf(errorMsg));
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkArgument(boolean expression, int code) {
|
||||
if (!expression) {
|
||||
throw new BusinessException(code, new ResponseEntity<>().setCode(code).getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.codvision.commoncore.utils;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* @author: fuyuaaaaa
|
||||
* @description: 随机数 工具 类
|
||||
* @program: smart-rear
|
||||
* @creat: 2018-09-21 10:10
|
||||
**/
|
||||
public class RandomUtil {
|
||||
|
||||
/**
|
||||
* 获取6位数验证码
|
||||
*
|
||||
* @return 验证码
|
||||
*/
|
||||
public static String getVerificationCode() {
|
||||
Random random = new Random();
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (int i = 0; i < 6; i++) {
|
||||
int a = random.nextInt(10);
|
||||
sb.append(a);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定长度验证码
|
||||
*
|
||||
* @param length 长度
|
||||
* @return 验证码
|
||||
*/
|
||||
public static String getRandomStr(int length) {
|
||||
String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
Random random = new Random();
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
for (int i = 0; i < length; i++) {
|
||||
int number = random.nextInt(26);
|
||||
stringBuilder.append(str.charAt(number));
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.codvision.commoncore.utils;
|
||||
|
||||
import com.codvision.commoncore.common.ResponseEntity;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
|
||||
/**
|
||||
* 响应工具类
|
||||
*
|
||||
* @author lingee
|
||||
* @date 2023/7/18
|
||||
*/
|
||||
public class ResponseUtil {
|
||||
|
||||
/**
|
||||
* 判断请求是否成功
|
||||
*
|
||||
* @param response
|
||||
* @return
|
||||
*/
|
||||
public static boolean isSuccess(ResponseEntity response) {
|
||||
if (ObjectUtils.isNotEmpty(response)
|
||||
&& response.getCode() == 200
|
||||
&& ObjectUtils.isNotEmpty(response.getData())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isSuccessNotData(ResponseEntity response) {
|
||||
if (ObjectUtils.isNotEmpty(response)
|
||||
&& response.getCode() == 200) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.codvision.commoncore.utils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* 树节点父类
|
||||
* <p>
|
||||
* 所有需要使用{@linkplain TreeUtils}工具类形成树形结构等操作的节点都需要实现该接口
|
||||
*
|
||||
* @author lingee
|
||||
* @date 2024/04/24
|
||||
*/
|
||||
public interface TreeNode<T> {
|
||||
/**
|
||||
* 获取节点id
|
||||
*
|
||||
* @return 树节点id
|
||||
*/
|
||||
T id();
|
||||
|
||||
/**
|
||||
* 获取该节点的父节点id
|
||||
*
|
||||
* @return 父节点id
|
||||
*/
|
||||
T parentId();
|
||||
|
||||
/**
|
||||
* 是否是根节点
|
||||
*
|
||||
* @return true:根节点
|
||||
*/
|
||||
boolean root();
|
||||
|
||||
/**
|
||||
* 设置节点的子节点列表
|
||||
*
|
||||
* @param children 子节点
|
||||
*/
|
||||
void setChildren(List<? extends TreeNode<T>> children);
|
||||
|
||||
/**
|
||||
* 获取所有子节点
|
||||
*
|
||||
* @return 子节点列表
|
||||
*/
|
||||
List<? extends TreeNode<T>> getChildren();
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package com.codvision.commoncore.utils;
|
||||
|
||||
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 树形结构工具类
|
||||
*
|
||||
* @author lingee
|
||||
* @date 2024/04/24
|
||||
*/
|
||||
public class TreeUtils {
|
||||
|
||||
/**
|
||||
* 根据所有树节点列表,生成含有所有树形结构的列表
|
||||
*
|
||||
* @param nodes 树形节点列表
|
||||
* @param <T> 节点类型
|
||||
* @return 树形结构列表
|
||||
*/
|
||||
public static <T extends TreeNode<?>> List<T> generateTrees(List<T> nodes) {
|
||||
List<T> roots = new ArrayList<>();
|
||||
for (Iterator<T> ite = nodes.iterator(); ite.hasNext(); ) {
|
||||
T node = ite.next();
|
||||
if (node.root()) {
|
||||
roots.add(node);
|
||||
// 从所有节点列表中删除该节点,以免后续重复遍历该节点
|
||||
ite.remove();
|
||||
}
|
||||
}
|
||||
|
||||
if (CollectionUtils.isEmpty(roots)) {
|
||||
roots.addAll(nodes);
|
||||
}
|
||||
|
||||
roots.forEach(r -> {
|
||||
setChildren(r, nodes);
|
||||
});
|
||||
|
||||
return roots;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从所有节点列表中查找并设置parent的所有子节点
|
||||
*
|
||||
* @param parent 父节点
|
||||
* @param nodes 所有树节点列表
|
||||
*/
|
||||
public static <T extends TreeNode> void setChildren(T parent, List<T> nodes) {
|
||||
List<T> children = new ArrayList<>();
|
||||
Object parentId = parent.id();
|
||||
for (Iterator<T> ite = nodes.iterator(); ite.hasNext(); ) {
|
||||
T node = ite.next();
|
||||
if (Objects.equals(node.parentId(), parentId)) {
|
||||
children.add(node);
|
||||
// 从所有节点列表中删除该节点,以免后续重复遍历该节点
|
||||
ite.remove();
|
||||
}
|
||||
}
|
||||
// 如果孩子为空,则直接返回,否则继续递归设置孩子的孩子
|
||||
if (children.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
parent.setChildren(children);
|
||||
children.forEach(m -> {
|
||||
// 递归设置子节点
|
||||
setChildren(m, nodes);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除父节点下的所有子节点
|
||||
*
|
||||
* @param parentId 父级id
|
||||
* @param nodes 节点列表
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
public static <T extends TreeNode> List<Integer> removeChildren(Integer parentId, List<T> nodes) {
|
||||
|
||||
List<Integer> removeIds = new ArrayList<>();
|
||||
for (Iterator<T> ite = nodes.iterator(); ite.hasNext(); ) {
|
||||
T node = ite.next();
|
||||
if (Objects.equals(node.parentId(), parentId)) {
|
||||
removeIds.add((Integer) node.id());
|
||||
ite.remove();
|
||||
}
|
||||
}
|
||||
return removeIds;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将parent的所有叶子节点填充至leafs列表中
|
||||
*
|
||||
* @param parent 父节点
|
||||
* @param leafs 叶子节点列表
|
||||
* @param <T> 实际节点类型
|
||||
*/
|
||||
public static <T extends TreeNode> void fillLeaf(T parent, List<T> leafs) {
|
||||
List<T> children = parent.getChildren();
|
||||
// 如果节点没有子节点则说明为叶子节点
|
||||
if (CollectionUtils.isEmpty(children)) {
|
||||
leafs.add(parent);
|
||||
return;
|
||||
}
|
||||
// 递归调用子节点,查找叶子节点
|
||||
for (T child : children) {
|
||||
fillLeaf(child, leafs);
|
||||
}
|
||||
}
|
||||
}
|
||||
38
template/cvbp/cvbp-public/cvbp-common-feign/.gitignore
vendored
Normal file
38
template/cvbp/cvbp-public/cvbp-common-feign/.gitignore
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea/modules.xml
|
||||
.idea/jarRepositories.xml
|
||||
.idea/compiler.xml
|
||||
.idea/libraries/
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### Eclipse ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
### Mac OS ###
|
||||
.DS_Store
|
||||
34
template/cvbp/cvbp-public/cvbp-common-feign/pom.xml
Normal file
34
template/cvbp/cvbp-public/cvbp-common-feign/pom.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
-->
|
||||
|
||||
<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>
|
||||
<groupId>com.codvision</groupId>
|
||||
<artifactId>cvbp-public</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>cvbp-common-feign</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<!--feign 依赖-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.codvision.commonfeign.config;
|
||||
|
||||
import feign.Logger;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
|
||||
/**
|
||||
* openfeign配置
|
||||
*
|
||||
* @author lingee
|
||||
* @date 2023/7/17
|
||||
*/
|
||||
@Configuration
|
||||
@EnableFeignClients(basePackages = {"com.codvision"})
|
||||
public class OpenFeignConfig {
|
||||
|
||||
/**
|
||||
* 测试环境下,打印全部请求信息
|
||||
* <p>
|
||||
* 更多日志配置参见 feign.Logger.Level
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
@Profile("dev")
|
||||
Logger.Level feignLoggerLevel() {
|
||||
return Logger.Level.FULL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
* openfeign远程调用
|
||||
*
|
||||
* @author lingee
|
||||
* @date 2023/7/17
|
||||
*/
|
||||
package com.codvision.commonfeign;
|
||||
@@ -0,0 +1 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.codvision.commonfeign.config.OpenFeignConfig
|
||||
38
template/cvbp/cvbp-public/cvbp-db-core/.gitignore
vendored
Normal file
38
template/cvbp/cvbp-public/cvbp-db-core/.gitignore
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea/modules.xml
|
||||
.idea/jarRepositories.xml
|
||||
.idea/compiler.xml
|
||||
.idea/libraries/
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### Eclipse ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
### Mac OS ###
|
||||
.DS_Store
|
||||
59
template/cvbp/cvbp-public/cvbp-db-core/pom.xml
Normal file
59
template/cvbp/cvbp-public/cvbp-db-core/pom.xml
Normal file
@@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
-->
|
||||
|
||||
<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>
|
||||
<groupId>com.codvision</groupId>
|
||||
<artifactId>cvbp-public</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>cvbp-db-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.codvision</groupId>
|
||||
<artifactId>cvbp-common-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-dbutils</groupId>
|
||||
<artifactId>commons-dbutils</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-dbcp</groupId>
|
||||
<artifactId>commons-dbcp</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.codvision.db;
|
||||
|
||||
|
||||
import com.codvision.db.constants.DbQueryProperty;
|
||||
|
||||
public interface DataSourceFactory {
|
||||
|
||||
/**
|
||||
* 创建数据源实例
|
||||
*
|
||||
* @param property
|
||||
* @return
|
||||
*/
|
||||
DbQuery createDbQuery(DbQueryProperty property);
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package com.codvision.db;
|
||||
|
||||
import com.codvision.db.core.DbColumn;
|
||||
import com.codvision.db.core.DbTable;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
/**
|
||||
* 表数据查询接口
|
||||
*
|
||||
* @author yuwei
|
||||
* @since 2020-03-14
|
||||
*/
|
||||
public interface DbDialect {
|
||||
|
||||
RowMapper<DbTable> tableMapper();
|
||||
|
||||
RowMapper<DbColumn> columnMapper();
|
||||
|
||||
RowMapper<String> viewMapper();
|
||||
|
||||
/**
|
||||
* 获取指定表的所有列
|
||||
*
|
||||
* @param dbName
|
||||
* @param tableName
|
||||
* @return
|
||||
*/
|
||||
String columns(String dbName, String tableName);
|
||||
|
||||
/**
|
||||
* 获取数据库下的 所有表
|
||||
*
|
||||
* @param dbName
|
||||
* @return
|
||||
*/
|
||||
String tables(String dbName);
|
||||
|
||||
/**
|
||||
* 获取表结构
|
||||
*
|
||||
* @param dbName
|
||||
* @param tableName
|
||||
* @return
|
||||
*/
|
||||
String table(String dbName, String tableName);
|
||||
|
||||
/**
|
||||
* 获取数据库下的 所有视图
|
||||
*
|
||||
* @param dbName
|
||||
* @return
|
||||
*/
|
||||
String views(String dbName);
|
||||
|
||||
/**
|
||||
* 构建 分页 sql
|
||||
*
|
||||
* @param sql
|
||||
* @param offset
|
||||
* @param count
|
||||
* @return
|
||||
*/
|
||||
String buildPaginationSql(String sql, long offset, long count);
|
||||
|
||||
/**
|
||||
* 包装 count sql
|
||||
*
|
||||
* @param sql
|
||||
* @return
|
||||
*/
|
||||
String count(String sql);
|
||||
|
||||
/**
|
||||
* oracl 读取long 类型会流关闭,是oracle的bug,需要特殊处理
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
default RowMapper<DbColumn> columnLongMapper() {
|
||||
return null;
|
||||
}
|
||||
|
||||
;
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
package com.codvision.db;
|
||||
|
||||
|
||||
import com.codvision.db.core.DbColumn;
|
||||
import com.codvision.db.core.DbTable;
|
||||
import com.codvision.db.core.PageResult;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 表数据查询接口
|
||||
*
|
||||
* @author yuwei
|
||||
* @since 2020-03-14
|
||||
*/
|
||||
public interface DbQuery {
|
||||
|
||||
/**
|
||||
* 获取数据库连接
|
||||
*/
|
||||
Connection getConnection();
|
||||
|
||||
/**
|
||||
* 检测连通性
|
||||
*/
|
||||
boolean valid();
|
||||
|
||||
/**
|
||||
* 关闭数据源
|
||||
*/
|
||||
void close();
|
||||
|
||||
/**
|
||||
* 获取指定表 具有的所有字段列表
|
||||
*
|
||||
* @param dbName
|
||||
* @param tableName
|
||||
* @return
|
||||
*/
|
||||
List<DbColumn> getTableColumns(String dbName, String tableName);
|
||||
|
||||
/**
|
||||
* 获取指定数据库下 所有的表信息
|
||||
*
|
||||
* @param dbName
|
||||
* @return
|
||||
*/
|
||||
List<DbTable> getTables(String dbName);
|
||||
|
||||
/**
|
||||
* 获取指定数据库下 指定表信息
|
||||
*
|
||||
* @param dbName
|
||||
* @param tableName
|
||||
* @return
|
||||
*/
|
||||
DbTable getTable(String dbName, String tableName);
|
||||
|
||||
/**
|
||||
* 获取数据库下的所有schemas
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
List<String> getSchemas();
|
||||
|
||||
/**
|
||||
* 获取数据库下的所有视图
|
||||
*
|
||||
* @param dbName 数据库名称
|
||||
* @return
|
||||
*/
|
||||
List<String> getViews(String dbName);
|
||||
|
||||
/**
|
||||
* 获取总数
|
||||
*
|
||||
* @param sql
|
||||
* @return
|
||||
*/
|
||||
int count(String sql);
|
||||
|
||||
/**
|
||||
* 获取总数带查询参数
|
||||
*
|
||||
* @param sql
|
||||
* @return
|
||||
*/
|
||||
int count(String sql, Object[] args);
|
||||
|
||||
/**
|
||||
* 获取总数带查询参数 NamedParameterJdbcTemplate
|
||||
*
|
||||
* @param sql
|
||||
* @return
|
||||
*/
|
||||
int count(String sql, Map<String, Object> params);
|
||||
|
||||
/**
|
||||
* 查询结果列表
|
||||
*
|
||||
* @param sql
|
||||
* @return
|
||||
*/
|
||||
List<Map<String, Object>> queryList(String sql);
|
||||
|
||||
/**
|
||||
* 查询结果列表带查询参数
|
||||
*
|
||||
* @param sql
|
||||
* @param args
|
||||
* @return
|
||||
*/
|
||||
List<Map<String, Object>> queryList(String sql, Object[] args);
|
||||
|
||||
/**
|
||||
* 查询结果分页
|
||||
*
|
||||
* @param sql
|
||||
* @param offset
|
||||
* @param size
|
||||
* @return
|
||||
*/
|
||||
PageResult<Map<String, Object>> queryByPage(String sql, long offset, long size);
|
||||
|
||||
/**
|
||||
* 查询结果分页带查询参数
|
||||
*
|
||||
* @param sql
|
||||
* @param args
|
||||
* @param offset
|
||||
* @param size
|
||||
* @return
|
||||
*/
|
||||
PageResult<Map<String, Object>> queryByPage(String sql, Object[] args, long offset, long size);
|
||||
|
||||
/**
|
||||
* 查询结果分页带查询参数 NamedParameterJdbcTemplate
|
||||
*
|
||||
* @param sql
|
||||
* @param params
|
||||
* @param offset
|
||||
* @param size
|
||||
* @return
|
||||
*/
|
||||
PageResult<Map<String, Object>> queryByPage(String sql, Map<String, Object> params, long offset, long size);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.codvision.db;
|
||||
|
||||
|
||||
import com.codvision.db.constants.DbType;
|
||||
import com.codvision.db.dialect.DialectRegistry;
|
||||
|
||||
/**
|
||||
* 方言工厂类
|
||||
*
|
||||
* @author yuwei
|
||||
* @since 2020-03-14
|
||||
*/
|
||||
public class DialectFactory {
|
||||
|
||||
private static final DialectRegistry DIALECT_REGISTRY = new DialectRegistry();
|
||||
|
||||
public static DbDialect getDialect(DbType dbType) {
|
||||
return DIALECT_REGISTRY.getDialect(dbType);
|
||||
}
|
||||
}
|
||||
123
template/cvbp/cvbp-public/cvbp-db-core/src/main/java/com/codvision/db/cache/DefaultSqlCache.java
vendored
Normal file
123
template/cvbp/cvbp-public/cvbp-db-core/src/main/java/com/codvision/db/cache/DefaultSqlCache.java
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
package com.codvision.db.cache;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
public class DefaultSqlCache extends LinkedHashMap<String, DefaultSqlCache.ExpireNode<Object>> implements SqlCache {
|
||||
|
||||
private int capacity;
|
||||
|
||||
private long expire;
|
||||
|
||||
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
|
||||
public DefaultSqlCache(int capacity, long expire) {
|
||||
super((int) Math.ceil(capacity / 0.75) + 1, 0.75f, true);
|
||||
// 容量
|
||||
this.capacity = capacity;
|
||||
// 固定过期时间
|
||||
this.expire = expire;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(String key, Object value, long ttl) {
|
||||
long expireTime = Long.MAX_VALUE;
|
||||
if (ttl >= 0) {
|
||||
expireTime = System.currentTimeMillis() + (ttl == 0 ? this.expire : ttl);
|
||||
}
|
||||
lock.writeLock().lock();
|
||||
try {
|
||||
// 封装成过期时间节点
|
||||
put(key, new ExpireNode<>(expireTime, value));
|
||||
} finally {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(String key) {
|
||||
lock.readLock().lock();
|
||||
ExpireNode<Object> expireNode;
|
||||
try {
|
||||
expireNode = super.get(key);
|
||||
} finally {
|
||||
lock.readLock().unlock();
|
||||
}
|
||||
if (expireNode == null) {
|
||||
return null;
|
||||
}
|
||||
// 惰性删除过期的
|
||||
if (this.expire > -1L && expireNode.expire < System.currentTimeMillis()) {
|
||||
try {
|
||||
lock.writeLock().lock();
|
||||
super.remove(key);
|
||||
} finally {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return expireNode.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(String key) {
|
||||
try {
|
||||
lock.writeLock().lock();
|
||||
Iterator<Map.Entry<String, ExpireNode<Object>>> iterator = super.entrySet().iterator();
|
||||
// 清除key的缓存
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<String, ExpireNode<Object>> entry = iterator.next();
|
||||
if (entry.getKey().equals(key)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Map.Entry<String, ExpireNode<Object>> eldest) {
|
||||
if (this.expire > -1L && size() > capacity) {
|
||||
clean();
|
||||
}
|
||||
// lru淘汰
|
||||
return size() > this.capacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理已过期的数据
|
||||
*/
|
||||
private void clean() {
|
||||
try {
|
||||
lock.writeLock().lock();
|
||||
Iterator<Map.Entry<String, ExpireNode<Object>>> iterator = super.entrySet().iterator();
|
||||
long now = System.currentTimeMillis();
|
||||
while (iterator.hasNext()) {
|
||||
Map.Entry<String, ExpireNode<Object>> next = iterator.next();
|
||||
// 判断是否过期
|
||||
if (next.getValue().expire < now) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 过期时间节点
|
||||
*/
|
||||
static class ExpireNode<V> {
|
||||
long expire;
|
||||
Object value;
|
||||
public ExpireNode(long expire, Object value) {
|
||||
this.expire = expire;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
41
template/cvbp/cvbp-public/cvbp-db-core/src/main/java/com/codvision/db/cache/SqlCache.java
vendored
Normal file
41
template/cvbp/cvbp-public/cvbp-db-core/src/main/java/com/codvision/db/cache/SqlCache.java
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
package com.codvision.db.cache;
|
||||
|
||||
import com.codvision.commoncore.utils.Md5Utils;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* SQL缓存接口
|
||||
*/
|
||||
public interface SqlCache {
|
||||
|
||||
/**
|
||||
* 计算key
|
||||
*/
|
||||
default String buildSqlCacheKey(String sql, Object[] args) {
|
||||
return Md5Utils.getMd5(sql + ":" + Arrays.toString(args));
|
||||
}
|
||||
|
||||
/**
|
||||
* 存入缓存
|
||||
*
|
||||
* @param key key
|
||||
* @param value 值
|
||||
*/
|
||||
void put(String key, Object value, long ttl);
|
||||
|
||||
/**
|
||||
* 获取缓存
|
||||
*
|
||||
* @param key key
|
||||
* @return
|
||||
*/
|
||||
<T> T get(String key);
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
*
|
||||
* @param key key
|
||||
*/
|
||||
void delete(String key);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.codvision.db.config;
|
||||
|
||||
import com.codvision.db.versionctl.DbVersionCtlInitializer;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 数据源模块配置
|
||||
*
|
||||
* @author lingee
|
||||
* @date 2023/12/5
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
@ImportAutoConfiguration(DBVCTLProps.class)
|
||||
public class DBConfig {
|
||||
|
||||
@Bean("dbVersionCtlInitializer")
|
||||
public DbVersionCtlInitializer init() {
|
||||
return new DbVersionCtlInitializer();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.codvision.db.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 数据版本配置控制
|
||||
*
|
||||
* @author lingee
|
||||
* @date 2023/12/5
|
||||
*/
|
||||
@Data
|
||||
@Configuration
|
||||
@ConfigurationProperties("cvbp.dbvctl")
|
||||
public class DBVCTLProps {
|
||||
|
||||
/**
|
||||
* 是否自动执行数据库版本控制,默认不执行
|
||||
*/
|
||||
private Boolean enabled = Boolean.FALSE;
|
||||
|
||||
/**
|
||||
* 数据库非空但首次使用数据库版本管理时,指定生成版本基线的业务空间及其基线版本,多个业务空间时使用逗号连接。
|
||||
* 例如:"raven_V1.0.0,sentry_V1.1.2"
|
||||
*/
|
||||
private String baselineBusinessSpaceAndVersions;
|
||||
|
||||
/**
|
||||
* 是否重置数据库基线版本
|
||||
*/
|
||||
private Boolean baselineReset = Boolean.FALSE;
|
||||
|
||||
/**
|
||||
* 数据库基线版本重置条件SQL,只有[baselineReset]设置为true,且该SQL查询结果非空,才会进行数据库基线版本重置操作
|
||||
* 通常建议使用时间戳字段[install_time]作为查询SQL的条件,这样只会生效一次,
|
||||
* 以后升级版本时,即使忘记将【baselineReset】属性清除或设置为false也不会导致数据库基线版本被误重置。
|
||||
*/
|
||||
private String baselineResetConditionSql = "";
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.codvision.db.constants;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.codvision.db.exception.DataQueryException;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class DbQueryProperty implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private DbType dbType;
|
||||
private String host;
|
||||
private String username;
|
||||
private String password;
|
||||
private Integer port;
|
||||
private String dbName;
|
||||
private String sid;
|
||||
|
||||
/**
|
||||
* 参数合法性校验
|
||||
*/
|
||||
public void valid() {
|
||||
if (ObjectUtil.isEmpty(dbType) || StrUtil.isEmpty(host) ||
|
||||
StrUtil.isEmpty(username) || StrUtil.isEmpty(password) ||
|
||||
ObjectUtil.isEmpty(port)) {
|
||||
throw new DataQueryException("参数不完整");
|
||||
}
|
||||
if (DbType.OTHER.getDb().equals(dbType)) {
|
||||
throw new DataQueryException("不支持的数据库类型");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.codvision.db.constants;
|
||||
|
||||
/**
|
||||
* 数据库类型
|
||||
*
|
||||
* @author yuwei
|
||||
* @since 2020-03-14
|
||||
*/
|
||||
public enum DbType {
|
||||
|
||||
/**
|
||||
* MYSQL
|
||||
*/
|
||||
MYSQL("1", "MySql数据库", "jdbc:mysql://${host}:${port}/${dbName}?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8"),
|
||||
/**
|
||||
* MARIADB
|
||||
*/
|
||||
MARIADB("2", "MariaDB数据库", "jdbc:mariadb://${host}:${port}/${dbName}"),
|
||||
/**
|
||||
* ORACLE
|
||||
*/
|
||||
ORACLE("3", "Oracle11g及以下数据库", "jdbc:oracle:thin:@${host}:${port}:${sid}"),
|
||||
/**
|
||||
* oracle12c new pagination
|
||||
*/
|
||||
ORACLE_12C("4", "Oracle12c+数据库", "jdbc:oracle:thin:@${host}:${port}:${sid}"),
|
||||
/**
|
||||
* POSTGRESQL
|
||||
*/
|
||||
POSTGRESQL("5", "PostgreSql数据库", "jdbc:postgresql://${host}:${port}/${dbName}"),
|
||||
/**
|
||||
* SQLSERVER2005
|
||||
*/
|
||||
MSSQL2008("6", "SQLServer2008及以下数据库", "jdbc:sqlserver://${host}:${port};DatabaseName=${dbName}"),
|
||||
/**
|
||||
* SQLSERVER
|
||||
*/
|
||||
MSSQL("7", "SQLServer2012+数据库", "jdbc:sqlserver://${host}:${port};DatabaseName=${dbName}"),
|
||||
/**
|
||||
* UNKONWN DB
|
||||
*/
|
||||
OTHER("8", "其他数据库", "");
|
||||
|
||||
/**
|
||||
* 数据库名称
|
||||
*/
|
||||
private final String db;
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
private final String desc;
|
||||
|
||||
/**
|
||||
* url
|
||||
*/
|
||||
private final String url;
|
||||
|
||||
public String getDb() {
|
||||
return this.db;
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return this.desc;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return this.url;
|
||||
}
|
||||
|
||||
DbType(String db, String desc, String url) {
|
||||
this.db = db;
|
||||
this.desc = desc;
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据库类型
|
||||
*
|
||||
* @param dbType 数据库类型字符串
|
||||
*/
|
||||
public static DbType getDbType(String dbType) {
|
||||
for (DbType type : DbType.values()) {
|
||||
if (type.name().equals(dbType)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return OTHER;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.codvision.db.core;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class DbColumn {
|
||||
|
||||
/**
|
||||
* 列名
|
||||
*/
|
||||
private String colName;
|
||||
|
||||
/**
|
||||
* 数据类型
|
||||
*/
|
||||
private String dataType;
|
||||
|
||||
/**
|
||||
* 数据长度
|
||||
*/
|
||||
private String dataLength;
|
||||
|
||||
/**
|
||||
* 数据精度
|
||||
*/
|
||||
private String dataPrecision;
|
||||
|
||||
/**
|
||||
* 数据小数位
|
||||
*/
|
||||
private String dataScale;
|
||||
|
||||
/**
|
||||
* 是否主键
|
||||
*/
|
||||
private Boolean colKey;
|
||||
|
||||
/**
|
||||
* 是否允许为空
|
||||
*/
|
||||
private Boolean nullable;
|
||||
|
||||
/**
|
||||
* 列的序号
|
||||
*/
|
||||
private Integer colPosition;
|
||||
|
||||
/**
|
||||
* 列默认值
|
||||
*/
|
||||
private String dataDefault;
|
||||
|
||||
/**
|
||||
* 列注释
|
||||
*/
|
||||
private String colComment;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.codvision.db.core;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class DbTable {
|
||||
|
||||
/**
|
||||
* 表名
|
||||
*/
|
||||
private String tableName;
|
||||
|
||||
/**
|
||||
* 表注释
|
||||
*/
|
||||
private String tableComment;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.codvision.db.core;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class PageResult<T> implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Integer pageNum;
|
||||
private Integer pageSize;
|
||||
private Integer total;
|
||||
private List<T> data;
|
||||
|
||||
public PageResult(Integer total, List<T> data) {
|
||||
this.total = total;
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package com.codvision.db.datasource;
|
||||
|
||||
import com.codvision.db.DataSourceFactory;
|
||||
import com.codvision.db.DbDialect;
|
||||
import com.codvision.db.DbQuery;
|
||||
import com.codvision.db.DialectFactory;
|
||||
import com.codvision.db.constants.DbQueryProperty;
|
||||
import com.codvision.db.constants.DbType;
|
||||
import com.codvision.db.exception.DataQueryException;
|
||||
import com.codvision.db.query.AbstractDbQueryFactory;
|
||||
import com.codvision.db.query.CacheDbQueryFactoryBean;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
public abstract class AbstractDataSourceFactory implements DataSourceFactory {
|
||||
|
||||
@Override
|
||||
public DbQuery createDbQuery(DbQueryProperty property) {
|
||||
property.valid();
|
||||
DataSource dataSource = createDataSource(property);
|
||||
DbQuery dbQuery = createDbQuery(dataSource, property.getDbType());
|
||||
return dbQuery;
|
||||
}
|
||||
|
||||
public DbQuery createDbQuery(DataSource dataSource, DbType dbType) {
|
||||
DbDialect dbDialect = DialectFactory.getDialect(dbType);
|
||||
if (dbDialect == null) {
|
||||
throw new DataQueryException("该数据库类型正在开发中");
|
||||
}
|
||||
AbstractDbQueryFactory dbQuery = new CacheDbQueryFactoryBean();
|
||||
dbQuery.setDataSource(dataSource);
|
||||
dbQuery.setJdbcTemplate(new JdbcTemplate(dataSource));
|
||||
dbQuery.setDbDialect(dbDialect);
|
||||
return dbQuery;
|
||||
}
|
||||
|
||||
public DataSource createDataSource(DbQueryProperty property) {
|
||||
HikariDataSource dataSource = new HikariDataSource();
|
||||
dataSource.setJdbcUrl(trainToJdbcUrl(property));
|
||||
dataSource.setUsername(property.getUsername());
|
||||
dataSource.setPassword(property.getPassword());
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
protected String trainToJdbcUrl(DbQueryProperty property) {
|
||||
String url = property.getDbType().getUrl();
|
||||
if (StringUtils.isEmpty(url)) {
|
||||
throw new DataQueryException("无效数据库类型!");
|
||||
}
|
||||
url = url.replace("${host}", property.getHost());
|
||||
url = url.replace("${port}", String.valueOf(property.getPort()));
|
||||
if (DbType.ORACLE.equals(property.getDbType()) || DbType.ORACLE_12C.equals(property.getDbType())) {
|
||||
url = url.replace("${sid}", property.getSid());
|
||||
} else {
|
||||
url = url.replace("${dbName}", property.getDbName());
|
||||
}
|
||||
return url;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.codvision.db.datasource;
|
||||
|
||||
|
||||
import com.codvision.db.constants.DbQueryProperty;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class CacheDataSourceFactoryBean extends AbstractDataSourceFactory {
|
||||
|
||||
/**
|
||||
* 数据源缓存
|
||||
*/
|
||||
private static Map<String, DataSource> dataSourceMap = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public DataSource createDataSource(DbQueryProperty property) {
|
||||
String key = property.getDbType() + ":" + property.getHost()
|
||||
+ ":" + property.getPort() + ":" + property.getUsername()
|
||||
+ ":" + property.getPassword() + ":" + property.getDbName()
|
||||
+ ":" + property.getSid();
|
||||
String s = compress(key);
|
||||
DataSource dataSource = dataSourceMap.get(s);
|
||||
if (null == dataSource) {
|
||||
synchronized (CacheDataSourceFactoryBean.class) {
|
||||
dataSource = super.createDataSource(property);
|
||||
dataSourceMap.put(s, dataSource);
|
||||
}
|
||||
}
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
// 压缩
|
||||
public static String compress(String str) {
|
||||
if (str == null || str.length() == 0) {
|
||||
return str;
|
||||
}
|
||||
MessageDigest md = null;
|
||||
try {
|
||||
md = MessageDigest.getInstance("MD5");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
md.update(str.getBytes());
|
||||
byte b[] = md.digest();
|
||||
int i;
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (int offset = 0; offset < b.length; offset++) {
|
||||
i = b[offset];
|
||||
if (i < 0)
|
||||
i += 256;
|
||||
if (i < 16)
|
||||
buf.append("0");
|
||||
buf.append(Integer.toHexString(i));
|
||||
}
|
||||
// System.out.println("MD5(" + str + ",32小写) = " + buf.toString());
|
||||
// System.out.println("MD5(" + str + ",32大写) = " + buf.toString().toUpperCase());
|
||||
// System.out.println("MD5(" + str + ",16小写) = " + buf.toString().substring(8, 24));
|
||||
// System.out.println("MD5(" + str + ",16大写) = " + buf.toString().substring(8, 24).toUpperCase());
|
||||
return buf.toString().substring(8, 24).toUpperCase();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package com.codvision.db.datasource;
|
||||
|
||||
public class DefaultDataSourceFactoryBean extends AbstractDataSourceFactory {
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.codvision.db.dialect;
|
||||
|
||||
|
||||
import com.codvision.db.DbDialect;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
|
||||
/**
|
||||
* 方言抽象类
|
||||
*
|
||||
* @author yuwei
|
||||
* @since 2020-03-14
|
||||
*/
|
||||
public abstract class AbstractDbDialect implements DbDialect {
|
||||
|
||||
@Override
|
||||
public RowMapper<String> viewMapper() {
|
||||
return (ResultSet rs, int rowNum) -> rs.getString("table_name");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String columns(String dbName, String tableName) {
|
||||
return "select column_name AS COLNAME, ordinal_position AS COLPOSITION, column_default AS DATADEFAULT, is_nullable AS NULLABLE, data_type AS DATATYPE, " +
|
||||
"character_maximum_length AS DATALENGTH, numeric_precision AS DATAPRECISION, numeric_scale AS DATASCALE, column_key AS COLKEY, column_comment AS COLCOMMENT " +
|
||||
"from information_schema.columns where table_schema = '" + dbName + "' and table_name = '" + tableName + "' order by ordinal_position ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tables(String dbName) {
|
||||
return "SELECT table_name AS TABLENAME, table_comment AS TABLECOMMENT FROM information_schema.tables where table_schema = '" + dbName + "' ";
|
||||
}
|
||||
|
||||
public String table(String dbName, String tableName) {
|
||||
return "SELECT table_name AS TABLENAME, table_comment AS TABLECOMMENT FROM information_schema.tables where table_schema = '" + dbName + "' and table_name = '" + tableName + "' ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String views(String dbName) {
|
||||
return "SELECT table_name AS TABLENAME FROM information_schema.views where table_schema = '" + dbName + "' ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String buildPaginationSql(String originalSql, long offset, long count) {
|
||||
// 获取 分页实际条数
|
||||
StringBuilder sqlBuilder = new StringBuilder(originalSql);
|
||||
sqlBuilder.append(" LIMIT ").append(offset).append(" , ").append(count);
|
||||
return sqlBuilder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String count(String sql) {
|
||||
return "SELECT COUNT(*) FROM ( " + sql + " ) TEMP";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.codvision.db.dialect;
|
||||
|
||||
|
||||
import com.codvision.db.DbDialect;
|
||||
import com.codvision.db.constants.DbType;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class DialectRegistry {
|
||||
|
||||
private final Map<DbType, DbDialect> dialect_enum_map = new EnumMap<>(DbType.class);
|
||||
|
||||
public DialectRegistry() {
|
||||
dialect_enum_map.put(DbType.MARIADB, new MariaDBDialect());
|
||||
dialect_enum_map.put(DbType.MYSQL, new MySqlDialect());
|
||||
dialect_enum_map.put(DbType.ORACLE_12C, new Oracle12cDialect());
|
||||
dialect_enum_map.put(DbType.ORACLE, new OracleDialect());
|
||||
dialect_enum_map.put(DbType.POSTGRESQL, new PostgreDialect());
|
||||
dialect_enum_map.put(DbType.MSSQL2008, new SQLServer2008Dialect());
|
||||
dialect_enum_map.put(DbType.MSSQL, new SQLServerDialect());
|
||||
dialect_enum_map.put(DbType.OTHER, new UnknownDialect());
|
||||
}
|
||||
|
||||
public DbDialect getDialect(DbType dbType) {
|
||||
return dialect_enum_map.get(dbType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.codvision.db.dialect;
|
||||
|
||||
/**
|
||||
* MariaDB 数据库方言
|
||||
*
|
||||
* @author yuwei
|
||||
* @since 2020-03-14
|
||||
*/
|
||||
public class MariaDBDialect extends MySqlDialect {
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.codvision.db.dialect;
|
||||
|
||||
import com.codvision.db.core.DbColumn;
|
||||
import com.codvision.db.core.DbTable;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
|
||||
/**
|
||||
* MySql 数据库方言
|
||||
*
|
||||
* @author yuwei
|
||||
* @since 2020-03-14
|
||||
*/
|
||||
public class MySqlDialect extends AbstractDbDialect {
|
||||
|
||||
@Override
|
||||
public RowMapper<DbColumn> columnMapper() {
|
||||
return (ResultSet rs, int rowNum) -> {
|
||||
DbColumn entity = new DbColumn();
|
||||
entity.setColName(rs.getString("COLNAME"));
|
||||
entity.setDataType(rs.getString("DATATYPE"));
|
||||
entity.setDataLength(rs.getString("DATALENGTH"));
|
||||
entity.setDataPrecision(rs.getString("DATAPRECISION"));
|
||||
entity.setDataScale(rs.getString("DATASCALE"));
|
||||
entity.setColKey("PRI".equals(rs.getString("COLKEY")));
|
||||
entity.setNullable("YES".equals(rs.getString("NULLABLE")));
|
||||
entity.setColPosition(rs.getInt("COLPOSITION"));
|
||||
entity.setDataDefault(rs.getString("DATADEFAULT"));
|
||||
entity.setColComment(rs.getString("COLCOMMENT"));
|
||||
return entity;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public RowMapper<DbTable> tableMapper() {
|
||||
return (ResultSet rs, int rowNum) -> {
|
||||
DbTable entity = new DbTable();
|
||||
entity.setTableName(rs.getString("TABLENAME"));
|
||||
entity.setTableComment(rs.getString("TABLECOMMENT"));
|
||||
return entity;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.codvision.db.dialect;
|
||||
|
||||
/**
|
||||
* ORACLE Oracle12c+数据库方言
|
||||
*
|
||||
* @author yuwei
|
||||
* @since 2020-03-14
|
||||
*/
|
||||
public class Oracle12cDialect extends OracleDialect {
|
||||
|
||||
@Override
|
||||
public String buildPaginationSql(String originalSql, long offset, long count) {
|
||||
StringBuilder sqlBuilder = new StringBuilder(originalSql);
|
||||
sqlBuilder.append(" OFFSET ").append(offset).append(" ROWS FETCH NEXT ").append(count).append(" ROWS ONLY ");
|
||||
return sqlBuilder.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package com.codvision.db.dialect;
|
||||
|
||||
import com.codvision.db.core.DbColumn;
|
||||
import com.codvision.db.core.DbTable;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
|
||||
/**
|
||||
* Oracle Oracle11g及以下数据库方言
|
||||
*
|
||||
* @author yuwei
|
||||
* @since 2020-03-14
|
||||
*/
|
||||
public class OracleDialect extends AbstractDbDialect {
|
||||
|
||||
@Override
|
||||
public String columns(String dbName, String tableName) {
|
||||
return "select columns.column_name AS colName, columns.data_type AS DATATYPE, columns.data_length AS DATALENGTH, columns.data_precision AS DATAPRECISION, " +
|
||||
"columns.data_scale AS DATASCALE, columns.nullable AS NULLABLE, columns.column_id AS COLPOSITION, columns.data_default AS DATADEFAULT, comments.comments AS COLCOMMENT," +
|
||||
"case when t.column_name is null then 0 else 1 end as COLKEY " +
|
||||
"from sys.user_tab_columns columns LEFT JOIN sys.user_col_comments comments ON columns.table_name = comments.table_name AND columns.column_name = comments.column_name " +
|
||||
"left join ( " +
|
||||
"select col.column_name as column_name, con.table_name as table_name from user_constraints con, user_cons_columns col " +
|
||||
"where con.constraint_name = col.constraint_name and con.constraint_type = 'P' " +
|
||||
") t on t.table_name = columns.table_name and columns.column_name = t.column_name " +
|
||||
"where columns.table_name = UPPER('" + tableName + "') order by columns.column_id ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tables(String dbName) {
|
||||
return "select tables.table_name AS TABLENAME, comments.comments AS TABLECOMMENT from sys.user_tables tables " +
|
||||
"LEFT JOIN sys.user_tab_comments comments ON tables.table_name = comments.table_name ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String table(String dbName, String tableName) {
|
||||
return "select tables.table_name AS TABLENAME, comments.comments AS TABLECOMMENT from sys.user_tables tables " +
|
||||
"LEFT JOIN sys.user_tab_comments comments ON tables.table_name = comments.table_name where tables.table_name = '" + tableName + "' ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String buildPaginationSql(String originalSql, long offset, long count) {
|
||||
StringBuilder sqlBuilder = new StringBuilder();
|
||||
sqlBuilder.append("SELECT * FROM ( SELECT TMP.*, ROWNUM ROW_ID FROM ( ");
|
||||
sqlBuilder.append(originalSql).append(" ) TMP WHERE ROWNUM <=").append((offset >= 1) ? (offset + count) : count);
|
||||
sqlBuilder.append(") WHERE ROW_ID > ").append(offset);
|
||||
return sqlBuilder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RowMapper<DbColumn> columnLongMapper() {
|
||||
return (ResultSet rs, int rowNum) -> {
|
||||
DbColumn entity = new DbColumn();
|
||||
entity.setDataDefault(rs.getString("DATADEFAULT"));
|
||||
return entity;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public RowMapper<DbColumn> columnMapper() {
|
||||
return (ResultSet rs, int rowNum) -> {
|
||||
DbColumn entity = new DbColumn();
|
||||
entity.setColName(rs.getString("COLNAME"));
|
||||
entity.setDataType(rs.getString("DATATYPE"));
|
||||
entity.setDataLength(rs.getString("DATALENGTH"));
|
||||
entity.setDataPrecision(rs.getString("DATAPRECISION"));
|
||||
entity.setDataScale(rs.getString("DATASCALE"));
|
||||
entity.setColKey("1".equals(rs.getString("COLKEY")));
|
||||
entity.setNullable("Y".equals(rs.getString("NULLABLE")));
|
||||
//long类型,单独处理
|
||||
//entity.setDataDefault(rs.getString("DATADEFAULT"));
|
||||
entity.setColPosition(rs.getInt("COLPOSITION"));
|
||||
entity.setColComment(rs.getString("COLCOMMENT"));
|
||||
return entity;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public RowMapper<DbTable> tableMapper() {
|
||||
return (ResultSet rs, int rowNum) -> {
|
||||
DbTable entity = new DbTable();
|
||||
entity.setTableName(rs.getString("TABLENAME"));
|
||||
entity.setTableComment(rs.getString("TABLECOMMENT"));
|
||||
return entity;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.codvision.db.dialect;
|
||||
|
||||
import com.codvision.db.core.DbColumn;
|
||||
import com.codvision.db.core.DbTable;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
|
||||
/**
|
||||
* Postgre 数据库方言
|
||||
*
|
||||
* @author yuwei
|
||||
* @since 2020-03-14
|
||||
*/
|
||||
public class PostgreDialect extends AbstractDbDialect {
|
||||
|
||||
@Override
|
||||
public String columns(String dbName, String tableName) {
|
||||
return "select col.column_name AS COLNAME, col.ordinal_position AS COLPOSITION, col.column_default AS DATADEFAULT, col.is_nullable AS NULLABLE, col.udt_name AS DATATYPE, " +
|
||||
"col.character_maximum_length AS DATALENGTH, col.numeric_precision AS DATAPRECISION, col.numeric_scale AS DATASCALE, des.description AS COLCOMMENT, " +
|
||||
"case when t.colname is null then 0 else 1 end as COLKEY " +
|
||||
"from information_schema.columns col left join pg_description des on col.table_name::regclass = des.objoid and col.ordinal_position = des.objsubid " +
|
||||
"left join ( " +
|
||||
"select pg_attribute.attname as colname from pg_constraint inner join pg_class on pg_constraint.conrelid = pg_class.oid " +
|
||||
"inner join pg_attribute on pg_attribute.attrelid = pg_class.oid and pg_attribute.attnum = any(pg_constraint.conkey) " +
|
||||
"where pg_class.relname = '" + tableName + "' and pg_constraint.contype = 'p' " +
|
||||
") t on t.colname = col.column_name " +
|
||||
"where col.table_catalog = '" + dbName + "' and col.table_schema = 'public' and col.table_name = '" + tableName + "' order by col.ordinal_position ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tables(String dbName) {
|
||||
return "select relname AS TABLENAME, cast(obj_description(relfilenode, 'pg_class') as varchar) AS TABLECOMMENT from pg_class " +
|
||||
"where relname in (select tablename from pg_tables where schemaname = 'public' and position('_2' in tablename) = 0) ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String table(String dbName, String tableName) {
|
||||
return "select relname AS TABLENAME, cast(obj_description(relfilenode, 'pg_class') as varchar) AS TABLECOMMENT from pg_class " +
|
||||
"where relname in (select tablename from pg_tables where schemaname = 'public' and tablename = '" + tableName + "'" +
|
||||
" and position('_2' in tablename) = 0) ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String buildPaginationSql(String originalSql, long offset, long count) {
|
||||
StringBuilder sqlBuilder = new StringBuilder(originalSql);
|
||||
sqlBuilder.append(" LIMIT ").append(count).append(" offset ").append(offset);
|
||||
return sqlBuilder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RowMapper<DbColumn> columnMapper() {
|
||||
return (ResultSet rs, int rowNum) -> {
|
||||
DbColumn entity = new DbColumn();
|
||||
entity.setColName(rs.getString("COLNAME"));
|
||||
entity.setDataType(rs.getString("DATATYPE"));
|
||||
entity.setDataLength(rs.getString("DATALENGTH"));
|
||||
entity.setDataPrecision(rs.getString("DATAPRECISION"));
|
||||
entity.setDataScale(rs.getString("DATASCALE"));
|
||||
entity.setColKey("1".equals(rs.getString("COLKEY")) ? true : false);
|
||||
entity.setNullable("YES".equals(rs.getString("NULLABLE")) ? true : false);
|
||||
entity.setColPosition(rs.getInt("COLPOSITION"));
|
||||
entity.setDataDefault(rs.getString("DATADEFAULT"));
|
||||
entity.setColComment(rs.getString("COLCOMMENT"));
|
||||
return entity;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public RowMapper<DbTable> tableMapper() {
|
||||
return (ResultSet rs, int rowNum) -> {
|
||||
DbTable entity = new DbTable();
|
||||
entity.setTableName(rs.getString("TABLENAME"));
|
||||
entity.setTableComment(rs.getString("TABLECOMMENT"));
|
||||
return entity;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package com.codvision.db.dialect;
|
||||
|
||||
import com.codvision.db.core.DbColumn;
|
||||
import com.codvision.db.core.DbTable;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
|
||||
/**
|
||||
* SQLServer 2005 数据库方言
|
||||
*
|
||||
* @author yuwei
|
||||
* @since 2020-03-14
|
||||
*/
|
||||
public class SQLServer2008Dialect extends AbstractDbDialect {
|
||||
|
||||
@Override
|
||||
public String columns(String dbName, String tableName) {
|
||||
return "select columns.name AS colName, columns.column_id AS COLPOSITION, columns.max_length AS DATALENGTH, columns.precision AS DATAPRECISION, columns.scale AS DATASCALE, " +
|
||||
"columns.is_nullable AS NULLABLE, types.name AS DATATYPE, CAST(ep.value AS NVARCHAR(128)) AS COLCOMMENT, e.text AS DATADEFAULT, " +
|
||||
"(select top 1 ind.is_primary_key from sys.index_columns ic left join sys.indexes ind on ic.object_id = ind.object_id and ic.index_id = ind.index_id and ind.name like 'PK_%' where ic.object_id=columns.object_id and ic.column_id=columns.column_id) AS COLKEY " +
|
||||
"from sys.columns columns LEFT JOIN sys.types types ON columns.system_type_id = types.system_type_id " +
|
||||
"LEFT JOIN syscomments e ON columns.default_object_id= e.id " +
|
||||
"LEFT JOIN sys.extended_properties ep ON ep.major_id = columns.object_id AND ep.minor_id = columns.column_id AND ep.name = 'MS_Description' " +
|
||||
"where columns.object_id = object_id('" + tableName + "') order by columns.column_id ";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tables(String dbName) {
|
||||
return "select tables.name AS TABLENAME, CAST(ep.value AS NVARCHAR(128)) AS TABLECOMMENT " +
|
||||
"from sys.tables tables LEFT JOIN sys.extended_properties ep ON ep.major_id = tables.object_id AND ep.minor_id = 0";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String table(String dbName, String tableName) {
|
||||
return "select tables.name AS TABLENAME, CAST(ep.value AS NVARCHAR(128)) AS TABLECOMMENT " +
|
||||
"from sys.tables tables LEFT JOIN sys.extended_properties ep ON ep.major_id = tables.object_id AND ep.minor_id = 0" +
|
||||
"where tables.name = '" + tableName + "'";
|
||||
}
|
||||
|
||||
|
||||
private static String getOrderByPart(String sql) {
|
||||
String loweredString = sql.toLowerCase();
|
||||
int orderByIndex = loweredString.indexOf("order by");
|
||||
if (orderByIndex != -1) {
|
||||
return sql.substring(orderByIndex);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String buildPaginationSql(String originalSql, long offset, long count) {
|
||||
StringBuilder pagingBuilder = new StringBuilder();
|
||||
String orderby = getOrderByPart(originalSql);
|
||||
String distinctStr = "";
|
||||
|
||||
String loweredString = originalSql.toLowerCase();
|
||||
String sqlPartString = originalSql;
|
||||
if (loweredString.trim().startsWith("select")) {
|
||||
int index = 6;
|
||||
if (loweredString.startsWith("select distinct")) {
|
||||
distinctStr = "DISTINCT ";
|
||||
index = 15;
|
||||
}
|
||||
sqlPartString = sqlPartString.substring(index);
|
||||
}
|
||||
pagingBuilder.append(sqlPartString);
|
||||
|
||||
// if no ORDER BY is specified use fake ORDER BY field to avoid errors
|
||||
if (StringUtils.isEmpty(orderby)) {
|
||||
orderby = "ORDER BY CURRENT_TIMESTAMP";
|
||||
}
|
||||
StringBuilder sql = new StringBuilder();
|
||||
sql.append("WITH selectTemp AS (SELECT ").append(distinctStr).append("TOP 100 PERCENT ")
|
||||
.append(" ROW_NUMBER() OVER (").append(orderby).append(") as __row_number__, ").append(pagingBuilder)
|
||||
.append(") SELECT * FROM selectTemp WHERE __row_number__ BETWEEN ")
|
||||
//FIX#299:原因:mysql中limit 10(offset,size) 是从第10开始(不包含10),;而这里用的BETWEEN是两边都包含,所以改为offset+1
|
||||
.append(offset + 1)
|
||||
.append(" AND ")
|
||||
.append(offset + count).append(" ORDER BY __row_number__");
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RowMapper<DbColumn> columnMapper() {
|
||||
return (ResultSet rs, int rowNum) -> {
|
||||
DbColumn entity = new DbColumn();
|
||||
entity.setColName(rs.getString("COLNAME"));
|
||||
entity.setDataType(rs.getString("DATATYPE"));
|
||||
entity.setDataLength(rs.getString("DATALENGTH"));
|
||||
entity.setDataPrecision(rs.getString("DATAPRECISION"));
|
||||
entity.setDataScale(rs.getString("DATASCALE"));
|
||||
entity.setColKey("1".equals(rs.getString("COLKEY")) ? true : false);
|
||||
entity.setNullable("1".equals(rs.getString("NULLABLE")) ? true : false);
|
||||
entity.setColPosition(rs.getInt("COLPOSITION"));
|
||||
entity.setDataDefault(rs.getString("DATADEFAULT"));
|
||||
entity.setColComment(rs.getString("COLCOMMENT"));
|
||||
return entity;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public RowMapper<DbTable> tableMapper() {
|
||||
return (ResultSet rs, int rowNum) -> {
|
||||
DbTable entity = new DbTable();
|
||||
entity.setTableName(rs.getString("TABLENAME"));
|
||||
entity.setTableComment(rs.getString("TABLECOMMENT"));
|
||||
return entity;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.codvision.db.dialect;
|
||||
|
||||
/**
|
||||
* SQLServer 数据库方言
|
||||
*
|
||||
* @author yuwei
|
||||
* @since 2020-03-14
|
||||
*/
|
||||
public class SQLServerDialect extends SQLServer2008Dialect {
|
||||
|
||||
@Override
|
||||
public String buildPaginationSql(String originalSql, long offset, long count) {
|
||||
StringBuilder sqlBuilder = new StringBuilder(originalSql);
|
||||
sqlBuilder.append(" OFFSET ").append(offset).append(" ROWS FETCH NEXT ").append(count).append(" ROWS ONLY ");
|
||||
return sqlBuilder.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.codvision.db.dialect;
|
||||
|
||||
import com.codvision.db.core.DbColumn;
|
||||
import com.codvision.db.core.DbTable;
|
||||
import com.codvision.db.exception.DataQueryException;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
/**
|
||||
* 未知 数据库方言
|
||||
*
|
||||
* @author yuwei
|
||||
* @since 2020-03-14
|
||||
*/
|
||||
public class UnknownDialect extends AbstractDbDialect {
|
||||
|
||||
@Override
|
||||
public String columns(String dbName, String tableName) {
|
||||
throw new DataQueryException("不支持的数据库类型");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tables(String dbName) {
|
||||
throw new DataQueryException("不支持的数据库类型");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String table(String dbName, String tableName) {
|
||||
throw new DataQueryException("不支持的数据库类型");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String buildPaginationSql(String sql, long offset, long count) {
|
||||
throw new DataQueryException("不支持的数据库类型");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String count(String sql) {
|
||||
throw new DataQueryException("不支持的数据库类型");
|
||||
}
|
||||
|
||||
@Override
|
||||
public RowMapper<DbColumn> columnMapper() {
|
||||
throw new DataQueryException("不支持的数据库类型");
|
||||
}
|
||||
|
||||
@Override
|
||||
public RowMapper<DbTable> tableMapper() {
|
||||
throw new DataQueryException("不支持的数据库类型");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.codvision.db.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 数据库类型
|
||||
*
|
||||
* @author lingee
|
||||
* @date 2023/12/5
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum DbTypeEnum {
|
||||
|
||||
/**
|
||||
* mysql数据库
|
||||
*/
|
||||
mysql("mysql"),
|
||||
|
||||
/**
|
||||
* pgsql数据库
|
||||
*/
|
||||
postgresql("postgresql");
|
||||
|
||||
private final String type;
|
||||
|
||||
public static DbTypeEnum resolve(String type) {
|
||||
for (DbTypeEnum value : values()) {
|
||||
if (value.getType().equals(type)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
throw new EnumConstantNotPresentException(DbTypeEnum.class, type);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2023 codvision.com All Rights Reserved.
|
||||
*/
|
||||
|
||||
package com.codvision.db.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 系统业务空间
|
||||
*
|
||||
* @author lingee
|
||||
* @date 2023/12/12
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum SysBusinessSpace {
|
||||
|
||||
/**
|
||||
* 基础能力中心
|
||||
*/
|
||||
SYS_BASE("base"),
|
||||
|
||||
/**
|
||||
* 监控中心
|
||||
*/
|
||||
SYS_MONITOR("monitor"),
|
||||
|
||||
/**
|
||||
* 认证中心
|
||||
*/
|
||||
SYS_AUTH("auth");
|
||||
|
||||
private final String code;
|
||||
|
||||
public static SysBusinessSpace resolve(String key) {
|
||||
for (SysBusinessSpace value : values()) {
|
||||
if (value.code.equals(key)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.codvision.db.exception;
|
||||
|
||||
public class DataQueryException extends RuntimeException {
|
||||
|
||||
public DataQueryException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user