Sending a Response to the Client - geetools/geemvc GitHub Wiki

Once your request handler has done all the work, you will want to send a response to the client, e.g. the browser. In most cases you will want to respond in one of the following ways.

View Options
  1. Forward to a JSP page or template.
  2. Redirect to another request handler.
  3. Convert objects to a particular media type, such as JSON, and return to some JavaScript API.
  4. Stream images or files to the client.

geeMVC can deal with all these scenarios for you. When forwarding to a JSP page or template you will often want to bind parameters beforehand to use therein. Alternatively, when redirecting to another page, you may want to pass parameters to it. Ensuring that objects survive a redirect can be tedious or even a challenge in some cases. geeMVC relieves you from the burden of creating unnecessary boiler-plate code to handle this by making use of flash-variables. Flash variables are added to the HTTP session shortly before the redirection takes place and then recovered prior to calling the next request handler. The flashed variables are now ready for use in the current view.

Forwarding to a JSP page or template

geeMVC provides two ways for forwarding to a view.

Forward Type Description Example
java.lang.String Simple view String when there is no need to bind a parameter. return "view: account/view";
com.geemvc.view.bean.Result The Result bean is used when you need to bind objects to the view. return Results.view("account/view") .bind("account", account);

We'll continue with the account example and add another two methods to demonstrate forwarding to a view.

Using a Forward String
    @Request("/view/without-binding")
    public String viewAccountWithoutBinding() {
        return "view: account/view";
    }
Binding Objects to your View
    @Request("/view/{id}")
    public Result viewAccount(@PathParam Long id) {
        AccountBean account = null;

        // If an id exists we'll pretend to get an account object from the database.
        if (id != null) {
            account = new AccountBean();
            account.setId(id);
            account.setForename("Tom");
            account.setSurname("Smith");
            account.setUsername("tom.smith");
        }

        // Finally we'll bind the account object to the view.
        // View method from statically imported Results object (import static com.geemvc.Results.*).
        return view("account/view").bind("account", account);
    }

Although we previously mentioned that the View Object lets you bind parameters and the String does not, there is also a way of binding parameters when returning a String, as you can see in the following example:

Using a Forward String and Binding Parameters
    @Request("/view/with-request-binding")
    public String viewAccountUsingRequestBinding(ServletRequest request) {
        
        AccountBean account = new AccountBean();
        account.setId(123L);
        account.setForename("Tom");
        account.setSurname("Smith");
        account.setUsername("tom.smith");
        
        // Manually add account bean to ServletRequest object.
        request.setAttribute("account", account);
        
        return "view: account/view";
    }

We highly recommend the first two options, but this would work just the same.

We have already created the view in a previous section, but we'll make a note of it here too nonetheless for the sake of completeness.

<!-- /WEB-INF/jsp/pages/account/view.jsp -->

<!-- Useful JSTL taglibs. -->
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<!-- geeMVC taglibs. -->
<%@ taglib uri="http://geetools.com/jsp/geemvc/form" prefix="f"%>
<%@ taglib uri="http://geetools.com/jsp/geemvc/html" prefix="h"%>

<h1>Your Account Details</h1>

<f:haserrors>
	<f:errors />
</f:haserrors>

<f:hasnotices>
	<f:notices />
</f:hasnotices>

<br />
<br />

<c:if test="${not empty account}">
	Welcome ${account.forename} ${account.surname}, your username is ${account.username}.
</c:if>

Back to the top

Redirecting to Another Request Handler

Redirecting to another URI or request handler works in a similar fashion to forwarding as we saw above. Depending on whether you just want to do a simple redirect or pass parameters to the next page, geeMVC offers the following possibilities:

Redirect Type Description Example
java.lang.String Simple redirect String when there is no need to bind a parameter. return "redirect: /accounts/view";
com.geemvc.view.bean.Result The Result bean is used when you need to flash-bind objects to the (redirect) result, thereby ensuring their existence on the redirected page. return Results.redirect("/accounts/view") .flash("account", account);

In the following example we will simply redirect to another request handler. As we are not doing anything special here a redirect String is sufficient at this point. Add the following handler method to your AccountController to see it in action.

    @Request("/redirect/{id}")
    public String redirectToAccount(@PathParam Long id) {
        return "redirect: /accounts/view/" + id;
    }
Flashing Variables Before Redirecting to Another Request Handler

