Not getting Spring + forEach loop to work - spring-mvc

I'm trying to display a list of messages, but nothing appears. If I debug the homeUser() method below, I can see that the messages list does contain a list of messages.
In the jsp page homeUser, IntelliJ indicates that ${messages} references the right model.
So why on earth does nothing appear?
#RequestMapping("/user_home")
public String homeUser(Model model) {
logger.info("homeUser called");
List<Message> messages = messageService.getAllMessages();
model.addAttribute("messages", messages);
return "userHome";
}
<c:forEach var="message" items="${messages}">
<tr>
<td>
${message.author}
<br/>
${message.text}
</td>
</tr>
</c:forEach>

In message class, You must have public getter and setter method

There can be two reasons for this i guess.
Your Message class doesn't has proper getter and setters for the fields you're trying to access.
In your JSP, you have

Related

inside single view create form as well as display data

I am creating a view page where I need to display data and as well as a form to insert data. To insert data I have bootstrap modal. How can I bind my view page so that I can have data to display in the page as well as create form to insert data. I mean how can I bind my view to display data?
public ActionResult GetFirm()
{
return View(db.FirmModels.ToList());
}
My view page
#model models.FirmModel
// code for bootstrap modal
// code for data table
<table id="tblFirmData">
<thead>
<tr>
<th>Edit/Print</th>
<th style="visibility:hidden;">#Html.DisplayNameFor(model => model.FirmId)</th>
<th>NAME</th>
<th>CONTACT</th>
</tr>
</thead>
<tbody>
#foreach(var item in models)
{
int status = item.FirmRegistrationStatus;
}
</tbody>
</table>
When I do foreach(var item in models) getting error 'models' is a namespace but is used like a variable and when I do #foreach(var item in Model) I am getting error foreach statement cannot operate on variables of type 'FirmModel' because 'FirmModel' does not contain a public instance definition for 'GetEnumerator'.
How to solve this problem, shall I need to modify my GetFirm return method or need to change in view page?
Because of you pass a list to the view define you view model as:
#model IEnumerable<models.FirmModel>
The IEnumerable interface is implementing the GetEnumerator() method used to iterate through the collection.
Or:
#model IList<models.FirmModel>
The IList interface inherits the IEnumerable.
And correspondingly:
#foreach(var item in Model)
{
....
}

Spring/Thymeleaf throws "Cannot create a session after the response has been committed" when processing #PostMapping

