Spring Boot - Customize annotations to record access paths and access information, and store the records in MySQL

1. Preparation stage

application.properties; yml can be passedyaml<interchange>properties

spring.datasource.url=jdbc:mysql://localhost:3306/study_annotate
spring.datasource.username=root
spring.datasource.password=123321
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update

Dependencies (take jpa as an example, simplify the code for convenience):

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.28</version>
</dependency>

2. Custom annotations

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD) // 因为路径在方法上所以作用目标为 METHOD
@Retention(RetentionPolicy.RUNTIME) // 运行时:通过反射在运行时读取注解信息
public @interface AccessLog {
    String value() default "";
}

3. First define an entity class

import lombok.Data;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.time.LocalDateTime;

@Entity
@Data
public class AccessLogEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String logMessage;
    private String ipAddress;
    private LocalDateTime timestamp;


    public AccessLogEntity() {
        this.timestamp = LocalDateTime.now();
    }

    public AccessLogEntity(String logMessage, String ipAddress) {
        this();
        this.logMessage = logMessage;
        this.ipAddress = ipAddress;
    }

}

4. Then

import com.lfsun.demolfsunstudyannotate.entity.AccessLogEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface AccessLogRepository extends JpaRepository<AccessLogEntity, Long> {
    // 这里可以定义一些自定义的查询方法,根据需要进行扩展
}


5. Then service

import com.lfsun.demolfsunstudyannotate.dao.AccessLogRepository;
import com.lfsun.demolfsunstudyannotate.entity.AccessLogEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class AccessLogService {

    @Autowired
    private AccessLogRepository accessLogRepository;

    public void saveLog(String logMessage, String ipAddress) {
        // 在这里实现将日志信息保存到MySQL数据库的逻辑
        AccessLogEntity logEntity = new AccessLogEntity(logMessage, ipAddress);
        accessLogRepository.save(logEntity);
    }
}

6. It’s time to cut the surface

import com.lfsun.demolfsunstudyannotate.annotate.AccessLog;
import com.lfsun.demolfsunstudyannotate.service.AccessLogService;
import com.lfsun.demolfsunstudyannotate.util.IpUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

@Aspect
@Component
public class AccessLogAspect {

    @Autowired
    private AccessLogService accessLogService;

    @Before("@annotation(accessLog)")
    public void logAccess(JoinPoint joinPoint, AccessLog accessLog) {
        String methodName = joinPoint.getSignature().toShortString();
        String logMessage = accessLog.value().isEmpty() ? methodName : accessLog.value();
        String ipAddress = IpUtil.getClientIpAddress();

        // 在这里将日志信息记录到MySQL数据库
        accessLogService.saveLog(logMessage, ipAddress);
    }

}

7、controller

import com.lfsun.demolfsunstudyannotate.annotate.AccessLog;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/")
public class HelloController {

    @AccessLog("/hello")
    @GetMapping("/hello")
    public String hello() {
        return "hello lfsun!";
    }
}

If you observe carefully, you can see: Click to return to the aspect just defined!
Insert image description here

8. Add IpUtil, a tool class for obtaining IP

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Objects;

@Slf4j
public class IpUtil {

    private static final String X_FORWARDED_FOR_HEADER = "X-Forwarded-For";
    private static final String PROXY_CLIENT_IP_HEADER = "Proxy-Client-IP";
    private static final String WL_PROXY_CLIENT_IP_HEADER = "WL-Proxy-Client-IP";

    /**
     * 获取客户端真实IP地址,考虑了代理服务器的情况。
     *
     * @param request HttpServletRequest对象
     * @return 客户端真实IP地址
     */
    public static String getClientIpAddress(HttpServletRequest request) {
        String xForwardedForHeader = request.getHeader(X_FORWARDED_FOR_HEADER);
        if (xForwardedForHeader != null && !xForwardedForHeader.isEmpty()) {
            // 如果有多个IP地址,取第一个
            return xForwardedForHeader.split(",")[0].trim();
        } else if (request.getHeader(PROXY_CLIENT_IP_HEADER) != null) {
            return request.getHeader(PROXY_CLIENT_IP_HEADER);
        } else if (request.getHeader(WL_PROXY_CLIENT_IP_HEADER) != null) {
            return request.getHeader(WL_PROXY_CLIENT_IP_HEADER);
        } else {
            // 如果以上都不存在,直接获取RemoteAddr
            String remoteAddr = request.getRemoteAddr();
            log.warn("使用 remoteAddr 无法确定客户端 IP 地址: {}", remoteAddr);
            return remoteAddr;
        }
    }

    /**
     * 获取客户端真实IP地址,使用Spring的RequestContextHolder。
     *
     * @return 客户端真实IP地址
     */
    public static String getClientIpAddress() {
        try {
            HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
            return getClientIpAddress(request);
        } catch (NullPointerException e) {
            log.error("无法从 RequestContextHolder 获取 HttpServletRequest.", e);
            return "unknown";
        }
    }

}

Project started and tested

1. Access and view logs from a local browser

Insert image description here

2. Access and view logs from the url penetrated through the intranet

Insert image description here

3. Penetrate the url from the intranet and then open the ladder to access and view the logs

Insert image description here

Let’s make a complaint. Is this disconnected from the internet? ~ ^ ~

Insert image description here

Guess you like

Origin blog.csdn.net/qq_43116031/article/details/134494389