How to display a Blob (byte[]) from database in a Tapestry template

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

How to display a Blob (byte[]) from database in a Tapestry template

Christopher Dodunski-4
Hi all,

I am having a little difficulty with what I imagine is a very common use
case: displaying a user's profile image alongside their personal details
following successful login.  Displaying the JavaBean strings served up by
Hibernate is easy.  Just displaying the database Blob (stored as a byte
array in the JavaBean entity) is proving more challenging.


[Welcome.tml]

    ...
    <div>
        <img src="${imageLink}" />
        <strong>${user.firstName} ${user.lastName}</strong><br/>
        User name: "${user.userName}"<br/>
        E-mail: ${user.email}<br/>
    </div>
    ...


[Welcome.java]

    ...
    public void onActivate(){
        user = authenticator.getLoggedUser();

        company = user.getCompany();

        ports = company.getPorts();
    }


    public Link getImageLink(){
        return pageLink.createPageRenderLinkWithContext(BlobImage.class,
user.getImage());
    }
    ...


[BlobImage.java]

package com.example.harbour.pages;

import org.apache.tapestry5.StreamResponse;
import org.apache.tapestry5.services.Response;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * Class created for displaying Blob (profile) images read from the
database, as per the below howto:
 *
https://stackoverflow.com/questions/13213236/tapestry-display-blob-using-markup
 */
public class BlobImage {

    public StreamResponse onActivate(byte[] byteArray){

        //Retrieve your image using the context parameter(s)
        final InputStream imageStream = new ByteArrayInputStream(byteArray);

        return new StreamResponse(){

            @Override
            public InputStream getStream() throws IOException {
                return imageStream;
            }

            @Override
            String getContentType(){
                return "image/png";
            }

            @Override
            void prepareResponse(Response response){}
        };
    }
}


[The Compilation Error]

[ERROR] Failed to execute goal
org.apache.maven.plugins:maven-compiler-plugin:2.3.2:compile
(default-compile) on project harbour: Compilation failure: Compilation
failure:
[ERROR]
\Users\Setup\Desktop\IdeaProjects\Harbour\src\main\java\com\example\harbour\pages\BlobImage.java:[37,17]
error: prepareResponse(Response) in <anonymous
com.example.harbour.pages.BlobImage$1> cannot implement
prepareResponse(Response) in StreamResponse
[ERROR]
\Users\Setup\Desktop\IdeaProjects\Harbour\src\main\java\com\example\harbour\pages\BlobImage.java:[32,19]
error: getContentType() in <anonymous
com.example.harbour.pages.BlobImage$1> cannot implement getContentType()
in StreamResponse


Is creating a separate image streaming class, like above, the best way of
displaying a database image in a Tapestry 5 template, as the 'howto' I
followed is 5+ years' old now?  I couldn't find any newer examples on the
Tapestry website.

Thanks for your assistance,

Chris.


---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: How to display a Blob (byte[]) from database in a Tapestry template

Cezary Biernacki
Hi,
first you have a compilation problem related to basic Java: methods
getContentType()
and prepareResponse() should be public as they are required by
StreamResponse interface - it is what the compiler complains about.

However the second problem is that BlobImage.onActivate() should not
require a byte array as input argument. onActivate() parameters are
retrieved from a request URL, so basically in your implementation BlobImage
would expect whole image encoded in URL and just send back it. Instead you
should rather expect user id, and retrieve the image from the database
inside BlobImage, and in getImageLink() the context should be a user, not
the whole image. BTW, You might consider setting some response parameters
to control image caching by user's browsers, but it is an optimisation.

On the other hand, if images are small, and you want to avoid reading data
twice from the database, you might remove BlobImage, and just encode the
image directly as a data URI. E.g.:

 public String getImageLink(){
        return "data:image/png;base64," +
Base64.getUrlEncoder().encodeToString(user.getImage());
    }



On Fri, Nov 3, 2017 at 1:40 AM, Christopher Dodunski <
[hidden email]> wrote:

> Hi all,
>
> I am having a little difficulty with what I imagine is a very common use
> case: displaying a user's profile image alongside their personal details
> following successful login.  Displaying the JavaBean strings served up by
> Hibernate is easy.  Just displaying the database Blob (stored as a byte
> array in the JavaBean entity) is proving more challenging.
>
>
> [Welcome.tml]
>
>     ...
>     <div>
>         <img src="${imageLink}" />
>         <strong>${user.firstName} ${user.lastName}</strong><br/>
>         User name: "${user.userName}"<br/>
>         E-mail: ${user.email}<br/>
>     </div>
>     ...
>
>
> [Welcome.java]
>
>     ...
>     public void onActivate(){
>         user = authenticator.getLoggedUser();
>
>         company = user.getCompany();
>
>         ports = company.getPorts();
>     }
>
>
>     public Link getImageLink(){
>         return pageLink.createPageRenderLinkWithContext(BlobImage.class,
> user.getImage());
>     }
>     ...
>
>
> [BlobImage.java]
>
> package com.example.harbour.pages;
>
> import org.apache.tapestry5.StreamResponse;
> import org.apache.tapestry5.services.Response;
>
> import java.io.ByteArrayInputStream;
> import java.io.IOException;
> import java.io.InputStream;
>
> /**
>  * Class created for displaying Blob (profile) images read from the
> database, as per the below howto:
>  *
> https://stackoverflow.com/questions/13213236/tapestry-
> display-blob-using-markup
>  */
> public class BlobImage {
>
>     public StreamResponse onActivate(byte[] byteArray){
>
>         //Retrieve your image using the context parameter(s)
>         final InputStream imageStream = new ByteArrayInputStream(
> byteArray);
>
>         return new StreamResponse(){
>
>             @Override
>             public InputStream getStream() throws IOException {
>                 return imageStream;
>             }
>
>             @Override
>             String getContentType(){
>                 return "image/png";
>             }
>
>             @Override
>             void prepareResponse(Response response){}
>         };
>     }
> }
>
>
> [The Compilation Error]
>
> [ERROR] Failed to execute goal
> org.apache.maven.plugins:maven-compiler-plugin:2.3.2:compile
> (default-compile) on project harbour: Compilation failure: Compilation
> failure:
> [ERROR]
> \Users\Setup\Desktop\IdeaProjects\Harbour\src\main\
> java\com\example\harbour\pages\BlobImage.java:[37,17]
> error: prepareResponse(Response) in <anonymous
> com.example.harbour.pages.BlobImage$1> cannot implement
> prepareResponse(Response) in StreamResponse
> [ERROR]
> \Users\Setup\Desktop\IdeaProjects\Harbour\src\main\
> java\com\example\harbour\pages\BlobImage.java:[32,19]
> error: getContentType() in <anonymous
> com.example.harbour.pages.BlobImage$1> cannot implement getContentType()
> in StreamResponse
>
>
> Is creating a separate image streaming class, like above, the best way of
> displaying a database image in a Tapestry 5 template, as the 'howto' I
> followed is 5+ years' old now?  I couldn't find any newer examples on the
> Tapestry website.
>
> Thanks for your assistance,
>
> Chris.
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [hidden email]
> For additional commands, e-mail: [hidden email]
>
>