2014-12-25 39 views
3

中公開HttpServletResponse我有一個RESTful服務器實現以及一個用於客戶端調用的庫,全部使用JAX-RS。服務器組件分爲接口FooResource和實施FooResourceService在實現中設置JAX-RS響應標頭,而不會在接口

爲了使客戶端和服務器庫共享REST風格的路徑和其他定義,我想給FooResource接口拆分爲自己的項目:

@Path(value = "foo") 
public interface FooResource { 

    @GET 
    public Bar getBar(@PathParam(value = "{id}") int id) { 

我想設置一些標題的響應。一個簡單的方法來做到這一點是在方法簽名中使用@Context HttpServletResponse

public Bar getBar(@PathParam(value = "{id}") int id, @Context HttpServletResponse servletResponse) { 

但問題是,這暴露了該接口實現細節。更具體地說,它突然要求我的REST定義項目(它在客戶端和服務器庫之間共享)拉入依賴關係---客戶端不需要(或期望)的東西。

我的RESTful資源服務實現如何在不拉動資源接口中的依賴關係的情況下設置HTTP響應頭?

我看到one post建議我注入HttpServletResponse作爲類成員。但是如果我的資源服務實現是單例,這將如何工作?它是否使用某種帶有線程本地代理的代理或者可以計算出正確的servlet響應的東西,即使單線程類被多個線程同時使用?還有其他解決方案嗎?

回答

3

正確的答案似乎是注入在執行的成員變量的HttpServletResponse,因爲我注意到, another post已經指出。

@Context //injected response proxy supporting multiple threads 
private HttpServletResponse servletResponse; 

即使peeskillet表明,對於新澤西州的半官方列表中沒有列出HttpServletResponse作爲代理能夠類型之一,當我通過代碼追蹤至少的RESTEasy似乎是創建一個代理(org.jbos[email protected]xxxxxxxx )。所以據我所知,單線程成員變量的線程安全注入似乎正在發生。

-2
@Path("/foo") 
public interface FooResource { 

    @GET 
    @Path("{id}") 
    public Response getBar(@PathParam("id") int id) { 
     Bar bar = new Bar(); 
     //Do some logic on bar 
     return Response.ok().entity(bar).header("header-name", "header-value").build() 
    } 
} 

返回bar實例的,狀態碼200和報頭header-name與值header-value JSON表示。它看起來應該是沿着線:

{ 
    "bar-field": "bar-field-value", 
    "bar-field-2": "bar-field-2" 
} 
+2

我不想在簽名中'Response'回報。我想要簽名中的一個'Bar'返回。 –

+2

我的瀏覽器沒有做軟件開發。我的開發人員是。我想創建一個乾淨的API,它在語義上指示返回的內容。我想將JAX-RS特定項目分解爲註釋和實現代碼。 –

2

所以注射HttpServletResponse似乎是一個沒有去。只有某些可代理類型可以注入單例。我相信完整列表如下:

HttpHeaders, Request, UriInfo, SecurityContext 

在JAX-RS規範這在一定程度上指出,但澤西參考指南

的例外存在的具體要求中解釋更清楚甚至可以注入構造函數或類字段的對象。對於這些對象,運行時將注入能夠同時服務更多請求的代理。這些請求對象是HttpHeaders,Request,UriInfo,SecurityContext。這些代理可以使用@Context註釋注入。

SecurityContext可能是澤西特定的,因爲它沒有在規範中說明,但我不確定。

現在,上面提到的這些類型對你來說並沒有多大作用,因爲它們都是請求上下文,沒有設置響應。

儘管一個想法是使用javax.ws.rs.container.ContainerResponseFilter以及HttpHeaders來設置臨時請求標頭。您可以通過傳遞給filter方法的ContainerRequestContext訪問該標題。然後,只需通過ContainerResponseContext設置響應標題,並傳遞給filter方法。如果頭部不是特定於該資源方法的上下文,則更容易。只需在過濾器中設置標題即可。

但是,假設標題是依賴於資源的方法的執行。然後,你可以不喜歡

@Singleton 
@Path("/singleton") 
public class SingletonResource { 

    @Context 
    javax.ws.rs.core.HttpHeaders headers; 

    @GET 
    public String getHello() { 

     String result = resultFromSomeCondition(new Object()); 
     headers.getRequestHeaders().putSingle("X-HELLO", result); 
     return "Hello World"; 
    } 

    private String resultFromSomeCondition(Object condition) { 
     return "World"; 
    } 
} 

然後ContainerResponseFilter可能是這個樣子

@Provider 
public class SingletonContainerResponseFilter 
          implements ContainerResponseFilter { 

    @Override 
    public void filter(ContainerRequestContext crc, 
      ContainerResponseContext crc1) throws IOException { 
     String header = crc.getHeaderString("X-HELLO"); 
     crc1.getHeaders().putSingle("X-HELLO", "World"); 
    } 
} 

而剛剛所以只有單班通過這個過濾器運行,我們可以簡單地用一個@NameBinding註釋

import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 
import javax.ws.rs.NameBinding; 

@NameBinding 
@Target(ElementType.TYPE) 
@Retention(RetentionPolicy.RUNTIME) 
public @interface SingletonHeader {} 

... 

@SingletonHeader 
public class SingletonResource { 

... 

@SingletonHeader 
public class SingletonContainerResponseFilter 
         implements ContainerResponseFilter { 

這是我能想到的來處理這種情況的唯一途徑。


資源:

+0

看到我的其他[回覆](http://stackoverflow.com/a/27648777/421049)在這裏。我試過了,它似乎與RESTEasy一起工作。 –

+1

所以它的工作原理,當你做'@ Singleton'註解包掃描,但是當你用'getSingletons註冊()'的'Application'類,當它失敗(我得到了NPE)的。在後一種情況下,對於Jersey,我只會得到一個異常,例如「不在請求範圍內」。 「@Singleton」仍然與澤西島失敗。對於任何遇到此問題的其他人,只需再花費一些費用。 –

+0

儘管如此,如果容器要處理注入,爲什麼在'getSingletons()'中實例化它不起作用。 –