form th:action not working using thymeleaf and spring - spring

i am new in spring and thymeleaf, i am trying to submit a form, insert to database, but whe i am using form submission with submission it simply redirects to page and don't invoke to controller
i don't know why,
please, help
here is my Controller
#Controller
public class AdminController {
#Autowired
private CategoryServiceImpl categoryService;
#GetMapping("/adminPage")
public String index(){
return "adminPage";
}
#GetMapping("/categoryList")
public String showCategory(){
return "categoryList";
}
#GetMapping("form")
public String categoryForm(Model model, Category category){
model.addAttribute("category", category);
// model.addAttribute("add", true);
// categoryService.create(category);
return "admin/categoryForm";
}
#PostMapping("create")
public String addOrgCategory(#Valid Category orgCategory) {
categoryService.create(orgCategory);
return "redirect:/categoryList";
}
my html form is here
<form action="#" th:action="#{/create}" th:object="${category}" method="POST">
<div class="form-group">
<label for="name" class="text-dark font-bold">Category name</label>
<input id="name" type="text" class="form-control" th:value="${category} ? ${category.name} : ' '" th:field="*{name}">
</div>
<div class="form-group">
</div>
<button
type="submit" class="btn btn-success" data-toggle="tooltip"
data-placement="top" title="Tooltip on top">Create
</button>
</form>

Related

Thymleaf controller request mapping binging issue

I am new to thymleaf and at first i used simple requestmapping and thymleaf th:action and th:object to bind controller methods. But after adding class level requestmapping i cannot view my html.
below is my controller class code where i redirect to login page.
#Controller
#RequestMapping("/project")
public class MyController {
#RequestMapping(value = {"/"}, method = RequestMethod.GET)
public String login(Model model) {
model.addAttribute("mylogin", new Credentials());
return "login";
}
}
below is my html page.
<form class="user" th:action="#{/project/login}" th:object="${mylogin}" method="POST">
<div class="form-group">
<input type="email" id="user_name" name="username"
class="form-control form-control-user"
placeholder="Enter Email Address..." />
</div>
<div class="form-group">
<input type="password" id="password" name="password"
class="form-control form-control-user"
placeholder="Password" />
</div>
<button class="btn btn-primary btn-user btn-block"
name="Submit" value="Login" type="Submit" th:text="Login"></button>
</form>
after adding #RequestMapping("/project") in class i cannot fetch html. If i remove this #RequestMapping("/project") and change th:action="#{/project/login}" to th:action="#{/login}" my code works.
What can be the problem for such issue?
Change This Request mapping this way /login with class level requestmapping and try again:
#RequestMapping(value = {"/login"}, method = RequestMethod.GET)
public String login(Model model) {
model.addAttribute("mylogin", new Credentials());
return "login";
}
OR
#GetMapping("/login")
public String login(Model model) {
model.addAttribute("mylogin", new Credentials());
return "login";
}

How to submit form jsp to controller?

In my jsp there are two fields: 1 types of documents and 2 are statuses.
The challenge is that I can send the selection to my controller. I can not figure out jsp how to send by action these values ​​at the click of a button
<div id="page-content-wrapper">
<div class="container-fluid">
<div class="card">
<div id="collapseSearchParams" class="collapse show" aria-labelledby="headingSearchParams" >
<div class="card-body">
<form:form action="${request.contextPath}/search" method="post">
<div class="row">
<div class="col-lg-3 col-md-4 col-sm-6">
<fieldset class="form-group">
<label class="form-label semibold" for="typeCode">${phDocType}</label>
<select class="form-control" id="typeCode">
<c:forEach var="type" items="${documentList}">
<option id = "${type.value}"> ${type.name} </ option>
</c:forEach>
</select>
</fieldset>
</div>
<div class="col-lg-3 col-md-4 col-sm-6">
<fieldset class="form-group">
<label class="form-label semibold" for="statusCode">${phOrderStatus}</label>
<select class="form-control" id="statusCode">
<option> A</ option>
<option> B</option>
<option> C</option>
<option> D</option>
</select>
</fieldset>
</div>
<div class="col-sm-12">
<button id ="btnSearchUsers" class="btn btn-sm btn-secondary" style="float: right; "><span class="fa fa-search"></span> <spring:message code="label.button.search" /></button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
How to get this data in the controller to process? What changes should I make in jsp and in the method?
#RequestMapping(value = "/perso")
public class PersoController {
#Autowired
private PersoService persoService;
private List<DocumentType> docTypeList = null;
#RequestMapping(value = "/list")
public String persoList(Principal principal, Model model) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
docTypeList = persoService.persoList(authentication, principal);
model.addAttribute("documentList", docTypeList);
return "admin/perso/list";
}
#RequestMapping(value = "/search", method = RequestMethod.POST)
public void searchOrders( ){
}
}
thanks in advance
It's better to use #RequestParam in your controller.
For Example:
#RequestMapping(value = "/bar")
public String testAction(#RequestParam String fieldName) {
//Do whatever you want to fieldName
return "view";
}
For your case
#RequestMapping(value = "/search", method = RequestMethod.POST)
public void searchOrders(#RequestParam String statusCode ,#RequestParam String typeCode)
{
//Do whatever you want
}

Spring MVC; error messages of validation form not being displayed

I have built a form for login. I've read about validations with spring mvc following a tutorial.
The form is blank & doesn't pass values, however it doesn't show any error messages.
This is my code for the controller:
#Controller
public class LoginController {
#RequestMapping("/login")
public ModelAndView login() {
return new ModelAndView("login", "user", new UserModel());
}
#RequestMapping("/submitLogin")
public ModelAndView submitLogin(#Valid UserModel user, BindingResult result) {
ModelAndView model = new ModelAndView();
model.addObject("user", user);
model.setViewName(result.hasErrors() ? "login" : "index");
return model;
}
}
This is my model:
#Data
public class UserModel {
#NotBlank(message = "The field login name is required")
private String login;
#NotBlank(message = "The field password is required")
private String password;
}
And this is my form:
<mvc:form modelAttribute="user" class="col s12" action="/submitLogin" method="POST">
<div class="container login-form">
<div class="row">
<div class="input-field col s12">
<mvc:input path="login" id="userName" type="text" class="validate" />
<mvc:label path="login" for="userName">Login name</mvc:label>
</div>
</div>
<div class="row">
<mvc:errors path="login" cssStyle="color: #ff0000;"/>
</div>
<div class="row">
<div class="input-field col s12">
<mvc:input path="password" id="password" type="password" class="validate" />
<mvc:label path="password" for="password">Password</mvc:label>
</div>
</div>
<div class="row">
<mvc:errors path="password" cssStyle="color: #ff0000;"/>
</div>
<div class="row">
<input type="submit" class="btn waves-effect waves-light pulse green" value="Entrar"/>
</div>
</div>
</mvc:form>
Did I miss any configuration on spring boot or annotation?

Spring Request method 'POST' not supported with th:field in select

I have strange problem with post method from form to method in controller.
Every mapping is ok but when i put th:field in 'select' I receive an error 405.
I tried remove this (th:field=*{code}) and then it's working but i dont have value of this.
So, in my controller in GET method i put to the model list of Code objects and new Position of object (for form)
Then in form html in "select" i display every single Code object.
In short, i would like to post data from select to the post method in my controller
Thats my code in controller:
#GetMapping("/add-shop-position")
public ModelAndView addShopPositionForm(){
ModelAndView modelAndView = new ModelAndView("admin/addShopPosition");
List<Code> codes = codeService.getAllCodes();
modelAndView.addObject("codes", codes);
modelAndView.addObject("position", new Position());
return modelAndView;
}
#PostMapping("/add-shop-position")
public ModelAndView addShopPositionSubmit(#ModelAttribute Position position){
ModelAndView modelAndView = new ModelAndView("admin/addShopPosition");
if(positionService.addPosition(position)){
//I will do something here in future
}else{
//I will do something here in future
}
return modelAndView;
}
And of course my controller has RequestMapping:
#Controller
#RequestMapping(value = "/admin")
public class AdminController {}
And thats my form, html view in Thymeleaf:
<form action="#" th:action="#{/admin/add-shop-position}" th:object="${position}" method="POST"
style="margin: 0 auto; width: 50%">
<div class="form-group">
<input class="form-control" type="text" th:field="*{title}" th:placeholder="Title">
</div>
<div class="form-group">
<input class="form-control" type="text" th:field="*{description}" th:placeholder="Description">
</div>
<div class="form-group">
<select class="form-control" th:field="*{code}">
<option th:each="code : ${codes}"
th:value="${code}"
th:text="${code.getCode()}"></option>
</select>
</div>
<div class="form-group">
<button class="btn btn-primary btn-block" type="submit" value="Submit">Create</button>
</div>
</form>

form:error not showing error

When validating object controller just refreshes the page, instead showing errors via form:errors, can you tell me where is the problem. I guest it needs to get error from binding result and insert it into the page, instead controller is just refreshing page
Controller :
#PreAuthorize("hasRole('ROLE_ADMIN')")
#RequestMapping(value = "/create", method = RequestMethod.POST)
public String createProduct(MultipartFile image, Model model,#ModelAttribute #Valid ProductDto product, BindingResult bindingResult) throws IOException {
productValidator.validate(product,bindingResult);
if (bindingResult.hasErrors()){
return "admin/create";
} else {
return "index";
}
}
#PreAuthorize("hasRole('ROLE_ADMIN')")
#RequestMapping(value = "/create", method = RequestMethod.GET)
public String createProduct(Model model) {
model.addAttribute("product", new ProductDto());
model.addAttribute("categories", categoryService.findAll());
return "admin/create";
}
Validator :
#Override
public boolean supports(Class<?> aClass) {
return ProductDto.class.equals(aClass);
}
#Override
public void validate(Object o, Errors errors) {
ProductDto product = (ProductDto) o;
if (product.getTitle().isEmpty() || product.getTitle() == null) {
errors.rejectValue("title", "product.title", "Product title cant be empty");
}
if (product.getDescription().isEmpty() || product.getDescription() == null) {
errors.rejectValue("description", "product.description", "Product description cant be empty");
}
if (product.getPrice() == null || product.getPrice()<=0) {
errors.rejectValue("price", "product.price", "Product price is not valid");
}
if (product.getCategoryId()==null) {
errors.rejectValue("category", "product.category", "Product category is not valid");
}
}
jstl page :
<spring:url value="/product/create" var="formUrl"/>
<form:form modelAttribute="product" action="${formUrl }" method="post" enctype="multipart/form-data">
<div class="form-group">
<label>Title</label>
<form:input id="title"
cssClass="form-control" path="title"/>
<form:errors path="title"/>
</div>
<div class="form-group">
<label>Description</label>
<form:textarea id="description" rows="10"
cssClass="form-control" path="description"/>
</div>
<div class="form-group">
<label>Price</label>
<form:input id="price" type="number"
cssClass="form-control" path="price"/>
<form:errors path="description"/>
</div>
<div class="form-group">
<label for="sel1">Select category</label>
<form:select id="sel1" cssClass="form-control" path="categoryId">
<form:options items="${categories}" itemValue="id" itemLabel="title"/>
</form:select>
</div>
<label class="btn btn-default btn-file">
Image <input type="file" multiple accept='image/*' ng-file-select="onFileSelect($files)" name="image" style="display: block;">
</label>
<br><br>
<div class="text-center">
<button type="submit" class="btn btn-lg btn-success text-center"><span
class="fa fa-check"></span> Submit
</button>
<a href="/" class="btn btn-danger btn-lg text-center"><span
class="fa fa-times"></span> Cancel
</a>
</div>
</form:form>
I think your product model attribute has different name in your POST-handling method.
According to documentation:
The default model attribute name is inferred from the declared
attribute type (i.e. the method parameter type or method return type),
based on the non-qualified class name: e.g. "orderAddress" for class
"mypackage.OrderAddress", or "orderAddressList" for
"List<mypackage.OrderAddress>".
So your ProductDto product attribute will have name productDto in resulting model. But you referring the product in your template.
Try to explicitly set the name attribute of #ModelAttribute annotation
public String createProduct(MultipartFile image, Model model, #ModelAttribute(name = "product") #Valid ProductDto product, BindingResult bindingResult)
And to make sure that bidning and validation actually works, try to log it:
if (bindingResult.hasErrors()) {
System.err.println("Form has errors!");
}

Resources