刘力
3 years ago
29 changed files with 856 additions and 408 deletions
-
59common/src/main/java/com/canvas/web/annotation/rest/AnonymousDeleteMapping.java
-
26common/src/main/java/com/canvas/web/config/AuditorConfig.java
-
41common/src/main/java/com/canvas/web/config/CommonConfig.java
-
21common/src/main/java/com/canvas/web/config/ElPermissionConfig.java
-
197common/src/main/java/com/canvas/web/config/RedisConfig.java
-
38common/src/main/java/com/canvas/web/config/UploadFileConfig.java
-
30common/src/main/java/com/canvas/web/enums/DataScopeEnum.java
-
294common/src/main/java/com/canvas/web/utils/CommonUtils.java
-
77common/src/main/java/com/canvas/web/utils/SecurityUtils.java
-
21system/src/main/java/com/canvas/web/config/thread/ThreadPoolExecutorUtil.java
-
15system/src/main/java/com/canvas/web/modules/controller/OnlineController.java
-
2system/src/main/java/com/canvas/web/modules/security/config/SpringSecurityConfig.java
-
52system/src/main/java/com/canvas/web/modules/security/controller/AuthorizationController.java
-
8system/src/main/java/com/canvas/web/modules/system/domain/Menu.java
-
38system/src/main/java/com/canvas/web/modules/system/domain/Org.java
-
11system/src/main/java/com/canvas/web/modules/system/domain/Role.java
-
6system/src/main/java/com/canvas/web/modules/system/domain/User.java
-
6system/src/main/java/com/canvas/web/modules/system/repository/MenuRepository.java
-
6system/src/main/java/com/canvas/web/modules/system/repository/OrgRepository.java
-
6system/src/main/java/com/canvas/web/modules/system/repository/RoleRepository.java
-
6system/src/main/java/com/canvas/web/modules/system/repository/UserRepository.java
-
20system/src/main/java/com/canvas/web/modules/system/service/impl/DataServiceImpl.java
-
20system/src/main/java/com/canvas/web/modules/system/service/impl/RoleServiceImpl.java
-
66system/src/main/java/com/canvas/web/modules/system/service/impl/UserServiceImpl.java
-
122system/src/main/resources/config/application-prod.yml
-
27system/src/main/resources/generator.properties
-
BINsystem/src/main/resources/ip2region/ip2region.db
-
4system/src/main/resources/log4jdbc.log4j2.properties
-
45system/src/main/resources/logback.xml
@ -0,0 +1,59 @@ |
|||
package com.canvas.web.annotation.rest; |
|||
|
|||
|
|||
import com.canvas.web.annotation.AnonymousAccess; |
|||
import org.springframework.core.annotation.AliasFor; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RequestMethod; |
|||
|
|||
import java.lang.annotation.*; |
|||
|
|||
@AnonymousAccess |
|||
@Target(ElementType.METHOD) |
|||
@Retention(RetentionPolicy.RUNTIME) |
|||
@Documented |
|||
@RequestMapping(method = RequestMethod.DELETE) |
|||
public @interface AnonymousDeleteMapping { |
|||
|
|||
/** |
|||
* Alias for {@link RequestMapping#name}. |
|||
*/ |
|||
@AliasFor(annotation = RequestMapping.class) |
|||
String name() default ""; |
|||
|
|||
/** |
|||
* Alias for {@link RequestMapping#value}. |
|||
*/ |
|||
@AliasFor(annotation = RequestMapping.class) |
|||
String[] value() default {}; |
|||
|
|||
/** |
|||
* Alias for {@link RequestMapping#path}. |
|||
*/ |
|||
@AliasFor(annotation = RequestMapping.class) |
|||
String[] path() default {}; |
|||
|
|||
/** |
|||
* Alias for {@link RequestMapping#params}. |
|||
*/ |
|||
@AliasFor(annotation = RequestMapping.class) |
|||
String[] params() default {}; |
|||
|
|||
/** |
|||
* Alias for {@link RequestMapping#headers}. |
|||
*/ |
|||
@AliasFor(annotation = RequestMapping.class) |
|||
String[] headers() default {}; |
|||
|
|||
/** |
|||
* Alias for {@link RequestMapping#consumes}. |
|||
*/ |
|||
@AliasFor(annotation = RequestMapping.class) |
|||
String[] consumes() default {}; |
|||
|
|||
/** |
|||
* Alias for {@link RequestMapping#produces}. |
|||
*/ |
|||
@AliasFor(annotation = RequestMapping.class) |
|||
String[] produces() default {}; |
|||
} |
@ -0,0 +1,26 @@ |
|||
package com.canvas.web.config; |
|||
|
|||
import com.canvas.web.utils.SecurityUtils; |
|||
import org.springframework.data.domain.AuditorAware; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import java.util.Optional; |
|||
|
|||
@Component("auditorAware") |
|||
public class AuditorConfig implements AuditorAware<String> { |
|||
/** |
|||
* 返回操作员标志信息 |
|||
* |
|||
* @return / |
|||
*/ |
|||
@Override |
|||
public Optional<String> getCurrentAuditor() { |
|||
try { |
|||
// 这里应根据实际业务情况获取具体信息 |
|||
return Optional.of(SecurityUtils.getCurrentUsername()); |
|||
}catch (Exception ignored){} |
|||
// 用户定时任务,或者无Token调用的情况 |
|||
return Optional.of("System"); |
|||
} |
|||
|
|||
} |
@ -1,41 +0,0 @@ |
|||
package com.canvas.web.config; |
|||
|
|||
|
|||
import lombok.Data; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.context.annotation.Configuration; |
|||
|
|||
@Configuration |
|||
@Data |
|||
public class CommonConfig { |
|||
|
|||
/** |
|||
* 图片域名 |
|||
*/ |
|||
public static String imageURL; |
|||
|
|||
/** |
|||
* 是否演示环境:true是,false否 |
|||
*/ |
|||
public static boolean appDebug; |
|||
|
|||
/** |
|||
* 图片域名赋值 |
|||
* |
|||
* @param url 域名地址 |
|||
*/ |
|||
@Value("${javaweb.image-url}") |
|||
public void setImageURL(String url) { |
|||
imageURL = url; |
|||
} |
|||
|
|||
/** |
|||
* 是否演示模式 |
|||
* |
|||
* @param debug |
|||
*/ |
|||
@Value("${javaweb.app-debug}") |
|||
public void setAppDebug(boolean debug) { |
|||
appDebug = debug; |
|||
} |
|||
} |
@ -0,0 +1,21 @@ |
|||
package com.canvas.web.config; |
|||
|
|||
|
|||
import com.canvas.web.utils.SecurityUtils; |
|||
import org.springframework.security.core.GrantedAuthority; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import java.util.Arrays; |
|||
import java.util.List; |
|||
import java.util.stream.Collectors; |
|||
|
|||
@Service(value = "el") |
|||
public class ElPermissionConfig { |
|||
|
|||
public Boolean check(String... permissions) { |
|||
// 获取当前用户的所有权限 |
|||
List<String> elPermissions = SecurityUtils.getCurrentUser().getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()); |
|||
// 判断当前用户的所有权限是否包含接口上定义的权限 |
|||
return elPermissions.contains("admin") || Arrays.stream(permissions).anyMatch(elPermissions::contains); |
|||
} |
|||
} |
@ -0,0 +1,197 @@ |
|||
package com.canvas.web.config; |
|||
|
|||
import cn.hutool.core.lang.Assert; |
|||
import com.alibaba.fastjson.JSON; |
|||
import com.alibaba.fastjson.parser.ParserConfig; |
|||
import com.alibaba.fastjson.serializer.SerializerFeature; |
|||
import com.canvas.web.utils.StringUtils; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.commons.codec.digest.DigestUtils; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; |
|||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; |
|||
import org.springframework.boot.autoconfigure.data.redis.RedisProperties; |
|||
import org.springframework.boot.context.properties.EnableConfigurationProperties; |
|||
import org.springframework.cache.Cache; |
|||
import org.springframework.cache.annotation.CachingConfigurerSupport; |
|||
import org.springframework.cache.annotation.EnableCaching; |
|||
import org.springframework.cache.interceptor.CacheErrorHandler; |
|||
import org.springframework.cache.interceptor.KeyGenerator; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.context.annotation.Configuration; |
|||
import org.springframework.data.redis.cache.RedisCacheConfiguration; |
|||
import org.springframework.data.redis.connection.RedisConnectionFactory; |
|||
import org.springframework.data.redis.core.RedisOperations; |
|||
import org.springframework.data.redis.core.RedisTemplate; |
|||
import org.springframework.data.redis.serializer.RedisSerializationContext; |
|||
import org.springframework.data.redis.serializer.RedisSerializer; |
|||
|
|||
import java.nio.charset.Charset; |
|||
import java.nio.charset.StandardCharsets; |
|||
import java.time.Duration; |
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
|
|||
@Slf4j |
|||
@Configuration |
|||
@EnableCaching |
|||
@ConditionalOnClass(RedisOperations.class) |
|||
@EnableConfigurationProperties(RedisProperties.class) |
|||
public class RedisConfig extends CachingConfigurerSupport { |
|||
|
|||
/** |
|||
* 设置 redis 数据默认过期时间,默认2小时 |
|||
* 设置@cacheable 序列化方式 |
|||
*/ |
|||
@Bean |
|||
public RedisCacheConfiguration redisCacheConfiguration(){ |
|||
FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class); |
|||
RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig(); |
|||
configuration = configuration.serializeValuesWith(RedisSerializationContext. |
|||
SerializationPair.fromSerializer(fastJsonRedisSerializer)).entryTtl(Duration.ofHours(6)); |
|||
return configuration; |
|||
} |
|||
|
|||
@SuppressWarnings("all") |
|||
@Bean(name = "redisTemplate") |
|||
@ConditionalOnMissingBean(name = "redisTemplate") |
|||
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { |
|||
RedisTemplate<Object, Object> template = new RedisTemplate<>(); |
|||
//序列化 |
|||
FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class); |
|||
// value值的序列化采用fastJsonRedisSerializer |
|||
template.setValueSerializer(fastJsonRedisSerializer); |
|||
template.setHashValueSerializer(fastJsonRedisSerializer); |
|||
// 全局开启AutoType,这里方便开发,使用全局的方式 |
|||
ParserConfig.getGlobalInstance().setAutoTypeSupport(true); |
|||
// 建议使用这种方式,小范围指定白名单 |
|||
// ParserConfig.getGlobalInstance().addAccept("me.zhengjie.domain"); |
|||
// key的序列化采用StringRedisSerializer |
|||
template.setKeySerializer(new StringRedisSerializer()); |
|||
template.setHashKeySerializer(new StringRedisSerializer()); |
|||
template.setConnectionFactory(redisConnectionFactory); |
|||
return template; |
|||
} |
|||
|
|||
/** |
|||
* 自定义缓存key生成策略,默认将使用该策略 |
|||
*/ |
|||
@Bean |
|||
@Override |
|||
public KeyGenerator keyGenerator() { |
|||
return (target, method, params) -> { |
|||
Map<String,Object> container = new HashMap<>(3); |
|||
Class<?> targetClassClass = target.getClass(); |
|||
// 类地址 |
|||
container.put("class",targetClassClass.toGenericString()); |
|||
// 方法名称 |
|||
container.put("methodName",method.getName()); |
|||
// 包名称 |
|||
container.put("package",targetClassClass.getPackage()); |
|||
// 参数列表 |
|||
for (int i = 0; i < params.length; i++) { |
|||
container.put(String.valueOf(i),params[i]); |
|||
} |
|||
// 转为JSON字符串 |
|||
String jsonString = JSON.toJSONString(container); |
|||
// 做SHA256 Hash计算,得到一个SHA256摘要作为Key |
|||
return DigestUtils.sha256Hex(jsonString); |
|||
}; |
|||
} |
|||
|
|||
@Bean |
|||
@Override |
|||
public CacheErrorHandler errorHandler() { |
|||
// 异常处理,当Redis发生异常时,打印日志,但是程序正常走 |
|||
log.info("初始化 -> [{}]", "Redis CacheErrorHandler"); |
|||
return new CacheErrorHandler() { |
|||
@Override |
|||
public void handleCacheGetError(RuntimeException e, Cache cache, Object key) { |
|||
log.error("Redis occur handleCacheGetError:key -> [{}]", key, e); |
|||
} |
|||
|
|||
@Override |
|||
public void handleCachePutError(RuntimeException e, Cache cache, Object key, Object value) { |
|||
log.error("Redis occur handleCachePutError:key -> [{}];value -> [{}]", key, value, e); |
|||
} |
|||
|
|||
@Override |
|||
public void handleCacheEvictError(RuntimeException e, Cache cache, Object key) { |
|||
log.error("Redis occur handleCacheEvictError:key -> [{}]", key, e); |
|||
} |
|||
|
|||
@Override |
|||
public void handleCacheClearError(RuntimeException e, Cache cache) { |
|||
log.error("Redis occur handleCacheClearError:", e); |
|||
} |
|||
}; |
|||
} |
|||
|
|||
} |
|||
|
|||
/** |
|||
* Value 序列化 |
|||
* |
|||
* @author / |
|||
* @param <T> |
|||
*/ |
|||
class FastJsonRedisSerializer<T> implements RedisSerializer<T> { |
|||
|
|||
private final Class<T> clazz; |
|||
|
|||
FastJsonRedisSerializer(Class<T> clazz) { |
|||
super(); |
|||
this.clazz = clazz; |
|||
} |
|||
|
|||
@Override |
|||
public byte[] serialize(T t) { |
|||
if (t == null) { |
|||
return new byte[0]; |
|||
} |
|||
return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(StandardCharsets.UTF_8); |
|||
} |
|||
|
|||
@Override |
|||
public T deserialize(byte[] bytes) { |
|||
if (bytes == null || bytes.length <= 0) { |
|||
return null; |
|||
} |
|||
String str = new String(bytes, StandardCharsets.UTF_8); |
|||
return JSON.parseObject(str, clazz); |
|||
} |
|||
|
|||
} |
|||
|
|||
/** |
|||
* 重写序列化器 |
|||
* |
|||
* @author / |
|||
*/ |
|||
class StringRedisSerializer implements RedisSerializer<Object> { |
|||
|
|||
private final Charset charset; |
|||
|
|||
StringRedisSerializer() { |
|||
this(StandardCharsets.UTF_8); |
|||
} |
|||
|
|||
private StringRedisSerializer(Charset charset) { |
|||
Assert.notNull(charset, "Charset must not be null!"); |
|||
this.charset = charset; |
|||
} |
|||
|
|||
@Override |
|||
public String deserialize(byte[] bytes) { |
|||
return (bytes == null ? null : new String(bytes, charset)); |
|||
} |
|||
|
|||
@Override |
|||
public byte[] serialize(Object object) { |
|||
String string = JSON.toJSONString(object); |
|||
if (StringUtils.isBlank(string)) { |
|||
return null; |
|||
} |
|||
string = string.replace("\"", ""); |
|||
return string.getBytes(charset); |
|||
} |
|||
} |
@ -1,38 +0,0 @@ |
|||
package com.canvas.web.config; |
|||
|
|||
|
|||
import lombok.Data; |
|||
import org.springframework.beans.factory.annotation.Value; |
|||
import org.springframework.context.annotation.Configuration; |
|||
|
|||
@Configuration |
|||
@Data |
|||
public class UploadFileConfig { |
|||
/** |
|||
* 上传目录 |
|||
*/ |
|||
public static String uploadFolder; |
|||
/** |
|||
* 访问路径 |
|||
*/ |
|||
public static String staticAccessPath; |
|||
/** |
|||
* 上传服务器的映射文件夹 |
|||
*/ |
|||
public static String accessPath; |
|||
|
|||
@Value("${file.uploadFolder}") |
|||
public void setUploadFolder(String path) { |
|||
uploadFolder = path; |
|||
} |
|||
|
|||
@Value("${file.staticAccessPath}") |
|||
public void setStaticAccessPath(String path) { |
|||
staticAccessPath = path; |
|||
} |
|||
|
|||
@Value("${file.accessPath}") |
|||
public void setAccessPath(String path) { |
|||
accessPath = path; |
|||
} |
|||
} |
@ -0,0 +1,30 @@ |
|||
package com.canvas.web.enums; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Getter; |
|||
|
|||
@Getter |
|||
@AllArgsConstructor |
|||
public enum DataScopeEnum { |
|||
|
|||
/* 全部的数据权限 */ |
|||
ALL("全部", "全部的数据权限"), |
|||
|
|||
/* 自己部门的数据权限 */ |
|||
THIS_LEVEL("本级", "自己部门的数据权限"), |
|||
|
|||
/* 自定义的数据权限 */ |
|||
CUSTOMIZE("自定义", "自定义的数据权限"); |
|||
|
|||
private final String value; |
|||
private final String description; |
|||
|
|||
public static DataScopeEnum find(String val) { |
|||
for (DataScopeEnum dataScopeEnum : DataScopeEnum.values()) { |
|||
if (val.equals(dataScopeEnum.getValue())) { |
|||
return dataScopeEnum; |
|||
} |
|||
} |
|||
return null; |
|||
} |
|||
} |
@ -1,294 +0,0 @@ |
|||
package com.canvas.web.utils; |
|||
|
|||
import com.alibaba.fastjson.JSONObject; |
|||
import com.canvas.web.config.CommonConfig; |
|||
import org.springframework.util.StringUtils; |
|||
|
|||
import java.lang.reflect.Field; |
|||
import java.security.MessageDigest; |
|||
import java.text.NumberFormat; |
|||
import java.text.ParseException; |
|||
import java.text.SimpleDateFormat; |
|||
import java.util.Date; |
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
import java.util.regex.Matcher; |
|||
import java.util.regex.Pattern; |
|||
|
|||
public class CommonUtils { |
|||
/** |
|||
* 分转元 |
|||
* |
|||
* @param amount |
|||
* @return |
|||
*/ |
|||
public static String fenToYuan(String amount) { |
|||
NumberFormat format = NumberFormat.getInstance(); |
|||
try { |
|||
Number number = format.parse(amount); |
|||
double temp = number.doubleValue() / 100.0; |
|||
format.setGroupingUsed(false); |
|||
// 设置返回的小数部分所允许的最大位数 |
|||
format.setMaximumFractionDigits(2); |
|||
amount = format.format(temp); |
|||
} catch (ParseException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
return amount; |
|||
} |
|||
|
|||
/** |
|||
* 元转分 |
|||
* |
|||
* @param amount |
|||
* @return |
|||
*/ |
|||
public static String yuanToFen(String amount) { |
|||
NumberFormat format = NumberFormat.getInstance(); |
|||
try { |
|||
Number number = format.parse(amount); |
|||
double temp = number.doubleValue() * 100.0; |
|||
format.setGroupingUsed(false); |
|||
// 设置返回数的小数部分所允许的最大位数 |
|||
format.setMaximumFractionDigits(0); |
|||
amount = format.format(temp); |
|||
} catch (ParseException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
return amount; |
|||
} |
|||
|
|||
/** |
|||
* 获取当前时间时间戳 |
|||
* |
|||
* @return |
|||
*/ |
|||
public static Integer timeStamp() { |
|||
long currentTime = System.currentTimeMillis(); |
|||
String time = String.valueOf(currentTime / 1000); |
|||
return Integer.valueOf(time); |
|||
} |
|||
|
|||
/** |
|||
* 时间转为日期格式 |
|||
* |
|||
* @param time |
|||
* @param format |
|||
* @return |
|||
*/ |
|||
public static String formatTime(Integer time, String format) { |
|||
if (StringUtils.isEmpty(time)) { |
|||
return ""; |
|||
} |
|||
SimpleDateFormat dateFormat = new SimpleDateFormat(format); |
|||
long timeLong = time.longValue() * 1000; |
|||
Date date = new Date(timeLong); |
|||
return dateFormat.format(date); |
|||
} |
|||
|
|||
/** |
|||
* 获取到图片域名的地址 |
|||
* |
|||
* @param imageUrl |
|||
* @return |
|||
*/ |
|||
public static String getImageURL(String imageUrl) { |
|||
return CommonConfig.imageURL + imageUrl; |
|||
} |
|||
|
|||
/** |
|||
* 验证邮箱是否正确 |
|||
* |
|||
* @param email |
|||
* @return |
|||
*/ |
|||
public static boolean isEmail(String email) { |
|||
boolean flag = false; |
|||
try { |
|||
String check = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$"; |
|||
Pattern regex = Pattern.compile(check); |
|||
Matcher matcher = regex.matcher(email); |
|||
flag = matcher.matches(); |
|||
} catch (Exception e) { |
|||
flag = false; |
|||
} |
|||
return flag; |
|||
} |
|||
|
|||
/** |
|||
* 验证手机号是否正确 |
|||
* |
|||
* @param mobile |
|||
* @return |
|||
*/ |
|||
public static boolean isMobile(String mobile) { |
|||
boolean flag = false; |
|||
try { |
|||
Pattern p = Pattern.compile("^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$"); |
|||
Matcher m = p.matcher(mobile); |
|||
flag = m.matches(); |
|||
} catch (Exception e) { |
|||
flag = false; |
|||
} |
|||
return flag; |
|||
} |
|||
|
|||
/** |
|||
* 生成指定位数的随机字符串 |
|||
* |
|||
* @param isNum 是否是纯数字 |
|||
* @param length 长度 |
|||
* @return |
|||
*/ |
|||
public static String getRandomStr(boolean isNum, int length) { |
|||
String resultStr = ""; |
|||
String str = isNum ? "1234567890" : "1234567890abcdefghijkmnpqrstuvwxyz"; |
|||
int len = str.length(); |
|||
boolean isStop = true; |
|||
do { |
|||
resultStr = ""; |
|||
int count = 0; |
|||
for (int i = 0; i < length; i++) { |
|||
double dblR = Math.random() * len; |
|||
int intR = (int) Math.floor(dblR); |
|||
char c = str.charAt(intR); |
|||
if (('0' <= c) && (c <= '9')) { |
|||
count++; |
|||
} |
|||
resultStr += str.charAt(intR); |
|||
} |
|||
if (count >= 2) { |
|||
isStop = false; |
|||
} |
|||
} while (isStop); |
|||
return resultStr; |
|||
} |
|||
|
|||
/** |
|||
* 判断是否在数组中 |
|||
* |
|||
* @param s |
|||
* @param array |
|||
* @return |
|||
*/ |
|||
public static boolean inArray(final String s, final String[] array) { |
|||
for (String item : array) { |
|||
if (item != null && item.equals(s)) { |
|||
return true; |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* 从html中提取纯文本 |
|||
* |
|||
* @param strHtml |
|||
* @return |
|||
*/ |
|||
public static String stripHtml(String strHtml) { |
|||
String content = strHtml.replaceAll("</?[^>]+>", ""); //剔出<html>的标签 |
|||
content = content.replaceAll("\\s*|\t|\r|\n", "");//去除字符串中的空格,回车,换行符,制表符 |
|||
return content; |
|||
} |
|||
|
|||
/** |
|||
* 去除字符串中的空格、回车、换行符、制表符等 |
|||
* |
|||
* @param str 原始字符串 |
|||
* @return |
|||
*/ |
|||
public static String replaceSpecialStr(String str) { |
|||
String repl = ""; |
|||
if (str != null) { |
|||
Pattern p = Pattern.compile("\\s*|\t|\r|\n"); |
|||
Matcher m = p.matcher(str); |
|||
repl = m.replaceAll(""); |
|||
} |
|||
return repl; |
|||
} |
|||
|
|||
/** |
|||
* 判断某个元素是否在数组中 |
|||
* |
|||
* @param key 元素 |
|||
* @param map 数组 |
|||
* @return |
|||
*/ |
|||
public static boolean inArray(String key, Map<String, String> map) { |
|||
boolean flag = false; |
|||
for (String k : map.keySet()) { |
|||
if (k.equals(key)) { |
|||
flag = true; |
|||
} |
|||
} |
|||
return flag; |
|||
} |
|||
|
|||
/** |
|||
* 对象转Map |
|||
* |
|||
* @param obj 对象 |
|||
* @return |
|||
* @throws IllegalAccessException |
|||
*/ |
|||
public static Map<String, Object> objectToMap(Object obj) throws IllegalAccessException { |
|||
Map<String, Object> map = new HashMap<>(); |
|||
Class<?> clazz = obj.getClass(); |
|||
for (Field field : clazz.getDeclaredFields()) { |
|||
field.setAccessible(true); |
|||
String fieldName = field.getName(); |
|||
Object value = field.get(obj); |
|||
map.put(fieldName, value); |
|||
} |
|||
return map; |
|||
} |
|||
|
|||
/** |
|||
* 判断是否是JSON格式 |
|||
* |
|||
* @param str JSON字符串 |
|||
* @return |
|||
*/ |
|||
private boolean isJson(String str) { |
|||
try { |
|||
JSONObject jsonStr = JSONObject.parseObject(str); |
|||
return true; |
|||
} catch (Exception e) { |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* MD5方法 |
|||
* |
|||
* @param source |
|||
* @return |
|||
*/ |
|||
public static String md5(byte[] source) { |
|||
try { |
|||
MessageDigest md = MessageDigest.getInstance("MD5"); |
|||
md.update(source); |
|||
StringBuffer buf = new StringBuffer(); |
|||
for (byte b : md.digest()) { |
|||
buf.append(String.format("%02x", b & 0xff)); |
|||
} |
|||
return buf.toString(); |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 密码加密 |
|||
* |
|||
* @param password 密码 |
|||
* @return |
|||
*/ |
|||
public static String password(String password) { |
|||
String md51 = md5(password.getBytes()); |
|||
String pwd = md5((md51 + "IgtUdEQJyVevaCxQnY").getBytes()); |
|||
return pwd; |
|||
} |
|||
} |
@ -0,0 +1,77 @@ |
|||
package com.canvas.web.utils; |
|||
|
|||
import cn.hutool.json.JSONArray; |
|||
import cn.hutool.json.JSONObject; |
|||
import cn.hutool.json.JSONUtil; |
|||
import com.canvas.web.enums.DataScopeEnum; |
|||
import com.canvas.web.exception.BaseException; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.security.core.Authentication; |
|||
import org.springframework.security.core.context.SecurityContextHolder; |
|||
import org.springframework.security.core.userdetails.UserDetails; |
|||
import org.springframework.security.core.userdetails.UserDetailsService; |
|||
|
|||
import java.util.List; |
|||
|
|||
@Slf4j |
|||
public class SecurityUtils { |
|||
|
|||
/** |
|||
* 获取当前登录的用户 |
|||
* */ |
|||
public static UserDetails getCurrentUser(){ |
|||
UserDetailsService userDetailsService=SpringContextHolder.getBean(UserDetailsService.class); |
|||
return userDetailsService.loadUserByUsername(getCurrentUsername()); |
|||
} |
|||
|
|||
|
|||
|
|||
/** |
|||
* 获取系统用户名称 |
|||
* |
|||
* @return 系统用户名称 |
|||
*/ |
|||
public static String getCurrentUsername() { |
|||
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); |
|||
if (authentication == null) { |
|||
throw new BaseException( "当前登录状态过期");//HttpStatus.UNAUTHORIZED, |
|||
} |
|||
if (authentication.getPrincipal() instanceof UserDetails) { |
|||
UserDetails userDetails = (UserDetails) authentication.getPrincipal(); |
|||
return userDetails.getUsername(); |
|||
} |
|||
throw new BaseException( "找不到当前登录的信息");//HttpStatus.UNAUTHORIZED |
|||
} |
|||
|
|||
/** |
|||
* 获取系统用户ID |
|||
* @return 系统用户ID |
|||
*/ |
|||
public static Long getCurrentUserId() { |
|||
UserDetails userDetails = getCurrentUser(); |
|||
return new JSONObject(new JSONObject(userDetails).get("user")).get("id", Long.class); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 获取当前用户的数据权限 |
|||
* @return / |
|||
*/ |
|||
public static List<Long> getCurrentUserDataScope(){ |
|||
UserDetails userDetails = getCurrentUser(); |
|||
JSONArray array = JSONUtil.parseArray(new JSONObject(userDetails).get("dataScopes")); |
|||
return JSONUtil.toList(array,Long.class); |
|||
} |
|||
|
|||
/** |
|||
* 获取数据权限级别 |
|||
* @return 级别 |
|||
*/ |
|||
public static String getDataScopeType() { |
|||
List<Long> dataScopes = getCurrentUserDataScope(); |
|||
if(dataScopes.size() != 0){ |
|||
return ""; |
|||
} |
|||
return DataScopeEnum.ALL.getValue(); |
|||
} |
|||
} |
@ -0,0 +1,21 @@ |
|||
package com.canvas.web.config.thread; |
|||
|
|||
import com.canvas.web.utils.SpringContextHolder; |
|||
|
|||
import java.util.concurrent.ArrayBlockingQueue; |
|||
import java.util.concurrent.ThreadPoolExecutor; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
public class ThreadPoolExecutorUtil { |
|||
public static ThreadPoolExecutor getPoll(){ |
|||
AsyncTaskProperties properties = SpringContextHolder.getBean(AsyncTaskProperties.class); |
|||
return new ThreadPoolExecutor( |
|||
properties.getCorePoolSize(), |
|||
properties.getMaxPoolSize(), |
|||
properties.getKeepAliveSeconds(), |
|||
TimeUnit.SECONDS, |
|||
new ArrayBlockingQueue<>(properties.getQueueCapacity()), |
|||
new TheadFactoryName() |
|||
); |
|||
} |
|||
} |
@ -1,15 +0,0 @@ |
|||
package com.canvas.web.modules.controller; |
|||
|
|||
|
|||
import com.canvas.web.modules.security.service.OnlineUserService; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
|
|||
@RestController |
|||
@RequiredArgsConstructor |
|||
@RequestMapping("/auth/online") |
|||
public class OnlineController { |
|||
|
|||
private final OnlineUserService onlineUserService; |
|||
} |
@ -1,8 +1,46 @@ |
|||
package com.canvas.web.modules.system.domain; |
|||
|
|||
import com.canvas.web.base.BaseEntity; |
|||
import io.swagger.annotations.ApiModelProperty; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
import javax.persistence.*; |
|||
import javax.validation.constraints.NotNull; |
|||
import java.io.Serializable; |
|||
import java.util.Objects; |
|||
|
|||
@Entity |
|||
@Getter |
|||
@Setter |
|||
@Table(name="organization") |
|||
public class Org extends BaseEntity implements Serializable { |
|||
@Id |
|||
@Column(name = "id") |
|||
@NotNull(groups = Update.class) |
|||
@GeneratedValue(strategy = GenerationType.IDENTITY) |
|||
@ApiModelProperty(value = "ID", hidden = true) |
|||
private Long id; |
|||
|
|||
private String name; |
|||
|
|||
private String version; |
|||
|
|||
@Override |
|||
public boolean equals(Object o) { |
|||
if (this == o) { |
|||
return true; |
|||
} |
|||
if (o == null || getClass() != o.getClass()) { |
|||
return false; |
|||
} |
|||
Org org = (Org) o; |
|||
return Objects.equals(id, org.id) && |
|||
Objects.equals(name, org.name); |
|||
} |
|||
|
|||
@Override |
|||
public int hashCode() { |
|||
return Objects.hash(id, name); |
|||
} |
|||
} |
@ -1,4 +1,8 @@ |
|||
package com.canvas.web.modules.system.repository; |
|||
|
|||
public interface MenuRepository { |
|||
import com.canvas.web.modules.system.domain.Menu; |
|||
import org.springframework.data.jpa.repository.JpaRepository; |
|||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; |
|||
|
|||
public interface MenuRepository extends JpaRepository<Menu, Long>, JpaSpecificationExecutor<Menu> { |
|||
} |
@ -1,4 +1,8 @@ |
|||
package com.canvas.web.modules.system.repository; |
|||
|
|||
public interface OrgRepository { |
|||
import com.canvas.web.modules.system.domain.Org; |
|||
import org.springframework.data.jpa.repository.JpaRepository; |
|||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; |
|||
|
|||
public interface OrgRepository extends JpaRepository<Org, Long>, JpaSpecificationExecutor<Org> { |
|||
} |
@ -1,4 +1,8 @@ |
|||
package com.canvas.web.modules.system.repository; |
|||
|
|||
public interface RoleRepository { |
|||
import com.canvas.web.modules.system.domain.Role; |
|||
import org.springframework.data.jpa.repository.JpaRepository; |
|||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; |
|||
|
|||
public interface RoleRepository extends JpaRepository<Role, Long>, JpaSpecificationExecutor<Role> { |
|||
} |
@ -1,4 +1,8 @@ |
|||
package com.canvas.web.modules.system.repository; |
|||
|
|||
public interface UserRepository { |
|||
import com.canvas.web.modules.system.domain.User; |
|||
import org.springframework.data.jpa.repository.JpaRepository; |
|||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; |
|||
|
|||
public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> { |
|||
} |
@ -0,0 +1,20 @@ |
|||
package com.canvas.web.modules.system.service.impl; |
|||
|
|||
import com.canvas.web.modules.system.service.DataService; |
|||
import com.canvas.web.modules.system.service.dto.UserDto; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.cache.annotation.CacheConfig; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import java.util.List; |
|||
|
|||
|
|||
@Service |
|||
@RequiredArgsConstructor |
|||
@CacheConfig(cacheNames = "data") |
|||
public class DataServiceImpl implements DataService { |
|||
@Override |
|||
public List<Long> getDeptIds(UserDto user) { |
|||
return null; |
|||
} |
|||
} |
@ -0,0 +1,20 @@ |
|||
package com.canvas.web.modules.system.service.impl; |
|||
|
|||
import com.canvas.web.modules.system.service.RoleService; |
|||
import com.canvas.web.modules.system.service.dto.UserDto; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.cache.annotation.CacheConfig; |
|||
import org.springframework.security.core.GrantedAuthority; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import java.util.List; |
|||
|
|||
@Service |
|||
@RequiredArgsConstructor |
|||
@CacheConfig(cacheNames = "role") |
|||
public class RoleServiceImpl implements RoleService { |
|||
@Override |
|||
public List<GrantedAuthority> mapToGrantedAuthorities(UserDto user) { |
|||
return null; |
|||
} |
|||
} |
@ -0,0 +1,66 @@ |
|||
package com.canvas.web.modules.system.service.impl; |
|||
|
|||
import com.canvas.web.modules.system.service.UserService; |
|||
import com.canvas.web.modules.system.service.dto.UserDto; |
|||
import com.canvas.web.modules.system.service.dto.UserQueryCriteria; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.cache.annotation.CacheConfig; |
|||
import org.springframework.data.domain.Pageable; |
|||
import org.springframework.stereotype.Service; |
|||
import org.springframework.web.multipart.MultipartFile; |
|||
|
|||
import javax.servlet.http.HttpServletResponse; |
|||
import java.io.IOException; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.Set; |
|||
|
|||
@Service |
|||
@RequiredArgsConstructor |
|||
@CacheConfig(cacheNames = "user") |
|||
public class UserServiceImpl implements UserService{ |
|||
@Override |
|||
public UserDto findById(long id) { |
|||
return null; |
|||
} |
|||
|
|||
@Override |
|||
public void delete(Set<Long> ids) { |
|||
|
|||
} |
|||
|
|||
@Override |
|||
public UserDto findByName(String userName) { |
|||
return null; |
|||
} |
|||
|
|||
@Override |
|||
public void updatePass(String username, String encryptPassword) { |
|||
|
|||
} |
|||
|
|||
@Override |
|||
public Map<String, String> updateAvatar(MultipartFile file) { |
|||
return null; |
|||
} |
|||
|
|||
@Override |
|||
public void updateEmail(String username, String email) { |
|||
|
|||
} |
|||
|
|||
@Override |
|||
public Object queryAll(UserQueryCriteria criteria, Pageable pageable) { |
|||
return null; |
|||
} |
|||
|
|||
@Override |
|||
public List<UserDto> queryAll(UserQueryCriteria criteria) { |
|||
return null; |
|||
} |
|||
|
|||
@Override |
|||
public void download(List<UserDto> queryAll, HttpServletResponse response) throws IOException { |
|||
|
|||
} |
|||
} |
@ -0,0 +1,122 @@ |
|||
#配置数据源 |
|||
spring: |
|||
datasource: |
|||
druid: |
|||
db-type: com.alibaba.druid.pool.DruidDataSource |
|||
driverClassName: net.sf.log4jdbc.sql.jdbcapi.DriverSpy |
|||
url: jdbc:log4jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME:yxk_canvasscreen}?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false |
|||
username: ${DB_USER:root} |
|||
password: ${DB_PWD:ftzn83560792} |
|||
# 初始连接数 |
|||
initial-size: 5 |
|||
# 最小连接数 |
|||
min-idle: 10 |
|||
# 最大连接数 |
|||
max-active: 20 |
|||
# 获取连接超时时间 |
|||
max-wait: 5000 |
|||
# 连接有效性检测时间 |
|||
time-between-eviction-runs-millis: 60000 |
|||
# 连接在池中最小生存的时间 |
|||
min-evictable-idle-time-millis: 300000 |
|||
# 连接在池中最大生存的时间 |
|||
max-evictable-idle-time-millis: 900000 |
|||
test-while-idle: true |
|||
test-on-borrow: false |
|||
test-on-return: false |
|||
# 检测连接是否有效 |
|||
validation-query: select 1 |
|||
# 配置监控统计 |
|||
webStatFilter: |
|||
enabled: true |
|||
stat-view-servlet: |
|||
enabled: true |
|||
url-pattern: /druid/* |
|||
reset-enable: false |
|||
login-username: admin |
|||
login-password: 123456 |
|||
filter: |
|||
stat: |
|||
enabled: true |
|||
# 记录慢SQL |
|||
log-slow-sql: true |
|||
slow-sql-millis: 1000 |
|||
merge-sql: true |
|||
wall: |
|||
config: |
|||
multi-statement-allow: true |
|||
|
|||
# 登录相关配置 |
|||
login: |
|||
# 登录缓存 |
|||
cache-enable: true |
|||
# 是否限制单用户登录 |
|||
single-login: false |
|||
# 验证码 |
|||
login-code: |
|||
# 验证码类型配置 查看 LoginProperties 类 |
|||
code-type: arithmetic |
|||
# 登录图形验证码有效时间/分钟 |
|||
expiration: 2 |
|||
# 验证码高度 |
|||
width: 111 |
|||
# 验证码宽度 |
|||
heigth: 36 |
|||
# 内容长度 |
|||
length: 2 |
|||
# 字体名称,为空则使用默认字体,如遇到线上乱码,设置其他字体即可 |
|||
font-name: |
|||
# 字体大小 |
|||
font-size: 25 |
|||
|
|||
#jwt |
|||
jwt: |
|||
header: Authorization |
|||
# 令牌前缀 |
|||
token-start-with: Bearer |
|||
# 必须使用最少88位的Base64对该令牌进行编码 |
|||
base64-secret: ZmQ0ZGI5NjQ0MDQwY2I4MjMxY2Y3ZmI3MjdhN2ZmMjNhODViOTg1ZGE0NTBjMGM4NDA5NzYxMjdjOWMwYWRmZTBlZjlhNGY3ZTg4Y2U3YTE1ODVkZDU5Y2Y3OGYwZWE1NzUzNWQ2YjFjZDc0NGMxZWU2MmQ3MjY1NzJmNTE0MzI= |
|||
# 令牌过期时间 此处单位/毫秒 ,默认2小时,可在此网站生成 https://www.convertworld.com/zh-hans/time/milliseconds.html |
|||
token-validity-in-seconds: 7200000 |
|||
# 在线用户key |
|||
online-key: online-token- |
|||
# 验证码 |
|||
code-key: code-key- |
|||
# token 续期检查时间范围(默认30分钟,单位默认毫秒),在token即将过期的一段时间内用户操作了,则给用户的token续期 |
|||
detect: 1800000 |
|||
# 续期时间范围,默认 1小时,这里单位毫秒 |
|||
renew: 3600000 |
|||
|
|||
# IP 本地解析 |
|||
ip: |
|||
local-parsing: false |
|||
|
|||
#是否允许生成代码,生产环境设置为false |
|||
generator: |
|||
enabled: false |
|||
|
|||
#如果生产环境要开启swagger,需要配置请求地址 |
|||
#springfox: |
|||
# documentation: |
|||
# swagger: |
|||
# v2: |
|||
# host: # 接口域名或外网ip |
|||
|
|||
#是否开启 swagger-ui |
|||
swagger: |
|||
enabled: true |
|||
|
|||
# 文件存储路径 |
|||
file: |
|||
mac: |
|||
path: ~/file/ |
|||
avatar: ~/avatar/ |
|||
linux: |
|||
path: /home/www/yxkadmin/file/ |
|||
avatar: /home/www/yxkadmin/avatar/ |
|||
windows: |
|||
path: D:\yxkdmin\file\ |
|||
avatar: D:\yxkadmin\avatar\ |
|||
# 文件大小 /M |
|||
maxSize: 100 |
|||
avatarMaxSize: 5 |
@ -0,0 +1,27 @@ |
|||
#数据库类型转Java类型 |
|||
tinyint=Integer |
|||
smallint=Integer |
|||
mediumint=Integer |
|||
int=Integer |
|||
integer=Integer |
|||
|
|||
bigint=Long |
|||
|
|||
float=Float |
|||
|
|||
double=Double |
|||
|
|||
decimal=BigDecimal |
|||
|
|||
bit=Boolean |
|||
|
|||
char=String |
|||
varchar=String |
|||
tinytext=String |
|||
text=String |
|||
mediumtext=String |
|||
longtext=String |
|||
|
|||
date=Timestamp |
|||
datetime=Timestamp |
|||
timestamp=Timestamp |
@ -0,0 +1,4 @@ |
|||
# If you use SLF4J. First, you need to tell log4jdbc-log4j2 that you want to use the SLF4J logger |
|||
log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator |
|||
log4jdbc.auto.load.popular.drivers=false |
|||
log4jdbc.drivers=com.mysql.cj.jdbc.Driver |
@ -0,0 +1,45 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<configuration scan="true" scanPeriod="30 seconds" debug="false"> |
|||
<contextName>yxkAdmin</contextName> |
|||
<property name="log.charset" value="utf-8" /> |
|||
<property name="log.pattern" value="%black(%contextName-) %red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}) - %gray(%msg%n)" /> |
|||
|
|||
<!--输出到控制台--> |
|||
<appender name="console" class="ch.qos.logback.core.ConsoleAppender"> |
|||
<encoder> |
|||
<pattern>${log.pattern}</pattern> |
|||
<charset>${log.charset}</charset> |
|||
</encoder> |
|||
</appender> |
|||
|
|||
<!--普通日志输出到控制台--> |
|||
<root level="info"> |
|||
<appender-ref ref="console" /> |
|||
</root> |
|||
|
|||
<!--监控sql日志输出 --> |
|||
<logger name="jdbc.sqlonly" level="INFO" additivity="false"> |
|||
<appender-ref ref="console" /> |
|||
</logger> |
|||
|
|||
<logger name="jdbc.resultset" level="ERROR" additivity="false"> |
|||
<appender-ref ref="console" /> |
|||
</logger> |
|||
|
|||
<!-- 如想看到表格数据,将OFF改为INFO --> |
|||
<logger name="jdbc.resultsettable" level="OFF" additivity="false"> |
|||
<appender-ref ref="console" /> |
|||
</logger> |
|||
|
|||
<logger name="jdbc.connection" level="OFF" additivity="false"> |
|||
<appender-ref ref="console" /> |
|||
</logger> |
|||
|
|||
<logger name="jdbc.sqltiming" level="OFF" additivity="false"> |
|||
<appender-ref ref="console" /> |
|||
</logger> |
|||
|
|||
<logger name="jdbc.audit" level="OFF" additivity="false"> |
|||
<appender-ref ref="console" /> |
|||
</logger> |
|||
</configuration> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue