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.
Related
I have an issue with using Postman to upload an Excel file to a Spring Boot application. I'm constantly getting the error "Current Request is not a multipart request".
I've tried other solutions explained on removing content-type headers and selecting form-data, but nothing worked as of now.
This is my controller code.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
import java.util.Set;
#CrossOrigin
#Controller
#RequestMapping("/player")
public class PlayerController {
#Autowired
PlayerService playerService;
#Autowired
TeamService teamService;
#PostMapping("/upload/{teamId}")
public ResponseEntity<ResponseMessage> uploadFile(#RequestPart("file") MultipartFile file, #PathVariable int teamId) {
String message;
if (ExcelHelper.hasExcelFormat(file)) {
try {
playerService.save(file, teamId);
message = "Uploaded the file successfully: " + file.getOriginalFilename();
return ResponseEntity.status(HttpStatus.OK).body(new ResponseMessage(message));
} catch (Exception e) {
message = "Could not upload the file: " + file.getOriginalFilename() + "!";
return ResponseEntity.status(HttpStatus.EXPECTATION_FAILED).body(new ResponseMessage(message));
}
}
message = "Please upload an excel file!";
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseMessage(message));
}
}
This is the curl request:
curl --location --request POST 'http://localhost:9090/player/upload/5' \
--header 'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzcmlrYXJrIiwiZXhwIjoxNjM1NzEzMDAwLCJpYXQiOjE2MzU2MjY2MDB9._GcCznGiiWE4fRRkaRfhc7El9ETEOhbzL6ErhPsU_aY' \
--form '=#"/C:/Users/srika/Documents/Git_Repos/abc-100-abc-xyz-00-Team/resources/PlayerList.xlsx"'
Below is the postman error message:
These are the headers postman is sending:
In application.properties, I have defined following details.
spring.servlet.multipart.max-file-size=2MB
spring.servlet.multipart.max-request-size=2MB
spring.http.multipart.enabled=false
It worked up-on removing the auto-generated Content-Type Header and adding this new header instead.
Content-Type:multipart/form-data; boundary=something
Also, updated the RequestMapping Annotation in the controller class to
#RequestMapping(value = "/upload/{teamId}",
method = RequestMethod.POST,
consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
add enctype="multipart/form-data" to your form tag.
this is my html
<form role="form" enctype="multipart/form-data" method="post" th:action="#{/upload_files}">
<div class="form-group">
<label for="exampleInputEmail1">Email address</label>
<input type="email" name="email" class="form-control" id="exampleInputEmail1" placeholder="Enter email">
</div>
<div class="form-group">
<label for="exampleInputPassword1">Username</label>
<input type="text" name="username" class="form-control" id="exampleInputPassword1" placeholder="Username">
</div>
<div class="form-group">
<label for="exampleInputFile">Single File</label>
<input type="file" name="sfile" id="exampleInputFile">
</div>
<div class="form-group">
<label for="files">Multiple File</label>
<input type="file" name="files" id="files" multiple>
</div>
single choose check box
<div class="checkbox">
<label>
<input type="checkbox" name="check" value="yes"> Check me out
</label>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
this is my controller
// 表单添加 enctype="multipart/form-data"
#PostMapping(value = "/upload_files")
public String when_upload(#RequestParam("email") String email,
#RequestParam("username") String username,
#RequestPart("sfile") MultipartFile file,
#RequestPart("files") MultipartFile[] files) {
log.info("{}, {}, {}, {}", email, username, file.getOriginalFilename(), files.length);
return "index";
}
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>
package com.project.agro.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.project.agro.model.Role;
import com.project.agro.model.User;
import com.project.agro.repos.UserRepository;
import java.util.HashSet;
import java.util.Set;
#Service
public class UserDetailsServiceImpl implements UserDetailsService{
#Autowired
private UserRepository userRepository;
#Override
#Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username) {
User user = userRepository.findByUsername(username);
if (user == null) throw new UsernameNotFoundException(username);
Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
for (Role role : user.getRoles()){
grantedAuthorities.add(new SimpleGrantedAuthority(role.getName()));
}
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), grantedAuthorities);
}
}
package com.project.agro.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.project.agro.model.Role;
import com.project.agro.model.User;
import com.project.agro.repos.UserRepository;
import java.util.HashSet;
import java.util.Set;
#Service
public class UserDetailsServiceImpl implements UserDetailsService{
#Autowired
private UserRepository userRepository;
#Override
#Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username) {
User user = userRepository.findByUsername(username);
if (user == null) throw new UsernameNotFoundException(username);
Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
for (Role role : user.getRoles()){
grantedAuthorities.add(new SimpleGrantedAuthority(role.getName()));
}
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), grantedAuthorities);
}
}
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="ISO-8859-1">
<title>Insert title here</title>
<link href="${contextPath}/resources/css/bootstrap.min.css" rel="stylesheet">
<link href="${contextPath}/resources/css/style.css" rel="stylesheet">
<link href="${contextPath}/resources/css/fixed.css" rel="stylesheet">
</head>
<body>
<%# include file="common/navbar.jsp"%>
<div class="container-fluid">
<div class="row">
<div class="col-3">
<div class="side-nav">
<nav>
<ul>
<li> <span>Title</span></li>
<li> <span>Crops</span></li>
<li class="active"> <span>Fertilizer</span></li>
<li> <span>Agro News</span></li>
</ul>
</nav>
</div>
</div>
<div class="col-9">
<form class="form-horizontal" action="/admin/crop/addcrop"
method="post" enctype="multipart/form-data" style="margin-top:5rem;" >
<fieldset>
<legend class="center-block">
New crop Information
</legend>
<!-- title -->
<div class="form-group" style="display:flex;">
<label class="col-sm-2 control-label" for="title">Crop Name</label>
<div class="col-sm-8">
<input type="text" name="cName" class="form-control" id="cName"
required="required" placeholder="Title" />
</div>
</div>
<!-- author -->
<div class="form-group" style="display:flex;">
<label class="col-md-2 control-label" for="cScientificName">
Scientific Name</label>
<div class="col-md-8">
<input type="text" name="cScientificName" class="form-control"
id="cScientificName" required="required"
placeholder="Scientific Name" />
</div>
</div>
<!-- description -->
<div class="form-group" style="display:flex;">
<label class="col-md-2 control-label" for="description">Description</label>
<div class="col-md-8">
<textarea name="description" rows="5" class="form-control"
id="description" placeholder="Description"></textarea>
</div>
</div>
<!-- upload image -->
<div class="form-group" style="display:flex;">
<div class="col-md-2">
<label for="cImage">Upload crop image</label>
</div>
<div class="col-md-8">
<input id="cImage" type="file" name="cImage" value="cImage" />
</div>
</div>
<!-- description -->
<div class="form-group" style="display:flex;">
<label class="col-md-2 control-label" for="description">Associated
Disease</label>
<div class="col-md-8">
<input type="text" name="associatedDisease" class="form-control"
id="description"
placeholder="Associated Disease" />
</div>
</div>
<div class="form-group" style="display:flex;">
<div class="col-md-2"></div>
<div class="col-md-8">
<button type="submit" class="btn btn-success">Add Book</button>
<a class="btn btn-danger" href="">Cancel</a>
</div>
</div>
</fieldset>
</form>
</div>
</div>
</div>
<script src="${contextPath}/resources/js/bootstrap.min.js" ></script>
<script src="${contextPath}/resources/js/jquery-3.3.1.min.js" ></script>
</body>
</html>
-
package com.project.agro;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/admin/**").hasAuthority("ADMIN")
.antMatchers("/resources/**", "/registration","/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll().defaultSuccessUrl("/welcome")
.and()
.logout()
.permitAll();
}
#Bean
public AuthenticationManager customAuthenticationManager() throws Exception {
return authenticationManager();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
}
package com.project.agro.controller;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import javax.servlet.http.HttpServletRequest;
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 org.springframework.web.multipart.MultipartFile;
import com.project.agro.model.Crop;
import com.project.agro.service.CropService;
#Controller
public class CropController {
#Autowired
private CropService cropService;
#RequestMapping(value="/admin/crop/addcrop" ,method = RequestMethod.GET)
public String addcrop(Model model) {
Crop crop = new Crop();
model.addAttribute("crop", crop);
return "addcrop";
}
#RequestMapping(value="/admin/crop/addcrop" , method = RequestMethod.POST)
public String addcroppost(#ModelAttribute(value="crop") Crop crop ,HttpServletRequest request){
cropService.save(crop);
MultipartFile cImage=crop.getcImage();
try {
byte[] bytes = cImage.getBytes();
String name = crop.getCropID() + ".png";
BufferedOutputStream stream = new BufferedOutputStream(
new FileOutputStream(new File("src/main/webapp/image/crop/" + name)));
stream.write(bytes);
stream.close();
} catch (Exception e) {
e.printStackTrace();
}
return "redirect:/cropList";
}
#RequestMapping("/cropList")
public String cropList(Model model) {
/*List<Book> bookList = bookService.findAll();*/
return "cropList";
}
}
I am trying to build an web application using Spring Boot and Spring Security.I am submitting a form with POST method as an admin to add some details into database but everytime I hit that submit button it shows the error page.I have added all the dependencies .The registration and login page works fine What am I suppose to do here?
i'm new in Spring and i trying to learn it with help Spring in action 5 (Craig Walls).I'm creating small Spring Boot MVC-application.Now i have a little problem with Thymeleaf.
I have Controller,View and model as POJO object.When i'm trying to get data from form Intellij Idea told me that something wrong with my Thymeleaf view in this line:
Model
import java.util.Date;
import java.util.List;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import lombok.Data;
#Data
public class Taco {
private Long id;
private Date createdAt;
#NotNull
#Size(min=5, message="Name must be at least 5 characters long")
private String name;
#Size(min=1, message="You must choose at least 1 ingredient")
private List<Ingredient> ingredients;
}
View
<!DOCTYPE html>
<html lang="en"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Taco Cloud</title>
<link rel="stylesheet" th:href="#{/styles.css}"/>
</head>
<body>
<h1>Design your taco!</h1>
<img src="../static/images/TacoCloud.png" alt="TacoCloud.png" th:src="#{/images/TacoCloud.png}">
<form method="POST" th:object="${taco}">
<div class="grid">
<div class="ingredient-group" id="wraps">
<h3>Designate yor wrap:</h3>
<div th:each="ingredient:${wrap}">
<input name="ingredients" type="checkbox" th:value="${ingredient.id}"/>
<span th:text="${ingredient.name}">INGREDIENT</span><br/>
</div>
</div>
<div class="ingredient-group" id="proteins">
<h3>Pick your protein:</h3>
<div th:each="ingredient: ${protein}">
<input name="ingredients" type="checkbox" th:value="${ingredient.id}"/>
<span th:text="${ingredient.name}">INGREDIENT</span>
</div>
</div>
<div class="ingredient-group" id="cheeses">
<h3>Choose your cheese:</h3>
<div th:each="ingredient:${cheese}">
<input name="ingredients" type="checkbox" th:value="${ingredient.id}"/>
<span th:text="${ingredient.name}">INGREDIENT</span><br/>
</div>
</div>
<div class="ingredient-group" id="veggies">
<h3>Determine your veggies:</h3>
<div th:each="ingredient : ${veggies}">
<input name="ingredients" type="checkbox" th:value="${ingredient.id}"
/>
<span th:text="${ingredient.name}">INGREDIENT</span><br/>
</div>
</div>
<div class="ingredient-group" id="sauces">
<h3>Select your sauce:</h3>
<div th:each="ingredient : ${sauce}">
<input name="ingredients" type="checkbox" th:value="${ingredient.id}"
/>
<span th:text="${ingredient.name}">INGREDIENT</span><br/>
</div>
</div>
</div>
<div>
<h3>Name your taco creation:</h3>
<input type="text" name="name" th:field="*{name}"/>
<br/>
<button>Submit your taco</button>
</div>
</form>
</body>
</html>
Controller
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import tacos.Ingredient.Type;
import tacos.Ingredient;
import org.springframework.web.bind.annotation.ModelAttribute;
import tacos.Taco;
import tacos.data.IngredientRepository;
import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
#Slf4j
#Controller
#RequestMapping("/design")
public class DesignTacoController {
private final IngredientRepository ingredientRepo;
#Autowired
public DesignTacoController(IngredientRepository ingredientRepo){
this.ingredientRepo=ingredientRepo;
}
#GetMapping
public String showDesignForm(Model model) {
List<Ingredient> ingredients=new ArrayList<>();
ingredientRepo.findAll().forEach(i->ingredients.add(i));
Type[] types = Ingredient.Type.values();
for (Type type : types) {
model.addAttribute(type.toString().toLowerCase(),
filterByType(ingredients, type));
}
return "design";
}
private List<Ingredient> filterByType(
List<Ingredient> ingredients, Type type) {
return ingredients
.stream()
.filter(x -> x.getType().equals(type))
.collect(Collectors.toList());
}
#PostMapping
public String processDesign(#Valid #ModelAttribute("design") Taco design, Errors errors, Model model) {
if (errors.hasErrors()) {
return "design";
}
// Save the taco design...
// We'll do this in chapter 3
log.info("Processing design: " + design);
return "redirect:/orders/current";
}
}
And finally i get this error:
org.thymeleaf.exceptions.TemplateInputException: An error happened during template parsing (template: "class path resource [templates/design.html]")
Caused by: org.attoparser.ParseException: Error during execution of processor 'org.thymeleaf.spring5.processor.SpringInputGeneralFieldTagProcessor' (template: "design" - line 64, col 45)
I noticed two things on your code.
I don't see th:action on your form that is required for form submission.
change form method="POST" th:object="${taco}" to form method="POST" th:object="${design}"
Try fixing these two and it should work.
I encountered same issue.
Resolution for me was to add getters in Taco.java for name. Somehow lombok is not generating getters automatically at run time.
And th:object="${taco}" should be th:object="${design}"
No need to make changes for th:action. From tutorial
If you take another look at the tag in your view, you can see that its method attribute is set to POST. Moreover, the doesn’t declare an action attribute. This means that when the form is submitted, the browser will gather up all the data in the form and send it to the server in an HTTP POST request to the same path for which a GET request displayed the form—the /design path.
I found two thing in code:
I do not find any action your form in html. You should use th:action tag to add an action.
in html you used th:object="${taco}" for declare an object for your html form. But you do not add “taco” object in your model in controller method from where you return the html design. You should add the “taco” object in your controller method like below.
model.addAttribute(“taco”, taco Object);
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";
}