Adding this line to my html leads to status 500
<div th:if="${#fields.hasErrors('name')}" th:errors="*{newBook.name}">Name error</div>
html itself:
<!DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form th:method="POST" th:action="#{/saveBook}" th:model="${newBook}" method="post">
<label for="name">Full name of your book:</label>
<input type="text" th:field="*{newBook.name}" id="name"/>
<div th:if="${#fields.hasErrors('name')}" th:errors="*{newBook.name}">Name error</div>
<br><br>
<label>Author:</label>
<input type="text" th:field="*{newBook.author}">
<br><br>
<label>Year:</label>
<input type="text" th:field="*{newBook.year}"/>
<br><br>
<label>Pages:</label>
<input type="text" th:field="*{newBook.pages}"/>
<br><br>
<input type="submit" value="OK"/>
</form>
</body>
</html>
view n2:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello World</title>
</head>
<body>
<h2>
Welcome to my pirate Library
<br>
<a href="allBooks" >Book list</a>
</h2>
</body>
</html>
view n3
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>All books</title>
</head>
<body>
<table>
<tbody>
<tr>
<th>Name</th>
<th>Author</th>
<th>Year</th>
<th>Pages</th>
<tr th:each="book: ${allBooks}">
<td th:text="${book.getName}"></td>
<td th:text="${book.getAuthor}"></td>
<td th:text="${book.getYear}"></td>
<td th:text="${book.getPages}"></td>
</tr>
</tr></tbody>
</table>
<br>
<input type="button" value="Add New Book" onclick="window.location.href='addBook'">
</body>
</html>
Controller:
#Controller
public class BasicController {
#Autowired
BasicService basicService;
#RequestMapping("/hello")
public String TestController() {
return "test-view";
}
#GetMapping("/allBooks")
public String showAllBooks(Model model) {
model.addAttribute("allBooks", basicService.getAllBooks());
return "all-books";
}
#GetMapping("/addBook")
public String addBook(Model model) {
Book book = new Book();
model.addAttribute("newBook", book);
return "book-adding";
}
#PostMapping("/saveBook")
public String saveBook(#ModelAttribute(name = "newBook") #Validated Book book, BindingResult bindingResult) {
if (!bindingResult.hasErrors()) {
basicService.addBook(book);
System.out.println(bindingResult.hasErrors());
return "redirect:/allBooks";
}
return "book-adding";
}
}
Entity:
#Entity
#Table(name = "books", schema = "my_db")
public class Book {
public Book() {
}
public Book(String name, String author, int year, int pages) {
this.name = name;
this.author = author;
this.year = year;
this.pages = pages;
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int id;
#Column(name = "name")
#NotBlank(message = "ddsadas")
#NotEmpty(message = "dsadas")
#Size(min = 2, message = "Should be greater than 2 symbols")
private String name;
private String author;
private int year;
private int pages;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getPages() {
return pages;
}
public void setPages(int pages) {
this.pages = pages;
}
}
I simply want to show validation message next to forms, but unfortunatly I've got no clue what's wrong.
Related
I am new to springboot and thymeleaf and I'm trying to understand the form handling methods that interact with the code. Below you will find my html documents linked to a Users class. I am trying to change them to link to a customer class amongst other things, but anytime I change the th:object=${users} to match the new entity 'customerentity' it gives me the error below. What more do I have to do to get the bean(?) to register my new attribute? Any help or links to other answers is greatly appreciated.
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'customerentity' available as request attribute
Here is my entity class
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import org.springframework.lang.NonNull;
#Entity
public class Users {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#NonNull
private String name;
#NonNull
private String email;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
// standard constructors / setters / getters / toString
}
The controller class
#Controller
public class UserController {
//set up a UserRepositoty variable
#Autowired
private UserRepository userRepository;
//create an UserRepository instance - instantiation (new) is done by Spring
public UserController(UserRepository userRepository) {
this.userRepository = userRepository;
}
//Mapping for the /index URL when initiated through Tomcat
#RequestMapping({"/index"})
public String showUserList(Model model) {
model.addAttribute("customers", userRepository.findAll());
return "index";
}
//Mapping for the /signup URL - calls the add-user HTML, to add a user
#RequestMapping({"/signup"})
public String showSignUpForm(Users user) {
return "add-user";
}
//Mapping for the /signup URL - to add a user
#RequestMapping({"/adduser"})
public String addUser(#Validated Users users, BindingResult result, Model model) {
if (result.hasErrors()) {
return "add-user";
}
userRepository.save(users);
return "redirect:/index";
}
//Mapping for the /edit/user URL to edit a user
#GetMapping("/edit/{id}")
public String showUpdateForm(#PathVariable("id") long id, Model model) {
Users user = userRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("Invalid user Id:" + id));
model.addAttribute("customer", user);
return "update-user";
}
//Mapping for the /update/id URL to update a user
#PostMapping("/update/{id}")
public String updateUser(#PathVariable("id") long id, #Validated Users user,
BindingResult result, Model model) {
if (result.hasErrors()) {
user.setId(id);
return "update-user";
}
userRepository.save(user);
return "redirect:/index";
}
//Mapping for the /delete/id URL to delete a user
#GetMapping("/delete/{id}")
public String deleteUser(#PathVariable("id") long id, Model model) {
Users user = userRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("Invalid user Id:" + id));
userRepository.delete(user);
return "redirect:/index";
}
}
The html documents
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Add User</title>
</head>
<body>
<form action="#" th:action="#{/adduser}" th:object="${users}" method="post">
<label for="name">Name</label>
<input type="text" th:field="*{name}" id="name" placeholder="Name">
<span th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></span>
<label for="email">Email</label>
<input type="text" th:field="*{email}" id="email" placeholder="Email">
<span th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></span>
<input type="submit" value="Add User">
</form>
</body>
</html>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="ISO-8859-1">
<title>Add User</title>
</head>
<body>
<div th:switch="${users}">
<h2 th:case="null">No users yet!</h2>
<div th:case="*">
<h2>Users</h2>
<table>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Edit</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
<tr th:each="user : ${users}">
<td th:text="${user.name}"></td>
<td th:text="${user.email}"></td>
<td><a th:href="#{/edit/{id}(id=${user.id})}">Edit</a></td>
<td><a th:href="#{/delete/{id}(id=${user.id})}">Delete</a></td>
</tr>
</tbody>
</table>
</div>
<p>Add a new user</p>
</div>
</body>
</html>
I'm referring to this guide (http://jvmhub.com/2015/08/09/spring-boot-with-thymeleaf-tutorial-part-3-spring-data-jpa/), the only difference is that i unified the classes PostEntity and Post assuming the name PostEntity.
When i try to store data in db through a form the applications works but it can't allow me to view stored data in a webpage as showed in the guide linked above.
The web page result.html is displayed as
"Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Thu Jul 05 14:25:42 CEST 2018
There was an unexpected error (type=Internal Server Error, status=500).
Exception evaluating SpringEL expression: "PostEntity.title" (template: "result" - line 11, col 9)"
and the console shows the exception:
org.springframework.expression.spel.SpelEvaluationException: EL1007E: Property or field 'title' cannot be found on null
It is throwed even with the other attributes (id and content) according to the order they are disposed in result.html.
If i try to print the content of records variable to the console it shows that it is not null so i can't figure out why there is this exception.
Controller:
#Controller
public class Home {
#Autowired private PostRepository postRepository;
#RequestMapping(value="/", method=RequestMethod.GET)
public String index(Model model) {
model.addAttribute("post", new PostEntity());
return "index";
}
#RequestMapping(value = "/", method = RequestMethod.POST)
public String addNewPost( PostEntity post, BindingResult bindingResult, Model model) {
if (bindingResult.hasErrors()) {
return "index";
}
postRepository.save(post);
List<PostEntity> records = (List<PostEntity>) postRepository.findAll();
model.addAttribute("posts", records);
return "redirect:result";
}
#RequestMapping(value = "/result", method = RequestMethod.GET)
public String showAllPosts(Model model) {
List<PostEntity> records = (List<PostEntity>) postRepository.findAll();
for (PostEntity record : records) {
System.out.println(record);
}
model.addAttribute("posts", records);
return "result";
}
}
Model class:
#Entity
public class PostEntity {
public PostEntity() {}
public PostEntity(String title, String content) {
this.title = title;
this.content = content;
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public int id;
public String title;
public String content;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
index:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Spring Boot and Thymeleaf example</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h3>Spring Boot and Thymeleaf, part 2 - forms</h3>
<form action="#" th:action="#{/}" th:object="${post}" method="post">
<table>
<tr>
<td>Title:</td>
<td><input type="text" th:field="*{title}" /></td>
<td th:if="${#fields.hasErrors('title')}" th:errors="*{title}">Title error message</td>
</tr>
<tr>
<td>Content:</td>
<td><input type="text" th:field="*{content}" /></td>
<td th:if="${#fields.hasErrors('content')}" th:errors="*{content}">Content error message</td>
</tr>
<tr>
<td><button type="submit">Submit post</button></td>
</tr>
</table>
</form>
</body>
</html>
result
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Spring Boot and Thymeleaf example</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h3>Spring Boot and Thymeleaf, part 3 - SPRING DATA JPA</h3>
<p th:each="PostEntity : ${posts}">
<h4>Title:</h4>
<div th:text="${PostEntity.title}"/></div>
<h4>ID:</h4>
<div th:text="${PostEntity.id}"/></div>
<h4>Content:</h4>
<div th:text="${PostEntity.content}"/></div>
<div>---------------------------------------------------------</div>
</p>
</body>
</html>
Any suggestions?
You are doing this redirect-thing. When doing this your objects added to the model doesn't reach the further process. I remember running into similar trouble.
I have an customer object whose fields I'm trying to access in my view with Thymeleaf. I've used the usual syntax i.e:
<p th:text="${customer.name}"></p>
however, this does not work, it does work when I use the get() method i.e:
<p th:text="${customer.get.name}"></p>
Any idea why that is happening? I'm just getting started with Thymeleaf, so I apologize in advance if this is a dumb question.
Here's my Model:
#Id
#GeneratedValue
private int id;
#NotNull
#Size(min = 2, message="Company name length must be at least 1 character long.")
private String name;
public Customer() {}
public Customer(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
And the Controller:
#RequestMapping("")
public String index(Model model) {
model.addAttribute("title", "Home");
model.addAttribute("customers", customerDao.findAllByOrderByNameAsc());
return "index";
}
#RequestMapping(value = "", method = RequestMethod.POST)
public String processFetch(#ModelAttribute Customer customer, Model model) {
model.addAttribute("title", "Home");
model.addAttribute("customers", customerDao.findAllByOrderByNameAsc());
model.addAttribute("c", customerDao.findById(customer.getId()));
return "index";
}
and the View:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org/">
<head th:replace="fragments::head"></head>
<body>
<nav th:replace="fragments::nav"></nav>
<div class="container">
<h1 class="title" th:text="${title}"></h1>
</div>
<div style="text-align: center">
<form method="post" th:object="${customers}" style="display: block;margin: 0 auto;width:300px;margin-top:5%">
<select class="form-control" name="customer">
<option style="text-align:center" th:each="customer:${customers}" th:value="${customer.id}" th:text="${customer.name}"></option>
</select>
<input class="button" style="display:block;margin:0 auto;margin-top:30px" type="submit" value="Fetch" />
</form>
</div>
<div>
<h1 th:text="${c.get().name}"></h1>
</div>
</body>
</html>
Here's my Repository class:
public interface CustomerDao extends CrudRepository<Customer, Integer> {
public Iterable<Customer> findAllByOrderByNameAsc();
}
The error I try to submit the form is:
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1007E: Property or field 'name' cannot be found on null
I'm not sure why it cannot find property 'name'. It should be part of the object.
I appreciate any insight into this!
When i try to access http://localhost:8080/XX/articles/addArticle
and submit the form, there is always a "400 BAD REQUEST" error.
i've tried to look up for the reason, all i got is that object transfered from the form is not as same type as my model(, which is an Article object? here). However, i don't think i really get it..
All codes are here, the config is all good.
Here are 2 models:
Article.java
#Entity
#Table(name="article_inf")
public class Article {
private int articleId;
private String title;
private User author;
private String content;
public Article() {
}
public Article(String title, User author, String content) {
this.title = title;
this.author = author;
this.content = content;
}
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
public int getArticleId() {
return articleId;
}
public void setArticleId(int articleId) {
this.articleId = articleId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
#ManyToOne(targetEntity=User.class)
#JoinColumn(name="author", referencedColumnName="userId", nullable=false)
public User getAuthor() {
return author;
}
public void setAuthor(User author) {
this.author = author;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
User.java
#Entity
#Table(name="agri_user_inf")
public class User {
private int userId;
private String userName;
private String password;
private String cellPhone;
private List<Article> articles;
public User() {
articles = new ArrayList<>();
}
public User(String userName, String password, String cellPhone) {
this.userName = userName;
this.password = password;
this.cellPhone = cellPhone;
}
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getCellPhone() {
return cellPhone;
}
public void setCellPhone(String cellPhone) {
this.cellPhone = cellPhone;
}
#OneToMany(targetEntity=Article.class, mappedBy="author")
public List<Article> getArticles() {
return articles;
}
public void setArticles(List<Article> articles) {
this.articles = articles;
}
controller
ArticleController.java
#Controller
#RequestMapping("articles")
public class ArticleController {
private ArticleDao articleDao;
#Autowired
public ArticleController(ArticleDao articleDao) {
this.articleDao = articleDao;
}
#RequestMapping(value="addArticle", method=GET)
public String addArticle(ModelMap modelMap) {
List<User> authors = userDao.getAllUsers();
// add all authors
modelMap.addAttribute("authors", authors);
return "articles/addArticleForm";
}
#RequestMapping(value="addArticle", method=POST)
public String addArticle(Article article) {
articleDao.addArticle(article);
return "redirect:/articles";
}
// other code
my form addArticleForm.jsp
<%# page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%#taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form method="post">
title: <input type="text" name="title"/><br/>
author: <select name="author">
<c:forEach items="${authors}" var="author">
<option value="${author}">${author.userName}</option>
</c:forEach>
</select>
<br/>
content: <input type="text" name="content"/><br/>
<input type="submit" value="add"/>
</form>
</body>
</html>
You are violating REST principles. Always use version in your endpoint and resource name after that. Example - /api/v1/articles. After that with help of HttpMethods access your resources. Example - If you want to
1.1 add new Article , use POST request to /api/v1/articles
1.2 delete existing Article, use DELETE request to /api/v1/articles/{articleId}
1.3 get one Article, use GET request to /api/v1/articles/{articleId}
1.4 get all Articles, use GET request to /api/v1/articles
1.5 update existing Article, use PUT request to /api/v1/articles/{articleId}
Never use your Entity which is going to be persisted in DB for all layers. It`s bad practice to connect Entity with your view, instead you can use DTO.
Use #ModelAttribute annotation in your controller layer with same name as in view to handle incoming Article object. Example
public String addArticle(#ModelAttribute("article") Article article )
To add new Article first you need to create endpoint which is returning empty Article object inside of ModelMap. Then you must handle this in your front end(JSP) and for submitting this form follow step 3.
Hope this will help.
I got solution :
<%# page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%#taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<form method="post">
title: <input type="text" name="title"/><br/>
author: <select name="author.userId">
<c:forEach items="${authors}" var="author">
<option value="${author.userId}">${author.userName}</option>
</c:forEach>
</select>
<br/>
content: <input type="text" name="content"/><br/>
<input type="submit" value="add"/>
</form>
</body>
</html>
change name of <select> tag from "author" to "author.userId" . That works.
I am trying to built my first Spring mvc application And working on Spring Mvc Form Validation.I am trying to check for empty field. But when to validate the 'long' type variable with #NotNull annotation it give me the above error.
I don't know how to solve it.
Here is My Student Bean
public class Student {
#NotNull
#Pattern(regexp="[A-Za-z]+")
private String name;
#Size(min=2, max=10)
private String father;
private String cnic;
#NotBlank
private String email;
#NotNull
private long phone;
public long getPhone() {
return phone;
}
public void setPhone(long phone) {
this.phone = phone;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCnic() {
return cnic;
}
public void setCnic(String cnic) {
this.cnic = cnic;
}
public String getFather() {
return father;
}
public void setFather(String father) {
this.father = father;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
And my studentmessage.properties file
Pattern.student1.name=The should not contain any Digits
Size.student1.father=please give the {0} between {2} and {1} characters
NotBlank.student1.email=please the email are requried
NotNull.student1.phone=sPlease provide integer data
Controller Class
#Controller
#RequestMapping(value="/student")
public class StudentController {
#RequestMapping(value="/Student",method=RequestMethod.GET)
public String std(Model m){
m.addAttribute("message", "Welcome To Registration ");
return "studentreg";
}
public ModelAndView insert(#Valid #ModelAttribute("student1") Student student1,BindingResult result) //ModelAttribute is used to directly connect the form data to the bean class
{
if(result.hasErrors()){
ModelAndView model=new ModelAndView("studentreg");
return model;
}
ModelAndView mo=new ModelAndView("success");
mo.addObject("message","user detail");
mo.addObject("stu", student1);
return mo;
}
}
Jsp file is
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%#taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<h2 align="center">${ message}</h2>
<form:errors path="student1.phone" style="color:red"/><br>
<form:form name="form" method="post" action="stu" >
<div align="center">
<table>
${ error}
<tr>
<td>Name :</td><td><input type="text" name="name" placeholder="EnterName"></td>
</tr>
<tr>
<td>Father Name</td>
<td><input type="text" name="father" placeholder="EnterFatherName"/></td>
</tr>
<tr>
<td>CNIC</td>
<td><input type="text" name="cnic" placeholder="Enter CNIC"/></td>
</tr>
<tr>
<td>Email</td>
<td><input type="text" name="email" placeholder="Enter Email"/></td>
</tr>
<tr>
<td>Phone:</td>
<td><input type="text" name="phone" placeholder="Enter Phone"/></td>
<form:errors path="phone"/>
</tr>
<tr>
<td><input type="submit" name="submite" value="Send"/></td>
</tr>
</table>
</table>
</table>
</div>
</table>
</form:form>
</body>
</html>
Try to use Long instead of long.
Because long can never be null it is not primitive type.
So you should use Long.