主要是因為我必須在xml中配置它。 如果您曾經做過JSF項目,那么您就會知道這是您稍后要做的事情。 或永遠不會。 最后一個選項是我看到的很多東西。 重寫將改變這一點。 程序化,易于使用和高度可定制的。 正是我想要的。

入門
從其中一個RedHat家伙那里獲得的東西入門非常容易。 啟動NetBeans,創建一個新的基于Maven的Webapp,將JSF和Primefaces添加到混合中并在GlassFish上運行。 向應用程序添加重寫魔術的第一步是向項目添加重寫依賴項。
<dependency><groupId>org.ocpsoft.rewrite</groupId><artifactId>rewrite-servlet</artifactId><version>1.1.0.Final</version></dependency>
這還不夠,因為我將它與JSF一起使用,您還需要jsf-integration。
<dependency><groupId>org.ocpsoft.rewrite</groupId><artifactId>rewrite-integration-faces</artifactId><version>1.1.0.Final</version></dependency>
接下來實現您自己的ConfigurationProvider。 這是發生大多數魔術的核心部分。現在我們將其稱為TricksProvider,我們還將擴展抽象的HttpConfigurationProvider。 一個簡單的第一個版本如下所示:
public class TricksProvider extends HttpConfigurationProvider
{@Overridepublic int priority(){return 10;}@Overridepublic Configuration getConfiguration(final ServletContext context){return ConfigurationBuilder.begin().addRule(Join.path("/").to("/welcomePrimefaces.xhtml"));}
}
現在,您必須注冊您的ConfigurationProvider。 為此,您可以在應用程序/ META-INF / services /文件夾中添加一個名為org.ocpsoft.rewrite.config.ConfigurationProvider的簡單文本文件。 向其添加ConfigurationProvider實現的標準名稱,即可完成操作。 如果您啟動應用程序。
重寫基礎
復制上述提供程序時,您隱式添加了第一個重寫規則。 通過請求http:// host:8080 / yourapp /,您將直接轉到NetBeans生成的Primefaces歡迎頁面。 所有規則都基于相同的原則。 每個規則都由一個條件和一個運算組成。 類似“如果發生X,則執行Y”。 重寫知道兩種不同的規則。 一些預配置的(加入)以“ addRule()”開頭,而流暢的接口以defineRule()開頭。 這有點令人困惑,因為下一個主要版本將棄用defineRule()并將其重命名為addRule()。 因此,您發現的大多數示例(尤其是最新主干中的測試用例)都無法在1.1.0.Final中使用。 重寫知道兩個不同的方向。 入站和出站。 入站很有可能像您知道的每個重寫引擎(例如mod_rewrite)一樣工作。 請求到達并被轉發或重定向到規則中定義的資源。 出站方向幾乎沒有。 它基本上在HttpServletRequest的encodeURL()方法中具有一個鉤子,并重寫您頁面中的鏈接(如果它們完全是在encodeURL的幫助下呈現的)。 JSF開箱即用。 如果您打算將其與JSP一起使用,則必須確保自己調用它。
用一些魔法將.html轉發到.xhtml
讓我們看一下您可以用重寫做的一些事情。 首先,我們將以下內容添加到TricksProvider中:
.defineRule()
.when(Direction.isInbound()
.and(Path.matches("{name}.html").where("name").matches("[a-zA-Z/]+")))
.perform(Forward.to("{name}.xhtml"));
這是一條規則,用于檢查入站請求,并檢查所有與正則表達式模式[a-zA-Z /] +確認的補丁匹配{name} .html,并將其轉發到{name} .xhtml文件。
如果執行此規則,則對http:// host:8080 / yourapp / something.html的所有請求最終都將轉發到something.xhtml。 現在,您的用戶將不再知道您在下面使用的是花哨的JSF內容,并認為您正在使用html :)如果請求的URL與正則表達式不匹配,例如類似http:// host:8080 / yourapp / something123.html根本不會轉發,如果您的應用程序中不存在something123.html,您最終將收到404錯誤。
改寫出站鏈接
相反,您還可以添加以下規則:
.defineRule()
.when(Path.matches("test.xhtml")
.and(Direction.isOutbound()))
.perform(Substitute.with("test.html"))
你想像這是在做什么,對嗎? 如果您的facelet包含以下內容:
<h:outputLink value="test.xhtml">Normal Test</h:outputLink>
呈現給用戶的鏈接將被重寫為test.html。 這是您永遠需要的出站鏈接的最基本操作。 大多數魔術都發生在入站鏈接上。 看到encodeURL()掛鉤的作用范圍非常有限,這并不讓人感到意外。
OutputBuffer
重寫中最令人驚訝的東西稱為OutputBuffer。 至少直到我們正在使用的發行版為止。 它會在2.0中重命名,但現在讓我們簡單地看一下您可以做什么。 OutputBuffer是您對響應的了解。 在響應真正到達客戶瀏覽器之前,您想對響應做什么。 考慮轉換標記? 轉換CSS? 甚至GZIP壓縮? 太好了,這正是您所能做的。 讓我們實現一個簡單的ZipOutputBuffer
public class ZipOutputBuffer implements OutputBuffer {private final static Logger LOGGER = Logger.getLogger(ZipOutputBuffer.class.getName());@Overridepublic InputStream execute(InputStream input) {String contents = Streams.toString(input);LOGGER.log(Level.FINER, "Content {0} Length {1}", new Object[]{contents, contents.getBytes().length});byte[] compressed = compress(contents);LOGGER.log(Level.FINER, "Length: {0}", compressed.length);return new ByteArrayInputStream(compressed);}public static byte[] compress(String string) {ByteArrayOutputStream os = new ByteArrayOutputStream(string.length());byte[] compressed = null;try {try (GZIPOutputStream gos = new GZIPOutputStream(os)) {gos.write(string.getBytes());} compressed = os.toByteArray();os.close();} catch (IOException iox) {LOGGER.log(Level.SEVERE, "Compression Failed: ", iox);}return compressed;}
}
如您所見,我在弄亂一些流,并使用java.util.zip.GZIPOutputStream縮小通過此方法接收的流。 接下來,我們必須將相關規則添加到TricksProvider中:
.defineRule()
.when(Path.matches("/gziptest").and(Direction.isInbound()))
.perform(Forward.to("test.xhtml")
.and(Response.withOutputBufferedBy(new ZipOutputBuffer())
.and(Response.addHeader("Content-Encoding", "gzip"))
.and(Response.addHeader("Content-Type", "text/html"))))
入站規則(我們不愿意在此處重寫頁面中的鏈接..因此必須入站),該規則將ZipOutputBuffer添加到Response中。 還要注意額外的響應標頭(兩個),除非您想讓瀏覽器抱怨我混在一起的內容:)就是這樣。 現在,請求http:// host:8080 / yourapp / gziptest提供了具有GZIP壓縮功能的te??st.xhtml。 那是2,6KB和1.23 KB! 不到尺寸的一半! 使用流和byte []并不是很方便。 而且我不確定這是否可以在較大的頁面大小上使用內存碎片,但是如果您沒有壓縮過濾器或者只需要壓縮應用程序的單個部分,這是一個簡單的解決方法。
通過重寫增強安全性
但這還不是您能做的:您還可以通過重寫來增強安全性。 林肯發表了關于用重寫保護您的應用程序的精彩文章。 關于如何使用此功能,有很多可能的示例。 我想到了一個用例,其中不想使用歡迎文件功能,而是希望單獨分派用戶。 在執行此操作時,我還將檢查他們的路徑,并檢查他們輸入的內容是否惡意。 您可以使用.matches()條件或使用自定義約束來執行此操作。 將以下內容添加到TricksProvider中:
Constraint<String> selectedCharacters = new Constraint<String>() {@Overridepublic boolean isSatisfiedBy(Rewrite event,EvaluationContext context, String value) {return value.matches("[a-zA-Z/]+");}};
并定義以下規則:
.defineRule()
.when(Direction.isInbound()
.and(Path.matches("{path}").where("path").matches("^(.+)/$")
.and(Path.captureIn("checkChar").where("checkChar").constrainedBy(selectedCharacters))))
.perform(Redirect.permanent(context.getContextPath() + "{path}index.html"))
另一個入站修改。 檢查路徑是否具有文件夾模式,并將其捕獲到根據自定義約束進行檢查的變量中。 大! 現在,您已經有了保存和輕松轉發的機制。 現在,所有http:// host:8080 / yourapp / folder /請求都被重寫為http:// host:8080 / yourapp / index.html。 如果您從上方查看其他規則,那么.html將被轉發到.xhtml……,您就完成了!
底線
我非常喜歡重寫。 與配置prettyfaces的xml文件相比,這感覺要容易得多,在使用林肯和Christian的第一步中,我真的很享受Lincoln和Christian的支持。 我很好奇2.0即將推出的產品,我希望我能為規則配置獲得更多調試輸出,以便了解正在發生的事情。 默認值是空,并且找到具有工作規則的條件的正確組合可能非常棘手。 尋找完整的資源? 在github上找到它們 。 很高興閱讀您的經歷。
GlassFish部分在哪里?
哦耶。 我在標題中提到了吧? 那應該更像是默認值。 我正在使用最新的GlassFish 3.1.2.2運行所有程序,因此可以確保它可以正常運行。 NetBeans目前為7.2 ,如果尚未嘗試,則應嘗試一下。 我沒有遇到任何與GlassFish相關的問題,我很高興在此強調這一點。 做得好! 最后一句話:在瘋狂地實現OutputBuffer之前,請看一下您最喜歡的應用服務器所擁有的庫存。 GlassFish已經了解GZIP壓縮 ,因此可以將其打開! 在這里實施之前,請三思而后行是一個好主意。
參考: 重寫邊緣-充分利用它! 在GlassFish上! 來自我們的JCG合作伙伴 Markus Eisele在Java的企業軟件開發博客中。
翻譯自: https://www.javacodegeeks.com/2012/08/rewrite-to-edge-getting-most-out-of-it.html