I build a Spring MVC application with thymeleaf views and ran into the following problem. I have a page which should process a form and create a new Entity to persist in the database. In my controller class I have two methods for this. First, the #GetMapping to render the page:
#GetMapping("/dispo/orderCreate")
private String showCreateOrder(Model model) {
List<MdUser> userList = service.getUsers();
model.addAttribute("userList", userList);
return "/dispo/orderCreate";
}
As far as I just wanted to show the page without adding some action to the form, everything works fine. The model attribute "userList" is correctly populated with users from the database.
Now I changed the view to add an action and an object to the form. The code of the view now looks like this:
<form action="#" class="form" id="newOrderForm" th:action="#{/dispo/addOrder}" th:object="${loadOrder}" method="post">
<table class="cont-table" cellpadding="2" cellspacing="2" width="100%">
<tbody>
<tr align="left">
<th align="left" valign="top" width="110">Protokollführer:</th>
<td>
<table border="0" cellpadding="0" cellspacing="1" width="100%">
<tbody>
<tr>
<td height="30">
<select class="selectOneMenue" id="newOrderPersoDropDown" th:field="*{supervisor}">
<option>Bitte auswählen</option>
<option th:each="user : ${userList}"
th:value="user.userId"
th:text="${user.firstName}+' '+${user.lastName}"></option>
</select>
</td>
. . .
</tr>
</tbody>
</table>
<br />
<input style="width:200px" type="submit" value="Speichern" class="commandExButton" id="newOrderSubmit" />
<input style="width:120px" type="reset" value="Zurücksetzen" class="commandExButton" id="newOrderReset" />
</form>
The corresponding #PostMapping looks like this:
#PostMapping("/dispo/addOrder")
public String submit(#ModelAttribute("loadOrder") LoadOrderModel loadOrder, BindingResult result, Model model) {
if (result.hasErrors()) {
return "error";
}
service.createAndSaveLoadOrder(loadOrder);
return "/dispo/success";
}
Now the rendering of the view crashes when the form is reached with the following stacktrace:
Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Error during execution of processor 'org.thymeleaf.spring5.processor.SpringActionTagProcessor' (template: "/dispo/orderCreate" - line 41, col 58)
at org.thymeleaf.processor.element.AbstractAttributeTagProcessor.doProcess(AbstractAttributeTagProcessor.java:117) ~[thymeleaf-3.0.9.RELEASE.jar:3.0.9.RELEASE]
at org.thymeleaf.processor.element.AbstractElementTagProcessor.process(AbstractElementTagProcessor.java:95) ~[thymeleaf-3.0.9.RELEASE.jar:3.0.9.RELEASE]
at org.thymeleaf.util.ProcessorConfigurationUtils$ElementTagProcessorWrapper.process(ProcessorConfigurationUtils.java:633) ~[thymeleaf-3.0.9.RELEASE.jar:3.0.9.RELEASE]
at org.thymeleaf.engine.ProcessorTemplateHandler.handleOpenElement(ProcessorTemplateHandler.java:1314) ~[thymeleaf-3.0.9.RELEASE.jar:3.0.9.RELEASE]
at org.thymeleaf.engine.TemplateHandlerAdapterMarkupHandler.handleOpenElementEnd(TemplateHandlerAdapterMarkupHandler.java:304) ~[thymeleaf-3.0.9.RELEASE.jar:3.0.9.RELEASE]
at org.thymeleaf.templateparser.markup.InlinedOutputExpressionMarkupHandler$InlineMarkupAdapterPreProcessorHandler.handleOpenElementEnd(InlinedOutputExpressionMarkupHandler.java:278) ~[thymeleaf-3.0.9.RELEASE.jar:3.0.9.RELEASE]
at org.thymeleaf.standard.inline.OutputExpressionInlinePreProcessorHandler.handleOpenElementEnd(OutputExpressionInlinePreProcessorHandler.java:186) ~[thymeleaf-3.0.9.RELEASE.jar:3.0.9.RELEASE]
at org.thymeleaf.templateparser.markup.InlinedOutputExpressionMarkupHandler.handleOpenElementEnd(InlinedOutputExpressionMarkupHandler.java:124) ~[thymeleaf-3.0.9.RELEASE.jar:3.0.9.RELEASE]
at org.attoparser.HtmlElement.handleOpenElementEnd(HtmlElement.java:109) ~[attoparser-2.0.4.RELEASE.jar:2.0.4.RELEASE]
at org.attoparser.HtmlMarkupHandler.handleOpenElementEnd(HtmlMarkupHandler.java:297) ~[attoparser-2.0.4.RELEASE.jar:2.0.4.RELEASE]
at org.attoparser.MarkupEventProcessorHandler.handleOpenElementEnd(MarkupEventProcessorHandler.java:402) ~[attoparser-2.0.4.RELEASE.jar:2.0.4.RELEASE]
at org.attoparser.ParsingElementMarkupUtil.parseOpenElement(ParsingElementMarkupUtil.java:159) ~[attoparser-2.0.4.RELEASE.jar:2.0.4.RELEASE]
at org.attoparser.MarkupParser.parseBuffer(MarkupParser.java:710) ~[attoparser-2.0.4.RELEASE.jar:2.0.4.RELEASE]
at org.attoparser.MarkupParser.parseDocument(MarkupParser.java:301) ~[attoparser-2.0.4.RELEASE.jar:2.0.4.RELEASE]
... 87 common frames omitted
Caused by: java.lang.IllegalStateException: Cannot create a session after the response has been committed
at org.apache.catalina.connector.Request.doGetSession(Request.java:3030) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
at org.apache.catalina.connector.Request.getSession(Request.java:2468) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
at org.apache.catalina.connector.RequestFacade.getSession(RequestFacade.java:896) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
at org.apache.catalina.connector.RequestFacade.getSession(RequestFacade.java:908) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:240) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:240) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
at org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.saveToken(HttpSessionCsrfTokenRepository.java:63) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
at org.springframework.security.web.csrf.LazyCsrfTokenRepository$SaveOnAccessCsrfToken.saveTokenIfNecessary(LazyCsrfTokenRepository.java:175) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
at org.springframework.security.web.csrf.LazyCsrfTokenRepository$SaveOnAccessCsrfToken.getToken(LazyCsrfTokenRepository.java:127) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
at org.springframework.security.web.servlet.support.csrf.CsrfRequestDataValueProcessor.getExtraHiddenFields(CsrfRequestDataValueProcessor.java:71) ~[spring-security-web-5.0.8.RELEASE.jar:5.0.8.RELEASE]
at org.thymeleaf.spring5.context.webmvc.SpringWebMvcThymeleafRequestDataValueProcessor.getExtraHiddenFields(SpringWebMvcThymeleafRequestDataValueProcessor.java:80) ~[thymeleaf-spring5-3.0.9.RELEASE.jar:3.0.9.RELEASE]
at org.thymeleaf.spring5.requestdata.RequestDataValueProcessorUtils.getExtraHiddenFields(RequestDataValueProcessorUtils.java:79) ~[thymeleaf-spring5-3.0.9.RELEASE.jar:3.0.9.RELEASE]
at org.thymeleaf.spring5.processor.SpringActionTagProcessor.doProcess(SpringActionTagProcessor.java:118) ~[thymeleaf-spring5-3.0.9.RELEASE.jar:3.0.9.RELEASE]
at org.thymeleaf.standard.processor.AbstractStandardExpressionAttributeTagProcessor.doProcess(AbstractStandardExpressionAttributeTagProcessor.java:142) ~[thymeleaf-3.0.9.RELEASE.jar:3.0.9.RELEASE]
at org.thymeleaf.processor.element.AbstractAttributeTagProcessor.doProcess(AbstractAttributeTagProcessor.java:74) ~[thymeleaf-3.0.9.RELEASE.jar:3.0.9.RELEASE]
... 100 common frames omitted
Line 41 as indicated by the TemplateProcessingException is the line with the form tag.
I have nearly no experience with frontend development so please have patience with me. I think I have to do some http session managing here but don't know what to do and how to do it. Can anyone help me?
I finally made it. The problem indeed lied in the http session, or to be more precise, in the HttpSecurity. So I added the following to my configure method in my SecurityConfig class:
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.ALWAYS)
I still have to find out what SessionCreationPolicy.ALWAYS means for the rest of my application but for now it works :D .
I was also having the same issue; applied the suggestion by #Raistlin and its working fine now!!
I had a modal dialog with "form-post" in the lading page. It will fail if I try the modal first. And works fine if I try a GET page first, and come back to this page; definitely something to do with session.
always – a session will always be created if one doesn't already exist
ifRequired – a session will be created only if required (default)
never – the framework will never create a session itself but it will use one if it already exists
stateless – no session will be created or used by Spring Security
https://www.baeldung.com/spring-security-session
You need to create new instance for the form object
#GetMapping("/dispo/orderCreate")
private String showCreateOrder(Model model) {
// ...
model.addAttribute("loadOrder", new LoadOrderModel();
return "/dispo/orderCreate";
}
In order to use th:object in a form, we must be able to map a new entity to that form. You can send it though an attribute or you can set a method like the one below in your controller and it will do it automatically for you.
#ModelAttribute(value = "loadOrder")
public LoadOrderModel newLoadOrder() {return new LoadOrderModel();}
I ran into the same Problem while upgrading from Spring Boot 1.x to 2.x (which also includes a newer Thymeleaf version).
My problem was that Thymeleaf tried to automatically create a hidden csrf input for each html form. The generated csrf tokens needed to be persisted in the http session.
Enabling sessions (like shown by #Raistlin) or disabling csrf protection (http.csrf().disable()) solved the issue for me.
You can also limit csrf token to certain pages using http.csrf().requireCsrfProtectionMatcher(..) or http.csrf().ignoringRequestMatchers(..)

how to insert partial view from another controller in asp.net mvc 5

I want to insert a partial view from NewsController into HomeController.
In my NewsController
public ActionResult LastNewsPatial()
{
var lstLastNews = db.Articles.Take(5).OrderByDescending(m => m.CreatedDate).ToList();
return PartialView(lstLastNews);
}
In Views/News folder i create LastNewsPatial.cshtml
#model IEnumerable<mytest.com.Models.Article>
#foreach (var item in Model) {
<div class="glidecontent">
<img src="#item.ImageURL" style="float: left; margin-right:21px;" />
<strong>#item.Title</strong><br /><br />
#item.Content
</div>
}
In Views/Home/Index.cshtml i insert a LastNewsPatial view
#Html.Partial("~/Views/News/LastNewsPatial.cshtml")
When i run my project then I received a error
Object reference not set to an instance of an object.
at row
#foreach (var item in Model)
in LastNewsPatial.cshtml
How can I fix it?
The reason for your error is that the Model isn't passed to the view... infact the action isn't even called at all. Set a breakpoint and you'll confirm this.
I think you should be calling #Html.RenderAction inside the index instead of #Html.Partial.
Instead of #Html.Partial("~/Views/News/LastNewsPatial.cshtml")
use
#Html.RenderAction("LastNewsPatial","News")
or #Html.Action("LastNewsPatial","News")
You don't need to give .cshtml in name of view when rendering a view. Only give name of PartialView without .cshtml like this.
#Html.Partial("~/Views/Shared/LastNewsPatial")
You can also use #Html.Action() to render your view like this
#Html.Action("LastNewsPatial","News")
This worked for me: #Html.Partial("../Views/Shared/LastNewsPatial")
The .. instead of the ~
Some of the answers here are missing the question
You use this
#Html.Partial("~/Views/News/LastNewsPatial.cshtml")
Which creates a partial view without a model. So in order for this to work you need to pass model.
#Html.Partial("~/Views/News/LastNewsPatial.cshtml", your_model)
Your problem is not view related and you simply pass no object to the partial. How to do it is up to you. Do you want a Html.Partial or Html.Action? Depending on your needs.
P.S.
Use RenderPartial and RederAction they are better practices since Partial and Action return an HTML string where instead using render allows ASP.NET to write directly to the response stream.

Delete Field Spring MVC

I am using SimpleFormController with a result page looking like this:
<tr>
<td>Name: </td>
<td>${product.name}</td>
</tr>
<tr>
<td>Text: </td>
<td>${product.text}</td>
</tr>
A user can enter a name and some text. I'm trying to implement a delete functionality for each entry (there should be a link next to each entry). I'm having trouble with understanding, if it can be done in the same Controller as for the input or not (am new to Spring) and how. The onSubmit method helps to display data that was added, do I need to implement an extra delete method? If yes, how can I "map" it to my delete link in my jsp?
I suppose you are not wanting to put a delete link even when the user is just entering the name!
Delete links should normally appear when you are displaying data, not creating them.
Here is how you can create a delete link according to associated ids.
<tr>
<td>Name: </td>
<td>${product.name}</td>
<td>delete</td>
</tr>
and this should be in your controller:
#Controller
public class ProductController{
#RequestMapping("/delete/{id}")
public String deleteProduct(#PathVariable("id")Integer id) {
// get product by id
// delete that product
// save database
// or do as you wish
return "redirect:/index";
}
}
Hope that helps :)

