master
parent
b9f8aa4f7d
commit
f863de50a4
|
@ -0,0 +1,14 @@
|
|||
@echo off
|
||||
echo.
|
||||
echo [信息] 使用Jar命令运行Gateway工程。
|
||||
echo.
|
||||
|
||||
cd %~dp0
|
||||
cd ../jing-gateway/target
|
||||
|
||||
set JAVA_OPTS=-Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m
|
||||
|
||||
java -Dfile.encoding=utf-8 %JAVA_OPTS% -jar jing-gateway.jar
|
||||
|
||||
cd bin
|
||||
pause
|
|
@ -0,0 +1,14 @@
|
|||
@echo off
|
||||
echo.
|
||||
echo [信息] 使用Jar命令运行Modules-File工程。
|
||||
echo.
|
||||
|
||||
cd %~dp0
|
||||
cd ../jing-modules/jing-file/target
|
||||
|
||||
set JAVA_OPTS=-Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m
|
||||
|
||||
java -Dfile.encoding=utf-8 %JAVA_OPTS% -jar jing-modules-file.jar
|
||||
|
||||
cd bin
|
||||
pause
|
|
@ -0,0 +1,14 @@
|
|||
@echo off
|
||||
echo.
|
||||
echo [信息] 使用Jar命令运行Modules-Gen工程。
|
||||
echo.
|
||||
|
||||
cd %~dp0
|
||||
cd ../jing-modules/jing-gen/target
|
||||
|
||||
set JAVA_OPTS=-Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m
|
||||
|
||||
java -Dfile.encoding=utf-8 %JAVA_OPTS% -jar jing-modules-gen.jar
|
||||
|
||||
cd bin
|
||||
pause
|
|
@ -0,0 +1,14 @@
|
|||
@echo off
|
||||
echo.
|
||||
echo [信息] 使用Jar命令运行Modules-Job工程。
|
||||
echo.
|
||||
|
||||
cd %~dp0
|
||||
cd ../jing-modules/jing-job/target
|
||||
|
||||
set JAVA_OPTS=-Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m
|
||||
|
||||
java -Dfile.encoding=utf-8 %JAVA_OPTS% -jar jing-modules-job.jar
|
||||
|
||||
cd bin
|
||||
pause
|
|
@ -0,0 +1,410 @@
|
|||
package com.jing.common.core.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.jing.common.core.text.Convert;
|
||||
import com.jing.common.core.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]);
|
||||
}
|
||||
}
|
||||
else if (cs[i] == boolean.class || cs[i] == Boolean.class)
|
||||
{
|
||||
args[i] = Convert.toBool(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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package com.jing.common.redis.configure;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
|
||||
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;
|
||||
|
||||
/**
|
||||
* redis配置
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
@AutoConfigureBefore(RedisAutoConfiguration.class)
|
||||
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);
|
||||
|
||||
// 使用StringRedisSerializer来序列化和反序列化redis的key值
|
||||
template.setKeySerializer(new StringRedisSerializer());
|
||||
template.setValueSerializer(serializer);
|
||||
|
||||
// Hash的key也采用StringRedisSerializer的序列化方式
|
||||
template.setHashKeySerializer(new StringRedisSerializer());
|
||||
template.setHashValueSerializer(serializer);
|
||||
|
||||
template.afterPropertiesSet();
|
||||
return template;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,268 @@
|
|||
package com.jing.common.redis.service;
|
||||
|
||||
import java.util.Collection;
|
||||
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.RedisTemplate;
|
||||
import org.springframework.data.redis.core.ValueOperations;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* spring redis 工具类
|
||||
*
|
||||
* @author ruoyi
|
||||
**/
|
||||
@SuppressWarnings(value = { "unchecked", "rawtypes" })
|
||||
@Component
|
||||
public class RedisService
|
||||
{
|
||||
@Autowired
|
||||
public RedisTemplate redisTemplate;
|
||||
|
||||
/**
|
||||
* 缓存基本的对象,Integer、String、实体类等
|
||||
*
|
||||
* @param key 缓存的键值
|
||||
* @param value 缓存的值
|
||||
*/
|
||||
public <T> void setCacheObject(final String key, final T value)
|
||||
{
|
||||
redisTemplate.opsForValue().set(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存基本的对象,Integer、String、实体类等
|
||||
*
|
||||
* @param key 缓存的键值
|
||||
* @param value 缓存的值
|
||||
* @param timeout 时间
|
||||
* @param timeUnit 时间颗粒度
|
||||
*/
|
||||
public <T> void setCacheObject(final String key, final T value, final Long timeout, final TimeUnit timeUnit)
|
||||
{
|
||||
redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置有效时间
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param timeout 超时时间
|
||||
* @return true=设置成功;false=设置失败
|
||||
*/
|
||||
public boolean expire(final String key, final long timeout)
|
||||
{
|
||||
return expire(key, timeout, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置有效时间
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param timeout 超时时间
|
||||
* @param unit 时间单位
|
||||
* @return true=设置成功;false=设置失败
|
||||
*/
|
||||
public boolean expire(final String key, final long timeout, final TimeUnit unit)
|
||||
{
|
||||
return redisTemplate.expire(key, timeout, unit);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取有效时间
|
||||
*
|
||||
* @param key Redis键
|
||||
* @return 有效时间
|
||||
*/
|
||||
public long getExpire(final String key)
|
||||
{
|
||||
return redisTemplate.getExpire(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断 key是否存在
|
||||
*
|
||||
* @param key 键
|
||||
* @return true 存在 false不存在
|
||||
*/
|
||||
public Boolean hasKey(String key)
|
||||
{
|
||||
return redisTemplate.hasKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的基本对象。
|
||||
*
|
||||
* @param key 缓存键值
|
||||
* @return 缓存键值对应的数据
|
||||
*/
|
||||
public <T> T getCacheObject(final String key)
|
||||
{
|
||||
ValueOperations<String, T> operation = redisTemplate.opsForValue();
|
||||
return operation.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除单个对象
|
||||
*
|
||||
* @param key
|
||||
*/
|
||||
public boolean deleteObject(final String key)
|
||||
{
|
||||
return redisTemplate.delete(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除集合对象
|
||||
*
|
||||
* @param collection 多个对象
|
||||
* @return
|
||||
*/
|
||||
public boolean deleteObject(final Collection collection)
|
||||
{
|
||||
return redisTemplate.delete(collection) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存List数据
|
||||
*
|
||||
* @param key 缓存的键值
|
||||
* @param dataList 待缓存的List数据
|
||||
* @return 缓存的对象
|
||||
*/
|
||||
public <T> long setCacheList(final String key, final List<T> dataList)
|
||||
{
|
||||
Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
|
||||
return count == null ? 0 : count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的list对象
|
||||
*
|
||||
* @param key 缓存的键值
|
||||
* @return 缓存键值对应的数据
|
||||
*/
|
||||
public <T> List<T> getCacheList(final String key)
|
||||
{
|
||||
return redisTemplate.opsForList().range(key, 0, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存Set
|
||||
*
|
||||
* @param key 缓存键值
|
||||
* @param dataSet 缓存的数据
|
||||
* @return 缓存数据的对象
|
||||
*/
|
||||
public <T> BoundSetOperations<String, T> setCacheSet(final String key, final 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(final String key)
|
||||
{
|
||||
return redisTemplate.opsForSet().members(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存Map
|
||||
*
|
||||
* @param key
|
||||
* @param dataMap
|
||||
*/
|
||||
public <T> void setCacheMap(final String key, final Map<String, T> dataMap)
|
||||
{
|
||||
if (dataMap != null) {
|
||||
redisTemplate.opsForHash().putAll(key, dataMap);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的Map
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public <T> Map<String, T> getCacheMap(final String key)
|
||||
{
|
||||
return redisTemplate.opsForHash().entries(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 往Hash中存入数据
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param hKey Hash键
|
||||
* @param value 值
|
||||
*/
|
||||
public <T> void setCacheMapValue(final String key, final String hKey, final T value)
|
||||
{
|
||||
redisTemplate.opsForHash().put(key, hKey, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Hash中的数据
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param hKey Hash键
|
||||
* @return Hash中的对象
|
||||
*/
|
||||
public <T> T getCacheMapValue(final String key, final String hKey)
|
||||
{
|
||||
HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
|
||||
return opsForHash.get(key, hKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取多个Hash中的数据
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param hKeys Hash键集合
|
||||
* @return Hash对象集合
|
||||
*/
|
||||
public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys)
|
||||
{
|
||||
return redisTemplate.opsForHash().multiGet(key, hKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除Hash中的某条数据
|
||||
*
|
||||
* @param key Redis键
|
||||
* @param hKey Hash键
|
||||
* @return 是否成功
|
||||
*/
|
||||
public boolean deleteCacheMapValue(final String key, final String hKey)
|
||||
{
|
||||
return redisTemplate.opsForHash().delete(key, hKey) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得缓存的基本对象列表
|
||||
*
|
||||
* @param pattern 字符串前缀
|
||||
* @return 对象列表
|
||||
*/
|
||||
public Collection<String> keys(final String pattern)
|
||||
{
|
||||
return redisTemplate.keys(pattern);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
import { makeMap } from '@/utils/index'
|
||||
|
||||
// 参考https://github.com/vuejs/vue/blob/v2.6.10/src/platforms/web/server/util.js
|
||||
const isAttr = makeMap(
|
||||
'accept,accept-charset,accesskey,action,align,alt,async,autocomplete,'
|
||||
+ 'autofocus,autoplay,autosave,bgcolor,border,buffered,challenge,charset,'
|
||||
+ 'checked,cite,class,code,codebase,color,cols,colspan,content,http-equiv,'
|
||||
+ 'name,contenteditable,contextmenu,controls,coords,data,datetime,default,'
|
||||
+ 'defer,dir,dirname,disabled,download,draggable,dropzone,enctype,method,for,'
|
||||
+ 'form,formaction,headers,height,hidden,high,href,hreflang,http-equiv,'
|
||||
+ 'icon,id,ismap,itemprop,keytype,kind,label,lang,language,list,loop,low,'
|
||||
+ 'manifest,max,maxlength,media,method,GET,POST,min,multiple,email,file,'
|
||||
+ 'muted,name,novalidate,open,optimum,pattern,ping,placeholder,poster,'
|
||||
+ 'preload,radiogroup,readonly,rel,required,reversed,rows,rowspan,sandbox,'
|
||||
+ 'scope,scoped,seamless,selected,shape,size,type,text,password,sizes,span,'
|
||||
+ 'spellcheck,src,srcdoc,srclang,srcset,start,step,style,summary,tabindex,'
|
||||
+ 'target,title,type,usemap,value,width,wrap'
|
||||
)
|
||||
|
||||
function vModel(self, dataObject, defaultValue) {
|
||||
dataObject.props.value = defaultValue
|
||||
|
||||
dataObject.on.input = val => {
|
||||
self.$emit('input', val)
|
||||
}
|
||||
}
|
||||
|
||||
const componentChild = {
|
||||
'el-button': {
|
||||
default(h, conf, key) {
|
||||
return conf[key]
|
||||
},
|
||||
},
|
||||
'el-input': {
|
||||
prepend(h, conf, key) {
|
||||
return <template slot="prepend">{conf[key]}</template>
|
||||
},
|
||||
append(h, conf, key) {
|
||||
return <template slot="append">{conf[key]}</template>
|
||||
}
|
||||
},
|
||||
'el-select': {
|
||||
options(h, conf, key) {
|
||||
const list = []
|
||||
conf.options.forEach(item => {
|
||||
list.push(<el-option label={item.label} value={item.value} disabled={item.disabled}></el-option>)
|
||||
})
|
||||
return list
|
||||
}
|
||||
},
|
||||
'el-radio-group': {
|
||||
options(h, conf, key) {
|
||||
const list = []
|
||||
conf.options.forEach(item => {
|
||||
if (conf.optionType === 'button') list.push(<el-radio-button label={item.value}>{item.label}</el-radio-button>)
|
||||
else list.push(<el-radio label={item.value} border={conf.border}>{item.label}</el-radio>)
|
||||
})
|
||||
return list
|
||||
}
|
||||
},
|
||||
'el-checkbox-group': {
|
||||
options(h, conf, key) {
|
||||
const list = []
|
||||
conf.options.forEach(item => {
|
||||
if (conf.optionType === 'button') {
|
||||
list.push(<el-checkbox-button label={item.value}>{item.label}</el-checkbox-button>)
|
||||
} else {
|
||||
list.push(<el-checkbox label={item.value} border={conf.border}>{item.label}</el-checkbox>)
|
||||
}
|
||||
})
|
||||
return list
|
||||
}
|
||||
},
|
||||
'el-upload': {
|
||||
'list-type': (h, conf, key) => {
|
||||
const list = []
|
||||
if (conf['list-type'] === 'picture-card') {
|
||||
list.push(<i class="el-icon-plus"></i>)
|
||||
} else {
|
||||
list.push(<el-button size="small" type="primary" icon="el-icon-upload">{conf.buttonText}</el-button>)
|
||||
}
|
||||
if (conf.showTip) {
|
||||
list.push(<div slot="tip" class="el-upload__tip">只能上传不超过 {conf.fileSize}{conf.sizeUnit} 的{conf.accept}文件</div>)
|
||||
}
|
||||
return list
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
render(h) {
|
||||
const dataObject = {
|
||||
attrs: {},
|
||||
props: {},
|
||||
on: {},
|
||||
style: {}
|
||||
}
|
||||
const confClone = JSON.parse(JSON.stringify(this.conf))
|
||||
const children = []
|
||||
|
||||
const childObjs = componentChild[confClone.tag]
|
||||
if (childObjs) {
|
||||
Object.keys(childObjs).forEach(key => {
|
||||
const childFunc = childObjs[key]
|
||||
if (confClone[key]) {
|
||||
children.push(childFunc(h, confClone, key))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Object.keys(confClone).forEach(key => {
|
||||
const val = confClone[key]
|
||||
if (key === 'vModel') {
|
||||
vModel(this, dataObject, confClone.defaultValue)
|
||||
} else if (dataObject[key]) {
|
||||
dataObject[key] = val
|
||||
} else if (!isAttr(key)) {
|
||||
dataObject.props[key] = val
|
||||
} else {
|
||||
dataObject.attrs[key] = val
|
||||
}
|
||||
})
|
||||
return h(this.conf.tag, dataObject, children)
|
||||
},
|
||||
props: ['conf']
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<script>
|
||||
export default {
|
||||
created() {
|
||||
const { params, query } = this.$route
|
||||
const { path } = params
|
||||
this.$router.replace({ path: '/' + path, query })
|
||||
},
|
||||
render: function(h) {
|
||||
return h() // avoid warning message
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,210 @@
|
|||
<template>
|
||||
<div class="register">
|
||||
<el-form ref="registerForm" :model="registerForm" :rules="registerRules" class="register-form">
|
||||
<h3 class="title">若依后台管理系统</h3>
|
||||
<el-form-item prop="username">
|
||||
<el-input v-model="registerForm.username" type="text" auto-complete="off" placeholder="账号">
|
||||
<svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="password">
|
||||
<el-input
|
||||
v-model="registerForm.password"
|
||||
type="password"
|
||||
auto-complete="off"
|
||||
placeholder="密码"
|
||||
@keyup.enter.native="handleRegister"
|
||||
>
|
||||
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="confirmPassword">
|
||||
<el-input
|
||||
v-model="registerForm.confirmPassword"
|
||||
type="password"
|
||||
auto-complete="off"
|
||||
placeholder="确认密码"
|
||||
@keyup.enter.native="handleRegister"
|
||||
>
|
||||
<svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item prop="code" v-if="captchaEnabled">
|
||||
<el-input
|
||||
v-model="registerForm.code"
|
||||
auto-complete="off"
|
||||
placeholder="验证码"
|
||||
style="width: 63%"
|
||||
@keyup.enter.native="handleRegister"
|
||||
>
|
||||
<svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
|
||||
</el-input>
|
||||
<div class="register-code">
|
||||
<img :src="codeUrl" @click="getCode" class="register-code-img"/>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item style="width:100%;">
|
||||
<el-button
|
||||
:loading="loading"
|
||||
size="medium"
|
||||
type="primary"
|
||||
style="width:100%;"
|
||||
@click.native.prevent="handleRegister"
|
||||
>
|
||||
<span v-if="!loading">注 册</span>
|
||||
<span v-else>注 册 中...</span>
|
||||
</el-button>
|
||||
<div style="float: right;">
|
||||
<router-link class="link-type" :to="'/login'">使用已有账户登录</router-link>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<!-- 底部 -->
|
||||
<div class="el-register-footer">
|
||||
<span>Copyright © 2018-2024 ruoyi.vip All Rights Reserved.</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getCodeImg, register } from "@/api/login";
|
||||
|
||||
export default {
|
||||
name: "Register",
|
||||
data() {
|
||||
const equalToPassword = (rule, value, callback) => {
|
||||
if (this.registerForm.password !== value) {
|
||||
callback(new Error("两次输入的密码不一致"));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
return {
|
||||
codeUrl: "",
|
||||
registerForm: {
|
||||
username: "",
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
code: "",
|
||||
uuid: ""
|
||||
},
|
||||
registerRules: {
|
||||
username: [
|
||||
{ required: true, trigger: "blur", message: "请输入您的账号" },
|
||||
{ min: 2, max: 20, message: '用户账号长度必须介于 2 和 20 之间', trigger: 'blur' }
|
||||
],
|
||||
password: [
|
||||
{ required: true, trigger: "blur", message: "请输入您的密码" },
|
||||
{ min: 5, max: 20, message: "用户密码长度必须介于 5 和 20 之间", trigger: "blur" },
|
||||
{ pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }
|
||||
],
|
||||
confirmPassword: [
|
||||
{ required: true, trigger: "blur", message: "请再次输入您的密码" },
|
||||
{ required: true, validator: equalToPassword, trigger: "blur" }
|
||||
],
|
||||
code: [{ required: true, trigger: "change", message: "请输入验证码" }]
|
||||
},
|
||||
loading: false,
|
||||
captchaEnabled: true
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.getCode();
|
||||
},
|
||||
methods: {
|
||||
getCode() {
|
||||
getCodeImg().then(res => {
|
||||
this.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabled;
|
||||
if (this.captchaEnabled) {
|
||||
this.codeUrl = "data:image/gif;base64," + res.img;
|
||||
this.registerForm.uuid = res.uuid;
|
||||
}
|
||||
});
|
||||
},
|
||||
handleRegister() {
|
||||
this.$refs.registerForm.validate(valid => {
|
||||
if (valid) {
|
||||
this.loading = true;
|
||||
register(this.registerForm).then(res => {
|
||||
const username = this.registerForm.username;
|
||||
this.$alert("<font color='red'>恭喜你,您的账号 " + username + " 注册成功!</font>", '系统提示', {
|
||||
dangerouslyUseHTMLString: true,
|
||||
type: 'success'
|
||||
}).then(() => {
|
||||
this.$router.push("/login");
|
||||
}).catch(() => {});
|
||||
}).catch(() => {
|
||||
this.loading = false;
|
||||
if (this.captchaEnabled) {
|
||||
this.getCode();
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss">
|
||||
.register {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
background-image: url("../assets/images/login-background.jpg");
|
||||
background-size: cover;
|
||||
}
|
||||
.title {
|
||||
margin: 0px auto 30px auto;
|
||||
text-align: center;
|
||||
color: #707070;
|
||||
}
|
||||
|
||||
.register-form {
|
||||
border-radius: 6px;
|
||||
background: #ffffff;
|
||||
width: 400px;
|
||||
padding: 25px 25px 5px 25px;
|
||||
.el-input {
|
||||
height: 38px;
|
||||
input {
|
||||
height: 38px;
|
||||
}
|
||||
}
|
||||
.input-icon {
|
||||
height: 39px;
|
||||
width: 14px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
.register-tip {
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
color: #bfbfbf;
|
||||
}
|
||||
.register-code {
|
||||
width: 33%;
|
||||
height: 38px;
|
||||
float: right;
|
||||
img {
|
||||
cursor: pointer;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
.el-register-footer {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
font-family: Arial;
|
||||
font-size: 12px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
.register-code-img {
|
||||
height: 38px;
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue