80 changed files with 3902 additions and 8 deletions
-
22common/src/main/java/com/storeroom/annotaion/DataPermission.java
-
14common/src/main/java/com/storeroom/annotaion/Query.java
-
18common/src/main/java/com/storeroom/exception/BadConfigurationException.java
-
38common/src/main/java/com/storeroom/utils/CacheKey.java
-
83common/src/main/java/com/storeroom/utils/EncryptUtils.java
-
46common/src/main/java/com/storeroom/utils/PageUtil.java
-
194common/src/main/java/com/storeroom/utils/QueryHelp.java
-
29common/src/main/java/com/storeroom/utils/ValidationUtil.java
-
53common/src/main/java/com/storeroom/utils/enums/RequestMethodEnum.java
-
3system/src/main/java/AppRun.java
-
24system/src/main/java/com/storeroom/modules/security/config/ConfigBeanConfiguration.java
-
179system/src/main/java/com/storeroom/modules/security/config/SpringSecurityConfig.java
-
50system/src/main/java/com/storeroom/modules/security/config/bean/LoginCode.java
-
30system/src/main/java/com/storeroom/modules/security/config/bean/LoginCodeEnum.java
-
89system/src/main/java/com/storeroom/modules/security/config/bean/LoginProperties.java
-
55system/src/main/java/com/storeroom/modules/security/config/bean/SecurityProperties.java
-
19system/src/main/java/com/storeroom/modules/security/security/JwtAccessDeniedHandler.java
-
19system/src/main/java/com/storeroom/modules/security/security/JwtAuthenticationEntryPoint.java
-
24system/src/main/java/com/storeroom/modules/security/security/TokenConfigurer.java
-
92system/src/main/java/com/storeroom/modules/security/security/TokenFilter.java
-
111system/src/main/java/com/storeroom/modules/security/security/TokenProvider.java
-
173system/src/main/java/com/storeroom/modules/security/service/OnlineUserService.java
-
29system/src/main/java/com/storeroom/modules/security/service/UserCacheClean.java
-
72system/src/main/java/com/storeroom/modules/security/service/UserDetailsServiceImpl.java
-
16system/src/main/java/com/storeroom/modules/security/service/dto/AuthUserDto.java
-
65system/src/main/java/com/storeroom/modules/security/service/dto/JwtUserDto.java
-
54system/src/main/java/com/storeroom/modules/security/service/dto/OnlineUserDto.java
-
69system/src/main/java/com/storeroom/modules/system/domain/Dept.java
-
36system/src/main/java/com/storeroom/modules/system/domain/Dict.java
-
40system/src/main/java/com/storeroom/modules/system/domain/DictDetail.java
-
56system/src/main/java/com/storeroom/modules/system/domain/Job.java
-
92system/src/main/java/com/storeroom/modules/system/domain/Menu.java
-
79system/src/main/java/com/storeroom/modules/system/domain/Role.java
-
108system/src/main/java/com/storeroom/modules/system/domain/User.java
-
18system/src/main/java/com/storeroom/modules/system/domain/vo/MenuMetaVo.java
-
29system/src/main/java/com/storeroom/modules/system/domain/vo/MenuVo.java
-
15system/src/main/java/com/storeroom/modules/system/domain/vo/UserPassVo.java
-
51system/src/main/java/com/storeroom/modules/system/repository/DeptRepository.java
-
24system/src/main/java/com/storeroom/modules/system/repository/DictRepository.java
-
23system/src/main/java/com/storeroom/modules/system/repository/JobRepository.java
-
69system/src/main/java/com/storeroom/modules/system/repository/MenuRepository.java
-
61system/src/main/java/com/storeroom/modules/system/repository/RoleRepository.java
-
112system/src/main/java/com/storeroom/modules/system/repository/UserRepository.java
-
10system/src/main/java/com/storeroom/modules/system/service/DataService.java
-
4system/src/main/java/com/storeroom/modules/system/service/DeptService.java
-
45system/src/main/java/com/storeroom/modules/system/service/DictDetailService.java
-
57system/src/main/java/com/storeroom/modules/system/service/DictService.java
-
4system/src/main/java/com/storeroom/modules/system/service/JobService.java
-
4system/src/main/java/com/storeroom/modules/system/service/MenuService.java
-
118system/src/main/java/com/storeroom/modules/system/service/RoleService.java
-
99system/src/main/java/com/storeroom/modules/system/service/UserService.java
-
61system/src/main/java/com/storeroom/modules/system/service/dto/DeptDto.java
-
29system/src/main/java/com/storeroom/modules/system/service/dto/DeptQueryCriteria.java
-
16system/src/main/java/com/storeroom/modules/system/service/dto/DeptSmallDto.java
-
23system/src/main/java/com/storeroom/modules/system/service/dto/DictDetailDto.java
-
15system/src/main/java/com/storeroom/modules/system/service/dto/DictDetailQueryCriteria.java
-
22system/src/main/java/com/storeroom/modules/system/service/dto/DictDto.java
-
12system/src/main/java/com/storeroom/modules/system/service/dto/DictQueryCriteria.java
-
12system/src/main/java/com/storeroom/modules/system/service/dto/DictSmallDto.java
-
27system/src/main/java/com/storeroom/modules/system/service/dto/JobDto.java
-
16system/src/main/java/com/storeroom/modules/system/service/dto/JobSmallDto.java
-
73system/src/main/java/com/storeroom/modules/system/service/dto/MenuDto.java
-
24system/src/main/java/com/storeroom/modules/system/service/dto/MenuQueryCriteria.java
-
46system/src/main/java/com/storeroom/modules/system/service/dto/RoleDto.java
-
17system/src/main/java/com/storeroom/modules/system/service/dto/RoleQueryCriteria.java
-
18system/src/main/java/com/storeroom/modules/system/service/dto/RoleSmallDto.java
-
50system/src/main/java/com/storeroom/modules/system/service/dto/UserDto.java
-
31system/src/main/java/com/storeroom/modules/system/service/dto/UserQueryCriteria.java
-
208system/src/main/java/com/storeroom/modules/system/service/impl/RoleServiceImpl.java
-
239system/src/main/java/com/storeroom/modules/system/service/impl/UserServiceImpl.java
-
12system/src/main/java/com/storeroom/modules/system/service/mapstruct/DeptMapper.java
-
11system/src/main/java/com/storeroom/modules/system/service/mapstruct/DictDetailMapper.java
-
11system/src/main/java/com/storeroom/modules/system/service/mapstruct/DictMapper.java
-
12system/src/main/java/com/storeroom/modules/system/service/mapstruct/DictSmallMapper.java
-
12system/src/main/java/com/storeroom/modules/system/service/mapstruct/JobMapper.java
-
12system/src/main/java/com/storeroom/modules/system/service/mapstruct/MenuMapper.java
-
12system/src/main/java/com/storeroom/modules/system/service/mapstruct/RoleMapper.java
-
12system/src/main/java/com/storeroom/modules/system/service/mapstruct/RoleSmallMapper.java
-
12system/src/main/java/com/storeroom/modules/system/service/mapstruct/UserMapper.java
-
41system/src/main/resources/application.yml
@ -0,0 +1,22 @@ |
|||
package com.storeroom.annotaion; |
|||
|
|||
|
|||
import java.lang.annotation.ElementType; |
|||
import java.lang.annotation.Retention; |
|||
import java.lang.annotation.RetentionPolicy; |
|||
import java.lang.annotation.Target; |
|||
|
|||
@Target(ElementType.TYPE) |
|||
@Retention(RetentionPolicy.RUNTIME) |
|||
public @interface DataPermission { |
|||
|
|||
/** |
|||
* Entity 中的字段名称 |
|||
*/ |
|||
String fieldName() default ""; |
|||
|
|||
/** |
|||
* Entity 中与部门关联的字段名称 |
|||
*/ |
|||
String joinName() default ""; |
|||
} |
@ -0,0 +1,18 @@ |
|||
package com.storeroom.exception; |
|||
|
|||
public class BadConfigurationException extends RuntimeException{ |
|||
|
|||
public BadConfigurationException(){super();} |
|||
|
|||
public BadConfigurationException(String message){super(message);} |
|||
|
|||
public BadConfigurationException(String message,Throwable cause){ |
|||
super(message, cause); |
|||
} |
|||
|
|||
public BadConfigurationException(Throwable cause){super(cause);} |
|||
|
|||
protected BadConfigurationException(String message,Throwable cause,boolean enableSuppression,boolean writableStackTrace){ |
|||
super(message, cause, enableSuppression, writableStackTrace); |
|||
} |
|||
} |
@ -0,0 +1,38 @@ |
|||
package com.storeroom.utils; |
|||
|
|||
public interface CacheKey { |
|||
|
|||
/** |
|||
* 用户 |
|||
*/ |
|||
String USER_ID = "user::id:"; |
|||
/** |
|||
* 数据 |
|||
*/ |
|||
String DATA_USER = "data::user:"; |
|||
/** |
|||
* 菜单 |
|||
*/ |
|||
String MENU_ID = "menu::id:"; |
|||
String MENU_USER = "menu::user:"; |
|||
/** |
|||
* 角色授权 |
|||
*/ |
|||
String ROLE_AUTH = "role::auth:"; |
|||
/** |
|||
* 角色信息 |
|||
*/ |
|||
String ROLE_ID = "role::id:"; |
|||
/** |
|||
* 部门 |
|||
*/ |
|||
String DEPT_ID = "dept::id:"; |
|||
/** |
|||
* 岗位 |
|||
*/ |
|||
String JOB_ID = "job::id:"; |
|||
/** |
|||
* 数据字典 |
|||
*/ |
|||
String DICT_NAME = "dict::name:"; |
|||
} |
@ -0,0 +1,83 @@ |
|||
package com.storeroom.utils; |
|||
|
|||
|
|||
import javax.crypto.Cipher; |
|||
import javax.crypto.SecretKey; |
|||
import javax.crypto.SecretKeyFactory; |
|||
import javax.crypto.spec.DESKeySpec; |
|||
import javax.crypto.spec.IvParameterSpec; |
|||
import java.nio.charset.StandardCharsets; |
|||
|
|||
/** |
|||
* 加密工具类 |
|||
*/ |
|||
public class EncryptUtils { |
|||
|
|||
private static final String STR_PARAM = "Passw0rd"; |
|||
|
|||
private static Cipher cipher; |
|||
|
|||
private static final IvParameterSpec IV = new IvParameterSpec(STR_PARAM.getBytes(StandardCharsets.UTF_8)); |
|||
|
|||
private static DESKeySpec getDesKeySpec(String source) throws Exception { |
|||
if (source == null || source.length() == 0){ |
|||
return null; |
|||
} |
|||
cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); |
|||
String strKey = "Passw0rd"; |
|||
return new DESKeySpec(strKey.getBytes(StandardCharsets.UTF_8)); |
|||
} |
|||
|
|||
/** |
|||
* 对称加密 |
|||
*/ |
|||
public static String desEncrypt(String source) throws Exception { |
|||
DESKeySpec desKeySpec = getDesKeySpec(source); |
|||
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); |
|||
SecretKey secretKey = keyFactory.generateSecret(desKeySpec); |
|||
cipher.init(Cipher.ENCRYPT_MODE, secretKey, IV); |
|||
return byte2hex( |
|||
cipher.doFinal(source.getBytes(StandardCharsets.UTF_8))).toUpperCase(); |
|||
} |
|||
|
|||
/** |
|||
* 对称解密 |
|||
*/ |
|||
public static String desDecrypt(String source) throws Exception { |
|||
byte[] src = hex2byte(source.getBytes(StandardCharsets.UTF_8)); |
|||
DESKeySpec desKeySpec = getDesKeySpec(source); |
|||
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); |
|||
SecretKey secretKey = keyFactory.generateSecret(desKeySpec); |
|||
cipher.init(Cipher.DECRYPT_MODE, secretKey, IV); |
|||
byte[] retByte = cipher.doFinal(src); |
|||
return new String(retByte); |
|||
} |
|||
|
|||
private static String byte2hex(byte[] inStr) { |
|||
String stmp; |
|||
StringBuilder out = new StringBuilder(inStr.length * 2); |
|||
for (byte b : inStr) { |
|||
stmp = Integer.toHexString(b & 0xFF); |
|||
if (stmp.length() == 1) { |
|||
// 如果是0至F的单位字符串,则添加0 |
|||
out.append("0").append(stmp); |
|||
} else { |
|||
out.append(stmp); |
|||
} |
|||
} |
|||
return out.toString(); |
|||
} |
|||
|
|||
private static byte[] hex2byte(byte[] b) { |
|||
int size = 2; |
|||
if ((b.length % size) != 0){ |
|||
throw new IllegalArgumentException("长度不是偶数"); |
|||
} |
|||
byte[] b2 = new byte[b.length / 2]; |
|||
for (int n = 0; n < b.length; n += size) { |
|||
String item = new String(b, n, 2); |
|||
b2[n / 2] = (byte) Integer.parseInt(item, 16); |
|||
} |
|||
return b2; |
|||
} |
|||
} |
@ -0,0 +1,46 @@ |
|||
package com.storeroom.utils; |
|||
|
|||
import org.springframework.data.domain.Page; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.LinkedHashMap; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
public class PageUtil extends cn.hutool.core.util.PageUtil{ |
|||
|
|||
/** |
|||
* List 分页 |
|||
*/ |
|||
public static List toPage(int page, int size , List list) { |
|||
int fromIndex = page * size; |
|||
int toIndex = page * size + size; |
|||
if(fromIndex > list.size()){ |
|||
return new ArrayList(); |
|||
} else if(toIndex >= list.size()) { |
|||
return list.subList(fromIndex,list.size()); |
|||
} else { |
|||
return list.subList(fromIndex,toIndex); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Page 数据处理,预防redis反序列化报错 |
|||
*/ |
|||
public static Map<String,Object> toPage(Page page) { |
|||
Map<String,Object> map = new LinkedHashMap<>(2); |
|||
map.put("content",page.getContent()); |
|||
map.put("totalElements",page.getTotalElements()); |
|||
return map; |
|||
} |
|||
|
|||
/** |
|||
* 自定义分页 |
|||
*/ |
|||
public static Map<String,Object> toPage(Object object, Object totalElements) { |
|||
Map<String,Object> map = new LinkedHashMap<>(2); |
|||
map.put("content",object); |
|||
map.put("totalElements",totalElements); |
|||
return map; |
|||
} |
|||
} |
@ -0,0 +1,194 @@ |
|||
package com.storeroom.utils; |
|||
|
|||
|
|||
import cn.hutool.core.collection.CollUtil; |
|||
import cn.hutool.core.collection.CollectionUtil; |
|||
import cn.hutool.core.util.ObjectUtil; |
|||
import com.storeroom.annotaion.DataPermission; |
|||
import com.storeroom.annotaion.Query; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
|
|||
import javax.persistence.criteria.*; |
|||
import java.lang.reflect.Field; |
|||
import java.util.ArrayList; |
|||
import java.util.Arrays; |
|||
import java.util.Collection; |
|||
import java.util.List; |
|||
|
|||
@Slf4j |
|||
@SuppressWarnings({"unchecked","all"}) |
|||
public class QueryHelp { |
|||
|
|||
public static <R, Q> Predicate getPredicate(Root<R> root, Q query, CriteriaBuilder cb) { |
|||
List<Predicate> list = new ArrayList<>(); |
|||
if(query == null){ |
|||
return cb.and(list.toArray(new Predicate[0])); |
|||
} |
|||
// 数据权限验证 |
|||
DataPermission permission = query.getClass().getAnnotation(DataPermission.class); |
|||
if(permission != null){ |
|||
// 获取数据权限 |
|||
List<Long> dataScopes = SecurityUtils.getCurrentUserDataScope(); |
|||
if(CollectionUtil.isNotEmpty(dataScopes)){ |
|||
if(StringUtils.isNotBlank(permission.joinName()) && StringUtils.isNotBlank(permission.fieldName())) { |
|||
Join join = root.join(permission.joinName(), JoinType.LEFT); |
|||
list.add(getExpression(permission.fieldName(),join, root).in(dataScopes)); |
|||
} else if (StringUtils.isBlank(permission.joinName()) && StringUtils.isNotBlank(permission.fieldName())) { |
|||
list.add(getExpression(permission.fieldName(),null, root).in(dataScopes)); |
|||
} |
|||
} |
|||
} |
|||
try { |
|||
List<Field> fields = getAllFields(query.getClass(), new ArrayList<>()); |
|||
for (Field field : fields) { |
|||
boolean accessible = field.isAccessible(); |
|||
// 设置对象的访问权限,保证对private的属性的访 |
|||
field.setAccessible(true); |
|||
Query q = field.getAnnotation(Query.class); |
|||
if (q != null) { |
|||
String propName = q.propName(); |
|||
String joinName = q.joinName(); |
|||
String blurry = q.blurry(); |
|||
String attributeName = isBlank(propName) ? field.getName() : propName; |
|||
Class<?> fieldType = field.getType(); |
|||
Object val = field.get(query); |
|||
if (ObjectUtil.isNull(val) || "".equals(val)) { |
|||
continue; |
|||
} |
|||
Join join = null; |
|||
// 模糊多字段 |
|||
if (ObjectUtil.isNotEmpty(blurry)) { |
|||
String[] blurrys = blurry.split(","); |
|||
List<Predicate> orPredicate = new ArrayList<>(); |
|||
for (String s : blurrys) { |
|||
orPredicate.add(cb.like(root.get(s) |
|||
.as(String.class), "%" + val.toString() + "%")); |
|||
} |
|||
Predicate[] p = new Predicate[orPredicate.size()]; |
|||
list.add(cb.or(orPredicate.toArray(p))); |
|||
continue; |
|||
} |
|||
if (ObjectUtil.isNotEmpty(joinName)) { |
|||
String[] joinNames = joinName.split(">"); |
|||
for (String name : joinNames) { |
|||
switch (q.join()) { |
|||
case LEFT: |
|||
if(ObjectUtil.isNotNull(join) && ObjectUtil.isNotNull(val)){ |
|||
join = join.join(name, JoinType.LEFT); |
|||
} else { |
|||
join = root.join(name, JoinType.LEFT); |
|||
} |
|||
break; |
|||
case RIGHT: |
|||
if(ObjectUtil.isNotNull(join) && ObjectUtil.isNotNull(val)){ |
|||
join = join.join(name, JoinType.RIGHT); |
|||
} else { |
|||
join = root.join(name, JoinType.RIGHT); |
|||
} |
|||
break; |
|||
case INNER: |
|||
if(ObjectUtil.isNotNull(join) && ObjectUtil.isNotNull(val)){ |
|||
join = join.join(name, JoinType.INNER); |
|||
} else { |
|||
join = root.join(name, JoinType.INNER); |
|||
} |
|||
break; |
|||
default: break; |
|||
} |
|||
} |
|||
} |
|||
switch (q.type()) { |
|||
case EQUAL: |
|||
list.add(cb.equal(getExpression(attributeName,join,root) |
|||
.as((Class<? extends Comparable>) fieldType),val)); |
|||
break; |
|||
case GREATER_THAN: |
|||
list.add(cb.greaterThanOrEqualTo(getExpression(attributeName,join,root) |
|||
.as((Class<? extends Comparable>) fieldType), (Comparable) val)); |
|||
break; |
|||
case LESS_THAN: |
|||
list.add(cb.lessThanOrEqualTo(getExpression(attributeName,join,root) |
|||
.as((Class<? extends Comparable>) fieldType), (Comparable) val)); |
|||
break; |
|||
case LESS_THAN_NQ: |
|||
list.add(cb.lessThan(getExpression(attributeName,join,root) |
|||
.as((Class<? extends Comparable>) fieldType), (Comparable) val)); |
|||
break; |
|||
case INNER_LIKE: |
|||
list.add(cb.like(getExpression(attributeName,join,root) |
|||
.as(String.class), "%" + val.toString() + "%")); |
|||
break; |
|||
case LEFT_LIKE: |
|||
list.add(cb.like(getExpression(attributeName,join,root) |
|||
.as(String.class), "%" + val.toString())); |
|||
break; |
|||
case RIGHT_LIKE: |
|||
list.add(cb.like(getExpression(attributeName,join,root) |
|||
.as(String.class), val.toString() + "%")); |
|||
break; |
|||
case IN: |
|||
if (CollUtil.isNotEmpty((Collection<Object>)val)) { |
|||
list.add(getExpression(attributeName,join,root).in((Collection<Object>) val)); |
|||
} |
|||
break; |
|||
case NOT_IN: |
|||
if (CollUtil.isNotEmpty((Collection<Object>)val)) { |
|||
list.add(getExpression(attributeName,join,root).in((Collection<Object>) val).not()); |
|||
} |
|||
break; |
|||
case NOT_EQUAL: |
|||
list.add(cb.notEqual(getExpression(attributeName,join,root), val)); |
|||
break; |
|||
case NOT_NULL: |
|||
list.add(cb.isNotNull(getExpression(attributeName,join,root))); |
|||
break; |
|||
case IS_NULL: |
|||
list.add(cb.isNull(getExpression(attributeName,join,root))); |
|||
break; |
|||
case BETWEEN: |
|||
List<Object> between = new ArrayList<>((List<Object>)val); |
|||
list.add(cb.between(getExpression(attributeName, join, root).as((Class<? extends Comparable>) between.get(0).getClass()), |
|||
(Comparable) between.get(0), (Comparable) between.get(1))); |
|||
break; |
|||
default: break; |
|||
} |
|||
} |
|||
field.setAccessible(accessible); |
|||
} |
|||
} catch (Exception e) { |
|||
log.error(e.getMessage(), e); |
|||
} |
|||
int size = list.size(); |
|||
return cb.and(list.toArray(new Predicate[size])); |
|||
} |
|||
|
|||
@SuppressWarnings("unchecked") |
|||
private static <T, R> Expression<T> getExpression(String attributeName, Join join, Root<R> root) { |
|||
if (ObjectUtil.isNotEmpty(join)) { |
|||
return join.get(attributeName); |
|||
} else { |
|||
return root.get(attributeName); |
|||
} |
|||
} |
|||
|
|||
private static boolean isBlank(final CharSequence cs) { |
|||
int strLen; |
|||
if (cs == null || (strLen = cs.length()) == 0) { |
|||
return true; |
|||
} |
|||
for (int i = 0; i < strLen; i++) { |
|||
if (!Character.isWhitespace(cs.charAt(i))) { |
|||
return false; |
|||
} |
|||
} |
|||
return true; |
|||
} |
|||
|
|||
public static List<Field> getAllFields(Class clazz, List<Field> fields) { |
|||
if (clazz != null) { |
|||
fields.addAll(Arrays.asList(clazz.getDeclaredFields())); |
|||
getAllFields(clazz.getSuperclass(), fields); |
|||
} |
|||
return fields; |
|||
} |
|||
} |
@ -0,0 +1,29 @@ |
|||
package com.storeroom.utils; |
|||
|
|||
import cn.hutool.core.util.ObjectUtil; |
|||
import com.storeroom.exception.BaseException; |
|||
import org.hibernate.validator.internal.constraintvalidators.hv.EmailValidator; |
|||
|
|||
|
|||
/** |
|||
* 验证工具类 |
|||
*/ |
|||
public class ValidationUtil { |
|||
|
|||
/** |
|||
* 验证空 |
|||
*/ |
|||
public static void isNull(Object obj, String entity, String parameter , Object value){ |
|||
if(ObjectUtil.isNull(obj)){ |
|||
String msg = entity + " 不存在: "+ parameter +" is "+ value; |
|||
throw new BaseException(msg); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 验证是否为邮箱 |
|||
*/ |
|||
public static boolean isEmail(String email) { |
|||
return new EmailValidator().isValid(email, null); |
|||
} |
|||
} |
@ -0,0 +1,53 @@ |
|||
package com.storeroom.utils.enums; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Getter; |
|||
|
|||
@Getter |
|||
@AllArgsConstructor |
|||
public enum RequestMethodEnum { |
|||
|
|||
/** |
|||
* 搜寻 @AnonymousGetMapping |
|||
*/ |
|||
GET("GET"), |
|||
|
|||
/** |
|||
* 搜寻 @AnonymousPostMapping |
|||
*/ |
|||
POST("POST"), |
|||
|
|||
/** |
|||
* 搜寻 @AnonymousPutMapping |
|||
*/ |
|||
PUT("PUT"), |
|||
|
|||
/** |
|||
* 搜寻 @AnonymousPatchMapping |
|||
*/ |
|||
PATCH("PATCH"), |
|||
|
|||
/** |
|||
* 搜寻 @AnonymousDeleteMapping |
|||
*/ |
|||
DELETE("DELETE"), |
|||
|
|||
/** |
|||
* 否则就是所有 Request 接口都放行 |
|||
*/ |
|||
ALL("All"); |
|||
|
|||
/** |
|||
* Request 类型 |
|||
*/ |
|||
private final String type; |
|||
|
|||
public static RequestMethodEnum find(String type) { |
|||
for (RequestMethodEnum value : RequestMethodEnum.values()) { |
|||
if (type.equals(value.getType())) { |
|||
return value; |
|||
} |
|||
} |
|||
return ALL; |
|||
} |
|||
} |
@ -0,0 +1,24 @@ |
|||
package com.storeroom.modules.security.config; |
|||
|
|||
|
|||
import com.storeroom.modules.security.config.bean.LoginProperties; |
|||
import org.springframework.boot.autoconfigure.security.SecurityProperties; |
|||
import org.springframework.boot.context.properties.ConfigurationProperties; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.context.annotation.Configuration; |
|||
|
|||
@Configuration |
|||
public class ConfigBeanConfiguration { |
|||
|
|||
@Bean |
|||
@ConfigurationProperties(prefix="login",ignoreUnknownFields=true) |
|||
public LoginProperties loginProperties(){ |
|||
return new LoginProperties(); |
|||
} |
|||
|
|||
@Bean |
|||
@ConfigurationProperties(prefix = "jwt",ignoreUnknownFields = true) |
|||
public SecurityProperties securityProperties(){ |
|||
return new SecurityProperties(); |
|||
} |
|||
} |
@ -0,0 +1,179 @@ |
|||
package com.storeroom.modules.security.config; |
|||
|
|||
|
|||
import com.storeroom.annotaion.AnonymousAccess; |
|||
import com.storeroom.modules.security.config.bean.SecurityProperties; |
|||
import com.storeroom.modules.security.security.JwtAccessDeniedHandler; |
|||
import com.storeroom.modules.security.security.JwtAuthenticationEntryPoint; |
|||
import com.storeroom.modules.security.security.TokenConfigurer; |
|||
import com.storeroom.modules.security.security.TokenProvider; |
|||
import com.storeroom.modules.security.service.OnlineUserService; |
|||
import com.storeroom.modules.security.service.UserCacheClean; |
|||
import com.storeroom.utils.enums.RequestMethodEnum; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.context.ApplicationContext; |
|||
import org.springframework.context.annotation.Bean; |
|||
import org.springframework.context.annotation.Configuration; |
|||
import org.springframework.http.HttpMethod; |
|||
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; |
|||
import org.springframework.security.config.annotation.web.builders.HttpSecurity; |
|||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; |
|||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; |
|||
import org.springframework.security.config.core.GrantedAuthorityDefaults; |
|||
import org.springframework.security.config.http.SessionCreationPolicy; |
|||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; |
|||
import org.springframework.security.crypto.password.PasswordEncoder; |
|||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; |
|||
import org.springframework.web.bind.annotation.RequestMethod; |
|||
import org.springframework.web.filter.CorsFilter; |
|||
import org.springframework.web.method.HandlerMethod; |
|||
import org.springframework.web.servlet.mvc.method.RequestMappingInfo; |
|||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; |
|||
|
|||
import java.util.*; |
|||
|
|||
@Configuration |
|||
@EnableWebSecurity |
|||
@RequiredArgsConstructor |
|||
@EnableGlobalMethodSecurity(prePostEnabled = true,securedEnabled = true) |
|||
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { |
|||
|
|||
private final TokenProvider tokenProvider; |
|||
|
|||
private final CorsFilter corsFilter; |
|||
private final JwtAuthenticationEntryPoint authenticationErrorHandler; |
|||
private final JwtAccessDeniedHandler jwtAccessDeniedHandler; |
|||
private final ApplicationContext applicationContext; |
|||
private final SecurityProperties properties; |
|||
private final OnlineUserService onlineUserService; |
|||
private final UserCacheClean userCacheClean; |
|||
|
|||
@Bean |
|||
GrantedAuthorityDefaults grantedAuthorityDefaults() { |
|||
// 去除 ROLE_ 前缀 |
|||
return new GrantedAuthorityDefaults(""); |
|||
} |
|||
|
|||
//密码交给框架管理 |
|||
@Bean |
|||
public PasswordEncoder passwordEncoder() { |
|||
// 密码加密方式 |
|||
return new BCryptPasswordEncoder(); |
|||
} |
|||
|
|||
@Override |
|||
protected void configure(HttpSecurity httpSecurity) throws Exception { |
|||
// 搜寻匿名标记 url: @AnonymousAccess |
|||
RequestMappingHandlerMapping requestMappingHandlerMapping = (RequestMappingHandlerMapping) applicationContext.getBean("requestMappingHandlerMapping"); |
|||
Map<RequestMappingInfo, HandlerMethod> handlerMethodMap = requestMappingHandlerMapping.getHandlerMethods(); |
|||
// 获取匿名标记 |
|||
Map<String, Set<String>> anonymousUrls = getAnonymousUrl(handlerMethodMap); |
|||
httpSecurity |
|||
// 禁用 CSRF |
|||
.csrf().disable() |
|||
.addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class) |
|||
// 授权异常 |
|||
.exceptionHandling() |
|||
.authenticationEntryPoint(authenticationErrorHandler) |
|||
.accessDeniedHandler(jwtAccessDeniedHandler) |
|||
// 防止iframe 造成跨域 |
|||
.and() |
|||
.headers() |
|||
.frameOptions() |
|||
.disable() |
|||
// 不创建会话 |
|||
.and() |
|||
.sessionManagement() |
|||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS) |
|||
.and() |
|||
.authorizeRequests() |
|||
// 放行资源 |
|||
.antMatchers( |
|||
HttpMethod.GET, |
|||
"/*.html", |
|||
"/**/*.html", |
|||
"/**/*.css", |
|||
"/**/*.js", |
|||
"/webSocket/**" |
|||
).permitAll() |
|||
// swagger 文档 |
|||
.antMatchers("/swagger-ui.html").permitAll() |
|||
.antMatchers("/swagger-resources/**").permitAll() |
|||
.antMatchers("/webjars/**").permitAll() |
|||
.antMatchers("/*/api-docs").permitAll() |
|||
// 文件 |
|||
.antMatchers("/avatar/**").permitAll() |
|||
.antMatchers("/file/**").permitAll() |
|||
// 阿里巴巴 druid |
|||
.antMatchers("/druid/**").permitAll() |
|||
// 放行OPTIONS请求 |
|||
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll() |
|||
// 自定义匿名访问所有url放行:允许匿名和带Token访问,细腻化到每个 Request 类型 |
|||
// GET |
|||
.antMatchers(HttpMethod.GET, anonymousUrls.get(RequestMethodEnum.GET.getType()).toArray(new String[0])).permitAll() |
|||
// POST |
|||
.antMatchers(HttpMethod.POST, anonymousUrls.get(RequestMethodEnum.POST.getType()).toArray(new String[0])).permitAll() |
|||
// PUT |
|||
.antMatchers(HttpMethod.PUT, anonymousUrls.get(RequestMethodEnum.PUT.getType()).toArray(new String[0])).permitAll() |
|||
// PATCH |
|||
.antMatchers(HttpMethod.PATCH, anonymousUrls.get(RequestMethodEnum.PATCH.getType()).toArray(new String[0])).permitAll() |
|||
// DELETE |
|||
.antMatchers(HttpMethod.DELETE, anonymousUrls.get(RequestMethodEnum.DELETE.getType()).toArray(new String[0])).permitAll() |
|||
// 所有类型的接口都放行 |
|||
.antMatchers(anonymousUrls.get(RequestMethodEnum.ALL.getType()).toArray(new String[0])).permitAll() |
|||
// 所有请求都需要认证 测试需求注释 |
|||
//.anyRequest().authenticated() |
|||
.and().apply(securityConfigurerAdapter()); |
|||
} |
|||
|
|||
private TokenConfigurer securityConfigurerAdapter() { |
|||
return new TokenConfigurer(tokenProvider, properties, onlineUserService, userCacheClean); |
|||
} |
|||
|
|||
private Map<String, Set<String>> getAnonymousUrl(Map<RequestMappingInfo, HandlerMethod> handlerMethodMap) { |
|||
Map<String, Set<String>> anonymousUrls = new HashMap<>(6); |
|||
Set<String> get = new HashSet<>(); |
|||
Set<String> post = new HashSet<>(); |
|||
Set<String> put = new HashSet<>(); |
|||
Set<String> patch = new HashSet<>(); |
|||
Set<String> delete = new HashSet<>(); |
|||
Set<String> all = new HashSet<>(); |
|||
for (Map.Entry<RequestMappingInfo, HandlerMethod> infoEntry : handlerMethodMap.entrySet()) { |
|||
HandlerMethod handlerMethod = infoEntry.getValue(); |
|||
AnonymousAccess anonymousAccess = handlerMethod.getMethodAnnotation(AnonymousAccess.class); |
|||
if (null != anonymousAccess) { |
|||
List<RequestMethod> requestMethods = new ArrayList<>(infoEntry.getKey().getMethodsCondition().getMethods()); |
|||
RequestMethodEnum request = RequestMethodEnum.find(requestMethods.size() == 0 ? RequestMethodEnum.ALL.getType() : requestMethods.get(0).name()); |
|||
switch (Objects.requireNonNull(request)) { |
|||
case GET: |
|||
get.addAll(infoEntry.getKey().getPatternsCondition().getPatterns()); |
|||
break; |
|||
case POST: |
|||
post.addAll(infoEntry.getKey().getPatternsCondition().getPatterns()); |
|||
break; |
|||
case PUT: |
|||
put.addAll(infoEntry.getKey().getPatternsCondition().getPatterns()); |
|||
break; |
|||
case PATCH: |
|||
patch.addAll(infoEntry.getKey().getPatternsCondition().getPatterns()); |
|||
break; |
|||
case DELETE: |
|||
delete.addAll(infoEntry.getKey().getPatternsCondition().getPatterns()); |
|||
break; |
|||
default: |
|||
all.addAll(infoEntry.getKey().getPatternsCondition().getPatterns()); |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
anonymousUrls.put(RequestMethodEnum.GET.getType(), get); |
|||
anonymousUrls.put(RequestMethodEnum.POST.getType(), post); |
|||
anonymousUrls.put(RequestMethodEnum.PUT.getType(), put); |
|||
anonymousUrls.put(RequestMethodEnum.PATCH.getType(), patch); |
|||
anonymousUrls.put(RequestMethodEnum.DELETE.getType(), delete); |
|||
anonymousUrls.put(RequestMethodEnum.ALL.getType(), all); |
|||
return anonymousUrls; |
|||
} |
|||
|
|||
|
|||
} |
@ -0,0 +1,50 @@ |
|||
package com.storeroom.modules.security.config.bean; |
|||
|
|||
|
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
public class LoginCode { |
|||
|
|||
/** |
|||
* 验证码配置 |
|||
*/ |
|||
private LoginCodeEnum codeType; |
|||
|
|||
/** |
|||
* 验证码有效期 分钟为单位 |
|||
*/ |
|||
private Long expiration = 2L; |
|||
|
|||
|
|||
/** |
|||
* 验证码长度 |
|||
*/ |
|||
private int length = 2; |
|||
|
|||
|
|||
/** |
|||
* 验证码宽度 |
|||
*/ |
|||
private int width = 111; |
|||
|
|||
/** |
|||
* 验证码高度 |
|||
*/ |
|||
private int height=36; |
|||
|
|||
/** |
|||
* 验证码字体 |
|||
*/ |
|||
private String fontName; |
|||
|
|||
/** |
|||
* 字体大小 |
|||
*/ |
|||
private int fontSize=25; |
|||
|
|||
|
|||
public LoginCodeEnum getCodeType() { |
|||
return codeType; |
|||
} |
|||
} |
@ -0,0 +1,30 @@ |
|||
package com.storeroom.modules.security.config.bean; |
|||
|
|||
|
|||
/** |
|||
* 验证码配置枚举 |
|||
*/ |
|||
public enum LoginCodeEnum { |
|||
|
|||
/** |
|||
* 算术 |
|||
*/ |
|||
arithmetic, |
|||
/** |
|||
* 中文 |
|||
*/ |
|||
chinese, |
|||
|
|||
/** |
|||
* 中文闪图 |
|||
*/ |
|||
chinese_gif, |
|||
|
|||
/** |
|||
* 闪图 |
|||
*/ |
|||
gif, |
|||
|
|||
spec |
|||
|
|||
} |
@ -0,0 +1,89 @@ |
|||
package com.storeroom.modules.security.config.bean; |
|||
|
|||
import com.storeroom.exception.BadConfigurationException; |
|||
import com.storeroom.utils.StringUtils; |
|||
import com.wf.captcha.*; |
|||
import com.wf.captcha.base.Captcha; |
|||
import lombok.Data; |
|||
|
|||
import java.awt.*; |
|||
import java.util.Objects; |
|||
|
|||
@Data |
|||
public class LoginProperties { |
|||
|
|||
private boolean singleLogin= false; |
|||
|
|||
private LoginCode loginCode; |
|||
|
|||
/** |
|||
* 用户登录信息缓存 |
|||
*/ |
|||
private boolean cacheEnable; |
|||
|
|||
|
|||
public boolean isSingleLogin() { |
|||
return singleLogin; |
|||
} |
|||
|
|||
public boolean isCacheEnable() { |
|||
return cacheEnable; |
|||
} |
|||
|
|||
/** |
|||
* 获取验证码生产类 |
|||
* @return |
|||
*/ |
|||
public Captcha getCaptcha(){ |
|||
if (Objects.isNull(loginCode)){ |
|||
loginCode=new LoginCode(); |
|||
if (Objects.isNull(loginCode.getCodeType())){ |
|||
loginCode.setCodeType(LoginCodeEnum.arithmetic); |
|||
} |
|||
} |
|||
return switchCaptcha(loginCode); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 依据配置信息生产验证码 |
|||
* @param loginCode |
|||
* @return |
|||
*/ |
|||
private Captcha switchCaptcha(LoginCode loginCode){ |
|||
Captcha captcha; |
|||
synchronized (this){ |
|||
switch (loginCode.getCodeType()){ |
|||
case arithmetic: |
|||
captcha=new ArithmeticCaptcha(loginCode.getWidth(),loginCode.getHeight()); |
|||
|
|||
//几位数运算,默认是两位 |
|||
captcha.setLen(loginCode.getLength()); |
|||
break; |
|||
case chinese: |
|||
captcha=new ChineseCaptcha(loginCode.getWidth(),loginCode.getHeight()); |
|||
captcha.setLen(loginCode.getLength()); |
|||
case chinese_gif: |
|||
captcha=new ChineseGifCaptcha(loginCode.getWidth(),loginCode.getHeight()); |
|||
captcha.setLen(loginCode.getLength()); |
|||
break; |
|||
case gif: |
|||
captcha=new GifCaptcha(loginCode.getWidth(),loginCode.getHeight()); |
|||
captcha.setLen(loginCode.getLength()); |
|||
case spec: |
|||
captcha=new SpecCaptcha(loginCode.getWidth(),loginCode.getHeight()); |
|||
captcha.setLen(loginCode.getLength()); |
|||
break; |
|||
default: |
|||
throw new BadConfigurationException("验证码配置信息错误!正确配置查看 LoginCodeEnum"); |
|||
} |
|||
} |
|||
if (StringUtils.isNotBlank(loginCode.getFontName())){ |
|||
captcha.setFont(new Font(loginCode.getFontName(), Font.PLAIN, loginCode.getFontSize())); |
|||
} |
|||
return captcha; |
|||
} |
|||
|
|||
|
|||
|
|||
} |
@ -0,0 +1,55 @@ |
|||
package com.storeroom.modules.security.config.bean; |
|||
|
|||
|
|||
import lombok.Data; |
|||
|
|||
/** |
|||
* Jwt 配置 |
|||
*/ |
|||
@Data |
|||
public class SecurityProperties { |
|||
|
|||
/** |
|||
* Request Headers:Authorization |
|||
*/ |
|||
private String header; |
|||
|
|||
/** |
|||
* 令牌前缀,最后留个空格 Bearer |
|||
*/ |
|||
private String tokenStartWith; |
|||
|
|||
/** |
|||
* 必须使用最少88位的Base64对该令牌进行编码 |
|||
*/ |
|||
private String base64Secret; |
|||
|
|||
/** |
|||
* 令牌过期时间此处单位/毫秒 |
|||
*/ |
|||
private Long tokenValidityInSeconds; |
|||
|
|||
/** |
|||
* 在线用户 key,根据 key 查询 redis 中在线用户的数据 |
|||
*/ |
|||
private String onlineKey; |
|||
|
|||
/** |
|||
* 验证码key |
|||
*/ |
|||
private String codeKey; |
|||
|
|||
/** |
|||
* token 续期检查 |
|||
*/ |
|||
private Long detect; |
|||
|
|||
/** |
|||
* 续期时间 |
|||
*/ |
|||
private Long renew; |
|||
|
|||
public String getTokenStartWith(){ |
|||
return tokenStartWith+" "; |
|||
} |
|||
} |
@ -0,0 +1,19 @@ |
|||
package com.storeroom.modules.security.security; |
|||
|
|||
import org.springframework.security.access.AccessDeniedException; |
|||
import org.springframework.security.web.access.AccessDeniedHandler; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import javax.servlet.ServletException; |
|||
import javax.servlet.http.HttpServletRequest; |
|||
import javax.servlet.http.HttpServletResponse; |
|||
import java.io.IOException; |
|||
|
|||
@Component |
|||
public class JwtAccessDeniedHandler implements AccessDeniedHandler { |
|||
@Override |
|||
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { |
|||
//当前用户在没有权限的情况下访问受保护的REST资源时,将调用此方法发送403 Forbidden响应 |
|||
response.sendError(HttpServletResponse.SC_FORBIDDEN, accessDeniedException.getMessage()); |
|||
} |
|||
} |
@ -0,0 +1,19 @@ |
|||
package com.storeroom.modules.security.security; |
|||
|
|||
import org.springframework.security.core.AuthenticationException; |
|||
import org.springframework.security.web.AuthenticationEntryPoint; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import javax.servlet.ServletException; |
|||
import javax.servlet.http.HttpServletRequest; |
|||
import javax.servlet.http.HttpServletResponse; |
|||
import java.io.IOException; |
|||
|
|||
@Component |
|||
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { |
|||
|
|||
@Override |
|||
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { |
|||
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException == null ? "Unauthorized" : authException.getMessage()); |
|||
} |
|||
} |
@ -0,0 +1,24 @@ |
|||
package com.storeroom.modules.security.security; |
|||
|
|||
import com.storeroom.modules.security.config.bean.SecurityProperties; |
|||
import com.storeroom.modules.security.service.OnlineUserService; |
|||
import com.storeroom.modules.security.service.UserCacheClean; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.security.config.annotation.SecurityConfigurerAdapter; |
|||
import org.springframework.security.config.annotation.web.builders.HttpSecurity; |
|||
import org.springframework.security.web.DefaultSecurityFilterChain; |
|||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; |
|||
|
|||
@RequiredArgsConstructor |
|||
public class TokenConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> { |
|||
private final TokenProvider tokenProvider; |
|||
private final SecurityProperties properties; |
|||
private final OnlineUserService onlineUserService; |
|||
private final UserCacheClean userCacheClean; |
|||
|
|||
@Override |
|||
public void configure(HttpSecurity http) { |
|||
TokenFilter customFilter = new TokenFilter(tokenProvider, properties, onlineUserService, userCacheClean); |
|||
http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class); |
|||
} |
|||
} |
@ -0,0 +1,92 @@ |
|||
package com.storeroom.modules.security.security; |
|||
|
|||
import cn.hutool.core.util.StrUtil; |
|||
import com.storeroom.modules.security.config.bean.SecurityProperties; |
|||
import com.storeroom.modules.security.service.OnlineUserService; |
|||
import com.storeroom.modules.security.service.UserCacheClean; |
|||
import com.storeroom.modules.security.service.dto.OnlineUserDto; |
|||
import io.jsonwebtoken.ExpiredJwtException; |
|||
import org.slf4j.Logger; |
|||
import org.slf4j.LoggerFactory; |
|||
import org.springframework.security.core.Authentication; |
|||
import org.springframework.security.core.context.SecurityContextHolder; |
|||
import org.springframework.util.StringUtils; |
|||
import org.springframework.web.filter.GenericFilterBean; |
|||
|
|||
import javax.servlet.FilterChain; |
|||
import javax.servlet.ServletException; |
|||
import javax.servlet.ServletRequest; |
|||
import javax.servlet.ServletResponse; |
|||
import javax.servlet.http.HttpServletRequest; |
|||
import java.io.IOException; |
|||
import java.util.Objects; |
|||
|
|||
public class TokenFilter extends GenericFilterBean { |
|||
|
|||
private static final Logger log= LoggerFactory.getLogger(TokenFilter.class); |
|||
|
|||
private final TokenProvider tokenProvider; |
|||
private final SecurityProperties properties; |
|||
private final OnlineUserService onlineUserService; |
|||
private final UserCacheClean userCacheClean; |
|||
|
|||
|
|||
/** |
|||
* @param tokenProvider Token |
|||
* @param properties JWT |
|||
* @param onlineUserService 用户在线 |
|||
* @param userCacheClean 用户缓存清理工具 |
|||
*/ |
|||
public TokenFilter(TokenProvider tokenProvider, SecurityProperties properties, OnlineUserService onlineUserService, UserCacheClean userCacheClean) { |
|||
this.properties = properties; |
|||
this.onlineUserService = onlineUserService; |
|||
this.tokenProvider = tokenProvider; |
|||
this.userCacheClean = userCacheClean; |
|||
} |
|||
|
|||
@Override |
|||
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) |
|||
throws IOException, ServletException { |
|||
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest; |
|||
String token = resolveToken(httpServletRequest); |
|||
// 对于 Token 为空的不需要去查 Redis |
|||
if (StrUtil.isNotBlank(token)) { |
|||
OnlineUserDto onlineUserDto = null; |
|||
boolean cleanUserCache = false; |
|||
try { |
|||
onlineUserDto = onlineUserService.getOne(properties.getOnlineKey() + token); |
|||
} catch (ExpiredJwtException e) { |
|||
log.error(e.getMessage()); |
|||
cleanUserCache = true; |
|||
} finally { |
|||
if (cleanUserCache || Objects.isNull(onlineUserDto)) { |
|||
userCacheClean.cleanUserCache(String.valueOf(tokenProvider.getClaims(token).get(TokenProvider.AUTHORITIES_KEY))); |
|||
} |
|||
} |
|||
if (onlineUserDto != null && StringUtils.hasText(token)) { |
|||
Authentication authentication = tokenProvider.getAuthentication(token); |
|||
SecurityContextHolder.getContext().setAuthentication(authentication); |
|||
// Token 续期 |
|||
tokenProvider.checkRenewal(token); |
|||
} |
|||
} |
|||
filterChain.doFilter(servletRequest, servletResponse); |
|||
} |
|||
|
|||
/** |
|||
* 初步检测Token |
|||
* |
|||
* @param request / |
|||
* @return / |
|||
*/ |
|||
private String resolveToken(HttpServletRequest request) { |
|||
String bearerToken = request.getHeader(properties.getHeader()); |
|||
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(properties.getTokenStartWith())) { |
|||
// 去掉令牌前缀 |
|||
return bearerToken.replace(properties.getTokenStartWith(), ""); |
|||
} else { |
|||
log.debug("非法Token:{}", bearerToken); |
|||
} |
|||
return null; |
|||
} |
|||
} |
@ -0,0 +1,111 @@ |
|||
package com.storeroom.modules.security.security; |
|||
|
|||
import cn.hutool.core.date.DateField; |
|||
import cn.hutool.core.date.DateUtil; |
|||
import cn.hutool.core.util.IdUtil; |
|||
import com.storeroom.modules.security.config.bean.SecurityProperties; |
|||
import com.storeroom.utils.RedisUtils; |
|||
import io.jsonwebtoken.*; |
|||
import io.jsonwebtoken.io.Decoders; |
|||
import io.jsonwebtoken.security.Keys; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.InitializingBean; |
|||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; |
|||
import org.springframework.security.core.Authentication; |
|||
import org.springframework.security.core.userdetails.User; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import javax.servlet.http.HttpServletRequest; |
|||
import java.security.Key; |
|||
import java.util.ArrayList; |
|||
import java.util.Date; |
|||
import java.util.concurrent.TimeUnit; |
|||
|
|||
@Slf4j |
|||
@Component |
|||
public class TokenProvider implements InitializingBean { |
|||
|
|||
private final SecurityProperties properties; |
|||
|
|||
private final RedisUtils redisUtils; |
|||
|
|||
public static final String AUTHORITIES_KEY="user"; |
|||
|
|||
private JwtParser jwtParser; |
|||
|
|||
private JwtBuilder jwtBuilder; |
|||
|
|||
public TokenProvider(SecurityProperties properties, RedisUtils redisUtils) { |
|||
this.properties = properties; |
|||
this.redisUtils = redisUtils; |
|||
} |
|||
|
|||
@Override |
|||
public void afterPropertiesSet() { |
|||
byte[] keyBytes = Decoders.BASE64.decode(properties.getBase64Secret()); |
|||
Key key = Keys.hmacShaKeyFor(keyBytes); |
|||
jwtParser = Jwts.parserBuilder() |
|||
.setSigningKey(key) |
|||
.build(); |
|||
jwtBuilder = Jwts.builder() |
|||
.signWith(key, SignatureAlgorithm.HS512); |
|||
} |
|||
|
|||
/** |
|||
* 创建Token 设置永不过期, |
|||
* Token 的时间有效性转到Redis 维护 |
|||
* |
|||
* @param authentication / |
|||
* @return / |
|||
*/ |
|||
public String createToken(Authentication authentication) { |
|||
return jwtBuilder |
|||
// 加入ID确保生成的 Token 都不一致 |
|||
.setId(IdUtil.simpleUUID()) |
|||
.claim(AUTHORITIES_KEY, authentication.getName()) |
|||
.setSubject(authentication.getName()) |
|||
.compact(); |
|||
} |
|||
|
|||
/** |
|||
* 依据Token 获取鉴权信息 |
|||
* |
|||
* @param token / |
|||
* @return / |
|||
*/ |
|||
Authentication getAuthentication(String token) { |
|||
Claims claims = getClaims(token); |
|||
User principal = new User(claims.getSubject(), "******", new ArrayList<>()); |
|||
return new UsernamePasswordAuthenticationToken(principal, token, new ArrayList<>()); |
|||
} |
|||
|
|||
public Claims getClaims(String token) { |
|||
return jwtParser |
|||
.parseClaimsJws(token) |
|||
.getBody(); |
|||
} |
|||
|
|||
/** |
|||
* @param token 需要检查的token |
|||
*/ |
|||
public void checkRenewal(String token) { |
|||
// 判断是否续期token,计算token的过期时间 |
|||
long time = redisUtils.getExpire(properties.getOnlineKey() + token) * 1000; |
|||
Date expireDate = DateUtil.offset(new Date(), DateField.MILLISECOND, (int) time); |
|||
// 判断当前时间与过期时间的时间差 |
|||
long differ = expireDate.getTime() - System.currentTimeMillis(); |
|||
// 如果在续期检查的范围内,则续期 |
|||
if (differ <= properties.getDetect()) { |
|||
long renew = time + properties.getRenew(); |
|||
redisUtils.expire(properties.getOnlineKey() + token, renew, TimeUnit.MILLISECONDS); |
|||
} |
|||
} |
|||
|
|||
public String getToken(HttpServletRequest request) { |
|||
final String requestHeader = request.getHeader(properties.getHeader()); |
|||
if (requestHeader != null && requestHeader.startsWith(properties.getTokenStartWith())) { |
|||
return requestHeader.substring(7); |
|||
} |
|||
return null; |
|||
} |
|||
} |
@ -0,0 +1,173 @@ |
|||
package com.storeroom.modules.security.service; |
|||
|
|||
|
|||
import com.storeroom.modules.security.config.bean.SecurityProperties; |
|||
import com.storeroom.modules.security.service.dto.JwtUserDto; |
|||
import com.storeroom.modules.security.service.dto.OnlineUserDto; |
|||
import com.storeroom.utils.*; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.data.domain.Pageable; |
|||
import org.springframework.scheduling.annotation.Async; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import javax.servlet.http.HttpServletRequest; |
|||
import javax.servlet.http.HttpServletResponse; |
|||
import java.io.IOException; |
|||
import java.util.*; |
|||
|
|||
@Service |
|||
@Slf4j |
|||
public class OnlineUserService { |
|||
|
|||
private final SecurityProperties properties; |
|||
private final RedisUtils redisUtils; |
|||
|
|||
public OnlineUserService(SecurityProperties properties, RedisUtils redisUtils) { |
|||
this.properties = properties; |
|||
this.redisUtils = redisUtils; |
|||
} |
|||
|
|||
/** |
|||
* 保存早先用户 |
|||
* @param jwtUserDto / |
|||
* @param token / |
|||
* @param request / |
|||
*/ |
|||
public void save(JwtUserDto jwtUserDto, String token, HttpServletRequest request){ |
|||
String dept = jwtUserDto.getUser().getDept().getName(); |
|||
String ip = StringUtils.getIp(request); |
|||
String browser = StringUtils.getBrowser(request); |
|||
String address = StringUtils.getCityInfo(ip); |
|||
OnlineUserDto onlineUserDto = null; |
|||
try { |
|||
onlineUserDto = new OnlineUserDto(jwtUserDto.getUsername(), jwtUserDto.getUser().getNickName(), dept, browser , ip, address, EncryptUtils.desEncrypt(token), new Date()); |
|||
} catch (Exception e) { |
|||
log.error(e.getMessage(),e); |
|||
} |
|||
redisUtils.set(properties.getOnlineKey() + token, onlineUserDto, properties.getTokenValidityInSeconds()/1000); |
|||
} |
|||
|
|||
/** |
|||
* 查询全部数据 |
|||
* @param filter / |
|||
* @param pageable / |
|||
* @return / |
|||
*/ |
|||
public Map<String,Object> getAll(String filter, Pageable pageable){ |
|||
List<OnlineUserDto> onlineUserDtos = getAll(filter); |
|||
return PageUtil.toPage( |
|||
PageUtil.toPage(pageable.getPageNumber(),pageable.getPageSize(), onlineUserDtos), |
|||
onlineUserDtos.size() |
|||
); |
|||
} |
|||
|
|||
/** |
|||
* 查询全部数据,不分页 |
|||
* @param filter / |
|||
* @return / |
|||
*/ |
|||
public List<OnlineUserDto> getAll(String filter){ |
|||
List<String> keys = redisUtils.scan(properties.getOnlineKey() + "*"); |
|||
Collections.reverse(keys); |
|||
List<OnlineUserDto> onlineUserDtos = new ArrayList<>(); |
|||
for (String key : keys) { |
|||
OnlineUserDto onlineUserDto = (OnlineUserDto) redisUtils.get(key); |
|||
if(StringUtils.isNotBlank(filter)){ |
|||
if(onlineUserDto.toString().contains(filter)){ |
|||
onlineUserDtos.add(onlineUserDto); |
|||
} |
|||
} else { |
|||
onlineUserDtos.add(onlineUserDto); |
|||
} |
|||
} |
|||
onlineUserDtos.sort((o1, o2) -> o2.getLoginTime().compareTo(o1.getLoginTime())); |
|||
return onlineUserDtos; |
|||
} |
|||
|
|||
/** |
|||
* 踢出用户 |
|||
* @param key / |
|||
*/ |
|||
public void kickOut(String key){ |
|||
key = properties.getOnlineKey() + key; |
|||
redisUtils.del(key); |
|||
} |
|||
|
|||
/** |
|||
* 退出登录 |
|||
* @param token / |
|||
*/ |
|||
public void logout(String token) { |
|||
String key = properties.getOnlineKey() + token; |
|||
redisUtils.del(key); |
|||
} |
|||
|
|||
/** |
|||
* 导出 |
|||
* @param all / |
|||
* @param response / |
|||
* @throws IOException / |
|||
*/ |
|||
public void download(List<OnlineUserDto> all, HttpServletResponse response) throws IOException { |
|||
List<Map<String, Object>> list = new ArrayList<>(); |
|||
for (OnlineUserDto user : all) { |
|||
Map<String,Object> map = new LinkedHashMap<>(); |
|||
map.put("用户名", user.getUserName()); |
|||
map.put("部门", user.getDept()); |
|||
map.put("登录IP", user.getIp()); |
|||
map.put("登录地点", user.getAddress()); |
|||
map.put("浏览器", user.getBrowser()); |
|||
map.put("登录日期", user.getLoginTime()); |
|||
list.add(map); |
|||
} |
|||
FileUtil.downloadExcel(list, response); |
|||
} |
|||
|
|||
/** |
|||
* 查询用户 |
|||
* @param key / |
|||
* @return / |
|||
*/ |
|||
public OnlineUserDto getOne(String key) { |
|||
return (OnlineUserDto)redisUtils.get(key); |
|||
} |
|||
|
|||
/** |
|||
* 检测用户是否在之前已经登录,已经登录踢下线 |
|||
* @param userName 用户名 |
|||
*/ |
|||
public void checkLoginOnUser(String userName, String igoreToken){ |
|||
List<OnlineUserDto> onlineUserDtos = getAll(userName); |
|||
if(onlineUserDtos ==null || onlineUserDtos.isEmpty()){ |
|||
return; |
|||
} |
|||
for(OnlineUserDto onlineUserDto : onlineUserDtos){ |
|||
if(onlineUserDto.getUserName().equals(userName)){ |
|||
try { |
|||
String token =EncryptUtils.desDecrypt(onlineUserDto.getKey()); |
|||
if(StringUtils.isNotBlank(igoreToken)&&!igoreToken.equals(token)){ |
|||
this.kickOut(token); |
|||
}else if(StringUtils.isBlank(igoreToken)){ |
|||
this.kickOut(token); |
|||
} |
|||
} catch (Exception e) { |
|||
log.error("checkUser is error",e); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 根据用户名强退用户 |
|||
* @param username / |
|||
*/ |
|||
@Async |
|||
public void kickOutForUsername(String username) { |
|||
List<OnlineUserDto> onlineUsers = getAll(username); |
|||
for (OnlineUserDto onlineUser : onlineUsers) { |
|||
if (onlineUser.getUserName().equals(username)) { |
|||
kickOut(onlineUser.getKey()); |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,29 @@ |
|||
package com.storeroom.modules.security.service; |
|||
|
|||
|
|||
import com.storeroom.utils.StringUtils; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
@Component |
|||
public class UserCacheClean { |
|||
|
|||
/** |
|||
* 清理特定用户缓存信息 |
|||
* 用户信息变更时 |
|||
* |
|||
* @param userName |
|||
*/ |
|||
public void cleanUserCache(String userName) { |
|||
if (StringUtils.isNotEmpty(userName)) { |
|||
UserDetailsServiceImpl.userDtoCache.remove(userName); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 清理所有用户的缓存信息 |
|||
* ,如发生角色授权信息变化,可以简便的全部失效缓存 |
|||
*/ |
|||
public void cleanAll() { |
|||
UserDetailsServiceImpl.userDtoCache.clear(); |
|||
} |
|||
} |
@ -0,0 +1,72 @@ |
|||
package com.storeroom.modules.security.service; |
|||
|
|||
import com.storeroom.exception.BaseException; |
|||
import com.storeroom.modules.security.config.bean.LoginProperties; |
|||
import com.storeroom.modules.security.service.dto.JwtUserDto; |
|||
import com.storeroom.modules.system.service.DataService; |
|||
import com.storeroom.modules.system.service.RoleService; |
|||
import com.storeroom.modules.system.service.UserService; |
|||
import com.storeroom.modules.system.service.dto.UserDto; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.security.core.userdetails.UserDetailsService; |
|||
import org.springframework.security.core.userdetails.UsernameNotFoundException; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import javax.persistence.EntityNotFoundException; |
|||
import java.util.Map; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
|
|||
|
|||
@RequiredArgsConstructor |
|||
@Service("userDetailsService") |
|||
public class UserDetailsServiceImpl implements UserDetailsService { |
|||
private final UserService userService; |
|||
private final RoleService roleService; |
|||
private final DataService dataService; |
|||
private final LoginProperties loginProperties; |
|||
|
|||
public void setEnableCache(boolean enableCache) { |
|||
this.loginProperties.setCacheEnable(enableCache); |
|||
} |
|||
|
|||
/** |
|||
* 用户信息缓存 |
|||
* |
|||
* @see {@link UserCacheClean} |
|||
*/ |
|||
static Map<String, JwtUserDto> userDtoCache = new ConcurrentHashMap<>(); |
|||
|
|||
|
|||
@Override |
|||
public JwtUserDto loadUserByUsername(String username) { |
|||
boolean searchDb = true; |
|||
JwtUserDto jwtUserDto = null; |
|||
if (loginProperties.isCacheEnable() && userDtoCache.containsKey(username)) { |
|||
jwtUserDto = userDtoCache.get(username); |
|||
searchDb = false; |
|||
} |
|||
if (searchDb) { |
|||
UserDto user; |
|||
try { |
|||
user = userService.findByName(username); |
|||
} catch (EntityNotFoundException e) { |
|||
// SpringSecurity会自动转换UsernameNotFoundException为BadCredentialsException |
|||
throw new UsernameNotFoundException("", e); |
|||
} |
|||
if (user == null) { |
|||
throw new UsernameNotFoundException(""); |
|||
} else { |
|||
if (!user.getEnabled()) { |
|||
throw new BaseException("账号未激活!"); |
|||
} |
|||
jwtUserDto = new JwtUserDto( |
|||
user, |
|||
dataService.getDeptIds(user), |
|||
roleService.mapToGrantedAuthorities(user) |
|||
); |
|||
userDtoCache.put(username, jwtUserDto); |
|||
} |
|||
} |
|||
return jwtUserDto; |
|||
} |
|||
} |
@ -0,0 +1,16 @@ |
|||
package com.storeroom.modules.security.service.dto; |
|||
|
|||
import javax.validation.constraints.NotBlank; |
|||
|
|||
public class AuthUserDto { |
|||
|
|||
@NotBlank |
|||
private String username; |
|||
|
|||
@NotBlank |
|||
private String password; |
|||
|
|||
private String code; |
|||
|
|||
private String uuid = ""; |
|||
} |
@ -0,0 +1,65 @@ |
|||
package com.storeroom.modules.security.service.dto; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonIgnore; |
|||
import com.storeroom.modules.system.service.dto.UserDto; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Getter; |
|||
import org.springframework.security.core.GrantedAuthority; |
|||
import org.springframework.security.core.userdetails.UserDetails; |
|||
|
|||
import java.util.List; |
|||
import java.util.Set; |
|||
import java.util.stream.Collectors; |
|||
|
|||
|
|||
@Getter |
|||
@AllArgsConstructor |
|||
public class JwtUserDto implements UserDetails { |
|||
|
|||
private final UserDto user; |
|||
|
|||
private final List<Long> dataScopes; |
|||
|
|||
@JsonIgnore |
|||
private final List<GrantedAuthority> authorities; |
|||
|
|||
public Set<String> getRoles() { |
|||
return authorities.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet()); |
|||
} |
|||
|
|||
@Override |
|||
@JsonIgnore |
|||
public String getPassword() { |
|||
return user.getPassword(); |
|||
} |
|||
|
|||
@Override |
|||
@JsonIgnore |
|||
public String getUsername() { |
|||
return user.getUsername(); |
|||
} |
|||
|
|||
@JsonIgnore |
|||
@Override |
|||
public boolean isAccountNonExpired() { |
|||
return true; |
|||
} |
|||
|
|||
@JsonIgnore |
|||
@Override |
|||
public boolean isAccountNonLocked() { |
|||
return true; |
|||
} |
|||
|
|||
@JsonIgnore |
|||
@Override |
|||
public boolean isCredentialsNonExpired() { |
|||
return true; |
|||
} |
|||
|
|||
@Override |
|||
@JsonIgnore |
|||
public boolean isEnabled() { |
|||
return user.getEnabled(); |
|||
} |
|||
} |
@ -0,0 +1,54 @@ |
|||
package com.storeroom.modules.security.service.dto; |
|||
|
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
|
|||
import java.util.Date; |
|||
|
|||
@Data |
|||
@AllArgsConstructor |
|||
@NoArgsConstructor |
|||
public class OnlineUserDto { |
|||
|
|||
/** |
|||
* 用户名 |
|||
*/ |
|||
private String userName; |
|||
|
|||
/** |
|||
* 昵称 |
|||
*/ |
|||
private String nickName; |
|||
|
|||
/** |
|||
* 岗位 |
|||
*/ |
|||
private String dept; |
|||
|
|||
/** |
|||
* 浏览器 |
|||
*/ |
|||
private String browser; |
|||
|
|||
/** |
|||
* IP |
|||
*/ |
|||
private String ip; |
|||
|
|||
/** |
|||
* 地址 |
|||
*/ |
|||
private String address; |
|||
|
|||
/** |
|||
* token |
|||
*/ |
|||
private String key; |
|||
|
|||
/** |
|||
* 登录时间 |
|||
*/ |
|||
private Date loginTime; |
|||
} |
@ -0,0 +1,69 @@ |
|||
package com.storeroom.modules.system.domain; |
|||
|
|||
|
|||
import com.alibaba.fastjson.annotation.JSONField; |
|||
import com.storeroom.base.BaseEntity; |
|||
import io.swagger.annotations.ApiModelProperty; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
import javax.persistence.*; |
|||
import javax.validation.constraints.NotBlank; |
|||
import javax.validation.constraints.NotNull; |
|||
import java.io.Serializable; |
|||
import java.util.Objects; |
|||
import java.util.Set; |
|||
|
|||
@Entity |
|||
@Getter |
|||
@Setter |
|||
@Table(name="sys_dept") |
|||
public class Dept extends BaseEntity implements Serializable { |
|||
|
|||
@Id |
|||
@Column(name = "dept_id") |
|||
@NotNull(groups = Update.class) |
|||
@ApiModelProperty(value = "ID", hidden = true) |
|||
@GeneratedValue(strategy = GenerationType.IDENTITY) |
|||
private Long id; |
|||
|
|||
@JSONField(serialize = false) |
|||
@ManyToMany(mappedBy = "depts") |
|||
@ApiModelProperty(value = "角色") |
|||
private Set<Role> roles; |
|||
|
|||
@ApiModelProperty(value = "排序") |
|||
private Integer deptSort; |
|||
|
|||
@NotBlank |
|||
@ApiModelProperty(value = "部门名称") |
|||
private String name; |
|||
|
|||
@NotNull |
|||
@ApiModelProperty(value = "是否启用") |
|||
private Boolean enabled; |
|||
|
|||
@ApiModelProperty(value = "上级部门") |
|||
private Long pid; |
|||
|
|||
@ApiModelProperty(value = "子节点数目", hidden = true) |
|||
private Integer subCount = 0; |
|||
|
|||
@Override |
|||
public boolean equals(Object o) { |
|||
if (this == o) { |
|||
return true; |
|||
} |
|||
if (o == null || getClass() != o.getClass()) { |
|||
return false; |
|||
} |
|||
Dept dept = (Dept) o; |
|||
return Objects.equals(id, dept.id) && |
|||
Objects.equals(name, dept.name); |
|||
} |
|||
|
|||
@Override |
|||
public int hashCode() { |
|||
return Objects.hash(id, name); |
|||
} |
|||
} |
@ -0,0 +1,36 @@ |
|||
package com.storeroom.modules.system.domain; |
|||
|
|||
import com.storeroom.base.BaseEntity; |
|||
import io.swagger.annotations.ApiModelProperty; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
import javax.persistence.*; |
|||
import javax.validation.constraints.NotBlank; |
|||
import javax.validation.constraints.NotNull; |
|||
import java.io.Serializable; |
|||
import java.util.List; |
|||
|
|||
@Entity |
|||
@Getter |
|||
@Setter |
|||
@Table(name="sys_dict") |
|||
public class Dict extends BaseEntity implements Serializable { |
|||
|
|||
@Id |
|||
@Column(name = "dict_id") |
|||
@NotNull(groups = Update.class) |
|||
@ApiModelProperty(value = "ID", hidden = true) |
|||
@GeneratedValue(strategy = GenerationType.IDENTITY) |
|||
private Long id; |
|||
|
|||
@OneToMany(mappedBy = "dict",cascade={CascadeType.PERSIST,CascadeType.REMOVE}) |
|||
private List<DictDetail> dictDetails; |
|||
|
|||
@NotBlank |
|||
@ApiModelProperty(value = "名称") |
|||
private String name; |
|||
|
|||
@ApiModelProperty(value = "描述") |
|||
private String description; |
|||
} |
@ -0,0 +1,40 @@ |
|||
package com.storeroom.modules.system.domain; |
|||
|
|||
import com.storeroom.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; |
|||
|
|||
|
|||
@Entity |
|||
@Getter |
|||
@Setter |
|||
@Table(name="sys_dict_detail") |
|||
public class DictDetail extends BaseEntity implements Serializable { |
|||
|
|||
@Id |
|||
@Column(name = "detail_id") |
|||
@NotNull(groups = Update.class) |
|||
@ApiModelProperty(value = "ID", hidden = true) |
|||
@GeneratedValue(strategy = GenerationType.IDENTITY) |
|||
private Long id; |
|||
|
|||
@JoinColumn(name = "dict_id") |
|||
@ManyToOne(fetch=FetchType.LAZY) |
|||
@ApiModelProperty(value = "字典", hidden = true) |
|||
private Dict dict; |
|||
|
|||
@ApiModelProperty(value = "字典标签") |
|||
private String label; |
|||
|
|||
@ApiModelProperty(value = "字典值") |
|||
private String value; |
|||
|
|||
@ApiModelProperty(value = "排序") |
|||
private Integer dictSort = 999; |
|||
|
|||
} |
@ -0,0 +1,56 @@ |
|||
package com.storeroom.modules.system.domain; |
|||
|
|||
import com.storeroom.base.BaseEntity; |
|||
import io.swagger.annotations.ApiModelProperty; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
import javax.persistence.*; |
|||
import javax.validation.constraints.NotBlank; |
|||
import javax.validation.constraints.NotNull; |
|||
import java.io.Serializable; |
|||
import java.util.Objects; |
|||
|
|||
|
|||
@Entity |
|||
@Getter |
|||
@Setter |
|||
@Table(name="sys_job") |
|||
public class Job extends BaseEntity implements Serializable { |
|||
|
|||
@Id |
|||
@Column(name = "job_id") |
|||
@NotNull(groups = Update.class) |
|||
@ApiModelProperty(value = "ID", hidden = true) |
|||
@GeneratedValue(strategy = GenerationType.IDENTITY) |
|||
private Long id; |
|||
|
|||
@NotBlank |
|||
@ApiModelProperty(value = "岗位名称") |
|||
private String name; |
|||
|
|||
@NotNull |
|||
@ApiModelProperty(value = "岗位排序") |
|||
private Long jobSort; |
|||
|
|||
@NotNull |
|||
@ApiModelProperty(value = "是否启用") |
|||
private Boolean enabled; |
|||
|
|||
@Override |
|||
public boolean equals(Object o) { |
|||
if (this == o) { |
|||
return true; |
|||
} |
|||
if (o == null || getClass() != o.getClass()) { |
|||
return false; |
|||
} |
|||
Job job = (Job) o; |
|||
return Objects.equals(id, job.id); |
|||
} |
|||
|
|||
@Override |
|||
public int hashCode() { |
|||
return Objects.hash(id); |
|||
} |
|||
} |
@ -0,0 +1,92 @@ |
|||
package com.storeroom.modules.system.domain; |
|||
|
|||
import com.alibaba.fastjson.annotation.JSONField; |
|||
import com.storeroom.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; |
|||
import java.util.Set; |
|||
|
|||
|
|||
@Entity |
|||
@Getter |
|||
@Setter |
|||
@Table(name = "sys_menu") |
|||
public class Menu extends BaseEntity implements Serializable { |
|||
|
|||
@Id |
|||
@Column(name = "menu_id") |
|||
@NotNull(groups = {Update.class}) |
|||
@ApiModelProperty(value = "ID", hidden = true) |
|||
@GeneratedValue(strategy = GenerationType.IDENTITY) |
|||
private Long id; |
|||
|
|||
@JSONField(serialize = false) |
|||
@ManyToMany(mappedBy = "menus") |
|||
@ApiModelProperty(value = "菜单角色") |
|||
private Set<Role> roles; |
|||
|
|||
@ApiModelProperty(value = "菜单标题") |
|||
private String title; |
|||
|
|||
@Column(name = "name") |
|||
@ApiModelProperty(value = "菜单组件名称") |
|||
private String componentName; |
|||
|
|||
@ApiModelProperty(value = "排序") |
|||
private Integer menuSort = 999; |
|||
|
|||
@ApiModelProperty(value = "组件路径") |
|||
private String component; |
|||
|
|||
@ApiModelProperty(value = "路由地址") |
|||
private String path; |
|||
|
|||
@ApiModelProperty(value = "菜单类型,目录、菜单、按钮") |
|||
private Integer type; |
|||
|
|||
@ApiModelProperty(value = "权限标识") |
|||
private String permission; |
|||
|
|||
@ApiModelProperty(value = "菜单图标") |
|||
private String icon; |
|||
|
|||
@Column(columnDefinition = "bit(1) default 0") |
|||
@ApiModelProperty(value = "缓存") |
|||
private Boolean cache; |
|||
|
|||
@Column(columnDefinition = "bit(1) default 0") |
|||
@ApiModelProperty(value = "是否隐藏") |
|||
private Boolean hidden; |
|||
|
|||
@ApiModelProperty(value = "上级菜单") |
|||
private Long pid; |
|||
|
|||
@ApiModelProperty(value = "子节点数目", hidden = true) |
|||
private Integer subCount = 0; |
|||
|
|||
@ApiModelProperty(value = "外链菜单") |
|||
private Boolean iFrame; |
|||
|
|||
@Override |
|||
public boolean equals(Object o) { |
|||
if (this == o) { |
|||
return true; |
|||
} |
|||
if (o == null || getClass() != o.getClass()) { |
|||
return false; |
|||
} |
|||
Menu menu = (Menu) o; |
|||
return Objects.equals(id, menu.id); |
|||
} |
|||
|
|||
@Override |
|||
public int hashCode() { |
|||
return Objects.hash(id); |
|||
} |
|||
} |
@ -0,0 +1,79 @@ |
|||
package com.storeroom.modules.system.domain; |
|||
|
|||
import com.alibaba.fastjson.annotation.JSONField; |
|||
import com.storeroom.base.BaseEntity; |
|||
import com.storeroom.utils.enums.DataScopeEnum; |
|||
import io.swagger.annotations.ApiModelProperty; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
import javax.persistence.*; |
|||
import javax.validation.constraints.NotBlank; |
|||
import javax.validation.constraints.NotNull; |
|||
import java.io.Serializable; |
|||
import java.util.Objects; |
|||
import java.util.Set; |
|||
|
|||
|
|||
@Getter |
|||
@Setter |
|||
@Entity |
|||
@Table(name = "sys_role") |
|||
public class Role extends BaseEntity implements Serializable { |
|||
@Id |
|||
@Column(name = "role_id") |
|||
@NotNull(groups = {Update.class}) |
|||
@GeneratedValue(strategy = GenerationType.IDENTITY) |
|||
@ApiModelProperty(value = "ID", hidden = true) |
|||
private Long id; |
|||
|
|||
@JSONField(serialize = false) |
|||
@ManyToMany(mappedBy = "roles") |
|||
@ApiModelProperty(value = "用户", hidden = true) |
|||
private Set<User> users; |
|||
|
|||
@ManyToMany(fetch = FetchType.EAGER) |
|||
@JoinTable(name = "sys_roles_menus", |
|||
joinColumns = {@JoinColumn(name = "role_id",referencedColumnName = "role_id")}, |
|||
inverseJoinColumns = {@JoinColumn(name = "menu_id",referencedColumnName = "menu_id")}) |
|||
@ApiModelProperty(value = "菜单", hidden = true) |
|||
private Set<Menu> menus; |
|||
|
|||
@ManyToMany |
|||
@JoinTable(name = "sys_roles_depts", |
|||
joinColumns = {@JoinColumn(name = "role_id",referencedColumnName = "role_id")}, |
|||
inverseJoinColumns = {@JoinColumn(name = "dept_id",referencedColumnName = "dept_id")}) |
|||
@ApiModelProperty(value = "部门", hidden = true) |
|||
private Set<Dept> depts; |
|||
|
|||
@NotBlank |
|||
@ApiModelProperty(value = "名称", hidden = true) |
|||
private String name; |
|||
|
|||
@ApiModelProperty(value = "数据权限,全部 、 本级 、 自定义") |
|||
private String dataScope = DataScopeEnum.THIS_LEVEL.getValue(); |
|||
|
|||
@Column(name = "level") |
|||
@ApiModelProperty(value = "级别,数值越小,级别越大") |
|||
private Integer level = 3; |
|||
|
|||
@ApiModelProperty(value = "描述") |
|||
private String description; |
|||
|
|||
@Override |
|||
public boolean equals(Object o) { |
|||
if (this == o) { |
|||
return true; |
|||
} |
|||
if (o == null || getClass() != o.getClass()) { |
|||
return false; |
|||
} |
|||
Role role = (Role) o; |
|||
return Objects.equals(id, role.id); |
|||
} |
|||
|
|||
@Override |
|||
public int hashCode() { |
|||
return Objects.hash(id); |
|||
} |
|||
} |
@ -0,0 +1,108 @@ |
|||
package com.storeroom.modules.system.domain; |
|||
|
|||
|
|||
import com.storeroom.base.BaseEntity; |
|||
import io.swagger.annotations.ApiModelProperty; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
import javax.persistence.*; |
|||
import javax.validation.constraints.Email; |
|||
import javax.validation.constraints.NotBlank; |
|||
import javax.validation.constraints.NotNull; |
|||
import java.io.Serializable; |
|||
import java.util.Date; |
|||
import java.util.Objects; |
|||
import java.util.Set; |
|||
|
|||
@Entity |
|||
@Getter |
|||
@Setter |
|||
@Table(name="sys_user") |
|||
public class User extends BaseEntity implements Serializable { |
|||
|
|||
@Id |
|||
@Column(name = "user_id") |
|||
@NotNull(groups = Update.class) |
|||
@GeneratedValue(strategy = GenerationType.IDENTITY) |
|||
@ApiModelProperty(value = "ID", hidden = true) |
|||
private Long id; |
|||
|
|||
@ManyToMany(fetch = FetchType.EAGER) |
|||
@ApiModelProperty(value = "用户角色") |
|||
@JoinTable(name = "sys_users_roles", |
|||
joinColumns = {@JoinColumn(name = "user_id",referencedColumnName = "user_id")}, |
|||
inverseJoinColumns = {@JoinColumn(name = "role_id",referencedColumnName = "role_id")}) |
|||
private Set<Role> roles; |
|||
|
|||
@ManyToMany(fetch = FetchType.EAGER) |
|||
@ApiModelProperty(value = "用户岗位") |
|||
@JoinTable(name = "sys_users_jobs", |
|||
joinColumns = {@JoinColumn(name = "user_id",referencedColumnName = "user_id")}, |
|||
inverseJoinColumns = {@JoinColumn(name = "job_id",referencedColumnName = "job_id")}) |
|||
private Set<Job> jobs; |
|||
|
|||
@OneToOne |
|||
@JoinColumn(name = "dept_id") |
|||
@ApiModelProperty(value = "用户部门") |
|||
private Dept dept; |
|||
|
|||
@NotBlank |
|||
@Column(unique = true) |
|||
@ApiModelProperty(value = "用户名称") |
|||
private String username; |
|||
|
|||
@NotBlank |
|||
@ApiModelProperty(value = "用户昵称") |
|||
private String nickName; |
|||
|
|||
@Email |
|||
@NotBlank |
|||
@ApiModelProperty(value = "邮箱") |
|||
private String email; |
|||
|
|||
@NotBlank |
|||
@ApiModelProperty(value = "电话号码") |
|||
private String phone; |
|||
|
|||
@ApiModelProperty(value = "用户性别") |
|||
private String gender; |
|||
|
|||
@ApiModelProperty(value = "头像真实名称",hidden = true) |
|||
private String avatarName; |
|||
|
|||
@ApiModelProperty(value = "头像存储的路径", hidden = true) |
|||
private String avatarPath; |
|||
|
|||
@ApiModelProperty(value = "密码") |
|||
private String password; |
|||
|
|||
@NotNull |
|||
@ApiModelProperty(value = "是否启用") |
|||
private Boolean enabled; |
|||
|
|||
@ApiModelProperty(value = "是否为admin账号", hidden = true) |
|||
private Boolean isAdmin = false; |
|||
|
|||
@Column(name = "pwd_reset_time") |
|||
@ApiModelProperty(value = "最后修改密码的时间", hidden = true) |
|||
private Date pwdResetTime; |
|||
|
|||
@Override |
|||
public boolean equals(Object o) { |
|||
if (this == o) { |
|||
return true; |
|||
} |
|||
if (o == null || getClass() != o.getClass()) { |
|||
return false; |
|||
} |
|||
User user = (User) o; |
|||
return Objects.equals(id, user.id) && |
|||
Objects.equals(username, user.username); |
|||
} |
|||
|
|||
@Override |
|||
public int hashCode() { |
|||
return Objects.hash(id, username); |
|||
} |
|||
} |
@ -0,0 +1,18 @@ |
|||
package com.storeroom.modules.system.domain.vo; |
|||
|
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Data; |
|||
|
|||
import java.io.Serializable; |
|||
|
|||
|
|||
@Data |
|||
@AllArgsConstructor |
|||
public class MenuMetaVo implements Serializable { |
|||
|
|||
private String title; |
|||
|
|||
private String icon; |
|||
|
|||
private Boolean noCache; |
|||
} |
@ -0,0 +1,29 @@ |
|||
package com.storeroom.modules.system.domain.vo; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonInclude; |
|||
import lombok.Data; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.List; |
|||
|
|||
|
|||
@Data |
|||
@JsonInclude(JsonInclude.Include.NON_EMPTY) |
|||
public class MenuVo implements Serializable { |
|||
|
|||
private String name; |
|||
|
|||
private String path; |
|||
|
|||
private Boolean hidden; |
|||
|
|||
private String redirect; |
|||
|
|||
private String component; |
|||
|
|||
private Boolean alwaysShow; |
|||
|
|||
private MenuMetaVo meta; |
|||
|
|||
private List<MenuVo> children; |
|||
} |
@ -0,0 +1,15 @@ |
|||
package com.storeroom.modules.system.domain.vo; |
|||
|
|||
|
|||
import lombok.Data; |
|||
|
|||
/** |
|||
* 修改密码的 VO 类 |
|||
*/ |
|||
@Data |
|||
public class UserPassVo { |
|||
|
|||
private String oldPass; |
|||
|
|||
private String newPass; |
|||
} |
@ -0,0 +1,51 @@ |
|||
package com.storeroom.modules.system.repository; |
|||
|
|||
import com.storeroom.modules.system.domain.Dept; |
|||
import org.springframework.data.jpa.repository.JpaRepository; |
|||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; |
|||
import org.springframework.data.jpa.repository.Modifying; |
|||
import org.springframework.data.jpa.repository.Query; |
|||
|
|||
import java.util.List; |
|||
import java.util.Set; |
|||
|
|||
public interface DeptRepository extends JpaRepository<Dept, Long>, JpaSpecificationExecutor<Dept> { |
|||
|
|||
/** |
|||
* 根据 PID 查询 |
|||
* @param id pid |
|||
* @return / |
|||
*/ |
|||
List<Dept> findByPid(Long id); |
|||
|
|||
/** |
|||
* 获取顶级部门 |
|||
* @return / |
|||
*/ |
|||
List<Dept> findByPidIsNull(); |
|||
|
|||
/** |
|||
* 根据角色ID 查询 |
|||
* @param roleId 角色ID |
|||
* @return / |
|||
*/ |
|||
@Query(value = "select d.* from sys_dept d, sys_roles_depts r where " + |
|||
"d.dept_id = r.dept_id and r.role_id = ?1", nativeQuery = true) |
|||
Set<Dept> findByRoleId(Long roleId); |
|||
|
|||
/** |
|||
* 判断是否存在子节点 |
|||
* @param pid / |
|||
* @return / |
|||
*/ |
|||
int countByPid(Long pid); |
|||
|
|||
/** |
|||
* 根据ID更新sub_count |
|||
* @param count / |
|||
* @param id / |
|||
*/ |
|||
@Modifying |
|||
@Query(value = " update sys_dept set sub_count = ?1 where dept_id = ?2 ",nativeQuery = true) |
|||
void updateSubCntById(Integer count, Long id); |
|||
} |
@ -0,0 +1,24 @@ |
|||
package com.storeroom.modules.system.repository; |
|||
|
|||
import cn.hutool.core.lang.Dict; |
|||
import org.springframework.data.jpa.repository.JpaRepository; |
|||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; |
|||
|
|||
import java.util.List; |
|||
import java.util.Set; |
|||
|
|||
public interface DictRepository extends JpaRepository<Dict, Long>, JpaSpecificationExecutor<Dict> { |
|||
|
|||
/** |
|||
* 删除 |
|||
* @param ids / |
|||
*/ |
|||
void deleteByIdIn(Set<Long> ids); |
|||
|
|||
/** |
|||
* 查询 |
|||
* @param ids / |
|||
* @return / |
|||
*/ |
|||
List<Dict> findByIdIn(Set<Long> ids); |
|||
} |
@ -0,0 +1,23 @@ |
|||
package com.storeroom.modules.system.repository; |
|||
|
|||
import com.storeroom.modules.system.domain.Job; |
|||
import org.springframework.data.jpa.repository.JpaRepository; |
|||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; |
|||
|
|||
import java.util.Set; |
|||
|
|||
public interface JobRepository extends JpaRepository<Job, Long>, JpaSpecificationExecutor<Job> { |
|||
|
|||
/** |
|||
* 根据名称查询 |
|||
* @param name 名称 |
|||
* @return / |
|||
*/ |
|||
Job findByName(String name); |
|||
|
|||
/** |
|||
* 根据Id删除 |
|||
* @param ids / |
|||
*/ |
|||
void deleteAllByIdIn(Set<Long> ids); |
|||
} |
@ -0,0 +1,69 @@ |
|||
package com.storeroom.modules.system.repository; |
|||
|
|||
import com.storeroom.modules.system.domain.Menu; |
|||
import org.springframework.data.jpa.repository.JpaRepository; |
|||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; |
|||
import org.springframework.data.jpa.repository.Modifying; |
|||
import org.springframework.data.jpa.repository.Query; |
|||
|
|||
import java.util.LinkedHashSet; |
|||
import java.util.List; |
|||
import java.util.Set; |
|||
|
|||
|
|||
|
|||
public interface MenuRepository extends JpaRepository<Menu, Long>, JpaSpecificationExecutor<Menu> { |
|||
|
|||
/** |
|||
* 根据菜单标题查询 |
|||
* @param title 菜单标题 |
|||
* @return / |
|||
*/ |
|||
Menu findByTitle(String title); |
|||
|
|||
/** |
|||
* 根据组件名称查询 |
|||
* @param name 组件名称 |
|||
* @return / |
|||
*/ |
|||
Menu findByComponentName(String name); |
|||
|
|||
/** |
|||
* 根据菜单的 PID 查询 |
|||
* @param pid / |
|||
* @return / |
|||
*/ |
|||
List<Menu> findByPid(long pid); |
|||
|
|||
/** |
|||
* 查询顶级菜单 |
|||
* @return / |
|||
*/ |
|||
List<Menu> findByPidIsNull(); |
|||
|
|||
/** |
|||
* 根据角色ID与菜单类型查询菜单 |
|||
* @param roleIds roleIDs |
|||
* @param type 类型 |
|||
* @return / |
|||
*/ |
|||
@Query(value = "SELECT m.* FROM sys_menu m, sys_roles_menus r WHERE " + |
|||
"m.menu_id = r.menu_id AND r.role_id IN ?1 AND type != ?2 order by m.menu_sort asc",nativeQuery = true) |
|||
LinkedHashSet<Menu> findByRoleIdsAndTypeNot(Set<Long> roleIds, int type); |
|||
|
|||
/** |
|||
* 获取节点数量 |
|||
* @param id / |
|||
* @return / |
|||
*/ |
|||
int countByPid(Long id); |
|||
|
|||
/** |
|||
* 更新节点数目 |
|||
* @param count / |
|||
* @param menuId / |
|||
*/ |
|||
@Modifying |
|||
@Query(value = " update sys_menu set sub_count = ?1 where menu_id = ?2 ",nativeQuery = true) |
|||
void updateSubCntById(int count, Long menuId); |
|||
} |
@ -0,0 +1,61 @@ |
|||
package com.storeroom.modules.system.repository; |
|||
|
|||
import com.storeroom.modules.system.domain.Role; |
|||
import org.springframework.data.jpa.repository.JpaRepository; |
|||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; |
|||
import org.springframework.data.jpa.repository.Modifying; |
|||
import org.springframework.data.jpa.repository.Query; |
|||
|
|||
import java.util.List; |
|||
import java.util.Set; |
|||
|
|||
public interface RoleRepository extends JpaRepository<Role, Long>, JpaSpecificationExecutor<Role> { |
|||
|
|||
/** |
|||
* 根据名称查询 |
|||
* @param name / |
|||
* @return / |
|||
*/ |
|||
Role findByName(String name); |
|||
|
|||
/** |
|||
* 删除多个角色 |
|||
* @param ids / |
|||
*/ |
|||
void deleteAllByIdIn(Set<Long> ids); |
|||
|
|||
/** |
|||
* 根据用户ID查询 |
|||
* @param id 用户ID |
|||
* @return / |
|||
*/ |
|||
@Query(value = "SELECT r.* FROM sys_role r, sys_users_roles u WHERE " + |
|||
"r.role_id = u.role_id AND u.user_id = ?1",nativeQuery = true) |
|||
Set<Role> findByUserId(Long id); |
|||
|
|||
/** |
|||
* 解绑角色菜单 |
|||
* @param id 菜单ID |
|||
*/ |
|||
@Modifying |
|||
@Query(value = "delete from sys_roles_menus where menu_id = ?1",nativeQuery = true) |
|||
void untiedMenu(Long id); |
|||
|
|||
/** |
|||
* 根据部门查询 |
|||
* @param deptIds / |
|||
* @return / |
|||
*/ |
|||
@Query(value = "select count(1) from sys_role r, sys_roles_depts d where " + |
|||
"r.role_id = d.role_id and d.dept_id in ?1",nativeQuery = true) |
|||
int countByDepts(Set<Long> deptIds); |
|||
|
|||
/** |
|||
* 根据菜单Id查询 |
|||
* @param menuIds / |
|||
* @return / |
|||
*/ |
|||
@Query(value = "SELECT r.* FROM sys_role r, sys_roles_menus m WHERE " + |
|||
"r.role_id = m.role_id AND m.menu_id in ?1",nativeQuery = true) |
|||
List<Role> findInMenuId(List<Long> menuIds); |
|||
} |
@ -0,0 +1,112 @@ |
|||
package com.storeroom.modules.system.repository; |
|||
|
|||
import com.storeroom.modules.system.domain.User; |
|||
import org.springframework.data.jpa.repository.JpaRepository; |
|||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; |
|||
import org.springframework.data.jpa.repository.Modifying; |
|||
import org.springframework.data.jpa.repository.Query; |
|||
|
|||
import java.util.Date; |
|||
import java.util.List; |
|||
import java.util.Set; |
|||
|
|||
public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> { |
|||
|
|||
/** |
|||
* 根据用户名查询 |
|||
* @param username 用户名 |
|||
* @return / |
|||
*/ |
|||
User findByUsername(String username); |
|||
|
|||
/** |
|||
* 根据邮箱查询 |
|||
* @param email 邮箱 |
|||
* @return / |
|||
*/ |
|||
User findByEmail(String email); |
|||
|
|||
/** |
|||
* 根据手机号查询 |
|||
* @param phone 手机号 |
|||
* @return / |
|||
*/ |
|||
User findByPhone(String phone); |
|||
|
|||
/** |
|||
* 修改密码 |
|||
* @param username 用户名 |
|||
* @param pass 密码 |
|||
* @param lastPasswordResetTime / |
|||
*/ |
|||
@Modifying |
|||
@Query(value = "update sys_user set password = ?2 , pwd_reset_time = ?3 where username = ?1",nativeQuery = true) |
|||
void updatePass(String username, String pass, Date lastPasswordResetTime); |
|||
|
|||
/** |
|||
* 修改邮箱 |
|||
* @param username 用户名 |
|||
* @param email 邮箱 |
|||
*/ |
|||
@Modifying |
|||
@Query(value = "update sys_user set email = ?2 where username = ?1",nativeQuery = true) |
|||
void updateEmail(String username, String email); |
|||
|
|||
/** |
|||
* 根据角色查询用户 |
|||
* @param roleId / |
|||
* @return / |
|||
*/ |
|||
@Query(value = "SELECT u.* FROM sys_user u, sys_users_roles r WHERE" + |
|||
" u.user_id = r.user_id AND r.role_id = ?1", nativeQuery = true) |
|||
List<User> findByRoleId(Long roleId); |
|||
|
|||
/** |
|||
* 根据角色中的部门查询 |
|||
* @param deptId / |
|||
* @return / |
|||
*/ |
|||
@Query(value = "SELECT u.* FROM sys_user u, sys_users_roles r, sys_roles_depts d WHERE " + |
|||
"u.user_id = r.user_id AND r.role_id = d.role_id AND d.dept_id = ?1 group by u.user_id", nativeQuery = true) |
|||
List<User> findByRoleDeptId(Long deptId); |
|||
|
|||
/** |
|||
* 根据菜单查询 |
|||
* @param id 菜单ID |
|||
* @return / |
|||
*/ |
|||
@Query(value = "SELECT u.* FROM sys_user u, sys_users_roles ur, sys_roles_menus rm WHERE\n" + |
|||
"u.user_id = ur.user_id AND ur.role_id = rm.role_id AND rm.menu_id = ?1 group by u.user_id", nativeQuery = true) |
|||
List<User> findByMenuId(Long id); |
|||
|
|||
/** |
|||
* 根据Id删除 |
|||
* @param ids / |
|||
*/ |
|||
void deleteAllByIdIn(Set<Long> ids); |
|||
|
|||
/** |
|||
* 根据岗位查询 |
|||
* @param ids / |
|||
* @return / |
|||
*/ |
|||
@Query(value = "SELECT count(1) FROM sys_user u, sys_users_jobs j WHERE u.user_id = j.user_id AND j.job_id IN ?1", nativeQuery = true) |
|||
int countByJobs(Set<Long> ids); |
|||
|
|||
/** |
|||
* 根据部门查询 |
|||
* @param deptIds / |
|||
* @return / |
|||
*/ |
|||
@Query(value = "SELECT count(1) FROM sys_user u WHERE u.dept_id IN ?1", nativeQuery = true) |
|||
int countByDepts(Set<Long> deptIds); |
|||
|
|||
/** |
|||
* 根据角色查询 |
|||
* @param ids / |
|||
* @return / |
|||
*/ |
|||
@Query(value = "SELECT count(1) FROM sys_user u, sys_users_roles r WHERE " + |
|||
"u.user_id = r.user_id AND r.role_id in ?1", nativeQuery = true) |
|||
int countByRoles(Set<Long> ids); |
|||
} |
@ -0,0 +1,10 @@ |
|||
package com.storeroom.modules.system.service; |
|||
|
|||
import com.storeroom.modules.system.service.dto.UserDto; |
|||
|
|||
import java.util.List; |
|||
|
|||
public interface DataService { |
|||
|
|||
List<Long> getDeptIds(UserDto user); |
|||
} |
@ -0,0 +1,4 @@ |
|||
package com.storeroom.modules.system.service; |
|||
|
|||
public interface DeptService { |
|||
} |
@ -0,0 +1,45 @@ |
|||
package com.storeroom.modules.system.service; |
|||
|
|||
import com.storeroom.modules.system.domain.DictDetail; |
|||
import com.storeroom.modules.system.service.dto.DictDetailDto; |
|||
import com.storeroom.modules.system.service.dto.DictDetailQueryCriteria; |
|||
import org.springframework.data.domain.Pageable; |
|||
|
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
public interface DictDetailService { |
|||
|
|||
/** |
|||
* 创建 |
|||
* @param resources / |
|||
*/ |
|||
void create(DictDetail resources); |
|||
|
|||
/** |
|||
* 编辑 |
|||
* @param resources / |
|||
*/ |
|||
void update(DictDetail resources); |
|||
|
|||
/** |
|||
* 删除 |
|||
* @param id / |
|||
*/ |
|||
void delete(Long id); |
|||
|
|||
/** |
|||
* 分页查询 |
|||
* @param criteria 条件 |
|||
* @param pageable 分页参数 |
|||
* @return / |
|||
*/ |
|||
Map<String,Object> queryAll(DictDetailQueryCriteria criteria, Pageable pageable); |
|||
|
|||
/** |
|||
* 根据字典名称获取字典详情 |
|||
* @param name 字典名称 |
|||
* @return / |
|||
*/ |
|||
List<DictDetailDto> getDictByName(String name); |
|||
} |
@ -0,0 +1,57 @@ |
|||
package com.storeroom.modules.system.service; |
|||
|
|||
import com.storeroom.modules.system.domain.Dict; |
|||
import com.storeroom.modules.system.service.dto.DictDto; |
|||
import com.storeroom.modules.system.service.dto.DictQueryCriteria; |
|||
import org.springframework.data.domain.Pageable; |
|||
|
|||
import javax.servlet.http.HttpServletResponse; |
|||
import java.io.IOException; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.Set; |
|||
|
|||
public interface DictService { |
|||
|
|||
/** |
|||
* 分页查询 |
|||
* @param criteria 条件 |
|||
* @param pageable 分页参数 |
|||
* @return / |
|||
*/ |
|||
Map<String,Object> queryAll(DictQueryCriteria criteria, Pageable pageable); |
|||
|
|||
/** |
|||
* 查询全部数据 |
|||
* @param dict / |
|||
* @return / |
|||
*/ |
|||
List<DictDto> queryAll(DictQueryCriteria dict); |
|||
|
|||
/** |
|||
* 创建 |
|||
* @param resources / |
|||
* @return / |
|||
*/ |
|||
void create(Dict resources); |
|||
|
|||
/** |
|||
* 编辑 |
|||
* @param resources / |
|||
*/ |
|||
void update(Dict resources); |
|||
|
|||
/** |
|||
* 删除 |
|||
* @param ids / |
|||
*/ |
|||
void delete(Set<Long> ids); |
|||
|
|||
/** |
|||
* 导出数据 |
|||
* @param queryAll 待导出的数据 |
|||
* @param response / |
|||
* @throws IOException / |
|||
*/ |
|||
void download(List<DictDto> queryAll, HttpServletResponse response) throws IOException; |
|||
} |
@ -0,0 +1,4 @@ |
|||
package com.storeroom.modules.system.service; |
|||
|
|||
public interface JobService { |
|||
} |
@ -0,0 +1,4 @@ |
|||
package com.storeroom.modules.system.service; |
|||
|
|||
public interface MenuService { |
|||
} |
@ -0,0 +1,118 @@ |
|||
package com.storeroom.modules.system.service; |
|||
|
|||
import com.storeroom.modules.system.domain.Role; |
|||
import com.storeroom.modules.system.service.dto.RoleDto; |
|||
import com.storeroom.modules.system.service.dto.RoleQueryCriteria; |
|||
import com.storeroom.modules.system.service.dto.RoleSmallDto; |
|||
import com.storeroom.modules.system.service.dto.UserDto; |
|||
import org.springframework.data.domain.Pageable; |
|||
import org.springframework.security.core.GrantedAuthority; |
|||
|
|||
import javax.servlet.http.HttpServletResponse; |
|||
import java.io.IOException; |
|||
import java.util.List; |
|||
import java.util.Set; |
|||
|
|||
public interface RoleService { |
|||
|
|||
/** |
|||
* 查询全部数据 |
|||
* @return / |
|||
*/ |
|||
List<RoleDto> queryAll(); |
|||
|
|||
/** |
|||
* 根据ID查询 |
|||
* @param id / |
|||
* @return / |
|||
*/ |
|||
RoleDto findById(long id); |
|||
|
|||
/** |
|||
* 创建 |
|||
* @param resources / |
|||
*/ |
|||
void create(Role resources); |
|||
|
|||
/** |
|||
* 编辑 |
|||
* @param resources / |
|||
*/ |
|||
void update(Role resources); |
|||
|
|||
/** |
|||
* 删除 |
|||
* @param ids / |
|||
*/ |
|||
void delete(Set<Long> ids); |
|||
|
|||
/** |
|||
* 根据用户ID查询 |
|||
* @param id 用户ID |
|||
* @return / |
|||
*/ |
|||
List<RoleSmallDto> findByUsersId(Long id); |
|||
|
|||
/** |
|||
* 根据角色查询角色级别 |
|||
* @param roles / |
|||
* @return / |
|||
*/ |
|||
Integer findByRoles(Set<Role> roles); |
|||
|
|||
/** |
|||
* 修改绑定的菜单 |
|||
* @param resources / |
|||
* @param roleDTO / |
|||
*/ |
|||
void updateMenu(Role resources, RoleDto roleDTO); |
|||
|
|||
/** |
|||
* 解绑菜单 |
|||
* @param id / |
|||
*/ |
|||
void untiedMenu(Long id); |
|||
|
|||
/** |
|||
* 待条件分页查询 |
|||
* @param criteria 条件 |
|||
* @param pageable 分页参数 |
|||
* @return / |
|||
*/ |
|||
Object queryAll(RoleQueryCriteria criteria, Pageable pageable); |
|||
|
|||
/** |
|||
* 查询全部 |
|||
* @param criteria 条件 |
|||
* @return / |
|||
*/ |
|||
List<RoleDto> queryAll(RoleQueryCriteria criteria); |
|||
|
|||
/** |
|||
* 导出数据 |
|||
* @param queryAll 待导出的数据 |
|||
* @param response / |
|||
* @throws IOException / |
|||
*/ |
|||
void download(List<RoleDto> queryAll, HttpServletResponse response) throws IOException; |
|||
|
|||
/** |
|||
* 获取用户权限信息 |
|||
* @param user 用户信息 |
|||
* @return 权限信息 |
|||
*/ |
|||
List<GrantedAuthority> mapToGrantedAuthorities(UserDto user); |
|||
|
|||
/** |
|||
* 验证是否被用户关联 |
|||
* @param ids / |
|||
*/ |
|||
void verification(Set<Long> ids); |
|||
|
|||
/** |
|||
* 根据菜单Id查询 |
|||
* @param menuIds / |
|||
* @return / |
|||
*/ |
|||
List<Role> findInMenuId(List<Long> menuIds); |
|||
} |
@ -0,0 +1,99 @@ |
|||
package com.storeroom.modules.system.service; |
|||
|
|||
import com.storeroom.modules.system.domain.User; |
|||
import com.storeroom.modules.system.service.dto.UserDto; |
|||
import com.storeroom.modules.system.service.dto.UserQueryCriteria; |
|||
import org.springframework.data.domain.Pageable; |
|||
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; |
|||
|
|||
public interface UserService { |
|||
|
|||
/** |
|||
* 根据ID查询 |
|||
* @param id ID |
|||
* @return / |
|||
*/ |
|||
UserDto findById(long id); |
|||
|
|||
/** |
|||
* 新增用户 |
|||
* @param resources / |
|||
*/ |
|||
void create(User resources); |
|||
|
|||
/** |
|||
* 编辑用户 |
|||
* @param resources / |
|||
* @throws Exception / |
|||
*/ |
|||
void update(User resources) throws Exception; |
|||
|
|||
/** |
|||
* 删除用户 |
|||
* @param ids / |
|||
*/ |
|||
void delete(Set<Long> ids); |
|||
|
|||
/** |
|||
* 根据用户名查询 |
|||
* @param userName / |
|||
* @return / |
|||
*/ |
|||
UserDto findByName(String userName); |
|||
|
|||
/** |
|||
* 修改密码 |
|||
* @param username 用户名 |
|||
* @param encryptPassword 密码 |
|||
*/ |
|||
void updatePass(String username, String encryptPassword); |
|||
|
|||
/** |
|||
* 修改头像 |
|||
* @param file 文件 |
|||
* @return / |
|||
*/ |
|||
Map<String, String> updateAvatar(MultipartFile file); |
|||
|
|||
/** |
|||
* 修改邮箱 |
|||
* @param username 用户名 |
|||
* @param email 邮箱 |
|||
*/ |
|||
void updateEmail(String username, String email); |
|||
|
|||
/** |
|||
* 查询全部 |
|||
* @param criteria 条件 |
|||
* @param pageable 分页参数 |
|||
* @return / |
|||
*/ |
|||
Object queryAll(UserQueryCriteria criteria, Pageable pageable); |
|||
|
|||
/** |
|||
* 查询全部不分页 |
|||
* @param criteria 条件 |
|||
* @return / |
|||
*/ |
|||
List<UserDto> queryAll(UserQueryCriteria criteria); |
|||
|
|||
/** |
|||
* 导出数据 |
|||
* @param queryAll 待导出的数据 |
|||
* @param response / |
|||
* @throws IOException / |
|||
*/ |
|||
void download(List<UserDto> queryAll, HttpServletResponse response) throws IOException; |
|||
|
|||
/** |
|||
* 用户自助修改资料 |
|||
* @param resources / |
|||
*/ |
|||
void updateCenter(User resources); |
|||
} |
@ -0,0 +1,61 @@ |
|||
package com.storeroom.modules.system.service.dto; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonInclude; |
|||
import com.storeroom.base.BaseDTO; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.List; |
|||
import java.util.Objects; |
|||
|
|||
|
|||
@Getter |
|||
@Setter |
|||
public class DeptDto extends BaseDTO implements Serializable { |
|||
|
|||
private Long id; |
|||
|
|||
private String name; |
|||
|
|||
private Boolean enabled; |
|||
|
|||
private Integer deptSort; |
|||
|
|||
@JsonInclude(JsonInclude.Include.NON_EMPTY) |
|||
private List<DeptDto> children; |
|||
|
|||
private Long pid; |
|||
|
|||
private Integer subCount; |
|||
|
|||
public Boolean getHasChildren() { |
|||
return subCount > 0; |
|||
} |
|||
|
|||
public Boolean getLeaf() { |
|||
return subCount <= 0; |
|||
} |
|||
|
|||
public String getLabel() { |
|||
return name; |
|||
} |
|||
|
|||
@Override |
|||
public boolean equals(Object o) { |
|||
if (this == o) { |
|||
return true; |
|||
} |
|||
if (o == null || getClass() != o.getClass()) { |
|||
return false; |
|||
} |
|||
DeptDto deptDto = (DeptDto) o; |
|||
return Objects.equals(id, deptDto.id) && |
|||
Objects.equals(name, deptDto.name); |
|||
} |
|||
|
|||
@Override |
|||
public int hashCode() { |
|||
return Objects.hash(id, name); |
|||
} |
|||
} |
@ -0,0 +1,29 @@ |
|||
package com.storeroom.modules.system.service.dto; |
|||
|
|||
|
|||
import com.storeroom.annotaion.DataPermission; |
|||
import com.storeroom.annotaion.Query; |
|||
import lombok.Data; |
|||
|
|||
import java.sql.Timestamp; |
|||
import java.util.List; |
|||
|
|||
@Data |
|||
@DataPermission(fieldName = "id") |
|||
public class DeptQueryCriteria { |
|||
|
|||
@Query(type = Query.Type.INNER_LIKE) |
|||
private String name; |
|||
|
|||
@Query |
|||
private Boolean enabled; |
|||
|
|||
@Query |
|||
private Long pid; |
|||
|
|||
@Query(type = Query.Type.IS_NULL, propName = "pid") |
|||
private Boolean pidIsNull; |
|||
|
|||
@Query(type = Query.Type.BETWEEN) |
|||
private List<Timestamp> createTime; |
|||
} |
@ -0,0 +1,16 @@ |
|||
package com.storeroom.modules.system.service.dto; |
|||
|
|||
import lombok.Data; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
import java.io.Serializable; |
|||
|
|||
|
|||
@Data |
|||
public class DeptSmallDto implements Serializable { |
|||
|
|||
private Long id; |
|||
|
|||
private String name; |
|||
} |
@ -0,0 +1,23 @@ |
|||
package com.storeroom.modules.system.service.dto; |
|||
|
|||
import com.storeroom.base.BaseDTO; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
import java.io.Serializable; |
|||
|
|||
|
|||
@Getter |
|||
@Setter |
|||
public class DictDetailDto extends BaseDTO implements Serializable { |
|||
|
|||
private Long id; |
|||
|
|||
private DictSmallDto dict; |
|||
|
|||
private String label; |
|||
|
|||
private String value; |
|||
|
|||
private Integer dictSort; |
|||
} |
@ -0,0 +1,15 @@ |
|||
package com.storeroom.modules.system.service.dto; |
|||
|
|||
|
|||
import com.storeroom.annotaion.Query; |
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
public class DictDetailQueryCriteria { |
|||
|
|||
@Query(type = Query.Type.INNER_LIKE) |
|||
private String label; |
|||
|
|||
@Query(propName = "name",joinName = "dict") |
|||
private String dictName; |
|||
} |
@ -0,0 +1,22 @@ |
|||
package com.storeroom.modules.system.service.dto; |
|||
|
|||
import com.storeroom.base.BaseDTO; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.List; |
|||
|
|||
|
|||
@Getter |
|||
@Setter |
|||
public class DictDto extends BaseDTO implements Serializable { |
|||
|
|||
private Long id; |
|||
|
|||
private List<DictDetailDto> dictDetails; |
|||
|
|||
private String name; |
|||
|
|||
private String description; |
|||
} |
@ -0,0 +1,12 @@ |
|||
package com.storeroom.modules.system.service.dto; |
|||
|
|||
import com.storeroom.annotaion.Query; |
|||
import lombok.Data; |
|||
|
|||
|
|||
@Data |
|||
public class DictQueryCriteria { |
|||
|
|||
@Query(blurry = "name,description") |
|||
private String blurry; |
|||
} |
@ -0,0 +1,12 @@ |
|||
package com.storeroom.modules.system.service.dto; |
|||
|
|||
|
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
@Getter |
|||
@Setter |
|||
public class DictSmallDto { |
|||
|
|||
private Long id; |
|||
} |
@ -0,0 +1,27 @@ |
|||
package com.storeroom.modules.system.service.dto; |
|||
|
|||
import com.storeroom.base.BaseDTO; |
|||
import lombok.Getter; |
|||
import lombok.NoArgsConstructor; |
|||
import lombok.Setter; |
|||
|
|||
import java.io.Serializable; |
|||
|
|||
@Getter |
|||
@Setter |
|||
@NoArgsConstructor |
|||
public class JobDto extends BaseDTO implements Serializable { |
|||
|
|||
private Long id; |
|||
|
|||
private Integer jobSort; |
|||
|
|||
private String name; |
|||
|
|||
private Boolean enabled; |
|||
|
|||
public JobDto(String name, Boolean enabled) { |
|||
this.name = name; |
|||
this.enabled = enabled; |
|||
} |
|||
} |
@ -0,0 +1,16 @@ |
|||
package com.storeroom.modules.system.service.dto; |
|||
|
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
|
|||
import java.io.Serializable; |
|||
|
|||
|
|||
@Data |
|||
@NoArgsConstructor |
|||
public class JobSmallDto implements Serializable { |
|||
|
|||
private Long id; |
|||
|
|||
private String name; |
|||
} |
@ -0,0 +1,73 @@ |
|||
package com.storeroom.modules.system.service.dto; |
|||
|
|||
import com.storeroom.base.BaseDTO; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.List; |
|||
import java.util.Objects; |
|||
|
|||
@Getter |
|||
@Setter |
|||
public class MenuDto extends BaseDTO implements Serializable { |
|||
|
|||
private Long id; |
|||
|
|||
private List<MenuDto> children; |
|||
|
|||
private Integer type; |
|||
|
|||
private String permission; |
|||
|
|||
private String title; |
|||
|
|||
private Integer menuSort; |
|||
|
|||
private String path; |
|||
|
|||
private String component; |
|||
|
|||
private Long pid; |
|||
|
|||
private Integer subCount; |
|||
|
|||
private Boolean iFrame; |
|||
|
|||
private Boolean cache; |
|||
|
|||
private Boolean hidden; |
|||
|
|||
private String componentName; |
|||
|
|||
private String icon; |
|||
|
|||
public Boolean getHasChildren() { |
|||
return subCount > 0; |
|||
} |
|||
|
|||
public Boolean getLeaf() { |
|||
return subCount <= 0; |
|||
} |
|||
|
|||
public String getLabel() { |
|||
return title; |
|||
} |
|||
|
|||
@Override |
|||
public boolean equals(Object o) { |
|||
if (this == o) { |
|||
return true; |
|||
} |
|||
if (o == null || getClass() != o.getClass()) { |
|||
return false; |
|||
} |
|||
MenuDto menuDto = (MenuDto) o; |
|||
return Objects.equals(id, menuDto.id); |
|||
} |
|||
|
|||
@Override |
|||
public int hashCode() { |
|||
return Objects.hash(id); |
|||
} |
|||
} |
@ -0,0 +1,24 @@ |
|||
package com.storeroom.modules.system.service.dto; |
|||
|
|||
|
|||
import com.storeroom.annotaion.Query; |
|||
import lombok.Data; |
|||
|
|||
import java.sql.Timestamp; |
|||
import java.util.List; |
|||
|
|||
@Data |
|||
public class MenuQueryCriteria { |
|||
|
|||
@Query(blurry = "title,component,permission") |
|||
private String blurry; |
|||
|
|||
@Query(type = Query.Type.BETWEEN) |
|||
private List<Timestamp> createTime; |
|||
|
|||
@Query(type = Query.Type.IS_NULL, propName = "pid") |
|||
private Boolean pidIsNull; |
|||
|
|||
@Query |
|||
private Long pid; |
|||
} |
@ -0,0 +1,46 @@ |
|||
package com.storeroom.modules.system.service.dto; |
|||
|
|||
import com.storeroom.base.BaseDTO; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.Objects; |
|||
import java.util.Set; |
|||
|
|||
|
|||
@Getter |
|||
@Setter |
|||
public class RoleDto extends BaseDTO implements Serializable { |
|||
|
|||
private Long id; |
|||
|
|||
private Set<MenuDto> menus; |
|||
|
|||
private Set<DeptDto> depts; |
|||
|
|||
private String name; |
|||
|
|||
private String dataScope; |
|||
|
|||
private Integer level; |
|||
|
|||
private String description; |
|||
|
|||
@Override |
|||
public boolean equals(Object o) { |
|||
if (this == o) { |
|||
return true; |
|||
} |
|||
if (o == null || getClass() != o.getClass()) { |
|||
return false; |
|||
} |
|||
RoleDto roleDto = (RoleDto) o; |
|||
return Objects.equals(id, roleDto.id); |
|||
} |
|||
|
|||
@Override |
|||
public int hashCode() { |
|||
return Objects.hash(id); |
|||
} |
|||
} |
@ -0,0 +1,17 @@ |
|||
package com.storeroom.modules.system.service.dto; |
|||
|
|||
import com.storeroom.annotaion.Query; |
|||
import lombok.Data; |
|||
|
|||
import java.sql.Timestamp; |
|||
import java.util.List; |
|||
|
|||
@Data |
|||
public class RoleQueryCriteria { |
|||
|
|||
@Query(blurry = "name,description") |
|||
private String blurry; |
|||
|
|||
@Query(type = Query.Type.BETWEEN) |
|||
private List<Timestamp> createTime; |
|||
} |
@ -0,0 +1,18 @@ |
|||
package com.storeroom.modules.system.service.dto; |
|||
|
|||
import lombok.Data; |
|||
|
|||
import java.io.Serializable; |
|||
|
|||
|
|||
@Data |
|||
public class RoleSmallDto implements Serializable { |
|||
|
|||
private Long id; |
|||
|
|||
private String name; |
|||
|
|||
private Integer level; |
|||
|
|||
private String dataScope; |
|||
} |
@ -0,0 +1,50 @@ |
|||
package com.storeroom.modules.system.service.dto; |
|||
|
|||
|
|||
import com.alibaba.fastjson.annotation.JSONField; |
|||
import com.storeroom.base.BaseDTO; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.Date; |
|||
import java.util.Set; |
|||
|
|||
@Getter |
|||
@Setter |
|||
public class UserDto extends BaseDTO implements Serializable { |
|||
|
|||
private Long id; |
|||
|
|||
private Set<RoleSmallDto> roles; |
|||
|
|||
private Set<JobSmallDto> jobs; |
|||
|
|||
private DeptSmallDto dept; |
|||
|
|||
private Long deptId; |
|||
|
|||
private String username; |
|||
|
|||
private String nickName; |
|||
|
|||
private String email; |
|||
|
|||
private String phone; |
|||
|
|||
private String gender; |
|||
|
|||
private String avatarName; |
|||
|
|||
private String avatarPath; |
|||
|
|||
@JSONField(serialize = false) |
|||
private String password; |
|||
|
|||
private Boolean enabled; |
|||
|
|||
@JSONField(serialize = false) |
|||
private Boolean isAdmin = false; |
|||
|
|||
private Date pwdResetTime; |
|||
} |
@ -0,0 +1,31 @@ |
|||
package com.storeroom.modules.system.service.dto; |
|||
|
|||
import com.storeroom.annotaion.Query; |
|||
import lombok.Data; |
|||
|
|||
import java.io.Serializable; |
|||
import java.sql.Timestamp; |
|||
import java.util.HashSet; |
|||
import java.util.List; |
|||
import java.util.Set; |
|||
|
|||
@Data |
|||
public class UserQueryCriteria implements Serializable { |
|||
|
|||
@Query |
|||
private Long id; |
|||
|
|||
@Query(propName = "id", type = Query.Type.IN, joinName = "dept") |
|||
private Set<Long> deptIds = new HashSet<>(); |
|||
|
|||
@Query(blurry = "email,username,nickName") |
|||
private String blurry; |
|||
|
|||
@Query |
|||
private Boolean enabled; |
|||
|
|||
private Long deptId; |
|||
|
|||
@Query(type = Query.Type.BETWEEN) |
|||
private List<Timestamp> createTime; |
|||
} |
@ -0,0 +1,208 @@ |
|||
package com.storeroom.modules.system.service.impl; |
|||
|
|||
import cn.hutool.core.collection.CollectionUtil; |
|||
import com.storeroom.exception.BaseException; |
|||
import com.storeroom.modules.security.service.UserCacheClean; |
|||
import com.storeroom.modules.system.domain.Menu; |
|||
import com.storeroom.modules.system.domain.Role; |
|||
import com.storeroom.modules.system.domain.User; |
|||
import com.storeroom.modules.system.repository.RoleRepository; |
|||
import com.storeroom.modules.system.repository.UserRepository; |
|||
import com.storeroom.modules.system.service.RoleService; |
|||
import com.storeroom.modules.system.service.dto.RoleDto; |
|||
import com.storeroom.modules.system.service.dto.RoleQueryCriteria; |
|||
import com.storeroom.modules.system.service.dto.RoleSmallDto; |
|||
import com.storeroom.modules.system.service.dto.UserDto; |
|||
import com.storeroom.modules.system.service.mapstruct.RoleMapper; |
|||
import com.storeroom.modules.system.service.mapstruct.RoleSmallMapper; |
|||
import com.storeroom.utils.*; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.cache.annotation.CacheConfig; |
|||
import org.springframework.cache.annotation.Cacheable; |
|||
import org.springframework.data.domain.Page; |
|||
import org.springframework.data.domain.Pageable; |
|||
import org.springframework.data.domain.Sort; |
|||
import org.springframework.security.core.GrantedAuthority; |
|||
import org.springframework.security.core.authority.SimpleGrantedAuthority; |
|||
import org.springframework.stereotype.Service; |
|||
import org.springframework.transaction.annotation.Transactional; |
|||
|
|||
import javax.servlet.http.HttpServletResponse; |
|||
import java.io.IOException; |
|||
import java.util.*; |
|||
import java.util.stream.Collectors; |
|||
|
|||
|
|||
@Service |
|||
@RequiredArgsConstructor |
|||
@CacheConfig(cacheNames = "role") |
|||
public class RoleServiceImpl implements RoleService { |
|||
|
|||
private final RoleRepository roleRepository; |
|||
private final RoleMapper roleMapper; |
|||
private final RoleSmallMapper roleSmallMapper; |
|||
private final RedisUtils redisUtils; |
|||
private final UserRepository userRepository; |
|||
private final UserCacheClean userCacheClean; |
|||
|
|||
|
|||
@Override |
|||
public List<RoleDto> queryAll() { |
|||
Sort sort = Sort.by(Sort.Direction.ASC, "level"); |
|||
return roleMapper.toDto(roleRepository.findAll(sort)); |
|||
} |
|||
|
|||
@Override |
|||
public List<RoleDto> queryAll(RoleQueryCriteria criteria) { |
|||
return roleMapper.toDto(roleRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder))); |
|||
} |
|||
|
|||
@Override |
|||
public Object queryAll(RoleQueryCriteria criteria, Pageable pageable) { |
|||
Page<Role> page = roleRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable); |
|||
return PageUtil.toPage(page.map(roleMapper::toDto)); |
|||
} |
|||
|
|||
@Override |
|||
@Cacheable(key = "'id:' + #p0") |
|||
@Transactional(rollbackFor = Exception.class) |
|||
public RoleDto findById(long id) { |
|||
Role role = roleRepository.findById(id).orElseGet(Role::new); |
|||
ValidationUtil.isNull(role.getId(), "Role", "id", id); |
|||
return roleMapper.toDto(role); |
|||
} |
|||
|
|||
@Override |
|||
@Transactional(rollbackFor = Exception.class) |
|||
public void create(Role resources) { |
|||
if (roleRepository.findByName(resources.getName()) != null) { |
|||
throw new BaseException("username", resources.getName()); |
|||
} |
|||
roleRepository.save(resources); |
|||
} |
|||
|
|||
@Override |
|||
@Transactional(rollbackFor = Exception.class) |
|||
public void update(Role resources) { |
|||
Role role = roleRepository.findById(resources.getId()).orElseGet(Role::new); |
|||
ValidationUtil.isNull(role.getId(), "Role", "id", resources.getId()); |
|||
|
|||
Role role1 = roleRepository.findByName(resources.getName()); |
|||
|
|||
if (role1 != null && !role1.getId().equals(role.getId())) { |
|||
throw new BaseException("username", resources.getName()); |
|||
} |
|||
role.setName(resources.getName()); |
|||
role.setDescription(resources.getDescription()); |
|||
role.setDataScope(resources.getDataScope()); |
|||
role.setDepts(resources.getDepts()); |
|||
role.setLevel(resources.getLevel()); |
|||
roleRepository.save(role); |
|||
// 更新相关缓存 |
|||
delCaches(role.getId(), null); |
|||
} |
|||
|
|||
@Override |
|||
public void updateMenu(Role resources, RoleDto roleDTO) { |
|||
Role role = roleMapper.toEntity(roleDTO); |
|||
List<User> users = userRepository.findByRoleId(role.getId()); |
|||
// 更新菜单 |
|||
role.setMenus(resources.getMenus()); |
|||
delCaches(resources.getId(), users); |
|||
roleRepository.save(role); |
|||
} |
|||
|
|||
@Override |
|||
@Transactional(rollbackFor = Exception.class) |
|||
public void untiedMenu(Long menuId) { |
|||
// 更新菜单 |
|||
roleRepository.untiedMenu(menuId); |
|||
} |
|||
|
|||
@Override |
|||
@Transactional(rollbackFor = Exception.class) |
|||
public void delete(Set<Long> ids) { |
|||
for (Long id : ids) { |
|||
// 更新相关缓存 |
|||
delCaches(id, null); |
|||
} |
|||
roleRepository.deleteAllByIdIn(ids); |
|||
} |
|||
|
|||
@Override |
|||
public List<RoleSmallDto> findByUsersId(Long id) { |
|||
return roleSmallMapper.toDto(new ArrayList<>(roleRepository.findByUserId(id))); |
|||
} |
|||
|
|||
@Override |
|||
public Integer findByRoles(Set<Role> roles) { |
|||
if (roles.size() == 0) { |
|||
return Integer.MAX_VALUE; |
|||
} |
|||
Set<RoleDto> roleDtos = new HashSet<>(); |
|||
for (Role role : roles) { |
|||
roleDtos.add(findById(role.getId())); |
|||
} |
|||
return Collections.min(roleDtos.stream().map(RoleDto::getLevel).collect(Collectors.toList())); |
|||
} |
|||
|
|||
@Override |
|||
@Cacheable(key = "'auth:' + #p0.id") |
|||
public List<GrantedAuthority> mapToGrantedAuthorities(UserDto user) { |
|||
Set<String> permissions = new HashSet<>(); |
|||
// 如果是管理员直接返回 |
|||
if (user.getIsAdmin()) { |
|||
permissions.add("admin"); |
|||
return permissions.stream().map(SimpleGrantedAuthority::new) |
|||
.collect(Collectors.toList()); |
|||
} |
|||
Set<Role> roles = roleRepository.findByUserId(user.getId()); |
|||
permissions = roles.stream().flatMap(role -> role.getMenus().stream()) |
|||
.filter(menu -> StringUtils.isNotBlank(menu.getPermission())) |
|||
.map(Menu::getPermission).collect(Collectors.toSet()); |
|||
return permissions.stream().map(SimpleGrantedAuthority::new) |
|||
.collect(Collectors.toList()); |
|||
} |
|||
|
|||
@Override |
|||
public void download(List<RoleDto> roles, HttpServletResponse response) throws IOException { |
|||
List<Map<String, Object>> list = new ArrayList<>(); |
|||
for (RoleDto role : roles) { |
|||
Map<String, Object> map = new LinkedHashMap<>(); |
|||
map.put("角色名称", role.getName()); |
|||
map.put("角色级别", role.getLevel()); |
|||
map.put("描述", role.getDescription()); |
|||
map.put("创建日期", role.getCreateTime()); |
|||
list.add(map); |
|||
} |
|||
FileUtil.downloadExcel(list, response); |
|||
} |
|||
|
|||
@Override |
|||
public void verification(Set<Long> ids) { |
|||
if (userRepository.countByRoles(ids) > 0) { |
|||
throw new BaseException("所选角色存在用户关联,请解除关联再试!"); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
public List<Role> findInMenuId(List<Long> menuIds) { |
|||
return roleRepository.findInMenuId(menuIds); |
|||
} |
|||
|
|||
/** |
|||
* 清理缓存 |
|||
* @param id / |
|||
*/ |
|||
public void delCaches(Long id, List<User> users) { |
|||
users = CollectionUtil.isEmpty(users) ? userRepository.findByRoleId(id) : users; |
|||
if (CollectionUtil.isNotEmpty(users)) { |
|||
users.forEach(item -> userCacheClean.cleanUserCache(item.getUsername())); |
|||
Set<Long> userIds = users.stream().map(User::getId).collect(Collectors.toSet()); |
|||
redisUtils.delByKeys(CacheKey.DATA_USER, userIds); |
|||
redisUtils.delByKeys(CacheKey.MENU_USER, userIds); |
|||
redisUtils.delByKeys(CacheKey.ROLE_AUTH, userIds); |
|||
} |
|||
redisUtils.del(CacheKey.ROLE_ID + id); |
|||
} |
|||
} |
@ -0,0 +1,239 @@ |
|||
package com.storeroom.modules.system.service.impl; |
|||
|
|||
|
|||
import com.storeroom.config.FileProperties; |
|||
import com.storeroom.exception.BaseException; |
|||
import com.storeroom.modules.security.service.OnlineUserService; |
|||
import com.storeroom.modules.security.service.UserCacheClean; |
|||
import com.storeroom.modules.system.domain.User; |
|||
import com.storeroom.modules.system.repository.UserRepository; |
|||
import com.storeroom.modules.system.service.UserService; |
|||
import com.storeroom.modules.system.service.dto.JobSmallDto; |
|||
import com.storeroom.modules.system.service.dto.RoleSmallDto; |
|||
import com.storeroom.modules.system.service.dto.UserDto; |
|||
import com.storeroom.modules.system.service.dto.UserQueryCriteria; |
|||
import com.storeroom.modules.system.service.mapstruct.UserMapper; |
|||
import com.storeroom.utils.*; |
|||
import lombok.RequiredArgsConstructor; |
|||
import org.springframework.cache.annotation.CacheConfig; |
|||
import org.springframework.cache.annotation.Cacheable; |
|||
import org.springframework.data.domain.Page; |
|||
import org.springframework.data.domain.Pageable; |
|||
import org.springframework.stereotype.Service; |
|||
import org.springframework.transaction.annotation.Transactional; |
|||
import org.springframework.web.multipart.MultipartFile; |
|||
|
|||
import javax.servlet.http.HttpServletResponse; |
|||
import javax.validation.constraints.NotBlank; |
|||
import java.io.File; |
|||
import java.io.IOException; |
|||
import java.util.*; |
|||
import java.util.stream.Collectors; |
|||
|
|||
|
|||
@Service |
|||
@RequiredArgsConstructor |
|||
@CacheConfig(cacheNames = "user") |
|||
public class UserServiceImpl implements UserService { |
|||
|
|||
private final UserRepository userRepository; |
|||
private final UserMapper userMapper; |
|||
private final FileProperties properties; |
|||
private final RedisUtils redisUtils; |
|||
private final UserCacheClean userCacheClean; |
|||
private final OnlineUserService onlineUserService; |
|||
|
|||
@Override |
|||
public Object queryAll(UserQueryCriteria criteria, Pageable pageable) { |
|||
Page<User> page = userRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder), pageable); |
|||
return PageUtil.toPage(page.map(userMapper::toDto)); |
|||
} |
|||
|
|||
@Override |
|||
public List<UserDto> queryAll(UserQueryCriteria criteria) { |
|||
List<User> users = userRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder)); |
|||
return userMapper.toDto(users); |
|||
} |
|||
|
|||
@Override |
|||
@Cacheable(key = "'id:' + #p0") |
|||
@Transactional(rollbackFor = Exception.class) |
|||
public UserDto findById(long id) { |
|||
User user = userRepository.findById(id).orElseGet(User::new); |
|||
ValidationUtil.isNull(user.getId(), "User", "id", id); |
|||
return userMapper.toDto(user); |
|||
} |
|||
|
|||
@Override |
|||
@Transactional(rollbackFor = Exception.class) |
|||
public void create(User resources) { |
|||
if (userRepository.findByUsername(resources.getUsername()) != null) { |
|||
throw new BaseException("username is not null"); |
|||
} |
|||
if (userRepository.findByEmail(resources.getEmail()) != null) { |
|||
throw new BaseException("email is not null"); |
|||
} |
|||
if (userRepository.findByPhone(resources.getPhone()) != null) { |
|||
throw new BaseException("phone is not null"); |
|||
} |
|||
userRepository.save(resources); |
|||
} |
|||
|
|||
@Override |
|||
@Transactional(rollbackFor = Exception.class) |
|||
public void update(User resources) throws Exception { |
|||
User user = userRepository.findById(resources.getId()).orElseGet(User::new); |
|||
ValidationUtil.isNull(user.getId(), "User", "id", resources.getId()); |
|||
User user1 = userRepository.findByUsername(resources.getUsername()); |
|||
User user2 = userRepository.findByEmail(resources.getEmail()); |
|||
User user3 = userRepository.findByPhone(resources.getPhone()); |
|||
if (user1 != null && !user.getId().equals(user1.getId())) { |
|||
throw new BaseException("username", resources.getUsername()); |
|||
} |
|||
if (user2 != null && !user.getId().equals(user2.getId())) { |
|||
throw new BaseException("email", resources.getEmail()); |
|||
} |
|||
if (user3 != null && !user.getId().equals(user3.getId())) { |
|||
throw new BaseException("phone", resources.getPhone()); |
|||
} |
|||
// 如果用户的角色改变 |
|||
if (!resources.getRoles().equals(user.getRoles())) { |
|||
redisUtils.del(CacheKey.DATA_USER + resources.getId()); |
|||
redisUtils.del(CacheKey.MENU_USER + resources.getId()); |
|||
redisUtils.del(CacheKey.ROLE_AUTH + resources.getId()); |
|||
} |
|||
// 如果用户被禁用,则清除用户登录信息 |
|||
if(!resources.getEnabled()){ |
|||
onlineUserService.kickOutForUsername(resources.getUsername()); |
|||
} |
|||
user.setUsername(resources.getUsername()); |
|||
user.setEmail(resources.getEmail()); |
|||
user.setEnabled(resources.getEnabled()); |
|||
user.setRoles(resources.getRoles()); |
|||
user.setDept(resources.getDept()); |
|||
user.setJobs(resources.getJobs()); |
|||
user.setPhone(resources.getPhone()); |
|||
user.setNickName(resources.getNickName()); |
|||
user.setGender(resources.getGender()); |
|||
userRepository.save(user); |
|||
// 清除缓存 |
|||
delCaches(user.getId(), user.getUsername()); |
|||
} |
|||
|
|||
@Override |
|||
@Transactional(rollbackFor = Exception.class) |
|||
public void updateCenter(User resources) { |
|||
User user = userRepository.findById(resources.getId()).orElseGet(User::new); |
|||
User user1 = userRepository.findByPhone(resources.getPhone()); |
|||
if (user1 != null && !user.getId().equals(user1.getId())) { |
|||
throw new BaseException("Bad is phone", resources.getPhone()); |
|||
} |
|||
user.setNickName(resources.getNickName()); |
|||
user.setPhone(resources.getPhone()); |
|||
user.setGender(resources.getGender()); |
|||
userRepository.save(user); |
|||
// 清理缓存 |
|||
delCaches(user.getId(), user.getUsername()); |
|||
} |
|||
|
|||
@Override |
|||
@Transactional(rollbackFor = Exception.class) |
|||
public void delete(Set<Long> ids) { |
|||
for (Long id : ids) { |
|||
// 清理缓存 |
|||
UserDto user = findById(id); |
|||
delCaches(user.getId(), user.getUsername()); |
|||
} |
|||
userRepository.deleteAllByIdIn(ids); |
|||
} |
|||
|
|||
@Override |
|||
public UserDto findByName(String userName) { |
|||
User user = userRepository.findByUsername(userName); |
|||
if (user == null) { |
|||
throw new BaseException("name is not null", userName); |
|||
} else { |
|||
return userMapper.toDto(user); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
@Transactional(rollbackFor = Exception.class) |
|||
public void updatePass(String username, String pass) { |
|||
userRepository.updatePass(username, pass, new Date()); |
|||
flushCache(username); |
|||
} |
|||
|
|||
@Override |
|||
@Transactional(rollbackFor = Exception.class) |
|||
public Map<String, String> updateAvatar(MultipartFile multipartFile) { |
|||
// 文件大小验证 |
|||
FileUtil.checkSize(properties.getAvatarMaxSize(), multipartFile.getSize()); |
|||
// 验证文件上传的格式 |
|||
String image = "gif jpg png jpeg"; |
|||
String fileType = FileUtil.getExtensionName(multipartFile.getOriginalFilename()); |
|||
if(fileType != null && !image.contains(fileType)){ |
|||
throw new BaseException("文件格式错误!, 仅支持 " + image +" 格式"); |
|||
} |
|||
User user = userRepository.findByUsername(SecurityUtils.getCurrentUsername()); |
|||
String oldPath = user.getAvatarPath(); |
|||
File file = FileUtil.upload(multipartFile, properties.getPath().getAvatar()); |
|||
user.setAvatarPath(Objects.requireNonNull(file).getPath()); |
|||
user.setAvatarName(file.getName()); |
|||
userRepository.save(user); |
|||
if (StringUtils.isNotBlank(oldPath)) { |
|||
FileUtil.del(oldPath); |
|||
} |
|||
@NotBlank String username = user.getUsername(); |
|||
flushCache(username); |
|||
return new HashMap<String, String>(1) {{ |
|||
put("avatar", file.getName()); |
|||
}}; |
|||
} |
|||
|
|||
@Override |
|||
@Transactional(rollbackFor = Exception.class) |
|||
public void updateEmail(String username, String email) { |
|||
userRepository.updateEmail(username, email); |
|||
flushCache(username); |
|||
} |
|||
|
|||
@Override |
|||
public void download(List<UserDto> queryAll, HttpServletResponse response) throws IOException { |
|||
List<Map<String, Object>> list = new ArrayList<>(); |
|||
for (UserDto userDTO : queryAll) { |
|||
List<String> roles = userDTO.getRoles().stream().map(RoleSmallDto::getName).collect(Collectors.toList()); |
|||
Map<String, Object> map = new LinkedHashMap<>(); |
|||
map.put("用户名", userDTO.getUsername()); |
|||
map.put("角色", roles); |
|||
map.put("部门", userDTO.getDept().getName()); |
|||
map.put("岗位", userDTO.getJobs().stream().map(JobSmallDto::getName).collect(Collectors.toList())); |
|||
map.put("邮箱", userDTO.getEmail()); |
|||
map.put("状态", userDTO.getEnabled() ? "启用" : "禁用"); |
|||
map.put("手机号码", userDTO.getPhone()); |
|||
map.put("修改密码的时间", userDTO.getPwdResetTime()); |
|||
map.put("创建日期", userDTO.getCreateTime()); |
|||
list.add(map); |
|||
} |
|||
FileUtil.downloadExcel(list, response); |
|||
} |
|||
|
|||
/** |
|||
* 清理缓存 |
|||
* |
|||
* @param id / |
|||
*/ |
|||
public void delCaches(Long id, String username) { |
|||
redisUtils.del(CacheKey.USER_ID + id); |
|||
flushCache(username); |
|||
} |
|||
|
|||
/** |
|||
* 清理 登陆时 用户缓存信息 |
|||
* |
|||
* @param username / |
|||
*/ |
|||
private void flushCache(String username) { |
|||
userCacheClean.cleanUserCache(username); |
|||
} |
|||
} |
@ -0,0 +1,12 @@ |
|||
package com.storeroom.modules.system.service.mapstruct; |
|||
|
|||
import com.storeroom.base.BaseMapper; |
|||
import com.storeroom.modules.system.domain.Dept; |
|||
import com.storeroom.modules.system.service.dto.DeptDto; |
|||
import org.mapstruct.Mapper; |
|||
import org.mapstruct.ReportingPolicy; |
|||
|
|||
|
|||
@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) |
|||
public interface DeptMapper extends BaseMapper<DeptDto, Dept> { |
|||
} |
@ -0,0 +1,11 @@ |
|||
package com.storeroom.modules.system.service.mapstruct; |
|||
|
|||
import com.storeroom.base.BaseMapper; |
|||
import com.storeroom.modules.system.domain.DictDetail; |
|||
import com.storeroom.modules.system.service.dto.DictDetailDto; |
|||
import org.mapstruct.Mapper; |
|||
import org.mapstruct.ReportingPolicy; |
|||
|
|||
@Mapper(componentModel = "spring", uses = {DictSmallMapper.class}, unmappedTargetPolicy = ReportingPolicy.IGNORE) |
|||
public interface DictDetailMapper extends BaseMapper<DictDetailDto, DictDetail> { |
|||
} |
@ -0,0 +1,11 @@ |
|||
package com.storeroom.modules.system.service.mapstruct; |
|||
|
|||
import com.storeroom.base.BaseMapper; |
|||
import com.storeroom.modules.system.domain.Dict; |
|||
import com.storeroom.modules.system.service.dto.DictDto; |
|||
import org.mapstruct.Mapper; |
|||
import org.mapstruct.ReportingPolicy; |
|||
|
|||
@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) |
|||
public interface DictMapper extends BaseMapper<DictDto, Dict> { |
|||
} |
@ -0,0 +1,12 @@ |
|||
package com.storeroom.modules.system.service.mapstruct; |
|||
|
|||
import com.storeroom.base.BaseMapper; |
|||
import com.storeroom.modules.system.domain.Dict; |
|||
import com.storeroom.modules.system.service.dto.DictSmallDto; |
|||
import org.mapstruct.Mapper; |
|||
import org.mapstruct.ReportingPolicy; |
|||
|
|||
|
|||
@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) |
|||
public interface DictSmallMapper extends BaseMapper<DictSmallDto, Dict> { |
|||
} |
@ -0,0 +1,12 @@ |
|||
package com.storeroom.modules.system.service.mapstruct; |
|||
|
|||
import com.storeroom.base.BaseMapper; |
|||
import com.storeroom.modules.system.domain.Job; |
|||
import com.storeroom.modules.system.service.dto.JobDto; |
|||
import org.mapstruct.Mapper; |
|||
import org.mapstruct.ReportingPolicy; |
|||
|
|||
|
|||
@Mapper(componentModel = "spring",uses = {DeptMapper.class},unmappedTargetPolicy = ReportingPolicy.IGNORE) |
|||
public interface JobMapper extends BaseMapper<JobDto, Job> { |
|||
} |
@ -0,0 +1,12 @@ |
|||
package com.storeroom.modules.system.service.mapstruct; |
|||
|
|||
import com.storeroom.base.BaseMapper; |
|||
import com.storeroom.modules.system.domain.Menu; |
|||
import com.storeroom.modules.system.service.dto.MenuDto; |
|||
import org.mapstruct.Mapper; |
|||
import org.mapstruct.ReportingPolicy; |
|||
|
|||
|
|||
@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) |
|||
public interface MenuMapper extends BaseMapper<MenuDto, Menu> { |
|||
} |
@ -0,0 +1,12 @@ |
|||
package com.storeroom.modules.system.service.mapstruct; |
|||
|
|||
|
|||
import com.storeroom.base.BaseMapper; |
|||
import com.storeroom.modules.system.domain.Role; |
|||
import com.storeroom.modules.system.service.dto.RoleDto; |
|||
import org.mapstruct.Mapper; |
|||
import org.mapstruct.ReportingPolicy; |
|||
|
|||
@Mapper(componentModel = "spring", uses = {MenuMapper.class, DeptMapper.class}, unmappedTargetPolicy = ReportingPolicy.IGNORE) |
|||
public interface RoleMapper extends BaseMapper<RoleDto, Role> { |
|||
} |
@ -0,0 +1,12 @@ |
|||
package com.storeroom.modules.system.service.mapstruct; |
|||
|
|||
import com.storeroom.base.BaseMapper; |
|||
import com.storeroom.modules.system.domain.Role; |
|||
import com.storeroom.modules.system.service.dto.RoleSmallDto; |
|||
import org.mapstruct.Mapper; |
|||
import org.mapstruct.ReportingPolicy; |
|||
|
|||
|
|||
@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE) |
|||
public interface RoleSmallMapper extends BaseMapper<RoleSmallDto, Role> { |
|||
} |
@ -0,0 +1,12 @@ |
|||
package com.storeroom.modules.system.service.mapstruct; |
|||
|
|||
|
|||
import com.storeroom.base.BaseMapper; |
|||
import com.storeroom.modules.system.domain.User; |
|||
import com.storeroom.modules.system.service.dto.UserDto; |
|||
import org.mapstruct.Mapper; |
|||
import org.mapstruct.ReportingPolicy; |
|||
|
|||
@Mapper(componentModel = "spring",uses = {RoleMapper.class, DeptMapper.class, JobMapper.class},unmappedTargetPolicy = ReportingPolicy.IGNORE) |
|||
public interface UserMapper extends BaseMapper<UserDto, User> { |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue