1.创建数据库
2.引入相关依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboothandlerIntercptor</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- velocity 模板引擎, Mybatis Plus 代码生成器需要 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.72</version>
</dependency>
<!--解析IP为中国|华南|广东省|深圳市|-->
<dependency>
<groupId>org.lionsoul</groupId>
<artifactId>ip2region</artifactId>
<version>1.7.2</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<!--解析IP为中国|华南|广东省|深圳市|-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<!--尤其要注意:----后面在com.atguigu的包下,想用mapper.xml,要加这个不然会报错-->
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3.去网上下载这个文件(必须要才能解析IP为省|市|县)https://github.com/lionsoul2014/ip2region/tree/master/data
4.利用mybatisplus代码生成器生成controller、mapper、service 、entity(代码生成器不了解可以看我博客前一章)
5.实现HandlerInterceptor接口,来对请求记录日志
package com.atguigu.loghandlerintercptor.intercptor;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.atguigu.loghandlerintercptor.entity.LoggerInfos;
import com.atguigu.loghandlerintercptor.service.impl.LoggerInfosServiceImpl;
import com.atguigu.loghandlerintercptor.util.RequestUtils;
import com.atguigu.loghandlerintercptor.util.SpringContextUtil;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
public class LoggerIntercptor implements HandlerInterceptor {
//请求开始时间标识
private static final String LOGGER_SEND_TIME="send_time";
//请求日志实体标识
private static final String LOGGER_ENTITY="_logger_entity";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("pre");
//创建日志实体类
LoggerInfos loggerInfos=new LoggerInfos();
//获取session
// HttpSession session=request.getSession();
// String sessionid=session.getId();
String sessionId = request.getRequestedSessionId();
//获取请求路径
String uri = request.getRequestURI();
//请求参数信息
String paramData = JSON.toJSONString(request.getParameterMap(),
SerializerFeature.DisableCircularReferenceDetect, SerializerFeature.WriteMapNullValue);
//设置客户端IP
loggerInfos.setClientId(RequestUtils.getIpAddr(request));
//设置客户端省市
loggerInfos.setCityInfo(RequestUtils.getCityInfo(RequestUtils.getIpAddr(request)));
//设置请求方法
loggerInfos.setMethod(request.getMethod());
//设置请求类型(json|普通请求)
loggerInfos.setType(RequestUtils.getRequestType(request));
//设置请求参数内容json字符串
loggerInfos.setParamData(paramData);
//设置请求地址
loggerInfos.setUri(uri);
//设置sessionid
loggerInfos.setSessionId(sessionId);
//设置请求开始时间
long currentTimeMillis=System.currentTimeMillis();
loggerInfos.setTime((new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS")).format(currentTimeMillis).toString());
request.setAttribute(LOGGER_SEND_TIME,currentTimeMillis);
//设置请求实体到request中,方便afterCompletion方法调用
request.setAttribute(LOGGER_ENTITY,loggerInfos);
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("after");
//获取请求错误码
int status = response.getStatus();
//当前时间
long currentTimeMillis = System.currentTimeMillis();
//获取请求开始时间
long time = (long)request.getAttribute(LOGGER_SEND_TIME);
//获取请求日志实体
LoggerInfos loggerInfos = (LoggerInfos)request.getAttribute(LOGGER_ENTITY);
//设置请求时间差
loggerInfos.setTimeConsuming(Integer.valueOf((currentTimeMillis-time)+""));
//设置返回时间
loggerInfos.setReturnTime((new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS")).format(currentTimeMillis).toString());
//设置返回错误码
loggerInfos.setHttpStatusCode(status+"");
//设置返回值
loggerInfos.setReturnData(JSON.toJSONString(request.getAttribute(RequestUtils.LOGGER_RETURN),
SerializerFeature.DisableCircularReferenceDetect, SerializerFeature.WriteMapNullValue));
System.out.println(loggerInfos);
//执行将日志写入数据库
LoggerInfosServiceImpl loggerInfosServiceImpl = (LoggerInfosServiceImpl) SpringContextUtil.getBean("loggerInfosServiceImpl");
loggerInfosServiceImpl.save(loggerInfos);
}
}
6.工具类RequestUtils(获取ip地址以及将ip转换为省|市|县)和 SpringContextUtil(获取bean)
package com.atguigu.loghandlerintercptor.util;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.lionsoul.ip2region.DataBlock;
import org.lionsoul.ip2region.DbConfig;
import org.lionsoul.ip2region.DbSearcher;
import org.lionsoul.ip2region.Util;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
@Slf4j
public class RequestUtils {
public static final String LOGGER_RETURN="logger_return";
private static final String UNKNOWN = "unknown";
/**
* 获取 IP地址
* 使用 Nginx等反向代理软件, 则不能通过 request.getRemoteAddr()获取 IP地址
* 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,
* X-Forwarded-For中第一个非 unknown的有效IP字符串,则为真实IP地址
*/
public static String getIpAddr(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
}
public static String getRequestType(HttpServletRequest request) {
//获取头部信息
String xRequestedWith = request.getHeader("X-Requested-With");
if (xRequestedWith != null && xRequestedWith.indexOf("XMLHttpRequest") != -1) {
return "json";
} else {
return "普通请求";
}
}
public static String getCityInfo(String ip) {
DbSearcher searcher = null;
try {
//这个/ip2region/ip2region.db文件在类路径下
String dbPath = RequestUtils.class.getResource("/ip2region/ip2region.db").getPath();
File file = new File(dbPath);
if (!file.exists()) {
//java.io.tmpdir:获取操作系统缓存的临时目录
String tmpDir = System.getProperties().getProperty("java.io.tmpdir");
dbPath = tmpDir + "ip.db";
file = new File(dbPath);
FileUtils.copyInputStreamToFile(RequestUtils.class.getClassLoader().getResourceAsStream("classpath:ip2region/ip2region.db"), file);
}
int algorithm = DbSearcher.BTREE_ALGORITHM;
DbConfig config = new DbConfig();
searcher = new DbSearcher(config, dbPath);
Method method = null;
switch (algorithm) {
case DbSearcher.BTREE_ALGORITHM:
method = searcher.getClass().getMethod("btreeSearch", String.class);
break;
case DbSearcher.BINARY_ALGORITHM:
method = searcher.getClass().getMethod("binarySearch", String.class);
break;
case DbSearcher.MEMORY_ALGORITYM:
method = searcher.getClass().getMethod("memorySearch", String.class);
break;
}
DataBlock dataBlock = null;
if (!Util.isIpAddress(ip)) {
log.error("Error: Invalid ip address");
}
dataBlock = (DataBlock) method.invoke(searcher, ip);
return dataBlock.getRegion();
} catch (Exception e) {
log.error("获取IP地址失败,{}", e.getMessage());
} finally {
if (searcher != null) {
try {
searcher.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
}
---------------------------------------------------------------------------------------------------
package com.atguigu.loghandlerintercptor.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* Spring Context 工具类
*
* @author MrBird
*
*/
@Component
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextUtil.applicationContext = applicationContext;
}
public static Object getBean(String name) {
return applicationContext.getBean(name);
}
public static <T> T getBean(Class<T> clazz){
return applicationContext.getBean(clazz);
}
public static <T> T getBean(String name, Class<T> requiredType) {
return applicationContext.getBean(name, requiredType);
}
public static boolean containsBean(String name) {
return applicationContext.containsBean(name);
}
public static boolean isSingleton(String name) {
return applicationContext.isSingleton(name);
}
public static Class<?> getType(String name) {
return applicationContext.getType(name);
}
}
7.在http://localhost:8080/swagger-ui.html中向这个controller发送请求
package com.atguigu.loghandlerintercptor.controller;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.loghandlerintercptor.util.RequestUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
/**
* <p>
* 前端控制器
* </p>
*
* @author testjava
* @since 2020-07-09
*/
@RestController
@RequestMapping("/index")
public class LoggerInfosController {
@GetMapping("/login")
public JSONObject login(HttpServletRequest request, String name){
JSONObject obj=new JSONObject();
obj.put("msg","用户:"+name+"登录成功");
//将返回值写入到请求中
request.setAttribute(RequestUtils.LOGGER_RETURN,obj);
return obj;
}
}
结果: