first commit.
This commit is contained in:
27
plusone-system/plusone-system-application/pom.xml
Normal file
27
plusone-system/plusone-system-application/pom.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>plusone-system</artifactId>
|
||||
<groupId>xyz.zhouxy</groupId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>plusone-system-application</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>xyz.zhouxy</groupId>
|
||||
<artifactId>plusone-system-domain</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>xyz.zhouxy</groupId>
|
||||
<artifactId>plusone-system-infrastructure</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>xyz.zhouxy</groupId>
|
||||
<artifactId>plusone-basic-application</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,61 @@
|
||||
package xyz.zhouxy.plusone.system.application.common.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import xyz.zhouxy.plusone.domain.IWithOrderNumber;
|
||||
import xyz.zhouxy.plusone.system.application.query.result.MenuViewObject;
|
||||
import xyz.zhouxy.plusone.system.domain.model.menu.Menu.MenuType;
|
||||
|
||||
/**
|
||||
* 菜单工具类
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
public class MenuUtil {
|
||||
private MenuUtil() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建菜单树
|
||||
*
|
||||
* @param allMenus 菜单列表
|
||||
* @return 菜单树
|
||||
*/
|
||||
public static List<MenuViewObject> buildMenuTree(Collection<MenuViewObject> allMenus) {
|
||||
// 先排序,保证添加到 rootMenus 中的顺序,以及 addChild 添加的子菜单的顺序
|
||||
allMenus = allMenus.stream()
|
||||
.sorted(Comparator.comparing(IWithOrderNumber::getOrderNumber))
|
||||
.toList();
|
||||
|
||||
// 一级菜单
|
||||
List<MenuViewObject> rootMenus = new ArrayList<>();
|
||||
// key: 菜单 id; value: 菜单对象. 方便根据 id 查找相应对象。
|
||||
Map<Long, MenuViewObject> menuListMap = new HashMap<>();
|
||||
|
||||
for (var menu : allMenus) {
|
||||
// 添加 MENU_LIST 到 map 中,方便后面调用对象的方法
|
||||
if (menu.getType() == MenuType.MENU_LIST.ordinal()) {
|
||||
menuListMap.put(menu.getId(), menu);
|
||||
}
|
||||
// 一级菜单
|
||||
if (menu.getParentId() == 0) {
|
||||
rootMenus.add(menu);
|
||||
}
|
||||
}
|
||||
for (var menu : allMenus) {
|
||||
var parent = menuListMap.getOrDefault(menu.getParentId(), null);
|
||||
// 父菜单存在于 map 中,调用父菜单的 addChild 方法将当前菜单添加为父菜单的子菜单。
|
||||
if (parent != null) {
|
||||
parent.addChild(menu);
|
||||
}
|
||||
}
|
||||
|
||||
return rootMenus;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package xyz.zhouxy.plusone.system.application.common.util;
|
||||
|
||||
import lombok.Getter;
|
||||
import xyz.zhouxy.plusone.constant.RegexConsts;
|
||||
|
||||
public enum PrincipalType {
|
||||
EMAIL(RegexConsts.EMAIL),
|
||||
MOBILE_PHONE(RegexConsts.MOBILE_PHONE),
|
||||
USERNAME(RegexConsts.USERNAME)
|
||||
;
|
||||
|
||||
@Getter
|
||||
private final String regex;
|
||||
|
||||
PrincipalType(String regex) {
|
||||
this.regex = regex;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package xyz.zhouxy.plusone.system.application.common.util;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import xyz.zhouxy.plusone.exception.InvalidInputException;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.Email;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.MobilePhone;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.Principal;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.Username;
|
||||
|
||||
/**
|
||||
* 根据字面值,判断并生成 {@link Principal} 值对象。
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
* @see Principal
|
||||
* @see Username
|
||||
* @see Email
|
||||
* @see MobilePhone
|
||||
* @see InvalidInputException
|
||||
*/
|
||||
public class PrincipalUtil {
|
||||
|
||||
private PrincipalUtil() {
|
||||
throw new IllegalStateException("Utility class");
|
||||
}
|
||||
|
||||
public static PrincipalType getPrincipalType(@Nullable String principal) {
|
||||
if (principal == null) {
|
||||
throw new IllegalArgumentException("principal 不能为空");
|
||||
}
|
||||
PrincipalType[] principalTypes = PrincipalType.values();
|
||||
for (var principalType : principalTypes) {
|
||||
if (principal.matches(principalType.getRegex())) {
|
||||
return principalType;
|
||||
}
|
||||
}
|
||||
throw InvalidInputException.unsupportedPrincipalTypeException();
|
||||
}
|
||||
|
||||
public static Principal getPrincipal(@Nullable String principal) {
|
||||
PrincipalType principalType = getPrincipalType(principal);
|
||||
if (principalType == PrincipalType.EMAIL) {
|
||||
return Email.of(principal);
|
||||
}
|
||||
if (principalType == PrincipalType.MOBILE_PHONE) {
|
||||
return MobilePhone.of(principal);
|
||||
}
|
||||
if (principalType == PrincipalType.USERNAME) {
|
||||
return Username.of(principal);
|
||||
}
|
||||
throw InvalidInputException.unsupportedPrincipalTypeException();
|
||||
}
|
||||
|
||||
public static Principal getEmailOrMobilePhone(@Nullable String principal) {
|
||||
PrincipalType principalType = getPrincipalType(principal);
|
||||
if (principalType == PrincipalType.EMAIL) {
|
||||
return Email.of(principal);
|
||||
}
|
||||
if (principalType == PrincipalType.MOBILE_PHONE) {
|
||||
return MobilePhone.of(principal);
|
||||
}
|
||||
throw InvalidInputException.unsupportedPrincipalTypeException("输入邮箱地址或手机号");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package xyz.zhouxy.plusone.system.application.controller;
|
||||
|
||||
import static xyz.zhouxy.plusone.system.constant.AuthLogic.adminAuthLogic;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import xyz.zhouxy.plusone.system.application.service.AccountContextService;
|
||||
import xyz.zhouxy.plusone.util.RestfulResult;
|
||||
|
||||
/**
|
||||
* 账号查询本身相关信息
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("account")
|
||||
public class AccountContextController {
|
||||
|
||||
private final AccountContextService service;
|
||||
|
||||
public AccountContextController(AccountContextService service) {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
@GetMapping("info")
|
||||
public RestfulResult getAccountInfo() {
|
||||
adminAuthLogic.checkLogin();
|
||||
var result = service.getAccountInfo();
|
||||
return RestfulResult.success("查询成功", result);
|
||||
}
|
||||
|
||||
@GetMapping("menus")
|
||||
public RestfulResult getMenuTree() {
|
||||
adminAuthLogic.checkLogin();
|
||||
var result = service.getMenuTree();
|
||||
return RestfulResult.success("查询成功", result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package xyz.zhouxy.plusone.system.application.controller;
|
||||
|
||||
import static xyz.zhouxy.plusone.system.constant.AuthLogic.adminAuthLogic;
|
||||
import static xyz.zhouxy.plusone.util.RestfulResult.success;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PatchMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import xyz.zhouxy.plusone.system.application.query.params.AccountQueryParams;
|
||||
import xyz.zhouxy.plusone.system.application.service.AccountManagementService;
|
||||
import xyz.zhouxy.plusone.system.application.service.command.CreateAccountCommand;
|
||||
import xyz.zhouxy.plusone.system.application.service.command.UpdateAccountCommand;
|
||||
import xyz.zhouxy.plusone.util.AssertResult;
|
||||
import xyz.zhouxy.plusone.util.RestfulResult;
|
||||
|
||||
/**
|
||||
* 账号管理
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("sys/account")
|
||||
public class AccountManagementController {
|
||||
|
||||
private final AccountManagementService service;
|
||||
|
||||
public AccountManagementController(AccountManagementService service) {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public RestfulResult createAccount(@RequestBody @Valid CreateAccountCommand command) {
|
||||
adminAuthLogic.checkLogin();
|
||||
adminAuthLogic.checkPermission("sys-account-create");
|
||||
service.createAccount(command);
|
||||
return success();
|
||||
}
|
||||
|
||||
@DeleteMapping
|
||||
public RestfulResult deleteAccounts(@RequestBody List<Long> ids) {
|
||||
adminAuthLogic.checkLogin();
|
||||
adminAuthLogic.checkPermission("sys-account-delete");
|
||||
service.deleteAccounts(ids);
|
||||
return success();
|
||||
}
|
||||
|
||||
@PatchMapping("{id}")
|
||||
public RestfulResult updateAccountInfo(
|
||||
@PathVariable("id") Long id,
|
||||
@RequestBody @Valid UpdateAccountCommand command) {
|
||||
adminAuthLogic.checkLogin();
|
||||
adminAuthLogic.checkPermission("sys-account-update");
|
||||
service.updateAccountInfo(id, command);
|
||||
return success();
|
||||
}
|
||||
|
||||
@GetMapping("query")
|
||||
public RestfulResult queryAccountOverviewList(AccountQueryParams queryParams) {
|
||||
adminAuthLogic.checkLogin();
|
||||
adminAuthLogic.checkPermission("sys-account-list");
|
||||
var accountOverviewList = service.queryAccountOverviewList(queryParams);
|
||||
return success("查询成功", accountOverviewList);
|
||||
}
|
||||
|
||||
@GetMapping("{accountId}")
|
||||
public RestfulResult queryAccountDetails(@PathVariable("accountId") Long accountId) {
|
||||
adminAuthLogic.checkLogin();
|
||||
adminAuthLogic.checkPermission("sys-account-details");
|
||||
var accountDetails = service.queryAccountDetails(accountId);
|
||||
AssertResult.nonNull(accountDetails);
|
||||
return success("查询成功", accountDetails);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package xyz.zhouxy.plusone.system.application.controller;
|
||||
|
||||
import static xyz.zhouxy.plusone.util.RestfulResult.success;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import xyz.zhouxy.plusone.system.application.service.AdminLoginService;
|
||||
import xyz.zhouxy.plusone.system.application.service.command.LoginByOtpCommand;
|
||||
import xyz.zhouxy.plusone.system.application.service.command.LoginByPasswordCommand;
|
||||
import xyz.zhouxy.plusone.util.RestfulResult;
|
||||
|
||||
/**
|
||||
* Admin 账号登录
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("login")
|
||||
public class AdminLoginController {
|
||||
|
||||
private final AdminLoginService service;
|
||||
|
||||
public AdminLoginController(AdminLoginService service) {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
@PostMapping("byPassword")
|
||||
public RestfulResult loginByPassword(@RequestBody LoginByPasswordCommand command) {
|
||||
var loginInfo = service.loginByPassword(command);
|
||||
return success("登录成功", loginInfo);
|
||||
}
|
||||
|
||||
@PostMapping("byOtp")
|
||||
public RestfulResult loginByOtp(@RequestBody LoginByOtpCommand command) {
|
||||
var loginInfo = service.loginByOtp(command);
|
||||
return success("登录成功", loginInfo);
|
||||
}
|
||||
|
||||
@GetMapping("sendOtp")
|
||||
public RestfulResult sendOtp(@RequestParam String principal) {
|
||||
service.sendOtp(principal);
|
||||
return success("发送成功");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package xyz.zhouxy.plusone.system.application.controller;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import xyz.zhouxy.plusone.system.application.service.AdminLogoutService;
|
||||
import xyz.zhouxy.plusone.util.RestfulResult;
|
||||
|
||||
/**
|
||||
* Admin 账号登出
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("logout")
|
||||
public class AdminLogoutController {
|
||||
|
||||
private final AdminLogoutService service;
|
||||
|
||||
public AdminLogoutController(AdminLogoutService service) {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public RestfulResult execute() {
|
||||
service.execute();
|
||||
return RestfulResult.success("注销成功");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package xyz.zhouxy.plusone.system.application.controller;
|
||||
|
||||
import static xyz.zhouxy.plusone.system.constant.AuthLogic.adminAuthLogic;
|
||||
import static xyz.zhouxy.plusone.util.RestfulResult.success;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PatchMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import xyz.zhouxy.plusone.system.application.query.params.DictQueryParams;
|
||||
import xyz.zhouxy.plusone.system.application.service.DictManagementService;
|
||||
import xyz.zhouxy.plusone.system.application.service.command.CreateDictCommand;
|
||||
import xyz.zhouxy.plusone.system.application.service.command.UpdateDictCommand;
|
||||
import xyz.zhouxy.plusone.util.RestfulResult;
|
||||
|
||||
/**
|
||||
* 数据字典管理
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("sys/dict")
|
||||
public class DictManagementController {
|
||||
|
||||
private final DictManagementService service;
|
||||
|
||||
public DictManagementController(DictManagementService service) {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public RestfulResult createDict(@RequestBody @Valid CreateDictCommand command) {
|
||||
adminAuthLogic.checkPermission("sys-dict-create");
|
||||
service.createDict(command);
|
||||
return success();
|
||||
}
|
||||
|
||||
@DeleteMapping
|
||||
public RestfulResult deleteDicts(@RequestBody List<Long> ids) {
|
||||
adminAuthLogic.checkPermission("sys-dict-delete");
|
||||
service.deleteDicts(ids);
|
||||
return success();
|
||||
}
|
||||
|
||||
@PatchMapping("{id}")
|
||||
public RestfulResult updateDict(
|
||||
@PathVariable("id") Long id,
|
||||
@RequestBody @Valid UpdateDictCommand command) {
|
||||
adminAuthLogic.checkPermission("sys-dict-update");
|
||||
service.updateDict(id, command);
|
||||
return success();
|
||||
}
|
||||
|
||||
@GetMapping("{dictId}")
|
||||
public RestfulResult findDictDetails(@PathVariable("dictId") Long dictId) {
|
||||
adminAuthLogic.checkPermission("sys-dict-details");
|
||||
var dictDetails = service.findDictDetails(dictId);
|
||||
return success("查询成功", dictDetails);
|
||||
}
|
||||
|
||||
@GetMapping("all")
|
||||
public RestfulResult loadAllDicts() {
|
||||
adminAuthLogic.checkPermissionAnd("sys-dict-list", "sys-dict-details");
|
||||
var dicts = service.loadAllDicts();
|
||||
return success("查询成功", dicts);
|
||||
}
|
||||
|
||||
@GetMapping("query")
|
||||
public RestfulResult queryDictOverviewList(@Valid DictQueryParams queryParams) {
|
||||
adminAuthLogic.checkPermission("sys-dict-list");
|
||||
var dicts = service.queryDictOverviewList(queryParams);
|
||||
return success("查询成功", dicts);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package xyz.zhouxy.plusone.system.application.controller;
|
||||
|
||||
import static xyz.zhouxy.plusone.system.constant.AuthLogic.adminAuthLogic;
|
||||
import static xyz.zhouxy.plusone.util.RestfulResult.success;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PatchMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import xyz.zhouxy.plusone.system.application.service.MenuManagementService;
|
||||
import xyz.zhouxy.plusone.system.application.service.command.CreateMenuCommand;
|
||||
import xyz.zhouxy.plusone.system.application.service.command.UpdateMenuCommand;
|
||||
import xyz.zhouxy.plusone.util.RestfulResult;
|
||||
|
||||
/**
|
||||
* 菜单管理
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("sys/menu")
|
||||
public class MenuManagementController {
|
||||
|
||||
private final MenuManagementService service;
|
||||
|
||||
public MenuManagementController(MenuManagementService service) {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
// ==================== create ====================
|
||||
@PostMapping
|
||||
public RestfulResult createMenu(@RequestBody @Valid CreateMenuCommand command) {
|
||||
adminAuthLogic.checkPermission("sys-menu-create");
|
||||
service.createMenu(command);
|
||||
return success();
|
||||
}
|
||||
|
||||
// ==================== delete ====================
|
||||
@DeleteMapping("{id}")
|
||||
public RestfulResult deleteMenu(@PathVariable("id") Long id) {
|
||||
adminAuthLogic.checkPermission("sys-menu-delete");
|
||||
service.deleteMenu(id);
|
||||
return success();
|
||||
}
|
||||
|
||||
// ==================== update ====================
|
||||
@PatchMapping("{id}")
|
||||
public RestfulResult updateMenu(
|
||||
@PathVariable("id") Long id,
|
||||
@RequestBody @Valid UpdateMenuCommand command) {
|
||||
adminAuthLogic.checkPermission("sys-menu-update");
|
||||
service.updateMenu(id, command);
|
||||
return success();
|
||||
}
|
||||
|
||||
// ==================== query ====================
|
||||
@GetMapping("{id}")
|
||||
public RestfulResult findById(@PathVariable("id") Long id) {
|
||||
adminAuthLogic.checkPermission("sys-menu-details");
|
||||
var result = service.findById(id);
|
||||
return RestfulResult.success("查询成功", result);
|
||||
}
|
||||
|
||||
@GetMapping("queryByAccountId")
|
||||
public RestfulResult queryByAccountId(@RequestParam Long accountId) {
|
||||
adminAuthLogic.checkPermission("sys-menu-details");
|
||||
var result = service.queryByAccountId(accountId);
|
||||
return success("查询成功", result);
|
||||
}
|
||||
|
||||
@GetMapping("queryByRoleId")
|
||||
public RestfulResult queryByRoleId(@RequestParam Long roleId) {
|
||||
adminAuthLogic.checkPermission("sys-menu-details");
|
||||
var result = service.queryByRoleId(roleId);
|
||||
return success("查询成功", result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package xyz.zhouxy.plusone.system.application.controller;
|
||||
|
||||
import static xyz.zhouxy.plusone.util.RestfulResult.success;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import xyz.zhouxy.plusone.system.application.service.RegisterAccountService;
|
||||
import xyz.zhouxy.plusone.system.application.service.command.RegisterAccountCommand;
|
||||
import xyz.zhouxy.plusone.util.RestfulResult;
|
||||
|
||||
/**
|
||||
* 注册账号服务
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("register")
|
||||
public class RegisterAccountController {
|
||||
|
||||
private final RegisterAccountService service;
|
||||
|
||||
public RegisterAccountController(RegisterAccountService service) {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public RestfulResult registerAccount(@RequestBody RegisterAccountCommand command) {
|
||||
service.registerAccount(command);
|
||||
return success("注册成功");
|
||||
}
|
||||
|
||||
@GetMapping("sendCode")
|
||||
public RestfulResult sendCode(@RequestParam String principal) {
|
||||
service.sendCode(principal);
|
||||
return success("发送成功");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package xyz.zhouxy.plusone.system.application.controller;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import static xyz.zhouxy.plusone.system.constant.AuthLogic.adminAuthLogic;
|
||||
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PatchMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import xyz.zhouxy.plusone.system.application.query.params.RoleQueryParams;
|
||||
import xyz.zhouxy.plusone.system.application.service.RoleManagementService;
|
||||
import xyz.zhouxy.plusone.system.application.service.command.CreateRoleCommand;
|
||||
import xyz.zhouxy.plusone.system.application.service.command.UpdateRoleCommand;
|
||||
import xyz.zhouxy.plusone.util.RestfulResult;
|
||||
|
||||
/**
|
||||
* 角色管理服务
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("sys/role")
|
||||
public class RoleManagementController {
|
||||
|
||||
private final RoleManagementService service;
|
||||
|
||||
public RoleManagementController(RoleManagementService service) {
|
||||
this.service = service;
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public RestfulResult createRole(@RequestBody @Valid CreateRoleCommand command) {
|
||||
adminAuthLogic.checkPermission("sys-role-create");
|
||||
service.createRole(command);
|
||||
return RestfulResult.success();
|
||||
}
|
||||
|
||||
@PatchMapping
|
||||
public RestfulResult updateRole(@RequestBody @Valid UpdateRoleCommand command) {
|
||||
adminAuthLogic.checkPermission("sys-role-update");
|
||||
service.updateRole(command);
|
||||
return RestfulResult.success();
|
||||
}
|
||||
|
||||
@DeleteMapping("{id}")
|
||||
public RestfulResult delete(@PathVariable("id") Long id) {
|
||||
adminAuthLogic.checkPermission("sys-role-delete");
|
||||
service.delete(id);
|
||||
return RestfulResult.success();
|
||||
}
|
||||
|
||||
@GetMapping("exists")
|
||||
public RestfulResult exists(@RequestParam("id") Long id) {
|
||||
adminAuthLogic.checkPermissionOr("sys-role-list", "sys-role-details");
|
||||
var isExists = service.exists(id);
|
||||
return RestfulResult.success(isExists ? "存在" : "不存在", isExists);
|
||||
}
|
||||
|
||||
@GetMapping("{id}")
|
||||
public RestfulResult findById(@PathVariable("id") Long id) {
|
||||
adminAuthLogic.checkPermission("sys-role-details");
|
||||
var result = service.findById(id);
|
||||
return RestfulResult.success("查询成功", result);
|
||||
}
|
||||
|
||||
@GetMapping("query")
|
||||
public RestfulResult query(RoleQueryParams params) {
|
||||
adminAuthLogic.checkPermission("sys-role-list");
|
||||
var result = service.query(params);
|
||||
return RestfulResult.success("查询成功", result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package xyz.zhouxy.plusone.system.application.exception;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
import xyz.zhouxy.plusone.exception.PlusoneException;
|
||||
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public class AccountLoginException extends PlusoneException {
|
||||
@java.io.Serial
|
||||
private static final long serialVersionUID = -3040996790739138556L;
|
||||
|
||||
private static final int DEFAULT_ERR_CODE = 4030000;
|
||||
|
||||
private AccountLoginException() {
|
||||
super(DEFAULT_ERR_CODE, "用户登录异常");
|
||||
}
|
||||
|
||||
private AccountLoginException(int code, String message) {
|
||||
super(code, message);
|
||||
}
|
||||
|
||||
public static AccountLoginException accountNotExistException() {
|
||||
return new AccountLoginException(4030101, "用户账户不存在");
|
||||
}
|
||||
|
||||
public static AccountLoginException otpErrorException() {
|
||||
return new AccountLoginException(4030501, "验证码错误");
|
||||
}
|
||||
|
||||
public static AccountLoginException otpNotExistsException() {
|
||||
return new AccountLoginException(4030502, "验证码不存在或已过期");
|
||||
}
|
||||
|
||||
public static AccountLoginException passwordErrorException() {
|
||||
return new AccountLoginException(4030200, "用户密码错误");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package xyz.zhouxy.plusone.system.application.exception;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
import xyz.zhouxy.plusone.exception.PlusoneException;
|
||||
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public class AccountRegisterException extends PlusoneException {
|
||||
|
||||
@java.io.Serial
|
||||
private static final long serialVersionUID = 7580245181633370195L;
|
||||
|
||||
public AccountRegisterException() {
|
||||
this(4020000, "用户注册错误");
|
||||
}
|
||||
|
||||
public AccountRegisterException(String message) {
|
||||
this(4020000, message);
|
||||
}
|
||||
|
||||
public AccountRegisterException(Throwable cause) {
|
||||
super(4020000, cause);
|
||||
}
|
||||
|
||||
public AccountRegisterException(int code, String message) {
|
||||
super(code, message);
|
||||
}
|
||||
|
||||
public AccountRegisterException(int code, Throwable cause) {
|
||||
super(code, cause);
|
||||
}
|
||||
|
||||
public static AccountRegisterException emailOrMobilePhoneRequiredException() {
|
||||
return new AccountRegisterException(4020300, "邮箱和手机号应至少绑定一个");
|
||||
}
|
||||
|
||||
public static AccountRegisterException usernameAlreadyExists(String username) {
|
||||
return new AccountRegisterException(4020400, String.format("用户名 %s 已存在", username));
|
||||
}
|
||||
|
||||
public static AccountRegisterException emailAlreadyExists(String value) {
|
||||
return new AccountRegisterException(4020500, String.format("邮箱 %s 已存在", value));
|
||||
}
|
||||
|
||||
public static AccountRegisterException mobilePhoneAlreadyExists(String value) {
|
||||
return new AccountRegisterException(4020600, String.format("手机号 %s 已存在", value));
|
||||
}
|
||||
|
||||
public static AccountRegisterException codeErrorException() {
|
||||
return new AccountRegisterException(4020701, "校验码错误");
|
||||
}
|
||||
|
||||
public static AccountRegisterException codeNotExistsException() {
|
||||
return new AccountRegisterException(4020702, "校验码不存在或已过期");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package xyz.zhouxy.plusone.system.application.exception;
|
||||
|
||||
import xyz.zhouxy.plusone.exception.InvalidInputException;
|
||||
|
||||
public class UnsupportedMenuTypeException extends InvalidInputException {
|
||||
|
||||
@java.io.Serial
|
||||
private static final long serialVersionUID = -769169844015637730L;
|
||||
|
||||
public UnsupportedMenuTypeException() {
|
||||
this("不支持的菜单类型");
|
||||
}
|
||||
|
||||
public UnsupportedMenuTypeException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package xyz.zhouxy.plusone.system.application.exception.handler;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
import cn.dev33.satoken.exception.DisableServiceException;
|
||||
import cn.dev33.satoken.exception.SameTokenInvalidException;
|
||||
import cn.dev33.satoken.exception.NotBasicAuthException;
|
||||
import cn.dev33.satoken.exception.NotLoginException;
|
||||
import cn.dev33.satoken.exception.NotPermissionException;
|
||||
import cn.dev33.satoken.exception.NotRoleException;
|
||||
import cn.dev33.satoken.exception.NotSafeException;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import xyz.zhouxy.plusone.exception.handler.BaseExceptionHandler;
|
||||
import xyz.zhouxy.plusone.util.RestfulResult;
|
||||
|
||||
/**
|
||||
* Sa-Token 异常处理器
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@RestControllerAdvice
|
||||
@Slf4j
|
||||
public class SaTokenExceptionHandler extends BaseExceptionHandler {
|
||||
|
||||
public SaTokenExceptionHandler(ExceptionInfoHolder exceptionInfoHolder) {
|
||||
super(exceptionInfoHolder);
|
||||
set(NotPermissionException.class, 4030103, "会话未能通过权限认证", HttpStatus.FORBIDDEN);
|
||||
set(NotRoleException.class, 4030103, "会话未能通过角色认证", HttpStatus.FORBIDDEN);
|
||||
set(DisableServiceException.class, 4030202, "账号指定服务已被封禁", HttpStatus.FORBIDDEN);
|
||||
set(SameTokenInvalidException.class, 4030400, "提供的 Same-Token 无效", HttpStatus.UNAUTHORIZED);
|
||||
set(NotBasicAuthException.class, 4030000, "会话未能通过 Http Basic 认证", HttpStatus.UNAUTHORIZED);
|
||||
set(NotSafeException.class, 4020300, "会话未能通过二级认证", HttpStatus.UNAUTHORIZED);
|
||||
set(NotLoginException.class,
|
||||
4020400,
|
||||
e -> switch (((NotLoginException) e).getType()) {
|
||||
case NotLoginException.NOT_TOKEN -> "未提供 Token";
|
||||
case NotLoginException.INVALID_TOKEN -> "Token 无效";
|
||||
case NotLoginException.TOKEN_TIMEOUT -> "Token 已过期";
|
||||
case NotLoginException.BE_REPLACED -> "Token 已被顶下线";
|
||||
case NotLoginException.KICK_OUT -> "Token 已被踢下线";
|
||||
default -> "当前会话未登录";
|
||||
},
|
||||
HttpStatus.UNAUTHORIZED);
|
||||
set(SaTokenException.class, 4020300, "未通过身份认证或权限认证", HttpStatus.FORBIDDEN);
|
||||
}
|
||||
|
||||
@ExceptionHandler(SaTokenException.class)
|
||||
public ResponseEntity<RestfulResult> handleSaTokenException(SaTokenException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
return buildExceptionResponse(e);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package xyz.zhouxy.plusone.system.application.query;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import xyz.zhouxy.plusone.system.application.query.params.AccountQueryParams;
|
||||
import xyz.zhouxy.plusone.system.application.query.result.AccountDetails;
|
||||
import xyz.zhouxy.plusone.system.application.query.result.AccountOverview;
|
||||
import xyz.zhouxy.plusone.util.PageDTO;
|
||||
|
||||
/**
|
||||
* 账号信息查询器
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Mapper
|
||||
public interface AccountQueries {
|
||||
|
||||
default PageDTO<AccountOverview> queryAccountOverviewPage(AccountQueryParams queryParams) {
|
||||
List<AccountOverview> content = queryAccountOverview(queryParams);
|
||||
long total = count(queryParams);
|
||||
return PageDTO.of(content, total);
|
||||
}
|
||||
|
||||
List<AccountOverview> queryAccountOverview(AccountQueryParams queryParams);
|
||||
|
||||
long count(AccountQueryParams queryParams);
|
||||
|
||||
AccountDetails queryAccountDetails(Long accountId);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package xyz.zhouxy.plusone.system.application.query;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.jdbc.core.BeanPropertyRowMapper;
|
||||
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import xyz.zhouxy.plusone.sql.SQL;
|
||||
import xyz.zhouxy.plusone.system.application.query.params.DictQueryParams;
|
||||
import xyz.zhouxy.plusone.system.application.query.result.DictOverview;
|
||||
|
||||
/**
|
||||
* 数据字典查询器
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Component
|
||||
public class DictQueries {
|
||||
|
||||
private final NamedParameterJdbcTemplate jdbcTemplate;
|
||||
|
||||
public DictQueries(NamedParameterJdbcTemplate jdbcTemplate) {
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
}
|
||||
|
||||
public List<DictOverview> queryDictOverviewList(DictQueryParams queryParams) {
|
||||
String sql = new SQL()
|
||||
.SELECT("id", "dict_type", "dict_label",
|
||||
"created_by", "create_time", "updated_by", "update_time", "count")
|
||||
.FROM("view_sys_dict_overview")
|
||||
.WHERE_IF(queryParams.getDictType() != null, "dict_type LIKE '%:dictType%'")
|
||||
.WHERE_IF(queryParams.getDictLabel() != null, "dict_label LIKE '%:dictLabel%'")
|
||||
.toString();
|
||||
return this.jdbcTemplate
|
||||
.query(sql, new BeanPropertySqlParameterSource(queryParams), new BeanPropertyRowMapper<>(DictOverview.class));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package xyz.zhouxy.plusone.system.application.query;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
public interface PermissionQueries {
|
||||
// TODO【添加】 权限信息查询器
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package xyz.zhouxy.plusone.system.application.query;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.jdbc.core.BeanPropertyRowMapper;
|
||||
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
|
||||
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import xyz.zhouxy.plusone.sql.SQL;
|
||||
import xyz.zhouxy.plusone.system.application.query.params.RoleQueryParams;
|
||||
import xyz.zhouxy.plusone.system.application.query.result.RoleOverview;
|
||||
|
||||
/**
|
||||
* 角色信息查询器
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Repository
|
||||
public class RoleQueries {
|
||||
|
||||
private final NamedParameterJdbcTemplate jdbcTemplate;
|
||||
|
||||
public RoleQueries(NamedParameterJdbcTemplate jdbcTemplate) {
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询 Role
|
||||
* <p>
|
||||
* <b> !!!注意:此方法内存在字符串拼接,勿在循环内使用。</b>
|
||||
* </p>
|
||||
*
|
||||
* @param params 查询参数
|
||||
* @return 查询结果
|
||||
*/
|
||||
public List<RoleOverview> query(RoleQueryParams params) {
|
||||
String b = new SQL()
|
||||
.SELECT("id")
|
||||
.FROM("sys_role")
|
||||
.WHERE_IF_NOT_NULL(params.getId(), "id = :id")
|
||||
.WHERE_IF_NOT_NULL(params.getName(), "name = :name")
|
||||
.WHERE_IF_NOT_NULL(params.getIdentifier(), "identifier = :identifier")
|
||||
.WHERE_IF_NOT_NULL(params.getStatus(), "status = :status")
|
||||
.WHERE_IF_NOT_NULL(params.getCreateTimeStart(), "create_time >= :createTimeStart")
|
||||
.WHERE_IF_NOT_NULL(params.getCreateTimeEnd(), "create_time < :createTimeEnd")
|
||||
.WHERE_IF_NOT_NULL(params.getUpdateTimeStart(), "update_time >= :updateTimeStart")
|
||||
.WHERE_IF_NOT_NULL(params.getUpdateTimeEnd(), "update_time < :updateTimeEnd")
|
||||
.LIMIT(params.getSize())
|
||||
.OFFSET(params.getOffset())
|
||||
.toString();
|
||||
var sql = """
|
||||
SELECT a.id AS id, a.name AS name, a.identifier AS identifier, a.status AS status
|
||||
FROM sys_role AS a, (
|
||||
""" + b + """
|
||||
) AS b
|
||||
WHERE a.id = b.id
|
||||
""";
|
||||
return this.jdbcTemplate
|
||||
.query(sql, new BeanPropertySqlParameterSource(params),
|
||||
new BeanPropertyRowMapper<>(RoleOverview.class));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package xyz.zhouxy.plusone.system.application.query.params;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import xyz.zhouxy.plusone.util.PagingAndSortingQueryParams;
|
||||
|
||||
/**
|
||||
* 账号信息查询参数
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@ToString
|
||||
public class AccountQueryParams extends PagingAndSortingQueryParams {
|
||||
|
||||
public AccountQueryParams() {
|
||||
super("id",
|
||||
"username",
|
||||
"email",
|
||||
"mobile_phone",
|
||||
"status",
|
||||
"nickname",
|
||||
"sex",
|
||||
"created_by",
|
||||
"create_time",
|
||||
"updated_by",
|
||||
"update_time");
|
||||
}
|
||||
|
||||
// TODO【添加】 注解参数校验
|
||||
private @Getter @Setter Long id;
|
||||
private @Getter @Setter String username;
|
||||
private @Getter @Setter String email;
|
||||
private @Getter @Setter String mobilePhone;
|
||||
private @Getter @Setter Integer status;
|
||||
private @Getter @Setter String nickname;
|
||||
private @Getter @Setter Integer sex;
|
||||
private @Getter @Setter Long createdBy;
|
||||
private @Getter @Setter LocalDate createTimeStart;
|
||||
private @Getter LocalDate createTimeEnd;
|
||||
private @Getter @Setter Long updatedBy;
|
||||
private @Getter @Setter LocalDate updateTimeStart;
|
||||
private @Getter LocalDate updateTimeEnd;
|
||||
private @Getter @Setter Long roleId;
|
||||
|
||||
public void setCreateTimeEnd(LocalDate createTimeEnd) {
|
||||
this.createTimeEnd = createTimeEnd.plusDays(1);
|
||||
}
|
||||
|
||||
public void setUpdateTimeEnd(LocalDate updateTimeEnd) {
|
||||
this.updateTimeEnd = updateTimeEnd.plusDays(1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package xyz.zhouxy.plusone.system.application.query.params;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
import xyz.zhouxy.plusone.util.PagingAndSortingQueryParams;
|
||||
|
||||
/**
|
||||
* 数据字典查询参数
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Accessors(chain = true)
|
||||
@ToString(callSuper = true)
|
||||
public class DictQueryParams extends PagingAndSortingQueryParams {
|
||||
String dictType;
|
||||
String dictLabel;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package xyz.zhouxy.plusone.system.application.query.params;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import xyz.zhouxy.plusone.util.PagingAndSortingQueryParams;
|
||||
|
||||
/**
|
||||
* 角色信息查询参数
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@ToString(callSuper = true)
|
||||
public class RoleQueryParams extends PagingAndSortingQueryParams {
|
||||
private @Getter @Setter Long id;
|
||||
private @Getter @Setter String name;
|
||||
private @Getter @Setter String identifier;
|
||||
private @Getter @Setter Integer status;
|
||||
|
||||
private @Getter @Setter LocalDate createTimeStart;
|
||||
private @Getter LocalDate createTimeEnd;
|
||||
private @Getter @Setter LocalDate updateTimeStart;
|
||||
private @Getter LocalDate updateTimeEnd;
|
||||
|
||||
public void setCreateTimeEnd(LocalDate createTimeEnd) {
|
||||
this.createTimeEnd = createTimeEnd.plusDays(1);
|
||||
}
|
||||
|
||||
public void setUpdateTimeEnd(LocalDate updateTimeEnd) {
|
||||
this.updateTimeEnd = updateTimeEnd.plusDays(1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package xyz.zhouxy.plusone.system.application.query.result;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* 账号详细信息
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@NoArgsConstructor
|
||||
@ToString
|
||||
public class AccountDetails {
|
||||
Long id;
|
||||
String username;
|
||||
String email;
|
||||
String mobilePhone;
|
||||
Integer status;
|
||||
Set<RoleOverview> roles;
|
||||
String nickname;
|
||||
String avatar;
|
||||
Integer sex;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package xyz.zhouxy.plusone.system.application.query.result;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Set;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 账号概述信息
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@Accessors(chain = true)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@ToString
|
||||
public class AccountOverview {
|
||||
Long id;
|
||||
String username;
|
||||
String email;
|
||||
String mobilePhone;
|
||||
Integer status;
|
||||
Set<String> roles;
|
||||
String nickname;
|
||||
String avatar;
|
||||
Integer sex;
|
||||
Long createdBy;
|
||||
LocalDateTime createTime;
|
||||
Long updatedBy;
|
||||
LocalDateTime updateTime;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package xyz.zhouxy.plusone.system.application.query.result;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 数据字典概述信息
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Data
|
||||
public class DictOverview {
|
||||
Long id;
|
||||
String dictType;
|
||||
String dictLabel;
|
||||
Integer count;
|
||||
Long createdBy;
|
||||
LocalDateTime createTime;
|
||||
Long updatedBy;
|
||||
LocalDateTime updateTime;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package xyz.zhouxy.plusone.system.application.query.result;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* 登录结果
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@ToString
|
||||
public class LoginInfoViewObject {
|
||||
private String token;
|
||||
private AccountDetails account;
|
||||
|
||||
public static LoginInfoViewObject of(String token, AccountDetails accountDetails) {
|
||||
return new LoginInfoViewObject(token, accountDetails);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
package xyz.zhouxy.plusone.system.application.query.result;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import xyz.zhouxy.plusone.domain.IWithOrderNumber;
|
||||
import xyz.zhouxy.plusone.system.domain.model.menu.Action;
|
||||
import xyz.zhouxy.plusone.system.domain.model.menu.Menu;
|
||||
import xyz.zhouxy.plusone.system.domain.model.menu.Menu.MenuType;
|
||||
|
||||
/**
|
||||
* 菜单信息
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@NoArgsConstructor
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
public class MenuViewObject implements IWithOrderNumber {
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
Integer type;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
String typeName;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
Long id;
|
||||
@Getter
|
||||
@Setter
|
||||
Long parentId;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
String name;
|
||||
// 若 type 为 MENU_ITEM 且 path 以 http:// 或 https:// 开头则被识别为外链
|
||||
@Getter
|
||||
@Setter
|
||||
String path;
|
||||
@Getter
|
||||
@Setter
|
||||
String title;
|
||||
@Getter
|
||||
@Setter
|
||||
String icon;
|
||||
@Getter
|
||||
@Setter
|
||||
boolean hidden;
|
||||
@Getter
|
||||
@Setter
|
||||
int orderNumber;
|
||||
@Getter
|
||||
@Setter
|
||||
Integer status;
|
||||
@Getter
|
||||
@Setter
|
||||
String remarks;
|
||||
|
||||
// MENU_ITEM
|
||||
@Getter
|
||||
@Setter
|
||||
String component;
|
||||
@Getter
|
||||
@Setter
|
||||
Boolean cache;
|
||||
@Getter
|
||||
@Setter
|
||||
String resource;
|
||||
@Getter
|
||||
@Setter
|
||||
List<Action> actions;
|
||||
|
||||
// MENU_LIST
|
||||
List<MenuViewObject> children;
|
||||
|
||||
public void addChild(MenuViewObject child) {
|
||||
if (this.children == null) {
|
||||
this.children = new ArrayList<>();
|
||||
}
|
||||
this.children.add(child);
|
||||
}
|
||||
|
||||
public void addChildren(Collection<MenuViewObject> children) {
|
||||
if (this.children == null) {
|
||||
this.children = new ArrayList<>();
|
||||
}
|
||||
this.children.addAll(children);
|
||||
}
|
||||
|
||||
public static MenuViewObject of(Menu menu) {
|
||||
var viewObject = new MenuViewObject();
|
||||
viewObject.type = menu.getType().ordinal();
|
||||
viewObject.typeName = menu.getType().name();
|
||||
viewObject.id = menu.getId().orElseThrow();
|
||||
viewObject.parentId = menu.getParentId();
|
||||
viewObject.name = menu.getName();
|
||||
viewObject.path = menu.getPath();
|
||||
viewObject.title = menu.getTitle();
|
||||
viewObject.icon = menu.getIcon();
|
||||
viewObject.hidden = menu.isHidden();
|
||||
viewObject.orderNumber = menu.getOrderNumber();
|
||||
viewObject.status = menu.getStatus().getValue();
|
||||
viewObject.remarks = menu.getRemarks();
|
||||
if (viewObject.type == MenuType.MENU_ITEM.ordinal()) {
|
||||
viewObject.component = menu.getComponent();
|
||||
viewObject.cache = menu.getCache();
|
||||
viewObject.resource = menu.getResource();
|
||||
viewObject.actions = menu.getActions();
|
||||
}
|
||||
return viewObject;
|
||||
}
|
||||
|
||||
public List<MenuViewObject> getChildren() {
|
||||
return Objects.nonNull(this.children)
|
||||
? this.children
|
||||
.stream()
|
||||
.sorted(Comparator.comparing(IWithOrderNumber::getOrderNumber))
|
||||
.toList()
|
||||
: null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package xyz.zhouxy.plusone.system.application.query.result;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 角色信息
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class RoleOverview {
|
||||
// 角色 id
|
||||
Long id;
|
||||
// 角色名
|
||||
String name;
|
||||
// 标识符(安全框架校验权限所用)
|
||||
String identifier;
|
||||
Integer status;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package xyz.zhouxy.plusone.system.application.service;
|
||||
|
||||
import static xyz.zhouxy.plusone.system.constant.AuthLogic.adminAuthLogic;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import xyz.zhouxy.plusone.system.application.query.AccountQueries;
|
||||
import xyz.zhouxy.plusone.system.application.query.result.AccountDetails;
|
||||
import xyz.zhouxy.plusone.system.application.query.result.MenuViewObject;
|
||||
|
||||
/**
|
||||
* 账号查询本身相关信息
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Service
|
||||
public class AccountContextService {
|
||||
|
||||
private final AccountQueries accountQueries;
|
||||
private final MenuManagementService menuManagementService;
|
||||
|
||||
public AccountContextService(AccountQueries accountQueries, MenuManagementService menuManagementService) {
|
||||
this.accountQueries = accountQueries;
|
||||
this.menuManagementService = menuManagementService;
|
||||
}
|
||||
|
||||
public AccountDetails getAccountInfo() {
|
||||
long accountId = adminAuthLogic.getLoginIdAsLong();
|
||||
return accountQueries.queryAccountDetails(accountId);
|
||||
}
|
||||
|
||||
public List<MenuViewObject> getMenuTree() {
|
||||
long accountId = adminAuthLogic.getLoginIdAsLong();
|
||||
return menuManagementService.queryByAccountId(accountId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package xyz.zhouxy.plusone.system.application.service;
|
||||
|
||||
import static xyz.zhouxy.plusone.system.constant.AuthLogic.adminAuthLogic;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
|
||||
import xyz.zhouxy.plusone.system.application.exception.AccountRegisterException;
|
||||
import xyz.zhouxy.plusone.system.application.query.AccountQueries;
|
||||
import xyz.zhouxy.plusone.system.application.query.params.AccountQueryParams;
|
||||
import xyz.zhouxy.plusone.system.application.query.result.AccountDetails;
|
||||
import xyz.zhouxy.plusone.system.application.query.result.AccountOverview;
|
||||
import xyz.zhouxy.plusone.system.application.service.command.CreateAccountCommand;
|
||||
import xyz.zhouxy.plusone.system.application.service.command.UpdateAccountCommand;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.Account;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.AccountInfo;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.AccountRepository;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.Email;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.MobilePhone;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.Username;
|
||||
import xyz.zhouxy.plusone.util.AssertResult;
|
||||
import xyz.zhouxy.plusone.util.PageDTO;
|
||||
|
||||
/**
|
||||
* 账号管理
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Service
|
||||
@Transactional
|
||||
public class AccountManagementService {
|
||||
|
||||
private final AccountRepository accountRepository;
|
||||
private final AccountQueries accountQueries;
|
||||
|
||||
public AccountManagementService(AccountRepository accountRepository, AccountQueries accountQueries) {
|
||||
this.accountRepository = accountRepository;
|
||||
this.accountQueries = accountQueries;
|
||||
}
|
||||
|
||||
public void createAccount(@Valid CreateAccountCommand command) {
|
||||
String username = command.getUsername();
|
||||
if (accountRepository.existsUsername(Username.of(username))) {
|
||||
throw AccountRegisterException.usernameAlreadyExists(username);
|
||||
}
|
||||
String email = command.getEmail();
|
||||
if (StringUtils.hasText(email) && accountRepository.existsEmail(Email.of(email))) {
|
||||
throw AccountRegisterException.emailAlreadyExists(email);
|
||||
}
|
||||
String mobilePhone = command.getMobilePhone();
|
||||
if (StringUtils.hasText(mobilePhone) && accountRepository.existsMobilePhone(MobilePhone.of(mobilePhone))) {
|
||||
throw AccountRegisterException.mobilePhoneAlreadyExists(mobilePhone);
|
||||
}
|
||||
Account account = Account.newInstance(
|
||||
username,
|
||||
email,
|
||||
mobilePhone,
|
||||
command.getPassword(),
|
||||
command.getPasswordConfirmation(),
|
||||
command.getStatus(),
|
||||
command.getRoleRefs(),
|
||||
AccountInfo.of(command.getNickname(), command.getAvatar(), command.getSex()),
|
||||
adminAuthLogic.getLoginIdAsLong());
|
||||
accountRepository.save(account);
|
||||
}
|
||||
|
||||
public void deleteAccounts(List<Long> ids) {
|
||||
Account accountToDelete;
|
||||
for (var id : ids) {
|
||||
accountToDelete = accountRepository.find(id);
|
||||
AssertResult.nonNull(accountToDelete);
|
||||
accountRepository.delete(accountToDelete);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateAccountInfo(Long id, @Valid UpdateAccountCommand command) {
|
||||
Assert.isTrue(Objects.equals(id, command.getId()), "参数错误: id 不匹配");
|
||||
Account account = accountRepository.find(id);
|
||||
AssertResult.nonNull(account, "该账号不存在");
|
||||
account.setAccountInfo(command.getNickname(), command.getAvatar(), command.getSex());
|
||||
account.setUpdatedBy(adminAuthLogic.getLoginIdAsLong());
|
||||
accountRepository.save(account);
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.SUPPORTS)
|
||||
public PageDTO<AccountOverview> queryAccountOverviewList(AccountQueryParams queryParams) {
|
||||
return accountQueries.queryAccountOverviewPage(queryParams);
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.SUPPORTS)
|
||||
public AccountDetails queryAccountDetails(@PathVariable("accountId") Long accountId) {
|
||||
var accountDetails = accountQueries.queryAccountDetails(accountId);
|
||||
AssertResult.nonNull(accountDetails);
|
||||
return accountDetails;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package xyz.zhouxy.plusone.system.application.service;
|
||||
|
||||
import static xyz.zhouxy.plusone.system.constant.AuthLogic.adminAuthLogic;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import xyz.zhouxy.plusone.exception.InvalidInputException;
|
||||
import xyz.zhouxy.plusone.system.application.common.util.PrincipalType;
|
||||
import xyz.zhouxy.plusone.system.application.common.util.PrincipalUtil;
|
||||
import xyz.zhouxy.plusone.system.application.exception.AccountLoginException;
|
||||
import xyz.zhouxy.plusone.system.application.query.AccountQueries;
|
||||
import xyz.zhouxy.plusone.system.application.query.result.LoginInfoViewObject;
|
||||
import xyz.zhouxy.plusone.system.application.service.command.LoginByOtpCommand;
|
||||
import xyz.zhouxy.plusone.system.application.service.command.LoginByPasswordCommand;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.Account;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.AccountRepository;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.Email;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.MobilePhone;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.Principal;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.Username;
|
||||
import xyz.zhouxy.plusone.validator.ValidateDto;
|
||||
|
||||
/**
|
||||
* Admin 账号登录
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Service
|
||||
@Transactional
|
||||
public class AdminLoginService {
|
||||
|
||||
private final AccountRepository accountRepository;
|
||||
private final AccountQueries accountQueries;
|
||||
private final MailAndSmsVerifyService mailAndSmsVerifyService;
|
||||
|
||||
AdminLoginService(AccountRepository accountRepository, AccountQueries accountQueries,
|
||||
MailAndSmsVerifyService mailAndSmsVerifyService) {
|
||||
this.accountRepository = accountRepository;
|
||||
this.accountQueries = accountQueries;
|
||||
this.mailAndSmsVerifyService = mailAndSmsVerifyService;
|
||||
}
|
||||
|
||||
@ValidateDto
|
||||
public LoginInfoViewObject loginByPassword(LoginByPasswordCommand command) {
|
||||
Principal principal = PrincipalUtil.getPrincipal(command.getPrincipal());
|
||||
Account account;
|
||||
if (principal instanceof Email) {
|
||||
account = accountRepository.findByEmail((Email) principal);
|
||||
} else if (principal instanceof MobilePhone) {
|
||||
account = accountRepository.findByMobilePhone((MobilePhone) principal);
|
||||
} else {
|
||||
account = accountRepository.findByUsername((Username) principal);
|
||||
}
|
||||
|
||||
if (account == null) {
|
||||
throw AccountLoginException.accountNotExistException();
|
||||
}
|
||||
@SuppressWarnings("null")
|
||||
boolean isPasswordCorrect = account.checkPassword(command.getPassword());
|
||||
if (!isPasswordCorrect) {
|
||||
throw AccountLoginException.passwordErrorException();
|
||||
}
|
||||
adminAuthLogic.login(account.getId().orElseThrow(), command.isRememberMe());
|
||||
|
||||
var accountDetails = accountQueries.queryAccountDetails(account.getId().orElseThrow());
|
||||
return LoginInfoViewObject.of(adminAuthLogic.getTokenValue(), accountDetails);
|
||||
}
|
||||
|
||||
@ValidateDto
|
||||
public LoginInfoViewObject loginByOtp(LoginByOtpCommand command) {
|
||||
String principal = command.getPrincipal();
|
||||
PrincipalType principalType = PrincipalUtil.getPrincipalType(principal);
|
||||
String otp = command.getOtp();
|
||||
boolean rememberMe = command.isRememberMe();
|
||||
|
||||
Account account;
|
||||
if (principalType == PrincipalType.EMAIL) {
|
||||
account = accountRepository.findByEmail(Email.of(principal));
|
||||
} else if (principalType == PrincipalType.MOBILE_PHONE) {
|
||||
account = accountRepository.findByMobilePhone(MobilePhone.of(principal));
|
||||
} else {
|
||||
throw InvalidInputException.unsupportedPrincipalTypeException("输入邮箱地址或手机号");
|
||||
}
|
||||
|
||||
if (account == null) {
|
||||
throw AccountLoginException.accountNotExistException();
|
||||
}
|
||||
mailAndSmsVerifyService.checkOtp(principal, otp);
|
||||
adminAuthLogic.login(account.getId().orElseThrow(), rememberMe);
|
||||
|
||||
var accountDetails = accountQueries.queryAccountDetails(account.getId().orElseThrow());
|
||||
return LoginInfoViewObject.of(adminAuthLogic.getTokenValue(), accountDetails);
|
||||
}
|
||||
|
||||
public void sendOtp(String principal) {
|
||||
Principal emailOrMobilePhone = PrincipalUtil.getEmailOrMobilePhone(principal);
|
||||
if (emailOrMobilePhone instanceof Email) {
|
||||
mailAndSmsVerifyService.sendOtpToEmail((Email) emailOrMobilePhone);
|
||||
} else {
|
||||
mailAndSmsVerifyService.sendOtpToMobilePhone((MobilePhone) emailOrMobilePhone);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package xyz.zhouxy.plusone.system.application.service;
|
||||
|
||||
import static xyz.zhouxy.plusone.system.constant.AuthLogic.adminAuthLogic;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* Admin 账号登出
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Service
|
||||
public class AdminLogoutService {
|
||||
|
||||
public void execute() {
|
||||
adminAuthLogic.checkLogin();
|
||||
adminAuthLogic.logout();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package xyz.zhouxy.plusone.system.application.service;
|
||||
|
||||
import static xyz.zhouxy.plusone.system.constant.AuthLogic.*;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
import cn.dev33.satoken.stp.StpInterface;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import xyz.zhouxy.plusone.system.domain.model.menu.Action;
|
||||
import xyz.zhouxy.plusone.system.domain.model.menu.MenuRepository;
|
||||
import xyz.zhouxy.plusone.system.domain.model.role.ActionRef;
|
||||
import xyz.zhouxy.plusone.system.domain.model.role.Role;
|
||||
import xyz.zhouxy.plusone.system.domain.model.role.RoleRepository;
|
||||
|
||||
@Service
|
||||
public class AuthService implements StpInterface {
|
||||
|
||||
private RoleRepository roleRepository;
|
||||
private MenuRepository menuRepository;
|
||||
|
||||
public AuthService(RoleRepository roleRepository, MenuRepository menuRepository) {
|
||||
this.roleRepository = roleRepository;
|
||||
this.menuRepository = menuRepository;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getPermissionList(Object loginId, String loginType) {
|
||||
Collection<Role> roles = getRoleList(loginId);
|
||||
Set<Long> permissionIds = new HashSet<>();
|
||||
roles.forEach(role -> permissionIds.addAll(
|
||||
role.getPermissions()
|
||||
.stream()
|
||||
.map(ActionRef::actionId)
|
||||
.toList()));
|
||||
List<String> permValList = menuRepository.findPermissionsByIdIn(permissionIds)
|
||||
.stream().map(Action::value).toList();
|
||||
return permValList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getRoleList(Object loginId, String loginType) {
|
||||
SaSession session = switch (loginType) {
|
||||
case ADMIN_LOGIN_TYPE -> adminAuthLogic.getSessionByLoginId(loginId);
|
||||
case USER_LOGIN_TYPE -> userAuthLogic.getSessionByLoginId(loginId);
|
||||
default -> StpUtil.getSessionByLoginId(loginId);
|
||||
};
|
||||
return session.get("RoleList",
|
||||
() -> getRoleList(loginId).stream().map(Role::getIdentifier).toList());
|
||||
}
|
||||
|
||||
private Collection<Role> getRoleList(Object loginId) {
|
||||
return roleRepository.findByAccountId(Long.valueOf((String) loginId));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package xyz.zhouxy.plusone.system.application.service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import xyz.zhouxy.plusone.system.application.query.DictQueries;
|
||||
import xyz.zhouxy.plusone.system.application.query.params.DictQueryParams;
|
||||
import xyz.zhouxy.plusone.system.application.query.result.DictOverview;
|
||||
import xyz.zhouxy.plusone.system.application.service.command.CreateDictCommand;
|
||||
import xyz.zhouxy.plusone.system.application.service.command.UpdateDictCommand;
|
||||
import xyz.zhouxy.plusone.system.domain.model.dict.Dict;
|
||||
import xyz.zhouxy.plusone.system.domain.model.dict.DictRepository;
|
||||
|
||||
/**
|
||||
* 数据字典管理
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Service
|
||||
@Transactional
|
||||
public class DictManagementService {
|
||||
|
||||
private final DictRepository dictRepository;
|
||||
private final DictQueries dictQueries;
|
||||
|
||||
public DictManagementService(DictRepository dictRepository, DictQueries dictQueries) {
|
||||
this.dictRepository = dictRepository;
|
||||
this.dictQueries = dictQueries;
|
||||
}
|
||||
|
||||
public void createDict(@Valid CreateDictCommand command) {
|
||||
var dictToSave = Dict.newInstance(command.getDictType(),
|
||||
command.getDictLabel(),
|
||||
command.getKeyLabelMap());
|
||||
dictRepository.save(dictToSave);
|
||||
}
|
||||
|
||||
public void deleteDicts(List<Long> ids) {
|
||||
Dict dictToDelete;
|
||||
for (Long id : ids) {
|
||||
dictToDelete = dictRepository.find(id);
|
||||
dictRepository.delete(dictToDelete);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateDict(Long id, @Valid UpdateDictCommand command) {
|
||||
Assert.isTrue(Objects.equals(id, command.getId()), "id 不匹配");
|
||||
Dict dictToUpdate = dictRepository.find(command.getId());
|
||||
dictToUpdate.updateDict(command.getDictType(), command.getDictLabel(), command.getKeyLabelMap());
|
||||
dictRepository.save(dictToUpdate);
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.SUPPORTS)
|
||||
public Dict findDictDetails(Long dictId) {
|
||||
return dictRepository.find(dictId);
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.SUPPORTS)
|
||||
public List<Dict> loadAllDicts() {
|
||||
return dictRepository.findAll();
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.SUPPORTS)
|
||||
public List<DictOverview> queryDictOverviewList(@Valid DictQueryParams queryParams) {
|
||||
return dictQueries.queryDictOverviewList(queryParams);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package xyz.zhouxy.plusone.system.application.service;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import xyz.zhouxy.plusone.mail.MailService;
|
||||
import xyz.zhouxy.plusone.sms.SmsService;
|
||||
import xyz.zhouxy.plusone.system.application.exception.AccountLoginException;
|
||||
import xyz.zhouxy.plusone.system.application.exception.AccountRegisterException;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.AccountRepository;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.Email;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.MobilePhone;
|
||||
|
||||
/**
|
||||
* 邮箱和短信的验证服务
|
||||
*/
|
||||
@Service
|
||||
public class MailAndSmsVerifyService {
|
||||
private static final int CODE_LENGTH = 6;
|
||||
private final AccountRepository accountRepository;
|
||||
private final MailService mailService;
|
||||
private final SmsService smsService;
|
||||
private final StringRedisTemplate redisTemplate;
|
||||
|
||||
public MailAndSmsVerifyService(AccountRepository accountRepository, MailService mailService, SmsService smsService,
|
||||
StringRedisTemplate redisTemplate) {
|
||||
this.accountRepository = accountRepository;
|
||||
this.mailService = mailService;
|
||||
this.smsService = smsService;
|
||||
this.redisTemplate = redisTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送一次性密码到邮箱
|
||||
*
|
||||
* @param email 要求邮箱必须已注册
|
||||
*/
|
||||
public void sendOtpToEmail(Email email) {
|
||||
Assert.isTrue(accountRepository.existsEmail(email), "该邮箱未绑定任何帐号");
|
||||
var otp = generateCode();
|
||||
mailService.sendCodeMail(otp, email.value());
|
||||
redisTemplate.opsForValue().set("OTP-" + email.value(), otp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送一次性密码到手机号
|
||||
*
|
||||
* @param mobilePhone 要求手机号必须已注册
|
||||
*/
|
||||
public void sendOtpToMobilePhone(MobilePhone mobilePhone) {
|
||||
Assert.isTrue(accountRepository.existsMobilePhone(mobilePhone), "该手机号未绑定任何帐号");
|
||||
var otp = generateCode();
|
||||
smsService.sendCodeMessage(otp, mobilePhone.value());
|
||||
redisTemplate.opsForValue().set("OTP-" + mobilePhone.value(), otp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送校验码到邮箱
|
||||
*
|
||||
* @param email 要求邮箱必须未注册
|
||||
*/
|
||||
public void sendCodeToEmail(Email email) {
|
||||
Assert.isTrue(!accountRepository.existsEmail(email), "该邮箱未绑定任何帐号");
|
||||
var code = generateCode();
|
||||
mailService.sendCodeMail(code, email.value());
|
||||
redisTemplate.opsForValue().set("Code-" + email.value(), code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送校验码到手机号
|
||||
*
|
||||
* @param mobilePhone 要求手机号必须未注册
|
||||
*/
|
||||
public void sendCodeToMobilePhone(MobilePhone mobilePhone) {
|
||||
Assert.isTrue(!accountRepository.existsMobilePhone(mobilePhone), "该手机号未绑定任何帐号");
|
||||
var code = generateCode();
|
||||
smsService.sendCodeMessage(code, mobilePhone.value());
|
||||
redisTemplate.opsForValue().set("Code-" + mobilePhone.value(), code);
|
||||
}
|
||||
|
||||
public void checkOtp(String emailOrMobilePhone, String otp) {
|
||||
String key = "OTP-" + emailOrMobilePhone;
|
||||
String otpInRedis = redisTemplate.opsForValue().get(key);
|
||||
if (otpInRedis == null) {
|
||||
throw AccountLoginException.otpNotExistsException();
|
||||
}
|
||||
if (!Objects.equals(otpInRedis, otp)) {
|
||||
throw AccountLoginException.otpErrorException();
|
||||
}
|
||||
redisTemplate.delete(key);
|
||||
}
|
||||
|
||||
public void checkCode(String emailOrMobilePhone, String code) {
|
||||
String key = "Code-" + emailOrMobilePhone;
|
||||
String codeInRedis = redisTemplate.opsForValue().get(key);
|
||||
if (codeInRedis == null) {
|
||||
throw AccountRegisterException.codeNotExistsException();
|
||||
}
|
||||
if (!Objects.equals(codeInRedis, code)) {
|
||||
throw AccountRegisterException.codeErrorException();
|
||||
}
|
||||
redisTemplate.delete(key);
|
||||
}
|
||||
|
||||
private static String generateCode() {
|
||||
return RandomUtil.randomString(CODE_LENGTH);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
package xyz.zhouxy.plusone.system.application.service;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import xyz.zhouxy.plusone.domain.IWithOrderNumber;
|
||||
import xyz.zhouxy.plusone.system.application.exception.UnsupportedMenuTypeException;
|
||||
import xyz.zhouxy.plusone.system.application.query.result.MenuViewObject;
|
||||
import xyz.zhouxy.plusone.system.application.service.command.CreateMenuCommand;
|
||||
import xyz.zhouxy.plusone.system.application.service.command.UpdateMenuCommand;
|
||||
import xyz.zhouxy.plusone.system.domain.model.menu.Menu;
|
||||
import xyz.zhouxy.plusone.system.domain.model.menu.MenuConstructor;
|
||||
import xyz.zhouxy.plusone.system.domain.model.menu.MenuRepository;
|
||||
import xyz.zhouxy.plusone.system.domain.service.MenuService;
|
||||
import xyz.zhouxy.plusone.util.AssertResult;
|
||||
|
||||
/**
|
||||
* 菜单管理
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Service
|
||||
@Transactional
|
||||
public class MenuManagementService {
|
||||
|
||||
private final MenuService menuService;
|
||||
private final MenuRepository menuRepository;
|
||||
|
||||
MenuManagementService(MenuService roleRepository, MenuRepository menuRepository) {
|
||||
this.menuService = roleRepository;
|
||||
this.menuRepository = menuRepository;
|
||||
}
|
||||
|
||||
// ==================== create ====================
|
||||
public void createMenu(@Valid CreateMenuCommand command) {
|
||||
Menu menuToInsert;
|
||||
switch (command.getMenuType()) {
|
||||
case MENU_LIST:
|
||||
menuToInsert = createMenuList(command);
|
||||
break;
|
||||
case MENU_ITEM:
|
||||
menuToInsert = createMenuItem(command);
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedMenuTypeException();
|
||||
}
|
||||
menuRepository.save(menuToInsert);
|
||||
}
|
||||
|
||||
private Menu createMenuList(CreateMenuCommand command) {
|
||||
return MenuConstructor.newMenuList(
|
||||
command.getParentId(),
|
||||
command.getPath(),
|
||||
command.getName(),
|
||||
command.getTitle(),
|
||||
command.getIcon(),
|
||||
command.getHidden(),
|
||||
command.getOrderNumber(),
|
||||
command.getStatus(),
|
||||
command.getRemarks());
|
||||
}
|
||||
|
||||
private Menu createMenuItem(CreateMenuCommand command) {
|
||||
return MenuConstructor.newMenuItem(
|
||||
command.getParentId(),
|
||||
command.getPath(),
|
||||
command.getName(),
|
||||
command.getTitle(),
|
||||
command.getIcon(),
|
||||
command.getHidden(),
|
||||
command.getOrderNumber(),
|
||||
command.getStatus(),
|
||||
command.getComponent(),
|
||||
command.getResource(),
|
||||
command.getCache(),
|
||||
command.getRemarks());
|
||||
}
|
||||
|
||||
// ==================== delete ====================
|
||||
public void deleteMenu(Long id) {
|
||||
Menu menuToDelete = menuRepository.find(id);
|
||||
AssertResult.nonNull(menuToDelete);
|
||||
menuRepository.delete(menuToDelete);
|
||||
}
|
||||
|
||||
// ==================== update ====================
|
||||
public void updateMenu(Long id, @Valid UpdateMenuCommand command) {
|
||||
Assert.isTrue(Objects.equals(id, command.getId()), "id 不匹配");
|
||||
Menu menuToUpdate = menuRepository.find(command.getId());
|
||||
menuToUpdate.updateMenuInfo(
|
||||
command.getMenuType(),
|
||||
command.getParentId(),
|
||||
command.getPath(),
|
||||
command.getName(),
|
||||
command.getTitle(),
|
||||
command.getIcon(),
|
||||
command.getHidden(),
|
||||
command.getOrderNumber(),
|
||||
command.getStatus(),
|
||||
command.getComponent(),
|
||||
command.getResource(),
|
||||
command.getCache(),
|
||||
command.getRemarks());
|
||||
menuRepository.save(menuToUpdate);
|
||||
}
|
||||
|
||||
// ==================== query ====================
|
||||
@Transactional(propagation = Propagation.SUPPORTS)
|
||||
public MenuViewObject findById(Long id) {
|
||||
var menu = menuRepository.find(id);
|
||||
return MenuViewObject.of(menu);
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.SUPPORTS)
|
||||
public List<MenuViewObject> queryByAccountId(Long accountId) {
|
||||
var menus = menuService.queryAllMenuListByAccountId(accountId);
|
||||
var menuViewObjects = menus.stream().map(MenuViewObject::of).toList();
|
||||
return buildMenuTree(menuViewObjects);
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.SUPPORTS)
|
||||
public List<MenuViewObject> queryByRoleId(Long roleId) {
|
||||
var menus = menuRepository.queryByRoleId(roleId);
|
||||
var menuViewObjects = menus.stream().map(MenuViewObject::of).toList();
|
||||
return buildMenuTree(menuViewObjects);
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.SUPPORTS)
|
||||
public List<MenuViewObject> buildMenuTree(List<MenuViewObject> menus) {
|
||||
List<MenuViewObject> rootMenus = menus
|
||||
.stream()
|
||||
.filter(menu -> Objects.equals(menu.getParentId(), 0L))
|
||||
.toList();
|
||||
|
||||
Map<Long, MenuViewObject> allMenus = new HashMap<>();
|
||||
for (var item : menus) {
|
||||
allMenus.put(item.getId(), item);
|
||||
}
|
||||
|
||||
for (MenuViewObject menu : menus) {
|
||||
long parentId = menu.getParentId();
|
||||
while (parentId != 0 && !allMenus.containsKey(parentId)) {
|
||||
MenuViewObject parent = findById(parentId);
|
||||
if (parent == null) {
|
||||
break;
|
||||
}
|
||||
allMenus.put(parent.getId(), parent);
|
||||
parentId = parent.getParentId();
|
||||
}
|
||||
}
|
||||
|
||||
for (var menu : allMenus.values()) {
|
||||
var parent = allMenus.getOrDefault(menu.getParentId(), null);
|
||||
if (parent != null) {
|
||||
parent.addChild(menu);
|
||||
}
|
||||
}
|
||||
|
||||
return rootMenus
|
||||
.stream()
|
||||
.sorted(Comparator.comparing(IWithOrderNumber::getOrderNumber))
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package xyz.zhouxy.plusone.system.application.service;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import xyz.zhouxy.plusone.exception.InvalidInputException;
|
||||
import xyz.zhouxy.plusone.system.application.common.util.PrincipalType;
|
||||
import xyz.zhouxy.plusone.system.application.common.util.PrincipalUtil;
|
||||
import xyz.zhouxy.plusone.system.application.exception.AccountRegisterException;
|
||||
import xyz.zhouxy.plusone.system.application.service.command.RegisterAccountCommand;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.Account;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.AccountInfo;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.AccountRepository;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.AccountStatus;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.Email;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.MobilePhone;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.Password;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.Username;
|
||||
|
||||
/**
|
||||
* 注册账号服务
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Service
|
||||
@Transactional
|
||||
public class RegisterAccountService {
|
||||
|
||||
private static final long DEFAULT_ROLE_ID = 1L;
|
||||
|
||||
private final AccountRepository accountRepository;
|
||||
private final MailAndSmsVerifyService verifyService;
|
||||
|
||||
public RegisterAccountService(AccountRepository accountRepository, MailAndSmsVerifyService verifyService) {
|
||||
this.accountRepository = accountRepository;
|
||||
this.verifyService = verifyService;
|
||||
}
|
||||
|
||||
public void registerAccount(RegisterAccountCommand command) {
|
||||
String username = command.getUsername();
|
||||
var existsUsername = accountRepository.existsUsername(Username.of(username));
|
||||
if (existsUsername) {
|
||||
throw AccountRegisterException.usernameAlreadyExists(username);
|
||||
}
|
||||
// 1. 确定是使用邮箱地址还是手机号进行注册
|
||||
String emailOrMobilePhone = command.getEmailOrMobilePhone();
|
||||
if (emailOrMobilePhone == null) {
|
||||
throw new IllegalArgumentException("邮箱地址或手机号不能为空");
|
||||
}
|
||||
PrincipalType principalType = PrincipalUtil.getPrincipalType(emailOrMobilePhone);
|
||||
|
||||
// 2. 确定该邮箱地址或手机号是否存在,比对校验码
|
||||
Email email = null;
|
||||
MobilePhone mobilePhone = null;
|
||||
boolean isExists;
|
||||
|
||||
if (principalType == PrincipalType.EMAIL) {
|
||||
email = Email.of(emailOrMobilePhone);
|
||||
isExists = accountRepository.existsEmail(email);
|
||||
if (isExists) {
|
||||
throw AccountRegisterException.emailAlreadyExists(email.value());
|
||||
}
|
||||
} else if (principalType == PrincipalType.MOBILE_PHONE) {
|
||||
mobilePhone = MobilePhone.of(emailOrMobilePhone);
|
||||
isExists = accountRepository.existsMobilePhone(mobilePhone);
|
||||
if (isExists) {
|
||||
throw AccountRegisterException.emailAlreadyExists(mobilePhone.value());
|
||||
}
|
||||
} else {
|
||||
throw InvalidInputException.unsupportedPrincipalTypeException();
|
||||
}
|
||||
|
||||
verifyService.checkCode(emailOrMobilePhone, command.getCode());
|
||||
|
||||
Account accountToSave = Account.register(
|
||||
Username.of(username),
|
||||
email,
|
||||
mobilePhone,
|
||||
Password.newPassword(command.getPassword(), command.getPasswordConfirmation()),
|
||||
AccountStatus.AVAILABLE,
|
||||
Set.of(DEFAULT_ROLE_ID),
|
||||
AccountInfo.of(command.getNickname(), command.getAvatar(), command.getSex()));
|
||||
accountRepository.save(accountToSave);
|
||||
}
|
||||
|
||||
public void sendCode(String principal) {
|
||||
PrincipalType principalType = PrincipalUtil.getPrincipalType(principal);
|
||||
if (principalType == PrincipalType.EMAIL) {
|
||||
verifyService.sendCodeToEmail(Email.of(principal));
|
||||
} else if (principalType == PrincipalType.MOBILE_PHONE) {
|
||||
verifyService.sendCodeToMobilePhone(MobilePhone.of(principal));
|
||||
} else {
|
||||
throw InvalidInputException.unsupportedPrincipalTypeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package xyz.zhouxy.plusone.system.application.service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import xyz.zhouxy.plusone.system.application.query.RoleQueries;
|
||||
import xyz.zhouxy.plusone.system.application.query.params.RoleQueryParams;
|
||||
import xyz.zhouxy.plusone.system.application.query.result.RoleOverview;
|
||||
import xyz.zhouxy.plusone.system.application.service.command.CreateRoleCommand;
|
||||
import xyz.zhouxy.plusone.system.application.service.command.UpdateRoleCommand;
|
||||
import xyz.zhouxy.plusone.system.domain.model.menu.MenuRepository;
|
||||
import xyz.zhouxy.plusone.system.domain.model.role.ActionRef;
|
||||
import xyz.zhouxy.plusone.system.domain.model.role.MenuRef;
|
||||
import xyz.zhouxy.plusone.system.domain.model.role.Role;
|
||||
import xyz.zhouxy.plusone.system.domain.model.role.RoleRepository;
|
||||
|
||||
/**
|
||||
* 角色管理服务
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Service
|
||||
@Transactional
|
||||
public class RoleManagementService {
|
||||
|
||||
private final RoleRepository _roleRepository;
|
||||
private final MenuRepository _menuRepository;
|
||||
private final RoleQueries _roleQueries;
|
||||
|
||||
public RoleManagementService(RoleRepository roleRepository, MenuRepository menuRepository,
|
||||
RoleQueries roleQueries) {
|
||||
_roleRepository = roleRepository;
|
||||
_menuRepository = menuRepository;
|
||||
_roleQueries = roleQueries;
|
||||
}
|
||||
|
||||
public void createRole(@Valid CreateRoleCommand command) {
|
||||
Set<MenuRef> menuRefs = _menuRepository.findByIdIn(command.getMenus())
|
||||
.stream()
|
||||
.map(menu -> new MenuRef(menu.getId().orElseThrow()))
|
||||
.collect(Collectors.toSet());
|
||||
Set<ActionRef> permissionRefs = _menuRepository.findPermissionsByIdIn(command.getPermissions())
|
||||
.stream()
|
||||
.map(permission -> new ActionRef(permission.getId().orElseThrow()))
|
||||
.collect(Collectors.toSet());
|
||||
Role roleToCreate = Role.newInstance(
|
||||
command.getName(),
|
||||
command.getIdentifier(),
|
||||
command.getStatus(),
|
||||
command.getRemarks(),
|
||||
menuRefs,
|
||||
permissionRefs);
|
||||
_roleRepository.save(roleToCreate);
|
||||
}
|
||||
|
||||
public void updateRole(@Valid UpdateRoleCommand command) {
|
||||
Long roleId = command.getId();
|
||||
Role roleToUpdate = _roleRepository.find(roleId);
|
||||
roleToUpdate.update(
|
||||
command.getName(),
|
||||
command.getIdentifier(),
|
||||
command.getStatus(),
|
||||
command.getRemarks(),
|
||||
Set.copyOf(_menuRepository.findByIdIn(command.getMenus())),
|
||||
Set.copyOf(_menuRepository.findPermissionsByIdIn(command.getPermissions())));
|
||||
_roleRepository.save(roleToUpdate);
|
||||
}
|
||||
|
||||
public void delete(Long id) {
|
||||
Role role = _roleRepository.find(id);
|
||||
_roleRepository.delete(role);
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.SUPPORTS)
|
||||
public boolean exists(Long id) {
|
||||
return _roleRepository.exists(id);
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.SUPPORTS)
|
||||
public Role findById(Long id) {
|
||||
return _roleRepository.find(id);
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.SUPPORTS)
|
||||
public List<RoleOverview> query(RoleQueryParams params) {
|
||||
return _roleQueries.query(params);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package xyz.zhouxy.plusone.system.application.service.command;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Pattern;
|
||||
|
||||
import org.hibernate.validator.constraints.URL;
|
||||
|
||||
import lombok.Data;
|
||||
import xyz.zhouxy.plusone.constant.RegexConsts;
|
||||
import xyz.zhouxy.plusone.domain.ICommand;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.AccountStatus;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.Sex;
|
||||
|
||||
/**
|
||||
* 创建账号命令
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Data
|
||||
public class CreateAccountCommand implements ICommand {
|
||||
|
||||
@NotBlank
|
||||
@Pattern(regexp = RegexConsts.USERNAME, message = "用户名格式错误")
|
||||
String username;
|
||||
|
||||
@Email(message = "邮箱地址格式错误")
|
||||
String email;
|
||||
|
||||
@Pattern(regexp = RegexConsts.MOBILE_PHONE, message = "手机号格式错误")
|
||||
String mobilePhone;
|
||||
|
||||
@NotBlank
|
||||
@Pattern(regexp = RegexConsts.PASSWORD, message = "密码不符合要求")
|
||||
String password;
|
||||
@NotBlank
|
||||
@Pattern(regexp = RegexConsts.PASSWORD, message = "密码不符合要求")
|
||||
String passwordConfirmation;
|
||||
|
||||
@NotNull
|
||||
AccountStatus status;
|
||||
|
||||
Set<Long> roleRefs;
|
||||
|
||||
@Pattern(regexp = RegexConsts.NICKNAME, message = "昵称格式错误")
|
||||
String nickname;
|
||||
|
||||
@NotBlank
|
||||
@URL
|
||||
String avatar;
|
||||
|
||||
Sex sex;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package xyz.zhouxy.plusone.system.application.service.command;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import lombok.Data;
|
||||
import xyz.zhouxy.plusone.domain.ICommand;
|
||||
|
||||
/**
|
||||
* 创建数据字典命令
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Data
|
||||
public class CreateDictCommand implements ICommand {
|
||||
|
||||
@NotBlank
|
||||
String dictType;
|
||||
|
||||
@NotBlank
|
||||
String dictLabel;
|
||||
|
||||
@NotNull
|
||||
Map<Integer, String> keyLabelMap;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package xyz.zhouxy.plusone.system.application.service.command;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import xyz.zhouxy.plusone.constant.EntityStatus;
|
||||
import xyz.zhouxy.plusone.domain.ICommand;
|
||||
import xyz.zhouxy.plusone.system.domain.model.menu.Menu.MenuType;
|
||||
|
||||
/**
|
||||
* 创建菜单命令
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class CreateMenuCommand implements ICommand {
|
||||
@NotNull
|
||||
private MenuType menuType;
|
||||
|
||||
@NotNull
|
||||
private Long parentId;
|
||||
|
||||
@NotBlank
|
||||
private String path;
|
||||
|
||||
@NotBlank
|
||||
private String name;
|
||||
|
||||
@NotBlank
|
||||
private String title;
|
||||
|
||||
@NotBlank
|
||||
private String icon;
|
||||
|
||||
@NotNull
|
||||
private Boolean hidden;
|
||||
|
||||
@NotNull
|
||||
private Integer orderNumber;
|
||||
|
||||
@NotNull
|
||||
private EntityStatus status;
|
||||
|
||||
private String component;
|
||||
|
||||
private String resource;
|
||||
|
||||
@NotNull
|
||||
private Boolean cache;
|
||||
|
||||
private String remarks;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package xyz.zhouxy.plusone.system.application.service.command;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import lombok.Data;
|
||||
import xyz.zhouxy.plusone.constant.EntityStatus;
|
||||
import xyz.zhouxy.plusone.domain.ICommand;
|
||||
|
||||
/**
|
||||
* 创建角色命令
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Data
|
||||
public class CreateRoleCommand implements ICommand {
|
||||
|
||||
@NotBlank
|
||||
String name;
|
||||
@NotBlank
|
||||
String identifier;
|
||||
|
||||
@NotNull
|
||||
EntityStatus status;
|
||||
String remarks;
|
||||
|
||||
Set<Long> menus;
|
||||
Set<Long> permissions;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package xyz.zhouxy.plusone.system.application.service.command;
|
||||
|
||||
import lombok.Data;
|
||||
import xyz.zhouxy.plusone.domain.ICommand;
|
||||
|
||||
/**
|
||||
* 登录命令
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Data
|
||||
public class LoginByOtpCommand implements ICommand {
|
||||
|
||||
String principal; // 邮箱地址 / 手机号
|
||||
String otp; // 密码
|
||||
boolean rememberMe; // 记住我
|
||||
|
||||
// 进入登陆界面时或刷新验证码时,前端发送图形验证码的请求,后端生成 captcha 并暂存到 redis 中,key 为 UUID,将图形和 uuid 响应给前端。
|
||||
// String uuid; // 校验码的 key
|
||||
// String captcha; // 校验码
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package xyz.zhouxy.plusone.system.application.service.command;
|
||||
|
||||
import lombok.Data;
|
||||
import xyz.zhouxy.plusone.domain.ICommand;
|
||||
|
||||
/**
|
||||
* 登录命令
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Data
|
||||
public class LoginByPasswordCommand implements ICommand {
|
||||
|
||||
String principal; // 用户名 / 邮箱地址 / 手机号
|
||||
String password; // 密码
|
||||
boolean rememberMe; // 记住我
|
||||
|
||||
// 进入登陆界面时或刷新验证码时,前端发送图形验证码的请求,后端生成 captcha 并暂存到 redis 中,key 为 UUID,将图形和 uuid 响应给前端。
|
||||
// String uuid; // 校验码的 key
|
||||
// String captcha; // 校验码
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package xyz.zhouxy.plusone.system.application.service.command;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Pattern;
|
||||
|
||||
import org.hibernate.validator.constraints.URL;
|
||||
|
||||
import lombok.Data;
|
||||
import xyz.zhouxy.plusone.constant.RegexConsts;
|
||||
import xyz.zhouxy.plusone.domain.ICommand;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.Sex;
|
||||
|
||||
/**
|
||||
* 注册账号命令
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Data
|
||||
public class RegisterAccountCommand implements ICommand {
|
||||
|
||||
@NotBlank
|
||||
String emailOrMobilePhone;
|
||||
|
||||
@NotBlank
|
||||
@Pattern(regexp = RegexConsts.CAPTCHA)
|
||||
String code; // 校验码
|
||||
|
||||
@NotBlank
|
||||
@Pattern(regexp = RegexConsts.USERNAME)
|
||||
String username;
|
||||
|
||||
@NotBlank
|
||||
@Pattern(regexp = RegexConsts.PASSWORD)
|
||||
String password;
|
||||
String passwordConfirmation;
|
||||
|
||||
@Pattern(regexp = RegexConsts.NICKNAME)
|
||||
String nickname;
|
||||
|
||||
@NotBlank
|
||||
@URL
|
||||
String avatar;
|
||||
|
||||
Sex sex;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package xyz.zhouxy.plusone.system.application.service.command;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Pattern;
|
||||
|
||||
import org.hibernate.validator.constraints.URL;
|
||||
|
||||
import lombok.Data;
|
||||
import xyz.zhouxy.plusone.constant.RegexConsts;
|
||||
import xyz.zhouxy.plusone.domain.ICommand;
|
||||
import xyz.zhouxy.plusone.system.domain.model.account.Sex;
|
||||
|
||||
/**
|
||||
* 更新账号信息命令
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Data
|
||||
public class UpdateAccountCommand implements ICommand {
|
||||
|
||||
@NotNull
|
||||
Long id;
|
||||
|
||||
@Pattern(regexp = RegexConsts.NICKNAME)
|
||||
String nickname;
|
||||
|
||||
@URL
|
||||
String avatar;
|
||||
|
||||
Sex sex;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package xyz.zhouxy.plusone.system.application.service.command;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import lombok.Data;
|
||||
import xyz.zhouxy.plusone.domain.ICommand;
|
||||
|
||||
/**
|
||||
* 更新数据字典命令
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Data
|
||||
public class UpdateDictCommand implements ICommand {
|
||||
|
||||
@NotNull
|
||||
Long id;
|
||||
|
||||
@NotBlank
|
||||
String dictType;
|
||||
|
||||
@NotBlank
|
||||
String dictLabel;
|
||||
|
||||
@NotNull
|
||||
Map<Integer, String> keyLabelMap;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package xyz.zhouxy.plusone.system.application.service.command;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import xyz.zhouxy.plusone.constant.EntityStatus;
|
||||
import xyz.zhouxy.plusone.domain.ICommand;
|
||||
import xyz.zhouxy.plusone.system.domain.model.menu.Menu.MenuType;
|
||||
|
||||
/**
|
||||
* 更新菜单信息命令
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class UpdateMenuCommand implements ICommand {
|
||||
|
||||
@NotNull
|
||||
private Long id;
|
||||
|
||||
@NotNull
|
||||
private MenuType menuType;
|
||||
|
||||
@NotNull
|
||||
private Long parentId;
|
||||
|
||||
@NotBlank
|
||||
private String path;
|
||||
|
||||
@NotBlank
|
||||
private String name;
|
||||
|
||||
@NotBlank
|
||||
private String title;
|
||||
|
||||
@NotBlank
|
||||
private String icon;
|
||||
|
||||
@NotNull
|
||||
private Boolean hidden;
|
||||
|
||||
@NotNull
|
||||
private Integer orderNumber;
|
||||
|
||||
@NotNull
|
||||
private EntityStatus status;
|
||||
|
||||
private String component;
|
||||
|
||||
private String resource;
|
||||
|
||||
@NotNull
|
||||
private Boolean cache;
|
||||
|
||||
private String remarks;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package xyz.zhouxy.plusone.system.application.service.command;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import lombok.Data;
|
||||
import xyz.zhouxy.plusone.constant.EntityStatus;
|
||||
import xyz.zhouxy.plusone.domain.ICommand;
|
||||
|
||||
/**
|
||||
* 更新角色信息命令
|
||||
*
|
||||
* @author <a href="https://gitee.com/zhouxy108">ZhouXY</a>
|
||||
*/
|
||||
@Data
|
||||
public class UpdateRoleCommand implements ICommand {
|
||||
|
||||
@NotNull
|
||||
Long id;
|
||||
|
||||
@NotBlank
|
||||
String name;
|
||||
|
||||
@NotBlank
|
||||
String identifier;
|
||||
|
||||
@NotNull
|
||||
EntityStatus status;
|
||||
|
||||
@NotBlank
|
||||
String remarks;
|
||||
|
||||
@NotNull
|
||||
Set<Long> menus;
|
||||
|
||||
@NotNull
|
||||
Set<Long> permissions;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package xyz.zhouxy.plusone.system.application.service.command.validator;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import xyz.zhouxy.plusone.constant.RegexConsts;
|
||||
import xyz.zhouxy.plusone.system.application.service.command.LoginByOtpCommand;
|
||||
import xyz.zhouxy.plusone.util.RegexUtil;
|
||||
import xyz.zhouxy.plusone.validator.BaseValidator;
|
||||
import xyz.zhouxy.plusone.validator.DtoValidator;
|
||||
|
||||
@Component
|
||||
@DtoValidator(LoginByOtpCommand.class)
|
||||
public class LoginByOtpCommandValidator extends BaseValidator<LoginByOtpCommand> {
|
||||
public LoginByOtpCommandValidator() {
|
||||
ruleFor(loginCommand -> {
|
||||
String principal = loginCommand.getPrincipal();
|
||||
return StringUtils.hasText(principal)
|
||||
&&
|
||||
RegexUtil.matchesOr(principal, RegexConsts.EMAIL, RegexConsts.MOBILE_PHONE);
|
||||
}, "输入邮箱地址或手机号");
|
||||
ruleFor(loginCommand -> {
|
||||
String otp = loginCommand.getOtp();
|
||||
return StringUtils.hasText(otp) && Pattern.matches(RegexConsts.CAPTCHA, otp);
|
||||
}, "验证码不符合要求");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package xyz.zhouxy.plusone.system.application.service.command.validator;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import xyz.zhouxy.plusone.constant.RegexConsts;
|
||||
import xyz.zhouxy.plusone.system.application.service.command.LoginByPasswordCommand;
|
||||
import xyz.zhouxy.plusone.util.RegexUtil;
|
||||
import xyz.zhouxy.plusone.validator.BaseValidator;
|
||||
import xyz.zhouxy.plusone.validator.DtoValidator;
|
||||
|
||||
@Component
|
||||
@DtoValidator(LoginByPasswordCommand.class)
|
||||
public class LoginByPasswordCommandValidator extends BaseValidator<LoginByPasswordCommand> {
|
||||
public LoginByPasswordCommandValidator() {
|
||||
ruleFor(loginCommand -> {
|
||||
String principal = loginCommand.getPrincipal();
|
||||
return StringUtils.hasText(principal)
|
||||
&&
|
||||
RegexUtil.matchesOr(principal, RegexConsts.USERNAME, RegexConsts.EMAIL, RegexConsts.MOBILE_PHONE, principal);
|
||||
}, "输入用户名、邮箱地址或手机号");
|
||||
ruleFor(loginCommand -> {
|
||||
String password = loginCommand.getPassword();
|
||||
return StringUtils.hasText(password)
|
||||
&&
|
||||
Pattern.matches(RegexConsts.PASSWORD, password);
|
||||
}, "密码格式不正确");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="xyz.zhouxy.plusone.system.application.query.AccountQueries">
|
||||
<!-- //////////////////// SELECT //////////////////// -->
|
||||
|
||||
<resultMap id="AccountOverview_ResultMap" type="xyz.zhouxy.plusone.system.application.query.result.AccountOverview">
|
||||
<id column="a_id" property="id" javaType="Long" />
|
||||
<result column="a_username" property="username" />
|
||||
<result column="a_email" property="email" />
|
||||
<result column="a_mobile_phone" property="mobilePhone" />
|
||||
<result column="a_status" property="status" />
|
||||
<result column="a_nickname" property="nickname" />
|
||||
<result column="a_avatar" property="avatar" />
|
||||
<result column="a_sex" property="sex" />
|
||||
<result column="a_created_by" property="createdBy" javaType="Long" />
|
||||
<result column="a_create_time" property="createTime" javaType="java.time.LocalDateTime" />
|
||||
<result column="a_updated_by" property="updatedBy" javaType="Long" />
|
||||
<result column="a_update_time" property="updateTime" javaType="java.time.LocalDateTime" />
|
||||
<collection property="roles" select="xyz.zhouxy.plusone.system.application.query.AccountQueries.getRoleNameListByAccount" column="a_id" />
|
||||
</resultMap>
|
||||
|
||||
<!-- List<AccountOverview> queryAccountOverview(AccountQueryParams queryParams); -->
|
||||
<select id="queryAccountOverview" resultMap="AccountOverview_ResultMap">
|
||||
SELECT
|
||||
a.id AS a_id,
|
||||
a.username AS a_username,
|
||||
a.email AS a_email,
|
||||
a.mobile_phone AS a_mobile_phone,
|
||||
a.avatar AS a_avatar,
|
||||
a.sex AS a_sex,
|
||||
a.nickname AS a_nickname,
|
||||
a.status AS a_status,
|
||||
a.created_by AS a_created_by,
|
||||
a.create_time AS a_create_time,
|
||||
a.updated_by AS a_updated_by,
|
||||
a.update_time AS a_update_time
|
||||
FROM
|
||||
sys_account AS a,
|
||||
(
|
||||
SELECT sa.id
|
||||
FROM sys_account sa
|
||||
<if test="roleId != null">
|
||||
JOIN sys_account_role AS sar ON sa.id = sar.account_id
|
||||
JOIN sys_role AS sr ON sr.id = sar.role_id
|
||||
</if>
|
||||
WHERE sa.deleted = 0
|
||||
<if test="id != null">
|
||||
AND sa.id = #{id}
|
||||
</if>
|
||||
<if test="username != null">
|
||||
AND sa.username = #{username}
|
||||
</if>
|
||||
<if test="email != null">
|
||||
AND sa.email = #{email}
|
||||
</if>
|
||||
<if test="mobilePhone != null">
|
||||
AND sa.mobile_phone = #{mobilePhone}
|
||||
</if>
|
||||
<if test="status != null">
|
||||
AND sa.status = #{status}
|
||||
</if>
|
||||
<if test="nickname != null">
|
||||
AND sa.nickname = #{nickname}
|
||||
</if>
|
||||
<if test="sex != null">
|
||||
AND sa.sex = #{sex}
|
||||
</if>
|
||||
<if test="createdBy != null">
|
||||
AND sa.created_by = #{createdBy}
|
||||
</if>
|
||||
<if test="createTimeStart != null">
|
||||
AND sa.create_time >= #{createTimeStart}
|
||||
</if>
|
||||
<if test="createTimeEnd != null">
|
||||
AND sa.create_time < #{createTimeEnd}
|
||||
</if>
|
||||
<if test="updatedBy != null">
|
||||
AND sa.updated_by = #{updatedBy}
|
||||
</if>
|
||||
<if test="updateTimeStart != null">
|
||||
AND sa.update_time >= #{updateTimeStart}
|
||||
</if>
|
||||
<if test="updateTimeEnd != null">
|
||||
AND sa.update_time < #{updateTimeEnd}
|
||||
</if>
|
||||
<if test="roleId != null">
|
||||
AND sar.role_id = #{roleId}
|
||||
AND sr.deleted = 0
|
||||
</if>
|
||||
<if test="orderBy != null">
|
||||
ORDER BY sa.${orderBy}, sa.id
|
||||
</if>
|
||||
<if test="orderBy == null">
|
||||
ORDER BY sa.id
|
||||
</if>
|
||||
LIMIT #{size} OFFSET #{offset}
|
||||
) b
|
||||
WHERE a.id = b.id
|
||||
</select>
|
||||
|
||||
<!--
|
||||
long count(SysAccountQuery queryParams);
|
||||
-->
|
||||
<select id="count" resultType="long">
|
||||
SELECT COUNT(*)
|
||||
FROM sys_account sa
|
||||
<if test="roleId != null">
|
||||
JOIN sys_account_role AS sar ON sa.id = sar.account_id
|
||||
JOIN sys_role AS sr ON sr.id = sar.role_id
|
||||
</if>
|
||||
WHERE sa.deleted = 0
|
||||
<if test="id != null">
|
||||
AND sa.id = #{id}
|
||||
</if>
|
||||
<if test="username != null">
|
||||
AND sa.username = #{username}
|
||||
</if>
|
||||
<if test="email != null">
|
||||
AND sa.email = #{email}
|
||||
</if>
|
||||
<if test="mobilePhone != null">
|
||||
AND sa.mobile_phone = #{mobilePhone}
|
||||
</if>
|
||||
<if test="status != null">
|
||||
AND sa.status = #{status}
|
||||
</if>
|
||||
<if test="nickname != null">
|
||||
AND sa.nickname = #{nickname}
|
||||
</if>
|
||||
<if test="sex != null">
|
||||
AND sa.sex = #{sex}
|
||||
</if>
|
||||
<if test="createdBy != null">
|
||||
AND sa.created_by = #{createdBy}
|
||||
</if>
|
||||
<if test="createTimeStart != null">
|
||||
AND sa.create_time >= #{createTimeStart}
|
||||
</if>
|
||||
<if test="createTimeEnd != null">
|
||||
AND sa.create_time < #{createTimeEnd}
|
||||
</if>
|
||||
<if test="updatedBy != null">
|
||||
AND sa.updated_by = #{updatedBy}
|
||||
</if>
|
||||
<if test="updateTimeStart != null">
|
||||
AND sa.update_time >= #{updateTimeStart}
|
||||
</if>
|
||||
<if test="updateTimeEnd != null">
|
||||
AND sa.update_time < #{updateTimeEnd}
|
||||
</if>
|
||||
<if test="roleId != null">
|
||||
AND sar.role_id = #{roleId}
|
||||
AND sr.deleted = 0
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<select id="getRoleNameListByAccount" resultType="java.lang.String">
|
||||
SELECT r.name
|
||||
FROM sys_role AS r
|
||||
RIGHT JOIN sys_account_role AS ar ON r.id = ar.role_id
|
||||
WHERE ar.account_id = #{id} AND r.deleted = 0
|
||||
</select>
|
||||
|
||||
<!-- AccountDetails queryAccountDetails(Long accountId); -->
|
||||
<resultMap id="RoleOverview_ResultMap" type="xyz.zhouxy.plusone.system.application.query.result.RoleOverview">
|
||||
<id column="id" property="id" javaType="Long" />
|
||||
<result column="name" property="name" />
|
||||
<result column="identifier" property="identifier" />
|
||||
<result column="status" property="status" />
|
||||
</resultMap>
|
||||
|
||||
<select id="getRoleOverviewListByAccount" resultMap="RoleOverview_ResultMap">
|
||||
SELECT r.id, r.name, r.identifier, r.status
|
||||
FROM sys_role AS r
|
||||
RIGHT JOIN sys_account_role AS ar ON r.id = ar.role_id
|
||||
WHERE ar.account_id = #{id} AND r.deleted = 0
|
||||
</select>
|
||||
|
||||
<resultMap id="AccountDetails_ResultMap" type="xyz.zhouxy.plusone.system.application.query.result.AccountDetails">
|
||||
<id column="id" property="id" javaType="Long" />
|
||||
<result column="username" property="username" />
|
||||
<result column="email" property="email" />
|
||||
<result column="mobile_phone" property="mobilePhone" />
|
||||
<result column="status" property="status" />
|
||||
<result column="nickname" property="nickname" />
|
||||
<result column="avatar" property="avatar" />
|
||||
<result column="sex" property="sex" />
|
||||
<collection property="roles" select="xyz.zhouxy.plusone.system.application.query.AccountQueries.getRoleOverviewListByAccount" column="id" />
|
||||
</resultMap>
|
||||
|
||||
<select id="queryAccountDetails" resultMap="AccountDetails_ResultMap">
|
||||
SELECT id, username, email, mobile_phone, avatar, sex, nickname, status
|
||||
FROM sys_account
|
||||
WHERE id = #{id} AND deleted = 0
|
||||
</select>
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user