Usage scenarios

User parameters, such as tenant ID, TID, userID, and Token, are transparently transmitted. These parameters have nothing to do with specific services, but they are necessary (for example, tenant ID, which needs to be passed in the database when data is dropped, but is basically not used in other business codes). If the parameters used as methods are passed down from layer to layer, redundancy and extensibility of the code are bound to be affected.

Let’s use tenant ids as an example throughout this article.

1. Use ThreadLocal with AOP

When an interface is requested, the TenantID can often be retrieved from the Token or user information. In this case, the request interceptor takes the user TenantID and puts it into the thread. Later, when the TenantID is needed, it is pulled directly from the thread, thus ensuring both simplicity and ease of use.

2. The Pom

This article uses the Ali thread tool.

<! --TTL-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>transmittable-thread-local</artifactId>
    <version>2.11.4</version>
</dependency>
Copy the code

3.RequestFilter

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.GenericFilterBean;

import javax.servlet.FilterChain;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/ * * *@author litongzero
 */
@Slf4j
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class TenantContextHolderFilter extends GenericFilterBean {

	@Override
	@SneakyThrows
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) {
		HttpServletRequest request = (HttpServletRequest) servletRequest;
		HttpServletResponse response = (HttpServletResponse) servletResponse;
    // Obtain the tenant ID from Token/Header/param
		String headerTenantId = request.getHeader("TENANT_ID");

		log.debug(The TENANT_ID "TenantContextHolderFilter | header is: {}", headerTenantId);

    // Define your own logic
		if(headerTenantId ! =null&& headerTenantId ! ="" && !headerTenantId.equals("null")) {
			TenantContextHolder.setTenantId(Integer.parseInt(headerTenantId));
    } else {
      / / the default value
			TenantContextHolder.setTenantId(0);
		}
		filterChain.doFilter(request, response);
    // The request is complete, be sure to clear the thread's own parameters.TenantContextHolder.clear(); }}Copy the code

4.TenantContextHolder

/ * * *@author litongzero
 */
@UtilityClass
public class TenantContextHolder {

	private final ThreadLocal<Integer> THREAD_LOCAL_TENANT = new TransmittableThreadLocal<>();

	/** * TTL sets the tenant ID<br/> *@param tenantId
	 */
	public void setTenantId(Integer tenantId) {
		THREAD_LOCAL_TENANT.set(tenantId);
	}

	/** * Get the tenant ID * in the TTL@return* /
	public Integer getTenantId(a) {
		return THREAD_LOCAL_TENANT.get();
	}

	/** * clear tenants from the current thread */ with caution
	public void clear(a) { THREAD_LOCAL_TENANT.remove(); }}Copy the code

5. Use

In specific Controller, the Service, the Mapper, as long as is the thread of the current request, can be used directly TenantContextHolder. GetTenantId () to obtain the tenant ID.