How do I map URLs to resources instead of JSF pages? - jsf

I'm very used to Jax-RS and the ability to make data available to the caller through custom URLs like:
/bicycles/by_color/blue
by doing:
#Path("{searchCategory}/{searchParam}")
List<Item> get(#PathParam....
What is the equivalent in JSF? I have an application with a ReST API and would like to display a template page, grabbing a specific entity from the database according to part of the URL for the xhtml page to get data from that will be displayed.
I've seen examples with query parameters like '?id=5&pages=true' but nothing with URL mapping like '/5/true.' How do I accomplish this?

For those Googling for an actual answer to the question, PrettyFaces is one way of doing this. It does URL 'beautification,' which includes making elements of the URL's path into receivable parameters.
I'm going to give an example using JAX-RS, then the equivalent with PrettyFaces:
Jax-RS
#Path("user")
public class UserEndpoint{
#PersistenceContext
EntityManager em;
#GET
#Path("{userid}")
public UserEntity getUser(#PathParam("userid")long userId){
return em.find(UserEntity.class, userId);
}
}
JSF with PrettyFaces
Good help for it on here: http://www.ocpsoft.org/prettyfaces/
Backing Bean
#Named
public class UserViewController{
#PersistenceContext
EntityManager em;
public UserEntity getUser(){
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
Map<String, String> params = ec.getRequestParameterMap();
long userId = Long.valueOf(params.get("userid"));
return em.find(UserEntity.class, userId);
}
}
pretty-config.xml (special file that must be created inside the WEB-INF folder)
<pretty-config xmlns="http://ocpsoft.org/schema/rewrite-config-prettyfaces"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ocpsoft.org/schema/rewrite-config-prettyfaces
http://ocpsoft.org/xml/ns/prettyfaces/rewrite-config-prettyfaces.xsd">
<url-mapping id="view-user">
<pattern value="/user/#{userid}" />
<view-id value="/user/view.xhtml" />
</url-mapping>
</pretty-config>

Related

Display image from String Primefaces [duplicate]

I need to display images which reside outside of deploy folder in web application using JSF <h:graphicimage> tag or HTML <img> tag. How can I achieve that?
To the point, it has to be accessible by a public URL. Thus, the <img src> must ultimately refer a http:// URI, not something like a file:// URI or so. Ultimately, the HTML source is executed at enduser's machine and images are downloaded individually by the webbrowser during parsing the HTML source. When the webbrowser encounters a file:// URI such as C:\path\to\image.png, then it will look in enduser's own local disk file system for the image instead of the webserver's one. This is obviously not going to work if the webbrowser runs at a physically different machine than the webserver.
There are several ways to achieve this:
If you have full control over the images folder, then just drop the folder with all images, e.g. /images directly in servletcontainer's deploy folder, such as the /webapps folder in case of Tomcat and /domains/domain1/applications folder in case of GlassFish. No further configuration is necessary.
Or, add a new webapp context to the server which points to the absolute disk file system location of the folder with those images. How to do that depends on the container used. The below examples assume that images are located in /path/to/images and that you'd like to access them via http://.../images.
In case of Tomcat, add the following new entry to Tomcat's /conf/server.xml inside <Host>:
<Context docBase="/path/to/images" path="/images" />
In case of GlassFish, add the following entry to /WEB-INF/glassfish-web.xml:
<property name="alternatedocroot_1" value="from=/images/* dir=/path/to" />
In case of WildFly, add the following entry inside <host name="default-host"> of /standalone/configuration/standalone.xml ...
<location name="/images" handler="images-content" />
... and further down in <handlers> entry of the very same <subsystem> as above <location>:
<file name="images-content" path="/path/to/images" />
Or, create a Servlet which streams the image from disk to response:
#WebServlet("/images/*")
public class ImageServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String filename = request.getPathInfo().substring(1);
File file = new File("/path/to/images", filename);
response.setHeader("Content-Type", getServletContext().getMimeType(filename));
response.setHeader("Content-Length", String.valueOf(file.length()));
response.setHeader("Content-Disposition", "inline; filename=\"" + filename + "\"");
Files.copy(file.toPath(), response.getOutputStream());
}
}
If you happen to use OmniFaces, then the FileServlet may be useful as it also takes into account head, caching and range requests.
Or, use OmniFaces <o:graphicImage> which supports a bean property returning byte[] or InputStream:
#Named
#ApplicationScoped
public class Bean {
public InputStream getImage(String filename) {
return new FileInputStream(new File("/path/to/images", filename));
}
}
Or, use PrimeFaces <p:graphicImage> which supports a bean method returning PrimeFaces-specific StreamedContent.
#Named
#ApplicationScoped
public class Bean {
public StreamedContent getImage() throws IOException {
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
// So, we're rendering the view. Return a stub StreamedContent so that it will generate right URL.
return new DefaultStreamedContent();
}
else {
// So, browser is requesting the image. Return a real StreamedContent with the image bytes.
String filename = context.getExternalContext().getRequestParameterMap().get("filename");
return new DefaultStreamedContent(new FileInputStream(new File("/path/to/images", filename)));
}
}
}
For the first way and the Tomcat and WildFly approaches in second way, the images will be available by http://example.com/images/filename.ext and thus referencable in plain HTML as follows
<img src="/images/filename.ext" />
For the GlassFish approach in second way and the third way, the images will be available by http://example.com/context/images/filename.ext and thus referencable in plain HTML as follows
<img src="#{request.contextPath}/images/filename.ext" />
or in JSF as follows (context path is automatically prepended)
<h:graphicImage value="/images/filename.ext" />
For the OmniFaces approach in fourth way, reference it as follows
<o:graphicImage value="#{bean.getImage('filename.ext')}" />
For the PrimeFaces approach in fifth way, reference it as follows:
<p:graphicImage value="#{bean.image}">
<f:param name="filename" value="filename.ext" />
</p:graphicImage>
Note that the example #{bean} is #ApplicationScoped as it basically represents a stateless service. You can also make it #RequestScoped, but then the bean would be recreated on every single request, for nothing. You cannot make it #ViewScoped, because at the moment the browser needs to download the image, the server doesn't create a JSF page. You can make it #SessionScoped, but then it's saved in memory, for nothing.
See also:
Recommended way to save uploaded files in a servlet application
Simplest way to serve static data from outside the application server in a Java web application
Abstract template for a static resource servlet (supporting HTTP caching)
Show image as byte[] from database as graphic image in JSF page
Display dynamic image from database with p:graphicImage and StreamedContent
How to choose the right bean scope?
In order to achieve what you need using <h:graphicImage> or <img> tags, you require to create a Tomcat v7 alias in order to map the external path to your web app's context.
To do so, you will need to specify your web app's context. The easiest would be to define a META-INF/context.xml file with the following content:
<Context path="/myapp" aliases="/images=/path/to/external/images">
</Context>
Then after restarting your Tomcat server, you can access your images files using <h:graphicImage> or <img> tags as following:
<h:graphicImage value="/images/my-image.png">
or
<img src="/myapp/images/my-image.png">
*Note the context path is necessary for the tag but not for the
Another possible approach if you don't require the images to be available through HTTP GET method, could be to use Primefaces <p:fileDownload> tag (using commandLink or commandButton tags - HTTP POST method).
In your Facelet:
<h:form>
<h:commandLink id="downloadLink" value="Download">
<p:fileDownload value="#{fileDownloader.getStream(file.path)}" />
</h:commandLink>
</h:form
In your bean:
#ManagedBean
#ApplicationScope
public class FileDownloader {
public StreamedContent getStream(String absPath) throws Exception {
FileInputStream fis = new FileInputStream(absPath);
BufferedInputStream bis = new BufferedInputStream(fis);
StreamedContent content = new DefaultStreamedContent(bis);
return content;
}
}
}
In PrimeFaces you can implement your bean in this way:
private StreamedContent image;
public void setImage(StreamedContent image) {
this.image = image;
}
public StreamedContent getImage() throws Exception {
return image;
}
public void prepImage() throws Exception {
File file = new File("/path/to/your/image.png");
InputStream input = new FileInputStream(file);
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
setImage(new DefaultStreamedContent(input,externalContext.getMimeType(file.getName()), file.getName()));
}
In your HTML Facelet:
<body onload="#{yourBean.prepImage()}"></body>
<p:graphicImage value="#{youyBean.image}" style="width:100%;height:100%" cache="false" >
</p:graphicImage>
I suggest to set the attribute cache="false" in the graphicImage component.
In JSP
<img src="data:image/jpeg;base64,
<%= new String(Base64.encode(Files.readAllBytes(Paths.get("C:\\temp\\A.jpg"))))%>"/>
Packages are com.sun.jersey.core.util.Base64, java.nio.file.Paths and java.nio.file.Files.

