Stream of bytes as a response

29 views
Skip to first unread message

Reto

unread,
Aug 5, 2012, 1:03:39 PM8/5/12
to se...@googlegroups.com
Dear all,

I'm new to this great framework and love its simplicity. Thanks a lot.
I would like to know how to stream a mp3 file from a RestController as described below. Unfortunately I can not see how to access a responsehelper to
access the output stream from the response. Or do I need to create a Serializer and convert the Bytes into a String (String str = new String(bytes);)
Any help is highly appreciated.

Thanks a lot & kind regards

Reto

Example Code:
 @GET
  @DoNotRenderPage
  public void play() {
    // Gets song id and retrieve file
    String id = this.getId("song");
    Song song = getSong(id);
    File mp3 = new File(song.getLocation());
    FileInputStream is = new FileInputStream(mp3);
    // Stream the file to the response
    OutputStream os = response.getOutputStream();
    response.setContentType("audio/mpeg");
    response.setHeader("Content-Disposition","attachment; filename=song.mp3");
    response.setContentLength((int) mp3.length());
    BufferedInputStream buf = new BufferedInputStream(is);
    int readBytes = 0;
    //read from the file; write to the ServletOutputStream
    try {
      while ((readBytes = buf.read()) != -1) os.write(readBytes);
    } catch (IOException ioe) {
      throw new ServletException(ioe.getMessage());
    } finally {
      if (os != null)
        os.close();
      if (buf != null)
        buf.close();
    }

  }

Eduardo Yáñez Parareda

unread,
Aug 6, 2012, 10:33:24 AM8/6/12
to se...@googlegroups.com
Hi Reto, I'm glad to hear that you like SerfJ.

Yes, the response is not accesible from the controller because I like controllers to be as independents of javax.http as possible.
However, you should be able to do it with a Serializer... the problem is that serializers don't have methods like getContentLength or setHeader, only getContentType is available at this moment.

So.... to solve all of this, the easiest way would be to provide RestControllers a method to get the HttpServletResponse. Anyway I'd like to develop a more elegant solution... Let me think 
about this problem.

Reto

unread,
Aug 6, 2012, 4:05:05 PM8/6/12
to se...@googlegroups.com
Dear Eduardo,

I checked the code and an enhanced serializer interface would probably do the trick. Add the missing methods or a generic set/getProperty and a void serialize() method.
Anyway thanks a lot for taking care.

Reto

Eduardo Yáñez Parareda

unread,
Aug 6, 2012, 7:00:38 PM8/6/12
to se...@googlegroups.com
Yes, that's the solution I've been thinking to do.
--
--
Eduardo Yáñez Parareda - http://serfj.sourceforge.net


Eduardo Yáñez Parareda

unread,
Aug 8, 2012, 6:57:00 AM8/8/12
to se...@googlegroups.com
Well, I've implemented a solution for version 0.4.0. It'll be explained at the reference documentation, but I'll tell you here too with some snippet:

Controller:

import java.io.File;

import net.sf.serfj.RestController;
import net.sf.serfj.annotations.DoNotRenderPage;
import net.sf.serfj.annotations.GET;

public class Song extends RestController {

    // URL /songs/1.mp3
    @GET
    @DoNotRenderPage
    public void show() {
        String id = this.getId();
        Song song = getSong(id);
        File mp3 = new File(song.getLocation());
        // This line is very importan because it tells SerfJ that a file will be sent 
        this.getResponseHelper().setFile(mp3, "song.mp3");
    }

    // URL /songs/1/play.mp3
    @GET
    @DoNotRenderPage
    public void play() {
        String id = this.getId();
        Song song = getSong(id);
        File mp3 = new File(song.getLocation());
        // This line is very importan because it tells SerfJ that a file will be sent 
        this.getResponseHelper().setFile(mp3, "song.mp3");
    }
}


Serializer:

import net.sf.serfj.serializers.FileSerializer;

/**
 * Serializer for MP3 files.<br>
 */
public class Mp3Serializer extends FileSerializer {
    /**
     * Content type that will be used in the response.
     */
    public String getContentType() {
        return "audio/mpeg3";
    }
}

That's all. Furthermore if you use the default .file extension and sets a content type in the controller's method, you won't need to implement any serializer:

    // URL /songs/1.file
    @GET
    @DoNotRenderPage
    public void show() {
        String id = this.getId();
        Song song = getSong(id);
        File mp3 = new File(song.getLocation());
        // This line is very importan because it tells SerfJ that a file will be sent 
        this.getResponseHelper().setFile(mp3, "song.mp3", "audio/mpeg3");
    }


Now there is a new extension for serving files (.file) that uses a new serializer FileSerializer, so when the controller sets a file, SerfJ will send it to the client.
The default implementation sends "application/octect-stream" as content type. 

I'll release the new version today with more changes.
Reply all
Reply to author
Forward
0 new messages