Servlet Filters 简单sample

本文详细介绍了Java Web应用中Servlet过滤器的实现与配置过程。包括如何通过实现javax.servlet.Filter接口创建过滤器,以及如何在web.xml文件中进行配置来拦截特定URL请求。此外还展示了过滤器如何检查请求参数并决定是否阻止或转发请求。

转载自http://tutorials.jenkov.com/java-servlets/servlet-filters.html

突然觉得这个箭头标志有点错误,filter到Servlet,JSP.Static File,应该是双向的。


A Servlet filter is an object that can intercept HTTP requests targeted at your web application.

A servlet filter can intercept requests both for servlets, JSP's, HTML files or other static content, as illustrated in the diagram below:

A Servlet Filter in a Java Web Application
A Servlet Filter in a Java Web Application

In order to create a servlet filter you must implement the javax.servlet.Filter interface. Here is an example servlet filter implementation:

import javax.servlet.*;
import java.io.IOException;

/**

 */
public class SimpleServletFilter implements Filter {

    public void init(FilterConfig filterConfig) throws ServletException {
    }

    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain filterChain)
    throws IOException, ServletException {

    }

    public void destroy() {
    }
}

When the servlet filter is loaded the first time, its init() method is called, just like with servlets.

When a HTTP request arrives at your web application which the filter intercepts, the filter can inspect the request URI, the request parameters and the request headers, and based on that decide if it wants to block or forward the request to the target servlet, JSP etc.

It is the doFilter() method that does the interception. Here is a sample implementation:

public void doFilter(ServletRequest request, ServletResponse response,
                     FilterChain filterChain)
throws IOException, ServletException {

    String myParam = request.getParameter("myParam");

    if(!"blockTheRequest".equals(myParam)){
        filterChain.doFilter(request, response);
    }
}

Notice how the doFilter() method checks a request parameter, myParam, to see if it equals the string "blockTheRequest". If not, the request is forwarded to the target of the request, by calling thefilterChain.doFilter() method. If this method is not called, the request is not forwarded, but just blocked.

The servlet filter above just ignores the request if the request parameter myParam equals "blockTheRequest". You can also write a different response back to the browser. Just use theServletResponse object to do so, just like you would inside a servlet.

You may have to cast the ServletResponse to a HttpResponse to obtain a PrintWriter from it. Otherwise you only have the OutputStream available via getOutputStream().

Here is an example:

public void doFilter(ServletRequest request, ServletResponse response,
                     FilterChain filterChain)
throws IOException, ServletException {

    String myParam = request.getParameter("myParam");

    if(!"blockTheRequest".equals(myParam)){
        filterChain.doFilter(request, response);
        return;
    }

    HttpResponse httpResponse = (HttpResponse) httpResponse;
    httpResponse.getWriter().write("a different response... e.g in HTML");
}

Configuring the Servlet Filter in web.xml

You need to configure the servlet filter in the web.xml file of your web application, before it works. Here is how you do that:

<filter>
    <filter-name>myFilter</filter-name>
    <filter-class>servlets.SimpleServletFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>myFilter</filter-name>
    <url-pattern>*.simple</url-pattern>
</filter-mapping>

With this configuration all requests with URL's ending in .simple will be intercepted by the servlet filter. All others will be left untouched.


