feat: 开发中...
This commit is contained in:
@@ -20,12 +20,12 @@ public class BlogExceptionHandler {
|
|||||||
private Environment environment;
|
private Environment environment;
|
||||||
|
|
||||||
@ExceptionHandler(BadCredentialsException.class)
|
@ExceptionHandler(BadCredentialsException.class)
|
||||||
public ResponseVO<String> onException(BadCredentialsException e) {
|
public ResponseVO<String> onBadCredentialsException(BadCredentialsException e) {
|
||||||
return ResponseVO.failed(e.getMessage());
|
return ResponseVO.failed(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||||
public ResponseVO<String> onException(MethodArgumentNotValidException e) {
|
public ResponseVO<String> onMethodArgumentNotValidException(MethodArgumentNotValidException e) {
|
||||||
return ResponseVO.failed(e.getAllErrors()
|
return ResponseVO.failed(e.getAllErrors()
|
||||||
.stream()
|
.stream()
|
||||||
.findFirst()
|
.findFirst()
|
||||||
@@ -36,8 +36,8 @@ public class BlogExceptionHandler {
|
|||||||
|
|
||||||
@ExceptionHandler(Exception.class)
|
@ExceptionHandler(Exception.class)
|
||||||
public ResponseVO<String> onException(Exception e) {
|
public ResponseVO<String> onException(Exception e) {
|
||||||
log.error("", e);
|
|
||||||
if ("dev".equals(environment.getProperty("spring.profiles.active"))) {
|
if ("dev".equals(environment.getProperty("spring.profiles.active"))) {
|
||||||
|
log.error("", e);
|
||||||
StringWriter writer = new StringWriter();
|
StringWriter writer = new StringWriter();
|
||||||
e.printStackTrace(new PrintWriter(writer));
|
e.printStackTrace(new PrintWriter(writer));
|
||||||
// StringWriter 不需要 close()
|
// StringWriter 不需要 close()
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
package cn.hamster3.application.blog.config.security;
|
package cn.hamster3.application.blog.config.security;
|
||||||
|
|
||||||
import cn.hamster3.application.blog.constant.UserPermissions;
|
|
||||||
import cn.hamster3.application.blog.dao.UserRepository;
|
import cn.hamster3.application.blog.dao.UserRepository;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -9,6 +8,8 @@ import org.springframework.security.core.userdetails.UserDetailsService;
|
|||||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
public class BlogUserDetailService implements UserDetailsService {
|
public class BlogUserDetailService implements UserDetailsService {
|
||||||
@@ -22,10 +23,7 @@ public class BlogUserDetailService implements UserDetailsService {
|
|||||||
.map(user -> new BlogUser(
|
.map(user -> new BlogUser(
|
||||||
user.getEmail(),
|
user.getEmail(),
|
||||||
user.getPassword(),
|
user.getPassword(),
|
||||||
user.getPermissions()
|
Collections.singleton(user.getRole().getAuthority()),
|
||||||
.stream()
|
|
||||||
.map(UserPermissions::getAuthority)
|
|
||||||
.toList(),
|
|
||||||
user.getId()
|
user.getId()
|
||||||
)).orElseThrow(() -> new UsernameNotFoundException("user not found."));
|
)).orElseThrow(() -> new UsernameNotFoundException("user not found."));
|
||||||
}
|
}
|
||||||
|
@@ -2,12 +2,23 @@ package cn.hamster3.application.blog.constant;
|
|||||||
|
|
||||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
|
|
||||||
public enum UserPermissions {
|
public enum UserRole {
|
||||||
MODIFY_USER_INFO,
|
/**
|
||||||
MODIFY_USER_PERMISSION;
|
* 读者
|
||||||
|
*/
|
||||||
|
USER,
|
||||||
|
/**
|
||||||
|
* 作者
|
||||||
|
*/
|
||||||
|
AUTHOR,
|
||||||
|
/**
|
||||||
|
* 管理员
|
||||||
|
*/
|
||||||
|
ADMIN;
|
||||||
|
|
||||||
private final SimpleGrantedAuthority authority;
|
private final SimpleGrantedAuthority authority;
|
||||||
|
|
||||||
UserPermissions() {
|
UserRole() {
|
||||||
this.authority = new SimpleGrantedAuthority(name());
|
this.authority = new SimpleGrantedAuthority(name());
|
||||||
}
|
}
|
||||||
|
|
@@ -1,12 +1,11 @@
|
|||||||
package cn.hamster3.application.blog.controller;
|
package cn.hamster3.application.blog.controller;
|
||||||
|
|
||||||
import cn.hamster3.application.blog.vo.ResponseVO;
|
import cn.hamster3.application.blog.vo.ResponseVO;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
/**
|
@Tag(name = "附件接口", description = "附件相关接口")
|
||||||
* 附件相关接口
|
|
||||||
*/
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1/attach")
|
@RequestMapping("/api/v1/attach")
|
||||||
public class AttachController {
|
public class AttachController {
|
||||||
|
@@ -4,6 +4,8 @@ import cn.hamster3.application.blog.service.IBlogService;
|
|||||||
import cn.hamster3.application.blog.vo.ResponseVO;
|
import cn.hamster3.application.blog.vo.ResponseVO;
|
||||||
import cn.hamster3.application.blog.vo.blog.BlogInfoResponseVO;
|
import cn.hamster3.application.blog.vo.blog.BlogInfoResponseVO;
|
||||||
import cn.hamster3.application.blog.vo.blog.BlogUpdateRequireVO;
|
import cn.hamster3.application.blog.vo.blog.BlogUpdateRequireVO;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
@@ -21,26 +23,34 @@ public class BlogController {
|
|||||||
private IBlogService blogService;
|
private IBlogService blogService;
|
||||||
|
|
||||||
@PostMapping("/")
|
@PostMapping("/")
|
||||||
|
@Operation(summary = "创建博文")
|
||||||
public ResponseVO<Long> createBlog(@RequestBody @Valid BlogUpdateRequireVO requireVO) {
|
public ResponseVO<Long> createBlog(@RequestBody @Valid BlogUpdateRequireVO requireVO) {
|
||||||
return blogService.createBlog(requireVO);
|
return blogService.createBlog(requireVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/{blogID}/")
|
@GetMapping("/{blogID}/")
|
||||||
|
@Operation(summary = "获取博文信息")
|
||||||
public ResponseVO<BlogInfoResponseVO> getBlogInfo(@PathVariable Long blogID) {
|
public ResponseVO<BlogInfoResponseVO> getBlogInfo(@PathVariable Long blogID) {
|
||||||
return blogService.getBlogInfo(blogID);
|
return blogService.getBlogInfo(blogID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/")
|
@GetMapping("/")
|
||||||
public ResponseVO<List<BlogInfoResponseVO>> getBlogInfoList(int page, int size) {
|
@Operation(summary = "获取博文列表")
|
||||||
|
public ResponseVO<List<BlogInfoResponseVO>> getBlogInfoList(
|
||||||
|
@Parameter(description = "页码", example = "0") int page,
|
||||||
|
@Parameter(description = "大小", example = "10") int size
|
||||||
|
) {
|
||||||
return blogService.getBlogInfoList(PageRequest.of(page, size));
|
return blogService.getBlogInfoList(PageRequest.of(page, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/{blogID}/")
|
@PutMapping("/{blogID}/")
|
||||||
|
@Operation(summary = "更新博文")
|
||||||
public ResponseVO<Void> updateBlog(@PathVariable Long blogID, @RequestBody @Valid BlogUpdateRequireVO requireVO) {
|
public ResponseVO<Void> updateBlog(@PathVariable Long blogID, @RequestBody @Valid BlogUpdateRequireVO requireVO) {
|
||||||
return blogService.updateBlog(blogID, requireVO);
|
return blogService.updateBlog(blogID, requireVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping("/{blogID}/")
|
@DeleteMapping("/{blogID}/")
|
||||||
|
@Operation(summary = "删除博文")
|
||||||
public ResponseVO<Void> removeBlog(@PathVariable Long blogID) {
|
public ResponseVO<Void> removeBlog(@PathVariable Long blogID) {
|
||||||
return blogService.removeBlog(blogID);
|
return blogService.removeBlog(blogID);
|
||||||
}
|
}
|
||||||
|
@@ -1,20 +1,22 @@
|
|||||||
package cn.hamster3.application.blog.controller;
|
package cn.hamster3.application.blog.controller;
|
||||||
|
|
||||||
import cn.hamster3.application.blog.vo.ResponseVO;
|
import cn.hamster3.application.blog.vo.ResponseVO;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
/**
|
@Tag(name = "网站设置接口", description = "网站设置相关接口")
|
||||||
* 网站设置相关接口
|
|
||||||
*/
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping(value = "/api/v1/settings", produces = MediaType.APPLICATION_JSON_VALUE)
|
@RequestMapping(value = "/api/v1/settings", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
public class SiteSettingController {
|
public class SiteSettingController {
|
||||||
@GetMapping("/{path}/")
|
@GetMapping("/{path}/")
|
||||||
public ResponseVO<String> getSiteTitle(@PathVariable String path) {
|
@Operation(summary = "获取网站设置")
|
||||||
|
public ResponseVO<String> getSiteSettings(@Parameter(description = "设置ID") @PathVariable String path) {
|
||||||
return ResponseVO.success(path);
|
return ResponseVO.success(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,60 +1,84 @@
|
|||||||
package cn.hamster3.application.blog.controller;
|
package cn.hamster3.application.blog.controller;
|
||||||
|
|
||||||
import cn.hamster3.application.blog.service.IUserService;
|
import cn.hamster3.application.blog.service.IUserService;
|
||||||
import cn.hamster3.application.blog.vo.PageableResponseVO;
|
import cn.hamster3.application.blog.vo.PageableVO;
|
||||||
import cn.hamster3.application.blog.vo.ResponseVO;
|
import cn.hamster3.application.blog.vo.ResponseVO;
|
||||||
import cn.hamster3.application.blog.vo.attach.AttachInfoResponseVO;
|
import cn.hamster3.application.blog.vo.attach.AttachInfoResponseVO;
|
||||||
|
import cn.hamster3.application.blog.vo.blog.BlogInfoResponseVO;
|
||||||
import cn.hamster3.application.blog.vo.user.*;
|
import cn.hamster3.application.blog.vo.user.*;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import org.springframework.data.domain.PageRequest;
|
import org.springframework.data.domain.PageRequest;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
@Tag(name = "用户接口", description = "用户相关接口")
|
||||||
* 用户相关接口
|
|
||||||
*/
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping(value = "/api/v1/user", produces = MediaType.APPLICATION_JSON_VALUE)
|
@RequestMapping(value = "/api/v1/user", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
public class UserController {
|
public class UserController {
|
||||||
@Resource
|
@Resource
|
||||||
private IUserService userService;
|
private IUserService userService;
|
||||||
|
|
||||||
// @PostMapping("/login")
|
@PostMapping("/login")
|
||||||
// public ResponseVO<Void> loginUser(@RequestBody @Valid UserLoginRequireVO requireVO) {
|
public ResponseVO<Void> loginUser(@RequestBody @Valid UserLoginRequireVO requireVO) {
|
||||||
// return userService.loginUser(requireVO);
|
return userService.loginUser(requireVO);
|
||||||
// }
|
}
|
||||||
|
|
||||||
@GetMapping("/current")
|
@GetMapping("/current")
|
||||||
|
@Operation(summary = "查询当前用户")
|
||||||
public ResponseVO<UserInfoResponseVO> getCurrentUserInfo() {
|
public ResponseVO<UserInfoResponseVO> getCurrentUserInfo() {
|
||||||
return userService.getCurrentUserInfo();
|
return userService.getCurrentUserInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/")
|
@PostMapping("/")
|
||||||
|
@Operation(summary = "注册用户")
|
||||||
public ResponseVO<UserRegisterResponseVO> createUser(@RequestBody @Valid UserCreateRequireVO requireVO) {
|
public ResponseVO<UserRegisterResponseVO> createUser(@RequestBody @Valid UserCreateRequireVO requireVO) {
|
||||||
return userService.createUser(requireVO);
|
return userService.createUser(requireVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/")
|
@PutMapping("/")
|
||||||
|
@Operation(summary = "更新用户信息")
|
||||||
public ResponseVO<Void> updateUser(@RequestBody @Valid UserUpdateRequireVO requireVO) {
|
public ResponseVO<Void> updateUser(@RequestBody @Valid UserUpdateRequireVO requireVO) {
|
||||||
return userService.updateUser(requireVO);
|
return userService.updateUser(requireVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/")
|
@GetMapping("/")
|
||||||
public ResponseVO<PageableResponseVO<UserInfoResponseVO>> getAllUserInfo(int page, int size) {
|
@Operation(summary = "查询用户列表")
|
||||||
|
public ResponseVO<PageableVO<UserInfoResponseVO>> getAllUserInfo(
|
||||||
|
@Parameter(description = "页码", example = "0") int page,
|
||||||
|
@Parameter(description = "大小", example = "10") int size
|
||||||
|
) {
|
||||||
return userService.getAllUserInfo(PageRequest.of(page, size));
|
return userService.getAllUserInfo(PageRequest.of(page, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/{userID}/")
|
@GetMapping("/{userID}/")
|
||||||
public ResponseVO<UserInfoResponseVO> getUserInfo(@PathVariable UUID userID) {
|
@Operation(summary = "查询用户")
|
||||||
|
public ResponseVO<UserInfoResponseVO> getUserInfo(@Parameter(description = "用户ID") @PathVariable UUID userID) {
|
||||||
return userService.getUserInfo(userID);
|
return userService.getUserInfo(userID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/{userID}/attaches")
|
@GetMapping("/{userID}/blog/")
|
||||||
public ResponseVO<List<AttachInfoResponseVO>> getUserAttaches(@PathVariable UUID userID) {
|
@Operation(summary = "查询用户所有博文")
|
||||||
return userService.getUserAttaches(userID);
|
public ResponseVO<PageableVO<BlogInfoResponseVO>> getUserBlogList(
|
||||||
|
@Parameter(description = "用户ID") @PathVariable UUID userID,
|
||||||
|
@Parameter(description = "页码", example = "0") int page,
|
||||||
|
@Parameter(description = "大小", example = "10") int size
|
||||||
|
) {
|
||||||
|
return userService.getUserBlogList(userID, PageRequest.of(page, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/{userID}/attach/")
|
||||||
|
@Operation(summary = "查询用户所有附件")
|
||||||
|
public ResponseVO<PageableVO<AttachInfoResponseVO>> getUserAttachList(
|
||||||
|
@Parameter(description = "用户ID") @PathVariable UUID userID,
|
||||||
|
@Parameter(description = "页码", example = "0") int page,
|
||||||
|
@Parameter(description = "大小", example = "10") int size
|
||||||
|
) {
|
||||||
|
return userService.getUserAttachList(userID, PageRequest.of(page, size));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,8 +1,13 @@
|
|||||||
package cn.hamster3.application.blog.dao;
|
package cn.hamster3.application.blog.dao;
|
||||||
|
|
||||||
import cn.hamster3.application.blog.entity.AttachEntity;
|
import cn.hamster3.application.blog.entity.AttachEntity;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public interface AttachRepository extends JpaRepository<AttachEntity, Long>, JpaSpecificationExecutor<AttachEntity> {
|
public interface AttachRepository extends JpaRepository<AttachEntity, Long>, JpaSpecificationExecutor<AttachEntity> {
|
||||||
|
Page<AttachEntity> findByUploader_IdOrderByCreateTimeDesc(UUID id, Pageable pageable);
|
||||||
}
|
}
|
@@ -1,12 +1,16 @@
|
|||||||
package cn.hamster3.application.blog.dao;
|
package cn.hamster3.application.blog.dao;
|
||||||
|
|
||||||
import cn.hamster3.application.blog.entity.BlogEntity;
|
import cn.hamster3.application.blog.entity.BlogEntity;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.jpa.repository.*;
|
import org.springframework.data.jpa.repository.*;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public interface BlogRepository extends JpaRepository<BlogEntity, Long>, JpaSpecificationExecutor<BlogEntity> {
|
public interface BlogRepository extends JpaRepository<BlogEntity, Long>, JpaSpecificationExecutor<BlogEntity> {
|
||||||
|
Page<BlogEntity> findByUploader_IdOrderByAttachEntities_CreateTimeDesc(UUID id, Pageable pageable);
|
||||||
@EntityGraph(attributePaths = {"content"})
|
@EntityGraph(attributePaths = {"content"})
|
||||||
@Query("select b from BlogEntity b where b.id = ?1")
|
@Query("select b from BlogEntity b where b.id = ?1")
|
||||||
Optional<BlogEntity> findByIDWithContent(Long id);
|
Optional<BlogEntity> findByIDWithContent(Long id);
|
||||||
|
@@ -2,8 +2,6 @@ package cn.hamster3.application.blog.dao;
|
|||||||
|
|
||||||
import cn.hamster3.application.blog.entity.BlogEntity;
|
import cn.hamster3.application.blog.entity.BlogEntity;
|
||||||
import cn.hamster3.application.blog.entity.UserEntity;
|
import cn.hamster3.application.blog.entity.UserEntity;
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.springframework.data.jpa.repository.EntityGraph;
|
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
|
||||||
@@ -11,15 +9,10 @@ import java.util.Optional;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public interface UserRepository extends JpaRepository<UserEntity, UUID>, JpaSpecificationExecutor<BlogEntity> {
|
public interface UserRepository extends JpaRepository<UserEntity, UUID>, JpaSpecificationExecutor<BlogEntity> {
|
||||||
|
|
||||||
@EntityGraph(attributePaths = {"permissions"})
|
|
||||||
Optional<UserEntity> findByEmailIgnoreCase(String email);
|
Optional<UserEntity> findByEmailIgnoreCase(String email);
|
||||||
|
|
||||||
boolean existsByNicknameIgnoreCase(String nickname);
|
boolean existsByNicknameIgnoreCase(String nickname);
|
||||||
|
|
||||||
boolean existsByEmailIgnoreCase(String email);
|
boolean existsByEmailIgnoreCase(String email);
|
||||||
|
|
||||||
@EntityGraph(attributePaths = {"attachEntities"})
|
|
||||||
@NotNull
|
|
||||||
Optional<UserEntity> findById(@NotNull UUID uuid);
|
|
||||||
}
|
}
|
@@ -1,6 +1,6 @@
|
|||||||
package cn.hamster3.application.blog.entity;
|
package cn.hamster3.application.blog.entity;
|
||||||
|
|
||||||
import cn.hamster3.application.blog.constant.UserPermissions;
|
import cn.hamster3.application.blog.constant.UserRole;
|
||||||
import jakarta.persistence.*;
|
import jakarta.persistence.*;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
@@ -13,6 +13,7 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
|||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "user_entity")
|
@Table(name = "user_entity")
|
||||||
@@ -37,10 +38,9 @@ public class UserEntity {
|
|||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
@ElementCollection
|
@Enumerated
|
||||||
@Column(name = "permission")
|
@Column(name = "role", nullable = false)
|
||||||
@CollectionTable(name = "user_entity_permissions", joinColumns = @JoinColumn(name = "user_id"))
|
private UserRole role;
|
||||||
private Set<UserPermissions> permissions = new HashSet<>();
|
|
||||||
|
|
||||||
@Setter
|
@Setter
|
||||||
@OrderBy("create_time DESC")
|
@OrderBy("create_time DESC")
|
||||||
|
@@ -1,14 +1,13 @@
|
|||||||
package cn.hamster3.application.blog.service;
|
package cn.hamster3.application.blog.service;
|
||||||
|
|
||||||
import cn.hamster3.application.blog.vo.PageableResponseVO;
|
import cn.hamster3.application.blog.vo.PageableVO;
|
||||||
import cn.hamster3.application.blog.vo.ResponseVO;
|
import cn.hamster3.application.blog.vo.ResponseVO;
|
||||||
import cn.hamster3.application.blog.vo.attach.AttachInfoResponseVO;
|
import cn.hamster3.application.blog.vo.attach.AttachInfoResponseVO;
|
||||||
|
import cn.hamster3.application.blog.vo.blog.BlogInfoResponseVO;
|
||||||
import cn.hamster3.application.blog.vo.user.*;
|
import cn.hamster3.application.blog.vo.user.*;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public interface IUserService {
|
public interface IUserService {
|
||||||
@@ -20,9 +19,11 @@ public interface IUserService {
|
|||||||
|
|
||||||
@NotNull ResponseVO<Void> updateUser(@NotNull UserUpdateRequireVO requireVO);
|
@NotNull ResponseVO<Void> updateUser(@NotNull UserUpdateRequireVO requireVO);
|
||||||
|
|
||||||
@NotNull ResponseVO<PageableResponseVO<UserInfoResponseVO>> getAllUserInfo(@NotNull Pageable pageable);
|
@NotNull ResponseVO<PageableVO<UserInfoResponseVO>> getAllUserInfo(@NotNull Pageable pageable);
|
||||||
|
|
||||||
@NotNull ResponseVO<UserInfoResponseVO> getUserInfo(UUID id);
|
@NotNull ResponseVO<UserInfoResponseVO> getUserInfo(UUID id);
|
||||||
|
|
||||||
@NotNull ResponseVO<List<AttachInfoResponseVO>> getUserAttaches(@PathVariable UUID userID);
|
@NotNull ResponseVO<PageableVO<BlogInfoResponseVO>> getUserBlogList(@NotNull UUID userID, @NotNull Pageable pageable);
|
||||||
|
|
||||||
|
@NotNull ResponseVO<PageableVO<AttachInfoResponseVO>> getUserAttachList(@NotNull UUID userID, @NotNull Pageable pageable);
|
||||||
}
|
}
|
||||||
|
@@ -34,7 +34,7 @@ public class BlogService implements IBlogService {
|
|||||||
log.info("create blog vo: {}", requireVO);
|
log.info("create blog vo: {}", requireVO);
|
||||||
UserEntity user = userAuditorAware.getCurrentAuditor().orElse(null);
|
UserEntity user = userAuditorAware.getCurrentAuditor().orElse(null);
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
return ResponseVO.failed("not login.");
|
return ResponseVO.unauthorized();
|
||||||
}
|
}
|
||||||
BlogEntity entity = blogMapper.voToEntity(requireVO);
|
BlogEntity entity = blogMapper.voToEntity(requireVO);
|
||||||
entity = blogRepo.save(entity);
|
entity = blogRepo.save(entity);
|
||||||
@@ -64,7 +64,7 @@ public class BlogService implements IBlogService {
|
|||||||
}
|
}
|
||||||
BlogUser user = UserAuditorAware.currentUser().orElse(null);
|
BlogUser user = UserAuditorAware.currentUser().orElse(null);
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
return ResponseVO.failed("not login.");
|
return ResponseVO.unauthorized();
|
||||||
}
|
}
|
||||||
//todo 权限检查
|
//todo 权限检查
|
||||||
blogRepo.updateTitleAndAbstractsAndPasswordAndContentById(
|
blogRepo.updateTitleAndAbstractsAndPasswordAndContentById(
|
||||||
|
@@ -1,16 +1,20 @@
|
|||||||
package cn.hamster3.application.blog.service.impl;
|
package cn.hamster3.application.blog.service.impl;
|
||||||
|
|
||||||
import cn.hamster3.application.blog.config.security.UserAuditorAware;
|
|
||||||
import cn.hamster3.application.blog.config.security.BlogUser;
|
import cn.hamster3.application.blog.config.security.BlogUser;
|
||||||
import cn.hamster3.application.blog.constant.UserPermissions;
|
import cn.hamster3.application.blog.config.security.UserAuditorAware;
|
||||||
|
import cn.hamster3.application.blog.constant.UserRole;
|
||||||
|
import cn.hamster3.application.blog.dao.AttachRepository;
|
||||||
|
import cn.hamster3.application.blog.dao.BlogRepository;
|
||||||
import cn.hamster3.application.blog.dao.UserRepository;
|
import cn.hamster3.application.blog.dao.UserRepository;
|
||||||
import cn.hamster3.application.blog.entity.UserEntity;
|
import cn.hamster3.application.blog.entity.UserEntity;
|
||||||
import cn.hamster3.application.blog.entity.mapper.AttachMapper;
|
import cn.hamster3.application.blog.entity.mapper.AttachMapper;
|
||||||
|
import cn.hamster3.application.blog.entity.mapper.BlogMapper;
|
||||||
import cn.hamster3.application.blog.entity.mapper.UserMapper;
|
import cn.hamster3.application.blog.entity.mapper.UserMapper;
|
||||||
import cn.hamster3.application.blog.service.IUserService;
|
import cn.hamster3.application.blog.service.IUserService;
|
||||||
import cn.hamster3.application.blog.vo.PageableResponseVO;
|
import cn.hamster3.application.blog.vo.PageableVO;
|
||||||
import cn.hamster3.application.blog.vo.ResponseVO;
|
import cn.hamster3.application.blog.vo.ResponseVO;
|
||||||
import cn.hamster3.application.blog.vo.attach.AttachInfoResponseVO;
|
import cn.hamster3.application.blog.vo.attach.AttachInfoResponseVO;
|
||||||
|
import cn.hamster3.application.blog.vo.blog.BlogInfoResponseVO;
|
||||||
import cn.hamster3.application.blog.vo.user.*;
|
import cn.hamster3.application.blog.vo.user.*;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -20,9 +24,7 @@ import org.springframework.security.core.Authentication;
|
|||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@@ -34,10 +36,16 @@ public class UserService implements IUserService {
|
|||||||
@Resource
|
@Resource
|
||||||
private UserMapper userMapper;
|
private UserMapper userMapper;
|
||||||
@Resource
|
@Resource
|
||||||
|
private BlogMapper blogMapper;
|
||||||
|
@Resource
|
||||||
private AttachMapper attachMapper;
|
private AttachMapper attachMapper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private UserRepository userRepo;
|
private UserRepository userRepo;
|
||||||
|
@Resource
|
||||||
|
private BlogRepository blogRepo;
|
||||||
|
@Resource
|
||||||
|
private AttachRepository attachRepo;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull ResponseVO<Void> loginUser(@NotNull UserLoginRequireVO requireVO) {
|
public @NotNull ResponseVO<Void> loginUser(@NotNull UserLoginRequireVO requireVO) {
|
||||||
@@ -48,7 +56,7 @@ public class UserService implements IUserService {
|
|||||||
public @NotNull ResponseVO<UserInfoResponseVO> getCurrentUserInfo() {
|
public @NotNull ResponseVO<UserInfoResponseVO> getCurrentUserInfo() {
|
||||||
UUID uuid = UserAuditorAware.currentUserUUID().orElse(null);
|
UUID uuid = UserAuditorAware.currentUserUUID().orElse(null);
|
||||||
if (uuid == null) {
|
if (uuid == null) {
|
||||||
return ResponseVO.failed("not login.");
|
return ResponseVO.unauthorized();
|
||||||
}
|
}
|
||||||
return ResponseVO.success(
|
return ResponseVO.success(
|
||||||
userRepo.findById(uuid)
|
userRepo.findById(uuid)
|
||||||
@@ -71,6 +79,7 @@ public class UserService implements IUserService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
entity.setPassword(passwordEncoder.encode(entity.getPassword()));
|
entity.setPassword(passwordEncoder.encode(entity.getPassword()));
|
||||||
|
entity.setRole(UserRole.USER);
|
||||||
log.info("prepare to save userinfo: {}", entity);
|
log.info("prepare to save userinfo: {}", entity);
|
||||||
UserEntity save = userRepo.save(entity);
|
UserEntity save = userRepo.save(entity);
|
||||||
|
|
||||||
@@ -91,7 +100,7 @@ public class UserService implements IUserService {
|
|||||||
return ResponseVO.failed("你没有这个权限!");
|
return ResponseVO.failed("你没有这个权限!");
|
||||||
}
|
}
|
||||||
if (!blogUser.getId().equals(userEntity.getId())
|
if (!blogUser.getId().equals(userEntity.getId())
|
||||||
&& blogUser.getAuthorities().contains(UserPermissions.MODIFY_USER_INFO.getAuthority())) {
|
&& !blogUser.getAuthorities().contains(UserRole.ADMIN.getAuthority())) {
|
||||||
return ResponseVO.failed("你没有这个权限!");
|
return ResponseVO.failed("你没有这个权限!");
|
||||||
}
|
}
|
||||||
if (requireVO.getEmail() != null && !requireVO.getEmail().equals(userEntity.getEmail())) {
|
if (requireVO.getEmail() != null && !requireVO.getEmail().equals(userEntity.getEmail())) {
|
||||||
@@ -110,22 +119,23 @@ public class UserService implements IUserService {
|
|||||||
userEntity.setPassword(passwordEncoder.encode(requireVO.getPassword()));
|
userEntity.setPassword(passwordEncoder.encode(requireVO.getPassword()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (requireVO.getPermissions() != null) {
|
if (requireVO.getRole() != null) {
|
||||||
if (!blogUser.getAuthorities().contains(UserPermissions.MODIFY_USER_PERMISSION.getAuthority())) {
|
|
||||||
return ResponseVO.failed("你没有这个权限!");
|
|
||||||
}
|
|
||||||
// 用户必须具有 MODIFY_USER_PERMISSION 权限,且操作对象不为用户自己时才能更改权限
|
|
||||||
if (blogUser.getId().equals(userEntity.getId())) {
|
if (blogUser.getId().equals(userEntity.getId())) {
|
||||||
return ResponseVO.failed("你不能更改自己的权限!");
|
return ResponseVO.failed("你不能更改自己的权限!");
|
||||||
}
|
}
|
||||||
userEntity.setPermissions(requireVO.getPermissions());
|
if (!blogUser.getAuthorities().contains(UserRole.ADMIN.getAuthority())) {
|
||||||
|
return ResponseVO.failed("你没有这个权限!");
|
||||||
|
}
|
||||||
|
// 用户必须具有 ADMIN 权限,且操作对象不为用户自己时才能更改权限
|
||||||
|
userEntity.setRole(requireVO.getRole());
|
||||||
}
|
}
|
||||||
|
userRepo.save(userEntity);
|
||||||
return ResponseVO.success();
|
return ResponseVO.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull ResponseVO<PageableResponseVO<UserInfoResponseVO>> getAllUserInfo(@NotNull Pageable pageable) {
|
public @NotNull ResponseVO<PageableVO<UserInfoResponseVO>> getAllUserInfo(@NotNull Pageable pageable) {
|
||||||
return PageableResponseVO.success(
|
return PageableVO.success(
|
||||||
userRepo.findAll(pageable).map(o -> userMapper.entityToInfoVO(o))
|
userRepo.findAll(pageable).map(o -> userMapper.entityToInfoVO(o))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -138,14 +148,18 @@ public class UserService implements IUserService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull ResponseVO<List<AttachInfoResponseVO>> getUserAttaches(@PathVariable UUID userID) {
|
public @NotNull ResponseVO<PageableVO<BlogInfoResponseVO>> getUserBlogList(@NotNull UUID userID, @NotNull Pageable pageable) {
|
||||||
UserEntity userEntity = userRepo.findById(userID).orElse(null);
|
return PageableVO.success(
|
||||||
if (userEntity == null) {
|
blogRepo.findByUploader_IdOrderByAttachEntities_CreateTimeDesc(userID, pageable)
|
||||||
return ResponseVO.failed("未找到该用户!");
|
.map(o -> blogMapper.entityToInfoVO(o))
|
||||||
}
|
);
|
||||||
List<AttachInfoResponseVO> list = userEntity.getAttachEntities()
|
}
|
||||||
.stream().map(o -> attachMapper.entityToInfoVO(o))
|
|
||||||
.toList();
|
@Override
|
||||||
return ResponseVO.success(list);
|
public @NotNull ResponseVO<PageableVO<AttachInfoResponseVO>> getUserAttachList(@NotNull UUID userID, @NotNull Pageable pageable) {
|
||||||
|
return PageableVO.success(
|
||||||
|
attachRepo.findByUploader_IdOrderByCreateTimeDesc(userID, pageable)
|
||||||
|
.map(o -> attachMapper.entityToInfoVO(o))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,19 +8,19 @@ import java.util.List;
|
|||||||
|
|
||||||
@Data
|
@Data
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class PageableResponseVO<T> {
|
public class PageableVO<T> {
|
||||||
private int page;
|
private int page;
|
||||||
private int size;
|
private int size;
|
||||||
private long totalElements;
|
private long totalElements;
|
||||||
private int totalPage;
|
private int totalPage;
|
||||||
private List<T> data;
|
private List<T> data;
|
||||||
|
|
||||||
public static <T> ResponseVO<PageableResponseVO<T>> success(Page<T> page) {
|
public static <T> ResponseVO<PageableVO<T>> success(Page<T> page) {
|
||||||
return ResponseVO.success(of(page));
|
return ResponseVO.success(of(page));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> PageableResponseVO<T> of(Page<T> page) {
|
public static <T> PageableVO<T> of(Page<T> page) {
|
||||||
return new PageableResponseVO<>(
|
return new PageableVO<>(
|
||||||
page.getNumber(),
|
page.getNumber(),
|
||||||
page.getSize(),
|
page.getSize(),
|
||||||
page.getTotalElements(),
|
page.getTotalElements(),
|
@@ -27,7 +27,11 @@ public class ResponseVO<T> {
|
|||||||
return new ResponseVO<>(200, msg, data);
|
return new ResponseVO<>(200, msg, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> ResponseVO<T> failed(String msg) {
|
public static <T> ResponseVO<T> unauthorized() {
|
||||||
|
return new ResponseVO<>(401, "Unauthorized", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> ResponseVO<T> failed(@NotNull String msg) {
|
||||||
return new ResponseVO<>(403, msg, null);
|
return new ResponseVO<>(403, msg, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
package cn.hamster3.application.blog.vo.user;
|
package cn.hamster3.application.blog.vo.user;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import jakarta.validation.constraints.Pattern;
|
import jakarta.validation.constraints.Pattern;
|
||||||
import jakarta.validation.constraints.Size;
|
import jakarta.validation.constraints.Size;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
@@ -8,10 +9,13 @@ import lombok.Data;
|
|||||||
@Data
|
@Data
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public class UserCreateRequireVO {
|
public class UserCreateRequireVO {
|
||||||
|
@Parameter(name = "邮箱")
|
||||||
@Pattern(regexp = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$", message = "邮箱配置不合法!")
|
@Pattern(regexp = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$", message = "邮箱配置不合法!")
|
||||||
private String email;
|
private String email;
|
||||||
|
@Parameter(name = "昵称")
|
||||||
@Size(min = 3, max = 16, message = "用户昵称必须包含 3~16 个字符!")
|
@Size(min = 3, max = 16, message = "用户昵称必须包含 3~16 个字符!")
|
||||||
private String nickname;
|
private String nickname;
|
||||||
|
@Parameter(name = "密码")
|
||||||
@Size(min = 8, max = 16, message = "密码必须包含 8~16 个字符!")
|
@Size(min = 8, max = 16, message = "密码必须包含 8~16 个字符!")
|
||||||
private String password;
|
private String password;
|
||||||
}
|
}
|
||||||
|
@@ -1,10 +1,9 @@
|
|||||||
package cn.hamster3.application.blog.vo.user;
|
package cn.hamster3.application.blog.vo.user;
|
||||||
|
|
||||||
import cn.hamster3.application.blog.constant.UserPermissions;
|
import cn.hamster3.application.blog.constant.UserRole;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@@ -13,5 +12,5 @@ public class UserInfoResponseVO {
|
|||||||
private UUID id;
|
private UUID id;
|
||||||
private String email;
|
private String email;
|
||||||
private String nickname;
|
private String nickname;
|
||||||
private Set<UserPermissions> permissions;
|
private UserRole role;
|
||||||
}
|
}
|
||||||
|
@@ -1,11 +1,9 @@
|
|||||||
package cn.hamster3.application.blog.vo.user;
|
package cn.hamster3.application.blog.vo.user;
|
||||||
|
|
||||||
import cn.hamster3.application.blog.constant.UserPermissions;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@@ -14,7 +12,6 @@ public class UserRegisterResponseVO {
|
|||||||
private UUID id;
|
private UUID id;
|
||||||
private String email;
|
private String email;
|
||||||
private String nickname;
|
private String nickname;
|
||||||
private List<UserPermissions> permissions;
|
|
||||||
private Date createTime;
|
private Date createTime;
|
||||||
private Date updateTime;
|
private Date updateTime;
|
||||||
}
|
}
|
||||||
|
@@ -1,23 +1,28 @@
|
|||||||
package cn.hamster3.application.blog.vo.user;
|
package cn.hamster3.application.blog.vo.user;
|
||||||
|
|
||||||
import cn.hamster3.application.blog.constant.UserPermissions;
|
import cn.hamster3.application.blog.constant.UserRole;
|
||||||
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import jakarta.validation.constraints.Pattern;
|
import jakarta.validation.constraints.Pattern;
|
||||||
import jakarta.validation.constraints.Size;
|
import jakarta.validation.constraints.Size;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class UserUpdateRequireVO {
|
public class UserUpdateRequireVO {
|
||||||
|
@Parameter(name = "用户ID")
|
||||||
@NotNull(message = "用户id不能为空!")
|
@NotNull(message = "用户id不能为空!")
|
||||||
private UUID id;
|
private UUID id;
|
||||||
|
@Parameter(name = "邮箱")
|
||||||
@Pattern(regexp = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$", message = "邮箱配置不合法!")
|
@Pattern(regexp = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$", message = "邮箱配置不合法!")
|
||||||
private String email;
|
private String email;
|
||||||
|
@Parameter(name = "昵称")
|
||||||
@Size(min = 3, max = 16, message = "用户昵称必须包含 3~16 个字符!")
|
@Size(min = 3, max = 16, message = "用户昵称必须包含 3~16 个字符!")
|
||||||
private String nickname;
|
private String nickname;
|
||||||
|
@Parameter(name = "密码")
|
||||||
@Size(min = 8, max = 16, message = "密码必须包含 8~16 个字符!")
|
@Size(min = 8, max = 16, message = "密码必须包含 8~16 个字符!")
|
||||||
private String password;
|
private String password;
|
||||||
private Set<UserPermissions> permissions;
|
@Parameter(name = "角色")
|
||||||
|
private UserRole role;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user