31 changed files with 3027 additions and 301 deletions
@ -0,0 +1,22 @@ |
|||
package org.dromara.common.encrypt.config.jasypt; |
|||
|
|||
import org.jasypt.encryption.StringEncryptor; |
|||
|
|||
public class CustomEncryptorConfig implements StringEncryptor { |
|||
|
|||
/** |
|||
* 加密解密的 密钥 |
|||
*/ |
|||
private String crack = "ATPfOhpnAVp6yBas7RU"; |
|||
|
|||
@Override |
|||
public String encrypt(String s) { |
|||
return JasyptUtils.encryptWithMD5(s,crack); |
|||
} |
|||
|
|||
@Override |
|||
public String decrypt(String s) { |
|||
return JasyptUtils.decryptWithMD5(s,crack); |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,60 @@ |
|||
package org.dromara.common.encrypt.config.jasypt; |
|||
|
|||
|
|||
|
|||
import org.jasypt.encryption.pbe.StandardPBEStringEncryptor; |
|||
import org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig; |
|||
|
|||
|
|||
/** |
|||
* alibaba druid加解密规则: |
|||
* 明文密码+私钥(privateKey)加密=加密密码 |
|||
* 加密密码+公钥(publicKey)解密=明文密码 |
|||
*/ |
|||
public final class JasyptUtils { |
|||
/** |
|||
* 加密算法 |
|||
*/ |
|||
private static final String PBEWITHMD5ANDDES = "PBEWithMD5AndDES"; |
|||
/** |
|||
* @param text 待加密原文 |
|||
* @param crack 盐值(密钥) |
|||
* @return 加密后的字符串 |
|||
* @Description: Jasypt加密(PBEWithMD5AndDES) |
|||
*/ |
|||
public static String encryptWithMD5(String text, String crack) { |
|||
//1.创建加解密工具实例
|
|||
StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor(); |
|||
//2.加解密配置
|
|||
EnvironmentStringPBEConfig config = new EnvironmentStringPBEConfig(); |
|||
config.setAlgorithm(PBEWITHMD5ANDDES); |
|||
config.setPassword(crack); |
|||
encryptor.setConfig(config); |
|||
//3.加密
|
|||
return encryptor.encrypt(text); |
|||
} |
|||
|
|||
/** |
|||
* @param text 待解密原文 |
|||
* @param crack 盐值(密钥) |
|||
* @return 解密后的字符串 |
|||
* @Description: Jasypt解密(PBEWithMD5AndDES) |
|||
*/ |
|||
public static String decryptWithMD5(String text, String crack) { |
|||
StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor(); |
|||
EnvironmentStringPBEConfig config = new EnvironmentStringPBEConfig(); |
|||
config.setAlgorithm(PBEWITHMD5ANDDES); |
|||
config.setPassword(crack); |
|||
encryptor.setConfig(config); |
|||
return encryptor.decrypt(text); |
|||
} |
|||
public static void main(String[] args) { |
|||
//加密
|
|||
// String s = encryptWithMD5("jdbc:mysql://10.76.108.1:15144/zfjd?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8", "ATPfOhpnAVp6yBas7RU");
|
|||
// System.out.println(s);
|
|||
// String channelcs1 = decryptWithMD5("d4ohneeRrbUb1DsUxGfVs5K7/ZGrnDmSVMQOxx0GIcb0ZWzyCq9aC7CH4aBfwlq3T9G8BLy7cDfTO+IE4uPcstIfQmdHtOlqKxTbBAVxJOUArE3FykMxHzb/NGQ7k4ahHIt+QzH0HPagJACm5B3Wgz8oUZXwq9pZlHmmAG8994JaPIgMhIsA2Lxdnaw/LHBiGkq+FpE7j5TIcItow1HcGw==", "ATPfOhpnAVp6yBas7RU");
|
|||
// String channelcs2 = decryptWithMD5("jGDVr5PtJpE/xa9FyHzmV2PhFrtctWjETGP5lrUlOyZ68APa81+jbQYA9RNKMI/dldAm7xxTQian8370eQqlYSAyoQV9EYlhsK3MgJkn4+OmnfBNmg227+/hizsmt1swxyW2uQbdlhzw6QaXYJ175Rjtlq1yVx+NOiamEoeSO4hzHWqxKTJT/y19fHg6QTuQc3r+PEsAFQp503HsvC5lgA==", "ATPfOhpnAVp6yBas7RU");
|
|||
// System.out.println(channelcs1);
|
|||
System.out.println(decryptWithMD5("zTr/tj2VgFxQyunI4eIL7NyRWDPSMPSB0VlwTYeHTdsEWyu1H96xWw==","ATPfOhpnAVp6yBas7RU")); |
|||
} |
|||
} |
|||
@ -0,0 +1,95 @@ |
|||
package com.zdxt.enforcementcode.common; |
|||
|
|||
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"; |
|||
|
|||
/** |
|||
* 自动去除表前缀 |
|||
*/ |
|||
public static final String AUTO_REOMVE_PRE = "true"; |
|||
|
|||
/** |
|||
* 当前记录起始索引 |
|||
*/ |
|||
public static final String PAGE_NUM = "pageNum"; |
|||
|
|||
/** |
|||
* 每页显示记录数 |
|||
*/ |
|||
public static final String PAGE_SIZE = "pageSize"; |
|||
|
|||
/** |
|||
* 排序列 |
|||
*/ |
|||
public static final String ORDER_BY_COLUMN = "orderByColumn"; |
|||
|
|||
/** |
|||
* 排序的方向 "desc" 或者 "asc". |
|||
*/ |
|||
public static final String IS_ASC = "isAsc"; |
|||
|
|||
/** |
|||
* 资源映射路径 前缀 |
|||
*/ |
|||
public static final String RESOURCE_PREFIX = "/profile"; |
|||
/** |
|||
* 系统用户授权缓存 |
|||
*/ |
|||
public static final String SYS_AUTH_CACHE = "sys-authCache"; |
|||
|
|||
/** |
|||
* 参数管理 cache name |
|||
*/ |
|||
public static final String SYS_CONFIG_CACHE = "sys-config"; |
|||
|
|||
/** |
|||
* 参数管理 cache key |
|||
*/ |
|||
public static final String SYS_CONFIG_KEY = "sys_config:"; |
|||
|
|||
/** |
|||
* 字典管理 cache name |
|||
*/ |
|||
public static final String SYS_DICT_CACHE = "sys-dict"; |
|||
|
|||
/** |
|||
* 字典管理 cache key |
|||
*/ |
|||
public static final String SYS_DICT_KEY = "sys_dict:"; |
|||
|
|||
|
|||
|
|||
/** |
|||
* RMI 远程方法调用 |
|||
*/ |
|||
public static final String LOOKUP_RMI = "rmi://"; |
|||
} |
|||
@ -0,0 +1,116 @@ |
|||
package com.zdxt.enforcementcode.common.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"; |
|||
} |
|||
} |
|||
@ -0,0 +1,522 @@ |
|||
package com.zdxt.enforcementcode.common.util; |
|||
|
|||
import org.apache.commons.collections4.CollectionUtils; |
|||
import org.apache.logging.log4j.LogManager; |
|||
import org.apache.logging.log4j.Logger; |
|||
import org.springframework.data.redis.connection.DataType; |
|||
import org.springframework.data.redis.core.RedisTemplate; |
|||
import org.springframework.data.redis.support.atomic.RedisAtomicLong; |
|||
|
|||
import java.time.Instant; |
|||
import java.util.*; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
/** |
|||
* 缓存工具类 |
|||
* |
|||
* @author zzh |
|||
* @date 2019/8/15 19:11 |
|||
*/ |
|||
public class CacheUtils { |
|||
private static Logger logger = LogManager.getLogger(CacheUtils.class); |
|||
|
|||
private CacheUtils() { |
|||
} |
|||
|
|||
private static RedisTemplate redisTemplate; |
|||
|
|||
public static void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) { |
|||
CacheUtils.redisTemplate = redisTemplate; |
|||
} |
|||
|
|||
/** |
|||
* 获取指定 key 对应的值 |
|||
* |
|||
* @param key |
|||
* @return |
|||
*/ |
|||
public static <V> V get(String key) { |
|||
return (V) redisTemplate.opsForValue().get(key); |
|||
} |
|||
|
|||
/** |
|||
* 获取指定 key 对应的数据类型 |
|||
* |
|||
* @param key |
|||
* @return |
|||
*/ |
|||
public static DataType getType(String key) { |
|||
DataType type = redisTemplate.type(key); |
|||
return type; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 获取匹配 pattern 对应的所有 key 对应的值,慎用会有性能问题 |
|||
* |
|||
* @param pattern |
|||
* @return |
|||
*/ |
|||
public static <E> Set<E> getAll(String pattern) { |
|||
final Set<String> keys = redisTemplate.keys(pattern); |
|||
Set<E> set = new HashSet<>(); |
|||
for (String key : keys) { |
|||
E e = CacheUtils.get(key); |
|||
set.add(e); |
|||
} |
|||
return set; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 设置指定 key 对应的值到Redis,无过期时间 |
|||
* |
|||
* @param key |
|||
* @param value |
|||
*/ |
|||
public static void set(String key, Object value) { |
|||
redisTemplate.opsForValue().set(key, value); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 设置指定 key 对应的值到Redis |
|||
* |
|||
* @param key |
|||
* @param value |
|||
* @param seconds 存活时间,单位(秒) |
|||
*/ |
|||
public static void set(String key, Object value, long seconds) { |
|||
redisTemplate.opsForValue().set(key, value, seconds, TimeUnit.SECONDS); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 设置指定 key 对应的值到 Redis |
|||
* |
|||
* @param key |
|||
* @param value |
|||
* @param time 存活时间,单位根据传入的时间单位 |
|||
*/ |
|||
public static void set(String key, Object value, long time, TimeUnit unit) { |
|||
redisTemplate.opsForValue().set(key, value, time, unit); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 判断指定key是否存在 |
|||
* |
|||
* @param key |
|||
* @return |
|||
*/ |
|||
public static boolean exists(String key) { |
|||
return redisTemplate.hasKey(key).booleanValue(); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 根据 key 删除 |
|||
* |
|||
* @param key |
|||
*/ |
|||
public static boolean del(String key) { |
|||
return redisTemplate.delete(key); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 根据 pattern 匹配所有key,并删除 |
|||
* |
|||
* @param pattern |
|||
* @return 被删除的数量 |
|||
*/ |
|||
public static Long delAll(String pattern) { |
|||
final Set<String> keys = redisTemplate.keys(pattern); |
|||
return redisTemplate.delete(keys); |
|||
} |
|||
|
|||
/** |
|||
* 设置指定key的过期时间 |
|||
* |
|||
* @param key |
|||
* @param seconds 秒 |
|||
* @return |
|||
*/ |
|||
public static Boolean expire(String key, long seconds) { |
|||
return redisTemplate.expire(key, seconds, TimeUnit.SECONDS); |
|||
} |
|||
|
|||
/** |
|||
* 设置指定key的过期时间 |
|||
* |
|||
* @param key |
|||
* @param time |
|||
* @return |
|||
*/ |
|||
public static Boolean expire(String key, long time, TimeUnit unit) { |
|||
return redisTemplate.expire(key, time, unit); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 设置指定key,在指定的时间过期 |
|||
* |
|||
* @param key |
|||
* @param date |
|||
* @return |
|||
*/ |
|||
public static Boolean expireAt(String key, Date date) { |
|||
return redisTemplate.expireAt(key, date); |
|||
} |
|||
|
|||
/** |
|||
* 设置指定key,在指定的时间过期 |
|||
* |
|||
* @param key |
|||
* @param instant |
|||
* @return |
|||
*/ |
|||
public static Boolean expireAt(String key, Instant instant) { |
|||
return redisTemplate.expireAt(key, instant); |
|||
} |
|||
|
|||
/** |
|||
* 返回指定key 的剩余存活时间,单位(秒) |
|||
* |
|||
* @param key |
|||
* @return |
|||
*/ |
|||
public static long ttl(String key) { |
|||
return redisTemplate.getExpire(key).longValue(); |
|||
} |
|||
|
|||
/** |
|||
* 返回键 key 储存的字符串值的长度。 |
|||
* |
|||
* @param key |
|||
* @return |
|||
*/ |
|||
public static Long size(String key) { |
|||
return redisTemplate.opsForValue().size(key); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 设置指定 key 对应的hash表中的键值对 |
|||
* |
|||
* @param key |
|||
* @param hashKey |
|||
* @param value |
|||
*/ |
|||
public static void hset(String key, Object hashKey, Object value) { |
|||
long ttl = ttl(key); |
|||
redisTemplate.opsForHash().put(key, hashKey, value); |
|||
if(ttl > 0L) { |
|||
expire(key, ttl); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* hashKey 不存在时,设置指定 key对应的hash表中的键值对, |
|||
* |
|||
* @param key |
|||
* @param hashKey |
|||
* @param value |
|||
*/ |
|||
public static void hsetIfAbsent(String key, Object hashKey, Object value) { |
|||
long ttl = ttl(key); |
|||
redisTemplate.opsForHash().putIfAbsent(key, hashKey, value); |
|||
if(ttl > 0L) { |
|||
expire(key, ttl); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 将整个Map 存储为 Redis hash |
|||
* |
|||
* @param key |
|||
* @param map |
|||
*/ |
|||
public static void hsetAll(String key, Map map) { |
|||
redisTemplate.opsForHash().putAll(key, map); |
|||
} |
|||
|
|||
/** |
|||
* 将整个Map 存储为 Redis hash,且设置过期时间 |
|||
* |
|||
* @param key |
|||
* @param map |
|||
* @param time |
|||
*/ |
|||
public static void hsetAll(String key, Map map, long time, TimeUnit unit) { |
|||
redisTemplate.opsForHash().putAll(key, map); |
|||
CacheUtils.expire(key, time, unit); |
|||
} |
|||
|
|||
/** |
|||
* 获取指定 key 对应的hash表中 hashKey 对应的值 |
|||
* |
|||
* @param key |
|||
* @param hashKey |
|||
*/ |
|||
public static <V> V hget(String key, Object hashKey) { |
|||
return (V) redisTemplate.opsForHash().get(key, hashKey); |
|||
} |
|||
|
|||
/** |
|||
* 获取整个key对应的 hash |
|||
* |
|||
* @param key |
|||
* @return |
|||
*/ |
|||
public static Map hgetAll(String key) { |
|||
return redisTemplate.opsForHash().entries(key); |
|||
} |
|||
|
|||
/** |
|||
* 获取整个key对应的 值list |
|||
* |
|||
* @param key |
|||
* @return |
|||
*/ |
|||
public static List hvalues(String key) { |
|||
return redisTemplate.opsForHash().values(key); |
|||
} |
|||
|
|||
/** |
|||
* 删除指定 key 对应的hash表中,hashKeys 对应的键值 |
|||
* |
|||
* @param key |
|||
* @param hashKeys |
|||
*/ |
|||
public static Long hdel(String key, Object... hashKeys) { |
|||
return redisTemplate.opsForHash().delete(key, hashKeys); |
|||
} |
|||
|
|||
/** |
|||
* 查找 key 对应的hash表中,是否存在对应的 hashKey |
|||
* @param key |
|||
* @param hashKey |
|||
*/ |
|||
public static Boolean hexists(String key, String hashKey) { |
|||
return redisTemplate.opsForHash().hasKey(key, hashKey); |
|||
} |
|||
|
|||
/** |
|||
* 获取指定key对应的hash长度 |
|||
* @param key |
|||
* @return |
|||
*/ |
|||
public static Long hsize(String key) { |
|||
return redisTemplate.opsForHash().size(key); |
|||
} |
|||
|
|||
/** |
|||
* 添加 values 到指定key对应的set |
|||
* |
|||
* @param key |
|||
* @param values |
|||
*/ |
|||
public static Long sadd(String key, Object... values) { |
|||
return redisTemplate.opsForSet().add(key, values); |
|||
} |
|||
|
|||
/** |
|||
* 添加 values 到指定key对应的set |
|||
* |
|||
* @param key |
|||
* @param values |
|||
*/ |
|||
public static Long saddAll(String key, Collection<?> values) { |
|||
if(CollectionUtils.isNotEmpty(values)) { |
|||
Object[] objects = values.toArray(new Object[values.size()]); |
|||
return redisTemplate.opsForSet().add(key, objects); |
|||
} |
|||
return 0L; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 删除指定key对应的set中的 values |
|||
* |
|||
* @param key |
|||
* @param values |
|||
*/ |
|||
public static Long sdel(String key, Object... values) { |
|||
return redisTemplate.opsForSet().remove(key, values); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 获取指定key对应的set中的所有值 |
|||
* |
|||
* @param key |
|||
* @return |
|||
*/ |
|||
public static Set sall(String key) { |
|||
return redisTemplate.opsForSet().members(key); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 获取指定key对应的set中是否存在给定的值 |
|||
* |
|||
* @param key |
|||
* @param value |
|||
* @return |
|||
*/ |
|||
public static Boolean sexists(String key, Object value) { |
|||
return redisTemplate.opsForSet().isMember(key, value); |
|||
} |
|||
|
|||
/** |
|||
* 获取指定key对应的set长度 |
|||
* @param key |
|||
* @return |
|||
*/ |
|||
public static Long ssize(String key) { |
|||
return redisTemplate.opsForSet().size(key); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 自增指定 key 对应的值,从0开始 |
|||
* |
|||
* @param key |
|||
* @param seconds 失效时间只针对首次自增有效 |
|||
* @return |
|||
*/ |
|||
public static Long incr(String key, long seconds) { |
|||
RedisAtomicLong atomicLong = new RedisAtomicLong(key, redisTemplate.getConnectionFactory()); |
|||
Long increment = atomicLong.getAndIncrement(); |
|||
|
|||
//初始设置过期时间
|
|||
if ((null == increment || increment.longValue() == 0) && seconds > 0) { |
|||
atomicLong.expire(seconds, TimeUnit.SECONDS); |
|||
} |
|||
return increment; |
|||
} |
|||
|
|||
/** |
|||
* 自增指定 key 对应的值,从0开始,无过期时间 |
|||
* |
|||
* @param key |
|||
* @return |
|||
*/ |
|||
public static Long incr(String key) { |
|||
RedisAtomicLong atomicLong = new RedisAtomicLong(key, redisTemplate.getConnectionFactory()); |
|||
Long increment = atomicLong.getAndIncrement(); |
|||
return increment; |
|||
} |
|||
|
|||
/** |
|||
* 增加指定的值到key对应的数据 |
|||
* |
|||
* @param key |
|||
* @param delta 要减少的值 |
|||
* @return |
|||
*/ |
|||
public static Long incrValue(String key, long delta) { |
|||
RedisAtomicLong atomicLong = new RedisAtomicLong(key, redisTemplate.getConnectionFactory()); |
|||
return atomicLong.addAndGet(delta); |
|||
} |
|||
|
|||
/** |
|||
* 自减指定 key 对应的值 |
|||
* |
|||
* @param key |
|||
* @return |
|||
*/ |
|||
public static Long decr(String key) { |
|||
RedisAtomicLong atomicLong = new RedisAtomicLong(key, redisTemplate.getConnectionFactory()); |
|||
return atomicLong.decrementAndGet(); |
|||
} |
|||
|
|||
/** |
|||
* 减少指定的值到key对应的数据 |
|||
* |
|||
* @param key |
|||
* @param delta 要减少的值 |
|||
* @return |
|||
*/ |
|||
public static Long decrValue(String key, long delta) { |
|||
RedisAtomicLong atomicLong = new RedisAtomicLong(key, redisTemplate.getConnectionFactory()); |
|||
return atomicLong.addAndGet(-delta); |
|||
} |
|||
|
|||
/** |
|||
* key 对应的 list 增加value |
|||
* |
|||
* @param key |
|||
* @param value |
|||
* @return |
|||
*/ |
|||
public static long lpush(String key, Object value) { |
|||
return redisTemplate.opsForList().rightPush(key, value); |
|||
} |
|||
|
|||
/** |
|||
* key 对应的 list 增加values |
|||
* |
|||
* @param key |
|||
* @param values |
|||
* @return |
|||
*/ |
|||
public static long lpushAll(String key, Collection values) { |
|||
return redisTemplate.opsForList().rightPushAll(key, values); |
|||
} |
|||
|
|||
/** |
|||
* 根据范围获取 指定key 对应的列表 |
|||
* |
|||
* @param key |
|||
* @param start |
|||
* @param end |
|||
* @return |
|||
*/ |
|||
public static List lgetRange(String key, long start, long end) { |
|||
return redisTemplate.opsForList().range(key, start, end); |
|||
} |
|||
|
|||
/** |
|||
* 根据指定 index 获取list中的值 |
|||
* |
|||
* @param key |
|||
* @param index |
|||
* @return |
|||
*/ |
|||
public static <V> V lget(String key, long index) { |
|||
return (V) redisTemplate.opsForList().index(key, index); |
|||
} |
|||
|
|||
/** |
|||
* 根据指定 key 获取list中所有的值 |
|||
* |
|||
* @param key |
|||
* @return |
|||
*/ |
|||
public static <V> V lgetAll(String key) { |
|||
return (V) redisTemplate.opsForList().range(key, 0, -1); |
|||
} |
|||
|
|||
/** |
|||
* 根据指定 key 获取list 长度 |
|||
* |
|||
* @param key |
|||
* @return |
|||
*/ |
|||
public static Long lsize(String key) { |
|||
return redisTemplate.opsForList().size(key); |
|||
} |
|||
|
|||
/** |
|||
* 根据指定 key 移除和value相等的元素, |
|||
* |
|||
* @param key |
|||
* @param count 要移除的元素数量,0:移除全部,>0:从头开始移除 count 个,<0:从尾部开始移除 count 个 |
|||
* @return |
|||
*/ |
|||
public static Long ldel(String key, long count, Object value) { |
|||
return redisTemplate.opsForList().remove(key, count, value); |
|||
} |
|||
} |
|||
@ -0,0 +1,67 @@ |
|||
package com.zdxt.enforcementcode.common.util; |
|||
|
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
|
|||
import java.security.MessageDigest; |
|||
|
|||
/** |
|||
* 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; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,91 @@ |
|||
package com.zdxt.enforcementcode.common.util; |
|||
|
|||
import org.springframework.util.DigestUtils; |
|||
import org.springframework.util.StringUtils; |
|||
|
|||
import java.nio.charset.StandardCharsets; |
|||
import java.security.MessageDigest; |
|||
import java.security.NoSuchAlgorithmException; |
|||
import java.util.UUID; |
|||
|
|||
/** |
|||
* 密码工具类 |
|||
* 加盐加密 / 加盐解密 |
|||
*/ |
|||
public class PasswordTools { |
|||
|
|||
/** |
|||
*加盐加密 |
|||
* @param password |
|||
* @return 加密后的密码 |
|||
*/ |
|||
public static String encrypt(String password){ |
|||
//生成盐值,使用随机字符串UUID,UUID为32位的
|
|||
String salt = UUID.randomUUID().toString().replace("-",""); |
|||
//(盐值+密码)进行MD5加密,DigestUtils.md5DigestAsHex参数为字节数组,生成一个十六进制32位的字符串
|
|||
String finalPassword = DigestUtils.md5DigestAsHex((salt+password).getBytes(StandardCharsets.UTF_8)); |
|||
//将盐值和加密的密码组合返回,最终存储到数据库中的密码
|
|||
String dbPassword = salt + "$" + finalPassword; |
|||
return dbPassword; |
|||
} |
|||
|
|||
/** |
|||
* 校验密码 |
|||
* @param password |
|||
* @param dbPassword |
|||
* @return |
|||
*/ |
|||
public static boolean decrypt(String password,String dbPassword){ |
|||
if(StringUtils.hasLength(password) && StringUtils.hasLength(dbPassword) |
|||
&& dbPassword.length()==65 && dbPassword.contains("$")){ |
|||
String[] arr = dbPassword.split("\\$"); |
|||
String salt = arr[0]; |
|||
//根据获取的盐值生成校验的密码
|
|||
String checkPassword = salt + "$" + DigestUtils.md5DigestAsHex((salt+password).getBytes(StandardCharsets.UTF_8)); |
|||
//用校验密码与数据库保存的密码进行校验
|
|||
if(checkPassword.equals(dbPassword)){ |
|||
return true; |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* 字符串256 加密 |
|||
* @param str |
|||
* @return |
|||
*/ |
|||
public static String SHA256(String str){ |
|||
try { |
|||
// 创建SHA-256哈希算法的MessageDigest对象
|
|||
MessageDigest sha256 = MessageDigest.getInstance("SHA-256"); |
|||
|
|||
// 使用SHA-256计算输入字符串的哈希值
|
|||
byte[] hash = sha256.digest(str.getBytes("UTF-8")); |
|||
|
|||
// 将字节转换为十六进制字符串
|
|||
StringBuilder hexString = new StringBuilder(); |
|||
for (byte b : hash) { |
|||
String hex = Integer.toHexString(0xff & b); |
|||
if (hex.length() == 1) { |
|||
hexString.append('0'); |
|||
} |
|||
hexString.append(hex); |
|||
} |
|||
|
|||
return hexString.toString(); |
|||
} catch (NoSuchAlgorithmException e) { |
|||
e.printStackTrace(); |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
public static void main(String[] args) { |
|||
String dbPassword = encrypt("88879ayqwt"); |
|||
System.out.println(decrypt("88879ayqwt",dbPassword)); //true
|
|||
System.out.println(decrypt("45678",dbPassword)); //false
|
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,498 @@ |
|||
package com.zdxt.enforcementcode.common.util; |
|||
|
|||
import com.google.zxing.*; |
|||
import com.google.zxing.client.j2se.BufferedImageLuminanceSource; |
|||
import com.google.zxing.common.BitMatrix; |
|||
import com.google.zxing.common.HybridBinarizer; |
|||
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; |
|||
import org.springframework.http.MediaType; |
|||
import org.springframework.mock.web.MockMultipartFile; |
|||
import org.springframework.web.multipart.MultipartFile; |
|||
|
|||
import javax.imageio.ImageIO; |
|||
import java.awt.*; |
|||
import java.awt.geom.RoundRectangle2D; |
|||
import java.awt.image.BufferedImage; |
|||
import java.io.*; |
|||
import java.util.*; |
|||
|
|||
public class QRCodeUtil { |
|||
private static final String CHARSET = "utf-8"; |
|||
private static final String FORMAT_NAME = "JPG"; |
|||
// 二维码尺寸
|
|||
private static final int QRCODE_SIZE = 300; |
|||
// LOGO宽度
|
|||
private static final int WIDTH = 60; |
|||
// LOGO高度
|
|||
private static final int HEIGHT = 60; |
|||
|
|||
private static BufferedImage createImage(String content, String imgPath, |
|||
boolean needCompress) throws Exception { |
|||
Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>(); |
|||
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); |
|||
hints.put(EncodeHintType.CHARACTER_SET, CHARSET); |
|||
hints.put(EncodeHintType.MARGIN, 1); |
|||
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, |
|||
BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, hints); |
|||
int width = bitMatrix.getWidth(); |
|||
int height = bitMatrix.getHeight(); |
|||
BufferedImage image = new BufferedImage(width, height, |
|||
BufferedImage.TYPE_INT_RGB); |
|||
for (int x = 0; x < width; x++) { |
|||
for (int y = 0; y < height; y++) { |
|||
image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 |
|||
: 0xFFFFFFFF); |
|||
} |
|||
} |
|||
if (imgPath == null || "".equals(imgPath)) { |
|||
return image; |
|||
} |
|||
// 插入图片
|
|||
QRCodeUtil.insertImage(image, imgPath, needCompress); |
|||
return image; |
|||
} |
|||
|
|||
/** |
|||
* 插入LOGO |
|||
* |
|||
* @param source |
|||
* 二维码图片 |
|||
* @param imgPath |
|||
* LOGO图片地址 |
|||
* @param needCompress |
|||
* 是否压缩 |
|||
* @throws Exception |
|||
*/ |
|||
private static void insertImage(BufferedImage source, String imgPath, |
|||
boolean needCompress) throws Exception { |
|||
File file = new File(imgPath); |
|||
if (!file.exists()) { |
|||
System.err.println(""+imgPath+" 该文件不存在!"); |
|||
return; |
|||
} |
|||
Image src = ImageIO.read(new File(imgPath)); |
|||
int width = src.getWidth(null); |
|||
int height = src.getHeight(null); |
|||
if (needCompress) { // 压缩LOGO
|
|||
if (width > WIDTH) { |
|||
width = WIDTH; |
|||
} |
|||
if (height > HEIGHT) { |
|||
height = HEIGHT; |
|||
} |
|||
Image image = src.getScaledInstance(width, height, |
|||
Image.SCALE_SMOOTH); |
|||
BufferedImage tag = new BufferedImage(width, height, |
|||
BufferedImage.TYPE_INT_RGB); |
|||
Graphics g = tag.getGraphics(); |
|||
g.drawImage(image, 0, 0, null); // 绘制缩小后的图
|
|||
g.dispose(); |
|||
src = image; |
|||
} |
|||
// 插入LOGO
|
|||
Graphics2D graph = source.createGraphics(); |
|||
int x = (QRCODE_SIZE - width) / 2; |
|||
int y = (QRCODE_SIZE - height) / 2; |
|||
graph.drawImage(src, x, y, width, height, null); |
|||
Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6); |
|||
graph.setStroke(new BasicStroke(3f)); |
|||
graph.draw(shape); |
|||
graph.dispose(); |
|||
} |
|||
|
|||
/** |
|||
* 生成二维码(内嵌LOGO) |
|||
* |
|||
* @param content |
|||
* 内容 |
|||
* @param imgPath |
|||
* LOGO地址 |
|||
* @param destPath |
|||
* 存放目录 |
|||
* @param needCompress |
|||
* 是否压缩LOGO |
|||
* @throws Exception |
|||
*/ |
|||
public static File encodeFile(String content, String imgPath, String destPath, |
|||
boolean needCompress) throws Exception { |
|||
String file = new Random().nextInt(99999999)+".jpg"; |
|||
File file1 = new File(destPath + "/" + file); |
|||
BufferedImage image = QRCodeUtil.createImage(content, imgPath, |
|||
needCompress); |
|||
mkdirs(destPath); |
|||
|
|||
ImageIO.write(image, FORMAT_NAME, file1); |
|||
return file1; |
|||
} |
|||
/** |
|||
* 生成二维码(内嵌LOGO) |
|||
* |
|||
* @param content |
|||
* 内容 |
|||
* @param imgPath |
|||
* LOGO地址 |
|||
* @param destPath |
|||
* 存放目录 |
|||
* @param needCompress |
|||
* 是否压缩LOGO |
|||
* @throws Exception |
|||
*/ |
|||
public static String encode(String content, String imgPath, String destPath, |
|||
boolean needCompress) throws Exception { |
|||
|
|||
String file = new Random().nextInt(99999999)+".jpg"; |
|||
BufferedImage image = QRCodeUtil.createImage(content, imgPath, |
|||
needCompress); |
|||
mkdirs(destPath); |
|||
|
|||
ImageIO.write(image, FORMAT_NAME, new File(destPath + "/" + file)); |
|||
return destPath + "/" + file; |
|||
} |
|||
|
|||
/** |
|||
* 当文件夹不存在时,mkdirs会自动创建多层目录,区别于mkdir.(mkdir如果父目录不存在则会抛出异常) |
|||
* @param destPath 存放目录 |
|||
*/ |
|||
public static void mkdirs(String destPath) { |
|||
File file =new File(destPath); |
|||
//当文件夹不存在时,mkdirs会自动创建多层目录,区别于mkdir.(mkdir如果父目录不存在则会抛出异常)
|
|||
if (!file.exists() && !file.isDirectory()) { |
|||
file.mkdirs(); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 生成二维码(内嵌LOGO) |
|||
* |
|||
* @param content |
|||
* 内容 |
|||
* @param imgPath |
|||
* LOGO地址 |
|||
* @param destPath |
|||
* 存储地址 |
|||
* @throws Exception |
|||
*/ |
|||
public static void encode(String content, String imgPath, String destPath) |
|||
throws Exception { |
|||
QRCodeUtil.encode(content, imgPath, destPath, false); |
|||
} |
|||
|
|||
/** |
|||
* 生成二维码 |
|||
* |
|||
* @param content |
|||
* 内容 |
|||
* @param destPath |
|||
* 存储地址 |
|||
* @param needCompress |
|||
* 是否压缩LOGO |
|||
* @throws Exception |
|||
*/ |
|||
public static void encode(String content, String destPath, |
|||
boolean needCompress) throws Exception { |
|||
QRCodeUtil.encode(content, null, destPath, needCompress); |
|||
} |
|||
|
|||
/** |
|||
* 生成二维码 |
|||
* |
|||
* @param content |
|||
* 内容 |
|||
* @param destPath |
|||
* 存储地址 |
|||
* @throws Exception |
|||
*/ |
|||
public static void encode(String content, String destPath) throws Exception { |
|||
QRCodeUtil.encode(content, null, destPath, false); |
|||
} |
|||
|
|||
/** |
|||
* 生成二维码(内嵌LOGO) |
|||
* |
|||
* @param content |
|||
* 内容 |
|||
* @param imgPath |
|||
* LOGO地址 |
|||
* @param output |
|||
* 输出流 |
|||
* @param needCompress |
|||
* 是否压缩LOGO |
|||
* @throws Exception |
|||
*/ |
|||
public static void encode(String content, String imgPath, |
|||
OutputStream output, boolean needCompress) throws Exception { |
|||
BufferedImage image = QRCodeUtil.createImage(content, imgPath, |
|||
needCompress); |
|||
ImageIO.write(image, FORMAT_NAME, output); |
|||
} |
|||
|
|||
/** |
|||
* 生成二维码 |
|||
* |
|||
* @param content |
|||
* 内容 |
|||
* @param output |
|||
* 输出流 |
|||
* @throws Exception |
|||
*/ |
|||
public static void encode(String content, OutputStream output) |
|||
throws Exception { |
|||
QRCodeUtil.encode(content, null, output, false); |
|||
} |
|||
|
|||
/** |
|||
* 解析二维码 |
|||
* |
|||
* @param file |
|||
* 二维码图片 |
|||
* @return |
|||
* @throws Exception |
|||
*/ |
|||
public static String decode(File file) throws Exception { |
|||
BufferedImage image; |
|||
image = ImageIO.read(file); |
|||
if (image == null) { |
|||
return null; |
|||
} |
|||
BufferedImageLuminanceSource source = new BufferedImageLuminanceSource( |
|||
image); |
|||
BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); |
|||
Result result; |
|||
Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>(); |
|||
hints.put(DecodeHintType.CHARACTER_SET, CHARSET); |
|||
result = new MultiFormatReader().decode(bitmap, hints); |
|||
String resultStr = result.getText(); |
|||
return resultStr; |
|||
} |
|||
|
|||
/** |
|||
* 解析二维码 |
|||
* |
|||
* @param path |
|||
* 二维码图片地址 |
|||
* @return |
|||
* @throws Exception |
|||
*/ |
|||
public static String decode(String path) throws Exception { |
|||
return QRCodeUtil.decode(new File(path)); |
|||
} |
|||
|
|||
/** |
|||
* |
|||
* @param content |
|||
* @param imgPath |
|||
* @param destPath |
|||
* @param localUrl 当前环境的域名或者ip地址 |
|||
* @param needCompress |
|||
* @return |
|||
* @throws Exception |
|||
*/ |
|||
public static String encode(String content, String imgPath, String destPath,String localUrl, |
|||
boolean needCompress) throws Exception { |
|||
BufferedImage image = QRCodeUtil.createImage(content, imgPath, |
|||
needCompress); |
|||
mkdirs(destPath); |
|||
String file = new Random().nextInt(99999999)+".jpg"; |
|||
ImageIO.write(image, FORMAT_NAME, new File(destPath+"/"+file)); |
|||
return localUrl+file; |
|||
} |
|||
|
|||
public static String encodeDZ(String content, String imgPath, String destPath,String localUrl,int length,int width, |
|||
boolean needCompress) throws Exception { |
|||
BufferedImage image = QRCodeUtil.createImageDZ(content, imgPath,length,width, |
|||
needCompress); |
|||
mkdirs(destPath); |
|||
String file = new Random().nextInt(99999999)+".jpg"; |
|||
ImageIO.write(image, FORMAT_NAME, new File(destPath+"/"+file)); |
|||
return localUrl+file; |
|||
} |
|||
|
|||
private static BufferedImage createImageDZ(String content, String imgPath,int newlength,int newWidth, |
|||
boolean needCompress) throws Exception { |
|||
Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>(); |
|||
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); |
|||
hints.put(EncodeHintType.CHARACTER_SET, CHARSET); |
|||
hints.put(EncodeHintType.MARGIN, 1); |
|||
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, |
|||
BarcodeFormat.QR_CODE, newlength, newWidth, hints); |
|||
int width = bitMatrix.getWidth(); |
|||
int height = bitMatrix.getHeight(); |
|||
BufferedImage image = new BufferedImage(width, height, |
|||
BufferedImage.TYPE_INT_RGB); |
|||
for (int x = 0; x < width; x++) { |
|||
for (int y = 0; y < height; y++) { |
|||
image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 |
|||
: 0xFFFFFFFF); |
|||
} |
|||
} |
|||
if (imgPath == null || "".equals(imgPath)) { |
|||
return image; |
|||
} |
|||
// 插入图片
|
|||
QRCodeUtil.insertImage(image, imgPath, needCompress); |
|||
return image; |
|||
} |
|||
|
|||
/** |
|||
* 将图片url转换成base64流 |
|||
* @param url |
|||
* @return |
|||
*/ |
|||
public static String getBase64(String url){ |
|||
MultiFormatWriter multiFormatWriter = new MultiFormatWriter(); |
|||
Map hints = new HashMap(); |
|||
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); //设置字符集编码类型
|
|||
hints.put(EncodeHintType.MARGIN, 1); //设置白边
|
|||
BitMatrix bitMatrix = null; |
|||
try { |
|||
bitMatrix = multiFormatWriter.encode(url, BarcodeFormat.QR_CODE, 300, 300,hints); |
|||
BufferedImage image = toBufferedImage(bitMatrix); |
|||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); |
|||
//输出二维码图片流
|
|||
try { |
|||
ImageIO.write(image, "jpg",outputStream); |
|||
// String base = Base64Utils.encodeToString(outputStream.toByteArray());
|
|||
byte[] bytes = outputStream.toByteArray(); |
|||
String base = Base64.getEncoder().encodeToString(bytes); // ✅ 使用 Java 标准库
|
|||
|
|||
return base; |
|||
} catch (IOException e) { |
|||
// TODO Auto-generated catch block
|
|||
e.printStackTrace(); |
|||
} |
|||
} catch (WriterException e1) { |
|||
// TODO Auto-generated catch block
|
|||
e1.printStackTrace(); |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
|
|||
public static BufferedImage toBufferedImage(BitMatrix matrix) { |
|||
int width = matrix.getWidth(); |
|||
int height = matrix.getHeight(); |
|||
BufferedImage image = new BufferedImage(width, height, |
|||
BufferedImage.TYPE_INT_RGB); |
|||
for (int x = 0; x < width; x++) { |
|||
for (int y = 0; y < height; y++) { |
|||
image.setRGB(x, y, matrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);//0xFF000000黑;0xFFFFFFFF白
|
|||
} |
|||
} |
|||
return image; |
|||
} |
|||
|
|||
// 蓝色二维码前景色
|
|||
private static final int BLUE_FOREGROUND_COLOR = 0xFF003399; |
|||
|
|||
// classpath中的LOGO图片路径
|
|||
private static final String EMBEDDED_LOGO_PATH = "images/enterprise_pub_qrcode_logo.jpg"; |
|||
|
|||
/** |
|||
* 生成蓝色二维码并在中间插入自定义图片,返回BufferedImage |
|||
* |
|||
* @param content 二维码内容 |
|||
* @param imgPath 中间图片地址(为空则不插入图片) |
|||
* @param needCompress 是否压缩中间图片 |
|||
* @return BufferedImage |
|||
* @throws Exception |
|||
*/ |
|||
public static BufferedImage createBlueQrCode(String content, String imgPath, |
|||
boolean needCompress) throws Exception { |
|||
Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>(); |
|||
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); |
|||
hints.put(EncodeHintType.CHARACTER_SET, CHARSET); |
|||
hints.put(EncodeHintType.MARGIN, 1); |
|||
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, |
|||
BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, hints); |
|||
int width = bitMatrix.getWidth(); |
|||
int height = bitMatrix.getHeight(); |
|||
BufferedImage image = new BufferedImage(width, height, |
|||
BufferedImage.TYPE_INT_RGB); |
|||
for (int x = 0; x < width; x++) { |
|||
for (int y = 0; y < height; y++) { |
|||
image.setRGB(x, y, bitMatrix.get(x, y) ? BLUE_FOREGROUND_COLOR |
|||
: 0xFFFFFFFF); |
|||
} |
|||
} |
|||
if (imgPath != null && !"".equals(imgPath)) { |
|||
insertImage(image, imgPath, needCompress); |
|||
} |
|||
return image; |
|||
} |
|||
|
|||
/** |
|||
* 生成蓝色二维码并在中间插入classpath中的LOGO图片,返回BufferedImage |
|||
* |
|||
* @param content 二维码内容 |
|||
* @return BufferedImage |
|||
* @throws Exception |
|||
*/ |
|||
public static BufferedImage createBlueQrCodeWithLogo(String content,int size) throws Exception { |
|||
Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>(); |
|||
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); |
|||
hints.put(EncodeHintType.CHARACTER_SET, CHARSET); |
|||
hints.put(EncodeHintType.MARGIN, 1); |
|||
BitMatrix bitMatrix = new MultiFormatWriter().encode(content, |
|||
BarcodeFormat.QR_CODE, size, size, hints); |
|||
int width = bitMatrix.getWidth(); |
|||
int height = bitMatrix.getHeight(); |
|||
BufferedImage image = new BufferedImage(width, height, |
|||
BufferedImage.TYPE_INT_RGB); |
|||
for (int x = 0; x < width; x++) { |
|||
for (int y = 0; y < height; y++) { |
|||
image.setRGB(x, y, bitMatrix.get(x, y) ? BLUE_FOREGROUND_COLOR |
|||
: 0xFFFFFFFF); |
|||
} |
|||
} |
|||
// 从classpath读取LOGO图片并插入二维码中间
|
|||
InputStream logoStream = QRCodeUtil.class.getClassLoader().getResourceAsStream(EMBEDDED_LOGO_PATH); |
|||
if (logoStream != null) { |
|||
Image logo = ImageIO.read(logoStream); |
|||
logoStream.close(); |
|||
int logoWidth = Math.min(logo.getWidth(null), 100); |
|||
int logoHeight = Math.min(logo.getHeight(null), 100); |
|||
Image scaledLogo = logo.getScaledInstance(logoWidth, logoHeight, Image.SCALE_SMOOTH); |
|||
Graphics2D graph = image.createGraphics(); |
|||
int x = (size - logoWidth) / 2; |
|||
int y = (size - logoHeight) / 2; |
|||
graph.drawImage(scaledLogo, x, y, logoWidth, logoHeight, null); |
|||
Shape shape = new RoundRectangle2D.Float(x, y, logoWidth, logoHeight, 6, 6); |
|||
graph.setStroke(new BasicStroke(3f)); |
|||
graph.draw(shape); |
|||
graph.dispose(); |
|||
} |
|||
return image; |
|||
} |
|||
|
|||
public static MultipartFile getMultipartFile(File file) { |
|||
try (InputStream input = new FileInputStream(file)) { |
|||
return new MockMultipartFile( |
|||
"file", // 字段名
|
|||
file.getName(), // 原始文件名
|
|||
MediaType.IMAGE_JPEG_VALUE, // 文件类型
|
|||
input.readAllBytes() // 文件内容
|
|||
); |
|||
} catch (Exception e) { |
|||
throw new IllegalArgumentException("Invalid file: " + e, e); |
|||
} |
|||
} |
|||
|
|||
|
|||
public static void main(String[] args) throws Exception { |
|||
String text = "https://www.baidu.com/s?ie=UTF-8&wd=%E7%99%BE%E5%BA%A6"; |
|||
//这里设置自定义网站url
|
|||
String logoPath =null; |
|||
String destPath = "d:\\pic\\"; |
|||
// String url=QRCodeUtil.encode(text, logoPath, destPath, true);
|
|||
// System.out.println(url);
|
|||
|
|||
|
|||
/* String file="D:\\11.jpg"; |
|||
String info=QRCodeUtil.decode(file); |
|||
System.out.println(info);*/ |
|||
// 将地址转换为二维码图片 base64编码返回给页面
|
|||
String base64 = getBase64(text); |
|||
System.out.println("data:image/jpeg;base64," + base64); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,51 @@ |
|||
package com.zdxt.enforcementcode.common.util.file; |
|||
|
|||
|
|||
|
|||
import org.dromara.common.core.utils.StringUtils; |
|||
|
|||
import java.io.File; |
|||
|
|||
/** |
|||
* Created with IntelliJ IDEA. |
|||
* Description: |
|||
* User: ouyunhui |
|||
* Date: 2020-12-08 |
|||
* Time: 15:59 |
|||
*/ |
|||
public class FileTypeUtils { |
|||
/** |
|||
* 获取文件类型 |
|||
* <p> |
|||
* 例如: ruoyi.txt, 返回: txt |
|||
* |
|||
* @param file 文件名 |
|||
* @return 后缀(不含".") |
|||
*/ |
|||
public static String getFileType(File file) |
|||
{ |
|||
if (null == file) |
|||
{ |
|||
return StringUtils.EMPTY; |
|||
} |
|||
return getFileType(file.getName()); |
|||
} |
|||
|
|||
/** |
|||
* 获取文件类型 |
|||
* <p> |
|||
* 例如: ruoyi.txt, 返回: txt |
|||
* |
|||
* @param fileName 文件名 |
|||
* @return 后缀(不含".") |
|||
*/ |
|||
public static String getFileType(String fileName) |
|||
{ |
|||
int separatorIndex = fileName.lastIndexOf("."); |
|||
if (separatorIndex < 0) |
|||
{ |
|||
return ""; |
|||
} |
|||
return fileName.substring(separatorIndex + 1).toLowerCase(); |
|||
} |
|||
} |
|||
@ -0,0 +1,252 @@ |
|||
package com.zdxt.enforcementcode.common.util.file; |
|||
|
|||
|
|||
import com.zdxt.enforcementcode.common.Constants; |
|||
import com.zdxt.enforcementcode.common.config.RuoYiConfig; |
|||
import com.zdxt.enforcementcode.common.util.Md5Utils; |
|||
import com.zdxt.enforcementcode.exception.FileSizeLimitExceededException; |
|||
import com.zdxt.enforcementcode.exception.InvalidExtensionException; |
|||
import org.apache.commons.io.FilenameUtils; |
|||
import org.dromara.common.core.exception.base.BaseException; |
|||
import org.dromara.common.core.utils.DateUtils; |
|||
import org.dromara.common.core.utils.StringUtils; |
|||
import org.springframework.web.multipart.MultipartFile; |
|||
|
|||
import java.io.File; |
|||
import java.io.IOException; |
|||
|
|||
/** |
|||
* 文件上传工具类 |
|||
* |
|||
* @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; |
|||
|
|||
/** |
|||
* 常见的视频类型 |
|||
*/ |
|||
public static final String VIDEO_TYPE = "rm|rmvb|wmv|avi|mp4|3gp|mkvrm|rmvb|avi|mp4|3gp|mkv"; |
|||
|
|||
/** |
|||
* 默认上传的地址 |
|||
*/ |
|||
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 上传的文件 |
|||
* @return 返回上传成功的文件名 |
|||
* @throws FileSizeLimitExceededException 如果超出最大大小 |
|||
* @throws IOException 比如读写文件出错时 |
|||
* @throws InvalidExtensionException 文件校验异常 |
|||
*/ |
|||
public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension) |
|||
throws Exception |
|||
{ |
|||
int fileNamelength = file.getOriginalFilename().length(); |
|||
if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) |
|||
{ |
|||
throw new Exception("文件名称过长"); |
|||
} |
|||
|
|||
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 |
|||
*/ |
|||
public static final void assertAllowed(MultipartFile file, String[] allowedExtension) |
|||
throws Exception |
|||
{ |
|||
long size = file.getSize(); |
|||
|
|||
int begin = file.getOriginalFilename().lastIndexOf("."); |
|||
int last = file.getOriginalFilename().length(); |
|||
//获得文件后缀名
|
|||
String a = file.getOriginalFilename().substring(begin+1, last); |
|||
if(VIDEO_TYPE.indexOf(a) == -1){ //判断是否是视频
|
|||
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; |
|||
} |
|||
} |
|||
@ -0,0 +1,138 @@ |
|||
package com.zdxt.enforcementcode.common.util.file; |
|||
|
|||
|
|||
import jakarta.servlet.http.HttpServletRequest; |
|||
|
|||
import java.io.*; |
|||
import java.net.URLEncoder; |
|||
|
|||
/** |
|||
* 文件处理工具类 |
|||
* |
|||
* @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; |
|||
} |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
package com.zdxt.enforcementcode.common.util.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","apk", "mp4" , "mkv"}; |
|||
|
|||
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 ""; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
package com.zdxt.enforcementcode.controller.common; |
|||
|
|||
import com.zdxt.enforcementcode.service.common.FileUploadApi; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.dromara.common.core.domain.R; |
|||
import org.dromara.common.log.annotation.Log; |
|||
import org.dromara.common.log.enums.BusinessType; |
|||
import org.dromara.common.web.core.BaseController; |
|||
import org.springframework.http.MediaType; |
|||
import org.springframework.validation.annotation.Validated; |
|||
import org.springframework.web.bind.annotation.PostMapping; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RequestPart; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
import org.springframework.web.multipart.MultipartFile; |
|||
|
|||
/** |
|||
* 文件上传 控制层 |
|||
* |
|||
* @author Lion Li |
|||
*/ |
|||
@Validated |
|||
@RequiredArgsConstructor |
|||
@RestController |
|||
@RequestMapping("/common/file") |
|||
public class FileController extends BaseController { |
|||
|
|||
private final FileUploadApi fileUploadApi; |
|||
|
|||
/** |
|||
* 上传文件 |
|||
* |
|||
* @param file 文件 |
|||
*/ |
|||
@Log(title = "文件上传", businessType = BusinessType.INSERT) |
|||
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) |
|||
public R<String> upload(@RequestPart("file") MultipartFile file) { |
|||
String filePath = fileUploadApi.upload(file); |
|||
return R.ok("上传成功", filePath); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
package com.zdxt.enforcementcode.exception; |
|||
|
|||
import org.dromara.common.core.exception.base.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); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
package com.zdxt.enforcementcode.exception; |
|||
|
|||
/** |
|||
* 文件名称超长限制异常类 |
|||
* |
|||
* @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 }); |
|||
} |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
package com.zdxt.enforcementcode.exception; |
|||
|
|||
/** |
|||
* 文件名大小限制异常类 |
|||
* |
|||
* @author ruoyi |
|||
*/ |
|||
public class FileSizeLimitExceededException extends FileException |
|||
{ |
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
public FileSizeLimitExceededException(long defaultMaxSize) |
|||
{ |
|||
super("upload.exceed.maxSize", new Object[] { defaultMaxSize }); |
|||
} |
|||
} |
|||
@ -0,0 +1,73 @@ |
|||
package com.zdxt.enforcementcode.exception; |
|||
|
|||
|
|||
import org.apache.tomcat.util.http.fileupload.FileUploadException; |
|||
|
|||
import java.util.Arrays; |
|||
|
|||
/** |
|||
* 文件上传 误异常类 |
|||
* |
|||
* @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); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
package com.zdxt.enforcementcode.service.common; |
|||
|
|||
|
|||
import org.springframework.web.bind.annotation.RestController; |
|||
import org.springframework.web.multipart.MultipartFile; |
|||
|
|||
import java.io.IOException; |
|||
|
|||
/** |
|||
* 文件上传API |
|||
* |
|||
* @author QingWang.Li |
|||
* @date 2020/3/20 16:44 |
|||
*/ |
|||
|
|||
@RestController |
|||
public interface FileUploadApi { |
|||
|
|||
/** |
|||
* 上传文件 |
|||
* |
|||
* @param file 上传的文件 |
|||
* @return 文件路径 |
|||
* @throws IOException |
|||
*/ |
|||
String upload(MultipartFile file); |
|||
|
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
package com.zdxt.enforcementcode.service.common.impl; |
|||
|
|||
|
|||
import com.zdxt.enforcementcode.common.util.file.FileUploadUtils; |
|||
import com.zdxt.enforcementcode.service.common.FileUploadApi; |
|||
import org.dromara.common.core.exception.base.BaseException; |
|||
import org.springframework.stereotype.Service; |
|||
import org.springframework.web.multipart.MultipartFile; |
|||
|
|||
import java.io.IOException; |
|||
|
|||
/** |
|||
* 文件上传API-实现类 |
|||
* |
|||
* @author QingWang.Li |
|||
* @date 2020/3/20 16:50 |
|||
*/ |
|||
@Service |
|||
public class FileUploadApiImpl implements FileUploadApi { |
|||
|
|||
@Override |
|||
public String upload(MultipartFile file) { |
|||
String filePath = FileUploadUtils.getDefaultBaseDir(); |
|||
try { |
|||
return FileUploadUtils.upload(filePath, file); |
|||
} catch (IOException e) { |
|||
throw new BaseException("上传失败"); |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,301 @@ |
|||
//package com.zdxt.rest.test;
|
|||
//
|
|||
//import cn.dev33.satoken.context.mock.SaTokenContextMockUtil;
|
|||
//import org.dromara.ZdxtAdminApplication;
|
|||
//import org.junit.jupiter.api.*;
|
|||
//import org.springframework.beans.factory.annotation.Autowired;
|
|||
//import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
|||
//import org.springframework.boot.test.context.SpringBootTest;
|
|||
//import org.springframework.http.MediaType;
|
|||
//import org.springframework.test.web.servlet.MockMvc;
|
|||
//import org.springframework.test.web.servlet.MvcResult;
|
|||
//
|
|||
//import java.nio.charset.StandardCharsets;
|
|||
//
|
|||
//import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
|||
//import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
|
|||
//import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
|||
//
|
|||
///**
|
|||
// * AppEnterpriseLoginController 企业端-用户登录接口测试
|
|||
// * <p>
|
|||
// * 覆盖以下接口:
|
|||
// * 1. POST /app-ent/login/siqLogin - 深i企用户登录
|
|||
// * </p>
|
|||
// * <p>
|
|||
// * 注意:此测试需要配置真实的深i企接口地址,或在测试环境中 Mock 相关服务
|
|||
// * </p>
|
|||
// *
|
|||
// * @author zdxt
|
|||
// */
|
|||
//@SpringBootTest(classes = ZdxtAdminApplication.class)
|
|||
//@AutoConfigureMockMvc
|
|||
//@DisplayName("AppEnterpriseLoginController 企业端-用户登录接口测试")
|
|||
//@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
|||
//public class AppEnterpriseLoginControllerTest {
|
|||
//
|
|||
// @Autowired
|
|||
// private MockMvc mockMvc;
|
|||
//
|
|||
// private static final String BASE_URL = "/app-ent/login";
|
|||
// private static final String TEST_CLIENT_ID = "e5cd7e4891bf95d1d19206ce24a7b32e";
|
|||
//
|
|||
// @BeforeEach
|
|||
// public void setUp() {
|
|||
// SaTokenContextMockUtil.setMockContext();
|
|||
// }
|
|||
//
|
|||
// @AfterEach
|
|||
// public void tearDown() {
|
|||
// SaTokenContextMockUtil.clearContext();
|
|||
// }
|
|||
//
|
|||
// // ==================== siqLogin 接口测试 ====================
|
|||
//
|
|||
// @DisplayName("深i企登录 - 正常请求(需要有效的授权码)")
|
|||
// @Test
|
|||
// @Order(1)
|
|||
// public void testSiqLoginSuccess() throws Exception {
|
|||
// String requestBody = "{\"code\":\"test_authorization_code\"}";
|
|||
//
|
|||
// MvcResult result = mockMvc.perform(post(BASE_URL + "/siqLogin")
|
|||
// .contentType(MediaType.APPLICATION_JSON)
|
|||
// .content(requestBody))
|
|||
// .andDo(print())
|
|||
// .andExpect(status().isOk())
|
|||
// .andReturn();
|
|||
//
|
|||
// String responseBody = result.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
|||
// System.out.println("深i企登录接口响应: " + responseBody);
|
|||
//
|
|||
// if (responseBody.contains("\"code\":200")) {
|
|||
// Assertions.assertTrue(responseBody.contains("token"), "返回数据应包含 token");
|
|||
// Assertions.assertTrue(responseBody.contains("userId"), "返回数据应包含 userId");
|
|||
// Assertions.assertTrue(responseBody.contains("userName"), "返回数据应包含 userName");
|
|||
// Assertions.assertTrue(responseBody.contains("enterpriseId"), "返回数据应包含 enterpriseId");
|
|||
// Assertions.assertTrue(responseBody.contains("enterpriseName"), "返回数据应包含 enterpriseName");
|
|||
// System.out.println("深i企登录成功,返回了完整的用户和企业信息");
|
|||
// } else {
|
|||
// System.out.println("深i企登录失败(可能由于授权码无效或深i企接口未配置): " + responseBody);
|
|||
// }
|
|||
// }
|
|||
//
|
|||
// @DisplayName("深i企登录 - 缺少授权码参数应返回失败")
|
|||
// @Test
|
|||
// @Order(2)
|
|||
// public void testSiqLoginMissingCode() throws Exception {
|
|||
// String requestBody = "{}";
|
|||
//
|
|||
// mockMvc.perform(post(BASE_URL + "/siqLogin")
|
|||
// .contentType(MediaType.APPLICATION_JSON)
|
|||
// .content(requestBody))
|
|||
// .andDo(print())
|
|||
// .andExpect(status().isOk())
|
|||
// .andExpect(jsonPath("$.code").value(500));
|
|||
//
|
|||
// System.out.println("缺少授权码参数返回失败测试成功");
|
|||
// }
|
|||
//
|
|||
// @DisplayName("深i企登录 - 空授权码应返回失败")
|
|||
// @Test
|
|||
// @Order(3)
|
|||
// public void testSiqLoginEmptyCode() throws Exception {
|
|||
// String requestBody = "{\"code\":\"\"}";
|
|||
//
|
|||
// mockMvc.perform(post(BASE_URL + "/siqLogin")
|
|||
// .contentType(MediaType.APPLICATION_JSON)
|
|||
// .content(requestBody))
|
|||
// .andDo(print())
|
|||
// .andExpect(status().isOk())
|
|||
// .andExpect(jsonPath("$.code").value(500));
|
|||
//
|
|||
// System.out.println("空授权码返回失败测试成功");
|
|||
// }
|
|||
//
|
|||
// @DisplayName("深i企登录 - 无效授权码应返回失败")
|
|||
// @Test
|
|||
// @Order(4)
|
|||
// public void testSiqLoginInvalidCode() throws Exception {
|
|||
// String requestBody = "{\"code\":\"invalid_code_12345\"}";
|
|||
//
|
|||
// MvcResult result = mockMvc.perform(post(BASE_URL + "/siqLogin")
|
|||
// .contentType(MediaType.APPLICATION_JSON)
|
|||
// .content(requestBody))
|
|||
// .andDo(print())
|
|||
// .andExpect(status().isOk())
|
|||
// .andReturn();
|
|||
//
|
|||
// String responseBody = result.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
|||
//
|
|||
// if (responseBody.contains("\"code\":500")) {
|
|||
// System.out.println("无效授权码返回失败测试成功");
|
|||
// } else {
|
|||
// System.out.println("注意:无效授权码未返回预期错误,响应: " + responseBody);
|
|||
// }
|
|||
// }
|
|||
//
|
|||
// @DisplayName("深i企登录 - 验证返回数据结构完整性")
|
|||
// @Test
|
|||
// @Order(5)
|
|||
// public void testSiqLoginResponseStructure() throws Exception {
|
|||
// String requestBody = "{\"code\":\"test_code\"}";
|
|||
//
|
|||
// MvcResult result = mockMvc.perform(post(BASE_URL + "/siqLogin")
|
|||
// .contentType(MediaType.APPLICATION_JSON)
|
|||
// .content(requestBody))
|
|||
// .andDo(print())
|
|||
// .andExpect(status().isOk())
|
|||
// .andReturn();
|
|||
//
|
|||
// String responseBody = result.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
|||
// System.out.println("验证返回数据结构响应: " + responseBody);
|
|||
//
|
|||
// if (responseBody.contains("\"code\":200")) {
|
|||
// Assertions.assertTrue(responseBody.contains("\"data\""), "返回数据应包含 data 字段");
|
|||
//
|
|||
// String data = extractDataJson(responseBody);
|
|||
// if (data != null) {
|
|||
// Assertions.assertTrue(data.contains("token"), "data 中应包含 token");
|
|||
// Assertions.assertTrue(data.contains("userId"), "data 中应包含 userId");
|
|||
// Assertions.assertTrue(data.contains("userName"), "data 中应包含 userName");
|
|||
// Assertions.assertTrue(data.contains("loginName"), "data 中应包含 loginName");
|
|||
// Assertions.assertTrue(data.contains("phonenumber"), "data 中应包含 phonenumber");
|
|||
// Assertions.assertTrue(data.contains("enterpriseId"), "data 中应包含 enterpriseId");
|
|||
// Assertions.assertTrue(data.contains("enterpriseName"), "data 中应包含 enterpriseName");
|
|||
// Assertions.assertTrue(data.contains("enterpriseNumber"), "data 中应包含 enterpriseNumber");
|
|||
// System.out.println("返回数据结构完整,包含所有必需字段");
|
|||
// }
|
|||
// } else {
|
|||
// System.out.println("登录失败,无法验证数据结构");
|
|||
// }
|
|||
// }
|
|||
//
|
|||
// @DisplayName("深i企登录 - 重复登录应能正常处理(同一授权码多次调用)")
|
|||
// @Test
|
|||
// @Order(6)
|
|||
// public void testSiqLoginDuplicateCall() throws Exception {
|
|||
// String requestBody = "{\"code\":\"test_code\"}";
|
|||
//
|
|||
// for (int i = 1; i <= 3; i++) {
|
|||
// System.out.println("========== 第 " + i + " 次调用深i企登录 ==========");
|
|||
//
|
|||
// MvcResult result = mockMvc.perform(post(BASE_URL + "/siqLogin")
|
|||
// .contentType(MediaType.APPLICATION_JSON)
|
|||
// .content(requestBody))
|
|||
// .andDo(print())
|
|||
// .andExpect(status().isOk())
|
|||
// .andReturn();
|
|||
//
|
|||
// String responseBody = result.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
|||
// System.out.println("第 " + i + " 次调用响应: " + responseBody);
|
|||
//
|
|||
// Thread.sleep(1000);
|
|||
// }
|
|||
//
|
|||
// System.out.println("========== 重复登录测试完成 ==========");
|
|||
// }
|
|||
//
|
|||
// @DisplayName("深i企登录 - 验证 Token 格式")
|
|||
// @Test
|
|||
// @Order(7)
|
|||
// public void testSiqLoginTokenFormat() throws Exception {
|
|||
// String requestBody = "{\"code\":\"test_code\"}";
|
|||
//
|
|||
// MvcResult result = mockMvc.perform(post(BASE_URL + "/siqLogin")
|
|||
// .contentType(MediaType.APPLICATION_JSON)
|
|||
// .content(requestBody))
|
|||
// .andDo(print())
|
|||
// .andExpect(status().isOk())
|
|||
// .andReturn();
|
|||
//
|
|||
// String responseBody = result.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
|||
//
|
|||
// if (responseBody.contains("\"code\":200")) {
|
|||
// String token = extractTokenFromResponse(responseBody);
|
|||
// if (token != null && !token.isEmpty()) {
|
|||
// Assertions.assertTrue(token.length() > 10, "Token 长度应大于10个字符");
|
|||
// System.out.println("Token 格式验证通过,Token: " + token);
|
|||
// } else {
|
|||
// System.out.println("未能提取到 Token");
|
|||
// }
|
|||
// } else {
|
|||
// System.out.println("登录失败,无法验证 Token 格式");
|
|||
// }
|
|||
// }
|
|||
//
|
|||
// @DisplayName("深i企登录 - 验证企业信息关联")
|
|||
// @Test
|
|||
// @Order(8)
|
|||
// public void testSiqLoginEnterpriseAssociation() throws Exception {
|
|||
// String requestBody = "{\"code\":\"test_code\"}";
|
|||
//
|
|||
// MvcResult result = mockMvc.perform(post(BASE_URL + "/siqLogin")
|
|||
// .contentType(MediaType.APPLICATION_JSON)
|
|||
// .content(requestBody))
|
|||
// .andDo(print())
|
|||
// .andExpect(status().isOk())
|
|||
// .andReturn();
|
|||
//
|
|||
// String responseBody = result.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
|||
//
|
|||
// if (responseBody.contains("\"code\":200")) {
|
|||
// String data = extractDataJson(responseBody);
|
|||
// if (data != null) {
|
|||
// String enterpriseId = extractJsonValue(data, "enterpriseId");
|
|||
// String enterpriseName = extractJsonValue(data, "enterpriseName");
|
|||
// String enterpriseNumber = extractJsonValue(data, "enterpriseNumber");
|
|||
//
|
|||
// if (enterpriseId != null && enterpriseName != null && enterpriseNumber != null) {
|
|||
// Assertions.assertFalse(enterpriseId.isEmpty(), "企业ID不应为空");
|
|||
// Assertions.assertFalse(enterpriseName.isEmpty(), "企业名称不应为空");
|
|||
// Assertions.assertFalse(enterpriseNumber.isEmpty(), "企业统一信用代码不应为空");
|
|||
// System.out.println("企业信息关联验证通过");
|
|||
// System.out.println("企业ID: " + enterpriseId);
|
|||
// System.out.println("企业名称: " + enterpriseName);
|
|||
// System.out.println("企业统一信用代码: " + enterpriseNumber);
|
|||
// }
|
|||
// }
|
|||
// } else {
|
|||
// System.out.println("登录失败,无法验证企业信息关联");
|
|||
// }
|
|||
// }
|
|||
//
|
|||
// // ==================== 工具方法 ====================
|
|||
//
|
|||
// /**
|
|||
// * 从 JSON 响应中提取 data 字段
|
|||
// */
|
|||
// private String extractDataJson(String responseBody) {
|
|||
// if (responseBody != null && responseBody.contains("\"data\":{")) {
|
|||
// int start = responseBody.indexOf("\"data\":{") + 7;
|
|||
// int end = responseBody.lastIndexOf("}");
|
|||
// if (start > 0 && end > start) {
|
|||
// return responseBody.substring(start, end + 1);
|
|||
// }
|
|||
// }
|
|||
// return null;
|
|||
// }
|
|||
//
|
|||
// /**
|
|||
// * 从响应中提取 Token
|
|||
// */
|
|||
// private String extractTokenFromResponse(String responseBody) {
|
|||
// return extractJsonValue(responseBody, "token");
|
|||
// }
|
|||
//
|
|||
// /**
|
|||
// * 从 JSON 字符串中提取指定字段的值
|
|||
// */
|
|||
// private String extractJsonValue(String json, String key) {
|
|||
// if (json != null && json.contains("\"" + key + "\"")) {
|
|||
// int start = json.indexOf("\"" + key + "\":\"") + key.length() + 4;
|
|||
// int end = json.indexOf("\"", start);
|
|||
// if (start > 0 && end > start) {
|
|||
// return json.substring(start, end);
|
|||
// }
|
|||
// }
|
|||
// return null;
|
|||
// }
|
|||
//}
|
|||
//{
|
|||
//}
|
|||
Loading…
Reference in new issue