GP Coder

Trang chia sẻ kiến thức lập trình Java

  • Java Core
    • Basic Java
    • OOP
    • Exception Handling
    • Multi-Thread
    • Java I/O
    • Networking
    • Reflection
    • Collection
    • Java 8
  • Design pattern
    • Creational Pattern
    • Structuaral Pattern
    • Behavior Pattern
  • Web Service
    • SOAP
    • REST
  • JPA
  • Java library
    • Report
    • Json
    • Unit Test
  • Message Queue
    • ActiveMQ
    • RabbitMQ
  • All
Trang chủ Java Webservice REST Rest Web service: Filter và Interceptor với Jersey 2.x (P2)

Rest Web service: Filter và Interceptor với Jersey 2.x (P2)

Đăng vào 27/06/2019 . Được đăng bởi GP Coder . 2976 Lượt xem . Toàn màn hình

Ở bài viết trước, chúng ta đã cùng tìm hiểu về Filter. Trong phần này, chúng ta sẽ tìm hiểu tiếp Interceptor và một số cấu hình khác của Jersey.

Nội dung

  • 1 Jersey Interceptor
  • 2 Thứ tự thực thi Filter và Interceptor
  • 3 Name binding
  • 4 Dynamic binding
  • 5 Priorities

Jersey Interceptor

Interceptor có thể được sử dụng ở cả 2 phía Jersey Server và Jersey Client. Interceptor chủ yếu được sử dụng để chỉnh sửa data (entity) của input/ output stream. Một ví dụ về trường hợp sử dụng của Intercepter là zip/ unzip các data (entity) của input/ output stream.

Interceptor tham gia trong quá trình marshalling và unmarshalling HTTP message body có trong các request/ response.

Lưu ý: Intercepter được thực thi sau Filter và message body tồn tại.

Có 2 loại Interceptor:

  • ReaderInterceptor : được sử dụng để xử lý inbound entity stream ở phía Server và response entity stream ở phía Client.
  • WriterInterceptor : được sử dụng để xử lý outbound response entity ở phía Server và request entity stream ở phía Client.

Tạo WriterInterceptor

Tạo WriterInterceptor để wrap OutputStream bởi một GZIPOutputStream và gửi lên Server.

GZIPWriterInterceptor.java


package com.gpcoder.interceptor;

import java.io.IOException;
import java.io.OutputStream;
import java.util.zip.GZIPOutputStream;

import javax.ws.rs.ext.Provider;
import javax.ws.rs.ext.WriterInterceptor;
import javax.ws.rs.ext.WriterInterceptorContext;

public class GZIPWriterInterceptor implements WriterInterceptor {

	@Override
	public void aroundWriteTo(WriterInterceptorContext context) throws IOException {
		final OutputStream outputStream = context.getOutputStream();
		context.setOutputStream(new GZIPOutputStream(outputStream));
		context.proceed();
	}
}

Tạo ReaderInterceptor

Tạo ReaderInterceptor để wrap InputStream bởi một GZIPInputStream để đọc data đã được compress từ Client gửi lên.

GZIPReaderInterceptor.java


package com.gpcoder.interceptor;

import java.io.IOException;
import java.io.InputStream;

import javax.ws.rs.ext.Provider;
import javax.ws.rs.ext.ReaderInterceptor;
import javax.ws.rs.ext.ReaderInterceptorContext;

import com.gpcoder.util.ZipUtil;

@Provider
public class GZIPReaderInterceptor implements ReaderInterceptor {

	@Override
	public Object aroundReadFrom(ReaderInterceptorContext context) throws IOException {
		final InputStream originalInputStream = context.getInputStream();
		context.setInputStream(ZipUtil.decompressStream(originalInputStream));
		return context.proceed();
	}
}

Lưu ý: Chúng ta sử dụng @Provider để đăng ký Interceptor này với Jersey.

Lớp ZipUtil.java hỗ trợ decompress data đã được gzip:


package com.gpcoder.util;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
import java.io.RandomAccessFile;
import java.util.zip.GZIPInputStream;

public class ZipUtil {

	private ZipUtil() {
		super();
	}

	/**
	 * The method to decompress a input stream if a input stream is a gzip archive.
	 * 
	 * @param in the input stream to be decompressed.
	 * @return
	 */
	public static InputStream decompressStream(InputStream input) {
		try {
			// we need a pushbackstream to look ahead
			PushbackInputStream pb = new PushbackInputStream(input, 2);
			byte[] signature = new byte[2];
			int len = pb.read(signature); // read the signature
			pb.unread(signature, 0, len); // push back the signature to the stream
			if (signature[0] == (byte) 0x1f && signature[1] == (byte) 0x8b) {
				// check if matches standard gzip magic number
				return new GZIPInputStream(pb);
			}
			return pb;
		} catch (Exception e) {
			return input;
		}
	}
}

Test Interceptor sử dụng Jersey Client

InterceptorClient.java


package com.gpcoder.client;

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.logging.LoggingFeature;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.gpcoder.interceptor.GZIPWriterInterceptor;
import com.gpcoder.model.Order;

public class InterceptorClient {
	public static final String API_URL = "http://localhost:8080/RestfulWebServiceExample/rest/orders";

	public static void main(String[] args) {
		ClientConfig clientConfig = new ClientConfig();

		// Config logging for client side
		clientConfig.register( //
				new LoggingFeature( //
						Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME), //
						Level.INFO, //
						LoggingFeature.Verbosity.PAYLOAD_ANY, //
						10000));

		// Config filters
		clientConfig.register(new GZIPWriterInterceptor());

		String payload = convertToJson(new Order(1, "gpcoder"));

		Client client = ClientBuilder.newClient(clientConfig);
		Response response = client.target(API_URL).request(MediaType.APPLICATION_JSON_TYPE)
				.post(Entity.entity(payload, MediaType.APPLICATION_JSON));
		System.out.println(response.readEntity(String.class));
	}

	private static String convertToJson(Order order) {
		ObjectMapper mapper = new ObjectMapper();
		try {
			return mapper.writeValueAsString(order);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}
}

Chạy chương trình trên chúng ta có kết quả như sau:

Console ở Client:

Console ở Server:

Như bạn thấy, dữ liệu ở Client gửi lên, và ở server nhận được đều đã được compress/ decompress với gzip.

Các bạn có thể, bỏ đoạn code đăng ký GZIPWriterInterceptor ở Client. Sau đó chạy lại, bạn sẽ sẽ thấy dữ liệu gửi và nhận ở dạng plain/text như sau:

Thứ tự thực thi Filter và Interceptor

Thứ tự thực thi các Filter và Interceptor được minh họa như hình sau:

Name binding

Mặc định, các Filter và Interceptor sẽ được áp dụng trên tất cả các resource method. Chúng ta, có thể chỉ định Filter chỉ áp dụng trên một vài resource method bằng cách sử dụng Name binding.

Để làm được điều này, chúng tạo một Annotation và đánh dấu với Annotation @NameBinding. Sau đó, sử dụng Annotation này với resource method cần áp dụng Filter được chỉ định.

Ví dụ:

Tạo một Annotation để đánh dấu binding cho Filter Compress data với các resource method trả về kích thước dữ liệu lớn:

Compress.java


package com.gpcoder.annotation;

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

import javax.ws.rs.NameBinding;

// @Compress annotation is the name binding annotation
@NameBinding
@Retention(RetentionPolicy.RUNTIME)
public @interface Compress {
}

Tạo Rest Web service:


package com.gpcoder.api;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;

import com.gpcoder.annotation.Compress;

//URI:
//http(s)://<domain>:(port)/<YourApplicationName>/<UrlPattern in web.xml>/<path>
//http://localhost:8080/RestfulWebServiceExample/rest/compresses
@Path("/compresses")
public class HeavyService {

	@GET
	@Path("normal-data")
	public String getNormalData() {
		return "Normal data";
	}

	@GET
	@Path("big-data")
	@Compress
	public String getBigData() {
		return "Big data";
	}

	@GET
	@Path("dynamic-data")
	public String getDynamicData() {
		return "Dynamic data";
	}
}

Test ứng dụng:

  • /normal-data : dữ liệu trả về dạng plain-text.
  • /big-data : dữ liệu trả về đã được compress ở định dạng gzip.
  • /dynamic-data : dữ liệu trả về dạng plain-text.

Dynamic binding

Ngoài sử dụng custom Annotation @NameBinding, chúng ta có thể áp dụng một Filter trên một số resource method nếu nó thõa mãn một số điều kiện nhất định.

Ví dụ:

Tạo DynamicFeature để kiểm tra nếu tên resource method có chứa “DynamicData” thì sẽ sử dụng GZIPWriterInterceptor.


package com.gpcoder.interceptor;

import javax.ws.rs.container.DynamicFeature;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.FeatureContext;
import javax.ws.rs.ext.Provider;

import com.gpcoder.api.HeavyService;

//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.
@Provider
public class CompressionDynamicBinding implements DynamicFeature {

	@Override
	public void configure(ResourceInfo resourceInfo, FeatureContext context) {
		if (HeavyService.class.equals(resourceInfo.getResourceClass())
				&& resourceInfo.getResourceMethod().getName().contains("DynamicData")) {
			context.register(GZIPWriterInterceptor.class);
		}
	}
}

Chạy lại ứng dụng trên, chúng ta có kết quả như sau:

  • /normal-data : dữ liệu trả về dạng plain-text.
  • /big-data : dữ liệu trả về đã được compress ở định dạng gzip.
  • /dynamic-data : dữ liệu trả về đã được compress ở định dạng gzip.

Priorities

Trong trường hợp đăng ký nhiều Filter và Interceptor, chúng ta mong muốn ứng dụng thực thi các Filter và Interceptor theo đúng thứ tự được chỉ định. Để làm được điều này, chúng ta sẽ sử dụng Annotation @Priority(number) trên các Fitler và Interceptor class.

  • ContainerRequestFilter, ClientRequestFilter, ReaderInterceptor, WriterInterceptor : được sắp thứ tự ưu tiên tăng dần. Số nhỏ được thực thi trước.
  • ContainerResponseFilter, ClientResponseFilter : được sắp thứ tự ưu tiên giảm dần. Số lớn được thực thi trước.

Ví dụ:

Tạo REST web service:


package com.gpcoder.api;

import javax.ws.rs.POST;
import javax.ws.rs.Path;

//URI:
//http(s)://<domain>:(port)/<YourApplicationName>/<UrlPattern in web.xml>/<path>
//http://localhost:8080/RestfulWebServiceExample/rest/priorities
@Path("/priorities")
public class PrioprityService {

	@POST
	public String create(String data) {
		return "Created " + data;
	}
}

Chúng ta có các Filter sau:


package com.gpcoder.filter;

import java.io.IOException;

import javax.annotation.Priority;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.ext.Provider;

@Priority(10)
@Provider
public class Priority1RequestFilter implements ContainerRequestFilter {

	@Override
	public void filter(ContainerRequestContext requestContext) throws IOException {
		System.out.println("#1 Priority1RequestFilter running ... ");
	}
}


@Priority(20)
@Provider
public class Priority2RequestFilter implements ContainerRequestFilter {

	@Override
	public void filter(ContainerRequestContext requestContext) throws IOException {
		System.out.println("#2 Priority2RequestFilter running ... ");
	}
}


@Priority(10)
@Provider
public class Priority1ResponseFilter implements ContainerResponseFilter {

	@Override
	public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
			throws IOException {
		System.out.println("#1 Priority1ResponseFilter running ... ");
	}
}


@Priority(20)
@Provider
public class Priority2ResponseFilter implements ContainerResponseFilter {

	@Override
	public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
			throws IOException {
		System.out.println("#2 Priority2ResponseFilter running ... ");
	}
}

Và các Interceptor sau:


package com.gpcoder.interceptor;

import java.io.IOException;

import javax.annotation.Priority;
import javax.ws.rs.ext.Provider;
import javax.ws.rs.ext.WriterInterceptor;
import javax.ws.rs.ext.WriterInterceptorContext;

@Priority(10)
@Provider
public class Priority1WriterInterceptor implements WriterInterceptor {

	@Override
	public void aroundWriteTo(WriterInterceptorContext context) throws IOException {
		System.out.println("#1 Priority1WriterInterceptor running ... ");
		context.proceed();
	}
}


@Priority(20)
@Provider
public class Priority2WriterInterceptor implements WriterInterceptor {

	@Override
	public void aroundWriteTo(WriterInterceptorContext context) throws IOException {
		System.out.println("#2 Priority2WriterInterceptor running ... ");
		context.proceed();
	}
}


@Priority(10)
@Provider
public class Priority1ReaderInterceptor implements ReaderInterceptor {

	@Override
	public Object aroundReadFrom(ReaderInterceptorContext context) throws IOException {
		System.out.println("#1 Priority1ReaderInterceptor running ... ");
		return context.proceed();
	}
}


@Priority(20)
@Provider
public class Priority2ReaderInterceptor implements ReaderInterceptor {

	@Override
	public Object aroundReadFrom(ReaderInterceptorContext context) throws IOException {
		System.out.println("#2 Priority1ReaderInterceptor running ... ");
		return context.proceed();
	}
}

Test API trên, chúng ta có kết quả sau:

