删除文件 ruoyi
This commit is contained in:
parent
abdb1048ed
commit
b279aa391c
|
@ -1,43 +0,0 @@
|
||||||
######################################################################
|
|
||||||
# Build Tools
|
|
||||||
|
|
||||||
.gradle
|
|
||||||
/build/
|
|
||||||
!gradle/wrapper/gradle-wrapper.jar
|
|
||||||
|
|
||||||
target/
|
|
||||||
!.mvn/wrapper/maven-wrapper.jar
|
|
||||||
|
|
||||||
######################################################################
|
|
||||||
# IDE
|
|
||||||
|
|
||||||
### STS ###
|
|
||||||
.apt_generated
|
|
||||||
.classpath
|
|
||||||
.factorypath
|
|
||||||
.project
|
|
||||||
.settings
|
|
||||||
.springBeans
|
|
||||||
|
|
||||||
### IntelliJ IDEA ###
|
|
||||||
.idea
|
|
||||||
*.iws
|
|
||||||
*.iml
|
|
||||||
*.ipr
|
|
||||||
|
|
||||||
### NetBeans ###
|
|
||||||
nbproject/private/
|
|
||||||
build/*
|
|
||||||
nbbuild/
|
|
||||||
dist/
|
|
||||||
nbdist/
|
|
||||||
.nb-gradle/
|
|
||||||
|
|
||||||
######################################################################
|
|
||||||
# Others
|
|
||||||
*.log
|
|
||||||
*.xml.versionsBackup
|
|
||||||
|
|
||||||
!*/build/*.java
|
|
||||||
!*/build/*.html
|
|
||||||
!*/build/*.xml
|
|
|
@ -1,12 +0,0 @@
|
||||||
@echo off
|
|
||||||
echo.
|
|
||||||
echo [信息] 清理生成路径。
|
|
||||||
echo.
|
|
||||||
|
|
||||||
%~d0
|
|
||||||
cd %~dp0
|
|
||||||
|
|
||||||
cd ..
|
|
||||||
call mvn clean
|
|
||||||
|
|
||||||
pause
|
|
|
@ -1,12 +0,0 @@
|
||||||
@echo off
|
|
||||||
echo.
|
|
||||||
echo [信息] 打包Web工程,生成war/jar包文件。
|
|
||||||
echo.
|
|
||||||
|
|
||||||
%~d0
|
|
||||||
cd %~dp0
|
|
||||||
|
|
||||||
cd ..
|
|
||||||
call mvn clean package -Dmaven.test.skip=true
|
|
||||||
|
|
||||||
pause
|
|
|
@ -1,14 +0,0 @@
|
||||||
@echo off
|
|
||||||
echo.
|
|
||||||
echo [信息] 使用 Spring Boot Tomcat 运行 Web 工程。
|
|
||||||
echo.
|
|
||||||
|
|
||||||
%~d0
|
|
||||||
cd %~dp0
|
|
||||||
|
|
||||||
cd ..
|
|
||||||
title %cd%
|
|
||||||
set MAVEN_OPTS=%MAVEN_OPTS% -Xms256m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m
|
|
||||||
call mvn clean spring-boot:run -Dmaven.test.skip=true -U
|
|
||||||
|
|
||||||
pause
|
|
282
ruoyi/pom.xml
282
ruoyi/pom.xml
|
@ -1,282 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
|
|
||||||
<groupId>com.ruoyi</groupId>
|
|
||||||
<artifactId>ruoyi</artifactId>
|
|
||||||
<version>2.0.0</version>
|
|
||||||
<packaging>jar</packaging>
|
|
||||||
|
|
||||||
<name>ruoyi</name>
|
|
||||||
<url>http://www.ruoyi.vip</url>
|
|
||||||
<description>若依管理系统</description>
|
|
||||||
|
|
||||||
<parent>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-parent</artifactId>
|
|
||||||
<version>2.1.1.RELEASE</version>
|
|
||||||
<relativePath />
|
|
||||||
</parent>
|
|
||||||
|
|
||||||
<properties>
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
|
||||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
|
||||||
<java.version>1.8</java.version>
|
|
||||||
<mybatis.spring.boot.starter.version>1.3.2</mybatis.spring.boot.starter.version>
|
|
||||||
<pagehelper.spring.boot.starter.version>1.2.5</pagehelper.spring.boot.starter.version>
|
|
||||||
<fastjson.version>1.2.47</fastjson.version>
|
|
||||||
<druid.version>1.1.14</druid.version>
|
|
||||||
<commons.io.version>2.5</commons.io.version>
|
|
||||||
<commons.fileupload.version>1.3.3</commons.fileupload.version>
|
|
||||||
<bitwalker.version>1.19</bitwalker.version>
|
|
||||||
<jwt.version>0.9.0</jwt.version>
|
|
||||||
<swagger.version>2.9.2</swagger.version>
|
|
||||||
<poi.version>3.17</poi.version>
|
|
||||||
<oshi.version>3.9.1</oshi.version>
|
|
||||||
<velocity.version>1.7</velocity.version>
|
|
||||||
</properties>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
|
|
||||||
<!-- SpringBoot 核心包 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter</artifactId>
|
|
||||||
<!--
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
-->
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- SpringBoot 测试 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-test</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- SpringBoot 拦截器 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-aop</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- SpringBoot Web容器 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- spring-boot-devtools -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-devtools</artifactId>
|
|
||||||
<optional>true</optional> <!-- 表示依赖不会传递 -->
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- spring security 安全认证 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-security</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- redis 缓存操作 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- pool 对象池 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.commons</groupId>
|
|
||||||
<artifactId>commons-pool2</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- Mysql驱动包 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>mysql</groupId>
|
|
||||||
<artifactId>mysql-connector-java</artifactId>
|
|
||||||
<scope>runtime</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- SpringBoot集成mybatis框架 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.mybatis.spring.boot</groupId>
|
|
||||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
|
||||||
<version>${mybatis.spring.boot.starter.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- pagehelper 分页插件 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.pagehelper</groupId>
|
|
||||||
<artifactId>pagehelper-spring-boot-starter</artifactId>
|
|
||||||
<version>${pagehelper.spring.boot.starter.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!--阿里数据库连接池 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.alibaba</groupId>
|
|
||||||
<artifactId>druid-spring-boot-starter</artifactId>
|
|
||||||
<version>${druid.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!--常用工具类 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.commons</groupId>
|
|
||||||
<artifactId>commons-lang3</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!--io常用工具类 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>commons-io</groupId>
|
|
||||||
<artifactId>commons-io</artifactId>
|
|
||||||
<version>${commons.io.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!--文件上传工具类 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>commons-fileupload</groupId>
|
|
||||||
<artifactId>commons-fileupload</artifactId>
|
|
||||||
<version>${commons.fileupload.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- 解析客户端操作系统、浏览器等 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>eu.bitwalker</groupId>
|
|
||||||
<artifactId>UserAgentUtils</artifactId>
|
|
||||||
<version>${bitwalker.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- 阿里JSON解析器 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.alibaba</groupId>
|
|
||||||
<artifactId>fastjson</artifactId>
|
|
||||||
<version>${fastjson.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!--Spring框架基本的核心工具-->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework</groupId>
|
|
||||||
<artifactId>spring-context-support</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!--Token生成与解析-->
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
|
||||||
<artifactId>jjwt</artifactId>
|
|
||||||
<version>${jwt.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- swagger2-->
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.springfox</groupId>
|
|
||||||
<artifactId>springfox-swagger2</artifactId>
|
|
||||||
<version>${swagger.version}</version>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>io.swagger</groupId>
|
|
||||||
<artifactId>swagger-annotations</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
<exclusion>
|
|
||||||
<groupId>io.swagger</groupId>
|
|
||||||
<artifactId>swagger-models</artifactId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!--防止进入swagger页面报类型转换错误,排除2.9.2中的引用,手动增加1.5.21版本-->
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.swagger</groupId>
|
|
||||||
<artifactId>swagger-annotations</artifactId>
|
|
||||||
<version>1.5.21</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.swagger</groupId>
|
|
||||||
<artifactId>swagger-models</artifactId>
|
|
||||||
<version>1.5.21</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- swagger2-UI-->
|
|
||||||
<dependency>
|
|
||||||
<groupId>io.springfox</groupId>
|
|
||||||
<artifactId>springfox-swagger-ui</artifactId>
|
|
||||||
<version>${swagger.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- 获取系统信息 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.oshi</groupId>
|
|
||||||
<artifactId>oshi-core</artifactId>
|
|
||||||
<version>${oshi.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>net.java.dev.jna</groupId>
|
|
||||||
<artifactId>jna</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>net.java.dev.jna</groupId>
|
|
||||||
<artifactId>jna-platform</artifactId>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<!-- excel工具 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.poi</groupId>
|
|
||||||
<artifactId>poi-ooxml</artifactId>
|
|
||||||
<version>${poi.version}</version>
|
|
||||||
</dependency>
|
|
||||||
<!--velocity代码生成使用模板 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.apache.velocity</groupId>
|
|
||||||
<artifactId>velocity</artifactId>
|
|
||||||
<version>${velocity.version}</version>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<finalName>${project.artifactId}</finalName>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
|
||||||
<configuration>
|
|
||||||
<fork>true</fork> <!-- 如果没有该配置,devtools不会生效 -->
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
<repositories>
|
|
||||||
<repository>
|
|
||||||
<id>public</id>
|
|
||||||
<name>aliyun nexus</name>
|
|
||||||
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
|
|
||||||
<releases>
|
|
||||||
<enabled>true</enabled>
|
|
||||||
</releases>
|
|
||||||
</repository>
|
|
||||||
</repositories>
|
|
||||||
|
|
||||||
<pluginRepositories>
|
|
||||||
<pluginRepository>
|
|
||||||
<id>public</id>
|
|
||||||
<name>aliyun nexus</name>
|
|
||||||
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
|
|
||||||
<releases>
|
|
||||||
<enabled>true</enabled>
|
|
||||||
</releases>
|
|
||||||
<snapshots>
|
|
||||||
<enabled>false</enabled>
|
|
||||||
</snapshots>
|
|
||||||
</pluginRepository>
|
|
||||||
</pluginRepositories>
|
|
||||||
|
|
||||||
</project>
|
|
86
ruoyi/ry.sh
86
ruoyi/ry.sh
|
@ -1,86 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
AppName=ruoyi.jar
|
|
||||||
|
|
||||||
#JVM参数
|
|
||||||
JVM_OPTS="-Dname=$AppName -Duser.timezone=Asia/Shanghai -Xms512M -Xmx512M -XX:PermSize=256M -XX:MaxPermSize=512M -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC"
|
|
||||||
APP_HOME=`pwd`
|
|
||||||
LOG_PATH=$APP_HOME/logs/$AppName.log
|
|
||||||
|
|
||||||
if [ "$1" = "" ];
|
|
||||||
then
|
|
||||||
echo -e "\033[0;31m 未输入操作名 \033[0m \033[0;34m {start|stop|restart|status} \033[0m"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$AppName" = "" ];
|
|
||||||
then
|
|
||||||
echo -e "\033[0;31m 未输入应用名 \033[0m"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
function start()
|
|
||||||
{
|
|
||||||
PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'`
|
|
||||||
|
|
||||||
if [ x"$PID" != x"" ]; then
|
|
||||||
echo "$AppName is running..."
|
|
||||||
else
|
|
||||||
nohup java -jar $JVM_OPTS target/$AppName > /dev/null 2>&1 &
|
|
||||||
echo "Start $AppName success..."
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
function stop()
|
|
||||||
{
|
|
||||||
echo "Stop $AppName"
|
|
||||||
|
|
||||||
PID=""
|
|
||||||
query(){
|
|
||||||
PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'`
|
|
||||||
}
|
|
||||||
|
|
||||||
query
|
|
||||||
if [ x"$PID" != x"" ]; then
|
|
||||||
kill -TERM $PID
|
|
||||||
echo "$AppName (pid:$PID) exiting..."
|
|
||||||
while [ x"$PID" != x"" ]
|
|
||||||
do
|
|
||||||
sleep 1
|
|
||||||
query
|
|
||||||
done
|
|
||||||
echo "$AppName exited."
|
|
||||||
else
|
|
||||||
echo "$AppName already stopped."
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
function restart()
|
|
||||||
{
|
|
||||||
stop
|
|
||||||
sleep 2
|
|
||||||
start
|
|
||||||
}
|
|
||||||
|
|
||||||
function status()
|
|
||||||
{
|
|
||||||
PID=`ps -ef |grep java|grep $AppName|grep -v grep|wc -l`
|
|
||||||
if [ $PID != 0 ];then
|
|
||||||
echo "$AppName is running..."
|
|
||||||
else
|
|
||||||
echo "$AppName is not running..."
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
case $1 in
|
|
||||||
start)
|
|
||||||
start;;
|
|
||||||
stop)
|
|
||||||
stop;;
|
|
||||||
restart)
|
|
||||||
restart;;
|
|
||||||
status)
|
|
||||||
status;;
|
|
||||||
*)
|
|
||||||
|
|
||||||
esac
|
|
|
@ -1,675 +0,0 @@
|
||||||
-- ----------------------------
|
|
||||||
-- 1、部门表
|
|
||||||
-- ----------------------------
|
|
||||||
drop table if exists sys_dept;
|
|
||||||
create table sys_dept (
|
|
||||||
dept_id bigint(20) not null auto_increment comment '部门id',
|
|
||||||
parent_id bigint(20) default 0 comment '父部门id',
|
|
||||||
ancestors varchar(50) default '' comment '祖级列表',
|
|
||||||
dept_name varchar(30) default '' comment '部门名称',
|
|
||||||
order_num int(4) default 0 comment '显示顺序',
|
|
||||||
leader varchar(20) default null comment '负责人',
|
|
||||||
phone varchar(11) default null comment '联系电话',
|
|
||||||
email varchar(50) default null comment '邮箱',
|
|
||||||
status char(1) default '0' comment '部门状态(0正常 1停用)',
|
|
||||||
del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)',
|
|
||||||
create_by varchar(64) default '' comment '创建者',
|
|
||||||
create_time datetime comment '创建时间',
|
|
||||||
update_by varchar(64) default '' comment '更新者',
|
|
||||||
update_time datetime comment '更新时间',
|
|
||||||
primary key (dept_id)
|
|
||||||
) engine=innodb auto_increment=200 comment = '部门表';
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- 初始化-部门表数据
|
|
||||||
-- ----------------------------
|
|
||||||
insert into sys_dept values(100, 0, '0', '若依科技', 0, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
|
|
||||||
insert into sys_dept values(101, 100, '0,100', '深圳总公司', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
|
|
||||||
insert into sys_dept values(102, 100, '0,100', '长沙分公司', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
|
|
||||||
insert into sys_dept values(103, 101, '0,100,101', '研发部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
|
|
||||||
insert into sys_dept values(104, 101, '0,100,101', '市场部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
|
|
||||||
insert into sys_dept values(105, 101, '0,100,101', '测试部门', 3, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
|
|
||||||
insert into sys_dept values(106, 101, '0,100,101', '财务部门', 4, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
|
|
||||||
insert into sys_dept values(107, 101, '0,100,101', '运维部门', 5, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
|
|
||||||
insert into sys_dept values(108, 102, '0,100,102', '市场部门', 1, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
|
|
||||||
insert into sys_dept values(109, 102, '0,100,102', '财务部门', 2, '若依', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
|
|
||||||
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- 2、用户信息表
|
|
||||||
-- ----------------------------
|
|
||||||
drop table if exists sys_user;
|
|
||||||
create table sys_user (
|
|
||||||
user_id bigint(20) not null auto_increment comment '用户ID',
|
|
||||||
dept_id bigint(20) default null comment '部门ID',
|
|
||||||
user_name varchar(30) not null comment '用户账号',
|
|
||||||
nick_name varchar(30) not null comment '用户昵称',
|
|
||||||
user_type varchar(2) default '00' comment '用户类型(00系统用户)',
|
|
||||||
email varchar(50) default '' comment '用户邮箱',
|
|
||||||
phonenumber varchar(11) default '' comment '手机号码',
|
|
||||||
sex char(1) default '0' comment '用户性别(0男 1女 2未知)',
|
|
||||||
avatar varchar(100) default '' comment '头像地址',
|
|
||||||
password varchar(100) default '' comment '密码',
|
|
||||||
status char(1) default '0' comment '帐号状态(0正常 1停用)',
|
|
||||||
del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)',
|
|
||||||
login_ip varchar(50) default '' comment '最后登陆IP',
|
|
||||||
login_date datetime comment '最后登陆时间',
|
|
||||||
create_by varchar(64) default '' comment '创建者',
|
|
||||||
create_time datetime comment '创建时间',
|
|
||||||
update_by varchar(64) default '' comment '更新者',
|
|
||||||
update_time datetime comment '更新时间',
|
|
||||||
remark varchar(500) default null comment '备注',
|
|
||||||
primary key (user_id)
|
|
||||||
) engine=innodb auto_increment=100 comment = '用户信息表';
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- 初始化-用户信息表数据
|
|
||||||
-- ----------------------------
|
|
||||||
insert into sys_user values(1, 103, 'admin', '若依', '00', 'ry@163.com', '15888888888', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', '2018-03-16 11-33-00', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '管理员');
|
|
||||||
insert into sys_user values(2, 105, 'ry', '若依', '00', 'ry@qq.com', '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', '2018-03-16 11-33-00', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '测试员');
|
|
||||||
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- 3、岗位信息表
|
|
||||||
-- ----------------------------
|
|
||||||
drop table if exists sys_post;
|
|
||||||
create table sys_post
|
|
||||||
(
|
|
||||||
post_id bigint(20) not null auto_increment comment '岗位ID',
|
|
||||||
post_code varchar(64) not null comment '岗位编码',
|
|
||||||
post_name varchar(50) not null comment '岗位名称',
|
|
||||||
post_sort int(4) not null comment '显示顺序',
|
|
||||||
status char(1) not null comment '状态(0正常 1停用)',
|
|
||||||
create_by varchar(64) default '' comment '创建者',
|
|
||||||
create_time datetime comment '创建时间',
|
|
||||||
update_by varchar(64) default '' comment '更新者',
|
|
||||||
update_time datetime comment '更新时间',
|
|
||||||
remark varchar(500) default null comment '备注',
|
|
||||||
primary key (post_id)
|
|
||||||
) engine=innodb comment = '岗位信息表';
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- 初始化-岗位信息表数据
|
|
||||||
-- ----------------------------
|
|
||||||
insert into sys_post values(1, 'ceo', '董事长', 1, '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_post values(2, 'se', '项目经理', 2, '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_post values(3, 'hr', '人力资源', 3, '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_post values(4, 'user', '普通员工', 4, '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- 4、角色信息表
|
|
||||||
-- ----------------------------
|
|
||||||
drop table if exists sys_role;
|
|
||||||
create table sys_role (
|
|
||||||
role_id bigint(20) not null auto_increment comment '角色ID',
|
|
||||||
role_name varchar(30) not null comment '角色名称',
|
|
||||||
role_key varchar(100) not null comment '角色权限字符串',
|
|
||||||
role_sort int(4) not null comment '显示顺序',
|
|
||||||
data_scope char(1) default '1' comment '数据范围(1:全部数据权限 2:自定数据权限 3:本部门数据权限 4:本部门及以下数据权限)',
|
|
||||||
status char(1) not null comment '角色状态(0正常 1停用)',
|
|
||||||
del_flag char(1) default '0' comment '删除标志(0代表存在 2代表删除)',
|
|
||||||
create_by varchar(64) default '' comment '创建者',
|
|
||||||
create_time datetime comment '创建时间',
|
|
||||||
update_by varchar(64) default '' comment '更新者',
|
|
||||||
update_time datetime comment '更新时间',
|
|
||||||
remark varchar(500) default null comment '备注',
|
|
||||||
primary key (role_id)
|
|
||||||
) engine=innodb auto_increment=100 comment = '角色信息表';
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- 初始化-角色信息表数据
|
|
||||||
-- ----------------------------
|
|
||||||
insert into sys_role values('1', '管理员', 'admin', 1, 1, '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '管理员');
|
|
||||||
insert into sys_role values('2', '普通角色', 'common', 2, 2, '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '普通角色');
|
|
||||||
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- 5、菜单权限表
|
|
||||||
-- ----------------------------
|
|
||||||
drop table if exists sys_menu;
|
|
||||||
create table sys_menu (
|
|
||||||
menu_id bigint(20) not null auto_increment comment '菜单ID',
|
|
||||||
menu_name varchar(50) not null comment '菜单名称',
|
|
||||||
parent_id bigint(20) default 0 comment '父菜单ID',
|
|
||||||
order_num int(4) default 0 comment '显示顺序',
|
|
||||||
path varchar(200) default '' comment '路由地址',
|
|
||||||
component varchar(255) default null comment '组件路径',
|
|
||||||
is_frame int(1) default 1 comment '是否为外链(0是 1否)',
|
|
||||||
menu_type char(1) default '' comment '菜单类型(M目录 C菜单 F按钮)',
|
|
||||||
visible char(1) default 0 comment '菜单状态(0显示 1隐藏)',
|
|
||||||
perms varchar(100) default null comment '权限标识',
|
|
||||||
icon varchar(100) default '#' comment '菜单图标',
|
|
||||||
create_by varchar(64) default '' comment '创建者',
|
|
||||||
create_time datetime comment '创建时间',
|
|
||||||
update_by varchar(64) default '' comment '更新者',
|
|
||||||
update_time datetime comment '更新时间',
|
|
||||||
remark varchar(500) default '' comment '备注',
|
|
||||||
primary key (menu_id)
|
|
||||||
) engine=innodb auto_increment=2000 comment = '菜单权限表';
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- 初始化-菜单信息表数据
|
|
||||||
-- ----------------------------
|
|
||||||
-- 一级菜单
|
|
||||||
insert into sys_menu values('1', '系统管理', '0', '1', 'system', null, 1, 'M', '0', '', 'system', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '系统管理目录');
|
|
||||||
insert into sys_menu values('2', '系统监控', '0', '2', 'monitor', null, 1, 'M', '0', '', 'monitor', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '系统监控目录');
|
|
||||||
insert into sys_menu values('3', '系统工具', '0', '3', 'tool', null, 1, 'M', '0', '', 'tool', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '系统工具目录');
|
|
||||||
insert into sys_menu values('4', '若依官网', '0', '4', 'http://ruoyi.vip', null , 0, 'M', '0', '', 'guide', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '若依官网地址');
|
|
||||||
-- 二级菜单
|
|
||||||
insert into sys_menu values('100', '用户管理', '1', '1', 'user', 'system/user/index', 1, 'C', '0', 'system:user:list', 'user', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '用户管理菜单');
|
|
||||||
insert into sys_menu values('101', '角色管理', '1', '2', 'role', 'system/role/index', 1, 'C', '0', 'system:role:list', 'peoples', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '角色管理菜单');
|
|
||||||
insert into sys_menu values('102', '菜单管理', '1', '3', 'menu', 'system/menu/index', 1, 'C', '0', 'system:menu:list', 'tree-table', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '菜单管理菜单');
|
|
||||||
insert into sys_menu values('103', '部门管理', '1', '4', 'dept', 'system/dept/index', 1, 'C', '0', 'system:dept:list', 'tree', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '部门管理菜单');
|
|
||||||
insert into sys_menu values('104', '岗位管理', '1', '5', 'post', 'system/post/index', 1, 'C', '0', 'system:post:list', 'post', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '岗位管理菜单');
|
|
||||||
insert into sys_menu values('105', '字典管理', '1', '6', 'dict', 'system/dict/index', 1, 'C', '0', 'system:dict:list', 'dict', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '字典管理菜单');
|
|
||||||
insert into sys_menu values('106', '参数设置', '1', '7', 'config', 'system/config/index', 1, 'C', '0', 'system:config:list', 'edit', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '参数设置菜单');
|
|
||||||
insert into sys_menu values('107', '通知公告', '1', '8', 'notice', 'system/notice/index', 1, 'C', '0', 'system:notice:list', 'message', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '通知公告菜单');
|
|
||||||
insert into sys_menu values('108', '日志管理', '1', '9', 'log', 'system/log/index', 1, 'M', '0', '', 'log', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '日志管理菜单');
|
|
||||||
insert into sys_menu values('109', '在线用户', '2', '1', 'online', 'monitor/online/index', 1, 'C', '0', 'monitor:online:list', 'online', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '在线用户菜单');
|
|
||||||
insert into sys_menu values('110', '定时任务', '2', '2', 'job', 'monitor/job/index', 1, 'C', '0', 'monitor:job:list', 'job', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '定时任务菜单');
|
|
||||||
insert into sys_menu values('111', '数据监控', '2', '3', 'druid', 'monitor/druid/index', 1, 'C', '0', 'monitor:druid:list', 'druid', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '数据监控菜单');
|
|
||||||
insert into sys_menu values('112', '服务监控', '2', '4', 'server', 'monitor/server/index', 1, 'C', '0', 'monitor:server:list', 'server', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '服务监控菜单');
|
|
||||||
insert into sys_menu values('113', '表单构建', '3', '1', 'build', 'tool/build/index', 1 ,'C', '0', 'tool:build:list', 'build', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '表单构建菜单');
|
|
||||||
insert into sys_menu values('114', '代码生成', '3', '2', 'gen', 'tool/gen/index', 1, 'C', '0', 'tool:gen:list', 'code', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '代码生成菜单');
|
|
||||||
insert into sys_menu values('115', '系统接口', '3', '3', 'swagger', 'tool/swagger/index', 1, 'C', '0', 'tool:swagger:list', 'swagger', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '系统接口菜单');
|
|
||||||
-- 三级菜单
|
|
||||||
insert into sys_menu values('500', '操作日志', '108', '1', 'operlog', 'monitor/operlog/index', 1, 'C', '0', 'monitor:operlog:list', 'form', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '操作日志菜单');
|
|
||||||
insert into sys_menu values('501', '登录日志', '108', '2', 'logininfor', 'monitor/logininfor/index', 1, 'C', '0', 'monitor:logininfor:list', 'logininfor', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '登录日志菜单');
|
|
||||||
-- 用户管理按钮
|
|
||||||
insert into sys_menu values('1001', '用户查询', '100', '1', '', '', 1, 'F', '0', 'system:user:query', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1002', '用户新增', '100', '2', '', '', 1, 'F', '0', 'system:user:add', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1003', '用户修改', '100', '3', '', '', 1, 'F', '0', 'system:user:edit', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1004', '用户删除', '100', '4', '', '', 1, 'F', '0', 'system:user:remove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1005', '用户导出', '100', '5', '', '', 1, 'F', '0', 'system:user:export', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1006', '用户导入', '100', '6', '', '', 1, 'F', '0', 'system:user:import', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1007', '重置密码', '100', '7', '', '', 1, 'F', '0', 'system:user:resetPwd', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
-- 角色管理按钮
|
|
||||||
insert into sys_menu values('1008', '角色查询', '101', '1', '', '', 1, 'F', '0', 'system:role:query', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1009', '角色新增', '101', '2', '', '', 1, 'F', '0', 'system:role:add', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1010', '角色修改', '101', '3', '', '', 1, 'F', '0', 'system:role:edit', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1011', '角色删除', '101', '4', '', '', 1, 'F', '0', 'system:role:remove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1012', '角色导出', '101', '5', '', '', 1, 'F', '0', 'system:role:export', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
-- 菜单管理按钮
|
|
||||||
insert into sys_menu values('1013', '菜单查询', '102', '1', '', '', 1, 'F', '0', 'system:menu:query', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1014', '菜单新增', '102', '2', '', '', 1, 'F', '0', 'system:menu:add', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1015', '菜单修改', '102', '3', '', '', 1, 'F', '0', 'system:menu:edit', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1016', '菜单删除', '102', '4', '', '', 1, 'F', '0', 'system:menu:remove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
-- 部门管理按钮
|
|
||||||
insert into sys_menu values('1017', '部门查询', '103', '1', '', '', 1, 'F', '0', 'system:dept:query', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1018', '部门新增', '103', '2', '', '', 1, 'F', '0', 'system:dept:add', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1019', '部门修改', '103', '3', '', '', 1, 'F', '0', 'system:dept:edit', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1020', '部门删除', '103', '4', '', '', 1, 'F', '0', 'system:dept:remove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
-- 岗位管理按钮
|
|
||||||
insert into sys_menu values('1021', '岗位查询', '104', '1', '', '', 1, 'F', '0', 'system:post:query', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1022', '岗位新增', '104', '2', '', '', 1, 'F', '0', 'system:post:add', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1023', '岗位修改', '104', '3', '', '', 1, 'F', '0', 'system:post:edit', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1024', '岗位删除', '104', '4', '', '', 1, 'F', '0', 'system:post:remove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1025', '岗位导出', '104', '5', '', '', 1, 'F', '0', 'system:post:export', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
-- 字典管理按钮
|
|
||||||
insert into sys_menu values('1026', '字典查询', '105', '1', '#', '', 1, 'F', '0', 'system:dict:query', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1027', '字典新增', '105', '2', '#', '', 1, 'F', '0', 'system:dict:add', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1028', '字典修改', '105', '3', '#', '', 1, 'F', '0', 'system:dict:edit', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1029', '字典删除', '105', '4', '#', '', 1, 'F', '0', 'system:dict:remove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1030', '字典导出', '105', '5', '#', '', 1, 'F', '0', 'system:dict:export', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
-- 参数设置按钮
|
|
||||||
insert into sys_menu values('1031', '参数查询', '106', '1', '#', '', 1, 'F', '0', 'system:config:query', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1032', '参数新增', '106', '2', '#', '', 1, 'F', '0', 'system:config:add', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1033', '参数修改', '106', '3', '#', '', 1, 'F', '0', 'system:config:edit', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1034', '参数删除', '106', '4', '#', '', 1, 'F', '0', 'system:config:remove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1035', '参数导出', '106', '5', '#', '', 1, 'F', '0', 'system:config:export', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
-- 通知公告按钮
|
|
||||||
insert into sys_menu values('1036', '公告查询', '107', '1', '#', '', 1, 'F', '0', 'system:notice:query', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1037', '公告新增', '107', '2', '#', '', 1, 'F', '0', 'system:notice:add', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1038', '公告修改', '107', '3', '#', '', 1, 'F', '0', 'system:notice:edit', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1039', '公告删除', '107', '4', '#', '', 1, 'F', '0', 'system:notice:remove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
-- 操作日志按钮
|
|
||||||
insert into sys_menu values('1040', '操作查询', '500', '1', '#', '', 1, 'F', '0', 'monitor:operlog:query', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1041', '操作删除', '500', '2', '#', '', 1, 'F', '0', 'monitor:operlog:remove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1042', '日志导出', '500', '4', '#', '', 1, 'F', '0', 'monitor:operlog:export', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
-- 登录日志按钮
|
|
||||||
insert into sys_menu values('1043', '登录查询', '501', '1', '#', '', 1, 'F', '0', 'monitor:logininfor:query', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1044', '登录删除', '501', '2', '#', '', 1, 'F', '0', 'monitor:logininfor:remove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1045', '日志导出', '501', '3', '#', '', 1, 'F', '0', 'monitor:logininfor:export', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
-- 在线用户按钮
|
|
||||||
insert into sys_menu values('1046', '在线查询', '109', '1', '#', '', 1, 'F', '0', 'monitor:online:query', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1047', '批量强退', '109', '2', '#', '', 1, 'F', '0', 'monitor:online:batchLogout', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1048', '单条强退', '109', '3', '#', '', 1, 'F', '0', 'monitor:online:forceLogout', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
-- 定时任务按钮
|
|
||||||
insert into sys_menu values('1049', '任务查询', '110', '1', '#', '', 1, 'F', '0', 'monitor:job:query', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1050', '任务新增', '110', '2', '#', '', 1, 'F', '0', 'monitor:job:add', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1051', '任务修改', '110', '3', '#', '', 1, 'F', '0', 'monitor:job:edit', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1052', '任务删除', '110', '4', '#', '', 1, 'F', '0', 'monitor:job:remove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1053', '状态修改', '110', '5', '#', '', 1, 'F', '0', 'monitor:job:changeStatus', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1054', '任务导出', '110', '7', '#', '', 1, 'F', '0', 'monitor:job:export', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
-- 代码生成按钮
|
|
||||||
insert into sys_menu values('1055', '生成查询', '114', '1', '#', '', 1, 'F', '0', 'tool:gen:query', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1056', '生成修改', '114', '2', '#', '', 1, 'F', '0', 'tool:gen:edit', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1057', '生成删除', '114', '3', '#', '', 1, 'F', '0', 'tool:gen:remove', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1058', '导入代码', '114', '2', '#', '', 1, 'F', '0', 'tool:gen:import', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1059', '预览代码', '114', '4', '#', '', 1, 'F', '0', 'tool:gen:preview', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_menu values('1060', '生成代码', '114', '5', '#', '', 1, 'F', '0', 'tool:gen:code', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- 6、用户和角色关联表 用户N-1角色
|
|
||||||
-- ----------------------------
|
|
||||||
drop table if exists sys_user_role;
|
|
||||||
create table sys_user_role (
|
|
||||||
user_id bigint(20) not null comment '用户ID',
|
|
||||||
role_id bigint(20) not null comment '角色ID',
|
|
||||||
primary key(user_id, role_id)
|
|
||||||
) engine=innodb comment = '用户和角色关联表';
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- 初始化-用户和角色关联表数据
|
|
||||||
-- ----------------------------
|
|
||||||
insert into sys_user_role values ('1', '1');
|
|
||||||
insert into sys_user_role values ('2', '2');
|
|
||||||
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- 7、角色和菜单关联表 角色1-N菜单
|
|
||||||
-- ----------------------------
|
|
||||||
drop table if exists sys_role_menu;
|
|
||||||
create table sys_role_menu (
|
|
||||||
role_id bigint(20) not null comment '角色ID',
|
|
||||||
menu_id bigint(20) not null comment '菜单ID',
|
|
||||||
primary key(role_id, menu_id)
|
|
||||||
) engine=innodb comment = '角色和菜单关联表';
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- 初始化-角色和菜单关联表数据
|
|
||||||
-- ----------------------------
|
|
||||||
insert into sys_role_menu values ('2', '1');
|
|
||||||
insert into sys_role_menu values ('2', '2');
|
|
||||||
insert into sys_role_menu values ('2', '3');
|
|
||||||
insert into sys_role_menu values ('2', '4');
|
|
||||||
insert into sys_role_menu values ('2', '100');
|
|
||||||
insert into sys_role_menu values ('2', '101');
|
|
||||||
insert into sys_role_menu values ('2', '102');
|
|
||||||
insert into sys_role_menu values ('2', '103');
|
|
||||||
insert into sys_role_menu values ('2', '104');
|
|
||||||
insert into sys_role_menu values ('2', '105');
|
|
||||||
insert into sys_role_menu values ('2', '106');
|
|
||||||
insert into sys_role_menu values ('2', '107');
|
|
||||||
insert into sys_role_menu values ('2', '108');
|
|
||||||
insert into sys_role_menu values ('2', '109');
|
|
||||||
insert into sys_role_menu values ('2', '110');
|
|
||||||
insert into sys_role_menu values ('2', '111');
|
|
||||||
insert into sys_role_menu values ('2', '112');
|
|
||||||
insert into sys_role_menu values ('2', '113');
|
|
||||||
insert into sys_role_menu values ('2', '114');
|
|
||||||
insert into sys_role_menu values ('2', '115');
|
|
||||||
insert into sys_role_menu values ('2', '500');
|
|
||||||
insert into sys_role_menu values ('2', '501');
|
|
||||||
insert into sys_role_menu values ('2', '1000');
|
|
||||||
insert into sys_role_menu values ('2', '1001');
|
|
||||||
insert into sys_role_menu values ('2', '1002');
|
|
||||||
insert into sys_role_menu values ('2', '1003');
|
|
||||||
insert into sys_role_menu values ('2', '1004');
|
|
||||||
insert into sys_role_menu values ('2', '1005');
|
|
||||||
insert into sys_role_menu values ('2', '1006');
|
|
||||||
insert into sys_role_menu values ('2', '1007');
|
|
||||||
insert into sys_role_menu values ('2', '1008');
|
|
||||||
insert into sys_role_menu values ('2', '1009');
|
|
||||||
insert into sys_role_menu values ('2', '1010');
|
|
||||||
insert into sys_role_menu values ('2', '1011');
|
|
||||||
insert into sys_role_menu values ('2', '1012');
|
|
||||||
insert into sys_role_menu values ('2', '1013');
|
|
||||||
insert into sys_role_menu values ('2', '1014');
|
|
||||||
insert into sys_role_menu values ('2', '1015');
|
|
||||||
insert into sys_role_menu values ('2', '1016');
|
|
||||||
insert into sys_role_menu values ('2', '1017');
|
|
||||||
insert into sys_role_menu values ('2', '1018');
|
|
||||||
insert into sys_role_menu values ('2', '1019');
|
|
||||||
insert into sys_role_menu values ('2', '1020');
|
|
||||||
insert into sys_role_menu values ('2', '1021');
|
|
||||||
insert into sys_role_menu values ('2', '1022');
|
|
||||||
insert into sys_role_menu values ('2', '1023');
|
|
||||||
insert into sys_role_menu values ('2', '1024');
|
|
||||||
insert into sys_role_menu values ('2', '1025');
|
|
||||||
insert into sys_role_menu values ('2', '1026');
|
|
||||||
insert into sys_role_menu values ('2', '1027');
|
|
||||||
insert into sys_role_menu values ('2', '1028');
|
|
||||||
insert into sys_role_menu values ('2', '1029');
|
|
||||||
insert into sys_role_menu values ('2', '1030');
|
|
||||||
insert into sys_role_menu values ('2', '1031');
|
|
||||||
insert into sys_role_menu values ('2', '1032');
|
|
||||||
insert into sys_role_menu values ('2', '1033');
|
|
||||||
insert into sys_role_menu values ('2', '1034');
|
|
||||||
insert into sys_role_menu values ('2', '1035');
|
|
||||||
insert into sys_role_menu values ('2', '1036');
|
|
||||||
insert into sys_role_menu values ('2', '1037');
|
|
||||||
insert into sys_role_menu values ('2', '1038');
|
|
||||||
insert into sys_role_menu values ('2', '1039');
|
|
||||||
insert into sys_role_menu values ('2', '1040');
|
|
||||||
insert into sys_role_menu values ('2', '1041');
|
|
||||||
insert into sys_role_menu values ('2', '1042');
|
|
||||||
insert into sys_role_menu values ('2', '1043');
|
|
||||||
insert into sys_role_menu values ('2', '1044');
|
|
||||||
insert into sys_role_menu values ('2', '1045');
|
|
||||||
insert into sys_role_menu values ('2', '1046');
|
|
||||||
insert into sys_role_menu values ('2', '1047');
|
|
||||||
insert into sys_role_menu values ('2', '1048');
|
|
||||||
insert into sys_role_menu values ('2', '1049');
|
|
||||||
insert into sys_role_menu values ('2', '1050');
|
|
||||||
insert into sys_role_menu values ('2', '1051');
|
|
||||||
insert into sys_role_menu values ('2', '1052');
|
|
||||||
insert into sys_role_menu values ('2', '1053');
|
|
||||||
insert into sys_role_menu values ('2', '1054');
|
|
||||||
insert into sys_role_menu values ('2', '1055');
|
|
||||||
insert into sys_role_menu values ('2', '1056');
|
|
||||||
insert into sys_role_menu values ('2', '1057');
|
|
||||||
insert into sys_role_menu values ('2', '1058');
|
|
||||||
insert into sys_role_menu values ('2', '1059');
|
|
||||||
insert into sys_role_menu values ('2', '1060');
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- 8、角色和部门关联表 角色1-N部门
|
|
||||||
-- ----------------------------
|
|
||||||
drop table if exists sys_role_dept;
|
|
||||||
create table sys_role_dept (
|
|
||||||
role_id bigint(20) not null comment '角色ID',
|
|
||||||
dept_id bigint(20) not null comment '部门ID',
|
|
||||||
primary key(role_id, dept_id)
|
|
||||||
) engine=innodb comment = '角色和部门关联表';
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- 初始化-角色和部门关联表数据
|
|
||||||
-- ----------------------------
|
|
||||||
insert into sys_role_dept values ('2', '100');
|
|
||||||
insert into sys_role_dept values ('2', '101');
|
|
||||||
insert into sys_role_dept values ('2', '105');
|
|
||||||
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- 9、用户与岗位关联表 用户1-N岗位
|
|
||||||
-- ----------------------------
|
|
||||||
drop table if exists sys_user_post;
|
|
||||||
create table sys_user_post
|
|
||||||
(
|
|
||||||
user_id bigint(20) not null comment '用户ID',
|
|
||||||
post_id bigint(20) not null comment '岗位ID',
|
|
||||||
primary key (user_id, post_id)
|
|
||||||
) engine=innodb comment = '用户与岗位关联表';
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- 初始化-用户与岗位关联表数据
|
|
||||||
-- ----------------------------
|
|
||||||
insert into sys_user_post values ('1', '1');
|
|
||||||
insert into sys_user_post values ('2', '2');
|
|
||||||
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- 10、操作日志记录
|
|
||||||
-- ----------------------------
|
|
||||||
drop table if exists sys_oper_log;
|
|
||||||
create table sys_oper_log (
|
|
||||||
oper_id bigint(20) not null auto_increment comment '日志主键',
|
|
||||||
title varchar(50) default '' comment '模块标题',
|
|
||||||
business_type int(2) default 0 comment '业务类型(0其它 1新增 2修改 3删除)',
|
|
||||||
method varchar(100) default '' comment '方法名称',
|
|
||||||
request_method varchar(10) default '' comment '请求方式',
|
|
||||||
operator_type int(1) default 0 comment '操作类别(0其它 1后台用户 2手机端用户)',
|
|
||||||
oper_name varchar(50) default '' comment '操作人员',
|
|
||||||
dept_name varchar(50) default '' comment '部门名称',
|
|
||||||
oper_url varchar(255) default '' comment '请求URL',
|
|
||||||
oper_ip varchar(50) default '' comment '主机地址',
|
|
||||||
oper_location varchar(255) default '' comment '操作地点',
|
|
||||||
oper_param varchar(2000) default '' comment '请求参数',
|
|
||||||
json_result varchar(2000) default '' comment '返回参数',
|
|
||||||
status int(1) default 0 comment '操作状态(0正常 1异常)',
|
|
||||||
error_msg varchar(2000) default '' comment '错误消息',
|
|
||||||
oper_time datetime comment '操作时间',
|
|
||||||
primary key (oper_id)
|
|
||||||
) engine=innodb auto_increment=100 comment = '操作日志记录';
|
|
||||||
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- 11、字典类型表
|
|
||||||
-- ----------------------------
|
|
||||||
drop table if exists sys_dict_type;
|
|
||||||
create table sys_dict_type
|
|
||||||
(
|
|
||||||
dict_id bigint(20) not null auto_increment comment '字典主键',
|
|
||||||
dict_name varchar(100) default '' comment '字典名称',
|
|
||||||
dict_type varchar(100) default '' comment '字典类型',
|
|
||||||
status char(1) default '0' comment '状态(0正常 1停用)',
|
|
||||||
create_by varchar(64) default '' comment '创建者',
|
|
||||||
create_time datetime comment '创建时间',
|
|
||||||
update_by varchar(64) default '' comment '更新者',
|
|
||||||
update_time datetime comment '更新时间',
|
|
||||||
remark varchar(500) default null comment '备注',
|
|
||||||
primary key (dict_id),
|
|
||||||
unique (dict_type)
|
|
||||||
) engine=innodb auto_increment=100 comment = '字典类型表';
|
|
||||||
|
|
||||||
insert into sys_dict_type values(1, '用户性别', 'sys_user_sex', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '用户性别列表');
|
|
||||||
insert into sys_dict_type values(2, '菜单状态', 'sys_show_hide', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '菜单状态列表');
|
|
||||||
insert into sys_dict_type values(3, '系统开关', 'sys_normal_disable', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '系统开关列表');
|
|
||||||
insert into sys_dict_type values(4, '任务状态', 'sys_job_status', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '任务状态列表');
|
|
||||||
insert into sys_dict_type values(5, '任务分组', 'sys_job_group', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '任务分组列表');
|
|
||||||
insert into sys_dict_type values(6, '系统是否', 'sys_yes_no', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '系统是否列表');
|
|
||||||
insert into sys_dict_type values(7, '通知类型', 'sys_notice_type', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '通知类型列表');
|
|
||||||
insert into sys_dict_type values(8, '通知状态', 'sys_notice_status', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '通知状态列表');
|
|
||||||
insert into sys_dict_type values(9, '操作类型', 'sys_oper_type', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '操作类型列表');
|
|
||||||
insert into sys_dict_type values(10, '系统状态', 'sys_common_status', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '登录状态列表');
|
|
||||||
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- 12、字典数据表
|
|
||||||
-- ----------------------------
|
|
||||||
drop table if exists sys_dict_data;
|
|
||||||
create table sys_dict_data
|
|
||||||
(
|
|
||||||
dict_code bigint(20) not null auto_increment comment '字典编码',
|
|
||||||
dict_sort int(4) default 0 comment '字典排序',
|
|
||||||
dict_label varchar(100) default '' comment '字典标签',
|
|
||||||
dict_value varchar(100) default '' comment '字典键值',
|
|
||||||
dict_type varchar(100) default '' comment '字典类型',
|
|
||||||
css_class varchar(100) default null comment '样式属性(其他样式扩展)',
|
|
||||||
list_class varchar(100) default null comment '表格回显样式',
|
|
||||||
is_default char(1) default 'N' comment '是否默认(Y是 N否)',
|
|
||||||
status char(1) default '0' comment '状态(0正常 1停用)',
|
|
||||||
create_by varchar(64) default '' comment '创建者',
|
|
||||||
create_time datetime comment '创建时间',
|
|
||||||
update_by varchar(64) default '' comment '更新者',
|
|
||||||
update_time datetime comment '更新时间',
|
|
||||||
remark varchar(500) default null comment '备注',
|
|
||||||
primary key (dict_code)
|
|
||||||
) engine=innodb auto_increment=100 comment = '字典数据表';
|
|
||||||
|
|
||||||
insert into sys_dict_data values(1, 1, '男', '0', 'sys_user_sex', '', '', 'Y', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '性别男');
|
|
||||||
insert into sys_dict_data values(2, 2, '女', '1', 'sys_user_sex', '', '', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '性别女');
|
|
||||||
insert into sys_dict_data values(3, 3, '未知', '2', 'sys_user_sex', '', '', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '性别未知');
|
|
||||||
insert into sys_dict_data values(4, 1, '显示', '0', 'sys_show_hide', '', 'primary', 'Y', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '显示菜单');
|
|
||||||
insert into sys_dict_data values(5, 2, '隐藏', '1', 'sys_show_hide', '', 'danger', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '隐藏菜单');
|
|
||||||
insert into sys_dict_data values(6, 1, '正常', '0', 'sys_normal_disable', '', 'primary', 'Y', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '正常状态');
|
|
||||||
insert into sys_dict_data values(7, 2, '停用', '1', 'sys_normal_disable', '', 'danger', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '停用状态');
|
|
||||||
insert into sys_dict_data values(8, 1, '正常', '0', 'sys_job_status', '', 'primary', 'Y', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '正常状态');
|
|
||||||
insert into sys_dict_data values(9, 2, '暂停', '1', 'sys_job_status', '', 'danger', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '停用状态');
|
|
||||||
insert into sys_dict_data values(10, 1, '默认', 'DEFAULT', 'sys_job_group', '', '', 'Y', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '默认分组');
|
|
||||||
insert into sys_dict_data values(11, 2, '系统', 'SYSTEM', 'sys_job_group', '', '', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '系统分组');
|
|
||||||
insert into sys_dict_data values(12, 1, '是', 'Y', 'sys_yes_no', '', 'primary', 'Y', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '系统默认是');
|
|
||||||
insert into sys_dict_data values(13, 2, '否', 'N', 'sys_yes_no', '', 'danger', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '系统默认否');
|
|
||||||
insert into sys_dict_data values(14, 1, '通知', '1', 'sys_notice_type', '', 'warning', 'Y', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '通知');
|
|
||||||
insert into sys_dict_data values(15, 2, '公告', '2', 'sys_notice_type', '', 'success', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '公告');
|
|
||||||
insert into sys_dict_data values(16, 1, '正常', '0', 'sys_notice_status', '', 'primary', 'Y', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '正常状态');
|
|
||||||
insert into sys_dict_data values(17, 2, '关闭', '1', 'sys_notice_status', '', 'danger', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '关闭状态');
|
|
||||||
insert into sys_dict_data values(18, 1, '新增', '1', 'sys_oper_type', '', 'info', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '新增操作');
|
|
||||||
insert into sys_dict_data values(19, 2, '修改', '2', 'sys_oper_type', '', 'info', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '修改操作');
|
|
||||||
insert into sys_dict_data values(20, 3, '删除', '3', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '删除操作');
|
|
||||||
insert into sys_dict_data values(21, 4, '授权', '4', 'sys_oper_type', '', 'primary', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '授权操作');
|
|
||||||
insert into sys_dict_data values(22, 5, '导出', '5', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '导出操作');
|
|
||||||
insert into sys_dict_data values(23, 6, '导入', '6', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '导入操作');
|
|
||||||
insert into sys_dict_data values(24, 7, '强退', '7', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '强退操作');
|
|
||||||
insert into sys_dict_data values(25, 8, '生成代码', '8', 'sys_oper_type', '', 'warning', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '生成操作');
|
|
||||||
insert into sys_dict_data values(26, 9, '清空数据', '9', 'sys_oper_type', '', 'danger', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '清空操作');
|
|
||||||
insert into sys_dict_data values(27, 1, '成功', '0', 'sys_common_status', '', 'primary', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '正常状态');
|
|
||||||
insert into sys_dict_data values(28, 2, '失败', '1', 'sys_common_status', '', 'danger', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '停用状态');
|
|
||||||
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- 13、参数配置表
|
|
||||||
-- ----------------------------
|
|
||||||
drop table if exists sys_config;
|
|
||||||
create table sys_config (
|
|
||||||
config_id int(5) not null auto_increment comment '参数主键',
|
|
||||||
config_name varchar(100) default '' comment '参数名称',
|
|
||||||
config_key varchar(100) default '' comment '参数键名',
|
|
||||||
config_value varchar(500) default '' comment '参数键值',
|
|
||||||
config_type char(1) default 'N' comment '系统内置(Y是 N否)',
|
|
||||||
create_by varchar(64) default '' comment '创建者',
|
|
||||||
create_time datetime comment '创建时间',
|
|
||||||
update_by varchar(64) default '' comment '更新者',
|
|
||||||
update_time datetime comment '更新时间',
|
|
||||||
remark varchar(500) default null comment '备注',
|
|
||||||
primary key (config_id)
|
|
||||||
) engine=innodb auto_increment=100 comment = '参数配置表';
|
|
||||||
|
|
||||||
insert into sys_config values(1, '主框架页-默认皮肤样式名称', 'sys.index.skinName', 'skin-blue', 'Y', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '蓝色 skin-blue、绿色 skin-green、紫色 skin-purple、红色 skin-red、黄色 skin-yellow' );
|
|
||||||
insert into sys_config values(2, '用户管理-账号初始密码', 'sys.user.initPassword', '123456', 'Y', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '初始化密码 123456' );
|
|
||||||
insert into sys_config values(3, '主框架页-侧边栏主题', 'sys.index.sideTheme', 'theme-dark', 'Y', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '深色主题theme-dark,浅色主题theme-light' );
|
|
||||||
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- 14、系统访问记录
|
|
||||||
-- ----------------------------
|
|
||||||
drop table if exists sys_logininfor;
|
|
||||||
create table sys_logininfor (
|
|
||||||
info_id bigint(20) not null auto_increment comment '访问ID',
|
|
||||||
user_name varchar(50) default '' comment '用户账号',
|
|
||||||
ipaddr varchar(50) default '' comment '登录IP地址',
|
|
||||||
login_location varchar(255) default '' comment '登录地点',
|
|
||||||
browser varchar(50) default '' comment '浏览器类型',
|
|
||||||
os varchar(50) default '' comment '操作系统',
|
|
||||||
status char(1) default '0' comment '登录状态(0成功 1失败)',
|
|
||||||
msg varchar(255) default '' comment '提示消息',
|
|
||||||
login_time datetime comment '访问时间',
|
|
||||||
primary key (info_id)
|
|
||||||
) engine=innodb auto_increment=100 comment = '系统访问记录';
|
|
||||||
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- 15、定时任务调度表
|
|
||||||
-- ----------------------------
|
|
||||||
drop table if exists sys_job;
|
|
||||||
create table sys_job (
|
|
||||||
job_id bigint(20) not null auto_increment comment '任务ID',
|
|
||||||
job_name varchar(64) default '' comment '任务名称',
|
|
||||||
job_group varchar(64) default 'DEFAULT' comment '任务组名',
|
|
||||||
invoke_target varchar(500) not null comment '调用目标字符串',
|
|
||||||
cron_expression varchar(255) default '' comment 'cron执行表达式',
|
|
||||||
misfire_policy varchar(20) default '3' comment '计划执行错误策略(1立即执行 2执行一次 3放弃执行)',
|
|
||||||
concurrent char(1) default '1' comment '是否并发执行(0允许 1禁止)',
|
|
||||||
status char(1) default '0' comment '状态(0正常 1暂停)',
|
|
||||||
create_by varchar(64) default '' comment '创建者',
|
|
||||||
create_time datetime comment '创建时间',
|
|
||||||
update_by varchar(64) default '' comment '更新者',
|
|
||||||
update_time datetime comment '更新时间',
|
|
||||||
remark varchar(500) default '' comment '备注信息',
|
|
||||||
primary key (job_id, job_name, job_group)
|
|
||||||
) engine=innodb auto_increment=100 comment = '定时任务调度表';
|
|
||||||
|
|
||||||
insert into sys_job values(1, '系统默认(无参)', 'DEFAULT', 'ryTask.ryNoParams', '0/10 * * * * ?', '3', '1', '1', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_job values(2, '系统默认(有参)', 'DEFAULT', 'ryTask.ryParams(\'ry\')', '0/15 * * * * ?', '3', '1', '1', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
insert into sys_job values(3, '系统默认(多参)', 'DEFAULT', 'ryTask.ryMultipleParams(\'ry\', true, 2000L, 316.50D, 100)', '0/20 * * * * ?', '3', '1', '1', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
|
|
||||||
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- 16、定时任务调度日志表
|
|
||||||
-- ----------------------------
|
|
||||||
drop table if exists sys_job_log;
|
|
||||||
create table sys_job_log (
|
|
||||||
job_log_id bigint(20) not null auto_increment comment '任务日志ID',
|
|
||||||
job_name varchar(64) not null comment '任务名称',
|
|
||||||
job_group varchar(64) not null comment '任务组名',
|
|
||||||
invoke_target varchar(500) not null comment '调用目标字符串',
|
|
||||||
job_message varchar(500) comment '日志信息',
|
|
||||||
status char(1) default '0' comment '执行状态(0正常 1失败)',
|
|
||||||
exception_info varchar(2000) default '' comment '异常信息',
|
|
||||||
create_time datetime comment '创建时间',
|
|
||||||
primary key (job_log_id)
|
|
||||||
) engine=innodb comment = '定时任务调度日志表';
|
|
||||||
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- 17、通知公告表
|
|
||||||
-- ----------------------------
|
|
||||||
drop table if exists sys_notice;
|
|
||||||
create table sys_notice (
|
|
||||||
notice_id int(4) not null auto_increment comment '公告ID',
|
|
||||||
notice_title varchar(50) not null comment '公告标题',
|
|
||||||
notice_type char(1) not null comment '公告类型(1通知 2公告)',
|
|
||||||
notice_content varchar(2000) default null comment '公告内容',
|
|
||||||
status char(1) default '0' comment '公告状态(0正常 1关闭)',
|
|
||||||
create_by varchar(64) default '' comment '创建者',
|
|
||||||
create_time datetime comment '创建时间',
|
|
||||||
update_by varchar(64) default '' comment '更新者',
|
|
||||||
update_time datetime comment '更新时间',
|
|
||||||
remark varchar(255) default null comment '备注',
|
|
||||||
primary key (notice_id)
|
|
||||||
) engine=innodb auto_increment=10 comment = '通知公告表';
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- 初始化-公告信息表数据
|
|
||||||
-- ----------------------------
|
|
||||||
insert into sys_notice values('1', '温馨提醒:2018-07-01 若依新版本发布啦', '2', '新版本内容', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '管理员');
|
|
||||||
insert into sys_notice values('2', '维护通知:2018-07-01 若依系统凌晨维护', '1', '维护内容', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '管理员');
|
|
||||||
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- 18、代码生成业务表
|
|
||||||
-- ----------------------------
|
|
||||||
drop table if exists gen_table;
|
|
||||||
create table gen_table (
|
|
||||||
table_id bigint(20) not null auto_increment comment '编号',
|
|
||||||
table_name varchar(200) default '' comment '表名称',
|
|
||||||
table_comment varchar(500) default '' comment '表描述',
|
|
||||||
class_name varchar(100) default '' comment '实体类名称',
|
|
||||||
tpl_category varchar(200) default 'crud' comment '使用的模板(crud单表操作 tree树表操作)',
|
|
||||||
package_name varchar(100) comment '生成包路径',
|
|
||||||
module_name varchar(30) comment '生成模块名',
|
|
||||||
business_name varchar(30) comment '生成业务名',
|
|
||||||
function_name varchar(50) comment '生成功能名',
|
|
||||||
function_author varchar(50) comment '生成功能作者',
|
|
||||||
options varchar(1000) comment '其它生成选项',
|
|
||||||
create_by varchar(64) default '' comment '创建者',
|
|
||||||
create_time datetime comment '创建时间',
|
|
||||||
update_by varchar(64) default '' comment '更新者',
|
|
||||||
update_time datetime comment '更新时间',
|
|
||||||
remark varchar(500) default null comment '备注',
|
|
||||||
primary key (table_id)
|
|
||||||
) engine=innodb auto_increment=1 comment = '代码生成业务表';
|
|
||||||
|
|
||||||
|
|
||||||
-- ----------------------------
|
|
||||||
-- 19、代码生成业务表字段
|
|
||||||
-- ----------------------------
|
|
||||||
drop table if exists gen_table_column;
|
|
||||||
create table gen_table_column (
|
|
||||||
column_id bigint(20) not null auto_increment comment '编号',
|
|
||||||
table_id varchar(64) comment '归属表编号',
|
|
||||||
column_name varchar(200) comment '列名称',
|
|
||||||
column_comment varchar(500) comment '列描述',
|
|
||||||
column_type varchar(100) comment '列类型',
|
|
||||||
java_type varchar(500) comment 'JAVA类型',
|
|
||||||
java_field varchar(200) comment 'JAVA字段名',
|
|
||||||
is_pk char(1) comment '是否主键(1是)',
|
|
||||||
is_increment char(1) comment '是否自增(1是)',
|
|
||||||
is_required char(1) comment '是否必填(1是)',
|
|
||||||
is_insert char(1) comment '是否为插入字段(1是)',
|
|
||||||
is_edit char(1) comment '是否编辑字段(1是)',
|
|
||||||
is_list char(1) comment '是否列表字段(1是)',
|
|
||||||
is_query char(1) comment '是否查询字段(1是)',
|
|
||||||
query_type varchar(200) default 'EQ' comment '查询方式(等于、不等于、大于、小于、范围)',
|
|
||||||
html_type varchar(200) comment '显示类型(文本框、文本域、下拉框、复选框、单选框、日期控件)',
|
|
||||||
dict_type varchar(200) default '' comment '字典类型',
|
|
||||||
sort int comment '排序',
|
|
||||||
create_by varchar(64) default '' comment '创建者',
|
|
||||||
create_time datetime comment '创建时间',
|
|
||||||
update_by varchar(64) default '' comment '更新者',
|
|
||||||
update_time datetime comment '更新时间',
|
|
||||||
primary key (column_id)
|
|
||||||
) engine=innodb auto_increment=1 comment = '代码生成业务表字段';
|
|
|
@ -1,30 +0,0 @@
|
||||||
package com.ruoyi;
|
|
||||||
|
|
||||||
import org.springframework.boot.SpringApplication;
|
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
|
||||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 启动程序
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
|
|
||||||
public class RuoYiApplication
|
|
||||||
{
|
|
||||||
public static void main(String[] args)
|
|
||||||
{
|
|
||||||
// System.setProperty("spring.devtools.restart.enabled", "false");
|
|
||||||
SpringApplication.run(RuoYiApplication.class, args);
|
|
||||||
System.out.println("(♥◠‿◠)ノ゙ 若依启动成功 ლ(´ڡ`ლ)゙ \n" +
|
|
||||||
" .-------. ____ __ \n" +
|
|
||||||
" | _ _ \\ \\ \\ / / \n" +
|
|
||||||
" | ( ' ) | \\ _. / ' \n" +
|
|
||||||
" |(_ o _) / _( )_ .' \n" +
|
|
||||||
" | (_,_).' __ ___(_ o _)' \n" +
|
|
||||||
" | |\\ \\ | || |(_,_)' \n" +
|
|
||||||
" | | \\ `' /| `-' / \n" +
|
|
||||||
" | | \\ / \\ / \n" +
|
|
||||||
" ''-' `'-' `-..-' ");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
package com.ruoyi;
|
|
||||||
|
|
||||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
|
||||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* web容器中进行部署
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class RuoYiServletInitializer extends SpringBootServletInitializer
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
protected SpringApplicationBuilder configure(SpringApplicationBuilder application)
|
|
||||||
{
|
|
||||||
return application.sources(RuoYiApplication.class);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,101 +0,0 @@
|
||||||
package com.ruoyi.common.constant;
|
|
||||||
|
|
||||||
import io.jsonwebtoken.Claims;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通用常量信息
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class Constants
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* UTF-8 字符集
|
|
||||||
*/
|
|
||||||
public static final String UTF8 = "UTF-8";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通用成功标识
|
|
||||||
*/
|
|
||||||
public static final String SUCCESS = "0";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通用失败标识
|
|
||||||
*/
|
|
||||||
public static final String FAIL = "1";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录成功
|
|
||||||
*/
|
|
||||||
public static final String LOGIN_SUCCESS = "Success";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 注销
|
|
||||||
*/
|
|
||||||
public static final String LOGOUT = "Logout";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录失败
|
|
||||||
*/
|
|
||||||
public static final String LOGIN_FAIL = "Error";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证码 redis key
|
|
||||||
*/
|
|
||||||
public static final String CAPTCHA_CODE_KEY = "captcha_codes:";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录用户 redis key
|
|
||||||
*/
|
|
||||||
public static final String LOGIN_TOKEN_KEY = "login_tokens:";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证码有效期(分钟)
|
|
||||||
*/
|
|
||||||
public static final Integer CAPTCHA_EXPIRATION = 2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 令牌
|
|
||||||
*/
|
|
||||||
public static final String TOKEN = "token";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 令牌前缀
|
|
||||||
*/
|
|
||||||
public static final String TOKEN_PREFIX = "Bearer ";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 令牌前缀
|
|
||||||
*/
|
|
||||||
public static final String LOGIN_USER_KEY = "login_user_key";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户ID
|
|
||||||
*/
|
|
||||||
public static final String JWT_USERID = "userid";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户名称
|
|
||||||
*/
|
|
||||||
public static final String JWT_USERNAME = Claims.SUBJECT;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户头像
|
|
||||||
*/
|
|
||||||
public static final String JWT_AVATAR = "avatar";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建时间
|
|
||||||
*/
|
|
||||||
public static final String JWT_CREATED = "created";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户权限
|
|
||||||
*/
|
|
||||||
public static final String JWT_AUTHORITIES = "authorities";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 资源映射路径 前缀
|
|
||||||
*/
|
|
||||||
public static final String RESOURCE_PREFIX = "/profile";
|
|
||||||
}
|
|
|
@ -1,94 +0,0 @@
|
||||||
package com.ruoyi.common.constant;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 代码生成通用常量
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class GenConstants
|
|
||||||
{
|
|
||||||
/** 单表(增删改查) */
|
|
||||||
public static final String TPL_CRUD = "crud";
|
|
||||||
|
|
||||||
/** 树表(增删改查) */
|
|
||||||
public static final String TPL_TREE = "tree";
|
|
||||||
|
|
||||||
/** 树编码字段 */
|
|
||||||
public static final String TREE_CODE = "treeCode";
|
|
||||||
|
|
||||||
/** 树父编码字段 */
|
|
||||||
public static final String TREE_PARENT_CODE = "treeParentCode";
|
|
||||||
|
|
||||||
/** 树名称字段 */
|
|
||||||
public static final String TREE_NAME = "treeName";
|
|
||||||
|
|
||||||
/** 数据库字符串类型 */
|
|
||||||
public static final String[] COLUMNTYPE_STR = { "char", "varchar", "narchar", "varchar2", "tinytext", "text",
|
|
||||||
"mediumtext", "longtext" };
|
|
||||||
|
|
||||||
/** 数据库时间类型 */
|
|
||||||
public static final String[] COLUMNTYPE_TIME = { "datetime", "time", "date", "timestamp" };
|
|
||||||
|
|
||||||
/** 数据库数字类型 */
|
|
||||||
public static final String[] COLUMNTYPE_NUMBER = { "tinyint", "smallint", "mediumint", "int", "number", "integer",
|
|
||||||
"bigint", "float", "float", "double", "decimal" };
|
|
||||||
|
|
||||||
/** 页面不需要编辑字段 */
|
|
||||||
public static final String[] COLUMNNAME_NOT_EDIT = { "id", "create_by", "create_time", "del_flag" };
|
|
||||||
|
|
||||||
/** 页面不需要显示的列表字段 */
|
|
||||||
public static final String[] COLUMNNAME_NOT_LIST = { "id", "create_by", "create_time", "del_flag", "update_by",
|
|
||||||
"update_time" };
|
|
||||||
|
|
||||||
/** 页面不需要查询字段 */
|
|
||||||
public static final String[] COLUMNNAME_NOT_QUERY = { "id", "create_by", "create_time", "del_flag", "update_by",
|
|
||||||
"update_time", "remark" };
|
|
||||||
|
|
||||||
/** Entity基类字段 */
|
|
||||||
public static final String[] BASE_ENTITY = { "createBy", "createTime", "updateBy", "updateTime", "remark" };
|
|
||||||
|
|
||||||
/** Tree基类字段 */
|
|
||||||
public static final String[] TREE_ENTITY = { "parentName", "parentId", "orderNum", "ancestors" };
|
|
||||||
|
|
||||||
/** 文本框 */
|
|
||||||
public static final String HTML_INPUT = "input";
|
|
||||||
|
|
||||||
/** 文本域 */
|
|
||||||
public static final String HTML_TEXTAREA = "textarea";
|
|
||||||
|
|
||||||
/** 下拉框 */
|
|
||||||
public static final String HTML_SELECT = "select";
|
|
||||||
|
|
||||||
/** 单选框 */
|
|
||||||
public static final String HTML_RADIO = "radio";
|
|
||||||
|
|
||||||
/** 复选框 */
|
|
||||||
public static final String HTML_CHECKBOX = "checkbox";
|
|
||||||
|
|
||||||
/** 日期控件 */
|
|
||||||
public static final String HTML_DATETIME = "datetime";
|
|
||||||
|
|
||||||
/** 字符串类型 */
|
|
||||||
public static final String TYPE_STRING = "String";
|
|
||||||
|
|
||||||
/** 整型 */
|
|
||||||
public static final String TYPE_INTEGER = "Integer";
|
|
||||||
|
|
||||||
/** 长整型 */
|
|
||||||
public static final String TYPE_LONG = "Long";
|
|
||||||
|
|
||||||
/** 浮点型 */
|
|
||||||
public static final String TYPE_DOUBLE = "Double";
|
|
||||||
|
|
||||||
/** 高精度计算类型 */
|
|
||||||
public static final String TYPE_BIGDECIMAL = "BigDecimal";
|
|
||||||
|
|
||||||
/** 时间类型 */
|
|
||||||
public static final String TYPE_DATE = "Date";
|
|
||||||
|
|
||||||
/** 模糊查询 */
|
|
||||||
public static final String QUERY_LIKE = "LIKE";
|
|
||||||
|
|
||||||
/** 需要 */
|
|
||||||
public static final String REQUIRE = "1";
|
|
||||||
}
|
|
|
@ -1,89 +0,0 @@
|
||||||
package com.ruoyi.common.constant;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 返回状态码
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public interface HttpStatus
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 操作成功
|
|
||||||
*/
|
|
||||||
public static final int SUCCESS = 200;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对象创建成功
|
|
||||||
*/
|
|
||||||
public static final int CREATED = 201;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 请求已经被接受
|
|
||||||
*/
|
|
||||||
public static final int ACCEPTED = 202;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 操作已经执行成功,但是没有返回数据
|
|
||||||
*/
|
|
||||||
public static final int NO_CONTENT = 204;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 资源已被移除
|
|
||||||
*/
|
|
||||||
public static final int MOVED_PERM = 301;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 重定向
|
|
||||||
*/
|
|
||||||
public static final int SEE_OTHER = 303;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 资源没有被修改
|
|
||||||
*/
|
|
||||||
public static final int NOT_MODIFIED = 304;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 参数列表错误(缺少,格式不匹配)
|
|
||||||
*/
|
|
||||||
public static final int BAD_REQUEST = 400;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 未授权
|
|
||||||
*/
|
|
||||||
public static final int UNAUTHORIZED = 401;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 访问受限,授权过期
|
|
||||||
*/
|
|
||||||
public static final int FORBIDDEN = 403;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 资源,服务未找到
|
|
||||||
*/
|
|
||||||
public static final int NOT_FOUND = 404;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 不允许的http方法
|
|
||||||
*/
|
|
||||||
public static final int BAD_METHOD = 405;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 资源冲突,或者资源被锁
|
|
||||||
*/
|
|
||||||
public static final int CONFLICT = 409;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 不支持的数据,媒体类型
|
|
||||||
*/
|
|
||||||
public static final int UNSUPPORTED_TYPE = 415;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 系统内部错误
|
|
||||||
*/
|
|
||||||
public static final int ERROR = 500;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 接口未实现
|
|
||||||
*/
|
|
||||||
public static final int NOT_IMPLEMENTED = 501;
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
package com.ruoyi.common.constant;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户常量信息
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class UserConstants
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 平台内系统用户的唯一标志
|
|
||||||
*/
|
|
||||||
public static final String SYS_USER = "SYS_USER";
|
|
||||||
|
|
||||||
/** 正常状态 */
|
|
||||||
public static final String NORMAL = "0";
|
|
||||||
|
|
||||||
/** 异常状态 */
|
|
||||||
public static final String EXCEPTION = "1";
|
|
||||||
|
|
||||||
/** 用户封禁状态 */
|
|
||||||
public static final String USER_BLOCKED = "1";
|
|
||||||
|
|
||||||
/** 角色封禁状态 */
|
|
||||||
public static final String ROLE_BLOCKED = "1";
|
|
||||||
|
|
||||||
/** 部门正常状态 */
|
|
||||||
public static final String DEPT_NORMAL = "0";
|
|
||||||
|
|
||||||
/** 字典正常状态 */
|
|
||||||
public static final String DICT_NORMAL = "0";
|
|
||||||
|
|
||||||
/** 是否为系统默认(是) */
|
|
||||||
public static final String YES = "Y";
|
|
||||||
|
|
||||||
/** 校验返回结果码 */
|
|
||||||
public final static String UNIQUE = "0";
|
|
||||||
public final static String NOT_UNIQUE = "1";
|
|
||||||
}
|
|
|
@ -1,481 +0,0 @@
|
||||||
package com.ruoyi.common.core.lang;
|
|
||||||
|
|
||||||
import java.security.MessageDigest;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.util.Random;
|
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
|
||||||
import com.ruoyi.common.exception.UtilException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 提供通用唯一识别码(universally unique identifier)(UUID)实现
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public final class UUID implements java.io.Serializable, Comparable<UUID>
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = -1185015143654744140L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SecureRandom 的单例
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private static class Holder
|
|
||||||
{
|
|
||||||
static final SecureRandom numberGenerator = getSecureRandom();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 此UUID的最高64有效位 */
|
|
||||||
private final long mostSigBits;
|
|
||||||
|
|
||||||
/** 此UUID的最低64有效位 */
|
|
||||||
private final long leastSigBits;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 私有构造
|
|
||||||
*
|
|
||||||
* @param data 数据
|
|
||||||
*/
|
|
||||||
private UUID(byte[] data)
|
|
||||||
{
|
|
||||||
long msb = 0;
|
|
||||||
long lsb = 0;
|
|
||||||
assert data.length == 16 : "data must be 16 bytes in length";
|
|
||||||
for (int i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
msb = (msb << 8) | (data[i] & 0xff);
|
|
||||||
}
|
|
||||||
for (int i = 8; i < 16; i++)
|
|
||||||
{
|
|
||||||
lsb = (lsb << 8) | (data[i] & 0xff);
|
|
||||||
}
|
|
||||||
this.mostSigBits = msb;
|
|
||||||
this.leastSigBits = lsb;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 使用指定的数据构造新的 UUID。
|
|
||||||
*
|
|
||||||
* @param mostSigBits 用于 {@code UUID} 的最高有效 64 位
|
|
||||||
* @param leastSigBits 用于 {@code UUID} 的最低有效 64 位
|
|
||||||
*/
|
|
||||||
public UUID(long mostSigBits, long leastSigBits)
|
|
||||||
{
|
|
||||||
this.mostSigBits = mostSigBits;
|
|
||||||
this.leastSigBits = leastSigBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的本地线程伪随机数生成器生成该 UUID。
|
|
||||||
*
|
|
||||||
* @return 随机生成的 {@code UUID}
|
|
||||||
*/
|
|
||||||
public static UUID fastUUID()
|
|
||||||
{
|
|
||||||
return randomUUID(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。
|
|
||||||
*
|
|
||||||
* @return 随机生成的 {@code UUID}
|
|
||||||
*/
|
|
||||||
public static UUID randomUUID()
|
|
||||||
{
|
|
||||||
return randomUUID(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。
|
|
||||||
*
|
|
||||||
* @param isSecure 是否使用{@link SecureRandom}如果是可以获得更安全的随机码,否则可以得到更好的性能
|
|
||||||
* @return 随机生成的 {@code UUID}
|
|
||||||
*/
|
|
||||||
public static UUID randomUUID(boolean isSecure)
|
|
||||||
{
|
|
||||||
final Random ng = isSecure ? Holder.numberGenerator : getRandom();
|
|
||||||
|
|
||||||
byte[] randomBytes = new byte[16];
|
|
||||||
ng.nextBytes(randomBytes);
|
|
||||||
randomBytes[6] &= 0x0f; /* clear version */
|
|
||||||
randomBytes[6] |= 0x40; /* set to version 4 */
|
|
||||||
randomBytes[8] &= 0x3f; /* clear variant */
|
|
||||||
randomBytes[8] |= 0x80; /* set to IETF variant */
|
|
||||||
return new UUID(randomBytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据指定的字节数组获取类型 3(基于名称的)UUID 的静态工厂。
|
|
||||||
*
|
|
||||||
* @param name 用于构造 UUID 的字节数组。
|
|
||||||
*
|
|
||||||
* @return 根据指定数组生成的 {@code UUID}
|
|
||||||
*/
|
|
||||||
public static UUID nameUUIDFromBytes(byte[] name)
|
|
||||||
{
|
|
||||||
MessageDigest md;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
md = MessageDigest.getInstance("MD5");
|
|
||||||
}
|
|
||||||
catch (NoSuchAlgorithmException nsae)
|
|
||||||
{
|
|
||||||
throw new InternalError("MD5 not supported");
|
|
||||||
}
|
|
||||||
byte[] md5Bytes = md.digest(name);
|
|
||||||
md5Bytes[6] &= 0x0f; /* clear version */
|
|
||||||
md5Bytes[6] |= 0x30; /* set to version 3 */
|
|
||||||
md5Bytes[8] &= 0x3f; /* clear variant */
|
|
||||||
md5Bytes[8] |= 0x80; /* set to IETF variant */
|
|
||||||
return new UUID(md5Bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据 {@link #toString()} 方法中描述的字符串标准表示形式创建{@code UUID}。
|
|
||||||
*
|
|
||||||
* @param name 指定 {@code UUID} 字符串
|
|
||||||
* @return 具有指定值的 {@code UUID}
|
|
||||||
* @throws IllegalArgumentException 如果 name 与 {@link #toString} 中描述的字符串表示形式不符抛出此异常
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static UUID fromString(String name)
|
|
||||||
{
|
|
||||||
String[] components = name.split("-");
|
|
||||||
if (components.length != 5)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("Invalid UUID string: " + name);
|
|
||||||
}
|
|
||||||
for (int i = 0; i < 5; i++)
|
|
||||||
{
|
|
||||||
components[i] = "0x" + components[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
long mostSigBits = Long.decode(components[0]).longValue();
|
|
||||||
mostSigBits <<= 16;
|
|
||||||
mostSigBits |= Long.decode(components[1]).longValue();
|
|
||||||
mostSigBits <<= 16;
|
|
||||||
mostSigBits |= Long.decode(components[2]).longValue();
|
|
||||||
|
|
||||||
long leastSigBits = Long.decode(components[3]).longValue();
|
|
||||||
leastSigBits <<= 48;
|
|
||||||
leastSigBits |= Long.decode(components[4]).longValue();
|
|
||||||
|
|
||||||
return new UUID(mostSigBits, leastSigBits);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 返回此 UUID 的 128 位值中的最低有效 64 位。
|
|
||||||
*
|
|
||||||
* @return 此 UUID 的 128 位值中的最低有效 64 位。
|
|
||||||
*/
|
|
||||||
public long getLeastSignificantBits()
|
|
||||||
{
|
|
||||||
return leastSigBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 返回此 UUID 的 128 位值中的最高有效 64 位。
|
|
||||||
*
|
|
||||||
* @return 此 UUID 的 128 位值中最高有效 64 位。
|
|
||||||
*/
|
|
||||||
public long getMostSignificantBits()
|
|
||||||
{
|
|
||||||
return mostSigBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 与此 {@code UUID} 相关联的版本号. 版本号描述此 {@code UUID} 是如何生成的。
|
|
||||||
* <p>
|
|
||||||
* 版本号具有以下含意:
|
|
||||||
* <ul>
|
|
||||||
* <li>1 基于时间的 UUID
|
|
||||||
* <li>2 DCE 安全 UUID
|
|
||||||
* <li>3 基于名称的 UUID
|
|
||||||
* <li>4 随机生成的 UUID
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @return 此 {@code UUID} 的版本号
|
|
||||||
*/
|
|
||||||
public int version()
|
|
||||||
{
|
|
||||||
// Version is bits masked by 0x000000000000F000 in MS long
|
|
||||||
return (int) ((mostSigBits >> 12) & 0x0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 与此 {@code UUID} 相关联的变体号。变体号描述 {@code UUID} 的布局。
|
|
||||||
* <p>
|
|
||||||
* 变体号具有以下含意:
|
|
||||||
* <ul>
|
|
||||||
* <li>0 为 NCS 向后兼容保留
|
|
||||||
* <li>2 <a href="http://www.ietf.org/rfc/rfc4122.txt">IETF RFC 4122</a>(Leach-Salz), 用于此类
|
|
||||||
* <li>6 保留,微软向后兼容
|
|
||||||
* <li>7 保留供以后定义使用
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @return 此 {@code UUID} 相关联的变体号
|
|
||||||
*/
|
|
||||||
public int variant()
|
|
||||||
{
|
|
||||||
// This field is composed of a varying number of bits.
|
|
||||||
// 0 - - Reserved for NCS backward compatibility
|
|
||||||
// 1 0 - The IETF aka Leach-Salz variant (used by this class)
|
|
||||||
// 1 1 0 Reserved, Microsoft backward compatibility
|
|
||||||
// 1 1 1 Reserved for future definition.
|
|
||||||
return (int) ((leastSigBits >>> (64 - (leastSigBits >>> 62))) & (leastSigBits >> 63));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 与此 UUID 相关联的时间戳值。
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* 60 位的时间戳值根据此 {@code UUID} 的 time_low、time_mid 和 time_hi 字段构造。<br>
|
|
||||||
* 所得到的时间戳以 100 毫微秒为单位,从 UTC(通用协调时间) 1582 年 10 月 15 日零时开始。
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* 时间戳值仅在在基于时间的 UUID(其 version 类型为 1)中才有意义。<br>
|
|
||||||
* 如果此 {@code UUID} 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。
|
|
||||||
*
|
|
||||||
* @throws UnsupportedOperationException 如果此 {@code UUID} 不是 version 为 1 的 UUID。
|
|
||||||
*/
|
|
||||||
public long timestamp() throws UnsupportedOperationException
|
|
||||||
{
|
|
||||||
checkTimeBase();
|
|
||||||
return (mostSigBits & 0x0FFFL) << 48//
|
|
||||||
| ((mostSigBits >> 16) & 0x0FFFFL) << 32//
|
|
||||||
| mostSigBits >>> 32;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 与此 UUID 相关联的时钟序列值。
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* 14 位的时钟序列值根据此 UUID 的 clock_seq 字段构造。clock_seq 字段用于保证在基于时间的 UUID 中的时间唯一性。
|
|
||||||
* <p>
|
|
||||||
* {@code clockSequence} 值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。 如果此 UUID 不是基于时间的 UUID,则此方法抛出
|
|
||||||
* UnsupportedOperationException。
|
|
||||||
*
|
|
||||||
* @return 此 {@code UUID} 的时钟序列
|
|
||||||
*
|
|
||||||
* @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1
|
|
||||||
*/
|
|
||||||
public int clockSequence() throws UnsupportedOperationException
|
|
||||||
{
|
|
||||||
checkTimeBase();
|
|
||||||
return (int) ((leastSigBits & 0x3FFF000000000000L) >>> 48);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 与此 UUID 相关的节点值。
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* 48 位的节点值根据此 UUID 的 node 字段构造。此字段旨在用于保存机器的 IEEE 802 地址,该地址用于生成此 UUID 以保证空间唯一性。
|
|
||||||
* <p>
|
|
||||||
* 节点值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。<br>
|
|
||||||
* 如果此 UUID 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。
|
|
||||||
*
|
|
||||||
* @return 此 {@code UUID} 的节点值
|
|
||||||
*
|
|
||||||
* @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1
|
|
||||||
*/
|
|
||||||
public long node() throws UnsupportedOperationException
|
|
||||||
{
|
|
||||||
checkTimeBase();
|
|
||||||
return leastSigBits & 0x0000FFFFFFFFFFFFL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 返回此{@code UUID} 的字符串表现形式。
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* UUID 的字符串表示形式由此 BNF 描述:
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* {@code
|
|
||||||
* UUID = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node>
|
|
||||||
* time_low = 4*<hexOctet>
|
|
||||||
* time_mid = 2*<hexOctet>
|
|
||||||
* time_high_and_version = 2*<hexOctet>
|
|
||||||
* variant_and_sequence = 2*<hexOctet>
|
|
||||||
* node = 6*<hexOctet>
|
|
||||||
* hexOctet = <hexDigit><hexDigit>
|
|
||||||
* hexDigit = [0-9a-fA-F]
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* </blockquote>
|
|
||||||
*
|
|
||||||
* @return 此{@code UUID} 的字符串表现形式
|
|
||||||
* @see #toString(boolean)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return toString(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 返回此{@code UUID} 的字符串表现形式。
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* UUID 的字符串表示形式由此 BNF 描述:
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* {@code
|
|
||||||
* UUID = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node>
|
|
||||||
* time_low = 4*<hexOctet>
|
|
||||||
* time_mid = 2*<hexOctet>
|
|
||||||
* time_high_and_version = 2*<hexOctet>
|
|
||||||
* variant_and_sequence = 2*<hexOctet>
|
|
||||||
* node = 6*<hexOctet>
|
|
||||||
* hexOctet = <hexDigit><hexDigit>
|
|
||||||
* hexDigit = [0-9a-fA-F]
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* </blockquote>
|
|
||||||
*
|
|
||||||
* @param isSimple 是否简单模式,简单模式为不带'-'的UUID字符串
|
|
||||||
* @return 此{@code UUID} 的字符串表现形式
|
|
||||||
*/
|
|
||||||
public String toString(boolean isSimple)
|
|
||||||
{
|
|
||||||
final StringBuilder builder = new StringBuilder(isSimple ? 32 : 36);
|
|
||||||
// time_low
|
|
||||||
builder.append(digits(mostSigBits >> 32, 8));
|
|
||||||
if (false == isSimple)
|
|
||||||
{
|
|
||||||
builder.append('-');
|
|
||||||
}
|
|
||||||
// time_mid
|
|
||||||
builder.append(digits(mostSigBits >> 16, 4));
|
|
||||||
if (false == isSimple)
|
|
||||||
{
|
|
||||||
builder.append('-');
|
|
||||||
}
|
|
||||||
// time_high_and_version
|
|
||||||
builder.append(digits(mostSigBits, 4));
|
|
||||||
if (false == isSimple)
|
|
||||||
{
|
|
||||||
builder.append('-');
|
|
||||||
}
|
|
||||||
// variant_and_sequence
|
|
||||||
builder.append(digits(leastSigBits >> 48, 4));
|
|
||||||
if (false == isSimple)
|
|
||||||
{
|
|
||||||
builder.append('-');
|
|
||||||
}
|
|
||||||
// node
|
|
||||||
builder.append(digits(leastSigBits, 12));
|
|
||||||
|
|
||||||
return builder.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 返回此 UUID 的哈希码。
|
|
||||||
*
|
|
||||||
* @return UUID 的哈希码值。
|
|
||||||
*/
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
long hilo = mostSigBits ^ leastSigBits;
|
|
||||||
return ((int) (hilo >> 32)) ^ (int) hilo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将此对象与指定对象比较。
|
|
||||||
* <p>
|
|
||||||
* 当且仅当参数不为 {@code null}、而是一个 UUID 对象、具有与此 UUID 相同的 varriant、包含相同的值(每一位均相同)时,结果才为 {@code true}。
|
|
||||||
*
|
|
||||||
* @param obj 要与之比较的对象
|
|
||||||
*
|
|
||||||
* @return 如果对象相同,则返回 {@code true};否则返回 {@code false}
|
|
||||||
*/
|
|
||||||
public boolean equals(Object obj)
|
|
||||||
{
|
|
||||||
if ((null == obj) || (obj.getClass() != UUID.class))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
UUID id = (UUID) obj;
|
|
||||||
return (mostSigBits == id.mostSigBits && leastSigBits == id.leastSigBits);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Comparison Operations
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将此 UUID 与指定的 UUID 比较。
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* 如果两个 UUID 不同,且第一个 UUID 的最高有效字段大于第二个 UUID 的对应字段,则第一个 UUID 大于第二个 UUID。
|
|
||||||
*
|
|
||||||
* @param val 与此 UUID 比较的 UUID
|
|
||||||
*
|
|
||||||
* @return 在此 UUID 小于、等于或大于 val 时,分别返回 -1、0 或 1。
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public int compareTo(UUID val)
|
|
||||||
{
|
|
||||||
// The ordering is intentionally set up so that the UUIDs
|
|
||||||
// can simply be numerically compared as two numbers
|
|
||||||
return (this.mostSigBits < val.mostSigBits ? -1 : //
|
|
||||||
(this.mostSigBits > val.mostSigBits ? 1 : //
|
|
||||||
(this.leastSigBits < val.leastSigBits ? -1 : //
|
|
||||||
(this.leastSigBits > val.leastSigBits ? 1 : //
|
|
||||||
0))));
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------
|
|
||||||
// Private method start
|
|
||||||
/**
|
|
||||||
* 返回指定数字对应的hex值
|
|
||||||
*
|
|
||||||
* @param val 值
|
|
||||||
* @param digits 位
|
|
||||||
* @return 值
|
|
||||||
*/
|
|
||||||
private static String digits(long val, int digits)
|
|
||||||
{
|
|
||||||
long hi = 1L << (digits * 4);
|
|
||||||
return Long.toHexString(hi | (val & (hi - 1))).substring(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查是否为time-based版本UUID
|
|
||||||
*/
|
|
||||||
private void checkTimeBase()
|
|
||||||
{
|
|
||||||
if (version() != 1)
|
|
||||||
{
|
|
||||||
throw new UnsupportedOperationException("Not a time-based UUID");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取{@link SecureRandom},类提供加密的强随机数生成器 (RNG)
|
|
||||||
*
|
|
||||||
* @return {@link SecureRandom}
|
|
||||||
*/
|
|
||||||
public static SecureRandom getSecureRandom()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return SecureRandom.getInstance("SHA1PRNG");
|
|
||||||
}
|
|
||||||
catch (NoSuchAlgorithmException e)
|
|
||||||
{
|
|
||||||
throw new UtilException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取随机数生成器对象<br>
|
|
||||||
* ThreadLocalRandom是JDK 7之后提供并发产生随机数,能够解决多个线程发生的竞争争夺。
|
|
||||||
*
|
|
||||||
* @return {@link ThreadLocalRandom}
|
|
||||||
*/
|
|
||||||
public static ThreadLocalRandom getRandom()
|
|
||||||
{
|
|
||||||
return ThreadLocalRandom.current();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,86 +0,0 @@
|
||||||
package com.ruoyi.common.core.text;
|
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 字符集工具类
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class CharsetKit
|
|
||||||
{
|
|
||||||
/** ISO-8859-1 */
|
|
||||||
public static final String ISO_8859_1 = "ISO-8859-1";
|
|
||||||
/** UTF-8 */
|
|
||||||
public static final String UTF_8 = "UTF-8";
|
|
||||||
/** GBK */
|
|
||||||
public static final String GBK = "GBK";
|
|
||||||
|
|
||||||
/** ISO-8859-1 */
|
|
||||||
public static final Charset CHARSET_ISO_8859_1 = Charset.forName(ISO_8859_1);
|
|
||||||
/** UTF-8 */
|
|
||||||
public static final Charset CHARSET_UTF_8 = Charset.forName(UTF_8);
|
|
||||||
/** GBK */
|
|
||||||
public static final Charset CHARSET_GBK = Charset.forName(GBK);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为Charset对象
|
|
||||||
*
|
|
||||||
* @param charset 字符集,为空则返回默认字符集
|
|
||||||
* @return Charset
|
|
||||||
*/
|
|
||||||
public static Charset charset(String charset)
|
|
||||||
{
|
|
||||||
return StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换字符串的字符集编码
|
|
||||||
*
|
|
||||||
* @param source 字符串
|
|
||||||
* @param srcCharset 源字符集,默认ISO-8859-1
|
|
||||||
* @param destCharset 目标字符集,默认UTF-8
|
|
||||||
* @return 转换后的字符集
|
|
||||||
*/
|
|
||||||
public static String convert(String source, String srcCharset, String destCharset)
|
|
||||||
{
|
|
||||||
return convert(source, Charset.forName(srcCharset), Charset.forName(destCharset));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换字符串的字符集编码
|
|
||||||
*
|
|
||||||
* @param source 字符串
|
|
||||||
* @param srcCharset 源字符集,默认ISO-8859-1
|
|
||||||
* @param destCharset 目标字符集,默认UTF-8
|
|
||||||
* @return 转换后的字符集
|
|
||||||
*/
|
|
||||||
public static String convert(String source, Charset srcCharset, Charset destCharset)
|
|
||||||
{
|
|
||||||
if (null == srcCharset)
|
|
||||||
{
|
|
||||||
srcCharset = StandardCharsets.ISO_8859_1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null == destCharset)
|
|
||||||
{
|
|
||||||
srcCharset = StandardCharsets.UTF_8;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StringUtils.isEmpty(source) || srcCharset.equals(destCharset))
|
|
||||||
{
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
return new String(source.getBytes(srcCharset), destCharset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return 系统字符集编码
|
|
||||||
*/
|
|
||||||
public static String systemCharset()
|
|
||||||
{
|
|
||||||
return Charset.defaultCharset().name();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,999 +0,0 @@
|
||||||
package com.ruoyi.common.core.text;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.text.NumberFormat;
|
|
||||||
import java.util.Set;
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 类型转换器
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class Convert
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 转换为字符串<br>
|
|
||||||
* 如果给定的值为null,或者转换失败,返回默认值<br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @param defaultValue 转换错误时的默认值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static String toStr(Object value, String defaultValue)
|
|
||||||
{
|
|
||||||
if (null == value)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
if (value instanceof String)
|
|
||||||
{
|
|
||||||
return (String) value;
|
|
||||||
}
|
|
||||||
return value.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为字符串<br>
|
|
||||||
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static String toStr(Object value)
|
|
||||||
{
|
|
||||||
return toStr(value, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为字符<br>
|
|
||||||
* 如果给定的值为null,或者转换失败,返回默认值<br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @param defaultValue 转换错误时的默认值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Character toChar(Object value, Character defaultValue)
|
|
||||||
{
|
|
||||||
if (null == value)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
if (value instanceof Character)
|
|
||||||
{
|
|
||||||
return (Character) value;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String valueStr = toStr(value, null);
|
|
||||||
return StringUtils.isEmpty(valueStr) ? defaultValue : valueStr.charAt(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为字符<br>
|
|
||||||
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Character toChar(Object value)
|
|
||||||
{
|
|
||||||
return toChar(value, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为byte<br>
|
|
||||||
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @param defaultValue 转换错误时的默认值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Byte toByte(Object value, Byte defaultValue)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
if (value instanceof Byte)
|
|
||||||
{
|
|
||||||
return (Byte) value;
|
|
||||||
}
|
|
||||||
if (value instanceof Number)
|
|
||||||
{
|
|
||||||
return ((Number) value).byteValue();
|
|
||||||
}
|
|
||||||
final String valueStr = toStr(value, null);
|
|
||||||
if (StringUtils.isEmpty(valueStr))
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return Byte.parseByte(valueStr);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为byte<br>
|
|
||||||
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Byte toByte(Object value)
|
|
||||||
{
|
|
||||||
return toByte(value, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为Short<br>
|
|
||||||
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @param defaultValue 转换错误时的默认值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Short toShort(Object value, Short defaultValue)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
if (value instanceof Short)
|
|
||||||
{
|
|
||||||
return (Short) value;
|
|
||||||
}
|
|
||||||
if (value instanceof Number)
|
|
||||||
{
|
|
||||||
return ((Number) value).shortValue();
|
|
||||||
}
|
|
||||||
final String valueStr = toStr(value, null);
|
|
||||||
if (StringUtils.isEmpty(valueStr))
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return Short.parseShort(valueStr.trim());
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为Short<br>
|
|
||||||
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Short toShort(Object value)
|
|
||||||
{
|
|
||||||
return toShort(value, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为Number<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @param defaultValue 转换错误时的默认值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Number toNumber(Object value, Number defaultValue)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
if (value instanceof Number)
|
|
||||||
{
|
|
||||||
return (Number) value;
|
|
||||||
}
|
|
||||||
final String valueStr = toStr(value, null);
|
|
||||||
if (StringUtils.isEmpty(valueStr))
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return NumberFormat.getInstance().parse(valueStr);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为Number<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Number toNumber(Object value)
|
|
||||||
{
|
|
||||||
return toNumber(value, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为int<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @param defaultValue 转换错误时的默认值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Integer toInt(Object value, Integer defaultValue)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
if (value instanceof Integer)
|
|
||||||
{
|
|
||||||
return (Integer) value;
|
|
||||||
}
|
|
||||||
if (value instanceof Number)
|
|
||||||
{
|
|
||||||
return ((Number) value).intValue();
|
|
||||||
}
|
|
||||||
final String valueStr = toStr(value, null);
|
|
||||||
if (StringUtils.isEmpty(valueStr))
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return Integer.parseInt(valueStr.trim());
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为int<br>
|
|
||||||
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Integer toInt(Object value)
|
|
||||||
{
|
|
||||||
return toInt(value, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为Integer数组<br>
|
|
||||||
*
|
|
||||||
* @param str 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Integer[] toIntArray(String str)
|
|
||||||
{
|
|
||||||
return toIntArray(",", str);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为Long数组<br>
|
|
||||||
*
|
|
||||||
* @param str 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Long[] toLongArray(String str)
|
|
||||||
{
|
|
||||||
return toLongArray(",", str);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为Integer数组<br>
|
|
||||||
*
|
|
||||||
* @param split 分隔符
|
|
||||||
* @param split 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Integer[] toIntArray(String split, String str)
|
|
||||||
{
|
|
||||||
if (StringUtils.isEmpty(str))
|
|
||||||
{
|
|
||||||
return new Integer[] {};
|
|
||||||
}
|
|
||||||
String[] arr = str.split(split);
|
|
||||||
final Integer[] ints = new Integer[arr.length];
|
|
||||||
for (int i = 0; i < arr.length; i++)
|
|
||||||
{
|
|
||||||
final Integer v = toInt(arr[i], 0);
|
|
||||||
ints[i] = v;
|
|
||||||
}
|
|
||||||
return ints;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为Long数组<br>
|
|
||||||
*
|
|
||||||
* @param split 分隔符
|
|
||||||
* @param str 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Long[] toLongArray(String split, String str)
|
|
||||||
{
|
|
||||||
if (StringUtils.isEmpty(str))
|
|
||||||
{
|
|
||||||
return new Long[] {};
|
|
||||||
}
|
|
||||||
String[] arr = str.split(split);
|
|
||||||
final Long[] longs = new Long[arr.length];
|
|
||||||
for (int i = 0; i < arr.length; i++)
|
|
||||||
{
|
|
||||||
final Long v = toLong(arr[i], null);
|
|
||||||
longs[i] = v;
|
|
||||||
}
|
|
||||||
return longs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为String数组<br>
|
|
||||||
*
|
|
||||||
* @param str 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static String[] toStrArray(String str)
|
|
||||||
{
|
|
||||||
return toStrArray(",", str);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为String数组<br>
|
|
||||||
*
|
|
||||||
* @param split 分隔符
|
|
||||||
* @param split 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static String[] toStrArray(String split, String str)
|
|
||||||
{
|
|
||||||
return str.split(split);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为long<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @param defaultValue 转换错误时的默认值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Long toLong(Object value, Long defaultValue)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
if (value instanceof Long)
|
|
||||||
{
|
|
||||||
return (Long) value;
|
|
||||||
}
|
|
||||||
if (value instanceof Number)
|
|
||||||
{
|
|
||||||
return ((Number) value).longValue();
|
|
||||||
}
|
|
||||||
final String valueStr = toStr(value, null);
|
|
||||||
if (StringUtils.isEmpty(valueStr))
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 支持科学计数法
|
|
||||||
return new BigDecimal(valueStr.trim()).longValue();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为long<br>
|
|
||||||
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Long toLong(Object value)
|
|
||||||
{
|
|
||||||
return toLong(value, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为double<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @param defaultValue 转换错误时的默认值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Double toDouble(Object value, Double defaultValue)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
if (value instanceof Double)
|
|
||||||
{
|
|
||||||
return (Double) value;
|
|
||||||
}
|
|
||||||
if (value instanceof Number)
|
|
||||||
{
|
|
||||||
return ((Number) value).doubleValue();
|
|
||||||
}
|
|
||||||
final String valueStr = toStr(value, null);
|
|
||||||
if (StringUtils.isEmpty(valueStr))
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 支持科学计数法
|
|
||||||
return new BigDecimal(valueStr.trim()).doubleValue();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为double<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Double toDouble(Object value)
|
|
||||||
{
|
|
||||||
return toDouble(value, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为Float<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @param defaultValue 转换错误时的默认值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Float toFloat(Object value, Float defaultValue)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
if (value instanceof Float)
|
|
||||||
{
|
|
||||||
return (Float) value;
|
|
||||||
}
|
|
||||||
if (value instanceof Number)
|
|
||||||
{
|
|
||||||
return ((Number) value).floatValue();
|
|
||||||
}
|
|
||||||
final String valueStr = toStr(value, null);
|
|
||||||
if (StringUtils.isEmpty(valueStr))
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return Float.parseFloat(valueStr.trim());
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为Float<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Float toFloat(Object value)
|
|
||||||
{
|
|
||||||
return toFloat(value, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为boolean<br>
|
|
||||||
* String支持的值为:true、false、yes、ok、no,1,0 如果给定的值为空,或者转换失败,返回默认值<br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @param defaultValue 转换错误时的默认值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Boolean toBool(Object value, Boolean defaultValue)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
if (value instanceof Boolean)
|
|
||||||
{
|
|
||||||
return (Boolean) value;
|
|
||||||
}
|
|
||||||
String valueStr = toStr(value, null);
|
|
||||||
if (StringUtils.isEmpty(valueStr))
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
valueStr = valueStr.trim().toLowerCase();
|
|
||||||
switch (valueStr)
|
|
||||||
{
|
|
||||||
case "true":
|
|
||||||
return true;
|
|
||||||
case "false":
|
|
||||||
return false;
|
|
||||||
case "yes":
|
|
||||||
return true;
|
|
||||||
case "ok":
|
|
||||||
return true;
|
|
||||||
case "no":
|
|
||||||
return false;
|
|
||||||
case "1":
|
|
||||||
return true;
|
|
||||||
case "0":
|
|
||||||
return false;
|
|
||||||
default:
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为boolean<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Boolean toBool(Object value)
|
|
||||||
{
|
|
||||||
return toBool(value, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为Enum对象<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<br>
|
|
||||||
*
|
|
||||||
* @param clazz Enum的Class
|
|
||||||
* @param value 值
|
|
||||||
* @param defaultValue 默认值
|
|
||||||
* @return Enum
|
|
||||||
*/
|
|
||||||
public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value, E defaultValue)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
if (clazz.isAssignableFrom(value.getClass()))
|
|
||||||
{
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
E myE = (E) value;
|
|
||||||
return myE;
|
|
||||||
}
|
|
||||||
final String valueStr = toStr(value, null);
|
|
||||||
if (StringUtils.isEmpty(valueStr))
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return Enum.valueOf(clazz, valueStr);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为Enum对象<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
|
|
||||||
*
|
|
||||||
* @param clazz Enum的Class
|
|
||||||
* @param value 值
|
|
||||||
* @return Enum
|
|
||||||
*/
|
|
||||||
public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value)
|
|
||||||
{
|
|
||||||
return toEnum(clazz, value, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为BigInteger<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @param defaultValue 转换错误时的默认值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static BigInteger toBigInteger(Object value, BigInteger defaultValue)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
if (value instanceof BigInteger)
|
|
||||||
{
|
|
||||||
return (BigInteger) value;
|
|
||||||
}
|
|
||||||
if (value instanceof Long)
|
|
||||||
{
|
|
||||||
return BigInteger.valueOf((Long) value);
|
|
||||||
}
|
|
||||||
final String valueStr = toStr(value, null);
|
|
||||||
if (StringUtils.isEmpty(valueStr))
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return new BigInteger(valueStr);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为BigInteger<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static BigInteger toBigInteger(Object value)
|
|
||||||
{
|
|
||||||
return toBigInteger(value, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为BigDecimal<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @param defaultValue 转换错误时的默认值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static BigDecimal toBigDecimal(Object value, BigDecimal defaultValue)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
if (value instanceof BigDecimal)
|
|
||||||
{
|
|
||||||
return (BigDecimal) value;
|
|
||||||
}
|
|
||||||
if (value instanceof Long)
|
|
||||||
{
|
|
||||||
return new BigDecimal((Long) value);
|
|
||||||
}
|
|
||||||
if (value instanceof Double)
|
|
||||||
{
|
|
||||||
return new BigDecimal((Double) value);
|
|
||||||
}
|
|
||||||
if (value instanceof Integer)
|
|
||||||
{
|
|
||||||
return new BigDecimal((Integer) value);
|
|
||||||
}
|
|
||||||
final String valueStr = toStr(value, null);
|
|
||||||
if (StringUtils.isEmpty(valueStr))
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return new BigDecimal(valueStr);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为BigDecimal<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static BigDecimal toBigDecimal(Object value)
|
|
||||||
{
|
|
||||||
return toBigDecimal(value, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将对象转为字符串<br>
|
|
||||||
* 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
|
|
||||||
*
|
|
||||||
* @param obj 对象
|
|
||||||
* @return 字符串
|
|
||||||
*/
|
|
||||||
public static String utf8Str(Object obj)
|
|
||||||
{
|
|
||||||
return str(obj, CharsetKit.CHARSET_UTF_8);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将对象转为字符串<br>
|
|
||||||
* 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
|
|
||||||
*
|
|
||||||
* @param obj 对象
|
|
||||||
* @param charsetName 字符集
|
|
||||||
* @return 字符串
|
|
||||||
*/
|
|
||||||
public static String str(Object obj, String charsetName)
|
|
||||||
{
|
|
||||||
return str(obj, Charset.forName(charsetName));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将对象转为字符串<br>
|
|
||||||
* 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
|
|
||||||
*
|
|
||||||
* @param obj 对象
|
|
||||||
* @param charset 字符集
|
|
||||||
* @return 字符串
|
|
||||||
*/
|
|
||||||
public static String str(Object obj, Charset charset)
|
|
||||||
{
|
|
||||||
if (null == obj)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj instanceof String)
|
|
||||||
{
|
|
||||||
return (String) obj;
|
|
||||||
}
|
|
||||||
else if (obj instanceof byte[] || obj instanceof Byte[])
|
|
||||||
{
|
|
||||||
return str((Byte[]) obj, charset);
|
|
||||||
}
|
|
||||||
else if (obj instanceof ByteBuffer)
|
|
||||||
{
|
|
||||||
return str((ByteBuffer) obj, charset);
|
|
||||||
}
|
|
||||||
return obj.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将byte数组转为字符串
|
|
||||||
*
|
|
||||||
* @param bytes byte数组
|
|
||||||
* @param charset 字符集
|
|
||||||
* @return 字符串
|
|
||||||
*/
|
|
||||||
public static String str(byte[] bytes, String charset)
|
|
||||||
{
|
|
||||||
return str(bytes, StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 解码字节码
|
|
||||||
*
|
|
||||||
* @param data 字符串
|
|
||||||
* @param charset 字符集,如果此字段为空,则解码的结果取决于平台
|
|
||||||
* @return 解码后的字符串
|
|
||||||
*/
|
|
||||||
public static String str(byte[] data, Charset charset)
|
|
||||||
{
|
|
||||||
if (data == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null == charset)
|
|
||||||
{
|
|
||||||
return new String(data);
|
|
||||||
}
|
|
||||||
return new String(data, charset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将编码的byteBuffer数据转换为字符串
|
|
||||||
*
|
|
||||||
* @param data 数据
|
|
||||||
* @param charset 字符集,如果为空使用当前系统字符集
|
|
||||||
* @return 字符串
|
|
||||||
*/
|
|
||||||
public static String str(ByteBuffer data, String charset)
|
|
||||||
{
|
|
||||||
if (data == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return str(data, Charset.forName(charset));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将编码的byteBuffer数据转换为字符串
|
|
||||||
*
|
|
||||||
* @param data 数据
|
|
||||||
* @param charset 字符集,如果为空使用当前系统字符集
|
|
||||||
* @return 字符串
|
|
||||||
*/
|
|
||||||
public static String str(ByteBuffer data, Charset charset)
|
|
||||||
{
|
|
||||||
if (null == charset)
|
|
||||||
{
|
|
||||||
charset = Charset.defaultCharset();
|
|
||||||
}
|
|
||||||
return charset.decode(data).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------- 全角半角转换
|
|
||||||
/**
|
|
||||||
* 半角转全角
|
|
||||||
*
|
|
||||||
* @param input String.
|
|
||||||
* @return 全角字符串.
|
|
||||||
*/
|
|
||||||
public static String toSBC(String input)
|
|
||||||
{
|
|
||||||
return toSBC(input, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 半角转全角
|
|
||||||
*
|
|
||||||
* @param input String
|
|
||||||
* @param notConvertSet 不替换的字符集合
|
|
||||||
* @return 全角字符串.
|
|
||||||
*/
|
|
||||||
public static String toSBC(String input, Set<Character> notConvertSet)
|
|
||||||
{
|
|
||||||
char c[] = input.toCharArray();
|
|
||||||
for (int i = 0; i < c.length; i++)
|
|
||||||
{
|
|
||||||
if (null != notConvertSet && notConvertSet.contains(c[i]))
|
|
||||||
{
|
|
||||||
// 跳过不替换的字符
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c[i] == ' ')
|
|
||||||
{
|
|
||||||
c[i] = '\u3000';
|
|
||||||
}
|
|
||||||
else if (c[i] < '\177')
|
|
||||||
{
|
|
||||||
c[i] = (char) (c[i] + 65248);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new String(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 全角转半角
|
|
||||||
*
|
|
||||||
* @param input String.
|
|
||||||
* @return 半角字符串
|
|
||||||
*/
|
|
||||||
public static String toDBC(String input)
|
|
||||||
{
|
|
||||||
return toDBC(input, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 替换全角为半角
|
|
||||||
*
|
|
||||||
* @param text 文本
|
|
||||||
* @param notConvertSet 不替换的字符集合
|
|
||||||
* @return 替换后的字符
|
|
||||||
*/
|
|
||||||
public static String toDBC(String text, Set<Character> notConvertSet)
|
|
||||||
{
|
|
||||||
char c[] = text.toCharArray();
|
|
||||||
for (int i = 0; i < c.length; i++)
|
|
||||||
{
|
|
||||||
if (null != notConvertSet && notConvertSet.contains(c[i]))
|
|
||||||
{
|
|
||||||
// 跳过不替换的字符
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c[i] == '\u3000')
|
|
||||||
{
|
|
||||||
c[i] = ' ';
|
|
||||||
}
|
|
||||||
else if (c[i] > '\uFF00' && c[i] < '\uFF5F')
|
|
||||||
{
|
|
||||||
c[i] = (char) (c[i] - 65248);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String returnString = new String(c);
|
|
||||||
|
|
||||||
return returnString;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 数字金额大写转换 先写个完整的然后将如零拾替换成零
|
|
||||||
*
|
|
||||||
* @param n 数字
|
|
||||||
* @return 中文大写数字
|
|
||||||
*/
|
|
||||||
public static String digitUppercase(double n)
|
|
||||||
{
|
|
||||||
String[] fraction = { "角", "分" };
|
|
||||||
String[] digit = { "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" };
|
|
||||||
String[][] unit = { { "元", "万", "亿" }, { "", "拾", "佰", "仟" } };
|
|
||||||
|
|
||||||
String head = n < 0 ? "负" : "";
|
|
||||||
n = Math.abs(n);
|
|
||||||
|
|
||||||
String s = "";
|
|
||||||
for (int i = 0; i < fraction.length; i++)
|
|
||||||
{
|
|
||||||
s += (digit[(int) (Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", "");
|
|
||||||
}
|
|
||||||
if (s.length() < 1)
|
|
||||||
{
|
|
||||||
s = "整";
|
|
||||||
}
|
|
||||||
int integerPart = (int) Math.floor(n);
|
|
||||||
|
|
||||||
for (int i = 0; i < unit[0].length && integerPart > 0; i++)
|
|
||||||
{
|
|
||||||
String p = "";
|
|
||||||
for (int j = 0; j < unit[1].length && n > 0; j++)
|
|
||||||
{
|
|
||||||
p = digit[integerPart % 10] + unit[1][j] + p;
|
|
||||||
integerPart = integerPart / 10;
|
|
||||||
}
|
|
||||||
s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s;
|
|
||||||
}
|
|
||||||
return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,92 +0,0 @@
|
||||||
package com.ruoyi.common.core.text;
|
|
||||||
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 字符串格式化
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class StrFormatter
|
|
||||||
{
|
|
||||||
public static final String EMPTY_JSON = "{}";
|
|
||||||
public static final char C_BACKSLASH = '\\';
|
|
||||||
public static final char C_DELIM_START = '{';
|
|
||||||
public static final char C_DELIM_END = '}';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 格式化字符串<br>
|
|
||||||
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
|
|
||||||
* 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
|
|
||||||
* 例:<br>
|
|
||||||
* 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br>
|
|
||||||
* 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
|
|
||||||
* 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
|
|
||||||
*
|
|
||||||
* @param strPattern 字符串模板
|
|
||||||
* @param argArray 参数列表
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static String format(final String strPattern, final Object... argArray)
|
|
||||||
{
|
|
||||||
if (StringUtils.isEmpty(strPattern) || StringUtils.isEmpty(argArray))
|
|
||||||
{
|
|
||||||
return strPattern;
|
|
||||||
}
|
|
||||||
final int strPatternLength = strPattern.length();
|
|
||||||
|
|
||||||
// 初始化定义好的长度以获得更好的性能
|
|
||||||
StringBuilder sbuf = new StringBuilder(strPatternLength + 50);
|
|
||||||
|
|
||||||
int handledPosition = 0;
|
|
||||||
int delimIndex;// 占位符所在位置
|
|
||||||
for (int argIndex = 0; argIndex < argArray.length; argIndex++)
|
|
||||||
{
|
|
||||||
delimIndex = strPattern.indexOf(EMPTY_JSON, handledPosition);
|
|
||||||
if (delimIndex == -1)
|
|
||||||
{
|
|
||||||
if (handledPosition == 0)
|
|
||||||
{
|
|
||||||
return strPattern;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ // 字符串模板剩余部分不再包含占位符,加入剩余部分后返回结果
|
|
||||||
sbuf.append(strPattern, handledPosition, strPatternLength);
|
|
||||||
return sbuf.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (delimIndex > 0 && strPattern.charAt(delimIndex - 1) == C_BACKSLASH)
|
|
||||||
{
|
|
||||||
if (delimIndex > 1 && strPattern.charAt(delimIndex - 2) == C_BACKSLASH)
|
|
||||||
{
|
|
||||||
// 转义符之前还有一个转义符,占位符依旧有效
|
|
||||||
sbuf.append(strPattern, handledPosition, delimIndex - 1);
|
|
||||||
sbuf.append(Convert.utf8Str(argArray[argIndex]));
|
|
||||||
handledPosition = delimIndex + 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 占位符被转义
|
|
||||||
argIndex--;
|
|
||||||
sbuf.append(strPattern, handledPosition, delimIndex - 1);
|
|
||||||
sbuf.append(C_DELIM_START);
|
|
||||||
handledPosition = delimIndex + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 正常占位符
|
|
||||||
sbuf.append(strPattern, handledPosition, delimIndex);
|
|
||||||
sbuf.append(Convert.utf8Str(argArray[argIndex]));
|
|
||||||
handledPosition = delimIndex + 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 加入最后一个占位符后所有的字符
|
|
||||||
sbuf.append(strPattern, handledPosition, strPattern.length());
|
|
||||||
|
|
||||||
return sbuf.toString();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
package com.ruoyi.common.enums;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import org.springframework.lang.Nullable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 请求方式
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public enum HttpMethod
|
|
||||||
{
|
|
||||||
GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE;
|
|
||||||
|
|
||||||
private static final Map<String, HttpMethod> mappings = new HashMap<>(16);
|
|
||||||
|
|
||||||
static
|
|
||||||
{
|
|
||||||
for (HttpMethod httpMethod : values())
|
|
||||||
{
|
|
||||||
mappings.put(httpMethod.name(), httpMethod);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static HttpMethod resolve(@Nullable String method)
|
|
||||||
{
|
|
||||||
return (method != null ? mappings.get(method) : null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean matches(String method)
|
|
||||||
{
|
|
||||||
return (this == resolve(method));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
package com.ruoyi.common.enums;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户状态
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public enum UserStatus
|
|
||||||
{
|
|
||||||
OK("0", "正常"), DISABLE("1", "停用"), DELETED("2", "删除");
|
|
||||||
|
|
||||||
private final String code;
|
|
||||||
private final String info;
|
|
||||||
|
|
||||||
UserStatus(String code, String info)
|
|
||||||
{
|
|
||||||
this.code = code;
|
|
||||||
this.info = info;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCode()
|
|
||||||
{
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getInfo()
|
|
||||||
{
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,97 +0,0 @@
|
||||||
package com.ruoyi.common.exception;
|
|
||||||
|
|
||||||
import com.ruoyi.common.utils.MessageUtils;
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 基础异常
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class BaseException extends RuntimeException
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 所属模块
|
|
||||||
*/
|
|
||||||
private String module;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 错误码
|
|
||||||
*/
|
|
||||||
private String code;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 错误码对应的参数
|
|
||||||
*/
|
|
||||||
private Object[] args;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 错误消息
|
|
||||||
*/
|
|
||||||
private String defaultMessage;
|
|
||||||
|
|
||||||
public BaseException(String module, String code, Object[] args, String defaultMessage)
|
|
||||||
{
|
|
||||||
this.module = module;
|
|
||||||
this.code = code;
|
|
||||||
this.args = args;
|
|
||||||
this.defaultMessage = defaultMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
public BaseException(String module, String code, Object[] args)
|
|
||||||
{
|
|
||||||
this(module, code, args, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BaseException(String module, String defaultMessage)
|
|
||||||
{
|
|
||||||
this(module, null, null, defaultMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BaseException(String code, Object[] args)
|
|
||||||
{
|
|
||||||
this(null, code, args, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BaseException(String defaultMessage)
|
|
||||||
{
|
|
||||||
this(null, null, null, defaultMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getMessage()
|
|
||||||
{
|
|
||||||
String message = null;
|
|
||||||
if (!StringUtils.isEmpty(code))
|
|
||||||
{
|
|
||||||
message = MessageUtils.message(code, args);
|
|
||||||
}
|
|
||||||
if (message == null)
|
|
||||||
{
|
|
||||||
message = defaultMessage;
|
|
||||||
}
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getModule()
|
|
||||||
{
|
|
||||||
return module;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCode()
|
|
||||||
{
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object[] getArgs()
|
|
||||||
{
|
|
||||||
return args;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDefaultMessage()
|
|
||||||
{
|
|
||||||
return defaultMessage;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
package com.ruoyi.common.exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 自定义异常
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class CustomException extends RuntimeException
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private Integer code;
|
|
||||||
|
|
||||||
private String message;
|
|
||||||
|
|
||||||
public CustomException(String message)
|
|
||||||
{
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CustomException(String message, Integer code)
|
|
||||||
{
|
|
||||||
this.message = message;
|
|
||||||
this.code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
public CustomException(String message, Throwable e)
|
|
||||||
{
|
|
||||||
super(message, e);
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getMessage()
|
|
||||||
{
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getCode()
|
|
||||||
{
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
package com.ruoyi.common.exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 演示模式异常
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class DemoModeException extends RuntimeException
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
public DemoModeException()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
package com.ruoyi.common.exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 工具类异常
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class UtilException extends RuntimeException
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 8247610319171014183L;
|
|
||||||
|
|
||||||
public UtilException(Throwable e)
|
|
||||||
{
|
|
||||||
super(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UtilException(String message)
|
|
||||||
{
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public UtilException(String message, Throwable throwable)
|
|
||||||
{
|
|
||||||
super(message, throwable);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
package com.ruoyi.common.exception.file;
|
|
||||||
|
|
||||||
import com.ruoyi.common.exception.BaseException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件信息异常类
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class FileException extends BaseException
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
public FileException(String code, Object[] args)
|
|
||||||
{
|
|
||||||
super("file", code, args, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
package com.ruoyi.common.exception.file;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件名称超长限制异常类
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class FileNameLengthLimitExceededException extends FileException
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
public FileNameLengthLimitExceededException(int defaultFileNameLength)
|
|
||||||
{
|
|
||||||
super("upload.filename.exceed.length", new Object[] { defaultFileNameLength });
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
package com.ruoyi.common.exception.file;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件名大小限制异常类
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class FileSizeLimitExceededException extends FileException
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
public FileSizeLimitExceededException(long defaultMaxSize)
|
|
||||||
{
|
|
||||||
super("upload.exceed.maxSize", new Object[] { defaultMaxSize });
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,71 +0,0 @@
|
||||||
package com.ruoyi.common.exception.file;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import org.apache.commons.fileupload.FileUploadException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件上传 误异常类
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class InvalidExtensionException extends FileUploadException
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private String[] allowedExtension;
|
|
||||||
private String extension;
|
|
||||||
private String filename;
|
|
||||||
|
|
||||||
public InvalidExtensionException(String[] allowedExtension, String extension, String filename)
|
|
||||||
{
|
|
||||||
super("filename : [" + filename + "], extension : [" + extension + "], allowed extension : [" + Arrays.toString(allowedExtension) + "]");
|
|
||||||
this.allowedExtension = allowedExtension;
|
|
||||||
this.extension = extension;
|
|
||||||
this.filename = filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getAllowedExtension()
|
|
||||||
{
|
|
||||||
return allowedExtension;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getExtension()
|
|
||||||
{
|
|
||||||
return extension;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFilename()
|
|
||||||
{
|
|
||||||
return filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class InvalidImageExtensionException extends InvalidExtensionException
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
public InvalidImageExtensionException(String[] allowedExtension, String extension, String filename)
|
|
||||||
{
|
|
||||||
super(allowedExtension, extension, filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class InvalidFlashExtensionException extends InvalidExtensionException
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
public InvalidFlashExtensionException(String[] allowedExtension, String extension, String filename)
|
|
||||||
{
|
|
||||||
super(allowedExtension, extension, filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class InvalidMediaExtensionException extends InvalidExtensionException
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
public InvalidMediaExtensionException(String[] allowedExtension, String extension, String filename)
|
|
||||||
{
|
|
||||||
super(allowedExtension, extension, filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
package com.ruoyi.common.exception.user;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证码错误异常类
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class CaptchaException extends UserException
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
public CaptchaException()
|
|
||||||
{
|
|
||||||
super("user.jcaptcha.error", null);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
package com.ruoyi.common.exception.user;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证码失效异常类
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class CaptchaExpireException extends UserException
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
public CaptchaExpireException()
|
|
||||||
{
|
|
||||||
super("user.jcaptcha.expire", null);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
package com.ruoyi.common.exception.user;
|
|
||||||
|
|
||||||
import com.ruoyi.common.exception.BaseException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户信息异常类
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class UserException extends BaseException
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
public UserException(String code, Object[] args)
|
|
||||||
{
|
|
||||||
super("user", code, args, null);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
package com.ruoyi.common.exception.user;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户密码不正确或不符合规范异常类
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class UserPasswordNotMatchException extends UserException
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
public UserPasswordNotMatchException()
|
|
||||||
{
|
|
||||||
super("user.password.not.match", null);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,114 +0,0 @@
|
||||||
package com.ruoyi.common.utils;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.math.RoundingMode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 精确的浮点数运算
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class Arith
|
|
||||||
{
|
|
||||||
|
|
||||||
/** 默认除法运算精度 */
|
|
||||||
private static final int DEF_DIV_SCALE = 10;
|
|
||||||
|
|
||||||
/** 这个类不能实例化 */
|
|
||||||
private Arith()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 提供精确的加法运算。
|
|
||||||
* @param v1 被加数
|
|
||||||
* @param v2 加数
|
|
||||||
* @return 两个参数的和
|
|
||||||
*/
|
|
||||||
public static double add(double v1, double v2)
|
|
||||||
{
|
|
||||||
BigDecimal b1 = new BigDecimal(Double.toString(v1));
|
|
||||||
BigDecimal b2 = new BigDecimal(Double.toString(v2));
|
|
||||||
return b1.add(b2).doubleValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 提供精确的减法运算。
|
|
||||||
* @param v1 被减数
|
|
||||||
* @param v2 减数
|
|
||||||
* @return 两个参数的差
|
|
||||||
*/
|
|
||||||
public static double sub(double v1, double v2)
|
|
||||||
{
|
|
||||||
BigDecimal b1 = new BigDecimal(Double.toString(v1));
|
|
||||||
BigDecimal b2 = new BigDecimal(Double.toString(v2));
|
|
||||||
return b1.subtract(b2).doubleValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 提供精确的乘法运算。
|
|
||||||
* @param v1 被乘数
|
|
||||||
* @param v2 乘数
|
|
||||||
* @return 两个参数的积
|
|
||||||
*/
|
|
||||||
public static double mul(double v1, double v2)
|
|
||||||
{
|
|
||||||
BigDecimal b1 = new BigDecimal(Double.toString(v1));
|
|
||||||
BigDecimal b2 = new BigDecimal(Double.toString(v2));
|
|
||||||
return b1.multiply(b2).doubleValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到
|
|
||||||
* 小数点以后10位,以后的数字四舍五入。
|
|
||||||
* @param v1 被除数
|
|
||||||
* @param v2 除数
|
|
||||||
* @return 两个参数的商
|
|
||||||
*/
|
|
||||||
public static double div(double v1, double v2)
|
|
||||||
{
|
|
||||||
return div(v1, v2, DEF_DIV_SCALE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
|
|
||||||
* 定精度,以后的数字四舍五入。
|
|
||||||
* @param v1 被除数
|
|
||||||
* @param v2 除数
|
|
||||||
* @param scale 表示表示需要精确到小数点以后几位。
|
|
||||||
* @return 两个参数的商
|
|
||||||
*/
|
|
||||||
public static double div(double v1, double v2, int scale)
|
|
||||||
{
|
|
||||||
if (scale < 0)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"The scale must be a positive integer or zero");
|
|
||||||
}
|
|
||||||
BigDecimal b1 = new BigDecimal(Double.toString(v1));
|
|
||||||
BigDecimal b2 = new BigDecimal(Double.toString(v2));
|
|
||||||
if (b1.compareTo(BigDecimal.ZERO) == 0)
|
|
||||||
{
|
|
||||||
return BigDecimal.ZERO.doubleValue();
|
|
||||||
}
|
|
||||||
return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 提供精确的小数位四舍五入处理。
|
|
||||||
* @param v 需要四舍五入的数字
|
|
||||||
* @param scale 小数点后保留几位
|
|
||||||
* @return 四舍五入后的结果
|
|
||||||
*/
|
|
||||||
public static double round(double v, int scale)
|
|
||||||
{
|
|
||||||
if (scale < 0)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"The scale must be a positive integer or zero");
|
|
||||||
}
|
|
||||||
BigDecimal b = new BigDecimal(Double.toString(v));
|
|
||||||
BigDecimal one = new BigDecimal("1");
|
|
||||||
return b.divide(one, scale, RoundingMode.HALF_UP).doubleValue();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,155 +0,0 @@
|
||||||
package com.ruoyi.common.utils;
|
|
||||||
|
|
||||||
import java.lang.management.ManagementFactory;
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
import org.apache.commons.lang3.time.DateFormatUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 时间工具类
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class DateUtils extends org.apache.commons.lang3.time.DateUtils
|
|
||||||
{
|
|
||||||
public static String YYYY = "yyyy";
|
|
||||||
|
|
||||||
public static String YYYY_MM = "yyyy-MM";
|
|
||||||
|
|
||||||
public static String YYYY_MM_DD = "yyyy-MM-dd";
|
|
||||||
|
|
||||||
public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
|
|
||||||
|
|
||||||
public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
|
|
||||||
|
|
||||||
private static String[] parsePatterns = {
|
|
||||||
"yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
|
|
||||||
"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
|
|
||||||
"yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取当前Date型日期
|
|
||||||
*
|
|
||||||
* @return Date() 当前日期
|
|
||||||
*/
|
|
||||||
public static Date getNowDate()
|
|
||||||
{
|
|
||||||
return new Date();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取当前日期, 默认格式为yyyy-MM-dd
|
|
||||||
*
|
|
||||||
* @return String
|
|
||||||
*/
|
|
||||||
public static String getDate()
|
|
||||||
{
|
|
||||||
return dateTimeNow(YYYY_MM_DD);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String getTime()
|
|
||||||
{
|
|
||||||
return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String dateTimeNow()
|
|
||||||
{
|
|
||||||
return dateTimeNow(YYYYMMDDHHMMSS);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String dateTimeNow(final String format)
|
|
||||||
{
|
|
||||||
return parseDateToStr(format, new Date());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String dateTime(final Date date)
|
|
||||||
{
|
|
||||||
return parseDateToStr(YYYY_MM_DD, date);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String parseDateToStr(final String format, final Date date)
|
|
||||||
{
|
|
||||||
return new SimpleDateFormat(format).format(date);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final Date dateTime(final String format, final String ts)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return new SimpleDateFormat(format).parse(ts);
|
|
||||||
}
|
|
||||||
catch (ParseException e)
|
|
||||||
{
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 日期路径 即年/月/日 如2018/08/08
|
|
||||||
*/
|
|
||||||
public static final String datePath()
|
|
||||||
{
|
|
||||||
Date now = new Date();
|
|
||||||
return DateFormatUtils.format(now, "yyyy/MM/dd");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 日期路径 即年/月/日 如20180808
|
|
||||||
*/
|
|
||||||
public static final String dateTime()
|
|
||||||
{
|
|
||||||
Date now = new Date();
|
|
||||||
return DateFormatUtils.format(now, "yyyyMMdd");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 日期型字符串转化为日期 格式
|
|
||||||
*/
|
|
||||||
public static Date parseDate(Object str)
|
|
||||||
{
|
|
||||||
if (str == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return parseDate(str.toString(), parsePatterns);
|
|
||||||
}
|
|
||||||
catch (ParseException e)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取服务器启动时间
|
|
||||||
*/
|
|
||||||
public static Date getServerStartDate()
|
|
||||||
{
|
|
||||||
long time = ManagementFactory.getRuntimeMXBean().getStartTime();
|
|
||||||
return new Date(time);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 计算两个时间差
|
|
||||||
*/
|
|
||||||
public static String getDatePoor(Date endDate, Date nowDate)
|
|
||||||
{
|
|
||||||
long nd = 1000 * 24 * 60 * 60;
|
|
||||||
long nh = 1000 * 60 * 60;
|
|
||||||
long nm = 1000 * 60;
|
|
||||||
// long ns = 1000;
|
|
||||||
// 获得两个时间的毫秒时间差异
|
|
||||||
long diff = endDate.getTime() - nowDate.getTime();
|
|
||||||
// 计算差多少天
|
|
||||||
long day = diff / nd;
|
|
||||||
// 计算差多少小时
|
|
||||||
long hour = diff % nd / nh;
|
|
||||||
// 计算差多少分钟
|
|
||||||
long min = diff % nd % nh / nm;
|
|
||||||
// 计算差多少秒//输出结果
|
|
||||||
// long sec = diff % nd % nh % nm / ns;
|
|
||||||
return day + "天" + hour + "小时" + min + "分钟";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
package com.ruoyi.common.utils;
|
|
||||||
|
|
||||||
import com.ruoyi.common.core.lang.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ID生成器工具类
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class IdUtils
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 获取随机UUID
|
|
||||||
*
|
|
||||||
* @return 随机UUID
|
|
||||||
*/
|
|
||||||
public static String randomUUID()
|
|
||||||
{
|
|
||||||
return UUID.randomUUID().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 简化的UUID,去掉了横线
|
|
||||||
*
|
|
||||||
* @return 简化的UUID,去掉了横线
|
|
||||||
*/
|
|
||||||
public static String simpleUUID()
|
|
||||||
{
|
|
||||||
return UUID.randomUUID().toString(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取随机UUID,使用性能更好的ThreadLocalRandom生成UUID
|
|
||||||
*
|
|
||||||
* @return 随机UUID
|
|
||||||
*/
|
|
||||||
public static String fastUUID()
|
|
||||||
{
|
|
||||||
return UUID.fastUUID().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 简化的UUID,去掉了横线,使用性能更好的ThreadLocalRandom生成UUID
|
|
||||||
*
|
|
||||||
* @return 简化的UUID,去掉了横线
|
|
||||||
*/
|
|
||||||
public static String fastSimpleUUID()
|
|
||||||
{
|
|
||||||
return UUID.fastUUID().toString(true);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
package com.ruoyi.common.utils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理并记录日志文件
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class LogUtils
|
|
||||||
{
|
|
||||||
public static String getBlock(Object msg)
|
|
||||||
{
|
|
||||||
if (msg == null)
|
|
||||||
{
|
|
||||||
msg = "";
|
|
||||||
}
|
|
||||||
return "[" + msg.toString() + "]";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
package com.ruoyi.common.utils;
|
|
||||||
|
|
||||||
import org.springframework.context.MessageSource;
|
|
||||||
import org.springframework.context.i18n.LocaleContextHolder;
|
|
||||||
import com.ruoyi.common.utils.spring.SpringUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取i18n资源文件
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class MessageUtils
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 根据消息键和参数 获取消息 委托给spring messageSource
|
|
||||||
*
|
|
||||||
* @param code 消息键
|
|
||||||
* @param args 参数
|
|
||||||
* @return 获取国际化翻译值
|
|
||||||
*/
|
|
||||||
public static String message(String code, Object... args)
|
|
||||||
{
|
|
||||||
MessageSource messageSource = SpringUtils.getBean(MessageSource.class);
|
|
||||||
return messageSource.getMessage(code, args, LocaleContextHolder.getLocale());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,90 +0,0 @@
|
||||||
package com.ruoyi.common.utils;
|
|
||||||
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
|
||||||
import com.ruoyi.common.constant.HttpStatus;
|
|
||||||
import com.ruoyi.common.exception.CustomException;
|
|
||||||
import com.ruoyi.framework.security.LoginUser;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 安全服务工具类
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class SecurityUtils
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 获取用户账户
|
|
||||||
**/
|
|
||||||
public static String getUsername()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return getLoginUser().getUsername();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
throw new CustomException("获取用户账户异常", HttpStatus.UNAUTHORIZED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取用户
|
|
||||||
**/
|
|
||||||
public static LoginUser getLoginUser()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return (LoginUser) getAuthentication().getPrincipal();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
throw new CustomException("获取用户信息异常", HttpStatus.UNAUTHORIZED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取Authentication
|
|
||||||
*/
|
|
||||||
public static Authentication getAuthentication()
|
|
||||||
{
|
|
||||||
return SecurityContextHolder.getContext().getAuthentication();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成BCryptPasswordEncoder密码
|
|
||||||
*
|
|
||||||
* @param password 密码
|
|
||||||
* @return 加密字符串
|
|
||||||
*/
|
|
||||||
public static String encryptPassword(String password)
|
|
||||||
{
|
|
||||||
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
|
||||||
return passwordEncoder.encode(password);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断密码是否相同
|
|
||||||
*
|
|
||||||
* @param rawPassword 真实密码
|
|
||||||
* @param encodedPassword 加密后字符
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static boolean matchesPassword(String rawPassword, String encodedPassword)
|
|
||||||
{
|
|
||||||
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
|
||||||
return passwordEncoder.matches(rawPassword, encodedPassword);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否为管理员
|
|
||||||
*
|
|
||||||
* @param userId 用户ID
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static boolean isAdmin(Long userId)
|
|
||||||
{
|
|
||||||
return userId != null && 1L == userId;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,136 +0,0 @@
|
||||||
package com.ruoyi.common.utils;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import javax.servlet.http.HttpSession;
|
|
||||||
import org.springframework.web.context.request.RequestAttributes;
|
|
||||||
import org.springframework.web.context.request.RequestContextHolder;
|
|
||||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
|
||||||
import com.ruoyi.common.core.text.Convert;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 客户端工具类
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class ServletUtils
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 获取String参数
|
|
||||||
*/
|
|
||||||
public static String getParameter(String name)
|
|
||||||
{
|
|
||||||
return getRequest().getParameter(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取String参数
|
|
||||||
*/
|
|
||||||
public static String getParameter(String name, String defaultValue)
|
|
||||||
{
|
|
||||||
return Convert.toStr(getRequest().getParameter(name), defaultValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取Integer参数
|
|
||||||
*/
|
|
||||||
public static Integer getParameterToInt(String name)
|
|
||||||
{
|
|
||||||
return Convert.toInt(getRequest().getParameter(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取Integer参数
|
|
||||||
*/
|
|
||||||
public static Integer getParameterToInt(String name, Integer defaultValue)
|
|
||||||
{
|
|
||||||
return Convert.toInt(getRequest().getParameter(name), defaultValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取request
|
|
||||||
*/
|
|
||||||
public static HttpServletRequest getRequest()
|
|
||||||
{
|
|
||||||
return getRequestAttributes().getRequest();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取response
|
|
||||||
*/
|
|
||||||
public static HttpServletResponse getResponse()
|
|
||||||
{
|
|
||||||
return getRequestAttributes().getResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取session
|
|
||||||
*/
|
|
||||||
public static HttpSession getSession()
|
|
||||||
{
|
|
||||||
return getRequest().getSession();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ServletRequestAttributes getRequestAttributes()
|
|
||||||
{
|
|
||||||
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
|
|
||||||
return (ServletRequestAttributes) attributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将字符串渲染到客户端
|
|
||||||
*
|
|
||||||
* @param response 渲染对象
|
|
||||||
* @param string 待渲染的字符串
|
|
||||||
* @return null
|
|
||||||
*/
|
|
||||||
public static String renderString(HttpServletResponse response, String string)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
response.setStatus(200);
|
|
||||||
response.setContentType("application/json");
|
|
||||||
response.setCharacterEncoding("utf-8");
|
|
||||||
response.getWriter().print(string);
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否是Ajax异步请求
|
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
*/
|
|
||||||
public static boolean isAjaxRequest(HttpServletRequest request)
|
|
||||||
{
|
|
||||||
String accept = request.getHeader("accept");
|
|
||||||
if (accept != null && accept.indexOf("application/json") != -1)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
String xRequestedWith = request.getHeader("X-Requested-With");
|
|
||||||
if (xRequestedWith != null && xRequestedWith.indexOf("XMLHttpRequest") != -1)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
String uri = request.getRequestURI();
|
|
||||||
if (StringUtils.inStringIgnoreCase(uri, ".json", ".xml"))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
String ajax = request.getParameter("__ajax");
|
|
||||||
if (StringUtils.inStringIgnoreCase(ajax, "json", "xml"))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,453 +0,0 @@
|
||||||
package com.ruoyi.common.utils;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import com.ruoyi.common.core.text.StrFormatter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 字符串工具类
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class StringUtils extends org.apache.commons.lang3.StringUtils
|
|
||||||
{
|
|
||||||
/** 空字符串 */
|
|
||||||
private static final String NULLSTR = "";
|
|
||||||
|
|
||||||
/** 下划线 */
|
|
||||||
private static final char SEPARATOR = '_';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取参数不为空值
|
|
||||||
*
|
|
||||||
* @param value defaultValue 要判断的value
|
|
||||||
* @return value 返回值
|
|
||||||
*/
|
|
||||||
public static <T> T nvl(T value, T defaultValue)
|
|
||||||
{
|
|
||||||
return value != null ? value : defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* * 判断一个Collection是否为空, 包含List,Set,Queue
|
|
||||||
*
|
|
||||||
* @param coll 要判断的Collection
|
|
||||||
* @return true:为空 false:非空
|
|
||||||
*/
|
|
||||||
public static boolean isEmpty(Collection<?> coll)
|
|
||||||
{
|
|
||||||
return isNull(coll) || coll.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* * 判断一个Collection是否非空,包含List,Set,Queue
|
|
||||||
*
|
|
||||||
* @param coll 要判断的Collection
|
|
||||||
* @return true:非空 false:空
|
|
||||||
*/
|
|
||||||
public static boolean isNotEmpty(Collection<?> coll)
|
|
||||||
{
|
|
||||||
return !isEmpty(coll);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* * 判断一个对象数组是否为空
|
|
||||||
*
|
|
||||||
* @param objects 要判断的对象数组
|
|
||||||
** @return true:为空 false:非空
|
|
||||||
*/
|
|
||||||
public static boolean isEmpty(Object[] objects)
|
|
||||||
{
|
|
||||||
return isNull(objects) || (objects.length == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* * 判断一个对象数组是否非空
|
|
||||||
*
|
|
||||||
* @param objects 要判断的对象数组
|
|
||||||
* @return true:非空 false:空
|
|
||||||
*/
|
|
||||||
public static boolean isNotEmpty(Object[] objects)
|
|
||||||
{
|
|
||||||
return !isEmpty(objects);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* * 判断一个Map是否为空
|
|
||||||
*
|
|
||||||
* @param map 要判断的Map
|
|
||||||
* @return true:为空 false:非空
|
|
||||||
*/
|
|
||||||
public static boolean isEmpty(Map<?, ?> map)
|
|
||||||
{
|
|
||||||
return isNull(map) || map.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* * 判断一个Map是否为空
|
|
||||||
*
|
|
||||||
* @param map 要判断的Map
|
|
||||||
* @return true:非空 false:空
|
|
||||||
*/
|
|
||||||
public static boolean isNotEmpty(Map<?, ?> map)
|
|
||||||
{
|
|
||||||
return !isEmpty(map);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* * 判断一个字符串是否为空串
|
|
||||||
*
|
|
||||||
* @param str String
|
|
||||||
* @return true:为空 false:非空
|
|
||||||
*/
|
|
||||||
public static boolean isEmpty(String str)
|
|
||||||
{
|
|
||||||
return isNull(str) || NULLSTR.equals(str.trim());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* * 判断一个字符串是否为非空串
|
|
||||||
*
|
|
||||||
* @param str String
|
|
||||||
* @return true:非空串 false:空串
|
|
||||||
*/
|
|
||||||
public static boolean isNotEmpty(String str)
|
|
||||||
{
|
|
||||||
return !isEmpty(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* * 判断一个对象是否为空
|
|
||||||
*
|
|
||||||
* @param object Object
|
|
||||||
* @return true:为空 false:非空
|
|
||||||
*/
|
|
||||||
public static boolean isNull(Object object)
|
|
||||||
{
|
|
||||||
return object == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* * 判断一个对象是否非空
|
|
||||||
*
|
|
||||||
* @param object Object
|
|
||||||
* @return true:非空 false:空
|
|
||||||
*/
|
|
||||||
public static boolean isNotNull(Object object)
|
|
||||||
{
|
|
||||||
return !isNull(object);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* * 判断一个对象是否是数组类型(Java基本型别的数组)
|
|
||||||
*
|
|
||||||
* @param object 对象
|
|
||||||
* @return true:是数组 false:不是数组
|
|
||||||
*/
|
|
||||||
public static boolean isArray(Object object)
|
|
||||||
{
|
|
||||||
return isNotNull(object) && object.getClass().isArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 去空格
|
|
||||||
*/
|
|
||||||
public static String trim(String str)
|
|
||||||
{
|
|
||||||
return (str == null ? "" : str.trim());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 截取字符串
|
|
||||||
*
|
|
||||||
* @param str 字符串
|
|
||||||
* @param start 开始
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static String substring(final String str, int start)
|
|
||||||
{
|
|
||||||
if (str == null)
|
|
||||||
{
|
|
||||||
return NULLSTR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (start < 0)
|
|
||||||
{
|
|
||||||
start = str.length() + start;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (start < 0)
|
|
||||||
{
|
|
||||||
start = 0;
|
|
||||||
}
|
|
||||||
if (start > str.length())
|
|
||||||
{
|
|
||||||
return NULLSTR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return str.substring(start);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 截取字符串
|
|
||||||
*
|
|
||||||
* @param str 字符串
|
|
||||||
* @param start 开始
|
|
||||||
* @param end 结束
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static String substring(final String str, int start, int end)
|
|
||||||
{
|
|
||||||
if (str == null)
|
|
||||||
{
|
|
||||||
return NULLSTR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (end < 0)
|
|
||||||
{
|
|
||||||
end = str.length() + end;
|
|
||||||
}
|
|
||||||
if (start < 0)
|
|
||||||
{
|
|
||||||
start = str.length() + start;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (end > str.length())
|
|
||||||
{
|
|
||||||
end = str.length();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (start > end)
|
|
||||||
{
|
|
||||||
return NULLSTR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (start < 0)
|
|
||||||
{
|
|
||||||
start = 0;
|
|
||||||
}
|
|
||||||
if (end < 0)
|
|
||||||
{
|
|
||||||
end = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return str.substring(start, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 格式化文本, {} 表示占位符<br>
|
|
||||||
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
|
|
||||||
* 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
|
|
||||||
* 例:<br>
|
|
||||||
* 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br>
|
|
||||||
* 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
|
|
||||||
* 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
|
|
||||||
*
|
|
||||||
* @param template 文本模板,被替换的部分用 {} 表示
|
|
||||||
* @param params 参数值
|
|
||||||
* @return 格式化后的文本
|
|
||||||
*/
|
|
||||||
public static String format(String template, Object... params)
|
|
||||||
{
|
|
||||||
if (isEmpty(params) || isEmpty(template))
|
|
||||||
{
|
|
||||||
return template;
|
|
||||||
}
|
|
||||||
return StrFormatter.format(template, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 字符串转set
|
|
||||||
*
|
|
||||||
* @param str 字符串
|
|
||||||
* @param sep 分隔符
|
|
||||||
* @return set集合
|
|
||||||
*/
|
|
||||||
public static final Set<String> str2Set(String str, String sep)
|
|
||||||
{
|
|
||||||
return new HashSet<String>(str2List(str, sep, true, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 字符串转list
|
|
||||||
*
|
|
||||||
* @param str 字符串
|
|
||||||
* @param sep 分隔符
|
|
||||||
* @param filterBlank 过滤纯空白
|
|
||||||
* @param trim 去掉首尾空白
|
|
||||||
* @return list集合
|
|
||||||
*/
|
|
||||||
public static final List<String> str2List(String str, String sep, boolean filterBlank, boolean trim)
|
|
||||||
{
|
|
||||||
List<String> list = new ArrayList<String>();
|
|
||||||
if (StringUtils.isEmpty(str))
|
|
||||||
{
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 过滤空白字符串
|
|
||||||
if (filterBlank && StringUtils.isBlank(str))
|
|
||||||
{
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
String[] split = str.split(sep);
|
|
||||||
for (String string : split)
|
|
||||||
{
|
|
||||||
if (filterBlank && StringUtils.isBlank(string))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (trim)
|
|
||||||
{
|
|
||||||
string = string.trim();
|
|
||||||
}
|
|
||||||
list.add(string);
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 下划线转驼峰命名
|
|
||||||
*/
|
|
||||||
public static String toUnderScoreCase(String str)
|
|
||||||
{
|
|
||||||
if (str == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
// 前置字符是否大写
|
|
||||||
boolean preCharIsUpperCase = true;
|
|
||||||
// 当前字符是否大写
|
|
||||||
boolean curreCharIsUpperCase = true;
|
|
||||||
// 下一字符是否大写
|
|
||||||
boolean nexteCharIsUpperCase = true;
|
|
||||||
for (int i = 0; i < str.length(); i++)
|
|
||||||
{
|
|
||||||
char c = str.charAt(i);
|
|
||||||
if (i > 0)
|
|
||||||
{
|
|
||||||
preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
preCharIsUpperCase = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
curreCharIsUpperCase = Character.isUpperCase(c);
|
|
||||||
|
|
||||||
if (i < (str.length() - 1))
|
|
||||||
{
|
|
||||||
nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase)
|
|
||||||
{
|
|
||||||
sb.append(SEPARATOR);
|
|
||||||
}
|
|
||||||
else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase)
|
|
||||||
{
|
|
||||||
sb.append(SEPARATOR);
|
|
||||||
}
|
|
||||||
sb.append(Character.toLowerCase(c));
|
|
||||||
}
|
|
||||||
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否包含字符串
|
|
||||||
*
|
|
||||||
* @param str 验证字符串
|
|
||||||
* @param strs 字符串组
|
|
||||||
* @return 包含返回true
|
|
||||||
*/
|
|
||||||
public static boolean inStringIgnoreCase(String str, String... strs)
|
|
||||||
{
|
|
||||||
if (str != null && strs != null)
|
|
||||||
{
|
|
||||||
for (String s : strs)
|
|
||||||
{
|
|
||||||
if (str.equalsIgnoreCase(trim(s)))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld
|
|
||||||
*
|
|
||||||
* @param name 转换前的下划线大写方式命名的字符串
|
|
||||||
* @return 转换后的驼峰式命名的字符串
|
|
||||||
*/
|
|
||||||
public static String convertToCamelCase(String name)
|
|
||||||
{
|
|
||||||
StringBuilder result = new StringBuilder();
|
|
||||||
// 快速检查
|
|
||||||
if (name == null || name.isEmpty())
|
|
||||||
{
|
|
||||||
// 没必要转换
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
else if (!name.contains("_"))
|
|
||||||
{
|
|
||||||
// 不含下划线,仅将首字母大写
|
|
||||||
return name.substring(0, 1).toUpperCase() + name.substring(1);
|
|
||||||
}
|
|
||||||
// 用下划线将原始字符串分割
|
|
||||||
String[] camels = name.split("_");
|
|
||||||
for (String camel : camels)
|
|
||||||
{
|
|
||||||
// 跳过原始字符串中开头、结尾的下换线或双重下划线
|
|
||||||
if (camel.isEmpty())
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// 首字母大写
|
|
||||||
result.append(camel.substring(0, 1).toUpperCase());
|
|
||||||
result.append(camel.substring(1).toLowerCase());
|
|
||||||
}
|
|
||||||
return result.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 驼峰式命名法 例如:user_name->userName
|
|
||||||
*/
|
|
||||||
public static String toCamelCase(String s)
|
|
||||||
{
|
|
||||||
if (s == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
s = s.toLowerCase();
|
|
||||||
StringBuilder sb = new StringBuilder(s.length());
|
|
||||||
boolean upperCase = false;
|
|
||||||
for (int i = 0; i < s.length(); i++)
|
|
||||||
{
|
|
||||||
char c = s.charAt(i);
|
|
||||||
|
|
||||||
if (c == SEPARATOR)
|
|
||||||
{
|
|
||||||
upperCase = true;
|
|
||||||
}
|
|
||||||
else if (upperCase)
|
|
||||||
{
|
|
||||||
sb.append(Character.toUpperCase(c));
|
|
||||||
upperCase = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sb.append(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,99 +0,0 @@
|
||||||
package com.ruoyi.common.utils;
|
|
||||||
|
|
||||||
import java.util.concurrent.CancellationException;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 线程相关工具类.
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class Threads
|
|
||||||
{
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(Threads.class);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* sleep等待,单位为毫秒
|
|
||||||
*/
|
|
||||||
public static void sleep(long milliseconds)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Thread.sleep(milliseconds);
|
|
||||||
}
|
|
||||||
catch (InterruptedException e)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 停止线程池
|
|
||||||
* 先使用shutdown, 停止接收新任务并尝试完成所有已存在任务.
|
|
||||||
* 如果超时, 则调用shutdownNow, 取消在workQueue中Pending的任务,并中断所有阻塞函数.
|
|
||||||
* 如果仍人超時,則強制退出.
|
|
||||||
* 另对在shutdown时线程本身被调用中断做了处理.
|
|
||||||
*/
|
|
||||||
public static void shutdownAndAwaitTermination(ExecutorService pool)
|
|
||||||
{
|
|
||||||
if (pool != null && !pool.isShutdown())
|
|
||||||
{
|
|
||||||
pool.shutdown();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!pool.awaitTermination(120, TimeUnit.SECONDS))
|
|
||||||
{
|
|
||||||
pool.shutdownNow();
|
|
||||||
if (!pool.awaitTermination(120, TimeUnit.SECONDS))
|
|
||||||
{
|
|
||||||
logger.info("Pool did not terminate");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (InterruptedException ie)
|
|
||||||
{
|
|
||||||
pool.shutdownNow();
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 打印线程异常信息
|
|
||||||
*/
|
|
||||||
public static void printException(Runnable r, Throwable t)
|
|
||||||
{
|
|
||||||
if (t == null && r instanceof Future<?>)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Future<?> future = (Future<?>) r;
|
|
||||||
if (future.isDone())
|
|
||||||
{
|
|
||||||
future.get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (CancellationException ce)
|
|
||||||
{
|
|
||||||
t = ce;
|
|
||||||
}
|
|
||||||
catch (ExecutionException ee)
|
|
||||||
{
|
|
||||||
t = ee.getCause();
|
|
||||||
}
|
|
||||||
catch (InterruptedException ie)
|
|
||||||
{
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (t != null)
|
|
||||||
{
|
|
||||||
logger.error(t.getMessage(), t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,226 +0,0 @@
|
||||||
package com.ruoyi.common.utils;
|
|
||||||
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Font;
|
|
||||||
import java.awt.Graphics;
|
|
||||||
import java.awt.Graphics2D;
|
|
||||||
import java.awt.RenderingHints;
|
|
||||||
import java.awt.geom.AffineTransform;
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Random;
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证码工具类
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class VerifyCodeUtils
|
|
||||||
{
|
|
||||||
// 使用到Algerian字体,系统里没有的话需要安装字体,字体只显示大写,去掉了1,0,i,o几个容易混淆的字符
|
|
||||||
public static final String VERIFY_CODES = "123456789ABCDEFGHJKLMNPQRSTUVWXYZ";
|
|
||||||
|
|
||||||
private static Random random = new SecureRandom();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 使用系统默认字符源生成验证码
|
|
||||||
*
|
|
||||||
* @param verifySize 验证码长度
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static String generateVerifyCode(int verifySize)
|
|
||||||
{
|
|
||||||
return generateVerifyCode(verifySize, VERIFY_CODES);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 使用指定源生成验证码
|
|
||||||
*
|
|
||||||
* @param verifySize 验证码长度
|
|
||||||
* @param sources 验证码字符源
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static String generateVerifyCode(int verifySize, String sources)
|
|
||||||
{
|
|
||||||
if (sources == null || sources.length() == 0)
|
|
||||||
{
|
|
||||||
sources = VERIFY_CODES;
|
|
||||||
}
|
|
||||||
int codesLen = sources.length();
|
|
||||||
Random rand = new Random(System.currentTimeMillis());
|
|
||||||
StringBuilder verifyCode = new StringBuilder(verifySize);
|
|
||||||
for (int i = 0; i < verifySize; i++)
|
|
||||||
{
|
|
||||||
verifyCode.append(sources.charAt(rand.nextInt(codesLen - 1)));
|
|
||||||
}
|
|
||||||
return verifyCode.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 输出指定验证码图片流
|
|
||||||
*
|
|
||||||
* @param w
|
|
||||||
* @param h
|
|
||||||
* @param os
|
|
||||||
* @param code
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public static void outputImage(int w, int h, OutputStream os, String code) throws IOException
|
|
||||||
{
|
|
||||||
int verifySize = code.length();
|
|
||||||
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
|
|
||||||
Random rand = new Random();
|
|
||||||
Graphics2D g2 = image.createGraphics();
|
|
||||||
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
|
||||||
Color[] colors = new Color[5];
|
|
||||||
Color[] colorSpaces = new Color[] { Color.WHITE, Color.CYAN, Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA,
|
|
||||||
Color.ORANGE, Color.PINK, Color.YELLOW };
|
|
||||||
float[] fractions = new float[colors.length];
|
|
||||||
for (int i = 0; i < colors.length; i++)
|
|
||||||
{
|
|
||||||
colors[i] = colorSpaces[rand.nextInt(colorSpaces.length)];
|
|
||||||
fractions[i] = rand.nextFloat();
|
|
||||||
}
|
|
||||||
Arrays.sort(fractions);
|
|
||||||
|
|
||||||
g2.setColor(Color.GRAY);// 设置边框色
|
|
||||||
g2.fillRect(0, 0, w, h);
|
|
||||||
|
|
||||||
Color c = getRandColor(200, 250);
|
|
||||||
g2.setColor(c);// 设置背景色
|
|
||||||
g2.fillRect(0, 2, w, h - 4);
|
|
||||||
|
|
||||||
// 绘制干扰线
|
|
||||||
Random random = new Random();
|
|
||||||
g2.setColor(getRandColor(160, 200));// 设置线条的颜色
|
|
||||||
for (int i = 0; i < 20; i++)
|
|
||||||
{
|
|
||||||
int x = random.nextInt(w - 1);
|
|
||||||
int y = random.nextInt(h - 1);
|
|
||||||
int xl = random.nextInt(6) + 1;
|
|
||||||
int yl = random.nextInt(12) + 1;
|
|
||||||
g2.drawLine(x, y, x + xl + 40, y + yl + 20);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加噪点
|
|
||||||
float yawpRate = 0.05f;// 噪声率
|
|
||||||
int area = (int) (yawpRate * w * h);
|
|
||||||
for (int i = 0; i < area; i++)
|
|
||||||
{
|
|
||||||
int x = random.nextInt(w);
|
|
||||||
int y = random.nextInt(h);
|
|
||||||
int rgb = getRandomIntColor();
|
|
||||||
image.setRGB(x, y, rgb);
|
|
||||||
}
|
|
||||||
|
|
||||||
shear(g2, w, h, c);// 使图片扭曲
|
|
||||||
|
|
||||||
g2.setColor(getRandColor(100, 160));
|
|
||||||
int fontSize = h - 4;
|
|
||||||
Font font = new Font("Algerian", Font.ITALIC, fontSize);
|
|
||||||
g2.setFont(font);
|
|
||||||
char[] chars = code.toCharArray();
|
|
||||||
for (int i = 0; i < verifySize; i++)
|
|
||||||
{
|
|
||||||
AffineTransform affine = new AffineTransform();
|
|
||||||
affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1),
|
|
||||||
(w / verifySize) * i + fontSize / 2, h / 2);
|
|
||||||
g2.setTransform(affine);
|
|
||||||
g2.drawChars(chars, i, 1, ((w - 10) / verifySize) * i + 5, h / 2 + fontSize / 2 - 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
g2.dispose();
|
|
||||||
ImageIO.write(image, "jpg", os);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Color getRandColor(int fc, int bc)
|
|
||||||
{
|
|
||||||
if (fc > 255)
|
|
||||||
fc = 255;
|
|
||||||
if (bc > 255)
|
|
||||||
bc = 255;
|
|
||||||
int r = fc + random.nextInt(bc - fc);
|
|
||||||
int g = fc + random.nextInt(bc - fc);
|
|
||||||
int b = fc + random.nextInt(bc - fc);
|
|
||||||
return new Color(r, g, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int getRandomIntColor()
|
|
||||||
{
|
|
||||||
int[] rgb = getRandomRgb();
|
|
||||||
int color = 0;
|
|
||||||
for (int c : rgb)
|
|
||||||
{
|
|
||||||
color = color << 8;
|
|
||||||
color = color | c;
|
|
||||||
}
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int[] getRandomRgb()
|
|
||||||
{
|
|
||||||
int[] rgb = new int[3];
|
|
||||||
for (int i = 0; i < 3; i++)
|
|
||||||
{
|
|
||||||
rgb[i] = random.nextInt(255);
|
|
||||||
}
|
|
||||||
return rgb;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void shear(Graphics g, int w1, int h1, Color color)
|
|
||||||
{
|
|
||||||
shearX(g, w1, h1, color);
|
|
||||||
shearY(g, w1, h1, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void shearX(Graphics g, int w1, int h1, Color color)
|
|
||||||
{
|
|
||||||
|
|
||||||
int period = random.nextInt(2);
|
|
||||||
|
|
||||||
boolean borderGap = true;
|
|
||||||
int frames = 1;
|
|
||||||
int phase = random.nextInt(2);
|
|
||||||
|
|
||||||
for (int i = 0; i < h1; i++)
|
|
||||||
{
|
|
||||||
double d = (double) (period >> 1)
|
|
||||||
* Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames);
|
|
||||||
g.copyArea(0, i, w1, 1, (int) d, 0);
|
|
||||||
if (borderGap)
|
|
||||||
{
|
|
||||||
g.setColor(color);
|
|
||||||
g.drawLine((int) d, i, 0, i);
|
|
||||||
g.drawLine((int) d + w1, i, w1, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void shearY(Graphics g, int w1, int h1, Color color)
|
|
||||||
{
|
|
||||||
|
|
||||||
int period = random.nextInt(40) + 10; // 50;
|
|
||||||
|
|
||||||
boolean borderGap = true;
|
|
||||||
int frames = 20;
|
|
||||||
int phase = 7;
|
|
||||||
for (int i = 0; i < w1; i++)
|
|
||||||
{
|
|
||||||
double d = (double) (period >> 1)
|
|
||||||
* Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames);
|
|
||||||
g.copyArea(i, 0, 1, h1, 0, (int) d);
|
|
||||||
if (borderGap)
|
|
||||||
{
|
|
||||||
g.setColor(color);
|
|
||||||
g.drawLine(i, (int) d, i, 0);
|
|
||||||
g.drawLine(i, (int) d + h1, i, h1);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,243 +0,0 @@
|
||||||
package com.ruoyi.common.utils.file;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import org.apache.commons.io.FilenameUtils;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
import com.ruoyi.common.constant.Constants;
|
|
||||||
import com.ruoyi.common.exception.file.FileNameLengthLimitExceededException;
|
|
||||||
import com.ruoyi.common.exception.file.FileSizeLimitExceededException;
|
|
||||||
import com.ruoyi.common.exception.file.InvalidExtensionException;
|
|
||||||
import com.ruoyi.common.utils.DateUtils;
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
|
||||||
import com.ruoyi.common.utils.security.Md5Utils;
|
|
||||||
import com.ruoyi.framework.config.RuoYiConfig;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件上传工具类
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class FileUploadUtils
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 默认大小 50M
|
|
||||||
*/
|
|
||||||
public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 默认的文件名最大长度 100
|
|
||||||
*/
|
|
||||||
public static final int DEFAULT_FILE_NAME_LENGTH = 100;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 默认上传的地址
|
|
||||||
*/
|
|
||||||
private static String defaultBaseDir = RuoYiConfig.getProfile();
|
|
||||||
|
|
||||||
private static int counter = 0;
|
|
||||||
|
|
||||||
public static void setDefaultBaseDir(String defaultBaseDir)
|
|
||||||
{
|
|
||||||
FileUploadUtils.defaultBaseDir = defaultBaseDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getDefaultBaseDir()
|
|
||||||
{
|
|
||||||
return defaultBaseDir;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 以默认配置进行文件上传
|
|
||||||
*
|
|
||||||
* @param file 上传的文件
|
|
||||||
* @return 文件名称
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
public static final String upload(MultipartFile file) throws IOException
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return upload(getDefaultBaseDir(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
throw new IOException(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据文件路径上传
|
|
||||||
*
|
|
||||||
* @param baseDir 相对应用的基目录
|
|
||||||
* @param file 上传的文件
|
|
||||||
* @return 文件名称
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
public static final String upload(String baseDir, MultipartFile file) throws IOException
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
throw new IOException(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件上传
|
|
||||||
*
|
|
||||||
* @param baseDir 相对应用的基目录
|
|
||||||
* @param file 上传的文件
|
|
||||||
* @param extension 上传文件类型
|
|
||||||
* @return 返回上传成功的文件名
|
|
||||||
* @throws FileSizeLimitExceededException 如果超出最大大小
|
|
||||||
* @throws FileNameLengthLimitExceededException 文件名太长
|
|
||||||
* @throws IOException 比如读写文件出错时
|
|
||||||
* @throws InvalidExtensionException 文件校验异常
|
|
||||||
*/
|
|
||||||
public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension)
|
|
||||||
throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
|
|
||||||
InvalidExtensionException
|
|
||||||
{
|
|
||||||
int fileNamelength = file.getOriginalFilename().length();
|
|
||||||
if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH)
|
|
||||||
{
|
|
||||||
throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
assertAllowed(file, allowedExtension);
|
|
||||||
|
|
||||||
String fileName = extractFilename(file);
|
|
||||||
|
|
||||||
File desc = getAbsoluteFile(baseDir, fileName);
|
|
||||||
file.transferTo(desc);
|
|
||||||
String pathFileName = getPathFileName(baseDir, fileName);
|
|
||||||
return pathFileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 编码文件名
|
|
||||||
*/
|
|
||||||
public static final String extractFilename(MultipartFile file)
|
|
||||||
{
|
|
||||||
String fileName = file.getOriginalFilename();
|
|
||||||
String extension = getExtension(file);
|
|
||||||
fileName = DateUtils.datePath() + "/" + encodingFilename(fileName) + "." + extension;
|
|
||||||
return fileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException
|
|
||||||
{
|
|
||||||
File desc = new File(uploadDir + File.separator + fileName);
|
|
||||||
|
|
||||||
if (!desc.getParentFile().exists())
|
|
||||||
{
|
|
||||||
desc.getParentFile().mkdirs();
|
|
||||||
}
|
|
||||||
if (!desc.exists())
|
|
||||||
{
|
|
||||||
desc.createNewFile();
|
|
||||||
}
|
|
||||||
return desc;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String getPathFileName(String uploadDir, String fileName) throws IOException
|
|
||||||
{
|
|
||||||
int dirLastIndex = RuoYiConfig.getProfile().length() + 1;
|
|
||||||
String currentDir = StringUtils.substring(uploadDir, dirLastIndex);
|
|
||||||
String pathFileName = Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName;
|
|
||||||
return pathFileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 编码文件名
|
|
||||||
*/
|
|
||||||
private static final String encodingFilename(String fileName)
|
|
||||||
{
|
|
||||||
fileName = fileName.replace("_", " ");
|
|
||||||
fileName = Md5Utils.hash(fileName + System.nanoTime() + counter++);
|
|
||||||
return fileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件大小校验
|
|
||||||
*
|
|
||||||
* @param file 上传的文件
|
|
||||||
* @return
|
|
||||||
* @throws FileSizeLimitExceededException 如果超出最大大小
|
|
||||||
* @throws InvalidExtensionException
|
|
||||||
*/
|
|
||||||
public static final void assertAllowed(MultipartFile file, String[] allowedExtension)
|
|
||||||
throws FileSizeLimitExceededException, InvalidExtensionException
|
|
||||||
{
|
|
||||||
long size = file.getSize();
|
|
||||||
if (DEFAULT_MAX_SIZE != -1 && size > DEFAULT_MAX_SIZE)
|
|
||||||
{
|
|
||||||
throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);
|
|
||||||
}
|
|
||||||
|
|
||||||
String fileName = file.getOriginalFilename();
|
|
||||||
String extension = getExtension(file);
|
|
||||||
if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension))
|
|
||||||
{
|
|
||||||
if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION)
|
|
||||||
{
|
|
||||||
throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension,
|
|
||||||
fileName);
|
|
||||||
}
|
|
||||||
else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION)
|
|
||||||
{
|
|
||||||
throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension,
|
|
||||||
fileName);
|
|
||||||
}
|
|
||||||
else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION)
|
|
||||||
{
|
|
||||||
throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension,
|
|
||||||
fileName);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new InvalidExtensionException(allowedExtension, extension, fileName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断MIME类型是否是允许的MIME类型
|
|
||||||
*
|
|
||||||
* @param extension
|
|
||||||
* @param allowedExtension
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static final boolean isAllowedExtension(String extension, String[] allowedExtension)
|
|
||||||
{
|
|
||||||
for (String str : allowedExtension)
|
|
||||||
{
|
|
||||||
if (str.equalsIgnoreCase(extension))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取文件名的后缀
|
|
||||||
*
|
|
||||||
* @param file 表单文件
|
|
||||||
* @return 后缀名
|
|
||||||
*/
|
|
||||||
public static final String getExtension(MultipartFile file)
|
|
||||||
{
|
|
||||||
String extension = FilenameUtils.getExtension(file.getOriginalFilename());
|
|
||||||
if (StringUtils.isEmpty(extension))
|
|
||||||
{
|
|
||||||
extension = MimeTypeUtils.getExtension(file.getContentType());
|
|
||||||
}
|
|
||||||
return extension;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,142 +0,0 @@
|
||||||
package com.ruoyi.common.utils.file;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.net.URLEncoder;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件处理工具类
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class FileUtils
|
|
||||||
{
|
|
||||||
public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 输出指定文件的byte数组
|
|
||||||
*
|
|
||||||
* @param filePath 文件路径
|
|
||||||
* @param os 输出流
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static void writeBytes(String filePath, OutputStream os) throws IOException
|
|
||||||
{
|
|
||||||
FileInputStream fis = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
File file = new File(filePath);
|
|
||||||
if (!file.exists())
|
|
||||||
{
|
|
||||||
throw new FileNotFoundException(filePath);
|
|
||||||
}
|
|
||||||
fis = new FileInputStream(file);
|
|
||||||
byte[] b = new byte[1024];
|
|
||||||
int length;
|
|
||||||
while ((length = fis.read(b)) > 0)
|
|
||||||
{
|
|
||||||
os.write(b, 0, length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (os != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
os.close();
|
|
||||||
}
|
|
||||||
catch (IOException e1)
|
|
||||||
{
|
|
||||||
e1.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (fis != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
fis.close();
|
|
||||||
}
|
|
||||||
catch (IOException e1)
|
|
||||||
{
|
|
||||||
e1.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除文件
|
|
||||||
*
|
|
||||||
* @param filePath 文件
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static boolean deleteFile(String filePath)
|
|
||||||
{
|
|
||||||
boolean flag = false;
|
|
||||||
File file = new File(filePath);
|
|
||||||
// 路径为文件且不为空则进行删除
|
|
||||||
if (file.isFile() && file.exists())
|
|
||||||
{
|
|
||||||
file.delete();
|
|
||||||
flag = true;
|
|
||||||
}
|
|
||||||
return flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文件名称验证
|
|
||||||
*
|
|
||||||
* @param filename 文件名称
|
|
||||||
* @return true 正常 false 非法
|
|
||||||
*/
|
|
||||||
public static boolean isValidFilename(String filename)
|
|
||||||
{
|
|
||||||
return filename.matches(FILENAME_PATTERN);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 下载文件名重新编码
|
|
||||||
*
|
|
||||||
* @param request 请求对象
|
|
||||||
* @param fileName 文件名
|
|
||||||
* @return 编码后的文件名
|
|
||||||
*/
|
|
||||||
public static String setFileDownloadHeader(HttpServletRequest request, String fileName)
|
|
||||||
throws UnsupportedEncodingException
|
|
||||||
{
|
|
||||||
final String agent = request.getHeader("USER-AGENT");
|
|
||||||
String filename = fileName;
|
|
||||||
if (agent.contains("MSIE"))
|
|
||||||
{
|
|
||||||
// IE浏览器
|
|
||||||
filename = URLEncoder.encode(filename, "utf-8");
|
|
||||||
filename = filename.replace("+", " ");
|
|
||||||
}
|
|
||||||
else if (agent.contains("Firefox"))
|
|
||||||
{
|
|
||||||
// 火狐浏览器
|
|
||||||
filename = new String(fileName.getBytes(), "ISO8859-1");
|
|
||||||
}
|
|
||||||
else if (agent.contains("Chrome"))
|
|
||||||
{
|
|
||||||
// google浏览器
|
|
||||||
filename = URLEncoder.encode(filename, "utf-8");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 其它浏览器
|
|
||||||
filename = URLEncoder.encode(filename, "utf-8");
|
|
||||||
}
|
|
||||||
return filename;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
package com.ruoyi.common.utils.file;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 媒体类型工具类
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class MimeTypeUtils
|
|
||||||
{
|
|
||||||
public static final String IMAGE_PNG = "image/png";
|
|
||||||
|
|
||||||
public static final String IMAGE_JPG = "image/jpg";
|
|
||||||
|
|
||||||
public static final String IMAGE_JPEG = "image/jpeg";
|
|
||||||
|
|
||||||
public static final String IMAGE_BMP = "image/bmp";
|
|
||||||
|
|
||||||
public static final String IMAGE_GIF = "image/gif";
|
|
||||||
|
|
||||||
public static final String[] IMAGE_EXTENSION = { "bmp", "gif", "jpg", "jpeg", "png" };
|
|
||||||
|
|
||||||
public static final String[] FLASH_EXTENSION = { "swf", "flv" };
|
|
||||||
|
|
||||||
public static final String[] MEDIA_EXTENSION = { "swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg",
|
|
||||||
"asf", "rm", "rmvb" };
|
|
||||||
|
|
||||||
public static final String[] DEFAULT_ALLOWED_EXTENSION = {
|
|
||||||
// 图片
|
|
||||||
"bmp", "gif", "jpg", "jpeg", "png",
|
|
||||||
// word excel powerpoint
|
|
||||||
"doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt",
|
|
||||||
// 压缩文件
|
|
||||||
"rar", "zip", "gz", "bz2",
|
|
||||||
// pdf
|
|
||||||
"pdf" };
|
|
||||||
|
|
||||||
public static String getExtension(String prefix)
|
|
||||||
{
|
|
||||||
switch (prefix)
|
|
||||||
{
|
|
||||||
case IMAGE_PNG:
|
|
||||||
return "png";
|
|
||||||
case IMAGE_JPG:
|
|
||||||
return "jpg";
|
|
||||||
case IMAGE_JPEG:
|
|
||||||
return "jpeg";
|
|
||||||
case IMAGE_BMP:
|
|
||||||
return "bmp";
|
|
||||||
case IMAGE_GIF:
|
|
||||||
return "gif";
|
|
||||||
default:
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,152 +0,0 @@
|
||||||
package com.ruoyi.common.utils.html;
|
|
||||||
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转义和反转义工具类
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class EscapeUtil
|
|
||||||
{
|
|
||||||
public static final String RE_HTML_MARK = "(<[^<]*?>)|(<[\\s]*?/[^<]*?>)|(<[^<]*?/[\\s]*?>)";
|
|
||||||
|
|
||||||
private static final char[][] TEXT = new char[64][];
|
|
||||||
|
|
||||||
static
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 64; i++)
|
|
||||||
{
|
|
||||||
TEXT[i] = new char[] { (char) i };
|
|
||||||
}
|
|
||||||
|
|
||||||
// special HTML characters
|
|
||||||
TEXT['\''] = "'".toCharArray(); // 单引号
|
|
||||||
TEXT['"'] = """.toCharArray(); // 单引号
|
|
||||||
TEXT['&'] = "&".toCharArray(); // &符
|
|
||||||
TEXT['<'] = "<".toCharArray(); // 小于号
|
|
||||||
TEXT['>'] = ">".toCharArray(); // 大于号
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转义文本中的HTML字符为安全的字符
|
|
||||||
*
|
|
||||||
* @param text 被转义的文本
|
|
||||||
* @return 转义后的文本
|
|
||||||
*/
|
|
||||||
public static String escape(String text)
|
|
||||||
{
|
|
||||||
return encode(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 还原被转义的HTML特殊字符
|
|
||||||
*
|
|
||||||
* @param content 包含转义符的HTML内容
|
|
||||||
* @return 转换后的字符串
|
|
||||||
*/
|
|
||||||
public static String unescape(String content)
|
|
||||||
{
|
|
||||||
return decode(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 清除所有HTML标签,但是不删除标签内的内容
|
|
||||||
*
|
|
||||||
* @param content 文本
|
|
||||||
* @return 清除标签后的文本
|
|
||||||
*/
|
|
||||||
public static String clean(String content)
|
|
||||||
{
|
|
||||||
return new HTMLFilter().filter(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Escape编码
|
|
||||||
*
|
|
||||||
* @param text 被编码的文本
|
|
||||||
* @return 编码后的字符
|
|
||||||
*/
|
|
||||||
private static String encode(String text)
|
|
||||||
{
|
|
||||||
int len;
|
|
||||||
if ((text == null) || ((len = text.length()) == 0))
|
|
||||||
{
|
|
||||||
return StringUtils.EMPTY;
|
|
||||||
}
|
|
||||||
StringBuilder buffer = new StringBuilder(len + (len >> 2));
|
|
||||||
char c;
|
|
||||||
for (int i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
c = text.charAt(i);
|
|
||||||
if (c < 64)
|
|
||||||
{
|
|
||||||
buffer.append(TEXT[c]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
buffer.append(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return buffer.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Escape解码
|
|
||||||
*
|
|
||||||
* @param content 被转义的内容
|
|
||||||
* @return 解码后的字符串
|
|
||||||
*/
|
|
||||||
public static String decode(String content)
|
|
||||||
{
|
|
||||||
if (StringUtils.isEmpty(content))
|
|
||||||
{
|
|
||||||
return content;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringBuilder tmp = new StringBuilder(content.length());
|
|
||||||
int lastPos = 0, pos = 0;
|
|
||||||
char ch;
|
|
||||||
while (lastPos < content.length())
|
|
||||||
{
|
|
||||||
pos = content.indexOf("%", lastPos);
|
|
||||||
if (pos == lastPos)
|
|
||||||
{
|
|
||||||
if (content.charAt(pos + 1) == 'u')
|
|
||||||
{
|
|
||||||
ch = (char) Integer.parseInt(content.substring(pos + 2, pos + 6), 16);
|
|
||||||
tmp.append(ch);
|
|
||||||
lastPos = pos + 6;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ch = (char) Integer.parseInt(content.substring(pos + 1, pos + 3), 16);
|
|
||||||
tmp.append(ch);
|
|
||||||
lastPos = pos + 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (pos == -1)
|
|
||||||
{
|
|
||||||
tmp.append(content.substring(lastPos));
|
|
||||||
lastPos = content.length();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tmp.append(content.substring(lastPos, pos));
|
|
||||||
lastPos = pos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return tmp.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args)
|
|
||||||
{
|
|
||||||
String html = "<script>alert(1);</script>";
|
|
||||||
System.out.println(EscapeUtil.clean(html));
|
|
||||||
System.out.println(EscapeUtil.escape(html));
|
|
||||||
System.out.println(EscapeUtil.unescape(html));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,569 +0,0 @@
|
||||||
package com.ruoyi.common.utils.html;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.ConcurrentMap;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* HTML过滤器,用于去除XSS漏洞隐患。
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public final class HTMLFilter
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* regex flag union representing /si modifiers in php
|
|
||||||
**/
|
|
||||||
private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL;
|
|
||||||
private static final Pattern P_COMMENTS = Pattern.compile("<!--(.*?)-->", Pattern.DOTALL);
|
|
||||||
private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI);
|
|
||||||
private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL);
|
|
||||||
private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI);
|
|
||||||
private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI);
|
|
||||||
private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI);
|
|
||||||
private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI);
|
|
||||||
private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI);
|
|
||||||
private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?");
|
|
||||||
private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?");
|
|
||||||
private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?");
|
|
||||||
private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))");
|
|
||||||
private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL);
|
|
||||||
private static final Pattern P_END_ARROW = Pattern.compile("^>");
|
|
||||||
private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)");
|
|
||||||
private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)");
|
|
||||||
private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)");
|
|
||||||
private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)");
|
|
||||||
private static final Pattern P_AMP = Pattern.compile("&");
|
|
||||||
private static final Pattern P_QUOTE = Pattern.compile("\"");
|
|
||||||
private static final Pattern P_LEFT_ARROW = Pattern.compile("<");
|
|
||||||
private static final Pattern P_RIGHT_ARROW = Pattern.compile(">");
|
|
||||||
private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>");
|
|
||||||
|
|
||||||
// @xxx could grow large... maybe use sesat's ReferenceMap
|
|
||||||
private static final ConcurrentMap<String, Pattern> P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<>();
|
|
||||||
private static final ConcurrentMap<String, Pattern> P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* set of allowed html elements, along with allowed attributes for each element
|
|
||||||
**/
|
|
||||||
private final Map<String, List<String>> vAllowed;
|
|
||||||
/**
|
|
||||||
* counts of open tags for each (allowable) html element
|
|
||||||
**/
|
|
||||||
private final Map<String, Integer> vTagCounts = new HashMap<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* html elements which must always be self-closing (e.g. "<img />")
|
|
||||||
**/
|
|
||||||
private final String[] vSelfClosingTags;
|
|
||||||
/**
|
|
||||||
* html elements which must always have separate opening and closing tags (e.g. "<b></b>")
|
|
||||||
**/
|
|
||||||
private final String[] vNeedClosingTags;
|
|
||||||
/**
|
|
||||||
* set of disallowed html elements
|
|
||||||
**/
|
|
||||||
private final String[] vDisallowed;
|
|
||||||
/**
|
|
||||||
* attributes which should be checked for valid protocols
|
|
||||||
**/
|
|
||||||
private final String[] vProtocolAtts;
|
|
||||||
/**
|
|
||||||
* allowed protocols
|
|
||||||
**/
|
|
||||||
private final String[] vAllowedProtocols;
|
|
||||||
/**
|
|
||||||
* tags which should be removed if they contain no content (e.g. "<b></b>" or "<b />")
|
|
||||||
**/
|
|
||||||
private final String[] vRemoveBlanks;
|
|
||||||
/**
|
|
||||||
* entities allowed within html markup
|
|
||||||
**/
|
|
||||||
private final String[] vAllowedEntities;
|
|
||||||
/**
|
|
||||||
* flag determining whether comments are allowed in input String.
|
|
||||||
*/
|
|
||||||
private final boolean stripComment;
|
|
||||||
private final boolean encodeQuotes;
|
|
||||||
/**
|
|
||||||
* flag determining whether to try to make tags when presented with "unbalanced" angle brackets (e.g. "<b text </b>"
|
|
||||||
* becomes "<b> text </b>"). If set to false, unbalanced angle brackets will be html escaped.
|
|
||||||
*/
|
|
||||||
private final boolean alwaysMakeTags;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default constructor.
|
|
||||||
*/
|
|
||||||
public HTMLFilter()
|
|
||||||
{
|
|
||||||
vAllowed = new HashMap<>();
|
|
||||||
|
|
||||||
final ArrayList<String> a_atts = new ArrayList<>();
|
|
||||||
a_atts.add("href");
|
|
||||||
a_atts.add("target");
|
|
||||||
vAllowed.put("a", a_atts);
|
|
||||||
|
|
||||||
final ArrayList<String> img_atts = new ArrayList<>();
|
|
||||||
img_atts.add("src");
|
|
||||||
img_atts.add("width");
|
|
||||||
img_atts.add("height");
|
|
||||||
img_atts.add("alt");
|
|
||||||
vAllowed.put("img", img_atts);
|
|
||||||
|
|
||||||
final ArrayList<String> no_atts = new ArrayList<>();
|
|
||||||
vAllowed.put("b", no_atts);
|
|
||||||
vAllowed.put("strong", no_atts);
|
|
||||||
vAllowed.put("i", no_atts);
|
|
||||||
vAllowed.put("em", no_atts);
|
|
||||||
|
|
||||||
vSelfClosingTags = new String[] { "img" };
|
|
||||||
vNeedClosingTags = new String[] { "a", "b", "strong", "i", "em" };
|
|
||||||
vDisallowed = new String[] {};
|
|
||||||
vAllowedProtocols = new String[] { "http", "mailto", "https" }; // no ftp.
|
|
||||||
vProtocolAtts = new String[] { "src", "href" };
|
|
||||||
vRemoveBlanks = new String[] { "a", "b", "strong", "i", "em" };
|
|
||||||
vAllowedEntities = new String[] { "amp", "gt", "lt", "quot" };
|
|
||||||
stripComment = true;
|
|
||||||
encodeQuotes = true;
|
|
||||||
alwaysMakeTags = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Map-parameter configurable constructor.
|
|
||||||
*
|
|
||||||
* @param conf map containing configuration. keys match field names.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public HTMLFilter(final Map<String, Object> conf)
|
|
||||||
{
|
|
||||||
|
|
||||||
assert conf.containsKey("vAllowed") : "configuration requires vAllowed";
|
|
||||||
assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags";
|
|
||||||
assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags";
|
|
||||||
assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed";
|
|
||||||
assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols";
|
|
||||||
assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts";
|
|
||||||
assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks";
|
|
||||||
assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities";
|
|
||||||
|
|
||||||
vAllowed = Collections.unmodifiableMap((HashMap<String, List<String>>) conf.get("vAllowed"));
|
|
||||||
vSelfClosingTags = (String[]) conf.get("vSelfClosingTags");
|
|
||||||
vNeedClosingTags = (String[]) conf.get("vNeedClosingTags");
|
|
||||||
vDisallowed = (String[]) conf.get("vDisallowed");
|
|
||||||
vAllowedProtocols = (String[]) conf.get("vAllowedProtocols");
|
|
||||||
vProtocolAtts = (String[]) conf.get("vProtocolAtts");
|
|
||||||
vRemoveBlanks = (String[]) conf.get("vRemoveBlanks");
|
|
||||||
vAllowedEntities = (String[]) conf.get("vAllowedEntities");
|
|
||||||
stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true;
|
|
||||||
encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true;
|
|
||||||
alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void reset()
|
|
||||||
{
|
|
||||||
vTagCounts.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------
|
|
||||||
// my versions of some PHP library functions
|
|
||||||
public static String chr(final int decimal)
|
|
||||||
{
|
|
||||||
return String.valueOf((char) decimal);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String htmlSpecialChars(final String s)
|
|
||||||
{
|
|
||||||
String result = s;
|
|
||||||
result = regexReplace(P_AMP, "&", result);
|
|
||||||
result = regexReplace(P_QUOTE, """, result);
|
|
||||||
result = regexReplace(P_LEFT_ARROW, "<", result);
|
|
||||||
result = regexReplace(P_RIGHT_ARROW, ">", result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* given a user submitted input String, filter out any invalid or restricted html.
|
|
||||||
*
|
|
||||||
* @param input text (i.e. submitted by a user) than may contain html
|
|
||||||
* @return "clean" version of input, with only valid, whitelisted html elements allowed
|
|
||||||
*/
|
|
||||||
public String filter(final String input)
|
|
||||||
{
|
|
||||||
reset();
|
|
||||||
String s = input;
|
|
||||||
|
|
||||||
s = escapeComments(s);
|
|
||||||
|
|
||||||
s = balanceHTML(s);
|
|
||||||
|
|
||||||
s = checkTags(s);
|
|
||||||
|
|
||||||
s = processRemoveBlanks(s);
|
|
||||||
|
|
||||||
s = validateEntities(s);
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isAlwaysMakeTags()
|
|
||||||
{
|
|
||||||
return alwaysMakeTags;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isStripComments()
|
|
||||||
{
|
|
||||||
return stripComment;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String escapeComments(final String s)
|
|
||||||
{
|
|
||||||
final Matcher m = P_COMMENTS.matcher(s);
|
|
||||||
final StringBuffer buf = new StringBuffer();
|
|
||||||
if (m.find())
|
|
||||||
{
|
|
||||||
final String match = m.group(1); // (.*?)
|
|
||||||
m.appendReplacement(buf, Matcher.quoteReplacement("<!--" + htmlSpecialChars(match) + "-->"));
|
|
||||||
}
|
|
||||||
m.appendTail(buf);
|
|
||||||
|
|
||||||
return buf.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String balanceHTML(String s)
|
|
||||||
{
|
|
||||||
if (alwaysMakeTags)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
// try and form html
|
|
||||||
//
|
|
||||||
s = regexReplace(P_END_ARROW, "", s);
|
|
||||||
s = regexReplace(P_BODY_TO_END, "<$1>", s);
|
|
||||||
s = regexReplace(P_XML_CONTENT, "$1<$2", s);
|
|
||||||
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//
|
|
||||||
// escape stray brackets
|
|
||||||
//
|
|
||||||
s = regexReplace(P_STRAY_LEFT_ARROW, "<$1", s);
|
|
||||||
s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2><", s);
|
|
||||||
|
|
||||||
//
|
|
||||||
// the last regexp causes '<>' entities to appear
|
|
||||||
// (we need to do a lookahead assertion so that the last bracket can
|
|
||||||
// be used in the next pass of the regexp)
|
|
||||||
//
|
|
||||||
s = regexReplace(P_BOTH_ARROWS, "", s);
|
|
||||||
}
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String checkTags(String s)
|
|
||||||
{
|
|
||||||
Matcher m = P_TAGS.matcher(s);
|
|
||||||
|
|
||||||
final StringBuffer buf = new StringBuffer();
|
|
||||||
while (m.find())
|
|
||||||
{
|
|
||||||
String replaceStr = m.group(1);
|
|
||||||
replaceStr = processTag(replaceStr);
|
|
||||||
m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr));
|
|
||||||
}
|
|
||||||
m.appendTail(buf);
|
|
||||||
|
|
||||||
// these get tallied in processTag
|
|
||||||
// (remember to reset before subsequent calls to filter method)
|
|
||||||
final StringBuilder sBuilder = new StringBuilder(buf.toString());
|
|
||||||
for (String key : vTagCounts.keySet())
|
|
||||||
{
|
|
||||||
for (int ii = 0; ii < vTagCounts.get(key); ii++)
|
|
||||||
{
|
|
||||||
sBuilder.append("</").append(key).append(">");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s = sBuilder.toString();
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String processRemoveBlanks(final String s)
|
|
||||||
{
|
|
||||||
String result = s;
|
|
||||||
for (String tag : vRemoveBlanks)
|
|
||||||
{
|
|
||||||
if (!P_REMOVE_PAIR_BLANKS.containsKey(tag))
|
|
||||||
{
|
|
||||||
P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?></" + tag + ">"));
|
|
||||||
}
|
|
||||||
result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result);
|
|
||||||
if (!P_REMOVE_SELF_BLANKS.containsKey(tag))
|
|
||||||
{
|
|
||||||
P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>"));
|
|
||||||
}
|
|
||||||
result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String regexReplace(final Pattern regex_pattern, final String replacement, final String s)
|
|
||||||
{
|
|
||||||
Matcher m = regex_pattern.matcher(s);
|
|
||||||
return m.replaceAll(replacement);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String processTag(final String s)
|
|
||||||
{
|
|
||||||
// ending tags
|
|
||||||
Matcher m = P_END_TAG.matcher(s);
|
|
||||||
if (m.find())
|
|
||||||
{
|
|
||||||
final String name = m.group(1).toLowerCase();
|
|
||||||
if (allowed(name))
|
|
||||||
{
|
|
||||||
if (false == inArray(name, vSelfClosingTags))
|
|
||||||
{
|
|
||||||
if (vTagCounts.containsKey(name))
|
|
||||||
{
|
|
||||||
vTagCounts.put(name, vTagCounts.get(name) - 1);
|
|
||||||
return "</" + name + ">";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// starting tags
|
|
||||||
m = P_START_TAG.matcher(s);
|
|
||||||
if (m.find())
|
|
||||||
{
|
|
||||||
final String name = m.group(1).toLowerCase();
|
|
||||||
final String body = m.group(2);
|
|
||||||
String ending = m.group(3);
|
|
||||||
|
|
||||||
// debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" );
|
|
||||||
if (allowed(name))
|
|
||||||
{
|
|
||||||
final StringBuilder params = new StringBuilder();
|
|
||||||
|
|
||||||
final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body);
|
|
||||||
final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body);
|
|
||||||
final List<String> paramNames = new ArrayList<>();
|
|
||||||
final List<String> paramValues = new ArrayList<>();
|
|
||||||
while (m2.find())
|
|
||||||
{
|
|
||||||
paramNames.add(m2.group(1)); // ([a-z0-9]+)
|
|
||||||
paramValues.add(m2.group(3)); // (.*?)
|
|
||||||
}
|
|
||||||
while (m3.find())
|
|
||||||
{
|
|
||||||
paramNames.add(m3.group(1)); // ([a-z0-9]+)
|
|
||||||
paramValues.add(m3.group(3)); // ([^\"\\s']+)
|
|
||||||
}
|
|
||||||
|
|
||||||
String paramName, paramValue;
|
|
||||||
for (int ii = 0; ii < paramNames.size(); ii++)
|
|
||||||
{
|
|
||||||
paramName = paramNames.get(ii).toLowerCase();
|
|
||||||
paramValue = paramValues.get(ii);
|
|
||||||
|
|
||||||
// debug( "paramName='" + paramName + "'" );
|
|
||||||
// debug( "paramValue='" + paramValue + "'" );
|
|
||||||
// debug( "allowed? " + vAllowed.get( name ).contains( paramName ) );
|
|
||||||
|
|
||||||
if (allowedAttribute(name, paramName))
|
|
||||||
{
|
|
||||||
if (inArray(paramName, vProtocolAtts))
|
|
||||||
{
|
|
||||||
paramValue = processParamProtocol(paramValue);
|
|
||||||
}
|
|
||||||
params.append(' ').append(paramName).append("=\"").append(paramValue).append("\"");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inArray(name, vSelfClosingTags))
|
|
||||||
{
|
|
||||||
ending = " /";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inArray(name, vNeedClosingTags))
|
|
||||||
{
|
|
||||||
ending = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ending == null || ending.length() < 1)
|
|
||||||
{
|
|
||||||
if (vTagCounts.containsKey(name))
|
|
||||||
{
|
|
||||||
vTagCounts.put(name, vTagCounts.get(name) + 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
vTagCounts.put(name, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ending = " /";
|
|
||||||
}
|
|
||||||
return "<" + name + params + ending + ">";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// comments
|
|
||||||
m = P_COMMENT.matcher(s);
|
|
||||||
if (!stripComment && m.find())
|
|
||||||
{
|
|
||||||
return "<" + m.group() + ">";
|
|
||||||
}
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
private String processParamProtocol(String s)
|
|
||||||
{
|
|
||||||
s = decodeEntities(s);
|
|
||||||
final Matcher m = P_PROTOCOL.matcher(s);
|
|
||||||
if (m.find())
|
|
||||||
{
|
|
||||||
final String protocol = m.group(1);
|
|
||||||
if (!inArray(protocol, vAllowedProtocols))
|
|
||||||
{
|
|
||||||
// bad protocol, turn into local anchor link instead
|
|
||||||
s = "#" + s.substring(protocol.length() + 1);
|
|
||||||
if (s.startsWith("#//"))
|
|
||||||
{
|
|
||||||
s = "#" + s.substring(3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String decodeEntities(String s)
|
|
||||||
{
|
|
||||||
StringBuffer buf = new StringBuffer();
|
|
||||||
|
|
||||||
Matcher m = P_ENTITY.matcher(s);
|
|
||||||
while (m.find())
|
|
||||||
{
|
|
||||||
final String match = m.group(1);
|
|
||||||
final int decimal = Integer.decode(match).intValue();
|
|
||||||
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
|
|
||||||
}
|
|
||||||
m.appendTail(buf);
|
|
||||||
s = buf.toString();
|
|
||||||
|
|
||||||
buf = new StringBuffer();
|
|
||||||
m = P_ENTITY_UNICODE.matcher(s);
|
|
||||||
while (m.find())
|
|
||||||
{
|
|
||||||
final String match = m.group(1);
|
|
||||||
final int decimal = Integer.valueOf(match, 16).intValue();
|
|
||||||
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
|
|
||||||
}
|
|
||||||
m.appendTail(buf);
|
|
||||||
s = buf.toString();
|
|
||||||
|
|
||||||
buf = new StringBuffer();
|
|
||||||
m = P_ENCODE.matcher(s);
|
|
||||||
while (m.find())
|
|
||||||
{
|
|
||||||
final String match = m.group(1);
|
|
||||||
final int decimal = Integer.valueOf(match, 16).intValue();
|
|
||||||
m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
|
|
||||||
}
|
|
||||||
m.appendTail(buf);
|
|
||||||
s = buf.toString();
|
|
||||||
|
|
||||||
s = validateEntities(s);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String validateEntities(final String s)
|
|
||||||
{
|
|
||||||
StringBuffer buf = new StringBuffer();
|
|
||||||
|
|
||||||
// validate entities throughout the string
|
|
||||||
Matcher m = P_VALID_ENTITIES.matcher(s);
|
|
||||||
while (m.find())
|
|
||||||
{
|
|
||||||
final String one = m.group(1); // ([^&;]*)
|
|
||||||
final String two = m.group(2); // (?=(;|&|$))
|
|
||||||
m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two)));
|
|
||||||
}
|
|
||||||
m.appendTail(buf);
|
|
||||||
|
|
||||||
return encodeQuotes(buf.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
private String encodeQuotes(final String s)
|
|
||||||
{
|
|
||||||
if (encodeQuotes)
|
|
||||||
{
|
|
||||||
StringBuffer buf = new StringBuffer();
|
|
||||||
Matcher m = P_VALID_QUOTES.matcher(s);
|
|
||||||
while (m.find())
|
|
||||||
{
|
|
||||||
final String one = m.group(1); // (>|^)
|
|
||||||
final String two = m.group(2); // ([^<]+?)
|
|
||||||
final String three = m.group(3); // (<|$)
|
|
||||||
// 不替换双引号为",防止json格式无效 regexReplace(P_QUOTE, """, two)
|
|
||||||
m.appendReplacement(buf, Matcher.quoteReplacement(one + two + three));
|
|
||||||
}
|
|
||||||
m.appendTail(buf);
|
|
||||||
return buf.toString();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String checkEntity(final String preamble, final String term)
|
|
||||||
{
|
|
||||||
|
|
||||||
return ";".equals(term) && isValidEntity(preamble) ? '&' + preamble : "&" + preamble;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isValidEntity(final String entity)
|
|
||||||
{
|
|
||||||
return inArray(entity, vAllowedEntities);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean inArray(final String s, final String[] array)
|
|
||||||
{
|
|
||||||
for (String item : array)
|
|
||||||
{
|
|
||||||
if (item != null && item.equals(s))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean allowed(final String name)
|
|
||||||
{
|
|
||||||
return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean allowedAttribute(final String name, final String paramName)
|
|
||||||
{
|
|
||||||
return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,248 +0,0 @@
|
||||||
package com.ruoyi.common.utils.http;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.net.ConnectException;
|
|
||||||
import java.net.SocketTimeoutException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.net.URLConnection;
|
|
||||||
import java.security.cert.X509Certificate;
|
|
||||||
import javax.net.ssl.HostnameVerifier;
|
|
||||||
import javax.net.ssl.HttpsURLConnection;
|
|
||||||
import javax.net.ssl.SSLContext;
|
|
||||||
import javax.net.ssl.SSLSession;
|
|
||||||
import javax.net.ssl.TrustManager;
|
|
||||||
import javax.net.ssl.X509TrustManager;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通用http发送方法
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class HttpUtils
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 向指定 URL 发送GET方法的请求
|
|
||||||
*
|
|
||||||
* @param url 发送请求的 URL
|
|
||||||
* @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
|
|
||||||
* @return 所代表远程资源的响应结果
|
|
||||||
*/
|
|
||||||
public static String sendGet(String url, String param)
|
|
||||||
{
|
|
||||||
StringBuilder result = new StringBuilder();
|
|
||||||
BufferedReader in = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
String urlNameString = url + "?" + param;
|
|
||||||
log.info("sendGet - {}", urlNameString);
|
|
||||||
URL realUrl = new URL(urlNameString);
|
|
||||||
URLConnection connection = realUrl.openConnection();
|
|
||||||
connection.setRequestProperty("accept", "*/*");
|
|
||||||
connection.setRequestProperty("connection", "Keep-Alive");
|
|
||||||
connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
|
|
||||||
connection.connect();
|
|
||||||
in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
|
||||||
String line;
|
|
||||||
while ((line = in.readLine()) != null)
|
|
||||||
{
|
|
||||||
result.append(line);
|
|
||||||
}
|
|
||||||
log.info("recv - {}", result);
|
|
||||||
}
|
|
||||||
catch (ConnectException e)
|
|
||||||
{
|
|
||||||
log.error("调用HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e);
|
|
||||||
}
|
|
||||||
catch (SocketTimeoutException e)
|
|
||||||
{
|
|
||||||
log.error("调用HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e);
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
log.error("调用HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
log.error("调用HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (in != null)
|
|
||||||
{
|
|
||||||
in.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 向指定 URL 发送POST方法的请求
|
|
||||||
*
|
|
||||||
* @param url 发送请求的 URL
|
|
||||||
* @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
|
|
||||||
* @return 所代表远程资源的响应结果
|
|
||||||
*/
|
|
||||||
public static String sendPost(String url, String param)
|
|
||||||
{
|
|
||||||
PrintWriter out = null;
|
|
||||||
BufferedReader in = null;
|
|
||||||
StringBuilder result = new StringBuilder();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
String urlNameString = url + "?" + param;
|
|
||||||
log.info("sendPost - {}", urlNameString);
|
|
||||||
URL realUrl = new URL(urlNameString);
|
|
||||||
URLConnection conn = realUrl.openConnection();
|
|
||||||
conn.setRequestProperty("accept", "*/*");
|
|
||||||
conn.setRequestProperty("connection", "Keep-Alive");
|
|
||||||
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
|
|
||||||
conn.setRequestProperty("Accept-Charset", "utf-8");
|
|
||||||
conn.setRequestProperty("contentType", "utf-8");
|
|
||||||
conn.setDoOutput(true);
|
|
||||||
conn.setDoInput(true);
|
|
||||||
out = new PrintWriter(conn.getOutputStream());
|
|
||||||
out.print(param);
|
|
||||||
out.flush();
|
|
||||||
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
|
|
||||||
String line;
|
|
||||||
while ((line = in.readLine()) != null)
|
|
||||||
{
|
|
||||||
result.append(line);
|
|
||||||
}
|
|
||||||
log.info("recv - {}", result);
|
|
||||||
}
|
|
||||||
catch (ConnectException e)
|
|
||||||
{
|
|
||||||
log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e);
|
|
||||||
}
|
|
||||||
catch (SocketTimeoutException e)
|
|
||||||
{
|
|
||||||
log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e);
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (out != null)
|
|
||||||
{
|
|
||||||
out.close();
|
|
||||||
}
|
|
||||||
if (in != null)
|
|
||||||
{
|
|
||||||
in.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException ex)
|
|
||||||
{
|
|
||||||
log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String sendSSLPost(String url, String param)
|
|
||||||
{
|
|
||||||
StringBuilder result = new StringBuilder();
|
|
||||||
String urlNameString = url + "?" + param;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
log.info("sendSSLPost - {}", urlNameString);
|
|
||||||
SSLContext sc = SSLContext.getInstance("SSL");
|
|
||||||
sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom());
|
|
||||||
URL console = new URL(urlNameString);
|
|
||||||
HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();
|
|
||||||
conn.setRequestProperty("accept", "*/*");
|
|
||||||
conn.setRequestProperty("connection", "Keep-Alive");
|
|
||||||
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
|
|
||||||
conn.setRequestProperty("Accept-Charset", "utf-8");
|
|
||||||
conn.setRequestProperty("contentType", "utf-8");
|
|
||||||
conn.setDoOutput(true);
|
|
||||||
conn.setDoInput(true);
|
|
||||||
|
|
||||||
conn.setSSLSocketFactory(sc.getSocketFactory());
|
|
||||||
conn.setHostnameVerifier(new TrustAnyHostnameVerifier());
|
|
||||||
conn.connect();
|
|
||||||
InputStream is = conn.getInputStream();
|
|
||||||
BufferedReader br = new BufferedReader(new InputStreamReader(is));
|
|
||||||
String ret = "";
|
|
||||||
while ((ret = br.readLine()) != null)
|
|
||||||
{
|
|
||||||
if (ret != null && !ret.trim().equals(""))
|
|
||||||
{
|
|
||||||
result.append(new String(ret.getBytes("ISO-8859-1"), "utf-8"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.info("recv - {}", result);
|
|
||||||
conn.disconnect();
|
|
||||||
br.close();
|
|
||||||
}
|
|
||||||
catch (ConnectException e)
|
|
||||||
{
|
|
||||||
log.error("调用HttpUtils.sendSSLPost ConnectException, url=" + url + ",param=" + param, e);
|
|
||||||
}
|
|
||||||
catch (SocketTimeoutException e)
|
|
||||||
{
|
|
||||||
log.error("调用HttpUtils.sendSSLPost SocketTimeoutException, url=" + url + ",param=" + param, e);
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
log.error("调用HttpUtils.sendSSLPost IOException, url=" + url + ",param=" + param, e);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
log.error("调用HttpsUtil.sendSSLPost Exception, url=" + url + ",param=" + param, e);
|
|
||||||
}
|
|
||||||
return result.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class TrustAnyTrustManager implements X509TrustManager
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void checkClientTrusted(X509Certificate[] chain, String authType)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void checkServerTrusted(X509Certificate[] chain, String authType)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public X509Certificate[] getAcceptedIssuers()
|
|
||||||
{
|
|
||||||
return new X509Certificate[] {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class TrustAnyHostnameVerifier implements HostnameVerifier
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public boolean verify(String hostname, SSLSession session)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
package com.ruoyi.common.utils.ip;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
|
||||||
import com.ruoyi.common.utils.http.HttpUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取地址类
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class AddressUtils
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(AddressUtils.class);
|
|
||||||
|
|
||||||
public static final String IP_URL = "http://ip.taobao.com/service/getIpInfo.php";
|
|
||||||
|
|
||||||
public static String getRealAddressByIP(String ip)
|
|
||||||
{
|
|
||||||
String address = "XX XX";
|
|
||||||
// 内网不查询
|
|
||||||
if (IpUtils.internalIp(ip))
|
|
||||||
{
|
|
||||||
return "内网IP";
|
|
||||||
}
|
|
||||||
String rspStr = HttpUtils.sendPost(IP_URL, "ip=" + ip);
|
|
||||||
if (StringUtils.isEmpty(rspStr))
|
|
||||||
{
|
|
||||||
log.error("获取地理位置异常 {}", ip);
|
|
||||||
return address;
|
|
||||||
}
|
|
||||||
JSONObject obj = JSONObject.parseObject(rspStr);
|
|
||||||
JSONObject data = obj.getObject("data", JSONObject.class);
|
|
||||||
String region = data.getString("region");
|
|
||||||
String city = data.getString("city");
|
|
||||||
address = region + " " + city;
|
|
||||||
return address;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,189 +0,0 @@
|
||||||
package com.ruoyi.common.utils.ip;
|
|
||||||
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.net.UnknownHostException;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取IP方法
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class IpUtils
|
|
||||||
{
|
|
||||||
public static String getIpAddr(HttpServletRequest request)
|
|
||||||
{
|
|
||||||
if (request == null)
|
|
||||||
{
|
|
||||||
return "unknown";
|
|
||||||
}
|
|
||||||
String ip = request.getHeader("x-forwarded-for");
|
|
||||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
|
|
||||||
{
|
|
||||||
ip = request.getHeader("Proxy-Client-IP");
|
|
||||||
}
|
|
||||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
|
|
||||||
{
|
|
||||||
ip = request.getHeader("X-Forwarded-For");
|
|
||||||
}
|
|
||||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
|
|
||||||
{
|
|
||||||
ip = request.getHeader("WL-Proxy-Client-IP");
|
|
||||||
}
|
|
||||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
|
|
||||||
{
|
|
||||||
ip = request.getHeader("X-Real-IP");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
|
|
||||||
{
|
|
||||||
ip = request.getRemoteAddr();
|
|
||||||
}
|
|
||||||
|
|
||||||
return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean internalIp(String ip)
|
|
||||||
{
|
|
||||||
byte[] addr = textToNumericFormatV4(ip);
|
|
||||||
return internalIp(addr) || "127.0.0.1".equals(ip);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean internalIp(byte[] addr)
|
|
||||||
{
|
|
||||||
if (StringUtils.isNull(addr) || addr.length < 2)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
final byte b0 = addr[0];
|
|
||||||
final byte b1 = addr[1];
|
|
||||||
// 10.x.x.x/8
|
|
||||||
final byte SECTION_1 = 0x0A;
|
|
||||||
// 172.16.x.x/12
|
|
||||||
final byte SECTION_2 = (byte) 0xAC;
|
|
||||||
final byte SECTION_3 = (byte) 0x10;
|
|
||||||
final byte SECTION_4 = (byte) 0x1F;
|
|
||||||
// 192.168.x.x/16
|
|
||||||
final byte SECTION_5 = (byte) 0xC0;
|
|
||||||
final byte SECTION_6 = (byte) 0xA8;
|
|
||||||
switch (b0)
|
|
||||||
{
|
|
||||||
case SECTION_1:
|
|
||||||
return true;
|
|
||||||
case SECTION_2:
|
|
||||||
if (b1 >= SECTION_3 && b1 <= SECTION_4)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case SECTION_5:
|
|
||||||
switch (b1)
|
|
||||||
{
|
|
||||||
case SECTION_6:
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将IPv4地址转换成字节
|
|
||||||
*
|
|
||||||
* @param text IPv4地址
|
|
||||||
* @return byte 字节
|
|
||||||
*/
|
|
||||||
public static byte[] textToNumericFormatV4(String text)
|
|
||||||
{
|
|
||||||
if (text.length() == 0)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] bytes = new byte[4];
|
|
||||||
String[] elements = text.split("\\.", -1);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
long l;
|
|
||||||
int i;
|
|
||||||
switch (elements.length)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
l = Long.parseLong(elements[0]);
|
|
||||||
if ((l < 0L) || (l > 4294967295L))
|
|
||||||
return null;
|
|
||||||
bytes[0] = (byte) (int) (l >> 24 & 0xFF);
|
|
||||||
bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF);
|
|
||||||
bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
|
|
||||||
bytes[3] = (byte) (int) (l & 0xFF);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
l = Integer.parseInt(elements[0]);
|
|
||||||
if ((l < 0L) || (l > 255L))
|
|
||||||
return null;
|
|
||||||
bytes[0] = (byte) (int) (l & 0xFF);
|
|
||||||
l = Integer.parseInt(elements[1]);
|
|
||||||
if ((l < 0L) || (l > 16777215L))
|
|
||||||
return null;
|
|
||||||
bytes[1] = (byte) (int) (l >> 16 & 0xFF);
|
|
||||||
bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
|
|
||||||
bytes[3] = (byte) (int) (l & 0xFF);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
for (i = 0; i < 2; ++i)
|
|
||||||
{
|
|
||||||
l = Integer.parseInt(elements[i]);
|
|
||||||
if ((l < 0L) || (l > 255L))
|
|
||||||
return null;
|
|
||||||
bytes[i] = (byte) (int) (l & 0xFF);
|
|
||||||
}
|
|
||||||
l = Integer.parseInt(elements[2]);
|
|
||||||
if ((l < 0L) || (l > 65535L))
|
|
||||||
return null;
|
|
||||||
bytes[2] = (byte) (int) (l >> 8 & 0xFF);
|
|
||||||
bytes[3] = (byte) (int) (l & 0xFF);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
for (i = 0; i < 4; ++i)
|
|
||||||
{
|
|
||||||
l = Integer.parseInt(elements[i]);
|
|
||||||
if ((l < 0L) || (l > 255L))
|
|
||||||
return null;
|
|
||||||
bytes[i] = (byte) (int) (l & 0xFF);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (NumberFormatException e)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getHostIp()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return InetAddress.getLocalHost().getHostAddress();
|
|
||||||
}
|
|
||||||
catch (UnknownHostException e)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
return "127.0.0.1";
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getHostName()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return InetAddress.getLocalHost().getHostName();
|
|
||||||
}
|
|
||||||
catch (UnknownHostException e)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
return "未知";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,872 +0,0 @@
|
||||||
package com.ruoyi.common.utils.poi;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.text.DecimalFormat;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
|
|
||||||
import org.apache.poi.ss.usermodel.BorderStyle;
|
|
||||||
import org.apache.poi.ss.usermodel.Cell;
|
|
||||||
import org.apache.poi.ss.usermodel.CellStyle;
|
|
||||||
import org.apache.poi.ss.usermodel.CellType;
|
|
||||||
import org.apache.poi.ss.usermodel.DataValidation;
|
|
||||||
import org.apache.poi.ss.usermodel.DataValidationConstraint;
|
|
||||||
import org.apache.poi.ss.usermodel.DataValidationHelper;
|
|
||||||
import org.apache.poi.ss.usermodel.DateUtil;
|
|
||||||
import org.apache.poi.ss.usermodel.FillPatternType;
|
|
||||||
import org.apache.poi.ss.usermodel.Font;
|
|
||||||
import org.apache.poi.ss.usermodel.HorizontalAlignment;
|
|
||||||
import org.apache.poi.ss.usermodel.IndexedColors;
|
|
||||||
import org.apache.poi.ss.usermodel.Row;
|
|
||||||
import org.apache.poi.ss.usermodel.Sheet;
|
|
||||||
import org.apache.poi.ss.usermodel.VerticalAlignment;
|
|
||||||
import org.apache.poi.ss.usermodel.Workbook;
|
|
||||||
import org.apache.poi.ss.usermodel.WorkbookFactory;
|
|
||||||
import org.apache.poi.ss.util.CellRangeAddressList;
|
|
||||||
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
|
|
||||||
import org.apache.poi.xssf.usermodel.XSSFDataValidation;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
|
|
||||||
import com.ruoyi.framework.aspectj.lang.annotation.Excel.ColumnType;
|
|
||||||
import com.ruoyi.framework.aspectj.lang.annotation.Excel.Type;
|
|
||||||
import com.ruoyi.framework.aspectj.lang.annotation.Excels;
|
|
||||||
import com.ruoyi.framework.config.RuoYiConfig;
|
|
||||||
import com.ruoyi.framework.web.domain.AjaxResult;
|
|
||||||
import com.ruoyi.common.core.text.Convert;
|
|
||||||
import com.ruoyi.common.exception.CustomException;
|
|
||||||
import com.ruoyi.common.utils.DateUtils;
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
|
||||||
import com.ruoyi.common.utils.reflect.ReflectUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Excel相关处理
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class ExcelUtil<T>
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Excel sheet最大行数,默认65536
|
|
||||||
*/
|
|
||||||
public static final int sheetSize = 65536;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 工作表名称
|
|
||||||
*/
|
|
||||||
private String sheetName;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 导出类型(EXPORT:导出数据;IMPORT:导入模板)
|
|
||||||
*/
|
|
||||||
private Type type;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 工作薄对象
|
|
||||||
*/
|
|
||||||
private Workbook wb;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 工作表对象
|
|
||||||
*/
|
|
||||||
private Sheet sheet;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 样式列表
|
|
||||||
*/
|
|
||||||
private Map<String, CellStyle> styles;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 导入导出数据列表
|
|
||||||
*/
|
|
||||||
private List<T> list;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 注解列表
|
|
||||||
*/
|
|
||||||
private List<Object[]> fields;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 实体对象
|
|
||||||
*/
|
|
||||||
public Class<T> clazz;
|
|
||||||
|
|
||||||
public ExcelUtil(Class<T> clazz)
|
|
||||||
{
|
|
||||||
this.clazz = clazz;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init(List<T> list, String sheetName, Type type)
|
|
||||||
{
|
|
||||||
if (list == null)
|
|
||||||
{
|
|
||||||
list = new ArrayList<T>();
|
|
||||||
}
|
|
||||||
this.list = list;
|
|
||||||
this.sheetName = sheetName;
|
|
||||||
this.type = type;
|
|
||||||
createExcelField();
|
|
||||||
createWorkbook();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对excel表单默认第一个索引名转换成list
|
|
||||||
*
|
|
||||||
* @param is 输入流
|
|
||||||
* @return 转换后集合
|
|
||||||
*/
|
|
||||||
public List<T> importExcel(InputStream is) throws Exception
|
|
||||||
{
|
|
||||||
return importExcel(StringUtils.EMPTY, is);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对excel表单指定表格索引名转换成list
|
|
||||||
*
|
|
||||||
* @param sheetName 表格索引名
|
|
||||||
* @param is 输入流
|
|
||||||
* @return 转换后集合
|
|
||||||
*/
|
|
||||||
public List<T> importExcel(String sheetName, InputStream is) throws Exception
|
|
||||||
{
|
|
||||||
this.type = Type.IMPORT;
|
|
||||||
this.wb = WorkbookFactory.create(is);
|
|
||||||
List<T> list = new ArrayList<T>();
|
|
||||||
Sheet sheet = null;
|
|
||||||
if (StringUtils.isNotEmpty(sheetName))
|
|
||||||
{
|
|
||||||
// 如果指定sheet名,则取指定sheet中的内容.
|
|
||||||
sheet = wb.getSheet(sheetName);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 如果传入的sheet名不存在则默认指向第1个sheet.
|
|
||||||
sheet = wb.getSheetAt(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sheet == null)
|
|
||||||
{
|
|
||||||
throw new IOException("文件sheet不存在");
|
|
||||||
}
|
|
||||||
|
|
||||||
int rows = sheet.getPhysicalNumberOfRows();
|
|
||||||
|
|
||||||
if (rows > 0)
|
|
||||||
{
|
|
||||||
// 定义一个map用于存放excel列的序号和field.
|
|
||||||
Map<String, Integer> cellMap = new HashMap<String, Integer>();
|
|
||||||
// 获取表头
|
|
||||||
Row heard = sheet.getRow(0);
|
|
||||||
for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++)
|
|
||||||
{
|
|
||||||
Cell cell = heard.getCell(i);
|
|
||||||
if (StringUtils.isNotNull(cell != null))
|
|
||||||
{
|
|
||||||
String value = this.getCellValue(heard, i).toString();
|
|
||||||
cellMap.put(value, i);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cellMap.put(null, i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 有数据时才处理 得到类的所有field.
|
|
||||||
Field[] allFields = clazz.getDeclaredFields();
|
|
||||||
// 定义一个map用于存放列的序号和field.
|
|
||||||
Map<Integer, Field> fieldsMap = new HashMap<Integer, Field>();
|
|
||||||
for (int col = 0; col < allFields.length; col++)
|
|
||||||
{
|
|
||||||
Field field = allFields[col];
|
|
||||||
Excel attr = field.getAnnotation(Excel.class);
|
|
||||||
if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
|
|
||||||
{
|
|
||||||
// 设置类的私有字段属性可访问.
|
|
||||||
field.setAccessible(true);
|
|
||||||
Integer column = cellMap.get(attr.name());
|
|
||||||
fieldsMap.put(column, field);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int i = 1; i < rows; i++)
|
|
||||||
{
|
|
||||||
// 从第2行开始取数据,默认第一行是表头.
|
|
||||||
Row row = sheet.getRow(i);
|
|
||||||
T entity = null;
|
|
||||||
for (Map.Entry<Integer, Field> entry : fieldsMap.entrySet())
|
|
||||||
{
|
|
||||||
Object val = this.getCellValue(row, entry.getKey());
|
|
||||||
|
|
||||||
// 如果不存在实例则新建.
|
|
||||||
entity = (entity == null ? clazz.newInstance() : entity);
|
|
||||||
// 从map中得到对应列的field.
|
|
||||||
Field field = fieldsMap.get(entry.getKey());
|
|
||||||
// 取得类型,并根据对象类型设置值.
|
|
||||||
Class<?> fieldType = field.getType();
|
|
||||||
if (String.class == fieldType)
|
|
||||||
{
|
|
||||||
String s = Convert.toStr(val);
|
|
||||||
if (StringUtils.endsWith(s, ".0"))
|
|
||||||
{
|
|
||||||
val = StringUtils.substringBefore(s, ".0");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
val = Convert.toStr(val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ((Integer.TYPE == fieldType) || (Integer.class == fieldType))
|
|
||||||
{
|
|
||||||
val = Convert.toInt(val);
|
|
||||||
}
|
|
||||||
else if ((Long.TYPE == fieldType) || (Long.class == fieldType))
|
|
||||||
{
|
|
||||||
val = Convert.toLong(val);
|
|
||||||
}
|
|
||||||
else if ((Double.TYPE == fieldType) || (Double.class == fieldType))
|
|
||||||
{
|
|
||||||
val = Convert.toDouble(val);
|
|
||||||
}
|
|
||||||
else if ((Float.TYPE == fieldType) || (Float.class == fieldType))
|
|
||||||
{
|
|
||||||
val = Convert.toFloat(val);
|
|
||||||
}
|
|
||||||
else if (BigDecimal.class == fieldType)
|
|
||||||
{
|
|
||||||
val = Convert.toBigDecimal(val);
|
|
||||||
}
|
|
||||||
else if (Date.class == fieldType)
|
|
||||||
{
|
|
||||||
if (val instanceof String)
|
|
||||||
{
|
|
||||||
val = DateUtils.parseDate(val);
|
|
||||||
}
|
|
||||||
else if (val instanceof Double)
|
|
||||||
{
|
|
||||||
val = DateUtil.getJavaDate((Double) val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (StringUtils.isNotNull(fieldType))
|
|
||||||
{
|
|
||||||
Excel attr = field.getAnnotation(Excel.class);
|
|
||||||
String propertyName = field.getName();
|
|
||||||
if (StringUtils.isNotEmpty(attr.targetAttr()))
|
|
||||||
{
|
|
||||||
propertyName = field.getName() + "." + attr.targetAttr();
|
|
||||||
}
|
|
||||||
else if (StringUtils.isNotEmpty(attr.readConverterExp()))
|
|
||||||
{
|
|
||||||
val = reverseByExp(String.valueOf(val), attr.readConverterExp());
|
|
||||||
}
|
|
||||||
ReflectUtils.invokeSetter(entity, propertyName, val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
list.add(entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对list数据源将其里面的数据导入到excel表单
|
|
||||||
*
|
|
||||||
* @param list 导出数据集合
|
|
||||||
* @param sheetName 工作表的名称
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public AjaxResult exportExcel(List<T> list, String sheetName)
|
|
||||||
{
|
|
||||||
this.init(list, sheetName, Type.EXPORT);
|
|
||||||
return exportExcel();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对list数据源将其里面的数据导入到excel表单
|
|
||||||
*
|
|
||||||
* @param sheetName 工作表的名称
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public AjaxResult importTemplateExcel(String sheetName)
|
|
||||||
{
|
|
||||||
this.init(null, sheetName, Type.IMPORT);
|
|
||||||
return exportExcel();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 对list数据源将其里面的数据导入到excel表单
|
|
||||||
*
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public AjaxResult exportExcel()
|
|
||||||
{
|
|
||||||
OutputStream out = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 取出一共有多少个sheet.
|
|
||||||
double sheetNo = Math.ceil(list.size() / sheetSize);
|
|
||||||
for (int index = 0; index <= sheetNo; index++)
|
|
||||||
{
|
|
||||||
createSheet(sheetNo, index);
|
|
||||||
|
|
||||||
// 产生一行
|
|
||||||
Row row = sheet.createRow(0);
|
|
||||||
int column = 0;
|
|
||||||
// 写入各个字段的列头名称
|
|
||||||
for (Object[] os : fields)
|
|
||||||
{
|
|
||||||
Excel excel = (Excel) os[1];
|
|
||||||
this.createCell(excel, row, column++);
|
|
||||||
}
|
|
||||||
if (Type.EXPORT.equals(type))
|
|
||||||
{
|
|
||||||
fillExcelData(index, row);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String filename = encodingFilename(sheetName);
|
|
||||||
out = new FileOutputStream(getAbsoluteFile(filename));
|
|
||||||
wb.write(out);
|
|
||||||
return AjaxResult.success(filename);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
log.error("导出Excel异常{}", e.getMessage());
|
|
||||||
throw new CustomException("导出Excel失败,请联系网站管理员!");
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (wb != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
wb.close();
|
|
||||||
}
|
|
||||||
catch (IOException e1)
|
|
||||||
{
|
|
||||||
e1.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (out != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
out.close();
|
|
||||||
}
|
|
||||||
catch (IOException e1)
|
|
||||||
{
|
|
||||||
e1.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 填充excel数据
|
|
||||||
*
|
|
||||||
* @param index 序号
|
|
||||||
* @param row 单元格行
|
|
||||||
*/
|
|
||||||
public void fillExcelData(int index, Row row)
|
|
||||||
{
|
|
||||||
int startNo = index * sheetSize;
|
|
||||||
int endNo = Math.min(startNo + sheetSize, list.size());
|
|
||||||
for (int i = startNo; i < endNo; i++)
|
|
||||||
{
|
|
||||||
row = sheet.createRow(i + 1 - startNo);
|
|
||||||
// 得到导出对象.
|
|
||||||
T vo = (T) list.get(i);
|
|
||||||
int column = 0;
|
|
||||||
for (Object[] os : fields)
|
|
||||||
{
|
|
||||||
Field field = (Field) os[0];
|
|
||||||
Excel excel = (Excel) os[1];
|
|
||||||
// 设置实体类私有属性可访问
|
|
||||||
field.setAccessible(true);
|
|
||||||
this.addCell(excel, row, vo, field, column++);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建表格样式
|
|
||||||
*
|
|
||||||
* @param wb 工作薄对象
|
|
||||||
* @return 样式列表
|
|
||||||
*/
|
|
||||||
private Map<String, CellStyle> createStyles(Workbook wb)
|
|
||||||
{
|
|
||||||
// 写入各条记录,每条记录对应excel表中的一行
|
|
||||||
Map<String, CellStyle> styles = new HashMap<String, CellStyle>();
|
|
||||||
CellStyle style = wb.createCellStyle();
|
|
||||||
style.setAlignment(HorizontalAlignment.CENTER);
|
|
||||||
style.setVerticalAlignment(VerticalAlignment.CENTER);
|
|
||||||
style.setBorderRight(BorderStyle.THIN);
|
|
||||||
style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
|
|
||||||
style.setBorderLeft(BorderStyle.THIN);
|
|
||||||
style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
|
|
||||||
style.setBorderTop(BorderStyle.THIN);
|
|
||||||
style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
|
|
||||||
style.setBorderBottom(BorderStyle.THIN);
|
|
||||||
style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
|
|
||||||
Font dataFont = wb.createFont();
|
|
||||||
dataFont.setFontName("Arial");
|
|
||||||
dataFont.setFontHeightInPoints((short) 10);
|
|
||||||
style.setFont(dataFont);
|
|
||||||
styles.put("data", style);
|
|
||||||
|
|
||||||
style = wb.createCellStyle();
|
|
||||||
style.cloneStyleFrom(styles.get("data"));
|
|
||||||
style.setAlignment(HorizontalAlignment.CENTER);
|
|
||||||
style.setVerticalAlignment(VerticalAlignment.CENTER);
|
|
||||||
style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());
|
|
||||||
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
|
|
||||||
Font headerFont = wb.createFont();
|
|
||||||
headerFont.setFontName("Arial");
|
|
||||||
headerFont.setFontHeightInPoints((short) 10);
|
|
||||||
headerFont.setBold(true);
|
|
||||||
headerFont.setColor(IndexedColors.WHITE.getIndex());
|
|
||||||
style.setFont(headerFont);
|
|
||||||
styles.put("header", style);
|
|
||||||
|
|
||||||
return styles;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建单元格
|
|
||||||
*/
|
|
||||||
public Cell createCell(Excel attr, Row row, int column)
|
|
||||||
{
|
|
||||||
// 创建列
|
|
||||||
Cell cell = row.createCell(column);
|
|
||||||
// 写入列信息
|
|
||||||
cell.setCellValue(attr.name());
|
|
||||||
setDataValidation(attr, row, column);
|
|
||||||
cell.setCellStyle(styles.get("header"));
|
|
||||||
return cell;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置单元格信息
|
|
||||||
*
|
|
||||||
* @param value 单元格值
|
|
||||||
* @param attr 注解相关
|
|
||||||
* @param cell 单元格信息
|
|
||||||
*/
|
|
||||||
public void setCellVo(Object value, Excel attr, Cell cell)
|
|
||||||
{
|
|
||||||
if (ColumnType.STRING == attr.cellType())
|
|
||||||
{
|
|
||||||
cell.setCellType(CellType.NUMERIC);
|
|
||||||
cell.setCellValue(StringUtils.isNull(value) ? attr.defaultValue() : value + attr.suffix());
|
|
||||||
}
|
|
||||||
else if (ColumnType.NUMERIC == attr.cellType())
|
|
||||||
{
|
|
||||||
cell.setCellType(CellType.NUMERIC);
|
|
||||||
cell.setCellValue(Integer.parseInt(value + ""));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建表格样式
|
|
||||||
*/
|
|
||||||
public void setDataValidation(Excel attr, Row row, int column)
|
|
||||||
{
|
|
||||||
if (attr.name().indexOf("注:") >= 0)
|
|
||||||
{
|
|
||||||
sheet.setColumnWidth(column, 6000);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 设置列宽
|
|
||||||
sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256));
|
|
||||||
row.setHeight((short) (attr.height() * 20));
|
|
||||||
}
|
|
||||||
// 如果设置了提示信息则鼠标放上去提示.
|
|
||||||
if (StringUtils.isNotEmpty(attr.prompt()))
|
|
||||||
{
|
|
||||||
// 这里默认设了2-101列提示.
|
|
||||||
setXSSFPrompt(sheet, "", attr.prompt(), 1, 100, column, column);
|
|
||||||
}
|
|
||||||
// 如果设置了combo属性则本列只能选择不能输入
|
|
||||||
if (attr.combo().length > 0)
|
|
||||||
{
|
|
||||||
// 这里默认设了2-101列只能选择不能输入.
|
|
||||||
setXSSFValidation(sheet, attr.combo(), 1, 100, column, column);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加单元格
|
|
||||||
*/
|
|
||||||
public Cell addCell(Excel attr, Row row, T vo, Field field, int column)
|
|
||||||
{
|
|
||||||
Cell cell = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 设置行高
|
|
||||||
row.setHeight((short) (attr.height() * 20));
|
|
||||||
// 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列.
|
|
||||||
if (attr.isExport())
|
|
||||||
{
|
|
||||||
// 创建cell
|
|
||||||
cell = row.createCell(column);
|
|
||||||
cell.setCellStyle(styles.get("data"));
|
|
||||||
|
|
||||||
// 用于读取对象中的属性
|
|
||||||
Object value = getTargetValue(vo, field, attr);
|
|
||||||
String dateFormat = attr.dateFormat();
|
|
||||||
String readConverterExp = attr.readConverterExp();
|
|
||||||
if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value))
|
|
||||||
{
|
|
||||||
cell.setCellValue(DateUtils.parseDateToStr(dateFormat, (Date) value));
|
|
||||||
}
|
|
||||||
else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value))
|
|
||||||
{
|
|
||||||
cell.setCellValue(convertByExp(String.valueOf(value), readConverterExp));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 设置列类型
|
|
||||||
setCellVo(value, attr, cell);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
log.error("导出Excel失败{}", e);
|
|
||||||
}
|
|
||||||
return cell;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置 POI XSSFSheet 单元格提示
|
|
||||||
*
|
|
||||||
* @param sheet 表单
|
|
||||||
* @param promptTitle 提示标题
|
|
||||||
* @param promptContent 提示内容
|
|
||||||
* @param firstRow 开始行
|
|
||||||
* @param endRow 结束行
|
|
||||||
* @param firstCol 开始列
|
|
||||||
* @param endCol 结束列
|
|
||||||
*/
|
|
||||||
public void setXSSFPrompt(Sheet sheet, String promptTitle, String promptContent, int firstRow, int endRow,
|
|
||||||
int firstCol, int endCol)
|
|
||||||
{
|
|
||||||
DataValidationHelper helper = sheet.getDataValidationHelper();
|
|
||||||
DataValidationConstraint constraint = helper.createCustomConstraint("DD1");
|
|
||||||
CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
|
|
||||||
DataValidation dataValidation = helper.createValidation(constraint, regions);
|
|
||||||
dataValidation.createPromptBox(promptTitle, promptContent);
|
|
||||||
dataValidation.setShowPromptBox(true);
|
|
||||||
sheet.addValidationData(dataValidation);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置某些列的值只能输入预制的数据,显示下拉框.
|
|
||||||
*
|
|
||||||
* @param sheet 要设置的sheet.
|
|
||||||
* @param textlist 下拉框显示的内容
|
|
||||||
* @param firstRow 开始行
|
|
||||||
* @param endRow 结束行
|
|
||||||
* @param firstCol 开始列
|
|
||||||
* @param endCol 结束列
|
|
||||||
* @return 设置好的sheet.
|
|
||||||
*/
|
|
||||||
public void setXSSFValidation(Sheet sheet, String[] textlist, int firstRow, int endRow, int firstCol, int endCol)
|
|
||||||
{
|
|
||||||
DataValidationHelper helper = sheet.getDataValidationHelper();
|
|
||||||
// 加载下拉列表内容
|
|
||||||
DataValidationConstraint constraint = helper.createExplicitListConstraint(textlist);
|
|
||||||
// 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列
|
|
||||||
CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
|
|
||||||
// 数据有效性对象
|
|
||||||
DataValidation dataValidation = helper.createValidation(constraint, regions);
|
|
||||||
// 处理Excel兼容性问题
|
|
||||||
if (dataValidation instanceof XSSFDataValidation)
|
|
||||||
{
|
|
||||||
dataValidation.setSuppressDropDownArrow(true);
|
|
||||||
dataValidation.setShowErrorBox(true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dataValidation.setSuppressDropDownArrow(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
sheet.addValidationData(dataValidation);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 解析导出值 0=男,1=女,2=未知
|
|
||||||
*
|
|
||||||
* @param propertyValue 参数值
|
|
||||||
* @param converterExp 翻译注解
|
|
||||||
* @return 解析后值
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
public static String convertByExp(String propertyValue, String converterExp) throws Exception
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
String[] convertSource = converterExp.split(",");
|
|
||||||
for (String item : convertSource)
|
|
||||||
{
|
|
||||||
String[] itemArray = item.split("=");
|
|
||||||
if (itemArray[0].equals(propertyValue))
|
|
||||||
{
|
|
||||||
return itemArray[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
return propertyValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 反向解析值 男=0,女=1,未知=2
|
|
||||||
*
|
|
||||||
* @param propertyValue 参数值
|
|
||||||
* @param converterExp 翻译注解
|
|
||||||
* @return 解析后值
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
public static String reverseByExp(String propertyValue, String converterExp) throws Exception
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
String[] convertSource = converterExp.split(",");
|
|
||||||
for (String item : convertSource)
|
|
||||||
{
|
|
||||||
String[] itemArray = item.split("=");
|
|
||||||
if (itemArray[1].equals(propertyValue))
|
|
||||||
{
|
|
||||||
return itemArray[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
return propertyValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 编码文件名
|
|
||||||
*/
|
|
||||||
public String encodingFilename(String filename)
|
|
||||||
{
|
|
||||||
filename = UUID.randomUUID().toString() + "_" + filename + ".xlsx";
|
|
||||||
return filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取下载路径
|
|
||||||
*
|
|
||||||
* @param filename 文件名称
|
|
||||||
*/
|
|
||||||
public String getAbsoluteFile(String filename)
|
|
||||||
{
|
|
||||||
String downloadPath = RuoYiConfig.getDownloadPath() + filename;
|
|
||||||
File desc = new File(downloadPath);
|
|
||||||
if (!desc.getParentFile().exists())
|
|
||||||
{
|
|
||||||
desc.getParentFile().mkdirs();
|
|
||||||
}
|
|
||||||
return downloadPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取bean中的属性值
|
|
||||||
*
|
|
||||||
* @param vo 实体对象
|
|
||||||
* @param field 字段
|
|
||||||
* @param excel 注解
|
|
||||||
* @return 最终的属性值
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
private Object getTargetValue(T vo, Field field, Excel excel) throws Exception
|
|
||||||
{
|
|
||||||
Object o = field.get(vo);
|
|
||||||
if (StringUtils.isNotEmpty(excel.targetAttr()))
|
|
||||||
{
|
|
||||||
String target = excel.targetAttr();
|
|
||||||
if (target.indexOf(".") > -1)
|
|
||||||
{
|
|
||||||
String[] targets = target.split("[.]");
|
|
||||||
for (String name : targets)
|
|
||||||
{
|
|
||||||
o = getValue(o, name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
o = getValue(o, target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 以类的属性的get方法方法形式获取值
|
|
||||||
*
|
|
||||||
* @param o
|
|
||||||
* @param name
|
|
||||||
* @return value
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
private Object getValue(Object o, String name) throws Exception
|
|
||||||
{
|
|
||||||
if (StringUtils.isNotEmpty(name))
|
|
||||||
{
|
|
||||||
Class<?> clazz = o.getClass();
|
|
||||||
String methodName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
|
|
||||||
Method method = clazz.getMethod(methodName);
|
|
||||||
o = method.invoke(o);
|
|
||||||
}
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 得到所有定义字段
|
|
||||||
*/
|
|
||||||
private void createExcelField()
|
|
||||||
{
|
|
||||||
this.fields = new ArrayList<Object[]>();
|
|
||||||
List<Field> tempFields = new ArrayList<>();
|
|
||||||
tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
|
|
||||||
tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
|
|
||||||
for (Field field : tempFields)
|
|
||||||
{
|
|
||||||
// 单注解
|
|
||||||
if (field.isAnnotationPresent(Excel.class))
|
|
||||||
{
|
|
||||||
putToField(field, field.getAnnotation(Excel.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 多注解
|
|
||||||
if (field.isAnnotationPresent(Excels.class))
|
|
||||||
{
|
|
||||||
Excels attrs = field.getAnnotation(Excels.class);
|
|
||||||
Excel[] excels = attrs.value();
|
|
||||||
for (Excel excel : excels)
|
|
||||||
{
|
|
||||||
putToField(field, excel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 放到字段集合中
|
|
||||||
*/
|
|
||||||
private void putToField(Field field, Excel attr)
|
|
||||||
{
|
|
||||||
if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
|
|
||||||
{
|
|
||||||
this.fields.add(new Object[] { field, attr });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建一个工作簿
|
|
||||||
*/
|
|
||||||
public void createWorkbook()
|
|
||||||
{
|
|
||||||
this.wb = new SXSSFWorkbook(500);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建工作表
|
|
||||||
*
|
|
||||||
* @param sheetNo sheet数量
|
|
||||||
* @param index 序号
|
|
||||||
*/
|
|
||||||
public void createSheet(double sheetNo, int index)
|
|
||||||
{
|
|
||||||
this.sheet = wb.createSheet();
|
|
||||||
this.styles = createStyles(wb);
|
|
||||||
// 设置工作表的名称.
|
|
||||||
if (sheetNo == 0)
|
|
||||||
{
|
|
||||||
wb.setSheetName(index, sheetName);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
wb.setSheetName(index, sheetName + index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取单元格值
|
|
||||||
*
|
|
||||||
* @param row 获取的行
|
|
||||||
* @param column 获取单元格列号
|
|
||||||
* @return 单元格值
|
|
||||||
*/
|
|
||||||
public Object getCellValue(Row row, int column)
|
|
||||||
{
|
|
||||||
if (row == null)
|
|
||||||
{
|
|
||||||
return row;
|
|
||||||
}
|
|
||||||
Object val = "";
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Cell cell = row.getCell(column);
|
|
||||||
if (cell != null)
|
|
||||||
{
|
|
||||||
if (cell.getCellTypeEnum() == CellType.NUMERIC || cell.getCellTypeEnum() == CellType.FORMULA)
|
|
||||||
{
|
|
||||||
val = cell.getNumericCellValue();
|
|
||||||
if (HSSFDateUtil.isCellDateFormatted(cell))
|
|
||||||
{
|
|
||||||
val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ((Double) val % 1 > 0)
|
|
||||||
{
|
|
||||||
val = new DecimalFormat("0.00").format(val);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
val = new DecimalFormat("0").format(val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (cell.getCellTypeEnum() == CellType.STRING)
|
|
||||||
{
|
|
||||||
val = cell.getStringCellValue();
|
|
||||||
}
|
|
||||||
else if (cell.getCellTypeEnum() == CellType.BOOLEAN)
|
|
||||||
{
|
|
||||||
val = cell.getBooleanCellValue();
|
|
||||||
}
|
|
||||||
else if (cell.getCellTypeEnum() == CellType.ERROR)
|
|
||||||
{
|
|
||||||
val = cell.getErrorCellValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,406 +0,0 @@
|
||||||
package com.ruoyi.common.utils.reflect;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.lang.reflect.ParameterizedType;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.util.Date;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.apache.commons.lang3.Validate;
|
|
||||||
import org.apache.poi.ss.usermodel.DateUtil;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import com.ruoyi.common.core.text.Convert;
|
|
||||||
import com.ruoyi.common.utils.DateUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("rawtypes")
|
|
||||||
public class ReflectUtils
|
|
||||||
{
|
|
||||||
private static final String SETTER_PREFIX = "set";
|
|
||||||
|
|
||||||
private static final String GETTER_PREFIX = "get";
|
|
||||||
|
|
||||||
private static final String CGLIB_CLASS_SEPARATOR = "$$";
|
|
||||||
|
|
||||||
private static Logger logger = LoggerFactory.getLogger(ReflectUtils.class);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 调用Getter方法.
|
|
||||||
* 支持多级,如:对象名.对象名.方法
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static <E> E invokeGetter(Object obj, String propertyName)
|
|
||||||
{
|
|
||||||
Object object = obj;
|
|
||||||
for (String name : StringUtils.split(propertyName, "."))
|
|
||||||
{
|
|
||||||
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name);
|
|
||||||
object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
|
|
||||||
}
|
|
||||||
return (E) object;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 调用Setter方法, 仅匹配方法名。
|
|
||||||
* 支持多级,如:对象名.对象名.方法
|
|
||||||
*/
|
|
||||||
public static <E> void invokeSetter(Object obj, String propertyName, E value)
|
|
||||||
{
|
|
||||||
Object object = obj;
|
|
||||||
String[] names = StringUtils.split(propertyName, ".");
|
|
||||||
for (int i = 0; i < names.length; i++)
|
|
||||||
{
|
|
||||||
if (i < names.length - 1)
|
|
||||||
{
|
|
||||||
String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
|
|
||||||
object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
|
|
||||||
invokeMethodByName(object, setterMethodName, new Object[] { value });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static <E> E getFieldValue(final Object obj, final String fieldName)
|
|
||||||
{
|
|
||||||
Field field = getAccessibleField(obj, fieldName);
|
|
||||||
if (field == null)
|
|
||||||
{
|
|
||||||
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
E result = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
result = (E) field.get(obj);
|
|
||||||
}
|
|
||||||
catch (IllegalAccessException e)
|
|
||||||
{
|
|
||||||
logger.error("不可能抛出的异常{}", e.getMessage());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数.
|
|
||||||
*/
|
|
||||||
public static <E> void setFieldValue(final Object obj, final String fieldName, final E value)
|
|
||||||
{
|
|
||||||
Field field = getAccessibleField(obj, fieldName);
|
|
||||||
if (field == null)
|
|
||||||
{
|
|
||||||
// throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
|
|
||||||
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
field.set(obj, value);
|
|
||||||
}
|
|
||||||
catch (IllegalAccessException e)
|
|
||||||
{
|
|
||||||
logger.error("不可能抛出的异常: {}", e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 直接调用对象方法, 无视private/protected修饰符.
|
|
||||||
* 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用.
|
|
||||||
* 同时匹配方法名+参数类型,
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static <E> E invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,
|
|
||||||
final Object[] args)
|
|
||||||
{
|
|
||||||
if (obj == null || methodName == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Method method = getAccessibleMethod(obj, methodName, parameterTypes);
|
|
||||||
if (method == null)
|
|
||||||
{
|
|
||||||
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return (E) method.invoke(obj, args);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
|
|
||||||
throw convertReflectionExceptionToUnchecked(msg, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 直接调用对象方法, 无视private/protected修饰符,
|
|
||||||
* 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用.
|
|
||||||
* 只匹配函数名,如果有多个同名函数调用第一个。
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static <E> E invokeMethodByName(final Object obj, final String methodName, final Object[] args)
|
|
||||||
{
|
|
||||||
Method method = getAccessibleMethodByName(obj, methodName, args.length);
|
|
||||||
if (method == null)
|
|
||||||
{
|
|
||||||
// 如果为空不报错,直接返回空。
|
|
||||||
logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 类型转换(将参数数据类型转换为目标方法参数类型)
|
|
||||||
Class<?>[] cs = method.getParameterTypes();
|
|
||||||
for (int i = 0; i < cs.length; i++)
|
|
||||||
{
|
|
||||||
if (args[i] != null && !args[i].getClass().equals(cs[i]))
|
|
||||||
{
|
|
||||||
if (cs[i] == String.class)
|
|
||||||
{
|
|
||||||
args[i] = Convert.toStr(args[i]);
|
|
||||||
if (StringUtils.endsWith((String) args[i], ".0"))
|
|
||||||
{
|
|
||||||
args[i] = StringUtils.substringBefore((String) args[i], ".0");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (cs[i] == Integer.class)
|
|
||||||
{
|
|
||||||
args[i] = Convert.toInt(args[i]);
|
|
||||||
}
|
|
||||||
else if (cs[i] == Long.class)
|
|
||||||
{
|
|
||||||
args[i] = Convert.toLong(args[i]);
|
|
||||||
}
|
|
||||||
else if (cs[i] == Double.class)
|
|
||||||
{
|
|
||||||
args[i] = Convert.toDouble(args[i]);
|
|
||||||
}
|
|
||||||
else if (cs[i] == Float.class)
|
|
||||||
{
|
|
||||||
args[i] = Convert.toFloat(args[i]);
|
|
||||||
}
|
|
||||||
else if (cs[i] == Date.class)
|
|
||||||
{
|
|
||||||
if (args[i] instanceof String)
|
|
||||||
{
|
|
||||||
args[i] = DateUtils.parseDate(args[i]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
args[i] = DateUtil.getJavaDate((Double) args[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (E) method.invoke(obj, args);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
|
|
||||||
throw convertReflectionExceptionToUnchecked(msg, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
|
|
||||||
* 如向上转型到Object仍无法找到, 返回null.
|
|
||||||
*/
|
|
||||||
public static Field getAccessibleField(final Object obj, final String fieldName)
|
|
||||||
{
|
|
||||||
// 为空不报错。直接返回 null
|
|
||||||
if (obj == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Validate.notBlank(fieldName, "fieldName can't be blank");
|
|
||||||
for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Field field = superClass.getDeclaredField(fieldName);
|
|
||||||
makeAccessible(field);
|
|
||||||
return field;
|
|
||||||
}
|
|
||||||
catch (NoSuchFieldException e)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
|
|
||||||
* 如向上转型到Object仍无法找到, 返回null.
|
|
||||||
* 匹配函数名+参数类型。
|
|
||||||
* 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
|
|
||||||
*/
|
|
||||||
public static Method getAccessibleMethod(final Object obj, final String methodName,
|
|
||||||
final Class<?>... parameterTypes)
|
|
||||||
{
|
|
||||||
// 为空不报错。直接返回 null
|
|
||||||
if (obj == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Validate.notBlank(methodName, "methodName can't be blank");
|
|
||||||
for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
|
|
||||||
makeAccessible(method);
|
|
||||||
return method;
|
|
||||||
}
|
|
||||||
catch (NoSuchMethodException e)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
|
|
||||||
* 如向上转型到Object仍无法找到, 返回null.
|
|
||||||
* 只匹配函数名。
|
|
||||||
* 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
|
|
||||||
*/
|
|
||||||
public static Method getAccessibleMethodByName(final Object obj, final String methodName, int argsNum)
|
|
||||||
{
|
|
||||||
// 为空不报错。直接返回 null
|
|
||||||
if (obj == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Validate.notBlank(methodName, "methodName can't be blank");
|
|
||||||
for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass())
|
|
||||||
{
|
|
||||||
Method[] methods = searchType.getDeclaredMethods();
|
|
||||||
for (Method method : methods)
|
|
||||||
{
|
|
||||||
if (method.getName().equals(methodName) && method.getParameterTypes().length == argsNum)
|
|
||||||
{
|
|
||||||
makeAccessible(method);
|
|
||||||
return method;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
|
|
||||||
*/
|
|
||||||
public static void makeAccessible(Method method)
|
|
||||||
{
|
|
||||||
if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
|
|
||||||
&& !method.isAccessible())
|
|
||||||
{
|
|
||||||
method.setAccessible(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
|
|
||||||
*/
|
|
||||||
public static void makeAccessible(Field field)
|
|
||||||
{
|
|
||||||
if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())
|
|
||||||
|| Modifier.isFinal(field.getModifiers())) && !field.isAccessible())
|
|
||||||
{
|
|
||||||
field.setAccessible(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处
|
|
||||||
* 如无法找到, 返回Object.class.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static <T> Class<T> getClassGenricType(final Class clazz)
|
|
||||||
{
|
|
||||||
return getClassGenricType(clazz, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通过反射, 获得Class定义中声明的父类的泛型参数的类型.
|
|
||||||
* 如无法找到, 返回Object.class.
|
|
||||||
*/
|
|
||||||
public static Class getClassGenricType(final Class clazz, final int index)
|
|
||||||
{
|
|
||||||
Type genType = clazz.getGenericSuperclass();
|
|
||||||
|
|
||||||
if (!(genType instanceof ParameterizedType))
|
|
||||||
{
|
|
||||||
logger.debug(clazz.getSimpleName() + "'s superclass not ParameterizedType");
|
|
||||||
return Object.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
|
|
||||||
|
|
||||||
if (index >= params.length || index < 0)
|
|
||||||
{
|
|
||||||
logger.debug("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
|
|
||||||
+ params.length);
|
|
||||||
return Object.class;
|
|
||||||
}
|
|
||||||
if (!(params[index] instanceof Class))
|
|
||||||
{
|
|
||||||
logger.debug(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
|
|
||||||
return Object.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (Class) params[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Class<?> getUserClass(Object instance)
|
|
||||||
{
|
|
||||||
if (instance == null)
|
|
||||||
{
|
|
||||||
throw new RuntimeException("Instance must not be null");
|
|
||||||
}
|
|
||||||
Class clazz = instance.getClass();
|
|
||||||
if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR))
|
|
||||||
{
|
|
||||||
Class<?> superClass = clazz.getSuperclass();
|
|
||||||
if (superClass != null && !Object.class.equals(superClass))
|
|
||||||
{
|
|
||||||
return superClass;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return clazz;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将反射时的checked exception转换为unchecked exception.
|
|
||||||
*/
|
|
||||||
public static RuntimeException convertReflectionExceptionToUnchecked(String msg, Exception e)
|
|
||||||
{
|
|
||||||
if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException
|
|
||||||
|| e instanceof NoSuchMethodException)
|
|
||||||
{
|
|
||||||
return new IllegalArgumentException(msg, e);
|
|
||||||
}
|
|
||||||
else if (e instanceof InvocationTargetException)
|
|
||||||
{
|
|
||||||
return new RuntimeException(msg, ((InvocationTargetException) e).getTargetException());
|
|
||||||
}
|
|
||||||
return new RuntimeException(msg, e);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,66 +0,0 @@
|
||||||
package com.ruoyi.common.utils.security;
|
|
||||||
|
|
||||||
import java.security.MessageDigest;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Md5加密方法
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class Md5Utils
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(Md5Utils.class);
|
|
||||||
|
|
||||||
private static byte[] md5(String s)
|
|
||||||
{
|
|
||||||
MessageDigest algorithm;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
algorithm = MessageDigest.getInstance("MD5");
|
|
||||||
algorithm.reset();
|
|
||||||
algorithm.update(s.getBytes("UTF-8"));
|
|
||||||
byte[] messageDigest = algorithm.digest();
|
|
||||||
return messageDigest;
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
log.error("MD5 Error...", e);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String toHex(byte hash[])
|
|
||||||
{
|
|
||||||
if (hash == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
StringBuffer buf = new StringBuffer(hash.length * 2);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < hash.length; i++)
|
|
||||||
{
|
|
||||||
if ((hash[i] & 0xff) < 0x10)
|
|
||||||
{
|
|
||||||
buf.append("0");
|
|
||||||
}
|
|
||||||
buf.append(Long.toString(hash[i] & 0xff, 16));
|
|
||||||
}
|
|
||||||
return buf.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String hash(String s)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return new String(toHex(md5(s)).getBytes("UTF-8"), "UTF-8");
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
log.error("not supported charset...{}", e);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,291 +0,0 @@
|
||||||
package com.ruoyi.common.utils.sign;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base64工具类
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public final class Base64
|
|
||||||
{
|
|
||||||
static private final int BASELENGTH = 128;
|
|
||||||
static private final int LOOKUPLENGTH = 64;
|
|
||||||
static private final int TWENTYFOURBITGROUP = 24;
|
|
||||||
static private final int EIGHTBIT = 8;
|
|
||||||
static private final int SIXTEENBIT = 16;
|
|
||||||
static private final int FOURBYTE = 4;
|
|
||||||
static private final int SIGN = -128;
|
|
||||||
static private final char PAD = '=';
|
|
||||||
static final private byte[] base64Alphabet = new byte[BASELENGTH];
|
|
||||||
static final private char[] lookUpBase64Alphabet = new char[LOOKUPLENGTH];
|
|
||||||
|
|
||||||
static
|
|
||||||
{
|
|
||||||
for (int i = 0; i < BASELENGTH; ++i)
|
|
||||||
{
|
|
||||||
base64Alphabet[i] = -1;
|
|
||||||
}
|
|
||||||
for (int i = 'Z'; i >= 'A'; i--)
|
|
||||||
{
|
|
||||||
base64Alphabet[i] = (byte) (i - 'A');
|
|
||||||
}
|
|
||||||
for (int i = 'z'; i >= 'a'; i--)
|
|
||||||
{
|
|
||||||
base64Alphabet[i] = (byte) (i - 'a' + 26);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = '9'; i >= '0'; i--)
|
|
||||||
{
|
|
||||||
base64Alphabet[i] = (byte) (i - '0' + 52);
|
|
||||||
}
|
|
||||||
|
|
||||||
base64Alphabet['+'] = 62;
|
|
||||||
base64Alphabet['/'] = 63;
|
|
||||||
|
|
||||||
for (int i = 0; i <= 25; i++)
|
|
||||||
{
|
|
||||||
lookUpBase64Alphabet[i] = (char) ('A' + i);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 26, j = 0; i <= 51; i++, j++)
|
|
||||||
{
|
|
||||||
lookUpBase64Alphabet[i] = (char) ('a' + j);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 52, j = 0; i <= 61; i++, j++)
|
|
||||||
{
|
|
||||||
lookUpBase64Alphabet[i] = (char) ('0' + j);
|
|
||||||
}
|
|
||||||
lookUpBase64Alphabet[62] = (char) '+';
|
|
||||||
lookUpBase64Alphabet[63] = (char) '/';
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isWhiteSpace(char octect)
|
|
||||||
{
|
|
||||||
return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isPad(char octect)
|
|
||||||
{
|
|
||||||
return (octect == PAD);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isData(char octect)
|
|
||||||
{
|
|
||||||
return (octect < BASELENGTH && base64Alphabet[octect] != -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Encodes hex octects into Base64
|
|
||||||
*
|
|
||||||
* @param binaryData Array containing binaryData
|
|
||||||
* @return Encoded Base64 array
|
|
||||||
*/
|
|
||||||
public static String encode(byte[] binaryData)
|
|
||||||
{
|
|
||||||
if (binaryData == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lengthDataBits = binaryData.length * EIGHTBIT;
|
|
||||||
if (lengthDataBits == 0)
|
|
||||||
{
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
|
|
||||||
int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
|
|
||||||
int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 : numberTriplets;
|
|
||||||
char encodedData[] = null;
|
|
||||||
|
|
||||||
encodedData = new char[numberQuartet * 4];
|
|
||||||
|
|
||||||
byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
|
|
||||||
|
|
||||||
int encodedIndex = 0;
|
|
||||||
int dataIndex = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < numberTriplets; i++)
|
|
||||||
{
|
|
||||||
b1 = binaryData[dataIndex++];
|
|
||||||
b2 = binaryData[dataIndex++];
|
|
||||||
b3 = binaryData[dataIndex++];
|
|
||||||
|
|
||||||
l = (byte) (b2 & 0x0f);
|
|
||||||
k = (byte) (b1 & 0x03);
|
|
||||||
|
|
||||||
byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
|
|
||||||
byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
|
|
||||||
byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc);
|
|
||||||
|
|
||||||
encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
|
|
||||||
encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
|
|
||||||
encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3];
|
|
||||||
encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];
|
|
||||||
}
|
|
||||||
|
|
||||||
// form integral number of 6-bit groups
|
|
||||||
if (fewerThan24bits == EIGHTBIT)
|
|
||||||
{
|
|
||||||
b1 = binaryData[dataIndex];
|
|
||||||
k = (byte) (b1 & 0x03);
|
|
||||||
byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
|
|
||||||
encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
|
|
||||||
encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4];
|
|
||||||
encodedData[encodedIndex++] = PAD;
|
|
||||||
encodedData[encodedIndex++] = PAD;
|
|
||||||
}
|
|
||||||
else if (fewerThan24bits == SIXTEENBIT)
|
|
||||||
{
|
|
||||||
b1 = binaryData[dataIndex];
|
|
||||||
b2 = binaryData[dataIndex + 1];
|
|
||||||
l = (byte) (b2 & 0x0f);
|
|
||||||
k = (byte) (b1 & 0x03);
|
|
||||||
|
|
||||||
byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
|
|
||||||
byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
|
|
||||||
|
|
||||||
encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
|
|
||||||
encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
|
|
||||||
encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2];
|
|
||||||
encodedData[encodedIndex++] = PAD;
|
|
||||||
}
|
|
||||||
return new String(encodedData);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decodes Base64 data into octects
|
|
||||||
*
|
|
||||||
* @param encoded string containing Base64 data
|
|
||||||
* @return Array containind decoded data.
|
|
||||||
*/
|
|
||||||
public static byte[] decode(String encoded)
|
|
||||||
{
|
|
||||||
if (encoded == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
char[] base64Data = encoded.toCharArray();
|
|
||||||
// remove white spaces
|
|
||||||
int len = removeWhiteSpace(base64Data);
|
|
||||||
|
|
||||||
if (len % FOURBYTE != 0)
|
|
||||||
{
|
|
||||||
return null;// should be divisible by four
|
|
||||||
}
|
|
||||||
|
|
||||||
int numberQuadruple = (len / FOURBYTE);
|
|
||||||
|
|
||||||
if (numberQuadruple == 0)
|
|
||||||
{
|
|
||||||
return new byte[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
byte decodedData[] = null;
|
|
||||||
byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;
|
|
||||||
char d1 = 0, d2 = 0, d3 = 0, d4 = 0;
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
int encodedIndex = 0;
|
|
||||||
int dataIndex = 0;
|
|
||||||
decodedData = new byte[(numberQuadruple) * 3];
|
|
||||||
|
|
||||||
for (; i < numberQuadruple - 1; i++)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))
|
|
||||||
|| !isData((d3 = base64Data[dataIndex++])) || !isData((d4 = base64Data[dataIndex++])))
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
} // if found "no data" just return null
|
|
||||||
|
|
||||||
b1 = base64Alphabet[d1];
|
|
||||||
b2 = base64Alphabet[d2];
|
|
||||||
b3 = base64Alphabet[d3];
|
|
||||||
b4 = base64Alphabet[d4];
|
|
||||||
|
|
||||||
decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
|
|
||||||
decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
|
|
||||||
decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++])))
|
|
||||||
{
|
|
||||||
return null;// if found "no data" just return null
|
|
||||||
}
|
|
||||||
|
|
||||||
b1 = base64Alphabet[d1];
|
|
||||||
b2 = base64Alphabet[d2];
|
|
||||||
|
|
||||||
d3 = base64Data[dataIndex++];
|
|
||||||
d4 = base64Data[dataIndex++];
|
|
||||||
if (!isData((d3)) || !isData((d4)))
|
|
||||||
{// Check if they are PAD characters
|
|
||||||
if (isPad(d3) && isPad(d4))
|
|
||||||
{
|
|
||||||
if ((b2 & 0xf) != 0)// last 4 bits should be zero
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
byte[] tmp = new byte[i * 3 + 1];
|
|
||||||
System.arraycopy(decodedData, 0, tmp, 0, i * 3);
|
|
||||||
tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
else if (!isPad(d3) && isPad(d4))
|
|
||||||
{
|
|
||||||
b3 = base64Alphabet[d3];
|
|
||||||
if ((b3 & 0x3) != 0)// last 2 bits should be zero
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
byte[] tmp = new byte[i * 3 + 2];
|
|
||||||
System.arraycopy(decodedData, 0, tmp, 0, i * 3);
|
|
||||||
tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
|
|
||||||
tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ // No PAD e.g 3cQl
|
|
||||||
b3 = base64Alphabet[d3];
|
|
||||||
b4 = base64Alphabet[d4];
|
|
||||||
decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
|
|
||||||
decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
|
|
||||||
decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
|
|
||||||
|
|
||||||
}
|
|
||||||
return decodedData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* remove WhiteSpace from MIME containing encoded Base64 data.
|
|
||||||
*
|
|
||||||
* @param data the byte array of base64 data (with WS)
|
|
||||||
* @return the new length
|
|
||||||
*/
|
|
||||||
private static int removeWhiteSpace(char[] data)
|
|
||||||
{
|
|
||||||
if (data == null)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// count characters that's not whitespace
|
|
||||||
int newSize = 0;
|
|
||||||
int len = data.length;
|
|
||||||
for (int i = 0; i < len; i++)
|
|
||||||
{
|
|
||||||
if (!isWhiteSpace(data[i]))
|
|
||||||
{
|
|
||||||
data[newSize++] = data[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return newSize;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,114 +0,0 @@
|
||||||
package com.ruoyi.common.utils.spring;
|
|
||||||
|
|
||||||
import org.springframework.aop.framework.AopContext;
|
|
||||||
import org.springframework.beans.BeansException;
|
|
||||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
|
||||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
|
||||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* spring工具类 方便在非spring管理环境中获取bean
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public final class SpringUtils implements BeanFactoryPostProcessor
|
|
||||||
{
|
|
||||||
/** Spring应用上下文环境 */
|
|
||||||
private static ConfigurableListableBeanFactory beanFactory;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException
|
|
||||||
{
|
|
||||||
SpringUtils.beanFactory = beanFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取对象
|
|
||||||
*
|
|
||||||
* @param name
|
|
||||||
* @return Object 一个以所给名字注册的bean的实例
|
|
||||||
* @throws org.springframework.beans.BeansException
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static <T> T getBean(String name) throws BeansException
|
|
||||||
{
|
|
||||||
return (T) beanFactory.getBean(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取类型为requiredType的对象
|
|
||||||
*
|
|
||||||
* @param clz
|
|
||||||
* @return
|
|
||||||
* @throws org.springframework.beans.BeansException
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static <T> T getBean(Class<T> clz) throws BeansException
|
|
||||||
{
|
|
||||||
T result = (T) beanFactory.getBean(clz);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
|
|
||||||
*
|
|
||||||
* @param name
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public static boolean containsBean(String name)
|
|
||||||
{
|
|
||||||
return beanFactory.containsBean(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
|
|
||||||
*
|
|
||||||
* @param name
|
|
||||||
* @return boolean
|
|
||||||
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException
|
|
||||||
{
|
|
||||||
return beanFactory.isSingleton(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param name
|
|
||||||
* @return Class 注册对象的类型
|
|
||||||
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static Class<?> getType(String name) throws NoSuchBeanDefinitionException
|
|
||||||
{
|
|
||||||
return beanFactory.getType(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 如果给定的bean名字在bean定义中有别名,则返回这些别名
|
|
||||||
*
|
|
||||||
* @param name
|
|
||||||
* @return
|
|
||||||
* @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public static String[] getAliases(String name) throws NoSuchBeanDefinitionException
|
|
||||||
{
|
|
||||||
return beanFactory.getAliases(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取aop代理对象
|
|
||||||
*
|
|
||||||
* @param invoker
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static <T> T getAopProxy(T invoker)
|
|
||||||
{
|
|
||||||
return (T) AopContext.currentProxy();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,36 +0,0 @@
|
||||||
package com.ruoyi.common.utils.sql;
|
|
||||||
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* sql操作工具类
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class SqlUtil
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 仅支持字母、数字、下划线、空格、逗号(支持多个字段排序)
|
|
||||||
*/
|
|
||||||
public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,]+";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查字符,防止注入绕过
|
|
||||||
*/
|
|
||||||
public static String escapeOrderBySql(String value)
|
|
||||||
{
|
|
||||||
if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value))
|
|
||||||
{
|
|
||||||
return StringUtils.EMPTY;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证 order by 语法是否符合规范
|
|
||||||
*/
|
|
||||||
public static boolean isValidOrderBySql(String value)
|
|
||||||
{
|
|
||||||
return value.matches(SQL_PATTERN);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,87 +0,0 @@
|
||||||
package com.ruoyi.common.utils.text;
|
|
||||||
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 字符集工具类
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class CharsetKit
|
|
||||||
{
|
|
||||||
/** ISO-8859-1 */
|
|
||||||
public static final String ISO_8859_1 = "ISO-8859-1";
|
|
||||||
/** UTF-8 */
|
|
||||||
public static final String UTF_8 = "UTF-8";
|
|
||||||
/** GBK */
|
|
||||||
public static final String GBK = "GBK";
|
|
||||||
|
|
||||||
/** ISO-8859-1 */
|
|
||||||
public static final Charset CHARSET_ISO_8859_1 = Charset.forName(ISO_8859_1);
|
|
||||||
/** UTF-8 */
|
|
||||||
public static final Charset CHARSET_UTF_8 = Charset.forName(UTF_8);
|
|
||||||
/** GBK */
|
|
||||||
public static final Charset CHARSET_GBK = Charset.forName(GBK);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为Charset对象
|
|
||||||
*
|
|
||||||
* @param charset 字符集,为空则返回默认字符集
|
|
||||||
* @return Charset
|
|
||||||
*/
|
|
||||||
public static Charset charset(String charset)
|
|
||||||
{
|
|
||||||
return StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换字符串的字符集编码
|
|
||||||
*
|
|
||||||
* @param source 字符串
|
|
||||||
* @param srcCharset 源字符集,默认ISO-8859-1
|
|
||||||
* @param destCharset 目标字符集,默认UTF-8
|
|
||||||
* @return 转换后的字符集
|
|
||||||
*/
|
|
||||||
public static String convert(String source, String srcCharset, String destCharset)
|
|
||||||
{
|
|
||||||
return convert(source, Charset.forName(srcCharset), Charset.forName(destCharset));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换字符串的字符集编码
|
|
||||||
*
|
|
||||||
* @param source 字符串
|
|
||||||
* @param srcCharset 源字符集,默认ISO-8859-1
|
|
||||||
* @param destCharset 目标字符集,默认UTF-8
|
|
||||||
* @return 转换后的字符集
|
|
||||||
*/
|
|
||||||
public static String convert(String source, Charset srcCharset, Charset destCharset)
|
|
||||||
{
|
|
||||||
if (null == srcCharset)
|
|
||||||
{
|
|
||||||
srcCharset = StandardCharsets.ISO_8859_1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null == destCharset)
|
|
||||||
{
|
|
||||||
srcCharset = StandardCharsets.UTF_8;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StringUtils.isEmpty(source) || srcCharset.equals(destCharset))
|
|
||||||
{
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
return new String(source.getBytes(srcCharset), destCharset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return 系统字符集编码
|
|
||||||
*/
|
|
||||||
public static String systemCharset()
|
|
||||||
{
|
|
||||||
return Charset.defaultCharset().name();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,999 +0,0 @@
|
||||||
package com.ruoyi.common.utils.text;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.text.NumberFormat;
|
|
||||||
import java.util.Set;
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 类型转换器
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class Convert
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 转换为字符串<br>
|
|
||||||
* 如果给定的值为null,或者转换失败,返回默认值<br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @param defaultValue 转换错误时的默认值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static String toStr(Object value, String defaultValue)
|
|
||||||
{
|
|
||||||
if (null == value)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
if (value instanceof String)
|
|
||||||
{
|
|
||||||
return (String) value;
|
|
||||||
}
|
|
||||||
return value.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为字符串<br>
|
|
||||||
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static String toStr(Object value)
|
|
||||||
{
|
|
||||||
return toStr(value, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为字符<br>
|
|
||||||
* 如果给定的值为null,或者转换失败,返回默认值<br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @param defaultValue 转换错误时的默认值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Character toChar(Object value, Character defaultValue)
|
|
||||||
{
|
|
||||||
if (null == value)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
if (value instanceof Character)
|
|
||||||
{
|
|
||||||
return (Character) value;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String valueStr = toStr(value, null);
|
|
||||||
return StringUtils.isEmpty(valueStr) ? defaultValue : valueStr.charAt(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为字符<br>
|
|
||||||
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Character toChar(Object value)
|
|
||||||
{
|
|
||||||
return toChar(value, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为byte<br>
|
|
||||||
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @param defaultValue 转换错误时的默认值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Byte toByte(Object value, Byte defaultValue)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
if (value instanceof Byte)
|
|
||||||
{
|
|
||||||
return (Byte) value;
|
|
||||||
}
|
|
||||||
if (value instanceof Number)
|
|
||||||
{
|
|
||||||
return ((Number) value).byteValue();
|
|
||||||
}
|
|
||||||
final String valueStr = toStr(value, null);
|
|
||||||
if (StringUtils.isEmpty(valueStr))
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return Byte.parseByte(valueStr);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为byte<br>
|
|
||||||
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Byte toByte(Object value)
|
|
||||||
{
|
|
||||||
return toByte(value, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为Short<br>
|
|
||||||
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @param defaultValue 转换错误时的默认值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Short toShort(Object value, Short defaultValue)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
if (value instanceof Short)
|
|
||||||
{
|
|
||||||
return (Short) value;
|
|
||||||
}
|
|
||||||
if (value instanceof Number)
|
|
||||||
{
|
|
||||||
return ((Number) value).shortValue();
|
|
||||||
}
|
|
||||||
final String valueStr = toStr(value, null);
|
|
||||||
if (StringUtils.isEmpty(valueStr))
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return Short.parseShort(valueStr.trim());
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为Short<br>
|
|
||||||
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Short toShort(Object value)
|
|
||||||
{
|
|
||||||
return toShort(value, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为Number<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @param defaultValue 转换错误时的默认值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Number toNumber(Object value, Number defaultValue)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
if (value instanceof Number)
|
|
||||||
{
|
|
||||||
return (Number) value;
|
|
||||||
}
|
|
||||||
final String valueStr = toStr(value, null);
|
|
||||||
if (StringUtils.isEmpty(valueStr))
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return NumberFormat.getInstance().parse(valueStr);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为Number<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Number toNumber(Object value)
|
|
||||||
{
|
|
||||||
return toNumber(value, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为int<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @param defaultValue 转换错误时的默认值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Integer toInt(Object value, Integer defaultValue)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
if (value instanceof Integer)
|
|
||||||
{
|
|
||||||
return (Integer) value;
|
|
||||||
}
|
|
||||||
if (value instanceof Number)
|
|
||||||
{
|
|
||||||
return ((Number) value).intValue();
|
|
||||||
}
|
|
||||||
final String valueStr = toStr(value, null);
|
|
||||||
if (StringUtils.isEmpty(valueStr))
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return Integer.parseInt(valueStr.trim());
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为int<br>
|
|
||||||
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Integer toInt(Object value)
|
|
||||||
{
|
|
||||||
return toInt(value, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为Integer数组<br>
|
|
||||||
*
|
|
||||||
* @param str 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Integer[] toIntArray(String str)
|
|
||||||
{
|
|
||||||
return toIntArray(",", str);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为Long数组<br>
|
|
||||||
*
|
|
||||||
* @param str 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Long[] toLongArray(String str)
|
|
||||||
{
|
|
||||||
return toLongArray(",", str);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为Integer数组<br>
|
|
||||||
*
|
|
||||||
* @param split 分隔符
|
|
||||||
* @param split 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Integer[] toIntArray(String split, String str)
|
|
||||||
{
|
|
||||||
if (StringUtils.isEmpty(str))
|
|
||||||
{
|
|
||||||
return new Integer[] {};
|
|
||||||
}
|
|
||||||
String[] arr = str.split(split);
|
|
||||||
final Integer[] ints = new Integer[arr.length];
|
|
||||||
for (int i = 0; i < arr.length; i++)
|
|
||||||
{
|
|
||||||
final Integer v = toInt(arr[i], 0);
|
|
||||||
ints[i] = v;
|
|
||||||
}
|
|
||||||
return ints;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为Long数组<br>
|
|
||||||
*
|
|
||||||
* @param split 分隔符
|
|
||||||
* @param str 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Long[] toLongArray(String split, String str)
|
|
||||||
{
|
|
||||||
if (StringUtils.isEmpty(str))
|
|
||||||
{
|
|
||||||
return new Long[] {};
|
|
||||||
}
|
|
||||||
String[] arr = str.split(split);
|
|
||||||
final Long[] longs = new Long[arr.length];
|
|
||||||
for (int i = 0; i < arr.length; i++)
|
|
||||||
{
|
|
||||||
final Long v = toLong(arr[i], null);
|
|
||||||
longs[i] = v;
|
|
||||||
}
|
|
||||||
return longs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为String数组<br>
|
|
||||||
*
|
|
||||||
* @param str 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static String[] toStrArray(String str)
|
|
||||||
{
|
|
||||||
return toStrArray(",", str);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为String数组<br>
|
|
||||||
*
|
|
||||||
* @param split 分隔符
|
|
||||||
* @param split 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static String[] toStrArray(String split, String str)
|
|
||||||
{
|
|
||||||
return str.split(split);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为long<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @param defaultValue 转换错误时的默认值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Long toLong(Object value, Long defaultValue)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
if (value instanceof Long)
|
|
||||||
{
|
|
||||||
return (Long) value;
|
|
||||||
}
|
|
||||||
if (value instanceof Number)
|
|
||||||
{
|
|
||||||
return ((Number) value).longValue();
|
|
||||||
}
|
|
||||||
final String valueStr = toStr(value, null);
|
|
||||||
if (StringUtils.isEmpty(valueStr))
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 支持科学计数法
|
|
||||||
return new BigDecimal(valueStr.trim()).longValue();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为long<br>
|
|
||||||
* 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Long toLong(Object value)
|
|
||||||
{
|
|
||||||
return toLong(value, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为double<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @param defaultValue 转换错误时的默认值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Double toDouble(Object value, Double defaultValue)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
if (value instanceof Double)
|
|
||||||
{
|
|
||||||
return (Double) value;
|
|
||||||
}
|
|
||||||
if (value instanceof Number)
|
|
||||||
{
|
|
||||||
return ((Number) value).doubleValue();
|
|
||||||
}
|
|
||||||
final String valueStr = toStr(value, null);
|
|
||||||
if (StringUtils.isEmpty(valueStr))
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 支持科学计数法
|
|
||||||
return new BigDecimal(valueStr.trim()).doubleValue();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为double<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Double toDouble(Object value)
|
|
||||||
{
|
|
||||||
return toDouble(value, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为Float<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @param defaultValue 转换错误时的默认值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Float toFloat(Object value, Float defaultValue)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
if (value instanceof Float)
|
|
||||||
{
|
|
||||||
return (Float) value;
|
|
||||||
}
|
|
||||||
if (value instanceof Number)
|
|
||||||
{
|
|
||||||
return ((Number) value).floatValue();
|
|
||||||
}
|
|
||||||
final String valueStr = toStr(value, null);
|
|
||||||
if (StringUtils.isEmpty(valueStr))
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return Float.parseFloat(valueStr.trim());
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为Float<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Float toFloat(Object value)
|
|
||||||
{
|
|
||||||
return toFloat(value, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为boolean<br>
|
|
||||||
* String支持的值为:true、false、yes、ok、no,1,0 如果给定的值为空,或者转换失败,返回默认值<br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @param defaultValue 转换错误时的默认值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Boolean toBool(Object value, Boolean defaultValue)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
if (value instanceof Boolean)
|
|
||||||
{
|
|
||||||
return (Boolean) value;
|
|
||||||
}
|
|
||||||
String valueStr = toStr(value, null);
|
|
||||||
if (StringUtils.isEmpty(valueStr))
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
valueStr = valueStr.trim().toLowerCase();
|
|
||||||
switch (valueStr)
|
|
||||||
{
|
|
||||||
case "true":
|
|
||||||
return true;
|
|
||||||
case "false":
|
|
||||||
return false;
|
|
||||||
case "yes":
|
|
||||||
return true;
|
|
||||||
case "ok":
|
|
||||||
return true;
|
|
||||||
case "no":
|
|
||||||
return false;
|
|
||||||
case "1":
|
|
||||||
return true;
|
|
||||||
case "0":
|
|
||||||
return false;
|
|
||||||
default:
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为boolean<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static Boolean toBool(Object value)
|
|
||||||
{
|
|
||||||
return toBool(value, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为Enum对象<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<br>
|
|
||||||
*
|
|
||||||
* @param clazz Enum的Class
|
|
||||||
* @param value 值
|
|
||||||
* @param defaultValue 默认值
|
|
||||||
* @return Enum
|
|
||||||
*/
|
|
||||||
public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value, E defaultValue)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
if (clazz.isAssignableFrom(value.getClass()))
|
|
||||||
{
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
E myE = (E) value;
|
|
||||||
return myE;
|
|
||||||
}
|
|
||||||
final String valueStr = toStr(value, null);
|
|
||||||
if (StringUtils.isEmpty(valueStr))
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return Enum.valueOf(clazz, valueStr);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为Enum对象<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
|
|
||||||
*
|
|
||||||
* @param clazz Enum的Class
|
|
||||||
* @param value 值
|
|
||||||
* @return Enum
|
|
||||||
*/
|
|
||||||
public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value)
|
|
||||||
{
|
|
||||||
return toEnum(clazz, value, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为BigInteger<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @param defaultValue 转换错误时的默认值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static BigInteger toBigInteger(Object value, BigInteger defaultValue)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
if (value instanceof BigInteger)
|
|
||||||
{
|
|
||||||
return (BigInteger) value;
|
|
||||||
}
|
|
||||||
if (value instanceof Long)
|
|
||||||
{
|
|
||||||
return BigInteger.valueOf((Long) value);
|
|
||||||
}
|
|
||||||
final String valueStr = toStr(value, null);
|
|
||||||
if (StringUtils.isEmpty(valueStr))
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return new BigInteger(valueStr);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为BigInteger<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static BigInteger toBigInteger(Object value)
|
|
||||||
{
|
|
||||||
return toBigInteger(value, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为BigDecimal<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @param defaultValue 转换错误时的默认值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static BigDecimal toBigDecimal(Object value, BigDecimal defaultValue)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
if (value instanceof BigDecimal)
|
|
||||||
{
|
|
||||||
return (BigDecimal) value;
|
|
||||||
}
|
|
||||||
if (value instanceof Long)
|
|
||||||
{
|
|
||||||
return new BigDecimal((Long) value);
|
|
||||||
}
|
|
||||||
if (value instanceof Double)
|
|
||||||
{
|
|
||||||
return new BigDecimal((Double) value);
|
|
||||||
}
|
|
||||||
if (value instanceof Integer)
|
|
||||||
{
|
|
||||||
return new BigDecimal((Integer) value);
|
|
||||||
}
|
|
||||||
final String valueStr = toStr(value, null);
|
|
||||||
if (StringUtils.isEmpty(valueStr))
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return new BigDecimal(valueStr);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 转换为BigDecimal<br>
|
|
||||||
* 如果给定的值为空,或者转换失败,返回默认值<br>
|
|
||||||
* 转换失败不会报错
|
|
||||||
*
|
|
||||||
* @param value 被转换的值
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static BigDecimal toBigDecimal(Object value)
|
|
||||||
{
|
|
||||||
return toBigDecimal(value, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将对象转为字符串<br>
|
|
||||||
* 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
|
|
||||||
*
|
|
||||||
* @param obj 对象
|
|
||||||
* @return 字符串
|
|
||||||
*/
|
|
||||||
public static String utf8Str(Object obj)
|
|
||||||
{
|
|
||||||
return str(obj, CharsetKit.CHARSET_UTF_8);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将对象转为字符串<br>
|
|
||||||
* 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
|
|
||||||
*
|
|
||||||
* @param obj 对象
|
|
||||||
* @param charsetName 字符集
|
|
||||||
* @return 字符串
|
|
||||||
*/
|
|
||||||
public static String str(Object obj, String charsetName)
|
|
||||||
{
|
|
||||||
return str(obj, Charset.forName(charsetName));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将对象转为字符串<br>
|
|
||||||
* 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
|
|
||||||
*
|
|
||||||
* @param obj 对象
|
|
||||||
* @param charset 字符集
|
|
||||||
* @return 字符串
|
|
||||||
*/
|
|
||||||
public static String str(Object obj, Charset charset)
|
|
||||||
{
|
|
||||||
if (null == obj)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj instanceof String)
|
|
||||||
{
|
|
||||||
return (String) obj;
|
|
||||||
}
|
|
||||||
else if (obj instanceof byte[] || obj instanceof Byte[])
|
|
||||||
{
|
|
||||||
return str((Byte[]) obj, charset);
|
|
||||||
}
|
|
||||||
else if (obj instanceof ByteBuffer)
|
|
||||||
{
|
|
||||||
return str((ByteBuffer) obj, charset);
|
|
||||||
}
|
|
||||||
return obj.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将byte数组转为字符串
|
|
||||||
*
|
|
||||||
* @param bytes byte数组
|
|
||||||
* @param charset 字符集
|
|
||||||
* @return 字符串
|
|
||||||
*/
|
|
||||||
public static String str(byte[] bytes, String charset)
|
|
||||||
{
|
|
||||||
return str(bytes, StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 解码字节码
|
|
||||||
*
|
|
||||||
* @param data 字符串
|
|
||||||
* @param charset 字符集,如果此字段为空,则解码的结果取决于平台
|
|
||||||
* @return 解码后的字符串
|
|
||||||
*/
|
|
||||||
public static String str(byte[] data, Charset charset)
|
|
||||||
{
|
|
||||||
if (data == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null == charset)
|
|
||||||
{
|
|
||||||
return new String(data);
|
|
||||||
}
|
|
||||||
return new String(data, charset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将编码的byteBuffer数据转换为字符串
|
|
||||||
*
|
|
||||||
* @param data 数据
|
|
||||||
* @param charset 字符集,如果为空使用当前系统字符集
|
|
||||||
* @return 字符串
|
|
||||||
*/
|
|
||||||
public static String str(ByteBuffer data, String charset)
|
|
||||||
{
|
|
||||||
if (data == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return str(data, Charset.forName(charset));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将编码的byteBuffer数据转换为字符串
|
|
||||||
*
|
|
||||||
* @param data 数据
|
|
||||||
* @param charset 字符集,如果为空使用当前系统字符集
|
|
||||||
* @return 字符串
|
|
||||||
*/
|
|
||||||
public static String str(ByteBuffer data, Charset charset)
|
|
||||||
{
|
|
||||||
if (null == charset)
|
|
||||||
{
|
|
||||||
charset = Charset.defaultCharset();
|
|
||||||
}
|
|
||||||
return charset.decode(data).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------- 全角半角转换
|
|
||||||
/**
|
|
||||||
* 半角转全角
|
|
||||||
*
|
|
||||||
* @param input String.
|
|
||||||
* @return 全角字符串.
|
|
||||||
*/
|
|
||||||
public static String toSBC(String input)
|
|
||||||
{
|
|
||||||
return toSBC(input, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 半角转全角
|
|
||||||
*
|
|
||||||
* @param input String
|
|
||||||
* @param notConvertSet 不替换的字符集合
|
|
||||||
* @return 全角字符串.
|
|
||||||
*/
|
|
||||||
public static String toSBC(String input, Set<Character> notConvertSet)
|
|
||||||
{
|
|
||||||
char c[] = input.toCharArray();
|
|
||||||
for (int i = 0; i < c.length; i++)
|
|
||||||
{
|
|
||||||
if (null != notConvertSet && notConvertSet.contains(c[i]))
|
|
||||||
{
|
|
||||||
// 跳过不替换的字符
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c[i] == ' ')
|
|
||||||
{
|
|
||||||
c[i] = '\u3000';
|
|
||||||
}
|
|
||||||
else if (c[i] < '\177')
|
|
||||||
{
|
|
||||||
c[i] = (char) (c[i] + 65248);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new String(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 全角转半角
|
|
||||||
*
|
|
||||||
* @param input String.
|
|
||||||
* @return 半角字符串
|
|
||||||
*/
|
|
||||||
public static String toDBC(String input)
|
|
||||||
{
|
|
||||||
return toDBC(input, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 替换全角为半角
|
|
||||||
*
|
|
||||||
* @param text 文本
|
|
||||||
* @param notConvertSet 不替换的字符集合
|
|
||||||
* @return 替换后的字符
|
|
||||||
*/
|
|
||||||
public static String toDBC(String text, Set<Character> notConvertSet)
|
|
||||||
{
|
|
||||||
char c[] = text.toCharArray();
|
|
||||||
for (int i = 0; i < c.length; i++)
|
|
||||||
{
|
|
||||||
if (null != notConvertSet && notConvertSet.contains(c[i]))
|
|
||||||
{
|
|
||||||
// 跳过不替换的字符
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (c[i] == '\u3000')
|
|
||||||
{
|
|
||||||
c[i] = ' ';
|
|
||||||
}
|
|
||||||
else if (c[i] > '\uFF00' && c[i] < '\uFF5F')
|
|
||||||
{
|
|
||||||
c[i] = (char) (c[i] - 65248);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String returnString = new String(c);
|
|
||||||
|
|
||||||
return returnString;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 数字金额大写转换 先写个完整的然后将如零拾替换成零
|
|
||||||
*
|
|
||||||
* @param n 数字
|
|
||||||
* @return 中文大写数字
|
|
||||||
*/
|
|
||||||
public static String digitUppercase(double n)
|
|
||||||
{
|
|
||||||
String[] fraction = { "角", "分" };
|
|
||||||
String[] digit = { "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" };
|
|
||||||
String[][] unit = { { "元", "万", "亿" }, { "", "拾", "佰", "仟" } };
|
|
||||||
|
|
||||||
String head = n < 0 ? "负" : "";
|
|
||||||
n = Math.abs(n);
|
|
||||||
|
|
||||||
String s = "";
|
|
||||||
for (int i = 0; i < fraction.length; i++)
|
|
||||||
{
|
|
||||||
s += (digit[(int) (Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", "");
|
|
||||||
}
|
|
||||||
if (s.length() < 1)
|
|
||||||
{
|
|
||||||
s = "整";
|
|
||||||
}
|
|
||||||
int integerPart = (int) Math.floor(n);
|
|
||||||
|
|
||||||
for (int i = 0; i < unit[0].length && integerPart > 0; i++)
|
|
||||||
{
|
|
||||||
String p = "";
|
|
||||||
for (int j = 0; j < unit[1].length && n > 0; j++)
|
|
||||||
{
|
|
||||||
p = digit[integerPart % 10] + unit[1][j] + p;
|
|
||||||
integerPart = integerPart / 10;
|
|
||||||
}
|
|
||||||
s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s;
|
|
||||||
}
|
|
||||||
return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,93 +0,0 @@
|
||||||
package com.ruoyi.common.utils.text;
|
|
||||||
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 字符串格式化
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class StrFormatter
|
|
||||||
{
|
|
||||||
public static final String EMPTY_JSON = "{}";
|
|
||||||
public static final char C_BACKSLASH = '\\';
|
|
||||||
public static final char C_DELIM_START = '{';
|
|
||||||
public static final char C_DELIM_END = '}';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 格式化字符串<br>
|
|
||||||
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
|
|
||||||
* 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
|
|
||||||
* 例:<br>
|
|
||||||
* 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br>
|
|
||||||
* 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
|
|
||||||
* 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
|
|
||||||
*
|
|
||||||
* @param strPattern 字符串模板
|
|
||||||
* @param argArray 参数列表
|
|
||||||
* @return 结果
|
|
||||||
*/
|
|
||||||
public static String format(final String strPattern, final Object... argArray)
|
|
||||||
{
|
|
||||||
if (StringUtils.isEmpty(strPattern) || StringUtils.isEmpty(argArray))
|
|
||||||
{
|
|
||||||
return strPattern;
|
|
||||||
}
|
|
||||||
final int strPatternLength = strPattern.length();
|
|
||||||
|
|
||||||
// 初始化定义好的长度以获得更好的性能
|
|
||||||
StringBuilder sbuf = new StringBuilder(strPatternLength + 50);
|
|
||||||
|
|
||||||
int handledPosition = 0;
|
|
||||||
int delimIndex;// 占位符所在位置
|
|
||||||
for (int argIndex = 0; argIndex < argArray.length; argIndex++)
|
|
||||||
{
|
|
||||||
delimIndex = strPattern.indexOf(EMPTY_JSON, handledPosition);
|
|
||||||
if (delimIndex == -1)
|
|
||||||
{
|
|
||||||
if (handledPosition == 0)
|
|
||||||
{
|
|
||||||
return strPattern;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ // 字符串模板剩余部分不再包含占位符,加入剩余部分后返回结果
|
|
||||||
sbuf.append(strPattern, handledPosition, strPatternLength);
|
|
||||||
return sbuf.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (delimIndex > 0 && strPattern.charAt(delimIndex - 1) == C_BACKSLASH)
|
|
||||||
{
|
|
||||||
if (delimIndex > 1 && strPattern.charAt(delimIndex - 2) == C_BACKSLASH)
|
|
||||||
{
|
|
||||||
// 转义符之前还有一个转义符,占位符依旧有效
|
|
||||||
sbuf.append(strPattern, handledPosition, delimIndex - 1);
|
|
||||||
sbuf.append(Convert.utf8Str(argArray[argIndex]));
|
|
||||||
handledPosition = delimIndex + 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 占位符被转义
|
|
||||||
argIndex--;
|
|
||||||
sbuf.append(strPattern, handledPosition, delimIndex - 1);
|
|
||||||
sbuf.append(C_DELIM_START);
|
|
||||||
handledPosition = delimIndex + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 正常占位符
|
|
||||||
sbuf.append(strPattern, handledPosition, delimIndex);
|
|
||||||
sbuf.append(Convert.utf8Str(argArray[argIndex]));
|
|
||||||
handledPosition = delimIndex + 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// append the characters following the last {} pair.
|
|
||||||
// 加入最后一个占位符后所有的字符
|
|
||||||
sbuf.append(strPattern, handledPosition, strPattern.length());
|
|
||||||
|
|
||||||
return sbuf.toString();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,97 +0,0 @@
|
||||||
package com.ruoyi.common.xss;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import javax.servlet.Filter;
|
|
||||||
import javax.servlet.FilterChain;
|
|
||||||
import javax.servlet.FilterConfig;
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.ServletRequest;
|
|
||||||
import javax.servlet.ServletResponse;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 防止XSS攻击的过滤器
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class XssFilter implements Filter
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 排除链接
|
|
||||||
*/
|
|
||||||
public List<String> excludes = new ArrayList<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* xss过滤开关
|
|
||||||
*/
|
|
||||||
public boolean enabled = false;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init(FilterConfig filterConfig) throws ServletException
|
|
||||||
{
|
|
||||||
String tempExcludes = filterConfig.getInitParameter("excludes");
|
|
||||||
String tempEnabled = filterConfig.getInitParameter("enabled");
|
|
||||||
if (StringUtils.isNotEmpty(tempExcludes))
|
|
||||||
{
|
|
||||||
String[] url = tempExcludes.split(",");
|
|
||||||
for (int i = 0; url != null && i < url.length; i++)
|
|
||||||
{
|
|
||||||
excludes.add(url[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (StringUtils.isNotEmpty(tempEnabled))
|
|
||||||
{
|
|
||||||
enabled = Boolean.valueOf(tempEnabled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
|
||||||
throws IOException, ServletException
|
|
||||||
{
|
|
||||||
HttpServletRequest req = (HttpServletRequest) request;
|
|
||||||
HttpServletResponse resp = (HttpServletResponse) response;
|
|
||||||
if (handleExcludeURL(req, resp))
|
|
||||||
{
|
|
||||||
chain.doFilter(request, response);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request);
|
|
||||||
chain.doFilter(xssRequest, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response)
|
|
||||||
{
|
|
||||||
if (!enabled)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (excludes == null || excludes.isEmpty())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
String url = request.getServletPath();
|
|
||||||
for (String pattern : excludes)
|
|
||||||
{
|
|
||||||
Pattern p = Pattern.compile("^" + pattern);
|
|
||||||
Matcher m = p.matcher(url);
|
|
||||||
if (m.find())
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void destroy()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,105 +0,0 @@
|
||||||
package com.ruoyi.common.xss;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import javax.servlet.ReadListener;
|
|
||||||
import javax.servlet.ServletInputStream;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletRequestWrapper;
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.springframework.http.HttpHeaders;
|
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
|
||||||
import com.ruoyi.common.utils.html.EscapeUtil;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* XSS过滤处理
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @param request
|
|
||||||
*/
|
|
||||||
public XssHttpServletRequestWrapper(HttpServletRequest request)
|
|
||||||
{
|
|
||||||
super(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getParameterValues(String name)
|
|
||||||
{
|
|
||||||
String[] values = super.getParameterValues(name);
|
|
||||||
if (values != null)
|
|
||||||
{
|
|
||||||
int length = values.length;
|
|
||||||
String[] escapseValues = new String[length];
|
|
||||||
for (int i = 0; i < length; i++)
|
|
||||||
{
|
|
||||||
// 防xss攻击和过滤前后空格
|
|
||||||
escapseValues[i] = EscapeUtil.clean(values[i]).trim();
|
|
||||||
}
|
|
||||||
return escapseValues;
|
|
||||||
}
|
|
||||||
return super.getParameterValues(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ServletInputStream getInputStream() throws IOException
|
|
||||||
{
|
|
||||||
// 非json类型,直接返回
|
|
||||||
if (!isJsonRequest())
|
|
||||||
{
|
|
||||||
return super.getInputStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 为空,直接返回
|
|
||||||
String json = IOUtils.toString(super.getInputStream(), "utf-8");
|
|
||||||
if (StringUtils.isEmpty(json))
|
|
||||||
{
|
|
||||||
return super.getInputStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
// xss过滤
|
|
||||||
json = EscapeUtil.clean(json).trim();
|
|
||||||
final ByteArrayInputStream bis = new ByteArrayInputStream(json.getBytes("utf-8"));
|
|
||||||
return new ServletInputStream()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public boolean isFinished()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isReady()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setReadListener(ReadListener readListener)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int read() throws IOException
|
|
||||||
{
|
|
||||||
return bis.read();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否是Json请求
|
|
||||||
*
|
|
||||||
* @param request
|
|
||||||
*/
|
|
||||||
public boolean isJsonRequest()
|
|
||||||
{
|
|
||||||
String header = super.getHeader(HttpHeaders.CONTENT_TYPE);
|
|
||||||
return MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(header)
|
|
||||||
|| MediaType.APPLICATION_JSON_UTF8_VALUE.equalsIgnoreCase(header);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,160 +0,0 @@
|
||||||
package com.ruoyi.framework.aspectj;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import org.aspectj.lang.JoinPoint;
|
|
||||||
import org.aspectj.lang.Signature;
|
|
||||||
import org.aspectj.lang.annotation.Aspect;
|
|
||||||
import org.aspectj.lang.annotation.Before;
|
|
||||||
import org.aspectj.lang.annotation.Pointcut;
|
|
||||||
import org.aspectj.lang.reflect.MethodSignature;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import com.ruoyi.common.utils.ServletUtils;
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
|
||||||
import com.ruoyi.common.utils.spring.SpringUtils;
|
|
||||||
import com.ruoyi.framework.aspectj.lang.annotation.DataScope;
|
|
||||||
import com.ruoyi.framework.security.LoginUser;
|
|
||||||
import com.ruoyi.framework.security.service.TokenService;
|
|
||||||
import com.ruoyi.framework.web.domain.BaseEntity;
|
|
||||||
import com.ruoyi.project.system.domain.SysRole;
|
|
||||||
import com.ruoyi.project.system.domain.SysUser;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 数据过滤处理
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Aspect
|
|
||||||
@Component
|
|
||||||
public class DataScopeAspect
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 全部数据权限
|
|
||||||
*/
|
|
||||||
public static final String DATA_SCOPE_ALL = "1";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 自定数据权限
|
|
||||||
*/
|
|
||||||
public static final String DATA_SCOPE_CUSTOM = "2";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 部门数据权限
|
|
||||||
*/
|
|
||||||
public static final String DATA_SCOPE_DEPT = "3";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 部门及以下数据权限
|
|
||||||
*/
|
|
||||||
public static final String DATA_SCOPE_DEPT_AND_CHILD = "4";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 仅本人数据权限
|
|
||||||
*/
|
|
||||||
public static final String DATA_SCOPE_SELF = "5";
|
|
||||||
|
|
||||||
// 配置织入点
|
|
||||||
@Pointcut("@annotation(com.ruoyi.framework.aspectj.lang.annotation.DataScope)")
|
|
||||||
public void dataScopePointCut()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@Before("dataScopePointCut()")
|
|
||||||
public void doBefore(JoinPoint point) throws Throwable
|
|
||||||
{
|
|
||||||
handleDataScope(point);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void handleDataScope(final JoinPoint joinPoint)
|
|
||||||
{
|
|
||||||
// 获得注解
|
|
||||||
DataScope controllerDataScope = getAnnotationLog(joinPoint);
|
|
||||||
if (controllerDataScope == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 获取当前的用户
|
|
||||||
LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest());
|
|
||||||
SysUser currentUser = loginUser.getUser();
|
|
||||||
if (currentUser != null)
|
|
||||||
{
|
|
||||||
// 如果是超级管理员,则不过滤数据
|
|
||||||
if (!currentUser.isAdmin())
|
|
||||||
{
|
|
||||||
dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(),
|
|
||||||
controllerDataScope.userAlias());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 数据范围过滤
|
|
||||||
*
|
|
||||||
* @param joinPoint 切点
|
|
||||||
* @param user 用户
|
|
||||||
* @param alias 别名
|
|
||||||
*/
|
|
||||||
public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias)
|
|
||||||
{
|
|
||||||
StringBuilder sqlString = new StringBuilder();
|
|
||||||
|
|
||||||
for (SysRole role : user.getRoles())
|
|
||||||
{
|
|
||||||
String dataScope = role.getDataScope();
|
|
||||||
if (DATA_SCOPE_ALL.equals(dataScope))
|
|
||||||
{
|
|
||||||
sqlString = new StringBuilder();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (DATA_SCOPE_CUSTOM.equals(dataScope))
|
|
||||||
{
|
|
||||||
sqlString.append(StringUtils.format(
|
|
||||||
" OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias,
|
|
||||||
role.getRoleId()));
|
|
||||||
}
|
|
||||||
else if (DATA_SCOPE_DEPT.equals(dataScope))
|
|
||||||
{
|
|
||||||
sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId()));
|
|
||||||
}
|
|
||||||
else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope))
|
|
||||||
{
|
|
||||||
sqlString.append(StringUtils.format(
|
|
||||||
" OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )",
|
|
||||||
deptAlias, user.getDeptId(), user.getDeptId()));
|
|
||||||
}
|
|
||||||
else if (DATA_SCOPE_SELF.equals(dataScope))
|
|
||||||
{
|
|
||||||
if (StringUtils.isNotBlank(userAlias))
|
|
||||||
{
|
|
||||||
sqlString.append(StringUtils.format(" OR {}.user_id = {} ", userAlias, user.getUserId()));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 数据权限为仅本人且没有userAlias别名不查询任何数据
|
|
||||||
sqlString.append(" OR 1=0 ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(sqlString.toString()))
|
|
||||||
{
|
|
||||||
BaseEntity baseEntity = (BaseEntity) joinPoint.getArgs()[0];
|
|
||||||
baseEntity.setDataScope(" AND (" + sqlString.substring(4) + ")");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否存在注解,如果存在就获取
|
|
||||||
*/
|
|
||||||
private DataScope getAnnotationLog(JoinPoint joinPoint)
|
|
||||||
{
|
|
||||||
Signature signature = joinPoint.getSignature();
|
|
||||||
MethodSignature methodSignature = (MethodSignature) signature;
|
|
||||||
Method method = methodSignature.getMethod();
|
|
||||||
|
|
||||||
if (method != null)
|
|
||||||
{
|
|
||||||
return method.getAnnotation(DataScope.class);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,76 +0,0 @@
|
||||||
package com.ruoyi.framework.aspectj;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
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.aspectj.lang.reflect.MethodSignature;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.core.annotation.Order;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
|
||||||
import com.ruoyi.framework.aspectj.lang.annotation.DataSource;
|
|
||||||
import com.ruoyi.framework.datasource.DynamicDataSourceContextHolder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 多数据源处理
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Aspect
|
|
||||||
@Order(1)
|
|
||||||
@Component
|
|
||||||
public class DataSourceAspect
|
|
||||||
{
|
|
||||||
protected Logger logger = LoggerFactory.getLogger(getClass());
|
|
||||||
|
|
||||||
@Pointcut("@annotation(com.ruoyi.framework.aspectj.lang.annotation.DataSource)"
|
|
||||||
+ "|| @within(com.ruoyi.framework.aspectj.lang.annotation.DataSource)")
|
|
||||||
public void dsPointCut()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Around("dsPointCut()")
|
|
||||||
public Object around(ProceedingJoinPoint point) throws Throwable
|
|
||||||
{
|
|
||||||
DataSource dataSource = getDataSource(point);
|
|
||||||
|
|
||||||
if (StringUtils.isNotNull(dataSource))
|
|
||||||
{
|
|
||||||
DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name());
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return point.proceed();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
// 销毁数据源 在执行方法之后
|
|
||||||
DynamicDataSourceContextHolder.clearDataSourceType();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取需要切换的数据源
|
|
||||||
*/
|
|
||||||
public DataSource getDataSource(ProceedingJoinPoint point)
|
|
||||||
{
|
|
||||||
MethodSignature signature = (MethodSignature) point.getSignature();
|
|
||||||
Class<? extends Object> targetClass = point.getTarget().getClass();
|
|
||||||
DataSource targetDataSource = targetClass.getAnnotation(DataSource.class);
|
|
||||||
if (StringUtils.isNotNull(targetDataSource))
|
|
||||||
{
|
|
||||||
return targetDataSource;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Method method = signature.getMethod();
|
|
||||||
DataSource dataSource = method.getAnnotation(DataSource.class);
|
|
||||||
return dataSource;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,217 +0,0 @@
|
||||||
package com.ruoyi.framework.aspectj;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.Map;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import org.aspectj.lang.JoinPoint;
|
|
||||||
import org.aspectj.lang.Signature;
|
|
||||||
import org.aspectj.lang.annotation.AfterReturning;
|
|
||||||
import org.aspectj.lang.annotation.AfterThrowing;
|
|
||||||
import org.aspectj.lang.annotation.Aspect;
|
|
||||||
import org.aspectj.lang.annotation.Pointcut;
|
|
||||||
import org.aspectj.lang.reflect.MethodSignature;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
import org.springframework.web.servlet.HandlerMapping;
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.ruoyi.common.enums.HttpMethod;
|
|
||||||
import com.ruoyi.common.utils.ServletUtils;
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
|
||||||
import com.ruoyi.common.utils.ip.IpUtils;
|
|
||||||
import com.ruoyi.common.utils.spring.SpringUtils;
|
|
||||||
import com.ruoyi.framework.aspectj.lang.annotation.Log;
|
|
||||||
import com.ruoyi.framework.aspectj.lang.enums.BusinessStatus;
|
|
||||||
import com.ruoyi.framework.manager.AsyncManager;
|
|
||||||
import com.ruoyi.framework.manager.factory.AsyncFactory;
|
|
||||||
import com.ruoyi.framework.security.LoginUser;
|
|
||||||
import com.ruoyi.framework.security.service.TokenService;
|
|
||||||
import com.ruoyi.project.monitor.domain.SysOperLog;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 操作日志记录处理
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Aspect
|
|
||||||
@Component
|
|
||||||
public class LogAspect
|
|
||||||
{
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
|
|
||||||
|
|
||||||
// 配置织入点
|
|
||||||
@Pointcut("@annotation(com.ruoyi.framework.aspectj.lang.annotation.Log)")
|
|
||||||
public void logPointCut()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理完请求后执行
|
|
||||||
*
|
|
||||||
* @param joinPoint 切点
|
|
||||||
*/
|
|
||||||
@AfterReturning(pointcut = "logPointCut()", returning = "jsonResult")
|
|
||||||
public void doAfterReturning(JoinPoint joinPoint, Object jsonResult)
|
|
||||||
{
|
|
||||||
handleLog(joinPoint, null, jsonResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 拦截异常操作
|
|
||||||
*
|
|
||||||
* @param joinPoint 切点
|
|
||||||
* @param e 异常
|
|
||||||
*/
|
|
||||||
@AfterThrowing(value = "logPointCut()", throwing = "e")
|
|
||||||
public void doAfterThrowing(JoinPoint joinPoint, Exception e)
|
|
||||||
{
|
|
||||||
handleLog(joinPoint, e, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 获得注解
|
|
||||||
Log controllerLog = getAnnotationLog(joinPoint);
|
|
||||||
if (controllerLog == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取当前的用户
|
|
||||||
LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest());
|
|
||||||
|
|
||||||
// *========数据库日志=========*//
|
|
||||||
SysOperLog operLog = new SysOperLog();
|
|
||||||
operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
|
|
||||||
// 请求的地址
|
|
||||||
String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
|
|
||||||
operLog.setOperIp(ip);
|
|
||||||
// 返回参数
|
|
||||||
operLog.setJsonResult(JSON.toJSONString(jsonResult));
|
|
||||||
|
|
||||||
operLog.setOperUrl(ServletUtils.getRequest().getRequestURI());
|
|
||||||
if (loginUser != null)
|
|
||||||
{
|
|
||||||
operLog.setOperName(loginUser.getUsername());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e != null)
|
|
||||||
{
|
|
||||||
operLog.setStatus(BusinessStatus.FAIL.ordinal());
|
|
||||||
operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
|
|
||||||
}
|
|
||||||
// 设置方法名称
|
|
||||||
String className = joinPoint.getTarget().getClass().getName();
|
|
||||||
String methodName = joinPoint.getSignature().getName();
|
|
||||||
operLog.setMethod(className + "." + methodName + "()");
|
|
||||||
// 设置请求方式
|
|
||||||
operLog.setRequestMethod(ServletUtils.getRequest().getMethod());
|
|
||||||
// 处理设置注解上的参数
|
|
||||||
getControllerMethodDescription(joinPoint, controllerLog, operLog);
|
|
||||||
// 保存数据库
|
|
||||||
AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
|
|
||||||
}
|
|
||||||
catch (Exception exp)
|
|
||||||
{
|
|
||||||
// 记录本地异常日志
|
|
||||||
log.error("==前置通知异常==");
|
|
||||||
log.error("异常信息:{}", exp.getMessage());
|
|
||||||
exp.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取注解中对方法的描述信息 用于Controller层注解
|
|
||||||
*
|
|
||||||
* @param log 日志
|
|
||||||
* @param operLog 操作日志
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog operLog) throws Exception
|
|
||||||
{
|
|
||||||
// 设置action动作
|
|
||||||
operLog.setBusinessType(log.businessType().ordinal());
|
|
||||||
// 设置标题
|
|
||||||
operLog.setTitle(log.title());
|
|
||||||
// 设置操作人类别
|
|
||||||
operLog.setOperatorType(log.operatorType().ordinal());
|
|
||||||
// 是否需要保存request,参数和值
|
|
||||||
if (log.isSaveRequestData())
|
|
||||||
{
|
|
||||||
// 获取参数的信息,传入到数据库中。
|
|
||||||
setRequestValue(joinPoint, operLog);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取请求的参数,放到log中
|
|
||||||
*
|
|
||||||
* @param operLog 操作日志
|
|
||||||
* @throws Exception 异常
|
|
||||||
*/
|
|
||||||
private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog) throws Exception
|
|
||||||
{
|
|
||||||
String requestMethod = operLog.getRequestMethod();
|
|
||||||
if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod))
|
|
||||||
{
|
|
||||||
String params = argsArrayToString(joinPoint.getArgs());
|
|
||||||
operLog.setOperParam(StringUtils.substring(params, 0, 2000));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Map<?, ?> paramsMap = (Map<?, ?>) ServletUtils.getRequest().getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
|
|
||||||
operLog.setOperParam(StringUtils.substring(paramsMap.toString(), 0, 2000));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否存在注解,如果存在就获取
|
|
||||||
*/
|
|
||||||
private Log getAnnotationLog(JoinPoint joinPoint) throws Exception
|
|
||||||
{
|
|
||||||
Signature signature = joinPoint.getSignature();
|
|
||||||
MethodSignature methodSignature = (MethodSignature) signature;
|
|
||||||
Method method = methodSignature.getMethod();
|
|
||||||
|
|
||||||
if (method != null)
|
|
||||||
{
|
|
||||||
return method.getAnnotation(Log.class);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 参数拼装
|
|
||||||
*/
|
|
||||||
private String argsArrayToString(Object[] paramsArray)
|
|
||||||
{
|
|
||||||
String params = "";
|
|
||||||
if (paramsArray != null && paramsArray.length > 0)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < paramsArray.length; i++)
|
|
||||||
{
|
|
||||||
if (!isFilterObject(paramsArray[i]))
|
|
||||||
{
|
|
||||||
Object jsonObj = JSON.toJSON(paramsArray[i]);
|
|
||||||
params += jsonObj.toString() + " ";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return params.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断是否需要过滤的对象。
|
|
||||||
*
|
|
||||||
* @param o 对象信息。
|
|
||||||
* @return 如果是需要过滤的对象,则返回true;否则返回false。
|
|
||||||
*/
|
|
||||||
public boolean isFilterObject(final Object o)
|
|
||||||
{
|
|
||||||
return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
package com.ruoyi.framework.aspectj.lang.annotation;
|
|
||||||
|
|
||||||
import java.lang.annotation.Documented;
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 数据权限过滤注解
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Target(ElementType.METHOD)
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Documented
|
|
||||||
public @interface DataScope
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 部门表的别名
|
|
||||||
*/
|
|
||||||
public String deptAlias() default "";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户表的别名
|
|
||||||
*/
|
|
||||||
public String userAlias() default "";
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
package com.ruoyi.framework.aspectj.lang.annotation;
|
|
||||||
|
|
||||||
import java.lang.annotation.Documented;
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Inherited;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
import com.ruoyi.framework.aspectj.lang.enums.DataSourceType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 自定义多数据源切换注解
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Documented
|
|
||||||
@Inherited
|
|
||||||
public @interface DataSource
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 切换数据源名称
|
|
||||||
*/
|
|
||||||
public DataSourceType value() default DataSourceType.MASTER;
|
|
||||||
}
|
|
|
@ -1,113 +0,0 @@
|
||||||
package com.ruoyi.framework.aspectj.lang.annotation;
|
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 自定义导出Excel数据注解
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Target(ElementType.FIELD)
|
|
||||||
public @interface Excel
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 导出到Excel中的名字.
|
|
||||||
*/
|
|
||||||
public String name() default "";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 日期格式, 如: yyyy-MM-dd
|
|
||||||
*/
|
|
||||||
public String dateFormat() default "";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 读取内容转表达式 (如: 0=男,1=女,2=未知)
|
|
||||||
*/
|
|
||||||
public String readConverterExp() default "";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 导出类型(0数字 1字符串)
|
|
||||||
*/
|
|
||||||
public ColumnType cellType() default ColumnType.STRING;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 导出时在excel中每个列的高度 单位为字符
|
|
||||||
*/
|
|
||||||
public double height() default 14;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 导出时在excel中每个列的宽 单位为字符
|
|
||||||
*/
|
|
||||||
public double width() default 16;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 文字后缀,如% 90 变成90%
|
|
||||||
*/
|
|
||||||
public String suffix() default "";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 当值为空时,字段的默认值
|
|
||||||
*/
|
|
||||||
public String defaultValue() default "";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 提示信息
|
|
||||||
*/
|
|
||||||
public String prompt() default "";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置只能选择不能输入的列内容.
|
|
||||||
*/
|
|
||||||
public String[] combo() default {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.
|
|
||||||
*/
|
|
||||||
public boolean isExport() default true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 另一个类中的属性名称,支持多级获取,以小数点隔开
|
|
||||||
*/
|
|
||||||
public String targetAttr() default "";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 字段类型(0:导出导入;1:仅导出;2:仅导入)
|
|
||||||
*/
|
|
||||||
Type type() default Type.ALL;
|
|
||||||
|
|
||||||
public enum Type
|
|
||||||
{
|
|
||||||
ALL(0), EXPORT(1), IMPORT(2);
|
|
||||||
private final int value;
|
|
||||||
|
|
||||||
Type(int value)
|
|
||||||
{
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int value()
|
|
||||||
{
|
|
||||||
return this.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum ColumnType
|
|
||||||
{
|
|
||||||
NUMERIC(0), STRING(1);
|
|
||||||
private final int value;
|
|
||||||
|
|
||||||
ColumnType(int value)
|
|
||||||
{
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int value()
|
|
||||||
{
|
|
||||||
return this.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
package com.ruoyi.framework.aspectj.lang.annotation;
|
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Excel注解集
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Target(ElementType.FIELD)
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
public @interface Excels
|
|
||||||
{
|
|
||||||
Excel[] value();
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
package com.ruoyi.framework.aspectj.lang.annotation;
|
|
||||||
|
|
||||||
import java.lang.annotation.Documented;
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
|
|
||||||
import com.ruoyi.framework.aspectj.lang.enums.OperatorType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 自定义操作日志记录注解
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Target({ ElementType.PARAMETER, ElementType.METHOD })
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Documented
|
|
||||||
public @interface Log
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 模块
|
|
||||||
*/
|
|
||||||
public String title() default "";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 功能
|
|
||||||
*/
|
|
||||||
public BusinessType businessType() default BusinessType.OTHER;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 操作人类别
|
|
||||||
*/
|
|
||||||
public OperatorType operatorType() default OperatorType.MANAGE;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否保存请求的参数
|
|
||||||
*/
|
|
||||||
public boolean isSaveRequestData() default true;
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
package com.ruoyi.framework.aspectj.lang.enums;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 操作状态
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public enum BusinessStatus
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 成功
|
|
||||||
*/
|
|
||||||
SUCCESS,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 失败
|
|
||||||
*/
|
|
||||||
FAIL,
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
package com.ruoyi.framework.aspectj.lang.enums;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 业务操作类型
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public enum BusinessType
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 其它
|
|
||||||
*/
|
|
||||||
OTHER,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 新增
|
|
||||||
*/
|
|
||||||
INSERT,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改
|
|
||||||
*/
|
|
||||||
UPDATE,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除
|
|
||||||
*/
|
|
||||||
DELETE,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 授权
|
|
||||||
*/
|
|
||||||
GRANT,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 导出
|
|
||||||
*/
|
|
||||||
EXPORT,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 导入
|
|
||||||
*/
|
|
||||||
IMPORT,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 强退
|
|
||||||
*/
|
|
||||||
FORCE,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生成代码
|
|
||||||
*/
|
|
||||||
GENCODE,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 清空数据
|
|
||||||
*/
|
|
||||||
CLEAN,
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
package com.ruoyi.framework.aspectj.lang.enums;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 数据源
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public enum DataSourceType
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 主库
|
|
||||||
*/
|
|
||||||
MASTER,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从库
|
|
||||||
*/
|
|
||||||
SLAVE
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
package com.ruoyi.framework.aspectj.lang.enums;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 操作人类别
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public enum OperatorType
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 其它
|
|
||||||
*/
|
|
||||||
OTHER,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 后台用户
|
|
||||||
*/
|
|
||||||
MANAGE,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 手机端用户
|
|
||||||
*/
|
|
||||||
MOBILE
|
|
||||||
}
|
|
|
@ -1,30 +0,0 @@
|
||||||
package com.ruoyi.framework.config;
|
|
||||||
|
|
||||||
import java.util.TimeZone;
|
|
||||||
import org.mybatis.spring.annotation.MapperScan;
|
|
||||||
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 程序注解配置
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
// 表示通过aop框架暴露该代理对象,AopContext能够访问
|
|
||||||
@EnableAspectJAutoProxy(exposeProxy = true)
|
|
||||||
// 指定要扫描的Mapper类的包的路径
|
|
||||||
@MapperScan("com.ruoyi.project.**.mapper")
|
|
||||||
public class ApplicationConfig
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 时区配置
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization()
|
|
||||||
{
|
|
||||||
return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.timeZone(TimeZone.getDefault());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,126 +0,0 @@
|
||||||
package com.ruoyi.framework.config;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import javax.servlet.Filter;
|
|
||||||
import javax.servlet.FilterChain;
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.ServletRequest;
|
|
||||||
import javax.servlet.ServletResponse;
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.context.annotation.Primary;
|
|
||||||
import com.alibaba.druid.pool.DruidDataSource;
|
|
||||||
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
|
|
||||||
import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
|
|
||||||
import com.alibaba.druid.util.Utils;
|
|
||||||
import com.ruoyi.common.utils.spring.SpringUtils;
|
|
||||||
import com.ruoyi.framework.aspectj.lang.enums.DataSourceType;
|
|
||||||
import com.ruoyi.framework.config.properties.DruidProperties;
|
|
||||||
import com.ruoyi.framework.datasource.DynamicDataSource;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* druid 配置多数据源
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
public class DruidConfig
|
|
||||||
{
|
|
||||||
@Bean
|
|
||||||
@ConfigurationProperties("spring.datasource.druid.master")
|
|
||||||
public DataSource masterDataSource(DruidProperties druidProperties)
|
|
||||||
{
|
|
||||||
DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
|
|
||||||
return druidProperties.dataSource(dataSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConfigurationProperties("spring.datasource.druid.slave")
|
|
||||||
@ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")
|
|
||||||
public DataSource slaveDataSource(DruidProperties druidProperties)
|
|
||||||
{
|
|
||||||
DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
|
|
||||||
return druidProperties.dataSource(dataSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean(name = "dynamicDataSource")
|
|
||||||
@Primary
|
|
||||||
public DynamicDataSource dataSource(DataSource masterDataSource)
|
|
||||||
{
|
|
||||||
Map<Object, Object> targetDataSources = new HashMap<>();
|
|
||||||
targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);
|
|
||||||
setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource");
|
|
||||||
return new DynamicDataSource(masterDataSource, targetDataSources);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置数据源
|
|
||||||
*
|
|
||||||
* @param targetDataSources 备选数据源集合
|
|
||||||
* @param sourceName 数据源名称
|
|
||||||
* @param beanName bean名称
|
|
||||||
*/
|
|
||||||
public void setDataSource(Map<Object, Object> targetDataSources, String sourceName, String beanName)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
DataSource dataSource = SpringUtils.getBean(beanName);
|
|
||||||
targetDataSources.put(sourceName, dataSource);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 去除监控页面底部的广告
|
|
||||||
*/
|
|
||||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnProperty(name = "spring.datasource.druid.statViewServlet.enabled", havingValue = "true")
|
|
||||||
public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties)
|
|
||||||
{
|
|
||||||
// 获取web监控页面的参数
|
|
||||||
DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();
|
|
||||||
// 提取common.js的配置路径
|
|
||||||
String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*";
|
|
||||||
String commonJsPattern = pattern.replaceAll("\\*", "js/common.js");
|
|
||||||
final String filePath = "support/http/resources/js/common.js";
|
|
||||||
// 创建filter进行过滤
|
|
||||||
Filter filter = new Filter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void init(javax.servlet.FilterConfig filterConfig) throws ServletException
|
|
||||||
{
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
|
||||||
throws IOException, ServletException
|
|
||||||
{
|
|
||||||
chain.doFilter(request, response);
|
|
||||||
// 重置缓冲区,响应头不会被重置
|
|
||||||
response.resetBuffer();
|
|
||||||
// 获取common.js
|
|
||||||
String text = Utils.readFromResource(filePath);
|
|
||||||
// 正则替换banner, 除去底部的广告信息
|
|
||||||
text = text.replaceAll("<a.*?banner\"></a><br/>", "");
|
|
||||||
text = text.replaceAll("powered.*?shrek.wang</a>", "");
|
|
||||||
response.getWriter().write(text);
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void destroy()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
|
|
||||||
registrationBean.setFilter(filter);
|
|
||||||
registrationBean.addUrlPatterns(commonJsPattern);
|
|
||||||
return registrationBean;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,69 +0,0 @@
|
||||||
package com.ruoyi.framework.config;
|
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
|
||||||
import com.fasterxml.jackson.databind.JavaType;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.fasterxml.jackson.databind.type.TypeFactory;
|
|
||||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
|
||||||
import org.springframework.data.redis.serializer.SerializationException;
|
|
||||||
import com.alibaba.fastjson.parser.ParserConfig;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Redis使用FastJson序列化
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T>
|
|
||||||
{
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
private ObjectMapper objectMapper = new ObjectMapper();
|
|
||||||
|
|
||||||
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
|
|
||||||
|
|
||||||
private Class<T> clazz;
|
|
||||||
|
|
||||||
static
|
|
||||||
{
|
|
||||||
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FastJson2JsonRedisSerializer(Class<T> clazz)
|
|
||||||
{
|
|
||||||
super();
|
|
||||||
this.clazz = clazz;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] serialize(T t) throws SerializationException
|
|
||||||
{
|
|
||||||
if (t == null)
|
|
||||||
{
|
|
||||||
return new byte[0];
|
|
||||||
}
|
|
||||||
return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
|
|
||||||
}
|
|
||||||
|
|
||||||
public T deserialize(byte[] bytes) throws SerializationException
|
|
||||||
{
|
|
||||||
if (bytes == null || bytes.length <= 0)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
String str = new String(bytes, DEFAULT_CHARSET);
|
|
||||||
|
|
||||||
return JSON.parseObject(str, clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setObjectMapper(ObjectMapper objectMapper)
|
|
||||||
{
|
|
||||||
Assert.notNull(objectMapper, "'objectMapper' must not be null");
|
|
||||||
this.objectMapper = objectMapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected JavaType getJavaType(Class<?> clazz)
|
|
||||||
{
|
|
||||||
return TypeFactory.defaultInstance().constructType(clazz);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
package com.ruoyi.framework.config;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import javax.servlet.DispatcherType;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
|
||||||
import com.ruoyi.common.xss.XssFilter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter配置
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
public class FilterConfig
|
|
||||||
{
|
|
||||||
@Value("${xss.enabled}")
|
|
||||||
private String enabled;
|
|
||||||
|
|
||||||
@Value("${xss.excludes}")
|
|
||||||
private String excludes;
|
|
||||||
|
|
||||||
@Value("${xss.urlPatterns}")
|
|
||||||
private String urlPatterns;
|
|
||||||
|
|
||||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
|
||||||
@Bean
|
|
||||||
public FilterRegistrationBean xssFilterRegistration()
|
|
||||||
{
|
|
||||||
FilterRegistrationBean registration = new FilterRegistrationBean();
|
|
||||||
registration.setDispatcherTypes(DispatcherType.REQUEST);
|
|
||||||
registration.setFilter(new XssFilter());
|
|
||||||
registration.addUrlPatterns(StringUtils.split(urlPatterns, ","));
|
|
||||||
registration.setName("xssFilter");
|
|
||||||
registration.setOrder(Integer.MAX_VALUE);
|
|
||||||
Map<String, String> initParameters = new HashMap<String, String>();
|
|
||||||
initParameters.put("excludes", excludes);
|
|
||||||
initParameters.put("enabled", enabled);
|
|
||||||
registration.setInitParameters(initParameters);
|
|
||||||
return registration;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,66 +0,0 @@
|
||||||
package com.ruoyi.framework.config;
|
|
||||||
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 读取代码生成相关配置
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
@ConfigurationProperties(prefix = "gen")
|
|
||||||
public class GenConfig
|
|
||||||
{
|
|
||||||
/** 作者 */
|
|
||||||
public static String author;
|
|
||||||
|
|
||||||
/** 生成包路径 */
|
|
||||||
public static String packageName;
|
|
||||||
|
|
||||||
/** 自动去除表前缀,默认是true */
|
|
||||||
public static boolean autoRemovePre;
|
|
||||||
|
|
||||||
/** 表前缀(类名不会包含表前缀) */
|
|
||||||
public static String tablePrefix;
|
|
||||||
|
|
||||||
public static String getAuthor()
|
|
||||||
{
|
|
||||||
return author;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAuthor(String author)
|
|
||||||
{
|
|
||||||
GenConfig.author = author;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getPackageName()
|
|
||||||
{
|
|
||||||
return packageName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPackageName(String packageName)
|
|
||||||
{
|
|
||||||
GenConfig.packageName = packageName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean getAutoRemovePre()
|
|
||||||
{
|
|
||||||
return autoRemovePre;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAutoRemovePre(boolean autoRemovePre)
|
|
||||||
{
|
|
||||||
GenConfig.autoRemovePre = autoRemovePre;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getTablePrefix()
|
|
||||||
{
|
|
||||||
return tablePrefix;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTablePrefix(String tablePrefix)
|
|
||||||
{
|
|
||||||
GenConfig.tablePrefix = tablePrefix;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,105 +0,0 @@
|
||||||
package com.ruoyi.framework.config;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
import org.apache.ibatis.io.VFS;
|
|
||||||
import org.apache.ibatis.session.SqlSessionFactory;
|
|
||||||
import org.mybatis.spring.SqlSessionFactoryBean;
|
|
||||||
import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.core.env.Environment;
|
|
||||||
import org.springframework.core.io.Resource;
|
|
||||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
|
||||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
|
||||||
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
|
|
||||||
import org.springframework.core.type.classreading.MetadataReader;
|
|
||||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
|
||||||
import org.springframework.util.ClassUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mybatis支持*匹配扫描包
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
public class MyBatisConfig
|
|
||||||
{
|
|
||||||
@Autowired
|
|
||||||
private Environment env;
|
|
||||||
|
|
||||||
static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
|
|
||||||
|
|
||||||
public static String setTypeAliasesPackage(String typeAliasesPackage)
|
|
||||||
{
|
|
||||||
ResourcePatternResolver resolver = (ResourcePatternResolver) new PathMatchingResourcePatternResolver();
|
|
||||||
MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resolver);
|
|
||||||
List<String> allResult = new ArrayList<String>();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
for (String aliasesPackage : typeAliasesPackage.split(","))
|
|
||||||
{
|
|
||||||
List<String> result = new ArrayList<String>();
|
|
||||||
aliasesPackage = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
|
|
||||||
+ ClassUtils.convertClassNameToResourcePath(aliasesPackage.trim()) + "/" + DEFAULT_RESOURCE_PATTERN;
|
|
||||||
Resource[] resources = resolver.getResources(aliasesPackage);
|
|
||||||
if (resources != null && resources.length > 0)
|
|
||||||
{
|
|
||||||
MetadataReader metadataReader = null;
|
|
||||||
for (Resource resource : resources)
|
|
||||||
{
|
|
||||||
if (resource.isReadable())
|
|
||||||
{
|
|
||||||
metadataReader = metadataReaderFactory.getMetadataReader(resource);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
result.add(Class.forName(metadataReader.getClassMetadata().getClassName()).getPackage().getName());
|
|
||||||
}
|
|
||||||
catch (ClassNotFoundException e)
|
|
||||||
{
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (result.size() > 0)
|
|
||||||
{
|
|
||||||
HashSet<String> hashResult = new HashSet<String>(result);
|
|
||||||
allResult.addAll(hashResult);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (allResult.size() > 0)
|
|
||||||
{
|
|
||||||
typeAliasesPackage = String.join(",", (String[]) allResult.toArray(new String[0]));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new RuntimeException("mybatis typeAliasesPackage 路径扫描错误,参数typeAliasesPackage:" + typeAliasesPackage + "未找到任何包");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return typeAliasesPackage;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception
|
|
||||||
{
|
|
||||||
String typeAliasesPackage = env.getProperty("mybatis.typeAliasesPackage");
|
|
||||||
String mapperLocations = env.getProperty("mybatis.mapperLocations");
|
|
||||||
typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage);
|
|
||||||
VFS.addImplClass(SpringBootVFS.class);
|
|
||||||
|
|
||||||
final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
|
|
||||||
sessionFactory.setDataSource(dataSource);
|
|
||||||
sessionFactory.setTypeAliasesPackage(typeAliasesPackage);
|
|
||||||
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations));
|
|
||||||
return sessionFactory.getObject();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
package com.ruoyi.framework.config;
|
|
||||||
|
|
||||||
import org.springframework.cache.annotation.CachingConfigurerSupport;
|
|
||||||
import org.springframework.cache.annotation.EnableCaching;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
|
||||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
|
||||||
import com.fasterxml.jackson.annotation.PropertyAccessor;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* redis配置
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
@EnableCaching
|
|
||||||
public class RedisConfig extends CachingConfigurerSupport
|
|
||||||
{
|
|
||||||
@Bean
|
|
||||||
@SuppressWarnings(value = { "unchecked", "rawtypes" })
|
|
||||||
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory)
|
|
||||||
{
|
|
||||||
RedisTemplate<Object, Object> template = new RedisTemplate<>();
|
|
||||||
template.setConnectionFactory(connectionFactory);
|
|
||||||
|
|
||||||
FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);
|
|
||||||
|
|
||||||
ObjectMapper mapper = new ObjectMapper();
|
|
||||||
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
|
|
||||||
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
|
|
||||||
serializer.setObjectMapper(mapper);
|
|
||||||
|
|
||||||
template.setValueSerializer(serializer);
|
|
||||||
// 使用StringRedisSerializer来序列化和反序列化redis的key值
|
|
||||||
template.setKeySerializer(new StringRedisSerializer());
|
|
||||||
template.afterPropertiesSet();
|
|
||||||
return template;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
package com.ruoyi.framework.config;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
|
||||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
|
||||||
import com.ruoyi.common.constant.Constants;
|
|
||||||
import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 通用配置
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
public class ResourcesConfig implements WebMvcConfigurer
|
|
||||||
{
|
|
||||||
@Autowired
|
|
||||||
private RepeatSubmitInterceptor repeatSubmitInterceptor;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addResourceHandlers(ResourceHandlerRegistry registry)
|
|
||||||
{
|
|
||||||
/** 本地文件上传路径 */
|
|
||||||
registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**").addResourceLocations("file:" + RuoYiConfig.getProfile() + "/");
|
|
||||||
|
|
||||||
/** swagger配置 */
|
|
||||||
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
|
|
||||||
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 自定义拦截规则
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void addInterceptors(InterceptorRegistry registry)
|
|
||||||
{
|
|
||||||
registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,116 +0,0 @@
|
||||||
package com.ruoyi.framework.config;
|
|
||||||
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 读取项目相关配置
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
@ConfigurationProperties(prefix = "ruoyi")
|
|
||||||
public class RuoYiConfig
|
|
||||||
{
|
|
||||||
/** 项目名称 */
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
/** 版本 */
|
|
||||||
private String version;
|
|
||||||
|
|
||||||
/** 版权年份 */
|
|
||||||
private String copyrightYear;
|
|
||||||
|
|
||||||
/** 实例演示开关 */
|
|
||||||
private boolean demoEnabled;
|
|
||||||
|
|
||||||
/** 上传路径 */
|
|
||||||
private static String profile;
|
|
||||||
|
|
||||||
/** 获取地址开关 */
|
|
||||||
private static boolean addressEnabled;
|
|
||||||
|
|
||||||
public String getName()
|
|
||||||
{
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setName(String name)
|
|
||||||
{
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getVersion()
|
|
||||||
{
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setVersion(String version)
|
|
||||||
{
|
|
||||||
this.version = version;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCopyrightYear()
|
|
||||||
{
|
|
||||||
return copyrightYear;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCopyrightYear(String copyrightYear)
|
|
||||||
{
|
|
||||||
this.copyrightYear = copyrightYear;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isDemoEnabled()
|
|
||||||
{
|
|
||||||
return demoEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDemoEnabled(boolean demoEnabled)
|
|
||||||
{
|
|
||||||
this.demoEnabled = demoEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getProfile()
|
|
||||||
{
|
|
||||||
return profile;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setProfile(String profile)
|
|
||||||
{
|
|
||||||
RuoYiConfig.profile = profile;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isAddressEnabled()
|
|
||||||
{
|
|
||||||
return addressEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAddressEnabled(boolean addressEnabled)
|
|
||||||
{
|
|
||||||
RuoYiConfig.addressEnabled = addressEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取头像上传路径
|
|
||||||
*/
|
|
||||||
public static String getAvatarPath()
|
|
||||||
{
|
|
||||||
return getProfile() + "/avatar";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取下载路径
|
|
||||||
*/
|
|
||||||
public static String getDownloadPath()
|
|
||||||
{
|
|
||||||
return getProfile() + "/download/";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取上传路径
|
|
||||||
*/
|
|
||||||
public static String getUploadPath()
|
|
||||||
{
|
|
||||||
return getProfile() + "/upload";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,134 +0,0 @@
|
||||||
package com.ruoyi.framework.config;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.http.HttpMethod;
|
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
|
||||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
|
||||||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|
||||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
|
||||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
|
||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
|
||||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
|
||||||
import com.ruoyi.framework.security.filter.JwtAuthenticationTokenFilter;
|
|
||||||
import com.ruoyi.framework.security.handle.AuthenticationEntryPointImpl;
|
|
||||||
import com.ruoyi.framework.security.handle.LogoutSuccessHandlerImpl;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* spring security配置
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
|
|
||||||
public class SecurityConfig extends WebSecurityConfigurerAdapter
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 自定义用户认证逻辑
|
|
||||||
*/
|
|
||||||
@Autowired
|
|
||||||
private UserDetailsService userDetailsService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 认证失败处理类
|
|
||||||
*/
|
|
||||||
@Autowired
|
|
||||||
private AuthenticationEntryPointImpl unauthorizedHandler;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 退出处理类
|
|
||||||
*/
|
|
||||||
@Autowired
|
|
||||||
private LogoutSuccessHandlerImpl logoutSuccessHandler;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* token认证过滤器
|
|
||||||
*/
|
|
||||||
@Autowired
|
|
||||||
private JwtAuthenticationTokenFilter authenticationTokenFilter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 解决 无法直接注入 AuthenticationManager
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
@Override
|
|
||||||
public AuthenticationManager authenticationManagerBean() throws Exception
|
|
||||||
{
|
|
||||||
return super.authenticationManagerBean();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* anyRequest | 匹配所有请求路径
|
|
||||||
* access | SpringEl表达式结果为true时可以访问
|
|
||||||
* anonymous | 匿名可以访问
|
|
||||||
* denyAll | 用户不能访问
|
|
||||||
* fullyAuthenticated | 用户完全认证可以访问(非remember-me下自动登录)
|
|
||||||
* hasAnyAuthority | 如果有参数,参数表示权限,则其中任何一个权限可以访问
|
|
||||||
* hasAnyRole | 如果有参数,参数表示角色,则其中任何一个角色可以访问
|
|
||||||
* hasAuthority | 如果有参数,参数表示权限,则其权限可以访问
|
|
||||||
* hasIpAddress | 如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问
|
|
||||||
* hasRole | 如果有参数,参数表示角色,则其角色可以访问
|
|
||||||
* permitAll | 用户可以任意访问
|
|
||||||
* rememberMe | 允许通过remember-me登录的用户访问
|
|
||||||
* authenticated | 用户登录后可访问
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void configure(HttpSecurity httpSecurity) throws Exception
|
|
||||||
{
|
|
||||||
httpSecurity
|
|
||||||
// CRSF禁用,因为不使用session
|
|
||||||
.csrf().disable()
|
|
||||||
// 认证失败处理类
|
|
||||||
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
|
|
||||||
// 基于token,所以不需要session
|
|
||||||
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
|
|
||||||
// 过滤请求
|
|
||||||
.authorizeRequests()
|
|
||||||
// 对于登录login 验证码captchaImage 允许匿名访问
|
|
||||||
.antMatchers("/login", "/captchaImage").anonymous()
|
|
||||||
.antMatchers(
|
|
||||||
HttpMethod.GET,
|
|
||||||
"/*.html",
|
|
||||||
"/**/*.html",
|
|
||||||
"/**/*.css",
|
|
||||||
"/**/*.js"
|
|
||||||
).permitAll()
|
|
||||||
.antMatchers("/profile/**").anonymous()
|
|
||||||
.antMatchers("/common/download**").anonymous()
|
|
||||||
.antMatchers("/swagger-ui.html").anonymous()
|
|
||||||
.antMatchers("/swagger-resources/**").anonymous()
|
|
||||||
.antMatchers("/webjars/**").anonymous()
|
|
||||||
.antMatchers("/*/api-docs").anonymous()
|
|
||||||
.antMatchers("/druid/**").anonymous()
|
|
||||||
// 除上面外的所有请求全部需要鉴权认证
|
|
||||||
.anyRequest().authenticated()
|
|
||||||
.and()
|
|
||||||
.headers().frameOptions().disable();
|
|
||||||
httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);
|
|
||||||
// 添加JWT filter
|
|
||||||
httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 强散列哈希加密实现
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
public BCryptPasswordEncoder bCryptPasswordEncoder()
|
|
||||||
{
|
|
||||||
return new BCryptPasswordEncoder();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 身份认证接口
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception
|
|
||||||
{
|
|
||||||
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
package com.ruoyi.framework.config;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import com.ruoyi.common.utils.ServletUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 服务相关配置
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class ServerConfig
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 获取完整的请求路径,包括:域名,端口,上下文访问路径
|
|
||||||
*
|
|
||||||
* @return 服务地址
|
|
||||||
*/
|
|
||||||
public String getUrl()
|
|
||||||
{
|
|
||||||
HttpServletRequest request = ServletUtils.getRequest();
|
|
||||||
return getDomain(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getDomain(HttpServletRequest request)
|
|
||||||
{
|
|
||||||
StringBuffer url = request.getRequestURL();
|
|
||||||
String contextPath = request.getServletContext().getContextPath();
|
|
||||||
return url.delete(url.length() - request.getRequestURI().length(), url.length()).append(contextPath).toString();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,113 +0,0 @@
|
||||||
package com.ruoyi.framework.config;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import io.swagger.annotations.ApiOperation;
|
|
||||||
import springfox.documentation.builders.ApiInfoBuilder;
|
|
||||||
import springfox.documentation.builders.PathSelectors;
|
|
||||||
import springfox.documentation.builders.RequestHandlerSelectors;
|
|
||||||
import springfox.documentation.service.ApiInfo;
|
|
||||||
import springfox.documentation.service.ApiKey;
|
|
||||||
import springfox.documentation.service.AuthorizationScope;
|
|
||||||
import springfox.documentation.service.Contact;
|
|
||||||
import springfox.documentation.service.SecurityReference;
|
|
||||||
import springfox.documentation.spi.DocumentationType;
|
|
||||||
import springfox.documentation.spi.service.contexts.SecurityContext;
|
|
||||||
import springfox.documentation.spring.web.plugins.Docket;
|
|
||||||
import springfox.documentation.swagger2.annotations.EnableSwagger2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Swagger2的接口配置
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
@EnableSwagger2
|
|
||||||
public class SwaggerConfig
|
|
||||||
{
|
|
||||||
/** 系统基础配置 */
|
|
||||||
@Autowired
|
|
||||||
private RuoYiConfig ruoyiConfig;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建API
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
public Docket createRestApi()
|
|
||||||
{
|
|
||||||
return new Docket(DocumentationType.SWAGGER_2)
|
|
||||||
.pathMapping("/dev-api")
|
|
||||||
// 用来创建该API的基本信息,展示在文档的页面中(自定义展示的信息)
|
|
||||||
.apiInfo(apiInfo())
|
|
||||||
// 设置哪些接口暴露给Swagger展示
|
|
||||||
.select()
|
|
||||||
// 扫描所有有注解的api,用这种方式更灵活
|
|
||||||
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
|
|
||||||
// 扫描指定包中的swagger注解
|
|
||||||
//.apis(RequestHandlerSelectors.basePackage("com.ruoyi.project.tool.swagger"))
|
|
||||||
// 扫描所有 .apis(RequestHandlerSelectors.any())
|
|
||||||
.paths(PathSelectors.any())
|
|
||||||
.build()
|
|
||||||
/* 设置安全模式,swagger可以设置访问token */
|
|
||||||
.securitySchemes(securitySchemes())
|
|
||||||
.securityContexts(securityContexts());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 安全模式,这里指定token通过Authorization头请求头传递
|
|
||||||
*/
|
|
||||||
private List<ApiKey> securitySchemes()
|
|
||||||
{
|
|
||||||
List<ApiKey> apiKeyList = new ArrayList<ApiKey>();
|
|
||||||
apiKeyList.add(new ApiKey("Authorization", "Authorization", "header"));
|
|
||||||
return apiKeyList;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 安全上下文
|
|
||||||
*/
|
|
||||||
private List<SecurityContext> securityContexts()
|
|
||||||
{
|
|
||||||
List<SecurityContext> securityContexts = new ArrayList<>();
|
|
||||||
securityContexts.add(
|
|
||||||
SecurityContext.builder()
|
|
||||||
.securityReferences(defaultAuth())
|
|
||||||
.forPaths(PathSelectors.regex("^(?!auth).*$"))
|
|
||||||
.build());
|
|
||||||
return securityContexts;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 默认的安全上引用
|
|
||||||
*/
|
|
||||||
private List<SecurityReference> defaultAuth()
|
|
||||||
{
|
|
||||||
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
|
|
||||||
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
|
|
||||||
authorizationScopes[0] = authorizationScope;
|
|
||||||
List<SecurityReference> securityReferences = new ArrayList<>();
|
|
||||||
securityReferences.add(new SecurityReference("Authorization", authorizationScopes));
|
|
||||||
return securityReferences;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 添加摘要信息
|
|
||||||
*/
|
|
||||||
private ApiInfo apiInfo()
|
|
||||||
{
|
|
||||||
// 用ApiInfoBuilder进行定制
|
|
||||||
return new ApiInfoBuilder()
|
|
||||||
// 设置标题
|
|
||||||
.title("标题:若依管理系统_接口文档")
|
|
||||||
// 描述
|
|
||||||
.description("描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...")
|
|
||||||
// 作者信息
|
|
||||||
.contact(new Contact(ruoyiConfig.getName(), null, null))
|
|
||||||
// 版本
|
|
||||||
.version("版本号:" + ruoyiConfig.getVersion())
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,62 +0,0 @@
|
||||||
package com.ruoyi.framework.config;
|
|
||||||
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
|
||||||
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
|
||||||
import com.ruoyi.common.utils.Threads;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 线程池配置
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
**/
|
|
||||||
@Configuration
|
|
||||||
public class ThreadPoolConfig
|
|
||||||
{
|
|
||||||
// 核心线程池大小
|
|
||||||
private int corePoolSize = 50;
|
|
||||||
|
|
||||||
// 最大可创建的线程数
|
|
||||||
private int maxPoolSize = 200;
|
|
||||||
|
|
||||||
// 队列最大长度
|
|
||||||
private int queueCapacity = 1000;
|
|
||||||
|
|
||||||
// 线程池维护线程所允许的空闲时间
|
|
||||||
private int keepAliveSeconds = 300;
|
|
||||||
|
|
||||||
@Bean(name = "threadPoolTaskExecutor")
|
|
||||||
public ThreadPoolTaskExecutor threadPoolTaskExecutor()
|
|
||||||
{
|
|
||||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
|
||||||
executor.setMaxPoolSize(maxPoolSize);
|
|
||||||
executor.setCorePoolSize(corePoolSize);
|
|
||||||
executor.setQueueCapacity(queueCapacity);
|
|
||||||
executor.setKeepAliveSeconds(keepAliveSeconds);
|
|
||||||
// 线程池对拒绝任务(无线程可用)的处理策略
|
|
||||||
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
|
|
||||||
return executor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行周期性或定时任务
|
|
||||||
*/
|
|
||||||
@Bean(name = "scheduledExecutorService")
|
|
||||||
protected ScheduledExecutorService scheduledExecutorService()
|
|
||||||
{
|
|
||||||
return new ScheduledThreadPoolExecutor(corePoolSize,
|
|
||||||
new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build())
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
protected void afterExecute(Runnable r, Throwable t)
|
|
||||||
{
|
|
||||||
super.afterExecute(r, t);
|
|
||||||
Threads.printException(r, t);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,77 +0,0 @@
|
||||||
package com.ruoyi.framework.config.properties;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import com.alibaba.druid.pool.DruidDataSource;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* druid 配置属性
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
public class DruidProperties
|
|
||||||
{
|
|
||||||
@Value("${spring.datasource.druid.initialSize}")
|
|
||||||
private int initialSize;
|
|
||||||
|
|
||||||
@Value("${spring.datasource.druid.minIdle}")
|
|
||||||
private int minIdle;
|
|
||||||
|
|
||||||
@Value("${spring.datasource.druid.maxActive}")
|
|
||||||
private int maxActive;
|
|
||||||
|
|
||||||
@Value("${spring.datasource.druid.maxWait}")
|
|
||||||
private int maxWait;
|
|
||||||
|
|
||||||
@Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}")
|
|
||||||
private int timeBetweenEvictionRunsMillis;
|
|
||||||
|
|
||||||
@Value("${spring.datasource.druid.minEvictableIdleTimeMillis}")
|
|
||||||
private int minEvictableIdleTimeMillis;
|
|
||||||
|
|
||||||
@Value("${spring.datasource.druid.maxEvictableIdleTimeMillis}")
|
|
||||||
private int maxEvictableIdleTimeMillis;
|
|
||||||
|
|
||||||
@Value("${spring.datasource.druid.validationQuery}")
|
|
||||||
private String validationQuery;
|
|
||||||
|
|
||||||
@Value("${spring.datasource.druid.testWhileIdle}")
|
|
||||||
private boolean testWhileIdle;
|
|
||||||
|
|
||||||
@Value("${spring.datasource.druid.testOnBorrow}")
|
|
||||||
private boolean testOnBorrow;
|
|
||||||
|
|
||||||
@Value("${spring.datasource.druid.testOnReturn}")
|
|
||||||
private boolean testOnReturn;
|
|
||||||
|
|
||||||
public DruidDataSource dataSource(DruidDataSource datasource)
|
|
||||||
{
|
|
||||||
/** 配置初始化大小、最小、最大 */
|
|
||||||
datasource.setInitialSize(initialSize);
|
|
||||||
datasource.setMaxActive(maxActive);
|
|
||||||
datasource.setMinIdle(minIdle);
|
|
||||||
|
|
||||||
/** 配置获取连接等待超时的时间 */
|
|
||||||
datasource.setMaxWait(maxWait);
|
|
||||||
|
|
||||||
/** 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 */
|
|
||||||
datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
|
|
||||||
|
|
||||||
/** 配置一个连接在池中最小、最大生存的时间,单位是毫秒 */
|
|
||||||
datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
|
|
||||||
datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。
|
|
||||||
*/
|
|
||||||
datasource.setValidationQuery(validationQuery);
|
|
||||||
/** 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 */
|
|
||||||
datasource.setTestWhileIdle(testWhileIdle);
|
|
||||||
/** 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */
|
|
||||||
datasource.setTestOnBorrow(testOnBorrow);
|
|
||||||
/** 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */
|
|
||||||
datasource.setTestOnReturn(testOnReturn);
|
|
||||||
return datasource;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
package com.ruoyi.framework.datasource;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import javax.sql.DataSource;
|
|
||||||
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 动态数据源
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class DynamicDataSource extends AbstractRoutingDataSource
|
|
||||||
{
|
|
||||||
public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources)
|
|
||||||
{
|
|
||||||
super.setDefaultTargetDataSource(defaultTargetDataSource);
|
|
||||||
super.setTargetDataSources(targetDataSources);
|
|
||||||
super.afterPropertiesSet();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Object determineCurrentLookupKey()
|
|
||||||
{
|
|
||||||
return DynamicDataSourceContextHolder.getDataSourceType();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
package com.ruoyi.framework.datasource;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 数据源切换处理
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class DynamicDataSourceContextHolder
|
|
||||||
{
|
|
||||||
public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,
|
|
||||||
* 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
|
|
||||||
*/
|
|
||||||
private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置数据源的变量
|
|
||||||
*/
|
|
||||||
public static void setDataSourceType(String dsType)
|
|
||||||
{
|
|
||||||
log.info("切换到{}数据源", dsType);
|
|
||||||
CONTEXT_HOLDER.set(dsType);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得数据源的变量
|
|
||||||
*/
|
|
||||||
public static String getDataSourceType()
|
|
||||||
{
|
|
||||||
return CONTEXT_HOLDER.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 清空数据源变量
|
|
||||||
*/
|
|
||||||
public static void clearDataSourceType()
|
|
||||||
{
|
|
||||||
CONTEXT_HOLDER.remove();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
package com.ruoyi.framework.interceptor;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.web.method.HandlerMethod;
|
|
||||||
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
import com.ruoyi.common.utils.ServletUtils;
|
|
||||||
import com.ruoyi.framework.interceptor.annotation.RepeatSubmit;
|
|
||||||
import com.ruoyi.framework.web.domain.AjaxResult;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 防止重复提交拦截器
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public abstract class RepeatSubmitInterceptor extends HandlerInterceptorAdapter
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
|
|
||||||
{
|
|
||||||
if (handler instanceof HandlerMethod)
|
|
||||||
{
|
|
||||||
HandlerMethod handlerMethod = (HandlerMethod) handler;
|
|
||||||
Method method = handlerMethod.getMethod();
|
|
||||||
RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);
|
|
||||||
if (annotation != null)
|
|
||||||
{
|
|
||||||
if (this.isRepeatSubmit(request))
|
|
||||||
{
|
|
||||||
AjaxResult ajaxResult = AjaxResult.error("不允许重复提交,请稍后再试");
|
|
||||||
ServletUtils.renderString(response, JSONObject.toJSONString(ajaxResult));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return super.preHandle(request, response, handler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证是否重复提交由子类实现具体的防重复提交的规则
|
|
||||||
*
|
|
||||||
* @param httpServletRequest
|
|
||||||
* @return
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
|
||||||
public abstract boolean isRepeatSubmit(HttpServletRequest request);
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
package com.ruoyi.framework.interceptor.annotation;
|
|
||||||
|
|
||||||
import java.lang.annotation.Documented;
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Inherited;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 自定义注解防止表单重复提交
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@Inherited
|
|
||||||
@Target(ElementType.METHOD)
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Documented
|
|
||||||
public @interface RepeatSubmit
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,94 +0,0 @@
|
||||||
package com.ruoyi.framework.interceptor.impl;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpSession;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断请求url和数据是否和上一次相同,
|
|
||||||
* 如果和上次相同,则是重复提交表单。 有效时间为10秒内。
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
|
|
||||||
{
|
|
||||||
public final String REPEAT_PARAMS = "repeatParams";
|
|
||||||
|
|
||||||
public final String REPEAT_TIME = "repeatTime";
|
|
||||||
|
|
||||||
public final String SESSION_REPEAT_KEY = "repeatData";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 间隔时间,单位:秒 默认10秒
|
|
||||||
*
|
|
||||||
* 两次相同参数的请求,如果间隔时间大于该参数,系统不会认定为重复提交的数据
|
|
||||||
*/
|
|
||||||
private int intervalTime = 10;
|
|
||||||
|
|
||||||
public void setIntervalTime(int intervalTime)
|
|
||||||
{
|
|
||||||
this.intervalTime = intervalTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Override
|
|
||||||
public boolean isRepeatSubmit(HttpServletRequest request)
|
|
||||||
{
|
|
||||||
// 本次参数及系统时间
|
|
||||||
String nowParams = JSONObject.toJSONString(request.getParameterMap());
|
|
||||||
Map<String, Object> nowDataMap = new HashMap<String, Object>();
|
|
||||||
nowDataMap.put(REPEAT_PARAMS, nowParams);
|
|
||||||
nowDataMap.put(REPEAT_TIME, System.currentTimeMillis());
|
|
||||||
|
|
||||||
// 请求地址(作为存放session的key值)
|
|
||||||
String url = request.getRequestURI();
|
|
||||||
|
|
||||||
HttpSession session = request.getSession();
|
|
||||||
Object sessionObj = session.getAttribute(SESSION_REPEAT_KEY);
|
|
||||||
if (sessionObj != null)
|
|
||||||
{
|
|
||||||
Map<String, Object> sessionMap = (Map<String, Object>) sessionObj;
|
|
||||||
if (sessionMap.containsKey(url))
|
|
||||||
{
|
|
||||||
Map<String, Object> preDataMap = (Map<String, Object>) sessionMap.get(url);
|
|
||||||
if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Map<String, Object> sessionMap = new HashMap<String, Object>();
|
|
||||||
sessionMap.put(url, nowDataMap);
|
|
||||||
session.setAttribute(SESSION_REPEAT_KEY, sessionMap);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断参数是否相同
|
|
||||||
*/
|
|
||||||
private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap)
|
|
||||||
{
|
|
||||||
String nowParams = (String) nowMap.get(REPEAT_PARAMS);
|
|
||||||
String preParams = (String) preMap.get(REPEAT_PARAMS);
|
|
||||||
return nowParams.equals(preParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断两次间隔时间
|
|
||||||
*/
|
|
||||||
private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap)
|
|
||||||
{
|
|
||||||
long time1 = (Long) nowMap.get(REPEAT_TIME);
|
|
||||||
long time2 = (Long) preMap.get(REPEAT_TIME);
|
|
||||||
if ((time1 - time2) < (this.intervalTime * 1000))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
package com.ruoyi.framework.manager;
|
|
||||||
|
|
||||||
import java.util.TimerTask;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import com.ruoyi.common.utils.Threads;
|
|
||||||
import com.ruoyi.common.utils.spring.SpringUtils;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 异步任务管理器
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class AsyncManager
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* 操作延迟10毫秒
|
|
||||||
*/
|
|
||||||
private final int OPERATE_DELAY_TIME = 10;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 异步操作任务调度线程池
|
|
||||||
*/
|
|
||||||
private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 单例模式
|
|
||||||
*/
|
|
||||||
private AsyncManager(){}
|
|
||||||
|
|
||||||
private static AsyncManager me = new AsyncManager();
|
|
||||||
|
|
||||||
public static AsyncManager me()
|
|
||||||
{
|
|
||||||
return me;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 执行任务
|
|
||||||
*
|
|
||||||
* @param task 任务
|
|
||||||
*/
|
|
||||||
public void execute(TimerTask task)
|
|
||||||
{
|
|
||||||
executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 停止任务线程池
|
|
||||||
*/
|
|
||||||
public void shutdown()
|
|
||||||
{
|
|
||||||
Threads.shutdownAndAwaitTermination(executor);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
package com.ruoyi.framework.manager;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import javax.annotation.PreDestroy;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 确保应用退出时能关闭后台线程
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class ShutdownManager
|
|
||||||
{
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger("sys-user");
|
|
||||||
|
|
||||||
@PreDestroy
|
|
||||||
public void destroy()
|
|
||||||
{
|
|
||||||
shutdownAsyncManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 停止异步执行任务
|
|
||||||
*/
|
|
||||||
private void shutdownAsyncManager()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
logger.info("====关闭后台任务任务线程池====");
|
|
||||||
AsyncManager.me().shutdown();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
logger.error(e.getMessage(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,101 +0,0 @@
|
||||||
package com.ruoyi.framework.manager.factory;
|
|
||||||
|
|
||||||
import java.util.TimerTask;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import com.ruoyi.common.constant.Constants;
|
|
||||||
import com.ruoyi.common.utils.LogUtils;
|
|
||||||
import com.ruoyi.common.utils.ServletUtils;
|
|
||||||
import com.ruoyi.common.utils.ip.AddressUtils;
|
|
||||||
import com.ruoyi.common.utils.ip.IpUtils;
|
|
||||||
import com.ruoyi.common.utils.spring.SpringUtils;
|
|
||||||
import com.ruoyi.project.monitor.domain.SysLogininfor;
|
|
||||||
import com.ruoyi.project.monitor.domain.SysOperLog;
|
|
||||||
import com.ruoyi.project.monitor.service.ISysLogininforService;
|
|
||||||
import com.ruoyi.project.monitor.service.ISysOperLogService;
|
|
||||||
import eu.bitwalker.useragentutils.UserAgent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 异步工厂(产生任务用)
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class AsyncFactory
|
|
||||||
{
|
|
||||||
private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 记录登陆信息
|
|
||||||
*
|
|
||||||
* @param username 用户名
|
|
||||||
* @param status 状态
|
|
||||||
* @param message 消息
|
|
||||||
* @param args 列表
|
|
||||||
* @return 任务task
|
|
||||||
*/
|
|
||||||
public static TimerTask recordLogininfor(final String username, final String status, final String message,
|
|
||||||
final Object... args)
|
|
||||||
{
|
|
||||||
final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
|
|
||||||
final String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
|
|
||||||
return new TimerTask()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
String address = AddressUtils.getRealAddressByIP(ip);
|
|
||||||
StringBuilder s = new StringBuilder();
|
|
||||||
s.append(LogUtils.getBlock(ip));
|
|
||||||
s.append(address);
|
|
||||||
s.append(LogUtils.getBlock(username));
|
|
||||||
s.append(LogUtils.getBlock(status));
|
|
||||||
s.append(LogUtils.getBlock(message));
|
|
||||||
// 打印信息到日志
|
|
||||||
sys_user_logger.info(s.toString(), args);
|
|
||||||
// 获取客户端操作系统
|
|
||||||
String os = userAgent.getOperatingSystem().getName();
|
|
||||||
// 获取客户端浏览器
|
|
||||||
String browser = userAgent.getBrowser().getName();
|
|
||||||
// 封装对象
|
|
||||||
SysLogininfor logininfor = new SysLogininfor();
|
|
||||||
logininfor.setUserName(username);
|
|
||||||
logininfor.setIpaddr(ip);
|
|
||||||
logininfor.setLoginLocation(address);
|
|
||||||
logininfor.setBrowser(browser);
|
|
||||||
logininfor.setOs(os);
|
|
||||||
logininfor.setMsg(message);
|
|
||||||
// 日志状态
|
|
||||||
if (Constants.LOGIN_SUCCESS.equals(status) || Constants.LOGOUT.equals(status))
|
|
||||||
{
|
|
||||||
logininfor.setStatus(Constants.SUCCESS);
|
|
||||||
}
|
|
||||||
else if (Constants.LOGIN_FAIL.equals(status))
|
|
||||||
{
|
|
||||||
logininfor.setStatus(Constants.FAIL);
|
|
||||||
}
|
|
||||||
// 插入数据
|
|
||||||
SpringUtils.getBean(ISysLogininforService.class).insertLogininfor(logininfor);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 操作日志记录
|
|
||||||
*
|
|
||||||
* @param operLog 操作日志信息
|
|
||||||
* @return 任务task
|
|
||||||
*/
|
|
||||||
public static TimerTask recordOper(final SysOperLog operLog)
|
|
||||||
{
|
|
||||||
return new TimerTask()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
// 远程查询操作地点
|
|
||||||
operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp()));
|
|
||||||
SpringUtils.getBean(ISysOperLogService.class).insertOperlog(operLog);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,207 +0,0 @@
|
||||||
package com.ruoyi.framework.redis;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.data.redis.core.BoundSetOperations;
|
|
||||||
import org.springframework.data.redis.core.HashOperations;
|
|
||||||
import org.springframework.data.redis.core.ListOperations;
|
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
|
||||||
import org.springframework.data.redis.core.ValueOperations;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* spring redis 工具类
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
**/
|
|
||||||
@SuppressWarnings(value = { "unchecked", "rawtypes" })
|
|
||||||
@Component
|
|
||||||
public class RedisCache
|
|
||||||
{
|
|
||||||
@Autowired
|
|
||||||
public RedisTemplate redisTemplate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 缓存基本的对象,Integer、String、实体类等
|
|
||||||
*
|
|
||||||
* @param key 缓存的键值
|
|
||||||
* @param value 缓存的值
|
|
||||||
* @return 缓存的对象
|
|
||||||
*/
|
|
||||||
public <T> ValueOperations<String, T> setCacheObject(String key, T value)
|
|
||||||
{
|
|
||||||
ValueOperations<String, T> operation = redisTemplate.opsForValue();
|
|
||||||
operation.set(key, value);
|
|
||||||
return operation;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 缓存基本的对象,Integer、String、实体类等
|
|
||||||
*
|
|
||||||
* @param key 缓存的键值
|
|
||||||
* @param value 缓存的值
|
|
||||||
* @param timeout 时间
|
|
||||||
* @param timeUnit 时间颗粒度
|
|
||||||
* @return 缓存的对象
|
|
||||||
*/
|
|
||||||
public <T> ValueOperations<String, T> setCacheObject(String key, T value, Integer timeout, TimeUnit timeUnit)
|
|
||||||
{
|
|
||||||
ValueOperations<String, T> operation = redisTemplate.opsForValue();
|
|
||||||
operation.set(key, value, timeout, timeUnit);
|
|
||||||
return operation;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得缓存的基本对象。
|
|
||||||
*
|
|
||||||
* @param key 缓存键值
|
|
||||||
* @return 缓存键值对应的数据
|
|
||||||
*/
|
|
||||||
public <T> T getCacheObject(String key)
|
|
||||||
{
|
|
||||||
ValueOperations<String, T> operation = redisTemplate.opsForValue();
|
|
||||||
return operation.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除单个对象
|
|
||||||
*
|
|
||||||
* @param key
|
|
||||||
*/
|
|
||||||
public void deleteObject(String key)
|
|
||||||
{
|
|
||||||
redisTemplate.delete(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除集合对象
|
|
||||||
*
|
|
||||||
* @param collection
|
|
||||||
*/
|
|
||||||
public void deleteObject(Collection collection)
|
|
||||||
{
|
|
||||||
redisTemplate.delete(collection);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 缓存List数据
|
|
||||||
*
|
|
||||||
* @param key 缓存的键值
|
|
||||||
* @param dataList 待缓存的List数据
|
|
||||||
* @return 缓存的对象
|
|
||||||
*/
|
|
||||||
public <T> ListOperations<String, T> setCacheList(String key, List<T> dataList)
|
|
||||||
{
|
|
||||||
ListOperations listOperation = redisTemplate.opsForList();
|
|
||||||
if (null != dataList)
|
|
||||||
{
|
|
||||||
int size = dataList.size();
|
|
||||||
for (int i = 0; i < size; i++)
|
|
||||||
{
|
|
||||||
listOperation.leftPush(key, dataList.get(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return listOperation;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得缓存的list对象
|
|
||||||
*
|
|
||||||
* @param key 缓存的键值
|
|
||||||
* @return 缓存键值对应的数据
|
|
||||||
*/
|
|
||||||
public <T> List<T> getCacheList(String key)
|
|
||||||
{
|
|
||||||
List<T> dataList = new ArrayList<T>();
|
|
||||||
ListOperations<String, T> listOperation = redisTemplate.opsForList();
|
|
||||||
Long size = listOperation.size(key);
|
|
||||||
|
|
||||||
for (int i = 0; i < size; i++)
|
|
||||||
{
|
|
||||||
dataList.add(listOperation.index(key, i));
|
|
||||||
}
|
|
||||||
return dataList;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 缓存Set
|
|
||||||
*
|
|
||||||
* @param key 缓存键值
|
|
||||||
* @param dataSet 缓存的数据
|
|
||||||
* @return 缓存数据的对象
|
|
||||||
*/
|
|
||||||
public <T> BoundSetOperations<String, T> setCacheSet(String key, Set<T> dataSet)
|
|
||||||
{
|
|
||||||
BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
|
|
||||||
Iterator<T> it = dataSet.iterator();
|
|
||||||
while (it.hasNext())
|
|
||||||
{
|
|
||||||
setOperation.add(it.next());
|
|
||||||
}
|
|
||||||
return setOperation;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得缓存的set
|
|
||||||
*
|
|
||||||
* @param key
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public <T> Set<T> getCacheSet(String key)
|
|
||||||
{
|
|
||||||
Set<T> dataSet = new HashSet<T>();
|
|
||||||
BoundSetOperations<String, T> operation = redisTemplate.boundSetOps(key);
|
|
||||||
dataSet = operation.members();
|
|
||||||
return dataSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 缓存Map
|
|
||||||
*
|
|
||||||
* @param key
|
|
||||||
* @param dataMap
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public <T> HashOperations<String, String, T> setCacheMap(String key, Map<String, T> dataMap)
|
|
||||||
{
|
|
||||||
HashOperations hashOperations = redisTemplate.opsForHash();
|
|
||||||
if (null != dataMap)
|
|
||||||
{
|
|
||||||
for (Map.Entry<String, T> entry : dataMap.entrySet())
|
|
||||||
{
|
|
||||||
hashOperations.put(key, entry.getKey(), entry.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return hashOperations;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得缓存的Map
|
|
||||||
*
|
|
||||||
* @param key
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public <T> Map<String, T> getCacheMap(String key)
|
|
||||||
{
|
|
||||||
Map<String, T> map = redisTemplate.opsForHash().entries(key);
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获得缓存的基本对象列表
|
|
||||||
*
|
|
||||||
* @param pattern 字符串前缀
|
|
||||||
* @return 对象列表
|
|
||||||
*/
|
|
||||||
public Collection<String> keys(String pattern)
|
|
||||||
{
|
|
||||||
return redisTemplate.keys(pattern);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,228 +0,0 @@
|
||||||
package com.ruoyi.framework.security;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Set;
|
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
|
||||||
import com.ruoyi.project.system.domain.SysUser;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录用户身份权限
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
public class LoginUser implements UserDetails
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户唯一标识
|
|
||||||
*/
|
|
||||||
private String token;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登陆时间
|
|
||||||
*/
|
|
||||||
private Long loginTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 过期时间
|
|
||||||
*/
|
|
||||||
private Long expireTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录IP地址
|
|
||||||
*/
|
|
||||||
private String ipaddr;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录地点
|
|
||||||
*/
|
|
||||||
private String loginLocation;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 浏览器类型
|
|
||||||
*/
|
|
||||||
private String browser;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 操作系统
|
|
||||||
*/
|
|
||||||
private String os;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 权限列表
|
|
||||||
*/
|
|
||||||
private Set<String> permissions;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户信息
|
|
||||||
*/
|
|
||||||
private SysUser user;
|
|
||||||
|
|
||||||
public String getToken()
|
|
||||||
{
|
|
||||||
return token;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setToken(String token)
|
|
||||||
{
|
|
||||||
this.token = token;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LoginUser()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public LoginUser(SysUser user, Set<String> permissions)
|
|
||||||
{
|
|
||||||
this.user = user;
|
|
||||||
this.permissions = permissions;
|
|
||||||
}
|
|
||||||
|
|
||||||
@JsonIgnore
|
|
||||||
@Override
|
|
||||||
public String getPassword()
|
|
||||||
{
|
|
||||||
return user.getPassword();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUsername()
|
|
||||||
{
|
|
||||||
return user.getUserName();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 账户是否未过期,过期无法验证
|
|
||||||
*/
|
|
||||||
@JsonIgnore
|
|
||||||
@Override
|
|
||||||
public boolean isAccountNonExpired()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 指定用户是否解锁,锁定的用户无法进行身份验证
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@JsonIgnore
|
|
||||||
@Override
|
|
||||||
public boolean isAccountNonLocked()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 指示是否已过期的用户的凭据(密码),过期的凭据防止认证
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@JsonIgnore
|
|
||||||
@Override
|
|
||||||
public boolean isCredentialsNonExpired()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否可用 ,禁用的用户不能身份验证
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@JsonIgnore
|
|
||||||
@Override
|
|
||||||
public boolean isEnabled()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getLoginTime()
|
|
||||||
{
|
|
||||||
return loginTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLoginTime(Long loginTime)
|
|
||||||
{
|
|
||||||
this.loginTime = loginTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getIpaddr()
|
|
||||||
{
|
|
||||||
return ipaddr;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setIpaddr(String ipaddr)
|
|
||||||
{
|
|
||||||
this.ipaddr = ipaddr;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getLoginLocation()
|
|
||||||
{
|
|
||||||
return loginLocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLoginLocation(String loginLocation)
|
|
||||||
{
|
|
||||||
this.loginLocation = loginLocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getBrowser()
|
|
||||||
{
|
|
||||||
return browser;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBrowser(String browser)
|
|
||||||
{
|
|
||||||
this.browser = browser;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getOs()
|
|
||||||
{
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setOs(String os)
|
|
||||||
{
|
|
||||||
this.os = os;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getExpireTime()
|
|
||||||
{
|
|
||||||
return expireTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setExpireTime(Long expireTime)
|
|
||||||
{
|
|
||||||
this.expireTime = expireTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<String> getPermissions()
|
|
||||||
{
|
|
||||||
return permissions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPermissions(Set<String> permissions)
|
|
||||||
{
|
|
||||||
this.permissions = permissions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SysUser getUser()
|
|
||||||
{
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUser(SysUser user)
|
|
||||||
{
|
|
||||||
this.user = user;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<? extends GrantedAuthority> getAuthorities()
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
package com.ruoyi.framework.security.filter;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import javax.servlet.FilterChain;
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
|
||||||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
|
||||||
import com.ruoyi.common.utils.SecurityUtils;
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
|
||||||
import com.ruoyi.framework.security.LoginUser;
|
|
||||||
import com.ruoyi.framework.security.service.TokenService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* token过滤器 验证token有效性
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter
|
|
||||||
{
|
|
||||||
@Autowired
|
|
||||||
private TokenService tokenService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
|
|
||||||
throws ServletException, IOException
|
|
||||||
{
|
|
||||||
LoginUser loginUser = tokenService.getLoginUser(request);
|
|
||||||
if (StringUtils.isNotNull(loginUser) && StringUtils.isNull(SecurityUtils.getAuthentication()))
|
|
||||||
{
|
|
||||||
tokenService.verifyToken(loginUser);
|
|
||||||
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
|
|
||||||
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
|
||||||
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
|
|
||||||
}
|
|
||||||
chain.doFilter(request, response);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
package com.ruoyi.framework.security.handle;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import org.springframework.security.core.AuthenticationException;
|
|
||||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.ruoyi.common.constant.HttpStatus;
|
|
||||||
import com.ruoyi.common.utils.ServletUtils;
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
|
||||||
import com.ruoyi.framework.web.domain.AjaxResult;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 认证失败处理类 返回未授权
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint, Serializable
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = -8970718410437077606L;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e)
|
|
||||||
throws IOException
|
|
||||||
{
|
|
||||||
int code = HttpStatus.UNAUTHORIZED;
|
|
||||||
String msg = StringUtils.format("请求访问:{},认证失败,无法访问系统资源", request.getRequestURI());
|
|
||||||
ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(code, msg)));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
package com.ruoyi.framework.security.handle;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.security.core.Authentication;
|
|
||||||
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import com.ruoyi.common.constant.Constants;
|
|
||||||
import com.ruoyi.common.constant.HttpStatus;
|
|
||||||
import com.ruoyi.common.utils.ServletUtils;
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
|
||||||
import com.ruoyi.framework.manager.AsyncManager;
|
|
||||||
import com.ruoyi.framework.manager.factory.AsyncFactory;
|
|
||||||
import com.ruoyi.framework.security.LoginUser;
|
|
||||||
import com.ruoyi.framework.security.service.TokenService;
|
|
||||||
import com.ruoyi.framework.web.domain.AjaxResult;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 自定义退出处理类 返回成功
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler
|
|
||||||
{
|
|
||||||
@Autowired
|
|
||||||
private TokenService tokenService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 退出处理
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
|
|
||||||
throws IOException, ServletException
|
|
||||||
{
|
|
||||||
LoginUser loginUser = tokenService.getLoginUser(request);
|
|
||||||
if (StringUtils.isNotNull(loginUser))
|
|
||||||
{
|
|
||||||
String userName = loginUser.getUsername();
|
|
||||||
// 删除用户缓存记录
|
|
||||||
tokenService.delLoginUser(loginUser.getToken());
|
|
||||||
// 记录用户退出日志
|
|
||||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, "退出成功"));
|
|
||||||
}
|
|
||||||
ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(HttpStatus.SUCCESS, "退出成功")));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,169 +0,0 @@
|
||||||
package com.ruoyi.framework.security.service;
|
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
import com.ruoyi.common.utils.ServletUtils;
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
|
||||||
import com.ruoyi.framework.security.LoginUser;
|
|
||||||
import com.ruoyi.project.system.domain.SysRole;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RuoYi首创 自定义权限实现,ss取自SpringSecurity首字母
|
|
||||||
*
|
|
||||||
* @author ruoyi
|
|
||||||
*/
|
|
||||||
@Service("ss")
|
|
||||||
public class PermissionService
|
|
||||||
{
|
|
||||||
/** 所有权限标识 */
|
|
||||||
private static final String ALL_PERMISSION = "*:*:*";
|
|
||||||
|
|
||||||
/** 管理员角色权限标识 */
|
|
||||||
private static final String SUPER_ADMIN = "admin";
|
|
||||||
|
|
||||||
private static final String ROLE_DELIMETER = ",";
|
|
||||||
|
|
||||||
private static final String PERMISSION_DELIMETER = ",";
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private TokenService tokenService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证用户是否具备某权限
|
|
||||||
*
|
|
||||||
* @param permission 权限字符串
|
|
||||||
* @return 用户是否具备某权限
|
|
||||||
*/
|
|
||||||
public boolean hasPermi(String permission)
|
|
||||||
{
|
|
||||||
if (StringUtils.isEmpty(permission))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
|
|
||||||
if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions()))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return hasPermissions(loginUser.getPermissions(), permission);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证用户是否不具备某权限,与 hasPermi逻辑相反
|
|
||||||
*
|
|
||||||
* @param permission 权限字符串
|
|
||||||
* @return 用户是否不具备某权限
|
|
||||||
*/
|
|
||||||
public boolean lacksPermi(String permission)
|
|
||||||
{
|
|
||||||
return hasPermi(permission) != true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证用户是否具有以下任意一个权限
|
|
||||||
*
|
|
||||||
* @param permissions 以 PERMISSION_NAMES_DELIMETER 为分隔符的权限列表
|
|
||||||
* @return 用户是否具有以下任意一个权限
|
|
||||||
*/
|
|
||||||
public boolean hasAnyPermi(String permissions)
|
|
||||||
{
|
|
||||||
if (StringUtils.isEmpty(permissions))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
|
|
||||||
if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions()))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Set<String> authorities = loginUser.getPermissions();
|
|
||||||
for (String permission : permissions.split(PERMISSION_DELIMETER))
|
|
||||||
{
|
|
||||||
if (permission != null && hasPermissions(authorities, permission))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断用户是否拥有某个角色
|
|
||||||
*
|
|
||||||
* @param role 角色字符串
|
|
||||||
* @return 用户是否具备某角色
|
|
||||||
*/
|
|
||||||
public boolean hasRole(String role)
|
|
||||||
{
|
|
||||||
if (StringUtils.isEmpty(role))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
|
|
||||||
if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles()))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (SysRole sysRole : loginUser.getUser().getRoles())
|
|
||||||
{
|
|
||||||
String roleKey = sysRole.getRoleKey();
|
|
||||||
if (SUPER_ADMIN.contains(roleKey) || roleKey.contains(StringUtils.trim(role)))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证用户是否不具备某角色,与 isRole逻辑相反。
|
|
||||||
*
|
|
||||||
* @param role 角色名称
|
|
||||||
* @return 用户是否不具备某角色
|
|
||||||
*/
|
|
||||||
public boolean lacksRole(String role)
|
|
||||||
{
|
|
||||||
return hasRole(role) != true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 验证用户是否具有以下任意一个角色
|
|
||||||
*
|
|
||||||
* @param roles 以 ROLE_NAMES_DELIMETER 为分隔符的角色列表
|
|
||||||
* @return 用户是否具有以下任意一个角色
|
|
||||||
*/
|
|
||||||
public boolean hasAnyRoles(String roles)
|
|
||||||
{
|
|
||||||
if (StringUtils.isEmpty(roles))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
|
|
||||||
if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles()))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (String role : roles.split(ROLE_DELIMETER))
|
|
||||||
{
|
|
||||||
if (hasRole(role))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 判断是否包含权限
|
|
||||||
*
|
|
||||||
* @param permissions 权限列表
|
|
||||||
* @param permission 权限字符串
|
|
||||||
* @return 用户是否具备某权限
|
|
||||||
*/
|
|
||||||
private boolean hasPermissions(Set<String> permissions, String permission)
|
|
||||||
{
|
|
||||||
return permissions.contains(ALL_PERMISSION) || permissions.contains(StringUtils.trim(permission));
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue