测试接口并优化接口功能

This commit is contained in:
weitang 2025-06-03 15:00:02 +08:00
parent 2d736e8f3d
commit 5e03d7ea5e
10 changed files with 218 additions and 117 deletions

View File

@ -34,6 +34,9 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private WebConfig webConfig;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
@ -41,6 +44,11 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
try {
String jwt = getJwtFromRequest(request);
// 拦截器中校验
if (webConfig.loginuserCache().get(jwt) != null) {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token 已失效");
return;
}
if (StringUtils.hasText(jwt) && SecurityContextHolder.getContext().getAuthentication() == null) {
String username = jwtUtils.getUsernameFromToken(jwt);

View File

@ -1,5 +1,8 @@
package com.stdproject.config;
import cn.hutool.cache.Cache;
import cn.hutool.cache.CacheUtil;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@ -12,6 +15,14 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
/**
* 用户缓存
*/
@Bean
public Cache<String, String> loginuserCache() {
return CacheUtil.newLRUCache(200);
}
/**
* 静态资源处理
*/

View File

@ -18,6 +18,7 @@ import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
/**
* <p>
@ -128,7 +129,7 @@ public class AppDictionaryController {
if (appDictionary.getOrderno() == null) {
// 获取同一字典编码下的最大序号
QueryWrapper<AppDictionary> orderQuery = new QueryWrapper<>();
orderQuery.eq("dictcode", appDictionary.getDictcode());
orderQuery.eq("app_id", appDictionary.getAppId());
orderQuery.orderByDesc("orderno");
orderQuery.last("LIMIT 1");
AppDictionary lastDict = appDictionaryService.getOne(orderQuery);
@ -244,7 +245,7 @@ public class AppDictionaryController {
@Operation(summary = "根据字典编码分组查询字典项")
@GetMapping("/grouped")
@OperationLog(type = "06", module = "数据字典管理", description = "根据字典编码分组查询字典项")
public Result<java.util.Map<String, List<AppDictionary>>> getGroupedDictionaries() {
public Result<Map<String, List<AppDictionary>>> getGroupedDictionaries() {
QueryWrapper<AppDictionary> queryWrapper = new QueryWrapper<>();
queryWrapper.orderByAsc("dictcode", "orderno");

View File

@ -8,6 +8,7 @@ import com.stdproject.common.PageRequest;
import com.stdproject.common.Result;
import com.stdproject.entity.AppMenu;
import com.stdproject.service.IAppMenuService;
import com.stdproject.service.IAppUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
@ -37,6 +38,10 @@ public class AppMenuController {
@Autowired
private IAppMenuService appMenuService;
@Autowired
private IAppUserService appUserService;
@Operation(summary = "分页查询菜单列表")
@PostMapping("/page")
@OperationLog(type = "06", module = "菜单管理", description = "分页查询菜单列表")
@ -155,6 +160,7 @@ public class AppMenuController {
}
appMenu.setLastmodifydate(LocalDateTime.now());
appMenu.setLastmodifier(appUserService.getCurrentUsername());
boolean success = appMenuService.save(appMenu);
return success ? Result.success("新增成功") : Result.error("新增失败");
}
@ -187,7 +193,7 @@ public class AppMenuController {
}
// 检查父级菜单是否存在如果不是顶级菜单
if (!"0".equals(appMenu.getParentid())) {
if (!"0".equals(existMenu.getParentid())) {
AppMenu parentMenu = appMenuService.getById(appMenu.getParentid());
if (parentMenu == null) {
return Result.error("父级菜单不存在");
@ -196,6 +202,7 @@ public class AppMenuController {
}
appMenu.setLastmodifydate(LocalDateTime.now());
appMenu.setLastmodifier(appUserService.getCurrentUsername());
boolean success = appMenuService.updateById(appMenu);
return success ? Result.success("修改成功") : Result.error("修改失败");
}

View File

@ -1,5 +1,6 @@
package com.stdproject.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@ -18,6 +19,7 @@ import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
/**
@ -113,7 +115,7 @@ public class AppOptLogController {
@Parameter(description = "限制条数") @RequestParam(defaultValue = "100") Integer limit) {
QueryWrapper<AppOptLog> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("module", module);
queryWrapper.orderByDesc("opttime");
queryWrapper.orderByDesc("logtime");
queryWrapper.last("LIMIT " + limit);
List<AppOptLog> logs = appOptLogService.list(queryWrapper);
@ -128,8 +130,8 @@ public class AppOptLogController {
@Parameter(description = "结束时间") @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime,
@Parameter(description = "限制条数") @RequestParam(defaultValue = "1000") Integer limit) {
QueryWrapper<AppOptLog> queryWrapper = new QueryWrapper<>();
queryWrapper.between("opttime", startTime, endTime);
queryWrapper.orderByDesc("opttime");
queryWrapper.between("logtime", startTime, endTime);
queryWrapper.orderByDesc("logtime");
queryWrapper.last("LIMIT " + limit);
List<AppOptLog> logs = appOptLogService.list(queryWrapper);
@ -144,14 +146,13 @@ public class AppOptLogController {
@Parameter(description = "限制条数") @RequestParam(defaultValue = "100") Integer limit) {
QueryWrapper<AppOptLog> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("ip", ip);
queryWrapper.orderByDesc("opttime");
queryWrapper.orderByDesc("logtime");
queryWrapper.last("LIMIT " + limit);
List<AppOptLog> logs = appOptLogService.list(queryWrapper);
return Result.success(logs);
}
@Operation(summary = "删除操作日志")
@DeleteMapping("/{id}")
@OperationLog(type = "03", module = "操作日志管理", description = "删除操作日志")
@ -172,10 +173,9 @@ public class AppOptLogController {
@DeleteMapping("/clean/{days}")
@OperationLog(type = "03", module = "操作日志管理", description = "清理历史操作日志")
public Result<String> cleanOldLogs(@Parameter(description = "保留天数") @PathVariable Integer days) {
LocalDateTime cutoffTime = LocalDateTime.now().minusDays(days);
QueryWrapper<AppOptLog> queryWrapper = new QueryWrapper<>();
queryWrapper.lt("logtime", cutoffTime);
LocalDateTime cutoff = LocalDateTime.now().minusDays(days);
LambdaQueryWrapper<AppOptLog> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.lt(AppOptLog::getLogtime, cutoff);
boolean success = appOptLogService.remove(queryWrapper);
return success ? Result.success("清理成功") : Result.error("清理失败");
}
@ -190,17 +190,17 @@ public class AppOptLogController {
// 今日日志数
LocalDateTime todayStart = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0);
QueryWrapper<AppOptLog> todayQuery = new QueryWrapper<>();
todayQuery.ge("opttime", todayStart);
todayQuery.ge("logtime", todayStart);
long todayCount = appOptLogService.count(todayQuery);
// 本周日志数
LocalDateTime weekStart = LocalDateTime.now().minusDays(7);
LocalDateTime weekStart = LocalDateTime.now().minusDays(7).withNano(0);
QueryWrapper<AppOptLog> weekQuery = new QueryWrapper<>();
weekQuery.ge("logtime", weekStart);
long weekCount = appOptLogService.count(weekQuery);
// 本月日志数
LocalDateTime monthStart = LocalDateTime.now().minusDays(30);
LocalDateTime monthStart = LocalDateTime.now().minusDays(30).withNano(0);
QueryWrapper<AppOptLog> monthQuery = new QueryWrapper<>();
monthQuery.ge("logtime", monthStart);
long monthCount = appOptLogService.count(monthQuery);
@ -231,18 +231,42 @@ public class AppOptLogController {
* 日志统计信息
*/
public static class LogStatistics {
private Long totalCount;
private Long todayCount;
private Long weekCount;
private Long monthCount;
public Long getTotalCount() { return totalCount; }
public void setTotalCount(Long totalCount) { this.totalCount = totalCount; }
public Long getTodayCount() { return todayCount; }
public void setTodayCount(Long todayCount) { this.todayCount = todayCount; }
public Long getWeekCount() { return weekCount; }
public void setWeekCount(Long weekCount) { this.weekCount = weekCount; }
public Long getMonthCount() { return monthCount; }
public void setMonthCount(Long monthCount) { this.monthCount = monthCount; }
public Long getTotalCount() {
return totalCount;
}
public void setTotalCount(Long totalCount) {
this.totalCount = totalCount;
}
public Long getTodayCount() {
return todayCount;
}
public void setTodayCount(Long todayCount) {
this.todayCount = todayCount;
}
public Long getWeekCount() {
return weekCount;
}
public void setWeekCount(Long weekCount) {
this.weekCount = weekCount;
}
public Long getMonthCount() {
return monthCount;
}
public void setMonthCount(Long monthCount) {
this.monthCount = monthCount;
}
}
}

View File

@ -3,6 +3,7 @@ package com.stdproject.controller;
import com.stdproject.common.Constants;
import com.stdproject.common.OperationLog;
import com.stdproject.common.Result;
import com.stdproject.config.WebConfig;
import com.stdproject.entity.AppUser;
import com.stdproject.service.IAppUserService;
import com.stdproject.utils.CaptchaUtils;
@ -20,6 +21,7 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@ -48,12 +50,14 @@ public class AuthController {
@Autowired
private IAppUserService appUserService;
@Autowired
private WebConfig webConfig;
/**
* 登录请求类
*/
public static class LoginRequest {
@NotBlank(message = "用户名不能为空")
private String username;
@ -67,20 +71,44 @@ public class AuthController {
private String captchaKey;
// Getters and Setters
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public String getCaptcha() { return captcha; }
public void setCaptcha(String captcha) { this.captcha = captcha; }
public String getCaptchaKey() { return captchaKey; }
public void setCaptchaKey(String captchaKey) { this.captchaKey = captchaKey; }
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getCaptcha() {
return captcha;
}
public void setCaptcha(String captcha) {
this.captcha = captcha;
}
public String getCaptchaKey() {
return captchaKey;
}
public void setCaptchaKey(String captchaKey) {
this.captchaKey = captchaKey;
}
}
/**
* 修改密码请求类
*/
public static class ChangePasswordRequest {
@NotBlank(message = "原密码不能为空")
private String oldPassword;
@ -88,10 +116,21 @@ public class AuthController {
private String newPassword;
// Getters and Setters
public String getOldPassword() { return oldPassword; }
public void setOldPassword(String oldPassword) { this.oldPassword = oldPassword; }
public String getNewPassword() { return newPassword; }
public void setNewPassword(String newPassword) { this.newPassword = newPassword; }
public String getOldPassword() {
return oldPassword;
}
public void setOldPassword(String oldPassword) {
this.oldPassword = oldPassword;
}
public String getNewPassword() {
return newPassword;
}
public void setNewPassword(String newPassword) {
this.newPassword = newPassword;
}
}
/**
@ -128,7 +167,8 @@ public class AuthController {
@Operation(summary = "用户登录", description = "用户登录认证")
@PostMapping("/login")
@OperationLog(type = Constants.OPT_TYPE_LOGIN, module = "认证管理", description = "用户登录")
public Result<Map<String, Object>> login(@Valid @RequestBody LoginRequest loginRequest, HttpServletRequest request) {
public Result<Map<String, Object>> login(@Valid @RequestBody LoginRequest loginRequest,
HttpServletRequest request) {
try {
// 注意在实际应用中应该从会话或其他存储中获取验证码进行验证
// 此处简化处理假设验证码已通过实际应用中需要实现验证逻辑
@ -141,12 +181,12 @@ public class AuthController {
loginRequest.getPassword()
)
);
AppUser user=appUserService.findByUsername(loginRequest.getUsername());
AppUser user = appUserService.findByUsername(loginRequest.getUsername());
// 设置认证信息到安全上下文
SecurityContextHolder.getContext().setAuthentication(authentication);
// 生成JWT Token
String token = jwtUtils.generateToken(user.getUsername(),user.getId());
String token = jwtUtils.generateToken(user.getUsername(), user.getId());
Map<String, Object> result = new HashMap<>();
result.put("token", token);
@ -172,10 +212,10 @@ public class AuthController {
String token = request.getHeader(Constants.JWT_HEADER);
if (token != null && token.startsWith(Constants.JWT_PREFIX)) {
token = token.substring(Constants.JWT_PREFIX.length());
// 注意在实际应用中应该实现Token失效机制
// 可以考虑使用短期Token或其他方式实现Token失效
// 此处省略Token黑名单实现
webConfig.loginuserCache().put(token, "1");
}
// 清除安全上下文
@ -216,14 +256,16 @@ public class AuthController {
@Operation(summary = "修改密码", description = "修改当前用户密码")
@PostMapping("/changePassword")
@OperationLog(type = Constants.OPT_TYPE_UPDATE, module = "认证管理", description = "修改密码")
public Result<Void> changePassword(@Valid @RequestBody ChangePasswordRequest request, HttpServletRequest httpRequest) {
public Result<Void> changePassword(@Valid @RequestBody ChangePasswordRequest request,
HttpServletRequest httpRequest) {
try {
String token = httpRequest.getHeader(Constants.JWT_HEADER);
if (token != null && token.startsWith(Constants.JWT_PREFIX)) {
token = token.substring(Constants.JWT_PREFIX.length());
String username = jwtUtils.getUsernameFromToken(token);
boolean success = appUserService.changePassword(username, request.getOldPassword(), request.getNewPassword());
boolean success = appUserService.changePassword(username, request.getOldPassword(),
request.getNewPassword());
if (success) {
return Result.success();
} else {
@ -262,5 +304,10 @@ public class AuthController {
}
}
@GetMapping("/getExpirationDateFromToken")
public Result<Date> getExpirationDateFromToken(String token) {
Date expirationDateFromToken = jwtUtils.getExpirationDateFromToken(token);
return Result.success(expirationDateFromToken);
}
}

View File

@ -2,6 +2,7 @@ package com.stdproject.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.stdproject.entity.AppOptLog;
import org.apache.ibatis.annotations.Delete;
/**
* <p>

View File

@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.stdproject.entity.AppOptLog;
import com.stdproject.mapper.AppOptLogMapper;
import com.stdproject.service.IAppOptLogService;
import org.apache.ibatis.annotations.Delete;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**