0

Im very new to the SpringBoot framework, currently i'm trying to create a working page for CRUD operations required for my project. The problem is in my controller BindingResult wont catch any errors when i submit a form with empty inputs. Here's my DTO class:

package com.estate.controllers;

import com.estate.model.Property;
import jakarta.persistence.Column;
import jakarta.persistence.PrePersist;
import jakarta.persistence.Temporal;
import jakarta.persistence.TemporalType;
import jakarta.validation.constraints.*;
import java.util.Date;
import org.springframework.web.multipart.MultipartFile;

public class PropertyDTO {
    @NotEmpty(message = "The name of the property is required")
    private String title;
    @Size(min = 10, message = "The description should be at least 10 characters long")
    @Size(max = 2000, message = "The description can not exceed 2000 characters")
    private String description;
    @NotEmpty(message = "The price is required")
    @Size(min = 0)
    private Double price;
    @NotEmpty(message = "The number of bedrooms is required")
    @Size(min = 0)
    private Integer bedrooms;
    @NotEmpty(message = "The number of bathrooms is required")
    @Size(min = 1,message = "The number of bathrooms must be at least 1")
    private Integer bathrooms;
    @NotEmpty(message = "The area is required")
    @Size(min = 0,message = "The area must be greater than 0")
    private Double area;
    @NotEmpty(message = "The name of the city is required")
    private String city;
    @NotEmpty(message = "The address is required")
    private String address;
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "created_at")
    private Date createdAt;

    @PrePersist
    protected void onCreate() {
        createdAt = new Date();
    }
    @Column(name = "image_url")
    private MultipartFile imageFile;

}

My controller where i even doubled the if statement for errors:

package com.estate.Admin;

import com.estate.controllers.PropertyDTO;
import com.estate.model.Property;
import com.estate.repository.PropertyRepository;
import com.estate.service.PropertyService;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;

@Controller
@RequestMapping("/properties")
@Validated
public class AdminPropertyController {

    private final PropertyService propertyService;

    @Autowired
    private PropertyRepository repo;

    public AdminPropertyController(PropertyService propertyService) {
        this.propertyService = propertyService;
    }
    @GetMapping({"","/"})
    public String showPropertyList(Model model){
                List<Property> properties = repo.findAll();
                model.addAttribute("properties", properties);
                return "propertyTemplate/index.html";
    }
    @GetMapping("/create")
    public String showCreatePage(@ModelAttribute("propertyDTO") PropertyDTO propertyDTO, Model model) {
        model.addAttribute("propertyDTO", propertyDTO);
        return "propertyTemplate/createProperty";
    }

    @PostMapping("/create")
    public String CreateProperty(@ModelAttribute("propertyDTO") @Valid PropertyDTO propertyDto, @Valid BindingResult result, Model model){
        if(result.hasErrors()){
            model.addAttribute("errors", result.getAllErrors());
            return "propertyTemplate/createProperty";
        }
        if(result.hasErrors()){
            return "propertyTemplate/createProperty";
        }

        return "redirect:/properties";
    }
}

And my html file, i use thymeleaf for displaying errors:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Online catalog</title>
  <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
