Spring thymeleaf problems: exception processing template - java

I'm building a simple web service with spring and thymeleaf. That's the code for now:
Controller:
package com.Basi.CheBBellaEmittente.Pages.Control;
#Controller
public class SimpleController {
#GetMapping("/nuovo-utente")
public String viewInserisciUtente(Model model){
model.addAttribute("nuovoUtente", new Utente());
return "nuovo-utente";
}
#PostMapping("/nuovo-utente")
public void memorizzaUtente(#ModelAttribute Utente utente){
System.out.println(utente.getId());
}
}
Model:
package com.Basi.CheBBellaEmittente.Pages.Model;
public class Utente {
private String id;
private String citta=null;
private String genere;
private String data_nascita=null;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getCitta() {
return citta;
}
public void setCitta(String citta) {
this.citta = citta;
}
public String getGenere() {
return genere;
}
public void setGenere(String genere) {
this.genere = genere;
}
public String getData_nascita() {
return data_nascita;
}
public void setData_nascita(String data_nascita) {
this.data_nascita = data_nascita;
}
}
html page:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Inserisci un nuovo utente</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h1>Form</h1>
<form action="#" th:action="#{/nuovo-utente}" th:object="${com.Basi.CheBBellaEmittente.Pages.Model.Utente}" method="post">
<p>Id: <input type="text" th:field="*{id}" /></p>
<p>Città: <input type="text" th:field="*{citta}" /></p>
<p>Genere: <input type="text" th:field="*{genere}" /></p>
<p>Data nascita: <input type="text" th:field="*{data_nascita}" /></p>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>
</body>
</html>
and the error:
2018-09-21 16:51:40.668 ERROR 3132 --- [nio-8080-exec-1] org.thymeleaf.TemplateEngine : [THYMELEAF][http-nio-8080-exec-1] Exception processing template "nuovo-utente": Exception evaluating SpringEL expression: "com.Basi.CheBBellaEmittente.Pages.Model.Utente" (template: "nuovo-utente" - line 9, col 51)
So, what can I do to handle this situation? I don't know what's wrong with this, is a very simple code. Can you give me some advice? I'm supposing is some fold packages issue but I can't understand what.

Since your model attribute is named nuovoUtente -- model.addAttribute("nuovoUtente", new Utente());, that's what you should be using as your th:object.
<form action="#" th:action="#{/nuovo-utente}" th:object="${nuovoUtente}" method="post">
An expression like this: ${com.Basi.CheBBellaEmittente.Pages.Model.Utente} will be interpreted as: com.getBasi().getCheBBellaEmittente().getPages().getModel().getUtente() -- which doesn't make sense.

In your controller you set the name of your model attribute to nuovoUtente so you have to do the next on the html:
<form action="#" th:action="#{/nuovo-utente}" th:object="${nuovoUtente}" method="post">
You want to create and submit a form. On the #GetMapping and #PostMapping you have to set different urls.
For example:
#GetMapping(/nuevo-utente-form) and #PostMapping(/nuevo-utente)
In the nuevo-utetente-form.html you write the code of the form, and in nuevo-utente.html you write the code for accept the form.

th:object="${com.Basi.CheBBellaEmittente.Pages.Model.Utente}"
it should point to actual object instance that you pass in your view model, not its class, so probably
th:object="${utente}"
is what it should be.

Related

Request method 'POST' not supported]

