Reputation: 4755
I have created a Java EE application that uses JSF. In my web
directory, I have a file named index.xhtml
. My goal is to serve different content on this webpage based upon the parent directory's name.
For example:
http://localhost:8080/myapp/1/index.xhtml
would print You accessed through "1"
.
http://localhost:8080/myapp/1234/index.xhtml
would print You accessed through "1234"
.
I do not want to create a directory for every single possible number; it should be completely dynamic.
Additionally, I need my navigation rules to still be usable. So if I have a navigation rule such as this:
<navigation-rule>
<display-name>*</display-name>
<from-view-id>*</from-view-id>
<navigation-case>
<from-outcome>index</from-outcome>
<to-view-id>/index.xhtml</to-view-id>
<redirect />
</navigation-case>
</navigation-rule>
Then if I am in the directory 1234
, it will still redirect to the index.xhtml
page within 1234
.
Is this possible? How can I do this?
Upvotes: 4
Views: 558
Reputation: 1108632
In order to forward /[number]/index.xhtml
to /index.xhtml
whereby [number]
is been stored as a request attribute, you need a servlet filter. The doFilter()
implementation can look like this:
@WebFilter("/*")
public class YourFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
String[] paths = request.getRequestURI().substring(request.getContextPath().length()).split("/");
if (paths.length == 3 && paths[2].equals("index.xhtml") && paths[1].matches("[0-9]{1,9}")) {
request.setAttribute("directory", Integer.valueOf(paths[1]));
request.getRequestDispatcher("/index.xhtml").forward(req, res);
}
else {
chain.doFilter(req, res);
}
}
// ...
}
It makes sure the number matches 1 to 9 latin digits and stores it as a request attribute identified by directory
and finally forwards to /index.xhtml
in context root. If nothing maches, it simply continues the request as if nothing special happened.
In the /index.xhtml
you can access the number by #{directory}
.
<p>You accessed through "#{directory}"</p>
Then, in order to make sure JSF navigation (and <h:form>
!) keeps working, you need a custom view handler which overrides the getActionURL()
to prepend the URL with the path represented by directory
request attribute, if any. Here's a kickoff example:
public class YourViewHandler extends ViewHandlerWrapper {
private ViewHandler wrapped;
public YourViewHandler(ViewHandler wrapped) {
this.wrapped = wrapped;
}
@Override
public String getActionURL(FacesContext context, String viewId) {
String actionURL = super.getActionURL(context, viewId);
if (actionURL.endsWith("/index.xhtml")) {
Integer directory = (Integer) context.getExternalContext().getRequestMap().get("directory");
if (directory != null) {
actionURL = actionURL.substring(0, actionURL.length() - 11) + directory + "/index.xhtml";
}
}
return actionURL;
}
@Override
public ViewHandler getWrapped() {
return wrapped;
}
}
In order to get it to run, register in faces-config.xml
as below.
<application>
<view-handler>com.example.YourViewHandler</view-handler>
</application>
This is also pretty much how JSF targeted URL rewrite engines such as PrettyFaces work.
Upvotes: 4