Merge branch 'dev'
This commit is contained in:
commit
f3ea4ffdfa
|
@ -26,6 +26,7 @@ ENTRYPOINT ["java","-jar","/home/server/app.jar"]
|
|||
|
||||
#暴露 8000 端口
|
||||
EXPOSE 8000
|
||||
EXPOSE 7070
|
||||
|
||||
# 生产环境
|
||||
# mvn clean package -Pprod -DskipTests
|
||||
|
|
|
@ -3,7 +3,7 @@ package cn.bunny.services.controller.configuration;
|
|||
import cn.bunny.services.domain.system.configuration.dto.WebConfigurationDto;
|
||||
import cn.bunny.services.domain.system.configuration.entity.WebConfiguration;
|
||||
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.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.service.configuration.ConfigurationService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
package cn.bunny.services.controller.configuration;
|
||||
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
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.system.email.dto.EmailTemplateAddDto;
|
||||
import cn.bunny.services.domain.system.email.dto.EmailTemplateDto;
|
||||
import cn.bunny.services.domain.system.email.dto.EmailTemplateUpdateDto;
|
||||
import cn.bunny.services.domain.system.email.entity.EmailTemplate;
|
||||
import cn.bunny.services.domain.system.email.vo.EmailTemplateVo;
|
||||
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.ResultCodeEnum;
|
||||
import cn.bunny.services.service.configuration.EmailTemplateService;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
|
@ -71,7 +71,7 @@ public class EmailTemplateController {
|
|||
}
|
||||
|
||||
@Operation(summary = "全部邮件类型列表", description = "获取全部邮件类型列表", tags = "emailTemplate::query")
|
||||
@GetMapping("public")
|
||||
@GetMapping("private")
|
||||
public Result<List<Map<String, String>>> getEmailTypeList() {
|
||||
List<Map<String, String>> list = emailTemplateService.getEmailTypeList();
|
||||
return Result.success(list);
|
||||
|
|
|
@ -7,7 +7,7 @@ import cn.bunny.services.domain.system.email.entity.EmailUsers;
|
|||
import cn.bunny.services.domain.system.email.vo.EmailUsersVo;
|
||||
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.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.service.configuration.EmailUsersService;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
|
|
|
@ -8,7 +8,7 @@ import cn.bunny.services.domain.system.i18n.entity.I18n;
|
|||
import cn.bunny.services.domain.system.i18n.vo.I18nVo;
|
||||
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.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.service.configuration.I18nService;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
|
|
|
@ -5,7 +5,7 @@ import cn.bunny.services.domain.system.i18n.dto.I18nTypeDto;
|
|||
import cn.bunny.services.domain.system.i18n.dto.I18nTypeUpdateDto;
|
||||
import cn.bunny.services.domain.system.i18n.vo.I18nTypeVo;
|
||||
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.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.service.configuration.I18nTypeService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
|
|
@ -7,7 +7,7 @@ import cn.bunny.services.domain.system.menuIcon.entity.MenuIcon;
|
|||
import cn.bunny.services.domain.system.menuIcon.vo.MenuIconVo;
|
||||
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.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.service.configuration.MenuIconService;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
|
|
|
@ -5,7 +5,7 @@ import cn.bunny.services.domain.system.log.entity.ScheduleExecuteLog;
|
|||
import cn.bunny.services.domain.system.log.vo.ScheduleExecuteLogVo;
|
||||
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.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.service.log.ScheduleExecuteLogService;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
|
|
|
@ -6,7 +6,7 @@ import cn.bunny.services.domain.system.log.vo.UserLoginLogLocalVo;
|
|||
import cn.bunny.services.domain.system.log.vo.UserLoginLogVo;
|
||||
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.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.service.log.UserLoginLogService;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
|
|
|
@ -9,7 +9,7 @@ import cn.bunny.services.domain.system.message.vo.MessageReceivedWithUserVo;
|
|||
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.Result;
|
||||
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.service.message.MessageService;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
|
|
|
@ -8,7 +8,7 @@ import cn.bunny.services.domain.system.message.vo.MessageReceivedWithMessageVo;
|
|||
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.Result;
|
||||
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.service.message.MessageReceivedService;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
|
|
|
@ -7,7 +7,7 @@ import cn.bunny.services.domain.system.message.entity.MessageType;
|
|||
import cn.bunny.services.domain.system.message.vo.MessageTypeVo;
|
||||
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.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.service.message.MessageTypeService;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
|
|
|
@ -3,7 +3,7 @@ package cn.bunny.services.controller.schedule;
|
|||
import cn.bunny.services.aop.scanner.QuartzSchedulersScanner;
|
||||
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.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.system.quartz.dto.SchedulersAddDto;
|
||||
import cn.bunny.services.domain.system.quartz.dto.SchedulersDto;
|
||||
import cn.bunny.services.domain.system.quartz.dto.SchedulersUpdateDto;
|
||||
|
|
|
@ -7,7 +7,7 @@ import cn.bunny.services.domain.system.quartz.entity.SchedulersGroup;
|
|||
import cn.bunny.services.domain.system.quartz.vo.SchedulersGroupVo;
|
||||
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.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.service.schedule.SchedulersGroupService;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
|
|
|
@ -7,7 +7,7 @@ import cn.bunny.services.domain.system.system.entity.Dept;
|
|||
import cn.bunny.services.domain.system.system.vo.DeptVo;
|
||||
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.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.service.system.DeptService;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
|
|
|
@ -10,7 +10,7 @@ import cn.bunny.services.domain.system.files.vo.FileInfoVo;
|
|||
import cn.bunny.services.domain.system.files.vo.FilesVo;
|
||||
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.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.service.system.FilesService;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
|
|
|
@ -4,7 +4,7 @@ import cn.bunny.services.aop.scanner.ControllerApiPermissionScanner;
|
|||
import cn.bunny.services.domain.common.model.dto.scanner.ScannerControllerInfoVo;
|
||||
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.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.system.system.dto.power.PermissionAddDto;
|
||||
import cn.bunny.services.domain.system.system.dto.power.PermissionDto;
|
||||
import cn.bunny.services.domain.system.system.dto.power.PermissionUpdateBatchByParentIdDto;
|
||||
|
|
|
@ -7,7 +7,7 @@ import cn.bunny.services.domain.system.system.entity.Role;
|
|||
import cn.bunny.services.domain.system.system.vo.RoleVo;
|
||||
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.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.service.system.RoleService;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
|
|
|
@ -5,7 +5,7 @@ import cn.bunny.services.domain.system.system.dto.router.RouterUpdateDto;
|
|||
import cn.bunny.services.domain.system.system.vo.router.RouterManageVo;
|
||||
import cn.bunny.services.domain.system.system.vo.router.WebUserRouterVo;
|
||||
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.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.service.system.RouterService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
package cn.bunny.services.controller.system;
|
||||
|
||||
import cn.bunny.services.domain.common.model.vo.LoginVo;
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
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.ResultCodeEnum;
|
||||
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.AdminUserUpdateDto;
|
||||
|
@ -91,13 +90,13 @@ public class UserController {
|
|||
|
||||
@Operation(summary = "已登录用户", description = "查询缓存中已登录用户", tags = "user::query")
|
||||
@GetMapping("getCacheUserPage/{page}/{limit}")
|
||||
public Result<PageResult<LoginVo>> getCacheUserPage(
|
||||
public Result<PageResult<UserVo>> getCacheUserPage(
|
||||
@Parameter(name = "page", description = "当前页", required = true)
|
||||
@PathVariable("page") Integer page,
|
||||
@Parameter(name = "limit", description = "每页记录数", required = true)
|
||||
@PathVariable("limit") Integer limit) {
|
||||
Page<AdminUser> pageParams = new Page<>(page, limit);
|
||||
PageResult<LoginVo> pageResult = userService.getCacheUserPage(pageParams);
|
||||
PageResult<UserVo> pageResult = userService.getCacheUserPage(pageParams);
|
||||
return Result.success(pageResult);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ 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.common.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.system.system.dto.user.AdminUserUpdateByLocalUserDto;
|
||||
import cn.bunny.services.domain.system.system.dto.user.LoginDto;
|
||||
import cn.bunny.services.domain.system.system.dto.user.RefreshTokenDto;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
server:
|
||||
port: 8000
|
||||
|
||||
tomcat:
|
||||
threads:
|
||||
max: 1000
|
||||
spring:
|
||||
profiles:
|
||||
active: @profiles.active@
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
public abstract class AbstractPermissionCheckHandler {
|
||||
|
||||
private AbstractPermissionCheckHandler abstractPermissionCheckHandler;
|
||||
|
||||
public AbstractPermissionCheckHandler(AbstractPermissionCheckHandler abstractPermissionCheckHandler) {
|
||||
this.abstractPermissionCheckHandler = abstractPermissionCheckHandler;
|
||||
}
|
||||
|
||||
abstract protected void checkPermission(String requestUrl);
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
package cn.bunny.services.config;
|
||||
|
||||
import cn.bunny.services.utils.TokenUtilsTest;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.test.context.TestConfiguration;
|
||||
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
// @TestConfiguration
|
||||
// public class WebConfig {
|
||||
// @Value("${server.port}")
|
||||
// private String port;
|
||||
//
|
||||
// @Autowired
|
||||
// private TokenUtilsTest tokenUtils;
|
||||
//
|
||||
// @Bean
|
||||
// public RestTemplate restTemplate(RestTemplateBuilder builder) {
|
||||
// String token = tokenUtils.getToken();
|
||||
// return builder.rootUri("http://localhost:" + port)
|
||||
// .defaultHeader("token", token)
|
||||
// .defaultHeader("Content-Type", "application/json")
|
||||
// .build();
|
||||
// }
|
||||
// }
|
|
@ -1,37 +0,0 @@
|
|||
package cn.bunny.services.controller;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.openqa.selenium.chrome.ChromeDriver;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@SpringBootTest
|
||||
@AutoConfigureMockMvc
|
||||
public class LoginTest {
|
||||
private ChromeDriver chromeDriver;
|
||||
|
||||
@BeforeEach
|
||||
void setUpMockMvc() {
|
||||
chromeDriver = new ChromeDriver();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
chromeDriver.quit();
|
||||
}
|
||||
|
||||
// 测试登录页面
|
||||
@Test
|
||||
// @WithMockUser(username = "Administrator", password = "admin123", roles = "admin")
|
||||
// @WithUserDetails("Administrator")
|
||||
void testLogin() throws InterruptedException {
|
||||
chromeDriver.get("http://localhost:7000/");
|
||||
TimeUnit.MINUTES.sleep(100);
|
||||
chromeDriver.manage().timeouts().implicitlyWait(Duration.of(1000L, TimeUnit.SECONDS.toChronoUnit()));
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
package cn.bunny.services.controller;
|
||||
|
||||
import cn.bunny.services.aop.scanner.ControllerApiPermissionScanner;
|
||||
import cn.bunny.services.domain.common.model.dto.scanner.ScannerControllerInfoVo;
|
||||
import cn.bunny.services.domain.system.system.entity.Permission;
|
||||
import cn.bunny.services.service.system.PermissionService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@SpringBootTest
|
||||
class TestControllerTest {
|
||||
|
||||
@Autowired
|
||||
private PermissionService permissionService;
|
||||
|
||||
@Test
|
||||
void test1() {
|
||||
List<ScannerControllerInfoVo> list = ControllerApiPermissionScanner.getSystemApiInfoList();
|
||||
list.forEach(parent -> {
|
||||
String parentPath = parent.getPath();
|
||||
String powerCode = parentPath.replace("/api/", "").replace("/**", "");
|
||||
powerCode = "user::" + powerCode;
|
||||
|
||||
Permission permission = new Permission();
|
||||
permission.setParentId(0L);
|
||||
permission.setPowerCode(powerCode);
|
||||
permission.setPowerName(parent.getSummary());
|
||||
permission.setRequestUrl(parentPath);
|
||||
permissionService.saveOrUpdate(permission);
|
||||
// System.out.println(permission);
|
||||
|
||||
List<Permission> permissionList = parent.getChildren().stream()
|
||||
.map(children -> {
|
||||
Permission childrenPermission = new Permission();
|
||||
childrenPermission.setParentId(permission.getId());
|
||||
childrenPermission.setPowerName(children.getSummary());
|
||||
if (!children.getPowerCodes().isEmpty()) {
|
||||
String ChildrenPowerCode = children.getPowerCodes().get(0);
|
||||
childrenPermission.setPowerCode(ChildrenPowerCode);
|
||||
}
|
||||
|
||||
String childrenPath = children.getPath();
|
||||
childrenPermission.setRequestUrl(childrenPath);
|
||||
childrenPermission.setRequestMethod(children.getHttpMethod());
|
||||
|
||||
return childrenPermission;
|
||||
})
|
||||
.toList();
|
||||
// System.out.println(JSON.toJSONString(permissionList));
|
||||
permissionService.saveOrUpdateBatch(permissionList);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,163 +0,0 @@
|
|||
package cn.bunny.services.controller.configuration;
|
||||
|
||||
import cn.bunny.services.domain.system.configuration.dto.WebConfigurationDto;
|
||||
import cn.bunny.services.domain.system.configuration.entity.WebConfiguration;
|
||||
import cn.bunny.services.domain.common.model.vo.result.Result;
|
||||
import cn.bunny.services.utils.TokenUtilsTest;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.TypeReference;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
@SpringBootTest
|
||||
@WebAppConfiguration
|
||||
class ConfigurationControllerTest {
|
||||
private static final String prefix = "/api/config";
|
||||
|
||||
@Autowired
|
||||
private WebApplicationContext webApplicationContext;
|
||||
|
||||
@Autowired
|
||||
private TokenUtilsTest tokenUtils;
|
||||
|
||||
private MockMvc mockMvc;
|
||||
|
||||
private String token;
|
||||
|
||||
@BeforeEach
|
||||
void setUpMockMvc() {
|
||||
token = tokenUtils.getToken();
|
||||
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
|
||||
.apply(SecurityMockMvcConfigurers.springSecurity())
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
void webConfig() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders
|
||||
.get(prefix + "/noAuth/webConfig")
|
||||
.header("token", token))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
.andExpect(result -> {
|
||||
MockHttpServletResponse response = result.getResponse();
|
||||
String contentAsString = response.getContentAsString();
|
||||
|
||||
WebConfiguration webConfiguration = JSON.parseObject(contentAsString, WebConfiguration.class);
|
||||
|
||||
if (!webConfiguration.getTitle().equals("BunnyAdmin")) {
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
System.out.println(webConfiguration);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void getWebConfig() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders
|
||||
.request(HttpMethod.GET, prefix + "/getWebConfig")
|
||||
.header("token", token))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
.andExpect(result -> {
|
||||
MockHttpServletResponse response = result.getResponse();
|
||||
String contentAsString = response.getContentAsString();
|
||||
|
||||
Result<WebConfiguration> webConfigurationResult = JSON.parseObject(contentAsString, new TypeReference<>() {
|
||||
});
|
||||
|
||||
if (!webConfigurationResult.getCode().equals(200)) {
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
if (!webConfigurationResult.getData().getShowModel().equals("smart")) {
|
||||
throw new Exception();
|
||||
}
|
||||
System.out.println(contentAsString);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateWebConfiguration() throws Exception {
|
||||
AtomicReference<WebConfigurationDto> webConfigurationDto = new AtomicReference<>();
|
||||
String testTitle = "修改的之";
|
||||
|
||||
// 获取原本的配置信息
|
||||
mockMvc.perform(MockMvcRequestBuilders
|
||||
.request(HttpMethod.GET, prefix + "/getWebConfig")
|
||||
.header("token", token))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
.andExpect(result -> {
|
||||
MockHttpServletResponse response = result.getResponse();
|
||||
String contentAsString = response.getContentAsString();
|
||||
|
||||
System.out.println(contentAsString);
|
||||
|
||||
Result<WebConfiguration> webConfigurationResult = JSON.parseObject(contentAsString, new TypeReference<>() {
|
||||
});
|
||||
|
||||
WebConfigurationDto dto = new WebConfigurationDto();
|
||||
BeanUtils.copyProperties(webConfigurationResult.getData(), dto);
|
||||
|
||||
webConfigurationDto.set(dto);
|
||||
});
|
||||
|
||||
// 修改原本的测试内容
|
||||
webConfigurationDto.get().setTitle(testTitle);
|
||||
|
||||
// 测试修改方法
|
||||
mockMvc.perform(MockMvcRequestBuilders.put(prefix + "/updateWebConfiguration")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(JSON.toJSONString(webConfigurationDto.get()))
|
||||
.header("token", token))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
.andExpect(result -> {
|
||||
String contentAsString = result.getResponse().getContentAsString();
|
||||
|
||||
System.out.println(contentAsString);
|
||||
|
||||
Result<String> stringResult = JSON.parseObject(contentAsString, new TypeReference<>() {
|
||||
});
|
||||
|
||||
if (!stringResult.getCode().equals(200)) {
|
||||
throw new Exception();
|
||||
}
|
||||
});
|
||||
|
||||
// 验证是否修改成功
|
||||
mockMvc.perform(MockMvcRequestBuilders
|
||||
.request(HttpMethod.GET, prefix + "/getWebConfig")
|
||||
.header("token", token))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
.andExpect(result -> {
|
||||
MockHttpServletResponse response = result.getResponse();
|
||||
String contentAsString = response.getContentAsString();
|
||||
|
||||
Result<WebConfiguration> webConfigurationResult = JSON.parseObject(contentAsString, new TypeReference<>() {
|
||||
});
|
||||
|
||||
if (!webConfigurationResult.getCode().equals(200)) {
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
if (!webConfigurationResult.getData().getTitle().equals(testTitle)) {
|
||||
throw new Exception();
|
||||
}
|
||||
System.out.println(contentAsString);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,215 +0,0 @@
|
|||
package cn.bunny.services.controller.configuration;
|
||||
|
||||
import cn.bunny.services.domain.system.email.dto.EmailTemplateAddDto;
|
||||
import cn.bunny.services.domain.system.email.dto.EmailTemplateUpdateDto;
|
||||
import cn.bunny.services.domain.system.email.vo.EmailTemplateVo;
|
||||
import cn.bunny.services.domain.common.enums.EmailTemplateEnums;
|
||||
import cn.bunny.services.domain.common.model.vo.result.PageResult;
|
||||
import cn.bunny.services.domain.common.model.vo.result.Result;
|
||||
import cn.bunny.services.utils.TokenUtilsTest;
|
||||
import cn.hutool.crypto.digest.MD5;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.alibaba.fastjson2.TypeReference;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@SpringBootTest
|
||||
@WebAppConfiguration
|
||||
class EmailTemplateControllerTest {
|
||||
private static final String prefix = "/api/emailTemplate";
|
||||
|
||||
private String token;
|
||||
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Autowired
|
||||
private WebApplicationContext webApplicationContext;
|
||||
|
||||
@Autowired
|
||||
private TokenUtilsTest tokenUtilsTest;
|
||||
|
||||
@Autowired
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
token = tokenUtilsTest.getToken();
|
||||
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
|
||||
.apply(SecurityMockMvcConfigurers.springSecurity())
|
||||
.build();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void getEmailTemplatePage() throws Exception {
|
||||
String api = prefix + "/getEmailTemplateList/1/10";
|
||||
|
||||
mockMvc.perform(MockMvcRequestBuilders
|
||||
.get(api)
|
||||
.header("token", token)
|
||||
.contentType(MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||
.param("type", "code"))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
.andExpect(result -> {
|
||||
String contentAsString = result.getResponse().getContentAsString();
|
||||
JSONObject jsonObject = JSONObject.parseObject(contentAsString);
|
||||
|
||||
if (jsonObject == null) {
|
||||
throw new Exception(contentAsString);
|
||||
}
|
||||
System.out.println(jsonObject);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void getEmailTypeList() throws Exception {
|
||||
String api = prefix + "/getEmailTypes";
|
||||
|
||||
mockMvc.perform(MockMvcRequestBuilders.get(api).header("token", token))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
.andExpect(result -> {
|
||||
String contentAsString = result.getResponse().getContentAsString();
|
||||
JSONObject jsonObject = JSONObject.parseObject(contentAsString);
|
||||
|
||||
if (jsonObject == null) {
|
||||
throw new Exception(contentAsString);
|
||||
}
|
||||
|
||||
System.out.println(jsonObject);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void addEmailTemplate() throws Exception {
|
||||
String api = prefix + "/addEmailTemplate";
|
||||
|
||||
EmailTemplateAddDto dto = EmailTemplateAddDto.builder()
|
||||
.emailUser(2L)
|
||||
.body("哈哈哈")
|
||||
.templateName("测试")
|
||||
.subject("test")
|
||||
.type(EmailTemplateEnums.NOTIFICATION.getType())
|
||||
.isDefault(false)
|
||||
.build();
|
||||
|
||||
mockMvc.perform(MockMvcRequestBuilders
|
||||
.post(api)
|
||||
.header("token", token)
|
||||
.content(JSONObject.toJSONString(dto))
|
||||
.contentType(MediaType.APPLICATION_JSON))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
.andExpect(result -> {
|
||||
String contentAsString = result.getResponse().getContentAsString();
|
||||
JSONObject jsonObject = JSONObject.parseObject(contentAsString);
|
||||
|
||||
System.out.println(jsonObject);
|
||||
});
|
||||
|
||||
getEmailTemplatePage();
|
||||
}
|
||||
|
||||
@Test
|
||||
void updateEmailTemplate() throws Exception {
|
||||
String api = prefix + "/updateEmailTemplate";
|
||||
String restTemplateApi = prefix + "/getEmailTemplateList/1/10";
|
||||
|
||||
String url = UriComponentsBuilder.fromUriString(restTemplateApi)
|
||||
.queryParam("subject", "test")
|
||||
.build()
|
||||
.toUriString();
|
||||
|
||||
Result<PageResult<EmailTemplateVo>> result = restTemplate.exchange(
|
||||
url,
|
||||
HttpMethod.GET,
|
||||
new HttpEntity<>(null),
|
||||
new ParameterizedTypeReference<Result<PageResult<EmailTemplateVo>>>() {
|
||||
}
|
||||
).getBody();
|
||||
|
||||
if (result == null) throw new Exception();
|
||||
if (!result.getCode().equals(200)) throw new Exception(result.getMessage());
|
||||
if (result.getData().getList().isEmpty()) throw new Exception("没有测试数据");
|
||||
|
||||
EmailTemplateVo emailTemplateVo = result.getData().getList().get(0);
|
||||
EmailTemplateUpdateDto emailTemplateUpdateDto = new EmailTemplateUpdateDto();
|
||||
BeanUtils.copyProperties(emailTemplateVo, emailTemplateUpdateDto);
|
||||
|
||||
System.out.println(emailTemplateUpdateDto);
|
||||
|
||||
emailTemplateUpdateDto.setBody(MD5.create().digestHex16(LocalDateTime.now().toString()));
|
||||
mockMvc.perform(MockMvcRequestBuilders.put(api)
|
||||
.header("token", token)
|
||||
.content(JSON.toJSONString(emailTemplateUpdateDto))
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
)
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
.andExpect(result1 -> {
|
||||
String contentAsString = result1.getResponse().getContentAsString();
|
||||
var pageResultResult = JSONObject.parseObject(contentAsString, new TypeReference<Result<PageResult<EmailTemplateVo>>>() {
|
||||
});
|
||||
if (pageResultResult == null) throw new Exception(contentAsString);
|
||||
if (!pageResultResult.getCode().equals(200)) throw new Exception(pageResultResult.getMessage());
|
||||
|
||||
System.out.println(pageResultResult);
|
||||
});
|
||||
|
||||
result = restTemplate.exchange(
|
||||
url,
|
||||
HttpMethod.GET,
|
||||
new HttpEntity<>(null),
|
||||
new ParameterizedTypeReference<Result<PageResult<EmailTemplateVo>>>() {
|
||||
}
|
||||
).getBody();
|
||||
|
||||
if (result == null) throw new Exception();
|
||||
if (!result.getCode().equals(200)) throw new Exception(result.getMessage());
|
||||
emailTemplateVo = result.getData().getList().get(0);
|
||||
if (!emailTemplateVo.getBody().equals(emailTemplateUpdateDto.getBody())) {
|
||||
throw new Exception(emailTemplateUpdateDto.getBody());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void deleteEmailTemplate() throws Exception {
|
||||
String api = prefix + "/deleteEmailTemplate";
|
||||
List<Long> ids = new ArrayList<>();
|
||||
ids.add(1905180657917157378L);
|
||||
mockMvc.perform(MockMvcRequestBuilders
|
||||
.delete(api)
|
||||
.header("token", token)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(JSON.toJSONString(ids)))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
.andExpect(result -> {
|
||||
String contentAsString = result.getResponse().getContentAsString();
|
||||
JSONObject jsonObject = JSONObject.parseObject(contentAsString);
|
||||
System.out.println(jsonObject);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,179 +0,0 @@
|
|||
package cn.bunny.services.controller.log;
|
||||
|
||||
import cn.bunny.services.domain.system.log.dto.UserLoginLogDto;
|
||||
import cn.bunny.services.domain.system.log.entity.UserLoginLog;
|
||||
import cn.bunny.services.domain.system.log.vo.UserLoginLogLocalVo;
|
||||
import cn.bunny.services.domain.system.log.vo.UserLoginLogVo;
|
||||
import cn.bunny.services.domain.common.model.vo.result.PageResult;
|
||||
import cn.bunny.services.domain.common.model.vo.result.Result;
|
||||
import cn.bunny.services.service.log.UserLoginLogService;
|
||||
import cn.bunny.services.utils.TokenUtilsTest;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.TypeReference;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers;
|
||||
import org.springframework.test.context.web.WebAppConfiguration;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@SpringBootTest
|
||||
@WebAppConfiguration
|
||||
class UserLoginLogControllerTest {
|
||||
private static final String prefix = "/api/userLoginLog";
|
||||
|
||||
private WebTestClient testClient;
|
||||
|
||||
@Autowired
|
||||
private WebApplicationContext webApplicationContext;
|
||||
|
||||
@Autowired
|
||||
private UserLoginLogService userLoginLogService;
|
||||
|
||||
@Autowired
|
||||
private TokenUtilsTest tokenUtils;
|
||||
|
||||
private MockMvc mockMvc;
|
||||
|
||||
private String token;
|
||||
|
||||
@Autowired
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
token = tokenUtils.getToken();
|
||||
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext)
|
||||
.apply(SecurityMockMvcConfigurers.springSecurity())
|
||||
.build();
|
||||
|
||||
testClient = WebTestClient.bindToController(new UserLoginLogController()).build();
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void tearDown() {
|
||||
}
|
||||
|
||||
@Test
|
||||
void getUserLoginLogPage() throws Exception {
|
||||
UserLoginLogDto dto = UserLoginLogDto.builder()
|
||||
.username("bunny")
|
||||
.build();
|
||||
|
||||
mockMvc.perform(MockMvcRequestBuilders.get(prefix + "/getUserLoginLogList/1/10")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(JSON.toJSONString(dto))
|
||||
.header("token", token))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
.andExpect(result -> {
|
||||
MockHttpServletResponse response = result.getResponse();
|
||||
String contentAsString = response.getContentAsString();
|
||||
|
||||
System.out.println(contentAsString);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void getUserLoginLogPage2() {
|
||||
UserLoginLogDto dto = UserLoginLogDto.builder()
|
||||
.username("bunny")
|
||||
.build();
|
||||
Map<String, String> params = JSON.parseObject(JSON.toJSONString(dto), new TypeReference<>() {
|
||||
});
|
||||
|
||||
// 发送请求
|
||||
ResponseEntity<Result<PageResult<UserLoginLogVo>>> response = restTemplate.exchange(
|
||||
prefix + "/getUserLoginLogList/1/10",
|
||||
HttpMethod.GET,
|
||||
new HttpEntity<>(params),
|
||||
new ParameterizedTypeReference<>() {
|
||||
}
|
||||
);
|
||||
|
||||
Result<PageResult<UserLoginLogVo>> body = response.getBody();
|
||||
System.out.println(JSON.toJSONString(body));
|
||||
}
|
||||
|
||||
@Test
|
||||
void getUserLoginLogPageByUser() throws Exception {
|
||||
String api = prefix + "/noManage/getUserLoginLogListByLocalUser/1/10";
|
||||
|
||||
mockMvc.perform(MockMvcRequestBuilders.get(api)
|
||||
.header("token", token))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
.andExpect(result -> {
|
||||
MockHttpServletResponse response = result.getResponse();
|
||||
String contentAsString = response.getContentAsString();
|
||||
|
||||
System.out.println(contentAsString);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void getUserLoginLogPageByUser2() {
|
||||
String api = prefix + "/noManage/getUserLoginLogListByLocalUser/1/10";
|
||||
|
||||
testClient.get()
|
||||
.uri(api)
|
||||
.header("token", token)
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody(new ParameterizedTypeReference<Result<PageResult<UserLoginLogLocalVo>>>() {
|
||||
})
|
||||
.consumeWith(result -> {
|
||||
Result<PageResult<UserLoginLogLocalVo>> responseBody = result.getResponseBody();
|
||||
System.out.println(JSON.toJSONString(responseBody));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void deleteUserLoginLog() throws Exception {
|
||||
String api = prefix + "/deleteUserLoginLog";
|
||||
|
||||
Page<UserLoginLog> page = new Page<>(1, 10);
|
||||
List<UserLoginLog> deleteBeforeList = userLoginLogService.list(page);
|
||||
List<Long> ids = deleteBeforeList.stream().map(UserLoginLog::getId).limit(4).toList();
|
||||
List<Long> deleteBeforeIds = deleteBeforeList.stream().map(UserLoginLog::getId).toList();
|
||||
|
||||
log.info("要删除的ids: {}", ids);
|
||||
log.info("删除前ids数据:{}", deleteBeforeIds);
|
||||
|
||||
mockMvc.perform(MockMvcRequestBuilders
|
||||
.delete(api)
|
||||
.header("token", token)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(JSON.toJSONString(ids)))
|
||||
.andExpect(MockMvcResultMatchers.status().isOk())
|
||||
.andExpect(result -> {
|
||||
MockHttpServletResponse response = result.getResponse();
|
||||
String contentAsString = response.getContentAsString();
|
||||
System.out.println(contentAsString);
|
||||
});
|
||||
|
||||
deleteBeforeList = userLoginLogService.list(page);
|
||||
deleteBeforeIds = deleteBeforeList.stream().map(UserLoginLog::getId).toList();
|
||||
log.info("要删除的ids: {}", ids);
|
||||
log.info("删除前ids数据:{}", deleteBeforeIds);
|
||||
}
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
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,25 +0,0 @@
|
|||
package cn.bunny.services.utils;
|
||||
|
||||
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.service.system.helper.UserLoginHelper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class TokenUtilsTest {
|
||||
@Autowired
|
||||
private UserLoginHelper userUtil;
|
||||
|
||||
@Autowired
|
||||
private UserMapper userMapper;
|
||||
|
||||
public String getToken() {
|
||||
AdminUser adminUser = userMapper.selectOne(Wrappers.<AdminUser>lambdaQuery().eq(AdminUser::getUsername, "Administrator"));
|
||||
adminUser.setPassword("admin123");
|
||||
LoginVo loginVo = userUtil.buildLoginUserVo(adminUser, 7);
|
||||
return loginVo.getToken();
|
||||
}
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
package impl;
|
||||
|
||||
import cn.bunny.services.domain.common.model.dto.excel.I18nExcel;
|
||||
import cn.bunny.services.domain.system.i18n.entity.I18n;
|
||||
import cn.bunny.services.mapper.configuration.I18nMapper;
|
||||
import com.alibaba.excel.EasyExcel;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
public class I18nServiceImplTest extends ServiceImpl<I18nMapper, I18n> {
|
||||
|
||||
@Test
|
||||
void downloadI18nByExcel() {
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
try (ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream)) {
|
||||
// 查找默认语言内容
|
||||
List<I18n> i18nList = list();
|
||||
Map<String, List<I18nExcel>> hashMap = i18nList.stream()
|
||||
.collect(Collectors.groupingBy(
|
||||
I18n::getTypeName,
|
||||
Collectors.mapping((I18n i18n) -> {
|
||||
String keyName = i18n.getKeyName();
|
||||
String translation = i18n.getTranslation();
|
||||
return I18nExcel.builder().keyName(keyName).translation(translation).build();
|
||||
}, Collectors.toList())
|
||||
));
|
||||
|
||||
|
||||
hashMap.forEach((key, value) -> {
|
||||
// EasyExcel.write(key + ".xlsx", I18nExcel.class).sheet(key).doWrite(value);
|
||||
|
||||
try {
|
||||
ZipEntry zipEntry = new ZipEntry(key + ".xlsx");
|
||||
zipOutputStream.putNextEntry(zipEntry);
|
||||
|
||||
// 直接写入到ZipOutputStream
|
||||
EasyExcel.write(zipOutputStream, I18nExcel.class).sheet(key).doWrite(value);
|
||||
zipOutputStream.closeEntry();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package impl;
|
||||
|
||||
import cn.bunny.services.AuthServiceApplication;
|
||||
import cn.bunny.services.core.template.PermissionTreeProcessor;
|
||||
import cn.bunny.services.domain.common.model.dto.excel.PermissionExcel;
|
||||
import cn.bunny.services.domain.system.system.entity.Permission;
|
||||
import cn.bunny.services.mapper.system.PermissionMapper;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@SpringBootTest(classes = AuthServiceApplication.class)
|
||||
class PermissionServiceImplTest {
|
||||
|
||||
@Autowired
|
||||
private PermissionMapper permissionMapper;
|
||||
|
||||
@Test
|
||||
void exportPermission() {
|
||||
|
||||
List<Permission> permissionList = permissionMapper.selectList(null);
|
||||
List<PermissionExcel> permissionExcelList = permissionList.stream().map(permission -> {
|
||||
PermissionExcel permissionExcel = new PermissionExcel();
|
||||
BeanUtils.copyProperties(permission, permissionExcel);
|
||||
|
||||
return permissionExcel;
|
||||
}).toList();
|
||||
|
||||
PermissionTreeProcessor permissionTreeProcessor = new PermissionTreeProcessor();
|
||||
List<PermissionExcel> buildTree = permissionTreeProcessor.process(permissionExcelList);
|
||||
|
||||
System.out.println(JSON.toJSONString(buildTree));
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -127,5 +127,11 @@
|
|||
<artifactId>ip2region</artifactId>
|
||||
<version>2.6.5</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Could not write JSON: Java 8 date/time type `java.time.LocalDateTime` not supported by default -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
@ -18,7 +18,6 @@ import org.springframework.data.redis.cache.RedisCacheManager;
|
|||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.RedisSerializationContext;
|
||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||
|
@ -42,13 +41,14 @@ public class RedisConfiguration {
|
|||
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory connectionFactory) {
|
||||
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
|
||||
redisTemplate.setConnectionFactory(connectionFactory);
|
||||
|
||||
// 设置key序列化为string
|
||||
redisTemplate.setKeySerializer(new StringRedisSerializer());
|
||||
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
|
||||
|
||||
// 设置value序列化为JSON,使用GenericJackson2JsonRedisSerializer替换默认序列化
|
||||
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
|
||||
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
|
||||
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
|
||||
redisTemplate.setValueSerializer(jsonRedisSerializer());
|
||||
redisTemplate.setHashValueSerializer(jsonRedisSerializer());
|
||||
|
||||
// 开启Redis事务
|
||||
redisTemplate.setEnableTransactionSupport(true);
|
||||
|
|
|
@ -12,15 +12,57 @@ public class RedisUserConstant {
|
|||
public static final Integer Cookie_EXPIRATION_TIME = 5 * 60 * 60;// cookies 过期时间 5 分钟
|
||||
public static final String WEB_CONFIG_KEY = "webConfig::platformConfig";// web配置
|
||||
|
||||
private static final String ADMIN_LOGIN_INFO_PREFIX = "admin::login_info::";
|
||||
private static final String ADMIN_EMAIL_CODE_PREFIX = "admin::email_code::";
|
||||
/* 用户登录前缀 */
|
||||
private static final String USER_LOGIN_INFO_PREFIX = "user::login_info::";
|
||||
|
||||
/* 用户邮箱验证码前缀 */
|
||||
private static final String USER_EMAIL_CODE_PREFIX = "user::email_code::";
|
||||
|
||||
/* 用户角色前缀 */
|
||||
private static final String USER_ROLES_CODE_PREFIX = "user::roles::";
|
||||
|
||||
/* 用户权限前缀 */
|
||||
private static final String USER_PERMISSION_CODE_PREFIX = "user::permission::";
|
||||
|
||||
/**
|
||||
* 用户登录前缀
|
||||
*
|
||||
* @param user 用户名信息
|
||||
* @return 格式化后缓存前缀
|
||||
*/
|
||||
public static String getUserLoginInfoPrefix(String user) {
|
||||
return USER_LOGIN_INFO_PREFIX + user;
|
||||
|
||||
public static String getAdminLoginInfoPrefix(String adminUser) {
|
||||
return ADMIN_LOGIN_INFO_PREFIX + adminUser;
|
||||
}
|
||||
|
||||
public static String getAdminUserEmailCodePrefix(String adminUser) {
|
||||
return ADMIN_EMAIL_CODE_PREFIX + adminUser;
|
||||
/**
|
||||
* 用户邮箱前缀
|
||||
*
|
||||
* @param user 用户信息
|
||||
* @return 邮箱验证码前缀
|
||||
*/
|
||||
public static String getUserEmailCodePrefix(String user) {
|
||||
return USER_EMAIL_CODE_PREFIX + user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户角色前缀
|
||||
*
|
||||
* @param user 用户信息
|
||||
* @return 格式化后用户角色前缀
|
||||
*/
|
||||
public static String getUserRolesCodePrefix(String user) {
|
||||
return USER_ROLES_CODE_PREFIX + user;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户权限前缀
|
||||
*
|
||||
* @param user 用户信息
|
||||
* @return 格式化后用户权限前缀
|
||||
*/
|
||||
public static String getUserPermissionCodePrefix(String user) {
|
||||
return USER_PERMISSION_CODE_PREFIX + user;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.services.domain.common.model.vo.result;
|
||||
package cn.bunny.services.domain.common.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
|
@ -53,7 +53,8 @@ public enum ResultCodeEnum {
|
|||
LOGIN_AUTH(208, "请先登陆"),
|
||||
AUTHENTICATION_EXPIRED(208, "身份验证过期"),
|
||||
SESSION_EXPIRATION(208, "会话过期"),
|
||||
|
||||
FAIL_NO_ACCESS_DENIED_USER_LOCKED(208, "该账户已封禁"),
|
||||
|
||||
// 209
|
||||
THE_SAME_USER_HAS_LOGGED_IN(209, "相同用户已登录"),
|
||||
|
||||
|
@ -71,7 +72,6 @@ public enum ResultCodeEnum {
|
|||
FAIL_NO_ACCESS_DENIED(403, "无权访问"),
|
||||
FAIL_NO_ACCESS_DENIED_USER_OFFLINE(403, "用户强制下线"),
|
||||
TOKEN_PARSING_FAILED(403, "token解析失败"),
|
||||
FAIL_NO_ACCESS_DENIED_USER_LOCKED(403, "该账户已封禁"),
|
||||
|
||||
// 系统错误 500
|
||||
UNKNOWN_EXCEPTION(500, "服务异常"),
|
|
@ -1,5 +1,6 @@
|
|||
package cn.bunny.services.domain.common.model.vo.result;
|
||||
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package cn.bunny.services.exception;
|
||||
|
||||
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
|
|
|
@ -2,7 +2,7 @@ package cn.bunny.services.exception;
|
|||
|
||||
|
||||
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.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.context.BaseContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.mybatis.spring.MyBatisSystemException;
|
||||
|
|
|
@ -2,7 +2,7 @@ package cn.bunny.services.minio;
|
|||
|
||||
import cn.bunny.services.domain.common.constant.MinioConstant;
|
||||
import cn.bunny.services.domain.common.model.dto.minio.MinioUploadFileInfo;
|
||||
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.exception.AuthCustomerException;
|
||||
import io.minio.*;
|
||||
import io.minio.messages.DeleteError;
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
package cn.bunny.services.processor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/* 构建树型结构模板处理器 */
|
||||
public abstract class TreeProcessor<T> {
|
||||
public final List<T> process(List<T> list) {
|
||||
List<T> roots = findRoots(list);
|
||||
for (T root : roots) {
|
||||
buildChildren(root, list);
|
||||
}
|
||||
return roots;
|
||||
}
|
||||
|
||||
protected abstract List<T> findRoots(List<T> list);
|
||||
|
||||
protected abstract void buildChildren(T parent, List<T> list);
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package cn.bunny.services.utils;
|
||||
|
||||
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.exception.AuthCustomerException;
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Jws;
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
public class MinioTest {
|
||||
|
||||
@Test
|
||||
void test() {
|
||||
SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM-dd");
|
||||
String date = formatter.format(new Date());
|
||||
System.out.println(date);
|
||||
}
|
||||
}
|
|
@ -21,9 +21,9 @@ public interface RolePermissionMapper extends BaseMapper<RolePermission> {
|
|||
/**
|
||||
* * 根据权限id列表删除角色权限相关
|
||||
*
|
||||
* @param powerIds 权限id列表
|
||||
* @param permissionIds 权限id列表
|
||||
*/
|
||||
void deleteBatchPowerIds(List<Long> powerIds);
|
||||
void deleteBatchPowerIds(List<Long> permissionIds);
|
||||
|
||||
/**
|
||||
* * 根据角色id删除角色权限
|
||||
|
@ -38,7 +38,7 @@ public interface RolePermissionMapper extends BaseMapper<RolePermission> {
|
|||
* @param roleId 角色id
|
||||
* @return 已选择的权限列表
|
||||
*/
|
||||
List<RolePermission> selectPowerListByRoleId(Long roleId);
|
||||
List<RolePermission> selectRolePermissionListByRoleId(Long roleId);
|
||||
|
||||
/**
|
||||
* 查看所有角色关联的权限
|
||||
|
@ -46,4 +46,12 @@ public interface RolePermissionMapper extends BaseMapper<RolePermission> {
|
|||
* @return 角色权限关系视图
|
||||
*/
|
||||
List<ViewRolePermission> viewRolePowerWithAll();
|
||||
|
||||
/**
|
||||
* 根据权限id列表查询角色和权限
|
||||
*
|
||||
* @param permissionIds 权限id列表
|
||||
* @return List<RolePermission>
|
||||
*/
|
||||
List<RolePermission> selectRolePermissionListByPermissionIds(List<Long> permissionIds);
|
||||
}
|
||||
|
|
|
@ -31,4 +31,12 @@ public interface UserRoleMapper extends BaseMapper<UserRole> {
|
|||
*/
|
||||
void deleteBatchIdsByRoleIds(List<Long> roleIds);
|
||||
|
||||
/**
|
||||
* 根据角色id列表查询
|
||||
*
|
||||
* @param ids 角色id列表
|
||||
* @return {@link List<UserRole>}
|
||||
*/
|
||||
List<UserRole> selectListByRoleIds(List<Long> ids);
|
||||
|
||||
}
|
||||
|
|
|
@ -53,15 +53,11 @@
|
|||
<!-- 根据用户id查询当前用户所有权限 -->
|
||||
<select id="selectListByUserId" resultType="cn.bunny.services.domain.system.system.entity.Permission">
|
||||
SELECT p.*
|
||||
FROM sys_user u,
|
||||
sys_user_role ur,
|
||||
sys_role_permission rp,
|
||||
sys_permission p
|
||||
WHERE u.id = ur.user_id
|
||||
AND u.is_deleted = 0
|
||||
AND ur.role_id = rp.role_id
|
||||
AND rp.power_id = p.id
|
||||
AND u.id = #{userId}
|
||||
FROM sys_permission p
|
||||
INNER JOIN sys_role_permission rp ON p.id = rp.power_id
|
||||
INNER JOIN sys_user_role ur ON rp.role_id = ur.role_id
|
||||
INNER JOIN sys_user u ON ur.user_id = u.id AND u.is_deleted = 0
|
||||
WHERE u.id = #{userId}
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
|
|
@ -43,12 +43,10 @@
|
|||
<!-- 根据用户id查询当前用户所有角色 -->
|
||||
<select id="selectListByUserId" resultType="cn.bunny.services.domain.system.system.entity.Role">
|
||||
SELECT r.*
|
||||
FROM sys_user u,
|
||||
sys_role r,
|
||||
sys_user_role ur
|
||||
WHERE u.id = ur.user_id
|
||||
AND u.is_deleted = 0
|
||||
AND r.id = ur.role_id
|
||||
FROM sys_user u
|
||||
INNER JOIN sys_user_role ur ON u.id = ur.user_id
|
||||
INNER JOIN sys_role r ON r.id = ur.role_id
|
||||
WHERE u.is_deleted = 0
|
||||
AND ur.user_id = #{userId}
|
||||
</select>
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
delete
|
||||
from sys_role_permission
|
||||
where power_id in
|
||||
<foreach collection="powerIds" item="id" open="(" close=")" separator=",">
|
||||
<foreach collection="permissionIds" item="id" open="(" close=")" separator=",">
|
||||
#{id}
|
||||
</foreach>
|
||||
</delete>
|
||||
|
@ -40,7 +40,8 @@
|
|||
</delete>
|
||||
|
||||
<!-- 根据角色id获取权限内容 -->
|
||||
<select id="selectPowerListByRoleId" resultType="cn.bunny.services.domain.system.system.entity.RolePermission">
|
||||
<select id="selectRolePermissionListByRoleId"
|
||||
resultType="cn.bunny.services.domain.system.system.entity.RolePermission">
|
||||
select *
|
||||
from sys_role_permission
|
||||
where role_id = #{roleId}
|
||||
|
@ -61,4 +62,14 @@
|
|||
LEFT JOIN sys_permission permission ON rp.power_id = permission.id
|
||||
</select>
|
||||
|
||||
<!-- 根据权限id列表查询角色和权限 -->
|
||||
<select id="selectRolePermissionListByPermissionIds"
|
||||
resultType="cn.bunny.services.domain.system.system.entity.RolePermission">
|
||||
SELECT * FROM
|
||||
sys_role_permission WHERE power_id IN
|
||||
<foreach collection="permissionIds" item="id" separator="," open="(" close=")">
|
||||
#{id}
|
||||
</foreach>
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
|
|
@ -39,4 +39,12 @@
|
|||
</foreach>
|
||||
</delete>
|
||||
|
||||
<!-- 根据角色id列表查询 -->
|
||||
<select id="selectListByRoleIds" resultType="cn.bunny.services.domain.system.system.entity.UserRole">
|
||||
SELECT * FROM sys_user_role WHERE role_id IN
|
||||
<foreach collection="ids" item="id" open="(" close=")" separator=",">
|
||||
#{id}
|
||||
</foreach>
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
|
|
@ -1,99 +0,0 @@
|
|||
package cn.bunny;
|
||||
|
||||
|
||||
import cn.bunny.core.TypeConvertCore;
|
||||
import cn.bunny.dao.entity.ColumnMetaData;
|
||||
import cn.bunny.dao.entity.TableMetaData;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@SpringBootTest
|
||||
public class JDBCTest {
|
||||
|
||||
DatabaseMetaData metaData;
|
||||
|
||||
private final DataSource dataSource;
|
||||
|
||||
public JDBCTest(DataSource dataSource) {
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() throws Exception {
|
||||
try (Connection connection = dataSource.getConnection()) {
|
||||
metaData = connection.getMetaData();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testComment() throws SQLException {
|
||||
String tableName = "sys_i18n";
|
||||
TableMetaData tableMetaData;
|
||||
ResultSet tables = metaData.getTables(null, null, tableName, new String[]{"TABLE"});
|
||||
|
||||
// 获取表的注释信息
|
||||
if (tables.next()) {
|
||||
String remarks = tables.getString("REMARKS");
|
||||
String tableCat = tables.getString("TABLE_CAT");
|
||||
|
||||
tableMetaData = TableMetaData.builder()
|
||||
.tableName(tableName)
|
||||
.comment(remarks)
|
||||
.tableCat(tableCat)
|
||||
.build();
|
||||
|
||||
System.out.println(tableMetaData);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAllTableComment() throws SQLException {
|
||||
ResultSet tables = metaData.getTables(null, null, "%", new String[]{"TABLE"});
|
||||
List<TableMetaData> list = new ArrayList<>();
|
||||
|
||||
while (tables.next()) {
|
||||
String tableName = tables.getString("TABLE_NAME");
|
||||
String remarks = tables.getString("REMARKS");
|
||||
String tableCat = tables.getString("TABLE_CAT");
|
||||
|
||||
TableMetaData tableMetaData = TableMetaData.builder()
|
||||
.tableName(tableName).comment(remarks)
|
||||
.tableCat(tableCat)
|
||||
.build();
|
||||
list.add(tableMetaData);
|
||||
}
|
||||
|
||||
System.out.println(list);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testColumnInfo() throws SQLException {
|
||||
List<ColumnMetaData> columns = new ArrayList<>();
|
||||
|
||||
try (ResultSet columnsRs = metaData.getColumns(null, null, "sys_i18n", null)) {
|
||||
while (columnsRs.next()) {
|
||||
ColumnMetaData column = new ColumnMetaData();
|
||||
column.setColumnName(columnsRs.getString("COLUMN_NAME"));
|
||||
column.setLowercaseName(TypeConvertCore.convertToCamelCase(column.getColumnName()));
|
||||
column.setJdbcType(columnsRs.getString("TYPE_NAME"));
|
||||
column.setJavaType(TypeConvertCore.convertToJavaType(column.getJdbcType()));
|
||||
column.setComment(columnsRs.getString("REMARKS"));
|
||||
|
||||
columns.add(column);
|
||||
System.out.println(column);
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println(columns);
|
||||
}
|
||||
}
|
|
@ -1,105 +0,0 @@
|
|||
package cn.bunny;
|
||||
|
||||
import cn.bunny.core.TypeConvertCore;
|
||||
import cn.bunny.dao.entity.ColumnMetaData;
|
||||
import cn.bunny.dao.entity.TableMetaData;
|
||||
import net.sf.jsqlparser.JSQLParserException;
|
||||
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
|
||||
import net.sf.jsqlparser.statement.Statement;
|
||||
import net.sf.jsqlparser.statement.create.table.CreateTable;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class SqlParserTest {
|
||||
|
||||
@Test
|
||||
public void test() throws JSQLParserException {
|
||||
String sql = """
|
||||
CREATE TABLE `sys_files` (
|
||||
`id` bigint NOT NULL COMMENT '文件的唯一标识符,自动递增',
|
||||
`filename` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '文件的名称',
|
||||
`filepath` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '文件在服务器上的存储路径',
|
||||
`file_size` int NOT NULL COMMENT '文件的大小,以字节为单位',
|
||||
`file_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '文件的MIME类型',
|
||||
`download_count` int NULL DEFAULT 0 COMMENT '下载数量',
|
||||
`create_user` bigint NOT NULL COMMENT '创建用户',
|
||||
`update_user` bigint NULL DEFAULT NULL COMMENT '操作用户',
|
||||
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '记录文件最后修改的时间戳',
|
||||
`is_deleted` tinyint(1) UNSIGNED ZEROFILL NOT NULL DEFAULT 0 COMMENT '文件是否被删除',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `idx_filename`(`filename` ASC) USING BTREE COMMENT '索引文件名',
|
||||
INDEX `idx_filepath`(`filepath` ASC) USING BTREE COMMENT '索引文件路径',
|
||||
INDEX `idx_file_type`(`file_type` ASC) USING BTREE COMMENT '索引文件类型',
|
||||
INDEX `idx_update_user`(`update_user` ASC) USING BTREE COMMENT '索引创更新用户',
|
||||
INDEX `idx_create_user`(`create_user` ASC) USING BTREE COMMENT '索引创建用户',
|
||||
INDEX `idx_user`(`update_user` ASC, `create_user` ASC) USING BTREE COMMENT '索引创建用户和更新用户',
|
||||
INDEX `idx_time`(`update_time` ASC, `create_time` ASC) USING BTREE COMMENT '索引创建时间和更新时间'
|
||||
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '系统文件表' ROW_FORMAT = DYNAMIC;
|
||||
""";
|
||||
|
||||
TableMetaData tableInfo = new TableMetaData();
|
||||
|
||||
// 解析sql
|
||||
Statement statement = CCJSqlParserUtil.parse(sql);
|
||||
if (!(statement instanceof CreateTable createTable)) {
|
||||
throw new IllegalArgumentException("Not a CREATE TABLE statement");
|
||||
}
|
||||
|
||||
// 设置表基本信息
|
||||
tableInfo.setTableName(createTable.getTable().getName());
|
||||
tableInfo.setTableType("TABLE");
|
||||
String tableOptionsStrings = String.join(" ", createTable.getTableOptionsStrings());
|
||||
|
||||
// 注释信息
|
||||
Pattern pattern = Pattern.compile("COMMENT\\s*=\\s*'(.*?)'", Pattern.CASE_INSENSITIVE);
|
||||
Matcher matcher = pattern.matcher(tableOptionsStrings);
|
||||
if (matcher.find()) {
|
||||
tableInfo.setComment(matcher.group(1));
|
||||
}
|
||||
|
||||
// 解析列信息
|
||||
List<ColumnMetaData> columnMetaData = createTable.getColumnDefinitions()
|
||||
.stream().map(column -> {
|
||||
// 列信息
|
||||
ColumnMetaData columnInfo = new ColumnMetaData();
|
||||
|
||||
// 列名称
|
||||
columnInfo.setColumnName(column.getColumnName());
|
||||
|
||||
// 设置 JDBC 类型
|
||||
String dataType = column.getColDataType().getDataType();
|
||||
columnInfo.setJdbcType(dataType);
|
||||
|
||||
// 设置 Java 类型
|
||||
String javaType = TypeConvertCore.convertToJavaType(dataType.contains("varchar") ? "varchar" : dataType);
|
||||
columnInfo.setJavaType(javaType);
|
||||
|
||||
// 设置 JavaScript 类型
|
||||
columnInfo.setJavascriptType(StringUtils.uncapitalize(javaType));
|
||||
|
||||
// 列字段转成 下划线 -> 小驼峰
|
||||
columnInfo.setLowercaseName(TypeConvertCore.convertToCamelCase(column.getColumnName()));
|
||||
// 列字段转成 下划线 -> 大驼峰名称
|
||||
columnInfo.setUppercaseName(TypeConvertCore.convertToCamelCase(column.getColumnName(), true));
|
||||
|
||||
// 解析注释
|
||||
List<String> columnSpecs = column.getColumnSpecs();
|
||||
String columnSpecsString = String.join(" ", columnSpecs);
|
||||
Matcher columnSpecsStringMatcher = Pattern.compile("COMMENT\\s*'(.*?)'", Pattern.CASE_INSENSITIVE).matcher(columnSpecsString);
|
||||
if (columnSpecsStringMatcher.find()) {
|
||||
columnInfo.setComment(columnSpecsStringMatcher.group(1));
|
||||
}
|
||||
|
||||
return columnInfo;
|
||||
}).toList();
|
||||
|
||||
System.out.println(tableInfo);
|
||||
System.out.println("----------------------------------------------------------------------------------------");
|
||||
System.out.println(columnMetaData);
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
package cn.bunny;
|
||||
|
||||
import cn.bunny.core.TypeConvertCore;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.assertj.core.util.introspection.CaseFormatUtils;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class StringFormatTest {
|
||||
|
||||
@Test
|
||||
void test1() {
|
||||
System.out.println(CaseFormatUtils.toCamelCase("user_login" ));
|
||||
System.out.println(CaseFormatUtils.toCamelCase("userLogin" ));
|
||||
System.out.println(CaseFormatUtils.toCamelCase("UserLogin" ));
|
||||
|
||||
System.out.println("--------------------------------" );
|
||||
|
||||
System.out.println(StringUtils.lowerCase("user_login" ));
|
||||
System.out.println(StringUtils.lowerCase("userLogin" ));
|
||||
System.out.println(StringUtils.lowerCase("UserLogin" ));
|
||||
|
||||
System.out.println("--------------------------------" );
|
||||
|
||||
System.out.println(StringUtils.upperCase("user_login" ));
|
||||
System.out.println(StringUtils.upperCase("userLogin" ));
|
||||
System.out.println(StringUtils.upperCase("UserLogin" ));
|
||||
}
|
||||
|
||||
@Test
|
||||
void test2() {
|
||||
System.out.println(TypeConvertCore.convertToCamelCase("user_login_A" ));
|
||||
System.out.println(TypeConvertCore.convertToCamelCase("User_Login_A" ));
|
||||
System.out.println(TypeConvertCore.convertToCamelCase("userLoginA" ));
|
||||
System.out.println(TypeConvertCore.convertToCamelCase("UserLoginA" ));
|
||||
|
||||
System.out.println("--------------------------------" );
|
||||
|
||||
System.out.println(TypeConvertCore.convertToCamelCase("i18n_type_A" , true));
|
||||
System.out.println(TypeConvertCore.convertToCamelCase("User_Login_A" , true));
|
||||
System.out.println(TypeConvertCore.convertToCamelCase("userLoginA" , true));
|
||||
System.out.println(TypeConvertCore.convertToCamelCase("UserLoginA" , true));
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
package cn.bunny;
|
||||
|
||||
import cn.hutool.crypto.digest.MD5;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class TimeTest {
|
||||
@Test
|
||||
void timeTest() {
|
||||
long currentTimeMillis = System.currentTimeMillis();
|
||||
String digestHex = MD5.create().digestHex(currentTimeMillis + "");
|
||||
System.out.println(currentTimeMillis);
|
||||
System.out.println(digestHex);
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
package cn.bunny.service.impl;
|
||||
|
||||
import cn.bunny.core.ResourceFileCore;
|
||||
import cn.bunny.dao.vo.VmsPathVo;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
class VmsServiceImplTest {
|
||||
|
||||
|
||||
@Test
|
||||
void vmsResourcePathList() throws IOException, URISyntaxException {
|
||||
List<String> vmsFiles = ResourceFileCore.getAbsoluteFiles("vms");
|
||||
System.out.println(vmsFiles);
|
||||
|
||||
System.out.println("--------------------------------------------------------------");
|
||||
|
||||
List<String> vmsRelativeFiles = ResourceFileCore.getRelativeFiles("vms");
|
||||
System.out.println(vmsRelativeFiles);
|
||||
|
||||
System.out.println("--------------------------集合对象模式------------------------------------");
|
||||
|
||||
Map<String, List<VmsPathVo>> map = vmsRelativeFiles.stream().map(vmFile -> {
|
||||
String[] filepathList = vmFile.split("/");
|
||||
String filename = filepathList[filepathList.length - 1].replace(".vm", "");
|
||||
|
||||
return VmsPathVo.builder().name(vmFile).label(filename).type(filepathList[0]).build();
|
||||
}).collect(Collectors.groupingBy(VmsPathVo::getType));
|
||||
|
||||
System.out.println(JSON.toJSONString(map));
|
||||
|
||||
System.out.println("----------------------------二维数组格式----------------------------------");
|
||||
List<List<VmsPathVo>> listMap = vmsRelativeFiles.stream().map(vmFile -> {
|
||||
String[] filepathList = vmFile.split("/");
|
||||
String filename = filepathList[filepathList.length - 1].replace(".vm", "");
|
||||
|
||||
return VmsPathVo.builder().name(vmFile).label(filename).type(filepathList[0]).build();
|
||||
})
|
||||
.collect(Collectors.groupingBy(VmsPathVo::getType))
|
||||
.values().stream().toList();
|
||||
|
||||
System.out.println(JSON.toJSONString(listMap));
|
||||
}
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
package cn.bunny.utils;
|
||||
|
||||
import cn.bunny.dao.entity.TableMetaData;
|
||||
import lombok.SneakyThrows;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.ResultSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@SpringBootTest
|
||||
class DatabaseInfoCoreTest {
|
||||
|
||||
String tableName = "sys_i18n";
|
||||
|
||||
@Autowired
|
||||
private DataSource dataSource;
|
||||
|
||||
|
||||
@Test
|
||||
void testTableInfoMetaData() {
|
||||
TableMetaData tableMetaData;
|
||||
|
||||
try (Connection connection = dataSource.getConnection()) {
|
||||
DatabaseMetaData metaData = connection.getMetaData();
|
||||
ResultSet tables = metaData.getTables(null, null, tableName, new String[]{"TABLE"});
|
||||
|
||||
// 获取表的注释信息
|
||||
if (tables.next()) {
|
||||
String remarks = tables.getString("REMARKS");
|
||||
String tableCat = tables.getString("TABLE_CAT");
|
||||
String tableType = tables.getString("TABLE_TYPE");
|
||||
|
||||
tableMetaData = TableMetaData.builder()
|
||||
.tableName(tableName)
|
||||
.comment(remarks)
|
||||
.tableCat(tableCat)
|
||||
.tableType(tableType)
|
||||
.build();
|
||||
} else {
|
||||
throw new RuntimeException("数据表不存在");
|
||||
}
|
||||
|
||||
System.out.println(tableMetaData);
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Test
|
||||
void getDbTableList() {
|
||||
String dbName = "auth_admin";
|
||||
|
||||
try (Connection connection = dataSource.getConnection()) {
|
||||
DatabaseMetaData metaData = connection.getMetaData();
|
||||
ResultSet tables = metaData.getTables(dbName, null, "%", new String[]{"TABLE"});
|
||||
|
||||
List<String> list = new ArrayList<>();
|
||||
|
||||
while (tables.next()) {
|
||||
dbName = tables.getString("TABLE_NAME");
|
||||
list.add(dbName);
|
||||
}
|
||||
|
||||
System.out.println(list);
|
||||
}
|
||||
}
|
||||
}
|
2
pom.xml
2
pom.xml
|
@ -43,7 +43,7 @@
|
|||
<velocity-tools.version>3.1</velocity-tools.version>
|
||||
<HikariCP.version>6.2.1</HikariCP.version>
|
||||
<dynamic.datasource.version>4.3.1</dynamic.datasource.version>
|
||||
<jackson-dataType.version>2.12.3</jackson-dataType.version>
|
||||
<jackson-dataType.version>2.19.0</jackson-dataType.version>
|
||||
<quartz-scheduler.version>2.3.2</quartz-scheduler.version>
|
||||
</properties>
|
||||
|
||||
|
|
|
@ -91,10 +91,5 @@
|
|||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package cn.bunny.services.aop.scanner;
|
||||
|
||||
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.exception.AuthCustomerException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
package cn.bunny.services.core.cache;
|
||||
|
||||
import cn.bunny.services.domain.common.constant.RedisUserConstant;
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Service
|
||||
public class EmailCacheService {
|
||||
|
||||
@Resource
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
/**
|
||||
* 存储邮箱验证码
|
||||
*
|
||||
* @param email 邮箱
|
||||
* @param emailCode 邮箱验证码
|
||||
*/
|
||||
public void buildEmailCodeCache(@NotNull String email, String emailCode) {
|
||||
// 在Redis中存储验证码
|
||||
String emailCodePrefix = RedisUserConstant.getUserEmailCodePrefix(email);
|
||||
redisTemplate.opsForValue().set(emailCodePrefix, emailCode, RedisUserConstant.REDIS_EXPIRATION_TIME, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取邮箱验证码
|
||||
*
|
||||
* @param email 邮箱
|
||||
* @return 邮箱验证码
|
||||
*/
|
||||
public String getEmailCode(@NotNull String email) {
|
||||
String userEmailCodePrefix = RedisUserConstant.getUserEmailCodePrefix(email);
|
||||
Object emailCode = redisTemplate.opsForValue().get(userEmailCodePrefix);
|
||||
|
||||
if (emailCode == null) {
|
||||
throw new UsernameNotFoundException(ResultCodeEnum.EMAIL_CODE_EMPTY.getMessage());
|
||||
}
|
||||
|
||||
return emailCode.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除邮箱验证码
|
||||
*
|
||||
* @param email 邮箱
|
||||
*/
|
||||
public void deleteEmailCodeCache(String email) {
|
||||
String emailCodePrefix = RedisUserConstant.getUserEmailCodePrefix(email);
|
||||
redisTemplate.delete(emailCodePrefix);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.services.redis;
|
||||
package cn.bunny.services.core.cache;
|
||||
|
||||
import cn.bunny.services.domain.common.constant.RedisUserConstant;
|
||||
import jakarta.annotation.Resource;
|
||||
|
@ -26,7 +26,7 @@ public class RedisService {
|
|||
*/
|
||||
@NotNull
|
||||
public List<String> scannerRedisKeyByPage(long pageNum, long pageSize) {
|
||||
String prefix = RedisUserConstant.getAdminLoginInfoPrefix("*");
|
||||
String prefix = RedisUserConstant.getUserLoginInfoPrefix("*");
|
||||
|
||||
List<String> keys = new ArrayList<>();
|
||||
ScanOptions scanOptions = ScanOptions.scanOptions()
|
110
service/src/main/java/cn/bunny/services/core/cache/UserAuthorizationCacheService.java
vendored
Normal file
110
service/src/main/java/cn/bunny/services/core/cache/UserAuthorizationCacheService.java
vendored
Normal file
|
@ -0,0 +1,110 @@
|
|||
package cn.bunny.services.core.cache;
|
||||
|
||||
import cn.bunny.services.domain.common.constant.RedisUserConstant;
|
||||
import cn.bunny.services.domain.system.system.entity.Permission;
|
||||
import cn.bunny.services.domain.system.system.entity.Role;
|
||||
import cn.bunny.services.mapper.system.PermissionMapper;
|
||||
import cn.bunny.services.mapper.system.RoleMapper;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.TypeReference;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Service
|
||||
public class UserAuthorizationCacheService {
|
||||
|
||||
@Resource
|
||||
private PermissionMapper permissionMapper;
|
||||
|
||||
@Resource
|
||||
private RoleMapper roleMapper;
|
||||
|
||||
@Resource
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
/**
|
||||
* 根据用户ID和用户名获取角色列表(缓存优先)
|
||||
*
|
||||
* <p><b>执行逻辑</b>:</p>
|
||||
* <ol>
|
||||
* <li>尝试从Redis缓存获取用户角色(使用用户名作为缓存key)</li>
|
||||
* <li>若缓存未命中,则从数据库查询并写入缓存(有效期1天)</li>
|
||||
* <li>若缓存命中,反序列化缓存数据返回</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param userId 用户ID(数据库查询用)
|
||||
* @param username 用户名(缓存key生成用)
|
||||
* @return 用户角色列表
|
||||
*/
|
||||
public List<Role> getRolesByUser(Long userId, String username) {
|
||||
// 角色列表
|
||||
List<Role> roleList;
|
||||
|
||||
// 尝试从缓存中获取当前用户角色
|
||||
String userRolesCodePrefix = RedisUserConstant.getUserRolesCodePrefix(username);
|
||||
Object object = redisTemplate.opsForValue().get(userRolesCodePrefix);
|
||||
|
||||
// 为空查询数据库,并将信息存入Redis
|
||||
if (Objects.isNull(object)) {
|
||||
roleList = roleMapper.selectListByUserId(userId);
|
||||
redisTemplate.opsForValue().set(userRolesCodePrefix, roleList, 1, TimeUnit.DAYS);
|
||||
}
|
||||
// 从缓存中得到当前用户的角色列表
|
||||
else {
|
||||
String jsonString = JSON.toJSONString(object);
|
||||
TypeReference<List<Role>> reference = new TypeReference<>() {
|
||||
};
|
||||
List<Role> list = JSON.parseObject(jsonString, reference);
|
||||
// 防止 list 为空报错
|
||||
roleList = list != null ? list : new ArrayList<>();
|
||||
}
|
||||
|
||||
return roleList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID和用户名获取权限列表(缓存优先)
|
||||
*
|
||||
* <p><b>执行逻辑</b>:</p>
|
||||
* <ol>
|
||||
* <li>尝试从Redis缓存获取用户权限(使用用户名作为缓存key)</li>
|
||||
* <li>若缓存未命中,则从数据库查询并写入缓存(有效期1天)</li>
|
||||
* <li>若缓存命中,反序列化缓存数据返回</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param userId 用户ID(数据库查询用)
|
||||
* @param username 用户名(缓存key生成用)
|
||||
* @return 用户权限列表
|
||||
*/
|
||||
public List<Permission> getPermissionsByUser(Long userId, String username) {
|
||||
// 权限列表
|
||||
List<Permission> permissionList;
|
||||
|
||||
// 获取缓存中的用户权限
|
||||
String userPermissionCodePrefix = RedisUserConstant.getUserPermissionCodePrefix(username);
|
||||
Object object = redisTemplate.opsForValue().get(userPermissionCodePrefix);
|
||||
|
||||
// 为空查询数据库,并将用户权限放在Redis中
|
||||
if (Objects.isNull(object)) {
|
||||
permissionList = permissionMapper.selectListByUserId(userId);
|
||||
redisTemplate.opsForValue().set(userPermissionCodePrefix, permissionList, 1, TimeUnit.DAYS);
|
||||
}
|
||||
// 从缓存中得到当前用户权限
|
||||
else {
|
||||
String jsonString = JSON.toJSONString(object);
|
||||
TypeReference<List<Permission>> reference = new TypeReference<>() {
|
||||
};
|
||||
List<Permission> list = JSON.parseObject(jsonString, reference);
|
||||
// 防止 list 为空报错
|
||||
permissionList = list != null ? list : new ArrayList<>();
|
||||
}
|
||||
|
||||
return permissionList;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package cn.bunny.services.core.cache;
|
||||
|
||||
import cn.bunny.services.domain.common.constant.RedisUserConstant;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class UserCacheCleaner {
|
||||
@Resource
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
public void cleanUserLoginCache(String username) {
|
||||
String key = RedisUserConstant.getUserLoginInfoPrefix(username);
|
||||
redisTemplate.delete(key);
|
||||
}
|
||||
|
||||
public void cleanUserRoleCache(String username) {
|
||||
String key = RedisUserConstant.getUserRolesCodePrefix(username);
|
||||
redisTemplate.delete(key);
|
||||
}
|
||||
|
||||
public void cleanUserPermissionCache(String username) {
|
||||
String key = RedisUserConstant.getUserPermissionCodePrefix(username);
|
||||
redisTemplate.delete(key);
|
||||
}
|
||||
|
||||
public void cleanAllUserCache(String username) {
|
||||
cleanUserLoginCache(username);
|
||||
cleanUserRoleCache(username);
|
||||
cleanUserPermissionCache(username);
|
||||
}
|
||||
}
|
105
service/src/main/java/cn/bunny/services/core/cache/UserLoginVoBuilderCacheService.java
vendored
Normal file
105
service/src/main/java/cn/bunny/services/core/cache/UserLoginVoBuilderCacheService.java
vendored
Normal file
|
@ -0,0 +1,105 @@
|
|||
package cn.bunny.services.core.cache;
|
||||
|
||||
import cn.bunny.services.core.utils.RoleHelper;
|
||||
import cn.bunny.services.domain.common.constant.LocalDateTimeConstant;
|
||||
import cn.bunny.services.domain.common.constant.RedisUserConstant;
|
||||
import cn.bunny.services.domain.common.model.vo.LoginVo;
|
||||
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.system.PermissionMapper;
|
||||
import cn.bunny.services.mapper.system.RoleMapper;
|
||||
import cn.bunny.services.minio.MinioHelper;
|
||||
import cn.bunny.services.utils.JwtTokenUtil;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.Value;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Service
|
||||
public class UserLoginVoBuilderCacheService {
|
||||
|
||||
@Resource
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
@Resource
|
||||
private MinioHelper minioHelper;
|
||||
|
||||
@Resource
|
||||
private RoleMapper roleMapper;
|
||||
|
||||
@Resource
|
||||
private PermissionMapper permissionMapper;
|
||||
|
||||
public LoginVo buildLoginUserVo(AdminUser user, long readMeDay) {
|
||||
String username = user.getUsername();
|
||||
Long userId = user.getId();
|
||||
|
||||
UserAuthInfo authInfo = getAuthInfo(userId, user);
|
||||
|
||||
// 设置用户返回对象
|
||||
LoginVo loginVo = new LoginVo();
|
||||
BeanUtils.copyProperties(user, loginVo);
|
||||
loginVo.setPersonDescription(user.getSummary());
|
||||
loginVo.setRoles(authInfo.getRoles());
|
||||
loginVo.setPermissions(authInfo.getPermissions());
|
||||
|
||||
// 使用用户名创建token
|
||||
String token = JwtTokenUtil.createToken(userId, username, (int) readMeDay);
|
||||
loginVo.setToken(token);
|
||||
loginVo.setRefreshToken(token);
|
||||
loginVo.setReadMeDay(readMeDay);
|
||||
|
||||
// 计算过期时间,并格式化返回
|
||||
String expires = calculateExpires(readMeDay);
|
||||
loginVo.setExpires(expires);
|
||||
|
||||
// 设置用户头像
|
||||
String userAvatar = minioHelper.getUserAvatar(user.getAvatar());
|
||||
loginVo.setAvatar(userAvatar);
|
||||
|
||||
String loginInfoPrefix = RedisUserConstant.getUserLoginInfoPrefix(username);
|
||||
redisTemplate.opsForValue().set(loginInfoPrefix, loginVo, readMeDay, TimeUnit.DAYS);
|
||||
return loginVo;
|
||||
}
|
||||
|
||||
private UserAuthInfo getAuthInfo(Long userId, AdminUser user) {
|
||||
// 用户角色
|
||||
List<String> roles = new ArrayList<>(roleMapper.selectListByUserId(userId).stream().map(Role::getRoleCode).toList());
|
||||
|
||||
// 判断是否是 admin 如果是admin 赋予所有权限
|
||||
List<String> permissions = new ArrayList<>();
|
||||
boolean isAdmin = RoleHelper.checkAdmin(roles, permissions, user);
|
||||
if (!isAdmin) {
|
||||
permissions = permissionMapper.selectListByUserId(userId).stream()
|
||||
.map(Permission::getPowerCode)
|
||||
.toList();
|
||||
}
|
||||
|
||||
// 为这两个去重,在判断 checkAdmin 会重新赋值
|
||||
permissions = permissions.stream().distinct().toList();
|
||||
roles = roles.stream().distinct().toList();
|
||||
|
||||
return new UserAuthInfo(roles, permissions);
|
||||
}
|
||||
|
||||
private String calculateExpires(long readMeDay) {
|
||||
LocalDateTime localDateTime = LocalDateTime.now();
|
||||
LocalDateTime plusDay = localDateTime.plusDays(readMeDay);
|
||||
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(LocalDateTimeConstant.YYYY_MM_DD_HH_MM_SS_SLASH);
|
||||
return plusDay.format(dateTimeFormatter);
|
||||
}
|
||||
|
||||
@Value
|
||||
private static class UserAuthInfo {
|
||||
List<String> roles;
|
||||
List<String> permissions;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package cn.bunny.services.core.event.event;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class ClearAllUserCacheEvent extends ApplicationEvent {
|
||||
private final String key;
|
||||
|
||||
public ClearAllUserCacheEvent(Object source, String key) {
|
||||
super(source);
|
||||
this.key = key;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package cn.bunny.services.core.event.event;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class UpdateUserinfoByPermissionIdsEvent extends ApplicationEvent {
|
||||
private final List<Long> permissionIds;
|
||||
|
||||
public UpdateUserinfoByPermissionIdsEvent(Object source, List<Long> permissionIds) {
|
||||
super(source);
|
||||
this.permissionIds = permissionIds;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package cn.bunny.services.core.event.event;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class UpdateUserinfoByRoleIdsEvent extends ApplicationEvent {
|
||||
private final List<Long> roleIds;
|
||||
|
||||
public UpdateUserinfoByRoleIdsEvent(Object source, List<Long> roleIds) {
|
||||
super(source);
|
||||
this.roleIds = roleIds;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package cn.bunny.services.core.event.event;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class UpdateUserinfoByUserIdsEvent extends ApplicationEvent {
|
||||
private final List<Long> userIds;
|
||||
|
||||
public UpdateUserinfoByUserIdsEvent(Object source, List<Long> userIds) {
|
||||
super(source);
|
||||
this.userIds = userIds;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.services.excel;
|
||||
package cn.bunny.services.core.event.listener.excel;
|
||||
|
||||
import cn.bunny.services.domain.common.model.dto.excel.I18nExcel;
|
||||
import cn.bunny.services.domain.system.i18n.entity.I18n;
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.services.excel;
|
||||
package cn.bunny.services.core.event.listener.excel;
|
||||
|
||||
import cn.bunny.services.domain.common.model.dto.excel.PermissionExcel;
|
||||
import cn.bunny.services.domain.system.system.entity.Permission;
|
|
@ -1,7 +1,7 @@
|
|||
package cn.bunny.services.excel;
|
||||
package cn.bunny.services.core.event.listener.excel;
|
||||
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.common.model.dto.excel.RoleExcel;
|
||||
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.system.system.entity.Role;
|
||||
import cn.bunny.services.exception.AuthCustomerException;
|
||||
import cn.bunny.services.service.system.RoleService;
|
|
@ -0,0 +1,34 @@
|
|||
package cn.bunny.services.core.event.listener.user;
|
||||
|
||||
import cn.bunny.services.core.cache.UserCacheCleaner;
|
||||
import cn.bunny.services.domain.common.constant.RedisUserConstant;
|
||||
import cn.bunny.services.domain.system.system.entity.AdminUser;
|
||||
import cn.bunny.services.mapper.system.UserMapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Component("AbstractUserInfoUpdateHandler")
|
||||
public abstract class AbstractUserInfoUpdateHandler {
|
||||
|
||||
@Resource
|
||||
protected UserMapper userMapper;
|
||||
|
||||
@Resource
|
||||
protected UserCacheCleaner userCacheCleaner;
|
||||
|
||||
@Resource
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
public void processUserUpdate(List<Long> userIds, Consumer<AdminUser> postProcess) {
|
||||
if (userIds.isEmpty()) return;
|
||||
|
||||
List<AdminUser> adminUsers = userMapper.selectBatchIds(userIds);
|
||||
adminUsers.stream()
|
||||
.filter(user -> redisTemplate.hasKey(RedisUserConstant.getUserLoginInfoPrefix(user.getUsername())))
|
||||
.forEach(postProcess);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package cn.bunny.services.core.event.listener.user;
|
||||
|
||||
import cn.bunny.services.core.cache.UserLoginVoBuilderCacheService;
|
||||
import cn.bunny.services.core.event.event.ClearAllUserCacheEvent;
|
||||
import cn.bunny.services.core.event.event.UpdateUserinfoByPermissionIdsEvent;
|
||||
import cn.bunny.services.core.event.event.UpdateUserinfoByRoleIdsEvent;
|
||||
import cn.bunny.services.core.event.event.UpdateUserinfoByUserIdsEvent;
|
||||
import cn.bunny.services.domain.common.constant.RedisUserConstant;
|
||||
import cn.bunny.services.domain.system.system.entity.RolePermission;
|
||||
import cn.bunny.services.domain.system.system.entity.UserRole;
|
||||
import cn.bunny.services.mapper.system.RolePermissionMapper;
|
||||
import cn.bunny.services.mapper.system.UserRoleMapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Component("UserinfoUpdateListener")
|
||||
public class UserinfoUpdateListener extends AbstractUserInfoUpdateHandler {
|
||||
|
||||
@Resource
|
||||
private UserLoginVoBuilderCacheService userLoginVoBuilderCacheService;
|
||||
|
||||
@Resource
|
||||
private UserRoleMapper userRoleMapper;
|
||||
|
||||
@Resource
|
||||
private RolePermissionMapper rolePermissionMapper;
|
||||
|
||||
/* 根据用户id更新用户信息,重新生成LoginVo对象 */
|
||||
@EventListener
|
||||
public void handlerUpdateUserinfoByUserIds(UpdateUserinfoByUserIdsEvent event) {
|
||||
List<Long> userIds = event.getUserIds();
|
||||
processUserUpdate(userIds, user -> {
|
||||
userCacheCleaner.cleanAllUserCache(user.getUsername());
|
||||
userLoginVoBuilderCacheService.buildLoginUserVo(user, RedisUserConstant.REDIS_EXPIRATION_TIME);
|
||||
});
|
||||
}
|
||||
|
||||
/* 根据角色id更新用户信息,重新生成LoginVo对象 */
|
||||
@EventListener
|
||||
public void handlerUserinfoUpdateByRoleId(UpdateUserinfoByRoleIdsEvent event) {
|
||||
List<Long> roleIds = event.getRoleIds();
|
||||
List<UserRole> userRoles = userRoleMapper.selectListByRoleIds(roleIds);
|
||||
List<Long> userIds = userRoles.stream().map(UserRole::getUserId).toList();
|
||||
|
||||
UpdateUserinfoByUserIdsEvent userIdsEvent = new UpdateUserinfoByUserIdsEvent(event.getSource(), userIds);
|
||||
handlerUpdateUserinfoByUserIds(userIdsEvent);
|
||||
}
|
||||
|
||||
/* 根据角色id更新用户信息,重新生成LoginVo对象 */
|
||||
@EventListener
|
||||
public void handlerUserinfoUpdateByPermissionId(UpdateUserinfoByPermissionIdsEvent event) {
|
||||
List<Long> permissionIds = event.getPermissionIds();
|
||||
List<RolePermission> rolePermissions = rolePermissionMapper.selectRolePermissionListByPermissionIds(permissionIds);
|
||||
List<Long> roleIds = rolePermissions.stream().map(RolePermission::getRoleId).toList();
|
||||
|
||||
UpdateUserinfoByRoleIdsEvent roleIdsEvent = new UpdateUserinfoByRoleIdsEvent(event.getSource(), roleIds);
|
||||
handlerUserinfoUpdateByRoleId(roleIdsEvent);
|
||||
}
|
||||
|
||||
/* 清除用户登录、角色、权限所有缓存 */
|
||||
@EventListener
|
||||
public void handlerDeleteAllUserCache(ClearAllUserCacheEvent event) {
|
||||
userCacheCleaner.cleanAllUserCache(event.getKey());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package cn.bunny.services.core.strategy.export;
|
||||
|
||||
import com.alibaba.excel.EasyExcel;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.List;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
public class ExcelExportStrategy implements ExportStrategy<List<?>> {
|
||||
|
||||
private final Class<?> clazz;
|
||||
private final String sheetName;
|
||||
|
||||
public ExcelExportStrategy(Class<?> clazz, String sheetName) {
|
||||
this.clazz = clazz;
|
||||
this.sheetName = sheetName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void export(List<?> data, ZipOutputStream zipOutputStream, String filename) {
|
||||
try {
|
||||
ByteArrayOutputStream excelOutputStream = new ByteArrayOutputStream();
|
||||
EasyExcel.write(excelOutputStream, clazz).sheet(sheetName).doWrite(data);
|
||||
|
||||
// 将Excel写入到Zip中
|
||||
ZipEntry zipEntry = new ZipEntry(filename);
|
||||
zipOutputStream.putNextEntry(zipEntry);
|
||||
zipOutputStream.write(excelOutputStream.toByteArray());
|
||||
zipOutputStream.closeEntry();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package cn.bunny.services.core.strategy.export;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
public interface ExportStrategy<T> {
|
||||
void export(T data, ZipOutputStream zipOutputStream, String filename) throws IOException;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package cn.bunny.services.core.strategy.export;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
public class JsonExportStrategy implements ExportStrategy<Object> {
|
||||
|
||||
@Override
|
||||
public void export(Object data, ZipOutputStream zipOutputStream, String filename) {
|
||||
try {
|
||||
ZipEntry zipEntry = new ZipEntry(filename);
|
||||
zipOutputStream.putNextEntry(zipEntry);
|
||||
zipOutputStream.write(JSON.toJSONString(data).getBytes(StandardCharsets.UTF_8));
|
||||
zipOutputStream.closeEntry();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.services.service.system.helper.login;
|
||||
package cn.bunny.services.core.strategy.login;
|
||||
|
||||
import cn.bunny.services.domain.system.system.dto.user.LoginDto;
|
||||
import cn.bunny.services.domain.system.system.entity.AdminUser;
|
|
@ -1,23 +1,22 @@
|
|||
package cn.bunny.services.service.system.helper.login;
|
||||
package cn.bunny.services.core.strategy.login;
|
||||
|
||||
import cn.bunny.services.domain.common.constant.RedisUserConstant;
|
||||
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
||||
import cn.bunny.services.core.cache.EmailCacheService;
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.system.system.dto.user.LoginDto;
|
||||
import cn.bunny.services.domain.system.system.entity.AdminUser;
|
||||
import cn.bunny.services.mapper.system.UserMapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
|
||||
/**
|
||||
* 邮箱登录策略
|
||||
*/
|
||||
public class EmailLoginStrategy implements LoginStrategy {
|
||||
private final RedisTemplate<String, Object> redisTemplate;
|
||||
private final EmailCacheService emailCacheService;
|
||||
private final UserMapper userMapper;
|
||||
|
||||
public EmailLoginStrategy(RedisTemplate<String, Object> redisTemplate, UserMapper userMapper) {
|
||||
this.redisTemplate = redisTemplate;
|
||||
public EmailLoginStrategy(EmailCacheService emailCacheService, UserMapper userMapper) {
|
||||
this.emailCacheService = emailCacheService;
|
||||
this.userMapper = userMapper;
|
||||
}
|
||||
|
||||
|
@ -38,13 +37,10 @@ public class EmailLoginStrategy implements LoginStrategy {
|
|||
String emailCode = loginDto.getEmailCode().toLowerCase();
|
||||
|
||||
// 查找Redis中的验证码
|
||||
Object redisEmailCode = redisTemplate.opsForValue().get(RedisUserConstant.getAdminUserEmailCodePrefix(username));
|
||||
if (redisEmailCode == null) {
|
||||
throw new UsernameNotFoundException(ResultCodeEnum.EMAIL_CODE_EMPTY.getMessage());
|
||||
}
|
||||
String redisEmailCode = emailCacheService.getEmailCode(username);
|
||||
|
||||
// 判断用户邮箱验证码是否和Redis中发送的验证码
|
||||
if (!emailCode.equals(redisEmailCode.toString().toLowerCase())) {
|
||||
if (!emailCode.equals(redisEmailCode.toLowerCase())) {
|
||||
throw new UsernameNotFoundException(ResultCodeEnum.EMAIL_CODE_NOT_MATCHING.getMessage());
|
||||
}
|
||||
|
||||
|
@ -63,8 +59,7 @@ public class EmailLoginStrategy implements LoginStrategy {
|
|||
@Override
|
||||
public void authenticateAfter(LoginDto loginDto, AdminUser adminUser) {
|
||||
// 将Redis中验证码删除
|
||||
String emailCodePrefix = RedisUserConstant.getAdminUserEmailCodePrefix(loginDto.getUsername());
|
||||
redisTemplate.delete(emailCodePrefix);
|
||||
emailCacheService.deleteEmailCodeCache(loginDto.getUsername());
|
||||
}
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.services.service.system.helper.login;
|
||||
package cn.bunny.services.core.strategy.login;
|
||||
|
||||
import cn.bunny.services.domain.system.system.dto.user.LoginDto;
|
||||
import cn.bunny.services.domain.system.system.entity.AdminUser;
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.services.service.system.helper.login;
|
||||
package cn.bunny.services.core.strategy.login;
|
||||
|
||||
|
||||
import cn.bunny.services.domain.system.system.dto.user.LoginDto;
|
||||
|
@ -21,7 +21,7 @@ public interface LoginStrategy {
|
|||
* 登录完成后的内容
|
||||
*
|
||||
* @param loginDto 登录参数
|
||||
* @param adminUser
|
||||
* @param adminUser {@link AdminUser}
|
||||
*/
|
||||
void authenticateAfter(LoginDto loginDto, AdminUser adminUser);
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package cn.bunny.services.core.template;
|
||||
|
||||
import cn.bunny.services.domain.common.model.dto.excel.PermissionExcel;
|
||||
import cn.bunny.services.processor.TreeProcessor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class PermissionTreeProcessor extends TreeProcessor<PermissionExcel> {
|
||||
@Override
|
||||
public List<PermissionExcel> findRoots(List<PermissionExcel> list) {
|
||||
return list.stream()
|
||||
.filter(p -> p.getParentId() == null || p.getParentId() == 0)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildChildren(PermissionExcel parent, List<PermissionExcel> list) {
|
||||
List<PermissionExcel> children = list.stream()
|
||||
.filter(p -> parent.getId().equals(p.getParentId()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!children.isEmpty()) {
|
||||
parent.setChildren(children);
|
||||
children.forEach(child -> buildChildren(child, list));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
package cn.bunny.services.service.configuration.helper.email;
|
||||
package cn.bunny.services.core.template.email;
|
||||
|
||||
import cn.bunny.services.config.mail.MailSenderConfiguration;
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
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.vo.result.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.system.email.entity.EmailTemplate;
|
||||
import cn.bunny.services.domain.system.email.entity.EmailUsers;
|
||||
import cn.bunny.services.exception.AuthCustomerException;
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.services.service.configuration.helper.email;
|
||||
package cn.bunny.services.core.template.email;
|
||||
|
||||
import cn.bunny.services.domain.system.email.entity.EmailTemplate;
|
||||
import cn.bunny.services.mapper.configuration.EmailTemplateMapper;
|
|
@ -1,29 +1,13 @@
|
|||
package cn.bunny.services.service.system.helper.role;
|
||||
package cn.bunny.services.core.utils;
|
||||
|
||||
import cn.bunny.services.context.BaseContext;
|
||||
import cn.bunny.services.domain.common.constant.RedisUserConstant;
|
||||
import cn.bunny.services.domain.common.constant.SecurityConfigConstant;
|
||||
import cn.bunny.services.domain.system.system.entity.AdminUser;
|
||||
import cn.bunny.services.mapper.system.UserMapper;
|
||||
import cn.bunny.services.service.system.helper.UserLoginHelper;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class RoleHelper {
|
||||
|
||||
@Resource
|
||||
private RedisTemplate<String, Object> redisTemplate;
|
||||
|
||||
@Resource
|
||||
private UserMapper userMapper;
|
||||
|
||||
@Resource
|
||||
private UserLoginHelper userloginHelper;
|
||||
|
||||
/**
|
||||
* 判断用户是否具有管理员权限
|
||||
* <p>
|
||||
|
@ -80,45 +64,4 @@ public class RoleHelper {
|
|||
// 判断是否是 admin
|
||||
return roleList.stream().anyMatch(permissionList::contains);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量更新Redis中用户权限信息
|
||||
*
|
||||
* <p><b>使用场景</b>:当用户角色或权限变更时,同步更新Redis中的用户权限数据</p>
|
||||
*
|
||||
* <p><b>实现策略</b>:</p>
|
||||
* <ol>
|
||||
* <li><b>主动更新(当前实现)</b>:重新构建用户权限信息并更新Redis缓存</li>
|
||||
* <li><b>强制下线</b>:删除用户登录态,强制重新认证获取最新权限</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p><b>技术实现</b>:</p>
|
||||
* <ul>
|
||||
* <li>采用Spring事件驱动机制触发更新</li>
|
||||
* <li>使用并行流(parallelStream)提高批量处理效率</li>
|
||||
* <li>仅更新Redis中存在登录态的用户</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param userIds 需要更新的用户ID集合
|
||||
* (仅处理集合中存在的有效用户)
|
||||
* @see RedisUserConstant Redis键前缀常量
|
||||
* @see UserLoginHelper#buildLoginUserVo 用户登录信息构建方法
|
||||
*/
|
||||
public void updateUserRedisInfo(List<Long> userIds) {
|
||||
if (userIds.isEmpty()) return;
|
||||
|
||||
// 批量查询用户
|
||||
List<AdminUser> adminUsers = userMapper.selectBatchIds(userIds);
|
||||
|
||||
// 并行处理用户更新
|
||||
adminUsers.parallelStream()
|
||||
.filter(user -> redisTemplate.hasKey(RedisUserConstant.getAdminLoginInfoPrefix(user.getUsername())))
|
||||
.forEach(user -> {
|
||||
// 策略1: 更新用户权限信息
|
||||
userloginHelper.buildLoginUserVo(user, RedisUserConstant.REDIS_EXPIRATION_TIME);
|
||||
|
||||
// 或者策略2: 强制用户下线
|
||||
// redisTemplate.delete(RedisUserConstant.getAdminLoginInfoPrefix(user.getUsername()));
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package cn.bunny.services.service.system.helper;
|
||||
package cn.bunny.services.core.utils;
|
||||
|
||||
import cn.bunny.services.context.BaseContext;
|
||||
import cn.bunny.services.domain.system.system.entity.RouterRole;
|
||||
|
@ -8,7 +8,6 @@ import cn.bunny.services.domain.system.system.views.ViewRolePermission;
|
|||
import cn.bunny.services.domain.system.system.views.ViewRouterRole;
|
||||
import cn.bunny.services.domain.system.system.vo.router.WebUserRouterVo;
|
||||
import cn.bunny.services.service.system.RouterRoleService;
|
||||
import cn.bunny.services.service.system.helper.role.RoleHelper;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import jakarta.annotation.Resource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
@ -21,7 +20,7 @@ import java.util.*;
|
|||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class RouterHelper {
|
||||
public class RouterServiceHelper {
|
||||
@Resource
|
||||
private RouterRoleService routerRoleService;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package cn.bunny.services.security.config;
|
||||
|
||||
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.system.system.entity.AdminUser;
|
||||
import cn.bunny.services.mapper.system.UserMapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package cn.bunny.services.security.exception;
|
||||
|
||||
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package cn.bunny.services.security.handelr;
|
||||
|
||||
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.enums.ResultCodeEnum;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package cn.bunny.services.security.handelr;
|
||||
|
||||
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.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.security.exception.CustomAuthenticationException;
|
||||
import cn.bunny.services.utils.ResponseUtil;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
|
|
@ -3,7 +3,7 @@ package cn.bunny.services.security.service;
|
|||
import cn.bunny.services.context.BaseContext;
|
||||
import cn.bunny.services.domain.common.model.dto.security.TokenInfo;
|
||||
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.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.security.exception.CustomAuthenticationException;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
package cn.bunny.services.security.service;
|
||||
|
||||
import cn.bunny.services.context.BaseContext;
|
||||
import cn.bunny.services.core.cache.UserAuthorizationCacheService;
|
||||
import cn.bunny.services.core.utils.RoleHelper;
|
||||
import cn.bunny.services.domain.system.system.entity.Permission;
|
||||
import cn.bunny.services.domain.system.system.entity.Role;
|
||||
import cn.bunny.services.mapper.system.PermissionMapper;
|
||||
import cn.bunny.services.mapper.system.RoleMapper;
|
||||
import cn.bunny.services.security.config.WebSecurityConfig;
|
||||
import cn.bunny.services.service.system.helper.role.RoleHelper;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
|
@ -23,10 +22,7 @@ import java.util.Objects;
|
|||
public class PermissionCheckService {
|
||||
|
||||
@Resource
|
||||
private PermissionMapper permissionMapper;
|
||||
|
||||
@Resource
|
||||
private RoleMapper roleMapper;
|
||||
private UserAuthorizationCacheService authorizationCacheService;
|
||||
|
||||
/**
|
||||
* 查询用户所属的角色信息
|
||||
|
@ -38,7 +34,9 @@ public class PermissionCheckService {
|
|||
|
||||
// 根据用户ID查询角色数据
|
||||
Long userId = BaseContext.getUserId();
|
||||
List<Role> roleList = roleMapper.selectListByUserId(userId);
|
||||
String username = BaseContext.getUsername();
|
||||
// List<Role> roleList = roleMapper.selectListByUserId(userId);
|
||||
List<Role> roleList = authorizationCacheService.getRolesByUser(userId, username);
|
||||
|
||||
// 角色代码
|
||||
List<String> roleCodeList = roleList.stream().map(Role::getRoleCode).toList();
|
||||
|
@ -54,7 +52,8 @@ public class PermissionCheckService {
|
|||
}
|
||||
|
||||
// 根据角色列表查询权限信息
|
||||
List<Permission> permissionList = permissionMapper.selectListByUserId(userId);
|
||||
// List<Permission> permissionList = permissionMapper.selectListByUserId(userId);
|
||||
List<Permission> permissionList = authorizationCacheService.getPermissionsByUser(userId, username);
|
||||
|
||||
// 判断是否与请求路径匹配
|
||||
return permissionList.stream()
|
||||
|
|
|
@ -1,21 +1,21 @@
|
|||
package cn.bunny.services.security.service;
|
||||
|
||||
import cn.bunny.services.domain.common.constant.RedisUserConstant;
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.common.model.dto.security.TokenInfo;
|
||||
import cn.bunny.services.domain.common.model.vo.LoginVo;
|
||||
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
||||
import cn.bunny.services.security.exception.CustomAuthenticationException;
|
||||
import cn.bunny.services.utils.JwtTokenUtil;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 处理Token相关逻辑
|
||||
*/
|
||||
@Component
|
||||
@Service
|
||||
public class TokenValidationService {
|
||||
|
||||
@Resource
|
||||
|
@ -39,7 +39,7 @@ public class TokenValidationService {
|
|||
Long userId = JwtTokenUtil.getUserId(token);
|
||||
|
||||
// 查找 Redis
|
||||
Object loginVoObject = redisTemplate.opsForValue().get(RedisUserConstant.getAdminLoginInfoPrefix(username));
|
||||
Object loginVoObject = redisTemplate.opsForValue().get(RedisUserConstant.getUserLoginInfoPrefix(username));
|
||||
LoginVo loginVo = JSON.parseObject(JSON.toJSONString(loginVoObject), LoginVo.class);
|
||||
|
||||
return TokenInfo.builder().userId(userId).username(username).token(token).loginVo(loginVo).build();
|
||||
|
|
|
@ -1,122 +0,0 @@
|
|||
package cn.bunny.services.service.configuration.helper.i18n;
|
||||
|
||||
import cn.bunny.services.domain.common.model.dto.excel.I18nExcel;
|
||||
import cn.bunny.services.domain.system.i18n.entity.I18n;
|
||||
import cn.bunny.services.service.configuration.impl.I18nServiceImpl;
|
||||
import com.alibaba.excel.EasyExcel;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
public class I18nHelper {
|
||||
/**
|
||||
* 将国际化资源列表写入Excel并打包到ZIP输出流
|
||||
*
|
||||
* <p>处理流程:</p>
|
||||
* <ol>
|
||||
* <li>按资源类型(typeName)分组 --- 多语言的类型,英文?中文?</li>
|
||||
* <li>每组数据生成单独多语言 key的Excel工作表</li>
|
||||
* <li>将Excel文件写入ZIP输出流</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param i18nList 国际化资源列表,包含key-value对和类型信息
|
||||
* @param zipOutputStream ZIP输出流,用于写入打包后的Excel文件
|
||||
* @throws RuntimeException 当IO操作失败时抛出
|
||||
*/
|
||||
public static void writeExcel(List<I18n> i18nList, ZipOutputStream zipOutputStream) {
|
||||
Map<String, List<I18nExcel>> hashMap = i18nList.stream()
|
||||
.collect(Collectors.groupingBy(
|
||||
I18n::getTypeName,
|
||||
Collectors.mapping((I18n i18n) -> {
|
||||
String keyName = i18n.getKeyName();
|
||||
String translation = i18n.getTranslation();
|
||||
return I18nExcel.builder().keyName(keyName).translation(translation).build();
|
||||
}, Collectors.toList())
|
||||
));
|
||||
|
||||
|
||||
hashMap.forEach((key, value) -> {
|
||||
try {
|
||||
// 创建临时ByteArrayOutputStream
|
||||
ByteArrayOutputStream excelOutputStream = new ByteArrayOutputStream();
|
||||
|
||||
ZipEntry zipEntry = new ZipEntry(key + ".xlsx");
|
||||
zipOutputStream.putNextEntry(zipEntry);
|
||||
|
||||
// 先写入到临时流
|
||||
EasyExcel.write(excelOutputStream, I18nExcel.class).sheet(key).doWrite(value);
|
||||
zipOutputStream.write(excelOutputStream.toByteArray());
|
||||
zipOutputStream.closeEntry();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 将国际化资源列表写入JSON并打包到ZIP输出流
|
||||
*
|
||||
* <p>处理流程:</p>
|
||||
* <ol>
|
||||
* <li>按资源类型(typeName)分组 --- 多语言的类型,英文?中文?</li>
|
||||
* <li>每组数据生成单独多语言 key的Excel工作表</li>
|
||||
* <li>将JSON文件写入ZIP输出流</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param i18nList 国际化资源列表
|
||||
* @param zipOutputStream ZIP输出流
|
||||
* @throws RuntimeException 当IO操作失败时抛出
|
||||
*/
|
||||
public static void writeJson(List<I18n> i18nList, ZipOutputStream zipOutputStream) {
|
||||
HashMap<String, Object> hashMap = getMapByI18nList(i18nList);
|
||||
|
||||
hashMap.forEach((k, v) -> {
|
||||
try {
|
||||
ZipEntry zipEntry = new ZipEntry(k + ".json");
|
||||
zipOutputStream.putNextEntry(zipEntry);
|
||||
|
||||
zipOutputStream.write(JSON.toJSONString(v).getBytes(StandardCharsets.UTF_8));
|
||||
zipOutputStream.closeEntry();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 将国际化资源列表转换为结构化Map
|
||||
*
|
||||
* <p>转换规则:</p>
|
||||
* <ul>
|
||||
* <li>外层Key: 资源类型(typeName)</li>
|
||||
* <li>内层Key: 资源键名(keyName)</li>
|
||||
* <li>值: 翻译文本(translation)</li>
|
||||
* </ul>
|
||||
* <p>详细结构和结果示例看前端传递的 {@link I18nServiceImpl#getI18nMap} 控制器</p>
|
||||
* <p>/api/i18n/public</p>
|
||||
*
|
||||
* @param i18nList 国际化资源列表
|
||||
* @return 结构化Map {typeName: {keyName: translation}}
|
||||
* @throws IllegalArgumentException 当参数为null时抛出
|
||||
*/
|
||||
@NotNull
|
||||
public static HashMap<String, Object> getMapByI18nList(@NotNull List<I18n> i18nList) {
|
||||
// 整理集合
|
||||
Map<String, Map<String, String>> map = i18nList.stream()
|
||||
.collect(Collectors.groupingBy(
|
||||
I18n::getTypeName,
|
||||
Collectors.toMap(I18n::getKeyName, I18n::getTranslation)));
|
||||
|
||||
// 返回集合
|
||||
return new HashMap<>(map);
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ package cn.bunny.services.service.configuration.impl;
|
|||
import cn.bunny.services.domain.system.configuration.dto.WebConfigurationDto;
|
||||
import cn.bunny.services.domain.system.configuration.entity.WebConfiguration;
|
||||
import cn.bunny.services.domain.common.constant.RedisUserConstant;
|
||||
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.exception.AuthCustomerException;
|
||||
import cn.bunny.services.service.configuration.ConfigurationService;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
|
|
|
@ -7,7 +7,7 @@ import cn.bunny.services.domain.system.email.entity.EmailTemplate;
|
|||
import cn.bunny.services.domain.system.email.vo.EmailTemplateVo;
|
||||
import cn.bunny.services.domain.common.enums.EmailTemplateEnums;
|
||||
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.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.exception.AuthCustomerException;
|
||||
import cn.bunny.services.mapper.configuration.EmailTemplateMapper;
|
||||
import cn.bunny.services.service.configuration.EmailTemplateService;
|
||||
|
|
|
@ -6,7 +6,7 @@ import cn.bunny.services.domain.system.email.dto.EmailUsersUpdateDto;
|
|||
import cn.bunny.services.domain.system.email.entity.EmailUsers;
|
||||
import cn.bunny.services.domain.system.email.vo.EmailUsersVo;
|
||||
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.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.exception.AuthCustomerException;
|
||||
import cn.bunny.services.mapper.configuration.EmailUsersMapper;
|
||||
import cn.bunny.services.service.configuration.EmailUsersService;
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
package cn.bunny.services.service.configuration.impl;
|
||||
|
||||
import cn.bunny.services.core.event.listener.excel.I18nExcelListener;
|
||||
import cn.bunny.services.core.strategy.export.ExcelExportStrategy;
|
||||
import cn.bunny.services.core.strategy.export.JsonExportStrategy;
|
||||
import cn.bunny.services.domain.common.constant.FileType;
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.common.model.dto.excel.I18nExcel;
|
||||
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.i18n.dto.I18nAddDto;
|
||||
import cn.bunny.services.domain.system.i18n.dto.I18nDto;
|
||||
import cn.bunny.services.domain.system.i18n.dto.I18nUpdateByFileDto;
|
||||
|
@ -12,12 +15,10 @@ import cn.bunny.services.domain.system.i18n.dto.I18nUpdateDto;
|
|||
import cn.bunny.services.domain.system.i18n.entity.I18n;
|
||||
import cn.bunny.services.domain.system.i18n.entity.I18nType;
|
||||
import cn.bunny.services.domain.system.i18n.vo.I18nVo;
|
||||
import cn.bunny.services.excel.I18nExcelListener;
|
||||
import cn.bunny.services.exception.AuthCustomerException;
|
||||
import cn.bunny.services.mapper.configuration.I18nMapper;
|
||||
import cn.bunny.services.mapper.configuration.I18nTypeMapper;
|
||||
import cn.bunny.services.service.configuration.I18nService;
|
||||
import cn.bunny.services.service.configuration.helper.i18n.I18nHelper;
|
||||
import cn.bunny.services.utils.FileUtil;
|
||||
import com.alibaba.excel.EasyExcel;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
|
@ -29,6 +30,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
|
@ -47,6 +49,7 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
/**
|
||||
|
@ -60,6 +63,7 @@ import java.util.zip.ZipOutputStream;
|
|||
@Service
|
||||
@Transactional
|
||||
public class I18nServiceImpl extends ServiceImpl<I18nMapper, I18n> implements I18nService {
|
||||
private static final String CACHE_NAMES = "i18n";
|
||||
|
||||
@Resource
|
||||
private I18nTypeMapper i18nTypeMapper;
|
||||
|
@ -70,13 +74,13 @@ public class I18nServiceImpl extends ServiceImpl<I18nMapper, I18n> implements I1
|
|||
* @return 多语言返回内容
|
||||
*/
|
||||
@Override
|
||||
@Cacheable(cacheNames = "i18n", key = "'i18n'", cacheManager = "cacheManagerWithMouth")
|
||||
@Cacheable(cacheNames = CACHE_NAMES, key = "'i18nMap'", cacheManager = "cacheManagerWithMouth")
|
||||
public HashMap<String, Object> getI18nMap() {
|
||||
// 查找默认语言内容
|
||||
I18nType i18nType = i18nTypeMapper.selectOne(Wrappers.<I18nType>lambdaQuery().eq(I18nType::getIsDefault, true));
|
||||
List<I18n> i18nList = list();
|
||||
|
||||
HashMap<String, Object> hashMap = I18nHelper.getMapByI18nList(i18nList);
|
||||
HashMap<String, Object> hashMap = getMapByI18nList(i18nList);
|
||||
hashMap.put("local", Objects.requireNonNull(i18nType.getTypeName(), "zh"));
|
||||
|
||||
return hashMap;
|
||||
|
@ -105,7 +109,7 @@ public class I18nServiceImpl extends ServiceImpl<I18nMapper, I18n> implements I1
|
|||
* @param dto 添加表单
|
||||
*/
|
||||
@Override
|
||||
@CacheEvict(cacheNames = "i18n", key = "'i18n'", beforeInvocation = true)
|
||||
@CacheEvict(cacheNames = CACHE_NAMES, key = "'i18nMap'", beforeInvocation = true)
|
||||
public void addI18n(@Valid I18nAddDto dto) {
|
||||
String keyName = dto.getKeyName();
|
||||
String typeName = dto.getTypeName();
|
||||
|
@ -126,7 +130,7 @@ public class I18nServiceImpl extends ServiceImpl<I18nMapper, I18n> implements I1
|
|||
* @param dto 更新表单
|
||||
*/
|
||||
@Override
|
||||
@CacheEvict(cacheNames = "i18n", key = "'i18n'", beforeInvocation = true)
|
||||
@CacheEvict(cacheNames = CACHE_NAMES, key = "'i18nMap'", beforeInvocation = true)
|
||||
public void updateI18n(@Valid I18nUpdateDto dto) {
|
||||
Long id = dto.getId();
|
||||
|
||||
|
@ -146,7 +150,7 @@ public class I18nServiceImpl extends ServiceImpl<I18nMapper, I18n> implements I1
|
|||
* @param ids 删除id列表
|
||||
*/
|
||||
@Override
|
||||
@CacheEvict(cacheNames = "i18n", key = "'i18n'", beforeInvocation = true)
|
||||
@CacheEvict(cacheNames = CACHE_NAMES, key = "'i18nMap'", beforeInvocation = true)
|
||||
public void deleteI18n(List<Long> ids) {
|
||||
// 判断数据请求是否为空
|
||||
if (ids.isEmpty()) throw new AuthCustomerException(ResultCodeEnum.REQUEST_IS_EMPTY);
|
||||
|
@ -163,18 +167,35 @@ public class I18nServiceImpl extends ServiceImpl<I18nMapper, I18n> implements I1
|
|||
@Override
|
||||
public ResponseEntity<byte[]> downloadI18n(String type) {
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
try (ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream)) {
|
||||
|
||||
try (ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream)) {
|
||||
// 查找默认语言内容
|
||||
List<I18n> i18nList = list();
|
||||
|
||||
// 类型是Excel写入Excel
|
||||
if (type.equals(FileType.EXCEL)) {
|
||||
I18nHelper.writeExcel(i18nList, zipOutputStream);
|
||||
i18nList.stream()
|
||||
.collect(Collectors.groupingBy(
|
||||
I18n::getTypeName,
|
||||
Collectors.mapping((I18n i18n) -> {
|
||||
String keyName = i18n.getKeyName();
|
||||
String translation = i18n.getTranslation();
|
||||
return I18nExcel.builder().keyName(keyName).translation(translation).build();
|
||||
}, Collectors.toList())
|
||||
))
|
||||
.forEach((key, value) -> {
|
||||
ExcelExportStrategy excelExportStrategy = new ExcelExportStrategy(I18nExcel.class, key);
|
||||
excelExportStrategy.export(value, zipOutputStream, key + ".xlsx");
|
||||
});
|
||||
}
|
||||
// 其他格式写入JSON
|
||||
else {
|
||||
I18nHelper.writeJson(i18nList, zipOutputStream);
|
||||
HashMap<String, Object> hashMap = getMapByI18nList(i18nList);
|
||||
|
||||
hashMap.forEach((k, v) -> {
|
||||
JsonExportStrategy jsonExportStrategy = new JsonExportStrategy();
|
||||
jsonExportStrategy.export(v, zipOutputStream, k + ".json");
|
||||
});
|
||||
}
|
||||
|
||||
// 设置响应头
|
||||
|
@ -193,7 +214,7 @@ public class I18nServiceImpl extends ServiceImpl<I18nMapper, I18n> implements I1
|
|||
* @param dto 文件更新对象
|
||||
*/
|
||||
@Override
|
||||
@CacheEvict(cacheNames = "i18n", key = "'i18n'", beforeInvocation = true)
|
||||
@CacheEvict(cacheNames = CACHE_NAMES, key = "'i18nMap'", beforeInvocation = true)
|
||||
public void uploadI18nFile(I18nUpdateByFileDto dto) {
|
||||
String type = dto.getType();
|
||||
MultipartFile file = dto.getFile();
|
||||
|
@ -240,4 +261,32 @@ public class I18nServiceImpl extends ServiceImpl<I18nMapper, I18n> implements I1
|
|||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将国际化资源列表转换为结构化Map
|
||||
*
|
||||
* <p>转换规则:</p>
|
||||
* <ul>
|
||||
* <li>外层Key: 资源类型(typeName)</li>
|
||||
* <li>内层Key: 资源键名(keyName)</li>
|
||||
* <li>值: 翻译文本(translation)</li>
|
||||
* </ul>
|
||||
* <p>详细结构和结果示例看前端传递的 {@link I18nServiceImpl#getI18nMap} 控制器</p>
|
||||
* <p>/api/i18n/public</p>
|
||||
*
|
||||
* @param i18nList 国际化资源列表
|
||||
* @return 结构化Map {typeName: {keyName: translation}}
|
||||
* @throws IllegalArgumentException 当参数为null时抛出
|
||||
*/
|
||||
@NotNull
|
||||
public HashMap<String, Object> getMapByI18nList(@NotNull List<I18n> i18nList) {
|
||||
// 整理集合
|
||||
Map<String, Map<String, String>> map = i18nList.stream()
|
||||
.collect(Collectors.groupingBy(
|
||||
I18n::getTypeName,
|
||||
Collectors.toMap(I18n::getKeyName, I18n::getTranslation)));
|
||||
|
||||
// 返回集合
|
||||
return new HashMap<>(map);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
package cn.bunny.services.service.configuration.impl;
|
||||
|
||||
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
|
||||
import cn.bunny.services.domain.system.i18n.dto.I18nTypeAddDto;
|
||||
import cn.bunny.services.domain.system.i18n.dto.I18nTypeDto;
|
||||
import cn.bunny.services.domain.system.i18n.dto.I18nTypeUpdateDto;
|
||||
import cn.bunny.services.domain.system.i18n.entity.I18nType;
|
||||
import cn.bunny.services.domain.system.i18n.vo.I18nTypeVo;
|
||||
import cn.bunny.services.domain.common.model.vo.result.ResultCodeEnum;
|
||||
import cn.bunny.services.exception.AuthCustomerException;
|
||||
import cn.bunny.services.mapper.configuration.I18nTypeMapper;
|
||||
import cn.bunny.services.service.configuration.I18nTypeService;
|
||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.cache.annotation.Caching;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
|
@ -28,6 +31,7 @@ import java.util.List;
|
|||
@Service
|
||||
@Transactional
|
||||
public class I18nTypeServiceImpl extends ServiceImpl<I18nTypeMapper, I18nType> implements I18nTypeService {
|
||||
private static final String CACHE_NAMES = "i18n";
|
||||
|
||||
/**
|
||||
* 获取多语言类型
|
||||
|
@ -35,6 +39,7 @@ public class I18nTypeServiceImpl extends ServiceImpl<I18nTypeMapper, I18nType> i
|
|||
* @return 多语言类型列表
|
||||
*/
|
||||
@Override
|
||||
@Cacheable(cacheNames = CACHE_NAMES, key = "'i18nTypeList'", cacheManager = "cacheManagerWithMouth")
|
||||
public List<I18nTypeVo> getI18nTypeList(I18nTypeDto dto) {
|
||||
List<I18nType> i18nTypeList = baseMapper.selectListByPage(dto);
|
||||
return i18nTypeList.stream().map(i18nType -> {
|
||||
|
@ -50,6 +55,10 @@ public class I18nTypeServiceImpl extends ServiceImpl<I18nTypeMapper, I18nType> i
|
|||
* @param dto 多语言类型添加
|
||||
*/
|
||||
@Override
|
||||
@Caching(evict = {
|
||||
@CacheEvict(cacheNames = CACHE_NAMES, key = "'i18nMap'", beforeInvocation = true),
|
||||
@CacheEvict(cacheNames = CACHE_NAMES, key = "'i18nTypeList'", beforeInvocation = true),
|
||||
})
|
||||
public void addI18nType(I18nTypeAddDto dto) {
|
||||
String typeName = dto.getTypeName();
|
||||
Boolean isDefault = dto.getIsDefault();
|
||||
|
@ -77,14 +86,18 @@ public class I18nTypeServiceImpl extends ServiceImpl<I18nTypeMapper, I18nType> i
|
|||
* @param dto 多语言类型更新
|
||||
*/
|
||||
@Override
|
||||
@Caching(evict = {
|
||||
@CacheEvict(cacheNames = CACHE_NAMES, key = "'i18nMap'", beforeInvocation = true),
|
||||
@CacheEvict(cacheNames = CACHE_NAMES, key = "'i18nTypeList'", beforeInvocation = true),
|
||||
})
|
||||
public void updateI18nType(I18nTypeUpdateDto dto) {
|
||||
Long id = dto.getId();
|
||||
Boolean isDefault = dto.getIsDefault();
|
||||
I18nType i18nType = new I18nType();
|
||||
|
||||
// 查询更新的内容是否存在
|
||||
List<I18nType> i18nTypeList = list(Wrappers.<I18nType>lambdaQuery().eq(I18nType::getId, id));
|
||||
if (i18nTypeList.isEmpty()) throw new AuthCustomerException(ResultCodeEnum.DATA_NOT_EXIST);
|
||||
I18nType dbI18nType = getOne(Wrappers.<I18nType>lambdaQuery().eq(I18nType::getId, id));
|
||||
if (dbI18nType == null) throw new AuthCustomerException(ResultCodeEnum.DATA_NOT_EXIST);
|
||||
|
||||
// 如果是默认,将其它内容设为false
|
||||
if (isDefault) {
|
||||
|
@ -104,6 +117,10 @@ public class I18nTypeServiceImpl extends ServiceImpl<I18nTypeMapper, I18nType> i
|
|||
* @param ids 删除id列表
|
||||
*/
|
||||
@Override
|
||||
@Caching(evict = {
|
||||
@CacheEvict(cacheNames = CACHE_NAMES, key = "'i18nMap'", beforeInvocation = true),
|
||||
@CacheEvict(cacheNames = CACHE_NAMES, key = "'i18nTypeList'", beforeInvocation = true),
|
||||
})
|
||||
public void deleteI18nType(List<Long> ids) {
|
||||
// 判断数据请求是否为空
|
||||
if (ids.isEmpty()) throw new AuthCustomerException(ResultCodeEnum.REQUEST_IS_EMPTY);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue