Thymleaf controller request mapping binging issue - spring-boot

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";
}

Related

Failed to load resource 405

I'm a bit at a loss here.
I have a thymeleaf page and a spring-boot backend that takes in a user object, getting the object to the page is fine, my problem comes in when I'm trying to get it to the back end to do stuff with it.
I keep getting the following
2021-09-15 09:21:07.834 WARN 3624 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported]
and on the browser
Failed to load resource: the server responded with a status of 405 ()
for my controller I have the following
#Controller("/user")
public class UserController {
#Autowired
private UserService userService;
#Autowired
private ModelMapper modelMapper;
#RequestMapping(value = "/add")
public String addUser(#ModelAttribute("user") final UserDto userDto) {
//do stuff
//userService.save(modelMapper.map(userDto, User.class));
return "/user";
}
}
as for my thymeleaf page
<form th:action="#{/user/add}" th:object="${user}" method="post">
<label for="fullName">Full Name</label>
<input id="fullName" class="form-control form-group" type="text" th:field="*{fullName}">
<label for="email">Email</label>
<input id="email" class="form-control form-group" type="email" th:field="*{email}">
<label for="password">Password</label>
<input id="password" class="form-control form-group" type="password" th:field="*{password}">
<p>
<button class="form-group form-control btn btn-primary" type="submit" value="Submit">Submit</button>
</p>
</form>
What am I missing here?
I did try to mess around the #GetMapping, #PostMapping, #RequestMapping(method = GET), #RequestMapping(method = POST), #RequestMapping(method = {GET, POST})
I also tried <form ... th:method="post"> and <form ... th:method="get">
But none of these seems to work.
You add global /user in #Controller. this annotation is used to implement Web Application not for path and it is better to give global path in application.properties like below code. Inside addUser() method you want to return with page name like return "user" if go to the url then put return "redirect:/user"
Here down is modified code:
application.properties
server.servlet.contextPath=/user/
Controller
#Controller
public class UserController {
#Autowired
private UserService userService;
#Autowired
private ModelMapper modelMapper;
#RequestMapping(value = "/add", method = RequestMethod.POST)
public String addUser(#ModelAttribute("user") final UserDto userDto) {
//do stuff
//userService.save(modelMapper.map(userDto, User.class));
return "pagename"; // enter page name where you wanna go not url
}
}
Template
<form th:action="#{/add}" th:object="${user}" method="post">
<label for="fullName">Full Name</label>
<input id="fullName" class="form-control form-group" type="text" th:field="*{fullName}">
<label for="email">Email</label>
<input id="email" class="form-control form-group" type="email" th:field="*{email}">
<label for="password">Password</label>
<input id="password" class="form-control form-group" type="password" th:field="*{password}">
<p>
<button class="form-group form-control btn btn-primary" type="submit" value="Submit">Submit</button>
</p>
</form>

form th:action not working using thymeleaf and 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>

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!");
}

spring RequestMapping not working without ModelAttribute

I have controller class with following request mapping method.
appStart() method is responsible for redirecting user to login.html and
logout() is responsible for invalidating session and redirecting user
back to login.jsp
if I remove #ModelAttribute from their parameter then these two methods are throwing exception, is there any hack to get these methods working without modelattribute?
controller methods.
#RequestMapping(value="/",method=RequestMethod.GET)
public String appStart(#ModelAttribute("tempAdmin") Admin tempAdmin) {
return "login.jsp";
}
#RequestMapping(method = RequestMethod.POST,name="doLogin")
public ModelAndView doLogin(#ModelAttribute("tempAdmin") Admin tempAdmin, HttpServletRequest request) {
ModelAndView mvc = new ModelAndView();
/*
Buisness logic
*/
mvc.setViewName("home.jsp");
return mvc;
}
#RequestMapping("doLogout")
public String logout(HttpServletRequest request) {
HttpSession session = request.getSession(false);
if(session != null){
session.invalidate();
}
return "login.jsp";
}
login.jsp
<form:form action="doLogin" modelAttribute="tempAdmin" cssClass="form-horizontal">
<div class="form-group">
<label for="username" class="col-sm-2 control-label">Username</label>
<div class="col-sm-10">
<form:input cssClass="form-control" path="adminId" placeholder="username" />
</div>
</div>
<div class="form-group">
<label for="passwd" class="col-sm-2 control-label">Password</label>
<div class="col-sm-10">
<form:password path="password" cssClass="form-control" id="passwd" placeholder="password" />
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">Sign in</button>
</div>
</div>
</form:form>
stacktrace.
Caused by: java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'tempAdmin' available as request attribute
at org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:144)
at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getBindStatus(AbstractDataBoundFormElementTag.java:168)
at org.springframework.web.servlet.tags.form.AbstractDataBoundFormElementTag.getPropertyPath(AbstractDataBoundFormElementTag.java:188)
I will tell you how to change your controller, to avoid binding result problem. Try this :
#RequestMapping(method = RequestMethod.POST,name="doLogin")
public String doLogin(#ModelAttribute("tempAdmin") Admin tempAdmin, HttpServletRequest request,Model model) {
model.addAttribute("tempadmin",new Admin());
// business logic
return "home";
}
Try this out, and if you have any other classes, then add the model.addAttribute for that as well. Can you post your JSP too?

Resources