feat: 优化登录功能;
删除不用的函数和冗余代码,将用户业务功能放在service下;Minio更名为MinioService将业务类和服务类拆分
This commit is contained in:
parent
a1e85e65f9
commit
0570ddd249
|
@ -3,7 +3,7 @@ package cn.bunny.services.aop;
|
||||||
import cn.bunny.services.domain.common.constant.LocalDateTimeConstant;
|
import cn.bunny.services.domain.common.constant.LocalDateTimeConstant;
|
||||||
import cn.bunny.services.domain.common.enums.JobEnums;
|
import cn.bunny.services.domain.common.enums.JobEnums;
|
||||||
import cn.bunny.services.domain.system.log.entity.ScheduleExecuteLog;
|
import cn.bunny.services.domain.system.log.entity.ScheduleExecuteLog;
|
||||||
import cn.bunny.services.domain.common.model.dto.quartz.ScheduleExecuteLogJson;
|
import cn.bunny.services.domain.common.quartz.ScheduleExecuteLogJson;
|
||||||
import cn.bunny.services.mapper.log.ScheduleExecuteLogMapper;
|
import cn.bunny.services.mapper.log.ScheduleExecuteLogMapper;
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
|
|
|
@ -1,16 +1,15 @@
|
||||||
package cn.bunny.services.controller.system;
|
package cn.bunny.services.controller.system;
|
||||||
|
|
||||||
import cn.bunny.services.context.BaseContext;
|
|
||||||
import cn.bunny.services.domain.common.model.vo.LoginVo;
|
|
||||||
import cn.bunny.services.domain.common.model.vo.result.PageResult;
|
import cn.bunny.services.domain.common.model.vo.result.PageResult;
|
||||||
import cn.bunny.services.domain.common.model.vo.result.Result;
|
import cn.bunny.services.domain.common.model.vo.result.Result;
|
||||||
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
||||||
import cn.bunny.services.domain.system.system.dto.user.*;
|
import cn.bunny.services.domain.system.system.dto.user.AdminUserAddDto;
|
||||||
|
import cn.bunny.services.domain.system.system.dto.user.AdminUserDto;
|
||||||
|
import cn.bunny.services.domain.system.system.dto.user.AdminUserUpdateByLocalUserDto;
|
||||||
|
import cn.bunny.services.domain.system.system.dto.user.AdminUserUpdateDto;
|
||||||
import cn.bunny.services.domain.system.system.entity.AdminUser;
|
import cn.bunny.services.domain.system.system.entity.AdminUser;
|
||||||
import cn.bunny.services.domain.system.system.vo.user.AdminUserVo;
|
import cn.bunny.services.domain.system.system.vo.user.AdminUserVo;
|
||||||
import cn.bunny.services.domain.system.system.vo.user.RefreshTokenVo;
|
|
||||||
import cn.bunny.services.domain.system.system.vo.user.UserVo;
|
import cn.bunny.services.domain.system.system.vo.user.UserVo;
|
||||||
import cn.bunny.services.exception.AuthCustomerException;
|
|
||||||
import cn.bunny.services.service.system.UserService;
|
import cn.bunny.services.service.system.UserService;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
@ -18,7 +17,6 @@ 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;
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
@ -33,49 +31,6 @@ public class UserController {
|
||||||
@Resource
|
@Resource
|
||||||
private UserService userService;
|
private UserService userService;
|
||||||
|
|
||||||
// -----------------------------------------
|
|
||||||
// 用户登录和退出
|
|
||||||
// -----------------------------------------
|
|
||||||
@Operation(summary = "用户登录", description = "前端用户登录")
|
|
||||||
@PostMapping("login")
|
|
||||||
public Result<LoginVo> login(@Valid @RequestBody LoginDto loginDto) {
|
|
||||||
LoginVo loginVo = userService.login(loginDto);
|
|
||||||
return Result.success(loginVo);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Operation(summary = "登录发送邮件验证码", description = "登录发送邮件验证码")
|
|
||||||
@PostMapping("public/sendLoginEmail")
|
|
||||||
public Result<String> sendLoginEmail(String email) {
|
|
||||||
if (!StringUtils.hasText(email)) throw new AuthCustomerException(ResultCodeEnum.REQUEST_IS_EMPTY);
|
|
||||||
|
|
||||||
userService.sendLoginEmail(email);
|
|
||||||
return Result.success(ResultCodeEnum.EMAIL_CODE_SEND_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Operation(summary = "刷新token", description = "刷新用户token")
|
|
||||||
@PostMapping("private/refreshToken")
|
|
||||||
public Result<RefreshTokenVo> refreshToken(@Valid @RequestBody RefreshTokenDto dto) {
|
|
||||||
RefreshTokenVo vo = userService.refreshToken(dto);
|
|
||||||
return Result.success(vo);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Operation(summary = "获取本地登录用户信息", description = "获取用户信息从Redis中获取")
|
|
||||||
@GetMapping("private/userinfo")
|
|
||||||
public Result<LoginVo> userinfo() {
|
|
||||||
LoginVo vo = BaseContext.getLoginVo();
|
|
||||||
return Result.success(vo);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Operation(summary = "退出登录", description = "退出登录")
|
|
||||||
@PostMapping("private/logout")
|
|
||||||
public Result<String> logout() {
|
|
||||||
userService.logout();
|
|
||||||
return Result.success(ResultCodeEnum.LOGOUT_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------
|
|
||||||
// 管理用户CURD
|
|
||||||
// -----------------------------------------
|
|
||||||
@Operation(summary = "分页查询", description = "分页查询用户信息", tags = "user::query")
|
@Operation(summary = "分页查询", description = "分页查询用户信息", tags = "user::query")
|
||||||
@GetMapping("{page}/{limit}")
|
@GetMapping("{page}/{limit}")
|
||||||
public Result<PageResult<AdminUserVo>> getUserPageByAdmin(
|
public Result<PageResult<AdminUserVo>> getUserPageByAdmin(
|
||||||
|
@ -89,21 +44,19 @@ public class UserController {
|
||||||
return Result.success(pageResult);
|
return Result.success(pageResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(summary = "添加", description = "添加用户信息", tags = "user::add")
|
@Operation(summary = "添加用户", description = "添加用户信息", tags = "user::add")
|
||||||
@PostMapping()
|
@PostMapping()
|
||||||
public Result<Object> addUserByAdmin(@Valid @RequestBody AdminUserAddDto dto) {
|
public Result<Object> addUserByAdmin(@Valid @RequestBody AdminUserAddDto dto) {
|
||||||
userService.addUserByAdmin(dto);
|
userService.addUserByAdmin(dto);
|
||||||
return Result.success(ResultCodeEnum.ADD_SUCCESS);
|
return Result.success(ResultCodeEnum.ADD_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(summary = "更新", description = "更新用户信息,需要更新Redis中的内容", tags = "user::update")
|
@Operation(summary = "更新用户", description = "更新用户信息,需要更新Redis中的内容", tags = "user::update")
|
||||||
@PutMapping()
|
@PutMapping()
|
||||||
public Result<String> updateUserByAdmin(
|
public Result<String> updateUserByAdmin(@Valid AdminUserUpdateDto dto,
|
||||||
@Valid AdminUserUpdateDto dto,
|
@RequestPart(value = "avatar", required = false) MultipartFile avatar) {
|
||||||
@RequestPart(value = "avatar", required = false) MultipartFile avatar) {
|
if (avatar != null) dto.setAvatar(avatar);
|
||||||
if (avatar != null) {
|
|
||||||
dto.setAvatar(avatar);
|
|
||||||
}
|
|
||||||
userService.updateUserByAdmin(dto);
|
userService.updateUserByAdmin(dto);
|
||||||
return Result.success(ResultCodeEnum.UPDATE_SUCCESS);
|
return Result.success(ResultCodeEnum.UPDATE_SUCCESS);
|
||||||
}
|
}
|
||||||
|
@ -129,16 +82,13 @@ public class UserController {
|
||||||
return Result.success(voList);
|
return Result.success(voList);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(summary = "强制退出", description = "强制退出", tags = "user::update")
|
@Operation(summary = "强制退出用户", description = "强制退出", tags = "user::update")
|
||||||
@PutMapping("forcedOffline")
|
@PutMapping("forcedOffline")
|
||||||
public Result<String> forcedOfflineByAdmin(@RequestBody Long id) {
|
public Result<String> forcedOfflineByAdmin(@RequestBody Long id) {
|
||||||
userService.forcedOfflineByAdmin(id);
|
userService.forcedOfflineByAdmin(id);
|
||||||
return Result.success();
|
return Result.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------
|
|
||||||
// 普通用户
|
|
||||||
// -----------------------------------------
|
|
||||||
@Operation(summary = "更新本地用户信息", description = "更新本地用户信息,需要更新Redis中的内容")
|
@Operation(summary = "更新本地用户信息", description = "更新本地用户信息,需要更新Redis中的内容")
|
||||||
@PutMapping("private/update/userinfo")
|
@PutMapping("private/update/userinfo")
|
||||||
public Result<String> updateAdminUserByLocalUser(@Valid @RequestBody AdminUserUpdateByLocalUserDto dto) {
|
public Result<String> updateAdminUserByLocalUser(@Valid @RequestBody AdminUserUpdateByLocalUserDto dto) {
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
package cn.bunny.services.controller.system;
|
||||||
|
|
||||||
|
import cn.bunny.services.context.BaseContext;
|
||||||
|
import cn.bunny.services.domain.common.model.vo.LoginVo;
|
||||||
|
import cn.bunny.services.domain.common.model.vo.result.Result;
|
||||||
|
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
||||||
|
import cn.bunny.services.domain.system.system.dto.user.LoginDto;
|
||||||
|
import cn.bunny.services.domain.system.system.dto.user.RefreshTokenDto;
|
||||||
|
import cn.bunny.services.domain.system.system.vo.user.RefreshTokenVo;
|
||||||
|
import cn.bunny.services.exception.AuthCustomerException;
|
||||||
|
import cn.bunny.services.service.system.UserLoginService;
|
||||||
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
@Tag(name = "用户登录", description = "用户登录相关接口")
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/user")
|
||||||
|
public class UserLoginController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private UserLoginService userLoginService;
|
||||||
|
|
||||||
|
@Operation(summary = "用户登录", description = "前端用户登录")
|
||||||
|
@PostMapping("login")
|
||||||
|
public Result<LoginVo> login(@Valid @RequestBody LoginDto loginDto) {
|
||||||
|
LoginVo loginVo = userLoginService.login(loginDto);
|
||||||
|
return Result.success(loginVo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "登录发送邮件验证码", description = "登录发送邮件验证码")
|
||||||
|
@PostMapping("public/sendLoginEmail")
|
||||||
|
public Result<String> sendLoginEmail(String email) {
|
||||||
|
if (!StringUtils.hasText(email)) throw new AuthCustomerException(ResultCodeEnum.REQUEST_IS_EMPTY);
|
||||||
|
|
||||||
|
userLoginService.sendLoginEmail(email);
|
||||||
|
return Result.success(ResultCodeEnum.EMAIL_CODE_SEND_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "刷新token", description = "刷新用户token")
|
||||||
|
@PostMapping("private/refreshToken")
|
||||||
|
public Result<RefreshTokenVo> refreshToken(@Valid @RequestBody RefreshTokenDto dto) {
|
||||||
|
RefreshTokenVo vo = userLoginService.refreshToken(dto);
|
||||||
|
return Result.success(vo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "获取本地登录用户信息", description = "获取用户信息从Redis中获取")
|
||||||
|
@GetMapping("private/userinfo")
|
||||||
|
public Result<LoginVo> userinfo() {
|
||||||
|
LoginVo vo = BaseContext.getLoginVo();
|
||||||
|
return Result.success(vo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "退出登录", description = "退出登录")
|
||||||
|
@PostMapping("private/logout")
|
||||||
|
public Result<String> logout() {
|
||||||
|
userLoginService.logout();
|
||||||
|
return Result.success(ResultCodeEnum.LOGOUT_SUCCESS);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
public abstract class AbstractPermissionCheckHandler {
|
||||||
|
|
||||||
|
private AbstractPermissionCheckHandler abstractPermissionCheckHandler;
|
||||||
|
|
||||||
|
public AbstractPermissionCheckHandler(AbstractPermissionCheckHandler abstractPermissionCheckHandler) {
|
||||||
|
this.abstractPermissionCheckHandler = abstractPermissionCheckHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract protected void checkPermission(String requestUrl);
|
||||||
|
}
|
|
@ -8,20 +8,20 @@ import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
@TestConfiguration
|
// @TestConfiguration
|
||||||
public class WebConfig {
|
// public class WebConfig {
|
||||||
@Value("${server.port}")
|
// @Value("${server.port}")
|
||||||
private String port;
|
// private String port;
|
||||||
|
//
|
||||||
@Autowired
|
// @Autowired
|
||||||
private TokenUtilsTest tokenUtils;
|
// private TokenUtilsTest tokenUtils;
|
||||||
|
//
|
||||||
@Bean
|
// @Bean
|
||||||
public RestTemplate restTemplate(RestTemplateBuilder builder) {
|
// public RestTemplate restTemplate(RestTemplateBuilder builder) {
|
||||||
String token = tokenUtils.getToken();
|
// String token = tokenUtils.getToken();
|
||||||
return builder.rootUri("http://localhost:" + port)
|
// return builder.rootUri("http://localhost:" + port)
|
||||||
.defaultHeader("token", token)
|
// .defaultHeader("token", token)
|
||||||
.defaultHeader("Content-Type", "application/json")
|
// .defaultHeader("Content-Type", "application/json")
|
||||||
.build();
|
// .build();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
package cn.bunny.services.controller.system;
|
||||||
|
|
||||||
|
import cn.bunny.services.domain.common.constant.RedisUserConstant;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.data.redis.core.Cursor;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.data.redis.core.ScanOptions;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
@SpringBootTest
|
||||||
|
class UserControllerTest {
|
||||||
|
@Resource
|
||||||
|
private RedisTemplate<String, Object> redisTemplate;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void test() {
|
||||||
|
// Set<String> keys = redisTemplate.keys("admin::login_info::*");
|
||||||
|
// for (String key : keys) {
|
||||||
|
// System.out.println(key);
|
||||||
|
// }
|
||||||
|
|
||||||
|
Map<String, Object> adminLoginInfoWithScan = getAdminLoginInfoWithScan();
|
||||||
|
JSONObject adminLoginInfo = new JSONObject(adminLoginInfoWithScan);
|
||||||
|
System.out.println(adminLoginInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Object> getAdminLoginInfoWithScan() {
|
||||||
|
String pattern = "admin::login_info::*";
|
||||||
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
|
||||||
|
// 使用scan命令迭代查找
|
||||||
|
ScanOptions options = ScanOptions.scanOptions().match(pattern).count(100).build();
|
||||||
|
Cursor<String> cursor = redisTemplate.scan(options);
|
||||||
|
|
||||||
|
while (cursor.hasNext()) {
|
||||||
|
String key = cursor.next();
|
||||||
|
Object value = redisTemplate.opsForValue().get(key);
|
||||||
|
result.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
cursor.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 处理异常
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,9 @@
|
||||||
package cn.bunny.services.utils;
|
package cn.bunny.services.utils;
|
||||||
|
|
||||||
import cn.bunny.services.domain.system.system.entity.AdminUser;
|
|
||||||
import cn.bunny.services.domain.common.model.vo.LoginVo;
|
import cn.bunny.services.domain.common.model.vo.LoginVo;
|
||||||
|
import cn.bunny.services.domain.system.system.entity.AdminUser;
|
||||||
import cn.bunny.services.mapper.system.UserMapper;
|
import cn.bunny.services.mapper.system.UserMapper;
|
||||||
import cn.bunny.services.utils.system.UserUtil;
|
import cn.bunny.services.service.system.helper.UserLoginHelper;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
@ -11,7 +11,7 @@ import org.springframework.stereotype.Component;
|
||||||
@Component
|
@Component
|
||||||
public class TokenUtilsTest {
|
public class TokenUtilsTest {
|
||||||
@Autowired
|
@Autowired
|
||||||
private UserUtil userUtil;
|
private UserLoginHelper userUtil;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private UserMapper userMapper;
|
private UserMapper userMapper;
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
package system;
|
||||||
|
|
||||||
|
import cn.bunny.services.controller.system.UserController;
|
||||||
|
import cn.bunny.services.domain.common.constant.RedisUserConstant;
|
||||||
|
import cn.bunny.services.service.system.impl.UserServiceImpl;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.data.redis.core.RedisConnectionUtils;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.test.context.web.WebAppConfiguration;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
@SpringBootTest(classes = UserServiceImpl.class)
|
||||||
|
class UserServiceTest {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RedisTemplate<String, Object> redisTemplate;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void test() {
|
||||||
|
String prefix = RedisUserConstant.getAdminUserEmailCodePrefix("");
|
||||||
|
Set<String> keys = redisTemplate.keys(prefix);
|
||||||
|
for (String key : keys) {
|
||||||
|
System.out.println(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,4 +6,7 @@ import lombok.Data;
|
||||||
public class UserConstant {
|
public class UserConstant {
|
||||||
public static final String USER_AVATAR = "https://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83eoj0hHXhgJNOTSOFsS4uZs8x1ConecaVOB8eIl115xmJZcT4oCicvia7wMEufibKtTLqiaJeanU2Lpg3w/132";
|
public static final String USER_AVATAR = "https://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83eoj0hHXhgJNOTSOFsS4uZs8x1ConecaVOB8eIl115xmJZcT4oCicvia7wMEufibKtTLqiaJeanU2Lpg3w/132";
|
||||||
public static final String PERSON_DESCRIPTION = "这个人很懒没有介绍...";
|
public static final String PERSON_DESCRIPTION = "这个人很懒没有介绍...";
|
||||||
|
public static final String LOGIN = "login";
|
||||||
|
public static final String LOGOUT = "logout";
|
||||||
|
public static final String FORCE_LOGOUT = "force_logout";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package cn.bunny.services.domain.common.model.dto.ip;
|
package cn.bunny.services.domain.common.ip;
|
||||||
|
|
||||||
import io.swagger.annotations.ApiModel;
|
import io.swagger.annotations.ApiModel;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
|
@ -1,4 +1,4 @@
|
||||||
package cn.bunny.services.domain.common.model.dto.quartz;
|
package cn.bunny.services.domain.common.quartz;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
|
@ -1,4 +1,4 @@
|
||||||
package cn.bunny.services.domain.common.model.dto.security;
|
package cn.bunny.services.domain.common.security;
|
||||||
|
|
||||||
import cn.bunny.services.domain.common.model.vo.LoginVo;
|
import cn.bunny.services.domain.common.model.vo.LoginVo;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
|
@ -1,4 +1,4 @@
|
||||||
package cn.bunny.services.config.mail;
|
package cn.bunny.services.mail;
|
||||||
|
|
||||||
import cn.bunny.services.domain.common.model.dto.email.EmailSend;
|
import cn.bunny.services.domain.common.model.dto.email.EmailSend;
|
||||||
import cn.bunny.services.domain.common.model.dto.email.EmailSendInit;
|
import cn.bunny.services.domain.common.model.dto.email.EmailSendInit;
|
|
@ -0,0 +1,111 @@
|
||||||
|
package cn.bunny.services.minio;
|
||||||
|
|
||||||
|
import cn.bunny.services.domain.common.constant.UserConstant;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.regex.PatternSyntaxException;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class MinioHelper {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private MinioProperties properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化用户头像URL
|
||||||
|
*
|
||||||
|
* <p>实现头像URL的统一存储和访问格式转换:</p>
|
||||||
|
*
|
||||||
|
* <ol>
|
||||||
|
* <li><b>存储处理</b>:将带HTTP前缀的头像URL转换为数据库存储格式
|
||||||
|
* <ul>
|
||||||
|
* <li>匹配正则表达式:^https?://.*?/(.*)</li>
|
||||||
|
* <li>提取路径部分:matcher.group(1)</li>
|
||||||
|
* <li>转换为存储格式:"/" + 提取的路径</li>
|
||||||
|
* </ul>
|
||||||
|
* </li>
|
||||||
|
* <li><b>访问处理</b>:返回带HTTP前缀的完整访问URL</li>
|
||||||
|
* </ol>
|
||||||
|
*
|
||||||
|
* <p>典型用例:</p>
|
||||||
|
* <pre>
|
||||||
|
* 输入:"http|s://example.com/images/avatar.jpg"
|
||||||
|
* 存储:"images/avatar.jpg"
|
||||||
|
* 访问:"http|s://xxx/images/avatar.jpg"
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param avatar 头像URL(可能包含HTTP前缀或数据库存储格式)
|
||||||
|
* @return 格式化后的头像URL(确保包含HTTP前缀)
|
||||||
|
* @throws PatternSyntaxException 当正则表达式匹配失败时抛出
|
||||||
|
* @throws IllegalArgumentException 当头像参数为空时抛出
|
||||||
|
*/
|
||||||
|
public String formatUserAvatar(String avatar) {
|
||||||
|
// 如果用户没有头像或者用户头像和默认头像相同,返回默认头像
|
||||||
|
String userAvatar = UserConstant.USER_AVATAR;
|
||||||
|
if (!StringUtils.hasText(avatar) || avatar.equals(userAvatar)) return userAvatar;
|
||||||
|
|
||||||
|
// 替换前端发送的host前缀,将其删除,只保留路径名称
|
||||||
|
String regex = "^https?://.*?/(.*)";
|
||||||
|
Pattern pattern = Pattern.compile(regex);
|
||||||
|
Matcher matcher = pattern.matcher(avatar);
|
||||||
|
|
||||||
|
// 如果没有匹配
|
||||||
|
if (!matcher.matches()) return avatar;
|
||||||
|
|
||||||
|
// 匹配后返回内容
|
||||||
|
return "/" + matcher.group(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查并格式化用户头像URL
|
||||||
|
*
|
||||||
|
* <p>处理逻辑:</p>
|
||||||
|
* <ol>
|
||||||
|
* <li>当头像为空或与默认头像相同时,返回系统默认头像</li>
|
||||||
|
* <li>尝试移除头像URL中的HTTP协议和域名部分(如果存在)</li>
|
||||||
|
* <li>最终返回MinIO存储中的完整对象访问路径</li>
|
||||||
|
* </ol>
|
||||||
|
*
|
||||||
|
* @param avatar 用户头像URL,可能为以下格式:
|
||||||
|
* - 空/null(使用默认头像)
|
||||||
|
* - 完整HTTP URL(如"http|s://example.com/images/1.jpg")
|
||||||
|
* - MinIO对象路径(如"images/1.jpg")
|
||||||
|
* @return 格式化后的头像URL,保证是可访问的完整路径
|
||||||
|
* - 默认头像(当输入无效时)
|
||||||
|
* - MinIO完整访问路径(处理成功时)
|
||||||
|
* @see UserConstant#USER_AVATAR 默认头像常量
|
||||||
|
* @see #getObjectNameFullPath MinIO路径处理方法
|
||||||
|
*/
|
||||||
|
public String getUserAvatar(String avatar) {
|
||||||
|
// 如果用户没有头像或者用户头像和默认头像相同,返回默认头像
|
||||||
|
String userAvatar = UserConstant.USER_AVATAR;
|
||||||
|
if (!StringUtils.hasText(avatar) || avatar.equals(userAvatar)) return userAvatar;
|
||||||
|
|
||||||
|
// 替换前端发送的host前缀,将其删除,只保留路径名称
|
||||||
|
String regex = "^https?://.*?/(.*)";
|
||||||
|
Pattern pattern = Pattern.compile(regex);
|
||||||
|
Matcher matcher = pattern.matcher(avatar);
|
||||||
|
|
||||||
|
// 如果没有匹配
|
||||||
|
if (matcher.matches()) return avatar;
|
||||||
|
|
||||||
|
// 匹配后返回内容
|
||||||
|
return getObjectNameFullPath(avatar);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Minio全路径名,Object带有桶名称
|
||||||
|
*
|
||||||
|
* @param objectName 对象名称
|
||||||
|
* @return 全路径
|
||||||
|
*/
|
||||||
|
public String getObjectNameFullPath(String objectName) {
|
||||||
|
String url = properties.getEndpointUrl();
|
||||||
|
|
||||||
|
return url + objectName;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package cn.bunny.services.config.minio;
|
package cn.bunny.services.minio;
|
||||||
|
|
||||||
import io.minio.BucketExistsArgs;
|
import io.minio.BucketExistsArgs;
|
||||||
import io.minio.MakeBucketArgs;
|
import io.minio.MakeBucketArgs;
|
|
@ -1,14 +1,15 @@
|
||||||
package cn.bunny.services.config.minio;
|
package cn.bunny.services.minio;
|
||||||
|
|
||||||
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
|
||||||
import cn.bunny.services.domain.common.constant.MinioConstant;
|
import cn.bunny.services.domain.common.constant.MinioConstant;
|
||||||
import cn.bunny.services.domain.common.model.dto.file.MinioFilePath;
|
import cn.bunny.services.domain.common.model.dto.file.MinioFilePath;
|
||||||
|
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
||||||
import cn.bunny.services.exception.AuthCustomerException;
|
import cn.bunny.services.exception.AuthCustomerException;
|
||||||
import io.minio.*;
|
import io.minio.*;
|
||||||
import io.minio.messages.DeleteError;
|
import io.minio.messages.DeleteError;
|
||||||
import io.minio.messages.DeleteObject;
|
import io.minio.messages.DeleteObject;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
@ -23,17 +24,14 @@ import java.util.UUID;
|
||||||
* Minio操作工具类 简化操作步骤
|
* Minio操作工具类 简化操作步骤
|
||||||
* 自定义封装
|
* 自定义封装
|
||||||
*/
|
*/
|
||||||
@Component
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class MinioUtil {
|
@Service
|
||||||
private final MinioProperties properties;
|
public class MinioService {
|
||||||
|
@Resource
|
||||||
|
private MinioProperties properties;
|
||||||
|
|
||||||
private final MinioClient minioClient;
|
@Resource
|
||||||
|
private MinioClient minioClient;
|
||||||
public MinioUtil(MinioProperties properties, MinioClient minioClient) {
|
|
||||||
this.properties = properties;
|
|
||||||
this.minioClient = minioClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取Minio文件路径
|
* 获取Minio文件路径
|
||||||
|
@ -112,18 +110,6 @@ public class MinioUtil {
|
||||||
throw new AuthCustomerException(ResultCodeEnum.GET_BUCKET_EXCEPTION);
|
throw new AuthCustomerException(ResultCodeEnum.GET_BUCKET_EXCEPTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取Minio全路径名,Object带有桶名称
|
|
||||||
*
|
|
||||||
* @param objectName 对象名称
|
|
||||||
* @return 全路径
|
|
||||||
*/
|
|
||||||
public String getObjectNameFullPath(String objectName) {
|
|
||||||
String url = properties.getEndpointUrl();
|
|
||||||
|
|
||||||
return url + objectName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上传文件
|
* 上传文件
|
||||||
*
|
*
|
||||||
|
@ -211,4 +197,5 @@ public class MinioUtil {
|
||||||
throw new AuthCustomerException("创建失败");
|
throw new AuthCustomerException("创建失败");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
package cn.bunny.services.utils;
|
package cn.bunny.services.utils;
|
||||||
|
|
||||||
import cn.bunny.services.domain.common.model.dto.ip.IpEntity;
|
import cn.bunny.services.domain.common.ip.IpEntity;
|
||||||
import jakarta.annotation.PostConstruct;
|
import jakarta.annotation.PostConstruct;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package cn.bunny.services.security.service;
|
package cn.bunny.services.security.service;
|
||||||
|
|
||||||
import cn.bunny.services.context.BaseContext;
|
import cn.bunny.services.context.BaseContext;
|
||||||
import cn.bunny.services.domain.common.model.dto.security.TokenInfo;
|
import cn.bunny.services.domain.common.security.TokenInfo;
|
||||||
import cn.bunny.services.domain.common.model.vo.LoginVo;
|
import cn.bunny.services.domain.common.model.vo.LoginVo;
|
||||||
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
||||||
import cn.bunny.services.security.exception.CustomAuthenticationException;
|
import cn.bunny.services.security.exception.CustomAuthenticationException;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package cn.bunny.services.security.service;
|
package cn.bunny.services.security.service;
|
||||||
|
|
||||||
import cn.bunny.services.domain.common.constant.RedisUserConstant;
|
import cn.bunny.services.domain.common.constant.RedisUserConstant;
|
||||||
import cn.bunny.services.domain.common.model.dto.security.TokenInfo;
|
import cn.bunny.services.domain.common.security.TokenInfo;
|
||||||
import cn.bunny.services.domain.common.model.vo.LoginVo;
|
import cn.bunny.services.domain.common.model.vo.LoginVo;
|
||||||
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
||||||
import cn.bunny.services.security.exception.CustomAuthenticationException;
|
import cn.bunny.services.security.exception.CustomAuthenticationException;
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package cn.bunny.services.service.message.impl;
|
package cn.bunny.services.service.message.impl;
|
||||||
|
|
||||||
|
import cn.bunny.services.context.BaseContext;
|
||||||
|
import cn.bunny.services.domain.common.model.vo.result.PageResult;
|
||||||
|
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
||||||
import cn.bunny.services.domain.system.message.dto.MessageReceivedDto;
|
import cn.bunny.services.domain.system.message.dto.MessageReceivedDto;
|
||||||
import cn.bunny.services.domain.system.message.dto.MessageReceivedUpdateDto;
|
import cn.bunny.services.domain.system.message.dto.MessageReceivedUpdateDto;
|
||||||
import cn.bunny.services.domain.system.message.dto.MessageUserDto;
|
import cn.bunny.services.domain.system.message.dto.MessageUserDto;
|
||||||
|
@ -7,13 +10,10 @@ import cn.bunny.services.domain.system.message.entity.Message;
|
||||||
import cn.bunny.services.domain.system.message.entity.MessageReceived;
|
import cn.bunny.services.domain.system.message.entity.MessageReceived;
|
||||||
import cn.bunny.services.domain.system.message.vo.MessageReceivedWithMessageVo;
|
import cn.bunny.services.domain.system.message.vo.MessageReceivedWithMessageVo;
|
||||||
import cn.bunny.services.domain.system.message.vo.MessageUserVo;
|
import cn.bunny.services.domain.system.message.vo.MessageUserVo;
|
||||||
import cn.bunny.services.domain.common.model.vo.result.PageResult;
|
|
||||||
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
|
||||||
import cn.bunny.services.context.BaseContext;
|
|
||||||
import cn.bunny.services.exception.AuthCustomerException;
|
import cn.bunny.services.exception.AuthCustomerException;
|
||||||
import cn.bunny.services.mapper.message.MessageReceivedMapper;
|
import cn.bunny.services.mapper.message.MessageReceivedMapper;
|
||||||
|
import cn.bunny.services.minio.MinioHelper;
|
||||||
import cn.bunny.services.service.message.MessageReceivedService;
|
import cn.bunny.services.service.message.MessageReceivedService;
|
||||||
import cn.bunny.services.utils.system.UserUtil;
|
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
@ -39,7 +39,7 @@ import java.util.List;
|
||||||
public class MessageReceivedServiceImpl extends ServiceImpl<MessageReceivedMapper, MessageReceived> implements MessageReceivedService {
|
public class MessageReceivedServiceImpl extends ServiceImpl<MessageReceivedMapper, MessageReceived> implements MessageReceivedService {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private UserUtil userUtil;
|
private MinioHelper minioHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 管理员管理用户消息接收分页查询
|
* 管理员管理用户消息接收分页查询
|
||||||
|
@ -58,7 +58,7 @@ public class MessageReceivedServiceImpl extends ServiceImpl<MessageReceivedMappe
|
||||||
|
|
||||||
// 设置封面返回内容
|
// 设置封面返回内容
|
||||||
String cover = vo.getCover();
|
String cover = vo.getCover();
|
||||||
cover = userUtil.checkGetUserAvatar(cover);
|
cover = minioHelper.getUserAvatar(cover);
|
||||||
vo.setCover(cover);
|
vo.setCover(cover);
|
||||||
return vo;
|
return vo;
|
||||||
}).toList();
|
}).toList();
|
||||||
|
@ -113,7 +113,7 @@ public class MessageReceivedServiceImpl extends ServiceImpl<MessageReceivedMappe
|
||||||
|
|
||||||
// 设置封面返回内容
|
// 设置封面返回内容
|
||||||
String cover = vo.getCover();
|
String cover = vo.getCover();
|
||||||
cover = userUtil.checkGetUserAvatar(cover);
|
cover = minioHelper.getUserAvatar(cover);
|
||||||
vo.setCover(cover);
|
vo.setCover(cover);
|
||||||
return vo;
|
return vo;
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package cn.bunny.services.service.message.impl;
|
package cn.bunny.services.service.message.impl;
|
||||||
|
|
||||||
|
import cn.bunny.services.context.BaseContext;
|
||||||
import cn.bunny.services.domain.common.model.entity.BaseEntity;
|
import cn.bunny.services.domain.common.model.entity.BaseEntity;
|
||||||
|
import cn.bunny.services.domain.common.model.vo.result.PageResult;
|
||||||
|
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
||||||
import cn.bunny.services.domain.system.message.dto.MessageAddDto;
|
import cn.bunny.services.domain.system.message.dto.MessageAddDto;
|
||||||
import cn.bunny.services.domain.system.message.dto.MessageDto;
|
import cn.bunny.services.domain.system.message.dto.MessageDto;
|
||||||
import cn.bunny.services.domain.system.message.dto.MessageUpdateDto;
|
import cn.bunny.services.domain.system.message.dto.MessageUpdateDto;
|
||||||
|
@ -10,16 +13,13 @@ import cn.bunny.services.domain.system.message.vo.MessageDetailVo;
|
||||||
import cn.bunny.services.domain.system.message.vo.MessageReceivedWithMessageVo;
|
import cn.bunny.services.domain.system.message.vo.MessageReceivedWithMessageVo;
|
||||||
import cn.bunny.services.domain.system.message.vo.MessageReceivedWithUserVo;
|
import cn.bunny.services.domain.system.message.vo.MessageReceivedWithUserVo;
|
||||||
import cn.bunny.services.domain.system.message.vo.MessageVo;
|
import cn.bunny.services.domain.system.message.vo.MessageVo;
|
||||||
import cn.bunny.services.domain.common.model.vo.result.PageResult;
|
|
||||||
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
|
||||||
import cn.bunny.services.context.BaseContext;
|
|
||||||
import cn.bunny.services.exception.AuthCustomerException;
|
import cn.bunny.services.exception.AuthCustomerException;
|
||||||
import cn.bunny.services.mapper.message.MessageMapper;
|
import cn.bunny.services.mapper.message.MessageMapper;
|
||||||
import cn.bunny.services.mapper.message.MessageReceivedMapper;
|
import cn.bunny.services.mapper.message.MessageReceivedMapper;
|
||||||
import cn.bunny.services.mapper.system.UserMapper;
|
import cn.bunny.services.mapper.system.UserMapper;
|
||||||
|
import cn.bunny.services.minio.MinioHelper;
|
||||||
import cn.bunny.services.service.message.MessageReceivedService;
|
import cn.bunny.services.service.message.MessageReceivedService;
|
||||||
import cn.bunny.services.service.message.MessageService;
|
import cn.bunny.services.service.message.MessageService;
|
||||||
import cn.bunny.services.utils.system.UserUtil;
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
|
@ -47,17 +47,14 @@ import java.util.stream.Collectors;
|
||||||
@Transactional
|
@Transactional
|
||||||
public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message> implements MessageService {
|
public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message> implements MessageService {
|
||||||
|
|
||||||
@Resource
|
|
||||||
private UserUtil userUtil;
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private MessageReceivedMapper messageReceivedMapper;
|
private MessageReceivedMapper messageReceivedMapper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private UserMapper userMapper;
|
private UserMapper userMapper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private MessageReceivedService messageReceivedService;
|
private MessageReceivedService messageReceivedService;
|
||||||
|
@Resource
|
||||||
|
private MinioHelper minioHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分页查询发送消息
|
* 分页查询发送消息
|
||||||
|
@ -152,7 +149,7 @@ public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message> impl
|
||||||
|
|
||||||
// 设置封面返回内容
|
// 设置封面返回内容
|
||||||
String cover = dto.getCover();
|
String cover = dto.getCover();
|
||||||
dto.setCover(userUtil.checkGetUserAvatar(cover));
|
dto.setCover(minioHelper.getUserAvatar(cover));
|
||||||
|
|
||||||
// 先保存消息数据,之后拿到保存消息的id
|
// 先保存消息数据,之后拿到保存消息的id
|
||||||
Message message = new Message();
|
Message message = new Message();
|
||||||
|
@ -198,7 +195,7 @@ public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message> impl
|
||||||
|
|
||||||
// 设置封面返回内容
|
// 设置封面返回内容
|
||||||
String cover = dto.getCover();
|
String cover = dto.getCover();
|
||||||
dto.setCover(userUtil.checkGetUserAvatar(cover));
|
dto.setCover(minioHelper.getUserAvatar(cover));
|
||||||
|
|
||||||
// 更新内容
|
// 更新内容
|
||||||
Message message = new Message();
|
Message message = new Message();
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
package cn.bunny.services.service.system;
|
||||||
|
|
||||||
|
import cn.bunny.services.domain.common.model.vo.LoginVo;
|
||||||
|
import cn.bunny.services.domain.system.system.dto.user.LoginDto;
|
||||||
|
import cn.bunny.services.domain.system.system.dto.user.RefreshTokenDto;
|
||||||
|
import cn.bunny.services.domain.system.system.entity.AdminUser;
|
||||||
|
import cn.bunny.services.domain.system.system.vo.user.RefreshTokenVo;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public interface UserLoginService extends IService<AdminUser> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 前台用户登录接口
|
||||||
|
*
|
||||||
|
* @param loginDto 登录参数
|
||||||
|
* @return 登录后结果返回
|
||||||
|
*/
|
||||||
|
LoginVo login(LoginDto loginDto);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录发送邮件验证码
|
||||||
|
*
|
||||||
|
* @param email 邮箱
|
||||||
|
*/
|
||||||
|
void sendLoginEmail(@NotNull String email);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新用户token
|
||||||
|
*
|
||||||
|
* @param dto 请求token
|
||||||
|
* @return 刷新token返回内容
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
RefreshTokenVo refreshToken(@NotNull RefreshTokenDto dto);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* * 退出登录
|
||||||
|
*/
|
||||||
|
void logout();
|
||||||
|
|
||||||
|
}
|
|
@ -1,16 +1,16 @@
|
||||||
package cn.bunny.services.service.system;
|
package cn.bunny.services.service.system;
|
||||||
|
|
||||||
import cn.bunny.services.domain.system.system.dto.user.*;
|
import cn.bunny.services.domain.common.model.vo.result.PageResult;
|
||||||
|
import cn.bunny.services.domain.system.system.dto.user.AdminUserAddDto;
|
||||||
|
import cn.bunny.services.domain.system.system.dto.user.AdminUserDto;
|
||||||
|
import cn.bunny.services.domain.system.system.dto.user.AdminUserUpdateByLocalUserDto;
|
||||||
|
import cn.bunny.services.domain.system.system.dto.user.AdminUserUpdateDto;
|
||||||
import cn.bunny.services.domain.system.system.entity.AdminUser;
|
import cn.bunny.services.domain.system.system.entity.AdminUser;
|
||||||
import cn.bunny.services.domain.system.system.vo.user.AdminUserVo;
|
import cn.bunny.services.domain.system.system.vo.user.AdminUserVo;
|
||||||
import cn.bunny.services.domain.system.system.vo.user.RefreshTokenVo;
|
|
||||||
import cn.bunny.services.domain.system.system.vo.user.UserVo;
|
import cn.bunny.services.domain.system.system.vo.user.UserVo;
|
||||||
import cn.bunny.services.domain.common.model.vo.LoginVo;
|
|
||||||
import cn.bunny.services.domain.common.model.vo.result.PageResult;
|
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -24,14 +24,6 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
public interface UserService extends IService<AdminUser> {
|
public interface UserService extends IService<AdminUser> {
|
||||||
|
|
||||||
/**
|
|
||||||
* 前台用户登录接口
|
|
||||||
*
|
|
||||||
* @param loginDto 登录参数
|
|
||||||
* @return 登录后结果返回
|
|
||||||
*/
|
|
||||||
LoginVo login(LoginDto loginDto);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* * 获取用户信息列表
|
* * 获取用户信息列表
|
||||||
*
|
*
|
||||||
|
@ -60,27 +52,6 @@ public interface UserService extends IService<AdminUser> {
|
||||||
*/
|
*/
|
||||||
void deleteUserByAdmin(List<Long> ids);
|
void deleteUserByAdmin(List<Long> ids);
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录发送邮件验证码
|
|
||||||
*
|
|
||||||
* @param email 邮箱
|
|
||||||
*/
|
|
||||||
void sendLoginEmail(@NotNull String email);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 刷新用户token
|
|
||||||
*
|
|
||||||
* @param dto 请求token
|
|
||||||
* @return 刷新token返回内容
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
RefreshTokenVo refreshToken(@NotNull RefreshTokenDto dto);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* * 退出登录
|
|
||||||
*/
|
|
||||||
void logout();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* * 获取用户信息
|
* * 获取用户信息
|
||||||
*
|
*
|
||||||
|
|
|
@ -0,0 +1,189 @@
|
||||||
|
package cn.bunny.services.service.system.helper;
|
||||||
|
|
||||||
|
import cn.bunny.services.domain.common.constant.LocalDateTimeConstant;
|
||||||
|
import cn.bunny.services.domain.common.constant.RedisUserConstant;
|
||||||
|
import cn.bunny.services.domain.common.constant.UserConstant;
|
||||||
|
import cn.bunny.services.domain.common.model.vo.LoginVo;
|
||||||
|
import cn.bunny.services.domain.system.log.entity.UserLoginLog;
|
||||||
|
import cn.bunny.services.domain.system.system.entity.AdminUser;
|
||||||
|
import cn.bunny.services.domain.system.system.entity.Permission;
|
||||||
|
import cn.bunny.services.domain.system.system.entity.Role;
|
||||||
|
import cn.bunny.services.mapper.log.UserLoginLogMapper;
|
||||||
|
import cn.bunny.services.mapper.system.PermissionMapper;
|
||||||
|
import cn.bunny.services.mapper.system.RoleMapper;
|
||||||
|
import cn.bunny.services.mapper.system.UserMapper;
|
||||||
|
import cn.bunny.services.minio.MinioHelper;
|
||||||
|
import cn.bunny.services.utils.IpUtil;
|
||||||
|
import cn.bunny.services.utils.JwtTokenUtil;
|
||||||
|
import cn.bunny.services.utils.system.RoleUtil;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@Transactional
|
||||||
|
public class UserLoginHelper {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RedisTemplate<String, Object> redisTemplate;
|
||||||
|
@Resource
|
||||||
|
private UserMapper userMapper;
|
||||||
|
@Resource
|
||||||
|
private UserLoginLogMapper userLoginLogMapper;
|
||||||
|
@Resource
|
||||||
|
private RoleMapper roleMapper;
|
||||||
|
@Resource
|
||||||
|
private PermissionMapper permissionMapper;
|
||||||
|
@Resource
|
||||||
|
private MinioHelper minioHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建用户登录返回对象(LoginVo)
|
||||||
|
*
|
||||||
|
* <p>主要处理流程:</p>
|
||||||
|
* <ol>
|
||||||
|
* <li><b>参数校验</b>:检查用户对象是否为空</li>
|
||||||
|
* <li><b>权限处理</b>:
|
||||||
|
* <ul>
|
||||||
|
* <li>查询用户角色和权限数据</li>
|
||||||
|
* <li>非管理员用户:从数据库加载权限信息</li>
|
||||||
|
* <li>管理员用户:通过RoleUtil.checkAdmin()自动设置管理员权限</li>
|
||||||
|
* <li>(可选)对角色和权限列表去重</li>
|
||||||
|
* </ul>
|
||||||
|
* </li>
|
||||||
|
* <li><b>信息装配</b>:
|
||||||
|
* <ul>
|
||||||
|
* <li>记录用户IP等访问信息</li>
|
||||||
|
* <li>使用BeanUtils.copyProperties()复制用户基础属性</li>
|
||||||
|
* <li>设置记住我功能及token过期时间</li>
|
||||||
|
* </ul>
|
||||||
|
* </li>
|
||||||
|
* <li><b>缓存处理</b>:将完整用户信息存入Redis</li>
|
||||||
|
* </ol>
|
||||||
|
*
|
||||||
|
* <p>注意事项:</p>
|
||||||
|
* <ul>
|
||||||
|
* <li>属性复制操作放在流程最后,确保所有字段正确同步</li>
|
||||||
|
* <li>IP信息需要同时更新到用户实体和返回对象</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @param user 用户实体对象(不可为空)
|
||||||
|
* @param readMeDay 记住我时长(单位:天)
|
||||||
|
* @return 完整的登录响应对象
|
||||||
|
* @throws IllegalArgumentException 当用户对象为空时抛出
|
||||||
|
*/
|
||||||
|
public LoginVo buildLoginUserVo(AdminUser user, long readMeDay) {
|
||||||
|
String username = user.getUsername();
|
||||||
|
Long userId = user.getId();
|
||||||
|
|
||||||
|
// 用户角色
|
||||||
|
List<String> roles = new ArrayList<>(roleMapper.selectListByUserId(userId).stream().map(Role::getRoleCode).toList());
|
||||||
|
|
||||||
|
// 判断是否是 admin 如果是admin 赋予所有权限
|
||||||
|
List<String> permissions = new ArrayList<>();
|
||||||
|
boolean isAdmin = RoleUtil.checkAdmin(roles, permissions, user);
|
||||||
|
if (!isAdmin) {
|
||||||
|
permissions = permissionMapper.selectListByUserId(userId).stream()
|
||||||
|
.map(Permission::getPowerCode)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
// 为这两个去重
|
||||||
|
permissions = permissions.stream().distinct().toList();
|
||||||
|
roles = roles.stream().distinct().toList();
|
||||||
|
|
||||||
|
// 获取IP地址并更新用户登录信息,
|
||||||
|
String ipAddr = IpUtil.getCurrentUserIpAddress().getIpAddr();
|
||||||
|
String ipRegion = IpUtil.getCurrentUserIpAddress().getIpRegion();
|
||||||
|
// 设置用户IP地址,并更新用户信息
|
||||||
|
user.setIpAddress(ipAddr);
|
||||||
|
user.setIpRegion(ipRegion);
|
||||||
|
userMapper.updateById(user);
|
||||||
|
|
||||||
|
LoginVo loginVo = new LoginVo();
|
||||||
|
BeanUtils.copyProperties(user, loginVo);
|
||||||
|
loginVo.setPersonDescription(user.getSummary());
|
||||||
|
loginVo.setRoles(roles);
|
||||||
|
loginVo.setPermissions(permissions);
|
||||||
|
|
||||||
|
// 使用用户名创建token
|
||||||
|
String token = JwtTokenUtil.createToken(userId, username, (int) readMeDay);
|
||||||
|
loginVo.setToken(token);
|
||||||
|
loginVo.setRefreshToken(token);
|
||||||
|
loginVo.setReadMeDay(readMeDay);
|
||||||
|
|
||||||
|
// 计算过期时间,并格式化返回
|
||||||
|
LocalDateTime localDateTime = LocalDateTime.now();
|
||||||
|
LocalDateTime plusDay = localDateTime.plusDays(readMeDay);
|
||||||
|
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(LocalDateTimeConstant.YYYY_MM_DD_HH_MM_SS_SLASH);
|
||||||
|
String expires = plusDay.format(dateTimeFormatter);
|
||||||
|
loginVo.setExpires(expires);
|
||||||
|
|
||||||
|
// 设置用户头像
|
||||||
|
String userAvatar = minioHelper.getUserAvatar(user.getAvatar());
|
||||||
|
loginVo.setAvatar(userAvatar);
|
||||||
|
|
||||||
|
// 将用户登录保存在用户登录日志表中
|
||||||
|
setUserLoginLog(user, token, UserConstant.LOGIN);
|
||||||
|
|
||||||
|
// 将信息保存在Redis中,一定要确保用户名是唯一的
|
||||||
|
String loginInfoPrefix = RedisUserConstant.getAdminLoginInfoPrefix(username);
|
||||||
|
redisTemplate.opsForValue().set(loginInfoPrefix, loginVo, readMeDay, TimeUnit.DAYS);
|
||||||
|
|
||||||
|
return loginVo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置用户登录日志内容
|
||||||
|
* <p>
|
||||||
|
* 该方法用于将管理员用户信息复制到用户登录日志对象中,同时处理特殊字段映射关系。
|
||||||
|
* <p>
|
||||||
|
* 实现说明:
|
||||||
|
* 1. 使用BeanUtils.copyProperties()复制属性时,会自动将AdminUser.id复制到UserLoginLog.id
|
||||||
|
* 2. 由于UserLoginLog实际需要的是userId字段而非id字段,需要特殊处理:
|
||||||
|
* - 先进行属性复制
|
||||||
|
* - 然后将UserLoginLog.userId设置为AdminUser.id
|
||||||
|
* - 最后将UserLoginLog.id显式设为null(避免自动生成的id被覆盖)
|
||||||
|
*
|
||||||
|
* @param user 管理员用户实体对象,包含用户基本信息
|
||||||
|
* @param token 本次登录/退出的认证令牌
|
||||||
|
* @param type 操作类型(LOGIN-登录/LOGOUT-退出)
|
||||||
|
*/
|
||||||
|
public void setUserLoginLog(AdminUser user, String token, String type) {
|
||||||
|
UserLoginLog userLoginLog = new UserLoginLog();
|
||||||
|
BeanUtils.copyProperties(user, userLoginLog);
|
||||||
|
userLoginLog.setUserId(user.getId());
|
||||||
|
userLoginLog.setId(null);
|
||||||
|
userLoginLog.setToken(token);
|
||||||
|
userLoginLog.setType(type);
|
||||||
|
|
||||||
|
// 当前请求request
|
||||||
|
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
||||||
|
if (requestAttributes != null) {
|
||||||
|
HttpServletRequest request = requestAttributes.getRequest();
|
||||||
|
|
||||||
|
// 获取User-Agent
|
||||||
|
String userAgent = request.getHeader("User-Agent");
|
||||||
|
userLoginLog.setUserAgent(userAgent);
|
||||||
|
|
||||||
|
// 获取X-Requested-With
|
||||||
|
String xRequestedWith = request.getHeader("X-Requested-With");
|
||||||
|
userLoginLog.setXRequestedWith(xRequestedWith);
|
||||||
|
}
|
||||||
|
|
||||||
|
userLoginLogMapper.insert(userLoginLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package cn.bunny.services.utils.login;
|
package cn.bunny.services.service.system.helper.login;
|
||||||
|
|
||||||
import cn.bunny.services.domain.system.system.dto.user.LoginDto;
|
import cn.bunny.services.domain.system.system.dto.user.LoginDto;
|
||||||
import cn.bunny.services.domain.system.system.entity.AdminUser;
|
import cn.bunny.services.domain.system.system.entity.AdminUser;
|
||||||
|
@ -31,4 +31,16 @@ public class DefaultLoginStrategy implements LoginStrategy {
|
||||||
queryWrapper.eq(AdminUser::getUsername, username);
|
queryWrapper.eq(AdminUser::getUsername, username);
|
||||||
return userMapper.selectOne(queryWrapper);
|
return userMapper.selectOne(queryWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录完成后的内容
|
||||||
|
*
|
||||||
|
* @param loginDto 登录参数
|
||||||
|
* @param adminUser 用户
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void authenticateAfter(LoginDto loginDto, AdminUser adminUser) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,9 +1,9 @@
|
||||||
package cn.bunny.services.utils.login;
|
package cn.bunny.services.service.system.helper.login;
|
||||||
|
|
||||||
import cn.bunny.services.domain.common.constant.RedisUserConstant;
|
import cn.bunny.services.domain.common.constant.RedisUserConstant;
|
||||||
|
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
||||||
import cn.bunny.services.domain.system.system.dto.user.LoginDto;
|
import cn.bunny.services.domain.system.system.dto.user.LoginDto;
|
||||||
import cn.bunny.services.domain.system.system.entity.AdminUser;
|
import cn.bunny.services.domain.system.system.entity.AdminUser;
|
||||||
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
|
||||||
import cn.bunny.services.mapper.system.UserMapper;
|
import cn.bunny.services.mapper.system.UserMapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
@ -53,4 +53,18 @@ public class EmailLoginStrategy implements LoginStrategy {
|
||||||
queryWrapper.eq(AdminUser::getEmail, username);
|
queryWrapper.eq(AdminUser::getEmail, username);
|
||||||
return userMapper.selectOne(queryWrapper);
|
return userMapper.selectOne(queryWrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录完成后的内容
|
||||||
|
*
|
||||||
|
* @param loginDto 登录参数
|
||||||
|
* @param adminUser 用户
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void authenticateAfter(LoginDto loginDto, AdminUser adminUser) {
|
||||||
|
// 将Redis中验证码删除
|
||||||
|
String emailCodePrefix = RedisUserConstant.getAdminUserEmailCodePrefix(loginDto.getUsername());
|
||||||
|
redisTemplate.delete(emailCodePrefix);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,9 +1,8 @@
|
||||||
package cn.bunny.services.utils.login;
|
package cn.bunny.services.service.system.helper.login;
|
||||||
|
|
||||||
import cn.bunny.services.domain.system.system.dto.user.LoginDto;
|
import cn.bunny.services.domain.system.system.dto.user.LoginDto;
|
||||||
import cn.bunny.services.domain.system.system.entity.AdminUser;
|
import cn.bunny.services.domain.system.system.entity.AdminUser;
|
||||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -13,11 +12,9 @@ import java.util.Map;
|
||||||
public class LoginContext {
|
public class LoginContext {
|
||||||
|
|
||||||
private final Map<String, LoginStrategy> strategies;
|
private final Map<String, LoginStrategy> strategies;
|
||||||
private final PasswordEncoder passwordEncoder;
|
|
||||||
|
|
||||||
public LoginContext(Map<String, LoginStrategy> strategies, PasswordEncoder passwordEncoder) {
|
public LoginContext(Map<String, LoginStrategy> strategies) {
|
||||||
this.strategies = strategies;
|
this.strategies = strategies;
|
||||||
this.passwordEncoder = passwordEncoder;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,4 +34,16 @@ public class LoginContext {
|
||||||
|
|
||||||
return strategy.authenticate(loginDto);
|
return strategy.authenticate(loginDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录完成后的内容
|
||||||
|
*
|
||||||
|
* @param loginDto 登录参数
|
||||||
|
*/
|
||||||
|
public void loginAfter(LoginDto loginDto, AdminUser adminUser) {
|
||||||
|
String type = loginDto.getType();
|
||||||
|
LoginStrategy strategy = strategies.get(type);
|
||||||
|
|
||||||
|
strategy.authenticateAfter(loginDto, adminUser);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package cn.bunny.services.utils.login;
|
package cn.bunny.services.service.system.helper.login;
|
||||||
|
|
||||||
|
|
||||||
import cn.bunny.services.domain.system.system.dto.user.LoginDto;
|
import cn.bunny.services.domain.system.system.dto.user.LoginDto;
|
||||||
|
@ -16,4 +16,12 @@ public interface LoginStrategy {
|
||||||
* @return 鉴定身份验证
|
* @return 鉴定身份验证
|
||||||
*/
|
*/
|
||||||
AdminUser authenticate(LoginDto loginDto);
|
AdminUser authenticate(LoginDto loginDto);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录完成后的内容
|
||||||
|
*
|
||||||
|
* @param loginDto 登录参数
|
||||||
|
* @param adminUser
|
||||||
|
*/
|
||||||
|
void authenticateAfter(LoginDto loginDto, AdminUser adminUser);
|
||||||
}
|
}
|
|
@ -1,11 +1,9 @@
|
||||||
package cn.bunny.services.service.system.impl;
|
package cn.bunny.services.service.system.impl;
|
||||||
|
|
||||||
import cn.bunny.services.config.minio.MinioProperties;
|
|
||||||
import cn.bunny.services.config.minio.MinioUtil;
|
|
||||||
import cn.bunny.services.context.BaseContext;
|
import cn.bunny.services.context.BaseContext;
|
||||||
|
import cn.bunny.services.domain.common.model.dto.file.MinioFilePath;
|
||||||
import cn.bunny.services.domain.common.model.vo.result.PageResult;
|
import cn.bunny.services.domain.common.model.vo.result.PageResult;
|
||||||
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
||||||
import cn.bunny.services.domain.common.model.dto.file.MinioFilePath;
|
|
||||||
import cn.bunny.services.domain.system.files.dto.FileUploadDto;
|
import cn.bunny.services.domain.system.files.dto.FileUploadDto;
|
||||||
import cn.bunny.services.domain.system.files.dto.FilesAddDto;
|
import cn.bunny.services.domain.system.files.dto.FilesAddDto;
|
||||||
import cn.bunny.services.domain.system.files.dto.FilesDto;
|
import cn.bunny.services.domain.system.files.dto.FilesDto;
|
||||||
|
@ -15,6 +13,9 @@ import cn.bunny.services.domain.system.files.vo.FileInfoVo;
|
||||||
import cn.bunny.services.domain.system.files.vo.FilesVo;
|
import cn.bunny.services.domain.system.files.vo.FilesVo;
|
||||||
import cn.bunny.services.exception.AuthCustomerException;
|
import cn.bunny.services.exception.AuthCustomerException;
|
||||||
import cn.bunny.services.mapper.system.FilesMapper;
|
import cn.bunny.services.mapper.system.FilesMapper;
|
||||||
|
import cn.bunny.services.minio.MinioHelper;
|
||||||
|
import cn.bunny.services.minio.MinioProperties;
|
||||||
|
import cn.bunny.services.minio.MinioService;
|
||||||
import cn.bunny.services.service.system.FilesService;
|
import cn.bunny.services.service.system.FilesService;
|
||||||
import cn.bunny.services.utils.FileUtil;
|
import cn.bunny.services.utils.FileUtil;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
@ -59,11 +60,15 @@ public class FilesServiceImpl extends ServiceImpl<FilesMapper, Files> implements
|
||||||
private MinioProperties properties;
|
private MinioProperties properties;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private MinioUtil minioUtil;
|
private MinioService minioService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private MinioHelper minioHelper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private FilesMapper filesMapper;
|
private FilesMapper filesMapper;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* * 系统文件表 服务实现类
|
* * 系统文件表 服务实现类
|
||||||
*
|
*
|
||||||
|
@ -92,7 +97,7 @@ public class FilesServiceImpl extends ServiceImpl<FilesMapper, Files> implements
|
||||||
public void addFiles(FilesAddDto dto) {
|
public void addFiles(FilesAddDto dto) {
|
||||||
List<Files> list = dto.getFiles().stream().map(file -> {
|
List<Files> list = dto.getFiles().stream().map(file -> {
|
||||||
try {
|
try {
|
||||||
MinioFilePath minioFilePath = minioUtil.uploadObjectReturnFilePath(file, dto.getFilepath());
|
MinioFilePath minioFilePath = minioService.uploadObjectReturnFilePath(file, dto.getFilepath());
|
||||||
|
|
||||||
Files files = new Files();
|
Files files = new Files();
|
||||||
files.setFileType(file.getContentType());
|
files.setFileType(file.getContentType());
|
||||||
|
@ -124,7 +129,7 @@ public class FilesServiceImpl extends ServiceImpl<FilesMapper, Files> implements
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
// 文件路径
|
// 文件路径
|
||||||
String filePath = files.getFilepath().replace("/" + properties.getBucketName() + "/", "");
|
String filePath = files.getFilepath().replace("/" + properties.getBucketName() + "/", "");
|
||||||
minioUtil.updateFile(properties.getBucketName(), filePath, file);
|
minioService.updateFile(properties.getBucketName(), filePath, file);
|
||||||
|
|
||||||
// 设置文件信息
|
// 设置文件信息
|
||||||
files.setFileSize(file.getSize());
|
files.setFileSize(file.getSize());
|
||||||
|
@ -160,7 +165,7 @@ public class FilesServiceImpl extends ServiceImpl<FilesMapper, Files> implements
|
||||||
String filename = file.getOriginalFilename();
|
String filename = file.getOriginalFilename();
|
||||||
|
|
||||||
// 上传文件
|
// 上传文件
|
||||||
MinioFilePath minioFIlePath = minioUtil.uploadObjectReturnFilePath(file, type);
|
MinioFilePath minioFIlePath = minioService.uploadObjectReturnFilePath(file, type);
|
||||||
String bucketNameFilepath = minioFIlePath.getBucketNameFilepath();
|
String bucketNameFilepath = minioFIlePath.getBucketNameFilepath();
|
||||||
|
|
||||||
// 盘读研数据是否过大
|
// 盘读研数据是否过大
|
||||||
|
@ -183,7 +188,7 @@ public class FilesServiceImpl extends ServiceImpl<FilesMapper, Files> implements
|
||||||
.fileSize(fileSize)
|
.fileSize(fileSize)
|
||||||
.fileType(contentType)
|
.fileType(contentType)
|
||||||
.filename(filename)
|
.filename(filename)
|
||||||
.url(minioUtil.getObjectNameFullPath(bucketNameFilepath))
|
.url(minioHelper.getObjectNameFullPath(bucketNameFilepath))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,7 +210,7 @@ public class FilesServiceImpl extends ServiceImpl<FilesMapper, Files> implements
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
// 删除目标文件
|
// 删除目标文件
|
||||||
minioUtil.removeObjects(list);
|
minioService.removeObjects(list);
|
||||||
|
|
||||||
// 删除数据库内容
|
// 删除数据库内容
|
||||||
removeByIds(ids);
|
removeByIds(ids);
|
||||||
|
@ -229,7 +234,7 @@ public class FilesServiceImpl extends ServiceImpl<FilesMapper, Files> implements
|
||||||
String filepath = files.getFilepath();
|
String filepath = files.getFilepath();
|
||||||
int end = filepath.indexOf("/", 1);
|
int end = filepath.indexOf("/", 1);
|
||||||
filepath = filepath.substring(end + 1);
|
filepath = filepath.substring(end + 1);
|
||||||
byte[] bytes = minioUtil.getBucketObjectByte(filepath);
|
byte[] bytes = minioService.getBucketObjectByte(filepath);
|
||||||
|
|
||||||
// 设置响应头
|
// 设置响应头
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
|
|
@ -94,7 +94,7 @@ public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements Ro
|
||||||
* @return 所有角色列表
|
* @return 所有角色列表
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@Cacheable(cacheNames = "role", key = "'allRole'", cacheManager = "cacheManagerWithMouth")
|
@Cacheable(cacheNames = "role", key = "'roleList'", cacheManager = "cacheManagerWithMouth")
|
||||||
public List<RoleVo> roleList() {
|
public List<RoleVo> roleList() {
|
||||||
return list().stream().map(role -> {
|
return list().stream().map(role -> {
|
||||||
RoleVo roleVo = new RoleVo();
|
RoleVo roleVo = new RoleVo();
|
||||||
|
@ -155,7 +155,7 @@ public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements Ro
|
||||||
* @param file Excel文件
|
* @param file Excel文件
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@CacheEvict(cacheNames = "role", key = "'allRole'", beforeInvocation = true)
|
@CacheEvict(cacheNames = "role", key = "'roleList'", beforeInvocation = true)
|
||||||
public void updateRoleByFile(MultipartFile file) {
|
public void updateRoleByFile(MultipartFile file) {
|
||||||
if (file == null) {
|
if (file == null) {
|
||||||
throw new AuthCustomerException(ResultCodeEnum.REQUEST_IS_EMPTY);
|
throw new AuthCustomerException(ResultCodeEnum.REQUEST_IS_EMPTY);
|
||||||
|
@ -176,7 +176,7 @@ public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements Ro
|
||||||
* @param dto 角色添加
|
* @param dto 角色添加
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@CacheEvict(cacheNames = "role", key = "'allRole'", beforeInvocation = true)
|
@CacheEvict(cacheNames = "role", key = "'roleList'", beforeInvocation = true)
|
||||||
public void addRole(@Valid RoleAddDto dto) {
|
public void addRole(@Valid RoleAddDto dto) {
|
||||||
Role role = new Role();
|
Role role = new Role();
|
||||||
BeanUtils.copyProperties(dto, role);
|
BeanUtils.copyProperties(dto, role);
|
||||||
|
@ -189,7 +189,7 @@ public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements Ro
|
||||||
* @param dto 角色更新
|
* @param dto 角色更新
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@CacheEvict(cacheNames = "role", key = "'allRole'", beforeInvocation = true)
|
@CacheEvict(cacheNames = "role", key = "'roleList'", beforeInvocation = true)
|
||||||
public void updateRole(@Valid RoleUpdateDto dto) {
|
public void updateRole(@Valid RoleUpdateDto dto) {
|
||||||
// 查询更新的角色是否存在
|
// 查询更新的角色是否存在
|
||||||
List<Role> roleList = list(Wrappers.<Role>lambdaQuery().eq(Role::getId, dto.getId()));
|
List<Role> roleList = list(Wrappers.<Role>lambdaQuery().eq(Role::getId, dto.getId()));
|
||||||
|
@ -213,7 +213,7 @@ public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements Ro
|
||||||
* @param ids 删除id列表
|
* @param ids 删除id列表
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@CacheEvict(cacheNames = "role", key = "'allRole'", beforeInvocation = true)
|
@CacheEvict(cacheNames = "role", key = "'roleList'", beforeInvocation = true)
|
||||||
public void deleteRole(List<Long> ids) {
|
public void deleteRole(List<Long> ids) {
|
||||||
// 判断数据请求是否为空
|
// 判断数据请求是否为空
|
||||||
if (ids.isEmpty()) throw new AuthCustomerException(ResultCodeEnum.REQUEST_IS_EMPTY);
|
if (ids.isEmpty()) throw new AuthCustomerException(ResultCodeEnum.REQUEST_IS_EMPTY);
|
||||||
|
|
|
@ -0,0 +1,184 @@
|
||||||
|
package cn.bunny.services.service.system.impl;
|
||||||
|
|
||||||
|
import cn.bunny.services.context.BaseContext;
|
||||||
|
import cn.bunny.services.domain.common.constant.RedisUserConstant;
|
||||||
|
import cn.bunny.services.domain.common.constant.UserConstant;
|
||||||
|
import cn.bunny.services.domain.common.enums.EmailTemplateEnums;
|
||||||
|
import cn.bunny.services.domain.common.enums.LoginEnums;
|
||||||
|
import cn.bunny.services.domain.common.model.vo.LoginVo;
|
||||||
|
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
||||||
|
import cn.bunny.services.domain.system.email.entity.EmailTemplate;
|
||||||
|
import cn.bunny.services.domain.system.system.dto.user.LoginDto;
|
||||||
|
import cn.bunny.services.domain.system.system.dto.user.RefreshTokenDto;
|
||||||
|
import cn.bunny.services.domain.system.system.entity.AdminUser;
|
||||||
|
import cn.bunny.services.domain.system.system.vo.user.RefreshTokenVo;
|
||||||
|
import cn.bunny.services.exception.AuthCustomerException;
|
||||||
|
import cn.bunny.services.mapper.configuration.EmailTemplateMapper;
|
||||||
|
import cn.bunny.services.mapper.system.UserMapper;
|
||||||
|
import cn.bunny.services.service.system.UserLoginService;
|
||||||
|
import cn.bunny.services.service.system.helper.UserLoginHelper;
|
||||||
|
import cn.bunny.services.service.system.helper.login.DefaultLoginStrategy;
|
||||||
|
import cn.bunny.services.service.system.helper.login.EmailLoginStrategy;
|
||||||
|
import cn.bunny.services.service.system.helper.login.LoginContext;
|
||||||
|
import cn.bunny.services.service.system.helper.login.LoginStrategy;
|
||||||
|
import cn.bunny.services.utils.IpUtil;
|
||||||
|
import cn.bunny.services.utils.JwtTokenUtil;
|
||||||
|
import cn.bunny.services.utils.email.ConcreteSenderEmailTemplate;
|
||||||
|
import cn.hutool.captcha.CaptchaUtil;
|
||||||
|
import cn.hutool.captcha.CircleCaptcha;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class UserLoginServiceImpl extends ServiceImpl<UserMapper, AdminUser> implements UserLoginService {
|
||||||
|
@Resource
|
||||||
|
private UserLoginHelper userloginHelper;
|
||||||
|
@Resource
|
||||||
|
private RedisTemplate<String, Object> redisTemplate;
|
||||||
|
@Resource
|
||||||
|
private PasswordEncoder passwordEncoder;
|
||||||
|
@Resource
|
||||||
|
private UserMapper userMapper;
|
||||||
|
@Resource
|
||||||
|
private EmailTemplateMapper emailTemplateMapper;
|
||||||
|
@Resource
|
||||||
|
private ConcreteSenderEmailTemplate concreteSenderEmailTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 前台用户登录接口
|
||||||
|
* 这里不用判断用户是否为空,因为在登录时已经校验过了
|
||||||
|
* <p>
|
||||||
|
* 抛出异常使用自带的 UsernameNotFoundException 或者自己封装<br/>
|
||||||
|
* 但是这两个效果传入参数都是一样的,所以全部使用 UsernameNotFoundException
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param loginDto 登录参数
|
||||||
|
* @return 登录后结果返回
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public LoginVo login(LoginDto loginDto) {
|
||||||
|
// 初始化所有策略(可扩展)
|
||||||
|
HashMap<String, LoginStrategy> loginStrategyHashMap = new HashMap<>();
|
||||||
|
// 默认的登录方式
|
||||||
|
loginStrategyHashMap.put(LoginEnums.default_STRATEGY.getValue(), new DefaultLoginStrategy(userMapper));
|
||||||
|
// 注册邮箱
|
||||||
|
loginStrategyHashMap.put(LoginEnums.EMAIL_STRATEGY.getValue(), new EmailLoginStrategy(redisTemplate, userMapper));
|
||||||
|
|
||||||
|
// 使用登录上下文调用登录策略
|
||||||
|
LoginContext loginContext = new LoginContext(loginStrategyHashMap);
|
||||||
|
AdminUser user = loginContext.executeStrategy(loginDto);
|
||||||
|
|
||||||
|
// 验证登录逻辑
|
||||||
|
if (user == null) throw new UsernameNotFoundException(ResultCodeEnum.USER_IS_EMPTY.getMessage());
|
||||||
|
|
||||||
|
// 数据库密码
|
||||||
|
String dbPassword = user.getPassword();
|
||||||
|
String password = loginDto.getPassword();
|
||||||
|
if (!passwordEncoder.matches(password, dbPassword)) {
|
||||||
|
throw new UsernameNotFoundException(ResultCodeEnum.LOGIN_ERROR.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断用户是否禁用
|
||||||
|
if (user.getStatus()) {
|
||||||
|
throw new UsernameNotFoundException(ResultCodeEnum.FAIL_NO_ACCESS_DENIED_USER_LOCKED.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 登录结束后的操作
|
||||||
|
loginContext.loginAfter(loginDto, user);
|
||||||
|
|
||||||
|
user.setUpdateUser(user.getId());
|
||||||
|
user.setCreateUser(user.getId());
|
||||||
|
return userloginHelper.buildLoginUserVo(user, loginDto.getReadMeDay());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录发送邮件验证码
|
||||||
|
*
|
||||||
|
* @param email 邮箱
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void sendLoginEmail(@NotNull String email) {
|
||||||
|
// 查询验证码邮件模板
|
||||||
|
LambdaQueryWrapper<EmailTemplate> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||||
|
lambdaQueryWrapper.eq(EmailTemplate::getIsDefault, true);
|
||||||
|
lambdaQueryWrapper.eq(EmailTemplate::getType, EmailTemplateEnums.VERIFICATION_CODE.getType());
|
||||||
|
EmailTemplate emailTemplate = emailTemplateMapper.selectOne(lambdaQueryWrapper);
|
||||||
|
|
||||||
|
// 生成验证码
|
||||||
|
CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(150, 48, 4, 2);
|
||||||
|
String emailCode = captcha.getCode();
|
||||||
|
|
||||||
|
// 需要替换模板内容
|
||||||
|
HashMap<String, Object> hashMap = new HashMap<>();
|
||||||
|
hashMap.put("#title#", "BunnyAdmin");
|
||||||
|
hashMap.put("#verifyCode#", emailCode);
|
||||||
|
hashMap.put("#expires#", 15);
|
||||||
|
hashMap.put("#sendEmailUser#", emailTemplate.getEmailUser());
|
||||||
|
hashMap.put("#companyName#", "BunnyAdmin");
|
||||||
|
|
||||||
|
// 发送邮件
|
||||||
|
concreteSenderEmailTemplate.sendEmailTemplate(email, emailTemplate, hashMap);
|
||||||
|
|
||||||
|
// 在Redis中存储验证码
|
||||||
|
redisTemplate.opsForValue().set(RedisUserConstant.getAdminUserEmailCodePrefix(email), emailCode, RedisUserConstant.REDIS_EXPIRATION_TIME, TimeUnit.MINUTES);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新用户token
|
||||||
|
*
|
||||||
|
* @param dto 请求token
|
||||||
|
* @return 刷新token返回内容
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public RefreshTokenVo refreshToken(@NotNull RefreshTokenDto dto) {
|
||||||
|
Long userId = JwtTokenUtil.getUserId(dto.getRefreshToken());
|
||||||
|
AdminUser adminUser = getOne(Wrappers.<AdminUser>lambdaQuery().eq(AdminUser::getId, userId));
|
||||||
|
|
||||||
|
// 用户存在且没有禁用
|
||||||
|
if (adminUser == null) throw new AuthCustomerException(ResultCodeEnum.USER_IS_EMPTY);
|
||||||
|
if (adminUser.getStatus()) throw new AuthCustomerException(ResultCodeEnum.FAIL_NO_ACCESS_DENIED_USER_LOCKED);
|
||||||
|
|
||||||
|
LoginVo buildUserVo = userloginHelper.buildLoginUserVo(adminUser, dto.getReadMeDay());
|
||||||
|
RefreshTokenVo refreshTokenVo = new RefreshTokenVo();
|
||||||
|
BeanUtils.copyProperties(buildUserVo, refreshTokenVo);
|
||||||
|
|
||||||
|
return refreshTokenVo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退出登录
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void logout() {
|
||||||
|
// 获取上下文对象中的用户ID和用户token
|
||||||
|
LoginVo loginVo = BaseContext.getLoginVo();
|
||||||
|
String token = loginVo.getToken();
|
||||||
|
Long userId = BaseContext.getUserId();
|
||||||
|
|
||||||
|
// 获取IP地址
|
||||||
|
String ipAddr = IpUtil.getCurrentUserIpAddress().getIpAddr();
|
||||||
|
String ipRegion = IpUtil.getCurrentUserIpAddress().getIpRegion();
|
||||||
|
|
||||||
|
// 查询用户信息
|
||||||
|
AdminUser adminUser = getOne(Wrappers.<AdminUser>lambdaQuery().eq(AdminUser::getId, userId));
|
||||||
|
adminUser.setIpAddress(ipAddr);
|
||||||
|
adminUser.setIpRegion(ipRegion);
|
||||||
|
userloginHelper.setUserLoginLog(adminUser, token, UserConstant.LOGOUT);
|
||||||
|
|
||||||
|
// 删除Redis中用户信息
|
||||||
|
String loginInfoPrefix = RedisUserConstant.getAdminLoginInfoPrefix(adminUser.getUsername());
|
||||||
|
redisTemplate.delete(loginInfoPrefix);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,17 +1,17 @@
|
||||||
package cn.bunny.services.service.system.impl;
|
package cn.bunny.services.service.system.impl;
|
||||||
|
|
||||||
|
import cn.bunny.services.context.BaseContext;
|
||||||
import cn.bunny.services.domain.common.constant.RedisUserConstant;
|
import cn.bunny.services.domain.common.constant.RedisUserConstant;
|
||||||
|
import cn.bunny.services.domain.common.model.vo.LoginVo;
|
||||||
|
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
||||||
import cn.bunny.services.domain.system.system.dto.user.AssignRolesToUsersDto;
|
import cn.bunny.services.domain.system.system.dto.user.AssignRolesToUsersDto;
|
||||||
import cn.bunny.services.domain.system.system.entity.AdminUser;
|
import cn.bunny.services.domain.system.system.entity.AdminUser;
|
||||||
import cn.bunny.services.domain.system.system.entity.UserRole;
|
import cn.bunny.services.domain.system.system.entity.UserRole;
|
||||||
import cn.bunny.services.domain.common.model.vo.LoginVo;
|
|
||||||
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
|
||||||
import cn.bunny.services.context.BaseContext;
|
|
||||||
import cn.bunny.services.exception.AuthCustomerException;
|
import cn.bunny.services.exception.AuthCustomerException;
|
||||||
import cn.bunny.services.mapper.system.UserMapper;
|
import cn.bunny.services.mapper.system.UserMapper;
|
||||||
import cn.bunny.services.mapper.system.UserRoleMapper;
|
import cn.bunny.services.mapper.system.UserRoleMapper;
|
||||||
import cn.bunny.services.service.system.UserRoleService;
|
import cn.bunny.services.service.system.UserRoleService;
|
||||||
import cn.bunny.services.utils.system.UserUtil;
|
import cn.bunny.services.service.system.helper.UserLoginHelper;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
|
@ -35,14 +35,11 @@ import java.util.concurrent.TimeUnit;
|
||||||
public class UserRoleServiceImpl extends ServiceImpl<UserRoleMapper, UserRole> implements UserRoleService {
|
public class UserRoleServiceImpl extends ServiceImpl<UserRoleMapper, UserRole> implements UserRoleService {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private UserRoleMapper userRoleMapper;
|
private UserLoginHelper userloginHelper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private UserUtil userUtil;
|
private UserRoleMapper userRoleMapper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private UserMapper userMapper;
|
private UserMapper userMapper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private RedisTemplate<String, Object> redisTemplate;
|
private RedisTemplate<String, Object> redisTemplate;
|
||||||
|
|
||||||
|
@ -94,7 +91,7 @@ public class UserRoleServiceImpl extends ServiceImpl<UserRoleMapper, UserRole> i
|
||||||
|
|
||||||
// 重新设置Redis中的用户存储信息vo对象
|
// 重新设置Redis中的用户存储信息vo对象
|
||||||
String username = adminUser.getUsername();
|
String username = adminUser.getUsername();
|
||||||
loginVo = userUtil.buildLoginUserVo(adminUser, readMeDay);
|
loginVo = userloginHelper.buildLoginUserVo(adminUser, readMeDay);
|
||||||
redisTemplate.opsForValue().set(RedisUserConstant.getAdminLoginInfoPrefix(username), loginVo, readMeDay, TimeUnit.DAYS);
|
redisTemplate.opsForValue().set(RedisUserConstant.getAdminLoginInfoPrefix(username), loginVo, readMeDay, TimeUnit.DAYS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,40 +1,34 @@
|
||||||
package cn.bunny.services.service.system.impl;
|
package cn.bunny.services.service.system.impl;
|
||||||
|
|
||||||
import cn.bunny.services.context.BaseContext;
|
import cn.bunny.services.context.BaseContext;
|
||||||
|
import cn.bunny.services.domain.common.constant.MinioConstant;
|
||||||
import cn.bunny.services.domain.common.constant.RedisUserConstant;
|
import cn.bunny.services.domain.common.constant.RedisUserConstant;
|
||||||
import cn.bunny.services.domain.common.enums.EmailTemplateEnums;
|
import cn.bunny.services.domain.common.constant.UserConstant;
|
||||||
import cn.bunny.services.domain.common.enums.LoginEnums;
|
|
||||||
import cn.bunny.services.domain.common.model.vo.LoginVo;
|
|
||||||
import cn.bunny.services.domain.common.model.vo.result.PageResult;
|
import cn.bunny.services.domain.common.model.vo.result.PageResult;
|
||||||
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
||||||
import cn.bunny.services.domain.system.email.entity.EmailTemplate;
|
import cn.bunny.services.domain.system.files.dto.FileUploadDto;
|
||||||
|
import cn.bunny.services.domain.system.files.vo.FileInfoVo;
|
||||||
import cn.bunny.services.domain.system.log.entity.UserLoginLog;
|
import cn.bunny.services.domain.system.log.entity.UserLoginLog;
|
||||||
import cn.bunny.services.domain.system.system.dto.user.*;
|
import cn.bunny.services.domain.system.system.dto.user.AdminUserAddDto;
|
||||||
|
import cn.bunny.services.domain.system.system.dto.user.AdminUserDto;
|
||||||
|
import cn.bunny.services.domain.system.system.dto.user.AdminUserUpdateByLocalUserDto;
|
||||||
|
import cn.bunny.services.domain.system.system.dto.user.AdminUserUpdateDto;
|
||||||
import cn.bunny.services.domain.system.system.entity.AdminUser;
|
import cn.bunny.services.domain.system.system.entity.AdminUser;
|
||||||
import cn.bunny.services.domain.system.system.entity.Role;
|
import cn.bunny.services.domain.system.system.entity.Role;
|
||||||
import cn.bunny.services.domain.system.system.entity.UserDept;
|
import cn.bunny.services.domain.system.system.entity.UserDept;
|
||||||
import cn.bunny.services.domain.system.system.views.ViewUserDept;
|
import cn.bunny.services.domain.system.system.views.ViewUserDept;
|
||||||
import cn.bunny.services.domain.system.system.vo.user.AdminUserVo;
|
import cn.bunny.services.domain.system.system.vo.user.AdminUserVo;
|
||||||
import cn.bunny.services.domain.system.system.vo.user.RefreshTokenVo;
|
|
||||||
import cn.bunny.services.domain.system.system.vo.user.UserVo;
|
import cn.bunny.services.domain.system.system.vo.user.UserVo;
|
||||||
import cn.bunny.services.exception.AuthCustomerException;
|
import cn.bunny.services.exception.AuthCustomerException;
|
||||||
import cn.bunny.services.mapper.configuration.EmailTemplateMapper;
|
|
||||||
import cn.bunny.services.mapper.log.UserLoginLogMapper;
|
import cn.bunny.services.mapper.log.UserLoginLogMapper;
|
||||||
import cn.bunny.services.mapper.system.RoleMapper;
|
import cn.bunny.services.mapper.system.RoleMapper;
|
||||||
import cn.bunny.services.mapper.system.UserDeptMapper;
|
import cn.bunny.services.mapper.system.UserDeptMapper;
|
||||||
import cn.bunny.services.mapper.system.UserMapper;
|
import cn.bunny.services.mapper.system.UserMapper;
|
||||||
import cn.bunny.services.mapper.system.UserRoleMapper;
|
import cn.bunny.services.mapper.system.UserRoleMapper;
|
||||||
|
import cn.bunny.services.minio.MinioHelper;
|
||||||
|
import cn.bunny.services.service.system.FilesService;
|
||||||
import cn.bunny.services.service.system.UserService;
|
import cn.bunny.services.service.system.UserService;
|
||||||
import cn.bunny.services.utils.IpUtil;
|
import cn.bunny.services.service.system.helper.UserLoginHelper;
|
||||||
import cn.bunny.services.utils.JwtTokenUtil;
|
|
||||||
import cn.bunny.services.utils.email.ConcreteSenderEmailTemplate;
|
|
||||||
import cn.bunny.services.utils.login.DefaultLoginStrategy;
|
|
||||||
import cn.bunny.services.utils.login.EmailLoginStrategy;
|
|
||||||
import cn.bunny.services.utils.login.LoginContext;
|
|
||||||
import cn.bunny.services.utils.login.LoginStrategy;
|
|
||||||
import cn.bunny.services.utils.system.UserUtil;
|
|
||||||
import cn.hutool.captcha.CaptchaUtil;
|
|
||||||
import cn.hutool.captcha.CircleCaptcha;
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
|
@ -42,18 +36,15 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
|
||||||
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.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -67,150 +58,23 @@ import java.util.concurrent.TimeUnit;
|
||||||
public class UserServiceImpl extends ServiceImpl<UserMapper, AdminUser> implements UserService {
|
public class UserServiceImpl extends ServiceImpl<UserMapper, AdminUser> implements UserService {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private UserUtil userUtil;
|
private UserLoginHelper userloginHelper;
|
||||||
@Resource
|
@Resource
|
||||||
private ConcreteSenderEmailTemplate concreteSenderEmailTemplate;
|
private PasswordEncoder passwordEncoder;
|
||||||
@Resource
|
@Resource
|
||||||
private RedisTemplate<String, Object> redisTemplate;
|
private RedisTemplate<String, Object> redisTemplate;
|
||||||
@Resource
|
@Resource
|
||||||
|
private FilesService filesService;
|
||||||
|
@Resource
|
||||||
private UserDeptMapper userDeptMapper;
|
private UserDeptMapper userDeptMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private UserRoleMapper userRoleMapper;
|
private UserRoleMapper userRoleMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private UserLoginLogMapper userLoginLogMapper;
|
private UserLoginLogMapper userLoginLogMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private EmailTemplateMapper emailTemplateMapper;
|
|
||||||
@Resource
|
|
||||||
private RoleMapper roleMapper;
|
private RoleMapper roleMapper;
|
||||||
@Resource
|
@Resource
|
||||||
private UserMapper userMapper;
|
private MinioHelper minioHelper;
|
||||||
@Resource
|
|
||||||
private PasswordEncoder passwordEncoder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 前台用户登录接口
|
|
||||||
* 这里不用判断用户是否为空,因为在登录时已经校验过了
|
|
||||||
* <p>
|
|
||||||
* 抛出异常使用自带的 UsernameNotFoundException 或者自己封装<br/>
|
|
||||||
* 但是这两个效果传入参数都是一样的,所以全部使用 UsernameNotFoundException
|
|
||||||
* </p>
|
|
||||||
*
|
|
||||||
* @param loginDto 登录参数
|
|
||||||
* @return 登录后结果返回
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public LoginVo login(LoginDto loginDto) {
|
|
||||||
Long readMeDay = loginDto.getReadMeDay();
|
|
||||||
|
|
||||||
// 初始化所有策略(可扩展)
|
|
||||||
HashMap<String, LoginStrategy> loginStrategyHashMap = new HashMap<>();
|
|
||||||
// 默认的登录方式
|
|
||||||
loginStrategyHashMap.put(LoginEnums.default_STRATEGY.getValue(), new DefaultLoginStrategy(userMapper));
|
|
||||||
// 注册邮箱
|
|
||||||
loginStrategyHashMap.put(LoginEnums.EMAIL_STRATEGY.getValue(), new EmailLoginStrategy(redisTemplate, userMapper));
|
|
||||||
|
|
||||||
// 使用登录上下文调用登录策略
|
|
||||||
LoginContext loginContext = new LoginContext(loginStrategyHashMap, passwordEncoder);
|
|
||||||
AdminUser user = loginContext.executeStrategy(loginDto);
|
|
||||||
|
|
||||||
// 验证登录逻辑
|
|
||||||
if (user == null) throw new UsernameNotFoundException(ResultCodeEnum.USER_IS_EMPTY.getMessage());
|
|
||||||
|
|
||||||
// 数据库密码
|
|
||||||
String dbPassword = user.getPassword();
|
|
||||||
|
|
||||||
// 用户登录密码
|
|
||||||
String password = loginDto.getPassword();
|
|
||||||
|
|
||||||
if (!passwordEncoder.matches(password, dbPassword)) {
|
|
||||||
throw new UsernameNotFoundException(ResultCodeEnum.LOGIN_ERROR.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 判断用户是否禁用
|
|
||||||
if (user.getStatus()) {
|
|
||||||
throw new UsernameNotFoundException(ResultCodeEnum.FAIL_NO_ACCESS_DENIED_USER_LOCKED.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
return userUtil.buildLoginUserVo(user, readMeDay);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 登录发送邮件验证码
|
|
||||||
*
|
|
||||||
* @param email 邮箱
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void sendLoginEmail(@NotNull String email) {
|
|
||||||
// 查询验证码邮件模板
|
|
||||||
LambdaQueryWrapper<EmailTemplate> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
|
||||||
lambdaQueryWrapper.eq(EmailTemplate::getIsDefault, true);
|
|
||||||
lambdaQueryWrapper.eq(EmailTemplate::getType, EmailTemplateEnums.VERIFICATION_CODE.getType());
|
|
||||||
EmailTemplate emailTemplate = emailTemplateMapper.selectOne(lambdaQueryWrapper);
|
|
||||||
|
|
||||||
// 生成验证码
|
|
||||||
CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(150, 48, 4, 2);
|
|
||||||
String emailCode = captcha.getCode();
|
|
||||||
|
|
||||||
// 需要替换模板内容
|
|
||||||
HashMap<String, Object> hashMap = new HashMap<>();
|
|
||||||
hashMap.put("#title#", "BunnyAdmin");
|
|
||||||
hashMap.put("#verifyCode#", emailCode);
|
|
||||||
hashMap.put("#expires#", 15);
|
|
||||||
hashMap.put("#sendEmailUser#", emailTemplate.getEmailUser());
|
|
||||||
hashMap.put("#companyName#", "BunnyAdmin");
|
|
||||||
|
|
||||||
// 发送邮件
|
|
||||||
concreteSenderEmailTemplate.sendEmailTemplate(email, emailTemplate, hashMap);
|
|
||||||
|
|
||||||
// 在Redis中存储验证码
|
|
||||||
redisTemplate.opsForValue().set(RedisUserConstant.getAdminUserEmailCodePrefix(email), emailCode, RedisUserConstant.REDIS_EXPIRATION_TIME, TimeUnit.MINUTES);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 刷新用户token
|
|
||||||
*
|
|
||||||
* @param dto 请求token
|
|
||||||
* @return 刷新token返回内容
|
|
||||||
*/
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public RefreshTokenVo refreshToken(@NotNull RefreshTokenDto dto) {
|
|
||||||
Long userId = JwtTokenUtil.getUserId(dto.getRefreshToken());
|
|
||||||
AdminUser adminUser = getOne(Wrappers.<AdminUser>lambdaQuery().eq(AdminUser::getId, userId));
|
|
||||||
|
|
||||||
// 用户存在且没有禁用
|
|
||||||
if (adminUser == null) throw new AuthCustomerException(ResultCodeEnum.USER_IS_EMPTY);
|
|
||||||
if (adminUser.getStatus()) throw new AuthCustomerException(ResultCodeEnum.FAIL_NO_ACCESS_DENIED_USER_LOCKED);
|
|
||||||
|
|
||||||
LoginVo buildUserVo = userUtil.buildLoginUserVo(adminUser, dto.getReadMeDay());
|
|
||||||
RefreshTokenVo refreshTokenVo = new RefreshTokenVo();
|
|
||||||
BeanUtils.copyProperties(buildUserVo, refreshTokenVo);
|
|
||||||
|
|
||||||
return refreshTokenVo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 退出登录
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void logout() {
|
|
||||||
// 获取上下文对象中的用户ID和用户token
|
|
||||||
LoginVo loginVo = BaseContext.getLoginVo();
|
|
||||||
String token = loginVo.getToken();
|
|
||||||
Long userId = BaseContext.getUserId();
|
|
||||||
|
|
||||||
// 获取IP地址
|
|
||||||
String ipAddr = IpUtil.getCurrentUserIpAddress().getIpAddr();
|
|
||||||
String ipRegion = IpUtil.getCurrentUserIpAddress().getIpRegion();
|
|
||||||
|
|
||||||
// 查询用户信息
|
|
||||||
AdminUser adminUser = getOne(Wrappers.<AdminUser>lambdaQuery().eq(AdminUser::getId, userId));
|
|
||||||
UserLoginLog userLoginLog = userUtil.setUserLoginLog(adminUser, token, ipAddr, ipRegion, "logout");
|
|
||||||
userLoginLogMapper.insert(userLoginLog);
|
|
||||||
|
|
||||||
// 删除Redis中用户信息
|
|
||||||
redisTemplate.delete(RedisUserConstant.getAdminLoginInfoPrefix(adminUser.getUsername()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* * 获取用户信息
|
* * 获取用户信息
|
||||||
|
@ -226,18 +90,19 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, AdminUser> implemen
|
||||||
|
|
||||||
// 用户是否存在
|
// 用户是否存在
|
||||||
if (user == null) throw new AuthCustomerException(ResultCodeEnum.DATA_NOT_EXIST);
|
if (user == null) throw new AuthCustomerException(ResultCodeEnum.DATA_NOT_EXIST);
|
||||||
|
|
||||||
// 用户头像
|
// 用户头像
|
||||||
String avatar = user.getAvatar();
|
String avatar = user.getAvatar();
|
||||||
|
|
||||||
UserVo userVo = new UserVo();
|
UserVo userVo = new UserVo();
|
||||||
BeanUtils.copyProperties(user, userVo);
|
BeanUtils.copyProperties(user, userVo);
|
||||||
|
|
||||||
userVo.setAvatar(userUtil.checkGetUserAvatar(avatar));
|
String userAvatar = minioHelper.getUserAvatar(avatar);
|
||||||
|
userVo.setAvatar(userAvatar);
|
||||||
return userVo;
|
return userVo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* * 强制退出
|
* 强制退出
|
||||||
*
|
*
|
||||||
* @param id 用户id
|
* @param id 用户id
|
||||||
*/
|
*/
|
||||||
|
@ -251,11 +116,9 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, AdminUser> implemen
|
||||||
|
|
||||||
// 将用户登录保存在用户登录日志表中
|
// 将用户登录保存在用户登录日志表中
|
||||||
UserLoginLog userLoginLog = new UserLoginLog();
|
UserLoginLog userLoginLog = new UserLoginLog();
|
||||||
|
BeanUtils.copyProperties(adminUser, userLoginLog);
|
||||||
userLoginLog.setUserId(adminUser.getId());
|
userLoginLog.setUserId(adminUser.getId());
|
||||||
userLoginLog.setIpAddress(adminUser.getIpAddress());
|
userLoginLog.setType(UserConstant.FORCE_LOGOUT);
|
||||||
userLoginLog.setIpRegion(adminUser.getIpRegion());
|
|
||||||
userLoginLog.setToken(null);
|
|
||||||
userLoginLog.setType("forcedOffline");
|
|
||||||
userLoginLogMapper.insert(userLoginLog);
|
userLoginLogMapper.insert(userLoginLog);
|
||||||
|
|
||||||
// 删除Redis中用户信息
|
// 删除Redis中用户信息
|
||||||
|
@ -304,8 +167,9 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, AdminUser> implemen
|
||||||
AdminUser user = getOne(Wrappers.<AdminUser>lambdaQuery().eq(AdminUser::getId, userId));
|
AdminUser user = getOne(Wrappers.<AdminUser>lambdaQuery().eq(AdminUser::getId, userId));
|
||||||
if (user == null) throw new AuthCustomerException(ResultCodeEnum.USER_IS_EMPTY);
|
if (user == null) throw new AuthCustomerException(ResultCodeEnum.USER_IS_EMPTY);
|
||||||
|
|
||||||
// 检查用户头像
|
// 检查用户头像,因为更新用户信息会带着用户之前的信息,如果没有更新头像,前端显示的http:xxx
|
||||||
dto.setAvatar(userUtil.checkPostUserAvatar(dto.getAvatar()));
|
String userAvatar = minioHelper.formatUserAvatar(dto.getAvatar());
|
||||||
|
dto.setAvatar(userAvatar);
|
||||||
|
|
||||||
// 更新用户
|
// 更新用户
|
||||||
AdminUser adminUser = new AdminUser();
|
AdminUser adminUser = new AdminUser();
|
||||||
|
@ -315,7 +179,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, AdminUser> implemen
|
||||||
|
|
||||||
// 重新生成用户信息到Redis中
|
// 重新生成用户信息到Redis中
|
||||||
BeanUtils.copyProperties(dto, user);
|
BeanUtils.copyProperties(dto, user);
|
||||||
userUtil.buildUserVo(user, RedisUserConstant.REDIS_EXPIRATION_TIME);
|
userloginHelper.buildLoginUserVo(user, RedisUserConstant.REDIS_EXPIRATION_TIME);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -363,7 +227,7 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, AdminUser> implemen
|
||||||
List<AdminUserVo> voList = page.getRecords().stream()
|
List<AdminUserVo> voList = page.getRecords().stream()
|
||||||
.map(adminUser -> {
|
.map(adminUser -> {
|
||||||
// 如果存在用户头像,则设置用户头像
|
// 如果存在用户头像,则设置用户头像
|
||||||
String avatar = userUtil.checkGetUserAvatar(adminUser.getAvatar());
|
String avatar = minioHelper.getUserAvatar(adminUser.getAvatar());
|
||||||
|
|
||||||
AdminUserVo adminUserVo = new AdminUserVo();
|
AdminUserVo adminUserVo = new AdminUserVo();
|
||||||
BeanUtils.copyProperties(adminUser, adminUserVo);
|
BeanUtils.copyProperties(adminUser, adminUserVo);
|
||||||
|
@ -442,15 +306,18 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, AdminUser> implemen
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新头像
|
// 更新头像
|
||||||
userUtil.uploadAvatarByAdmin(dto, adminUser);
|
uploadAvatarByAdmin(dto, adminUser);
|
||||||
|
|
||||||
// 构建用户返回信息,同步到redis
|
// 构建用户返回信息,同步到redis
|
||||||
userUtil.buildUserVo(adminUser, RedisUserConstant.REDIS_EXPIRATION_TIME);
|
userloginHelper.buildLoginUserVo(adminUser, RedisUserConstant.REDIS_EXPIRATION_TIME);
|
||||||
|
|
||||||
// 更新密码,放在最后,如果更新密码就将密码删除
|
// 更新密码,放在最后,如果更新密码就将密码删除
|
||||||
userUtil.updateUserPasswordByAdmin(adminUser);
|
updateUserPasswordByAdmin(adminUser);
|
||||||
|
|
||||||
updateById(adminUser);
|
updateById(adminUser);
|
||||||
|
// 删除Redis中用户信息
|
||||||
|
String loginInfoPrefix = RedisUserConstant.getAdminLoginInfoPrefix(adminUser.getUsername());
|
||||||
|
redisTemplate.delete(loginInfoPrefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -471,11 +338,56 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, AdminUser> implemen
|
||||||
// 逻辑删除
|
// 逻辑删除
|
||||||
removeByIds(ids);
|
removeByIds(ids);
|
||||||
|
|
||||||
// 删除用 也要删除对应的 角色和部门,但是如果做的时物理删除就不需要,因为数据库中设置了外键检查,如果删除用户,相关表也会删除
|
|
||||||
// 删除部门相关
|
// 删除部门相关
|
||||||
userDeptMapper.deleteBatchIdsByUserIds(ids);
|
userDeptMapper.deleteBatchIdsByUserIds(ids);
|
||||||
|
|
||||||
// 删除用户角色相关
|
// 删除用户角色相关
|
||||||
userRoleMapper.deleteBatchIdsByUserIds(ids);
|
userRoleMapper.deleteBatchIdsByUserIds(ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* * 管理员修改管理员用户密码
|
||||||
|
*
|
||||||
|
* @param adminUser 管理员用户修改密码
|
||||||
|
*/
|
||||||
|
private void updateUserPasswordByAdmin(AdminUser adminUser) {
|
||||||
|
Long userId = adminUser.getId();
|
||||||
|
String password = adminUser.getPassword();
|
||||||
|
|
||||||
|
// 密码更新是否存在
|
||||||
|
if (!StringUtils.hasText(password)) return;
|
||||||
|
|
||||||
|
// 对密码加密
|
||||||
|
String encode = passwordEncoder.encode(password);
|
||||||
|
|
||||||
|
// 判断新密码是否与旧密码相同
|
||||||
|
if (adminUser.getPassword().equals(encode)) {
|
||||||
|
throw new AuthCustomerException(ResultCodeEnum.UPDATE_NEW_PASSWORD_SAME_AS_OLD_PASSWORD);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新用户密码
|
||||||
|
adminUser.setPassword(encode);
|
||||||
|
adminUser.setId(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理员上传用户头像
|
||||||
|
*
|
||||||
|
* @param dto 管理员用户修改头像
|
||||||
|
*/
|
||||||
|
private void uploadAvatarByAdmin(AdminUserUpdateDto dto, AdminUser adminUser) {
|
||||||
|
MultipartFile avatar = dto.getAvatar();
|
||||||
|
Long userId = dto.getId();
|
||||||
|
|
||||||
|
// 上传头像是否存在
|
||||||
|
if (avatar == null) return;
|
||||||
|
|
||||||
|
// 上传头像
|
||||||
|
FileUploadDto uploadDto = FileUploadDto.builder().file(avatar).type(MinioConstant.avatar).build();
|
||||||
|
FileInfoVo fileInfoVo = filesService.upload(uploadDto);
|
||||||
|
|
||||||
|
// 更新用户
|
||||||
|
adminUser.setId(userId);
|
||||||
|
adminUser.setAvatar(fileInfoVo.getFilepath());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
package cn.bunny.services.utils.email;
|
package cn.bunny.services.utils.email;
|
||||||
|
|
||||||
import cn.bunny.services.config.mail.MailSenderConfiguration;
|
|
||||||
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
|
||||||
import cn.bunny.services.domain.common.model.dto.email.EmailSend;
|
import cn.bunny.services.domain.common.model.dto.email.EmailSend;
|
||||||
import cn.bunny.services.domain.common.model.dto.email.EmailSendInit;
|
import cn.bunny.services.domain.common.model.dto.email.EmailSendInit;
|
||||||
|
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
||||||
import cn.bunny.services.domain.system.email.entity.EmailTemplate;
|
import cn.bunny.services.domain.system.email.entity.EmailTemplate;
|
||||||
import cn.bunny.services.domain.system.email.entity.EmailUsers;
|
import cn.bunny.services.domain.system.email.entity.EmailUsers;
|
||||||
import cn.bunny.services.exception.AuthCustomerException;
|
import cn.bunny.services.exception.AuthCustomerException;
|
||||||
|
import cn.bunny.services.mail.MailSenderConfiguration;
|
||||||
import cn.bunny.services.mapper.configuration.EmailUsersMapper;
|
import cn.bunny.services.mapper.configuration.EmailUsersMapper;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
import jakarta.mail.MessagingException;
|
import jakarta.mail.MessagingException;
|
||||||
|
|
|
@ -5,6 +5,7 @@ import cn.bunny.services.domain.common.constant.RedisUserConstant;
|
||||||
import cn.bunny.services.domain.common.constant.SecurityConfigConstant;
|
import cn.bunny.services.domain.common.constant.SecurityConfigConstant;
|
||||||
import cn.bunny.services.domain.system.system.entity.AdminUser;
|
import cn.bunny.services.domain.system.system.entity.AdminUser;
|
||||||
import cn.bunny.services.mapper.system.UserMapper;
|
import cn.bunny.services.mapper.system.UserMapper;
|
||||||
|
import cn.bunny.services.service.system.helper.UserLoginHelper;
|
||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
@ -22,15 +23,30 @@ public class RoleUtil {
|
||||||
private UserMapper userMapper;
|
private UserMapper userMapper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private UserUtil userUtil;
|
private UserLoginHelper userloginHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断是否是管理员
|
* 判断用户是否具有管理员权限
|
||||||
|
* <p>
|
||||||
|
* 管理员判定规则:
|
||||||
|
* 1. 系统默认管理员:用户ID为1的预设管理员账号(用户名为Administrator)
|
||||||
|
* 2. 角色授权管理员:用户角色列表包含"admin"角色的账号
|
||||||
|
* <p>
|
||||||
|
* 权限控制说明:
|
||||||
|
* - 管理员权限用于前端按钮级权限控制,支持以下通配符格式:
|
||||||
|
* - "*::*::*":全部模块的全部操作权限
|
||||||
|
* - "*::*" :指定模块的全部操作权限
|
||||||
|
* - "*" :基础通配权限
|
||||||
|
* - 若无细粒度按钮控制需求,可不设置具体权限
|
||||||
|
* 详细查看
|
||||||
|
* <a href="https://pure-admin.cn/pages/RBAC/#%E7%AC%AC%E4%BA%8C%E7%A7%8D%E6%A8%A1%E5%BC%8F-%E7%99%BB%E5%BD%95%E6%8E%A5%E5%8F%A3%E8%BF%94%E5%9B%9E%E6%8C%89%E9%92%AE%E7%BA%A7%E5%88%AB%E6%9D%83%E9%99%90">
|
||||||
|
* 查看前端权限设置
|
||||||
|
* </a>
|
||||||
*
|
*
|
||||||
* @param roleList 角色代码列表
|
* @param roleList 用户角色编码列表(可能包含"admin"角色)
|
||||||
* @param permissions 权限列表
|
* @param permissions 用户权限列表(用于前端按钮控制)
|
||||||
* @param adminUser 用户信息
|
* @param adminUser 用户实体对象(需包含userId字段)
|
||||||
* @return 是否是管理员
|
* @return true-是管理员,false-非管理员
|
||||||
*/
|
*/
|
||||||
public static boolean checkAdmin(List<String> roleList, List<String> permissions, AdminUser adminUser) {
|
public static boolean checkAdmin(List<String> roleList, List<String> permissions, AdminUser adminUser) {
|
||||||
// 判断是否是超级管理员
|
// 判断是否是超级管理员
|
||||||
|
@ -87,6 +103,6 @@ public class RoleUtil {
|
||||||
Object object = redisTemplate.opsForValue().get(adminLoginInfoPrefix);
|
Object object = redisTemplate.opsForValue().get(adminLoginInfoPrefix);
|
||||||
return object != null;
|
return object != null;
|
||||||
})
|
})
|
||||||
.forEach(user -> userUtil.buildUserVo(user, RedisUserConstant.REDIS_EXPIRATION_TIME));
|
.forEach(user -> userloginHelper.buildLoginUserVo(user, RedisUserConstant.REDIS_EXPIRATION_TIME));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,316 +0,0 @@
|
||||||
package cn.bunny.services.utils.system;
|
|
||||||
|
|
||||||
import cn.bunny.services.config.minio.MinioUtil;
|
|
||||||
import cn.bunny.services.domain.common.constant.LocalDateTimeConstant;
|
|
||||||
import cn.bunny.services.domain.common.constant.MinioConstant;
|
|
||||||
import cn.bunny.services.domain.common.constant.RedisUserConstant;
|
|
||||||
import cn.bunny.services.domain.common.constant.UserConstant;
|
|
||||||
import cn.bunny.services.domain.common.model.vo.LoginVo;
|
|
||||||
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
|
||||||
import cn.bunny.services.domain.system.files.dto.FileUploadDto;
|
|
||||||
import cn.bunny.services.domain.system.files.vo.FileInfoVo;
|
|
||||||
import cn.bunny.services.domain.system.log.entity.UserLoginLog;
|
|
||||||
import cn.bunny.services.domain.system.system.dto.user.AdminUserUpdateDto;
|
|
||||||
import cn.bunny.services.domain.system.system.entity.AdminUser;
|
|
||||||
import cn.bunny.services.domain.system.system.entity.Permission;
|
|
||||||
import cn.bunny.services.domain.system.system.entity.Role;
|
|
||||||
import cn.bunny.services.exception.AuthCustomerException;
|
|
||||||
import cn.bunny.services.mapper.log.UserLoginLogMapper;
|
|
||||||
import cn.bunny.services.mapper.system.PermissionMapper;
|
|
||||||
import cn.bunny.services.mapper.system.RoleMapper;
|
|
||||||
import cn.bunny.services.mapper.system.UserMapper;
|
|
||||||
import cn.bunny.services.service.system.FilesService;
|
|
||||||
import cn.bunny.services.utils.IpUtil;
|
|
||||||
import cn.bunny.services.utils.JwtTokenUtil;
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import org.springframework.beans.BeanUtils;
|
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
import org.springframework.web.context.request.RequestContextHolder;
|
|
||||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
@Component
|
|
||||||
public class UserUtil {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private MinioUtil minioUtil;
|
|
||||||
@Resource
|
|
||||||
private PermissionMapper permissionMapper;
|
|
||||||
@Resource
|
|
||||||
private RoleMapper roleMapper;
|
|
||||||
@Resource
|
|
||||||
private UserMapper userMapper;
|
|
||||||
@Resource
|
|
||||||
private UserLoginLogMapper userLoginLogMapper;
|
|
||||||
@Resource
|
|
||||||
private RedisTemplate<String, Object> redisTemplate;
|
|
||||||
@Resource
|
|
||||||
private PasswordEncoder passwordEncoder;
|
|
||||||
@Resource
|
|
||||||
private FilesService filesService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建登录用户返回对象
|
|
||||||
*
|
|
||||||
* @param user 用户
|
|
||||||
* @param readMeDay 保存登录信息时间
|
|
||||||
* @return 登录信息
|
|
||||||
*/
|
|
||||||
@Transactional(rollbackFor = AuthCustomerException.class)
|
|
||||||
public LoginVo buildLoginUserVo(AdminUser user, long readMeDay) {
|
|
||||||
Long userId = user.getId();
|
|
||||||
String email = user.getEmail();
|
|
||||||
String username = user.getUsername();
|
|
||||||
|
|
||||||
// 使用用户名创建token
|
|
||||||
String token = JwtTokenUtil.createToken(userId, username, (int) readMeDay);
|
|
||||||
|
|
||||||
// 获取IP地址并更新用户登录信息
|
|
||||||
String ipAddr = IpUtil.getCurrentUserIpAddress().getIpAddr();
|
|
||||||
String ipRegion = IpUtil.getCurrentUserIpAddress().getIpRegion();
|
|
||||||
|
|
||||||
// 设置用户IP地址,并更新用户信息
|
|
||||||
AdminUser updateUser = new AdminUser();
|
|
||||||
updateUser.setId(userId);
|
|
||||||
updateUser.setIpAddress(ipAddr);
|
|
||||||
updateUser.setIpRegion(ipRegion);
|
|
||||||
userMapper.updateById(updateUser);
|
|
||||||
|
|
||||||
// 将用户登录保存在用户登录日志表中
|
|
||||||
userLoginLogMapper.insert(setUserLoginLog(user, token, ipAddr, ipRegion, "login"));
|
|
||||||
|
|
||||||
// 设置用户返回信息
|
|
||||||
LoginVo loginVo = setLoginVo(user, token, readMeDay, ipAddr, ipRegion);
|
|
||||||
|
|
||||||
// 将Redis中验证码删除
|
|
||||||
redisTemplate.delete(RedisUserConstant.getAdminUserEmailCodePrefix(email));
|
|
||||||
|
|
||||||
// 将信息保存在Redis中,一定要确保用户名是唯一的
|
|
||||||
redisTemplate.opsForValue().set(RedisUserConstant.getAdminLoginInfoPrefix(username), loginVo, readMeDay, TimeUnit.DAYS);
|
|
||||||
|
|
||||||
return loginVo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* * 构建用户返回对象LoginVo
|
|
||||||
*
|
|
||||||
* @param user 用户对象
|
|
||||||
* @param readMeDay 记住我时间
|
|
||||||
*/
|
|
||||||
public void buildUserVo(AdminUser user, long readMeDay) {
|
|
||||||
Long userId = user.getId();
|
|
||||||
String username = user.getUsername();
|
|
||||||
String loginInfoPrefix = RedisUserConstant.getAdminLoginInfoPrefix(username);
|
|
||||||
|
|
||||||
// 使用用户名创建token
|
|
||||||
String token = JwtTokenUtil.createToken(userId, username, (int) readMeDay);
|
|
||||||
|
|
||||||
// 设置用户返回信息
|
|
||||||
LoginVo loginVo = setLoginVo(user, token, readMeDay, user.getIpAddress(), user.getIpRegion());
|
|
||||||
|
|
||||||
// 将信息保存在Redis中,一定要确保用户名是唯一的
|
|
||||||
redisTemplate.opsForValue().set(loginInfoPrefix, loginVo, readMeDay, TimeUnit.DAYS);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置更新用户设置内容
|
|
||||||
*
|
|
||||||
* @param user AdminUser
|
|
||||||
* @param token token
|
|
||||||
* @param readMeDay 记住我天数
|
|
||||||
* @param ipAddr IP地址
|
|
||||||
* @param ipRegion IP属地
|
|
||||||
* @return LoginVo
|
|
||||||
*/
|
|
||||||
public LoginVo setLoginVo(AdminUser user, String token, long readMeDay, String ipAddr, String ipRegion) {
|
|
||||||
Long userId = user.getId();
|
|
||||||
|
|
||||||
// 判断用户是否有头像,如果没有头像设置默认头像,并且用户头像不能和默认头像相同
|
|
||||||
String avatar = checkGetUserAvatar(user.getAvatar());
|
|
||||||
|
|
||||||
// 查找用户橘色
|
|
||||||
List<String> roles = new ArrayList<>(roleMapper.selectListByUserId(userId).stream().map(Role::getRoleCode).toList());
|
|
||||||
List<String> permissions = new ArrayList<>();
|
|
||||||
|
|
||||||
// 判断是否是 admin 如果是admin 赋予所有权限
|
|
||||||
boolean isAdmin = RoleUtil.checkAdmin(roles, permissions, user);
|
|
||||||
if (!isAdmin) {
|
|
||||||
permissions = permissionMapper.selectListByUserId(userId).stream().map(Permission::getPowerCode).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算过期时间,并格式化返回
|
|
||||||
LocalDateTime localDateTime = LocalDateTime.now();
|
|
||||||
LocalDateTime plusDay = localDateTime.plusDays(readMeDay);
|
|
||||||
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(LocalDateTimeConstant.YYYY_MM_DD_HH_MM_SS_SLASH);
|
|
||||||
String expires = plusDay.format(dateTimeFormatter);
|
|
||||||
|
|
||||||
// 构建返回对象,设置用户需要内容
|
|
||||||
LoginVo loginVo = new LoginVo();
|
|
||||||
BeanUtils.copyProperties(user, loginVo);
|
|
||||||
loginVo.setNickname(user.getNickname());
|
|
||||||
loginVo.setAvatar(avatar);
|
|
||||||
loginVo.setToken(token);
|
|
||||||
loginVo.setRefreshToken(token);
|
|
||||||
loginVo.setIpAddress(ipAddr);
|
|
||||||
loginVo.setIpRegion(ipRegion);
|
|
||||||
loginVo.setRoles(roles);
|
|
||||||
loginVo.setPermissions(permissions);
|
|
||||||
loginVo.setUpdateUser(userId);
|
|
||||||
loginVo.setPersonDescription(user.getSummary());
|
|
||||||
loginVo.setExpires(expires);
|
|
||||||
loginVo.setReadMeDay(readMeDay);
|
|
||||||
|
|
||||||
return loginVo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查用户头像是否合规
|
|
||||||
*
|
|
||||||
* @param avatar 头像字符串
|
|
||||||
* @return 整理好的头像内容
|
|
||||||
*/
|
|
||||||
public String checkPostUserAvatar(String avatar) {
|
|
||||||
// 如果用户没有头像或者用户头像和默认头像相同,返回默认头像
|
|
||||||
String userAvatar = UserConstant.USER_AVATAR;
|
|
||||||
if (!StringUtils.hasText(avatar) || avatar.equals(userAvatar)) return userAvatar;
|
|
||||||
|
|
||||||
// 替换前端发送的host前缀,将其删除,只保留路径名称
|
|
||||||
String regex = "^https?://.*?/(.*)";
|
|
||||||
Pattern pattern = Pattern.compile(regex);
|
|
||||||
Matcher matcher = pattern.matcher(avatar);
|
|
||||||
|
|
||||||
// 如果没有匹配
|
|
||||||
if (!matcher.matches()) return avatar;
|
|
||||||
|
|
||||||
// 匹配后返回内容
|
|
||||||
return "/" + matcher.group(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查用户头像是否合规
|
|
||||||
*
|
|
||||||
* @param avatar 头像字符串
|
|
||||||
* @return 整理好的头像内容
|
|
||||||
*/
|
|
||||||
public String checkGetUserAvatar(String avatar) {
|
|
||||||
// 如果用户没有头像或者用户头像和默认头像相同,返回默认头像
|
|
||||||
String userAvatar = UserConstant.USER_AVATAR;
|
|
||||||
if (!StringUtils.hasText(avatar) || avatar.equals(userAvatar)) return userAvatar;
|
|
||||||
|
|
||||||
// 替换前端发送的host前缀,将其删除,只保留路径名称
|
|
||||||
String regex = "^https?://.*?/(.*)";
|
|
||||||
Pattern pattern = Pattern.compile(regex);
|
|
||||||
Matcher matcher = pattern.matcher(avatar);
|
|
||||||
|
|
||||||
// 如果没有匹配
|
|
||||||
if (matcher.matches()) return avatar;
|
|
||||||
|
|
||||||
// 匹配后返回内容
|
|
||||||
return minioUtil.getObjectNameFullPath(avatar);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置用户登录日志内容
|
|
||||||
*
|
|
||||||
* @param user AdminUser
|
|
||||||
* @param token token
|
|
||||||
* @param ipAddr IP地址
|
|
||||||
* @param ipRegion IP属地
|
|
||||||
* @param type 类型登录/退出
|
|
||||||
* @return UserLoginLog
|
|
||||||
*/
|
|
||||||
public UserLoginLog setUserLoginLog(AdminUser user, String token, String ipAddr, String ipRegion, String type) {
|
|
||||||
Long userId = user.getId();
|
|
||||||
|
|
||||||
UserLoginLog userLoginLog = new UserLoginLog();
|
|
||||||
userLoginLog.setUsername(user.getUsername());
|
|
||||||
userLoginLog.setUserId(userId);
|
|
||||||
userLoginLog.setIpAddress(ipAddr);
|
|
||||||
userLoginLog.setIpRegion(ipRegion);
|
|
||||||
userLoginLog.setToken(token);
|
|
||||||
userLoginLog.setType(type);
|
|
||||||
userLoginLog.setCreateUser(userId);
|
|
||||||
userLoginLog.setUpdateUser(userId);
|
|
||||||
userLoginLog.setCreateTime(LocalDateTime.now());
|
|
||||||
userLoginLog.setUpdateTime(LocalDateTime.now());
|
|
||||||
|
|
||||||
// 当前请求request
|
|
||||||
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
|
||||||
if (requestAttributes == null) return userLoginLog;
|
|
||||||
HttpServletRequest request = requestAttributes.getRequest();
|
|
||||||
|
|
||||||
// 获取User-Agent
|
|
||||||
String userAgent = request.getHeader("User-Agent");
|
|
||||||
userLoginLog.setUserAgent(userAgent);
|
|
||||||
|
|
||||||
// 获取X-Requested-With
|
|
||||||
String xRequestedWith = request.getHeader("X-Requested-With");
|
|
||||||
userLoginLog.setXRequestedWith(xRequestedWith);
|
|
||||||
|
|
||||||
return userLoginLog;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* * 管理员修改管理员用户密码
|
|
||||||
*
|
|
||||||
* @param adminUser 管理员用户修改密码
|
|
||||||
*/
|
|
||||||
public void updateUserPasswordByAdmin(AdminUser adminUser) {
|
|
||||||
Long userId = adminUser.getId();
|
|
||||||
String password = adminUser.getPassword();
|
|
||||||
|
|
||||||
// 密码更新是否存在
|
|
||||||
if (!StringUtils.hasText(password)) return;
|
|
||||||
|
|
||||||
// 对密码加密
|
|
||||||
String encode = passwordEncoder.encode(password);
|
|
||||||
|
|
||||||
// 判断新密码是否与旧密码相同
|
|
||||||
if (adminUser.getPassword().equals(encode))
|
|
||||||
throw new AuthCustomerException(ResultCodeEnum.UPDATE_NEW_PASSWORD_SAME_AS_OLD_PASSWORD);
|
|
||||||
|
|
||||||
// 更新用户密码
|
|
||||||
adminUser.setPassword(encode);
|
|
||||||
adminUser.setId(userId);
|
|
||||||
|
|
||||||
// 删除Redis中用户信息
|
|
||||||
String loginInfoPrefix = RedisUserConstant.getAdminLoginInfoPrefix(adminUser.getUsername());
|
|
||||||
redisTemplate.delete(loginInfoPrefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 管理员上传用户头像
|
|
||||||
*
|
|
||||||
* @param dto 管理员用户修改头像
|
|
||||||
*/
|
|
||||||
public void uploadAvatarByAdmin(AdminUserUpdateDto dto, AdminUser adminUser) {
|
|
||||||
MultipartFile avatar = dto.getAvatar();
|
|
||||||
Long userId = dto.getId();
|
|
||||||
|
|
||||||
// 上传头像是否存在
|
|
||||||
if (avatar == null) return;
|
|
||||||
|
|
||||||
// 上传头像
|
|
||||||
FileUploadDto uploadDto = FileUploadDto.builder().file(avatar).type(MinioConstant.avatar).build();
|
|
||||||
FileInfoVo fileInfoVo = filesService.upload(uploadDto);
|
|
||||||
|
|
||||||
// 更新用户
|
|
||||||
adminUser.setId(userId);
|
|
||||||
adminUser.setAvatar(fileInfoVo.getFilepath());
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue