介绍
目前正在着手开发一款功能全面的接口自动化测试平台,该平台将涵盖登录、用户管理、权限控制、项目管理、用例管理、测试数据管理、测试报告生成、任务调度、缺陷跟踪以及系统配置等多个核心模块。为了有效追踪每位测试人员在平台上的活动轨迹,决定引入一个用户行为记录功能。本文将简要介绍这一功能的实现思路。
用户行为记录功能详解
技术选型
- 后端:采用Java作为主要开发语言。
- 前端:使用VUE框架进行界面展示。
- 行为记录:Java服务负责记录用户行为,而VUE则用于展示这些行为记录。
统一接口响应格式
为了统一接口响应格式并便于后续根据响应状态决定是否记录用户行为(仅记录成功操作),我们封装了一个RespBean
类,该类使用ResponseEntity
来构建响应体。
import lombok.Getter;
import lombok.Setter;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import java.util.HashMap;
import java.util.Map;
@Getter
@Setter
public class RespBean {
private String msg;
private Object obj;
public static ResponseEntity<Map<String, Object>> ok(String msg) {
Map<String, Object> map = new HashMap<>();
map.put("msg", msg);
return ResponseEntity.status(HttpStatus.OK).body(map);
}
public static ResponseEntity<Map<String, Object>> ok(String msg, Object obj) {
Map<String, Object> map = new HashMap<>();
map.put("msg", msg);
map.put("obj", obj);
return ResponseEntity.status(HttpStatus.OK).body(map);
}
public static ResponseEntity<Map<String, Object>> error(String msg) {
Map<String, Object> map = new HashMap<>();
map.put("msg", msg);
return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(map);
}
public static ResponseEntity<Map<String, Object>> error(String msg, Object obj) {
Map<String, Object> map = new HashMap<>();
map.put("msg", msg);
map.put("obj", obj);
return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(map);
}
}
用户行为映射
我们定义了一个UserAction
枚举类,用于映射需要记录用户行为的接口及其对应的操作描述。
import lombok.Getter;
import java.util.HashMap;
import java.util.Map;
@Getter
public enum UserAction {
LOGIN("/login", "登录系统"),
ADD_USER("/user/add", "添加新用户");
private final String path;
private final String userAction;
UserAction(String path, String userAction) {
this.path = path;
this.userAction = userAction;
}
private static final Map<String, UserAction> pathToActionMap = new HashMap<>();
static {
for (UserAction action : UserAction.values()) {
pathToActionMap.put(action.getPath(), action);
pathToActionMap.put(action.getUserAction(), action);
}
}
public static UserAction fromPath(String path) {
return pathToActionMap.getOrDefault(path, null);
}
public static UserAction fromAction(String action) {
return pathToActionMap.getOrDefault(action, null);
}
}
拦截器实现
通过实现HandlerInterceptor
接口中的afterCompletion
方法,我们能够在接口调用完成后进行拦截。当接口在UserAction
映射中存在且响应状态码为200时,我们会将用户行为记录到数据库中。
import com.zkx.spidertest.commons.enumeration.UserAction;
import com.zkx.spidertest.commons.user.User;
import com.zkx.spidertest.commons.utils.RedisUtil;
import com.zkx.spidertest.commons.utils.TokenUtil;
import com.zkx.spidertest.dto.user.UserLogDTO;
import com.zkx.spidertest.service.user.UserLogService;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.List;
@Component
public class MyInterceptor implements HandlerInterceptor {
public static final Logger logger = LoggerFactory.getLogger(MyInterceptor.class);
@Autowired
UserLogService userLogService;
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, @NotNull Object handler, Exception ex) {
String token = request.getHeader("token");
String userId = TokenUtil.JudgementToken(token);
int statusCode = response.getStatus();
if (UserAction.fromPath(request.getRequestURI()) != null && statusCode == 200) {
UserLogDTO userLogDTO = new UserLogDTO();
userLogDTO.setUserId(Integer.valueOf(userId));
userLogDTO.setUrl(request.getRequestURI());
UserAction userAction = UserAction.fromAction(request.getRequestURI());
userLogDTO.setAction(userAction.getUserAction());
userLogService.addUserLog(userLogDTO);
}
}
}
拦截器配置
最后,需要将自定义的拦截器注册到Spring MVC配置中。这可以通过实现WebMvcConfigurer
接口来完成。
import com.zkx.spidertest.framework.Interceptor.MyInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.nio.charset.Charset;
import java.util.List;
@Configuration
public class WebAppConfigurer implements WebMvcConfigurer {
@Autowired
private MyInterceptor myInterceptor;
@Bean
public HttpMessageConverter responseBodyConverter(){
StringHttpMessageConverter converter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
return converter;
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(responseBodyConverter());
}
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")
.allowCredentials(true)
.maxAge(3600)
.allowedHeaders("*");
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myInterceptor)
.addPathPatterns("/**") // 拦截所有路径
.excludePathPatterns("/login", "/getVerifyCode", "/logout", "/error"); // 放行路径
}
}
记录结果展示
完成上述配置后,所有在UserAction
中映射的接口在用户成功操作后,其行为记录都会被保存到数据库中。这些记录可以在前端界面上进行展示和查询。
通过以上步骤,我们成功实现了在接口自动化测试平台中记录用户行为的功能。这一功能不仅有助于追踪测试人员的活动轨迹,还能为后续的审计和问题排查提供有力支持。