How to grab a local path from end-user in JSF - jsf

I'm facing a simple problem
I would like to get a local path from the end-user of my web application. I need only that and not to actually upload a file. (I know there are fileUpload tags in seam or in Primefaces but I just need the local full path as I'm uploading directly to Picasa Web Albums via the Google API)
In other words I would like to bind some kind of html tag : input type="file"
to a bean property (I notice that the JSF tag h:inputText tag doesn't have a type attribute)
Any ideas?
Env : JBoss AS 5.1, JSF1.2, Seam 2.2, Primefaces 1.1
Edit : here is my working solution
Thanks to the answers, I implemented the use-case of uploading a file directly to Picasa
<h:form prependId="false" enctype="multipart/form-data">
<s:fileUpload id="fileUpload"
data="#{picasa.incomingFile}"
contentType="#{picasa.fileType}"/>
<h:inputText id="albumId"
value="#{picasa.albumId}" />
<h:commandLink action="#{picasa.upload()}"
value="Upload">
<f:param name="s"
value="#{subjectHome.id}"/>
</h:commandLink>
</h:form>
and the component code
#Name("picasa")
public class PicasaService {
#Logger private Log log;
private PicasawebService service;
private InputStream incomingFile;
private String fileType;
private String albumId;
#Create
public void setUp()
{
service = new PicasawebService("picasaService");
try {
service.setUserCredentials("xxx#yyyy.zzz", "password");
} catch (AuthenticationException e) {
e.printStackTrace();
}
}
public void upload()
{
URL albumUrl;
PhotoEntry returnedPhoto;
try {
albumUrl = new URL("https://picasaweb.google.com/data/feed/api/user/default/albumid/" + albumId);
MediaStreamSource myMedia = new MediaStreamSource(incomingFile , this.fileType);
returnedPhoto = service.insert(albumUrl, PhotoEntry.class, myMedia);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ServiceException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
This way, it seems to me that the file is not transferred twice (one from end-user machine to my web app's server and from there to picasa WA server).
Hope this helps

but I just need the local full path as I'm uploading directly to Picasa Web Albums via the Google API
You need to get the file's content as an InputStream from the JSF file upload component and write it to an FileOutputStream on the server's local disk file system the usual way, then you can reference it as a File and pass it to the Picasa API as documented.
See also:
What is the alternative of file browse in JSF?

You can't get the local path for security reasons, all modern browsers won't provide your code with that information... bestcase is they give you the file name only...

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.

Display p:fileupload image in p:graphicImage preview without saving it

I am using PrimeFaces 5.3 <p:fileUpload> to upload a PNG image and I would like to show a preview of it in <p:graphicImage> before saving in database.
Here's a MCVE:
<h:form enctype="multipart/form-data">
<p:fileUpload value="#{bean.uploadedFile}" mode="simple" />
<p:graphicImage value="#{bean.image}" />
<p:commandButton action="#{bean.preview}" ajax="false" value="Preview" />
</h:form>
private UploadedFile uploadedFile;
public UploadedFile getUploadedFile() {
return uploadedFile;
}
public void setUploadedFile(UploadedFile uploadedFile) {
this.uploadedFile = uploadedFile;
}
public void preview() {
// NOOP for now.
}
public StreamedContent getImage() {
if (uploadedFile == null) {
return new DefaultStreamedContent();
} else {
return new DefaultStreamedContent(new ByteArrayInputStream(uploadedFile.getContents()), "image/png");
}
}
No error occurring on the backing bean, and the image won't be load and display at front-end. The client mentions that the image returned a 404 not found error.
Your problem is two-fold. It failed because the uploaded file contents is request scoped and because the image is requested in a different HTTP request. To better understand the inner working, carefully read the answers on following closely related Q&A:
Display dynamic image from database with p:graphicImage and StreamedContent
How to choose the right bean scope?
To solve the first problem, you need to read the uploaded file contents immediately in the action method associated with the form submit. In your specific case, that would look like:
private UploadedFile uploadedFile;
private byte[] fileContents;
public void preview() {
fileContents = uploadedFile.getContents();
}
// ...
To solve the second problem, your best bet is to use the data URI scheme. This makes it possible to render the image directly in the very same response and therefore you can safely use a #ViewScoped bean without facing "context not active" issues or saving the byte[] in session or disk in order to enable serving the image in a different request. Browser support on data URI scheme is currently pretty good. Replace the entire <p:graphicImage> with below:
<ui:fragment rendered="#{not empty bean.uploadedFile}">
<img src="data:image/png;base64,#{bean.imageContentsAsBase64}" />
</ui:fragment>
public String getImageContentsAsBase64() {
return Base64.getEncoder().encodeToString(imageContents);
}
Note: I assume that Java 8 is available to you as java.util.Base64 was only introduced in that version. In case you're using an older Java version, use DatatypeConverter.printBase64Binary(imageContents) instead.
In case you happen to use JSF utility library OmniFaces, you can also just use its <o:graphicImage> component instead which is on contrary to <p:graphicImage> capable of directly referencing a byte[] and InputStream bean property and rendering a data URI.
<o:graphicImage value="#{bean.imageContents}" dataURI="true" rendered="#{not empty bean.imageContents}">

Send HTTP POST request to external site using <h:form>

I want to send a HTTP post request to another server using <h:form> component.
I can send a POST request to an external site using HTML <form> component, but <h:form> component does not support this.
<form action="http://www.test.ge/get" method="post">
<input type="text" name="name" value="test"/>
<input type="submit" value="CALL"/>
</form>
How can I achieve this with <h:form>?
It's not possible to use <h:form> to submit to another server. The <h:form> submits by default to the current request URL. Also, it would automatically add extra hidden input fields such as the form identifier and the JSF view state. Also, it would change the request parameter names as represented by input field names. This all would make it insuitable for submitting it to an external server.
Just use <form>. You can perfectly fine use plain HTML in a JSF page.
Update: as per the comments, your actual problem is that you have no idea how to deal with the zip file as obtained from the webservice which you're POSTing to and for which you were actually looking for the solution in the wrong direction.
Just keep using JSF <h:form> and submit to the webservice using its usual client API and once you got the ZIP file in flavor of InputStream (please, do not wrap it a Reader as indicated in your comment, a zip file is binary content not character content), just write it to the HTTP response body via ExternalContext#getResponseOutputStream() as follows:
public void submit() throws IOException {
InputStream zipFile = yourWebServiceClient.submit(someData);
String fileName = "some.zip";
FacesContext fc = FacesContext.getCurrentInstance();
ExternalContext ec = fc.getExternalContext();
ec.responseReset();
ec.setResponseContentType("application/zip");
ec.setResponseHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
OutputStream output = ec.getResponseOutputStream();
try {
byte[] buffer = new byte[1024];
for (int length = 0; (length = zipFile.read(buffer)) > 0;) {
output.write(buffer, 0, length);
}
} finally {
try { output.close(); } catch (IOException ignore) {}
try { zipFile.close(); } catch (IOException ignore) {}
}
fc.responseComplete();
}
See also:
How to provide a file download from a JSF backing bean?

URL encoding and JSF REDIRECT

I must have utf-8 characters in url.
For example there is a string that is to be put in url:
"Hayranlık"
I thought to encode it:
try{
selected=URLEncoder.encode(selected,"UTF-8");
}catch(Exception e){
e.printStackTrace();
}
try {
FacesContext.getCurrentInstance().getExternalContext().redirect("http://" + serverUrl +"/myjsfpage.jsf?param=" + selected );
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
I debug it and I see an expected string : Hayranl%C4%B1k%24
In another controller, I must handle it, so I get the url by
HttpServletRequest req = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
String selected = (String)req.getParameter("param");
if(selected ==null){
//show no result message
return;
}
After that i try to decode it, but "before" decoding, my string that I get from url is something like "Hayranlık$".
try{
selected=URLDecoder.decode(selected,"UTF-8");
}catch(Exception e){
e.printStackTrace();
}
Does JSF redirection cause the problem, or is the browser URL handling the problem?
It's the servletcontainer itself who decodes HTTP request parameters. You don't and shouldn't need URLDecoder for this. The character encoding used for HTTP request parameter decoding needs for GET requests to be configured in the servletcontainer configuration.
It's unclear which one you're using, but based on your question history, it's Tomcat. In that case, you need to set the URIEncoding attribute of <Connector> element in Tomcat's /conf/server.xml to UTF-8.
<Connector ... URIEncoding="UTF-8">
See also:
Unicode - How to get the characters right?
Unrelated to the concrete problem, the way how you pulled the request parameter in JSF is somewhat clumsy. The following is simpler and doesn't introduce a Servlet API dependency in your JSF managed bean:
String selected = externalContext.getRequestParameterMap().get("param");
Or, if you're in a request scoped bean, just inject it by #ManagedProperty.
#ManagedProperty("#{param.param}")
private String param;
(note that #{param} is an implicit EL object referring the request parameter map and that #{param.param} merely returns map.get("param"); you might want to change the parameter name to make it more clear, e.g. "?selected=" + selected and then #{param.selected})
Or if you're in a view scoped bean, just set it by <f:viewParam>.
<f:viewParam name="param" value="#{bean.param}" />
See also:
ViewParam vs #ManagedProperty(value = "#{param.id}")

How to insert uploaded image from p:fileUpload as BLOB in MySQL?

How to insert uploaded image from p:fileUpload as BLOB in MySQL?
#Lob
#Column(name = "photo")
private byte[] photo;
And in XHTML page, I write this:
<p:inputText value="#{condidat.condidat.photo}" >
<p:fileUpload fileUploadListener="#{fileUploadController.handleFileUpload}"
allowTypes="*.jpg;*.png;*.gif;" description="Images"/>
</p:inputText>
How can I retreive the value of uploaded file as byte[]?
You can get the uploaded file content via FileUploadEvent. In PrimeFaces 4.x with Apache Commons FileUpload, or in PrimeFaces 5.x with context param primefaces.UPLOADER set to commons, you can use UploadedFile#getContents() to obtain the uploaded file as byte[].
public void handleFileUpload(FileUploadEvent event) {
byte[] content = event.getFile().getContents();
// ...
}
In PrimeFaces 5.x with context param primefaces.UPLOADER absent or set to auto or native while using JSF 2.2, then getContents() will return null as that's not implemented in NativeUploadedFile implementation. Use UploadedFile#getInputStream() instead and then read bytes from it, e.g. with help of commons IO.
public void handleFileUpload(FileUploadEvent event) {
byte[] content = IOUtils.toByteArray(event.getFile().getInputstream());
// ...
}
Finally, just set this byte[] in your entity and persist/merge it.
Make sure that you have set the form encoding type to multipart/form-data and, when using the Apache Commons FileUpload, that you have configured the file upload filter in web.xml as per PrimeFaces user guide.
It might be helpful to mention that, I had to use:
public void handleUpload(FileUploadEvent e) throws Exception {
byte[] contents = IOUtils.toByteArray(e.getFile().getInputstream());
//....
}
As it seems that in PrimeFaces 5.x, the getContents() always returns null !

Resources