How to set an attribute into a session with thymeleaf? - spring

I'm trying to add an attribute to an HTTP session with thyme leaf, but I can't. I had a "Project" object and I need to pass it to the controller. I had a form in the page, so I've tried this, but it doesn't work:
<input type="hidden" th:attr="${#session.setAttribute('proyecto', '${proyecto}')}"
The controller receives the attribute proyecto but the value is "${proyecto}", not the content of the project object

Send the value using a form and then set the session attribute in your controller.
HTML
<form th:action="#{/newProject}" th:object="${newProject}" method="post">
<input th:field="*{id}"></input>
</form>
Controller
#RequestMapping(value = "/newProject", method = RequestMethod.POST)
public String addProject(HttpSession session, #ModelAttribute("newProject") Project project) {
session.setAttribute("proyecto", project);
return "/newPage";
}
This is just example of course. You would need to add all the project fields in your HTML.

Related

Pass through variable in Spring boot / Thymeleaf

I am looking for a way to pass the whole object through without having to use <input type="hidden" /> on the different variables. It seems like the th:object will not carry over the incoming information on the "whole object"
<form action="#" th:action="#{/api/result/save}" th:object="${result}" th:method="post">
<!--- Input fields -->
<input type="hidden" th:field="${result}"> <---- Not working.
<button type="submit" class="btn btn-primary" value="spara">Spara</button>
From the model I have
Result result = new Result(teams);
result.setTeam1ID(aTeam1.get().getId()); // This variable will not be changed in the HTML so I would like to pass that to the next page
// Other variables
When I get to the /save the Result will only contain variables set in Thymeleaf it will not retain the information from the original model above.
#PostMapping("/save")
public RedirectView saveResult(Result result, Model model) {
service.saveResult(result);
Thymeleaf is use to generate view, you can store some variable but not the whole object.
Though you can try these method:
If you object is already stored at server-side in memory or data base. You just pass the unique key of that object get it back using hidden input type.
Store the object into session then get it from there whenever requered.

Pass data from Thymeleaf template to springboot controller

I have simple web application written using Springboot and Thymeleaf templates. Report controller receives the data from form and builds the TestPlanReportResponse object which is added as model attribute like this:
#PostMapping("/report")
public String homeSubmit(#ModelAttribute HomeFormInput homeFormInput, Model model, Errors errors) {
final TestPlanReportResponse response = new TestPlanReportResponse(homeFormInput);
model.addAttribute("allData", response);
return "charts";
}
I can work with that data in "charts" thymeleaf template and show the data I need, but I need to send exactly the same object back to controller when button is clicked, but i getting TestPlanReportResponse
object as parameter with nulls set.
#PostMapping("/report/send")
public String sendReport(#ModelAttribute TestPlanReportResponse reportData, Model model) {
//reportData contains just nulls
}
Here is how my button is set in charts template:
<form action="#" th:action="#{/report/send}" th:object="${allData}" method="post">
<button type="submit">Send the report</button>
</form>
So my question is how to send the object back from thymeleaf template? Should i create a hidden input and put there the "allData" object just to send it back? It looks for me like dirty hack. What would be the appropriate way to pass data back? I want to have this app stateless so don't to store the data on a server side.
When I used to work with Spring and Thymeleaf and form, we had the same issue, passing the data back and forth between a form, the template, and different controllers.
And what you suggest is what we did, we used hidden input as dirty as it may look,it was the standard suggested answer, we did not find anything better.
You need to create an input, with a type a value and link it to a field, like this:
<form action="#" th:action="#{/report/send}" th:object="${allData}" method="post">
<input type="hidden" th:value="*{allDataValue1}" th:field="*{allDataField1}" />
//Do this for all your attributes/values that you wish to pass to the controller
<button class="btn btn-info btn-lg btn-block" type="submit">Send the report</button>
</form>
Though, i found this answer, you can try looking into this thread

Spring MVC: How do I preserve model attributes in spring validation errors

I searched around on Stack Overflow, but could not find the solution to my query. I have a controller function that adds multiple model attributes on a GET request
#RequestMapping(method = RequestMethod.GET, value = "/showdeletesearchqueryform")
public String showDeleteSearchQuery(final Model model) {
if (LOG.isDebugEnabled()) {
LOG.debug("Fetching all the search query results.");
}
ImmutableList<ArtQueryResults> results = this.searchQueriesService
.getSearchQueries(APPNAME);
// Adding model attribute # 1
model.addAttribute("searchResults", results);
if (LOG.isDebugEnabled()) {
LOG.debug("\"searchResults\" model attribute has been intialized from "
+ results);
}
ArtDeleteQueryRequest request = new ArtDeleteQueryRequest();
request.setAppName(APPNAME);
if (LOG.isDebugEnabled()) {
LOG.debug("Model attribute initialized = " + request);
}
// Adding model attribute # 2
model.addAttribute("deletedAttributes", request);
return "deletesearchqueries";
}
My JSP
<div class="column-group">
<form:form method="POST" action="${pageContext.request.contextPath}/arttestresults/showdeletesearchqueryform" modelAttribute="deletedAttributes">
<form:errors path="*" cssClass="alert alert-danger column lg-units-5 units-2" element="div"/>
<form:hidden path="appName" id="appNameId" htmlEscape="true"/>
<div class = "units-1 column lg-units-12">
<!-- Hidden Key for app name. -->
<form:select path="idsToBeDeleted" id="IdsToBeDeletedSelectId">
<c:forEach items="${searchResults}" var="searchResult" varStatus="loop">
<form:option label="${searchResult.searchQuery}" value="${searchResult.id}" />
</c:forEach>
</form:select>
</div>
<div class="units-1 column lg-units-12">
<%-- This is a hack that make sure that form is submitted on a click. Not sure why form is not being submitted. --%>
<button class="button" type="submit" onclick="javascript:$('form').submit();">Delete Selected Queries</button>
</div>
</form:form>
My controller POST function
#RequestMapping(method = RequestMethod.POST, value = "/showdeletesearchqueryform")
public String deleteSearchQueries(
Model model,
#ModelAttribute(value = "deletedAttributes") #Valid final ArtDeleteQueryRequest request,
final BindingResult result) {
if (result.hasErrors()) {
LOG.warn("There are " + result.getErrorCount() + " validation errors.");
return "deletesearchqueries";
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("The ids to be deleted are " + request.getIdsToBeDeleted());
}
this.searchQueriesService.deleteSearchQueriesById(
ImmutableList.copyOf(request.getIdsToBeDeleted()));
return "redirect:/arttestresults/showdeletesearchqueryform";
}
}
If there is a validation failure, the model attribute searchResults is not being picked up when I return a view on error condition? Is there a way to preserve the other defined model attributes as well?
Seems that you need flash attributes which were added in spring 3.1. Please take a look at example/explanation:
http://viralpatel.net/blogs/spring-mvc-flash-attribute-example/
The get and the post are different requests. What you get in the post request, is only what comes from the form, so only the "deletedAttributes" model attribute and only the fields that are <input> in the JSP.
You need to put again the searchResults model attribute explicitely like you did in get method.
As suggested by M. Deinum, if one or more attribute(s) will be used by all methods in a controller, you can use a #ModelAttribute annotated method to put it (them) in model automatically.
You can also use SessionAttributes model attributes, that is attributes that are stored in session and not in request. But it is hard to have them properly cleaned from session if user do not post the form but go into another part of the application. You have an example of usage ofSessionAttributes` in Spring's Petclinic example.

Checkboxes tag spring mvc and binding

I have checkboxes tag in my web application with spring mvc. Checkboxes are created from a map in controller like this:
Map demOrgs = createMap();
model.addAttribute("demOrgs", demOrgs); // example : (1, my-description)
1 --> will be value of checkbox
my-description --> will be label of checkbox
In my jsp :
<form:form commandName="myBean" method="POST" >
<form:checkboxes items="${demOrgs}" path="demOrg" element='div class="checkboxes"' />
</form:form>
My bean has only one field :
String demOrg;
When I send the form demOrg attribute has the value of checkboxes clicked, for example: (1,5,8)
I store myBean in session, when I go to the next step in my application. But when I return, I want the checkboxes were checked, still checked and isn't that way.
When the bind value of checkbox is a boolean value, allways work but I'm binding a custom value :
<input id="demOrg1" type="checkbox" value="2" name="demOrg">
<label for="demOrg1">My label description</label>
<input id="demOrg2" type="checkbox" value="3" name="demOrg">
<label for="demOrg2">My label description 2</label>
.....
Does anyone know how to do this?
thanks to all!!
What does the signature of your controller method look like? Are you including myBean as a method signature argument, annotated with #ModelAttribute ?
Something like:
#RequestMapping(......)
public String myController (#ModelAttribute MyBeanType myBean, Model model) {
Map demOrgs = createMap();
model.addAttribute("demOrgs", demOrgs);
model.addAttribute(myBean);
}
Optionally you can annotate the method parameter with #Valid as well if you are using JSR-303 bean validation .
I think the trick is to make sure your demOrg property is actually a collection. Check out the
checkbox reference here. In particular, the text that says:
Typically the bound property is a collection so it can hold multiple values selected by the user.
Though "myBean" is stored in the session, isn't it reloaded again from the database when the controller is ran?

how to do binding in Spring annotated request parameter?

i have a controller that is using annotation for request mapping and requestParam.
the controller is working fine. However when submitting a command object with array, spring will crap out saying array index out of bound. i am guessing there is something wrong with binding but don't know how to fix it.
to be more specific, in eclipse i would set debugger at the beginning of the controller, and when submitting the form (by hitting a input submit button) eclipse debugger will not trigger and i will see array index out of bound error in console.
the controller is something like this:
#RequestMapping(value = {"/internal/pcsearch.dex", "/external/pcsearch.dex"},
method = {RequestMethod.POST, RequestMethod.GET})
public ModelAndView executeProductCatalogSearch(
HttpServletRequest request,
#RequestParam(value = "cat" ,required = false) String cat,
#RequestParam(value = "brand" ,required = false) String brand,
#ModelAttribute("command") ProductCatalogCommand cmd
){
[edit]
and the jsp is like:
<form name="pForm"
id="pForm"
action="<c:url value="psearch.dex"><c:param name="cat" value="${cat}"/></c:url>"
method="POST"
style="display:inline;">
...
...
<c:forEach var="model" items="${models}" varStatus="modelLinkStatus">
<script>
var modelImg<c:out value="${modelLinkStatus.index}"/>Src = '<c:out value="${model.altModelImage}"/>';
</script>
<spring:bind path="command.models[${modelLinkStatus.index}].modelSkusDisplayed">
<input type="hidden" name="<c:out value="${status.expression}"/>" id="<c:out value="${status.expression}"/>" value="<c:out value="${status.value}"/>"/>
</spring:bind>
<spring:bind path="command.updateCartButton">
<input type="submit" value="<spring:message code="orderEntryMessages.ecatalog.button.addToCart" text="Add to Cart" htmlEscape="yes" />" name="<c:out value="${status.expression}"/>" id="<c:out value="${status.expression}"/>" class="sub_buttons"/>
</spring:bind>
...
and the command object declare the model array as:
private List<ModelLink> models = new ArrayList<ModelLink>();
where modelLink is a custom ds.
the first foreach tag handle the the model command object and the 2nd part is the submit button i clicked on.
i think you should use AutoPopulatingList as models to bind list to view and controller. for example please refer link. This might resolve your problem of index.

Resources