I'm working on a jsf project, and I have several xhtml pages which use the same template. The template contains the layout and the page header. I would like to know if it is possible to not reload the header when user navigates to another page, since it is always the same; and as it contains a couple of images it makes navigating unnecessarily slower.
One remark: I'm using a filter that adds the following headers to the response, for security reasons:
HttpServletResponse resp = (HttpServletResponse) response;
resp.setHeader("Cache-Control", "no-cache,no-store,must-revalidate"); // HTTP 1.1
resp.setHeader("Pragma", "no-cache"); // HTTP 1.0
resp.setDateHeader("Expires", 0); // Proxies.
Can it be done without removing those headers?
Thanks!
Damian
The template contains the layout and the page header. I would like to know if it is possible to not reload the header when user navigates to another page, since it is always the same;
This is only possible when using a HTML frame (not recommended) or when refreshing the page parts by Ajax requests instead of normal requests. However, the disadvantage is that you end up with unbookmarkable URLs.
and as it contains a couple of images it makes navigating unnecessarily slower.
If that is the real problem, then you need to instruct the browser to actually cache the images (and CSS and JS). So if you're setting those response headers on image/CSS/JS requests as well, then the browser is forced to reload them everytime. This is unnecessary and will indeed result in slow loading. You need to ensure that those headers are only set on JSF pages, so you need to ensure that the URL pattern of the filter matches JSF page requests only, e.g. *.jsf or *.xhtml and thus not /* or something.
See also:
Java EE Web application performance tips and tricks
Looking for a similar technique in my audio player to don't stop listenig during navigation. I just look at soundcloud site. U can refresh content in ajax and change url in javascript with window.history.pushState look here:
http://www.whatwg.org/specs/web-apps/current-work/multipage/history.html#dom-history-pushstate
It probably doesn't work with old browser...
Related
I think the title above is a bit confusing.
What I'm trying to achieve:
I have a jps page(located in WEB-INF) with a hyperlink in it that will call another jsp (in WEB-INF) via servlet.
I understand that this can be achieved using the following:
Go to this page
But because there will be lots of hyperlinks, my idea was to have a general servlet(OpenPagesServlet) to handle all those pages.
Something like this:
JSP page:
<% request.setAttribute("page", "page1.jsp");%>
Page 1
OpenPagesServlet in doGet method:
String page = (String) request.getAttribute("page");
request.getRequestDispatcher("/WEB-INF/" + page).forward(request, response);
I tried the code above and I get:
HTTP Status 404 - Not Found
type Status report
messageNot Found
descriptionThe requested resource is not available.
But if I try with session.setAttribute / sesion.getAttribute the code works fine, but I don't want to have sessions on each time I click on hyperlinks.
The other approach I found was to use:
Page 1
and inside the servlet:
String page = (String)request.getParameter("value");
request.getRequestDispatcher("/WEB-INF/" + page).forward(request, response);
It worked, but this approach is not good because the page can then be accessed directly using the url:
http://localhost:8080/WebApp/OpenPagesServlet?value=page1
So...my question is why request.setAttribute/request.getAttribute is returning 404?
Is there a different approach to achieve what I'm trying to do?
An HttpServletRequest and its attributes only live for the duration of one HTTP request/response cycle. After yo've set the attribute in the JSP, the JSP is rendered and sent as part of the HTTP response body. The Servlet container considers the request handled and clears its attributes. The attribute is now gone.
It is therefore no longer available in the next request that arrives after the user clicks the link.
The session attribute or request parameter is fine. Consider looking into the Front Controller pattern.
Also, consider using the core tag library (in particular the url tag) instead of scriptlets for constructing your links.
Currently I have three different apps deployed in the same AppServer. Their contexts are /appPortal, /appPortal/app1, /appPortal/app2
The app1 and app2 both have a common header which includes a jsp from appPortal like
<c:import url="/jsps/topHeader.jsp" context="/appPortal">
I tried to add some logic in this topHeader.jsp to redirect the user to another noaccess page who tried to access app1&app2 directly without login in the /appPortal but it doesn't work, and I don't want to add a filter to each application. What can I do, how can I make the redirection works?
Using a filter would be an ideal choice. But if you want to have it in JSP, try to keep the redirection logic before any HTML content is rendered.
"forward" and or "dispatcher". Those two words should be of use.
I would like to basically do what Jason asked for here
In one sentence, I would like the url bar to represent the state of the AJAX application so that I can allow to bookmark it as well as allow the user to return to the previous state by using the back/forward buttons in the browser.
The difference for me (From what Jason asked) is that I am using JSF 2.0.
I've read that JSF 2.0 added the ability to use get, but I am not sure what the correct way to use this.
Thanks for the help.
Further Clarification
If I understand correctly, to be able to bookmark specific states in the AJAX webapp I will have to use the location.hash. Am I correct? I'm trying to achieve a gmail-like behaviour in the sense that, while the app is complete AJAXified and no redirects occur, I can still use Back/Forward and bookmark (And that's why I would like the URL bar to be updated from the AJAX app itself and not through redirection)
Update
Just found this similar question
The difference for me (From what Jason asked) is that I am using JSF 2.0. I've read that JSF 2.0 added the ability to use get, but I am not sure what the correct way to use this.
Please note that this is not the same as maintaining the Ajax state. It usually happens by fragment identifiers (the part starting with # in URL, also known as hashbang). JSF doesn't offer builtin components/functionality for this. As far I have also not seen a component library which does that. You may however find this answer useful to get started with a homegrown hash fragment processor in JSF.
As to using GET requests, just use <h:link>, <h:outputLink> or even <a> to create GET links. You can supply request parameters in the h: components by <f:param>. E.g.
<h:link value="Edit product" outcome="product/edit">
<f:param name="id" value="#{product.id}" />
</h:link>
In the product/edit.xhtml page you can define parameters to set and actions to execute upon a GET request
<f:metadata>
<f:viewParam name="id" value="#{productEditor.id}" />
<f:event type="preRenderView" listener="#{productEditor.init}" />
</f:metadata>
In the request or view scoped bean associated with product/edit.xhtml page -in this example #{productEditor}-, you just define the properties and the listener method. The listener method will be executed after all properties are been gathered, converted, validated and updated in the model.
private Long id;
private Product product;
public void init() {
product = productService.find(id);
}
Normally you'd use AJAX to prevent complete page refreshes. AFAIK all current browsers would issue a page refresh if you change the base uri. Thus you would have to use the hash part as suggested in the question you provided.
We had a similar problem and did something like this:
We settled for the fact that users cannot bookmark the url.
For URLs that should be unique/bookmarkable we used different links that issue a redirect. Those URLs are provided in a sitemap.
For browser back, we added an intermediate page after login. This page does navigation and a redirect to the application. The navigation is stored in the session and when the server gets a navigation request (which can be a history back) the corresponding state is restored. A browser back opens that intermediate page which issues a redirect along with a navigation request on the server side.
I have a jsp search page (Search.jsp) and a result page (Result.jsp), both of them can choose search criteria. and then passed the parameters to a java controller file (Controller.java) to build a query string and performs query searching. The query string and searched results will be passed to Result.jsp for displaying.
Currently I use servletContext to remember the processed query string, and if users use Result.jsp to select search criteria, Controller.java will append such criteria to the existing query string. If I do a few searches using Result.jsp. For example, query string would display ((Query1) AND Query2) AND Query3 on the Result.jsp page. Then using the browser's back button to go back to the previous display page. For the same example, query string displays (Query1) AND Query2. Then if I do search again. The query string (((Query1) AND Query2) AND Query3) AND Query4 would be used. I know this is expected with my current implementation since Result.jsp does not do any modification with the processed query string.
However, I would like when user uses the browser Back button, for example, query string displays on the page as (Query1) AND Query2, and perform search, the query string should be ((Query1) AND Query2) AND Query4 in which the query string is build based on the current displayed query string on the Result.jsp page plus the current selection. How can I do that? It sounds quite simple but I have tried several ways of using the in Result.jsp to update the query string, but still couldn't get it right. Therefore I am wondering maybe my approach of using <c:set> is wrong. I would like to hear your suggestion. Thanks in advance.
Currently I use servletContext to remember the processed query string
Do you realize that the ServletContext is shared among all users/sessions who are visiting your webapplication? Once visitor X modifies it, the changes are reflected for all other visitors. Don't you rather want to store it in the HttpSession to keep the data visitor-specific?
See also:
Servlet lifecycle and multithreading
I want to use back button for some reason
I really have a hard time in understanding your functional requirement (the some reason part). But at least, since you'd like to have the back button to work properly, you'd like to use idempotent requests here. So, where applicable, replace POST by GET.
Whenever you'd like to refire a real HTTP request on the server instead of loading the page from browser's cache, you'd like to instruct the browser to not cache the pages by adding the following headers to the response:
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setDateHeader("Expires", 0); // Proxies.
You can do that in your controller or some Filter covering the url-pattern of interest.
See also:
Make sure that a webpage is not cached across all browsers
Webbrowser caching tutorial
How can I use Servlets to access the HTML uses of having JSP without having to have all my client-facing pages called *.jsp?
I would rather do this than using all the response.write() stuff because I think it is easier to read and maintain when it is all clean "HTML".
Is this is fair assesment?
EDIT: What I'm going for is having the Servlets output things to the screen without having to redirect to a .jsp file.
In this way, I could write all the JSP stuff, but when it comes time to display it, the page the URL the user sees is essentially, "http://blah.com/posts/post-id" which is the address of the servlet and not "http://blah.com/posts.jsp?pos=post-id".
But I would still write all presentation logic in an external .jsp.
Just hide the JSP away in /WEB-INF folder so that noone can access it directly and create a servlet which forwards the request to this JSP file. Don't do a redirect, else you will see the new URL being reflected in the address bar. E.g.
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String postId = request.getPathInfo();
// Do your business thing here. Any results can be placed in request scope. E.g.
request.setAttribute("post", post); // post is a bean containing information you'd like to display in JSP.
// Then forward request to JSP file.
request.getRequestDispatcher("/WEB-INF/posts.jsp").forward(request, response);
}
Map this servlet on an url-pattern of /posts/*.
In the /WEB-INF/posts.jsp make use of taglibs to control page flow and EL to access the data. E.g.
<h2>${post.title}</h2>
<p><fmt:formatDate value="${post.date}" type="date" /> - ${post.message}</p>
Finally just invoke the servlet by http://example.com/posts/postid. The /postid part will be available by HttpServletRequest#getPathInfo(). You need to parse the value yourself and do the business thing with it.
I'm not entirely sure what you're asking here. You can ge servlets themselves to write HTML, but that's not clean at all.
An alternative is to get your servlets to create HTML via a templating engine, such as Velocity or Freemarker. The syntax in the templates may be cleaner for your particular application, if less fully featured.
Back in ancient times (think '98...) this was called a "Model 2 architecture": a servlet received the request, processed it, and handed the request over to a JSP page that handled the view.
See this article for one example of how this is done, or simply search for "JSP Model 2".
Edit: for that, you can use RequestDispatcher.include() instead of forward() as described in the previous article. The rest should still be applicable.
If I understand correctly you want to hide *.jsp extension from user, right?
In that case when your Servlet redirects to a jsp page have it do this:
RequestDispatcher disp = request.getRequestDispatcher("hidden.jsp");
disp.forward(request,response);
By using Request Dispatcher instead of redirect you "hide" your .jsp extension behind the servlet name. However in case your JSP page redirects to another JSP page this won't work.
If you want the .jsp file to be visible use response.encodeURL or response.sendRedirect
I think you're looking for the Front Controller Pattern - this is the basis of "JSP Model 2" web apps (as #andri mentioned) and pretty much all the (hundreds?) of Java web frameworks.