Compare commits
4 Commits
7624d94145
...
db55b2f748
Author | SHA1 | Date | |
---|---|---|---|
db55b2f748 | |||
ee8d7d16d0 | |||
b4da8c3bf0 | |||
e4bf57f3ec |
16
pom.xml
16
pom.xml
@ -142,6 +142,22 @@
|
||||
<version>3.0.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>2.0.16</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
<version>0.9.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
|
@ -2,11 +2,10 @@ package com.zsc.edu.gateway;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
|
||||
/**
|
||||
* @author zhuang
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@EnableAspectJAutoProxy
|
||||
public class IotGatewayApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
@ -2,15 +2,11 @@ package com.zsc.edu.gateway.framework.security;
|
||||
|
||||
import com.zsc.edu.gateway.common.util.TreeUtil;
|
||||
import com.zsc.edu.gateway.exception.StateException;
|
||||
import com.zsc.edu.gateway.modules.system.entity.Dept;
|
||||
import com.zsc.edu.gateway.modules.system.entity.Menu;
|
||||
import com.zsc.edu.gateway.modules.system.entity.RoleAuthority;
|
||||
import com.zsc.edu.gateway.modules.system.entity.User;
|
||||
import com.zsc.edu.gateway.modules.system.repo.AuthorityRepository;
|
||||
import com.zsc.edu.gateway.modules.system.repo.MenuRepository;
|
||||
import com.zsc.edu.gateway.modules.system.repo.RoleAuthoritiesRepository;
|
||||
import com.zsc.edu.gateway.modules.system.repo.UserRepository;
|
||||
import com.zsc.edu.gateway.modules.system.entity.*;
|
||||
import com.zsc.edu.gateway.modules.system.repo.*;
|
||||
import com.zsc.edu.gateway.modules.system.service.DeptService;
|
||||
import com.zsc.edu.gateway.modules.system.service.RoleService;
|
||||
import com.zsc.edu.gateway.modules.system.service.impl.RoleServiceImpl;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
@ -33,6 +29,9 @@ public class JpaUserDetailsServiceImpl implements UserDetailsService {
|
||||
private final AuthorityRepository authorityRepository;
|
||||
private final MenuRepository menuRepository;
|
||||
private final DeptService deptService;
|
||||
private final RoleRepository roleRepository;
|
||||
private final RoleService roleService;
|
||||
private final UserRolesRepository userRolesRepository;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@ -41,6 +40,9 @@ public class JpaUserDetailsServiceImpl implements UserDetailsService {
|
||||
if (!user.getEnableState()) {
|
||||
throw new StateException("用户 '" + username + "' 已被禁用!请联系管理员");
|
||||
}
|
||||
List<Long> roleIds = userRolesRepository.selectByUserId(user.getId());
|
||||
List<Role> roles = roleRepository.selectByIds(roleIds);
|
||||
user.setRoles(roles);
|
||||
List<Dept> depts = deptService.listTree(user.deptId);
|
||||
List<Dept> flat = TreeUtil.flat(depts, Dept::getChildren, d -> d.setChildren(null));
|
||||
Set<Long> dataScopeDeptIds = flat.stream().map(Dept::getId).collect(Collectors.toSet());
|
||||
|
@ -11,6 +11,7 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -32,11 +33,12 @@ public class UserDetailsImpl implements UserDetails {
|
||||
public String name;
|
||||
public Dept dept;
|
||||
public Role role;
|
||||
public List<Role> roles;
|
||||
public Set<Authority> authorities;
|
||||
public Set<String> permissions;
|
||||
public Set<Long> dataScopeDeptIds;
|
||||
|
||||
public UserDetailsImpl(Long id, String username, String password, String name, Boolean enableState, Dept dept, Set<Long> dataScopeDeptIds, Role role, Set<Authority> authorities, Set<String> permissions) {
|
||||
public UserDetailsImpl(Long id, String username, String password, String name, Boolean enableState, Dept dept, Set<Long> dataScopeDeptIds, Role role, Set<Authority> authorities, Set<String> permissions, List<Role> roles) {
|
||||
this.id = id;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
@ -47,6 +49,7 @@ public class UserDetailsImpl implements UserDetails {
|
||||
this.role = role;
|
||||
this.authorities = authorities;
|
||||
this.permissions = permissions;
|
||||
this.roles = roles;
|
||||
}
|
||||
|
||||
public static UserDetailsImpl from(User user, Set<String> permissions) {
|
||||
@ -60,7 +63,8 @@ public class UserDetailsImpl implements UserDetails {
|
||||
user.dataScopeDeptIds,
|
||||
user.role,
|
||||
user.role.authorities,
|
||||
permissions
|
||||
permissions,
|
||||
user.roles
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -51,9 +51,9 @@ public class BulletinServiceImpl extends ServiceImpl<BulletinRepository, Bulleti
|
||||
if (state != null) {
|
||||
bulletinVo.getState().checkStatus(state);
|
||||
}
|
||||
bulletinVo.setEditUsername(userRepository.selectNameById(bulletinVo.getEditUserId()));
|
||||
bulletinVo.setPublishUsername(userRepository.selectNameById(bulletinVo.getPublishUserId()));
|
||||
bulletinVo.setCloseUsername(userRepository.selectNameById(bulletinVo.getCloseUserId()));
|
||||
bulletinVo.setEditUsername(UserRepository.selectNameById(bulletinVo.getEditUserId()));
|
||||
bulletinVo.setPublishUsername(UserRepository.selectNameById(bulletinVo.getPublishUserId()));
|
||||
bulletinVo.setCloseUsername(UserRepository.selectNameById(bulletinVo.getCloseUserId()));
|
||||
return bulletinVo;
|
||||
}
|
||||
/**
|
||||
|
@ -0,0 +1,48 @@
|
||||
package com.zsc.edu.gateway.modules.operationLog.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.zsc.edu.gateway.modules.operationLog.entity.OperationLog;
|
||||
import com.zsc.edu.gateway.modules.operationLog.query.OperationLogQuery;
|
||||
import com.zsc.edu.gateway.modules.operationLog.repo.OperationLogRepository;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author zhuang
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/api/rest/log")
|
||||
public class OperationController {
|
||||
private OperationLogRepository repo;
|
||||
|
||||
/**
|
||||
* 获取操作日志详情
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public OperationLog crate(@PathVariable("id") Long id) {
|
||||
return repo.selectById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取操作日志分页
|
||||
*/
|
||||
@GetMapping("")
|
||||
public Page<OperationLog> query(Page<OperationLog> page, OperationLogQuery query) {
|
||||
return repo.selectPage(page, query.wrapper());
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除操作日志
|
||||
*/
|
||||
@DeleteMapping("/batch")
|
||||
public int deleteBatch(@RequestBody List<Long> ids) {
|
||||
LambdaQueryWrapper<OperationLog> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.in(OperationLog::getId, ids);
|
||||
return repo.delete(wrapper);
|
||||
}
|
||||
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
package com.zsc.edu.gateway.modules.operationLog.dto;
|
||||
|
||||
import com.zsc.edu.gateway.modules.operationLog.entity.OperationLog;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @author zhuang
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class OperationLogDto {
|
||||
/**
|
||||
* 模块类型
|
||||
*/
|
||||
private OperationLog.ModelType modelType;
|
||||
|
||||
/**
|
||||
* 操作类型
|
||||
*/
|
||||
private OperationLog.OperationType operationType;
|
||||
|
||||
/**
|
||||
* 操作内容
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 操作时间
|
||||
*/
|
||||
private LocalDateTime makeTime;
|
||||
}
|
@ -1,5 +1,8 @@
|
||||
package com.zsc.edu.gateway.modules.operationLog.entity;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class ExpressionRootObject {
|
||||
private final Object object;
|
||||
private final Object[] args;
|
||||
@ -9,11 +12,4 @@ public class ExpressionRootObject {
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public Object getObject() {
|
||||
return object;
|
||||
}
|
||||
|
||||
public Object[] getArgs() {
|
||||
return args;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,51 @@
|
||||
package com.zsc.edu.gateway.modules.operationLog.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IEnum;
|
||||
import com.zsc.edu.gateway.common.enums.IState;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author lenovo
|
||||
*/
|
||||
|
||||
@Getter
|
||||
public enum FunctionTypeEnum implements IEnum<String>, IState<FunctionTypeEnum> {
|
||||
save("save", "save"),
|
||||
update("update", "update"),
|
||||
delete("delete", "delete"),
|
||||
query("query", "query"),
|
||||
other("other", "other");
|
||||
|
||||
private final String code;
|
||||
private final String message;
|
||||
|
||||
FunctionTypeEnum(String code, String message) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.message;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据代码获取消息
|
||||
*
|
||||
* @param code 代码
|
||||
* @return 消息
|
||||
*/
|
||||
public static String getMessageByCode(String code) {
|
||||
for (FunctionTypeEnum type : FunctionTypeEnum.values()) {
|
||||
if (type.getCode().equalsIgnoreCase(code)) {
|
||||
return type.getMessage();
|
||||
}
|
||||
}
|
||||
return other.getMessage();
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
package com.zsc.edu.gateway.modules.operationLog.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IEnum;
|
||||
import com.zsc.edu.gateway.common.enums.IState;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author lenovo
|
||||
*/
|
||||
@Getter
|
||||
public enum ModuleTypeEnum implements IEnum<String>, IState<ModuleTypeEnum> {
|
||||
user("user", "user"),
|
||||
role("role", "role"),
|
||||
menu("menu", "menu"),
|
||||
dept("dept", "dept"),
|
||||
device("device", "device"),
|
||||
product("product", "product"),
|
||||
serve("serve", "serve"),
|
||||
event("event", "event"),
|
||||
property("property", "property"),
|
||||
notice("notice", "notice"),
|
||||
bulletin("bulletin", "bulletin"),
|
||||
attachment("attachment", "attachment"),
|
||||
other("other", "other");
|
||||
|
||||
private final String code;
|
||||
private final String messageCode;
|
||||
|
||||
private static final Map<String, ModuleTypeEnum> CODE_MAP = Arrays.stream(values())
|
||||
.collect(Collectors.toMap(
|
||||
type -> type.getCode().toLowerCase(),
|
||||
type -> type
|
||||
));
|
||||
|
||||
ModuleTypeEnum(String code, String message) {
|
||||
this.code = code;
|
||||
this.messageCode = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.messageCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据代码获取消息
|
||||
*
|
||||
* @param code 代码
|
||||
* @return 消息
|
||||
*/
|
||||
public static String getMessageByCode(String code) {
|
||||
ModuleTypeEnum type = CODE_MAP.get(code.toLowerCase());
|
||||
return Objects.requireNonNullElse(type, other).getMessageCode();
|
||||
}
|
||||
|
||||
}
|
@ -1,10 +1,8 @@
|
||||
package com.zsc.edu.gateway.modules.operationLog.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IEnum;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.zsc.edu.gateway.common.enums.IState;
|
||||
import lombok.*;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
@ -27,12 +25,12 @@ public class OperationLog {
|
||||
/**
|
||||
* 模块类型
|
||||
*/
|
||||
private ModelType modelType;
|
||||
private ModuleTypeEnum moduleType;
|
||||
|
||||
/**
|
||||
* 操作类型
|
||||
*/
|
||||
private OperationType operationType;
|
||||
private FunctionTypeEnum functionType;
|
||||
|
||||
/**
|
||||
* 操作内容
|
||||
@ -43,53 +41,4 @@ public class OperationLog {
|
||||
* 操作时间
|
||||
*/
|
||||
private LocalDateTime makeTime;
|
||||
|
||||
public enum ModelType implements IEnum<Integer>, IState<ModelType> {
|
||||
ATTACHMENT(1, "附件模块"),
|
||||
IOT(2, "物模型模块"),
|
||||
MESSAGE(3, "公告消息模块"),
|
||||
SYSTEM(4, "系统模块");
|
||||
|
||||
private final Integer value;
|
||||
private final String name;
|
||||
|
||||
ModelType(int value, String name) {
|
||||
this.value = value;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
|
||||
public enum OperationType implements IEnum<Integer>, IState<OperationType> {
|
||||
CREATE(1, "添加"),
|
||||
UPDATE(2, "更新"),
|
||||
DELETE(3, "删除");
|
||||
|
||||
private final Integer value;
|
||||
private final String name;
|
||||
|
||||
OperationType(int value, String name) {
|
||||
this.value = value;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,4 +13,9 @@ public @interface OperationLogAnnotation {
|
||||
* 日志内容,支持SpEL表达式
|
||||
*/
|
||||
String content() default "";
|
||||
|
||||
/**
|
||||
* 操作类型,例如:SAVE, UPDATE, DELETE, QUERY
|
||||
*/
|
||||
String operationType() default "";
|
||||
}
|
||||
|
@ -1,15 +0,0 @@
|
||||
package com.zsc.edu.gateway.modules.operationLog.mapper;
|
||||
|
||||
import com.zsc.edu.gateway.common.mapstruct.BaseMapper;
|
||||
import com.zsc.edu.gateway.modules.operationLog.dto.OperationLogDto;
|
||||
import com.zsc.edu.gateway.modules.operationLog.entity.OperationLog;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.MappingConstants;
|
||||
import org.mapstruct.ReportingPolicy;
|
||||
|
||||
/**
|
||||
* @author zhuang
|
||||
*/
|
||||
@Mapper(componentModel = MappingConstants.ComponentModel.SPRING, unmappedTargetPolicy = ReportingPolicy.IGNORE)
|
||||
public interface OperationLogMapper extends BaseMapper<OperationLog, OperationLogDto> {
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package com.zsc.edu.gateway.modules.operationLog.query;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.zsc.edu.gateway.modules.operationLog.entity.OperationLog;
|
||||
import com.zsc.edu.gateway.modules.operationLog.entity.FunctionTypeEnum;
|
||||
import com.zsc.edu.gateway.modules.operationLog.entity.ModuleTypeEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author zhuang
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class OperationLogQuery {
|
||||
private String username;
|
||||
private ModuleTypeEnum moduleType;
|
||||
private FunctionTypeEnum functionType;
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime publishTimeBegin;
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime publishTimeEnd;
|
||||
|
||||
public LambdaQueryWrapper<OperationLog> wrapper() {
|
||||
LambdaQueryWrapper<OperationLog> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.like(StringUtils.hasText(this.username), OperationLog::getContent, this.username);
|
||||
queryWrapper.eq(Objects.nonNull(this.moduleType), OperationLog::getModuleType, this.moduleType);
|
||||
queryWrapper.eq(Objects.nonNull(this.functionType), OperationLog::getFunctionType, this.functionType);
|
||||
if (publishTimeBegin != null && publishTimeEnd != null) {
|
||||
queryWrapper.between(OperationLog::getMakeTime, this.publishTimeBegin, this.publishTimeEnd);
|
||||
}
|
||||
return queryWrapper;
|
||||
}
|
||||
}
|
@ -3,5 +3,8 @@ package com.zsc.edu.gateway.modules.operationLog.repo;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.zsc.edu.gateway.modules.operationLog.entity.OperationLog;
|
||||
|
||||
/**
|
||||
* @author zhuang
|
||||
*/
|
||||
public interface OperationLogRepository extends BaseMapper<OperationLog> {
|
||||
}
|
||||
|
@ -1,7 +0,0 @@
|
||||
package com.zsc.edu.gateway.modules.operationLog.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.zsc.edu.gateway.modules.operationLog.entity.OperationLog;
|
||||
|
||||
public interface OperationLogService extends IService<OperationLog> {
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
package com.zsc.edu.gateway.modules.operationLog.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.zsc.edu.gateway.modules.operationLog.entity.OperationLog;
|
||||
import com.zsc.edu.gateway.modules.operationLog.repo.OperationLogRepository;
|
||||
import com.zsc.edu.gateway.modules.operationLog.service.OperationLogService;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author zhuang
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Service
|
||||
public class OperationLogServiceImpl extends ServiceImpl<OperationLogRepository, OperationLog> implements OperationLogService {
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package com.zsc.edu.gateway.modules.operationLog.util;
|
||||
|
||||
|
||||
import com.zsc.edu.gateway.modules.operationLog.entity.ExpressionRootObject;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.context.expression.AnnotatedElementKey;
|
||||
import org.springframework.context.expression.CachedExpressionEvaluator;
|
||||
import org.springframework.context.expression.MethodBasedEvaluationContext;
|
||||
import org.springframework.core.DefaultParameterNameDiscoverer;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.expression.Expression;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class ExpressionEvaluator<T> extends CachedExpressionEvaluator {
|
||||
private final ParameterNameDiscoverer paramNameDiscoverer = (ParameterNameDiscoverer) new DefaultParameterNameDiscoverer();
|
||||
private final Map<ExpressionKey, Expression> conditionCache = new ConcurrentHashMap<>(64);
|
||||
private final Map<AnnotatedElementKey, Method> targetMethodCache = new ConcurrentHashMap<>(64);
|
||||
|
||||
public MethodBasedEvaluationContext createEvaluationContext(Object object, Class<?> targetClass, Method method, Object[] args) {
|
||||
Method targetMethod = getTargetMethod(targetClass, method);
|
||||
ExpressionRootObject root = new ExpressionRootObject(object, args);
|
||||
return new MethodBasedEvaluationContext(root, targetMethod, args, this.paramNameDiscoverer);
|
||||
}
|
||||
|
||||
public T condition(String conditionExpression, AnnotatedElementKey elementKey, MethodBasedEvaluationContext evalContext, Class<String> clazz) {
|
||||
return (T) getExpression(this.conditionCache, elementKey, conditionExpression).getValue(evalContext, clazz);
|
||||
}
|
||||
|
||||
private Method getTargetMethod(Class<?> targetClass, Method method) {
|
||||
AnnotatedElementKey methodKey = new AnnotatedElementKey(method, targetClass);
|
||||
Method targetMethod = this.targetMethodCache.get(methodKey);
|
||||
if (targetMethod == null) {
|
||||
targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
|
||||
this.targetMethodCache.put(methodKey, targetMethod);
|
||||
}
|
||||
return targetMethod;
|
||||
}
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
package com.zsc.edu.gateway.modules.operationLog.util;
|
||||
|
||||
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
||||
import com.zsc.edu.gateway.framework.security.UserDetailsImpl;
|
||||
import com.zsc.edu.gateway.modules.operationLog.entity.FunctionTypeEnum;
|
||||
import com.zsc.edu.gateway.modules.operationLog.entity.ModuleTypeEnum;
|
||||
import com.zsc.edu.gateway.modules.operationLog.entity.OperationLog;
|
||||
import com.zsc.edu.gateway.modules.operationLog.entity.OperationLogAnnotation;
|
||||
import com.zsc.edu.gateway.modules.operationLog.repo.OperationLogRepository;
|
||||
import com.zsc.edu.gateway.modules.system.repo.UserRepository;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.annotation.AfterReturning;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.context.expression.AnnotatedElementKey;
|
||||
import org.springframework.context.expression.MethodBasedEvaluationContext;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @author zhuang
|
||||
*/
|
||||
@Slf4j
|
||||
@Aspect
|
||||
@Component
|
||||
public class OperationLogAspect {
|
||||
|
||||
private static final ExpressionEvaluator<String> EVALUATOR = new ExpressionEvaluator<>();
|
||||
|
||||
@Resource
|
||||
OperationLogRepository operationLogRepository;
|
||||
@Resource
|
||||
UserRepository userRepository;
|
||||
|
||||
/**
|
||||
* 被执行方法上添加OperationLogAnnotation注解的才会执行这个方法
|
||||
*/
|
||||
@AfterReturning(pointcut = "@annotation(com.zsc.edu.gateway.modules.operationLog.entity.OperationLogAnnotation)", returning = "jsonResult")
|
||||
public void doAfterReturning(JoinPoint joinPoint, Object jsonResult) {
|
||||
handleOperationLog(joinPoint, jsonResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作日志处理逻辑,包括:格式处理,持久化
|
||||
*/
|
||||
protected void handleOperationLog(final JoinPoint joinPoint, Object jsonResult) {
|
||||
|
||||
OperationLogAnnotation operationLogAnnotation = ((MethodSignature) joinPoint.getSignature()).getMethod().
|
||||
getAnnotation(OperationLogAnnotation.class);
|
||||
|
||||
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||
HttpServletRequest request = attributes.getRequest();
|
||||
|
||||
// 获取方法名
|
||||
String methodName = joinPoint.getSignature().getName().toLowerCase();
|
||||
// 根据方法名判定方法类型
|
||||
String methodType = FunctionTypeEnum.getMessageByCode(methodName);
|
||||
|
||||
// 获取类名
|
||||
String className = joinPoint.getTarget().getClass().getSimpleName().toLowerCase();
|
||||
String moduleType = className.substring(0, className.length() - "controller".length());
|
||||
moduleType = ModuleTypeEnum.getMessageByCode(moduleType);
|
||||
|
||||
|
||||
// 使用SecurityContextHolder获取当前用户信息
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
if (authentication != null && authentication.isAuthenticated()) {
|
||||
UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
|
||||
|
||||
// content的默认值为返回结果
|
||||
String content = "";
|
||||
|
||||
// 获取operationLogAnnotation注解的content内容
|
||||
if (StringUtils.isNotBlank(operationLogAnnotation.content())) {
|
||||
// 解析EL表达式
|
||||
content = this.evalExpression(joinPoint, operationLogAnnotation.content());
|
||||
log.info("expression:{}", content);
|
||||
}
|
||||
|
||||
// 获取操作类型
|
||||
String operationType = operationLogAnnotation.operationType();
|
||||
if (StringUtils.isNotBlank(operationType)) {
|
||||
content = operationType + " " + content;
|
||||
}
|
||||
|
||||
// 添加操作人信息
|
||||
content = "操作人:" + userDetails.getUsername() + " " + content;
|
||||
|
||||
// 操作日志保存到数据库内
|
||||
OperationLog operationLog = new OperationLog();
|
||||
if (StringUtils.isNotBlank(moduleType) && StringUtils.isNotBlank(methodType)) {
|
||||
operationLog.setModuleType(ModuleTypeEnum.valueOf(moduleType));
|
||||
operationLog.setFunctionType(FunctionTypeEnum.valueOf(methodType));
|
||||
operationLog.setContent(content);
|
||||
operationLog.setMakeTime(LocalDateTime.now());
|
||||
operationLogRepository.insert(operationLog);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String evalExpression(JoinPoint point, String expression) {
|
||||
MethodSignature ms = (MethodSignature) point.getSignature();
|
||||
Method method = ms.getMethod();
|
||||
Object[] args = point.getArgs();
|
||||
Object target = point.getTarget();
|
||||
Class<?> targetClass = target.getClass();
|
||||
MethodBasedEvaluationContext context = EVALUATOR.createEvaluationContext(target, target.getClass(), method, args);
|
||||
AnnotatedElementKey elementKey = new AnnotatedElementKey(method, targetClass);
|
||||
return EVALUATOR.condition(expression, elementKey, context, String.class);
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.sun.source.tree.Tree;
|
||||
import com.zsc.edu.gateway.framework.mybatisplus.DataPermission;
|
||||
import com.zsc.edu.gateway.framework.security.UserDetailsImpl;
|
||||
import com.zsc.edu.gateway.modules.operationLog.entity.OperationLogAnnotation;
|
||||
import com.zsc.edu.gateway.modules.system.dto.UserCreateDto;
|
||||
import com.zsc.edu.gateway.modules.system.dto.UserSelfUpdateDto;
|
||||
import com.zsc.edu.gateway.modules.system.dto.UserSelfUpdatePasswordDto;
|
||||
@ -51,6 +52,7 @@ public class UserController {
|
||||
* @param csrfToken csrf令牌
|
||||
* @return 包含csrf令牌和登录用户的认证主体信息
|
||||
*/
|
||||
@OperationLogAnnotation(operationType = "登录")
|
||||
@RequestMapping(value = "me", method = {RequestMethod.POST, RequestMethod.GET})
|
||||
public Map<String, Object> me(@AuthenticationPrincipal Object principal, CsrfToken csrfToken) {
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
@ -59,6 +61,10 @@ public class UserController {
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换角色
|
||||
*/
|
||||
@OperationLogAnnotation(content = "切换角色", operationType = "更新")
|
||||
@PatchMapping("/switch/{roleId}")
|
||||
public UserDetailsImpl switchRole(@PathVariable Long roleId) {
|
||||
return service.switchRole(roleId);
|
||||
@ -90,6 +96,7 @@ public class UserController {
|
||||
* @param dto 表单数据
|
||||
* @return 更新后的用户信息
|
||||
*/
|
||||
@OperationLogAnnotation(content = "信息", operationType = "更新")
|
||||
@PatchMapping("self")
|
||||
public Boolean selfUpdate(
|
||||
@AuthenticationPrincipal UserDetailsImpl userDetails,
|
||||
@ -104,6 +111,8 @@ public class UserController {
|
||||
* @param userDetails 操作用户
|
||||
* @param dto 表单数据
|
||||
*/
|
||||
|
||||
@OperationLogAnnotation(content = "'密码'", operationType = "更新")
|
||||
@PatchMapping("self/update-password")
|
||||
public Boolean selfUpdatePassword(
|
||||
@AuthenticationPrincipal UserDetailsImpl userDetails,
|
||||
@ -138,6 +147,8 @@ public class UserController {
|
||||
* @param dto 表单数据
|
||||
* @return 新建的用户信息
|
||||
*/
|
||||
|
||||
@OperationLogAnnotation(operationType = "新建")
|
||||
@PostMapping
|
||||
@PreAuthorize("hasAuthority('system:user:create')")
|
||||
public Boolean create(@RequestBody UserCreateDto dto) {
|
||||
@ -151,6 +162,7 @@ public class UserController {
|
||||
* @param id ID
|
||||
* @return 更新后的用户
|
||||
*/
|
||||
@OperationLogAnnotation(operationType = "更新")
|
||||
@PatchMapping("{id}")
|
||||
@PreAuthorize("hasAuthority('system:user:update')")
|
||||
public Boolean update(@RequestBody UserUpdateDto dto, @PathVariable("id") Long id) {
|
||||
@ -163,6 +175,7 @@ public class UserController {
|
||||
* @param id ID
|
||||
* @param password 新密码
|
||||
*/
|
||||
@OperationLogAnnotation(content = "'密码'", operationType = "更新")
|
||||
@PatchMapping("{id}/update-password")
|
||||
@PreAuthorize("hasAuthority('system:user:update')")
|
||||
public Boolean updatePassword(@PathVariable("id") Long id, @RequestParam String password) {
|
||||
@ -183,6 +196,7 @@ public class UserController {
|
||||
/**
|
||||
* 删除用户 hasAuthority('SYSTEM:USER:DELETE')
|
||||
* */
|
||||
@OperationLogAnnotation(operationType = "删除")
|
||||
@DeleteMapping("{id}")
|
||||
@PreAuthorize("hasAuthority('system:user:delete')")
|
||||
public Boolean delete(@PathVariable("id") Long id) {
|
||||
|
@ -6,6 +6,9 @@ import lombok.NoArgsConstructor;
|
||||
|
||||
import jakarta.validation.constraints.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 用户新建Dto
|
||||
*
|
||||
@ -53,9 +56,8 @@ public class UserCreateDto {
|
||||
public Long deptId;
|
||||
|
||||
/**
|
||||
* 用户身份集合
|
||||
* 用户当前身份
|
||||
*/
|
||||
@NotEmpty(message = "角色不能为空")
|
||||
public Long roleId;
|
||||
/**
|
||||
* 昵称
|
||||
@ -79,4 +81,9 @@ public class UserCreateDto {
|
||||
*/
|
||||
public Integer code;
|
||||
|
||||
/**
|
||||
* 用户角色id集合
|
||||
*/
|
||||
@NotEmpty(message = "角色集合不能为空")
|
||||
public List<Long> roleIds;
|
||||
}
|
||||
|
@ -12,6 +12,9 @@ import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import jakarta.validation.constraints.Pattern;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 用户更新Dto
|
||||
*
|
||||
@ -59,11 +62,13 @@ public class UserUpdateDto {
|
||||
public String address;
|
||||
|
||||
/**
|
||||
* 用户身份集合
|
||||
* 用户身份
|
||||
*/
|
||||
@NotEmpty(message = "角色不能为空")
|
||||
public Long roleId;
|
||||
|
||||
public String remark;
|
||||
|
||||
@NotEmpty(message = "角色集合不能为空")
|
||||
public List<Long> roleIds;
|
||||
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import lombok.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@ -77,6 +78,12 @@ public class User extends BaseEntity {
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
public Role role;
|
||||
|
||||
/**
|
||||
* 拥有的所有角色
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
public List<Role> roles;
|
||||
/**
|
||||
* 头像
|
||||
*/
|
||||
|
@ -16,5 +16,8 @@ public interface UserRepository extends BaseMapper<User> {
|
||||
User selectByUsername(String username);
|
||||
|
||||
@Select("select sys_user.name from sys_user where sys_user.id=#{id}")
|
||||
String selectNameById(Long id);
|
||||
static String selectNameById(Long id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,9 +2,15 @@ package com.zsc.edu.gateway.modules.system.repo;
|
||||
|
||||
import com.zsc.edu.gateway.modules.system.entity.UserRole;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author zhuang
|
||||
*/
|
||||
public interface UserRolesRepository extends BaseMapper<UserRole> {
|
||||
@Select("select role_id from sys_users_roles where user_id = #{userId}")
|
||||
List<Long> selectByUserId(@Param("userId") Long userId);
|
||||
}
|
@ -5,19 +5,14 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.zsc.edu.gateway.exception.ConstraintException;
|
||||
import com.zsc.edu.gateway.framework.security.SecurityUtil;
|
||||
import com.zsc.edu.gateway.framework.security.UserDetailsImpl;
|
||||
import com.zsc.edu.gateway.modules.operationLog.entity.OperationLogAnnotation;
|
||||
import com.zsc.edu.gateway.modules.system.dto.UserCreateDto;
|
||||
import com.zsc.edu.gateway.modules.system.dto.UserSelfUpdateDto;
|
||||
import com.zsc.edu.gateway.modules.system.dto.UserSelfUpdatePasswordDto;
|
||||
import com.zsc.edu.gateway.modules.system.dto.UserUpdateDto;
|
||||
import com.zsc.edu.gateway.modules.system.entity.Menu;
|
||||
import com.zsc.edu.gateway.modules.system.entity.Role;
|
||||
import com.zsc.edu.gateway.modules.system.entity.RoleMenu;
|
||||
import com.zsc.edu.gateway.modules.system.entity.User;
|
||||
import com.zsc.edu.gateway.modules.system.entity.*;
|
||||
import com.zsc.edu.gateway.modules.system.mapper.UserMapper;
|
||||
import com.zsc.edu.gateway.modules.system.repo.MenuRepository;
|
||||
import com.zsc.edu.gateway.modules.system.repo.RoleMenuRepository;
|
||||
import com.zsc.edu.gateway.modules.system.repo.RoleRepository;
|
||||
import com.zsc.edu.gateway.modules.system.repo.UserRepository;
|
||||
import com.zsc.edu.gateway.modules.system.repo.*;
|
||||
import com.zsc.edu.gateway.modules.system.service.MenuService;
|
||||
import com.zsc.edu.gateway.modules.system.service.UserService;
|
||||
import com.zsc.edu.gateway.modules.system.utils.sendMail;
|
||||
@ -53,14 +48,22 @@ public class UserServiceImpl extends ServiceImpl<UserRepository, User> implement
|
||||
private final RoleMenuRepository RoleMenuRepository;
|
||||
private final RoleMenuRepository roleMenuRepository;
|
||||
private final MenuRepository menuRepository;
|
||||
private final UserRolesRepository userRolesRepository;
|
||||
|
||||
@Override
|
||||
public Boolean create(UserCreateDto dto) {
|
||||
User user = new User();
|
||||
dto.setRoleId(dto.getRoleIds().get(0));
|
||||
userMapper.convert(dto, user);
|
||||
return save(user);
|
||||
boolean saveSuccess = save(user);
|
||||
if (!saveSuccess) {
|
||||
return false;
|
||||
}
|
||||
if (dto.getRoleIds() != null && !dto.getRoleIds().isEmpty()) {
|
||||
addUserRole(dto.getRoleIds(), user.getId());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean update(UserUpdateDto dto, Long id) {
|
||||
User user = getById(id);
|
||||
@ -72,6 +75,11 @@ public class UserServiceImpl extends ServiceImpl<UserRepository, User> implement
|
||||
if (user.getEmail().equals(dto.getEmail()) && existsByEmail) {
|
||||
throw new ConstraintException("email", dto.email, "邮箱地址已存在");
|
||||
}
|
||||
if (dto.getRoleIds() != null && !dto.getRoleIds().isEmpty()) {
|
||||
userRolesRepository.delete(new LambdaQueryWrapper<UserRole>().eq(UserRole::getUserId, id));
|
||||
dto.setRoleId(dto.getRoleIds().get(0));
|
||||
addUserRole(dto.getRoleIds(), user.getId());
|
||||
}
|
||||
BeanUtils.copyProperties(dto, user);
|
||||
return updateById(user);
|
||||
}
|
||||
@ -149,4 +157,16 @@ public class UserServiceImpl extends ServiceImpl<UserRepository, User> implement
|
||||
return userDetails;
|
||||
}
|
||||
|
||||
public Boolean addUserRole(List<Long> roleIds, Long userId) {
|
||||
List<UserRole> userRoles = roleIds.stream()
|
||||
.map(roleId -> {
|
||||
UserRole userRole = new UserRole();
|
||||
userRole.setUserId(userId);
|
||||
userRole.setRoleId(roleId);
|
||||
return userRole;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
userRolesRepository.insert(userRoles);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -54,3 +54,6 @@ storage:
|
||||
attachment: ./storage/attachment
|
||||
temp: ./storage/temp
|
||||
|
||||
jwt:
|
||||
secret: your_secret_key_here
|
||||
expiration: 3600
|
||||
|
@ -766,3 +766,16 @@ VALUES (1, 1, 'user1', 'password1', '13800138000', 'user1@example.com', '张三'
|
||||
'admin', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, '备注4', '启用', 4),
|
||||
(5, 5, 'user5', 'password5', '13800138004', 'user5@example.com', '孙七', 'avatar5.jpg', '杭州市', 'admin',
|
||||
'admin', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, '备注5', '启用', 5);
|
||||
|
||||
INSERT INTO operation_log (module_type, function_type, content, make_time)
|
||||
VALUES ('user', 'create', 'Created a new user', '2023-10-01 10:00:00'),
|
||||
('role', 'update', 'Updated role permissions', '2023-10-01 10:15:00'),
|
||||
('menu', 'delete', 'Deleted a menu item', '2023-10-01 10:30:00'),
|
||||
('dept', 'create', 'Created a new department', '2023-10-01 10:45:00'),
|
||||
('device', 'update', 'Updated device settings', '2023-10-01 11:00:00'),
|
||||
('product', 'create', 'Added a new product', '2023-10-01 11:15:00'),
|
||||
('serve', 'delete', 'Removed a service', '2023-10-01 11:30:00'),
|
||||
('event', 'create', 'Logged an event', '2023-10-01 11:45:00'),
|
||||
('property', 'update', 'Updated property value', '2023-10-01 12:00:00'),
|
||||
('notice', 'create', 'Sent a notice', '2023-10-01 12:15:00');
|
||||
|
||||
|
29
src/main/resources/db/gateway/public/operation_log.sql
Normal file
29
src/main/resources/db/gateway/public/operation_log.sql
Normal file
@ -0,0 +1,29 @@
|
||||
create table operation_log
|
||||
(
|
||||
id bigint generated by default as identity
|
||||
constraint operation_log_pk
|
||||
primary key,
|
||||
module_type varchar not null,
|
||||
function_type varchar not null,
|
||||
content varchar,
|
||||
make_time timestamp
|
||||
);
|
||||
|
||||
comment
|
||||
on column operation_log.id is '主键';
|
||||
|
||||
comment
|
||||
on column operation_log.module_type is '模块类型';
|
||||
|
||||
comment
|
||||
on column operation_log.function_type is '操作类型';
|
||||
|
||||
comment
|
||||
on column operation_log.content is '操作内容';
|
||||
|
||||
comment
|
||||
on column operation_log.make_time is '操作时间';
|
||||
|
||||
alter table operation_log
|
||||
owner to gitea;
|
||||
|
Loading…
Reference in New Issue
Block a user