如何将自定义 headers 添加到 Spring Data Rest 中的特定资源
How to add custom headers to a specific resource in Spring Data Rest
我在 Spring Data Rest 中的一个实体有一个属性值,应该添加到响应的 header 中。如何做到这一点?
我已经找到了使用处理程序拦截器更改 default headers(对于所有响应)的方法。而且我还发现了关于版本、etag 和修改的东西..
这些都不是我想要的。
必须在 1 个 REST 资源上设置 header,并且该值取决于 instance/record。
例如:Person
具有属性 age
。每个对 Person REST 资源的请求(例如 GET /person/{id}
)必须 return age
的值作为 http header(例如:age:32
)。
提前致谢。
首先,您可以将拦截器绑定到特定路径,这样问题就解决了一半。
第二个问题是获取对已请求的 Person 资源的引用。您可以在此处查看使用 ThreadLocal:
public class PersonContext{
private static ThreadLocal<Person> context = new ThreadLocal<Person>();
public static Person getPerson(Person person){
return context.get();
}
public static void setPerson(Person person){
context.set(person);
}
public static void cleanUp(){
context.remove();
}
}
标准的 JPA 实体侦听器可用于将引用绑定到已加载的 Person:
public class PersonListener{
@PostLoad
public void setContext(Person person){
PersonContext.set(person);
}
}
可以在实体上注册实体侦听器:
@Entity
@EntityListeners(PersonListener.class)
public class Person(){
}
在拦截器中,您可以获得对绑定到当前线程上下文的 Person 的引用,并相应地设置 header:
public class PersonInterceptor extends HandlerInterceptorAdapter {
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
if(request.getMethod().equals("GET")){
Person person = PersonContext.getPerson();
response.addHeader("age", person.getAge());
}
PersonContext.cleanUp();
}
}
最后用 Spring 数据 Rest 注册你的拦截器:
@Bean
public MappedInterceptor myMappedInterceptor() {
return new MappedInterceptor(new String[]{"person/**"}, new PersonInterceptor());
}
问题:
- post 负载侦听器将在 Person 的每个负载上执行,即使在其他路径上也是如此,因此 clean-up 需要更好。在所有路径上注册第二个拦截器以处理 clean-up??
另一种方法可能是在拦截器中重新查询数据库。所以上面的内容可以用类似这样的拦截器代替:
public class PersonInterceptor extends HandlerInterceptorAdapter {
@Autowired
private PersonRepository repository;
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
super.postHandle(request, response, handler, modelAndView);
if(request.getMethod().equals("GET")){
Long personID = // Extract id by examining request.getServletPath();
Person person = repository.findOne(personID);
response.addHeader("age", person.getAge());
}
}
}
这会产生额外查询的开销,但这可能可以通过配置 OpenEntityManagerInViewFilter 来避免,这意味着它是从一级缓存中获取的。
根据我之前的回答,我可以看到最新版本的 SDR API 有一个方法 RepositoryRestMvcConfiguration#httpHeadersPreparer()
。
我可以看到此方法在 2.6.8 中可用,但在我当前使用的 2.5.10 版本中不可用。
看来你可以做类似的事情:
@Configuration
public class MyConfiguration extends RepositoryRestMvcConfiguration
{
@Override
public HttpHeadersPreparer httpHeadersPreparer()
{
HttpHeadersPreparer preparer = new HttpHeadersPreparer(){
@Override
public HttpHeaders prepareHeaders(PersistentEntityResource resource, Object value)
{
org.springframework.http.HttpHeaders headers = super.prepareHeaders(resource);
if(value instanceof Person){
headers.add("age", ((Person)value).getAge());
}
}
};
return preparer;
}
}
我在 Spring Data Rest 中的一个实体有一个属性值,应该添加到响应的 header 中。如何做到这一点?
我已经找到了使用处理程序拦截器更改 default headers(对于所有响应)的方法。而且我还发现了关于版本、etag 和修改的东西.. 这些都不是我想要的。
必须在 1 个 REST 资源上设置 header,并且该值取决于 instance/record。
例如:Person
具有属性 age
。每个对 Person REST 资源的请求(例如 GET /person/{id}
)必须 return age
的值作为 http header(例如:age:32
)。
提前致谢。
首先,您可以将拦截器绑定到特定路径,这样问题就解决了一半。
第二个问题是获取对已请求的 Person 资源的引用。您可以在此处查看使用 ThreadLocal:
public class PersonContext{
private static ThreadLocal<Person> context = new ThreadLocal<Person>();
public static Person getPerson(Person person){
return context.get();
}
public static void setPerson(Person person){
context.set(person);
}
public static void cleanUp(){
context.remove();
}
}
标准的 JPA 实体侦听器可用于将引用绑定到已加载的 Person:
public class PersonListener{
@PostLoad
public void setContext(Person person){
PersonContext.set(person);
}
}
可以在实体上注册实体侦听器:
@Entity
@EntityListeners(PersonListener.class)
public class Person(){
}
在拦截器中,您可以获得对绑定到当前线程上下文的 Person 的引用,并相应地设置 header:
public class PersonInterceptor extends HandlerInterceptorAdapter {
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
if(request.getMethod().equals("GET")){
Person person = PersonContext.getPerson();
response.addHeader("age", person.getAge());
}
PersonContext.cleanUp();
}
}
最后用 Spring 数据 Rest 注册你的拦截器:
@Bean
public MappedInterceptor myMappedInterceptor() {
return new MappedInterceptor(new String[]{"person/**"}, new PersonInterceptor());
}
问题:
- post 负载侦听器将在 Person 的每个负载上执行,即使在其他路径上也是如此,因此 clean-up 需要更好。在所有路径上注册第二个拦截器以处理 clean-up??
另一种方法可能是在拦截器中重新查询数据库。所以上面的内容可以用类似这样的拦截器代替:
public class PersonInterceptor extends HandlerInterceptorAdapter {
@Autowired
private PersonRepository repository;
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
super.postHandle(request, response, handler, modelAndView);
if(request.getMethod().equals("GET")){
Long personID = // Extract id by examining request.getServletPath();
Person person = repository.findOne(personID);
response.addHeader("age", person.getAge());
}
}
}
这会产生额外查询的开销,但这可能可以通过配置 OpenEntityManagerInViewFilter 来避免,这意味着它是从一级缓存中获取的。
根据我之前的回答,我可以看到最新版本的 SDR API 有一个方法 RepositoryRestMvcConfiguration#httpHeadersPreparer()
。
我可以看到此方法在 2.6.8 中可用,但在我当前使用的 2.5.10 版本中不可用。
看来你可以做类似的事情:
@Configuration
public class MyConfiguration extends RepositoryRestMvcConfiguration
{
@Override
public HttpHeadersPreparer httpHeadersPreparer()
{
HttpHeadersPreparer preparer = new HttpHeadersPreparer(){
@Override
public HttpHeaders prepareHeaders(PersistentEntityResource resource, Object value)
{
org.springframework.http.HttpHeaders headers = super.prepareHeaders(resource);
if(value instanceof Person){
headers.add("age", ((Person)value).getAge());
}
}
};
return preparer;
}
}