javax.servlet.http.Part not being transfered to Server-side using <h:inputFile>

I am trying to use JSF 2.2 new to let the user upload a photografy to his profile. Anyway I need an Ajax behavior, which I achieved with the following snippet:
<h:form enctype="multipart/form-data">
<h:inputFile value="#{usuarioController.part}">
<f:ajax listener="#{usuarioController.uploadImage}"/>
</h:inputFile>
</h:form>
But at the moment my public void uploadImage() the javax.servlet.http.Part part still null..
This is the controller:
#Named(value="usuarioController")
#SessionScoped
public class UsuarioController extends GenericPersonificacaoCrudController<Usuario>{
private static final long serialVersionUID = 3233882970467365819L;
private Part part;
public void uploadImage(){
System.out.println(part);
}
public Part getPart() {
return part;
}
public void setPart(Part part) {
this.part = part;
}
}
I am using Mojarra 2.2.6 implementation of JSF with Tomcat + Weld CDI and Primefaces 5.1 which is unrelated to the question since I am using the native fileUpload component, but I am including just to let you know I also tried using it and it doesnt work with the mode="advanced" which use ajax, what make me wonder if it is some kind of incompatibility or conflict of the libraries I am using.
You're trying to access the file using the java representation of the <h:inputFile/> component; you should not be doing this. As you have it, file should be bound to an instance of javax.servlet.http.Part, from which you can get an InputStream. The rest is quite straightforward from that point. Your code would look something like this:
public Part file;
//getter and setter
public void uploadImagem(){
long fileSize = file.getSize();
byte[] fileStorage = new byte[fileSize];
BufferedInputStream bis = new BufferedInputStream(file.getInputStream);
bis.read(fileStorage);
//do whatever you want with the array.
}
Tip: You should also know that the Part also has a convenience method write() that allows you to write the file to a specified directory, directly

