gpt4 book ai didi

java - 使用自定义注释扩展类级别 RequestMapping

转载 作者:行者123 更新时间:2023-11-30 10:12:24 27 4
gpt4 key购买 nike

我想在我的 Spring Boot 应用程序中创建一个自定义注释,它总是向我的类级别 RequestMapping 路径 添加一个前缀

我的 Controller :

import com.sagemcom.smartvillage.smartvision.common.MyApi;
import org.springframework.web.bind.annotation.GetMapping;

@MyApi("/users")
public class UserController {

@GetMapping("/stackoverflow")
public String get() {
return "Best users";
}

}

我的自定义注释

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RestController
@RequestMapping(path = "/api")
public @interface MyApi {

@AliasFor(annotation = RequestMapping.class)
String value();

}

目标:最后像这样的映射:/api/users/stackoverflow

注意事项:

  • server.servlet.context-path 不是一个选项,因为我想创建其中几个
  • 我使用的是 Spring Boot 2.0.4 版

最佳答案

我没能为这个问题找到一个优雅的解决方案。但是,这有效:

稍微修改了注释,因为改变 value 的行为变得更加困难。

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RestController
@RequestMapping
public @interface MyApi {

@AliasFor(annotation = RequestMapping.class, attribute = "path")
String apiPath();

}

Bean 注释处理器

import com.sagemcom.smartvillage.smartvision.common.MyApi;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;

@Component
public class MyApiProcessor implements BeanPostProcessor {

private static final String ANNOTATIONS = "annotations";
private static final String ANNOTATION_DATA = "annotationData";

public Object postProcessBeforeInitialization(@NonNull final Object bean, String beanName) throws BeansException {
MyApi myApi = bean.getClass().getAnnotation(MyApi.class);
if (myApi != null) {
MyApi alteredMyApi = new MyApi() {

@Override
public Class<? extends Annotation> annotationType() {
return MyApi.class;
}

@Override
public String apiPath() {
return "/api" + myApi.apiPath();
}

};
alterAnnotationOn(bean.getClass(), MyApi.class, alteredMyApi);
}
return bean;
}

@Override
public Object postProcessAfterInitialization(@NonNull Object bean, String beanName) throws BeansException {
return bean;
}

@SuppressWarnings("unchecked")
private static void alterAnnotationOn(Class clazzToLookFor, Class<? extends Annotation> annotationToAlter, Annotation annotationValue) {
try {
// In JDK8 Class has a private method called annotationData().
// We first need to invoke it to obtain a reference to AnnotationData class which is a private class
Method method = Class.class.getDeclaredMethod(ANNOTATION_DATA, null);
method.setAccessible(true);
// Since AnnotationData is a private class we cannot create a direct reference to it. We will have to manage with just Object
Object annotationData = method.invoke(clazzToLookFor);
// We now look for the map called "annotations" within AnnotationData object.
Field annotations = annotationData.getClass().getDeclaredField(ANNOTATIONS);
annotations.setAccessible(true);
Map<Class<? extends Annotation>, Annotation> map = (Map<Class<? extends Annotation>, Annotation>) annotations.get(annotationData);
map.put(annotationToAlter, annotationValue);
} catch (Exception e) {
e.printStackTrace();
}
}

}

Controller :

import com.sagemcom.smartvillage.smartvision.common.MyApi;
import org.springframework.web.bind.annotation.GetMapping;

@MyApi(apiPath = "/users")
public class UserController {

@GetMapping("/stackoverflow")
public String get() {
return "Best users";
}

}

关于java - 使用自定义注释扩展类级别 RequestMapping,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51897285/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com