33 changed files with 2003 additions and 45 deletions
-
18common/src/main/java/com/storeroom/config/RsaProperties.java
-
12system/pom.xml
-
6system/src/main/java/com/storeroom/AppRun.java
-
47system/src/main/java/com/storeroom/config/ConfigurerAdapter.java
-
15system/src/main/java/com/storeroom/config/WebSocketConfig.java
-
51system/src/main/java/com/storeroom/config/thread/AsyncTaskExecutePool.java
-
20system/src/main/java/com/storeroom/config/thread/AsyncTaskProperties.java
-
44system/src/main/java/com/storeroom/config/thread/TheadFactoryName.java
-
22system/src/main/java/com/storeroom/config/thread/ThreadPoolExecutorUtil.java
-
6system/src/main/java/com/storeroom/modules/security/config/ConfigBeanConfiguration.java
-
125system/src/main/java/com/storeroom/modules/security/controller/AuthorizationController.java
-
3system/src/main/java/com/storeroom/modules/security/security/JwtAccessDeniedHandler.java
-
7system/src/main/java/com/storeroom/modules/security/security/JwtAuthenticationEntryPoint.java
-
6system/src/main/java/com/storeroom/modules/security/service/dto/AuthUserDto.java
-
188system/src/main/java/com/storeroom/modules/system/controller/UserController.java
-
17system/src/main/java/com/storeroom/modules/system/repository/DictDetailRepository.java
-
3system/src/main/java/com/storeroom/modules/system/repository/DictRepository.java
-
102system/src/main/java/com/storeroom/modules/system/service/DeptService.java
-
66system/src/main/java/com/storeroom/modules/system/service/JobService.java
-
102system/src/main/java/com/storeroom/modules/system/service/MenuService.java
-
24system/src/main/java/com/storeroom/modules/system/service/dto/JobQueryCriteria.java
-
73system/src/main/java/com/storeroom/modules/system/service/impl/DataServiceImpl.java
-
267system/src/main/java/com/storeroom/modules/system/service/impl/DeptServiceImpl.java
-
80system/src/main/java/com/storeroom/modules/system/service/impl/DictDetailServiceImpl.java
-
104system/src/main/java/com/storeroom/modules/system/service/impl/DictServiceImpl.java
-
106system/src/main/java/com/storeroom/modules/system/service/impl/JobServiceImpl.java
-
339system/src/main/java/com/storeroom/modules/system/service/impl/MenuServiceImpl.java
-
68system/src/main/resources/application-dev.yml
-
43system/src/main/resources/application.yml
-
8system/src/main/resources/banner.txt
-
27system/src/main/resources/generator.properties
-
4system/src/main/resources/log4jdbc.log4j2.properties
-
45system/src/main/resources/logback.xml
@ -0,0 +1,18 @@ |
|||||
|
package com.storeroom.config; |
||||
|
|
||||
|
|
||||
|
import lombok.Data; |
||||
|
import org.springframework.beans.factory.annotation.Value; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
@Data |
||||
|
@Component |
||||
|
public class RsaProperties { |
||||
|
|
||||
|
public static String privateKey; |
||||
|
|
||||
|
@Value("${rsa.private_key}") |
||||
|
public void setPrivateKey(String privateKey) { |
||||
|
RsaProperties.privateKey = privateKey; |
||||
|
} |
||||
|
} |
@ -0,0 +1,47 @@ |
|||||
|
package com.storeroom.config; |
||||
|
|
||||
|
import org.springframework.context.annotation.Bean; |
||||
|
import org.springframework.context.annotation.Configuration; |
||||
|
import org.springframework.web.cors.CorsConfiguration; |
||||
|
import org.springframework.web.cors.UrlBasedCorsConfigurationSource; |
||||
|
import org.springframework.web.filter.CorsFilter; |
||||
|
import org.springframework.web.servlet.config.annotation.EnableWebMvc; |
||||
|
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; |
||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; |
||||
|
|
||||
|
|
||||
|
@Configuration |
||||
|
@EnableWebMvc |
||||
|
public class ConfigurerAdapter implements WebMvcConfigurer { |
||||
|
|
||||
|
/** 文件配置 */ |
||||
|
private final FileProperties properties; |
||||
|
|
||||
|
public ConfigurerAdapter(FileProperties properties) { |
||||
|
this.properties = properties; |
||||
|
} |
||||
|
|
||||
|
@Bean |
||||
|
public CorsFilter corsFilter() { |
||||
|
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); |
||||
|
CorsConfiguration config = new CorsConfiguration(); |
||||
|
config.setAllowCredentials(true); |
||||
|
config.addAllowedOriginPattern("*"); |
||||
|
config.addAllowedHeader("*"); |
||||
|
config.addAllowedMethod("*"); |
||||
|
|
||||
|
|
||||
|
source.registerCorsConfiguration("/**", config); |
||||
|
return new CorsFilter(source); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void addResourceHandlers(ResourceHandlerRegistry registry) { |
||||
|
FileProperties.YsPath path = properties.getPath(); |
||||
|
String avatarUtl = "file:" + path.getAvatar().replace("\\","/"); |
||||
|
String pathUtl = "file:" + path.getPath().replace("\\","/"); |
||||
|
registry.addResourceHandler("/avatar/**").addResourceLocations(avatarUtl).setCachePeriod(0); |
||||
|
registry.addResourceHandler("/file/**").addResourceLocations(pathUtl).setCachePeriod(0); |
||||
|
registry.addResourceHandler("/**").addResourceLocations("classpath:/META-INF/resources/").setCachePeriod(0); |
||||
|
} |
||||
|
} |
@ -0,0 +1,15 @@ |
|||||
|
package com.storeroom.config; |
||||
|
|
||||
|
|
||||
|
import org.springframework.context.annotation.Bean; |
||||
|
import org.springframework.context.annotation.Configuration; |
||||
|
import org.springframework.web.socket.server.standard.ServerEndpointExporter; |
||||
|
|
||||
|
@Configuration |
||||
|
public class WebSocketConfig { |
||||
|
|
||||
|
@Bean |
||||
|
public ServerEndpointExporter serverEndpointExporter() { |
||||
|
return new ServerEndpointExporter(); |
||||
|
} |
||||
|
} |
@ -0,0 +1,51 @@ |
|||||
|
package com.storeroom.config.thread; |
||||
|
|
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; |
||||
|
import org.springframework.context.annotation.Configuration; |
||||
|
import org.springframework.scheduling.annotation.AsyncConfigurer; |
||||
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; |
||||
|
|
||||
|
import java.util.concurrent.Executor; |
||||
|
import java.util.concurrent.ThreadPoolExecutor; |
||||
|
|
||||
|
|
||||
|
@Slf4j |
||||
|
@Configuration |
||||
|
public class AsyncTaskExecutePool implements AsyncConfigurer { |
||||
|
|
||||
|
/** 注入配置类 */ |
||||
|
private final AsyncTaskProperties config; |
||||
|
|
||||
|
public AsyncTaskExecutePool(AsyncTaskProperties config) { |
||||
|
this.config = config; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public Executor getAsyncExecutor() { |
||||
|
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); |
||||
|
//核心线程池大小 |
||||
|
executor.setCorePoolSize(config.getCorePoolSize()); |
||||
|
//最大线程数 |
||||
|
executor.setMaxPoolSize(config.getMaxPoolSize()); |
||||
|
//队列容量 |
||||
|
executor.setQueueCapacity(config.getQueueCapacity()); |
||||
|
//活跃时间 |
||||
|
executor.setKeepAliveSeconds(config.getKeepAliveSeconds()); |
||||
|
//线程名字前缀 |
||||
|
executor.setThreadNamePrefix("yxk-async-"); |
||||
|
// setRejectedExecutionHandler:当pool已经达到max size的时候,如何处理新任务 |
||||
|
// CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行 |
||||
|
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); |
||||
|
executor.initialize(); |
||||
|
return executor; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { |
||||
|
return (throwable, method, objects) -> { |
||||
|
log.error("===="+throwable.getMessage()+"====", throwable); |
||||
|
log.error("exception method:"+method.getName()); |
||||
|
}; |
||||
|
} |
||||
|
} |
@ -0,0 +1,20 @@ |
|||||
|
package com.storeroom.config.thread; |
||||
|
|
||||
|
|
||||
|
import lombok.Data; |
||||
|
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
@Data |
||||
|
@Component |
||||
|
@ConfigurationProperties(prefix = "task.pool") |
||||
|
public class AsyncTaskProperties { |
||||
|
|
||||
|
private int corePoolSize; |
||||
|
|
||||
|
private int maxPoolSize; |
||||
|
|
||||
|
private int keepAliveSeconds; |
||||
|
|
||||
|
private int queueCapacity; |
||||
|
} |
@ -0,0 +1,44 @@ |
|||||
|
package com.storeroom.config.thread; |
||||
|
|
||||
|
import org.springframework.stereotype.Component; |
||||
|
|
||||
|
import java.util.concurrent.ThreadFactory; |
||||
|
import java.util.concurrent.atomic.AtomicInteger; |
||||
|
|
||||
|
|
||||
|
@Component |
||||
|
public class TheadFactoryName implements ThreadFactory { |
||||
|
|
||||
|
private static final AtomicInteger POOL_NUMBER = new AtomicInteger(1); |
||||
|
private final ThreadGroup group; |
||||
|
private final AtomicInteger threadNumber = new AtomicInteger(1); |
||||
|
private final String namePrefix; |
||||
|
|
||||
|
public TheadFactoryName() { |
||||
|
this("yxk-pool"); |
||||
|
} |
||||
|
|
||||
|
private TheadFactoryName(String name){ |
||||
|
SecurityManager s = System.getSecurityManager(); |
||||
|
group = (s != null) ? s.getThreadGroup() : |
||||
|
Thread.currentThread().getThreadGroup(); |
||||
|
//此时namePrefix就是 name + 第几个用这个工厂创建线程池的 |
||||
|
this.namePrefix = name + |
||||
|
POOL_NUMBER.getAndIncrement(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public Thread newThread(Runnable r) { |
||||
|
//此时线程的名字 就是 namePrefix + -thread- + 这个线程池中第几个执行的线程 |
||||
|
Thread t = new Thread(group, r, |
||||
|
namePrefix + "-thread-"+threadNumber.getAndIncrement(), |
||||
|
0); |
||||
|
if (t.isDaemon()) { |
||||
|
t.setDaemon(false); |
||||
|
} |
||||
|
if (t.getPriority() != Thread.NORM_PRIORITY) { |
||||
|
t.setPriority(Thread.NORM_PRIORITY); |
||||
|
} |
||||
|
return t; |
||||
|
} |
||||
|
} |
@ -0,0 +1,22 @@ |
|||||
|
package com.storeroom.config.thread; |
||||
|
|
||||
|
import com.storeroom.utils.SpringContextHolder; |
||||
|
|
||||
|
import java.util.concurrent.ArrayBlockingQueue; |
||||
|
import java.util.concurrent.ThreadPoolExecutor; |
||||
|
import java.util.concurrent.TimeUnit; |
||||
|
|
||||
|
public class ThreadPoolExecutorUtil { |
||||
|
|
||||
|
public static ThreadPoolExecutor getPoll(){ |
||||
|
AsyncTaskProperties properties = SpringContextHolder.getBean(AsyncTaskProperties.class); |
||||
|
return new ThreadPoolExecutor( |
||||
|
properties.getCorePoolSize(), |
||||
|
properties.getMaxPoolSize(), |
||||
|
properties.getKeepAliveSeconds(), |
||||
|
TimeUnit.SECONDS, |
||||
|
new ArrayBlockingQueue<>(properties.getQueueCapacity()), |
||||
|
new TheadFactoryName() |
||||
|
); |
||||
|
} |
||||
|
} |
@ -0,0 +1,125 @@ |
|||||
|
package com.storeroom.modules.security.controller; |
||||
|
|
||||
|
|
||||
|
import cn.hutool.core.util.IdUtil; |
||||
|
import com.storeroom.annotaion.rest.AnonymousDeleteMapping; |
||||
|
import com.storeroom.annotaion.rest.AnonymousGetMapping; |
||||
|
import com.storeroom.annotaion.rest.AnonymousPostMapping; |
||||
|
import com.storeroom.config.RsaProperties; |
||||
|
import com.storeroom.exception.BaseException; |
||||
|
import com.storeroom.exception.constant.ResponseStatus; |
||||
|
import com.storeroom.modules.security.config.bean.LoginCodeEnum; |
||||
|
import com.storeroom.modules.security.config.bean.LoginProperties; |
||||
|
import com.storeroom.modules.security.config.bean.SecurityProperties; |
||||
|
import com.storeroom.modules.security.security.TokenProvider; |
||||
|
import com.storeroom.modules.security.service.OnlineUserService; |
||||
|
import com.storeroom.modules.security.service.dto.AuthUserDto; |
||||
|
import com.storeroom.modules.security.service.dto.JwtUserDto; |
||||
|
import com.storeroom.utils.*; |
||||
|
import com.storeroom.utils.enums.DataStatusEnum; |
||||
|
import com.wf.captcha.base.Captcha; |
||||
|
import io.swagger.annotations.Api; |
||||
|
import io.swagger.annotations.ApiOperation; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.springframework.http.HttpStatus; |
||||
|
import org.springframework.http.ResponseEntity; |
||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; |
||||
|
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; |
||||
|
import org.springframework.security.core.Authentication; |
||||
|
import org.springframework.security.core.context.SecurityContextHolder; |
||||
|
import org.springframework.validation.annotation.Validated; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
|
||||
|
import javax.annotation.Resource; |
||||
|
import javax.servlet.http.HttpServletRequest; |
||||
|
import java.util.HashMap; |
||||
|
import java.util.Map; |
||||
|
import java.util.concurrent.TimeUnit; |
||||
|
|
||||
|
@Slf4j |
||||
|
@RestController |
||||
|
@RequestMapping("/auth") |
||||
|
@RequiredArgsConstructor |
||||
|
@Api(tags = "系统:系统授权接口") |
||||
|
public class AuthorizationController { |
||||
|
|
||||
|
private final SecurityProperties properties; |
||||
|
private final RedisUtils redisUtils; |
||||
|
private final OnlineUserService onlineUserService; |
||||
|
private final TokenProvider tokenProvider; |
||||
|
private final AuthenticationManagerBuilder authenticationManagerBuilder; |
||||
|
|
||||
|
@Resource |
||||
|
private LoginProperties loginProperties; |
||||
|
|
||||
|
|
||||
|
@ApiOperation("登录授权") |
||||
|
@AnonymousPostMapping(value = "/login") |
||||
|
public ApiResponse<Object> login(@Validated @RequestBody AuthUserDto authUser, HttpServletRequest request) throws Exception { |
||||
|
// 密码解密 |
||||
|
String password = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey, authUser.getPassword()); |
||||
|
// 查询验证码 |
||||
|
String code = (String) redisUtils.get(authUser.getUuid()); |
||||
|
// 清除验证码 |
||||
|
redisUtils.del(authUser.getUuid()); |
||||
|
if (StringUtils.isBlank(code)) { |
||||
|
throw new BaseException("验证码不存在或已过期"); |
||||
|
} |
||||
|
if (StringUtils.isBlank(authUser.getCode()) || !authUser.getCode().equalsIgnoreCase(code)) { |
||||
|
throw new BaseException("验证码错误"); |
||||
|
} |
||||
|
UsernamePasswordAuthenticationToken authenticationToken = |
||||
|
new UsernamePasswordAuthenticationToken(authUser.getUsername(), password); |
||||
|
Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken); |
||||
|
SecurityContextHolder.getContext().setAuthentication(authentication); |
||||
|
String token = tokenProvider.createToken(authentication); |
||||
|
final JwtUserDto jwtUserDto = (JwtUserDto) authentication.getPrincipal(); |
||||
|
// 保存在线信息 |
||||
|
onlineUserService.save(jwtUserDto, token, request); |
||||
|
// 返回 token 与 用户信息 |
||||
|
Map<String, Object> authInfo = new HashMap<String, Object>(2) {{ |
||||
|
put("token", properties.getTokenStartWith() + token); |
||||
|
put("user", jwtUserDto); |
||||
|
}}; |
||||
|
if (loginProperties.isSingleLogin()) { |
||||
|
//踢掉之前已经登录的token |
||||
|
onlineUserService.checkLoginOnUser(authUser.getUsername(), token); |
||||
|
} |
||||
|
return ApiResponse.success(authInfo); |
||||
|
} |
||||
|
|
||||
|
@ApiOperation("获取用户信息") |
||||
|
@GetMapping(value = "/info") |
||||
|
public ApiResponse<Object> getUserInfo() { |
||||
|
return ApiResponse.success(SecurityUtils.getCurrentUser()); |
||||
|
} |
||||
|
|
||||
|
@ApiOperation("获取验证码") |
||||
|
@AnonymousGetMapping(value = "/code") |
||||
|
public ApiResponse<Object> getCode() { |
||||
|
// 获取运算的结果 |
||||
|
Captcha captcha = loginProperties.getCaptcha(); |
||||
|
String uuid = properties.getCodeKey() + IdUtil.simpleUUID(); |
||||
|
//当验证码类型为 arithmetic时且长度 >= 2 时,captcha.text()的结果有几率为浮点型 |
||||
|
String captchaValue = captcha.text(); |
||||
|
if (captcha.getCharType() - 1 == LoginCodeEnum.arithmetic.ordinal() && captchaValue.contains(".")) { |
||||
|
captchaValue = captchaValue.split("\\.")[0]; |
||||
|
} |
||||
|
// 保存 |
||||
|
redisUtils.set(uuid, captchaValue, loginProperties.getLoginCode().getExpiration(), TimeUnit.MINUTES); |
||||
|
// 验证码信息 |
||||
|
Map<String, Object> imgResult = new HashMap<String, Object>(2) {{ |
||||
|
put("img", captcha.toBase64()); |
||||
|
put("uuid", uuid); |
||||
|
}}; |
||||
|
return ApiResponse.success(imgResult); |
||||
|
} |
||||
|
|
||||
|
@ApiOperation("退出登录") |
||||
|
@AnonymousDeleteMapping(value = "/logout") |
||||
|
public ApiResponse<Object> logout(HttpServletRequest request) { |
||||
|
onlineUserService.logout(tokenProvider.getToken(request)); |
||||
|
return ApiResponse.success(ResponseStatus.SUCCESS); |
||||
|
} |
||||
|
} |
@ -0,0 +1,188 @@ |
|||||
|
package com.storeroom.modules.system.controller; |
||||
|
|
||||
|
|
||||
|
import cn.hutool.core.collection.CollectionUtil; |
||||
|
import com.storeroom.config.RsaProperties; |
||||
|
import com.storeroom.exception.BaseException; |
||||
|
import com.storeroom.modules.system.domain.Dept; |
||||
|
import com.storeroom.modules.system.domain.User; |
||||
|
import com.storeroom.modules.system.domain.vo.UserPassVo; |
||||
|
import com.storeroom.modules.system.service.DataService; |
||||
|
import com.storeroom.modules.system.service.DeptService; |
||||
|
import com.storeroom.modules.system.service.RoleService; |
||||
|
import com.storeroom.modules.system.service.UserService; |
||||
|
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.utils.PageUtil; |
||||
|
import com.storeroom.utils.RsaUtils; |
||||
|
import com.storeroom.utils.SecurityUtils; |
||||
|
import io.swagger.annotations.Api; |
||||
|
import io.swagger.annotations.ApiOperation; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import org.springframework.data.domain.Pageable; |
||||
|
import org.springframework.http.HttpStatus; |
||||
|
import org.springframework.http.ResponseEntity; |
||||
|
import org.springframework.security.access.prepost.PreAuthorize; |
||||
|
import org.springframework.security.crypto.password.PasswordEncoder; |
||||
|
import org.springframework.util.CollectionUtils; |
||||
|
import org.springframework.util.ObjectUtils; |
||||
|
import org.springframework.validation.annotation.Validated; |
||||
|
import org.springframework.web.bind.annotation.*; |
||||
|
import org.springframework.web.multipart.MultipartFile; |
||||
|
|
||||
|
import javax.servlet.http.HttpServletResponse; |
||||
|
import java.io.IOException; |
||||
|
import java.util.Collections; |
||||
|
import java.util.List; |
||||
|
import java.util.Set; |
||||
|
import java.util.stream.Collectors; |
||||
|
|
||||
|
@Api(tags = "系统:用户管理") |
||||
|
@RestController |
||||
|
@RequestMapping("/api/users") |
||||
|
@RequiredArgsConstructor |
||||
|
public class UserController { |
||||
|
|
||||
|
|
||||
|
private final PasswordEncoder passwordEncoder; |
||||
|
private final UserService userService; |
||||
|
private final DataService dataService; |
||||
|
private final DeptService deptService; |
||||
|
private final RoleService roleService; |
||||
|
|
||||
|
|
||||
|
|
||||
|
@ApiOperation("导出用户数据") |
||||
|
@GetMapping(value = "/download") |
||||
|
@PreAuthorize("@el.check('user:list')") |
||||
|
public void exportUser(HttpServletResponse response, UserQueryCriteria criteria) throws IOException { |
||||
|
userService.download(userService.queryAll(criteria), response); |
||||
|
} |
||||
|
|
||||
|
@ApiOperation("查询用户") |
||||
|
@GetMapping |
||||
|
@PreAuthorize("@el.check('user:list')") |
||||
|
public ResponseEntity<Object> queryUser(UserQueryCriteria criteria, Pageable pageable){ |
||||
|
if (!ObjectUtils.isEmpty(criteria.getDeptId())) { |
||||
|
criteria.getDeptIds().add(criteria.getDeptId()); |
||||
|
// 先查找是否存在子节点 |
||||
|
List<Dept> data = deptService.findByPid(criteria.getDeptId()); |
||||
|
// 然后把子节点的ID都加入到集合中 |
||||
|
criteria.getDeptIds().addAll(deptService.getDeptChildren(data)); |
||||
|
} |
||||
|
// 数据权限 |
||||
|
List<Long> dataScopes = dataService.getDeptIds(userService.findByName(SecurityUtils.getCurrentUsername())); |
||||
|
// criteria.getDeptIds() 不为空并且数据权限不为空则取交集 |
||||
|
if (!CollectionUtils.isEmpty(criteria.getDeptIds()) && !CollectionUtils.isEmpty(dataScopes)){ |
||||
|
// 取交集 |
||||
|
criteria.getDeptIds().retainAll(dataScopes); |
||||
|
if(!CollectionUtil.isEmpty(criteria.getDeptIds())){ |
||||
|
return new ResponseEntity<>(userService.queryAll(criteria,pageable), HttpStatus.OK); |
||||
|
} |
||||
|
} else { |
||||
|
// 否则取并集 |
||||
|
criteria.getDeptIds().addAll(dataScopes); |
||||
|
return new ResponseEntity<>(userService.queryAll(criteria,pageable),HttpStatus.OK); |
||||
|
} |
||||
|
return new ResponseEntity<>(PageUtil.toPage(null,0),HttpStatus.OK); |
||||
|
} |
||||
|
|
||||
|
//@Log("新增用户") |
||||
|
@ApiOperation("新增用户") |
||||
|
@PostMapping |
||||
|
@PreAuthorize("@el.check('user:add')") |
||||
|
public ResponseEntity<Object> createUser(@Validated @RequestBody User resources){ |
||||
|
checkLevel(resources); |
||||
|
// 默认密码 123456 |
||||
|
resources.setPassword(passwordEncoder.encode("123456")); |
||||
|
userService.create(resources); |
||||
|
return new ResponseEntity<>(HttpStatus.CREATED); |
||||
|
} |
||||
|
|
||||
|
//@Log("修改用户") |
||||
|
@ApiOperation("修改用户") |
||||
|
@PutMapping |
||||
|
@PreAuthorize("@el.check('user:edit')") |
||||
|
public ResponseEntity<Object> updateUser(@Validated(User.Update.class) @RequestBody User resources) throws Exception { |
||||
|
checkLevel(resources); |
||||
|
userService.update(resources); |
||||
|
return new ResponseEntity<>(HttpStatus.NO_CONTENT); |
||||
|
} |
||||
|
|
||||
|
//@Log("修改用户:个人中心") |
||||
|
@ApiOperation("修改用户:个人中心") |
||||
|
@PutMapping(value = "center") |
||||
|
public ResponseEntity<Object> centerUser(@Validated(User.Update.class) @RequestBody User resources){ |
||||
|
if(!resources.getId().equals(SecurityUtils.getCurrentUserId())){ |
||||
|
throw new BaseException("不能修改他人资料"); |
||||
|
} |
||||
|
userService.updateCenter(resources); |
||||
|
return new ResponseEntity<>(HttpStatus.NO_CONTENT); |
||||
|
} |
||||
|
|
||||
|
//@Log("删除用户") |
||||
|
@ApiOperation("删除用户") |
||||
|
@DeleteMapping |
||||
|
@PreAuthorize("@el.check('user:del')") |
||||
|
public ResponseEntity<Object> deleteUser(@RequestBody Set<Long> ids){ |
||||
|
for (Long id : ids) { |
||||
|
Integer currentLevel = Collections.min(roleService.findByUsersId(SecurityUtils.getCurrentUserId()).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList())); |
||||
|
Integer optLevel = Collections.min(roleService.findByUsersId(id).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList())); |
||||
|
if (currentLevel > optLevel) { |
||||
|
throw new BaseException("角色权限不足,不能删除:" + userService.findById(id).getUsername()); |
||||
|
} |
||||
|
} |
||||
|
userService.delete(ids); |
||||
|
return new ResponseEntity<>(HttpStatus.OK); |
||||
|
} |
||||
|
|
||||
|
@ApiOperation("修改密码") |
||||
|
@PostMapping(value = "/updatePass") |
||||
|
public ResponseEntity<Object> updateUserPass(@RequestBody UserPassVo passVo) throws Exception { |
||||
|
String oldPass = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey,passVo.getOldPass()); |
||||
|
String newPass = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey,passVo.getNewPass()); |
||||
|
UserDto user = userService.findByName(SecurityUtils.getCurrentUsername()); |
||||
|
if(!passwordEncoder.matches(oldPass, user.getPassword())){ |
||||
|
throw new BaseException("修改失败,旧密码错误"); |
||||
|
} |
||||
|
if(passwordEncoder.matches(newPass, user.getPassword())){ |
||||
|
throw new BaseException("新密码不能与旧密码相同"); |
||||
|
} |
||||
|
userService.updatePass(user.getUsername(),passwordEncoder.encode(newPass)); |
||||
|
return new ResponseEntity<>(HttpStatus.OK); |
||||
|
} |
||||
|
|
||||
|
@ApiOperation("修改头像") |
||||
|
@PostMapping(value = "/updateAvatar") |
||||
|
public ResponseEntity<Object> updateUserAvatar(@RequestParam MultipartFile avatar){ |
||||
|
return new ResponseEntity<>(userService.updateAvatar(avatar), HttpStatus.OK); |
||||
|
} |
||||
|
|
||||
|
//@Log("修改邮箱") |
||||
|
// @ApiOperation("修改邮箱") |
||||
|
// @PostMapping(value = "/updateEmail/{code}") |
||||
|
// public ResponseEntity<Object> updateUserEmail(@PathVariable String code,@RequestBody User user) throws Exception { |
||||
|
// String password = RsaUtils.decryptByPrivateKey(RsaProperties.privateKey,user.getPassword()); |
||||
|
// UserDto userDto = userService.findByName(SecurityUtils.getCurrentUsername()); |
||||
|
// if(!passwordEncoder.matches(password, userDto.getPassword())){ |
||||
|
// throw new BaseException("密码错误"); |
||||
|
// } |
||||
|
// verificationCodeService.validated(CodeEnum.EMAIL_RESET_EMAIL_CODE.getKey() + user.getEmail(), code); |
||||
|
// userService.updateEmail(userDto.getUsername(),user.getEmail()); |
||||
|
// return new ResponseEntity<>(HttpStatus.OK); |
||||
|
// } |
||||
|
|
||||
|
/** |
||||
|
* 如果当前用户的角色级别低于创建用户的角色级别,则抛出权限不足的错误 |
||||
|
* @param resources / |
||||
|
*/ |
||||
|
private void checkLevel(User resources) { |
||||
|
Integer currentLevel = Collections.min(roleService.findByUsersId(SecurityUtils.getCurrentUserId()).stream().map(RoleSmallDto::getLevel).collect(Collectors.toList())); |
||||
|
Integer optLevel = roleService.findByRoles(resources.getRoles()); |
||||
|
if (currentLevel > optLevel) { |
||||
|
throw new BaseException("角色权限不足"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,17 @@ |
|||||
|
package com.storeroom.modules.system.repository; |
||||
|
|
||||
|
import com.storeroom.modules.system.domain.DictDetail; |
||||
|
import org.springframework.data.jpa.repository.JpaRepository; |
||||
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
public interface DictDetailRepository extends JpaRepository<DictDetail, Long>, JpaSpecificationExecutor<DictDetail> { |
||||
|
|
||||
|
/** |
||||
|
* 根据字典名称查询 |
||||
|
* @param name / |
||||
|
* @return / |
||||
|
*/ |
||||
|
List<DictDetail> findByDictName(String name); |
||||
|
} |
@ -1,4 +1,106 @@ |
|||||
package com.storeroom.modules.system.service; |
package com.storeroom.modules.system.service; |
||||
|
|
||||
|
import com.storeroom.modules.system.domain.Dept; |
||||
|
import com.storeroom.modules.system.service.dto.DeptDto; |
||||
|
import com.storeroom.modules.system.service.dto.DeptQueryCriteria; |
||||
|
|
||||
|
import javax.servlet.http.HttpServletResponse; |
||||
|
import java.io.IOException; |
||||
|
import java.util.List; |
||||
|
import java.util.Set; |
||||
|
|
||||
public interface DeptService { |
public interface DeptService { |
||||
|
|
||||
|
/** |
||||
|
* 查询所有数据 |
||||
|
* @param criteria 条件 |
||||
|
* @param isQuery / |
||||
|
* @throws Exception / |
||||
|
* @return / |
||||
|
*/ |
||||
|
List<DeptDto> queryAll(DeptQueryCriteria criteria, Boolean isQuery) throws Exception; |
||||
|
|
||||
|
/** |
||||
|
* 根据ID查询 |
||||
|
* @param id / |
||||
|
* @return / |
||||
|
*/ |
||||
|
DeptDto findById(Long id); |
||||
|
|
||||
|
/** |
||||
|
* 创建 |
||||
|
* @param resources / |
||||
|
*/ |
||||
|
void create(Dept resources); |
||||
|
|
||||
|
/** |
||||
|
* 编辑 |
||||
|
* @param resources / |
||||
|
*/ |
||||
|
void update(Dept resources); |
||||
|
|
||||
|
/** |
||||
|
* 删除 |
||||
|
* @param deptDtos / |
||||
|
* |
||||
|
*/ |
||||
|
void delete(Set<DeptDto> deptDtos); |
||||
|
|
||||
|
/** |
||||
|
* 根据PID查询 |
||||
|
* @param pid / |
||||
|
* @return / |
||||
|
*/ |
||||
|
List<Dept> findByPid(long pid); |
||||
|
|
||||
|
/** |
||||
|
* 根据角色ID查询 |
||||
|
* @param id / |
||||
|
* @return / |
||||
|
*/ |
||||
|
Set<Dept> findByRoleId(Long id); |
||||
|
|
||||
|
/** |
||||
|
* 导出数据 |
||||
|
* @param queryAll 待导出的数据 |
||||
|
* @param response / |
||||
|
* @throws IOException / |
||||
|
*/ |
||||
|
void download(List<DeptDto> queryAll, HttpServletResponse response) throws IOException; |
||||
|
|
||||
|
/** |
||||
|
* 获取待删除的部门 |
||||
|
* @param deptList / |
||||
|
* @param deptDtos / |
||||
|
* @return / |
||||
|
*/ |
||||
|
Set<DeptDto> getDeleteDepts(List<Dept> deptList, Set<DeptDto> deptDtos); |
||||
|
|
||||
|
/** |
||||
|
* 根据ID获取同级与上级数据 |
||||
|
* @param deptDto / |
||||
|
* @param depts / |
||||
|
* @return / |
||||
|
*/ |
||||
|
List<DeptDto> getSuperior(DeptDto deptDto, List<Dept> depts); |
||||
|
|
||||
|
/** |
||||
|
* 构建树形数据 |
||||
|
* @param deptDtos / |
||||
|
* @return / |
||||
|
*/ |
||||
|
Object buildTree(List<DeptDto> deptDtos); |
||||
|
|
||||
|
/** |
||||
|
* 获取 |
||||
|
* @param deptList |
||||
|
* @return |
||||
|
*/ |
||||
|
List<Long> getDeptChildren(List<Dept> deptList); |
||||
|
|
||||
|
/** |
||||
|
* 验证是否被角色或用户关联 |
||||
|
* @param deptDtos / |
||||
|
*/ |
||||
|
void verification(Set<DeptDto> deptDtos); |
||||
} |
} |
@ -1,4 +1,70 @@ |
|||||
package com.storeroom.modules.system.service; |
package com.storeroom.modules.system.service; |
||||
|
|
||||
|
import com.storeroom.modules.system.domain.Job; |
||||
|
import com.storeroom.modules.system.service.dto.JobDto; |
||||
|
import com.storeroom.modules.system.service.dto.JobQueryCriteria; |
||||
|
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 JobService { |
public interface JobService { |
||||
|
|
||||
|
/** |
||||
|
* 根据ID查询 |
||||
|
* @param id / |
||||
|
* @return / |
||||
|
*/ |
||||
|
JobDto findById(Long id); |
||||
|
|
||||
|
/** |
||||
|
* 创建 |
||||
|
* @param resources / |
||||
|
* @return / |
||||
|
*/ |
||||
|
void create(Job resources); |
||||
|
|
||||
|
/** |
||||
|
* 编辑 |
||||
|
* @param resources / |
||||
|
*/ |
||||
|
void update(Job resources); |
||||
|
|
||||
|
/** |
||||
|
* 删除 |
||||
|
* @param ids / |
||||
|
*/ |
||||
|
void delete(Set<Long> ids); |
||||
|
|
||||
|
/** |
||||
|
* 分页查询 |
||||
|
* @param criteria 条件 |
||||
|
* @param pageable 分页参数 |
||||
|
* @return / |
||||
|
*/ |
||||
|
Map<String,Object> queryAll(JobQueryCriteria criteria, Pageable pageable); |
||||
|
|
||||
|
/** |
||||
|
* 查询全部数据 |
||||
|
* @param criteria / |
||||
|
* @return / |
||||
|
*/ |
||||
|
List<JobDto> queryAll(JobQueryCriteria criteria); |
||||
|
|
||||
|
/** |
||||
|
* 导出数据 |
||||
|
* @param queryAll 待导出的数据 |
||||
|
* @param response / |
||||
|
* @throws IOException / |
||||
|
*/ |
||||
|
void download(List<JobDto> queryAll, HttpServletResponse response) throws IOException; |
||||
|
|
||||
|
/** |
||||
|
* 验证是否被用户关联 |
||||
|
* @param ids / |
||||
|
*/ |
||||
|
void verification(Set<Long> ids); |
||||
} |
} |
@ -1,4 +1,106 @@ |
|||||
package com.storeroom.modules.system.service; |
package com.storeroom.modules.system.service; |
||||
|
|
||||
|
import com.storeroom.modules.system.domain.Menu; |
||||
|
import com.storeroom.modules.system.service.dto.MenuDto; |
||||
|
import com.storeroom.modules.system.service.dto.MenuQueryCriteria; |
||||
|
|
||||
|
import javax.servlet.http.HttpServletResponse; |
||||
|
import java.io.IOException; |
||||
|
import java.util.List; |
||||
|
import java.util.Set; |
||||
|
|
||||
public interface MenuService { |
public interface MenuService { |
||||
|
|
||||
|
/** |
||||
|
* 查询全部数据 |
||||
|
* @param criteria 条件 |
||||
|
* @param isQuery / |
||||
|
* @throws Exception / |
||||
|
* @return / |
||||
|
*/ |
||||
|
List<MenuDto> queryAll(MenuQueryCriteria criteria, Boolean isQuery) throws Exception; |
||||
|
|
||||
|
/** |
||||
|
* 根据ID查询 |
||||
|
* @param id / |
||||
|
* @return / |
||||
|
*/ |
||||
|
MenuDto findById(long id); |
||||
|
|
||||
|
/** |
||||
|
* 创建 |
||||
|
* @param resources / |
||||
|
*/ |
||||
|
void create(Menu resources); |
||||
|
|
||||
|
/** |
||||
|
* 编辑 |
||||
|
* @param resources / |
||||
|
*/ |
||||
|
void update(Menu resources); |
||||
|
|
||||
|
/** |
||||
|
* 获取所有子节点,包含自身ID |
||||
|
* @param menuList / |
||||
|
* @param menuSet / |
||||
|
* @return / |
||||
|
*/ |
||||
|
Set<Menu> getChildMenus(List<Menu> menuList, Set<Menu> menuSet); |
||||
|
|
||||
|
/** |
||||
|
* 构建菜单树 |
||||
|
* @param menuDtos 原始数据 |
||||
|
* @return / |
||||
|
*/ |
||||
|
List<MenuDto> buildTree(List<MenuDto> menuDtos); |
||||
|
|
||||
|
/** |
||||
|
* 构建菜单树 |
||||
|
* @param menuDtos / |
||||
|
* @return / |
||||
|
*/ |
||||
|
Object buildMenus(List<MenuDto> menuDtos); |
||||
|
|
||||
|
/** |
||||
|
* 根据ID查询 |
||||
|
* @param id / |
||||
|
* @return / |
||||
|
*/ |
||||
|
Menu findOne(Long id); |
||||
|
|
||||
|
/** |
||||
|
* 删除 |
||||
|
* @param menuSet / |
||||
|
*/ |
||||
|
void delete(Set<Menu> menuSet); |
||||
|
|
||||
|
/** |
||||
|
* 导出 |
||||
|
* @param queryAll 待导出的数据 |
||||
|
* @param response / |
||||
|
* @throws IOException / |
||||
|
*/ |
||||
|
void download(List<MenuDto> queryAll, HttpServletResponse response) throws IOException; |
||||
|
|
||||
|
/** |
||||
|
* 懒加载菜单数据 |
||||
|
* @param pid / |
||||
|
* @return / |
||||
|
*/ |
||||
|
List<MenuDto> getMenus(Long pid); |
||||
|
|
||||
|
/** |
||||
|
* 根据ID获取同级与上级数据 |
||||
|
* @param menuDto / |
||||
|
* @param objects / |
||||
|
* @return / |
||||
|
*/ |
||||
|
List<MenuDto> getSuperior(MenuDto menuDto, List<Menu> objects); |
||||
|
|
||||
|
/** |
||||
|
* 根据当前用户获取菜单 |
||||
|
* @param currentUserId / |
||||
|
* @return / |
||||
|
*/ |
||||
|
List<MenuDto> findByUser(Long currentUserId); |
||||
} |
} |
@ -0,0 +1,24 @@ |
|||||
|
package com.storeroom.modules.system.service.dto; |
||||
|
|
||||
|
import com.storeroom.annotaion.Query; |
||||
|
import lombok.Data; |
||||
|
import lombok.NoArgsConstructor; |
||||
|
|
||||
|
import java.sql.Timestamp; |
||||
|
import java.util.List; |
||||
|
|
||||
|
|
||||
|
@Data |
||||
|
@NoArgsConstructor |
||||
|
public class JobQueryCriteria { |
||||
|
|
||||
|
|
||||
|
@Query(type = Query.Type.INNER_LIKE) |
||||
|
private String name; |
||||
|
|
||||
|
@Query |
||||
|
private Boolean enabled; |
||||
|
|
||||
|
@Query(type = Query.Type.BETWEEN) |
||||
|
private List<Timestamp> createTime; |
||||
|
} |
@ -0,0 +1,73 @@ |
|||||
|
package com.storeroom.modules.system.service.impl; |
||||
|
|
||||
|
|
||||
|
import com.storeroom.modules.system.domain.Dept; |
||||
|
import com.storeroom.modules.system.service.DataService; |
||||
|
import com.storeroom.modules.system.service.DeptService; |
||||
|
import com.storeroom.modules.system.service.RoleService; |
||||
|
import com.storeroom.modules.system.service.dto.RoleSmallDto; |
||||
|
import com.storeroom.modules.system.service.dto.UserDto; |
||||
|
import com.storeroom.utils.enums.DataScopeEnum; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import org.springframework.cache.annotation.CacheConfig; |
||||
|
import org.springframework.cache.annotation.Cacheable; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
|
||||
|
import java.util.*; |
||||
|
|
||||
|
@Service |
||||
|
@RequiredArgsConstructor |
||||
|
@CacheConfig(cacheNames = "data") |
||||
|
public class DataServiceImpl implements DataService { |
||||
|
|
||||
|
private final RoleService roleService; |
||||
|
private final DeptService deptService; |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* 用户角色改变时需清理缓存 |
||||
|
* @param user / |
||||
|
* @return / |
||||
|
*/ |
||||
|
@Override |
||||
|
@Cacheable(key = "'user:' + #p0.id") |
||||
|
public List<Long> getDeptIds(UserDto user) { |
||||
|
// 用于存储部门id |
||||
|
Set<Long> deptIds = new HashSet<>(); |
||||
|
// 查询用户角色 |
||||
|
List<RoleSmallDto> roleSet = roleService.findByUsersId(user.getId()); |
||||
|
// 获取对应的部门ID |
||||
|
for (RoleSmallDto role : roleSet) { |
||||
|
DataScopeEnum dataScopeEnum = DataScopeEnum.find(role.getDataScope()); |
||||
|
switch (Objects.requireNonNull(dataScopeEnum)) { |
||||
|
case THIS_LEVEL: |
||||
|
deptIds.add(user.getDept().getId()); |
||||
|
break; |
||||
|
case CUSTOMIZE: |
||||
|
deptIds.addAll(getCustomize(deptIds, role)); |
||||
|
break; |
||||
|
default: |
||||
|
return new ArrayList<>(deptIds); |
||||
|
} |
||||
|
} |
||||
|
return new ArrayList<>(deptIds); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取自定义的数据权限 |
||||
|
* @param deptIds 部门ID |
||||
|
* @param role 角色 |
||||
|
* @return 数据权限ID |
||||
|
*/ |
||||
|
public Set<Long> getCustomize(Set<Long> deptIds, RoleSmallDto role){ |
||||
|
Set<Dept> depts = deptService.findByRoleId(role.getId()); |
||||
|
for (Dept dept : depts) { |
||||
|
deptIds.add(dept.getId()); |
||||
|
List<Dept> deptChildren = deptService.findByPid(dept.getId()); |
||||
|
if (deptChildren != null && deptChildren.size() != 0) { |
||||
|
deptIds.addAll(deptService.getDeptChildren(deptChildren)); |
||||
|
} |
||||
|
} |
||||
|
return deptIds; |
||||
|
} |
||||
|
} |
@ -0,0 +1,267 @@ |
|||||
|
package com.storeroom.modules.system.service.impl; |
||||
|
|
||||
|
import cn.hutool.core.collection.CollectionUtil; |
||||
|
import cn.hutool.core.util.ObjectUtil; |
||||
|
import com.storeroom.exception.BaseException; |
||||
|
import com.storeroom.modules.system.domain.Dept; |
||||
|
import com.storeroom.modules.system.domain.User; |
||||
|
import com.storeroom.modules.system.repository.DeptRepository; |
||||
|
import com.storeroom.modules.system.repository.RoleRepository; |
||||
|
import com.storeroom.modules.system.repository.UserRepository; |
||||
|
import com.storeroom.modules.system.service.DeptService; |
||||
|
import com.storeroom.modules.system.service.dto.DeptDto; |
||||
|
import com.storeroom.modules.system.service.dto.DeptQueryCriteria; |
||||
|
import com.storeroom.modules.system.service.mapstruct.DeptMapper; |
||||
|
import com.storeroom.utils.*; |
||||
|
import com.storeroom.utils.enums.DataScopeEnum; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import org.springframework.cache.annotation.CacheConfig; |
||||
|
import org.springframework.cache.annotation.Cacheable; |
||||
|
import org.springframework.data.domain.Sort; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.springframework.transaction.annotation.Transactional; |
||||
|
|
||||
|
import javax.servlet.http.HttpServletResponse; |
||||
|
import java.io.IOException; |
||||
|
import java.lang.reflect.Field; |
||||
|
import java.util.*; |
||||
|
import java.util.stream.Collectors; |
||||
|
|
||||
|
|
||||
|
@Service |
||||
|
@RequiredArgsConstructor |
||||
|
@CacheConfig(cacheNames = "dept") |
||||
|
public class DeptServiceImpl implements DeptService { |
||||
|
|
||||
|
private final DeptRepository deptRepository; |
||||
|
private final DeptMapper deptMapper; |
||||
|
private final UserRepository userRepository; |
||||
|
private final RedisUtils redisUtils; |
||||
|
private final RoleRepository roleRepository; |
||||
|
|
||||
|
|
||||
|
@Override |
||||
|
public List<DeptDto> queryAll(DeptQueryCriteria criteria, Boolean isQuery) throws Exception { |
||||
|
Sort sort = Sort.by(Sort.Direction.ASC, "deptSort"); |
||||
|
String dataScopeType = SecurityUtils.getDataScopeType(); |
||||
|
if (isQuery) { |
||||
|
if(dataScopeType.equals(DataScopeEnum.ALL.getValue())){ |
||||
|
criteria.setPidIsNull(true); |
||||
|
} |
||||
|
List<Field> fields = QueryHelp.getAllFields(criteria.getClass(), new ArrayList<>()); |
||||
|
List<String> fieldNames = new ArrayList<String>(){{ add("pidIsNull");add("enabled");}}; |
||||
|
for (Field field : fields) { |
||||
|
//设置对象的访问权限,保证对private的属性的访问 |
||||
|
field.setAccessible(true); |
||||
|
Object val = field.get(criteria); |
||||
|
if(fieldNames.contains(field.getName())){ |
||||
|
continue; |
||||
|
} |
||||
|
if (ObjectUtil.isNotNull(val)) { |
||||
|
criteria.setPidIsNull(null); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
List<DeptDto> list = deptMapper.toDto(deptRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),sort)); |
||||
|
// 如果为空,就代表为自定义权限或者本级权限,就需要去重,不理解可以注释掉,看查询结果 |
||||
|
if(StringUtils.isBlank(dataScopeType)){ |
||||
|
return deduplication(list); |
||||
|
} |
||||
|
return list; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
@Cacheable(key = "'id:' + #p0") |
||||
|
public DeptDto findById(Long id) { |
||||
|
Dept dept = deptRepository.findById(id).orElseGet(Dept::new); |
||||
|
ValidationUtil.isNull(dept.getId(),"Dept","id",id); |
||||
|
return deptMapper.toDto(dept); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public List<Dept> findByPid(long pid) { |
||||
|
return deptRepository.findByPid(pid); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public Set<Dept> findByRoleId(Long id) { |
||||
|
return deptRepository.findByRoleId(id); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public void create(Dept resources) { |
||||
|
deptRepository.save(resources); |
||||
|
// 计算子节点数目 |
||||
|
resources.setSubCount(0); |
||||
|
// 清理缓存 |
||||
|
updateSubCnt(resources.getPid()); |
||||
|
// 清理自定义角色权限的datascope缓存 |
||||
|
delCaches(resources.getPid()); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public void update(Dept resources) { |
||||
|
// 旧的部门 |
||||
|
Long oldPid = findById(resources.getId()).getPid(); |
||||
|
Long newPid = resources.getPid(); |
||||
|
if(resources.getPid() != null && resources.getId().equals(resources.getPid())) { |
||||
|
throw new BaseException("上级不能为自己"); |
||||
|
} |
||||
|
Dept dept = deptRepository.findById(resources.getId()).orElseGet(Dept::new); |
||||
|
ValidationUtil.isNull( dept.getId(),"Dept","id",resources.getId()); |
||||
|
resources.setId(dept.getId()); |
||||
|
deptRepository.save(resources); |
||||
|
// 更新父节点中子节点数目 |
||||
|
updateSubCnt(oldPid); |
||||
|
updateSubCnt(newPid); |
||||
|
// 清理缓存 |
||||
|
delCaches(resources.getId()); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public void delete(Set<DeptDto> deptDtos) { |
||||
|
for (DeptDto deptDto : deptDtos) { |
||||
|
// 清理缓存 |
||||
|
delCaches(deptDto.getId()); |
||||
|
deptRepository.deleteById(deptDto.getId()); |
||||
|
updateSubCnt(deptDto.getPid()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void download(List<DeptDto> deptDtos, HttpServletResponse response) throws IOException { |
||||
|
List<Map<String, Object>> list = new ArrayList<>(); |
||||
|
for (DeptDto deptDTO : deptDtos) { |
||||
|
Map<String,Object> map = new LinkedHashMap<>(); |
||||
|
map.put("部门名称", deptDTO.getName()); |
||||
|
map.put("部门状态", deptDTO.getEnabled() ? "启用" : "停用"); |
||||
|
map.put("创建日期", deptDTO.getCreateTime()); |
||||
|
list.add(map); |
||||
|
} |
||||
|
FileUtil.downloadExcel(list, response); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public Set<DeptDto> getDeleteDepts(List<Dept> menuList, Set<DeptDto> deptDtos) { |
||||
|
for (Dept dept : menuList) { |
||||
|
deptDtos.add(deptMapper.toDto(dept)); |
||||
|
List<Dept> depts = deptRepository.findByPid(dept.getId()); |
||||
|
if(depts!=null && depts.size()!=0){ |
||||
|
getDeleteDepts(depts, deptDtos); |
||||
|
} |
||||
|
} |
||||
|
return deptDtos; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public List<Long> getDeptChildren(List<Dept> deptList) { |
||||
|
List<Long> list = new ArrayList<>(); |
||||
|
deptList.forEach(dept -> { |
||||
|
if (dept!=null && dept.getEnabled()) { |
||||
|
List<Dept> depts = deptRepository.findByPid(dept.getId()); |
||||
|
if (depts.size() != 0) { |
||||
|
list.addAll(getDeptChildren(depts)); |
||||
|
} |
||||
|
list.add(dept.getId()); |
||||
|
} |
||||
|
} |
||||
|
); |
||||
|
return list; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public List<DeptDto> getSuperior(DeptDto deptDto, List<Dept> depts) { |
||||
|
if(deptDto.getPid() == null){ |
||||
|
depts.addAll(deptRepository.findByPidIsNull()); |
||||
|
return deptMapper.toDto(depts); |
||||
|
} |
||||
|
depts.addAll(deptRepository.findByPid(deptDto.getPid())); |
||||
|
return getSuperior(findById(deptDto.getPid()), depts); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public Object buildTree(List<DeptDto> deptDtos) { |
||||
|
Set<DeptDto> trees = new LinkedHashSet<>(); |
||||
|
Set<DeptDto> depts= new LinkedHashSet<>(); |
||||
|
List<String> deptNames = deptDtos.stream().map(DeptDto::getName).collect(Collectors.toList()); |
||||
|
boolean isChild; |
||||
|
for (DeptDto deptDTO : deptDtos) { |
||||
|
isChild = false; |
||||
|
if (deptDTO.getPid() == null) { |
||||
|
trees.add(deptDTO); |
||||
|
} |
||||
|
for (DeptDto it : deptDtos) { |
||||
|
if (it.getPid() != null && deptDTO.getId().equals(it.getPid())) { |
||||
|
isChild = true; |
||||
|
if (deptDTO.getChildren() == null) { |
||||
|
deptDTO.setChildren(new ArrayList<>()); |
||||
|
} |
||||
|
deptDTO.getChildren().add(it); |
||||
|
} |
||||
|
} |
||||
|
if(isChild) { |
||||
|
depts.add(deptDTO); |
||||
|
} else if(deptDTO.getPid() != null && !deptNames.contains(findById(deptDTO.getPid()).getName())) { |
||||
|
depts.add(deptDTO); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (CollectionUtil.isEmpty(trees)) { |
||||
|
trees = depts; |
||||
|
} |
||||
|
Map<String,Object> map = new HashMap<>(2); |
||||
|
map.put("totalElements",deptDtos.size()); |
||||
|
map.put("content",CollectionUtil.isEmpty(trees)? deptDtos :trees); |
||||
|
return map; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void verification(Set<DeptDto> deptDtos) { |
||||
|
Set<Long> deptIds = deptDtos.stream().map(DeptDto::getId).collect(Collectors.toSet()); |
||||
|
if(userRepository.countByDepts(deptIds) > 0){ |
||||
|
throw new BaseException("所选部门存在用户关联,请解除后再试!"); |
||||
|
} |
||||
|
if(roleRepository.countByDepts(deptIds) > 0){ |
||||
|
throw new BaseException("所选部门存在角色关联,请解除后再试!"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void updateSubCnt(Long deptId){ |
||||
|
if(deptId != null){ |
||||
|
int count = deptRepository.countByPid(deptId); |
||||
|
deptRepository.updateSubCntById(count, deptId); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private List<DeptDto> deduplication(List<DeptDto> list) { |
||||
|
List<DeptDto> deptDtos = new ArrayList<>(); |
||||
|
for (DeptDto deptDto : list) { |
||||
|
boolean flag = true; |
||||
|
for (DeptDto dto : list) { |
||||
|
if (dto.getId().equals(deptDto.getPid())) { |
||||
|
flag = false; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
if (flag){ |
||||
|
deptDtos.add(deptDto); |
||||
|
} |
||||
|
} |
||||
|
return deptDtos; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 清理缓存 |
||||
|
* @param id / |
||||
|
*/ |
||||
|
public void delCaches(Long id){ |
||||
|
List<User> users = userRepository.findByRoleDeptId(id); |
||||
|
// 删除数据权限 |
||||
|
redisUtils.delByKeys(CacheKey.DATA_USER, users.stream().map(User::getId).collect(Collectors.toSet())); |
||||
|
redisUtils.del(CacheKey.DEPT_ID + id); |
||||
|
} |
||||
|
} |
@ -0,0 +1,80 @@ |
|||||
|
package com.storeroom.modules.system.service.impl; |
||||
|
|
||||
|
import com.storeroom.modules.system.domain.Dict; |
||||
|
import com.storeroom.modules.system.domain.DictDetail; |
||||
|
import com.storeroom.modules.system.repository.DictDetailRepository; |
||||
|
import com.storeroom.modules.system.repository.DictRepository; |
||||
|
import com.storeroom.modules.system.service.DictDetailService; |
||||
|
import com.storeroom.modules.system.service.dto.DictDetailDto; |
||||
|
import com.storeroom.modules.system.service.dto.DictDetailQueryCriteria; |
||||
|
import com.storeroom.modules.system.service.mapstruct.DictDetailMapper; |
||||
|
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 java.util.List; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
|
||||
|
@Service |
||||
|
@RequiredArgsConstructor |
||||
|
@CacheConfig(cacheNames = "dict") |
||||
|
public class DictDetailServiceImpl implements DictDetailService { |
||||
|
|
||||
|
|
||||
|
private final DictRepository dictRepository; |
||||
|
private final DictDetailRepository dictDetailRepository; |
||||
|
private final DictDetailMapper dictDetailMapper; |
||||
|
private final RedisUtils redisUtils; |
||||
|
|
||||
|
|
||||
|
@Override |
||||
|
public Map<String,Object> queryAll(DictDetailQueryCriteria criteria, Pageable pageable) { |
||||
|
Page<DictDetail> page = dictDetailRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable); |
||||
|
return PageUtil.toPage(page.map(dictDetailMapper::toDto)); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public void create(DictDetail resources) { |
||||
|
dictDetailRepository.save(resources); |
||||
|
// 清理缓存 |
||||
|
delCaches(resources); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public void update(DictDetail resources) { |
||||
|
DictDetail dictDetail = dictDetailRepository.findById(resources.getId()).orElseGet(DictDetail::new); |
||||
|
ValidationUtil.isNull( dictDetail.getId(),"DictDetail","id",resources.getId()); |
||||
|
resources.setId(dictDetail.getId()); |
||||
|
dictDetailRepository.save(resources); |
||||
|
// 清理缓存 |
||||
|
delCaches(resources); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
@Cacheable(key = "'name:' + #p0") |
||||
|
public List<DictDetailDto> getDictByName(String name) { |
||||
|
return dictDetailMapper.toDto(dictDetailRepository.findByDictName(name)); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public void delete(Long id) { |
||||
|
DictDetail dictDetail = dictDetailRepository.findById(id).orElseGet(DictDetail::new); |
||||
|
// 清理缓存 |
||||
|
delCaches(dictDetail); |
||||
|
dictDetailRepository.deleteById(id); |
||||
|
} |
||||
|
|
||||
|
public void delCaches(DictDetail dictDetail){ |
||||
|
Dict dict = dictRepository.findById(dictDetail.getDict().getId()).orElseGet(Dict::new); |
||||
|
redisUtils.del(CacheKey.DICT_NAME + dict.getName()); |
||||
|
} |
||||
|
} |
@ -0,0 +1,104 @@ |
|||||
|
package com.storeroom.modules.system.service.impl; |
||||
|
|
||||
|
import cn.hutool.core.collection.CollectionUtil; |
||||
|
import com.storeroom.modules.system.domain.Dict; |
||||
|
import com.storeroom.modules.system.repository.DictRepository; |
||||
|
import com.storeroom.modules.system.service.DictService; |
||||
|
import com.storeroom.modules.system.service.dto.DictDetailDto; |
||||
|
import com.storeroom.modules.system.service.dto.DictDto; |
||||
|
import com.storeroom.modules.system.service.dto.DictQueryCriteria; |
||||
|
import com.storeroom.modules.system.service.mapstruct.DictMapper; |
||||
|
import com.storeroom.utils.*; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import org.springframework.cache.annotation.CacheConfig; |
||||
|
import org.springframework.data.domain.Page; |
||||
|
import org.springframework.data.domain.Pageable; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.springframework.transaction.annotation.Transactional; |
||||
|
|
||||
|
import javax.servlet.http.HttpServletResponse; |
||||
|
import java.io.IOException; |
||||
|
import java.util.*; |
||||
|
|
||||
|
|
||||
|
@Service |
||||
|
@RequiredArgsConstructor |
||||
|
@CacheConfig(cacheNames = "dict") |
||||
|
public class DictServiceImpl implements DictService { |
||||
|
|
||||
|
private final DictRepository dictRepository; |
||||
|
private final DictMapper dictMapper; |
||||
|
private final RedisUtils redisUtils; |
||||
|
|
||||
|
@Override |
||||
|
public Map<String, Object> queryAll(DictQueryCriteria dict, Pageable pageable){ |
||||
|
Page<Dict> page = dictRepository.findAll((root, query, cb) -> QueryHelp.getPredicate(root, dict, cb), pageable); |
||||
|
return PageUtil.toPage(page.map(dictMapper::toDto)); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public List<DictDto> queryAll(DictQueryCriteria dict) { |
||||
|
List<Dict> list = dictRepository.findAll((root, query, cb) -> QueryHelp.getPredicate(root, dict, cb)); |
||||
|
return dictMapper.toDto(list); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public void create(Dict resources) { |
||||
|
dictRepository.save(resources); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public void update(Dict resources) { |
||||
|
// 清理缓存 |
||||
|
delCaches(resources); |
||||
|
Dict dict = dictRepository.findById(resources.getId()).orElseGet(Dict::new); |
||||
|
ValidationUtil.isNull( dict.getId(),"Dict","id",resources.getId()); |
||||
|
dict.setName(resources.getName()); |
||||
|
dict.setDescription(resources.getDescription()); |
||||
|
dictRepository.save(dict); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public void delete(Set<Long> ids) { |
||||
|
// 清理缓存 |
||||
|
List<Dict> dicts = dictRepository.findByIdIn(ids); |
||||
|
for (Dict dict : dicts) { |
||||
|
delCaches(dict); |
||||
|
} |
||||
|
dictRepository.deleteByIdIn(ids); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void download(List<DictDto> dictDtos, HttpServletResponse response) throws IOException { |
||||
|
List<Map<String, Object>> list = new ArrayList<>(); |
||||
|
for (DictDto dictDTO : dictDtos) { |
||||
|
if(CollectionUtil.isNotEmpty(dictDTO.getDictDetails())){ |
||||
|
for (DictDetailDto dictDetail : dictDTO.getDictDetails()) { |
||||
|
Map<String,Object> map = new LinkedHashMap<>(); |
||||
|
map.put("字典名称", dictDTO.getName()); |
||||
|
map.put("字典描述", dictDTO.getDescription()); |
||||
|
map.put("字典标签", dictDetail.getLabel()); |
||||
|
map.put("字典值", dictDetail.getValue()); |
||||
|
map.put("创建日期", dictDetail.getCreateTime()); |
||||
|
list.add(map); |
||||
|
} |
||||
|
} else { |
||||
|
Map<String,Object> map = new LinkedHashMap<>(); |
||||
|
map.put("字典名称", dictDTO.getName()); |
||||
|
map.put("字典描述", dictDTO.getDescription()); |
||||
|
map.put("字典标签", null); |
||||
|
map.put("字典值", null); |
||||
|
map.put("创建日期", dictDTO.getCreateTime()); |
||||
|
list.add(map); |
||||
|
} |
||||
|
} |
||||
|
FileUtil.downloadExcel(list, response); |
||||
|
} |
||||
|
|
||||
|
public void delCaches(Dict dict){ |
||||
|
redisUtils.del(CacheKey.DICT_NAME + dict.getName()); |
||||
|
} |
||||
|
} |
@ -0,0 +1,106 @@ |
|||||
|
package com.storeroom.modules.system.service.impl; |
||||
|
|
||||
|
import com.storeroom.exception.BaseException; |
||||
|
import com.storeroom.modules.system.domain.Job; |
||||
|
import com.storeroom.modules.system.repository.JobRepository; |
||||
|
import com.storeroom.modules.system.repository.UserRepository; |
||||
|
import com.storeroom.modules.system.service.JobService; |
||||
|
import com.storeroom.modules.system.service.dto.JobDto; |
||||
|
import com.storeroom.modules.system.service.dto.JobQueryCriteria; |
||||
|
import com.storeroom.modules.system.service.mapstruct.JobMapper; |
||||
|
import com.storeroom.utils.*; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import org.springframework.cache.annotation.CacheConfig; |
||||
|
import org.springframework.cache.annotation.CacheEvict; |
||||
|
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 javax.servlet.http.HttpServletResponse; |
||||
|
import java.io.IOException; |
||||
|
import java.util.*; |
||||
|
|
||||
|
@Service |
||||
|
@RequiredArgsConstructor |
||||
|
@CacheConfig(cacheNames = "job") |
||||
|
public class JobServiceImpl implements JobService { |
||||
|
|
||||
|
private final JobRepository jobRepository; |
||||
|
private final JobMapper jobMapper; |
||||
|
private final RedisUtils redisUtils; |
||||
|
private final UserRepository userRepository; |
||||
|
|
||||
|
@Override |
||||
|
public Map<String,Object> queryAll(JobQueryCriteria criteria, Pageable pageable) { |
||||
|
Page<Job> page = jobRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable); |
||||
|
return PageUtil.toPage(page.map(jobMapper::toDto).getContent(),page.getTotalElements()); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public List<JobDto> queryAll(JobQueryCriteria criteria) { |
||||
|
List<Job> list = jobRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)); |
||||
|
return jobMapper.toDto(list); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
@Cacheable(key = "'id:' + #p0") |
||||
|
public JobDto findById(Long id) { |
||||
|
Job job = jobRepository.findById(id).orElseGet(Job::new); |
||||
|
ValidationUtil.isNull(job.getId(),"Job","id",id); |
||||
|
return jobMapper.toDto(job); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public void create(Job resources) { |
||||
|
Job job = jobRepository.findByName(resources.getName()); |
||||
|
if(job != null){ |
||||
|
throw new BaseException("name",resources.getName()); |
||||
|
} |
||||
|
jobRepository.save(resources); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
@CacheEvict(key = "'id:' + #p0.id") |
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public void update(Job resources) { |
||||
|
Job job = jobRepository.findById(resources.getId()).orElseGet(Job::new); |
||||
|
Job old = jobRepository.findByName(resources.getName()); |
||||
|
if(old != null && !old.getId().equals(resources.getId())){ |
||||
|
throw new BaseException("name",resources.getName()); |
||||
|
} |
||||
|
ValidationUtil.isNull( job.getId(),"Job","id",resources.getId()); |
||||
|
resources.setId(job.getId()); |
||||
|
jobRepository.save(resources); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public void delete(Set<Long> ids) { |
||||
|
jobRepository.deleteAllByIdIn(ids); |
||||
|
// 删除缓存 |
||||
|
redisUtils.delByKeys(CacheKey.JOB_ID, ids); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void download(List<JobDto> jobDtos, HttpServletResponse response) throws IOException { |
||||
|
List<Map<String, Object>> list = new ArrayList<>(); |
||||
|
for (JobDto jobDTO : jobDtos) { |
||||
|
Map<String,Object> map = new LinkedHashMap<>(); |
||||
|
map.put("岗位名称", jobDTO.getName()); |
||||
|
map.put("岗位状态", jobDTO.getEnabled() ? "启用" : "停用"); |
||||
|
map.put("创建日期", jobDTO.getCreateTime()); |
||||
|
list.add(map); |
||||
|
} |
||||
|
FileUtil.downloadExcel(list, response); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void verification(Set<Long> ids) { |
||||
|
if(userRepository.countByJobs(ids) > 0){ |
||||
|
throw new BaseException("所选的岗位中存在用户关联,请解除关联再试!"); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,339 @@ |
|||||
|
package com.storeroom.modules.system.service.impl; |
||||
|
|
||||
|
import cn.hutool.core.collection.CollectionUtil; |
||||
|
import cn.hutool.core.util.ObjectUtil; |
||||
|
import com.storeroom.exception.BaseException; |
||||
|
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.domain.vo.MenuMetaVo; |
||||
|
import com.storeroom.modules.system.domain.vo.MenuVo; |
||||
|
import com.storeroom.modules.system.repository.MenuRepository; |
||||
|
import com.storeroom.modules.system.repository.UserRepository; |
||||
|
import com.storeroom.modules.system.service.MenuService; |
||||
|
import com.storeroom.modules.system.service.RoleService; |
||||
|
import com.storeroom.modules.system.service.dto.MenuDto; |
||||
|
import com.storeroom.modules.system.service.dto.MenuQueryCriteria; |
||||
|
import com.storeroom.modules.system.service.dto.RoleSmallDto; |
||||
|
import com.storeroom.modules.system.service.mapstruct.MenuMapper; |
||||
|
import com.storeroom.utils.*; |
||||
|
import lombok.RequiredArgsConstructor; |
||||
|
import org.springframework.cache.annotation.CacheConfig; |
||||
|
import org.springframework.cache.annotation.Cacheable; |
||||
|
import org.springframework.data.domain.Sort; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.springframework.transaction.annotation.Transactional; |
||||
|
|
||||
|
import javax.servlet.http.HttpServletResponse; |
||||
|
import java.io.IOException; |
||||
|
import java.lang.reflect.Field; |
||||
|
import java.util.*; |
||||
|
import java.util.stream.Collectors; |
||||
|
|
||||
|
|
||||
|
@Service |
||||
|
@RequiredArgsConstructor |
||||
|
@CacheConfig(cacheNames = "menu") |
||||
|
public class MenuServiceImpl implements MenuService { |
||||
|
|
||||
|
private final MenuRepository menuRepository; |
||||
|
private final UserRepository userRepository; |
||||
|
private final MenuMapper menuMapper; |
||||
|
private final RoleService roleService; |
||||
|
private final RedisUtils redisUtils; |
||||
|
|
||||
|
@Override |
||||
|
public List<MenuDto> queryAll(MenuQueryCriteria criteria, Boolean isQuery) throws Exception { |
||||
|
Sort sort = Sort.by(Sort.Direction.ASC, "menuSort"); |
||||
|
if(Boolean.TRUE.equals(isQuery)){ |
||||
|
criteria.setPidIsNull(true); |
||||
|
List<Field> fields = QueryHelp.getAllFields(criteria.getClass(), new ArrayList<>()); |
||||
|
for (Field field : fields) { |
||||
|
//设置对象的访问权限,保证对private的属性的访问 |
||||
|
field.setAccessible(true); |
||||
|
Object val = field.get(criteria); |
||||
|
if("pidIsNull".equals(field.getName())){ |
||||
|
continue; |
||||
|
} |
||||
|
if (ObjectUtil.isNotNull(val)) { |
||||
|
criteria.setPidIsNull(null); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return menuMapper.toDto(menuRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),sort)); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
@Cacheable(key = "'id:' + #p0") |
||||
|
public MenuDto findById(long id) { |
||||
|
Menu menu = menuRepository.findById(id).orElseGet(Menu::new); |
||||
|
ValidationUtil.isNull(menu.getId(),"Menu","id",id); |
||||
|
return menuMapper.toDto(menu); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 用户角色改变时需清理缓存 |
||||
|
* @param currentUserId / |
||||
|
* @return / |
||||
|
*/ |
||||
|
@Override |
||||
|
@Cacheable(key = "'user:' + #p0") |
||||
|
public List<MenuDto> findByUser(Long currentUserId) { |
||||
|
List<RoleSmallDto> roles = roleService.findByUsersId(currentUserId); |
||||
|
Set<Long> roleIds = roles.stream().map(RoleSmallDto::getId).collect(Collectors.toSet()); |
||||
|
LinkedHashSet<Menu> menus = menuRepository.findByRoleIdsAndTypeNot(roleIds, 2); |
||||
|
return menus.stream().map(menuMapper::toDto).collect(Collectors.toList()); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public void create(Menu resources) { |
||||
|
if(menuRepository.findByTitle(resources.getTitle()) != null){ |
||||
|
throw new BaseException("title",resources.getTitle()); |
||||
|
} |
||||
|
if(StringUtils.isNotBlank(resources.getComponentName())){ |
||||
|
if(menuRepository.findByComponentName(resources.getComponentName()) != null){ |
||||
|
throw new BaseException("componentName",resources.getComponentName()); |
||||
|
} |
||||
|
} |
||||
|
if(resources.getPid().equals(0L)){ |
||||
|
resources.setPid(null); |
||||
|
} |
||||
|
if(resources.getIFrame()){ |
||||
|
String http = "http://", https = "https://"; |
||||
|
if (!(resources.getPath().toLowerCase().startsWith(http)||resources.getPath().toLowerCase().startsWith(https))) { |
||||
|
throw new BaseException("外链必须以http://或者https://开头"); |
||||
|
} |
||||
|
} |
||||
|
menuRepository.save(resources); |
||||
|
// 计算子节点数目 |
||||
|
resources.setSubCount(0); |
||||
|
// 更新父节点菜单数目 |
||||
|
updateSubCnt(resources.getPid()); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public void update(Menu resources) { |
||||
|
if(resources.getId().equals(resources.getPid())) { |
||||
|
throw new BaseException("上级不能为自己"); |
||||
|
} |
||||
|
Menu menu = menuRepository.findById(resources.getId()).orElseGet(Menu::new); |
||||
|
ValidationUtil.isNull(menu.getId(),"Permission","id",resources.getId()); |
||||
|
|
||||
|
if(resources.getIFrame()){ |
||||
|
String http = "http://", https = "https://"; |
||||
|
if (!(resources.getPath().toLowerCase().startsWith(http)||resources.getPath().toLowerCase().startsWith(https))) { |
||||
|
throw new BaseException("外链必须以http://或者https://开头"); |
||||
|
} |
||||
|
} |
||||
|
Menu menu1 = menuRepository.findByTitle(resources.getTitle()); |
||||
|
|
||||
|
if(menu1 != null && !menu1.getId().equals(menu.getId())){ |
||||
|
throw new BaseException("title",resources.getTitle()); |
||||
|
} |
||||
|
|
||||
|
if(resources.getPid().equals(0L)){ |
||||
|
resources.setPid(null); |
||||
|
} |
||||
|
|
||||
|
// 记录的父节点ID |
||||
|
Long oldPid = menu.getPid(); |
||||
|
Long newPid = resources.getPid(); |
||||
|
|
||||
|
if(StringUtils.isNotBlank(resources.getComponentName())){ |
||||
|
menu1 = menuRepository.findByComponentName(resources.getComponentName()); |
||||
|
if(menu1 != null && !menu1.getId().equals(menu.getId())){ |
||||
|
throw new BaseException("componentName",resources.getComponentName()); |
||||
|
} |
||||
|
} |
||||
|
menu.setTitle(resources.getTitle()); |
||||
|
menu.setComponent(resources.getComponent()); |
||||
|
menu.setPath(resources.getPath()); |
||||
|
menu.setIcon(resources.getIcon()); |
||||
|
menu.setIFrame(resources.getIFrame()); |
||||
|
menu.setPid(resources.getPid()); |
||||
|
menu.setMenuSort(resources.getMenuSort()); |
||||
|
menu.setCache(resources.getCache()); |
||||
|
menu.setHidden(resources.getHidden()); |
||||
|
menu.setComponentName(resources.getComponentName()); |
||||
|
menu.setPermission(resources.getPermission()); |
||||
|
menu.setType(resources.getType()); |
||||
|
menuRepository.save(menu); |
||||
|
// 计算父级菜单节点数目 |
||||
|
updateSubCnt(oldPid); |
||||
|
updateSubCnt(newPid); |
||||
|
// 清理缓存 |
||||
|
delCaches(resources.getId()); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public Set<Menu> getChildMenus(List<Menu> menuList, Set<Menu> menuSet) { |
||||
|
for (Menu menu : menuList) { |
||||
|
menuSet.add(menu); |
||||
|
List<Menu> menus = menuRepository.findByPid(menu.getId()); |
||||
|
if(menus!=null && menus.size()!=0){ |
||||
|
getChildMenus(menus, menuSet); |
||||
|
} |
||||
|
} |
||||
|
return menuSet; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public void delete(Set<Menu> menuSet) { |
||||
|
for (Menu menu : menuSet) { |
||||
|
// 清理缓存 |
||||
|
delCaches(menu.getId()); |
||||
|
roleService.untiedMenu(menu.getId()); |
||||
|
menuRepository.deleteById(menu.getId()); |
||||
|
updateSubCnt(menu.getPid()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public List<MenuDto> getMenus(Long pid) { |
||||
|
List<Menu> menus; |
||||
|
if(pid != null && !pid.equals(0L)){ |
||||
|
menus = menuRepository.findByPid(pid); |
||||
|
} else { |
||||
|
menus = menuRepository.findByPidIsNull(); |
||||
|
} |
||||
|
return menuMapper.toDto(menus); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public List<MenuDto> getSuperior(MenuDto menuDto, List<Menu> menus) { |
||||
|
if(menuDto.getPid() == null){ |
||||
|
menus.addAll(menuRepository.findByPidIsNull()); |
||||
|
return menuMapper.toDto(menus); |
||||
|
} |
||||
|
menus.addAll(menuRepository.findByPid(menuDto.getPid())); |
||||
|
return getSuperior(findById(menuDto.getPid()), menus); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public List<MenuDto> buildTree(List<MenuDto> menuDtos) { |
||||
|
List<MenuDto> trees = new ArrayList<>(); |
||||
|
Set<Long> ids = new HashSet<>(); |
||||
|
for (MenuDto menuDTO : menuDtos) { |
||||
|
if (menuDTO.getPid() == null) { |
||||
|
trees.add(menuDTO); |
||||
|
} |
||||
|
for (MenuDto it : menuDtos) { |
||||
|
if (menuDTO.getId().equals(it.getPid())) { |
||||
|
if (menuDTO.getChildren() == null) { |
||||
|
menuDTO.setChildren(new ArrayList<>()); |
||||
|
} |
||||
|
menuDTO.getChildren().add(it); |
||||
|
ids.add(it.getId()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
if(trees.size() == 0){ |
||||
|
trees = menuDtos.stream().filter(s -> !ids.contains(s.getId())).collect(Collectors.toList()); |
||||
|
} |
||||
|
return trees; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public List<MenuVo> buildMenus(List<MenuDto> menuDtos) { |
||||
|
List<MenuVo> list = new LinkedList<>(); |
||||
|
menuDtos.forEach(menuDTO -> { |
||||
|
if (menuDTO!=null){ |
||||
|
List<MenuDto> menuDtoList = menuDTO.getChildren(); |
||||
|
MenuVo menuVo = new MenuVo(); |
||||
|
menuVo.setName(ObjectUtil.isNotEmpty(menuDTO.getComponentName()) ? menuDTO.getComponentName() : menuDTO.getTitle()); |
||||
|
// 一级目录需要加斜杠,不然会报警告 |
||||
|
menuVo.setPath(menuDTO.getPid() == null ? "/" + menuDTO.getPath() :menuDTO.getPath()); |
||||
|
menuVo.setHidden(menuDTO.getHidden()); |
||||
|
// 如果不是外链 |
||||
|
if(!menuDTO.getIFrame()){ |
||||
|
if(menuDTO.getPid() == null){ |
||||
|
menuVo.setComponent(StringUtils.isEmpty(menuDTO.getComponent())?"Layout":menuDTO.getComponent()); |
||||
|
// 如果不是一级菜单,并且菜单类型为目录,则代表是多级菜单 |
||||
|
}else if(menuDTO.getType() == 0){ |
||||
|
menuVo.setComponent(StringUtils.isEmpty(menuDTO.getComponent())?"ParentView":menuDTO.getComponent()); |
||||
|
}else if(StringUtils.isNoneBlank(menuDTO.getComponent())){ |
||||
|
menuVo.setComponent(menuDTO.getComponent()); |
||||
|
} |
||||
|
} |
||||
|
menuVo.setMeta(new MenuMetaVo(menuDTO.getTitle(),menuDTO.getIcon(),!menuDTO.getCache())); |
||||
|
if(CollectionUtil.isNotEmpty(menuDtoList)){ |
||||
|
menuVo.setAlwaysShow(true); |
||||
|
menuVo.setRedirect("noredirect"); |
||||
|
menuVo.setChildren(buildMenus(menuDtoList)); |
||||
|
// 处理是一级菜单并且没有子菜单的情况 |
||||
|
} else if(menuDTO.getPid() == null){ |
||||
|
MenuVo menuVo1 = new MenuVo(); |
||||
|
menuVo1.setMeta(menuVo.getMeta()); |
||||
|
// 非外链 |
||||
|
if(!menuDTO.getIFrame()){ |
||||
|
menuVo1.setPath("index"); |
||||
|
menuVo1.setName(menuVo.getName()); |
||||
|
menuVo1.setComponent(menuVo.getComponent()); |
||||
|
} else { |
||||
|
menuVo1.setPath(menuDTO.getPath()); |
||||
|
} |
||||
|
menuVo.setName(null); |
||||
|
menuVo.setMeta(null); |
||||
|
menuVo.setComponent("Layout"); |
||||
|
List<MenuVo> list1 = new ArrayList<>(); |
||||
|
list1.add(menuVo1); |
||||
|
menuVo.setChildren(list1); |
||||
|
} |
||||
|
list.add(menuVo); |
||||
|
} |
||||
|
} |
||||
|
); |
||||
|
return list; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public Menu findOne(Long id) { |
||||
|
Menu menu = menuRepository.findById(id).orElseGet(Menu::new); |
||||
|
ValidationUtil.isNull(menu.getId(),"Menu","id",id); |
||||
|
return menu; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void download(List<MenuDto> menuDtos, HttpServletResponse response) throws IOException { |
||||
|
List<Map<String, Object>> list = new ArrayList<>(); |
||||
|
for (MenuDto menuDTO : menuDtos) { |
||||
|
Map<String,Object> map = new LinkedHashMap<>(); |
||||
|
map.put("菜单标题", menuDTO.getTitle()); |
||||
|
map.put("菜单类型", menuDTO.getType() == null ? "目录" : menuDTO.getType() == 1 ? "菜单" : "按钮"); |
||||
|
map.put("权限标识", menuDTO.getPermission()); |
||||
|
map.put("外链菜单", menuDTO.getIFrame() ? "是" : "否"); |
||||
|
map.put("菜单可见", menuDTO.getHidden() ? "否" : "是"); |
||||
|
map.put("是否缓存", menuDTO.getCache() ? "是" : "否"); |
||||
|
map.put("创建日期", menuDTO.getCreateTime()); |
||||
|
list.add(map); |
||||
|
} |
||||
|
FileUtil.downloadExcel(list, response); |
||||
|
} |
||||
|
|
||||
|
private void updateSubCnt(Long menuId){ |
||||
|
if(menuId != null){ |
||||
|
int count = menuRepository.countByPid(menuId); |
||||
|
menuRepository.updateSubCntById(count, menuId); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 清理缓存 |
||||
|
* @param id 菜单ID |
||||
|
*/ |
||||
|
public void delCaches(Long id){ |
||||
|
List<User> users = userRepository.findByMenuId(id); |
||||
|
redisUtils.del(CacheKey.MENU_ID + id); |
||||
|
redisUtils.delByKeys(CacheKey.MENU_USER, users.stream().map(User::getId).collect(Collectors.toSet())); |
||||
|
// 清除 Role 缓存 |
||||
|
List<Role> roles = roleService.findInMenuId(new ArrayList<Long>(){{ |
||||
|
add(id); |
||||
|
}}); |
||||
|
redisUtils.delByKeys(CacheKey.ROLE_ID, roles.stream().map(Role::getId).collect(Collectors.toSet())); |
||||
|
} |
||||
|
|
||||
|
} |
@ -0,0 +1,8 @@ |
|||||
|
██ ██ ██ ██ ██ ██ ████████ ██ ███████ |
||||
|
░░██ ██ ░░██ ██ ░██ ██ ██░░░░░░ ░██ ░██░░░░██ |
||||
|
░░████ ░░██ ██ ░██ ██ ░██ ██████ ██████ ██████ █████ ░██ ░██ ██████ ██████ ██████████ |
||||
|
░░██ ░░███ ░████ ░█████████░░░██░ ██░░░░██░░██░░█ ██░░░██ ░███████ ██░░░░██ ██░░░░██░░██░░██░░██ |
||||
|
░██ ██░██ ░██░██ ░░░░░░░░██ ░██ ░██ ░██ ░██ ░ ░███████ ░██░░░██ ░██ ░██░██ ░██ ░██ ░██ ░██ |
||||
|
░██ ██ ░░██ ░██░░██ ░██ ░██ ░██ ░██ ░██ ░██░░░░ ░██ ░░██ ░██ ░██░██ ░██ ░██ ░██ ░██ |
||||
|
░██ ██ ░░██░██ ░░██ ████████ ░░██ ░░██████ ░███ ░░██████ ░██ ░░██░░██████ ░░██████ ███ ░██ ░██ |
||||
|
░░ ░░ ░░ ░░ ░░ ░░░░░░░░ ░░ ░░░░░░ ░░░ ░░░░░░ ░░ ░░ ░░░░░░ ░░░░░░ ░░░ ░░ ░░ |
@ -0,0 +1,27 @@ |
|||||
|
#数据库类型转Java类型 |
||||
|
tinyint=Integer |
||||
|
smallint=Integer |
||||
|
mediumint=Integer |
||||
|
int=Integer |
||||
|
integer=Integer |
||||
|
|
||||
|
bigint=Long |
||||
|
|
||||
|
float=Float |
||||
|
|
||||
|
double=Double |
||||
|
|
||||
|
decimal=BigDecimal |
||||
|
|
||||
|
bit=Boolean |
||||
|
|
||||
|
char=String |
||||
|
varchar=String |
||||
|
tinytext=String |
||||
|
text=String |
||||
|
mediumtext=String |
||||
|
longtext=String |
||||
|
|
||||
|
date=Timestamp |
||||
|
datetime=Timestamp |
||||
|
timestamp=Timestamp |
@ -0,0 +1,4 @@ |
|||||
|
# If you use SLF4J. First, you need to tell log4jdbc-log4j2 that you want to use the SLF4J logger |
||||
|
log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator |
||||
|
log4jdbc.auto.load.popular.drivers=false |
||||
|
log4jdbc.drivers=com.mysql.cj.jdbc.Driver |
@ -0,0 +1,45 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||
|
<configuration scan="true" scanPeriod="30 seconds" debug="false"> |
||||
|
<contextName>yxk-storeroom</contextName> |
||||
|
<property name="log.charset" value="utf-8" /> |
||||
|
<property name="log.pattern" value="%contextName- %red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}) - %msg%n" /> |
||||
|
|
||||
|
<!--输出到控制台--> |
||||
|
<appender name="console" class="ch.qos.logback.core.ConsoleAppender"> |
||||
|
<encoder> |
||||
|
<pattern>${log.pattern}</pattern> |
||||
|
<charset>${log.charset}</charset> |
||||
|
</encoder> |
||||
|
</appender> |
||||
|
|
||||
|
<!--普通日志输出到控制台--> |
||||
|
<root level="info"> |
||||
|
<appender-ref ref="console" /> |
||||
|
</root> |
||||
|
|
||||
|
<!--监控sql日志输出,如需监控 Sql 打印,请设置为 INFO --> |
||||
|
<logger name="jdbc.sqlonly" level="ERROR" additivity="false"> |
||||
|
<appender-ref ref="console" /> |
||||
|
</logger> |
||||
|
|
||||
|
<logger name="jdbc.resultset" level="ERROR" additivity="false"> |
||||
|
<appender-ref ref="console" /> |
||||
|
</logger> |
||||
|
|
||||
|
<!-- 如想看到表格数据,将OFF改为INFO --> |
||||
|
<logger name="jdbc.resultsettable" level="OFF" additivity="false"> |
||||
|
<appender-ref ref="console" /> |
||||
|
</logger> |
||||
|
|
||||
|
<logger name="jdbc.connection" level="OFF" additivity="false"> |
||||
|
<appender-ref ref="console" /> |
||||
|
</logger> |
||||
|
|
||||
|
<logger name="jdbc.sqltiming" level="OFF" additivity="false"> |
||||
|
<appender-ref ref="console" /> |
||||
|
</logger> |
||||
|
|
||||
|
<logger name="jdbc.audit" level="OFF" additivity="false"> |
||||
|
<appender-ref ref="console" /> |
||||
|
</logger> |
||||
|
</configuration> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue