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 (P1)

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

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

Trong bài này, chúng ta sẽ cùng tìm hiểu về Filter, Interceptor và một số cấu hình của Jersey 2.x. Filter và Interceptor có thể được sử dụng ở cả 2 phía Jersey Server và Jersey Client. Filter có thể được sử dụng để chỉnh sửa các dữ liệu đầu vào/ đầu ra từ các request và response, bao gồm: header, data (entity), parameter. 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.

Nội dung

  • 1 Jersey Filter
  • 2 Jersey Interceptor

Jersey Filter

Như đã giới thiệu, Filter có thể được sử dụng ở cả 2 phía Jersey Server và Jersey Client. Nó có thể được sử dụng để chỉnh sửa các dữ liệu đầu vào/ đầu ra (inbound/ outbound) từ các request và response, bao gồm: header, data (entity), parameter.

Jersey Server filter:

  • ContainerRequestFilter : sử dụng filter này khi cần thực hiện một số hành động trước khi resource method được thực thi. Chẳng hạn, chứng thực user trước khi truy cập resource.
  • ContainerResponseFilter: sử dụng filter này khi cần thực hiện một số hành động trước khi trả kết quả về client. Chẳng hạn, thêm một số thông header gửi về Client.
  • ContainerRequestFilter với Annotation @PreMatching:
    • ContainerRequestFilter mặc định là một post-matching filter, nghĩa là filter được áp dụng chỉ sau khi đã tìm thấy một resource method phù hợp để xử lý request, tức là sau request matching thực thi. Request matching là quá trình tìm resource method để thực thi dựa trên Path, HTTP Method và một và parameter khác. Khi post-matching request filter được gọi, các filter khác sẽ không làm ảnh hưởng đến xử lý resource method matching.
    • @PreMatching : là một request filter được thực thi trước khi request matching bắt đầu. Vì vậy nó có thể làm ảnh hưởng đến kết quả tìm kiếm một resource method thực thi. Chẳng hạn, chúng ta có thể thay đổi request method của Client từ PUT sang POST.

Jersey Client Filter:

  • ClientRequestFilter : sử dụng filter này khi cần thực hiện một số hành động trước khi gửi request lên server. Chẳng hạn, thêm token đã chứng thực lên server.
  • ClientResponseFilter : sử dụng filter này khi cần thực hiện một số hành động sau khi đã nhận response từ server trước khi phương thức ở Client nhận kết quả.

Tạo REST Web service

OrderService.java


package com.gpcoder.api;

import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Response;

import com.gpcoder.model.Order;

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

	@GET
	@Path("/{id}")
	public Response get(@PathParam("id") int id) {
		System.out.println("OrderService#get()");
		return Response.ok("OrderService#get()").build();
	}

	@POST
	public Response insert(Order order) {
		System.out.println("OrderService#insert()");
		return Response.ok("OrderService#insert()").build();
	}

	@PUT
	public Response update(Order order) {
		System.out.println("OrderService#update()");
		return Response.ok("OrderService#update()").build();
	}

	@DELETE
	@Path("/{id}")
	public Response delete(@PathParam("id") int id) {
		System.out.println("OrderService#delete()");
		return Response.ok("OrderService#delete()").build();
	}
}

Tạo Server Filter

Tạo ContainerRequestFilter chứng thực user: nếu HTTP request là DELETE thì cần được chứng thực. Nếu chưa được chứng thực thì sẽ trả về Client status Response.Status.UNAUTHORIZED.

AuthorizationRequestFilter.java


package com.gpcoder.filter;

import java.io.IOException;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;

@Provider
public class AuthorizationRequestFilter implements ContainerRequestFilter {

	@Override
	public void filter(ContainerRequestContext requestContext) throws IOException {
		System.out.println("AuthorizationRequestFilter running ... ");

		// Must be logged-in to perform the delete action
		if ("DELETE".equals(requestContext.getMethod()) 
				&& !hasToken(requestContext)) {
			Response response = Response.status(Response.Status.UNAUTHORIZED) //
					.entity("User cannot access the resource.") //
					.build();
			requestContext.abortWith(response);
		}
	}

	private boolean hasToken(ContainerRequestContext requestContext) {
		// Extract Authorization header details
		String authorizationHeader = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
		if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer")) {
			return false;
		}
		// Extract the token
		String token = authorizationHeader.substring("Bearer".length()).trim();
		System.out.println("token: " + token);
		return token != null && token.trim().length() > 0;
	}
}

Lưu ý: chúng ta cần sử dụng @Provider hoặc gọi phương thức register() trong ResourceConfig để đăng ký với Jersey sử dụng Filter này.

Tạo ContainerResponseFilter thêm một vài thông tin header trước khi trả kết quả về Client:

PoweredByResponseFilter.java


package com.gpcoder.filter;

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.ext.Provider;

@Provider
public class PoweredByResponseFilter implements ContainerResponseFilter {

	@Override
	public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
			throws IOException {
		System.out.println("PoweredByResponseFilter running ... ");
		responseContext.getHeaders().add("X-Api-Version", "2.x");
		responseContext.getHeaders().add("X-Powered-By", "api.gpcoder.com");
	}
}

Tạo @PreMatching ContainerRequestFilter để tự động chuyển hướng request của Client từ HTTP PUT sang HTTP POST.

PreMatchingFilter.java


package com.gpcoder.filter;

import java.io.IOException;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.PreMatching;
import javax.ws.rs.ext.Provider;

@Provider
@PreMatching
public class PreMatchingFilter implements ContainerRequestFilter {

