Spring forward with added parameters?

Tony R picture Tony R · Dec 21, 2011 · Viewed 70.4k times · Source

Is there a way to forward a request to another Controller while adding some parameter data to it? I tried adding to the ModelMap, but it doesn't seem to hang around. I am doing something like:

return "forward:/my-other-controller";

Only other way I can think of is to put the parameters on the session and then pop them off in the target controller.

Answer

Bogdan picture Bogdan · Dec 28, 2011

The simplest way is to add the data to the request. Since this is a forward, the same request is passed around to different handlers within the server.

As example, let's start with a simple setup of two controllers, one forwarding to the other:

@Controller
public class TestController {
    @RequestMapping(value="/test")
    public String showTestPage() {
        return "forward:/test2";
    }
}

@Controller
public class TestController2 {
    @RequestMapping(value="/test2")
    public String showTestPage() {
        return "testPageView";
    }
}

First way to add the data is to set it as attributes on the request. The new controllers will look like this (A):

@Controller
public class TestController {
    @RequestMapping(value="/test")
    public String showTestPage(HttpServletRequest request) {
        request.setAttribute("param1", "foo");
        request.setAttribute("param2", "bar");
        return "forward:/test2";
    }
}

@Controller
public class TestController2 {
    @RequestMapping(value="/test2")
    public String showTestPage(HttpServletRequest request) {
        String param1 = (String) request.getAttribute("param1");
        String param2 = (String) request.getAttribute("param2");
        return "testPageView";
    }
}

Since the view name in the forward prefix is basically an URL, you can also have the following versions (attribute changed to parameter) (B):

@Controller
public class TestController {
    @RequestMapping(value="/test")
    public String showTestPage() {
        return "forward:/test2?param1=foo&param2=bar";
    }
}

@Controller
public class TestController2 {
    @RequestMapping(value="/test2")
    public String showTestPage(HttpServletRequest request) {
        String param1 = request.getParameter("param1");
        String param2 = request.getParameter("param2");
        return "testPageView";
    }
}

You can also further simplify the second controller by using annotations instead:

@Controller
public class TestController2 {
    @RequestMapping(value="/test2")
    public String showTestPage(@RequestParam String param1, @RequestParam String param2) {
        return "testPageView";
    }
}

And just for the fun of it, and to show Spring's binding behavior in action, you could do it even like this (C):

@Controller
public class TestController {
    @RequestMapping(value="/test")
    public String showTestPage() {
        return "forward:/test2?param1=foo&param2=bar";
    }
}

@Controller
public class TestController2 {
    @RequestMapping(value="/test2")
    public String showTestPage(@ModelAttribute DummyBinder params) {
        String param1 = params.getParam1();
        String param2 = params.getParam2();
        return "testPageView";
    }
}

class DummyBinder {
    private String param1;
    private String param2;

    public String getParam1() {
        return param1;
    }

    public void setParam1(String param1) {
        this.param1 = param1;
    }

    public String getParam2() {
        return param2;
    }

    public void setParam2(String param2) {
        this.param2 = param2;
    }
}

I would personally go with solution A for many parameters, and solution B for a few. Solution C has a sort of "huh...?!" effect so I would avoid it (also it works with parameters added to the URL so a few of those or you get a messy URL).

Adding the data in the session would also work off course, but would extend the data's life time unnecessarily, so the best place is to add it on the request during the transition to the second controller.