当前位置:网站首页>Record of user behavior log in SSO microservice Engineering
Record of user behavior log in SSO microservice Engineering
2022-06-26 18:27:00 【[email protected]】
System requirements analysis
Business description
The user is in sso-resource When a project accesses our resource data , Get the user's behavior log information , And pass it to sso-system engineering , Store log information in the database .
Business architecture analysis

Design of log storage in system service
In this design , The system service is responsible for writing the user behavior logs obtained by other services to the database .
Pojo Logic implementation
Define a Log object , Used to store user behavior log information in memory , for example :
package com.jt.system.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* Encapsulate user behavior logs based on this object ?
* Who did what at what time , What methods were accessed , What parameters are passed , How long is the visit .
*/
@Data
@TableName("tb_logs")
public class Log implements Serializable {
private static final long serialVersionUID = 3054471551801044482L;
@TableId(type = IdType.AUTO)
private Long id;
private String username;
private String operation;
private String method;
private String params;
private Long time;
private String ip;
@TableField("createdTime")
private Date createdTime;
private Integer status;
private String error;
}
Dao Logic implementation
First step : Create a user behavior log data layer object , Logic for handling data persistence , for example
package com.jt.system.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jt.system.pojo.Log;
import org.apache.ibatis.annotations.Mapper;
/**
* User behavior log data layer object
*/
@Mapper
public interface LogMapper extends BaseMapper<Log> {
}
The second step : Define unit tests , Unit test the data layer method
package com.jt;
import com.jt.system.dao.LogMapper;
import com.jt.system.pojo.Log;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Date;
@SpringBootTest
public class LogMapperTests {
@Autowired
private LogMapper logMapper;
@Test
void testInsert(){
// Build user behavior log object ( Store some user behavior logs based on this object , First use false data )
Log log=new Log();
log.setUsername("cgb2107");
log.setIp("192.168.100.200");
log.setOperation(" Query resources ");
log.setMethod("pkg.ResourceController.doSelect");
log.setParams("");
log.setStatus(1);
log.setTime(100L);
log.setCreatedTime(new Date());
// Persist logs to database
logMapper.insert(log);
}
}
Service Logic implementation
First step : Define log business interface , for example :
package com.jt.system.service;
import com.jt.system.pojo.Log;
/**
* User behavior log business logic interface definition
*/
public interface LogService {
/**
* Save user behavior log .
* @param log
*/
void insertLog(Log log);
//.....
}
The second step : Define the log business interface implementation class , for example :
package com.jt.system.service.impl;
import com.jt.system.dao.LogMapper;
import com.jt.system.pojo.Log;
import com.jt.system.service.LogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class LogServiceImpl implements LogService {
@Autowired
private LogMapper logMapper;
/**
* @Async The underlying method described will execute asynchronously ( Not from web The service thread executes ,
* It is to hand over to spring Threads in the built-in thread pool execute ) however @Async Annotated
* Application has a premise , Asynchronous execution needs to be started on the startup class ( add to @EnableAsync Note description ).
* advantage : It won't block for a long time web service ( for example tomcat) Threads
*/
@Async
@Override
public void insertLog(Log log) {
logMapper.insert(log);
}
}
Controller Logic implementation
First step : Definition LogController object , Used to implement log control logic , for example :
package com.jt.system.controller;
import com.jt.system.pojo.Log;
import com.jt.system.service.LogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/log")
public class LogController {
@Autowired
private LogService logService;
@PostMapping
public void doInsertLog(@RequestBody Log log){
logService.insertLog(log);
}
}
Add to the startup class
package com.jt;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@EnableAsync // Start asynchronous operation
@SpringBootApplication
public class SystemApplication {
public static void main(String[] args) {
SpringApplication.run(SystemApplication.class,args);
}
}
The second step : Start the service , be based on postman Conduct interview tests , for example :