Sometimes you need to redirect to another page without losing the view data along the way. To achieve this we will use flash-variables. In contrast to the previous example we will now swap the processing order, i.e. we will first get the account bean and then redirect to a view only request handler, not forgetting to flash the bean beforehand. Try the following example by adding the two new methods to your AccountController.

    @Request("/redirect-and-flash-account/{id}")
    public Result redirectAndFlashAccount(@PathParam Long id) {
        AccountBean account = null;

        // If an id exists we'll pretend to get an account object from the database.
        if (id != null) {
            account = new AccountBean();
            account.setId(id);
            account.setForename("Tom");
            account.setSurname("Smith");
            account.setUsername("tom.smith");
        }

        // Finally we'll flash-bind the account object to the redirect view.
        // Redirect method from statically imported Results object (import static com.geemvc.Results.*).
        return redirect("/accounts/view-flashed-account").flash("account", account);
    }

    @Request("/view-flashed-account")
    public String viewFlashedAccount() {
        // The flash-variables have already been recovered automatically
        // by geeMVC, so we'll just forward to the view here.
        return "view: account/view";
    }

Back to the top

Automatically Converting Objects to a Particular Media Type, such as JSON

Whether you are working with extensive JavaScript frameworks or making simple AJAX calls, sometimes you need to get your data in a specific format - in this case most likely in JSON. Thanks to the JAX-RS functionality, streaming your data directly in a specific format to the client is very easy. Simply return the object in your request handler and let geeMVC know which format or media type it supports. Again we'll use the AccountController to demonstrate a simple example.

    @Request(path = "/api/{id}", produces = "application/json")
    public AccountBean accountAsJson(@PathParam Long id) {
        AccountBean account = null;

        // If an id exists we'll pretend to get an account object from the database.
        if (id != null) {
            account = new AccountBean();
            account.setId(id);
            account.setForename("Tom");
            account.setSurname("Smith");
            account.setUsername("tom.smith");
        }

        // Finally we'll return the account object, which will 
        // automatically get converted to JSON.
        return account;
    }

Notice how we are simply returning an object and letting geeMVC know which media type is supported by utilizing the produces element. This is lean and simple. In order to test however you will need to send the "Accept" header along with your request. This can either be in your AJAX call or, if you are simply testing with your browser, you will need a plugin that lets you add your own headers. Make sure you set Accept: application/json for this particular test. The response will then look like this:

{"age":0,"email":null,"forename":"Tom","id":123,"password":null,"surname":"Smith","username":"tom.smith"}

In this example we used a Chrome plugin, which looks like the following after the header has been set:

Modify Headers - Accept: application/javascript

Back to the top

Streaming Images and Files to the Client.

On occasions you will need to dynamically load files and stream them to the client. Again geeMVC makes this very easy to do. In the following example we will be streaming a text file and an image to the browser. Although this has little to do with the AccountController, we have added the handler methods here anyway to keep things simple. Take a look at the following code:

    @Request(path = "/view-file", produces = MediaType.WILDCARD)
    public Result viewFile(@Param("name") String relativeFilePath, ServletContext servletContext) {
        // Load the file from the system in the form of an InputStream.
        InputStream is = servletContext.getResourceAsStream("/media/" + relativeFilePath);

        if (is != null)
            // Stream method from statically imported Results object (import static com.geemvc.Results.*).
            return stream(mimeType(relativeFilePath), is);

        // If the file cannot be found we simply return a 404 status code.
        else
            // Status method from statically imported Results object (import static com.geemvc.Results.*).
            return status(HttpServletResponse.SC_NOT_FOUND, relativeFilePath);
    }

    /**
     * Simple method for getting the mime-type of the file
     * by evaluating the file extension.
     */
    protected String mimeType(String filename) {
        if (filename.endsWith(".gif"))
            return "image/gif";
        else if (filename.endsWith(".txt"))
            return "text/plain";
        else
            return "application/octet-stream";
    }

Notice how we are:

  1. Informing geeMVC that this handler method will produce any content type.
  2. Injecting the ServletContext to help us load the files.
  3. Simply sending a 404 status message when the file could not be found.

In order to test this we have copied two files to a new media folder. If you are unsure where to put your test files, check this screenshot.

Here is what the result should look like when restarting jetty with mvn clean jetty:run and then opening up the following URLs in your browser:

http://localhost:8080/accounts/view-file/?name=img/geeMVC-java-mvc-framework-rocks.gif geeMVC Java MVC Framework rocks!

http://localhost:8080/accounts/view-file/?name=doc/geeMVC-java-mvc-framework-rocks.txt geeMVC Java MVC Framework rocks!

http://localhost:8080/accounts/view-file/?name=doc/file-does-not-exist.txt geeMVC Java MVC Framework rocks!

Back to the top

⚠️ **GitHub.com Fallback** ⚠️