- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
本文介绍Filters
、Interceptors
及其配置。Filters
和Interceptors
可以在客户端和服务器端使用。Filters
可以修改入站和出站请求和响应,包括修改头、实体和其他请求/响应参数。Interceptors
主要用于修改实体输入和输出流。例如,可以使用Interceptors
压缩和解压缩输出和输入实体流。
当您想修改任何请求或响应参数(如标题)时,可以使用过滤器。例如,您希望将响应标题“X-Powered-By”添加到每个生成的响应中。您将使用响应过滤器来添加此头,而不是在每个资源方法中添加此头。
服务器端和客户端都有筛选器。
服务器筛选器:
ContainerResponseFilter
-以下示例显示了一个简单的容器响应过滤器,它向每个响应添加一个标头。****
**示例:**容器响应筛选器
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.Response;
public class PoweredByResponseFilter implements ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
throws IOException {
responseContext.getHeaders().add("X-Powered-By", "Jersey :-)");
}
}
1.在上面的示例中,PoweredByResponseFilter
总是在响应中添加标题“X-Powered-By”。筛选器必须从ContainerResponseFilter
继承,并且必须注册为提供程序。
1.在大多数情况下,执行资源方法后,将对每个响应执行筛选器。即使未运行资源方法,也会执行响应过滤器,例如,当未找到资源方法且Jersey
运行时返回404“未找到”响应代码时。在这种情况下,将执行过滤器并处理404响应。
1.filter()
方法有两个参数,容器请求和容器响应。ContainerRequestContext
只能用于只读目的,因为过滤器已经在响应阶段执行。可以在ContainerResponseContext
中进行修改。
ContainerRequestFilter-以下示例显示了请求筛选器的用法。
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
public class AuthorizationRequestFilter implements ContainerRequestFilter {
@Override
public void filter(ContainerRequestContext requestContext)
throws IOException {
final SecurityContext securityContext =
requestContext.getSecurityContext();
if (securityContext == null ||
!securityContext.isUserInRole("privileged")) {
requestContext.abortWith(Response
.status(Response.Status.UNAUTHORIZED)
.entity("User cannot access the resource.")
.build());
}
}
}
示例中的AuthorizationRequestFilter
检查经过身份验证的用户是否处于特权角色。
上面显示的所有请求筛选器都实现为后匹配筛选器。这意味着只有在选择了合适的资源方法来处理实际请求后,即在进行请求匹配后,才会应用过滤器
请求匹配是根据请求路径和其他请求参数查找应执行的资源方法的过程。由于在选择了特定的资源方法时会调用后期匹配请求筛选器,因此此类筛选器不会影响资源方法匹配过程。
为了克服上述限制,可以将服务器请求过滤器标记为预匹配过滤器,即用@PreMatching
注解注解过滤器类。预匹配筛选器是在启动请求匹配之前执行的请求筛选器。正因为如此,预匹配请求过滤器有可能影响匹配的方法。这样一个预匹配请求过滤器示例如下所示:
**示例:**预匹配请求筛选器
...
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.PreMatching;
...
@PreMatching
public class PreMatchingFilter implements ContainerRequestFilter {
@Override
public void filter(ContainerRequestContext requestContext)
throws IOException {
// change all PUT methods to POST
if (requestContext.getMethod().equals("PUT")) {
requestContext.setMethod("POST");
}
}
}
客户端筛选器类似于容器筛选器。ClientRequestFilter
中的响应也可以中止,这将导致实际上根本不会向服务器发送任何请求。一个新的响应被传递给中止方法。此响应将作为请求调用的结果使用和交付。这样的响应通过客户端响应过滤器。这与服务器端的情况类似
该过程如以下示例所示:
public class CheckRequestFilter implements ClientRequestFilter {
@Override
public void filter(ClientRequestContext requestContext)
throws IOException {
if (requestContext.getHeaders(
).get("Client-Name") == null) {
requestContext.abortWith(
Response.status(Response.Status.BAD_REQUEST)
.entity("Client-Name header must be defined.")
.build());
}
}
}
**CheckRequestFilter **
验证传出请求。检查是否存在客户端名称标头。如果标头不存在,则请求将被中止,并在实体正文中添加一个带有适当代码和消息的虚构响应。这将导致原始请求无法有效地发送到服务器,但实际调用仍将以响应结束,就像它将由服务器端生成一样。如果有任何客户端响应过滤器,它将在该响应上执行。
拦截器为服务器端和客户端共享一个公共API。过滤器主要用于操作请求和响应参数,如HTTP
头、URIs
和/或HTTP方法,而拦截器则用于通过操作实体输入/输出流来操作实体。例如,如果您需要对客户机请求的实体体进行编码,那么您可以实现一个拦截器来完成这项工作。
拦截器有两种,
读卡器拦截器用于操作入站实体流。这些是来自“电线”的溪流。因此,使用读取器拦截器,您可以操作服务器端的请求实体流(从客户端请求读取实体)和客户端的响应实体流(在客户端从服务器响应读取实体)。
编写器拦截器用于将实体写入“连线”的情况,在服务器上,这意味着在写出响应实体时,以及在客户端编写要发送到服务器的请求实体时。
编写器和读取器拦截器在执行消息体读取器或编写器之前执行,其主要目的是包装将在消息体读出器和编写器中使用的实体流。
下面的示例显示了一个writer拦截器,它支持整个实体体的GZIP压缩。
示例:GZIP
writer interceptor
public class GZIPWriterInterceptor implements WriterInterceptor {
@Override
public void aroundWriteTo(WriterInterceptorContext context)
throws IOException, WebApplicationException {
final OutputStream outputStream = context.getOutputStream();
context.setOutputStream(new GZIPOutputStream(outputStream));
context.proceed();
}
}
拦截器从WriterInterceptorContext
获取一个输出流,并设置一个新的输出流,它是原始输出流的GZIP
包装器。毕竟,拦截器被执行,最后设置为WriterInterceptorContext
的输出流将用于实体的序列化。
现在让我们看一个ReaderInterceptor
的例子
**示例:**GZIP阅读器拦截器
public class GZIPReaderInterceptor implements ReaderInterceptor {
@Override
public Object aroundReadFrom(ReaderInterceptorContext context)
throws IOException, WebApplicationException {
final InputStream originalInputStream = context.getInputStream();
context.setInputStream(new GZIPInputStream(originalInputStream));
return context.proceed();
}
}
GZIPReaderInterceptor
用GZIPInputStream
包装原始输入流。对实体流的所有进一步读取都将导致此流解压缩数据。拦截器方法aroundReadFrom()
必须返回实体。该实体是从ReaderInterceptorContext
的proceed方法返回的
proceed方法在内部调用包装的拦截器,该拦截器还必须返回实体。从链中的最后一个拦截器调用的proceed方法调用消息体读取器,该读取器反序列化实体端返回它。如果有需要,每个拦截器都可以更改此实体,但在大多数情况下,拦截器只会返回从proceed方法返回的实体。
让我们仔细看看过滤器和拦截器的执行上下文。以下步骤描述了JAX-RS
客户端向服务器发出POST请求的场景。服务器接收到一个实体,并用同一实体发送回响应。GZIP
读写器拦截器在客户端和服务器上注册。此外,过滤器在客户端和服务器上注册,更改请求和响应的头。
***调用的客户端请求:**带有附加实体的POST请求构建在客户端上并被调用。
***ClientRequestFilters:**客户端请求过滤器在客户端上执行,它们操作请求头。
***客户端WriterInterceptor:**由于请求包含实体,因此在客户端注册的writer interceptor将在执行MessageBodyWriter之前执行。它用GZipOutputStream包装实体输出流。
***客户端MessageBodyWriter:**消息体编写器在客户端上执行,该客户端将实体序列化到新的GZipOutput流中。此流压缩数据并将其发送到“连线”。
***服务器:**服务器接收请求。实体的数据被压缩,这意味着从实体输入流中纯读取将返回压缩数据。
***服务器预匹配ContainerRequestFilters:**执行ContainerQuestFilters可以操作资源方法匹配过程。
***服务器:**匹配:资源方法匹配完成。
***服务器:**后匹配ContainerRequestFilters:Container请求过滤器后匹配过滤器被执行。这包括执行所有全局筛选器(没有名称绑定)和筛选器绑定到匹配方法的名称。
***Server ReaderInterceptor:**读卡器拦截器在服务器上执行。GZIPReaderInterceptor将输入流(来自“wire”的流)包装到GZipInputStream中,并将其设置为context。
***服务器MessageBodyReader:**执行服务器消息体读取器,并从新的GZipInputStream反序列化实体(从上下文获取)。这意味着阅读器将从“连线”读取解压缩的数据,而不是压缩的数据。
***执行服务器资源方法:**反序列化的实体对象作为参数传递给匹配的资源方法。该方法将此实体作为响应实体返回。
***执行服务器ContainerResponseFilters:**在服务器上执行响应筛选器,并操作响应标头。这包括所有全局绑定筛选器(没有名称绑定)和所有绑定到资源方法的筛选器名称。
***服务器WriterInterceptor:**在服务器上执行。它用一个新的GZIPOutStream包装原始输出流。原始流是“连接”的流(底层服务器容器的响应输出流)。
***服务器MessageBodyWriter:**消息体编写器在服务器上执行,该服务器将实体序列化为GZIPOutputStream。此流压缩数据并将其写入原始流,原始流将此压缩数据发送回客户端。
***客户端收到响应:**响应包含压缩的实体数据。
***客户端响应筛选器:**执行客户端响应筛选器并操作响应标头。
***返回客户端响应:javax.ws.rs.core。请求调用返回响应。
***客户端代码调用响应。readEntity():**读取实体在客户端上执行,以从响应中提取实体。
***客户端ReaderInterceptor:**客户端读取器拦截器在调用readEntity(Class)时执行。拦截器使用GZIPInputStream包装实体输入流。这将从原始输入流中解压缩数据。
***客户端MessageBodyReaders:**调用客户端消息正文阅读器,从GZIPInputStream读取解压缩数据并反序列化实体。
***客户端:**实体从readEntity()返回。
可以使用@NameBinding
注解将筛选器或拦截器分配给资源方法。
示例:
...
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.zip.GZIPInputStream;
import javax.ws.rs.GET;
import javax.ws.rs.NameBinding;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
...
// @Compress annotation is the name binding annotation
@NameBinding
@Retention(RetentionPolicy.RUNTIME)
public @interface Compress {}
@Path("helloworld")
public class HelloWorldResource {
@GET
@Produces("text/plain")
public String getHello() {
return "Hello World!";
}
@GET
@Path("too-much-data")
@Compress
public String getVeryLongString() {
String str = ... // very long string
return str;
}
}
// interceptor will be executed only when resource methods
// annotated with @Compress annotation will be executed
@Compress
public class GZIPWriterInterceptor implements WriterInterceptor {
@Override
public void aroundWriteTo(WriterInterceptorContext context)
throws IOException, WebApplicationException {
final OutputStream outputStream = context.getOutputStream();
context.setOutputStream(new GZIPOutputStream(outputStream));
context.proceed();
}
}
上例定义了一个新的@Compress
注解,它是一个名称绑定注解,因为它是用@NameBinding
进行注解的。上例中的注解是自我描述的。
动态绑定是一种以动态方式为资源方法分配过滤器和拦截器的方法。
...
import javax.ws.rs.core.FeatureContext;
import javax.ws.rs.container.DynamicFeature;
...
@Path("helloworld")
public class HelloWorldResource {
@GET
@Produces("text/plain")
public String getHello() {
return "Hello World!";
}
@GET
@Path("too-much-data")
public String getVeryLongString() {
String str = ... // very long string
return str;
}
}
// This dynamic binding provider registers GZIPWriterInterceptor
// only for HelloWorldResource and methods that contain
// "VeryLongString" in their name. It will be executed during
// application initialization phase.
public class CompressionDynamicBinding implements DynamicFeature {
@Override
public void configure(ResourceInfo resourceInfo, FeatureContext context) {
if (HelloWorldResource.class.equals(resourceInfo.getResourceClass())
&& resourceInfo.getResourceMethod()
.getName().contains("VeryLongString")) {
context.register(GZIPWriterInterceptor.class);
}
}
}
绑定是使用实现DynamicFeature
接口的提供程序完成的。该接口定义了一个带有两个参数(ResourceInfo
和FeatureContext
)的configure方法。ResourceInfo
包含有关可以进行绑定的资源和方法的信息。
如果您注册了更多过滤器和拦截器,您可能需要定义调用它们的确切顺序。顺序可以由javax.annotation.Priority
类定义的@Priority
注解控制。为过滤器和拦截器分配优先级是一个好做法。
...
import javax.annotation.Priority;
import javax.ws.rs.Priorities;
...
@Priority(Priorities.HEADER_DECORATOR)
public class ResponseFilter implements ContainerResponseFilter {
@Override
public void filter(ContainerRequestContext requestContext,
ContainerResponseContext responseContext)
throws IOException {
responseContext.getHeaders().add("X-Powered-By", "Jersey :-)");
}
}
参考:https://jersey.github.io/documentation/latest/filters-and-interceptors.html
我有一个对象数组,我想在键传入“filter”过滤器时提取值。下面是我尝试过的 Controller 代码片段,但我得到的响应类型未定义。请帮我找出哪里出错了。 var states = [{"HI
如果任何 J2EE 应用程序直接访问 servlet,然后 servlet 将相同的请求转发到某个 .jsp 页面。 request.getRequestDispatcher("Login.jsp")
我有一个带有图像缩略图的表单,可以通过复选框进行选择以进行下载。我想要一个包含 jQuery 中图像的数组,用于 Ajax 调用。 2个问题: - 表格顶部有一个复选框,用于切换我想要从映射中排除的所
我必须从服务器转储数据库,将 .sql 传输到另一台服务器,然后运行以下脚本以使用此语法删除某些行: DELETE wp_posts FROM wp_posts INNER JOIN wp_postm
我想从目录中过滤掉特定类型的文件,但收到错误“ token 语法错误,删除这些 token ”: File dir = new File("c:/etc/etc"); File[] f
几乎所有的 Web 应用程序都依赖外部的输入。这些数据通常来自用户或其他应用程序(比如 web 服务)。通过使用过滤器,您能够确保应用程序获得正确的输入类型。 您应该始终对外部数据进行过滤! 输
我正在开发一个由 OData 服务提供支持的搜索功能。它将返回一个或一列标题对象作为结果。我们需要搜索的许多字段不在标题对象中。它们仅在子对象(导航属性)中。能够针对子字段执行 OData 搜索并仍然
假设我有以下模型,它有一个方法 variants(): class Example(models.Model): text = models.CharField(max_length=255)
我有一个默认的列表列表,但我基本上想这样做: myDefaultDict = filter(lambda k: len(k)>1, myDefaultDict) 除了它似乎只适用于列表。我能做什么?
我正在使用 django-filter 来输出我的模型的过滤结果。那里没有问题。下一步是添加一个分页器……尽管现在已经苦苦挣扎了好几天。 views.py: def funds_overview(re
我正在做一个概念证明,我正在试验一种奇怪的行为。 我有一个按日期字段按范围分区的表,如果我设置固定日期或由 SYSDATE 创建的日期,查询的成本会发生很大变化。 这些是解释计划: SQL> SELE
如果一个或另一个值匹配,是否可以制作一个过滤器,例如一个中性的 PropertyFilter(并传递给链中的下一个过滤器)?就像是: value1 val
我是 VBA 初学者,正在尝试根据单元格值过滤数据,经过一番谷歌搜索后,我编写了一个有效的代码 Sub FilterDepartment_Sales() Sheet6.Activate
假设我在 excel 数据透视表中有两个过滤器。 两者最初都会显示筛选列的选定范围内的所有值。 当我仅在过滤器 1 中选择几个值时,过滤器 2 仍会继续显示基础数据中所选范围内特定过滤器列中的所有值。
是否可以定义自定义 build-ins (名称不再适合)在 ftl? 由于语义前提,我不想让它成为一个函数,而是一个内置的。 最佳答案 这是不可能的,?语法是为内置函数保留的。 (顺便说一句,这意味着
我试图在 Edit | 之外添加一个链接通过插件删除wordpress管理员>用户>所有用户列表中的链接..这是我第一次尝试通过查看其他插件或搜索google来制作wordpress插件.. 我添加了
我正在尝试按照以下教程使用 django 过滤器进行分页,但该教程似乎缺少某些内容,而且我无法使用基于函数的 View 方法显示分页。 https://simpleisbetterthancomple
由于我是 Powershell 新手,因此寻求最佳实践方面的帮助, 我有一个 csv 文件,我想过滤掉 csv 中的每一行,除了包含“未安装”的行 然后,我想根据包含计算机列表的单独 csv 文件过滤
我正在尝试创建一个搜索查询,它会告诉我我作为审阅者添加到其中的打开更改,但我还没有提交最新补丁集的代码审查。这应该包括其他人已经评论过的更改,但我没有。 我能找到的最接近的是 is:reviewer
在我的 Web 应用程序中,我有 3 个主要部分 1. 客户 2. 供应商 3. 管理员 我正在使用 java session 过滤器来检查用户 session 并允许访问网站的特定部分。 因此客户只
我是一名优秀的程序员,十分优秀!