新增修改密码功能,新增管理员添加用户功能,设置redis缓存超时时间,捕获部分redisTemplate异常以免影响正常业务,将部分基础crud操作移至dao service中

dev-active
lensfrex 2 years ago
parent ff1ae38707
commit 685b582d04
Signed by: lensfrex
GPG Key ID: 0F69A0A2FBEE98A0
  1. 24
      src/main/java/net/lensfrex/dscape/cache/InviteCodeService.java
  2. 32
      src/main/java/net/lensfrex/dscape/cache/UserBasicCache.java
  3. 2
      src/main/java/net/lensfrex/dscape/dao/entity/BlackList.java
  4. 2
      src/main/java/net/lensfrex/dscape/dao/entity/PatientData.java
  5. 2
      src/main/java/net/lensfrex/dscape/dao/entity/RegisterApplies.java
  6. 2
      src/main/java/net/lensfrex/dscape/dao/entity/RolePermission.java
  7. 4
      src/main/java/net/lensfrex/dscape/dao/entity/UserBasic.java
  8. 2
      src/main/java/net/lensfrex/dscape/dao/entity/UserRole.java
  9. 11
      src/main/java/net/lensfrex/dscape/dao/service/UserBasicService.java
  10. 37
      src/main/java/net/lensfrex/dscape/dao/service/impl/UserBasicServiceImpl.java
  11. 13
      src/main/java/net/lensfrex/dscape/dto/request/user/PasswordModifyRequestBody.java
  12. 14
      src/main/java/net/lensfrex/dscape/dto/request/user/UserAddRequest.java
  13. 11
      src/main/java/net/lensfrex/dscape/enums/user/UserRoleEnum.java
  14. 5
      src/main/java/net/lensfrex/dscape/exception/GlobalException.java
  15. 22
      src/main/java/net/lensfrex/dscape/exception/handler/GlobalExceptionHandler.java
  16. 18
      src/main/java/net/lensfrex/dscape/web/controllers/Error.java
  17. 12
      src/main/java/net/lensfrex/dscape/web/controllers/Index.java
  18. 10
      src/main/java/net/lensfrex/dscape/web/controllers/user/UserController.java
  19. 22
      src/main/java/net/lensfrex/dscape/web/controllers/user/admin/AdminController.java
  20. 40
      src/main/java/net/lensfrex/dscape/web/service/user/AdminService.java
  21. 64
      src/main/java/net/lensfrex/dscape/web/service/user/UserService.java
  22. 6
      src/main/resources/application.yml

@ -57,18 +57,26 @@ public class InviteCodeService {
}
public boolean checkInviteCode(String code) {
return redis.opsForHash().get(REGISTER_INVITE_CODE_KEY, code) == null;
try {
return redis.opsForHash().get(REGISTER_INVITE_CODE_KEY, code) == null;
} catch (Exception e) {
return false;
}
}
public String useInviteCode(String code) {
String superior = (String) redis.opsForHash().get(REGISTER_INVITE_CODE_KEY, code);
if (superior == null) {
throw new GlobalException(ResponseCode.INVITE_CODE_WRONG);
}
try {
String superior = (String) redis.opsForHash().get(REGISTER_INVITE_CODE_KEY, code);
if (superior == null) {
throw new GlobalException(ResponseCode.INVITE_CODE_WRONG);
}
redis.opsForHash().delete(REGISTER_INVITE_CODE_KEY, code);
redis.opsForValue().decrement(String.format(ADMIN_INVITE_CODE_COUNTER_KEY, superior));
redis.opsForHash().delete(REGISTER_INVITE_CODE_KEY, code);
redis.opsForValue().decrement(String.format(ADMIN_INVITE_CODE_COUNTER_KEY, superior));
return superior;
return superior;
} catch (Exception e) {
throw new GlobalException(ResponseCode.INVITE_CODE_WRONG);
}
}
}