How to safely init a ViewScoped bean with URL GET request parameters? [duplicate]

This question already has answers here:
How do I process GET query string URL parameters in backing bean on page load?
(4 answers)
Closed 7 years ago.
I have a few managed bean (ViewScoped) that are currently initialized with data in the session. I would like to initialize them with a URL GET parameter so I can provide URLs with the entity ID I want to display in my view. Something like displayClient.xhtml?entityId=123.
Right now I am thinking of something like this in the getter of the view main entity :
public clientModel getclientM() {
if (this.clientM == null) {
// TODO: Check for empty, non-integer or garbage parameters...
// Anything exists to "sanitize" URL parameters?
int entityId = Integer.parseInt(FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("entityId"));
// I guess I should check here if the logged user is authorized to
// load client entity with this entityId... anything else to check?
this.clientM = this.clientS.find(entityId);
}
return this.clientM;
}
Any hint or suggestion of best practices would be greatly appreciated.
I'd think something along these lines are best practice:
displayclient.xhtml:
<f:metadata>
<f:viewParam name=“entityId”
value="#{bean.clientM}”
required="true"
converter=“clientModelConverter”
converterMessage="Bad request. Unknown ClientModel.”
requiredMessage="Bad request. Please use a link from within the system.">
</f:viewParam>
</f:metadata>
Converter:
#ManagedBean
#RequestScoped
public class ClientModelConverter implements Converter {
#EJB
private ClientService clientService;
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
// TODO: check if value is instanceof ClientModel
return String.valueOf(((ClientModel) value).getId());
}
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
// TODO: catch NumberFormatException and throw ConverterException
return clientService.find(Integer.valueOf(value));
}
}
Call the page with for example:
<h:link value=“Display” outcome="displayClient">
<f:param name=“entityId" value=“#{…}” />
</h:link>
or just a raw url for example displayClient.xhtml?entityId=123.
Heavily inspired by
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for? and
JSF 2.0 view parameters to pass objects.
Store entityId in session, for example SessionScoped Bean
In your View Scoped managed beans, add #PostConstruct method, where you will get entityId from session and populate data with this
I did something similar, for the same exact reason : Providing an external link to a jsf page.
In your ViewScoped bean, have a #PostConstruct method to force a fail-safe scan for the Get Param
#PostConstruct
public void scanEntityId(){
int entityId = 0; // or some other default value
try{
// Try to fetch entityId from url with GET
int entityId = Integer.getInteger(FacesContext.getExternalContext().getRequestParameterMap().get("entityId") );
}catch(Exception e){
// Did not find anything from GET
}
// TODO: do stuff using the entityId's value. e.g.:
if(entityId >0){
this.clientM = this.clientS.find(entityId);
}
}
Just make sure to handle the cases where the entityId var is not found in the Get params
If you want to link to that page from another xhtml page of the same app, you can use the f:param
<h:link value="Go in a page that uses thatViewScoped Bean"
outcome="#{thatViewScopedBean.takeMeToThatPage}" >
<f:param name="entityId" value="#{somebean.somevar.entityId}" />
</h:link>
A nice tutorial can also be found here
You might also like to see this answer, and this article to see more options and get a more clear view.

