Why javax validation not working in DTO class? - java

I am trying to learn the spring boot. And, I am stuck on the form validation process. I have followed the process as instructed here.
Here is my controller class
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
#Controller
public class TalentCategoryController {
#GetMapping("talent-category")
public ModelAndView create(CreateTalentCategoryRequest talentCategory) {
ModelAndView model = new ModelAndView();
model.setViewName("talent-category/create");
model.addObject("talentCategory", talentCategory);
return model ;
}
#Autowired
TalentCategoryService talentCategoryService ;
#RequestMapping(path="talent-category", method = RequestMethod.POST, consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
public ModelAndView store(#Valid #ModelAttribute CreateTalentCategoryRequest talentCategory, BindingResult result) {
// result.hasErrors is false
if(result.hasErrors()) {
System.out.println("Validation working");
ModelAndView model = new ModelAndView();
model.setViewName("talent-category/create");
return model;
}
System.out.println("Validation not working");
talentCategoryService.store();
return null ;
}
}
DTO class :
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import lombok.Data;
#Data
public class CreateTalentCategoryRequest {
#NotBlank(message="Cannot be empty")
#Size(min=10, max=30)
private String name ;
#NotBlank(message="Cannot be empty")
private String status ;
#NotBlank(message="Cannot be empty")
private String approved ;
#NotBlank(message="Cannot be empty")
private String sort_order ;
}
View :
<form th:object="${talentCategory}" name="create-talent-category" method="POST" th:action="#{/talent-category}">
<div class="row">
<div class="col-4">
<div class="form-group">
<label for="name">Name</label>
<input th:field="*{name}" type="text" class="form-control form-control-sm" id="name" placeholder="Category Name" />
<p class="alert alert-danger" th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></p>
</div>
</div>
<div class="col-2">
<div class="form-group">
<label for="sort_order">Sort Order</label>
<input type="text" class="form-control form-control-sm" id="sort_order" placeholder="Eg : 1" />
</div>
</div>
<div class="col-2">
<div class="form-group">
<label for="status">Status</label>
<select name="status" id="status" class="form-control form-control-sm">
<option selected>Choose...</option>
<option value="1">Active</option>
<option value="0">Passive</option>
</select>
</div>
</div>
<div class="col-2">
<div class="form-group">
<label for="approved">Approved</label>
<select name="approved" id="approved" class="form-control form-control-sm">
<option selected>Choose...</option>
<option value="1">Yes</option>
<option value="0">No</option>
</select>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<button name="create" class="btn btn-sm btn-primary">Create</button>
</div>
</div>
</form>
When a form is submitted with all the fields empty, the request is not redirect to the form(prints validation not working in console).

if you are using spring version 2.3+ , make sure you have following dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

Related

Spring Thymeleaf - POST into ResponseEntity?

