2012-06-07 19 views
2

爲了提供正確的瀏覽器緩存,我想擺脫conversationContext參數,即Apache MyFaces Orchestra添加到每個請求中,以便請求到css文件。如何刪除靜態資源的Orchestra轉換上下文參數?

由於Bozho建議,我已經實現了一個設置Orchestra正在查找的屬性的過濾器。

public class ResourceFilter implements Filter { 

@Override 
public void doFilter(ServletRequest request, ServletResponse theResponse, FilterChain theChain) throws IOException, ServletException { 
    if(shouldNotAppendConversation(request)) { 
     request.setAttribute(RequestParameterServletFilter.REQUEST_PARAM_FILTER_CALLED, Boolean.TRUE); 
    } 

    theChain.doFilter(request, theResponse); 
} 

private boolean shouldNotAppendConversation(ServletRequest theRequest) { 
    HttpServletRequest aRequest = (HttpServletRequest) theRequest; 
    String aPath = aRequest.getRequestURI(); 
    if(aPath.endsWith(".css.jsf")) { 
     return true; 
    } 

    return false; 
} 

@Override 
public void init(FilterConfig theFilterConfig) throws ServletException { 
} 

@Override 
public void destroy() { 
} 
} 

這不起作用的參數仍然附加到每個請求。在調試時,我發現過濾器首先被jsf網站的請求命中。當然,我想在該請求中包含conversation context,因此過濾器會將請求直接轉發到鏈中的下一個過濾器。點擊過濾器的下一個請求(通常是對css文件的請求)已經包含在請求中的conversation context

奇怪的是,如果我修改過濾器到總是設置屬性,所有的請求將不會有conversation context屬性。但這意味着,conversation context也不包括在jsf網站的請求中(但應該)。

我注意到,在生成的jsf網站的HTML鏈接到CSS文件也包含conversation context屬性或不依賴於過濾器的實現。我想這是因爲第二個請求已經包含了conversation context參數?

我不明白爲什麼Orchestra會將conversation context參數附加到每個請求上,而不僅僅是未設置屬性的請求。

如何實現過濾器正常工作?

回答

3

下一個請求(例如,對於CSS文件)在您的頁面請求之後觸擊您的過濾器已經包含conversationContext參數,因爲這是此頁面在上一個請求中呈現此資源的URL的方式。

因此,應該在渲染時對conversationContext進行控制。以下解決方案適用於JSF 2(我正在使用Mojarra 2.1.11,myfaces-orchestra-core20 1.5,RichFaces 4.1.0.Final)。一個特殊的Servlet過濾器正在做什麼,但我們自己的包裝包裝HttpServletResponse

public class RfOrchestraParamControlFilter implements Filter { 
    ... 
    @Override 
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 
     response = new RfOrchestraParamControlResponseWrapper((HttpServletResponse)response); 
     chain.doFilter(request, response); 
    } 
    ... 
} 

的響應包裝測試網址進行編碼以便being a richfaces resource並打開樂團ConversationRequestParameterProvider的分離模式在當前線程的時間編碼:

package ... 
import javax.faces.application.ResourceHandler; 
import org.richfaces.resource.ResourceHandlerImpl; 
import org.apache.myfaces.orchestra.conversation.ConversationRequestParameterProvider; 

public class RfOrchestraParamControlResponseWrapper extends HttpServletResponseWrapper { 

    public RfOrchestraParamControlResponseWrapper(HttpServletResponse httpServletResponse) { 
     super(httpServletResponse); 
    } 

    @Override 
    public String encodeURL(String url) { 
     if (url.contains(ResourceHandler.RESOURCE_IDENTIFIER) || url.contains(ResourceHandlerImpl.RICHFACES_RESOURCE_IDENTIFIER)) { 
     boolean current = ConversationRequestParameterProvider.isInSeparationMode(); 
     /* Disable conversationContext parameter in current thread for the time of rendering link to a resource */ 
     ConversationRequestParameterProvider.setInSeparationMode(true); 

     String result = super.encodeURL(url); 

     /* Restore */ 
     ConversationRequestParameterProvider.setInSeparationMode(current); 
     return result; 
     } 
     else return super.encodeURL(url); 
    } 

} 

(我有,作爲一個資源的上下文路徑和servlet路徑發生預先考慮通過URL測試URL時使用String.contains(),而不是String.startsWith()

但是,這一點都沒有幫助。原因是Orchestra使用自己的響應包裝發生在其RequestParameterFacesContextFactory中,並且在我們的過濾器被擊中後發生。通過這種方式,Orchestra的包裝器變成了我們的外部包裝器,這導致我們的包裝器接收到url太遲了,當url已被攔截並且conversationContext被追加。

爲了避免這種情況,我們有一種方法可以使我們的響應包裝器在樂團的外部,通過替換效果從RequestParameterFacesContextFactory攔截器與RequestParameterServletFilter其中實際上does the same work。不幸的是,使用另一個過濾器在我們不可能的地方並不完美,但我目前還沒有看到另一種方式。

所以,在web.xml把你的過濾器樂團之一:

<filter> 
    <filter-name>requestParameterFilter</filter-name> 
    <filter-class>org.apache.myfaces.orchestra.requestParameterProvider.RequestParameterServletFilter</filter-class> 
</filter> 
<filter> 
    <filter-name>myOrchestraFilter</filter-name> 
    <filter-class>mypkg.RfOrchestraParamControlFilter</filter-class> 
</filter> 

<filter-mapping> 
    <filter-name>requestParameterFilter</filter-name> 
    <servlet-name>Faces Servlet</servlet-name> 
</filter-mapping> 
<filter-mapping> 
    <filter-name>myOrchestraFilter</filter-name> 
    <servlet-name>Faces Servlet</servlet-name> 
</filter-mapping>