Commit f1b93458 authored by Fei 张飞's avatar Fei 张飞

init

parent 00f3a5f7
/.idea/
/target/
/yst-dch-score.iml
/interface/target/
/interface/interface.iml
# Compiled class file # Compiled class file
*.class *.class
......
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**
!**/src/test/**
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
### VS Code ###
.vscode/
/.mvn/
/mvnw
/mvnw.cmd
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>yst-dch-score</artifactId>
<groupId>com.elitesland</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>core</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>core</name>
<description>Elitesland YST core framework</description>
<properties>
<java.version>11</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<!--华为云仓库-->
<repository>
<id>huaweicloud</id>
<name>huaweicloud-maven</name>
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
</repository>
<!--阿里云仓库-->
<repository>
<id>aliyun</id>
<name>aliyun-maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
</repository>
<!-- 阿里云spring仓库 -->
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://maven.aliyun.com/repository/spring</url>
</repository>
<!-- 中央仓库 -->
<repository>
<id>central</id>
<name>maven-central</name>
<url>http://central.maven.org/maven2/</url>
</repository>
</repositories>
</project>
#! /bin/shell
# Copyright 2019-2029 elitesland(https://elitesland.com)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#======================================================================
# 项目重启shell脚本
# 先调用shutdown.sh停服
# 然后调用startup.sh启动服务
#
# author: Mir
# date: 2020-2-18
#======================================================================
# 项目名称
APPLICATION="yst-cms-svr"
# 停服
echo stop ${APPLICATION} Application...
sh shutdown.sh
# 启动服务
echo start ${APPLICATION} Application...
sh startup.sh
\ No newline at end of file
#! /bin/shell
# Copyright 2019-2029 elitesland(https://elitesland.com)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#======================================================================
# 项目停服shell脚本
# 通过项目名称查找到PID
# 然后kill -9 pid
#
# author: Mir
# date: 2020-2-18
#======================================================================
# 项目名称
APPLICATION="yst-cms-svr"
# 项目启动jar包名称
APPLICATION_JAR="${APPLICATION}.jar"
PID=$(ps -ef | grep ${APPLICATION_JAR} | grep -v grep | awk '{ print $2 }')
if [ -z "$PID" ]
then
echo ${APPLICATION} is already stopped
else
echo kill ${PID}
kill -9 ${PID}
echo ${APPLICATION} stopped successfully
fi
\ No newline at end of file
rem Copyright 2019-2029 elitesland(https://elitesland.com)
rem
rem Licensed under the Apache License, Version 2.0 (the "License");
rem you may not use this file except in compliance with the License.
rem You may obtain a copy of the License at
rem
rem http://www.apache.org/licenses/LICENSE-2.0
rem
rem Unless required by applicable law or agreed to in writing, software
rem distributed under the License is distributed on an "AS IS" BASIS,
rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
rem See the License for the specific language governing permissions and
rem limitations under the License.
rem ======================================================================
rem windows启动脚本
rem
rem author: Mir
rem date: 2020-2-18
rem ======================================================================
rem startup jar
java -jar ../lib/yst-cms-svr.jar --spring.config.location=../config/ --elbootplus.isEnableAnsi=false
pause
\ No newline at end of file
#! /bin/shell
# Copyright 2019-2029 elitesland(https://elitesland.com)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#======================================================================
# 项目启动shell脚本
# config目录: 配置文件目录
# logs目录: 项目运行日志目录
# logs/spring-boot-plus_startup.log: 记录启动日志
# logs/back目录: 项目运行日志备份目录
# nohup后台运行
#
# author: Mir
# date: 2020-2-18
#======================================================================
# 项目名称
APPLICATION="yst-cms-svr"
# 项目启动jar包名称
APPLICATION_JAR="${APPLICATION}.jar"
# bin目录绝对路径
BIN_PATH=$(cd $(dirname "$0"); pwd)
# 进入bin目录
cd $(dirname "$0")
# 返回到上一级项目根目录路径
cd ..
# 打印项目根目录绝对路径
# `pwd` 执行系统命令并获得结果
BASE_PATH=$(pwd)
# 外部配置文件绝对目录,如果是目录需要/结尾,也可以直接指定文件
# 如果指定的是目录,spring则会读取目录中的所有配置文件
CONFIG_DIR=${BASE_PATH}"/config/"
# 项目日志输出绝对路径
LOG_DIR=${BASE_PATH}"/logs"
LOG_FILE="${APPLICATION}.log"
LOG_PATH="${LOG_DIR}/${LOG_FILE}"
# 日志备份目录
LOG_BACK_DIR="${LOG_DIR}/back/"
# 项目启动日志输出绝对路径
LOG_STARTUP_PATH="${LOG_DIR}/${APPLICATION}_startup.log"
# 当前时间
NOW=$(date --date='0 days ago' "+%Y-%m-%d-%H-%M-%S")
NOW_PRETTY=$(date --date='0 days ago' "+%Y-%m-%d %H:%M:%S")
# 启动日志
STARTUP_LOG="================================================ ${NOW_PRETTY} ================================================\n"
# 如果logs文件夹不存在,则创建文件夹
if [ ! -d "${LOG_DIR}" ]; then
mkdir "${LOG_DIR}"
fi
# 如果logs/back文件夹不存在,则创建文件夹
if [ ! -d "${LOG_BACK_DIR}" ]; then
mkdir "${LOG_BACK_DIR}"
fi
# 如果项目运行日志存在,则重命名备份
if [ -f "${LOG_PATH}" ]; then
mv ${LOG_PATH} "${LOG_BACK_DIR}/${APPLICATION}_back_${NOW}.log"
fi
# 创建新的项目运行日志
echo "" > ${LOG_PATH}
# 如果项目启动日志不存在,则创建,否则追加
echo ${STARTUP_LOG} >> ${LOG_STARTUP_PATH}
#==========================================================================================
# JVM Configuration
# -Xmx1g:设置JVM最大可用内存为1G。
# -Xms1g:设置JVM初始内存41。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存
# -Xmn512m:设置年轻代大小为512m。整个JVM内存大小=年轻代大小 + 年老代大小 + 持久代大小。
# 持久代一般固定大小为64m,所以增大年轻代,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8
# -XX:MetaspaceSize=64m:存储class的内存大小,该值越大触发Metaspace GC的时机就越晚
# -XX:MaxMetaspaceSize=320m:限制Metaspace增长的上限,防止因为某些情况导致Metaspace无限的使用本地内存,影响到其他程序
# -XX:-OmitStackTraceInFastThrow:解决重复异常不打印堆栈信息问题
#==========================================================================================
JAVA_OPT="-server -Xms1g -Xmx1g -Xmn512m -XX:MetaspaceSize=64m -XX:MaxMetaspaceSize=256m"
JAVA_OPT="${JAVA_OPT} -XX:-OmitStackTraceInFastThrow"
#=======================================================
# 将命令启动相关日志追加到日志文件
#=======================================================
# 输出项目名称
STARTUP_LOG="${STARTUP_LOG}application name: ${APPLICATION}\n"
# 输出jar包名称
STARTUP_LOG="${STARTUP_LOG}application jar name: ${APPLICATION_JAR}\n"
# 输出项目bin路径
STARTUP_LOG="${STARTUP_LOG}application bin path: ${BIN_PATH}\n"
# 输出项目根目录
STARTUP_LOG="${STARTUP_LOG}application root path: ${BASE_PATH}\n"
# 打印日志路径
STARTUP_LOG="${STARTUP_LOG}application log path: ${LOG_PATH}\n"
# 打印JVM配置
STARTUP_LOG="${STARTUP_LOG}application JAVA_OPT : ${JAVA_OPT}\n"
# 打印启动命令
STARTUP_LOG="${STARTUP_LOG}application background startup command: nohup java ${JAVA_OPT} -jar ${BASE_PATH}/lib/${APPLICATION_JAR} --spring.config.location=${CONFIG_DIR} --logging.config=${CONFIG_DIR}logback.xml > ${LOG_PATH} 2>&1 &\n"
#======================================================================
# 执行启动命令:后台启动项目,并将日志输出到项目根目录下的logs文件夹下
#======================================================================
nohup java ${JAVA_OPT} -jar ${BASE_PATH}/lib/${APPLICATION_JAR} --spring.config.location=${CONFIG_DIR} --logging.config=${CONFIG_DIR}logback.xml > ${LOG_PATH} 2>&1 &
# 进程ID
PID=$(ps -ef | grep ${APPLICATION_JAR} | grep -v grep | awk '{ print $2 }')
STARTUP_LOG="${STARTUP_LOG}application pid: ${PID}\n"
# 启动日志追加到启动日志文件中
echo -e ${STARTUP_LOG} >> ${LOG_STARTUP_PATH}
# 打印启动日志
echo -e ${STARTUP_LOG}
# 打印项目日志
tail -f ${LOG_PATH}
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2019-2029 elitesland(https://elitesland.com)
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<assembly>
<!-- 可自定义,这里指定的是项目环境 -->
<!-- spring-boot-plus-server-1.0.1-RELEASE-local.tar.gz -->
<!-- <id>${project.version}-${profileActive}</id> -->
<id>assembly</id>
<!-- 打包的类型,如果有N个,将会打N个类型的包 -->
<formats>
<format>tar.gz</format>
<!-- <format>zip</format> -->
</formats>
<includeBaseDirectory>true</includeBaseDirectory>
<fileSets>
<!--
0755->即用户具有读/写/执行权限,组用户和其它用户具有读写权限;
0644->即用户具有读写权限,组用户和其它用户具有只读权限;
-->
<!-- 将src/bin目录下的所有文件输出到打包后的bin目录中 -->
<fileSet>
<directory>${basedir}/src/bin</directory>
<outputDirectory>bin</outputDirectory>
<fileMode>0755</fileMode>
<includes>
<include>**.sh</include>
<include>**.bat</include>
</includes>
</fileSet>
<!-- 指定输出target/classes中的配置文件到config目录中 -->
<fileSet>
<directory>${basedir}/target/classes/config</directory>
<outputDirectory>config</outputDirectory>
<fileMode>0644</fileMode>
<includes>
<include>*</include>
</includes>
</fileSet>
<!-- 将项目启动jar打包到lib目录中 -->
<fileSet>
<directory>${basedir}/target</directory>
<outputDirectory>lib</outputDirectory>
<fileMode>0755</fileMode>
<includes>
<include>${project.build.finalName}.jar</include>
</includes>
</fileSet>
<!-- 指定日志目录 -->
<fileSet>
<directory>${basedir}/src/logs</directory>
<outputDirectory>logs</outputDirectory>
<fileMode>0755</fileMode>
</fileSet>
<!-- 包含根目录下的文件 -->
<fileSet>
<directory>${basedir}</directory>
<includes>
<include>NOTICE</include>
<include>LICENSE</include>
</includes>
</fileSet>
</fileSets>
</assembly>
\ No newline at end of file
package com.elitesland.core;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CoreApplication {
public static void main(String[] args) {
SpringApplication.run(CoreApplication.class, args);
}
}
package com.elitesland.core.base;
/**
* <p>
* REST API 响应码
* </p>
*
* @author Mir
* @date 2018-11-08
*/
public enum ApiCode {
/**
* Http response entity status code, corresponding to HTTP Status Code
*/
SUCCESS(200, "操作成功"),
UNAUTHORIZED(401, "请先登录"),
NOT_PERMISSION(403, "没有权限"),
NOT_FOUND(404, "你请求的资源不存在"),
FAIL(500, "操作失败"),
LOGIN_EXCEPTION(4000, "登录失败"),
SYSTEM_EXCEPTION(5000, "系统异常!"),
PARAMETER_EXCEPTION(5001, "请求参数校验异常"),
PARAMETER_PARSE_EXCEPTION(5002, "请求参数解析异常"),
HTTP_MEDIA_TYPE_EXCEPTION(5003, "HTTP Media 类型异常"),
SPRING_BOOT_PLUS_EXCEPTION(5100, "系统处理异常"),
BUSINESS_EXCEPTION(5101, "业务处理异常"),
DAO_EXCEPTION(5102, "数据库处理异常"),
VERIFICATION_CODE_EXCEPTION(5103, "验证码校验异常"),
AUTHENTICATION_EXCEPTION(5104, "登录授权异常"),
UNAUTHENTICATED_EXCEPTION(5105, "没有访问权限"),
UNAUTHORIZED_EXCEPTION(5106, "没有访问权限"),
UNAUTHORIZED_ANONYMOUS(5107, "匿名用户,未授权访问"),
NO_USER_FOUND_EXCEPTION(5108, "用户信息未找到,系统异常")
;
private final int code;
private final String msg;
ApiCode(final int code, final String msg) {
this.code = code;
this.msg = msg;
}
public static ApiCode getApiCode(int code) {
ApiCode[] ecs = ApiCode.values();
for (ApiCode ec : ecs) {
if (ec.getCode() == code) {
return ec;
}
}
return SUCCESS;
}
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
package com.elitesland.core.base;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
/**
* <p>
* REST API 返回结果
* </p>
*
* @author Mir
* @date 2018-11-08
*/
@Data
@Accessors(chain = true)
@Builder
@AllArgsConstructor
public class ApiResult<T> implements Serializable {
private static final long serialVersionUID = 7722914707623525357L;
/**
* 响应码
*/
private int code;
/**
* 响应消息
*/
private String msg;
/**
* 是否成功
*/
private boolean success;
/**
* 响应数据
*/
private T data;
/**
* 响应时间
*/
// @JSONField(format = "yyyy-MM-ddTHH:mm:ss")
// @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime time = LocalDateTime.now();
public ApiResult() {
}
public static <T> ApiResult<T> result(boolean flag) {
if (flag) {
return ok();
}
return fail();
}
public static <T> ApiResult<T> result(ApiCode apiCode) {
return result(apiCode, null);
}
public static <T> ApiResult<T> result(ApiCode apiCode, T data) {
return result(apiCode, null, data);
}
public static <T> ApiResult<T> result(ApiCode apiCode, String msg, T data) {
boolean success = false;
if (apiCode.getCode() == ApiCode.SUCCESS.getCode()) {
success = true;
}
String message = apiCode.getMsg();
if (StrUtil.isNotBlank(msg)) {
message = msg;
}
return ApiResult.<T>builder()
.code(apiCode.getCode())
.msg(message)
.data(data)
.success(success)
.time(LocalDateTime.now())
.build();
}
public static <T> ApiResult<T> ok() {
return ok(null);
}
public static <T> ApiResult<T> ok(T data) {
return result(ApiCode.SUCCESS, data);
}
public static <T> ApiResult<T> ok(T data, String msg) {
return result(ApiCode.SUCCESS, msg, data);
}
public static <T> ApiResult<Map<String, T>> okMap(String key, T value) {
Map<String, T> map = new HashMap<>(1);
map.put(key, value);
return ok(map);
}
public static <T> ApiResult<T> fail(ApiCode apiCode) {
return result(apiCode, null);
}
public static <T> ApiResult<T> fail(String msg) {
return result(ApiCode.FAIL, msg, null);
}
public static <T> ApiResult<T> fail(ApiCode apiCode, T data) {
if (ApiCode.SUCCESS == apiCode) {
throw new RuntimeException("失败结果状态码不能为" + ApiCode.SUCCESS.getCode());
}
return result(apiCode, data);
}
public static <T> ApiResult<Map<String, T>> fail(String key, T value) {
Map<String, T> map = new HashMap<>(1);
map.put(key, value);
return result(ApiCode.FAIL, map);
}
public static <T> ApiResult<T> fail() {
return fail(ApiCode.FAIL);
}
}
\ No newline at end of file
package com.elitesland.core.base;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.hibernate.annotations.GenericGenerator;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import javax.validation.constraints.Null;
import java.time.LocalDateTime;
/**
* <pre>
* JPA数据实体类的基础类,用于唯一ID生成策略绑定
* 审计字段、版本和逻辑删除标记,
* 未来扩展租户ID信息
* </pre>
* @author Moz
* @date 3/17/2020
*/
@Data
@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
public class BaseModel {
@Id
@GenericGenerator(name = "el-id", strategy = "com.elitesland.core.util.IdGenerator")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "el-id")
@JsonSerialize(using = ToStringSerializer.class)
@ApiModelProperty("账号唯一ID")
@Column(columnDefinition = "bigint default 0 comment '唯一编号ID'")
private Long id;
@CreatedBy
@Column(columnDefinition = "bigint default 0 comment '记录创建者ID'")
private Long creator;
@CreatedDate
@Column(columnDefinition = "timestamp default NULL comment '记录创建时间'")
private LocalDateTime created = LocalDateTime.now();
@LastModifiedBy
@Column(columnDefinition = "bigint default 0 comment '记录最后更新者ID'")
private Long updater;
@LastModifiedDate
@Column(columnDefinition = "timestamp default NULL comment '记录最后更新时间'")
private LocalDateTime updated = LocalDateTime.now();
@ApiModelProperty(value = "逻辑删除,0:未删除,1:已删除")
@Null(message = "逻辑删除不用传")
@Column(columnDefinition = "int default 0 comment '逻辑删除,0:未删除,1:已删除'")
private Integer deleted;
@ApiModelProperty(value = "版本")
@Null(message = "版本不用传")
@Column(columnDefinition = "int default 0 comment '版本信息,前端不用传'")
private Integer version;
}
package com.elitesland.core.base;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Builder;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Collections;
import java.util.List;
/**
* @author Mir
* @date 2018-11-08
*/
@ApiModel("分页")
@Data
@Accessors(chain = true)
@Builder
public class PagingVO<T> implements Serializable {
private static final long serialVersionUID = -1683800405530086022L;
@ApiModelProperty("总行数")
@JsonProperty("total")
private Long total = 0L;
@ApiModelProperty("数据列表")
@JsonProperty("records")
private List<T> records = Collections.emptyList();
public PagingVO() {
}
public PagingVO(long total, List<T> records) {
this.total = total;
this.records = records;
}
public PagingVO(IPage<T> page) {
this.total = page.getTotal();
this.records = page.getRecords();
}
@Override
public String toString() {
return "Paging{" +
"total=" + total +
", records=" + records +
'}';
}
}
package com.elitesland.core.base.param;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.querydsl.core.types.Order;
import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.PathBuilder;
import com.querydsl.jpa.impl.JPAQuery;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.val;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.query.JpaQueryCreator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
/**
* 可排序查询参数对象
*
* @author Mir
* @date 2019-08-04
*/
@Data
@EqualsAndHashCode(callSuper = true)
@ApiModel("可排序查询参数对象")
public abstract class AbstractOrderQueryParam extends QueryParam {
private static final long serialVersionUID = 57714391204790143L;
@ApiModelProperty(value = "排序")
private List<OrderItem> orders;
public List<OrderItem> getOrders() {
return orders;
}
public void setOrders(List<OrderItem> orders) {
this.orders = orders;
}
public void defaultOrder(OrderItem orderItem) {
this.defaultOrders(Collections.singletonList(orderItem));
}
public void defaultOrders(List<OrderItem> orderItems) {
if (CollectionUtils.isEmpty(orderItems)) {
return;
}
this.orders = orderItems;
}
@JsonIgnore
public PageRequest getPageRequest() {
val orderBys = CollectionUtils.isEmpty(orders) ? new ArrayList<Sort.Order>() :
orders.stream().map(o -> new Sort.Order(
o.isAsc() ? Sort.Direction.ASC : Sort.Direction.DESC,
o.getColumn()
)).collect(Collectors.toList());
return PageRequest.of(getCurrent(), getSize(), Sort.by(orderBys));
}
@JsonIgnore
public void fillOrders(JPAQuery<?> query){
val pageRequest = getPageRequest();
pageRequest.getSort().forEach(s -> {
val orderbyExpression = new PathBuilder<>(Object.class, "object");
query.orderBy(new OrderSpecifier(s.isAscending() ?
Order.ASC : Order.DESC, orderbyExpression.get(s.getProperty())));
});
}
@JsonIgnore
public void setPaging(JPAQuery<?> query){
query.offset(getCurrent() * getSize());
query.limit(getSize());
}
}
package com.elitesland.core.base.param;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
/**
* @author Mir
* @date 2018-11-08
*/
@Data
@ApiModel("ID参数")
public class IdParam implements Serializable {
private static final long serialVersionUID = -5353973980674510450L;
@NotBlank(message = "ID不能为空")
private String id;
}
package com.elitesland.core.base.param;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
/**
* @author Mir
* @date 2018-11-08
*/
@ApiModel("主键状态VO")
public class IdStatusParam implements Serializable {
private static final long serialVersionUID = -7581307955242965701L;
@ApiModelProperty("主键ID")
private String id;
@ApiModelProperty("状态,1:启用 0:禁用")
private Integer status;
}
package com.elitesland.core.base.param;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
/**
* 名称参数
*
* @author Mir
* @date 2018-11-08
*/
@ApiModel("名称参数")
public class NameParam implements Serializable {
private static final long serialVersionUID = -3710501706034574149L;
@ApiModelProperty("名称")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "NameParam{" +
"name='" + name + '\'' +
'}';
}
}
package com.elitesland.core.base.param;
import com.elitesland.core.constant.CommonConstant;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
/**
* 查询参数
*
* @author Mir
* @date 2018-11-08
*/
@Data
@ApiModel("查询参数对象")
public abstract class QueryParam implements Serializable {
private static final long serialVersionUID = -3263921252635611410L;
@ApiModelProperty(value = "页码,默认为1", example = "0")
private Integer current = CommonConstant.DEFAULT_PAGE_INDEX;
@ApiModelProperty(value = "页大小,默认为10", example = "10")
private Integer size = CommonConstant.DEFAULT_PAGE_SIZE;
@ApiModelProperty(value = "搜索字符串", example = "")
private String keyword;
public Integer getCurrent() {
return current;
}
public Integer getSize() {
return size;
}
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
public void setCurrent(Integer current) {
if (current == null || current < 0) {
this.current = CommonConstant.DEFAULT_PAGE_INDEX;
} else {
this.current = current;
}
}
public void setSize(Integer size) {
if (size == null || size <= 0) {
this.size = CommonConstant.DEFAULT_PAGE_SIZE;
} else {
this.size = size;
}
}
}
package com.elitesland.core.config;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.persistence.EntityManager;
/**
* <pre>
*
* </pre>
* @author Mir
* @date 2020-06-20
*/
@Configuration
public class QueryDSLConfig {
@Bean
public JPAQueryFactory jpaQueryFactory(EntityManager em) {
return new JPAQueryFactory(em);
}
}
package com.elitesland.core.config.json;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* @author Mir
*/
@Configuration
public class LocalDateTimeSerializerConfig {
@Value("${spring.jackson.date-format: yyyy-MM-dd HH:mm:ss}")
private String pattern;
private LocalDateTimeSerializer localDateTimeSerializer;
private LocalDateTimeDeserializer localDateTimeDeserializer;
@Autowired
public void setLocalDateTimeSerializer(LocalDateTimeSerializer localDateTimeSerializer) {
this.localDateTimeSerializer = localDateTimeSerializer;
}
@Autowired
public void setLocalDateTimeDeserializer(LocalDateTimeDeserializer localDateTimeDeserializer) {
this.localDateTimeDeserializer = localDateTimeDeserializer;
}
@Bean
public LocalDateTimeSerializer localDateTimeSerializer() {
return new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(pattern));
}
@Bean
public LocalDateTimeDeserializer localDateTimeDeserializer() {
return new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(pattern));
}
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
return jacksonObjectMapperBuilder -> {
jacksonObjectMapperBuilder.serializerByType(LocalDateTime.class, localDateTimeSerializer);
jacksonObjectMapperBuilder.deserializerByType(LocalDateTime.class, localDateTimeDeserializer);
// jacksonObjectMapperBuilder.serializerByType(Long.class, ToStringSerializer.instance);
// jacksonObjectMapperBuilder.serializerByType(Long.TYPE, ToStringSerializer.instance);
};
}
}
package com.elitesland.core.constant;
public interface CacheKey {
}
package com.elitesland.core.constant;
/**
* 常量
*
* @author Mir
* @date 2018-11-08
*/
public interface CommonConstant {
/**
* 默认页码为1
*/
Integer DEFAULT_PAGE_INDEX = 0;
/**
* 默认页大小为10
*/
Integer DEFAULT_PAGE_SIZE = 10;
/**
* 登录用户
*/
String LOGIN_SYS_USER = "loginSysUser";
/**
* 登录token
*/
String JWT_DEFAULT_TOKEN_NAME = "token";
/**
* JWT用户名
*/
String JWT_USERNAME = "username";
/**
* JWT刷新新token响应状态码
*/
int JWT_REFRESH_TOKEN_CODE = 460;
/**
* JWT刷新新token响应状态码,
* Redis中不存在,但jwt未过期,不生成新的token,返回361状态码
*/
int JWT_INVALID_TOKEN_CODE = 461;
/**
* JWT Token默认密钥
*/
String JWT_DEFAULT_SECRET = "666666";
/**
* JWT 默认过期时间,3600L,单位秒
*/
Long JWT_DEFAULT_EXPIRE_SECOND = 3600L;
/**
* 初始密码
*/
String INIT_PWD = "123456";
/**
* 默认头像
*/
String DEFAULT_HEAD_URL = "";
/**
* 管理员角色名称
*/
String ADMIN_ROLE_NAME = "管理员";
String ADMIN_LOGIN = "adminLogin";
/**
* 验证码token
*/
String VERIFY_TOKEN = "verifyToken";
/**
* 图片
*/
String IMAGE = "image";
/**
* JPEG
*/
String JPEG = "JPEG";
/**
* base64前缀
*/
String BASE64_PREFIX = "data:image/png;base64,";
String AUDIT_CREATOR = "creator";
String AUDIT_CREATED = "created";
String AUDIT_UPDATER = "updater";
String AUDIT_UPDATED = "updated";
}
package com.elitesland.core.constant;
/**
* <p>
* redis key 常量
* </p>
*
* @author Mir
* @date 2019-05-23
**/
public interface CommonRedisKey {
/**
* 登录用户token信息key
*/
String LOGIN_TOKEN = "login:token:%s";
/**
* 登录用户信息key
*/
String LOGIN_USER = "login:user:%s";
/**
* 登录用户盐值信息key
*/
String LOGIN_SALT = "login:salt:%s";
/**
* 登录用户username token
*/
String LOGIN_USER_TOKEN = "login:user:token:%s:%s";
/**
* 验证码
*/
String VERIFY_CODE = "verify.code:%s";
}
package com.elitesland.core.constant;
/**
* <p>
* 日期格式常量
* </p>
*
* @author Mir
* @date 2018-11-08
*/
public interface DatePattern {
/**
* 年-月-日
*/
String yyyy_MM_dd = "yyyy-MM-dd";
/**
* 年-月-日 时:分
*/
String yyyy_MM_dd_HH_mm = "yyyy-MM-dd HH:mm";
/**
* 年-月-日 时:分:秒
*/
String yyyy_MM_dd_HH_mm_ss = "yyyy-MM-dd HH:mm:ss";
/**
* 年-月-日 时:分:秒:毫秒
*/
String yyyy_MM_dd_HH_mm_ss_S = "yyyy-MM-dd HH:mm:ss.S";
/**
* 时:分
*/
String HH_mm = "HH:mm";
/**
* 时:分:秒
*/
String HH_mm_ss = "HH:mm:ss";
/**
* 时:分:秒:毫秒
*/
String HH_mm_ss_S = "HH:mm:ss:S";
}
package com.elitesland.core.constant;
/**
* @author Mir
* @date 2020/03/18
*/
public interface HttpConstant {
String CHARSET_ENCODING_UTF8 = "UTF-8";
String CONTENT_TYPE_JSON = "application/json";
}
package com.elitesland.core.demo.service;
import org.springframework.stereotype.Service;
/**
* <p>
* 功能说明
* </p>
*
* @author Mir
* @date 2020/6/28
*/
@Service
public class DemoService {
public Integer add(int a, int b){
return a + b;
}
}
package com.elitesland.core.exception;
import org.springframework.security.core.AuthenticationException;
/**
* <pre>
* [功能说明]
* </pre>
*
* @author Mir
* @date 2020/6/24
*/
public class BadCaptchaException extends AuthenticationException {
private static final long serialVersionUID = 8337958032785176060L;
public BadCaptchaException(String msg) {
super(msg);
}
}
/*
* Copyright 2019-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.elitesland.core.exception;
/**
* <pre>
* 统一关于错误配置信息 异常
* </pre>
*
* @author Mir
* @date 2020-06-20
*/
public class BadConfigurationException extends RuntimeException {
private static final long serialVersionUID = -5628549105671311130L;
/**
* Constructs a new runtime exception with {@code null} as its
* detail message. The cause is not initialized, and may subsequently be
* initialized by a call to {@link #initCause}.
*/
public BadConfigurationException() {
super();
}
/**
* Constructs a new runtime exception with the specified detail message.
* The cause is not initialized, and may subsequently be initialized by a
* call to {@link #initCause}.
*
* @param message the detail message. The detail message is saved for
* later retrieval by the {@link #getMessage()} method.
*/
public BadConfigurationException(String message) {
super(message);
}
/**
* Constructs a new runtime exception with the specified detail message and
* cause. <p>Note that the detail message associated with
* {@code cause} is <i>not</i> automatically incorporated in
* this runtime exception's detail message.
*
* @param message the detail message (which is saved for later retrieval
* by the {@link #getMessage()} method).
* @param cause the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A {@code null} value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
* @since 1.4
*/
public BadConfigurationException(String message, Throwable cause) {
super(message, cause);
}
/**
* Constructs a new runtime exception with the specified cause and a
* detail message of {@code (cause==null ? null : cause.toString())}
* (which typically contains the class and detail message of
* {@code cause}). This constructor is useful for runtime exceptions
* that are little more than wrappers for other throwables.
*
* @param cause the cause (which is saved for later retrieval by the
* {@link #getCause()} method). (A {@code null} value is
* permitted, and indicates that the cause is nonexistent or
* unknown.)
* @since 1.4
*/
public BadConfigurationException(Throwable cause) {
super(cause);
}
/**
* Constructs a new runtime exception with the specified detail
* message, cause, suppression enabled or disabled, and writable
* stack trace enabled or disabled.
*
* @param message the detail message.
* @param cause the cause. (A {@code null} value is permitted,
* and indicates that the cause is nonexistent or unknown.)
* @param enableSuppression whether or not suppression is enabled
* or disabled
* @param writableStackTrace whether or not the stack trace should
* be writable
* @since 1.7
*/
protected BadConfigurationException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
package com.elitesland.core.exception;
import com.elitesland.core.base.ApiCode;
import lombok.Getter;
/**
* <pre>
* 业务异常
* </pre>
*
* @author Mir
* @date 2020/6/22
*/
@Getter
public class BusinessException extends RuntimeException {
private static final long serialVersionUID = -2205002357611194846L;
private ApiCode code;
public BusinessException() {
super();
}
public BusinessException(String message) {
super(message);
}
public BusinessException(ApiCode code, String message) {
super(message);
this.code = code;
}
public BusinessException(String message, Throwable cause) {
super(message, cause);
}
public BusinessException(Throwable cause) {
super(cause);
}
public BusinessException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
package com.elitesland.core.exception;
import org.springframework.security.core.AuthenticationException;
/**
* <pre>
* [功能说明]
* </pre>
*
* @author Mir
* @date 2020/6/24
*/
public class CaptchaExpiredException extends AuthenticationException {
private static final long serialVersionUID = -2209433381756411634L;
public CaptchaExpiredException(String msg) {
super(msg);
}
}
package com.elitesland.core.exception.handler;
import com.elitesland.core.base.ApiCode;
import com.elitesland.core.base.ApiResult;
import com.elitesland.core.exception.BusinessException;
import com.elitesland.core.util.ThrowableUtil;
import io.undertow.util.BadRequestException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* <pre>
* [功能说明]
* </pre>
*
* @author Mir
* @date 2020/6/22
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BadRequestException.class)
public ApiResult<Object> handleBadRequestException(BadRequestException e) {
log.error(ThrowableUtil.getStackTrace(e));
return ApiResult.fail(ApiCode.VERIFICATION_CODE_EXCEPTION, ThrowableUtil.getStackTrace(e));
}
@ExceptionHandler(BusinessException.class)
public ApiResult<Object> handleBusinessException(BusinessException e) {
log.error(ThrowableUtil.getStackTrace(e));
return ApiResult.fail(e.getCode(), ThrowableUtil.getStackTrace(e));
}
}
package com.elitesland.core.exception.rest;
import lombok.val;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.Optional;
/**
* <pre>
* [功能说明]
* </pre>
*
* @author Mir
* @date 2020/6/24
*/
@RestController
public class FilterErrorController extends BasicErrorController {
public FilterErrorController() {
super(new DefaultErrorAttributes(), new ErrorProperties());
}
@Override
@RequestMapping(produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
val body = getErrorAttributes(request, ErrorAttributeOptions.of(
ErrorAttributeOptions.Include.MESSAGE,
ErrorAttributeOptions.Include.BINDING_ERRORS,
ErrorAttributeOptions.Include.STACK_TRACE,
ErrorAttributeOptions.Include.EXCEPTION));
val status = getStatus(request);
return ResponseEntity.of(Optional.of(body));
}
@Override
public String getErrorPath() {
return "error/error";
}
}
package com.elitesland.core.micro;
import java.sql.Timestamp;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
/**
* Clock Pool
* <p>
* 利用ScheduledExecutorService实现高并发场景下System.currentTimeMillis()的性能问题的优化.
*
* @author Mir
* @date 3/17/2020
*
* https://github.com/yu120/neural
*/
public enum ClockPool {
// ====
INSTANCE(1);
private final long period;
private final AtomicLong nowTime;
private boolean started = false;
private ScheduledExecutorService executorService;
ClockPool(long period) {
this.period = period;
this.nowTime = new AtomicLong(System.currentTimeMillis());
}
/**
* The initialize scheduled executor service
*/
public void initialize() {
if (started) {
return;
}
this.executorService = new ScheduledThreadPoolExecutor(1, r -> {
Thread thread = new Thread(r, "system-clock");
thread.setDaemon(true);
return thread;
});
executorService.scheduleAtFixedRate(() -> nowTime.set(System.currentTimeMillis()),
this.period, this.period, TimeUnit.MILLISECONDS);
Runtime.getRuntime().addShutdownHook(new Thread(this::destroy));
started = true;
}
/**
* The get current time milliseconds
*
* @return long time
*/
public long currentTimeMillis() {
return started ? nowTime.get() : System.currentTimeMillis();
}
/**
* The get string current time
*
* @return string time
*/
public String currentTime() {
return new Timestamp(currentTimeMillis()).toString();
}
/**
* The destroy of executor service
*/
public void destroy() {
if (executorService != null) {
executorService.shutdown();
}
}
}
package com.elitesland.core.micro;
import java.net.InetAddress;
import java.util.concurrent.ThreadLocalRandom;
/**
* 基于Twitter的Snowflake算法实现分布式高效有序ID生产黑科技(sequence)——升级版Snowflake
*
* <br>
* SnowFlake的结构如下(每部分用-分开):<br>
* <br>
* 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000 <br>
* <br>
* 1位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0<br>
* <br>
* 41位时间截(毫秒级),注意,41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截)
* 得到的值),这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的(如下START_TIME属性)。
* 41位的时间截,可以使用69年,年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69<br>
* <br>
* 10位的数据机器位,可以部署在1024个节点,包括5位dataCenterId和5位workerId<br>
* <br>
* 12位序列,毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号<br>
* <br>
* <br>
* 加起来刚好64位,为一个Long型。<br>
* SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分),
* 并且效率较高,经测试,SnowFlake每秒能够产生26万ID左右。
* <p>
* <p>
* 特性:
* 1.支持自定义允许时间回拨的范围<p>
* 2.解决跨毫秒起始值每次为0开始的情况(避免末尾必定为偶数,而不便于取余使用问题)<p>
* 3.解决高并发场景中获取时间戳性能问题<p>
* 4.支撑根据IP末尾数据作为workerId
* 5.时间回拨方案思考:1024个节点中分配10个点作为时间回拨序号(连续10次时间回拨的概率较小)
*
* @author Mir
* @date 3/17/2020
*
* https://github.com/yu120/neural
*/
public class Snowflake {
/**
* 起始时间戳
**/
private final static long START_TIME = 1519740777809L;
/**
* dataCenterId占用的位数:2
**/
private final static long DATA_CENTER_ID_BITS = 2L;
/**
* workerId占用的位数:8
**/
private final static long WORKER_ID_BITS = 8L;
/**
* 序列号占用的位数:12(表示只允许workId的范围为:0-4095)
**/
private final static long SEQUENCE_BITS = 12L;
/**
* workerId可以使用范围:0-255
**/
private final static long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);
/**
* dataCenterId可以使用范围:0-3
**/
private final static long MAX_DATA_CENTER_ID = ~(-1L << DATA_CENTER_ID_BITS);
private final static long WORKER_ID_SHIFT = SEQUENCE_BITS;
private final static long DATA_CENTER_ID_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;
private final static long TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS + DATA_CENTER_ID_BITS;
/**
* 用mask防止溢出:位与运算保证计算的结果范围始终是 0-4095
**/
private final static long SEQUENCE_MASK = ~(-1L << SEQUENCE_BITS);
private final long workerId;
private final long dataCenterId;
private long sequence = 0L;
private long lastTimestamp = -1L;
private static byte LAST_IP = 0;
private final boolean clock;
private final long timeOffset;
private final boolean randomSequence;
private final ThreadLocalRandom tlr = ThreadLocalRandom.current();
public Snowflake(long dataCenterId) {
this(dataCenterId, 0x000000FF & getLastIPAddress(), false, 5L, false);
}
public Snowflake(long dataCenterId, boolean clock, boolean randomSequence) {
this(dataCenterId, 0x000000FF & getLastIPAddress(), clock, 5L, randomSequence);
}
/**
* 基于Snowflake创建分布式ID生成器
*
* @param dataCenterId 数据中心ID,数据范围为0~255
* @param workerId 工作机器ID,数据范围为0~3
* @param clock true表示解决高并发下获取时间戳的性能问题
* @param timeOffset 允许时间回拨的毫秒量,建议5ms
* @param randomSequence true表示使用毫秒内的随机序列(超过范围则取余)
*/
public Snowflake(long dataCenterId, long workerId, boolean clock, long timeOffset, boolean randomSequence) {
if (dataCenterId > MAX_DATA_CENTER_ID || dataCenterId < 0) {
throw new IllegalArgumentException("Data Center Id can't be greater than " +
MAX_DATA_CENTER_ID + " or less than 0");
}
if (workerId > MAX_WORKER_ID || workerId < 0) {
throw new IllegalArgumentException("Worker Id can't be greater than " +
MAX_WORKER_ID + " or less than 0");
}
this.workerId = workerId;
this.dataCenterId = dataCenterId;
this.clock = clock;
this.timeOffset = timeOffset;
this.randomSequence = randomSequence;
}
/**
* 获取ID
*
* @return long
*/
public synchronized Long nextId() {
long currentTimestamp = this.timeGen();
// 闰秒:如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过,这个时候应当抛出异常
if (currentTimestamp < lastTimestamp) {
// 校验时间偏移回拨量
long offset = lastTimestamp - currentTimestamp;
if (offset > timeOffset) {
throw new RuntimeException("Clock moved backwards, refusing to generate id for [" + offset + "ms]");
}
try {
// 时间回退timeOffset毫秒内,则允许等待2倍的偏移量后重新获取,解决小范围的时间回拨问题
this.wait(offset << 1);
} catch (Exception e) {
throw new RuntimeException(e);
}
// 再次获取
currentTimestamp = this.timeGen();
// 再次校验
if (currentTimestamp < lastTimestamp) {
throw new RuntimeException("Clock moved backwards, refusing to generate id for [" + offset + "ms]");
}
}
// 同一毫秒内序列直接自增
if (lastTimestamp == currentTimestamp) {
// randomSequence为true表示随机生成允许范围内的序列起始值并取余数,否则毫秒内起始值为0L开始自增
long tempSequence = sequence + 1;
if (randomSequence && tempSequence > SEQUENCE_MASK) {
tempSequence = tempSequence % SEQUENCE_MASK;
}
// 通过位与运算保证计算的结果范围始终是 0-4095
sequence = tempSequence & SEQUENCE_MASK;
if (sequence == 0) {
currentTimestamp = this.tilNextMillis(lastTimestamp);
}
} else {
// randomSequence为true表示随机生成允许范围内的序列起始值,否则毫秒内起始值为0L开始自增
sequence = randomSequence ? tlr.nextLong(SEQUENCE_MASK + 1) : 0L;
}
lastTimestamp = currentTimestamp;
long currentOffsetTime = currentTimestamp - START_TIME;
/*
* 1.左移运算是为了将数值移动到对应的段(41、5、5,12那段因为本来就在最右,因此不用左移)
* 2.然后对每个左移后的值(la、lb、lc、sequence)做位或运算,是为了把各个短的数据合并起来,合并成一个二进制数
* 3.最后转换成10进制,就是最终生成的id
*/
return (currentOffsetTime << TIMESTAMP_LEFT_SHIFT) |
// 数据中心位
(dataCenterId << DATA_CENTER_ID_SHIFT) |
// 工作ID位
(workerId << WORKER_ID_SHIFT) |
// 毫秒序列化位
sequence;
}
/**
* 保证返回的毫秒数在参数之后(阻塞到下一个毫秒,直到获得新的时间戳)——CAS
*
* @param lastTimestamp last timestamp
* @return next millis
*/
private long tilNextMillis(long lastTimestamp) {
long timestamp = this.timeGen();
while (timestamp <= lastTimestamp) {
// 如果发现时间回拨,则自动重新获取(可能会处于无限循环中)
timestamp = this.timeGen();
}
return timestamp;
}
/**
* 获得系统当前毫秒时间戳
*
* @return timestamp 毫秒时间戳
*/
private long timeGen() {
return clock ? ClockPool.INSTANCE.currentTimeMillis() : System.currentTimeMillis();
}
/**
* 用IP地址最后几个字节标示
* <p>
* eg:192.168.1.30->30
*
* @return last IP
*/
private static byte getLastIPAddress() {
if (LAST_IP != 0) {
return LAST_IP;
}
try {
InetAddress inetAddress = InetAddress.getLocalHost();
byte[] addressByte = inetAddress.getAddress();
LAST_IP = addressByte[addressByte.length - 1];
} catch (Exception e) {
throw new RuntimeException("Unknown Host Exception", e);
}
return LAST_IP;
}
}
/*
* Copyright 2019-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.elitesland.core.util;
/**
* @author: liaojinlong
* @date: 2020/6/9 17:02
* @since: 1.0
* @see {@link SpringContextHolder}
* 针对某些初始化方法,在SpringContextHolder 初始化前时,<br>
* 可提交一个 提交回调任务。<br>
* 在SpringContextHolder 初始化后,进行回调使用
*/
public interface CallBack {
/**
* 回调执行方法
*/
void executor();
/**
* 本回调任务名称
* @return /
*/
default String getCallBackName() {
return Thread.currentThread().getId() + ":" + this.getClass().getName();
}
}
package com.elitesland.core.util;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import lombok.val;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.time.LocalDateTime;
/**
* @author Mir
* @date 2018-11-08
*/
public final class HttpServletResponseUtil {
private static String UTF8 = "UTF-8";
private static String CONTENT_TYPE = "application/json";
private HttpServletResponseUtil() {
throw new AssertionError();
}
public static void printJSON(HttpServletResponse response, Object object) throws Exception {
val mapper = new ObjectMapper();
val javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(LocalDateTime.class, SpringContextHolder.getBean(LocalDateTimeSerializer.class));
javaTimeModule.addDeserializer(LocalDateTime.class, SpringContextHolder.getBean(LocalDateTimeDeserializer.class));
mapper.registerModule(javaTimeModule);
response.setCharacterEncoding(UTF8);
response.setContentType(CONTENT_TYPE);
PrintWriter printWriter = response.getWriter();
printWriter.write(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(object));
printWriter.flush();
printWriter.close();
}
}
package com.elitesland.core.util;
import com.elitesland.core.micro.Snowflake;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.IdentifierGenerator;
import java.io.Serializable;
/**
* 适用于JPA的基于Snowflake算法的ID生成器
*
* @author Moz
* @date 3/17/2020
*/
public class IdGenerator implements IdentifierGenerator {
private final Snowflake snowflake = new Snowflake(1);
@Override
public Serializable generate(SharedSessionContractImplementor sharedSessionContractImplementor, Object o) throws HibernateException {
return snowflake.nextId();
}
}
package com.elitesland.core.util;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
/**
* <pre>
* 封装请求,并替换getParameter从原有的Parameter获取值,为从Attribute中获取值
* </pre>
*
* @author Mir
* @date 2020/6/16
*/
public class ParameterRequestWrapper extends HttpServletRequestWrapper {
public ParameterRequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public String getParameter(String name) {
return (String) super.getAttribute(name);
}
}
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.elitesland.core.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisConnectionUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* <pre>
* Redis访问的工具类
* </pre>
*
* @author Mir
* @date 2020-06-20
*/
@Component
@SuppressWarnings({"unchecked", "all"})
public class RedisUtils {
private static final Logger log = LoggerFactory.getLogger(RedisUtils.class);
private RedisTemplate<Object, Object> redisTemplate;
@Value("${jwt.online-key}")
private String onlineKey;
public RedisUtils(RedisTemplate<Object, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
/**
* 指定缓存失效时间
*
* @param key 键
* @param time 时间(秒)
*/
public boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
return true;
}
/**
* 指定缓存失效时间
*
* @param key 键
* @param time 时间(秒)
* @param timeUnit 单位
*/
public boolean expire(String key, long time, TimeUnit timeUnit) {
try {
if (time > 0) {
redisTemplate.expire(key, time, timeUnit);
}
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
return true;
}
/**
* 根据 key 获取过期时间
*
* @param key 键 不能为null
* @return 时间(秒) 返回0代表为永久有效
*/
public long getExpire(Object key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/**
* 查找匹配key
*
* @param pattern key
* @return /
*/
public List<String> scan(String pattern) {
ScanOptions options = ScanOptions.scanOptions().match(pattern).build();
RedisConnectionFactory factory = redisTemplate.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()));
}
try {
RedisConnectionUtils.releaseConnection(rc, factory);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return result;
}
/**
* 分页查询 key
*
* @param patternKey key
* @param page 页码
* @param size 每页数目
* @return /
*/
public List<String> findKeysForPage(String patternKey, int page, int size) {
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();
}
try {
RedisConnectionUtils.releaseConnection(rc, factory);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return result;
}
/**
* 判断key是否存在
*
* @param key 键
* @return true 存在 false不存在
*/
public boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
}
/**
* 删除缓存
*
* @param key 可以传一个值 或多个
*/
public void del(String... keys) {
if (keys != null && keys.length > 0) {
if (keys.length == 1) {
boolean result = redisTemplate.delete(keys[0]);
System.out.println("--------------------------------------------");
System.out.println(new StringBuilder("删除缓存:").append(keys[0]).append(",结果:").append(result));
System.out.println("--------------------------------------------");
} else {
Set<Object> keySet = new HashSet<>();
for (String key : keys) {
keySet.addAll(redisTemplate.keys(key));
}
long count = redisTemplate.delete(keySet);
System.out.println("--------------------------------------------");
System.out.println("成功删除缓存:" + keySet.toString());
System.out.println("缓存删除数量:" + count + "个");
System.out.println("--------------------------------------------");
}
}
}
// ============================String=============================
/**
* 普通缓存获取
*
* @param key 键
* @return 值
*/
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}
/**
* 批量获取
*
* @param keys
* @return
*/
public List<Object> multiGet(List<String> keys) {
Object obj = redisTemplate.opsForValue().multiGet(Collections.singleton(keys));
return null;
}
/**
* 普通缓存放入
*
* @param key 键
* @param value 值
* @return true成功 false失败
*/
public boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
}
/**
* 普通缓存放入并设置时间
*
* @param key 键
* @param value 值
* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
* @return true成功 false 失败
*/
public boolean set(String key, Object value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
set(key, value);
}
return true;
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
}
/**
* 普通缓存放入并设置时间
*
* @param key 键
* @param value 值
* @param time 时间
* @param timeUnit 类型
* @return true成功 false 失败
*/
public boolean set(String key, Object value, long time, TimeUnit timeUnit) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, timeUnit);
} else {
set(key, value);
}
return true;
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
}
// ================================Map=================================
/**
* HashGet
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return 值
*/
public Object hget(String key, String item) {
return redisTemplate.opsForHash().get(key, item);
}
/**
* 获取hashKey对应的所有键值
*
* @param key 键
* @return 对应的多个键值
*/
public Map<Object, Object> hmget(String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* HashSet
*
* @param key 键
* @param map 对应多个键值
* @return true 成功 false 失败
*/
public boolean hmset(String key, Map<String, Object> map) {
try {
redisTemplate.opsForHash().putAll(key, map);
return true;
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
}
/**
* HashSet 并设置时间
*
* @param key 键
* @param map 对应多个键值
* @param time 时间(秒)
* @return true成功 false失败
*/
public boolean hmset(String key, Map<String, Object> map, long time) {
try {
redisTemplate.opsForHash().putAll(key, map);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value) {
try {
redisTemplate.opsForHash().put(key, item, value);
return true;
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value, long time) {
try {
redisTemplate.opsForHash().put(key, item, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
}
/**
* 删除hash表中的值
*
* @param key 键 不能为null
* @param item 项 可以使多个 不能为null
*/
public void hdel(String key, Object... item) {
redisTemplate.opsForHash().delete(key, item);
}
/**
* 判断hash表中是否有该项的值
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return true 存在 false不存在
*/
public boolean hHasKey(String key, String item) {
return redisTemplate.opsForHash().hasKey(key, item);
}
/**
* hash递增 如果不存在,就会创建一个 并把新增后的值返回
*
* @param key 键
* @param item 项
* @param by 要增加几(大于0)
* @return
*/
public double hincr(String key, String item, double by) {
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) {
return redisTemplate.opsForHash().increment(key, item, -by);
}
// ============================set=============================
/**
* 根据key获取Set中的所有值
*
* @param key 键
* @return
*/
public Set<Object> sGet(String key) {
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
log.error(e.getMessage(), e);
return null;
}
}
/**
* 根据value从一个set中查询,是否存在
*
* @param key 键
* @param value 值
* @return true 存在 false不存在
*/
public boolean sHasKey(String key, Object value) {
try {
return redisTemplate.opsForSet().isMember(key, value);
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
}
/**
* 将数据放入set缓存
*
* @param key 键
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSet(String key, Object... values) {
try {
return redisTemplate.opsForSet().add(key, values);
} catch (Exception e) {
log.error(e.getMessage(), e);
return 0;
}
}
/**
* 将set数据放入缓存
*
* @param key 键
* @param time 时间(秒)
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSetAndTime(String key, long time, Object... values) {
try {
Long count = redisTemplate.opsForSet().add(key, values);
if (time > 0) {
expire(key, time);
}
return count;
} catch (Exception e) {
log.error(e.getMessage(), e);
return 0;
}
}
/**
* 获取set缓存的长度
*
* @param key 键
* @return
*/
public long sGetSetSize(String key) {
try {
return redisTemplate.opsForSet().size(key);
} catch (Exception e) {
log.error(e.getMessage(), e);
return 0;
}
}
/**
* 移除值为value的
*
* @param key 键
* @param values 值 可以是多个
* @return 移除的个数
*/
public long setRemove(String key, Object... values) {
try {
Long count = redisTemplate.opsForSet().remove(key, values);
return count;
} catch (Exception e) {
log.error(e.getMessage(), e);
return 0;
}
}
// ===============================list=================================
/**
* 获取list缓存的内容
*
* @param key 键
* @param start 开始
* @param end 结束 0 到 -1代表所有值
* @return
*/
public List<Object> lGet(String key, long start, long end) {
try {
return redisTemplate.opsForList().range(key, start, end);
} catch (Exception e) {
log.error(e.getMessage(), e);
return null;
}
}
/**
* 获取list缓存的长度
*
* @param key 键
* @return
*/
public long lGetListSize(String key) {
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
log.error(e.getMessage(), e);
return 0;
}
}
/**
* 通过索引 获取list中的值
*
* @param key 键
* @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
* @return
*/
public Object lGetIndex(String key, long index) {
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
log.error(e.getMessage(), e);
return null;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @return
*/
public boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, Object value, long time) {
try {
redisTemplate.opsForList().rightPush(key, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @return
*/
public boolean lSet(String key, List<Object> value) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
return true;
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, List<Object> value, long time) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
}
/**
* 根据索引修改list中的某条数据
*
* @param key 键
* @param index 索引
* @param value 值
* @return /
*/
public boolean lUpdateIndex(String key, long index, Object value) {
try {
redisTemplate.opsForList().set(key, index, value);
return true;
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
}
/**
* 移除N个值为value
*
* @param key 键
* @param count 移除多少个
* @param value 值
* @return 移除的个数
*/
public long lRemove(String key, long count, Object value) {
try {
return redisTemplate.opsForList().remove(key, count, value);
} catch (Exception e) {
log.error(e.getMessage(), e);
return 0;
}
}
/**
* @param prefix 前缀
* @param ids id
*/
public void delByKeys(String prefix, Set<Long> ids) {
Set<Object> keys = new HashSet<>();
for (Long id : ids) {
keys.addAll(redisTemplate.keys(new StringBuffer(prefix).append(id).toString()));
}
long count = redisTemplate.delete(keys);
// 此处提示可自行删除
System.out.println("--------------------------------------------");
System.out.println("成功删除缓存:" + keys.toString());
System.out.println("缓存删除数量:" + count + "个");
System.out.println("--------------------------------------------");
}
}
package com.elitesland.core.util;
import lombok.val;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
/**
* <pre>
* 将请求的body的二进制内容转为字符串
* </pre>
*
* @author Mir
* @date 2020/6/16
*/
public class RequestUtil {
private static final Logger log = LoggerFactory.getLogger(RequestUtil.class);
private RequestUtil() {
}
public static String obtainBody(ServletRequest request) {
BufferedReader br = null;
val sb = new StringBuilder();
try {
br = request.getReader();
String str;
while ((str = br.readLine()) != null) {
sb.append(str);
}
br.close();
} catch (IOException e) {
log.error("request body error");
} finally {
if (null != br) {
try {
br.close();
} catch (IOException e) {
log.error("request reader close error");
}
}
}
return sb.toString();
}
}
package com.elitesland.core.util;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
/**
* @author https://www.cnblogs.com/nihaorz/p/10690643.html
* @description Rsa 工具类,公钥私钥生成,加解密
* @date 2020-05-18
**/
public class RsaUtils {
private static final String SRC = "123456";
public static void main(String[] args) throws Exception {
System.out.println("\n");
RsaKeyPair keyPair = generateKeyPair();
System.out.println("公钥:" + keyPair.getPublicKey());
System.out.println("私钥:" + keyPair.getPrivateKey());
System.out.println("\n");
test1(keyPair);
System.out.println("\n");
test2(keyPair);
System.out.println("\n");
}
/**
* 公钥加密私钥解密
*/
private static void test1(RsaKeyPair keyPair) throws Exception {
System.out.println("***************** 公钥加密私钥解密开始 *****************");
String text1 = encryptByPublicKey(keyPair.getPublicKey(), RsaUtils.SRC);
String text2 = decryptByPrivateKey(keyPair.getPrivateKey(), text1);
System.out.println("加密前:" + RsaUtils.SRC);
System.out.println("加密后:" + text1);
System.out.println("解密后:" + text2);
if (RsaUtils.SRC.equals(text2)) {
System.out.println("解密字符串和原始字符串一致,解密成功");
} else {
System.out.println("解密字符串和原始字符串不一致,解密失败");
}
System.out.println("***************** 公钥加密私钥解密结束 *****************");
}
/**
* 私钥加密公钥解密
* @throws Exception /
*/
private static void test2(RsaKeyPair keyPair) throws Exception {
System.out.println("***************** 私钥加密公钥解密开始 *****************");
String text1 = encryptByPrivateKey(keyPair.getPrivateKey(), RsaUtils.SRC);
String text2 = decryptByPublicKey(keyPair.getPublicKey(), text1);
System.out.println("加密前:" + RsaUtils.SRC);
System.out.println("加密后:" + text1);
System.out.println("解密后:" + text2);
if (RsaUtils.SRC.equals(text2)) {
System.out.println("解密字符串和原始字符串一致,解密成功");
} else {
System.out.println("解密字符串和原始字符串不一致,解密失败");
}
System.out.println("***************** 私钥加密公钥解密结束 *****************");
}
/**
* 公钥解密
*
* @param publicKeyText 公钥
* @param text 待解密的信息
* @return /
* @throws Exception /
*/
public static String decryptByPublicKey(String publicKeyText, String text) throws Exception {
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, publicKey);
byte[] result = cipher.doFinal(Base64.decodeBase64(text));
return new String(result);
}
/**
* 私钥加密
*
* @param privateKeyText 私钥
* @param text 待加密的信息
* @return /
* @throws Exception /
*/
public static String encryptByPrivateKey(String privateKeyText, String text) throws Exception {
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
byte[] result = cipher.doFinal(text.getBytes());
return Base64.encodeBase64String(result);
}
/**
* 私钥解密
*
* @param privateKeyText 私钥
* @param text 待解密的文本
* @return /
* @throws Exception /
*/
public static String decryptByPrivateKey(String privateKeyText, String text) throws Exception {
PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec5);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] result = cipher.doFinal(Base64.decodeBase64(text));
return new String(result);
}
/**
* 公钥加密
*
* @param publicKeyText 公钥
* @param text 待加密的文本
* @return /
*/
public static String encryptByPublicKey(String publicKeyText, String text) throws Exception {
X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec2);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] result = cipher.doFinal(text.getBytes());
return Base64.encodeBase64String(result);
}
/**
* 构建RSA密钥对
*
* @return /
* @throws NoSuchAlgorithmException /
*/
public static RsaKeyPair generateKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
String publicKeyString = Base64.encodeBase64String(rsaPublicKey.getEncoded());
String privateKeyString = Base64.encodeBase64String(rsaPrivateKey.getEncoded());
return new RsaKeyPair(publicKeyString, privateKeyString);
}
/**
* RSA密钥对对象
*/
public static class RsaKeyPair {
private final String publicKey;
private final String privateKey;
public RsaKeyPair(String publicKey, String privateKey) {
this.publicKey = publicKey;
this.privateKey = privateKey;
}
public String getPublicKey() {
return publicKey;
}
public String getPrivateKey() {
return privateKey;
}
}
}
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.elitesland.core.util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.env.Environment;
import java.util.ArrayList;
import java.util.List;
/**
* @author Jie
* @date 2019-01-07
*/
@Slf4j
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
private static ApplicationContext applicationContext = null;
private static final List<CallBack> CALL_BACKS = new ArrayList<>();
private static boolean addCallback = true;
/**
* 针对 某些初始化方法,在SpringContextHolder 未初始化时 提交回调方法。
* 在SpringContextHolder 初始化后,进行回调使用
*
* @param callBack 回调函数
*/
public synchronized static void addCallBacks(CallBack callBack) {
if (addCallback) {
SpringContextHolder.CALL_BACKS.add(callBack);
} else {
log.warn("CallBack:{} 已无法添加!立即执行", callBack.getCallBackName());
callBack.executor();
}
}
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) {
assertContextInjected();
return (T) applicationContext.getBean(name);
}
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
public static <T> T getBean(Class<T> requiredType) {
assertContextInjected();
return applicationContext.getBean(requiredType);
}
/**
* 获取SpringBoot 配置信息
*
* @param property 属性key
* @param defaultValue 默认值
* @param requiredType 返回类型
* @return /
*/
public static <T> T getProperties(String property, T defaultValue, Class<T> requiredType) {
T result = defaultValue;
try {
result = getBean(Environment.class).getProperty(property, requiredType);
} catch (Exception ignored) {}
return result;
}
/**
* 获取SpringBoot 配置信息
*
* @param property 属性key
* @return /
*/
public static String getProperties(String property) {
return getProperties(property, null, String.class);
}
/**
* 获取SpringBoot 配置信息
*
* @param property 属性key
* @param requiredType 返回类型
* @return /
*/
public static <T> T getProperties(String property, Class<T> requiredType) {
return getProperties(property, null, requiredType);
}
/**
* 检查ApplicationContext不为空.
*/
private static void assertContextInjected() {
if (applicationContext == null) {
throw new IllegalStateException("applicaitonContext属性未注入, 请在applicationContext" +
".xml中定义SpringContextHolder或在SpringBoot启动类中注册SpringContextHolder.");
}
}
/**
* 清除SpringContextHolder中的ApplicationContext为Null.
*/
private static void clearHolder() {
log.debug("清除SpringContextHolder中的ApplicationContext:"
+ applicationContext);
applicationContext = null;
}
@Override
public void destroy() {
SpringContextHolder.clearHolder();
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (SpringContextHolder.applicationContext != null) {
log.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + SpringContextHolder.applicationContext);
}
SpringContextHolder.applicationContext = applicationContext;
if (addCallback) {
for (CallBack callBack : SpringContextHolder.CALL_BACKS) {
callBack.executor();
}
CALL_BACKS.clear();
}
SpringContextHolder.addCallback = false;
}
}
package com.elitesland.core.util;
import lombok.val;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
* <pre>
* 整理异常中的堆栈信息,返回信息字符串
* </pre>
*
* @author Mir
* @date 2020/6/22
*/
public class ThrowableUtil {
public static String getStackTrace(Throwable e) {
val sw = new StringWriter();
try (val pw = new PrintWriter(sw)) {
e.printStackTrace(pw);
return sw.toString();
}
}
}
package org.hibernate.cfg;
import org.hibernate.AnnotationException;
import org.hibernate.annotations.common.reflection.XAnnotatedElement;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.cfg.AccessType;
import org.hibernate.cfg.AnnotationBinder;
import org.hibernate.cfg.PropertyData;
import org.hibernate.cfg.annotations.EntityBinder;
import org.hibernate.mapping.PersistentClass;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* <p>
* 将默认BaseModel字段在前,其他字段在后的顺序调整为:
* id, 其他字段,审计字段
* </p>
*
* @author Mir
* @date 2020/5/19
*/
public class InheritanceState {
private XClass clazz;
/**
* Has sibling (either mappedsuperclass entity)
*/
private boolean hasSiblings = false;
/**
* a mother entity is available
*/
private boolean hasParents = false;
private InheritanceType type;
private boolean isEmbeddableSuperclass = false;
private Map<XClass, org.hibernate.cfg.InheritanceState> inheritanceStatePerClass;
private List<XClass> classesToProcessForMappedSuperclass = new ArrayList<XClass>();
private MetadataBuildingContext buildingContext;
private AccessType accessType;
private ElementsToProcess elementsToProcess;
private Boolean hasIdClassOrEmbeddedId;
public InheritanceState(
XClass clazz,
Map<XClass, org.hibernate.cfg.InheritanceState> inheritanceStatePerClass,
MetadataBuildingContext buildingContext) {
this.setClazz( clazz );
this.buildingContext = buildingContext;
this.inheritanceStatePerClass = inheritanceStatePerClass;
extractInheritanceType();
}
private void extractInheritanceType() {
XAnnotatedElement element = getClazz();
Inheritance inhAnn = element.getAnnotation( Inheritance.class );
MappedSuperclass mappedSuperClass = element.getAnnotation( MappedSuperclass.class );
if ( mappedSuperClass != null ) {
setEmbeddableSuperclass( true );
setType( inhAnn == null ? null : inhAnn.strategy() );
}
else {
setType( inhAnn == null ? InheritanceType.SINGLE_TABLE : inhAnn.strategy() );
}
}
boolean hasTable() {
return !hasParents() || !InheritanceType.SINGLE_TABLE.equals( getType() );
}
boolean hasDenormalizedTable() {
return hasParents() && InheritanceType.TABLE_PER_CLASS.equals( getType() );
}
public static org.hibernate.cfg.InheritanceState getInheritanceStateOfSuperEntity(
XClass clazz, Map<XClass, org.hibernate.cfg.InheritanceState> states
) {
XClass superclass = clazz;
do {
superclass = superclass.getSuperclass();
org.hibernate.cfg.InheritanceState currentState = states.get( superclass );
if ( currentState != null && !currentState.isEmbeddableSuperclass() ) {
return currentState;
}
}
while ( superclass != null && !Object.class.getName().equals( superclass.getName() ) );
return null;
}
public static org.hibernate.cfg.InheritanceState getSuperclassInheritanceState(XClass clazz, Map<XClass, org.hibernate.cfg.InheritanceState> states) {
XClass superclass = clazz;
do {
superclass = superclass.getSuperclass();
org.hibernate.cfg.InheritanceState currentState = states.get( superclass );
if ( currentState != null ) {
return currentState;
}
}
while ( superclass != null && !Object.class.getName().equals( superclass.getName() ) );
return null;
}
public XClass getClazz() {
return clazz;
}
public void setClazz(XClass clazz) {
this.clazz = clazz;
}
public boolean hasSiblings() {
return hasSiblings;
}
public void setHasSiblings(boolean hasSiblings) {
this.hasSiblings = hasSiblings;
}
public boolean hasParents() {
return hasParents;
}
public void setHasParents(boolean hasParents) {
this.hasParents = hasParents;
}
public InheritanceType getType() {
return type;
}
public void setType(InheritanceType type) {
this.type = type;
}
public boolean isEmbeddableSuperclass() {
return isEmbeddableSuperclass;
}
public void setEmbeddableSuperclass(boolean embeddableSuperclass) {
isEmbeddableSuperclass = embeddableSuperclass;
}
void postProcess(PersistentClass persistenceClass, EntityBinder entityBinder) {
//make sure we run elements to process
getElementsToProcess();
addMappedSuperClassInMetadata( persistenceClass );
entityBinder.setPropertyAccessType( accessType );
}
public XClass getClassWithIdClass(boolean evenIfSubclass) {
if ( !evenIfSubclass && hasParents() ) {
return null;
}
if ( clazz.isAnnotationPresent( IdClass.class ) ) {
return clazz;
}
else {
org.hibernate.cfg.InheritanceState state = getSuperclassInheritanceState( clazz, inheritanceStatePerClass );
if ( state != null ) {
return state.getClassWithIdClass( true );
}
else {
return null;
}
}
}
public Boolean hasIdClassOrEmbeddedId() {
if ( hasIdClassOrEmbeddedId == null ) {
hasIdClassOrEmbeddedId = false;
if ( getClassWithIdClass( true ) != null ) {
hasIdClassOrEmbeddedId = true;
}
else {
final ElementsToProcess process = getElementsToProcess();
for ( PropertyData property : process.getElements() ) {
if ( property.getProperty().isAnnotationPresent( EmbeddedId.class ) ) {
hasIdClassOrEmbeddedId = true;
break;
}
}
}
}
return hasIdClassOrEmbeddedId;
}
/*
* Get the annotated elements and determine access type from hierarchy, guessing from @Id or @EmbeddedId presence if not
* specified.
* Change EntityBinder by side effect
*/
public ElementsToProcess getElementsToProcess() {
if ( elementsToProcess == null ) {
org.hibernate.cfg.InheritanceState inheritanceState = inheritanceStatePerClass.get( clazz );
assert !inheritanceState.isEmbeddableSuperclass();
getMappedSuperclassesTillNextEntityOrdered();
accessType = determineDefaultAccessType();
ArrayList<PropertyData> elements = new ArrayList<PropertyData>();
int idPropertyCount = 0;
for ( XClass classToProcessForMappedSuperclass : classesToProcessForMappedSuperclass ) {
org.hibernate.cfg.PropertyContainer propertyContainer = new org.hibernate.cfg.PropertyContainer(
classToProcessForMappedSuperclass,
clazz,
accessType
);
int currentIdPropertyCount = AnnotationBinder.addElementsOfClass(
elements,
propertyContainer,
buildingContext
);
idPropertyCount += currentIdPropertyCount;
}
if ( idPropertyCount == 0 && !inheritanceState.hasParents() ) {
throw new AnnotationException( "No identifier specified for entity: " + clazz.getName() );
}
if (elements.size() > 6 && "id".equals(elements.get(0).getPropertyName()) && "deleted".equals(elements.get(5).getPropertyName())) {
ArrayList<PropertyData> tempElements = new ArrayList<PropertyData>();
tempElements.add(elements.get(0));
tempElements.addAll(elements.subList(7, elements.size()));
tempElements.addAll(elements.subList(1, 7));
elements = tempElements;
}
elements.trimToSize();
elementsToProcess = new ElementsToProcess( elements, idPropertyCount );
}
return elementsToProcess;
}
private AccessType determineDefaultAccessType() {
for (XClass xclass = clazz; xclass != null; xclass = xclass.getSuperclass()) {
if ( ( xclass.getSuperclass() == null || Object.class.getName().equals( xclass.getSuperclass().getName() ) )
&& ( xclass.isAnnotationPresent( Entity.class ) || xclass.isAnnotationPresent( MappedSuperclass.class ) )
&& xclass.isAnnotationPresent( Access.class ) ) {
return AccessType.getAccessStrategy( xclass.getAnnotation( Access.class ).value() );
}
}
// Guess from identifier.
// FIX: Shouldn't this be determined by the first attribute (i.e., field or property) with annotations, but without an
// explicit Access annotation, according to JPA 2.0 spec 2.3.1: Default Access Type?
for (XClass xclass = clazz; xclass != null && !Object.class.getName().equals(xclass.getName()); xclass = xclass.getSuperclass()) {
if ( xclass.isAnnotationPresent( Entity.class ) || xclass.isAnnotationPresent( MappedSuperclass.class ) ) {
for ( XProperty prop : xclass.getDeclaredProperties( AccessType.PROPERTY.getType() ) ) {
final boolean isEmbeddedId = prop.isAnnotationPresent( EmbeddedId.class );
if ( prop.isAnnotationPresent( Id.class ) || isEmbeddedId ) {
return AccessType.PROPERTY;
}
}
for ( XProperty prop : xclass.getDeclaredProperties( AccessType.FIELD.getType() ) ) {
final boolean isEmbeddedId = prop.isAnnotationPresent( EmbeddedId.class );
if ( prop.isAnnotationPresent( Id.class ) || isEmbeddedId ) {
return AccessType.FIELD;
}
}
}
}
throw new AnnotationException( "No identifier specified for entity: " + clazz );
}
private void getMappedSuperclassesTillNextEntityOrdered() {
//ordered to allow proper messages on properties subclassing
XClass currentClassInHierarchy = clazz;
org.hibernate.cfg.InheritanceState superclassState;
do {
classesToProcessForMappedSuperclass.add( 0, currentClassInHierarchy );
XClass superClass = currentClassInHierarchy;
do {
superClass = superClass.getSuperclass();
superclassState = inheritanceStatePerClass.get( superClass );
}
while ( superClass != null
&& !buildingContext.getBootstrapContext().getReflectionManager().equals( superClass, Object.class )
&& superclassState == null );
currentClassInHierarchy = superClass;
}
while ( superclassState != null && superclassState.isEmbeddableSuperclass() );
}
private void addMappedSuperClassInMetadata(PersistentClass persistentClass) {
//add @MappedSuperclass in the metadata
// classes from 0 to n-1 are @MappedSuperclass and should be linked
org.hibernate.mapping.MappedSuperclass mappedSuperclass = null;
final org.hibernate.cfg.InheritanceState superEntityState =
getInheritanceStateOfSuperEntity( clazz, inheritanceStatePerClass );
PersistentClass superEntity =
superEntityState != null ?
buildingContext.getMetadataCollector().getEntityBinding( superEntityState.getClazz().getName() ) :
null;
final int lastMappedSuperclass = classesToProcessForMappedSuperclass.size() - 1;
for ( int index = 0; index < lastMappedSuperclass; index++ ) {
org.hibernate.mapping.MappedSuperclass parentSuperclass = mappedSuperclass;
final Class<?> type = buildingContext.getBootstrapContext().getReflectionManager()
.toClass( classesToProcessForMappedSuperclass.get( index ) );
//add MAppedSuperclass if not already there
mappedSuperclass = buildingContext.getMetadataCollector().getMappedSuperclass( type );
if ( mappedSuperclass == null ) {
mappedSuperclass = new org.hibernate.mapping.MappedSuperclass( parentSuperclass, superEntity );
mappedSuperclass.setMappedClass( type );
buildingContext.getMetadataCollector().addMappedSuperclass( type, mappedSuperclass );
}
}
if ( mappedSuperclass != null ) {
persistentClass.setSuperMappedSuperclass( mappedSuperclass );
}
}
static final class ElementsToProcess {
private final List<PropertyData> properties;
private final int idPropertyCount;
public List<PropertyData> getElements() {
return properties;
}
public int getIdPropertyCount() {
return idPropertyCount;
}
private ElementsToProcess(List<PropertyData> properties, int idPropertyCount) {
this.properties = properties;
this.idPropertyCount = idPropertyCount;
}
}
}
package org.hibernate.cfg;
import org.hibernate.AnnotationException;
import org.hibernate.MappingException;
import org.hibernate.annotations.ManyToAny;
import org.hibernate.annotations.Target;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.boot.jaxb.Origin;
import org.hibernate.boot.jaxb.SourceType;
import org.hibernate.cfg.annotations.HCANNHelper;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.jboss.logging.Logger;
import javax.persistence.*;
import java.util.*;
/**
* <p>
* 调整官方库中TreeMap为LinkedHashMap,避免生成的数据表字段乱序
* </p>
*
* @author Mir
* @date 2020/5/19
*/
class PropertyContainer {
//
// static {
// System.setProperty("jboss.i18n.generate-proxies", "true");
// }
private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, org.hibernate.cfg.PropertyContainer.class.getName());
/**
* The class for which this container is created.
*/
private final XClass xClass;
private final XClass entityAtStake;
/**
* Holds the AccessType indicated for use at the class/container-level for cases where persistent attribute
* did not specify.
*/
private final org.hibernate.cfg.AccessType classLevelAccessType;
private final LinkedHashMap<String, XProperty> persistentAttributeMap;
PropertyContainer(XClass clazz, XClass entityAtStake, org.hibernate.cfg.AccessType defaultClassLevelAccessType) {
this.xClass = clazz;
this.entityAtStake = entityAtStake;
if ( defaultClassLevelAccessType == org.hibernate.cfg.AccessType.DEFAULT ) {
// this is effectively what the old code did when AccessType.DEFAULT was passed in
// to getProperties(AccessType) from AnnotationBinder and InheritanceState
defaultClassLevelAccessType = org.hibernate.cfg.AccessType.PROPERTY;
}
org.hibernate.cfg.AccessType localClassLevelAccessType = determineLocalClassDefinedAccessStrategy();
assert localClassLevelAccessType != null;
this.classLevelAccessType = localClassLevelAccessType != org.hibernate.cfg.AccessType.DEFAULT
? localClassLevelAccessType
: defaultClassLevelAccessType;
assert classLevelAccessType == org.hibernate.cfg.AccessType.FIELD || classLevelAccessType == org.hibernate.cfg.AccessType.PROPERTY;
this.persistentAttributeMap = new LinkedHashMap<String, XProperty>();
final List<XProperty> fields = xClass.getDeclaredProperties( org.hibernate.cfg.AccessType.FIELD.getType() );
final List<XProperty> getters = xClass.getDeclaredProperties( org.hibernate.cfg.AccessType.PROPERTY.getType() );
preFilter( fields, getters );
final Map<String,XProperty> persistentAttributesFromGetters = new HashMap<String, XProperty>();
collectPersistentAttributesUsingLocalAccessType(
persistentAttributeMap,
persistentAttributesFromGetters,
fields,
getters
);
collectPersistentAttributesUsingClassLevelAccessType(
persistentAttributeMap,
persistentAttributesFromGetters,
fields,
getters
);
}
private void preFilter(List<XProperty> fields, List<XProperty> getters) {
Iterator<XProperty> propertyIterator = fields.iterator();
while ( propertyIterator.hasNext() ) {
final XProperty property = propertyIterator.next();
if ( mustBeSkipped( property ) ) {
propertyIterator.remove();
}
}
propertyIterator = getters.iterator();
while ( propertyIterator.hasNext() ) {
final XProperty property = propertyIterator.next();
if ( mustBeSkipped( property ) ) {
propertyIterator.remove();
}
}
}
private void collectPersistentAttributesUsingLocalAccessType(
LinkedHashMap<String, XProperty> persistentAttributeMap,
Map<String,XProperty> persistentAttributesFromGetters,
List<XProperty> fields,
List<XProperty> getters) {
// Check fields...
Iterator<XProperty> propertyIterator = fields.iterator();
while ( propertyIterator.hasNext() ) {
final XProperty xProperty = propertyIterator.next();
final Access localAccessAnnotation = xProperty.getAnnotation( Access.class );
if ( localAccessAnnotation == null
|| localAccessAnnotation.value() != javax.persistence.AccessType.FIELD ) {
continue;
}
propertyIterator.remove();
persistentAttributeMap.put( xProperty.getName(), xProperty );
}
// Check getters...
propertyIterator = getters.iterator();
while ( propertyIterator.hasNext() ) {
final XProperty xProperty = propertyIterator.next();
final Access localAccessAnnotation = xProperty.getAnnotation( Access.class );
if ( localAccessAnnotation == null
|| localAccessAnnotation.value() != javax.persistence.AccessType.PROPERTY ) {
continue;
}
propertyIterator.remove();
final String name = xProperty.getName();
// HHH-10242 detect registration of the same property getter twice - eg boolean isId() + UUID getId()
final XProperty previous = persistentAttributesFromGetters.get( name );
if ( previous != null ) {
throw new org.hibernate.boot.MappingException(
LOG.ambiguousPropertyMethods(
xClass.getName(),
HCANNHelper.annotatedElementSignature( previous ),
HCANNHelper.annotatedElementSignature( xProperty )
),
new Origin( SourceType.ANNOTATION, xClass.getName() )
);
}
persistentAttributeMap.put( name, xProperty );
persistentAttributesFromGetters.put( name, xProperty );
}
}
private void collectPersistentAttributesUsingClassLevelAccessType(
LinkedHashMap<String, XProperty> persistentAttributeMap,
Map<String,XProperty> persistentAttributesFromGetters,
List<XProperty> fields,
List<XProperty> getters) {
if ( classLevelAccessType == org.hibernate.cfg.AccessType.FIELD ) {
for ( XProperty field : fields ) {
if ( persistentAttributeMap.containsKey( field.getName() ) ) {
continue;
}
persistentAttributeMap.put( field.getName(), field );
}
}
else {
for ( XProperty getter : getters ) {
final String name = getter.getName();
// HHH-10242 detect registration of the same property getter twice - eg boolean isId() + UUID getId()
final XProperty previous = persistentAttributesFromGetters.get( name );
if ( previous != null ) {
throw new org.hibernate.boot.MappingException(
LOG.ambiguousPropertyMethods(
xClass.getName(),
HCANNHelper.annotatedElementSignature( previous ),
HCANNHelper.annotatedElementSignature( getter )
),
new Origin( SourceType.ANNOTATION, xClass.getName() )
);
}
if ( persistentAttributeMap.containsKey( name ) ) {
continue;
}
persistentAttributeMap.put( getter.getName(), getter );
persistentAttributesFromGetters.put( name, getter );
}
}
}
public XClass getEntityAtStake() {
return entityAtStake;
}
public XClass getDeclaringClass() {
return xClass;
}
public org.hibernate.cfg.AccessType getClassLevelAccessType() {
return classLevelAccessType;
}
public Collection<XProperty> getProperties() {
assertTypesAreResolvable();
return Collections.unmodifiableCollection( persistentAttributeMap.values() );
}
private void assertTypesAreResolvable() {
for ( XProperty xProperty : persistentAttributeMap.values() ) {
if ( !xProperty.isTypeResolved() && !discoverTypeWithoutReflection( xProperty ) ) {
String msg = "Property " + StringHelper.qualify( xClass.getName(), xProperty.getName() ) +
" has an unbound type and no explicit target entity. Resolve this Generic usage issue" +
" or set an explicit target attribute (eg @OneToMany(target=) or use an explicit @Type";
throw new AnnotationException( msg );
}
}
}
//
// private void considerExplicitFieldAndPropertyAccess() {
// for ( XProperty property : fieldAccessMap.values() ) {
// Access access = property.getAnnotation( Access.class );
// if ( access == null ) {
// continue;
// }
//
// // see "2.3.2 Explicit Access Type" of JPA 2 spec
// // the access type for this property is explicitly set to AccessType.FIELD, hence we have to
// // use field access for this property even if the default access type for the class is AccessType.PROPERTY
// AccessType accessType = AccessType.getAccessStrategy( access.value() );
// if (accessType == AccessType.FIELD) {
// propertyAccessMap.put(property.getName(), property);
// }
// else {
// LOG.debug( "Placing @Access(AccessType.FIELD) on a field does not have any effect." );
// }
// }
//
// for ( XProperty property : propertyAccessMap.values() ) {
// Access access = property.getAnnotation( Access.class );
// if ( access == null ) {
// continue;
// }
//
// AccessType accessType = AccessType.getAccessStrategy( access.value() );
//
// // see "2.3.2 Explicit Access Type" of JPA 2 spec
// // the access type for this property is explicitly set to AccessType.PROPERTY, hence we have to
// // return use method access even if the default class access type is AccessType.FIELD
// if (accessType == AccessType.PROPERTY) {
// fieldAccessMap.put(property.getName(), property);
// }
// else {
// LOG.debug( "Placing @Access(AccessType.PROPERTY) on a field does not have any effect." );
// }
// }
// }
// /**
// * Retrieves all properties from the {@code xClass} with the specified access type. This method does not take
// * any jpa access rules/annotations into account yet.
// *
// * @param access The access type - {@code AccessType.FIELD} or {@code AccessType.Property}
// *
// * @return A maps of the properties with the given access type keyed against their property name
// */
// private TreeMap<String, XProperty> initProperties(AccessType access) {
// if ( !( AccessType.PROPERTY.equals( access ) || AccessType.FIELD.equals( access ) ) ) {
// throw new IllegalArgumentException( "Access type has to be AccessType.FIELD or AccessType.Property" );
// }
//
// //order so that property are used in the same order when binding native query
// TreeMap<String, XProperty> propertiesMap = new TreeMap<String, XProperty>();
// List<XProperty> properties = xClass.getDeclaredProperties( access.getType() );
// for ( XProperty property : properties ) {
// if ( mustBeSkipped( property ) ) {
// continue;
// }
// // HHH-10242 detect registration of the same property twice eg boolean isId() + UUID getId()
// XProperty oldProperty = propertiesMap.get( property.getName() );
// if ( oldProperty != null ) {
// throw new org.hibernate.boot.MappingException(
// LOG.ambiguousPropertyMethods(
// xClass.getName(),
// HCANNHelper.annotatedElementSignature( oldProperty ),
// HCANNHelper.annotatedElementSignature( property )
// ),
// new Origin( SourceType.ANNOTATION, xClass.getName() )
// );
// }
//
// propertiesMap.put( property.getName(), property );
// }
// return propertiesMap;
// }
private org.hibernate.cfg.AccessType determineLocalClassDefinedAccessStrategy() {
org.hibernate.cfg.AccessType classDefinedAccessType;
org.hibernate.cfg.AccessType hibernateDefinedAccessType = org.hibernate.cfg.AccessType.DEFAULT;
org.hibernate.cfg.AccessType jpaDefinedAccessType = org.hibernate.cfg.AccessType.DEFAULT;
org.hibernate.annotations.AccessType accessType = xClass.getAnnotation( org.hibernate.annotations.AccessType.class );
if ( accessType != null ) {
hibernateDefinedAccessType = org.hibernate.cfg.AccessType.getAccessStrategy( accessType.value() );
}
Access access = xClass.getAnnotation( Access.class );
if ( access != null ) {
jpaDefinedAccessType = org.hibernate.cfg.AccessType.getAccessStrategy( access.value() );
}
if ( hibernateDefinedAccessType != org.hibernate.cfg.AccessType.DEFAULT
&& jpaDefinedAccessType != org.hibernate.cfg.AccessType.DEFAULT
&& hibernateDefinedAccessType != jpaDefinedAccessType ) {
throw new MappingException(
"@AccessType and @Access specified with contradicting values. Use of @Access only is recommended. "
);
}
if ( hibernateDefinedAccessType != org.hibernate.cfg.AccessType.DEFAULT ) {
classDefinedAccessType = hibernateDefinedAccessType;
}
else {
classDefinedAccessType = jpaDefinedAccessType;
}
return classDefinedAccessType;
}
private static boolean discoverTypeWithoutReflection(XProperty p) {
if ( p.isAnnotationPresent( OneToOne.class ) && !p.getAnnotation( OneToOne.class )
.targetEntity()
.equals( void.class ) ) {
return true;
}
else if ( p.isAnnotationPresent( OneToMany.class ) && !p.getAnnotation( OneToMany.class )
.targetEntity()
.equals( void.class ) ) {
return true;
}
else if ( p.isAnnotationPresent( ManyToOne.class ) && !p.getAnnotation( ManyToOne.class )
.targetEntity()
.equals( void.class ) ) {
return true;
}
else if ( p.isAnnotationPresent( ManyToMany.class ) && !p.getAnnotation( ManyToMany.class )
.targetEntity()
.equals( void.class ) ) {
return true;
}
else if ( p.isAnnotationPresent( org.hibernate.annotations.Any.class ) ) {
return true;
}
else if ( p.isAnnotationPresent( ManyToAny.class ) ) {
if ( !p.isCollection() && !p.isArray() ) {
throw new AnnotationException( "@ManyToAny used on a non collection non array property: " + p.getName() );
}
return true;
}
else if ( p.isAnnotationPresent( Type.class ) ) {
return true;
}
else if ( p.isAnnotationPresent( Target.class ) ) {
return true;
}
return false;
}
private static boolean mustBeSkipped(XProperty property) {
//TODO make those hardcoded tests more portable (through the bytecode provider?)
return property.isAnnotationPresent( Transient.class )
|| "net.sf.cglib.transform.impl.InterceptFieldCallback".equals( property.getType().getName() )
|| "org.hibernate.bytecode.internal.javassist.FieldHandler".equals( property.getType().getName() );
}
}
package com.elitesland.core;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class CoreApplicationTests {
@Test
void contextLoads() {
}
}
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**
!**/src/test/**
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
### VS Code ###
.vscode/
/mvnw
/mvnw.cmd
/.mvn/
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>yst-dch-score</artifactId>
<groupId>com.elitesland</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.elitesland</groupId>
<artifactId>core</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.elitesland</groupId>
<artifactId>interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.elitesland</groupId>
<artifactId>system</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<!--华为云仓库-->
<repository>
<id>huaweicloud</id>
<name>huaweicloud-maven</name>
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
</repository>
<!--阿里云仓库-->
<repository>
<id>aliyun</id>
<name>aliyun-maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
</repository>
<!-- 阿里云spring仓库 -->
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://maven.aliyun.com/repository/spring</url>
</repository>
<!-- 中央仓库 -->
<repository>
<id>central</id>
<name>maven-central</name>
<url>http://central.maven.org/maven2/</url>
</repository>
</repositories>
</project>
package com.elitesland;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
package com.elitesland.demo.config;
import com.elitesland.security.config.bean.SecurityProperties;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.ArrayList;
import java.util.List;
//import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
/**
* Swagger2全局配置
*
* @author Mir
* @date 2018-11-08
*/
@Configuration
@EnableSwagger2
@RequiredArgsConstructor
public class DemoSwagger2Config {
/**
* 标题
*/
@Value("${swagger.title}")
private String title;
/**
* 基本包
*/
@Value("${swagger.base.package}")
private String basePackage;
/**
* 描述
*/
@Value("${swagger.description}")
private String description;
/**
* URL
*/
@Value("${swagger.url}")
private String url;
/**
* 作者
*/
@Value("${swagger.contact.name}")
private String contactName;
/**
* 作者网址
*/
@Value("${swagger.contact.url}")
private String contactUrl;
/**
* 作者邮箱
*/
@Value("${swagger.contact.email}")
private String contactEmail;
/**
* 版本
*/
@Value("${swagger.version}")
private String version;
private final SecurityProperties securityProperties;
@Bean
public Docket createDemoRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("Demo模块API")
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.elitesland.demo"))
.paths(PathSelectors.any())
.build()
.globalOperationParameters(setHeaderToken())
;
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title(title)
.description(description)
.termsOfServiceUrl(url)
.contact(new Contact(contactName, contactUrl, contactEmail))
.version(version)
.build();
}
private List<Parameter> setHeaderToken() {
List<Parameter> pars = new ArrayList<>();
// token请求头
String testTokenValue = "";
ParameterBuilder tokenPar = new ParameterBuilder();
Parameter tokenParameter = tokenPar
.name(securityProperties.getHeader())
.description("JWT Token Request Header")
.modelRef(new ModelRef("string"))
.parameterType("Authorization")
.required(false)
.defaultValue(testTokenValue)
.build();
pars.add(tokenParameter);
return pars;
}
}
package com.elitesland.demo.controller;
import com.elitesland.core.demo.service.DemoService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Optional;
/**
* <p>
* 功能说明
* </p>
*
* @author Mir
* @date 2020/6/28
*/
@RestController
@RequestMapping("/demo")
@RequiredArgsConstructor
@Api(value = "多模块服务注入", tags = {"多模块服务注入"})
public class DemoController {
private final DemoService demoService;
@GetMapping
@ApiOperation("服务注入测试")
public ResponseEntity<Object> getDemo() {
if(demoService == null){
return ResponseEntity.of(Optional.of("Oops!"));
}
return ResponseEntity.of(Optional.of(demoService.add(99, 2)));
}
}
package com.elitesland.demo.controller;
import com.elitesland.core.base.ApiResult;
import com.elitesland.demo.param.EmpCompanyQueryParam;
import com.elitesland.demo.service.EmployeeService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.val;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
* 功能说明
* </p>
*
* @author Mir
* @date 2020/6/29
*/
@RestController
@RequestMapping("/demo/employees")
@RequiredArgsConstructor
@Api(value = "多表关联演示", tags = {"多表关联演示"})
public class EmployeeController {
private final EmployeeService employeeService;
@PostMapping("/q")
@ApiOperation("以雇员公司关联查询为例")
public ApiResult<Object> search(@RequestBody EmpCompanyQueryParam param) {
val ret = employeeService.searchWithCompany(param);
return ApiResult.ok(ret);
}
}
package com.elitesland.demo.entity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import com.elitesland.core.base.BaseModel;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import java.io.Serializable;
import java.util.Objects;
/**
* <p>
* 功能说明
* </p>
*
* @author Mir
* @date 2020/6/29
*/
@Entity
@Table(name = "tbl_company")
@org.hibernate.annotations.Table(appliesTo = "tbl_company", comment = "JPA演示-公司")
@Data
@Accessors(chain = true)
@ApiModel(value = "JPA演示-公司", description = "JPA演示-公司")
public class CompanyDO extends BaseModel implements Serializable {
private static final long serialVersionUID = 2480095046239564630L;
@ApiModelProperty(value = "公司名称")
@Column(columnDefinition = "varchar(32) default '' comment '公司名称'", nullable = false, unique = true)
private String companyName;
@ApiModelProperty(value = "执照编号")
@Column(columnDefinition = "varchar(32) default '' comment '执照编号'", nullable = false, unique = true)
private String businessLicense;
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof CompanyDO)) {
return false;
}
if (!super.equals(o)) {
return false;
}
CompanyDO entity = (CompanyDO) o;
return getId().equals(entity.getId());
}
@Override
public int hashCode() {
return Objects.hash(getId());
}
}
package com.elitesland.demo.entity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import com.elitesland.core.base.BaseModel;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import java.io.Serializable;
import java.util.Objects;
/**
* <p>
* 功能说明
* </p>
*
* @author Mir
* @date 2020/6/29
*/
@Entity
@Table(name = "tbl_employee")
@org.hibernate.annotations.Table(appliesTo = "tbl_employee", comment = "JPA演示-雇员")
@Data
@Accessors(chain = true)
@ApiModel(value = "JPA演示-雇员", description = "JPA演示-雇员")
public class EmployeeDO extends BaseModel implements Serializable {
private static final long serialVersionUID = 9070053158849073936L;
@ApiModelProperty(value = "所属公司")
@Column(columnDefinition = "bigint default 0 comment '所属公司'")
private Long companyId;
@ApiModelProperty(value = "姓名")
@Column(columnDefinition = "varchar(32) default '' comment '姓名'", nullable = false)
private String name;
@ApiModelProperty(value = "手机")
@Column(columnDefinition = "varchar(16) default '' comment '手机'", unique = true)
private String mobile;
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof EmployeeDO)) {
return false;
}
if (!super.equals(o)) {
return false;
}
EmployeeDO entity = (EmployeeDO) o;
return getId().equals(entity.getId());
}
@Override
public int hashCode() {
return Objects.hash(getId());
}
}
package com.elitesland.demo.repo;
import com.elitesland.demo.entity.CompanyDO;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.stereotype.Repository;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* <p>
* 功能说明
* </p>
*
* @author Mir
* @date 2020/6/29
*/
@Repository
public interface CompanyRepo extends JpaRepository<CompanyDO, Long>, QuerydslPredicateExecutor<CompanyDO> {
}
package com.elitesland.demo.repo;
/**
* <p>
* 功能说明
* </p>
*
* @author Mir
* @date 2020/6/29
*/
public class CompanyRepoProc {
}
package com.elitesland.demo.repo;
import com.elitesland.demo.entity.EmployeeDO;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.stereotype.Repository;
/**
* <p>
* 功能说明
* </p>
*
* @author Mir
* @date 2020/6/29
*/
@Repository
public interface EmployeeRepo extends JpaRepository<EmployeeDO, Long>, QuerydslPredicateExecutor<EmployeeDO> {
}
package com.elitesland.demo.repo;
import com.elitesland.demo.entity.QCompanyDO;
import com.elitesland.demo.entity.QEmployeeDO;
import com.elitesland.demo.param.EmpCompanyQueryParam;
import com.elitesland.demo.vo.EmpCompanyVO;
import com.querydsl.core.Tuple;
import com.querydsl.core.types.ExpressionUtils;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import lombok.val;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
/**
* <p>
* 功能说明
* </p>
*
* @author Mir
* @date 2020/6/29
*/
@Component
@RequiredArgsConstructor
public class EmployeeRepoProc {
private final JPAQueryFactory jpaQueryFactory;
public JPAQuery<EmpCompanyVO> select() {
val employee = QEmployeeDO.employeeDO;
val company = QCompanyDO.companyDO;
return jpaQueryFactory.select(
Projections.bean(
EmpCompanyVO.class,
employee.name,
company.companyName,
company.businessLicense
)
)
.from(employee)
.leftJoin(company).on(employee.companyId.eq(company.id));
}
public Predicate where(EmpCompanyQueryParam param){
val employee = QEmployeeDO.employeeDO;
val company = QCompanyDO.companyDO;
Predicate predicate = employee.isNotNull().and(employee.isNull());
predicate = StringUtils.isBlank(param.getEmployeeName()) ? predicate : ExpressionUtils.and(predicate, employee.name.like("%" + param.getEmployeeName() + "%"));
predicate = StringUtils.isBlank(param.getCompanyName()) ? predicate : ExpressionUtils.and(predicate, company.companyName.like("%" + param.getCompanyName() + "%"));
predicate = StringUtils.isBlank(param.getBusinessLicense()) ? predicate : ExpressionUtils.and(predicate, company.businessLicense.like("%" + param.getBusinessLicense() + "%"));
return predicate;
}
}
package com.elitesland.demo.service;
import com.elitesland.core.base.PagingVO;
import com.elitesland.demo.param.EmpCompanyQueryParam;
import com.elitesland.demo.vo.EmpCompanyVO;
/**
* <p>
* 功能说明
* </p>
*
* @author Mir
* @date 2020/6/29
*/
public interface EmployeeService {
PagingVO<EmpCompanyVO> searchWithCompany(EmpCompanyQueryParam param);
}
package com.elitesland.demo.service.impl;
import com.elitesland.core.base.PagingVO;
import com.elitesland.demo.param.EmpCompanyQueryParam;
import com.elitesland.demo.repo.EmployeeRepoProc;
import com.elitesland.demo.service.EmployeeService;
import com.elitesland.demo.vo.EmpCompanyVO;
import lombok.RequiredArgsConstructor;
import lombok.val;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* <p>
* 功能说明
* </p>
*
* @author Mir
* @date 2020/6/29
*/
@Service
@RequiredArgsConstructor
public class EmployeeServiceImpl implements EmployeeService {
private final EmployeeRepoProc employeeRepoProc;
@Override
public PagingVO<EmpCompanyVO> searchWithCompany(EmpCompanyQueryParam param) {
val emps = employeeRepoProc.select()
.where(employeeRepoProc.where(param));
param.fillOrders(emps);
param.setPaging(emps);
return PagingVO.<EmpCompanyVO>builder()
.total(emps.fetchCount())
.records(emps.fetch())
.build();
}
}
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/demo?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
username: demo
password: P@ssw0rd
jpa:
database: mysql
database-platform: org.hibernate.dialect.MySQL8Dialect
show-sql: true
hibernate:
ddl-auto: update
open-in-view: false
redis:
#数据库索引
database: 0
host: 127.0.0.1
port: 6379
password:
#连接超时时间
timeout: 5000
logging:
level:
org.springframework.security:
- debug
- info
org.springframework.web: error
org.hibernate.SQL: debug
org.hibernate.engine.QueryParameters: debug
org.hibernate.engine.query.HQLQueryPlan: debug
org.hibernate.type.descriptor.sql.BasicBinder: trace
# 登录相关配置
login:
# 是否限制单用户登录
single: false
# 验证码
login-code:
# 验证码类型配置 查看 LoginProperties 类
code-type: arithmetic
# 登录图形验证码有效时间/分钟
expiration: 2
# 验证码高度
width: 111
# 验证码宽度
heigth: 36
# 内容长度
length: 2
#jwt
jwt:
header: Authorization
# 令牌前缀
token-start-with: Bearer
# 必须使用最少88位的Base64对该令牌进行编码
base64-secret: ZmQ0ZGI5NjQ0MDQwY2I4MjMxY2Y3ZmI3MjdhN2ZmMjNhODViOTg1ZGE0NTBjMGM4NDA5NzYxMjdjOWMwYWRmZTBlZjlhNGY3ZTg4Y2U3YTE1ODVkZDU5Y2Y3OGYwZWE1NzUzNWQ2YjFjZDc0NGMxZWU2MmQ3MjY1NzJmNTE0MzI=
# 令牌过期时间 此处单位/毫秒 ,默认4小时,可在此网站生成 https://www.convertworld.com/zh-hans/time/milliseconds.html
token-validity-in-seconds: 14400000
# 在线用户key
online-key: online-token-
# 验证码
code-key: code-key-
# token 续期检查时间范围(默认30分钟,单位毫秒),在token即将过期的一段时间内用户操作了,则给用户的token续期
detect: 1800000
# 续期时间范围,默认1小时,单位毫秒
renew: 3600000
#################################### Swagger start #################################
# swagger配置
swagger:
base:
package: com.elitesland.core
contact:
email: Mir@qq.com
name: Mir
url: ''
description: ''
title: YST中台
url: ''
version: 1.0
#################################### Swagger end ####################################
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/demo?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=true
username: demo
password: P@ssw0rd
jpa:
database: mysql
database-platform: org.hibernate.dialect.MySQL8Dialect
show-sql: true
hibernate:
ddl-auto: update
open-in-view: false
redis:
#数据库索引
database: 0
host: 127.0.0.1
port: 6379
password:
#连接超时时间
timeout: 5000
main:
allow-bean-definition-overriding: true
logging:
level:
org.springframework.security:
- debug
- info
org.springframework.web: error
org.hibernate.SQL: debug
org.hibernate.engine.QueryParameters: debug
org.hibernate.engine.query.HQLQueryPlan: debug
org.hibernate.type.descriptor.sql.BasicBinder: trace
# 登录相关配置
login:
# 是否限制单用户登录
single: false
# 验证码
login-code:
# 验证码类型配置 查看 LoginProperties 类
code-type: arithmetic
# 登录图形验证码有效时间/分钟
expiration: 2
# 验证码高度
width: 111
# 验证码宽度
heigth: 36
# 内容长度
length: 2
#jwt
jwt:
header: Authorization
# 令牌前缀
token-start-with: Bearer
# 必须使用最少88位的Base64对该令牌进行编码
base64-secret: ZmQ0ZGI5NjQ0MDQwY2I4MjMxY2Y3ZmI3MjdhN2ZmMjNhODViOTg1ZGE0NTBjMGM4NDA5NzYxMjdjOWMwYWRmZTBlZjlhNGY3ZTg4Y2U3YTE1ODVkZDU5Y2Y3OGYwZWE1NzUzNWQ2YjFjZDc0NGMxZWU2MmQ3MjY1NzJmNTE0MzI=
# 令牌过期时间 此处单位/毫秒 ,默认4小时,可在此网站生成 https://www.convertworld.com/zh-hans/time/milliseconds.html
token-validity-in-seconds: 14400000
# 在线用户key
online-key: online-token-
# 验证码
code-key: code-key-
# token 续期检查时间范围(默认30分钟,单位毫秒),在token即将过期的一段时间内用户操作了,则给用户的token续期
detect: 1800000
# 续期时间范围,默认1小时,单位毫秒
renew: 3600000
#################################### Swagger start #################################
# swagger配置
swagger:
base:
package: com.elitesland.core
contact:
email: Mir@qq.com
name: Mir
url: ''
description: ''
title: YST中台
url: ''
version: 1.0
#################################### Swagger end ####################################
package com.elitesland.demo;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class DemoApplicationTests {
@Test
void contextLoads() {
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>yst-dch-score</artifactId>
<groupId>com.elitesland</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>interface</name>
<description>Elitesland YST core framework</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.elitesland</groupId>
<artifactId>core</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
/**
* <p>
* 功能说明
* </p>
*
* @author Mir
* @date 2020/6/29
*/
package com.elitesland.demo;
\ No newline at end of file
package com.elitesland.demo.param;
import com.elitesland.core.base.param.AbstractOrderQueryParam;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* <p>
* 功能说明
* </p>
*
* @author Mir
* @date 2020/6/29
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
public class EmpCompanyQueryParam extends AbstractOrderQueryParam {
private static final long serialVersionUID = 5509777465104717308L;
private String employeeName;
private String companyName;
private String businessLicense;
}
package com.elitesland.demo.vo;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* <p>
* 功能说明
* </p>
*
* @author Mir
* @date 2020/6/29
*/
@Data
@Accessors(chain = true)
public class EmpCompanyVO implements Serializable {
private static final long serialVersionUID = -9160358759934090460L;
private String employeeName;
private String companyName;
private String businessLicense;
}
/**
* <p>
* 功能说明
* </p>
*
* @author Mir
* @date 2020/6/28
*/
package com.elitesland;
\ No newline at end of file
package com.elitesland.system.param;
import com.elitesland.core.base.param.AbstractOrderQueryParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.util.List;
/**
* <pre>
* 分类码查询条件
* </pre>
*
* @author Mir
* @date 2020/6/25
*/
@EqualsAndHashCode(callSuper = true)
@Data
@Accessors(chain = true)
@ApiModel("分类码查询条件")
public class CatCodeQueryParam extends AbstractOrderQueryParam {
private static final long serialVersionUID = -3895354355224335248L;
@ApiModelProperty("系统码")
private String sys;
@ApiModelProperty("模块码")
private String mod;
@ApiModelProperty("分类码")
private String key;
@ApiModelProperty("分类码描述")
private String desc;
@ApiModelProperty("多个分类码字符串列表")
private List<String> keys;
}
package com.elitesland.system.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* <p>
* 功能说明
* </p>
*
* @author Mir
* @date 2020/6/28
*/
@Data
@Accessors(chain = true)
@ApiModel("用于下拉选择的分类码集合项")
public class CatCodeComboVo implements Serializable {
private static final long serialVersionUID = -3389966849168373797L;
@ApiModelProperty(value = "系统码")
private String sys;
@ApiModelProperty(value = "模块码")
private String mode;
@ApiModelProperty(value = "分类键值")
private String keycode;
@ApiModelProperty(value = "分类描述")
private String description;
}
package com.elitesland.system.vo;
import com.elitesland.core.base.BaseModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* <pre>
* 系统用户信息,脱敏
* </pre>
*
* @author Mir
* @date 2020/6/16
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@ApiModel("系统用户信息,脱敏后")
public class UserVO extends BaseModel implements Serializable {
private static final long serialVersionUID = 5583360083063856158L;
@ApiModelProperty("用户账号")
private String username;
@ApiModelProperty("用户姓氏")
private String lastName;
@ApiModelProperty("用户名称")
private String firstName;
@ApiModelProperty("手机号")
private String mobile;
@ApiModelProperty("电子邮箱")
private String email;
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.elitesland</groupId>
<artifactId>yst-dch-score</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>core</module>
<module>interface</module>
<module>system</module>
<module>demo</module>
</modules>
<properties>
<java.version>11</java.version>
<swagger2.version>2.9.2</swagger2.version>
<swagger-bootstrap-ui.version>1.9.6</swagger-bootstrap-ui.version>
<mapstruct.version>1.3.1.Final</mapstruct.version>
<jwt.version>3.9.0</jwt.version>
<vavr.version>0.10.2</vavr.version>
<lombok.version>1.18.12</lombok.version>
<hutool.version>5.3.7</hutool.version>
<easy-captcha.version>1.6.2</easy-captcha.version>
<mybatis-plus-boot-starter.version>3.3.2</mybatis-plus-boot-starter.version>
<guava.version>29.0-jre</guava.version>
<commons-lang3.version>3.10</commons-lang3.version>
<commons-codec.version>1.14</commons-codec.version>
<commons-collections4.version>4.4</commons-collections4.version>
<maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
<maven-resources-plugin.version>3.1.0</maven-resources-plugin.version>
<maven-surefire-plugin.version>2.22.2</maven-surefire-plugin.version>
<maven-javadoc-plugin.version>3.1.1</maven-javadoc-plugin.version>
<spring.boot.version>2.3.1.RELEASE</spring.boot.version>
<lombok.version>1.18.12</lombok.version>
<mysql.version>8.0.20</mysql.version>
<querydsl.version>4.3.1</querydsl.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring.boot.version}</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>${spring.boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<version>${spring.boot.version}</version>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>${spring.boot.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring.boot.version}</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<!-- Apache Commons -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons-codec.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>${commons-collections4.version}</version>
</dependency>
<!-- Apache Commons end -->
<!-- 对象属性复制 https://mapstruct.org/ -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<!-- 函数式编程库 https://https://www.vavr.io/vavr-docs/ -->
<dependency>
<groupId>io.vavr</groupId>
<artifactId>vavr</artifactId>
<version>${vavr.version}</version>
</dependency>
<!-- JWT start -->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>${jwt.version}</version>
</dependency>
<!-- JWT end -->
<!-- QueryDSL beging -->
<!--QueryDSL支持-->
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl.version}</version>
<scope>provided</scope>
</dependency>
<!--QueryDSL支持-->
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
<version>${querydsl.version}</version>
</dependency>
<!-- QueryDSL end -->
<!-- swagger start -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger2.version}</version>
<exclusions>
<exclusion>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>${swagger-bootstrap-ui.version}</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>com.github.xiaoymin</groupId>-->
<!-- <artifactId>knife4j-spring-boot-starter</artifactId>-->
<!-- <version>${knife4j-spring-boot-starter.version}</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>io.springfox</groupId>-->
<!-- <artifactId>springfox-swagger-ui</artifactId>-->
<!-- <version>${swagger2.version}</version>-->
<!-- </dependency>-->
<!-- swagger end -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<!-- Java图形验证码 -->
<dependency>
<groupId>com.github.whvcse</groupId>
<artifactId>easy-captcha</artifactId>
<version>${easy-captcha.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis-plus-boot-starter.version}</version>
</dependency>
</dependencies>
<build>
<resources>
<!-- 资源文件配置 -->
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<excludes>
<exclude>config/**</exclude>
</excludes>
</resource>
<!-- 过滤配置文件到config目录 -->
<resource>
<directory>src/main/resources/config</directory>
<filtering>true</filtering>
<targetPath>config</targetPath>
<includes>
<include>application.yml</include>
<include>application-${profileActive}.yml</include>
<include>banner.txt</include>
<include>*.xml</include>
<include>*.properties</include>
</includes>
</resource>
</resources>
<plugins>
<!-- 由于没有直接继承spring-boot-starter-parent,此处修添加主类和设置repackage -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
<configuration>
<fork>true</fork>
<mainClass>com.el.CmsSvrApplication</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>1.1.3</version>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources/java</outputDirectory>
<processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>${maven-resources-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<annotationProcessorPaths>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
<!-- 打包时跳过测试 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<skipTests>true</skipTests>
<testFailureIgnore>true</testFailureIgnore>
</configuration>
</plugin>
<!-- &lt;!&ndash; 打包插件 &ndash;&gt;-->
<!-- <plugin>-->
<!-- <artifactId>maven-assembly-plugin</artifactId>-->
<!-- <version>3.3.0</version>-->
<!-- <configuration>-->
<!-- <finalName>${project.build.finalName}-server</finalName>-->
<!-- <descriptors>-->
<!-- <descriptor>src/main/assembly/assembly.xml</descriptor>-->
<!-- </descriptors>-->
<!-- </configuration>-->
<!-- <executions>-->
<!-- <execution>-->
<!-- <id>make-assembly</id>-->
<!-- <phase>package</phase>-->
<!-- <goals>-->
<!-- <goal>single</goal>-->
<!-- </goals>-->
<!-- </execution>-->
<!-- </executions>-->
<!-- </plugin>-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>${maven-javadoc-plugin.version}</version>
<configuration>
<additionalOptions>
<additionalOption>-Xdoclint:none</additionalOption>
</additionalOptions>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<!--MAVEN打包选择运行环境-->
<!-- 1:local(默认) 本地 2:dev:开发环境 3:test 4:uat 用户验收测试 5.prod:生产环境 -->
<profiles>
<profile>
<id>local</id>
<properties>
<profileActive>local</profileActive>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>dev</id>
<properties>
<profileActive>dev</profileActive>
</properties>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
</profile>
<profile>
<id>test</id>
<properties>
<profileActive>test</profileActive>
</properties>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
</profile>
<profile>
<id>uat</id>
<properties>
<profileActive>uat</profileActive>
</properties>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
</profile>
<profile>
<id>prod</id>
<properties>
<profileActive>prod</profileActive>
</properties>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
</profile>
</profiles>
<repositories>
<!--华为云仓库-->
<repository>
<id>huaweicloud</id>
<name>huaweicloud-maven</name>
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
</repository>
<!--阿里云仓库-->
<repository>
<id>aliyun</id>
<name>aliyun-maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
</repository>
<!-- 阿里云spring仓库 -->
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://maven.aliyun.com/repository/spring</url>
</repository>
<!-- 中央仓库 -->
<repository>
<id>central</id>
<name>maven-central</name>
<url>http://central.maven.org/maven2/</url>
</repository>
</repositories>
</project>
\ No newline at end of file
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**
!**/src/test/**
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
### VS Code ###
.vscode/
/mvnw
/mvnw.cmd
/.mvn/
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>yst-dch-score</artifactId>
<groupId>com.elitesland</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>system</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>system</name>
<description>System module for YST</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.elitesland</groupId>
<artifactId>core</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.elitesland</groupId>
<artifactId>interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<!--华为云仓库-->
<repository>
<id>huaweicloud</id>
<name>huaweicloud-maven</name>
<url>https://mirrors.huaweicloud.com/repository/maven/</url>
</repository>
<!--阿里云仓库-->
<repository>
<id>aliyun</id>
<name>aliyun-maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
</repository>
<!-- 阿里云spring仓库 -->
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://maven.aliyun.com/repository/spring</url>
</repository>
<!-- 中央仓库 -->
<repository>
<id>central</id>
<name>maven-central</name>
<url>http://central.maven.org/maven2/</url>
</repository>
</repositories>
</project>
package com.elitesland.security;
import com.elitesland.system.entity.RoleDO;
import com.elitesland.system.repo.PermissionRepo;
import com.elitesland.system.repo.RoleRepo;
import lombok.val;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import reactor.util.function.Tuples;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.stream.Collectors;
/**
* <pre>
* 动态鉴权的核心,根据访问的URL,获取对应的角色列表
* </pre>
*
* @author Mir
* @date 2020/6/15
*/
public class DynamicFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
@Resource
private RequestMatcherCreator requestMatcherCreator;
@Resource
private PermissionRepo permissionRepo;
@Resource
private RoleRepo roleRepo;
@Override
public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
val request = ((FilterInvocation) object).getRequest();
val permissions = permissionRepo.findAll();
val metaResources = permissions.stream()
.map(p -> Tuples.of(p.getPattern(), request.getMethod()))
.collect(Collectors.toSet());
val requestMatchers = requestMatcherCreator.convertToRequestMatcher(metaResources);
val reqMatcher = requestMatchers.stream().filter(m -> m.matches(request))
.findAny();
if (reqMatcher.isPresent()) {
val antPathRequestMatcher = (AntPathRequestMatcher) reqMatcher.get();
val pattern = antPathRequestMatcher.getPattern();
val permRoleCodes = permissions.stream().filter(p -> p.getPattern().equals(pattern))
.flatMap(p -> p.getRoles().stream().map(RoleDO::getCode))
.toArray(String[]::new);
return SecurityConfig.createList(permRoleCodes);
}
return SecurityConfig.createList();
}
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
val roleList = roleRepo.findAll();
val roleCodeList = roleList.stream().map(RoleDO::getCode).toArray(String[]::new);
return SecurityConfig.createList(roleCodeList);
}
@Override
public boolean supports(Class<?> clazz) {
return FilterInvocation.class.isAssignableFrom(clazz);
}
}
package com.elitesland.security;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.elitesland.core.util.RequestUtil;
import lombok.val;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import static com.elitesland.security.filter.PreLoginFilter.LOGIN_CAPTCHA_KEY;
import static com.elitesland.security.filter.PreLoginFilter.LOGIN_CAPTCHA_UID;
import static org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.SPRING_SECURITY_FORM_PASSWORD_KEY;
import static org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.SPRING_SECURITY_FORM_USERNAME_KEY;
/**
* <pre>
* JSON格式登录信息处理器
* </pre>
*
* @author Mir
* @date 2020/6/16
*/
public class JsonLoginProcessor implements LoginPostProcessor {
private static ThreadLocal<String> passwordThreadLocal = new ThreadLocal<>();
private static ThreadLocal<String> captchaThreadLocal = new ThreadLocal<>();
private static ThreadLocal<String> capuidThreadLocal = new ThreadLocal<>();
@Override
public LoginTypeEnum getLoginType() {
return LoginTypeEnum.JSON;
}
@Override
public String obtainsUsername(ServletRequest request) {
val requestWrapper = new HttpServletRequestWrapper((HttpServletRequest) request);
val body = RequestUtil.obtainBody(requestWrapper);
JSONObject jsonObj = JSONUtil.parseObj(body);
passwordThreadLocal.set(jsonObj.getStr(SPRING_SECURITY_FORM_PASSWORD_KEY));
captchaThreadLocal.set(jsonObj.getStr(LOGIN_CAPTCHA_KEY));
capuidThreadLocal.set(jsonObj.getStr(LOGIN_CAPTCHA_UID));
return jsonObj.getStr(SPRING_SECURITY_FORM_USERNAME_KEY);
}
@Override
public String obtainPassword(ServletRequest request) {
val password = passwordThreadLocal.get();
passwordThreadLocal.remove();
return password;
}
@Override
public String obtainCaptcha(ServletRequest request) {
val captcha = captchaThreadLocal.get();
captchaThreadLocal.remove();
return captcha;
}
@Override
public String obtainCapUid(ServletRequest request) {
val capUid = capuidThreadLocal.get();
capuidThreadLocal.remove();
return capUid;
}
}
package com.elitesland.security;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
/**
* <pre>
* [功能说明]
* </pre>
*
* @author Mir
* @date 2020/6/16
*/
@Slf4j
public class JwtTokenFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
logger.debug("JWT token filter triggerred");
filterChain.doFilter(servletRequest, servletResponse);
}
}
package com.elitesland.security;
import javax.servlet.ServletRequest;
/**
* <pre>
* 多种登录方式统一信息提取接口
* </pre>
*
* @author Mir
* @date 2020/6/16
*/
public interface LoginPostProcessor {
/**
* 从请求查询参数中,获取登录类型,表单还是JSON
*
* @return 登录类型枚举值
*/
LoginTypeEnum getLoginType();
/**
* 从请求中获取登录用户账号
*
* @param request 请求对象
* @return 登录用户账号
*/
String obtainsUsername(ServletRequest request);
/**
* 从请求中获取登录密码
*
* @param request 请求对象
* @return 登录密码
*/
String obtainPassword(ServletRequest request);
/**
* 从请求中获取验证码
*
* @param request 请求对象
* @return 验证码字符串
*/
String obtainCaptcha(ServletRequest request);
/**
* 从请求中获取验证码缓存UID
*
* @param request 请求对象
* @return 验证码缓存UID
*/
String obtainCapUid(ServletRequest request);
}
package com.elitesland.security;
/**
* <pre>
* 登录方式分类
* </pre>
*
* @author Mir
* @date 2020/6/16
*/
public enum LoginTypeEnum {
//表单登录
FORM("表单登录"),
//JSON登录
JSON("JSON登录");
private final String desc;
LoginTypeEnum(String desc) {
this.desc = desc;
}
public String getDesc() {
return this.desc;
}
}
package com.elitesland.security;
import org.springframework.security.web.util.matcher.RequestMatcher;
import reactor.util.function.Tuple2;
import java.util.Set;
/**
* <pre>
* 函数式接口,用于创建对应的函数工厂
* </pre>
*
* @author Mir
* @date 2020/6/15
*/
public interface RequestMatcherCreator {
Set<RequestMatcher> convertToRequestMatcher(Set<Tuple2<String, String>> metaResources);
}
package com.elitesland.security.config;
import com.elitesland.security.JsonLoginProcessor;
import com.elitesland.security.JwtTokenFilter;
import com.elitesland.security.LoginPostProcessor;
import com.elitesland.security.filter.PreLoginFilter;
import com.elitesland.security.handle.JsonAuthenticationEntryPoint;
import com.elitesland.security.handle.SimpleAccessDeniedException;
import com.elitesland.core.util.RedisUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.annotation.Resource;
import java.util.Collection;
/**
* <pre>
* [功能说明]
* </pre>
*
* @author Mir
* @date 2020/6/15
*/
@Configuration
@ConditionalOnClass(WebSecurityConfigurerAdapter.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public class SecurityConfig {
private static final String LOGIN_PROCESSING_URL = "/process";
@Bean
public JsonLoginProcessor jsonLoginProcessor() {
return new JsonLoginProcessor();
}
@Bean
public PreLoginFilter preLoginFilter(Collection<LoginPostProcessor> loginPostProcessors, RedisUtils redisUtils) {
return new PreLoginFilter(LOGIN_PROCESSING_URL, loginPostProcessors, redisUtils);
}
@Bean
public JwtTokenFilter jwtTokenFilter() {
return new JwtTokenFilter();
}
@Configuration
@Order(SecurityProperties.BASIC_AUTH_ORDER)
static class SecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Resource
private PreLoginFilter preLoginFilter;
@Resource
private JwtTokenFilter jwtTokenFilter;
@Resource
private FilterInvocationSecurityMetadataSource filterInvocationSecurityMetadataSource;
@Resource
private AccessDecisionManager accessDecisionManager;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
super.configure(auth);
}
@Override
public void configure(WebSecurity web) throws Exception {
super.configure(web);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.cors()
.and()
.exceptionHandling()
.authenticationEntryPoint(new JsonAuthenticationEntryPoint())
.accessDeniedHandler(new SimpleAccessDeniedException())
.and()
.authorizeRequests()
.antMatchers("/sys/**").permitAll()
.anyRequest().authenticated()
.withObjectPostProcessor(filterSecurityInterceptorObjectPostProcessor())
.and()
.addFilterBefore(preLoginFilter, UsernamePasswordAuthenticationFilter.class)
.addFilterAfter(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class)
.formLogin()
.loginProcessingUrl("/process");
}
private ObjectPostProcessor<FilterSecurityInterceptor> filterSecurityInterceptorObjectPostProcessor() {
return new ObjectPostProcessor<>() {
@Override
public <O extends FilterSecurityInterceptor> O postProcess(O o) {
o.setAccessDecisionManager(accessDecisionManager);
o.setSecurityMetadataSource(filterInvocationSecurityMetadataSource);
return o;
}
};
}
}
}
package com.elitesland.security.config;
import com.elitesland.security.DynamicFilterInvocationSecurityMetadataSource;
import com.elitesland.security.RequestMatcherCreator;
import com.elitesland.security.config.bean.CaptchaProperties;
import com.elitesland.security.config.bean.SecurityProperties;
import com.elitesland.system.service.UserService;
import lombok.val;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDecisionVoter;
import org.springframework.security.access.vote.AffirmativeBased;
import org.springframework.security.access.vote.RoleVoter;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.UserDetailsManager;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;
/**
* <pre>
* 用于Spring Security配置的,初始配置工作
* </pre>
*
* @author Mir
* @date 2020/6/15
*/
@Configuration
public class SecuritySetupConfig {
@Bean
@ConfigurationProperties(prefix = "login", ignoreUnknownFields = true)
public CaptchaProperties captchaProperties() {
return new CaptchaProperties();
}
@Bean
@ConfigurationProperties(prefix = "jwt", ignoreUnknownFields = true)
public SecurityProperties securityProperties() {
return new SecurityProperties();
}
@Bean
public RequestMatcherCreator requestMatcherCreator() {
return metaResources -> metaResources.stream()
.map(r -> new AntPathRequestMatcher(r.getT1(), r.getT2()))
.collect(Collectors.toSet());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public FilterInvocationSecurityMetadataSource filterInvocationSecurityMetadataSource() {
return new DynamicFilterInvocationSecurityMetadataSource();
}
@Bean
public RoleVoter roleVoter() {
return new RoleVoter();
}
@Bean
public AccessDecisionManager affirmativeBase(List<AccessDecisionVoter<?>> decisionVoters) {
return new AffirmativeBased(decisionVoters);
}
@Bean
public UserDetailsManager userDetailsManager() {
return new UserDetailsManager() {
@Resource
private UserService userService;
@Override
public void createUser(UserDetails user) {
}
@Override
public void updateUser(UserDetails user) {
}
@Override
public void deleteUser(String username) {
}
@Override
public void changePassword(String oldPassword, String newPassword) {
}
@Override
public boolean userExists(String username) {
return userService.isUserExists(username);
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
val userDetailsOpt = userService.loadUserDetailsByUsername(username);
return userDetailsOpt.orElse(null);
}
};
}
}
package com.elitesland.security.config;
import com.elitesland.system.entity.UserDO;
import lombok.val;
import org.springframework.data.domain.AuditorAware;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import java.util.Optional;
/**
* @author Mir
* @date 3/17/2020
*/
@Component("auditorAware")
public class SpringSecurityAuditorAware implements AuditorAware<Long> {
/**
* 从SecurityContext中,获取当前登录用的用户ID
*
* @return 当前登录用户的用户ID
*/
@Override
public Optional<Long> getCurrentAuditor() {
val details = SecurityContextHolder.getContext().getAuthentication().getDetails();
if (details instanceof UserDO) {
return Optional.of(((UserDO) details).getId());
}
return Optional.of(0L);
}
}
/*
* Copyright 2019-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.elitesland.security.config.bean;
/**
* <pre>
* 验证码配置枚举
* </pre>
*
* @author Mir
* @date 2020-06-20
*/
public enum CaptchaCodeEnum {
/**
* 算数
*/
arithmetic,
/**
* 中文
*/
chinese,
/**
* 中文闪图
*/
chinese_gif,
/**
* 闪图
*/
gif,
spec
}
/*
* Copyright 2019-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.elitesland.security.config.bean;
import lombok.Data;
/**
* <pre>
* 登录验证码配置信息
* </pre>
*
* @author Mir
* @date 2020-06-20
*/
@Data
public class CaptchaInfo {
/**
* 验证码配置
*/
private CaptchaCodeEnum codeType;
/**
* 验证码有效期 分钟
*/
private Long expiration = 2L;
/**
* 验证码内容长度
*/
private int length = 2;
/**
* 验证码宽度
*/
private int width = 111;
/**
* 验证码高度
*/
private int height = 36;
}
/*
* Copyright 2019-2020 the original author or authors.
*
* Licensed under the Apache License, Version loginCode.length.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-loginCode.length.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.elitesland.security.config.bean;
import com.elitesland.core.exception.BadConfigurationException;
import com.wf.captcha.*;
import com.wf.captcha.base.Captcha;
import java.util.Objects;
/**
* <pre>
* 读取Captcha的配置信息
* </pre>>
* @author Mir
* @date 2020-06-20
*/
public class CaptchaProperties {
/**
* 账号单用户 登录
*/
private boolean singleLogin = false;
private CaptchaInfo captchaInfo;
public boolean isSingleLogin() {
return singleLogin;
}
public void setSingleLogin(boolean singleLogin) {
this.singleLogin = singleLogin;
}
public CaptchaInfo getCaptchaInfo() {
return captchaInfo;
}
public void setCaptchaInfo(CaptchaInfo captchaInfo) {
this.captchaInfo = captchaInfo;
}
/**
* 获取验证码生产类
*
* @return /
*/
public Captcha getCaptcha() {
if (Objects.isNull(captchaInfo)) {
captchaInfo = new CaptchaInfo();
if (Objects.isNull(captchaInfo.getCodeType())) {
captchaInfo.setCodeType(CaptchaCodeEnum.arithmetic);
}
}
return switchCaptcha(captchaInfo);
}
/**
* 依据配置信息生产验证码
*
* @param captchaInfo 验证码配置信息
* @return /
*/
private Captcha switchCaptcha(CaptchaInfo captchaInfo) {
Captcha captcha;
synchronized (this) {
switch (captchaInfo.getCodeType()) {
case arithmetic:
// 算术类型 https://gitee.com/whvse/EasyCaptcha
captcha = new ArithmeticCaptcha(captchaInfo.getWidth(), captchaInfo.getHeight());
// 几位数运算,默认是两位
captcha.setLen(captchaInfo.getLength());
break;
case chinese:
captcha = new ChineseCaptcha(captchaInfo.getWidth(), captchaInfo.getHeight());
captcha.setLen(captchaInfo.getLength());
break;
case chinese_gif:
captcha = new ChineseGifCaptcha(captchaInfo.getWidth(), captchaInfo.getHeight());
captcha.setLen(captchaInfo.getLength());
break;
case gif:
captcha = new GifCaptcha(captchaInfo.getWidth(), captchaInfo.getHeight());
captcha.setLen(captchaInfo.getLength());
break;
case spec:
captcha = new SpecCaptcha(captchaInfo.getWidth(), captchaInfo.getHeight());
captcha.setLen(captchaInfo.getLength());
break;
default:
throw new BadConfigurationException("验证码配置信息错误!!!正确配置查看 me.zhengjie.modules.security.config.bean.LoginCodeEnum ");
}
}
return captcha;
}
}
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.elitesland.security.config.bean;
import lombok.Data;
/**
* <pre>
* Jwt参数配置
* </pre>
*
* @author Mir
* @date 2020-06-20
*/
@Data
public class SecurityProperties {
/**
* Request Headers : Authorization
*/
private String header;
/**
* 令牌前缀,最后留个空格 Bearer
*/
private String tokenStartWith;
/**
* 必须使用最少88位的Base64对该令牌进行编码
*/
private String base64Secret;
/**
* 令牌过期时间 此处单位/毫秒
*/
private Long tokenValidityInSeconds;
/**
* 在线用户 key,根据 key 查询 redis 中在线用户的数据
*/
private String onlineKey;
/**
* 验证码 key
*/
private String codeKey;
/**
* token 续期检查
*/
private Long detect;
/**
* 续期时间
*/
private Long renew;
public String getTokenStartWith() {
return tokenStartWith + " ";
}
}
package com.elitesland.security.filter;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;
/**
* <pre>
* [功能说明]
* </pre>
*
* @author Mir
* @date 2020/6/23
*/
public class CaptchaFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
}
}
package com.elitesland.security.filter;
import cn.hutool.core.util.StrUtil;
import com.elitesland.core.exception.BadCaptchaException;
import com.elitesland.security.LoginPostProcessor;
import com.elitesland.security.LoginTypeEnum;
import com.elitesland.security.handle.JsonAuthenticationEntryPoint;
import com.elitesland.core.util.ParameterRequestWrapper;
import com.elitesland.core.util.RedisUtils;
import lombok.val;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.filter.GenericFilterBean;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import static org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.SPRING_SECURITY_FORM_PASSWORD_KEY;
import static org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.SPRING_SECURITY_FORM_USERNAME_KEY;
/**
* <pre>
* [功能说明]
* </pre>
*
* @author Mir
* @date 2020/6/16
*/
public class PreLoginFilter extends GenericFilterBean {
public static final String LOGIN_TYPE_KEY = "login_type";
public static final String LOGIN_CAPTCHA_KEY = "captcha";
public static final String LOGIN_CAPTCHA_UID = "capuid";
private final RequestMatcher requiredAuthenticationRequestMatcher;
private final Map<LoginTypeEnum, LoginPostProcessor> processors = new HashMap<>();
private RedisUtils redisUtils = null;
private final AuthenticationEntryPoint authenticationEntryPoint = new JsonAuthenticationEntryPoint();
public PreLoginFilter(String loginProcessingUrl, Collection<LoginPostProcessor> loginPostProcessors, RedisUtils redisUtils) {
Assert.notNull(loginProcessingUrl, "loginProcessingUrl must not be empty");
requiredAuthenticationRequestMatcher = new AntPathRequestMatcher(loginProcessingUrl, "POST");
this.redisUtils = redisUtils;
val loginPostProcessor = defaultLoginProcessor();
processors.put(loginPostProcessor.getLoginType(), loginPostProcessor);
if (!CollectionUtils.isEmpty(loginPostProcessors)) {
loginPostProcessors.forEach(e -> processors.put(e.getLoginType(), e));
}
}
private LoginTypeEnum getTypeFromReq(ServletRequest request) {
val parameter = request.getParameter(LOGIN_TYPE_KEY);
var i = 0;
if (parameter != null) {
i = Integer.parseInt(parameter);
}
val values = LoginTypeEnum.values();
return values[i];
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException, AuthenticationException {
val parameterRequestWrapper = new ParameterRequestWrapper((HttpServletRequest) servletRequest);
if (requiredAuthenticationRequestMatcher.matches((HttpServletRequest) servletRequest)) {
val typeFromReq = getTypeFromReq(servletRequest);
val loginPostProcessor = processors.get(typeFromReq);
val captchaStr = loginPostProcessor.obtainCaptcha(servletRequest);
val capUid = loginPostProcessor.obtainCapUid(servletRequest);
val code = (String) redisUtils.get(capUid);
redisUtils.del(capUid);
if (StrUtil.isBlank(code)) {
authenticationEntryPoint.commence(
(HttpServletRequest) servletRequest,
(HttpServletResponse) servletResponse,
new BadCredentialsException("验证码不存在或已过期"));
return;
}
if (StrUtil.isBlank(captchaStr) || !captchaStr.equalsIgnoreCase(code)) {
authenticationEntryPoint.commence(
(HttpServletRequest) servletRequest,
(HttpServletResponse) servletResponse,
new BadCaptchaException("验证码错误")
);
return;
}
val username = loginPostProcessor.obtainsUsername(servletRequest);
val password = loginPostProcessor.obtainPassword(servletRequest);
parameterRequestWrapper.setAttribute(SPRING_SECURITY_FORM_USERNAME_KEY, username);
parameterRequestWrapper.setAttribute(SPRING_SECURITY_FORM_PASSWORD_KEY, password);
}
filterChain.doFilter(parameterRequestWrapper, servletResponse);
}
private LoginPostProcessor defaultLoginProcessor() {
return new LoginPostProcessor() {
@Override
public LoginTypeEnum getLoginType() {
return LoginTypeEnum.FORM;
}
@Override
public String obtainsUsername(ServletRequest request) {
return request.getParameter(SPRING_SECURITY_FORM_USERNAME_KEY);
}
@Override
public String obtainPassword(ServletRequest request) {
return request.getParameter(SPRING_SECURITY_FORM_PASSWORD_KEY);
}
@Override
public String obtainCaptcha(ServletRequest request) {
return request.getParameter(LOGIN_CAPTCHA_KEY);
}
@Override
public String obtainCapUid(ServletRequest request) {
return request.getParameter(LOGIN_CAPTCHA_UID);
}
};
}
}
package com.elitesland.security.handle;
import com.elitesland.core.base.ApiCode;
import com.elitesland.core.base.ApiResult;
import com.elitesland.core.util.HttpServletResponseUtil;
import lombok.SneakyThrows;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* <pre>
* [功能说明]
* </pre>
*
* @author Mir
* @date 2020/6/24
*/
public class JsonAuthenticationEntryPoint implements AuthenticationEntryPoint {
@SneakyThrows
@Override
public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
HttpServletResponseUtil.printJSON(httpServletResponse, ApiResult.fail(ApiCode.VERIFICATION_CODE_EXCEPTION, e.getMessage()));
}
}
package com.elitesland.security.handle;
import com.elitesland.core.base.ApiCode;
import com.elitesland.core.base.ApiResult;
import com.elitesland.core.util.HttpServletResponseUtil;
import lombok.SneakyThrows;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* <pre>
* [功能说明]
* </pre>
*
* @author Mir
* @date 2020/6/25
*/
public class SimpleAccessDeniedException implements AccessDeniedHandler {
@SneakyThrows
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
HttpServletResponseUtil.printJSON(httpServletResponse, ApiResult.fail(ApiCode.VERIFICATION_CODE_EXCEPTION, e.getMessage()));
}
}
package com.elitesland.security.rest;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.RestController;
/**
* <pre>
* [功能说明]
* </pre>
*
* @author Mir
* @date 2020/6/21
*/
@RestController
@Api(value = "", tags = {""})
public class OnlineController {
}
package com.elitesland.security.rest;
import cn.hutool.core.util.IdUtil;
import com.elitesland.core.base.ApiResult;
import com.elitesland.security.config.bean.CaptchaProperties;
import com.elitesland.security.config.bean.SecurityProperties;
import com.elitesland.core.util.RedisUtils;
import com.wf.captcha.base.Captcha;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.val;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;
/**
* <pre>
* 认证相关信息的接口,如Captcha图片的生成
* </pre>
*
* @author Mir
* @date 2020/6/21
*/
@RestController
@RequestMapping("/sec")
@Api(value = "安全相关的接口", tags = {"系统安全"})
@RequiredArgsConstructor
public class SecurityController {
private final SecurityProperties properties;
private final CaptchaProperties captchaProperties;
private final RedisUtils redisUtils;
@GetMapping("/captcha")
@ApiOperation("获取验证码图片,和缓存标识的UUID")
public ResponseEntity<Object> getCaptcha() {
// 获取运算的结果
Captcha captcha = captchaProperties.getCaptcha();
String uuid = properties.getCodeKey() + IdUtil.simpleUUID();
// 保存
redisUtils.set(uuid, captcha.text(), captchaProperties.getCaptchaInfo().getExpiration(), TimeUnit.MINUTES);
// 验证码信息
val imgResult = new HashMap<String, Object>(2) {
private static final long serialVersionUID = -856648464071963590L;
{
put("img", captcha.toBase64());
put("uuid", uuid);
}
};
return ResponseEntity.ok(imgResult);
}
@GetMapping("/capkey/{uuid}")
@ApiOperation("Captcha的UUID对应key")
public ApiResult<String> getKey(@PathVariable("uuid") String uuid) {
val o = redisUtils.get(uuid);
return ApiResult.ok(o.toString());
}
}
package com.elitesland.system;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SystemApplication {
public static void main(String[] args) {
SpringApplication.run(SystemApplication.class, args);
}
}
package com.elitesland.system.annotation;
import java.lang.annotation.*;
/**
* @author Mir
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysCode {
String sys() default "";
String mod() default "";
}
package com.elitesland.system.annotation;
import java.lang.annotation.*;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SysCodeProc {
}
package com.elitesland.system.aop;
import com.elitesland.core.base.PagingVO;
import com.elitesland.system.annotation.SysCode;
import com.elitesland.system.service.CatCodeService;
import lombok.AllArgsConstructor;
import lombok.val;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* <pre>
* 针对数据库返回结果集进行切面处理UDC的转换
* </pre>
* @author Mir
* @date 2020-04-20
*/
@Aspect
@Component
@AllArgsConstructor
public class SysCodeAop {
private final CatCodeService catCodeService;
@Pointcut("@annotation(com.elitesland.system.annotation.SysCodeProc)")
public void sysCodeCut() {
}
@Around("sysCodeCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
val result = point.proceed();
if (result != null) {
if (result instanceof PagingVO) {
val resultList = (PagingVO<?>) result;
for (int i = 0; i < resultList.getRecords().size(); i++) {
Object oi = resultList.getRecords().get(i);
translate(oi);
}
}
if (result instanceof List) {
val resultList = (List<?>) result;
for (Object o : resultList) {
translate(o);
}
} else {
translate(result);
}
}
return result;
}
private void translate(Object oi) throws InvocationTargetException, IllegalAccessException {
Class<?> c = oi.getClass();
Class<?>[] types = {String.class};
val fieldNames = Arrays.stream(c.getDeclaredFields()).map(Field::getName).collect(Collectors.toList());
for (Field field : c.getDeclaredFields()) {
if (field.getType() != String.class && field.isAnnotationPresent(SysCode.class)) {
try {
val getter = c.getMethod("get" + StringUtils.capitalize(field.getName()));
val o = getter.invoke(oi);
translate(o);
} catch (NoSuchMethodException ignored) {
}
}
if (field.isAnnotationPresent(SysCode.class)) {
if (fieldNames.contains(field.getName() + "Name")) {
try {
val anno = field.getAnnotation(SysCode.class);
val codeMap = catCodeService.getCodeMap(anno.sys(), anno.mod());
val fieldMethodName = StringUtils.capitalize(field.getName());
val getter = c.getMethod("get" + fieldMethodName);
String code = (String) getter.invoke(oi);
val desc = codeMap.getOrDefault(code, "");
val m = c.getMethod("set" + fieldMethodName + "Name", types);
m.invoke(oi, desc);
} catch (NoSuchMethodException ignored) {
}
}
}
}
}
}
package com.elitesland.system.config;
import com.elitesland.security.config.bean.SecurityProperties;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import java.util.ArrayList;
import java.util.List;
//import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
/**
* Swagger2全局配置
*
* @author Mir
* @date 2018-11-08
*/
@Configuration
@RequiredArgsConstructor
public class SystemSwagger2Config {
/**
* 标题
*/
@Value("${swagger.title}")
private String title;
/**
* 基本包
*/
@Value("${swagger.base.package}")
private String basePackage;
/**
* 描述
*/
@Value("${swagger.description}")
private String description;
/**
* URL
*/
@Value("${swagger.url}")
private String url;
/**
* 作者
*/
@Value("${swagger.contact.name}")
private String contactName;
/**
* 作者网址
*/
@Value("${swagger.contact.url}")
private String contactUrl;
/**
* 作者邮箱
*/
@Value("${swagger.contact.email}")
private String contactEmail;
/**
* 版本
*/
@Value("${swagger.version}")
private String version;
private final SecurityProperties securityProperties;
@Bean
public Docket createSystemRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("System模块API")
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.elitesland.system"))
.paths(PathSelectors.any())
.build()
.globalOperationParameters(setHeaderToken())
;
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title(title)
.description(description)
.termsOfServiceUrl(url)
.contact(new Contact(contactName, contactUrl, contactEmail))
.version(version)
.build();
}
private List<Parameter> setHeaderToken() {
List<Parameter> pars = new ArrayList<>();
// token请求头
String testTokenValue = "";
ParameterBuilder tokenPar = new ParameterBuilder();
Parameter tokenParameter = tokenPar
.name(securityProperties.getHeader())
.description("JWT Token Request Header")
.modelRef(new ModelRef("string"))
.parameterType("Authorization")
.required(false)
.defaultValue(testTokenValue)
.build();
pars.add(tokenParameter);
return pars;
}
}
package com.elitesland.system.controller;
import com.elitesland.core.base.ApiResult;
import com.elitesland.core.base.PagingVO;
import com.elitesland.system.entity.CatCodeDO;
import com.elitesland.system.param.CatCodeQueryParam;
import com.elitesland.system.service.CatCodeService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.val;
import org.springframework.web.bind.annotation.*;
/**
* <pre>
* [功能说明]
* </pre>
*
* @author Mir
* @date 2020/6/25
*/
@RestController
@RequestMapping("/sys/codes")
@Api(value = "系统分类码维护", tags = {"系统分类码维护"})
@RequiredArgsConstructor
public class CatCodeController {
private final CatCodeService catCodeService;
@PostMapping("/q")
@ApiOperation("分类码列表")
public ApiResult<PagingVO<CatCodeDO>> listCodes(@RequestBody CatCodeQueryParam param) {
val ret = catCodeService.search(param);
return ApiResult.ok(ret);
}
@PostMapping
@ApiOperation("创建分类码")
public ApiResult<Object> createCode(@RequestBody CatCodeDO code) {
catCodeService.createCode(code);
return ApiResult.ok();
}
@PutMapping
@ApiOperation("更新分类码")
public ApiResult<Object> updateCode(@RequestBody CatCodeDO code) {
catCodeService.updateCode(code);
return ApiResult.ok();
}
}
package com.elitesland.system.controller;
import com.elitesland.system.convert.UserConvert;
import com.elitesland.system.entity.UserDO;
import com.elitesland.system.repo.UserRepo;
import com.elitesland.system.vo.UserVO;
import io.swagger.annotations.Api;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.stream.Collectors;
/**
* <pre>
* 系统用户账号维护接口
* </pre>
*
* @author Mir
* @date 2020/6/15
*/
@Slf4j
@RestController
@RequestMapping("/sys/users")
@RequiredArgsConstructor
@Api(value = "系统用户账号维护", tags = {"系统用户账号维护"})
public class UserController {
private final UserRepo userRepo;
private final PasswordEncoder passwordEncoder;
@GetMapping
public ResponseEntity<List<UserVO>> listAll() {
val userVos = userRepo.findAll().stream().map(UserConvert.INSTANCE::doToVo).collect(Collectors.toList());
return ResponseEntity.ok(userVos);
}
@PostMapping
public ResponseEntity<Long> create(@RequestBody UserDO userDO) {
userDO.setPassword(passwordEncoder.encode(userDO.getPassword()));
val u = userRepo.save(userDO);
return ResponseEntity.ok(u.getId());
}
}
package com.elitesland.system.convert;
import com.elitesland.system.entity.CatCodeDO;
import com.elitesland.system.vo.CatCodeComboVo;
import org.mapstruct.factory.Mappers;
/**
* <p>
* 功能说明
* </p>
*
* @author Mir
* @date 2020/6/28
*/
public interface CatCodeConvert {
CatCodeConvert INSTANCE = Mappers.getMapper(CatCodeConvert.class);
/**
* 分类码数据对象转型为VO对象
* @return
*/
CatCodeComboVo codeToComboVo(CatCodeDO code);
}
package com.elitesland.system.convert;
import com.elitesland.system.entity.UserDO;
import com.elitesland.system.vo.UserVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
* <pre>
* 系统用户在DO和VO之间拷贝转型
* </pre>
*
* @author Mir
* @date 2020/6/16
*/
@Mapper
public interface UserConvert {
UserConvert INSTANCE = Mappers.getMapper(UserConvert.class);
/**
* 转换UserDO到VO,并脱敏移除密码和角色清单
*
* @param user UserDO对象
* @return UserVO对象
*/
UserVO doToVo(UserDO user);
}
package com.elitesland.system.entity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.data.annotation.CreatedBy;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedBy;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.*;
import javax.validation.constraints.Null;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* <p>
* 分类码明细表
* </p>
*
* @author Mir
* @date 2020/5/15
*/
@Entity
@Table(name = "y0055")
@org.hibernate.annotations.Table(appliesTo = "y0055", comment = "分类码明细记录,对应分类码定义表的分类集合")
@Data
@ApiModel(value = "分类码明细", description = "分类码明细")
@EntityListeners(AuditingEntityListener.class)
public class CatCodeDO implements Serializable {
private static final long serialVersionUID = 407028412678884366L;
@EmbeddedId
private CatCodeKey key;
@ApiModelProperty("描述、说明")
@Column(columnDefinition = "varchar(32) default '' comment '描述、说明'", nullable = true)
private String description;
@ApiModelProperty("是否硬编码")
@Column(columnDefinition = "tinyint(1) default true comment '是否硬编码'")
private Boolean isHD;
@ApiModelProperty("预留整数01")
@Column(columnDefinition = "int default 0 comment '预留整数01'")
private Integer int01;
@ApiModelProperty("预留整数02")
@Column(columnDefinition = "int default 0 comment '预留整数02'")
private Integer int02;
@ApiModelProperty("预留整数03")
@Column(columnDefinition = "int default 0 comment '预留整数03'")
private Integer int03;
@ApiModelProperty("预留整数04")
@Column(columnDefinition = "int default 0 comment '预留整数04'")
private Integer int04;
@ApiModelProperty("预留浮点数01")
@Column(columnDefinition = "float(18, 4) default 0.0 comment '预留浮点数01'")
private Double double01;
@ApiModelProperty("预留浮点数02")
@Column(columnDefinition = "float(18, 4) default 0.0 comment '预留浮点数02'")
private Double double02;
@ApiModelProperty("预留浮点数03")
@Column(columnDefinition = "float(18, 4) default 0.0 comment '预留浮点数03'")
private Double double03;
@ApiModelProperty("预留浮点数04")
@Column(columnDefinition = "float(18, 4) default 0.0 comment '预留浮点数04'")
private Double double04;
@ApiModelProperty("预留字符串01")
@Column(columnDefinition = "varchar(128) default '' comment '预留字符串01'")
private String string01;
@ApiModelProperty("预留字符串02")
@Column(columnDefinition = "varchar(128) default '' comment '预留字符串02'")
private String string02;
@ApiModelProperty("预留字符串03")
@Column(columnDefinition = "varchar(128) default '' comment '预留字符串03'")
private String string03;
@ApiModelProperty("预留字符串04")
@Column(columnDefinition = "varchar(128) default '' comment '预留字符串04'")
private String string04;
@ApiModelProperty("预留日期时间01")
@Column(columnDefinition = "datetime default NULL comment '预留日期时间01'")
private LocalDateTime datetime01;
@ApiModelProperty("预留日期时间02")
@Column(columnDefinition = "datetime default NULL comment '预留日期时间02'")
private LocalDateTime datetime02;
@ApiModelProperty("预留日期时间03")
@Column(columnDefinition = "datetime default NULL comment '预留日期时间03'")
private LocalDateTime datetime03;
@ApiModelProperty("预留日期时间04")
@Column(columnDefinition = "datetime default NULL comment '预留日期时间04'")
private LocalDateTime datetime04;
@ApiModelProperty("预留开关01")
@Column(columnDefinition = "tinyint(1) default NULL comment '预留开关01'")
private Boolean flag01;
@CreatedBy
@Column(columnDefinition = "bigint default 0 comment '记录创建者ID'")
private Long creator;
@CreatedDate
@Column(columnDefinition = "timestamp default NULL comment '记录创建时间'")
private LocalDateTime created;
@LastModifiedBy
@Column(columnDefinition = "bigint default 0 comment '记录最后更新者ID'")
private Long updater;
@LastModifiedDate
@Column(columnDefinition = "timestamp default NULL comment '记录最后更新时间'")
private LocalDateTime updated;
@ApiModelProperty(value = "逻辑删除,0:未删除,1:已删除")
@Null(message = "逻辑删除不用传")
@Column(columnDefinition = "int default 0 comment '逻辑删除,0:未删除,1:已删除'")
private Integer deleted;
@ApiModelProperty(value = "版本")
@Null(message = "版本不用传")
@Column(columnDefinition = "int default 0 comment '版本信息,前端不用传'")
private Integer version;
}
package com.elitesland.system.entity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import java.io.Serializable;
/**
* <p>
* 分类码复合主键
* </p>
*
* @author Mir
* @date 2020/5/19
*/
@Embeddable
@Data
public class CatCodeKey implements Serializable {
private static final long serialVersionUID = 1020446498764362502L;
public CatCodeKey() {
}
@ApiModelProperty("系统码")
@Column(columnDefinition = "varchar(8) default '' comment '系统分类码,对应中台模块'")
private String sysCode;
@ApiModelProperty("模块码")
@Column(columnDefinition = "varchar(8) default '' comment '模块码,中台模块下的子分类'")
private String modCode;
@ApiModelProperty("分类码")
@Column(columnDefinition = "varchar(16) default '' comment '分类码'")
private String catCode;
}
package com.elitesland.system.entity;
import com.elitesland.core.base.BaseModel;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Objects;
import java.util.Set;
/**
* <pre>
* [功能说明]
* </pre>
*
* @author Mir
* @date 2020/6/15
*/
@Entity
@Table(name = "sys_permission")
@org.hibernate.annotations.Table(appliesTo = "sys_permission", comment = "系统权限表,包括URL、操作")
@Data
@Accessors(chain = true)
@ApiModel(value = "系统权限表", description = "系统权限表,包括URL、操作")
public class PermissionDO extends BaseModel implements Serializable {
private static final long serialVersionUID = 6810626977765149177L;
@ApiModelProperty(value = "权限代码")
@Column(columnDefinition = "varchar(16) default '' comment '权限代码'", nullable = false, unique = true)
private String code;
@ApiModelProperty(value = "权限名称")
@Column(columnDefinition = "varchar(16) default '' comment '权限名称'", nullable = false)
private String name;
@ApiModelProperty(value = "权限类型")
@Column(columnDefinition = "int default 0 comment '权限类型'")
private Integer permType;
@ApiModelProperty(value = "父权限ID")
@Column(columnDefinition = "int default 0 comment '父权限ID'")
private Integer parentId;
@ApiModelProperty(value = "权限层级路径")
@Column(columnDefinition = "varchar(256) default '' comment '权限层级路径'")
private String path;
@ApiModelProperty(value = "权限层级")
@Column(columnDefinition = "int default 0 comment '权限层级'")
private Integer level;
@ApiModelProperty(value = "URL路径模式")
@Column(columnDefinition = "varchar(256) default '' comment 'URL路径模式'")
private String pattern;
@ManyToMany(mappedBy = "permissions", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JsonIgnoreProperties({"permissions"})
private Set<RoleDO> roles;
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof PermissionDO)) {
return false;
}
if (!super.equals(o)) {
return false;
}
PermissionDO entity = (PermissionDO) o;
return getId().equals(entity.getId());
}
@Override
public int hashCode() {
return Objects.hash(getId());
}
}
\ No newline at end of file
package com.elitesland.system.entity;
import static com.querydsl.core.types.PathMetadataFactory.*;
import com.querydsl.core.types.dsl.*;
import com.querydsl.core.types.PathMetadata;
import javax.annotation.Generated;
import com.querydsl.core.types.Path;
import com.querydsl.core.types.dsl.PathInits;
/**
* QCatCodeDO is a Querydsl query type for CatCodeDO
*/
@Generated("com.querydsl.codegen.EntitySerializer")
public class QCatCodeDO extends EntityPathBase<CatCodeDO> {
private static final long serialVersionUID = -2042391316L;
private static final PathInits INITS = PathInits.DIRECT2;
public static final QCatCodeDO catCodeDO = new QCatCodeDO("catCodeDO");
public final DateTimePath<java.time.LocalDateTime> created = createDateTime("created", java.time.LocalDateTime.class);
public final NumberPath<Long> creator = createNumber("creator", Long.class);
public final DateTimePath<java.time.LocalDateTime> datetime01 = createDateTime("datetime01", java.time.LocalDateTime.class);
public final DateTimePath<java.time.LocalDateTime> datetime02 = createDateTime("datetime02", java.time.LocalDateTime.class);
public final DateTimePath<java.time.LocalDateTime> datetime03 = createDateTime("datetime03", java.time.LocalDateTime.class);
public final DateTimePath<java.time.LocalDateTime> datetime04 = createDateTime("datetime04", java.time.LocalDateTime.class);
public final NumberPath<Integer> deleted = createNumber("deleted", Integer.class);
public final StringPath description = createString("description");
public final NumberPath<Double> double01 = createNumber("double01", Double.class);
public final NumberPath<Double> double02 = createNumber("double02", Double.class);
public final NumberPath<Double> double03 = createNumber("double03", Double.class);
public final NumberPath<Double> double04 = createNumber("double04", Double.class);
public final BooleanPath flag01 = createBoolean("flag01");
public final NumberPath<Integer> int01 = createNumber("int01", Integer.class);
public final NumberPath<Integer> int02 = createNumber("int02", Integer.class);
public final NumberPath<Integer> int03 = createNumber("int03", Integer.class);
public final NumberPath<Integer> int04 = createNumber("int04", Integer.class);
public final BooleanPath isHD = createBoolean("isHD");
public final QCatCodeKey key;
public final StringPath string01 = createString("string01");
public final StringPath string02 = createString("string02");
public final StringPath string03 = createString("string03");
public final StringPath string04 = createString("string04");
public final DateTimePath<java.time.LocalDateTime> updated = createDateTime("updated", java.time.LocalDateTime.class);
public final NumberPath<Long> updater = createNumber("updater", Long.class);
public final NumberPath<Integer> version = createNumber("version", Integer.class);
public QCatCodeDO(String variable) {
this(CatCodeDO.class, forVariable(variable), INITS);
}
public QCatCodeDO(Path<? extends CatCodeDO> path) {
this(path.getType(), path.getMetadata(), PathInits.getFor(path.getMetadata(), INITS));
}
public QCatCodeDO(PathMetadata metadata) {
this(metadata, PathInits.getFor(metadata, INITS));
}
public QCatCodeDO(PathMetadata metadata, PathInits inits) {
this(CatCodeDO.class, metadata, inits);
}
public QCatCodeDO(Class<? extends CatCodeDO> type, PathMetadata metadata, PathInits inits) {
super(type, metadata, inits);
this.key = inits.isInitialized("key") ? new QCatCodeKey(forProperty("key")) : null;
}
}
package com.elitesland.system.entity;
import static com.querydsl.core.types.PathMetadataFactory.*;
import com.querydsl.core.types.dsl.*;
import com.querydsl.core.types.PathMetadata;
import javax.annotation.Generated;
import com.querydsl.core.types.Path;
/**
* QCatCodeKey is a Querydsl query type for CatCodeKey
*/
@Generated("com.querydsl.codegen.EmbeddableSerializer")
public class QCatCodeKey extends BeanPath<CatCodeKey> {
private static final long serialVersionUID = 1110386174L;
public static final QCatCodeKey catCodeKey = new QCatCodeKey("catCodeKey");
public final StringPath catCode = createString("catCode");
public final StringPath modCode = createString("modCode");
public final StringPath sysCode = createString("sysCode");
public QCatCodeKey(String variable) {
super(CatCodeKey.class, forVariable(variable));
}
public QCatCodeKey(Path<? extends CatCodeKey> path) {
super(path.getType(), path.getMetadata());
}
public QCatCodeKey(PathMetadata metadata) {
super(CatCodeKey.class, metadata);
}
}
package com.elitesland.system.entity;
import static com.querydsl.core.types.PathMetadataFactory.*;
import com.querydsl.core.types.dsl.*;
import com.querydsl.core.types.PathMetadata;
import javax.annotation.Generated;
import com.querydsl.core.types.Path;
import com.querydsl.core.types.dsl.PathInits;
/**
* QPermissionDO is a Querydsl query type for PermissionDO
*/
@Generated("com.querydsl.codegen.EntitySerializer")
public class QPermissionDO extends EntityPathBase<PermissionDO> {
private static final long serialVersionUID = 1493341084L;
public static final QPermissionDO permissionDO = new QPermissionDO("permissionDO");
public final com.elitesland.core.base.QBaseModel _super = new com.elitesland.core.base.QBaseModel(this);
public final StringPath code = createString("code");
//inherited
public final DateTimePath<java.time.LocalDateTime> created = _super.created;
//inherited
public final NumberPath<Long> creator = _super.creator;
//inherited
public final NumberPath<Integer> deleted = _super.deleted;
//inherited
public final NumberPath<Long> id = _super.id;
public final NumberPath<Integer> level = createNumber("level", Integer.class);
public final StringPath name = createString("name");
public final NumberPath<Integer> parentId = createNumber("parentId", Integer.class);
public final StringPath path = createString("path");
public final StringPath pattern = createString("pattern");
public final NumberPath<Integer> permType = createNumber("permType", Integer.class);
public final SetPath<RoleDO, QRoleDO> roles = this.<RoleDO, QRoleDO>createSet("roles", RoleDO.class, QRoleDO.class, PathInits.DIRECT2);
//inherited
public final DateTimePath<java.time.LocalDateTime> updated = _super.updated;
//inherited
public final NumberPath<Long> updater = _super.updater;
//inherited
public final NumberPath<Integer> version = _super.version;
public QPermissionDO(String variable) {
super(PermissionDO.class, forVariable(variable));
}
public QPermissionDO(Path<? extends PermissionDO> path) {
super(path.getType(), path.getMetadata());
}
public QPermissionDO(PathMetadata metadata) {
super(PermissionDO.class, metadata);
}
}
package com.elitesland.system.entity;
import static com.querydsl.core.types.PathMetadataFactory.*;
import com.querydsl.core.types.dsl.*;
import com.querydsl.core.types.PathMetadata;
import javax.annotation.Generated;
import com.querydsl.core.types.Path;
import com.querydsl.core.types.dsl.PathInits;
/**
* QRoleDO is a Querydsl query type for RoleDO
*/
@Generated("com.querydsl.codegen.EntitySerializer")
public class QRoleDO extends EntityPathBase<RoleDO> {
private static final long serialVersionUID = -1287083517L;
public static final QRoleDO roleDO = new QRoleDO("roleDO");
public final com.elitesland.core.base.QBaseModel _super = new com.elitesland.core.base.QBaseModel(this);
public final StringPath code = createString("code");
//inherited
public final DateTimePath<java.time.LocalDateTime> created = _super.created;
//inherited
public final NumberPath<Long> creator = _super.creator;
//inherited
public final NumberPath<Integer> deleted = _super.deleted;
//inherited
public final NumberPath<Long> id = _super.id;
public final StringPath name = createString("name");
public final SetPath<PermissionDO, QPermissionDO> permissions = this.<PermissionDO, QPermissionDO>createSet("permissions", PermissionDO.class, QPermissionDO.class, PathInits.DIRECT2);
//inherited
public final DateTimePath<java.time.LocalDateTime> updated = _super.updated;
//inherited
public final NumberPath<Long> updater = _super.updater;
public final SetPath<UserDO, QUserDO> users = this.<UserDO, QUserDO>createSet("users", UserDO.class, QUserDO.class, PathInits.DIRECT2);
//inherited
public final NumberPath<Integer> version = _super.version;
public QRoleDO(String variable) {
super(RoleDO.class, forVariable(variable));
}
public QRoleDO(Path<? extends RoleDO> path) {
super(path.getType(), path.getMetadata());
}
public QRoleDO(PathMetadata metadata) {
super(RoleDO.class, metadata);
}
}
package com.elitesland.system.entity;
import static com.querydsl.core.types.PathMetadataFactory.*;
import com.querydsl.core.types.dsl.*;
import com.querydsl.core.types.PathMetadata;
import javax.annotation.Generated;
import com.querydsl.core.types.Path;
import com.querydsl.core.types.dsl.PathInits;
/**
* QUserDO is a Querydsl query type for UserDO
*/
@Generated("com.querydsl.codegen.EntitySerializer")
public class QUserDO extends EntityPathBase<UserDO> {
private static final long serialVersionUID = -1197698024L;
public static final QUserDO userDO = new QUserDO("userDO");
public final com.elitesland.core.base.QBaseModel _super = new com.elitesland.core.base.QBaseModel(this);
//inherited
public final DateTimePath<java.time.LocalDateTime> created = _super.created;
//inherited
public final NumberPath<Long> creator = _super.creator;
//inherited
public final NumberPath<Integer> deleted = _super.deleted;
public final StringPath email = createString("email");
public final StringPath firstName = createString("firstName");
//inherited
public final NumberPath<Long> id = _super.id;
public final StringPath lastName = createString("lastName");
public final StringPath mobile = createString("mobile");
public final StringPath password = createString("password");
public final SetPath<RoleDO, QRoleDO> roles = this.<RoleDO, QRoleDO>createSet("roles", RoleDO.class, QRoleDO.class, PathInits.DIRECT2);
//inherited
public final DateTimePath<java.time.LocalDateTime> updated = _super.updated;
//inherited
public final NumberPath<Long> updater = _super.updater;
public final StringPath username = createString("username");
//inherited
public final NumberPath<Integer> version = _super.version;
public QUserDO(String variable) {
super(UserDO.class, forVariable(variable));
}
public QUserDO(Path<? extends UserDO> path) {
super(path.getType(), path.getMetadata());
}
public QUserDO(PathMetadata metadata) {
super(UserDO.class, metadata);
}
}
package com.elitesland.system.entity;
import com.elitesland.core.base.BaseModel;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Objects;
import java.util.Set;
/**
* <pre>
* [功能说明]
* </pre>
*
* @author Mir
* @date 2020/6/15
*/
@Entity
@Table(name = "sys_role")
@org.hibernate.annotations.Table(appliesTo = "sys_role", comment = "系统角色表")
@Data
@Accessors(chain = true)
@ApiModel(value = "系统角色表", description = "系统角色表")
public class RoleDO extends BaseModel implements Serializable {
private static final long serialVersionUID = 5152159757116510744L;
@ApiModelProperty(value = "角色代码")
@Column(columnDefinition = "varchar(16) default '' comment '角色代码'", nullable = false, unique = true)
private String code;
@ApiModelProperty(value = "角色名称")
@Column(columnDefinition = "varchar(32) default '' comment '角色名称'", nullable = false)
private String name;
@ManyToMany(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
@JoinTable(name = "sys_role_perm", joinColumns = @JoinColumn(name = "role_id"), inverseJoinColumns = @JoinColumn(name = "permission_id"))
@JsonIgnoreProperties({"roles"})
private Set<PermissionDO> permissions;
@ManyToMany(mappedBy = "roles", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JsonIgnoreProperties({"roles"})
private Set<UserDO> users;
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof RoleDO)) {
return false;
}
if (!super.equals(o)) {
return false;
}
RoleDO entity = (RoleDO) o;
return getId().equals(entity.getId());
}
@Override
public int hashCode() {
return Objects.hash(getId());
}
}
package com.elitesland.system.entity;
import com.elitesland.core.base.BaseModel;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Objects;
import java.util.Set;
/**
* <pre>
* 系统用户账号表
* </pre>
*
* @author Mir
* @date 2020-06-15
*/
@Entity
@Table(name = "sys_user")
@org.hibernate.annotations.Table(appliesTo = "sys_user", comment = "系统用户账号表")
@Data
@Accessors(chain = true)
@ApiModel(value = "系统用户账号表", description = "系统用户账号表")
public class UserDO extends BaseModel implements Serializable {
private static final long serialVersionUID = -7840804475330315230L;
@ApiModelProperty(value = "用户账号名称")
@Column(columnDefinition = "varchar(32) default '' comment '用户账号名称'", nullable = false, unique = true)
private String username;
@ApiModelProperty(value = "用户姓氏")
@Column(columnDefinition = "varchar(16) default '' comment '用户姓氏'")
private String lastName;
@ApiModelProperty(value = "用户名称")
@Column(columnDefinition = "varchar(16) default '' comment '用户名称'")
private String firstName;
@ApiModelProperty(value = "用户手机号码")
@Column(columnDefinition = "varchar(16) default '' comment '用户手机号码'", unique = true)
private String mobile;
@ApiModelProperty(value = "用户邮箱地址")
@Column(columnDefinition = "varchar(32) default '' comment '用户邮箱地址'")
private String email;
@ApiModelProperty(value = "用户账号密码-hashed")
@Column(columnDefinition = "varchar(128) default '' comment '用户账号密码-hashed'", nullable = false)
private String password;
@ManyToMany(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
@JoinTable(name = "sys_user_role", joinColumns = @JoinColumn(name = "user_id"), inverseJoinColumns = @JoinColumn(name = "role_id"))
@JsonIgnoreProperties({"users"})
private Set<RoleDO> roles;
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof UserDO)) {
return false;
}
if (!super.equals(o)) {
return false;
}
UserDO entity = (UserDO) o;
return getId().equals(entity.getId());
}
@Override
public int hashCode() {
return Objects.hash(getId());
}
}
\ No newline at end of file
package com.elitesland.system.repo;
import com.elitesland.system.entity.CatCodeDO;
import com.elitesland.system.entity.CatCodeKey;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.stereotype.Repository;
/**
* <pre>
* [功能说明]
* </pre>
*
* @author Mir
* @date 2020/6/25
*/
@Repository
public interface CatCodeRepo extends JpaRepository<CatCodeDO, CatCodeKey>, QuerydslPredicateExecutor<CatCodeDO> {
}
package com.elitesland.system.repo;
import cn.hutool.core.util.StrUtil;
import com.elitesland.system.entity.QCatCodeDO;
import com.elitesland.system.param.CatCodeQueryParam;
import com.querydsl.core.types.ExpressionUtils;
import com.querydsl.core.types.Predicate;
import lombok.val;
import org.apache.commons.collections4.CollectionUtils;
/**
* <p>
* 功能说明
* </p>
*
* @author Mir
* @date 2020/6/29
*/
public class CatCodeRepoProc {
public static Predicate where(CatCodeQueryParam param){
val catCode = QCatCodeDO.catCodeDO;
com.querydsl.core.types.Predicate predicate = catCode.isNotNull().or(catCode.isNull());
predicate = StrUtil.isBlank(param.getSys()) ? predicate : ExpressionUtils.and(predicate, catCode.key.sysCode.like("%" + param.getSys() + "%"));
predicate = StrUtil.isBlank(param.getMod()) ? predicate : ExpressionUtils.and(predicate, catCode.key.modCode.like("%" + param.getMod() + "%"));
predicate = StrUtil.isBlank(param.getKey()) ? predicate : ExpressionUtils.and(predicate, catCode.key.catCode.like("%" + param.getKey() + "%"));
predicate = StrUtil.isBlank(param.getDesc()) ? predicate : ExpressionUtils.and(predicate, catCode.description.like("%" + param.getDesc() + "%"));
predicate = CollectionUtils.isEmpty(param.getKeys()) ? predicate : ExpressionUtils.and(predicate, catCode.key.catCode.in(param.getKeys()));
return predicate;
}
}
package com.elitesland.system.repo;
import com.elitesland.system.entity.PermissionDO;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.stereotype.Repository;
/**
* <pre>
* 系统权限表JPA+QueryDSL访问封装
* </pre>
*
* @author Mir
* @date 2020/6/15
*/
@Repository
public interface PermissionRepo extends JpaRepository<PermissionDO, Long>, QuerydslPredicateExecutor<PermissionDO> {
}
package com.elitesland.system.repo;
import com.elitesland.system.entity.RoleDO;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.stereotype.Repository;
/**
* <pre>
* 系统角色表JPA+QueryDSL访问封装
* </pre>
*
* @author Mir
* @date 2020/6/15
*/
@Repository
public interface RoleRepo extends JpaRepository<RoleDO, Long>, QuerydslPredicateExecutor<RoleDO> {
}
package com.elitesland.system.repo;
import com.elitesland.system.entity.UserDO;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.stereotype.Repository;
/**
* <pre>
* 系统用户账号表JPA+QueryDSL访问封装
* </pre>
*
* @author Mir
* @date 2020/6/15
*/
@Repository
public interface UserRepo extends JpaRepository<UserDO, Long>, QuerydslPredicateExecutor<UserDO> {
}
package com.elitesland.system.service;
import com.elitesland.core.base.PagingVO;
import com.elitesland.system.entity.CatCodeDO;
import com.elitesland.system.entity.CatCodeKey;
import com.elitesland.system.param.CatCodeQueryParam;
import com.elitesland.system.vo.CatCodeComboVo;
import java.util.List;
import java.util.Map;
import java.util.Optional;
/**
* <pre>
* [功能说明]
* </pre>
*
* @author Mir
* @date 2020/6/25
*/
public interface CatCodeService {
/**
* 检索分类码
* @param param 分类查询、分页和排序对象
* @return 分页结果集
*/
PagingVO<CatCodeDO> search(CatCodeQueryParam param);
/**
* 根据关键字段,返回对应的分类码
* @param key 关键字段
* @return 分类码对象
*/
Optional<CatCodeDO> findOne(CatCodeKey key);
/**
* 创建分类码
*
* @param code 分类码对象
*/
void createCode(CatCodeDO code);
/**
* 更新分类码
*
* @param code 分类码对象
*/
void updateCode(CatCodeDO code);
/**
* 获取用于下来选择的分类码
*
* @param sys
* @param mod
* @return
*/
List<CatCodeComboVo> listCodeCombos(String sys, String mod);
/**
* 获取分类码的Map对应列表
* @param sys
* @param mod
* @return
*/
Map<String, String> getCodeMap(String sys, String mod);
}
package com.elitesland.system.service;
import com.elitesland.system.entity.UserDO;
import com.elitesland.system.vo.UserVO;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Optional;
/**
* <pre>
* 系统用户操作逻辑服务类
* </pre>
*
* @author Mir
* @date 2020/6/16
*/
public interface UserService {
/**
* 根据用户账号,返回所有的用户信息,包括密码和角色清单
*
* @param username 用户账号
* @return 对应的用户信息
*/
Optional<UserDO> getUserByUsernameSec(String username);
/**
* 根据用户账号,返回脱敏的用户信息,VO
*
* @param username 用户账号
* @return 脱敏的用户信息
*/
Optional<UserVO> getUserByUsername(String username);
/**
* 判断对应用户账号是否存在
*
* @param username 用户账号
* @return 是否存在
*/
boolean isUserExists(String username);
/**
* 根据用户账号,返回对应Spring Security用UserDetails对象
*
* @param username 用户账号
* @return UserDetails信息
*/
Optional<UserDetails> loadUserDetailsByUsername(String username);
}
package com.elitesland.system.service.impl;
import com.elitesland.core.base.PagingVO;
import com.elitesland.system.convert.CatCodeConvert;
import com.elitesland.system.entity.CatCodeDO;
import com.elitesland.system.entity.CatCodeKey;
import com.elitesland.system.entity.QCatCodeDO;
import com.elitesland.system.param.CatCodeQueryParam;
import com.elitesland.system.repo.CatCodeRepo;
import com.elitesland.system.repo.CatCodeRepoProc;
import com.elitesland.system.service.CatCodeService;
import com.elitesland.system.vo.CatCodeComboVo;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import lombok.val;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* <pre>
* [功能说明]
* </pre>
*
* @author Mir
* @date 2020/6/25
*/
@Service
@RequiredArgsConstructor
public class CatCodeServiceImpl implements CatCodeService {
private final CatCodeRepo catCodeRepo;
private final JPAQueryFactory jpaQueryFactory;
@Override
public PagingVO<CatCodeDO> search(CatCodeQueryParam param) {
val records = catCodeRepo.findAll(CatCodeRepoProc.where(param), param.getPageRequest());
return PagingVO.<CatCodeDO>builder()
.total(records.getTotalElements())
.records(records.getContent())
.build();
}
@Override
public Optional<CatCodeDO> findOne(CatCodeKey key) {
val code = QCatCodeDO.catCodeDO;
return catCodeRepo.findOne(code.key.sysCode.eq(key.getSysCode())
.and(code.key.modCode.eq(key.getModCode())
.and(code.key.catCode.eq(key.getCatCode()))));
}
@Override
public void createCode(CatCodeDO code) {
catCodeRepo.save(code);
}
@Override
public void updateCode(CatCodeDO code) {
val codeOpt = findOne(code.getKey());
codeOpt.ifPresent(c -> {
code.setCreator(c.getCreator());
code.setCreated(c.getCreated());
catCodeRepo.save(code);
}
);
}
@Override
@Cacheable(value = "catcodecombos", key = "targetClass + '-' + #sys + '-' + #mode")
public List<CatCodeComboVo> listCodeCombos(String sys, String mode) {
val catCode = QCatCodeDO.catCodeDO;
val codes = jpaQueryFactory.select(catCode)
.from(catCode)
.where(catCode.key.sysCode.eq(sys) )
.where(catCode.key.modCode.eq(mode)).fetch();
return codes.stream().map(CatCodeConvert.INSTANCE::codeToComboVo).collect(Collectors.toList());
}
@Override
public Map<String, String> getCodeMap(String sys, String mod) {
return null;
}
}
package com.elitesland.system.service.impl;
import com.elitesland.system.convert.UserConvert;
import com.elitesland.system.entity.QUserDO;
import com.elitesland.system.entity.RoleDO;
import com.elitesland.system.entity.UserDO;
import com.elitesland.system.repo.UserRepo;
import com.elitesland.system.service.UserService;
import com.elitesland.system.vo.UserVO;
import lombok.RequiredArgsConstructor;
import lombok.val;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import java.util.Optional;
/**
* <pre>
* [功能说明]
* </pre>
*
* @author Mir
* @date 2020/6/16
*/
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
private final UserRepo userRepo;
@Override
public Optional<UserDO> getUserByUsernameSec(String username) {
val userModel = QUserDO.userDO;
val predicate = userModel.username.eq(username);
return userRepo.findOne(predicate);
}
@Override
public Optional<UserVO> getUserByUsername(String username) {
val userOpt = getUserByUsernameSec(username);
return userOpt.map(UserConvert.INSTANCE::doToVo);
}
@Override
public boolean isUserExists(String username) {
val userOpt = getUserByUsernameSec(username);
return userOpt.isPresent();
}
@Override
public Optional<UserDetails> loadUserDetailsByUsername(String username) {
val userOpt = getUserByUsernameSec(username);
return userOpt.map(o -> User.builder()
.username(o.getUsername())
.password(o.getPassword())
.authorities(AuthorityUtils.createAuthorityList(o.getRoles().stream().map(RoleDO::getCode).toArray(String[]::new)))
.build());
}
}
/**
* <pre>
* [功能说明]
* </pre>
*
* @author Mir
* @date 2020/6/16
*/
package com.elitesland.system.service;
\ No newline at end of file
package com.elitesland.system;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class SystemApplicationTests {
@Test
void contextLoads() {
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment