过滤与拦截——>实现日志的打印
三级目录
1、请求拦截的简单示例
过滤代码新建一个 TimeFilter 实现 Filter
package com.llcbenwu.filter;
import com.llcbenwu.exception.BusinessException;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import java.io.IOException;
@Component
public class TimeFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("time filter start");
long start = System.currentTimeMillis();
chain.doFilter(request,response);
System.out.println("耗时:" +(System.currentTimeMillis()-start));
System.out.println("time filter finish");
}
@Override
public void destroy() {
}
}
执行结果
如果我们需要接第三方的过滤器那么将TimeFilter 当成第三方的并且没有@Component执行
package com.llcbenwu.config;
import com.llcbenwu.filter.TimeFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.List;
@Configuration
public class WebConfig {
@Bean
public FilterRegistrationBean timeFilter(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
TimeFilter timeFilter = new TimeFilter();
registrationBean.setFilter(timeFilter);
//在哪些路径起作用
List<String> urls = new ArrayList<>();
urls.add("/*");
// urls.add("/bksSubtheme/*"); 就只拦截带有bksSubtheme路径的接口
registrationBean.setUrlPatterns(urls);
return registrationBean;
}
}
测试结果
过滤
这里是不知道执行的方法,因为这个是Java2E的而我们的框架式是spring MVC的要想知道只有通过拦截器(Interceptor)
2、请求拦截并且打印相关参数(日志)
结果示例:
设置请求拦截配置
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.List;
/**
* @description 请求拦截配置
* @author lilinchun
* @date 2022/3/7 0007 18:36
**/
@Configuration
public class WebConfig {
@Bean
public FilterRegistrationBean timeFilter(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
// TimeFilter timeFilter = new TimeFilter();
LoggingFilter loggingFilter=new LoggingFilter();
registrationBean.setFilter(loggingFilter);
//在哪些路径起作用
List<String> urls = new ArrayList<>();
urls.add("/*");
registrationBean.setUrlPatterns(urls);
return registrationBean;
}
}
日志过滤器
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
/**
* @description 日志过滤器
* @author lilinchun
* @date 2022/3/7 0007 18:30
**/
@Slf4j
@Configuration
public class LoggingFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
request = new RequestWrapper(request);
response = new ResponseWrapper(response);
filterChain.doFilter(request, response);
// 请求开始时间
long start = System.currentTimeMillis();
StringBuilder stringBuilder= printRequestLog(request);
printResponseLog((ResponseWrapper) response,stringBuilder);
stringBuilder.append("<== 请求耗时:").append(System.currentTimeMillis()-start).append("s\n");
log.info(stringBuilder.toString());
}
private StringBuilder printRequestLog(final HttpServletRequest request) {
// 请求者IP 地址
String ipAddress = getIpAddress(request);
StringBuilder stringBuilder=new StringBuilder();
RequestWrapper requestWrapper = (RequestWrapper) request;
stringBuilder.append("\n==> 拦截到请求\n")
.append("==> 请求者IP:").append(ipAddress).append( "\n")
.append("==> 请求时间:").append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Calendar.getInstance().getTime())).append("\n")
.append("==> 请求接口:").append(request.getMethod()).append(" ").append(request.getRequestURL()).append("\n")
.append("==> 请求方法:").append(request.getRequestURI()).append("\n")
.append("==> 参数内容:").append(requestWrapper.getRequestBodyString(request)).append("\n")
.toString();
return stringBuilder;
}
/**
* @param: [request]
* @return: java.lang.String
* @desc: 获取IP地址
* @see
* @since
*/
private String getIpAddress(HttpServletRequest request){
final String unknown = "unknown";
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.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || unknown.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
private boolean isBinaryContent(final HttpServletRequest request) {
if (request.getContentType() == null) {
return false;
}
return request.getContentType().startsWith("image")
|| request.getContentType().startsWith("video")
|| request.getContentType().startsWith("audio");
}
private boolean isMultipart(final HttpServletRequest request) {
return request.getContentType() != null
&& request.getContentType().startsWith("multipart/form-data");
}
private void printResponseLog(final ResponseWrapper response,StringBuilder stringBuilder) {
try {
//1.1 先将字符串转换成ISO-8859-1 , 然后利用String的构造函数将字符串转换成UTF-8 new String(Bytes[] bytes , “UTF-8”)
//将name变量的值转换成字节组,默认转换成ISO-8859-1编码
String name = new String(response.toByteArray(), response.getCharacterEncoding());
byte[] bytes = name.getBytes();
//将name从ISO-8859-1转换成UTF-8
name = new String(bytes,"UTF-8");
//1.2 直接将字符串转换成UTF-8
byte[] bytes1 = name.getBytes("UTF-8");
name = new String(bytes1);
//1.3 UrlEncoder的encoder(字符串,字符码)设置编码 , UrlDecoder的decoder(字符串,字符码)解密,然后设置指定的字符码
String nameEncode = URLEncoder.encode(name, "ISO-8859-1");
nameEncode = URLDecoder.decode(nameEncode, "UTF-8");
stringBuilder.append("<== 应答内容:").append( nameEncode ).append("\n");
} catch (UnsupportedEncodingException e) {
log.warn("Failed to parse response payload", e);
}
}
}
请求包装器
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.Charset;
/**
* @description 请求包装器
* @author lilinchun
* @date 2022/3/7 0007 18:35
**/
public class RequestWrapper extends HttpServletRequestWrapper {
private final byte[] body;
public RequestWrapper(HttpServletRequest request) throws IOException {
super(request);
body = getRequestBodyString(request).getBytes(Charset.defaultCharset());
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public int read() throws IOException {
return bais.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener listener) {
}
};
}
public String getRequestBodyString(ServletRequest request) {
StringBuilder sb = new StringBuilder();
InputStream inputStream = null;
BufferedReader reader = null;
try {
inputStream = request.getInputStream();
reader = new BufferedReader(new InputStreamReader(inputStream, Charset.defaultCharset()));
String line;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return sb.toString();
}
}
响应包装器
import org.apache.commons.io.output.TeeOutputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletResponse;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @description 响应包装器
* @author lilinchun
* @date 2022/3/7 0007 18:35
**/
public class ResponseWrapper extends HttpServletResponseWrapper {
private final ByteArrayOutputStream bos = new ByteArrayOutputStream();
private PrintWriter writer = new PrintWriter(bos);
public ResponseWrapper(HttpServletResponse response) {
super(response);
}
@Override
public ServletResponse getResponse() {
return this;
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
return new ServletOutputStream() {
@Override
public boolean isReady() {
return false;
}
@Override
public void setWriteListener(WriteListener listener) {
}
private TeeOutputStream tee = new TeeOutputStream(ResponseWrapper.super.getOutputStream(), bos);
@Override
public void write(int b) throws IOException {
tee.write(b);
}
};
}
@Override
public PrintWriter getWriter() throws IOException {
return new TeePrintWriter(super.getWriter(), writer);
}
public byte[] toByteArray() {
return bos.toByteArray();
}
}
import java.io.PrintWriter;
//PrintWriter是一种写入字符的一种操作类,可以写入字符,TeePrintWriter继承了他,主要功能是把原始的字符流copy到branch里面。
public class TeePrintWriter extends PrintWriter {
PrintWriter branch;
public TeePrintWriter(PrintWriter main, PrintWriter branch) {
super(main, true);
this.branch = branch;
}
public void write(char buf[], int off, int len) {
super.write(buf, off, len);
super.flush();
branch.write(buf, off, len);
branch.flush();
}
public void write(String s, int off, int len) {
super.write(s, off, len);
super.flush();
branch.write(s, off, len);
branch.flush();
}
public void write(int c) {
super.write(c);
super.flush();
branch.write(c);
branch.flush();
}
public void flush() {
super.flush();
branch.flush();
}
}
发现一个问题:目前未能解决…
错误提示:
2022-03-10 10:24:01,011 - Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.multipart.MultipartException: Failed to parse multipart servlet request; nested exception is java.io.IOException: org.apache.tomcat.util.http.fileupload.FileUploadException: Stream closed] with root cause
java.io.IOException: Stream closed
at org.apache.catalina.connector.InputBuffer.throwIfClosed(InputBuffer.java:527)
at org.apache.catalina.connector.InputBuffer.read(InputBuffer.java:338)
at org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:132)
at java.io.FilterInputStream.read(FilterInputStream.java:133)
at org.apache.tomcat.util.http.fileupload.util.LimitedInputStream.read(LimitedInputStream.java:132)
at org.apache.tomcat.util.http.fileupload.MultipartStream$ItemInputStream.makeAvailable(MultipartStream.java:975)
at org.apache.tomcat.util.http.fileupload.MultipartStream$ItemInputStream.read(MultipartStream.java:879)
at java.io.InputStream.read(InputStream.java:101)
at org.apache.tomcat.util.http.fileupload.util.Streams.copy(Streams.java:98)
at org.apache.tomcat.util.http.fileupload.util.Streams.copy(Streams.java:68)
at org.apache.tomcat.util.http.fileupload.MultipartStream.readBodyData(MultipartStream.java:572)
at org.apache.tomcat.util.http.fileupload.MultipartStream.discardBodyData(MultipartStream.java:596)
at org.apache.tomcat.util.http.fileupload.MultipartStream.skipPreamble(MultipartStream.java:614)
at org.apache.tomcat.util.http.fileupload.impl.FileItemIteratorImpl.findNextItem(FileItemIteratorImpl.java:213)
at org.apache.tomcat.util.http.fileupload.impl.FileItemIteratorImpl.<init>(FileItemIteratorImpl.java:127)
at org.apache.tomcat.util.http.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:256)
at org.apache.tomcat.util.http.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:280)
at org.apache.catalina.connector.Request.parseParts(Request.java:2922)
at org.apache.catalina.connector.Request.getParts(Request.java:2824)
at org.apache.catalina.connector.RequestFacade.getParts(RequestFacade.java:1098)
at javax.servlet.http.HttpServletRequestWrapper.getParts(HttpServletRequestWrapper.java:359)
at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.parseRequest(StandardMultipartHttpServletRequest.java:95)
at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.<init>(StandardMultipartHttpServletRequest.java:88)
at org.springframework.web.multipart.support.StandardServletMultipartResolver.resolveMultipart(StandardServletMultipartResolver.java:87)
at org.springframework.web.servlet.DispatcherServlet.checkMultipart(DispatcherServlet.java:1201)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1035)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:681)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:228)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:163)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:163)
at com.llcbk.filter.LoggingFilter.doFilterInternal(LoggingFilter.java:32)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:163)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:163)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:163)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:163)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1723)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
引起原因:我请求上传了一个文件,导致不能请求拦截。。。。。。
解决方案一:排除文件上传的那个路径。