Design of behavior log operation in resource service
Business description
Without modifying the target business method code implementation , When accessing the target method , Get user behavior log .
Pojo Logical object definition
Define log objects , The user encapsulates the obtained user behavior log , for example :
package com.jt.resource.pojo;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* Encapsulate user behavior logs based on this object ?
* Who did what at what time , What methods were accessed , What parameters are passed , How long is the visit .
*/
@Data
public class Log implements Serializable {
private static final long serialVersionUID = 3054471551801044482L;
private Long id;
private String username;
private String operation;
private String method;
private String params;
private Long time;
private String ip;
private Date createdTime;
private Integer status;
private String error;
}
Pointcut annotation definition
Build a custom annotation , The name is RequiredLog, The following description will be based on this annotation as the entry point , Define pointcut methods . for example :
package com.jt.resource.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Definition RequiredLog annotation , With this annotation, you need
* The method of logging is described
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequiredLog {
String value() default "";
}
AOP Get and record logs
Define a log facet , Based on the notification method in this aspect, the acquisition and recording of user behavior log are realized
package com.jt.resource.aspect;
import com.jt.resource.annotation.RequiredLog;
import com.jt.resource.pojo.Log;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.lang.reflect.Method;
import java.util.Date;
/**
* @Aspect The type described by the annotation is a facet type , In this class, you can define :
* 1) The breakthrough point ( Cut into the location of the extension logic ~ For example, authority control , logging , The location of the transaction ), stay
* @Aspect In the class described , Usually use @Pointcut Annotations define . The method described using pointcuts is the pointcut method .
*
* 2) Notification method ( Before and after the target method corresponding to the pointcut is executed, the execution logic needs to be written into such a method ), stay
* @Aspect In the class described , adopt @Before,@After,@Aroud,@AfterReturning,@AfterThrowing
* Such annotations describe .
* a: @Before Before the pointcut method executes
* b: @After After the pointcut method is executed ( Whether the pointcut method is executed successfully or not , It will all execute )
* c: @Aroud Pointcut methods can be executed before and after execution ( above all )
* d: @AfterReturning After the pointcut method is successfully executed
* e: @AfterThrowing If an exception occurs during the execution of the pointcut method, it will execute
*/
@Aspect
@Component
public class LogAspect {
/**
* @Pointcut Annotations are used to define pointcuts , The content in this annotation is the pointcut expression
* @annotation Is a pointcut expression in annotation mode , The expression in this way is a fine-grained pointcut expression ,
* Because it can be accurate to the method , For example, we now use RequiredLog When annotating a method , The method described by it
* Is a pointcut approach .
*/
@Pointcut("@annotation(com.jt.resource.annotation.RequiredLog)")
public void doLog(){
// Nothing needs to be written in this method , Only responsible for carrying @Pointcut annotation
}
/**
* @Around The method described by the annotation is Aspect A surround notification method in , In this method
* Internally, you can control the call to the target method .
* @param joinPoint Connection point object , This object encapsulates the pointcut method information you want to execute , Can be based on
* This object makes reflection calls to pointcut methods
* @return The return value of the pointcut method in the target execution chain .
* @throws Throwable
*/
@Around("doLog()")
public Object doAround(ProceedingJoinPoint joinPoint)throws Throwable{
int status=1;// state
String error=null;// error message
long time=0l;// The execution time
long t1=System.currentTimeMillis();
try {
// Manually call the target execution chain ( This execution chain contains pointcut methods ~ The target method )
Object result = joinPoint.proceed();
long t2=System.currentTimeMillis();
time=t2-t1;
return result;
}catch (Throwable e){
long t3=System.currentTimeMillis();
time=t3-t1;
status=0;
error=e.getMessage();
throw e;
}finally {
saveLog(joinPoint,time,status,error);
}
}
// Store user behavior logs
private void saveLog(ProceedingJoinPoint joinPoint,long time,
int status,String error)throws Throwable{
//1. Get user behavior log
//1.1 Get target object type ( The type of the class where the pointcut method is located )
Class<?> targetClass = joinPoint.getTarget().getClass();
//1.2. Get the target method
//1.2.1 Get method signature ( Contains method information ,....)
MethodSignature signature = (MethodSignature)joinPoint.getSignature();
//1.2.2 Get method object
Method targetMethod=
targetClass.getDeclaredMethod(signature.getName(),signature.getParameterTypes());
//1.3 On the method RequiredLog Note content
//1.3.1 Get the annotation on the target method
RequiredLog requiredLog=targetMethod.getAnnotation(RequiredLog.class);
//1.3.2 Get the content in the annotation ( This content defines the operation name for us )
String operation=requiredLog.value();
//1.4 Get the target method name ( Class name + Method name )
String targetMethodName=targetClass.getName()+"."+targetMethod.getName();
//1.5 Get the parameters passed in during the execution of the target method
String params=new ObjectMapper().writeValueAsString(joinPoint.getArgs());
//1.6 Get login user name ( Refer to the Security Official code )
String username=(String)
SecurityContextHolder.getContext()
.getAuthentication()
.getPrincipal();
//1.7 obtain ip Address ( Get... From the current thread request object , Then based on request obtain ip Address )
//String ip="192.168.1.100";
ServletRequestAttributes requestAttributes =
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
String ip=requestAttributes.getRequest().getRemoteAddr();
//2. Log user behavior , Package to Log object
Log logInfo=new Log();
logInfo.setIp(ip);// Follow up
logInfo.setUsername(username);
logInfo.setOperation(operation);
logInfo.setMethod(targetMethodName);
logInfo.setParams(params);
logInfo.setTime(time);
logInfo.setStatus(status);
logInfo.setError(error);
logInfo.setCreatedTime(new Date());
System.out.println("logInfo="+logInfo);
}
}
Start the service for access testing
Start in turn nacos,sso-system,sso-auth,sso-resource,sso-gateway,sso-ui Engineering services , Then execute login , After successful login, query my resources , Test log output .
In service AOP Technical application principle analysis
AOP It's a design idea , The function it wants to achieve is " Add a beautiful thing to a contrasting beautiful thing ", Is to try not to modify the original target method , Add some extended functions , For example, log records , Control of authority , Control of transactions , Asynchronous task execution, etc , Its application principle is shown in the figure :