@ -29,21 +29,33 @@ public class UserBasicCache {
}
public UserBasic getUserByUid(String uid) {
String cacheData = (String) redis.opsForHash().get(USER_INFO_CACHE_KEY, uid);
if (cacheData != null) {
return objectJsonSerializer.deserialize(cacheData, UserBasic.class);
} else {
log.debug("缓存中没有用户信息");
try {
String cacheData = (String) redis.opsForHash().get(USER_INFO_CACHE_KEY, uid);
if (cacheData != null) {
return objectJsonSerializer.deserialize(cacheData, UserBasic.class);
} else {
log.debug("缓存中没有用户信息");
return null;
}
} catch (Exception e) {
log.warn("获取缓存时出现问题");
log.debug("追踪:", e);
return null;
}
}
public UserBasic getUserByUserName(String username) {
String uid = (String) redis.opsForHash().get(USERNAME_UID_CACHE_KEY, username);
if (uid != null) {
return this.getUserByUid(uid);
} else {
log.debug("缓存中没有用户名和uid的对应信息");
try {
String uid = (String) redis.opsForHash().get(USERNAME_UID_CACHE_KEY, username);
if (uid != null) {
return this.getUserByUid(uid);
} else {
log.debug("缓存中没有用户名和uid的对应信息");
return null;
}
} catch (Exception e) {
log.warn("获取缓存时出现问题");
log.debug("追踪:", e);
return null;
}
}

@ -1,5 +1,6 @@
package net.lensfrex.dscape.dao.entity;
import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.Data;
import java.util.Date;
import java.util.List;
@ -51,6 +52,7 @@ public class BlackList implements Serializable {
/**
* is_deleted
*/
@TableLogic
private int isDeleted;
public BlackList() {}

@ -1,5 +1,6 @@
package net.lensfrex.dscape.dao.entity;
import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
@ -61,6 +62,7 @@ public class PatientData implements Serializable {
/**
* is_deleted
*/
@TableLogic
private int isDeleted;
public PatientData() {}

@ -1,5 +1,6 @@
package net.lensfrex.dscape.dao.entity;
import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.Data;
import java.time.LocalDateTime;
@ -51,6 +52,7 @@ public class RegisterApplies implements Serializable {
/**
* is_deleted
*/
@TableLogic
private int isDeleted;
public RegisterApplies() {}

@ -1,5 +1,6 @@
package net.lensfrex.dscape.dao.entity;
import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.Data;
import java.time.LocalDateTime;
@ -46,6 +47,7 @@ public class RolePermission implements Serializable {
/**
* is_deleted
*/
@TableLogic
private int isDeleted;
public RolePermission() {}

@ -1,5 +1,6 @@
package net.lensfrex.dscape.dao.entity;
import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.Data;
import java.time.LocalDateTime;
@ -20,12 +21,12 @@ public class UserBasic implements Serializable {
/**
* id
*/
@TableId(type = IdType.AUTO)
private Integer id;
/**
* 用户唯一uuid
*/
@TableId(type = IdType.AUTO)
private String uid;
/**
@ -66,6 +67,7 @@ public class UserBasic implements Serializable {
/**
* is_deleted
*/
@TableLogic
private int isDeleted;
public UserBasic() {}

@ -1,5 +1,6 @@
package net.lensfrex.dscape.dao.entity;
import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.Data;
import java.io.Serializable;
import java.time.LocalDateTime;
@ -46,6 +47,7 @@ public class UserRole implements Serializable {
/**
* is_deleted
*/
@TableLogic
private int isDeleted;
public UserRole() {}

@ -1,4 +1,7 @@
package net.lensfrex.dscape.dao.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import net.lensfrex.dscape.dao.entity.UserBasic;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.IService;
@ -9,5 +12,13 @@ import com.baomidou.mybatisplus.extension.service.IService;
*/
@Service
public interface UserBasicService extends IService<UserBasic> {
UserBasic getUser(SFunction<UserBasic, ?> function, String index);
UserBasic getUser(QueryWrapper<UserBasic> wrapper);
boolean userNameExists(String username);
void modify(SFunction<UserBasic, ?> colm, Object index, SFunction<UserBasic, ?> modifyColm, Object newValue);
void modify(UpdateWrapper<UserBasic> wrapper);
}

@ -4,6 +4,9 @@
package net.lensfrex.dscape.dao.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.lensfrex.dscape.dao.entity.UserBasic;
import net.lensfrex.dscape.dao.mapper.UserBasicMapper;
@ -12,5 +15,39 @@ import org.springframework.stereotype.Service;
@Service
public class UserBasicServiceImpl extends ServiceImpl<UserBasicMapper, UserBasic> implements UserBasicService {
@Override
public UserBasic getUser(SFunction<UserBasic, ?> indexColm, String index) {
QueryWrapper<UserBasic> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(indexColm, index);
return this.getOne(wrapper);
}
@Override
public UserBasic getUser(QueryWrapper<UserBasic> wrapper) {
return this.getOne(wrapper);
}
@Override
public boolean userNameExists(String username) {
QueryWrapper<UserBasic> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(UserBasic::getUserName, username);
return this.count(wrapper) != 0;
}
@Override
public void modify(SFunction<UserBasic, ?> indexColm, Object index, SFunction<UserBasic, ?> modifyColm, Object newValue) {
UpdateWrapper<UserBasic> wrapper = new UpdateWrapper<>();
wrapper.lambda()
.eq(indexColm, index)
.set(modifyColm, newValue);
this.update(wrapper);
}
@Override
public void modify(UpdateWrapper<UserBasic> wrapper) {
this.update(wrapper);
}
}

@ -0,0 +1,13 @@
package net.lensfrex.dscape.dto.request.user;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class PasswordModifyRequestBody {
@JsonProperty("old_password")
String oldPassword;
@JsonProperty("new_password")
String newPassword;
}

@ -0,0 +1,14 @@
package net.lensfrex.dscape.dto.request.user;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class UserAddRequest {
@JsonProperty("user_name")
private String userName;
private String password;
private int role;
}

@ -17,4 +17,15 @@ public enum UserRoleEnum {
this.code = code;
this.name = name;
}
private final static UserRoleEnum[] allEnums = values();
public static UserRoleEnum getTypeEnumByCode(int code) {
for (UserRoleEnum result : allEnums) {
if (result.code == code) {
return result;
}
}
throw new IllegalArgumentException(String.format("角色id\"%s\"不存在", code));
}
}

@ -10,6 +10,11 @@ public class GlobalException extends RuntimeException {
this.responseCode = responseCode;
}
public GlobalException(ResponseCode responseCode, String message) {
super(message);
this.responseCode = responseCode;
}
public ResponseCode getResponseCode() {
return responseCode;
}

@ -1,5 +1,7 @@
package net.lensfrex.dscape.exception.handler;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotRoleException;
import com.fasterxml.jackson.databind.JsonMappingException;
import net.lensfrex.dscape.dto.response.general.Response;
import net.lensfrex.dscape.dto.response.general.ResponseCode;
@ -134,4 +136,24 @@ public class GlobalExceptionHandler {
log.debug(String.format("请求错误(%s): %s", e.getClass().getName(), e.getMessage()));
return Response.error(ResponseCode.INVALID_REQUEST);
}
/**
* 权限不足
* @param e 异常
* @return 统一响应
*/
@ExceptionHandler(NotRoleException.class)
public Response<Object> handler(NotRoleException e) {
return Response.error(ResponseCode.PERMISSION_DENIED);
}
/**
* 没登陆
* @param e 异常
* @return 统一响应
*/
@ExceptionHandler(NotLoginException.class)
public Response<Object> handler(NotLoginException e) {
return Response.error(ResponseCode.PERMISSION_DENIED);
}
}

@ -1,18 +0,0 @@
/*
* Class created by lensfrex.
*/
package net.lensfrex.dscape.web.controllers;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
@ControllerAdvice
public class Error extends AbstractMethodError {
// @ExceptionHandler({ RuntimeException.class })
// public Response error() {
// return Response.error(50000, "服务器内部错误....");
// }
}

@ -1,12 +0,0 @@
package net.lensfrex.dscape.web.controllers;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class Index {
@RequestMapping("/")
public String index() {
return "Wow~~~~~~~~~~~~~~~~~~~~~~";
}
}

@ -9,6 +9,7 @@ import cn.dev33.satoken.stp.StpUtil;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import net.lensfrex.dscape.dto.request.UserLoginRequestBody;
import net.lensfrex.dscape.dto.request.user.PasswordModifyRequestBody;
import net.lensfrex.dscape.dto.request.user.RegisterRequestBody;
import net.lensfrex.dscape.dto.response.general.Response;
import net.lensfrex.dscape.dto.response.general.ResponseCode;
@ -66,8 +67,11 @@ public class UserController {
}
@PostMapping(value = "/modifyPassword/{uid}", produces = "application/json")
public Response modifyPassword(@RequestBody String body, @PathVariable String uid,
@RequestHeader String token) {
return Response.error(ResponseCode.API_NOT_IMPLEMENT);
public Response<Object> modifyPassword(@RequestBody PasswordModifyRequestBody body, @PathVariable String uid) {
StpUtil.checkLogin();
userService.modifyPassword(uid, body.getOldPassword(), body.getNewPassword());
return Response.success();
}
}

@ -4,15 +4,20 @@
package net.lensfrex.dscape.web.controllers.user.admin;
import cn.dev33.satoken.annotation.SaCheckRole;
import cn.dev33.satoken.stp.StpUtil;
import lombok.extern.slf4j.Slf4j;
import net.lensfrex.dscape.dto.request.user.UserAddRequest;
import net.lensfrex.dscape.dto.response.general.Response;
import net.lensfrex.dscape.dto.response.general.ResponseCode;
import net.lensfrex.dscape.dto.response.user.RegisterResponseBody;
import net.lensfrex.dscape.enums.user.UserRoleEnum;
import net.lensfrex.dscape.exception.GlobalException;
import net.lensfrex.dscape.web.service.user.admin.AdminService;
import net.lensfrex.dscape.utils.NetworkUtil;
import net.lensfrex.dscape.web.service.user.AdminService;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
@Slf4j
@ -27,14 +32,17 @@ public class AdminController {
}
@PostMapping(value = "/add", produces = "application/json")
public Response<Object> addUser(@RequestBody String body,
@RequestHeader String token) {
return Response.error(ResponseCode.API_NOT_IMPLEMENT);
public Response<RegisterResponseBody> addUser(@RequestBody UserAddRequest request, HttpServletRequest httpServletRequest) {
StpUtil.checkRole(String.valueOf(UserRoleEnum.ADMIN.getCode()));
return Response.success(adminService.adminAddUser(request, NetworkUtil.getRealIP(httpServletRequest)));
}
@PostMapping(value = "/modifyStatus", produces = "application/json")
public Response<Object> modifyStatus(@RequestParam String uid, @RequestParam int status) {
if (!StpUtil.hasRole(String.valueOf(UserRoleEnum.ADMIN.getCode()))) {
StpUtil.checkRole(String.valueOf(UserRoleEnum.ADMIN.getCode()));
if (StpUtil.getLoginIdAsString().equals(uid)) {
throw new GlobalException(ResponseCode.PERMISSION_DENIED);
}
@ -59,9 +67,7 @@ public class AdminController {
@GetMapping(value = "/inviteCode", produces = "application/json")
public Response<List<String>> generateInviteCodes(@RequestParam(required = false, defaultValue = "-1") long expired,
@RequestParam(required = false, defaultValue = "1") int count) {
if (!StpUtil.hasRole(String.valueOf(UserRoleEnum.ADMIN.getCode()))) {
throw new GlobalException(ResponseCode.PERMISSION_DENIED);
}
StpUtil.checkRole(String.valueOf(UserRoleEnum.ADMIN.getCode()));
if (count > 1024) {
throw new GlobalException(ResponseCode.INVALID_REQUEST);

@ -2,9 +2,14 @@
* Class created by lensfrex.
*/
package net.lensfrex.dscape.web.service.user.admin;
/*
* Class created by lensfrex.
*/
package net.lensfrex.dscape.web.service.user;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import net.lensfrex.dscape.cache.InviteCodeService;
import net.lensfrex.dscape.cache.UserBasicCache;
@ -12,7 +17,13 @@ import net.lensfrex.dscape.dao.entity.BlackList;
import net.lensfrex.dscape.dao.entity.UserBasic;
import net.lensfrex.dscape.dao.service.BlackListService;
import net.lensfrex.dscape.dao.service.UserBasicService;
import net.lensfrex.dscape.dto.request.user.UserAddRequest;
import net.lensfrex.dscape.dto.response.general.ResponseCode;
import net.lensfrex.dscape.dto.response.user.RegisterResponseBody;
import net.lensfrex.dscape.enums.user.BlackListTypeEnum;
import net.lensfrex.dscape.enums.user.UserRoleEnum;
import net.lensfrex.dscape.exception.GlobalException;
import net.lensfrex.dscape.web.service.user.UserService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
@ -24,6 +35,8 @@ public class AdminService {
private final UserBasicService userBasicService;
private final UserService userService;
private final BlackListService blackListService;
private final InviteCodeService inviteCodeService;
@ -32,12 +45,14 @@ public class AdminService {
public AdminService(RedisTemplate<String, String> redis,
UserBasicService userBasicService,
UserService userService,
BlackListService blackListService,
InviteCodeService inviteCodeService,
UserBasicCache userBasicCache) {
this.redis = redis;
this.userBasicService = userBasicService;
this.userService = userService;
this.blackListService = blackListService;
this.inviteCodeService = inviteCodeService;
this.userBasicCache = userBasicCache;
@ -67,16 +82,27 @@ public class AdminService {
}
public void deleteUser(String uid) {
UpdateWrapper<UserBasic> wrapper = new UpdateWrapper<>();
wrapper.lambda()
.eq(UserBasic::getUid, uid)
.set(UserBasic::getIsDeleted, 1);
this.clearUserBasicCache(uid);
userBasicService.update(wrapper);
userBasicService.removeById(uid);
}
private void clearUserBasicCache(String uid) {
userBasicCache.clear(uid);
}
public RegisterResponseBody adminAddUser(UserAddRequest requestBody, String registerIp) {
if (userService.userNameExists(requestBody.getUserName())) {
throw new GlobalException(ResponseCode.USER_NAME_EXISTS);
}
String uid = userService.addUserToDatabase(requestBody.getUserName(), requestBody.getPassword(),
StpUtil.getLoginIdAsString(), UserRoleEnum.getTypeEnumByCode(requestBody.getRole()), registerIp);
RegisterResponseBody registerResponseBody = new RegisterResponseBody();
registerResponseBody.setUid(uid);
return registerResponseBody;
}
}

@ -7,6 +7,8 @@ package net.lensfrex.dscape.web.service.user;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import lombok.extern.slf4j.Slf4j;
import net.lensfrex.dscape.cache.InviteCodeService;
import net.lensfrex.dscape.cache.UserBasicCache;
@ -85,31 +87,37 @@ public class UserService {
}
private UserBasic getUserAndCache(String username) {
// 进数据库里边查
QueryWrapper<UserBasic> wrapper = new QueryWrapper<>();
wrapper.lambda()
.eq(UserBasic::getUserName, username)
.eq(UserBasic::getIsDeleted, 0);
UserBasic userBasic = userBasicService.getUser(UserBasic::getUserName, username);
this.cacheUser(userBasic);
UserBasic userBasic = userBasicService.getOne(wrapper);
return userBasic;
}
private UserBasic getUserAndCacheByUid(String uid) {
UserBasic userBasic = userBasicService.getUser(UserBasic::getUid, uid);
this.cacheUser(userBasic);
return userBasic;
}
private boolean cacheUser(UserBasic userBasic) {
try {
if (userBasic != null) {
userBasicCache.save(userBasic);
}
} catch (Exception e) {
log.info("将用户数据存入redis缓存时发生错误", e);
log.info("将用户数据存入redis缓存时发生错误");
log.debug("追踪:", e);
return false;
}
return userBasic;
return true;
}
@Transactional
public RegisterResponseBody register(RegisterRequestBody requestBody, String registerIp) {
QueryWrapper<UserBasic> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(UserBasic::getUserName, requestBody.getUserName())
.eq(UserBasic::getIsDeleted, 0);
// 检查用户名是否被占用
if (userBasicService.count(wrapper) != 0) {
if (userNameExists(requestBody.getUserName())) {
throw new GlobalException(ResponseCode.USER_NAME_EXISTS);
}
@ -143,7 +151,7 @@ public class UserService {
* @param userRoleEnum 用户角色
* @return 用户uid
*/
private String addUserToDatabase(String userName, String password, String superior, UserRoleEnum userRoleEnum, String userIp) {
protected String addUserToDatabase(String userName, String password, String superior, UserRoleEnum userRoleEnum, String userIp) {
UserBasic userBasic = new UserBasic();
String uid = UUID.randomUUID().toString();
@ -162,4 +170,32 @@ public class UserService {
return uid;
}
protected boolean userNameExists(String username) {
return userBasicService.userNameExists(username);
}
public void modifyPassword(String uid, String oldPassword, String newPassword) {
String loginUser = StpUtil.getLoginIdAsString();
UserBasic userBasic = this.getUserAndCacheByUid(uid);
if (userBasic == null) {
return;
}
if (!loginUser.equals(uid)) {
if (!loginUser.equals(userBasic.getSuperior())) {
throw new GlobalException(ResponseCode.PERMISSION_DENIED);
}
}
if (BCrypt.checkpw(userBasic.getPassword(), oldPassword)) {
throw new GlobalException(ResponseCode.PERMISSION_DENIED);
}
String newHashedPassword = BCrypt.hashpw(newPassword, BCrypt.gensalt());
userBasicService.modify(UserBasic::getUid, uid,
UserBasic::getPassword, newHashedPassword);
}
}

@ -22,6 +22,7 @@ spring:
port: 49153
username: default
password: bd2fbffa5
timeout: 2000ms
lettuce:
pool:
max-active: 8
@ -33,6 +34,11 @@ mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
default-enum-type-handler: org.apache.ibatis.type.EnumOrdinalTypeHandler
global-config:
db-config:
logic-delete-field: id_deleted
logic-not-delete-value: 0
logic-delete-value: 1
sa-token:
token-name: dscape-token

Loading…
Cancel
Save