feat: 根据token分页查询用户日志和用户信息

This commit is contained in:
bunny 2024-10-22 10:59:18 +08:00
parent fd63363101
commit e2fb65cc29
27 changed files with 277 additions and 80 deletions

View File

@ -1,4 +1,62 @@
# 搭建后端运行环境 # 接口说明
## 请求接口
请求接口都是`/admin`前缀,部分接口会被忽略,忽略接口看下面。
所有分页请求内容都是通过路径传参方式
请求时需要带有token只要前端在请求头中添加`token:内容`即可
采用SpringSecurity验证
## 接口忽略
### SpringSecurity接口忽略
这是相关拦截请求内容如果要访问接口必须携带token但是有些接口是不需要token的不需要token就配置在这里。但是放在这里后如果用户请求的地址是被忽略的那么也就拿不到token也就拿不到登录相关信息。
获取用户自身的登录请求是不需要携带用户Id只要有token去解析即可。
```java
// 排出鉴定路径
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
String[] annotations = {
"/", "/ws/**",
"/*/*/noAuth/**", "/*/noAuth/**", "/noAuth/**",
"/media.ico", "/favicon.ico", "*.html", "/webjars/**", "/v3/api-docs/**", "swagger-ui/**",
"/*/files/**",
"/error", "/*/i18n/getI18n",
};
return web -> web.ignoring().requestMatchers(annotations)
.requestMatchers(RegexRequestMatcher.regexMatcher(".*\\.(css|js)$"));
}
```
![image-20241022095731221](./data/images/image-20241022095731221.png)
有些会被忽略的接口,凡是带有`noAuth`都是不需要验证的,但是要注意一点,不需要验证但是后端需要拿到登录相关信息是拿不到的。
![image-20241022095311658](./data/images/image-20241022095311658.png)
我是将用户相关请求使用SpringSecurity进行拦截如果有相关匹配路径那么就会被拦截此时接口参数中会带有token内容拿到token进行解析之后取出相关用户信息比如用户Id、username等。
将这些信息拿出来后放到ThreadLocal中存储在线程中如果微服务中需要需要放在请求头中因为微服务不在同一个线程中。这个操作适合单体或者是微服务中不需要请求其它微服务的方式。
![image-20241022095641040](./data/images/image-20241022095641040.png)
### 不需要管理接口
请求是会有不需要登录就能访问的接口,也需要不要被管理的接口
## 验证码验证忽略
为了公网上的展示,如果需要获取验证码比较的麻烦,如果你的需求和我一样那么可以在这里放开这些注释
![image-20241022100317018](./data/images/image-20241022100317018.png)
# 搭建后端环境
1. 需要JDK17 1. 需要JDK17
2. MySQL 2. MySQL
@ -42,6 +100,7 @@ docker rm slave_3304
docker run --name slave_3304 -p 3304:3306 \ docker run --name slave_3304 -p 3304:3306 \
-v /bunny/docker_data/mysql/slave_3304/etc/my.cnf:/etc/my.cnf \ -v /bunny/docker_data/mysql/slave_3304/etc/my.cnf:/etc/my.cnf \
-v /bunny/docker_data/mysql/slave_3304/data:/var/lib/mysql \ -v /bunny/docker_data/mysql/slave_3304/data:/var/lib/mysql \
-v /bunny/docker_data/mysql/slave_3304/backup:\
--restart=always --privileged=true \ --restart=always --privileged=true \
-e MYSQL_ROOT_PASSWORD=02120212 \ -e MYSQL_ROOT_PASSWORD=02120212 \
-e TZ=Asia/Shanghai \ -e TZ=Asia/Shanghai \
@ -62,11 +121,10 @@ FLUSH PRIVILEGES;
```shell ```shell
[mysqld] [mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
skip-host-cache skip-host-cache
skip-name-resolve skip-name-resolve
secure-file-priv=/var/lib/mysql-files secure-file-priv=/var/lib/mysql-files
user=mysql
# 设置字符集 # 设置字符集
character-set-server=utf8mb4 character-set-server=utf8mb4
@ -80,9 +138,6 @@ log-bin=mysql-bin
# 设置表名不区分大小写 # 设置表名不区分大小写
lower_case_table_names = 1 lower_case_table_names = 1
[client]
socket=/var/run/mysqld/mysqld.sock
``` ```
## 安装Redis ## 安装Redis
@ -119,6 +174,30 @@ docker run -d \
minio/minio server /data --console-address ":9090" minio/minio server /data --console-address ":9090"
``` ```
# 动态定时任务
使用`Quartz `数据存储在数据库中持久化存储.
所有的Quartz内容都放在这个目录中因为前端需要知道有哪些定时任务这时候又不能将数据添加到数据库中如果以后需要更多的定时任务那么需要再数据库中添加这样做很麻烦。
我们可以通过反射只要约定好内容,通过反射扫描的方式来获取这些可以使用的定时任务,反射的注解是这个:`@QuartzSchedulers(type = "test", description = "JobHello任务内容")`
![image-20241022101534393](./data/images/image-20241022101534393.png)
## 注解说明
扫描注解包,可以通过依赖注入的方式使用
![image-20241022102210149](./data/images/image-20241022102210149.png)
类型注解存放位置在下面。
![image-20241022101742586](./data/images/image-20241022101742586.png)
获取所有可用定时任务
![image-20241022102510646](data/images/image-20241022102510646.png)
# Quartz 方法 # Quartz 方法
## TriggerBuilder ## TriggerBuilder

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB

View File

@ -19,12 +19,18 @@ public class AnnotationScanner {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Set<Class<?>> getClassesWithAnnotation(Class<?> annotation) { public Set<Class<?>> getClassesWithAnnotation(Class<?> annotation) {
// 设置是否延迟初始化
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false); ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
// 只需要带有 Annotation 注解类的内容
scanner.addIncludeFilter(new AnnotationTypeFilter((Class<? extends Annotation>) annotation)); scanner.addIncludeFilter(new AnnotationTypeFilter((Class<? extends Annotation>) annotation));
// 扫描到的内容排除重复的内容
Set<Class<?>> classes = new HashSet<>(); Set<Class<?>> classes = new HashSet<>();
// 只要 cn.bunny.services 包下面的全部内容
for (BeanDefinition bd : scanner.findCandidateComponents("cn.bunny.services")) { for (BeanDefinition bd : scanner.findCandidateComponents("cn.bunny.services")) {
try { try {
// 通过反射加载类并将类名转换为 Class 对象
Class<?> clazz = Class.forName(bd.getBeanClassName()); Class<?> clazz = Class.forName(bd.getBeanClassName());
classes.add(clazz); classes.add(clazz);
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {

View File

@ -52,7 +52,7 @@ public class EmailUsersController {
} }
@Operation(summary = "获取所有邮箱配置用户", description = "获取所有邮箱配置用户") @Operation(summary = "获取所有邮箱配置用户", description = "获取所有邮箱配置用户")
@GetMapping("getAllMailboxConfigurationUsers") @GetMapping("noManage/getAllMailboxConfigurationUsers")
public Mono<Result<List<Map<String, String>>>> getAllMailboxConfigurationUsers() { public Mono<Result<List<Map<String, String>>>> getAllMailboxConfigurationUsers() {
List<Map<String, String>> list = emailUsersService.getAllMailboxConfigurationUsers(); List<Map<String, String>> list = emailUsersService.getAllMailboxConfigurationUsers();
return Mono.just(Result.success(list)); return Mono.just(Result.success(list));

View File

@ -62,14 +62,14 @@ public class FilesController {
} }
@Operation(summary = "获取所有文件类型", description = "获取所有文件类型") @Operation(summary = "获取所有文件类型", description = "获取所有文件类型")
@GetMapping("getAllMediaTypes") @GetMapping("noManage/getAllMediaTypes")
public Mono<Result<Set<String>>> getAllMediaTypes() { public Mono<Result<Set<String>>> getAllMediaTypes() {
Set<String> list = filesService.getAllMediaTypes(); Set<String> list = filesService.getAllMediaTypes();
return Mono.just(Result.success(list)); return Mono.just(Result.success(list));
} }
@Operation(summary = "获取所有文件存储基础路径", description = "获取所有文件存储基础路径") @Operation(summary = "获取所有文件存储基础路径", description = "获取所有文件存储基础路径")
@GetMapping("getAllFilesStoragePath") @GetMapping("noManage/getAllFilesStoragePath")
public Mono<Result<List<String>>> getAllFilesStoragePath() { public Mono<Result<List<String>>> getAllFilesStoragePath() {
Map<String, String> typeMap = MinioConstant.typeMap; Map<String, String> typeMap = MinioConstant.typeMap;
List<String> list = typeMap.keySet().stream().toList(); List<String> list = typeMap.keySet().stream().toList();

View File

@ -50,7 +50,7 @@ public class MenuIconController {
} }
@Operation(summary = "获取查询图标名称列", description = "获取查询图标名称列") @Operation(summary = "获取查询图标名称列", description = "获取查询图标名称列")
@GetMapping("getIconNameList") @GetMapping("noManage/getIconNameList")
public Mono<Result<List<MenuIconVo>>> getIconNameList(String iconName) { public Mono<Result<List<MenuIconVo>>> getIconNameList(String iconName) {
List<MenuIconVo> voList = menuIconService.getIconNameList(iconName); List<MenuIconVo> voList = menuIconService.getIconNameList(iconName);
return Mono.just(Result.success(voList)); return Mono.just(Result.success(voList));

View File

@ -50,7 +50,7 @@ public class RoleController {
} }
@Operation(summary = "获取所有角色", description = "获取所有角色") @Operation(summary = "获取所有角色", description = "获取所有角色")
@GetMapping("getAllRoles") @GetMapping("noManage/getAllRoles")
public Mono<Result<List<RoleVo>>> getAllRoles() { public Mono<Result<List<RoleVo>>> getAllRoles() {
List<RoleVo> roleVoList = roleService.getAllRoles(); List<RoleVo> roleVoList = roleService.getAllRoles();
return Mono.just(Result.success(roleVoList)); return Mono.just(Result.success(roleVoList));

View File

@ -29,7 +29,7 @@ public class RolePowerController {
private RolePowerService rolePowerService; private RolePowerService rolePowerService;
@Operation(summary = "根据角色id获取权限内容", description = "角色列获取已选择的权限") @Operation(summary = "根据角色id获取权限内容", description = "角色列获取已选择的权限")
@GetMapping("getPowerListByRoleId") @GetMapping("noManage/getPowerListByRoleId")
public Mono<Result<List<String>>> getPowerListByRoleId(Long id) { public Mono<Result<List<String>>> getPowerListByRoleId(Long id) {
List<String> voList = rolePowerService.getPowerListByRoleId(id); List<String> voList = rolePowerService.getPowerListByRoleId(id);
return Mono.just(Result.success(voList)); return Mono.just(Result.success(voList));

View File

@ -39,7 +39,7 @@ public class RouterController {
private RouterService routerService; private RouterService routerService;
@Operation(summary = "获取用户菜单", description = "获取用户菜单") @Operation(summary = "获取用户菜单", description = "获取用户菜单")
@GetMapping("getRouterAsync") @GetMapping("noManage/getRouterAsync")
public Mono<Result<List<UserRouterVo>>> getRouterAsync() { public Mono<Result<List<UserRouterVo>>> getRouterAsync() {
List<UserRouterVo> voList = routerService.getRouterAsync(); List<UserRouterVo> voList = routerService.getRouterAsync();
return Mono.just(Result.success(voList)); return Mono.just(Result.success(voList));

View File

@ -51,7 +51,7 @@ public class SchedulersController {
} }
@Operation(summary = "获取所有可用调度任务", description = "获取所有可用调度任务") @Operation(summary = "获取所有可用调度任务", description = "获取所有可用调度任务")
@GetMapping("getAllScheduleJobList") @GetMapping("noManage/getAllScheduleJobList")
public Mono<Result<List<Map<String, String>>>> getAllScheduleJobList() { public Mono<Result<List<Map<String, String>>>> getAllScheduleJobList() {
List<Map<String, String>> mapList = schedulersService.getAllScheduleJobList(); List<Map<String, String>> mapList = schedulersService.getAllScheduleJobList();
return Mono.just(Result.success(mapList)); return Mono.just(Result.success(mapList));

View File

@ -42,6 +42,13 @@ public class UserController {
return Mono.just(Result.success(pageResult)); return Mono.just(Result.success(pageResult));
} }
@Operation(summary = "获取本地登录用户信息", description = "获取本地登录用户信息")
@GetMapping("noManage/getUserinfo")
public Mono<Result<UserVo>> getUserinfo() {
UserVo vo = userService.getUserinfo();
return Mono.just(Result.success(vo));
}
@Operation(summary = "获取用户信息", description = "获取用户信息") @Operation(summary = "获取用户信息", description = "获取用户信息")
@GetMapping("getUserinfoById") @GetMapping("getUserinfoById")
public Mono<Result<UserVo>> getUserinfoById(Long id) { public Mono<Result<UserVo>> getUserinfoById(Long id) {
@ -50,7 +57,7 @@ public class UserController {
} }
@Operation(summary = "多条件查询用户", description = "多条件查询用户") @Operation(summary = "多条件查询用户", description = "多条件查询用户")
@GetMapping("queryUser") @GetMapping("noManage/queryUser")
public Mono<Result<List<AdminUserVo>>> queryUser(String keyword) { public Mono<Result<List<AdminUserVo>>> queryUser(String keyword) {
List<AdminUserVo> voList = userService.queryUser(keyword); List<AdminUserVo> voList = userService.queryUser(keyword);
return Mono.just(Result.success(voList)); return Mono.just(Result.success(voList));
@ -113,7 +120,7 @@ public class UserController {
} }
@Operation(summary = "退出登录", description = "退出登录") @Operation(summary = "退出登录", description = "退出登录")
@PostMapping("logout") @PostMapping("noManage/logout")
public Result<String> logout() { public Result<String> logout() {
userService.logout(); userService.logout();
return Result.success(ResultCodeEnum.LOGOUT_SUCCESS); return Result.success(ResultCodeEnum.LOGOUT_SUCCESS);

View File

@ -46,6 +46,18 @@ public class UserLoginLogController {
return Mono.just(Result.success(pageResult)); return Mono.just(Result.success(pageResult));
} }
@Operation(summary = "获取本地用户登录日志", description = "获取本地用户登录日志")
@GetMapping("noManage/getUserLoginLogListByLocalUser/{page}/{limit}")
public Mono<Result<PageResult<UserLoginLogVo>>> getUserLoginLogListByLocalUser(
@Parameter(name = "page", description = "当前页", required = true)
@PathVariable("page") Integer page,
@Parameter(name = "limit", description = "每页记录数", required = true)
@PathVariable("limit") Integer limit) {
Page<UserLoginLog> pageParams = new Page<>(page, limit);
PageResult<UserLoginLogVo> voPageResult = userLoginLogService.getUserLoginLogListByLocalUser(pageParams);
return Mono.just(Result.success(voPageResult));
}
@Operation(summary = "删除用户登录日志", description = "删除用户登录日志") @Operation(summary = "删除用户登录日志", description = "删除用户登录日志")
@DeleteMapping("deleteUserLoginLog") @DeleteMapping("deleteUserLoginLog")
public Mono<Result<String>> deleteUserLoginLog(@RequestBody List<Long> ids) { public Mono<Result<String>> deleteUserLoginLog(@RequestBody List<Long> ids) {

View File

@ -0,0 +1,35 @@
package cn.bunny.services.factory;
import cn.bunny.dao.entity.log.UserLoginLog;
import cn.bunny.dao.pojo.result.PageResult;
import cn.bunny.dao.vo.log.UserLoginLogVo;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class UserLoginLogFactory {
/**
* 用户登录日志分页查询通用方法
*
* @param page 分页结果
* @return 分页用户登录日志
*/
public PageResult<UserLoginLogVo> getUserLoginLogVoPageResult(IPage<UserLoginLog> page) {
List<UserLoginLogVo> voList = page.getRecords().stream().map(userLoginLog -> {
UserLoginLogVo userLoginLogVo = new UserLoginLogVo();
BeanUtils.copyProperties(userLoginLog, userLoginLogVo);
return userLoginLogVo;
}).toList();
return PageResult.<UserLoginLogVo>builder()
.list(voList)
.pageNo(page.getCurrent())
.pageSize(page.getSize())
.total(page.getTotal())
.build();
}
}

View File

@ -36,4 +36,12 @@ public interface UserLoginLogMapper extends BaseMapper<UserLoginLog> {
* @param ids 删除 id 列表 * @param ids 删除 id 列表
*/ */
void deleteBatchIdsWithPhysics(List<Long> ids); void deleteBatchIdsWithPhysics(List<Long> ids);
/**
* * 分页查询根据用户Id用户登录日志内容
*
* @param pageParams 分页查询内容
* @return 用户登录日志返回列表
*/
IPage<UserLoginLog> selectListByPageWithLocalUser(Page<UserLoginLog> pageParams, Long id);
} }

View File

@ -55,14 +55,17 @@ public class CustomAuthorizationManagerServiceImpl implements AuthorizationManag
boolean checkedAdmin = CustomCheckIsAdmin.checkAdmin(roleCodeList, loginVo); boolean checkedAdmin = CustomCheckIsAdmin.checkAdmin(roleCodeList, loginVo);
if (checkedAdmin) return true; if (checkedAdmin) return true;
// 不是 admin查询角色权限关系表 // 判断请求地址是否是 noManage 不需要被验证的
List<String> powerCodes = loginVo.getPermissions(); String requestURI = request.getRequestURI();
if (requestURI.contains("noManage")) return true;
// 根据权限码查询可以访问URL // 不是 admin查询角色权限关系表,根据权限码查询可以访问URL
List<String> powerCodes = loginVo.getPermissions();
List<Power> powerList = powerMapper.selectListByPowerCodes(powerCodes); List<Power> powerList = powerMapper.selectListByPowerCodes(powerCodes);
// 判断是否与请求路径匹配 // 判断是否与请求路径匹配
return powerList.stream().anyMatch(power -> AntPathRequestMatcher.antMatcher(power.getRequestUrl()).matches(request) || return powerList.stream()
request.getRequestURI().matches(power.getRequestUrl())); .anyMatch(power -> AntPathRequestMatcher.antMatcher(power.getRequestUrl()).matches(request) ||
requestURI.matches(power.getRequestUrl()));
} }
} }

View File

@ -32,4 +32,12 @@ public interface UserLoginLogService extends IService<UserLoginLog> {
* @param ids 删除id列表 * @param ids 删除id列表
*/ */
void deleteUserLoginLog(List<Long> ids); void deleteUserLoginLog(List<Long> ids);
/**
* * 获取本地用户登录日志
*
* @param pageParams 分页查询内容
* @return 用户登录日志返回列表
*/
PageResult<UserLoginLogVo> getUserLoginLogListByLocalUser(Page<UserLoginLog> pageParams);
} }

View File

@ -115,4 +115,11 @@ public interface UserService extends IService<AdminUser> {
* @param dto 管理员用户修改密码 * @param dto 管理员用户修改密码
*/ */
void updateUserStatusByAdmin(AdminUserUpdateUserStatusDto dto); void updateUserStatusByAdmin(AdminUserUpdateUserStatusDto dto);
/**
* * 获取本地登录用户信息
*
* @return 用户信息
*/
UserVo getUserinfo();
} }

View File

@ -1,15 +1,17 @@
package cn.bunny.services.service.impl; package cn.bunny.services.service.impl;
import cn.bunny.common.service.context.BaseContext;
import cn.bunny.dao.dto.log.UserLoginLogDto; import cn.bunny.dao.dto.log.UserLoginLogDto;
import cn.bunny.dao.entity.log.UserLoginLog; import cn.bunny.dao.entity.log.UserLoginLog;
import cn.bunny.dao.pojo.result.PageResult; import cn.bunny.dao.pojo.result.PageResult;
import cn.bunny.dao.vo.log.UserLoginLogVo; import cn.bunny.dao.vo.log.UserLoginLogVo;
import cn.bunny.services.factory.UserLoginLogFactory;
import cn.bunny.services.mapper.UserLoginLogMapper; import cn.bunny.services.mapper.UserLoginLogMapper;
import cn.bunny.services.service.UserLoginLogService; import cn.bunny.services.service.UserLoginLogService;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.List; import java.util.List;
@ -25,6 +27,9 @@ import java.util.List;
@Service @Service
public class UserLoginLogServiceImpl extends ServiceImpl<UserLoginLogMapper, UserLoginLog> implements UserLoginLogService { public class UserLoginLogServiceImpl extends ServiceImpl<UserLoginLogMapper, UserLoginLog> implements UserLoginLogService {
@Autowired
private UserLoginLogFactory factory;
/** /**
* * 用户登录日志 服务实现类 * * 用户登录日志 服务实现类
* *
@ -37,18 +42,7 @@ public class UserLoginLogServiceImpl extends ServiceImpl<UserLoginLogMapper, Use
// 分页查询菜单图标 // 分页查询菜单图标
IPage<UserLoginLog> page = baseMapper.selectListByPage(pageParams, dto); IPage<UserLoginLog> page = baseMapper.selectListByPage(pageParams, dto);
List<UserLoginLogVo> voList = page.getRecords().stream().map(userLoginLog -> { return factory.getUserLoginLogVoPageResult(page);
UserLoginLogVo userLoginLogVo = new UserLoginLogVo();
BeanUtils.copyProperties(userLoginLog, userLoginLogVo);
return userLoginLogVo;
}).toList();
return PageResult.<UserLoginLogVo>builder()
.list(voList)
.pageNo(page.getCurrent())
.pageSize(page.getSize())
.total(page.getTotal())
.build();
} }
/** /**
@ -60,4 +54,18 @@ public class UserLoginLogServiceImpl extends ServiceImpl<UserLoginLogMapper, Use
public void deleteUserLoginLog(List<Long> ids) { public void deleteUserLoginLog(List<Long> ids) {
baseMapper.deleteBatchIdsWithPhysics(ids); baseMapper.deleteBatchIdsWithPhysics(ids);
} }
/**
* * 获取本地用户登录日志
*
* @param pageParams 分页查询内容
* @return 用户登录日志返回列表
*/
@Override
public PageResult<UserLoginLogVo> getUserLoginLogListByLocalUser(Page<UserLoginLog> pageParams) {
Long userId = BaseContext.getUserId();
IPage<UserLoginLog> page = baseMapper.selectListByPageWithLocalUser(pageParams, userId);
return factory.getUserLoginLogVoPageResult(page);
}
} }

View File

@ -301,6 +301,27 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, AdminUser> implemen
updateById(adminUser); updateById(adminUser);
} }
/**
* * 获取本地登录用户信息
*
* @return 用户信息
*/
@Override
public UserVo getUserinfo() {
// 查询当前用户信息
Long userId = BaseContext.getUserId();
AdminUser adminUser = getOne(Wrappers.<AdminUser>lambdaQuery().eq(AdminUser::getId, userId));
// 赋值对象
UserVo userVo = new UserVo();
BeanUtils.copyProperties(adminUser, userVo);
// 设置用户头像内容
String avatar = adminUser.getAvatar();
if (StringUtils.hasText(avatar)) userVo.setAvatar(minioUtil.getObjectNameFullPath(avatar));
return userVo;
}
/** /**
* * 用户信息 服务实现类 * * 用户信息 服务实现类
* *

View File

@ -70,6 +70,13 @@
</where> </where>
</select> </select>
<!-- 分页查询根据用户Id用户登录日志内容 -->
<select id="selectListByPageWithLocalUser" resultType="cn.bunny.dao.entity.log.UserLoginLog">
select
<include refid="Base_Column_List"/>
from log_user_login where user_id = #{id} order by create_time desc
</select>
<!-- 物理删除用户登录日志 --> <!-- 物理删除用户登录日志 -->
<delete id="deleteBatchIdsWithPhysics"> <delete id="deleteBatchIdsWithPhysics">
delete delete

View File

@ -0,0 +1,28 @@
{
"Version": "5.8.0",
"Title": "BunnyAdmin",
"Copyright": "Copyright © 2020-present",
"FixedHeader": true,
"HiddenSideBar": false,
"MultiTagsCache": false,
"KeepAlive": true,
"Locale": "zh",
"Layout": "vertical",
"Theme": "light",
"DarkMode": false,
"OverallStyle": "light",
"Grey": false,
"Weak": false,
"HideTabs": false,
"HideFooter": false,
"Stretch": false,
"SidebarStatus": true,
"EpThemeColor": "#409EFF",
"ShowLogo": true,
"ShowModel": "smart",
"MenuArrowIconNoTransition": false,
"CachingAsyncRoutes": false,
"TooltipEffect": "light",
"ResponsiveStorageNameSpace": "responsive-",
"MenuSearchHistory": 6
}

View File

@ -1,45 +0,0 @@
<body style="margin: 0; padding: 0; background-color: #f5f5f5;">
<div style="max-width: 600px; margin: 0 auto;">
<table style="width: 100%; border-collapse: collapse; background-color: #ffffff; font-family: Arial, sans-serif;">
<tr>
<th style="height: 60px; padding: 20px; background-color: #0074d3; border-radius: 5px 5px 0 0;"
valign="middle">
<h1 style="margin: 0; color: #ffffff; font-size: 24px;">BunnyBBS邮箱验证码</h1>
</th>
</tr>
<tr>
<td style="padding: 20px;">
<div style="background-color: #ffffff; padding: 25px;">
<h2 style="margin: 10px 0; font-size: 18px; color: #333333;">
尊敬的用户,
</h2>
<p style="margin: 10px 0; font-size: 16px; color: #333333;">
感谢您注册我们的产品. 您的账号正在进行电子邮件验证.
</p>
<p style="margin: 10px 0; font-size: 16px; color: #333333;">
验证码为: <span class="button" style="color: #1100ff;">${verifyCode}</span>
</p>
<p style="margin: 10px 0; font-size: 16px; color: #333333;">
验证码的有效期只有一分钟,请抓紧时间进行验证吧!
</p>
<p style="margin: 10px 0; font-size: 16px; color: #dc1818;">
如果非本人操作,请忽略此邮件
</p>
</div>
</td>
</tr>
<tr>
<td style="text-align: center; padding: 20px; background-color: #f5f5f5;">
<p style="margin: 0; font-size: 12px; color: #747474;">
XXXXX<br>
Contact us: XXXXXXX@qq.com
</p>
<p style="margin: 10px 0; font-size: 12px; color: #747474;">
This is an automated email, please do not reply.<br>
© Company Name
</p>
</td>
</tr>
</table>
</div>
</body>

View File

@ -26,7 +26,9 @@ public class TestPath {
// 执行后读取内容 // 执行后读取内容
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line; String line;
while ((line = reader.readLine()) != null) {System.out.println(line);} while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} }
@SneakyThrows @SneakyThrows

View File

@ -0,0 +1,11 @@
package cn.bunny.services.security.service.impl;
import org.junit.jupiter.api.Test;
class CustomAuthorizationManagerServiceImplTest {
@Test
void testRequestUrl() {
String requestURI = "http://localhost:7000/api/user/noManage/getAdminUserList";
System.out.println(requestURI.contains("noManage"));
}
}