</head>
  <body>
      <div class ="container">
          <div class="row">
            <div class="col-md-8 mx-auto rounded border p-4 m-4">
              <h2 class="text-center mb-5">New Property</h2>
              <form :form method ="POST" enctype="multipart/form-data" th:object="${propertyDTO}">

                <div class="row mb-3">
                  <label class="col-sm-4 col-form-label">Name</label>
                  <div class="col-sm-8">
                    <input class="form-control" placeholder="Введите название" th:field="${propertyDTO.title}">
                    <p th:if="${#fields.hasErrors('title')}" th:errorclass="text-danger"
                       th:errors="${propertyDTO.title}"></p>
                  </div>
                </div>

                <div class="row mb-3">
                  <label class="col-sm-4 col-form-label">Description</label>
                  <div class="col-sm-8">
                    <textarea class="form-control" placeholder="Введите описание"
                              th:field="${propertyDTO.description}"></textarea>
                    <p th:if="${#fields.hasErrors('description')}" th:errorclass="text-danger"
                       th:errors="${propertyDTO.description}"></p>
                  </div>
                </div>

                <div class="row mb-3">
                  <label class="col-sm-4 col-form-label">Price</label>
                  <div class="col-sm-8">
                    <input class="form-control" type="number" step="0.01" min="0" value="0" placeholder="Введите цену"
                           th:field="${propertyDTO.price}">
                    <p th:if="${#fields.hasErrors('price')}" th:errorclass="text-danger"
                       th:errors="${propertyDTO.price}"></p>
                  </div>
                </div>

                <div class="row mb-3">
                  <label class="col-sm-4 col-form-label">Bedrooms</label>
                  <div class="col-sm-8">
                    <input class="form-control" type="number" step="1" min="0" value="0" placeholder="Введите количество комнат"
                           th:field="${propertyDTO.bedrooms}">
                    <p th:if="${#fields.hasErrors('bedrooms')}" th:errorclass="text-danger"
                       th:errors="${propertyDTO.bedrooms}"></p>
                  </div>
                </div>

                <div class="row mb-3">
                  <label class="col-sm-4 col-form-label">Bathrooms</label>
                  <div class="col-sm-8">
                    <input class="form-control" type="number" step="1" min="0" value="0" placeholder="Введите количество комнат"
                           th:field="${propertyDTO.bathrooms}">
                    <p th:if="${#fields.hasErrors('bathrooms')}" th:errorclass="text-danger"
                       th:errors="${propertyDTO.bathrooms}"></p>
                  </div>
                </div>

                <div class="row mb-3">
                  <label class="col-sm-4 col-form-label">Area</label>
                  <div class="col-sm-8">
                    <input class="form-control" type="number" step="0.01" min="0" placeholder="Введите площадь"
                           th:field="${propertyDTO.area}">
                    <p th:if="${#fields.hasErrors('area')}" th:errorclass="text-danger"
                       th:errors="${propertyDTO.area}"></p>
                  </div>
                </div>

                <div class="row mb-3">
                  <label class="col-sm-4 col-form-label">City</label>
                  <div class="col-sm-8">
                    <input class="form-control" placeholder="Введите город"
                           th:field="${propertyDTO.city}">
                    <p th:if="${#fields.hasErrors('city')}" th:errorclass="text-danger"
                       th:errors="${propertyDTO.city}"></p>
                  </div>
                </div>

                <div class="row mb-3">
                  <label class="col-sm-4 col-form-label">Address</label>
                  <div class="col-sm-8">
                    <input class="form-control" placeholder="Введите адресс"
                           th:field="${propertyDTO.address}">
                    <p th:if="${#fields.hasErrors('address')}" th:errorclass="text-danger"
                       th:errors="${propertyDTO.address}"></p>
                  </div>
                </div>

                <div class="row mb-3">
                  <label class="col-sm-4 col-form-label">Image</label>
                  <div class="col-sm-8">
                    <input type="file" class="form-control"
                           th:field="${propertyDTO.imageFile}">
                    <p th:if="${#fields.hasErrors('imageFile')}" th:errorclass="text-danger"
                       th:errors="${propertyDTO.imageFile}"></p>
                  </div>
                </div>

                <div class="row">
                  <div class="offset-sm-4 col-sm-4 d-grid">
                    <button type="submit" class="btn btn-primary">Submit</button>
                  </div>
                  <div class="col-sm-4 d-grid">
                    <a class="btn btn-outline-primary" href="/properties" role="button">Cancel</a>
                  </div>
                </div>

              </form>
            </div>
          </div>
      </div>
      <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"      crossorigin="anonymous"></script>
  </body>
    </html>

I tried changing names of the model attribute cause at first in project logs i was seing an issue with it, but now im hard stuck at this propblem. I would appreciate any pointers for the problems or incorrections beyond the validation problem.

4
  • For starters your th:field="${propertyDTO.title}" should be th:field="*{title}" in your form. Applies to your other form fields as well ofcourse. Additionally make sure you added spring-boot-starter-validation as a dependency and didn't mess around with individual validation-api dependencies etc. Commented Apr 29, 2024 at 9:11
  • Wow, didn't expect to get answer so quickly. Thank you a lot! it appears my dependencies were not in place and i changed html by your suggestion. Now i can see error messages in project logs. But there's new issue, controller catches the error of empty input fields and redirects me to the create page again where i expect to see error messages for every input field, instead i see error page with 500 code. Maybe i have still did something wrong in html using thymeleaf? '<p th:if="${#fields.hasErrors('description')}" th:errorclass="error" th:errors="${description}"></p>' Commented Apr 29, 2024 at 11:14
  • Well the 500 error, or rather the stacktrace on the server side will tell you what is wrong. One thing is that the th:errors syntax should be the same as for the th:field so th:errors="*{description}" instead of th:errors="${description}. I would strongly suggest a read of the documentation instead of trail and error. Commented Apr 29, 2024 at 11:15
  • Thank you very much for your quick responses! As you suggested i'll read the documentation for further progress on my project. Big thanks again! Commented Apr 29, 2024 at 11:20

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.