explain : When we define in the project AOP After cutting , When the system starts , Yes @Aspect The class described by the annotation is loaded and analyzed , The pointcut based description is the target type object , Create proxy object , And create an execution chain inside the proxy object , This execution chain contains interceptors ( Encapsulates the pointcut information ), notice (Around,…), Target object, etc , When we request a target object resource , Resources will be called directly in the order of the execution chain
Feign Pass the log to the system service
First step : Make sure sso-resource The project added openfeign rely on , for example :
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
The second step : Make sure sso-resource Added... To the start of the project @EnableFeignClients annotation , for example :
package com.jt;
@EnableFeignClients
@SpringBootApplication
public class ResourceApplication {
public static void main(String[] args) {
SpringApplication.run(ResourceApplication.class, args);
}
}
The third step : Define the log remote service call interface , for example :
package com.jt.resource.service;
import com.jt.resource.pojo.Log;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@FeignClient(value = "sso-system",contextId = "remoteLogService")
public interface RemoteLogService {
@PostMapping("/log")
public void insertLog(@RequestBody Log log);
}
Step four : stay LogAspect Class injection RemoteLogService object , And pass the log object to sso-system service
@Autowired
private RemoteLogService remoteLogService;
....
Step five : Start the services in turn for access testing .
版权声明
本文为[[email protected]@yxg]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/177/202206261820088489.html
边栏推荐
- Do you know how to compare two objects
- Determine whether a sequence is a stack pop-up sequence
- Procedure steps for burning a disc
- To: seek truth from facts
- 输入n个整数,输出出现次数大于等于数组长度一半的数
- vutils. make_ A little experience of grid () in relation to black and white images
- IDEA收藏代码、快速打开favorites收藏窗口
- Map和List<Map>转相应的对象
- Publish message publishers and subscribe message subscribers of ROS
- 分页查询、JOIN关联查询优化
猜你喜欢

(必须掌握的多线程知识点)认识线程,创建线程,使用Thread的常见方法及属性,以及线程的状态和状态转移的意义

LeetCode 128最长连续序列

爬取豆瓣读书Top250,导入sqlist数据库(或excel表格)中

Properties file garbled

必须要掌握的面试重点——索引和事务(附讲B-树与B+树)

MYSQL的下载与配置 mysql远程操控

Do you know how to compare two objects

wm_ Concat() and group_ Concat() function

Decompilation of zero time technology smart contract security series articles

Leetcode interview question 29 clockwise print matrix
随机推荐
Do you know how to compare two objects
Crawl Douban to read top250 and import it into SqList database (or excel table)
ROS query topic specific content common instructions
Logstash安装及使用
Insert string B into string A. how many insertion methods can make the new string a palindrome string
Soft test preparation multimedia system
Leetcode interview question 29 clockwise print matrix
预编译处理指令中的条件编译
新手炒股开户选哪个证券公司比较好?怎样炒股比较安全??
项目实战六:分布式事务-Seata
redis 基础知识
tag动态规划-刷题预备知识-2. 0-1背包理论基础和二维数组解法模板
MYSQL的下载与配置 mysql远程操控
Plt How to keep show() not closed
NFTGameFi链游系统开发详解方案丨链游系统开发原理解析
Determine whether a sequence is a stack pop-up sequence
Ethereum技术架构介绍
xlua获取ugui的button注册click事件
Yujun product methodology
Solve the problem that each letter occupies a space in pycharm