From 9b5916daf33a9a24c3afcb53d7ef60a278fe330c Mon Sep 17 00:00:00 2001 From: tjq Date: Sat, 16 Mar 2024 18:41:33 +0800 Subject: [PATCH] feat: support user manager #860 --- .../server/auth/common/AuthErrorCode.java | 4 + .../login/impl/PowerJobLoginServiceImpl.java | 18 +++- .../persistence/remote/model/UserInfoDO.java | 5 ++ .../remote/repository/UserInfoRepository.java | 5 +- .../server/auth/service/WebAuthService.java | 6 ++ .../auth/service/impl/WebAuthServiceImpl.java | 6 ++ .../web/controller/UserInfoController.java | 89 ++++++++++++++++--- .../server/web/converter/UserConverter.java | 13 ++- .../server/web/request/QueryUserRequest.java | 32 +++++++ .../server/web/response/UserBaseVO.java | 22 +++++ .../server/web/response/UserDetailVO.java | 13 +-- .../server/web/service/UserWebService.java | 5 ++ .../web/service/impl/UserWebServiceImpl.java | 47 +++++++++- 13 files changed, 238 insertions(+), 27 deletions(-) create mode 100644 powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/request/QueryUserRequest.java diff --git a/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/common/AuthErrorCode.java b/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/common/AuthErrorCode.java index 8d51f25d..ae2c90b3 100644 --- a/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/common/AuthErrorCode.java +++ b/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/common/AuthErrorCode.java @@ -16,6 +16,10 @@ public enum AuthErrorCode { USER_NOT_LOGIN("-100", "UserNotLoggedIn"), USER_NOT_EXIST("-101", "UserNotExist"), USER_AUTH_FAILED("-102", "UserAuthFailed"), + /** + * 账户被停用 + */ + USER_DISABLED("-103", "UserDisabled"), NO_PERMISSION("-200", "NoPermission"), diff --git a/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/service/login/impl/PowerJobLoginServiceImpl.java b/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/service/login/impl/PowerJobLoginServiceImpl.java index b7da1439..5dab326f 100644 --- a/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/service/login/impl/PowerJobLoginServiceImpl.java +++ b/powerjob-server/powerjob-server-auth/src/main/java/tech/powerjob/server/auth/service/login/impl/PowerJobLoginServiceImpl.java @@ -22,6 +22,7 @@ import tech.powerjob.server.auth.login.*; import tech.powerjob.server.auth.service.login.LoginRequest; import tech.powerjob.server.auth.service.login.PowerJobLoginService; import tech.powerjob.server.common.Loggers; +import tech.powerjob.server.common.constants.SwitchableStatus; import tech.powerjob.server.persistence.remote.model.UserInfoDO; import tech.powerjob.server.persistence.remote.repository.UserInfoRepository; @@ -108,9 +109,11 @@ public class PowerJobLoginServiceImpl implements PowerJobLoginService { powerJobUserOpt = userInfoRepository.findByUsername(dbUserName); } else { - // 更新二次校验的 TOKEN 信息 UserInfoDO dbUserInfoDO = powerJobUserOpt.get(); + checkUserStatus(dbUserInfoDO); + + // 更新二次校验的 TOKEN 信息 dbUserInfoDO.setTokenLoginVerifyInfo(JsonUtils.toJSONString(bizUser.getTokenLoginVerifyInfo())); dbUserInfoDO.setGmtModified(new Date()); @@ -147,6 +150,8 @@ public class PowerJobLoginServiceImpl implements PowerJobLoginService { UserInfoDO dbUser = dbUserInfoOpt.get(); + checkUserStatus(dbUser); + PowerJobUser powerJobUser = new PowerJobUser(); String tokenLoginVerifyInfoStr = dbUser.getTokenLoginVerifyInfo(); @@ -174,6 +179,17 @@ public class PowerJobLoginServiceImpl implements PowerJobLoginService { return Optional.of(powerJobUser); } + /** + * 检查 user 状态 + * @param dbUser user + */ + private void checkUserStatus(UserInfoDO dbUser) { + int accountStatus = Optional.ofNullable(dbUser.getStatus()).orElse(SwitchableStatus.ENABLE.getV()); + if (accountStatus == SwitchableStatus.DISABLE.getV()) { + throw new PowerJobAuthException(AuthErrorCode.USER_DISABLED); + } + } + private ThirdPartyLoginService fetchBizLoginService(String loginType) { final ThirdPartyLoginService loginService = code2ThirdPartyLoginService.get(loginType); if (loginService == null) { diff --git a/powerjob-server/powerjob-server-persistence/src/main/java/tech/powerjob/server/persistence/remote/model/UserInfoDO.java b/powerjob-server/powerjob-server-persistence/src/main/java/tech/powerjob/server/persistence/remote/model/UserInfoDO.java index d0c5db1d..2c3ef4d6 100644 --- a/powerjob-server/powerjob-server-persistence/src/main/java/tech/powerjob/server/persistence/remote/model/UserInfoDO.java +++ b/powerjob-server/powerjob-server-persistence/src/main/java/tech/powerjob/server/persistence/remote/model/UserInfoDO.java @@ -71,6 +71,11 @@ public class UserInfoDO { */ private String originUsername; + /** + * 账号当前状态 + */ + private Integer status; + private Date gmtCreate; private Date gmtModified; diff --git a/powerjob-server/powerjob-server-persistence/src/main/java/tech/powerjob/server/persistence/remote/repository/UserInfoRepository.java b/powerjob-server/powerjob-server-persistence/src/main/java/tech/powerjob/server/persistence/remote/repository/UserInfoRepository.java index 3e70cef4..60a2ae1b 100644 --- a/powerjob-server/powerjob-server-persistence/src/main/java/tech/powerjob/server/persistence/remote/repository/UserInfoRepository.java +++ b/powerjob-server/powerjob-server-persistence/src/main/java/tech/powerjob/server/persistence/remote/repository/UserInfoRepository.java @@ -1,7 +1,8 @@ package tech.powerjob.server.persistence.remote.repository; -import tech.powerjob.server.persistence.remote.model.UserInfoDO; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import tech.powerjob.server.persistence.remote.model.UserInfoDO; import java.util.List; import java.util.Optional; @@ -12,7 +13,7 @@ import java.util.Optional; * @author tjq * @since 2020/4/12 */ -public interface UserInfoRepository extends JpaRepository { +public interface UserInfoRepository extends JpaRepository, JpaSpecificationExecutor { Optional findByUsername(String username); diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/service/WebAuthService.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/service/WebAuthService.java index f579ea19..c0a1bb08 100644 --- a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/service/WebAuthService.java +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/service/WebAuthService.java @@ -52,5 +52,11 @@ public interface WebAuthService { */ boolean hasPermission(RoleScope roleScope, Long target, Permission permission); + /** + * 是否为全局管理员 + * @return true or false + */ + boolean isGlobalAdmin(); + Map> fetchMyPermissionTargets(RoleScope roleScope); } diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/service/impl/WebAuthServiceImpl.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/service/impl/WebAuthServiceImpl.java index 1fbb7251..d43cd651 100644 --- a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/service/impl/WebAuthServiceImpl.java +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/auth/service/impl/WebAuthServiceImpl.java @@ -7,6 +7,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import tech.powerjob.common.serialize.JsonUtils; import tech.powerjob.server.auth.*; +import tech.powerjob.server.auth.common.AuthConstants; import tech.powerjob.server.auth.common.AuthErrorCode; import tech.powerjob.server.auth.common.PowerJobAuthException; import tech.powerjob.server.auth.service.WebAuthService; @@ -71,6 +72,11 @@ public class WebAuthServiceImpl implements WebAuthService { return powerJobPermissionService.hasPermission(powerJobUser.getId(), roleScope, target, permission); } + @Override + public boolean isGlobalAdmin() { + return hasPermission(RoleScope.GLOBAL, AuthConstants.GLOBAL_ADMIN_TARGET_ID, Permission.SU); + } + @Override public Map> fetchMyPermissionTargets(RoleScope roleScope) { diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/controller/UserInfoController.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/controller/UserInfoController.java index 95e31f42..53114259 100644 --- a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/controller/UserInfoController.java +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/controller/UserInfoController.java @@ -4,18 +4,23 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.*; +import tech.powerjob.common.exception.PowerJobException; import tech.powerjob.common.response.ResultDTO; +import tech.powerjob.server.auth.Permission; import tech.powerjob.server.auth.PowerJobUser; import tech.powerjob.server.auth.Role; import tech.powerjob.server.auth.RoleScope; import tech.powerjob.server.auth.common.AuthErrorCode; import tech.powerjob.server.auth.common.PowerJobAuthException; +import tech.powerjob.server.auth.interceptor.ApiPermission; import tech.powerjob.server.auth.service.WebAuthService; import tech.powerjob.server.auth.service.login.PowerJobLoginService; +import tech.powerjob.server.common.constants.SwitchableStatus; import tech.powerjob.server.persistence.remote.model.AppInfoDO; import tech.powerjob.server.persistence.remote.model.NamespaceDO; import tech.powerjob.server.persistence.remote.model.UserInfoDO; @@ -25,10 +30,12 @@ import tech.powerjob.server.persistence.remote.repository.UserInfoRepository; import tech.powerjob.server.web.converter.NamespaceConverter; import tech.powerjob.server.web.converter.UserConverter; import tech.powerjob.server.web.request.ModifyUserInfoRequest; +import tech.powerjob.server.web.request.QueryUserRequest; import tech.powerjob.server.web.response.AppBaseVO; import tech.powerjob.server.web.response.NamespaceBaseVO; import tech.powerjob.server.web.response.UserBaseVO; import tech.powerjob.server.web.response.UserDetailVO; +import tech.powerjob.server.web.service.UserWebService; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; @@ -41,9 +48,14 @@ import java.util.stream.Collectors; * @author tjq * @since 2020/4/12 */ + +@Slf4j @RestController @RequestMapping("/user") public class UserInfoController { + + @Resource + private UserWebService userWebService; @Resource private UserInfoRepository userInfoRepository; @Resource @@ -59,21 +71,14 @@ public class UserInfoController { @PostMapping("/modify") public ResultDTO modifyUser(@RequestBody ModifyUserInfoRequest modifyUserInfoRequest, HttpServletRequest httpServletRequest) { - Optional powerJobUserOpt = powerJobLoginService.ifLogin(httpServletRequest); - if (!powerJobUserOpt.isPresent()) { - throw new PowerJobAuthException(AuthErrorCode.USER_NOT_LOGIN); - } - Long userId = modifyUserInfoRequest.getId(); + checkModifyUserPermission(userId, httpServletRequest); + Optional userOpt = userInfoRepository.findById(userId); if (!userOpt.isPresent()) { throw new IllegalArgumentException("can't find user by userId:" + userId); } - if (!Objects.equals(powerJobUserOpt.get().getId(), userId)) { - throw new IllegalAccessException("no permission to change others user info"); - } - UserInfoDO dbUser = userOpt.get(); // 拷入允许修改的内容 @@ -111,6 +116,19 @@ public class UserInfoController { return ResultDTO.success(convert(result)); } + /** + * 查询用户信息(用于管理员操作,会返回敏感信息) + * @param queryUserRequest 查询请求 + * @return 响应 + */ + @PostMapping("/query") + @ApiPermission(name = "User-Query", roleScope = RoleScope.GLOBAL, requiredPermission = Permission.SU) + public ResultDTO> query(@RequestBody QueryUserRequest queryUserRequest) { + List userInfoDos = userWebService.list(queryUserRequest); + List userBaseVOS = userInfoDos.stream().map(x -> UserConverter.do2BaseVo(x, true)).collect(Collectors.toList()); + return ResultDTO.success(userBaseVOS); + } + @GetMapping("/detail") public ResultDTO getUserDetail(HttpServletRequest httpServletRequest) { Optional powerJobUserOpt = powerJobLoginService.ifLogin(httpServletRequest); @@ -171,11 +189,62 @@ public class UserInfoController { return ResultDTO.success(userDetailVO); } + @PostMapping("/disable") + public ResultDTO disableUser(Long uid, HttpServletRequest httpServletRequest) { + changeAccountStatus(uid, SwitchableStatus.DISABLE, httpServletRequest); + return ResultDTO.success(null); + } + + @PostMapping("/enable") + public ResultDTO enableUser(Long uid, HttpServletRequest httpServletRequest) { + changeAccountStatus(uid, SwitchableStatus.ENABLE, httpServletRequest); + return ResultDTO.success(null); + } + + private void changeAccountStatus(Long uid, SwitchableStatus targetStatus, HttpServletRequest httpServletRequest) { + checkModifyUserPermission(uid, httpServletRequest); + + Optional userOpt = userInfoRepository.findById(uid); + if (!userOpt.isPresent()) { + throw new IllegalArgumentException("can't find user by userId:" + uid); + } + + UserInfoDO dbUser = userOpt.get(); + + dbUser.setStatus(targetStatus.getV()); + dbUser.setGmtModified(new Date()); + + userInfoRepository.saveAndFlush(dbUser); + log.info("[UserInfoController] changeAccountStatus, userId={},targetStatus={}", uid, targetStatus); + } + + /** + * 检查针对 user 处理的权限 + * @param uid 目标 userId + * @param httpServletRequest http 上下文请求 + */ + private void checkModifyUserPermission(Long uid, HttpServletRequest httpServletRequest) { + Optional powerJobUserOpt = powerJobLoginService.ifLogin(httpServletRequest); + if (!powerJobUserOpt.isPresent()) { + throw new PowerJobAuthException(AuthErrorCode.USER_NOT_LOGIN); + } + PowerJobUser currentLoginUser = powerJobUserOpt.get(); + + boolean myself = uid.equals(currentLoginUser.getId()); + boolean globalAdmin = webAuthService.isGlobalAdmin(); + + if (myself || globalAdmin) { + return; + } + + throw new PowerJobException("Only the administrator and account owner can modify the account"); + } + private static List convert(List data) { if (CollectionUtils.isEmpty(data)) { return Lists.newLinkedList(); } - return data.stream().map(UserConverter::do2BaseVo).collect(Collectors.toList()); + return data.stream().map(x -> UserConverter.do2BaseVo(x, false)).collect(Collectors.toList()); } private static Set mergeIds(Map> map) { diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/converter/UserConverter.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/converter/UserConverter.java index 77876d93..c69048dd 100644 --- a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/converter/UserConverter.java +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/converter/UserConverter.java @@ -1,8 +1,11 @@ package tech.powerjob.server.web.converter; +import tech.powerjob.server.common.constants.SwitchableStatus; import tech.powerjob.server.persistence.remote.model.UserInfoDO; import tech.powerjob.server.web.response.UserBaseVO; +import java.util.Optional; + /** * UserConverter * @@ -11,13 +14,21 @@ import tech.powerjob.server.web.response.UserBaseVO; */ public class UserConverter { - public static UserBaseVO do2BaseVo(UserInfoDO x) { + public static UserBaseVO do2BaseVo(UserInfoDO x, boolean includeSensitiveInfo) { UserBaseVO userBaseVO = new UserBaseVO(); userBaseVO.setId(x.getId()); + userBaseVO.setAccountType(x.getAccountType()); userBaseVO.setUsername(x.getUsername()); userBaseVO.setNick(x.getNick()); + userBaseVO.setStatus(Optional.ofNullable(x.getStatus()).orElse(SwitchableStatus.ENABLE.getV())); + userBaseVO.setEnable(userBaseVO.getStatus() == SwitchableStatus.ENABLE.getV()); + + if (includeSensitiveInfo) { + userBaseVO.setPhone(x.getPhone()); + userBaseVO.setEmail(x.getEmail()); + } userBaseVO.genShowName(); return userBaseVO; diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/request/QueryUserRequest.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/request/QueryUserRequest.java new file mode 100644 index 00000000..cbb90ab5 --- /dev/null +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/request/QueryUserRequest.java @@ -0,0 +1,32 @@ +package tech.powerjob.server.web.request; + +import lombok.Data; + +import java.io.Serializable; + +/** + * 用户查询请求 + * + * @author tjq + * @since 2024/3/16 + */ +@Data +public class QueryUserRequest implements Serializable { + + /** + * 通过 userId 精确查询 + */ + private Long userIdEq; + + private String accountTypeEq; + + /** + * nick 模糊查询 + */ + private String nickLike; + + /** + * 手机号模糊查询 + */ + private String phoneLike; +} diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/response/UserBaseVO.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/response/UserBaseVO.java index 1b0ee206..83b81648 100644 --- a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/response/UserBaseVO.java +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/response/UserBaseVO.java @@ -15,10 +15,32 @@ import org.apache.commons.lang3.StringUtils; @Setter @NoArgsConstructor public class UserBaseVO { + protected Long id; protected String username; protected String nick; + /** + * 账户类型 + */ + private String accountType; + + /** + * 手机号 + */ + private String phone; + /** + * 邮箱地址 + */ + private String email; + + /** + * 账号当前状态 + */ + private Integer status; + + private boolean enable; + /** * 前端展示名称,更容易辨认 */ diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/response/UserDetailVO.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/response/UserDetailVO.java index 7b83e496..8cca9ff8 100644 --- a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/response/UserDetailVO.java +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/response/UserDetailVO.java @@ -18,23 +18,12 @@ import java.util.Map; @ToString public class UserDetailVO extends UserBaseVO { - /** - * 账户类型 - */ - private String accountType; + /** * 密码 */ private String password; - /** - * 手机号 - */ - private String phone; - /** - * 邮箱地址 - */ - private String email; /** * webHook */ diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/service/UserWebService.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/service/UserWebService.java index c6fe2ccc..4db42550 100644 --- a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/service/UserWebService.java +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/service/UserWebService.java @@ -1,7 +1,10 @@ package tech.powerjob.server.web.service; +import tech.powerjob.server.persistence.remote.model.UserInfoDO; +import tech.powerjob.server.web.request.QueryUserRequest; import tech.powerjob.server.web.response.UserBaseVO; +import java.util.List; import java.util.Optional; /** @@ -13,4 +16,6 @@ import java.util.Optional; public interface UserWebService { Optional fetchBaseUserInfo(Long userId); + + List list(QueryUserRequest queryUserRequest); } diff --git a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/service/impl/UserWebServiceImpl.java b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/service/impl/UserWebServiceImpl.java index fd44bce3..04cc3812 100644 --- a/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/service/impl/UserWebServiceImpl.java +++ b/powerjob-server/powerjob-server-starter/src/main/java/tech/powerjob/server/web/service/impl/UserWebServiceImpl.java @@ -2,14 +2,21 @@ package tech.powerjob.server.web.service.impl; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; +import com.google.common.collect.Lists; +import org.apache.commons.lang3.StringUtils; +import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Service; +import tech.powerjob.server.persistence.QueryConvertUtils; import tech.powerjob.server.persistence.remote.model.UserInfoDO; import tech.powerjob.server.persistence.remote.repository.UserInfoRepository; import tech.powerjob.server.web.converter.UserConverter; +import tech.powerjob.server.web.request.QueryUserRequest; import tech.powerjob.server.web.response.UserBaseVO; import tech.powerjob.server.web.service.UserWebService; import javax.annotation.Resource; +import javax.persistence.criteria.Predicate; +import java.util.List; import java.util.Optional; import java.util.concurrent.TimeUnit; @@ -50,9 +57,47 @@ public class UserWebServiceImpl implements UserWebService { throw new IllegalArgumentException("can't find user by userId: " + userId); }); - return Optional.of(UserConverter.do2BaseVo(userInfoDO)); + return Optional.of(UserConverter.do2BaseVo(userInfoDO, false)); } catch (Exception e) { return Optional.empty(); } } + + @Override + public List list(QueryUserRequest q) { + + Long userIdEq = q.getUserIdEq(); + String accountTypeEq = q.getAccountTypeEq(); + String nickLike = q.getNickLike(); + String phoneLike = q.getPhoneLike(); + + + Specification specification = (root, query, cb) -> { + + List predicates = Lists.newArrayList(); + + if (userIdEq != null) { + predicates.add(cb.equal(root.get("id"), userIdEq)); + } + + if (StringUtils.isNotEmpty(accountTypeEq)) { + predicates.add(cb.equal(root.get("accountType"), accountTypeEq)); + } + + if (StringUtils.isNotEmpty(nickLike)) { + predicates.add(cb.like(root.get("nick"), QueryConvertUtils.convertLikeParams(nickLike))); + } + + if (StringUtils.isNotEmpty(phoneLike)) { + predicates.add(cb.like(root.get("phone"), QueryConvertUtils.convertLikeParams(phoneLike))); + } + + if (predicates.isEmpty()) { + return null; + } + return query.where(predicates.toArray(new Predicate[0])).getRestriction(); + }; + + return userInfoRepository.findAll(specification); + } }