具有 Java EE/Wildfly 的单页应用程序:服务器端配置

Single page application with Java EE/Wildfly: server-side configuration

我想编写一个 SPA,在客户端使用 AngularJS,在服务器端使用 Java EE。如果我理解正确的话,前端的想法是创建一个默认页面(我们称之为 index.html)并实现路由以交换该默认页面的各个部分。因此,对于每个请求,都会加载默认页面,并且路由逻辑会根据上下文路径替换其部分:

<!-- index.html -->
<html>
    <body>
        <!-- this block is replaced depending on context -->
        <div ng-view></div>
    </body>
</html>

<!-- page one -->
<div>
    <h1>Page One</h1>
    <a href="/specific">Some specific stuff</a>
</div>

<!-- page two -->
<div>
    <h1>Page Two</h1>
</div>

现在,路由逻辑可能是这样的:

angular.module('myApp', [])
    .config(['$routeProvider', function ($routeProvider) {
        $routeProvider
            .when('/', {templateUrl: 'pages/pageOne.html'})
            .when('/someSpecific', {templateUrl: 'pageTwo.html'})
            .otherwise({redirectTo: '/'});
    }
]);

问题是,如何将其与 Java EE 和 Wildfly 服务器实例结合使用?如果我将 index.html 声明为欢迎页面并且什么都不做,像 http://website.org/someSpecificContext 这样的直接调用将失败,因为没有页面映射到路径(也不应该),所以没有页面也没有 angular 代码将被加载。如果我在 servlet 过滤器中从每个可能的子路径重定向到 index.html,那么路径信息将丢失,因此每次调用都将在索引页面结束。也许这是一个愚蠢的新手问题,但我真的被困在这里,非常感谢任何帮助。

好的,我就是这样处理的。这是独立于服务器的,您更改的唯一文件在您的 Java EE 项目中:

  • 将所有文件放在适当的目录中:

    / (project's sources root)
    |
     -> js/
     -> css/
     -> webpages/
     -> etc
    
  • 实施新的javax.servlet.Filter:

    public class FilterAccess implements Filter {
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            if (!(request instanceof HttpServletRequest)) {
                return;
            }
            HttpServletRequest req = (HttpServletRequest) request;
    
            if (isAllowed(req)) {
                chain.doFilter(request, response);
            } else { // forward every other request to index page
                req.getRequestDispatcher("/pages/index.html").forward(request, response);
            }
        }
    
        private boolean isAllowed(HttpServletRequest req) {
            List<String> allowed = Arrays.asList("/webpages", "/js", "/css", ...);
            for (String path : allowed) {
                if (req.getServletPath().startsWith(path)) {
                    return true;
                }
            }
            return false;
        }
    }
    
  • web.xml文件中绑定:

    <filter>
        <filter-name>FilterAccess</filter-name>
        <filter-class>package.for.FilterAccess</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>FilterAccess</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    

基本上,这个想法是将对不在允许目录之一中的资源的每个请求转发到主页。您还可以根据需要重新实现 isAllowed 函数,例如检查请求的 URL 是否以 .js 结尾以允许 javascript 文件等。此外,代码不是很干净,可以将允许的路径声明为常量,甚至将它们移动到外部资源文件等,但无论如何你明白了 ;-)

不过,我还不会接受我自己的回答,因为我仍然不知道在使用 Java EE 构建单页应用程序时这是否是正确的方法。

我个人为此使用 undertow 重写处理程序。不幸的是,没有很多关于此功能的文档。您可以找到信息 here and also here。您基本上必须重写只有 Angular 知道的 html 5 个 url,但是当 Angular 询问时,您必须使用服务器端 REST 组件(我想您正在使用 REST)进行响应用于后端数据。我的 REST 资源位于 /api 根路径下。这是将 undertow-handlers.conf 文件放置在 WEB-INF 文件夹中的示例:

regex['(.*/order/?.*?$)'] and not regex['(.*/api.*)'] -> rewrite['/index.html']
regex['(.*/billing/?.*?$)'] and not regex['(.*/api.*)'] -> rewrite['/index.html']