I have a problem with updatePowerPlant() method, when I try to update powerPlant entity with given id and click the submit button in the update form under localhost:8080/updatePowerPlant adress I get redirected to this url http://localhost:8080/updatePowerPlant/savePowerPlant.
I don't know why. I should get redireted to /powerPlants, wethever entity with given id exists or not, instead /savePowerPlant is added as a last part of a url localhost:8080/updatePowerPlant and I get Request method 'POST' not supported], I know that this is the message I should get afterall there is no GetController with such url but why do I get this weird url? Is it because I use GetController for update?
localhost:8080/updatePowerPlant this I enter in browser to get update form
http://localhost:8080/updatePowerPlant/savePowerPlant this I get when I clik submit in update form
Controller class
#RequiredArgsConstructor
#Controller
public class PowerPlantsController {
private final PowerPlantRepository powerPlantRepository;
private final EventRepository eventRepository;
private final PlantService plantService;
private final EventService eventService;
#GetMapping("form")
public String getForm(Model model) {
model.addAttribute("plant", new PlantViewModel());
return "save";
}
#PostMapping("savePowerPlant")
public String addPowerPlant(#ModelAttribute("plant") #Valid PlantViewModel plant, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
if (plant.getId() == null) {
return "save";
} else return "updatePowerPlant";
}
if (plant.getId() == null){
plantService.add(plant);
}else {
plantService.update(plant);
}
return "redirect:/powerPlants";
}
#GetMapping("updatePowerPlant/{id}")
public String updatePowerPlant(#PathVariable(value = "id") Integer id, Model model) {
var find = powerPlantRepository.getOne(id);
var plants = plantService.powerPlantToViewModel(find);
model.addAttribute("plant", plants);
return "updatePowerPlant";
}
#ResponseBody
#GetMapping("failures/{id}")
public long failures(#PathVariable("id") int id) {
return eventService.NumberOfFailureEventsForId(id);
}
#ResponseBody
#GetMapping("powerPlants")
public List<PowerPlant> findAll() {
return powerPlantRepository.findAll();
}
#GetMapping("powerPlants/{id}")
public String findById(#PathVariable("id") Integer id, Model model) {
model.addAttribute("plant", powerPlantRepository.getOne(id));
return "plant";
}
#GetMapping("delete/powerPlants")
public String deleteById(#RequestParam(value = "id") Integer id) {
powerPlantRepository.deleteById(id);
return "redirect:/powerPlants";
}
#GetMapping("addEventToPlant")
public String addEventToPlant(#RequestParam(value = "plantId") Long plantId, #RequestParam(value = "eventId")
Long eventId, Model model) {
if (powerPlantRepository.findById(Math.toIntExact(plantId)).isPresent()
&& eventRepository.findById(Math.toIntExact(eventId)).isPresent()) {
var pl = powerPlantRepository.getOne(Math.toIntExact(plantId));
var ev = eventRepository.getOne(Math.toIntExact(eventId));
var eventsForPlant = pl.getEvents();
eventsForPlant.add(ev);
pl.setEvents(eventsForPlant);
powerPlantRepository.save(pl);
}
var t = powerPlantRepository.getOne(Math.toIntExact(plantId)).getEvents();
model.addAttribute("plant", t);
return "plant_events";
}
}
Service class
#org.springframework.stereotype.Service
#RequiredArgsConstructor
public class PlantService implements powerForPowerPlantPerDay, Add, PlantServiceToViewModel {
private final EventRepository eventRepository;
private final PowerPlantRepository powerPlantRepository;
public Map<Integer, String> powerForPowerPlantPerDay(Timestamp date) {
List<Event> list = new ArrayList<>(getAllEvents());
Map<Integer, String> map = new HashMap<>();
list.stream()
.filter(e -> e.startDate.equals(date))
.forEach(e -> map.put(e.id, e.typeOfEvent));
return map;
}
public Collection<Event> getAllEvents() {
return eventRepository.findAll();
}
public void add(PlantViewModel plantViewModel) {
var p = PowerPlant.builder().
name(plantViewModel.getName())
.power(plantViewModel.getPower())
.events(plantViewModel.getListOfEventsForPlant())
.build();
powerPlantRepository.save(p);
}
public PlantViewModel powerPlantToViewModel(PowerPlant powerPlant) {
return PlantViewModel.builder()
.id(powerPlant.getId())
.name(powerPlant.getName())
.power(powerPlant.getPower())
.build();
}
public PowerPlant update(PlantViewModel plantViewModel) {
var plant = powerPlantRepository.getOne(plantViewModel.getId());
plant.setName(plantViewModel.getName());
plant.setPower(plantViewModel.getPower());
return powerPlantRepository.save(plant);
}
}
update html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"/>
</head>
<body>
<div class="container">
<h1>Update</h1>
<hr>
<h2>Update powerPlant</h2>
<form action="#" th:action="#{savePowerPlant}" th:object="${plant}" method="POST">
<input id="studentId" th:value="${plant.id}" type="hidden" th:field="*{id}">
<div th:if="${#fields.hasErrors('name')}" th:errors="*{name}">Invalid Name</div>
<input type="text" th:field="*{name}" placeholder="Name" class="form-control mb-4 col-4">
<div th:if="${#fields.hasErrors('power')}" th:errors="*{power}">Invalid power</div>
<input type="text" th:field="*{power}" placeholder="power" class="form-control mb-4 col-4">
<button type="submit" class="btn btn-info col-2">Save</button>
</form>
<hr>
</div>
</body>
</html>
save html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>New Student</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"/>
</head>
<body>
<div class="container">
<h1>Save</h1>
<hr>
<h2>Save powerPlant</h2>
<form action="#" th:action="#{savePowerPlant}" th:object="${plant}" method="POST">
<div th:if="${#fields.hasErrors('name')}" th:errors="*{name}">Invalid Name</div>
<input type="text" th:field="*{name}" placeholder="Name" class="form-control mb-4 col-4">
<div th:if="${#fields.hasErrors('power')}" th:errors="*{power}">Invalid power</div>
<input type="text" th:field="*{power}" placeholder="power" class="form-control mb-4 col-4">
<button type="submit" class="btn btn-info col-2">Save</button>
</form>
<hr>
</div>
</body>
</html>
As you can see here in the documentation you are using relative URLs in your th:action. These get appended to the current URL in the address bar.
So th:action="#{savePowerPlant}" results in current/URL/savePowerPlant.
Simple solution is to switch to absolute URLs either by typing it out completely (http://localhost:portNumber/savePowerPlant) or perhaps even better use server relative URL: th:href="#{~/savePowerPlant}.

ThymeLeaf: Neither BindingResult nor plain target object for bean name available as request attribute

I am trying to build a simple select and Option list in thymeleaf, but i keep getting the error
Neither BindingResult nor plain target object for bean name 'BOLForm' available as request attribute
I am pretty sure there is something wrong with my bol.html. But not able to figure out the missing mappings.
Below is my Controller:
#Controller
public class BillOfLadingController {
#Autowired
private DepotList depotList;
#GetMapping("/BillOfLading")
public String getBOLForm(){
return "bol";
}
#PostMapping("/BillOfLading")
public String Login(#ModelAttribute(name="BOLForm") BOLForm bolForm,Model model) {
model.addAttribute("BOLForm", bolForm);
List<DepotDetailEntity> depotDropDown = depotList.getDepots().getDepotDetail();
if(depotDropDown.size() == 0) {
return "login";
}
model.addAttribute("depots", depotDropDown);
return "bol";
}
}
The Form Class
#Component
public class BOLForm {
private String BOL;
private String depotId;
public String getBOL() {
return BOL;
}
public void setBOL(String bOL) {
BOL = bOL;
}
public String getDepotId() {
return depotId;
}
public void setDepotId(String depotId) {
this.depotId = depotId;
}
}
the bol.html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>BillOfLading Request Page</title>
</head>
<body>
<h1>BillOfLading Report</h1>
<form th:action="#{/BillOfLading}" th:object="${BOLForm}" method="post">
<label for="bol">BOL No.</label>
<input type="text" id="bol" name="bol">
<br/>
<table>
<tr>
<td>Select DC:</td>
<td>
<select th:field="*{depotId}">
<option value=""> -- </option>
<option th:each="depot : ${depots}"
th:value="${depot.depotId}"
th:utext="${depot.depotName}"/>
</select>
</td>
</tr>
<tr>
<td><input name="submit" type="submit" value="submit" /></td>
</tr>
</table>
</form>
</body>
</html>
When I replace my bol.html as below, it works:
<form th:action="#{/BillOfLading}" th:object="${BOLForm}" method="post">
<label for="bol">BOL No.</label>
<input type="text" id="bol" name="bol">
<br/>
<label for="depotId">DepotID </label>
<input type="text" id="depotId" name="depotId">
<br/>
In the controller, you need to add the BOLForm object as an attribute of the model:
#GetMapping("/BillOfLading")
public String getBOLForm(Model model){
model.addAttribute("BOLForm", new BOLForm());
return "bol";
}

Error:Neither BindingResult nor plain target object for bean name 'id' available as request attribute

i am using the thymeleaf and spring. i want to implement the post request.
my controller class is
public class URLController {
#RequestMapping(value = "index")
public String index1(Model model){
model.addAttribute("employee",new Employee());
return "index";
}
#RequestMapping(value = "/")
public String index(Model model){
model.addAttribute("employee",new Employee());
return "index";
}
#PostMapping("/result")
public String result(#ModelAttribute Employee employee){
System.out.print(employee.getName());
return "result";
}
}
and the html page is
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index page</title>
</head>
<body>
<form action="#" th:action="#{/result}" modelAttribute="employee" method="post">
<p>Id: <input type="text" th:field="*{id}" /></p>
<p>name: <input type="text" th:field="*{name}" /></p>
<p>phone: <input type="text" th:field="*{phone}" /></p>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>
</body>
</html>
there is no binding with the id field.
In your HTML, you need to use the proper syntax for your model attribute. Spring is complaining that it can't find the property id because you are providing the string employee, not the object.
modelAttribute="employee" --> th:object="${employee}"
Additionally, you can consolidate to:
#Controller //please add this
public class URLController {
#GetMapping({"/", "/index"})
public String index1(Model model){
model.addAttribute("employee",new Employee());
return "index";
}
#PostMapping("/result")
public String result(#ModelAttribute Employee employee){
System.out.print(employee.getName()); //use a logger instead
return "result"; //may want to return a different page name for clarity
}
}
Your IDE will not complain if you change your HTML tag to:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
Lastly, you may want to use the tel input type for the phone field. Doing so will allow for a custom keyboard to show for mobile users.

Spring thymeleaf give error in post request

I have this simple code: This is my controller class where i redirecting to a page
#Controller
public class SimpleController {
#GetMapping("/nuovo-utente")
public String viewInserisciUtente(Model model){
model.addAttribute("nuovoUtente", new Utente());
return "nuovo-utente";
}
#PostMapping("/nuovo-utente")
public void memorizzaUtente(#ModelAttribute Utente utente){
System.out.println(utente.getId());
}
}
This is model class.
public class Utente {
private String id=null;
private String citta=null;
private String genere=null;
private String data_nascita=null;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getCitta() {
return citta;
}
public void setCitta(String citta) {
this.citta = citta;
}
public String getGenere() {
return genere;
}
public void setGenere(String genere) {
this.genere = genere;
}
public String getData_nascita() {
return data_nascita;
}
public void setData_nascita(String data_nascita) {
this.data_nascita = data_nascita;
}
}
and My html page with thymeleaf is like :
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Inserisci un nuovo utente</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h1>Form</h1>
<form action="#" th:action="#{/nuovo-utente}" th:object="${nuovoUtente}" method="post">
<p>Id: <input type="text" th:field="*{id}" /></p>
<p>Città: <input type="text" th:field="*{citta}" /></p>
<p>Genere: <input type="text" th:field="*{genere}" /></p>
<p>Data nascita: <input type="text" th:field="*{data_nascita}" /></p>
<p><input type="submit" value="Submit" /> <input type="reset" value="Reset" /></p>
</form>
</body>
</html>
So, as I said into the title, this simple code for a form give me error when I try to submit the form by post request. The error is the above:
Error during execution of processor 'org.thymeleaf.spring5.processor.SpringInputGeneralFieldTagProcessor' (template: "nuovo-utente" - line 10, col 32)
What can you say to me? Some help will be appreciate
You have to use diferent html and urls. One to create the form and another one to submit the form. You are using the same url.
First of all in your html page change
<html xmlns:th="http://www.thymeleaf.org">
to
<html xmlns:th="http://www.w3.org/1999/xhtml">
And write your controller class like
#PostMapping("/nuovo-utente")
public String memorizzaUtente(#ModelAttribute("nuovoUtente") Utente utente) {
System.out.println(utente.getId());
return "any page";
}
}