Trên đây là toàn bộ những lý thuyết và ví dụ cơ bản về sử dụng Filter và Interceptor với Jersey. Đây là phần rất là hay, nếu áp dụng tốt sẽ giúp chúng ta đỡ tốn công sức rất là nhiều. Mọi thứ đều được xử lý một cách tự động và thống nhất trên tất cả request/ response. Hy vọng bài viết giúp ích cho các bạn, hẹn gặp lại ở các bài viết tiếp theo!

Tài liệu tham khảo:

  • https://jersey.github.io/documentation/latest/filters-and-interceptors.html
  • https://www.baeldung.com/jersey-filters-interceptors
5.0
06
Nếu bạn thấy hay thì hãy chia sẻ bài viết cho mọi người nhé! Và Donate tác giả

Shares

Chuyên mục: Java Webservice, REST Được gắn thẻ: Interceptor, Jersey, REST, Webservice

Rest Web service: Filter và Interceptor với Jersey 2.x (P1)
Tìm hiểu về xác thực và phân quyền trong ứng dụng

Có thể bạn muốn xem:

  • Rest Web service: Filter và Interceptor với Jersey 2.x (P1) (25/06/2019)
  • Làm thế nào để Test Jersey Rest API với JUnit? (22/08/2019)
  • Giới thiệu Feign – Tạo ứng dụng Java RESTful Client không thể đơn giản hơn (22/07/2019)
  • SOAP Web service: Upload và Download file sử dụng MTOM trong JAX-WS (06/06/2019)
  • Tìm hiểu về Web Service (21/05/2019)

Bình luận

bình luận

Tìm kiếm

Bài viết mới

  • Clean code 13/01/2024
  • Giới thiệu CloudAMQP – Một RabbitMQ server trên Cloud 02/10/2020
  • Kết nối RabbitMQ sử dụng Web STOMP Plugin 19/06/2020
  • Sử dụng publisher confirm trong RabbitMQ 16/06/2020
  • Sử dụng Dead Letter Exchange trong RabbitMQ 13/06/2020

Xem nhiều

  • Hướng dẫn Java Design Pattern – Factory Method (98059 lượt xem)
  • Hướng dẫn Java Design Pattern – Singleton (97700 lượt xem)
  • Giới thiệu Design Patterns (87764 lượt xem)
  • Lập trình đa luồng trong Java (Java Multi-threading) (86433 lượt xem)
  • Giới thiệu về Stream API trong Java 8 (83839 lượt xem)

Nội dung bài viết

  • 1 Jersey Interceptor
  • 2 Thứ tự thực thi Filter và Interceptor
  • 3 Name binding
  • 4 Dynamic binding
  • 5 Priorities

Lưu trữ

Thẻ đánh dấu

Annotation Authentication Basic Java Behavior Pattern Collection Creational Design Pattern Cấu trúc điều khiển Database Dependency Injection Design pattern Eclipse Exception Executor Service Google Guice Gson Hibernate How to Interceptor IO Jackson Java 8 Java Core JDBC JDK Jersey JMS JPA json JUnit JWT Message Queue Mockito Multithreading OOP PowerMockito RabbitMQ Reflection Report REST SOAP Structuaral Pattern Swagger Thread Pool Unit Test Webservice

Liên kết

  • Clean Code
  • JavaTpoint
  • Refactoring Guru
  • Source Making
  • TutorialsPoint
  • W3Schools Online Web Tutorials

Giới thiệu

GP Coder là trang web cá nhân, được thành lập với mục đích lưu trữ, chia sẽ kiến thức đã học và làm việc của tôi. Các bài viết trên trang này chủ yếu về ngôn ngữ Java và các công nghệ có liên quan đến Java như: Spring, JSF, Web Services, Unit Test, Hibernate, SQL, ...
Hi vọng góp được chút ít công sức cho sự phát triển cộng đồng Coder Việt.

Donate tác giả

Tìm kiếm các bài viết của GP Coder với Google Search

Liên hệ

Các bạn có thể liên hệ với tôi thông qua:
  • Trang liên hệ
  • Linkedin: gpcoder
  • Email: contact@gpcoder.com
  • Skype: ptgiang56it

Follow me

Copyright 2025 © GP Coder · All Rights Reserved · Giới thiệu · Chính sách · Điều khoản · Liên hệ ·

Share

Blogger
Delicious
Digg
Email
Facebook
Facebook messenger
Flipboard
Google
Hacker News
Line
LinkedIn
Mastodon
Mix
Odnoklassniki
PDF
Pinterest
Pocket
Print
Reddit
Renren
Short link
SMS
Skype
Telegram
Tumblr
Twitter
VKontakte
wechat
Weibo
WhatsApp
X
Xing
Yahoo! Mail

Copy short link

Copy link