2012-03-28 41 views
7

Giả cảnh quan ứng dụng sau:JSF. giải pháp viết lại URL cần

+-----------------+ 
| App server  | 
+-----------------+ 
|     |         +-------+ 
| ear1   |         |  | 
| +-web1 (/ctx1) +--<-- http://localhost/ctx1/xxx/ --+  +--<-- http://www.domain.com/xxx/ 
|     |         |  | 
|     |         | proxy | 
| ear2   |         |  | 
| +-web2 (/ctx2) +--<-- http://localhost/ctx2/yyy/ --+  +--<-- http://abc.domain.com/yyy/ 
|     |         |  | 
+-----------------+         +-------+ 

Như bạn thấy, proxy (nginx trong trường hợp của tôi) được chuyển tiếp yêu cầu đến một trường hợp máy chủ ứng dụng duy nhất, do đó có nhiều mô-đun web với các đường dẫn ngữ cảnh khác nhau. Tất nhiên tôi không muốn máy chủ công cộng của tôi để lộ rễ nội bộ và proxy làm công việc của nó tốt, kết thúc tốt đẹp và unwraps http yêu cầu, vv Nhưng vẫn còn một vấn đề lớn: JSF-tạo mã html (liên kết, css, js tài nguyên, hình thức hành động) chứa đường dẫn ngữ cảnh, /ctx1/ctx2 trong trường hợp của tôi. Đó là những gì tôi muốn tránh.

Tôi không có giải pháp tại thời điểm này ngoại trừ việc sử dụng ngày càng nhiều trường hợp khác nhau (tên miền) của máy chủ ứng dụng, khiến tài nguyên phần cứng của tôi biến mất. Như tôi đã hiểu, tôi cần mở rộng các ứng dụng JSF của mình bằng một số trình bao bọc, có khả năng được đăng ký trong faces-config.xml, điều này sẽ loại bỏ tiền tố ngữ cảnh trong html được tạo ra. Bất kỳ giải pháp nào khác cũng được hoan nghênh.

Hãy chỉ cho tôi đi đúng hướng.

Trả lời

4

Tôi đang đăng giải pháp có thể hữu ích cho những người khác phải đối mặt với cùng một vấn đề. Tất cả tôi cần làm là thực hiện của riêng tôi javax.faces.application.ViewHandler và đăng ký nó trong faces-config.xml:

public class CustomViewHandler extends ViewHandlerWrapper { 
    private ViewHandler wrappped; 

    public CustomViewHandler(ViewHandler wrappped) { 
    super(); 
    this.wrappped = wrappped; 
    } 

    @Override 
    public ViewHandler getWrapped() { 
    return wrappped; 
    } 

    @Override 
    public String getActionURL(FacesContext context, String viewId) { 
    String url = super.getActionURL(context, viewId); 
    return removeContextPath(context, url); 
    } 

    @Override 
    public String getRedirectURL(FacesContext context, String viewId, Map<String, List<String>> parameters, boolean includeViewParams) { 
    String url = super.getRedirectURL(context, viewId, parameters, includeViewParams); 
    return removeContextPath(context, url); 
    } 

    @Override 
    public String getResourceURL(FacesContext context, String path) { 
    String url = super.getResourceURL(context, path); 
    return removeContextPath(context, url); 
    } 

    private String removeContextPath(FacesContext context, String url) { 
    ServletContext servletContext = (ServletContext) context.getExternalContext().getContext(); 
    String contextPath = servletContext.getContextPath(); 
    if("".equals(contextPath)) return url; // root context path, nothing to remove 
    return url.startsWith(contextPath) ? url.substring(contextPath.length()) : url; 
    } 
} 

faces-config.xml:

<faces-config xmlns="http://java.sun.com/xml/ns/javaee" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd" 
       version="2.0"> 
    <application> 
    <view-handler>test.CustomViewHandler</view-handler> 
    </application> 
</faces-config> 
+2

Lưu ý: Điều này cũng có thể được thực hiện với một 'Filter' và ít hơn một nửa số mã. – BalusC

+0

@BalusC, hôm nay tôi chuẩn bị triển khai giải pháp Lọc của bạn, nhưng đã sợ hãi vì thực tế là bài đăng của bạn đã bị xóa)) – Osw

+0

Tôi chỉ xóa nó vì nó không đáng để nỗ lực. – BalusC

5

Bạn có thể sử dụng OCPsoft Rewrite URLRewriteFilter cho điều này (không PrettyFaces hiện nay, nhưng bạn có thể sử dụng cả hai cùng một lúc cho đến khi họ chính thức tham gia cùng nhau sau khi phát hành PrettyFaces 4 - Viết lại là dự án cốt lõi cho PrettyFaces 4)

Làm điều gì đó như thế này khá đơn giản bằng cách sử dụng một tội lỗi quy tắc cấu hình gle. Bạn rõ ràng có thể fiddle nếu quy tắc này là quá nghiêm ngặt hoặc quá chung chung.