When using Spring, When is the Form class property stored in the value that's sent from the html form tag?

I should implement like execute(#ModelAttribute RegisterForm registerForm, Model model) in Controller class below.
I forgot put the #ModelAttribute.
However it works. When is name in RegisterForm class stored in the value that's sent from html?
Part of Controller class
#Controller
public class RegisterController {
#RequestMapping(value = "/register/")
public String register() {
return "register";
}
#RequestMapping(value="/register/execute", method=RequestMethod.POST)
//(#ModelAttribute RegisterForm registerForm, Model model) is better
public String execute(RegisterForm registerForm, Model model) {
model.addAttribute("registered_name", registerForm.getName());
return "index";
}
}
Form class
public class RegisterForm {
private String name; //when is this property stored in the value??
public String getName() {
return name;
}
}
Part of HTML file
<div class="input">
<p>Enter your name</p>
<input type="text" name="name" />
</div>
Please let me know if you need more information to solve this.Thanks.
add setter name to your class RegisterForm it's important
you should lik this :
<form action="register/execute">
<div class="input">
<p>Enter your name</p>
<input type="text" name="name" />
</div>
<form>
or usign tag form spring :
add this in your controller
#RequestMapping(value="/index", method=RequestMethod.POST)
public String executet(Model model) {
model.addAttribute("registerForm ", new RegisterForm ());
return "index";
}
include this code in your jsp
<%# taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<form:form method="POST" modelAttribute="registerForm ">
<form:input path="name" />
<input type="submit" value="Register">
</form:form>

Categories