想记录用户行为日志有多种方式,在controller层用注解是比较简单的方式,在需要记录日志的方法前添加注解,就可以自动存入相关参数写入日志表。
实现分为3步。
1、添加SPRING AOP的必要POM文件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2、自定义注解,实现用户日志AOP类
2.1 声明注解类,参数为调用接口的描述
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UserLog {
//操作模块描述
String value() default "";
}
2.2 实现AOP类(Utils.getIpAddr获取IP地址,网上有很多例子,fUserLogService.addLog往数据库新增日志代码就不贴了)
@Aspect
@Component
public class UserLogAspect {
@Autowired
RedisAPPTool redisAPPTool;
@Autowired
FUserLogService fUserLogService;
static FUser fUser=new FUser();
static {
fUser.setFid(0);
fUser.setFnickname("游客");
fUser.setFusername("游客");
}
@Pointcut("@annotation(com.jinhua.app.annotation.UserLog)")
public void annotationPointcut() {
}
@AfterReturning(value = "@annotation(userLog)")
public void doAround(JoinPoint joinPoint,UserLog userLog){
//获取方法名(是方法名不是RequestMapping)
String methodName = joinPoint.getSignature().getName();
//获取所有参数和参数值
Map<String,Object> map=this.getNameAndValue(joinPoint);
//将所有参数转成JSON保存(最好加密一下,我这里没加密)
JSONObject json = new JSONObject(map);
BaseController baseController=(BaseController)joinPoint.getThis();
System.out.println("userLog:" + methodName + "--"+userLog.value()+"--"+
Utils.getIpAddr(baseController.getRequest())+"--"+ json.toString());
if(map.get("uid")!=null) {
Integer uid = Integer.parseInt(map.get("uid").toString());
FUser user = null;
//通过UID获取TOKEN
String token=redisAPPTool.getToken(uid);
if(token!=null) {
//通过TOKEN获取用户信息
user=redisAPPTool.getUserByToken(token);
if (user == null) {
user = fUser;
}
//用户日志
FUserLog fUserLog=new FUserLog();
//用户ID
fUserLog.setFuserid(uid);
//访问接口方法名
fUserLog.setFmodule(methodName);
//类型
fUserLog.setFtype(FUserLogEnum.LOG_TYPE_OPERATION);
//接口描述
fUserLog.setFdescription(userLog.value());
//参数JSON
fUserLog.setFjosn(json.toString());
//IP地址
fUserLog.setFip(Utils.getIpAddr(baseController.getRequest()));
//插入
//fUserLogService.addLog(fUserLog);
}
}
else
{
System.out.println("私有接口错误!IP:"+Utils.getIpAddr(baseController.getRequest())+",Time:"+Utils.getCurTimeString()+",JOSN:"+json.toString());
}
//UserLog log = method.getAnnotation(UserLog.class);
}
/**
* 获取参数Map集合
* @param joinPoint
* @return
*/
private Map<String, Object> getNameAndValue(JoinPoint joinPoint) {
Map<String, Object> param = new HashMap<>();
Object[] paramValues = joinPoint.getArgs();
String[] paramNames = ((CodeSignature)joinPoint.getSignature()).getParameterNames();
for (int i = 0; i < paramNames.length; i++) {
param.put(paramNames[i], paramValues[i]);
}
return param;
}
}
3、在controller方法上添加日志注解
3.1 方法前添加“@UserLog”
@Controller
public class QuAndAnController extends BaseController{
@Autowired
FQuestionService fQuestionService;
/**
* 添加回答
* @param fquid
* @param fcontext
* @param fpraise
* @param uid
* @param time
* @param sign
* @return
*/
@UserLog
@RequestMapping("insertAn")
@ResponseBody
public String insertAn(
@RequestParam(value = "fquid") Long fquid,
@RequestParam(value = "fcontext") String fcontext,
@RequestParam(value = "fpraise") Integer fpraise,
@RequestParam(value = "uid") int uid,
@RequestParam(value = "time") Long time,
@RequestParam(value = "sign") String sign
) {
//验证TOKEN开始
FUser user = null;
try {
user = checkAPI(uid, sign, time);
} catch (Exception e) {
e.printStackTrace();
return "失败";
}
if (user == null) {
return "失败";
}
//验证TOKEN结束
int result = 0;
/*FAnswer fAnswer = new FAnswer();
//问题ID
fAnswer.setFquid(fquid);
//回答内容
fAnswer.setFcontext(Utils.filterXSS(fcontext));
//回答ID
fAnswer.setFuid(uid);
//赞
fAnswer.setFpraise(0);
try {
result = fQuestionService.insertAn(fAnswer);
} catch (Exception e) {
e.printStackTrace();
}*/
if (result == 1) {
return "成功";
} else {
return "失败";
}
}
}
相关实体和工具类
/**
* 所有controller的父类
*/
public class BaseController {
protected HttpServletRequest request;
protected HttpServletResponse response;
protected HttpSession session;
@Autowired
RedisAPPTool redisAPPTool;
@ModelAttribute
public void setReqAndRes(HttpServletRequest request, HttpServletResponse response) {
this.request = request;
this.response = response;
this.session = request.getSession();
}
//验证私有接口
public FUser checkAPI(Integer uid, String sign,Long time) throws Exception {
String token=redisAPPTool.getToken(uid);
if(!redisAPPTool.apiRate(token)){
throw new Exception("访问太快,请稍后在试");
}
if(Math.abs(System.currentTimeMillis()-time)> FRedisEnum.API_TIME
|| !APICheck.checkAPI(request,sign,token)){
throw new Exception("签名有误");
}
FUser user=redisAPPTool.getUserByToken(token);
if(user==null || uid!=user.getFid()){
throw new Exception("失败,验证录失效,请重新登录");
}
return user;
}
public HttpServletRequest getRequest()
{
return this.request;
}
}
@Component
public class RedisAPPTool {
@Autowired
RedisTool redisTool;
/**
* 获取登录用户信息
*
* @param token 登录token
* @return
*/
public FUser getUserByToken(String token) {
if (StringUtils.isEmpty(token)) {
return null;
}
String json = redisTool.getString(token);
if (StringUtils.isEmpty(json)) {
return null;
}
JSONObject obj = JSON.parseObject(json);
Object resultStr = obj.get("extObject");
if (resultStr == null) {
return null;
}
return JSON.parseObject(resultStr.toString(), FUser.class);
}
/**
* 获取用户信息
*
* @return
*/
public String getToken(Integer uid) {
if (StringUtils.isEmpty(uid)) {
return null;
}
String token = redisTool.getString(FRedisEnum.ACCOUNT_LOGIN_KEY+uid);
if (StringUtils.isEmpty(token)) {
return null;
}
return token;
}
/**
* 访问频率限制
*
* @param token 登录token
* @return
*/
public boolean apiRate(String token) {
if (StringUtils.isEmpty(token)) {
return false;
}
String json = redisTool.getString(FRedisEnum.API_RATE+token);
if (StringUtils.isEmpty(json)) {
redisTool.set(FRedisEnum.API_RATE+token,true,3*1000L);
return true;
}else {
return false;
}
}
}
public class FUserLog implements Serializable {
private static final long serialVersionUID = 1L;
private Long fid;
private Integer ftype;
private String fmodule;
private String fdescription;
private String fip;
private String fjosn;
private Integer fuserid;
private Date fcreatetime;
public FUserLog() {
}
public Long getFid() {
return fid;
}
public void setFid(Long fid) {
this.fid = fid;
}
public Integer getFtype() {
return ftype;
}
public void setFtype(Integer ftype) {
this.ftype = ftype;
}
public String getFmodule() {
return fmodule;
}
public void setFmodule(String fmodule) {
this.fmodule = fmodule;
}
public String getFdescription() {
return fdescription;
}
public void setFdescription(String fdescription) {
this.fdescription = fdescription;
}
public String getFip() {
return fip;
}
public void setFip(String fip) {
this.fip = fip;
}
public String getFjosn() {
return fjosn;
}
public void setFjosn(String fjosn) {
this.fjosn = fjosn;
}
public Integer getFuserid() {
return fuserid;
}
public void setFuserid(Integer fuserid) {
this.fuserid = fuserid;
}
public Date getFcreatetime() {
return fcreatetime;
}
public void setFcreatetime(Date fcreatetime) {
this.fcreatetime = fcreatetime;
}
}