.defineRule() 
.when(URL.matches("{prefix}" + context.getContextPath() + "{suffix}") 
.perform(Substitute.with("{prefix}{suffix}")) 

Kiểm tra trang web viết lại. Nó khá dễ dàng để thiết lập. http://ocpsoft.org/rewrite/

+0

Xin chào Lincoln! Nó cũng sẽ hoạt động cho css, js và các tài nguyên khác mà tôi có trên các trang của mình? – Osw

+0

Miễn là các liên kết đó được hiển thị qua JSF và không được mã hóa cứng trong HTML, thì có, tuyệt đối. Nếu không, bạn có thể thiết lập các quy tắc bổ sung để xử lý kịch bản đó. – Lincoln

1

Tôi đang đối mặt với cùng một vấn đề và đã thử giải pháp của bạn. Mặc dù nó ít nhiều hoạt động, nhưng vẫn còn một vài trục trặc. Và thành thật mà nói, nó cảm thấy giống như chống lại các triệu chứng như trái ngược với chữa bệnh.

Vì vậy, đây là những gì cuối cùng làm việc cho tôi:

Thay vì thiết lập triển khai ngoài thông qua các con đường, tôi được phân công mỗi triển khai đến cảng riêng của mình:

foo.war <-- http://localhost:8080/ -- | Proxy | <-- http://www.foo.com -- | Client | 
bar.war <-- http://localhost:8181/ -- | Proxy | <-- http://www.bar.com -- | Client | 

Bằng cách này, cả hai triển khai có thể sử dụng/như đường dẫn ngữ cảnh của họ, do đó không cần phải chỉnh sửa đường dẫn ngữ cảnh.

Để đạt được điều này, bạn không nhất thiết phải chạy hai máy chủ ứng dụng. Trong trường hợp của tôi (Wildfly 10,0) đó là đủ để xác định hai máy chủ undertow trong cấu hình wildfly, đều có riêng máy chủ ảo và http người nghe, như vậy:

<server name="foo-server"> 
    <http-listener name="foo-listener" proxy-address-forwarding="true" socket-binding="foo-http"/> 
    <host name="foo-host" default-web-module="foo.war" alias="localhost, foo.com, wwww.foo.com"/> 
</server> 
<server name="bar-server"> 
    <http-listener name="bar-listener" proxy-address-forwarding="true" socket-binding="bar-http"/> 
    <host name="bar-host" default-web-module="bar.war" alias="localhost, bar.com, wwww.bar.com"/> 
</server> 

<socket-binding name="foo-http" port="${jboss.http.port:8080}"/> 
<socket-binding name="bar-http" port="${jboss.http.port:8181}"/> 

Bạn cũng sẽ cần một JBoss-web.xml trong dự án của bạn:

<?xml version="1.0" encoding="UTF-8"?> 
<jboss-web> 
    <server-instance>foo-server</server-instance> 
    <virtual-host>foo-host</virtual-host> 
    <context-root>/</context-root> 
</jboss-web> 

Hai máy chủ là cần thiết vì bạn không thể thêm ổ cắm ràng buộc vào máy chủ ảo. Vì vậy, có một chi phí nhỏ ở đây, nhưng không đáng kể so với chạy hai máy chủ ứng dụng hoàn chỉnh.

Sửa 1:

Nó chỉ xảy ra với tôi rằng nó có lẽ thậm chí không cần phải sử dụng các cổng khác nhau và sử dụng một máy chủ undertow mỗi deplyoment có lẽ là không cần thiết nữa.

Vì proxy có thể chuyển tiếp máy chủ theo yêu cầu của máy khách đến máy chủ ứng dụng, nên đảm bảo có thể chọn máy chủ ảo thích hợp thông qua tham số bí danh.

Về cơ bản, proxy sẽ chuyển tiếp mọi yêu cầu tới foo.com hoặc bar.com đến localhost: 8080 và để AS sắp xếp mọi thứ.

tôi đã không kiểm tra này, nhưng đây là làm thế nào nó có thể làm việc (một lần nữa, đây là cho Wildfly 10,0):

<server name="default-server"> 
    <http-listener name="http" proxy-address-forwarding="true" socket-binding="http"/> 
    <host name="foo-host" default-web-module="foo.war" alias="foo.com, wwww.foo.com"/> 
    <host name="bar-host" default-web-module="bar.war" alias="bar.com, wwww.bar.com"/> 
</server> 

Và JBoss-web.xml sẽ mất thẻ server:

<?xml version="1.0" encoding="UTF-8"?> 
<jboss-web> 
    <virtual-host>foo-host</virtual-host> 
    <context-root>/</context-root> 
</jboss-web> 

Trong trường hợp tác phẩm này sẽ không có chi phí liên quan nào cả.

Chỉnh sửa 2:

Chỉ cần thử nghiệm cách tiếp cận đơn giản - vâng, nó hoạt động :)

Các vấn đề liên quan