具有 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']
我想编写一个 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']