提交 dab3e597 编写于 作者: 查尔斯-BUG万象集's avatar 查尔斯-BUG万象集

优化:优化部分校验类型(业务验证迁移到 Service 层,使用 CheckUtils 来验证)

上级 693e8251
......@@ -226,6 +226,7 @@ continew-admin # 全局通用项目配置及依赖版本管理
│ │ ├─ dto # 公共 DTO(Data Transfer Object)
│ │ ├─ entity # 公共实体对象
│ │ ├─ query # 公共查询条件
│ │ ├─ request # 公共请求对象
│ │ └─ vo # 公共 VO(View Object)
│ └─ util # 公共工具类
│ ├─ helper # 公共 Helper(助手)
......
......@@ -33,6 +33,7 @@ import top.charles7c.cnadmin.common.enums.DisEnableStatusEnum;
* @since 2023/1/24 19:51
*/
@Data
@Schema(description = "修改状态信息")
public class UpdateStatusRequest implements Serializable {
private static final long serialVersionUID = 1L;
......@@ -40,7 +41,7 @@ public class UpdateStatusRequest implements Serializable {
/**
* 状态(1启用 2禁用)
*/
@Schema(description = "状态(1启用 2禁用)")
@Schema(description = "状态(1启用 2禁用)", type = "Integer", allowableValues = {"1", "2"})
@NotNull(message = "状态非法")
private DisEnableStatusEnum status;
}
......@@ -23,7 +23,7 @@ import lombok.extern.slf4j.Slf4j;
import top.charles7c.cnadmin.common.exception.ServiceException;
/**
* 业务检查工具类(抛出 500 ServiceException)
* 业务参数校验工具类(抛出 500 ServiceException)
*
* @author Charles7c
* @see ServiceException
......
......@@ -23,7 +23,7 @@ import lombok.extern.slf4j.Slf4j;
import top.charles7c.cnadmin.common.exception.BadRequestException;
/**
* 校验工具类(抛出 400 BadRequestException)
* 基本参数校验工具类(抛出 400 BadRequestException)
*
* @author Charles7c
* @since 2022/12/21 20:56
......
......@@ -38,7 +38,7 @@ import top.charles7c.cnadmin.common.model.vo.PageInfo;
import top.charles7c.cnadmin.common.util.ExceptionUtils;
import top.charles7c.cnadmin.common.util.ReflectUtils;
import top.charles7c.cnadmin.common.util.helper.QueryHelper;
import top.charles7c.cnadmin.common.util.validate.ValidationUtils;
import top.charles7c.cnadmin.common.util.validate.CheckUtils;
import top.charles7c.cnadmin.monitor.mapper.LogMapper;
import top.charles7c.cnadmin.monitor.model.entity.SysLog;
import top.charles7c.cnadmin.monitor.model.query.LoginLogQuery;
......@@ -135,7 +135,7 @@ public class LogServiceImpl implements LogService {
@Override
public SystemLogDetailVO detail(Long logId) {
SysLog sysLog = logMapper.selectById(logId);
ValidationUtils.throwIfNull(sysLog, String.format("ID为 [%s] 的日志已不存在", logId));
CheckUtils.throwIfNull(sysLog, String.format("ID为 [%s] 的日志已不存在", logId));
SystemLogDetailVO detailVO = BeanUtil.copyProperties(sysLog, SystemLogDetailVO.class);
this.fill(detailVO);
......
......@@ -28,7 +28,7 @@ import top.charles7c.cnadmin.common.enums.DisEnableStatusEnum;
import top.charles7c.cnadmin.common.model.dto.LoginUser;
import top.charles7c.cnadmin.common.util.SecureUtils;
import top.charles7c.cnadmin.common.util.helper.LoginHelper;
import top.charles7c.cnadmin.common.util.validate.ValidationUtils;
import top.charles7c.cnadmin.common.util.validate.CheckUtils;
import top.charles7c.cnadmin.system.model.entity.SysUser;
import top.charles7c.cnadmin.system.service.UserService;
......@@ -46,15 +46,11 @@ public class LoginServiceImpl implements LoginService {
@Override
public String login(String username, String password) {
// 查询用户
SysUser sysUser = userService.getByUsername(username);
// 校验
ValidationUtils.throwIfNull(sysUser, "用户名或密码错误");
CheckUtils.throwIfNull(sysUser, "用户名或密码错误");
Long userId = sysUser.getUserId();
ValidationUtils.throwIfNotEqual(SecureUtils.md5Salt(password, userId.toString()), sysUser.getPassword(),
"用户名或密码错误");
ValidationUtils.throwIfEqual(DisEnableStatusEnum.DISABLE, sysUser.getStatus(), "此账号已被禁用,如有疑问,请联系管理员");
CheckUtils.throwIfNotEqual(SecureUtils.md5Salt(password, userId.toString()), sysUser.getPassword(), "用户名或密码错误");
CheckUtils.throwIfEqual(DisEnableStatusEnum.DISABLE, sysUser.getStatus(), "此账号已被禁用,如有疑问,请联系管理员");
// 登录
LoginUser loginUser = BeanUtil.copyProperties(sysUser, LoginUser.class);
......
......@@ -19,12 +19,13 @@ package top.charles7c.cnadmin.system.model.request;
import java.io.Serializable;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import lombok.Data;
import io.swagger.v3.oas.annotations.media.Schema;
import org.hibernate.validator.constraints.Length;
/**
* 创建部门信息
*
......@@ -60,6 +61,6 @@ public class CreateDeptRequest implements Serializable {
* 描述
*/
@Schema(description = "描述")
@Size(max = 200, message = "描述长度不能超过 200 个字符")
@Length(max = 200, message = "描述长度不能超过 200 个字符")
private String description;
}
......@@ -20,12 +20,13 @@ import java.io.Serializable;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import lombok.Data;
import io.swagger.v3.oas.annotations.media.Schema;
import org.hibernate.validator.constraints.Length;
import top.charles7c.cnadmin.common.enums.GenderEnum;
/**
......@@ -45,7 +46,7 @@ public class UpdateBasicInfoRequest implements Serializable {
*/
@Schema(description = "昵称")
@NotBlank(message = "昵称不能为空")
@Size(max = 32, message = "昵称长度不能超过 32 个字符")
@Length(max = 32, message = "昵称长度不能超过 32 个字符")
private String nickname;
/**
......
......@@ -37,6 +37,7 @@ import top.charles7c.cnadmin.common.enums.DisEnableStatusEnum;
import top.charles7c.cnadmin.common.util.ExceptionUtils;
import top.charles7c.cnadmin.common.util.TreeUtils;
import top.charles7c.cnadmin.common.util.helper.QueryHelper;
import top.charles7c.cnadmin.common.util.validate.CheckUtils;
import top.charles7c.cnadmin.system.mapper.DeptMapper;
import top.charles7c.cnadmin.system.model.entity.SysDept;
import top.charles7c.cnadmin.system.model.query.DeptQuery;
......@@ -75,7 +76,7 @@ public class DeptServiceImpl implements DeptService {
return new ArrayList<>();
}
// 去
// 去除重复子部门列表
List<DeptVO> deDuplicationDeptList = deDuplication(list);
return deDuplicationDeptList.stream().map(d -> d.setChildren(this.getChildren(d, list)))
.collect(Collectors.toList());
......@@ -134,6 +135,11 @@ public class DeptServiceImpl implements DeptService {
@Override
@Transactional(rollbackFor = Exception.class)
public Long create(CreateDeptRequest request) {
String deptName = request.getDeptName();
boolean isExist = this.checkDeptNameExist(deptName, request.getParentId(), null);
CheckUtils.throwIf(() -> isExist, String.format("新增失败,'%s'已存在", deptName));
// 保存部门信息
SysDept sysDept = BeanUtil.copyProperties(request, SysDept.class);
sysDept.setStatus(DisEnableStatusEnum.ENABLE);
deptMapper.insert(sysDept);
......
......@@ -30,15 +30,16 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.StrUtil;
import top.charles7c.cnadmin.common.config.properties.LocalStorageProperties;
import top.charles7c.cnadmin.common.consts.FileConstants;
import top.charles7c.cnadmin.common.model.dto.LoginUser;
import top.charles7c.cnadmin.common.util.FileUtils;
import top.charles7c.cnadmin.common.util.SecureUtils;
import top.charles7c.cnadmin.common.util.helper.LoginHelper;
import top.charles7c.cnadmin.common.util.validate.CheckUtils;
import top.charles7c.cnadmin.common.util.validate.ValidationUtils;
import top.charles7c.cnadmin.system.mapper.UserMapper;
import top.charles7c.cnadmin.system.model.entity.SysUser;
import top.charles7c.cnadmin.system.service.UserService;
......@@ -64,6 +65,14 @@ public class UserServiceImpl implements UserService {
@Override
@Transactional(rollbackFor = Exception.class)
public String uploadAvatar(MultipartFile avatarFile, Long userId) {
Long avatarMaxSizeInMb = localStorageProperties.getAvatarMaxSizeInMb();
CheckUtils.throwIf(() -> avatarFile.getSize() > avatarMaxSizeInMb * 1024 * 1024,
String.format("请上传小于 %s MB 的图片", avatarMaxSizeInMb));
String avatarImageType = FileNameUtil.extName(avatarFile.getOriginalFilename());
String[] avatarSupportImgTypes = FileConstants.AVATAR_SUPPORTED_IMG_TYPES;
CheckUtils.throwIf(() -> !StrUtil.equalsAnyIgnoreCase(avatarImageType, avatarSupportImgTypes),
String.format("头像仅支持 %s 格式的图片", String.join(",", avatarSupportImgTypes)));
// 上传新头像
String avatarPath = localStorageProperties.getPath().getAvatar();
File newAvatarFile = FileUtils.upload(avatarFile, avatarPath, false);
......@@ -103,8 +112,9 @@ public class UserServiceImpl implements UserService {
@Override
@Transactional(rollbackFor = Exception.class)
public void updatePassword(String oldPassword, String newPassword, Long userId) {
CheckUtils.throwIfEqual(newPassword, oldPassword, "新密码不能与当前密码相同");
SysUser sysUser = this.getById(userId);
ValidationUtils.throwIfNotEqual(SecureUtils.md5Salt(oldPassword, userId.toString()), sysUser.getPassword(),
CheckUtils.throwIfNotEqual(SecureUtils.md5Salt(oldPassword, userId.toString()), sysUser.getPassword(),
"当前密码错误");
// 更新密码和密码重置时间
......@@ -123,13 +133,12 @@ public class UserServiceImpl implements UserService {
@Override
@Transactional(rollbackFor = Exception.class)
public void updateEmail(String newEmail, String currentPassword, Long userId) {
// 校验
SysUser sysUser = this.getById(userId);
ValidationUtils.throwIfNotEqual(SecureUtils.md5Salt(currentPassword, userId.toString()), sysUser.getPassword(),
CheckUtils.throwIfNotEqual(SecureUtils.md5Salt(currentPassword, userId.toString()), sysUser.getPassword(),
"当前密码错误");
Long count = userMapper.selectCount(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getEmail, newEmail));
ValidationUtils.throwIf(() -> count > 0, "邮箱已绑定其他账号,请更换其他邮箱");
ValidationUtils.throwIfEqual(newEmail, sysUser.getEmail(), "新邮箱不能与当前邮箱相同");
CheckUtils.throwIf(() -> count > 0, "邮箱已绑定其他账号,请更换其他邮箱");
CheckUtils.throwIfEqual(newEmail, sysUser.getEmail(), "新邮箱不能与当前邮箱相同");
// 更新邮箱
userMapper.update(null,
......@@ -143,9 +152,8 @@ public class UserServiceImpl implements UserService {
@Override
public SysUser getById(Long userId) {
ValidationUtils.throwIfNull(userId, "用户不存在");
SysUser sysUser = userMapper.selectById(userId);
ValidationUtils.throwIfNull(sysUser, String.format("ID为 [%s] 的用户已不存在", userId));
CheckUtils.throwIfNull(sysUser, String.format("ID为 [%s] 的用户已不存在", userId));
return sysUser;
}
}
......@@ -35,7 +35,6 @@ import top.charles7c.cnadmin.auth.model.request.LoginRequest;
import top.charles7c.cnadmin.auth.model.vo.LoginVO;
import top.charles7c.cnadmin.auth.model.vo.UserInfoVO;
import top.charles7c.cnadmin.auth.service.LoginService;
import top.charles7c.cnadmin.common.config.properties.CaptchaProperties;
import top.charles7c.cnadmin.common.consts.CacheConstants;
import top.charles7c.cnadmin.common.model.dto.LoginUser;
import top.charles7c.cnadmin.common.model.vo.R;
......@@ -58,7 +57,6 @@ import top.charles7c.cnadmin.common.util.validate.ValidationUtils;
public class LoginController {
private final LoginService loginService;
private final CaptchaProperties captchaProperties;
@SaIgnore
@Operation(summary = "用户登录", description = "根据用户名和密码进行登录认证")
......
......@@ -47,7 +47,7 @@ import top.charles7c.cnadmin.common.consts.CacheConstants;
import top.charles7c.cnadmin.common.model.vo.CaptchaVO;
import top.charles7c.cnadmin.common.model.vo.R;
import top.charles7c.cnadmin.common.util.*;
import top.charles7c.cnadmin.common.util.validate.ValidationUtils;
import top.charles7c.cnadmin.common.util.validate.CheckUtils;
/**
* 验证码 API
......@@ -89,12 +89,11 @@ public class CaptchaController {
public R getMailCaptcha(
@NotBlank(message = "邮箱不能为空") @Pattern(regexp = RegexPool.EMAIL, message = "邮箱格式错误") String email)
throws MessagingException {
// 校验
String limitCacheKey = CacheConstants.LIMIT_CACHE_KEY;
String captchaCacheKey = CacheConstants.CAPTCHA_CACHE_KEY;
String limitCaptchaKey = RedisUtils.formatKey(limitCacheKey, captchaCacheKey, email);
long limitTimeInMillisecond = RedisUtils.getTimeToLive(limitCaptchaKey);
ValidationUtils.throwIf(() -> limitTimeInMillisecond > 0,
CheckUtils.throwIf(() -> limitTimeInMillisecond > 0,
String.format("发送邮箱验证码过于频繁,请您 %ds 后再试", limitTimeInMillisecond / 1000));
// 生成验证码
......
......@@ -43,7 +43,6 @@ import top.charles7c.cnadmin.system.service.DeptService;
* @since 2023/1/22 21:48
*/
@Tag(name = "公共 API")
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping(value = "/common", produces = MediaType.APPLICATION_JSON_VALUE)
......@@ -51,7 +50,7 @@ public class CommonController {
private final DeptService deptService;
@Operation(summary = "查询部门树")
@Operation(summary = "查询部门树", description = "查询树结构的部门列表")
@GetMapping("/tree/dept")
public R<List<Tree<Long>>> deptTree(@Validated DeptQuery query) {
List<DeptVO> list = deptService.list(query);
......
......@@ -47,7 +47,6 @@ import top.charles7c.cnadmin.monitor.service.LogService;
* @since 2023/1/18 23:55
*/
@Tag(name = "日志管理 API")
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping(value = "/monitor/log", produces = MediaType.APPLICATION_JSON_VALUE)
......
......@@ -43,7 +43,7 @@ import top.charles7c.cnadmin.common.model.dto.LoginUser;
import top.charles7c.cnadmin.common.model.query.PageQuery;
import top.charles7c.cnadmin.common.model.vo.PageInfo;
import top.charles7c.cnadmin.common.model.vo.R;
import top.charles7c.cnadmin.common.util.validate.ValidationUtils;
import top.charles7c.cnadmin.common.util.validate.CheckUtils;
import top.charles7c.cnadmin.monitor.model.query.OnlineUserQuery;
import top.charles7c.cnadmin.monitor.model.vo.*;
......@@ -54,7 +54,6 @@ import top.charles7c.cnadmin.monitor.model.vo.*;
* @since 2023/1/20 21:51
*/
@Tag(name = "在线用户 API")
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping(value = "/monitor/online/user", produces = MediaType.APPLICATION_JSON_VALUE)
......@@ -67,7 +66,7 @@ public class OnlineUserController {
List<String> tokenKeyList = StpUtil.searchTokenValue("", 0, -1, false);
for (String tokenKey : tokenKeyList) {
String token = StrUtil.subAfter(tokenKey, ":", true);
// 忽略已过期或失效 token
// 忽略已过期或失效 Token
if (StpUtil.stpLogic.getTokenActivityTimeoutByToken(token) < SaTokenDao.NEVER_EXPIRE) {
continue;
}
......@@ -118,7 +117,7 @@ public class OnlineUserController {
@DeleteMapping("/{token}")
public R kickout(@PathVariable String token) {
String currentToken = StpUtil.getTokenValue();
ValidationUtils.throwIfEqual(token, currentToken, "不能强退当前登录");
CheckUtils.throwIfEqual(token, currentToken, "不能强退当前登录");
StpUtil.kickoutByTokenValue(token);
return R.ok("强退成功");
......
......@@ -43,7 +43,6 @@ import top.charles7c.cnadmin.system.service.DeptService;
* @since 2023/1/22 17:50
*/
@Tag(name = "部门管理 API")
@Validated
@RestController
@RequiredArgsConstructor
@RequestMapping(value = "/system/dept", produces = MediaType.APPLICATION_JSON_VALUE)
......@@ -61,17 +60,12 @@ public class DeptController {
@Operation(summary = "新增部门")
@PostMapping
public R<Long> create(@Validated @RequestBody CreateDeptRequest request) {
// 校验
String deptName = request.getDeptName();
boolean isExist = deptService.checkDeptNameExist(deptName, request.getParentId(), null);
if (isExist) {
return R.fail(String.format("新增失败,'%s'已存在", deptName));
}
return R.ok("新增成功", deptService.create(request));
Long id = deptService.create(request);
return R.ok("新增成功", id);
}
@Operation(summary = "修改部门状态")
@Parameter(name = "ids", description = "ID 列表", in = ParameterIn.PATH)
@PatchMapping("/{ids}")
public R updateStatus(@PathVariable List<Long> ids, @Validated @RequestBody UpdateStatusRequest request) {
deptService.updateStatus(ids, request.getStatus());
......
......@@ -29,13 +29,9 @@ import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import top.charles7c.cnadmin.common.config.properties.LocalStorageProperties;
import top.charles7c.cnadmin.common.consts.CacheConstants;
import top.charles7c.cnadmin.common.consts.FileConstants;
import top.charles7c.cnadmin.common.consts.RegExpConstants;
import top.charles7c.cnadmin.common.model.vo.R;
import top.charles7c.cnadmin.common.util.ExceptionUtils;
......@@ -64,20 +60,11 @@ import top.charles7c.cnadmin.system.service.UserService;
public class UserCenterController {
private final UserService userService;
private final LocalStorageProperties localStorageProperties;
@Operation(summary = "上传头像", description = "用户上传个人头像")
@PostMapping("/avatar")
public R<AvatarVO> uploadAvatar(@NotNull(message = "头像不能为空") MultipartFile avatarFile) {
// 校验
ValidationUtils.throwIf(avatarFile::isEmpty, "头像不能为空");
Long avatarMaxSizeInMb = localStorageProperties.getAvatarMaxSizeInMb();
ValidationUtils.throwIf(() -> avatarFile.getSize() > avatarMaxSizeInMb * 1024 * 1024,
String.format("请上传小于 %s MB 的图片", avatarMaxSizeInMb));
String avatarImageType = FileNameUtil.extName(avatarFile.getOriginalFilename());
String[] avatarSupportImgTypes = FileConstants.AVATAR_SUPPORTED_IMG_TYPES;
ValidationUtils.throwIf(() -> !StrUtil.equalsAnyIgnoreCase(avatarImageType, avatarSupportImgTypes),
String.format("头像仅支持 %s 格式的图片", String.join(",", avatarSupportImgTypes)));
// 上传头像
String newAvatar = userService.uploadAvatar(avatarFile, LoginHelper.getUserId());
......@@ -97,18 +84,14 @@ public class UserCenterController {
@Operation(summary = "修改密码", description = "修改用户登录密码")
@PatchMapping("/password")
public R updatePassword(@Validated @RequestBody UpdatePasswordRequest updatePasswordRequest) {
// 解密
String rawOldPassword =
ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(updatePasswordRequest.getOldPassword()));
ValidationUtils.throwIfBlank(rawOldPassword, "当前密码解密失败");
String rawNewPassword =
ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(updatePasswordRequest.getNewPassword()));
ValidationUtils.throwIfBlank(rawNewPassword, "新密码解密失败");
// 校验
ValidationUtils.throwIf(() -> !ReUtil.isMatch(RegExpConstants.PASSWORD, rawNewPassword),
"密码长度 6 到 32 位,同时包含数字和字母");
ValidationUtils.throwIfEqual(rawNewPassword, rawOldPassword, "新密码不能与当前密码相同");
// 修改密码
userService.updatePassword(rawOldPassword, rawNewPassword, LoginHelper.getUserId());
......@@ -118,12 +101,11 @@ public class UserCenterController {
@Operation(summary = "修改邮箱", description = "修改用户邮箱")
@PatchMapping("/email")
public R updateEmail(@Validated @RequestBody UpdateEmailRequest updateEmailRequest) {
// 解密
String rawCurrentPassword =
ExceptionUtils.exToNull(() -> SecureUtils.decryptByRsaPrivateKey(updateEmailRequest.getCurrentPassword()));
ValidationUtils.throwIfBlank(rawCurrentPassword, "当前密码解密失败");
// 校验
// 校验验证码
String captchaKey = RedisUtils.formatKey(CacheConstants.CAPTCHA_CACHE_KEY, updateEmailRequest.getNewEmail());
String captcha = RedisUtils.getCacheObject(captchaKey);
ValidationUtils.throwIfBlank(captcha, "验证码已失效");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册