@ApiOperation("批量下载图像及label文件成压缩包接口") @PostMapping("/downloadZip") public DeferredResult<ResponseEntity<StreamingResponseBody>> downloadZip(@RequestBody List<Long> ids) { DeferredResult<ResponseEntity<StreamingResponseBody>> deferredResult = new DeferredResult<>(3600000L); CompletableFuture.runAsync(() -> { try { // 提前校验数据 List<CpImageInfo> cpImageInfos = cpImageMapper.selectBatchIds(ids); if (cpImageInfos.isEmpty()) { throw new RuntimeException("未找到样本信息"); } String zipName = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + ".zip"; HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); headers.setContentDisposition(ContentDisposition.builder("attachment") .filename(URLEncoder.encode(zipName, "UTF-8")).build()); // 使用匿名内部类 StreamingResponseBody stream = new StreamingResponseBody() { @Override public void writeTo(OutputStream outputStream) throws IOException { try { fileImageService.downloadZip(ids, outputStream); } catch (Exception e) { log.error("文件流生成异常", e); throw new IOException("压缩过程发生错误"); } } }; deferredResult.setResult(ResponseEntity.ok() .headers(headers) .body(stream)); } catch (Exception e) { deferredResult.setErrorResult( ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body("下载失败: " + e.getMessage())); } }); deferredResult.onTimeout(() -> deferredResult.setErrorResult( ResponseEntity.status(HttpStatus.REQUEST_TIMEOUT) .body("下载超时"))); deferredResult.onError(ex -> deferredResult.setErrorResult( ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body("系统错误: " + ex.getMessage()))); return deferredResult; } @Override public void downloadZip(List<Long> ids, OutputStream outputStream) throws IOException { List<CpImageInfo> cpImageInfos = cpImageMapper.selectBatchIds(ids); if (cpImageInfos.isEmpty()) { throw new RuntimeException("未找到样本信息"); } // 使用非缓冲流提高大文件性能 try (ZipOutputStream zos = new ZipOutputStream(outputStream)) { zos.setLevel(Deflater.DEFAULT_COMPRESSION); // 平衡速度和压缩率 String rootDir = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + "/"; int i = 0; for (CpImageInfo imageInfo : cpImageInfos) { if (Thread.currentThread().isInterrupted()) { throw new IOException("下载被中断"); } i++; String safeImageName = sanitizeFilename(imageInfo.getImageName()); String name = removeParentheses(safeImageName); String sampleDir = rootDir + name + "(" + i + ")/"; // 处理图像文件 List<CpImageBasicInfo> imageFiles = cpImageBasicMapper.selectByUniqueValue(imageInfo.getUniqueValue()); for (CpImageBasicInfo file : imageFiles) { addFileToZip(zos, sampleDir + "img/" + file.getImageName(), file.getImagePath()); } // 处理标签文件 List<CpLabelBasicInfo> labelFiles = cpLabelBasicMapper.selectByUniqueValue(imageInfo.getUniqueValue()); for (CpLabelBasicInfo file : labelFiles) { addFileToZip(zos, sampleDir + "gt/" + file.getLabelFileName(), file.getLabelFilePath()); } // 定期刷新输出流 zos.flush(); outputStream.flush(); } } } // 改进的文件添加方法 private void addFileToZip(ZipOutputStream zos, String entryName, String filePath) throws IOException { File file = new File(filePath); if (!file.exists()) { log.warn("文件不存在: {}", filePath); return; } try (FileInputStream fis = new FileInputStream(file)) { ZipEntry zipEntry = new ZipEntry(entryName); zos.putNextEntry(zipEntry); byte[] buffer = new byte[65536]; // 64KB 缓冲区 int len; while ((len = fis.read(buffer)) > 0) { // 检查是否中断 if (Thread.currentThread().isInterrupted()) { throw new IOException("下载被中断"); } zos.write(buffer, 0, len); } zos.closeEntry(); } } // 文件名消毒处理 private String sanitizeFilename(String filename) { return filename.replaceAll("[\\\\/:*?\"<>|]", "_"); } public String removeParentheses(String filename) { if (filename == null) { return null; } String result = filename; int prevLength; // 循环替换直到没有括号内容 do { prevLength = result.length(); result = result.replaceAll("\\(.*?\\)", ""); } while (result.length() < prevLength); return result; } 2025-06-06 10:56:59.176 ERROR 22432 --- [ MvcAsync1] c.a.e.c.sample.FileImageController : 文件流生成异常 org.apache.catalina.connector.ClientAbortException: java.io.IOException: 远程主机强迫关闭了一个现有的连接。 at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:353) ~[tomcat-embed-core-9.0.63.jar:9.0.63] at org.apache.catalina.connector.OutputBuffer.flushByteBuffer(OutputBuffer.java:783) ~[tomcat-embed-core-9.0.63.jar:9.0.63] at org.apache.catalina.connector.OutputBuffer.append(OutputBuffer.java:688) ~[tomcat-embed-core-9.0.63.jar:9.0.63] at org.apache.catalina.connector.OutputBuffer.writeBytes(OutputBuffer.java:388) ~[tomcat-embed-core-9.0.63.jar:9.0.63] at org.apache.catalina.connector.OutputBuffer.write(OutputBuffer.java:366) ~[tomcat-embed-core-9.0.63.jar:9.0.63] at org.apache.catalina.connector.CoyoteOutputStream.write(CoyoteOutputStream.java:96) ~[tomcat-embed-core-9.0.63.jar:9.0.63] at java.util.zip.DeflaterOutputStream.deflate(DeflaterOutputStream.java:253) ~[na:1.8.0_102] at java.util.zip.DeflaterOutputStream.write(DeflaterOutputStream.java:211) ~[na:1.8.0_102] at java.util.zip.ZipOutputStream.write(ZipOutputStream.java:331) ~[na:1.8.0_102] at com.aircas.evaluation.service.impl.sample.FileImageInfoServiceImpl.addFileToZip(FileImageInfoServiceImpl.java:876) ~[classes/:na] at com.aircas.evaluation.service.impl.sample.FileImageInfoServiceImpl.downloadZip(FileImageInfoServiceImpl.java:841) ~[classes/:na] at com.aircas.evaluation.service.impl.sample.FileImageInfoServiceImpl$$FastClassBySpringCGLIB$$50be5633.invoke(<generated>) ~[classes/:na] at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.20.jar:5.3.20] at org.springframework.aop.framework.CglibAopProxy.invokeMethod(CglibAopProxy.java:386) ~[spring-aop-5.3.20.jar:5.3.20] at org.springframework.aop.framework.CglibAopProxy.access$000(CglibAopProxy.java:85) ~[spring-aop-5.3.20.jar:5.3.20] at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:704) ~[spring-aop-5.3.20.jar:5.3.20] at com.aircas.evaluation.service.impl.sample.FileImageInfoServiceImpl$$EnhancerBySpringCGLIB$$5e579eb.downloadZip(<generated>) ~[classes/:na] at com.aircas.evaluation.controller.sample.FileImageController$1.writeTo(FileImageController.java:315) ~[classes/:na] at org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBodyReturnValueHandler$StreamingResponseBodyTask.call(StreamingResponseBodyReturnValueHandler.java:111) [spring-webmvc-5.3.20.jar:5.3.20] at org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBodyReturnValueHandler$StreamingResponseBodyTask.call(StreamingResponseBodyReturnValueHandler.java:98) [spring-webmvc-5.3.20.jar:5.3.20] at org.springframework.web.context.request.async.WebAsyncManager.lambda$startCallableProcessing$4(WebAsyncManager.java:337) [spring-web-5.3.20.jar:5.3.20] at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) ~[na:1.8.0_102] at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266) ~[na:1.8.0_102] at java.util.concurrent.FutureTask.run(FutureTask.java) ~[na:1.8.0_102] at java.lang.Thread.run(Thread.java:745) ~[na:1.8.0_102] Suppressed: org.apache.catalina.connector.ClientAbortException: java.io.IOException: The current thread was interrupted at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:353) ~[tomcat-embed-core-9.0.63.jar:9.0.63] at org.apache.catalina.connector.OutputBuffer.flushByteBuffer(OutputBuffer.java:783) ~[tomcat-embed-core-9.0.63.jar:9.0.63] at org.apache.catalina.connector.OutputBuffer.append(OutputBuffer.java:688) ~[tomcat-embed-core-9.0.63.jar:9.0.63] at org.apache.catalina.connector.OutputBuffer.writeBytes(OutputBuffer.java:388) ~[tomcat-embed-core-9.0.63.jar:9.0.63] at org.apache.catalina.connector.OutputBuffer.write(OutputBuffer.java:366) ~[tomcat-embed-core-9.0.63.jar:9.0.63] at org.apache.catalina.connector.CoyoteOutputStream.write(CoyoteOutputStream.java:96) ~[tomcat-embed-core-9.0.63.jar:9.0.63] at java.util.zip.DeflaterOutputStream.deflate(DeflaterOutputStream.java:253) ~[na:1.8.0_102] at java.util.zip.ZipOutputStream.closeEntry(ZipOutputStream.java:255) ~[na:1.8.0_102] at java.util.zip.ZipOutputStream.finish(ZipOutputStream.java:360) ~[na:1.8.0_102] at java.util.zip.DeflaterOutputStream.close(DeflaterOutputStream.java:238) ~[na:1.8.0_102] at java.util.zip.ZipOutputStream.close(ZipOutputStream.java:377) ~[na:1.8.0_102] at com.aircas.evaluation.service.impl.sample.FileImageInfoServiceImpl.downloadZip(FileImageInfoServiceImpl.java:854) ~[classes/:na] ... 14 common frames omitted Caused by: java.io.IOException: The current thread was interrupted at org.apache.tomcat.util.net.NioChannel.checkInterruptStatus(NioChannel.java:236) at org.apache.tomcat.util.net.NioChannel.write(NioChannel.java:134) at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.doWrite(NioEndpoint.java:1384) at org.apache.tomcat.util.net.SocketWrapperBase.doWrite(SocketWrapperBase.java:773) at org.apache.tomcat.util.net.SocketWrapperBase.writeBlocking(SocketWrapperBase.java:593) at org.apache.tomcat.util.net.SocketWrapperBase.write(SocketWrapperBase.java:537) at org.apache.coyote.http11.Http11OutputBuffer$SocketOutputBuffer.doWrite(Http11OutputBuffer.java:547) at org.apache.coyote.http11.filters.ChunkedOutputFilter.doWrite(ChunkedOutputFilter.java:110) at org.apache.coyote.http11.Http11OutputBuffer.doWrite(Http11OutputBuffer.java:194) at org.apache.coyote.Response.doWrite(Response.java:615) at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:340) ... 25 common frames omitted Caused by: java.io.IOException: 远程主机强迫关闭了一个现有的连接。 at sun.nio.ch.SocketDispatcher.write0(Native Method) ~[na:1.8.0_102] at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:51) ~[na:1.8.0_102] at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:93) ~[na:1.8.0_102] at sun.nio.ch.IOUtil.write(IOUtil.java:65) ~[na:1.8.0_102] at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:471) ~[na:1.8.0_102] at org.apache.tomcat.util.net.NioChannel.write(NioChannel.java:135) ~[tomcat-embed-core-9.0.63.jar:9.0.63] at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.doWrite(NioEndpoint.java:1384) ~[tomcat-embed-core-9.0.63.jar:9.0.63] at org.apache.tomcat.util.net.SocketWrapperBase.doWrite(SocketWrapperBase.java:773) ~[tomcat-embed-core-9.0.63.jar:9.0.63] at org.apache.tomcat.util.net.SocketWrapperBase.writeBlocking(SocketWrapperBase.java:593) ~[tomcat-embed-core-9.0.63.jar:9.0.63] at org.apache.tomcat.util.net.SocketWrapperBase.write(SocketWrapperBase.java:537) ~[tomcat-embed-core-9.0.63.jar:9.0.63] at org.apache.coyote.http11.Http11OutputBuffer$SocketOutputBuffer.doWrite(Http11OutputBuffer.java:547) ~[tomcat-embed-core-9.0.63.jar:9.0.63] at org.apache.coyote.http11.filters.ChunkedOutputFilter.doWrite(ChunkedOutputFilter.java:112) ~[tomcat-embed-core-9.0.63.jar:9.0.63] at org.apache.coyote.http11.Http11OutputBuffer.doWrite(Http11OutputBuffer.java:194) ~[tomcat-embed-core-9.0.63.jar:9.0.63] at org.apache.coyote.Response.doWrite(Response.java:615) ~[tomcat-embed-core-9.0.63.jar:9.0.63] at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:340) ~[tomcat-embed-core-9.0.63.jar:9.0.63] ... 24 common frames omitted
06-07
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值