	@Override
	public void filter(ContainerRequestContext requestContext) throws IOException {
		System.out.println("PreMatchingFilter running ... ");
		if (requestContext.getMethod().equals("PUT")) {
			System.out.println("Change PUT methods to POST");
			requestContext.setMethod("POST");
		}
	}
}

Test Server Filter

Test @GET http://localhost:8080/RestfulWebServiceExample/rest/orders/1

Mở browser và truy cập địa chỉ: http://localhost:8080/RestfulWebServiceExample/rest/orders/1

Mở cửa sổ console của server, bạn sẽ thấy thứ tự thực thi của các filter và request/ response như sau:

Test @PUT http://localhost:8080/RestfulWebServiceExample/rest/orders

Như bạn thấy, request từ Client là PUT, nhưng được filter chuyển sang POST.

Test @DELETE http://localhost:8080/RestfulWebServiceExample/rest/orders/1

Như bạn thấy, request đã không được chấp nhận và response trả về với status Status.UNAUTHORIZED.

Tạo Client Filter

Tạo ClientRequestFilter để tự động thêm Token đã được chứng thực trước khi gửi request lên server.

CheckClientRequestFilter.java


package com.gpcoder.filter;

import java.io.IOException;

import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.ClientRequestFilter;
import javax.ws.rs.core.HttpHeaders;

public class CheckClientRequestFilter implements ClientRequestFilter {

	@Override
	public void filter(ClientRequestContext requestContext) throws IOException {
		System.out.println("CheckClientRequestFilter running ... ");
		String authorization = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
		if (authorization == null || authorization.trim().isEmpty()) {
			requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, "Bearer gpcoder-token");
		}
	}
}

Tạo ClientResponseFilter để thêm thông tin header sau khi nhận được response từ server.

CheckClientResponseFilter.java


package com.gpcoder.filter;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.ClientResponseContext;
import javax.ws.rs.client.ClientResponseFilter;

public class CheckClientResponseFilter implements ClientResponseFilter {

	@Override
	public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) {
		System.out.println("CheckClientResponseFilter running ... ");
		responseContext.getHeaders().add("X-Test-Client", "gpcoder client filter");
		System.out.println(LocalDateTime.now().format(DateTimeFormatter.ofPattern("dd/MM/yyyy hh:mm:ss")));
	}
}

Test Client Filter

Trong ví dụ này, tôi sẽ tạo request HTTP DELETE. API delete trên server yêu cầu xác thực mới được thực thi. Do đó, phía Client cần phải gửi thông tin token đã xác thực. Chúng ta sẽ xem 2 cách gửi thông tin xác thực như sau:

  • Sử dụng Invocation.Builder để thêm header.
  • Sử dụng Filter

package com.gpcoder.client;

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.Invocation;
import javax.ws.rs.client.WebTarget;
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.gpcoder.filter.CheckClientRequestFilter;
import com.gpcoder.filter.CheckClientResponseFilter;

public class OrderServiceClient {

	public static final String API_URL = "http://localhost:8080/RestfulWebServiceExample/rest/orders";
	public static final String API_TOKEN = "gpcoder-token";

	public static void main(String[] args) {
		callApiWithoutFilter();
		System.out.println("------");
		callApiWithFilter();
	}

	public static void callApiWithFilter() {
		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 CheckClientRequestFilter());
		clientConfig.register(new CheckClientResponseFilter());

		Client client = ClientBuilder.newClient(clientConfig);
		WebTarget target = client.target(API_URL).path("1");

		Invocation.Builder invocationBuilder = target.request(MediaType.APPLICATION_JSON_TYPE);
		// Don't need to add this line because it's already added automatically by CheckClientRequestFilter
		// invocationBuilder.header("Authorization", "Bearer " + API_TOKEN);

		final Response response = invocationBuilder.delete();
		System.out.println("Header added by CheckClientResponseFilter: " + response.getHeaderString("X-Test-Client"));
		System.out.println("Call delete() successful with the result: " + response.readEntity(String.class));
	}

	public static void callApiWithoutFilter() {
		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));

		Client client = ClientBuilder.newClient(clientConfig);
		WebTarget target = client.target(API_URL).path("1");

		Invocation.Builder invocationBuilder = target.request(MediaType.APPLICATION_JSON_TYPE);
		invocationBuilder.header("Authorization", "Bearer " + API_TOKEN);

		String result = invocationBuilder.delete(String.class);
		System.out.println("Call delete() successful with the result: " + result);
	}
}

Chạy ứng dụng Client, chúng ta có kết quả như sau:

Console ở Client:

Console ở Server:

Jersey Interceptor

Bài viết khá là dài nên mình sẽ tách phần Interceptor ra ở một bài viết khác. Các bạn xem tiếp tại đây.

Tài liệu tham khảo:

  • https://jersey.github.io/documentation/latest/filters-and-interceptors.html
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: HTTP Status Code và xử lý ngoại lệ RESTful web service với Jersey 2.x
Rest Web service: Filter và Interceptor với Jersey 2.x (P2)

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

  • Giới thiệu SOAP UI và thực hiện test Web Service (30/05/2019)
  • REST Web service: Basic Authentication trong Jersey 2.x (03/07/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)
  • Cài đặt và sử dụng Swagger UI (07/08/2019)
  • Sử dụng Swagger UI trong jersey REST WS project (15/08/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 (98058 lượt xem)
  • Hướng dẫn Java Design Pattern – Singleton (97699 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 Filter
  • 2 Jersey Interceptor

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