68

I have the following code setting a variable in my controller:

model.set("type", type);

In the thymeleaf view I want to construct a form with action url:

/mycontroller/{type}

Any ideas how to achieve this? I've read thymeleaf documentation with no luck.

Chris
  • 923
  • 1
  • 8
  • 11

5 Answers5

130

As user482745 suggests in the comments (now deleted), the string concatenation I previously suggested

<form th:action="@{/mycontroller/} + ${type}">

will fail in some web contexts.

Thymeleaf uses LinkExpression that resolves the @{..} expression. Internally, this uses HttpServletResponse#encodeURL(String). Its javadoc states

For robust session tracking, all URLs emitted by a servlet should be run through this method. Otherwise, URL rewriting cannot be used with browsers which do not support cookies.

In web applications where the session tracking is done through the URL, that part will be appended to the string emitted for @{..} before the ${..} is appended. You don't want this.

Instead, use path variables as suggested in the documentation

You can also include parameters in the form of path variables similarly to normal parameters but specifying a placeholder inside your URL’s path:

<a th:href="@{/order/{id}/details(id=3,action='show_all')}">

So your example would look like

<form th:action="@{/mycontroller/{path}(path=${type})}"> //adding ending curly brace
Community
  • 1
  • 1
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
47

If You don't want to use string concatenation (proposed by Sotirios), You can use expression preprocessing in URL link:

<form th:action="@{/mycontroller/__${type}__}">
Community
  • 1
  • 1
lu_ko
  • 4,055
  • 2
  • 26
  • 31
  • 1
    I also think that this is better solution than solution proposed by Sotirios. I have links like `th:action="@{/offers/__${offer.id}__/changeStatus}"`. – sebast26 Aug 21 '14 at 06:41
  • This works, but you should be aware that this bypasses the URL encoding of the path variable that Thymeleaf does when using the solution in Sotirios' answer. – Kris Feb 12 '19 at 12:45
19

You need concatenate string inside @{}.

<form th:action="@{'/mycontroller/' + ${type}}">

@{} is used for URL rewriting. Part of URL rewriting is keeping track of session. First time user request URL, app server adds to url ;jsessionid=somehexvalue and generates cookie with jsessionid. When client sends cookie during next request server knows client supports cookies. If server knows that client support cookies, server will not keep addind jsessionid in URL.

My preferred way is literal substitution with the pipeline syntax (|).

<form th:action="@{|/mycontroller/${type}|}">

Thymeleaf path variable syntax is

<form th:action="@{/mycontroller/{pathParam}(pathParam=${type}}">

Reference: Thymeleaf Standard URL Syntax

user482745
  • 1,165
  • 1
  • 11
  • 31
  • 2
    I also prefer the literal substitution, as it is clearer and easy to maintain. The thymeleaf syntax is too complex for simple tasks. – Hugo Baés Jun 24 '16 at 18:50
  • 1
    Doing string concatenation works for me, but this is very ugly. Why doesn't it just work to write `th:href="@{/foo/bar/{obj.property}}"`? That does not work for me. – Rick Jan 05 '17 at 09:16
  • The Thymeleaf version here works nice but it is missing the right parentheses. It should be: `
    `
    – HokiEJP Aug 26 '20 at 21:47
7

What you need it is:

<a th:href="@{/mycontroller/{type}(type=${type})}">

Documentation:

Great help is here: http://www.thymeleaf.org/doc/articles/standardurlsyntax.html. What I used from there was:

You can also include parameters in the form of path variables similarly to normal parameters but specifying a placeholder inside your URL’s path:

<a th:href="@{/order/{id}/details(id=3,action='show_all')}">

... What’s more: an URL expression like:

<a th:href="@{/order/details(id=${order.id})}">

Witold Kaczurba
  • 9,845
  • 3
  • 58
  • 67
  • 2
    One thing to mention is that the parameters need to all be at the end of the link expression. This is incorrect syntax: `@{/order/{id}(id=${anIdExpression})/detail/{detail}(detail=${aDetailExpression)}` But this is correct: `@{/order/{id}/detail/{detail}(id=${anIdExpression}, detail=${aDetailExpression)}` The docs aren't very clear on this point, so I thought I'd save other folks the time I spent on trial and error. – rdguam Jan 16 '18 at 01:20
0
Exception evaluating SpringEL expression: "businessId" (login:50)

I have the same problem and solve via string concatination like below.

LoginController.java

@RequestMapping(value = "/login/{businessId}", method = RequestMethod.GET)
    public ModelAndView get(HttpServletRequest request, @PathVariable String businessId) {
        ModelAndView modelAndView = new ModelAndView("login");
        modelAndView.addObject("businessId", businessId);
        return modelAndView;
    }

login.html

            <form role="form" th:action="@{/login} + '/'+ ${businessId}" th:method="post">
                            <fieldset>
                                <div class="form-group">
                                    <input class="form-control" placeholder="E-mail" name="userName"
                                        type="email"></input>
                                </div>
                                <div class="form-group">
                                    <input class="form-control" placeholder="Password"
                                        name="password" type="password" value=""></input>
                                </div>
                                <div class="checkbox">
                                    <label> <input name="remember" type="checkbox"
                                        value="Remember Me"></input>Remember Me
                                    </label>
                                </div>
                                <!-- Change this to a button or input when using this as a form -->
                                <button id="login" class="btn btn-lg btn-success btn-block" type="submit">Login</button>
                            </fieldset>
            </form>
erhun
  • 3,549
  • 2
  • 35
  • 44