This commit is contained in:
iizmg
2020-04-27 14:03:43 +08:00
parent 25e1e60bc4
commit e71604a175
13 changed files with 721 additions and 0 deletions
@@ -1,12 +1,31 @@
package org.itkk.udf.api.common;
import lombok.extern.slf4j.Slf4j;
import org.itkk.udf.api.common.dto.UserDto;
import org.itkk.udf.starter.core.exception.AuthException;
import javax.servlet.http.HttpServletRequest;
/**
* 工具类
*/
@Slf4j
public class CommonUtil {
/**
* 获得用户信息
*
* @param request request
* @return TokenInfoDto
*/
public static UserDto getUser(HttpServletRequest request) {
Object tokenInfoDtoObj = request.getAttribute(CommonConstant.PARAMETER_NAME_TOKEN_INFO);
if (tokenInfoDtoObj == null) {
throw new AuthException("token信息不存在");
}
return (UserDto) tokenInfoDtoObj;
}
/**
* 私有化构造函数
*/
@@ -0,0 +1,67 @@
package org.itkk.udf.api.common.dto;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
@Data
@Accessors(chain = true)
@NoArgsConstructor
@ToString
@EqualsAndHashCode(callSuper = false)
public class UserDto implements Serializable {
/**
* ID
*/
private static final long serialVersionUID = -6075064116058975444L;
/**
* 主键(PK)(非空)
*/
private String id;
/**
* 用户ID(UK_1)(非空)
*/
private String userId;
/**
* 用户昵称(非空)
*/
private String nickName;
/**
* 用户头像文件ID(非空)
*/
private String avatarFileId;
/**
* 用户状态 (1:正常)
*/
private Integer status;
/**
* 创建人
*/
private String createBy;
/**
* 创建时间
*/
private Date createDate;
/**
* 更新人
*/
private String updateBy;
/**
* 更新时间
*/
private Date updateDate;
}
@@ -0,0 +1,15 @@
package org.itkk.udf.api.common.service;
import org.itkk.udf.api.common.dto.UserDto;
public interface IUserService {
/**
* 获得用户信息
*
* @param userId userId
* @return UserDto
*/
UserDto info(String userId);
}
@@ -0,0 +1,41 @@
package org.itkk.udf.api.rbac;
/**
* 常量类
*/
public class RbacConstant {
/**
* 用户注册缓存key
*/
public static final String USER_KEY_PREFIX = "USER_";
/**
* 用户状态(正常)
*/
public enum USER_STATUS {
/**
* 正常
*/
STATUS_1(1);
private Integer value;
USER_STATUS(Integer value) {
this.value = value;
}
public Integer value() {
return this.value;
}
}
/**
* 私有化构造函数
*/
private RbacConstant() {
}
}
@@ -5,6 +5,8 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.itkk.udf.api.common.CommonConstant;
import org.itkk.udf.api.common.CommonProperties;
import org.itkk.udf.api.common.dto.UserDto;
import org.itkk.udf.api.rbac.service.UserService;
import org.itkk.udf.starter.cache.db.dto.DbCacheDto;
import org.itkk.udf.starter.cache.db.service.DbCacheService;
import org.itkk.udf.starter.core.CoreUtil;
@@ -32,6 +34,12 @@ public class WebHandlerInterceptor implements HandlerInterceptor {
@Autowired
private CommonProperties commonProperties;
/**
* userService
*/
@Autowired
private UserService userService;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//排除options
@@ -48,6 +56,12 @@ public class WebHandlerInterceptor implements HandlerInterceptor {
if (dbCacheDto == null) {
throw new AuthException("token不存在");
}
//获得tokenInfo
UserDto userDto = userService.info(token, dbCacheDto.getValue());
//放入请求作用域
request.setAttribute(CommonConstant.PARAMETER_NAME_TOKEN_INFO, userDto);
//刷新token ttl
dbCacheService.setTtl(token, CommonConstant.TOKEN_CACHE_TTL);
}
//正常返回
return true;
@@ -0,0 +1,48 @@
package org.itkk.udf.api.rbac.dto;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.Accessors;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
@Data
@Accessors(chain = true)
@NoArgsConstructor
@ToString
@EqualsAndHashCode(callSuper = false)
public class ChangePswdDto implements Serializable {
/**
* ID
*/
private static final long serialVersionUID = -6075064116058975444L;
/**
* 用户ID(UK_1)(非空)
*/
@NotBlank(message = "用户名不能为空")
private String userId;
/**
* 原密码
*/
@NotBlank(message = "原密码不能为空")
private String originalPswd;
/**
* 密码
*/
@NotBlank(message = "密码不能为空")
@Length(min = 6, message = "密码至少6个字符")
private String pswd;
/**
* 密码确认
*/
@NotBlank(message = "密码确认不能为空")
private String pswdConfim;
}
@@ -0,0 +1,34 @@
package org.itkk.udf.api.rbac.dto;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
@Data
@Accessors(chain = true)
@NoArgsConstructor
@ToString
@EqualsAndHashCode(callSuper = false)
public class LoginDto implements Serializable {
/**
* ID
*/
private static final long serialVersionUID = -6075064116058975444L;
/**
* 用户ID(UK_1)(非空)
*/
@NotBlank(message = "用户名不能为空")
private String userId;
/**
* 密码
*/
@NotBlank(message = "密码不能为空")
private String pswd;
}
@@ -0,0 +1,43 @@
package org.itkk.udf.api.rbac.dto;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.Accessors;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
@Data
@Accessors(chain = true)
@NoArgsConstructor
@ToString
@EqualsAndHashCode(callSuper = false)
public class RegisteredDto implements Serializable {
/**
* ID
*/
private static final long serialVersionUID = -6075064116058975444L;
/**
* 用户ID(UK_1)(非空)
*/
@NotBlank(message = "用户名不能为空")
@Length(max = 50, message = "用户名长度不能超过50个字符")
private String userId;
/**
* 密码
*/
@NotBlank(message = "密码不能为空")
@Length(min = 6, message = "密码至少6个字符")
private String pswd;
/**
* 密码确认
*/
@NotBlank(message = "密码确认不能为空")
private String pswdConfim;
}
@@ -0,0 +1,42 @@
package org.itkk.udf.api.rbac.dto;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.Accessors;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
@Data
@Accessors(chain = true)
@NoArgsConstructor
@ToString
@EqualsAndHashCode(callSuper = false)
public class UserSaveDto implements Serializable {
/**
* ID
*/
private static final long serialVersionUID = -6075064116058975444L;
/**
* 用户ID(UK_1)(非空)
*/
@NotBlank(message = "用户名不能为空")
@Length(max = 50, message = "用户名长度不能超过50个字符")
private String userId;
/**
* 用户昵称(非空)
*/
@NotBlank(message = "昵称不能为空")
@Length(max = 50, message = "昵称长度不能超过50个字符")
private String nickName;
/**
* 用户头像文件ID(非空)
*/
private String avatarFileId;
}
@@ -46,6 +46,12 @@ public class UserEntity {
@TableField("AVATAR_FILE_ID")
private String avatarFileId;
/**
* 用户状态 (1:正常)(非空)
*/
@TableField("STATUS")
private Integer status;
/**
* 创建人
*/
@@ -0,0 +1,276 @@
package org.itkk.udf.api.rbac.service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.google.common.cache.Cache;
import org.apache.commons.codec.digest.DigestUtils;
import org.itkk.udf.api.common.CommonConstant;
import org.itkk.udf.api.common.dto.UserDto;
import org.itkk.udf.api.common.service.IUserService;
import org.itkk.udf.api.rbac.RbacConstant;
import org.itkk.udf.api.rbac.dto.ChangePswdDto;
import org.itkk.udf.api.rbac.dto.LoginDto;
import org.itkk.udf.api.rbac.dto.RegisteredDto;
import org.itkk.udf.api.rbac.dto.UserSaveDto;
import org.itkk.udf.api.rbac.entity.UserEntity;
import org.itkk.udf.api.rbac.repository.IUserRepository;
import org.itkk.udf.starter.cache.db.service.DbCacheService;
import org.itkk.udf.starter.core.CoreUtil;
import org.itkk.udf.starter.core.exception.AuthException;
import org.itkk.udf.starter.core.exception.ParameterValidException;
import org.itkk.udf.starter.core.id.IdWorker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.UUID;
@Service
public class UserService implements IUserService {
/**
* cache
*/
@Autowired
private Cache<String, Object> cache;
/**
* iUserRepository
*/
@Autowired
private IUserRepository iUserRepository;
/**
* idWorker
*/
@Autowired
private IdWorker idWorker;
/**
* dbCacheService
*/
@Autowired
private DbCacheService dbCacheService;
/**
* 登陆
*
* @param loginDto loginDto
* @return String
*/
public String login(LoginDto loginDto) {
//获得用户信息
UserDto userDto = this.info(loginDto.getUserId());
//校验
if (userDto == null) {
throw new ParameterValidException("用户不存在");
}
//校验密码
this.checkPswd(userDto.getId(), loginDto.getPswd());
//获得token
String token = UUID.randomUUID().toString();
//放入缓存
dbCacheService.set(token, userDto.getUserId(), CommonConstant.TOKEN_CACHE_TTL);
//返回token
return token;
}
/**
* 注册
*
* @param registeredDto registeredDto
* @return String
*/
@Transactional
public String registered(RegisteredDto registeredDto) {
//校验
if (registeredDto == null) {
throw new ParameterValidException("注册信息为空");
}
if (registeredDto.getPswd().equals(registeredDto.getPswdConfim())) {
throw new ParameterValidException("两次密码输入不一致");
}
if (iUserRepository.selectCount(new QueryWrapper<UserEntity>().lambda().eq(UserEntity::getUserId, registeredDto.getUserId())) > 0) {
throw new ParameterValidException("用户名已存在");
}
//构造实体
UserEntity userEntity = new UserEntity();
userEntity.setId(String.valueOf(idWorker.nextId()));
userEntity.setUserId(registeredDto.getUserId());
userEntity.setUserPswd(DigestUtils.md5Hex(registeredDto.getPswd()));
userEntity.setNickName(registeredDto.getUserId());
userEntity.setAvatarFileId(null);
userEntity.setStatus(RbacConstant.USER_STATUS.STATUS_1.value());
userEntity.setCreateBy(registeredDto.getUserId());
userEntity.setCreateDate(new Date());
userEntity.setUpdateBy(registeredDto.getUserId());
userEntity.setUpdateDate(new Date());
//定义锁
final String key = RbacConstant.USER_KEY_PREFIX + registeredDto.getUserId();
//获取锁
if (dbCacheService.setNx(key, CoreUtil.getTraceId(), CommonConstant.LOCK_EXPAIR)) {
try {
//新增
iUserRepository.insert(userEntity);
} finally {
//释放锁
dbCacheService.delete(key);
}
} else {
//获取锁失败
throw new ParameterValidException(CommonConstant.DEF_LOCK_FAIL_MSG);
}
//登陆 & 返回
return this.login(new LoginDto().setUserId(registeredDto.getUserId()).setPswd(registeredDto.getPswd()));
}
/**
* 更新用户密码
*
* @param changePswdDto changePswdDto
* @param userId userId
*/
@Transactional
public void changePswd(ChangePswdDto changePswdDto, String userId) {
//获得用户信息
UserDto userDto = this.info(changePswdDto.getUserId());
//校验
if (userDto == null) {
throw new ParameterValidException("用户不存在");
}
if (changePswdDto.getPswd().equals(changePswdDto.getPswdConfim())) {
throw new ParameterValidException("两次密码输入不一致");
}
//校验密码
this.checkPswd(userDto.getId(), changePswdDto.getOriginalPswd());
//定义锁
final String key = RbacConstant.USER_KEY_PREFIX + changePswdDto.getUserId();
//获取锁
if (dbCacheService.setNx(key, CoreUtil.getTraceId(), CommonConstant.LOCK_EXPAIR)) {
try {
//更新信息
iUserRepository.update(null, new UpdateWrapper<UserEntity>().lambda()
.set(UserEntity::getUserPswd, changePswdDto.getPswd())
.set(UserEntity::getUpdateBy, userId)
.set(UserEntity::getUpdateDate, new Date())
.eq(UserEntity::getUserId, changePswdDto.getUserId())
);
} finally {
//释放锁
dbCacheService.delete(key);
}
} else {
//获取锁失败
throw new ParameterValidException(CommonConstant.DEF_LOCK_FAIL_MSG);
}
}
/**
* 用户信息更新
*
* @param userSaveDto userSaveDto
* @param userId userId
*/
@Transactional
public void save(UserSaveDto userSaveDto, String userId) {
//获得用户信息
UserDto userDto = this.info(userSaveDto.getUserId());
//校验
if (userDto == null) {
throw new ParameterValidException("用户不存在");
}
if (iUserRepository.selectCount(new QueryWrapper<UserEntity>().lambda().eq(UserEntity::getNickName, userSaveDto.getNickName())) > 0) {
throw new ParameterValidException("昵称已经存在,请重新输入");
}
//定义锁
final String key = RbacConstant.USER_KEY_PREFIX + userSaveDto.getUserId();
//获取锁
if (dbCacheService.setNx(key, CoreUtil.getTraceId(), CommonConstant.LOCK_EXPAIR)) {
try {
//更新信息
iUserRepository.update(null, new UpdateWrapper<UserEntity>().lambda()
.set(UserEntity::getNickName, userSaveDto.getNickName())
.set(UserEntity::getAvatarFileId, userSaveDto.getAvatarFileId())
.set(UserEntity::getUpdateBy, userId)
.set(UserEntity::getUpdateDate, new Date())
.eq(UserEntity::getUserId, userSaveDto.getUserId())
);
} finally {
//释放锁
dbCacheService.delete(key);
}
} else {
//获取锁失败
throw new ParameterValidException(CommonConstant.DEF_LOCK_FAIL_MSG);
}
}
/**
* 返回用户信息
*
* @param token token
* @param userId userId
* @return UserDto
*/
public UserDto info(String token, String userId) {
//构造缓存key
final String cacheKey = "userDto_" + token;
//抓取缓存信息
Object cacheValue = cache.getIfPresent(cacheKey);
//判空
if (cacheValue != null) {
return (UserDto) cacheValue;
}
//获得用户信息
UserDto userDto = this.info(userId);
//判空
if (userDto == null) {
throw new AuthException("用户不存在");
}
//判定状态(status = 1 为正常 , 其它为不正常)
if (!Integer.valueOf(1).equals(userDto.getStatus())) {
throw new AuthException("用户为非可用状态");
}
//放入缓存
cache.put(cacheKey, userDto);
//返回
return userDto;
}
@Override
public UserDto info(String userId) {
//定义返回值
UserDto userDto = null;
//获得数据
UserEntity userEntity = iUserRepository.selectOne(new QueryWrapper<UserEntity>().lambda().eq(UserEntity::getUserId, userId));
//判空
if (userEntity != null) {
//实例化
userDto = new UserDto();
//转换
CoreUtil.copyPropertiesIgnoreNull(userEntity, userDto);
}
//返回
return userDto;
}
/**
* 密码校验
*
* @param id id
* @param pswd pswd
*/
private void checkPswd(String id, String pswd) {
//获得用户信息
UserEntity userEntity = iUserRepository.selectById(id);
//校验
if (userEntity == null) {
throw new ParameterValidException("用户不存在");
}
if (!userEntity.getUserPswd().equals(DigestUtils.md5Hex(pswd))) {
throw new ParameterValidException("密码不正确");
}
}
}
@@ -0,0 +1,68 @@
package org.itkk.udf.api.rbac.web;
import org.itkk.udf.api.common.CommonConstant;
import org.itkk.udf.api.common.CommonUtil;
import org.itkk.udf.api.common.dto.UserDto;
import org.itkk.udf.api.rbac.dto.ChangePswdDto;
import org.itkk.udf.api.rbac.dto.UserSaveDto;
import org.itkk.udf.api.rbac.service.UserService;
import org.itkk.udf.starter.core.RestResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
@RestController
@RequestMapping(value = CommonConstant.URL_ROOT_WEB_PRIVATE + "rbac/user")
public class UserController {
/**
* httpServletRequest
*/
@Autowired
private HttpServletRequest httpServletRequest;
/**
* pmPqrrService
*/
@Autowired
private UserService userService;
/**
* 更改密码
*
* @param changePswdDto changePswdDto
* @return RestResponse<String>
*/
@PutMapping("change/pswd")
public RestResponse<String> changePswd(@RequestBody @Valid ChangePswdDto changePswdDto) {
userService.changePswd(changePswdDto, CommonUtil.getUser(httpServletRequest).getUserId());
return RestResponse.success();
}
/**
* 保存用户信息
*
* @param userSaveDto userSaveDto
* @param userId userId
* @return RestResponse<String>
*/
@PutMapping("save")
public RestResponse<String> save(@RequestBody @Valid UserSaveDto userSaveDto, String userId) {
userService.save(userSaveDto, CommonUtil.getUser(httpServletRequest).getUserId());
return RestResponse.success();
}
/**
* 获得用户信息
*
* @param userId userId
* @return RestResponse<UserDto>
*/
@GetMapping("info/{userId}")
public RestResponse<UserDto> info(@PathVariable String userId) {
return new RestResponse<>(userService.info(userId));
}
}
@@ -0,0 +1,48 @@
package org.itkk.udf.api.rbac.web;
import org.itkk.udf.api.common.CommonConstant;
import org.itkk.udf.api.rbac.dto.LoginDto;
import org.itkk.udf.api.rbac.dto.RegisteredDto;
import org.itkk.udf.api.rbac.service.UserService;
import org.itkk.udf.starter.core.RestResponse;
import org.springframework.beans.factory.annotation.Autowired;
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 javax.validation.Valid;
@RestController
@RequestMapping(value = CommonConstant.URL_ROOT_WEB_PUBLIC + "rbac/user")
public class UserPublicController {
/**
* pmPqrrService
*/
@Autowired
private UserService userService;
/**
* 登陆
*
* @param loginDto loginDto
* @return RestResponse<String>
*/
@PostMapping("login")
public RestResponse<String> login(@RequestBody @Valid LoginDto loginDto) {
return new RestResponse<>(userService.login(loginDto));
}
/**
* 注册
*
* @param registeredDto registeredDto
* @return RestResponse<String>
*/
@PostMapping("registered")
public RestResponse<String> registered(@RequestBody @Valid RegisteredDto registeredDto) {
return new RestResponse<>(userService.registered(registeredDto));
}
}