Been at this all day. I may be missing an annotation somewhere. I also cannot get this app to serve the index.html.
What am I missing here? The primary issue is not being able to get the form to submit anything to the backend. Is ModelAttribute correct?
Thanks in advance.
Controller:
package com.lms.application.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.lms.application.entity.Course;
import com.lms.application.service.CourseService;
#RestController
#RequestMapping("/courses")
public class CourseController {
#Autowired
private CourseService service;
#RequestMapping(method=RequestMethod.GET)
public ResponseEntity<Object> getCourses(){
return new ResponseEntity<Object>(service.getCourses(), HttpStatus.OK);
}
#RequestMapping(value="/submit", method=RequestMethod.POST)
public ResponseEntity<Object> createCourse(#ModelAttribute("course") Course course){
return new ResponseEntity<Object>(service.createCourse(course), HttpStatus.CREATED);
}
Form
<div class="container">
<form method="post" th:object="${course}" th:action="#{/courses/submit}">
<div class="row mb-3">
<label for="title" class="col-sm-2 col-form-label">Course Title</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="course.title" th:field="${course.title}"></input>
</div>
</div>
<div class="row mb-3">
<label for="credit" class="col-sm-2 col-form-label">Course
Credits</label>
<div class="col-sm-10">
<input type="number" class="form-control" id="course.credits" th:field="${course.credits}"></input>
</div>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
Before demanding an Object from Thymeleaf you have to create and pass one there. Thymeleaf won't create an object for you.
You need to pass the object via Model to the Controller like so:
#ModelAttribute("course")
public Course course() {
return new Course();
}
You need to make sure Course object has getters, setters and default constructor for Thymeleaf to be able to work with it correctly.

How to get model map from model by key variable thymeleaf

> java controller code
import com.springboot.app.controllers.GlobalController;
import com.springboot.app.entities.Branch;
import com.springboot.app.services.ReportParamsAccessListService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import javax.persistence.Tuple;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
#Controller
public class GlobalReportController extends GlobalController {
#Autowired
ReportParamsAccessListService reportParamsAccessListService;
protected String branchParam(Model model,String paramName,String type, String name){
ModelMap modelMap = new ModelMap();
List<Branch> branchList = branchService.findAll();
modelMap.put("branchList",branchList);
modelMap.put("attr_name",name);
modelMap.put("attr_type",type);
model.addAttribute("branch",modelMap);
return "branch_param";
}
protected String dateParam(Model model,String paramName,String type,String name){
ModelMap modelMap = new ModelMap();
modelMap.put("attr_name",name);
modelMap.put("attr_type",type);
model.addAttribute("date",modelMap);
return "date_param";
}
#RequestMapping(value = "/report/test",method = RequestMethod.GET)
public String reportParams(Model model,String reportLink) {
LinkedHashMap<String,String> params = new LinkedHashMap<String, String>();
List<Tuple> reportParamAccess = reportParamsAccessListService.getReportParamAccess("reports/remittance_rub");
for (int i = 0; i<reportParamAccess.size(); i++){
try {
String name = reportParamAccess.get(i).get("name").toString();
String paramName = reportParamAccess.get(i).get("param_name").toString();
String attrType = reportParamAccess.get(i).get("attr_type").toString();
String attrName = reportParamAccess.get(i).get("attr_name").toString();
switch (name){
case "branch":
params.put(paramName,branchParam(model,paramName,attrType,attrName));
break;
case "date":
params.put(paramName,dateParam(model,paramName,attrType,attrName));
default:
}
} catch (Exception e) {
e.printStackTrace();
}
}
//System.out.println("params = " + params);
model.addAttribute("params",params);
//System.out.println(" dataAlling = " + model);
//return "report_params";
return pageContent(model,"report_params");
}
}
> useing thymealeaf template engine
> html code template brach param fragment
<div class="col-3" xmlns:th="http://www.thymeleaf.org" th:fragment="branch_param">
<div class="form-group" >
<button type="button" id="dropdownUl" class="btn btn-info dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Select Branch
</button>
<div class="dropdown hide">
<ul>
<li th:each="branchList : ${branch.branchList}">
<input th:id = "'md_checkbox_' + ${branchList.id}" th:type="${branch.attr_type}" th:value="${branchList.ip}" th:name="${branch.attr_name}" class="filled-in chk-col-light-blue" />
<label th:for="'md_checkbox_' + ${branchList.id}" th:text="${branchList.name}"></label>
</li>
</ul>
</div>
</div>
</div>
> html code template report params fragment
<ul xmlns:th="http://www.thymeleaf.org" th:fragment="report_params">
<li th:each="paramEntry : ${params}">
<div th:include="${paramEntry.value} :: ${paramEntry.value}" th:with="ParamName=${paramEntry.key}">
</div>
</li>
</ul>
> html code template date params fragment
<div class="col-2" xmlns:th="http://www.thymeleaf.org" th:fragment="date_param">
<div class="form-group" >
<input th:type="${date.attr_type}" th:name="${date.attr_name}" class="form-control" />
</div>
</div>
I want pass variable ParamName from report params to branch param and date param then use ParamName in fragments
for example like this in branch param
<div class="col-3" xmlns:th="http://www.thymeleaf.org" th:fragment="branch_param">
<div class="form-group" >
<button type="button" id="dropdownUl" class="btn btn-info dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Select Branch
</button>
<div class="dropdown hide">
<ul>
<li th:each="branchList : ${ParamName.branchList}">
<input th:id = "'md_checkbox_' + ${branchList.id}" th:type="${branch.attr_type}" th:value="${branchList.ip}" th:name="${branch.attr_name}" class="filled-in chk-col-light-blue" />
<label th:for="'md_checkbox_' + ${branchList.id}" th:text="${branchList.name}"></label>
</li>
</ul>
</div>
</div>
</div>
This is done by preprocessing mechanism in Thymeleaf
Here is a snippet of what you want to do:
<li th:each="branchList : ${__${paramName}__.branchList}">

Java : Cannot send a form with Angular 5 that contain an input of type file to a REST backend (Spring Boot)

i am working in a project in school, backend is a REST based on Spring Boot, Frontend is an Angular 5 application. i have red a lot of tutorials but i cannot
find the right answer for my question:
-How can i post a form that contain an input of type file and others input of type text
-i want to send a form that contain a picture to backend, after that i want to take the file, rename it with unique name and upload it to a folder and put the URL in the DataBase
-i Have this Error in Backend :
Unexpected character ('-' (code 45)) in numeric value: expected digit (0-9) to follow minus sign, for valid numeric value
Here is the Entity:
#Entity
public class Prestataires implements Serializable {
#Id #GeneratedValue
private Long id;
private String nom;
private String email;
private String tele;
private String fax;
private String rib;
private String adresse;
private String taches;
private String photo;
private File file;
//-------------------Constructors--------------------
//-------------------Getters and Setters-------------
}
Here is the RestController Class :
package smart.syndic.web;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import smart.syndic.dao.PrestatairesRepository;
import smart.syndic.entities.Prestataires;
#RestController
#CrossOrigin("*")
public class PrestatairesRestController {
#Autowired
private PrestatairesRepository repository;
#RequestMapping(value="/prestataires",
method=RequestMethod.POST)
public Prestataires addPrestataires(
#RequestBody Prestataires v) {
/*
Here will be the code to process the file coming from front End and
uploading it to folder then put the URL to DataBase
*/
return repository.save(v);
}
}
Here is the front end App:
<form class="form-horizontal form-label-left" #f1="ngForm">
<div id="containerAjouterPrestataires">
</div>
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12">Raison Social/Nom<span class="required">*</span>
</label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input [(ngModel)]="nom" name="nom" type="text" required class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12">Email<span class="required">*</span>
</label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input [(ngModel)]="email" name="email" type="email" required class="form-control col-md-7 col-xs-12">
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12">Téléphone<span class="required">*</span></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input [(ngModel)]="tele" name="tele" class="form-control col-md-7 col-xs-12" type="text" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12">Fax<span class="required">*</span></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input [(ngModel)]="fax" name="fax" class="form-control col-md-7 col-xs-12" type="text" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12">RIB<span class="required">*</span></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input [(ngModel)]="rib" name="rib" class="form-control col-md-7 col-xs-12" type="text" required>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12">Type<span class="required">*</span></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<div class="input-group">
<select class="form-control" name="selectTypes" [(ngModel)]="selectTypes">
<option selected="selected" *ngFor="let s of tousLesPrestatairesTypes" [value]="s.id" >
{{s.designation}}
</option>
</select>
<span class="input-group-btn">
<!-- Button trigger modal -->
<button type="button" class="btn btn-default" data-toggle="modal" data-target="#myModal">
Ajouter Type
</button>
</span>
</div>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12">Adresse<span class="required">*</span>
</label>
<div class="col-md-6 col-sm-6 col-xs-12">
<textarea [(ngModel)]="adresse" name="adresse" class="form-control" rows="3" placeholder="Adresse"></textarea>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12">Tâches<span class="required">*</span>
</label>
<div class="col-md-6 col-sm-6 col-xs-12">
<textarea [(ngModel)]="taches" name="taches" class="form-control" rows="3" placeholder="Tâches"></textarea>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3 col-sm-3 col-xs-12">Photo/Logo<span class="required">*</span></label>
<div class="col-md-6 col-sm-6 col-xs-12">
<input name="photo" class="form-control col-md-7 col-xs-12"
type="file" required="required" accept="image/*"
(change)="handleFileInput($event)">
</div>
</div>
<div class="form-group">
<div class="col-md-6 col-sm-6 col-xs-12 col-md-offset-3">
<button class="btn btn-warning" type="reset">Vider</button>
<button type="button" class="btn btn-success" (click)="ajouterPrestataires()">Ajouter</button>
</div>
</div>
</form>
Here is the TypeScript Controller:
import { Component, OnInit } from '#angular/core';
import {PrestatairesService} from "../../services/prestataires.service";
import {PrestatairesTypeModel} from "../../modeles/prestatairesType.model";
import {PrestatairesModel} from "../../modeles/prestataires.model";
#Component({
selector: 'app-ajouter-prestataires',
templateUrl: './ajouter-prestataires.component.html',
styleUrls: ['./ajouter-prestataires.component.css']
})
export class AjouterPrestatairesComponent implements OnInit {
nom:any;
email:any;
tele:any;
fax:any;
rib:any;
adresse:any;
taches:any;
photo:any;
selectTypes:any;
typePrestataire:any;
tousLesPrestatairesTypes:any;
modelType:any;
imageURL:string = "../assets/images/MeG.jpg";
fileToUpload:File = null;
modelPrestataires:any;
constructor(private service:PrestatairesService) { }
ngOnInit()
{
this.getAllTypes();
}
handleFileInput(file:any)
{
this.fileToUpload = <File>file.target.files[0];
}
ajouterPrestataires()
{
this.modelPrestataires = new PrestatairesModel();
this.modelPrestataires.nom = this.nom;
this.modelPrestataires.email = this.email;
this.modelPrestataires.tele = this.tele;
this.modelPrestataires.fax = this.fax;
this.modelPrestataires.rib = this.rib;
this.modelPrestataires.adresse = this.adresse;
this.modelPrestataires.taches = this.taches;
this.modelPrestataires.file = this.fileToUpload;
this.modelPrestataires.photo = this.photo;
this.getOneType(this.selectTypes);
this.modelPrestataires.prestatairesTypes = this.modelType;
this.service.uploadFile(this.modelPrestataires)
.subscribe(data=>{
console.log("Success");
}, err=>{
console.log("Error");
}, ()=>{
});
}
Here is the service :
import {Injectable} from "#angular/core";
import {HttpClient, HttpEvent, HttpHeaders, HttpParams, HttpRequest} from
"#angular/common/http";
#Injectable()
export class PrestatairesService
{
host:string = "http://localhost:8080/";
constructor(private http:HttpClient)
{
}
uploadFile(model:any){
let formData = new FormData();
formData.append('fichier', model.file);
let headers = new HttpHeaders().set('Content-Type','application/json');
let params = new HttpParams();
const options = {
params: params,
reportProgress: true,
headers: headers
};
const req = new HttpRequest('POST', this.host + "prestataires", formData,
options);
return this.http.request(req);
}
}
When uploading the file to the backend you can use Multipart file. You could also Base64 encode the file in the frontend and send it as a JSON string, but that causes a lot more bytes being sent over the wire.
In the multipart solution your controller should expect a multipart file like so.
Controller
#RestController
#CrossOrigin("*")
public class PrestatairesRestController {
#Autowired
private PrestatairesRepository repository;
#RequestMapping(value="/prestataires", method=RequestMethod.POST)
// you don't have to add #RequestBody for the Prestataires
public String postFileUpload(Prestataires prestataires, #RequestParam("multipartFile") MultipartFile file) {
// Make sure that in the frontend the name of the form field for the file is also multipartFile
// Also make sure that the mime type in the frontend is multipart/form-data
byte[] rawFile;
try {
rawFile = file.getBytes();
} catch (IOException e) {
e.printStackTrace();
return "error?";
}
prestataires.setFile(rawFile);
prestatairesRepository.save(prestataires);
return "redirect:/ or send response";
}
}
Your entity can't just have a File class as field. You need to have a byte[]; you will ultimately be storing raw bytes in your database - I think other datatypes are also allowed.
Entity
#Entity
public class Prestataires implements Serializable {
#Id #GeneratedValue
private Long id;
private String nom;
private String email;
private String tele;
private String fax;
private String rib;
private String adresse;
private String taches;
private String photo;
#Lob
#Column(name = "file", columnDefinition="BLOB")
private byte[] file;
//-------------------Constructors--------------------
//-------------------Getters and Setters-------------
}
For the Angular part I suppose this is a perfect example of what you need to upload files: https://stackoverflow.com/a/40216616/5473627

Spring MVC : Neither BindingResult nor plain target object for bean name 'user' available as

I am working with Spring MVC and I am getting the below error:
Caused by: java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'user' available as request attribute
This error usually occurs when we have not passed/added the object in the model inside the controller code. But I have done that and I am still getting the error.
I have looked through solutions on the internet with exact same errors but all of them point to adding the new object in the controller. Not sure why for me it's not working.
Not sure what I am doing wrong.
This is my form in login.html:
<div class="container">
<div class="starter-template">
<h2>Login</h2>
</div>
<form th:object="${user}" th:method="post" th:action="validateUser" class="form-horizontal">
<table class="table table-striped">
<tr>
<td>
<div class="control-group">
<label class="control-label">Email</label>
</div>
</td>
<td>
<div class="controls">
<input type="text" class="form-control" th:field="*{emailAddress}"/>
<label class="control-label"></label>
</div>
</td>
</tr>
<tr>
<td>
<div class="control-group">
<label class="control-label">Password</label>
</div>
</td>
<td>
<div class="controls">
<input type="password" class="form-control" th:field="*{password}"/>
<label class="control-label"></label>
</div>
</td>
</tr>
<tr>
<td></td>
<td>
<div class="form-actions pull-right">
<input type="submit" name="_eventId_validateUser" value="Login"
class="btn btn-success" tabindex="5"/>
<input type="submit" name="_eventId_cancel" value="Cancel"
class="btn btn-danger" tabindex="6"/>
</div>
</td>
</tr>
</table>
</form>
</div>
My Controller.java:
package com.niti.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.niti.authentication.service.AuthenticationService;
import com.niti.bo.UserBO;
import com.niti.service.exception.ServiceBusinessException;
#Controller
public class LoginController {
private static final Logger Logger = LoggerFactory.getLogger(LoginController.class);
#Autowired
private AuthenticationService authenticationService;
#RequestMapping(value = "/login", method = RequestMethod.GET)
public String login(Model model) {
model.addAttribute("user", new UserBO());
return "login";
}
#RequestMapping(value = "/validateUser", method = RequestMethod.POST)
public String processLoginInfo(#ModelAttribute UserBO userBO) throws ServiceBusinessException {
UserBO user = authenticationService.authenticateUser(userBO.getEmailAddress(), userBO.getPassword());
return "userDetails";
}
}
In your html form you are binding
th:object="${user}" // user
On the other hand you are binding a userBO by default in your controller method processLoginInfo.
Your method should be like so
#RequestMapping(value="/validateUser" , method=RequestMethod.POST)
public String processLoginInfo(#ModelAttribute("user") UserBO userBO) throws ServiceBusinessException {
UserBO user = authenticationService.authenticateUser(userBO.getEmailAddress(), userBO.getPassword());
return "userDetails";
}

403 error - CSRF token in modal window

I'm working on a Spring Boot + Bootstrap project.
I've created a modal window to confirm the removal of itens, but after I added Spring Security to the project, the modal stopped working.
How can I properly configure the CSRF token in a modal window?
I have tried some approaches, with no success.
I get the following error when deleting itens:
There was an unexpected error (type=Forbidden, status=403). Invalid
CSRF Token 'null' was found on the request parameter '_csrf' or header
'X-CSRF-TOKEN'.
Thanks for the help!
confirmRemove.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<div class="modal fade" id="confirmRemove" tabindex="-1"
data-keyboard="false" data-backdrop="static">
<div class="modal-dialog">
<form th:attr="data-url-base=#{/restaurants}" method="POST">
<input type="hidden" name="_method" value="DELETE" />
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">Você tem certeza?</h4>
</div>
<div class="modal-body">
<span>Are you sure you want to delete this restaurant?</span>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-link" data-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary">Delete</button>
</div>
</div>
</form>
</div>
</div>
</html>
restaurantpoll.js
$('#confirmRemove').on(
'show.bs.modal',
function(event) {
var button = $(event.relatedTarget);
var codeRestaurant = button.data('id');
var nameRestaurant = button.data('name');
var modal = $(this);
var form = modal.find('form');
var action = form.data('url-base');
if (!action.endsWith('/')) {
action += '/';
}
form.attr('action', action + codeRestaurant);
modal.find('.modal-body span').html(
'Are you sure you want to delete <strong>'
+ nameRestaurant + '</strong>?')
});
RestaurantController (only the relevant part)
package com.matmr.restaurantpoll.controller;
import java.util.Arrays;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.Errors;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.matmr.restaurantpoll.exception.RestaurantNotFoundException;
import com.matmr.restaurantpoll.model.Category;
import com.matmr.restaurantpoll.model.Restaurant;
import com.matmr.restaurantpoll.model.filter.RestaurantFilter;
import com.matmr.restaurantpoll.service.RestaurantService;
#Controller
#RequestMapping("/restaurants")
public class RestaurantController {
#Autowired
private RestaurantService restaurantService;
#Autowired
public RestaurantController(RestaurantService restaurantService) {
this.restaurantService = restaurantService;
}
#RequestMapping(value = "{id}", method = RequestMethod.DELETE)
public String delete(#PathVariable Long id, RedirectAttributes attributes) throws RestaurantNotFoundException {
restaurantService.deleteById(id);
attributes.addFlashAttribute("message", "The restaurant was successfully deleted.");
return "redirect:/restaurants";
}
}
restaurantList.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org"
xmlns:layout="http://ultraq.net.nz/thymeleaf/layout"
layout:decorator="Layout">
<head>
<title>Pesquisa de Restaurantes</title>
</head>
<section layout:fragment="conteudo">
<div class="panel panel-primary">
<div class="panel-heading">
<div class="clearfix">
<h1 class="panel-title liberty-title-panel">Pesquisa de
Restaurantes</h1>
<a class="btn btn-link liberty-link-panel"
th:href="#{/restaurants/new}">Cadastrar Novo Restaurante</a>
</div>
</div>
<div class="panel-body">
<form method="GET" class="form-horizontal"
th:action="#{/restaurants}" th:object="${filter}">
<div layout:include="MensagemGeral"></div>
<div layout:include="MensagemErro"></div>
<div class="form-group">
<div class="col-sm-4">
<div class="input-group">
<input class="form-control"
placeholder="Qual restaurante você está procurando?"
autofocus="autofocus" th:field="*{name}"></input> <span
class="input-group-btn">
<button type="submit" class="btn btn-default">
<i class="glyphicon glyphicon-search"></i>
</button>
</span>
</div>
</div>
</div>
</form>
<div class="table-responsive">
<table class="table table-bordered table-striped">
<thead>
<tr>
<th class="text-left col-md-1">#</th>
<th class="text-left col-md-2">Nome</th>
<th class="text-left col-md-3">Descrição</th>
<th class="text-left col-md-2">Categoria</th>
<th class="col-md-1"></th>
</tr>
</thead>
<tbody>
<tr th:each="restaurant : ${restaurants}">
<td class="text-left" th:text="${restaurant.id}"></td>
<td class="text-left" th:text="${restaurant.name}"></td>
<td class="text-left" th:text="${restaurant.description}"></td>
<td class="text-left"
th:text="${restaurant.category.description}"></td>
<td class="text-center"><a class="btn btn-link btn-xs"
th:href="#{/restaurants/{id}(id=${restaurant.id})}"
title="Editar" rel="tooltip" data-placement="top"> <span
class="glyphicon glyphicon-pencil"></span>
</a> <a class="btn btn-link btn-xs" data-toggle="modal"
data-target="#confirmRemove"
th:attr="data-id=${restaurant.id}, data-name=${restaurant.name}"
title="Excluir" rel="tooltip" data-placement="top"> <span
class="glyphicon glyphicon-remove"></span>
</a></td>
</tr>
<tr>
<td colspan="5" th:if="${#lists.isEmpty(restaurants)}">Nenhum
restaurante foi encontrado!</td>
</tr>
</tbody>
</table>
</div>
</div>
<div layout:include="confirmRemove"></div>
</div>
</section>
</html>
Adding th:action="#{/restaurants}" to the modal's form tag did the trick:
<form th:action="#{/restaurants}" th:attr="data-url-base=#{/restaurants}" method="POST">

Categories