How to output HTML Table instead of a Select box (generated with ListBoxFor) in ASP.NET?

I am generally new to ASP.NET and am modifying some code that I've inherited. There is a section of code that creates a Select box using a ListBoxFor based on a search term that's entered by the user:
#Html.ListBoxFor(m => m.SelectedItem,
Lookup.Models.myService.Search(Model.SearchTerm,
null == Model.SelectedCity ? 1 :
Int32.Parse(Model.SelectedCity))
The signature for Search() is:
public static List<SelectListItem> Search(string term, string city)
Instead of displaying a Select box, I want to output an HTML table instead with the data. I'm not even sure how to go about doing this or really what info to give you all in order to help me :)
The ListBoxFor helper displays <select> elements with multiple="multiple" attribute allowing multiple selections. If you want something else you should not use this helper. So you said that you wanted an HTML table.
Now, there's something very wrong with the code you have shown. You are calling Lookup.Models.myService.Search inside a view. Views are not supposed to pull data from some places. They are supposed to only display data that is being passed to them under the form of view models by a controller action. So this call should not be done in the view. It should be done beforehand and the result stored as a property on your view model:
public IEnumerable<SelectListItem> Items { get; set; }
Anyway. The first possibility is to write the markup yourself:
<table>
<thead>
<tr>
<th>Value</th>
<th>Text</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.Items)
{
<tr>
<td>#item.Value</td>
<td>#item.Text</td>
</tr>
}
</tbody>
</table>
Of course writing this code over and over again could become cumbersome. So you could externalize it in a DisplayTemplate. For example you could put it inside a ~/Views/Shared/DisplayTemplates/MyTableTemplate.cshtml and then when you needed to render it in a view you could use:
#Html.DisplayFor(x => x.Items, "MyTableTemplate")

Resources