How to save theme in Primefaces

I want to use Primefaces ThemeSwitcher. I'm interested how I can save the selected theme when I reload the web application. For example how I can set the theme name as variable from database?
You won't be needing the ThemeSwitcher to effect the kind of persistence you're looking for.
Simply perform the database lookup for the theme in a ServletContextListener and then store the value in the servlet context, possibly overriding whatever you've set in the web.xml
public Class MyContextListener implements ServletContextListener{
public void contextInitialized(ServletContextEvent sce){
String selectedTheme = myThemeDAO.getConfiguredTheme();
sce.getServletContext().setInitParameter("primefaces.THEME",selectedTheme);
}
}
link your ThemeSwitcher component to a managedBean and add a listener linked to a ajax event:
<h:form id="form-theme">
<p:themeSwitcher id="defaultSwitcher" value="#{themeSwitcherBean.theme}">
<f:selectItems value="#{themeSwitcherBean.themes}" />
<p:ajax listener="#{themeSwitcherBean.saveTheme}" />
</p:themeSwitcher>
</h:form>
in your managedbean create the method who call saveTheme, that going to call a class to persist in database, and call the the class for the database when start to get the theme who had saved into the database:
#SessionScoped
#ManagedBean(name="themeSwitcherBean")
public class ThemeSwitcherBean implements Serializable{
private Map<String, String> themes;
private String theme;
private GuestPreferences gp;
private void setGp(GuestPreferences gp) {
this.gp = gp;
}
public Map<String, String> getThemes() {
return themes;
}
public String getTheme() {
return theme;
}
public void setTheme(String theme) {
this.theme = theme;
}
#PostConstruct
public void init() {
setGp(new GuestPreferences()); // persistent class
setTheme(gp.getTheme()); // theme from the database;
themes = new TreeMap<String, String>();
themes.put("Aristo", "aristo");
themes.put("Black-Tie", "black-tie");
themes.put("Blitzer", "blitzer");
themes.put("Bluesky", "bluesky");
themes.put("Bootstrap", "bootstrap");
themes.put("Casablanca", "casablanca");
themes.put("Cupertino", "cupertino");
themes.put("Dark-Hive", "dark-hive");
themes.put("Dot-Luv", "dot-luv");
themes.put("Eggplant", "eggplant");
themes.put("Excite-Bike", "excite-bike");
themes.put("Flick", "flick");
themes.put("Glass-X", "glass-x");
themes.put("Hot-Sneaks", "hot-sneaks");
themes.put("Humanity", "humanity");
themes.put("Le-Frog", "le-frog");
themes.put("Midnight", "midnight");
themes.put("Mint-Choc", "mint-choc");
themes.put("Overcast", "overcast");
themes.put("Pepper-Grinder", "pepper-grinder");
themes.put("Redmond", "redmond");
themes.put("Rocket", "rocket");
themes.put("Sam", "sam");
themes.put("Smoothness", "smoothness");
themes.put("South-Street", "south-street");
themes.put("Start", "start");
themes.put("Sunny", "sunny");
themes.put("Swanky-Purse", "swanky-purse");
themes.put("Trontastic", "trontastic");
themes.put("UI-Darkness", "ui-darkness");
themes.put("UI-Lightness", "ui-lightness");
themes.put("Vader", "vader");
}
public void saveTheme() {
gp.setTheme(theme); // theme to database
}
}
method theme from class GuestPreferences is going to persist to the database
#SessionScoped
public class GuestPreferences {
public String getTheme(){
//return the theme from the database
}
public void setTheme(String theme){
//send the theme to the database
}
}
the form to send and receive data from the database depends of you prefer:
* jdbc
* jta
* jpa
for example, jta, make a persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="NAME-WHAT-YOU-WANT" transaction-type="JTA">
<provider>CLASS-OF-YOUR-PROVIDER</provider>
<jta-data-source>YOUR-DATASOURCE</jta-data-source>
<class>PATH-OF.GuestPreferences</class>
<properties>
<property name="NAME-OF-PROPERTY-TO-FORM-A-JDBC-URL" value="VALUE-OF-PROPERTY"/>
<property name="NAME-OF-PROPERTY-TO-FORM-A-JDBC-URL" value="VALUE-OF-PROPERTY"/>
<property name="NAME-OF-PROPERTY-TO-FORM-A-JDBC-URL" value="VALUE-OF-PROPERTY"/>
</properties>
</persistence-unit>
</persistence>
in a resources class you can declare:
#SuppressWarnings("unused")
#Produces
#PersistenceContext
private EntityManager em;
then, you can use it in your GuestPreferences class:
#Inject
private EntityManager em;
em.getTransaction().begin();
Query query = em.createQuery("SELECT u FROM user_table u where u.iduser=:iduser");
query.setParameter("iduser", "THEME-USER-ID");
User resultUser = (User) query.getResultList();
em.getTransaction().commit();
if(User!=null){
return resultUser.getTheme();
}
code above assumes you have a table called user_table where a user has a iduser, name ..., and a theme column, and it assumes you have an object called User to manage users
One more way to do this: include stylesheet to your pages template:
<h:body>
<h:outputStylesheet library="primefaces-#{themesBean.theme}" name="theme.css" /> </h:body>
Where #{themesBean.theme} variable reffers to name of your theme.
P.S. tested in PF5
I think setting selected theme in session would help:
session.setAttribute
Edit web.xml through code:
http://illegalargumentexception.blogspot.co.at/2008/08/java-using-xmlbeans-to-edit-webxml.html
<context-param>
<param-name>primefaces.THEME</param-name>
<param-value>EDITME</param-value>
</context-param>
Or create method before loading your page to choose the theme from db. (cleaner solution)

