■カスタムアノテーション
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface NamespaceAwareTransactionTokenCheck {
String namespace() default ""; // デフォルトは空
}
■Aspectを利用してnamespaceを設定
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.JoinPoint;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Aspect
@Component
public class NamespaceTransactionTokenAspect {
private final HttpServletRequest request;
public NamespaceTransactionTokenAspect(HttpServletRequest request) {
this.request = request;
}
@Before("@annotation(namespaceAwareTransactionTokenCheck)")
public void setNamespace(JoinPoint joinPoint, NamespaceAwareTransactionTokenCheck namespaceAwareTransactionTokenCheck) {
// ヘッダーからtabIdを取得
String tabId = request.getHeader("X-Tab-ID");
if (tabId == null) {
tabId = "defaultTabId";
}
// namespaceを設定
String namespace = "namespace_for_" + tabId;
NamespaceContext.setNamespace(namespace);
System.out.println("Namespace set for token check: " + namespace);
}
}
■NamespaceContextの実装
public class NamespaceContext {
private static final ThreadLocal<String> namespaceHolder = new ThreadLocal<>();
public static void setNamespace(String namespace) {
namespaceHolder.set(namespace);
}
public static String getNamespace() {
return namespaceHolder.get();
}
public static void clear() {
namespaceHolder.remove();
}
}
■コントローラで利用
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyController {
@GetMapping("/api/transaction")
@NamespaceAwareTransactionTokenCheck
public String handleTransaction(@RequestHeader(value = "X-Tab-ID", required = false) String tabId) {
// 現在のnamespaceを取得
String namespace = NamespaceContext.getNamespace();
return "Transaction processed with namespace: " + namespace;
}
}
- 動作の仕組み
ブラウザのタブごとにtabIdを生成。
リクエストヘッダーにtabIdを含めてサーバーに送信。
アスペクトでtabIdを受け取り、namespaceを動的に設定。
@NamespaceAwareTransactionTokenCheckがnamespaceを利用してトランザクショントークンを検証。