我试图在运行时改变HTTP GET方法的RequestMapping注解的值--。你好 (它返回一个简单的字符串)在一个休息服务类中--。S.A.S.R.R.Controller.
在hello方法的@RequestMapping注解中定义的uri的值是 "hello{name}". 我可以在运行时将注解的值改为 "hi{name}" 在SpringRestController类的构造函数中使用反射。
我能够通过在一个用@PostConstruct注解的init方法中打印注解的值来验证修改后的值,也能够在另一个控制器中打印。然而,当我试图在浏览器中访问GET方法时:用修改后的值----。http:/localhost:9090spring-boot-resthiPradeep。 (行不通)
与原值 - http:/localhost:9090spring-boot-resthelloPradeep。 (行得通)
我希望HTTP GET方法hello能够在运行时使用修改后的路径值进行访问--------。"hi{name}" 而不是原来的路径值 - "hello{name}". P.S - 这是我们的需求,需要这样做,以便@RequestMapping的值可以在外部配置,而无需修改源代码。 下面是代码 - SpringRestController.java
package com.example.spring.rest.controller;
import javax.annotation.PostConstruct;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.spring.rest.custom.annotations.ConfigurableRequestMapping;
import com.example.spring.rest.reflection.ReflectionUtils;
@RestController
@RequestMapping("/rest")
public class SpringRestController {
public SpringRestController() {
RequestMapping rm = SpringRestController.class.getAnnotation(RequestMapping.class);
System.out.println("Old annotation : " + rm.value()[0]);
RequestMapping rmNew = new ConfigurableRequestMapping("/rest");
ReflectionUtils.alterAnnotationValueJDK8_v2(SpringRestController.class, RequestMapping.class, rmNew);
RequestMapping rmModified = SpringRestController.class.getAnnotation(RequestMapping.class);
System.out.println("Constructor -> New annotation : " + rmModified.value()[0]);
}
@RequestMapping(value = "/hello/{name}")
public String hello(@PathVariable String name) {
System.out.println("Name : " + name);
return "Hello " + name;
}
@PostConstruct
private void init(){
System.out.println("Annotations initialization post construct.");
RequestMapping rmModified = SpringRestController.class.getAnnotation(RequestMapping.class);
System.out.println("Init method -> New annotation : " + rmModified.value()[0]);
}
}
改变注解值的代码--
ReflectionUtils.java
package com.example.spring.rest.reflection;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.springframework.web.bind.annotation.RequestMapping;
import com.example.spring.rest.controller.SpringRestController;
import com.example.spring.rest.custom.annotations.ConfigurableRequestMapping;
import com.example.spring.rest.utils.PropertyReader;
public class ReflectionUtils {
@SuppressWarnings("unchecked")
public static Object changeAnnotationValue(Annotation annotation, String key, Object newValue){
Object handler = Proxy.getInvocationHandler(annotation);
Field f;
try {
f = handler.getClass().getDeclaredField("memberValues");
} catch (NoSuchFieldException | SecurityException e) {
throw new IllegalStateException(e);
}
f.setAccessible(true);
Map<String, Object> memberValues;
try {
memberValues = (Map<String, Object>) f.get(handler);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
Object oldValue = memberValues.get(key);
if (oldValue == null || oldValue.getClass() != newValue.getClass()) {
throw new IllegalArgumentException();
}
memberValues.put(key,newValue);
return oldValue;
}
}
这是不可能在运行时改变注解值的,因为Spring已经注册了这个值。除了好奇你到底想实现什么之外,请随意使用多个 @PathVariable
参数,并自行处理评估。
// Either hardcoded values or loaded from elsewhere
private static List<String> GREETINGS = Arrays.asList("Hello", "Hi");
...
@GetMapping(value = "/{greeting}/{name}")
public String greeting(@PathVariable String greeting, @PathVariable String name) {
System.out.println("Name : " + name);
if (GREETINGS.stream().anyMatch(greeting::equalsIgnoreCase)) {
return greeting + " " + name;
}
throw new ResponseStatusException(HttpStatus.BAD_REQUEST,
"Unknown greeting " + greeting, e);
}
此外,REST API端点的意义是要成为 可预见. 你想达到的目的似乎与之相悖。你可以有多个端点,如 /hi/{name}
和 /hello/{name}
然而,在这种特殊情况下,要么是多个参数的使用是正确的,要么是下面这个尊重了 资源 并使用 @RequestParam
. 我宁愿用这种方式设计,因为 问候语 是资源。
/greeting?greeting={greeting}&name={name}
/greeting?greeting=Hello&name=Pradeep%20Prabhakaran