JSF page does not properly set object attributes

Simple question from a beginner at JSF:
I have very simple JSF form:
<h:form>
<p>#{messages.loginTextfieldUsername}</p>
<h:inputText value="#{userServiceImpl.user.name}" />
<p>#{messages.loginTextfieldPassword}</p>
<h:inputSecret value="#{userServiceImpl.user.password}" />
<h:commandButton value="#{messages.loginButtonLogin}" action="#{userServiceImpl.authenticateUser}" />
</h:form>
The userServiceImpl class is:
#Named
#RequestScoped
public class UserServiceImpl implements UserService {
private UserSession userSession;
private User user;
#Inject
public UserServiceImpl(UserSession userSession) {
this.userSession = userSession;
}
#PostConstruct
public void prepareService() {
user = new User();
}
#Override
public View authenticateUser() {
userSession.setLoggedUser(user);
return View.MAIN;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
My goal is pretty simple: when the user hits the login button, I want to authenticate the user.
The problem is:
When the authenticate method is called, the User attributes are null. I debugged the application and the getUser method is called and the values are properly set, but at some point (which I did not find [yet]) before the authenticateUser is called the User attributes are set to null...
I'm aware that this is a pretty basic question... but are you able to point out where my mistake is?
Thanks.
Based on your previous question, you seem to have experimented with <managed-bean-scope> of none in faces-config.xml for some reason. The problem symptoms matches exactly when using #ManagedBean #NoneScoped. You seem to have configured this bean in faces-config.xml as well on a none scope which totally explains this problem. With the none scope, a brand new bean instance is been created everytime when #{userServiceImpl} is been evaluated in EL. Your form submit has thus effectively created 3 beans: one where the user name is set, another one where user password is set and another one where action is invoked.
You need to remove the managed bean configuration from faces-config.xml. You should not use it when you intend to use #Inject (or #ManagedBean). The faces-config.xml way of configuring beans is a leftover from old JSF 1.x ages when annotations weren't available. As of JSF 2.x it would only override any bean management annotations.

Resources