Forum PCLab.pl: Problem z walidacją Spring - Forum PCLab.pl

Skocz do zawartości


Otwarty

Ikona Najnowsze pliki

Strona 1 z 1
  • Nie możesz rozpocząć nowego tematu
  • Nie możesz odpowiadać w tym temacie

Problem z walidacją Spring Oceń temat: -----

#1 Użytkownik jest niedostępny   Elzulninho 

  • Gaduła
  • PipPipPip
  • Grupa: Forumowicze
  • Postów: 129
  • Dołączył: Cz, 03 Sty 13

Napisany 19 Marzec 2019 - 10:46

Cześć mam taki kalkulator BMR:
Zrobiłem na klasie modelowej walidację jednak problem jest po stronie kontrolera , coś źle piszę , czegoś brakuje... w każdym razie walidacja nie działa
Formularz wygląda tak (plik bmrform)
<form class="list-inline"  th:object="${operationModel}" th:action="@{/bmr}" th:method="post" >
        <div class="form-group" >
            <label class="control-label">Wzrost:</label>
            <input type="text" class="form-control" th:field="*{height}" placeholder="Wzrost w centymetrach"/>
            <p th:if="${#fields.hasErrors('height')}" th:errors="*{height}"/>
        </div>

        <div class="form-group" >
            <label class="control-label">Masa ciała:</label>
            <input type="text" class="form-control" th:field="*{bodyweight}" placeholder="Masa ciała w kg"/>
            <p th:if="${#fields.hasErrors('bodyweight')}" th:errors="*{bodyweight}"/>
        </div>
        <div class="form-group" >
            <label class="control-label">Wiek:</label>
            <input type="text" class="form-control" th:field="*{age}" placeholder="Wiek"/>
            <p th:if="${#fields.hasErrors('age')}" th:errors="*{age}"/>
        </div>


Metody w kontrolerze
 @RequestMapping("/bmr")
    public String createOperationModel(Model model) {
        model.addAttribute("operationModel", new CalculatorFromBmr());
        return "bmrform";
    }

    @RequestMapping(path="/bmr", method = RequestMethod.POST)
    public String add(@ModelAttribute("operationModel") CalculatorFromBmr calculatorFromBmr, Model model) {
        model.addAttribute("result", calculatorBmr.calculate(calculatorFromBmr.getHeight(),calculatorFromBmr.getBodyweight(),calculatorFromBmr.getAge()));
        return "bmrform";
    }

I METODA Z WALIDACJA, W KTÓREJ CZEGOŚ BRAKUJE...

@RequestMapping( method = RequestMethod.POST)
    public String saveResult(@Valid CalculatorFromBmr calculatorFromBmr, BindingResult bindingResult) {

        if (bindingResult.hasErrors()) {
            System.out.println("There were errors");
            bindingResult.getAllErrors().forEach(error -> {
                        System.out.println(error.getObjectName() + " " + error.getDefaultMessage());
                    }
            );
            return "bmrform";
        } else {
            return "redirect:/bmr";
        }

    }



#2 Użytkownik jest niedostępny   Karister 

  • Gaduła
  • PipPipPip
  • Grupa: Forumowicze
  • Postów: 385
  • Dołączył: Nd, 14 Wrz 08

Napisany 19 Marzec 2019 - 15:39

Pokaż konfig beanów Spring i dependencje , jakie zaciągasz przez maven/gradle.

Ten post był edytowany przez Karister dnia: 19 Marzec 2019 - 15:40


#3 Użytkownik jest niedostępny   Elzulninho 

  • Gaduła
  • PipPipPip
  • Grupa: Forumowicze
  • Postów: 129
  • Dołączył: Cz, 03 Sty 13

Napisany 19 Marzec 2019 - 16:05

<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>



Tutaj część od kontrolera
@Controller
public class CalculatorBmrController {
    @Autowired
    CalculatorBmr calculatorBmr;



Tutaj klasa z metodą
@Component
public class CalculatorBmr {

    public double calculate(double height, double bodyweight,int age){
return 66+(13.7*bodyweight)+(5*height)-(6.76*age);
    }

}



#4 Użytkownik jest niedostępny   Karister 

  • Gaduła
  • PipPipPip
  • Grupa: Forumowicze
  • Postów: 385
  • Dołączył: Nd, 14 Wrz 08

Napisany 19 Marzec 2019 - 17:09

Formularz strzela POST pod /bmr, a w kontrolerze w metodzie zmapowanej pod ten adres nie ma @Valid. @Valid masz w zupełnie innej metodzie.

Ten post był edytowany przez Karister dnia: 19 Marzec 2019 - 17:11


#5 Użytkownik jest niedostępny   Elzulninho 

  • Gaduła
  • PipPipPip
  • Grupa: Forumowicze
  • Postów: 129
  • Dołączył: Cz, 03 Sty 13

Napisany 19 Marzec 2019 - 18:10

Więc muszę coś zrobić z tą drugą metodą, a ta 3 metoda w kontrolerze jest niepotrzebna? Próbowałem w ten sposób ale oczywiście robię coś źle...
  @RequestMapping(path="/bmr", method = RequestMethod.POST)
    public String add(@ModelAttribute("operationModel")@Valid CalculatorFromBmr calculatorFromBmr, Model model,BindingResult bindingResult) {
        model.addAttribute("result", calculatorBmr.calculate(calculatorFromBmr.getHeight(),calculatorFromBmr.getBodyweight(),calculatorFromBmr.getAge()));
        if (bindingResult.hasErrors()) {
            System.out.println("There were errors");
            bindingResult.getAllErrors().forEach(error -> {
                        System.out.println(error.getObjectName() + " " + error.getDefaultMessage());
                    }
            );
            return "bmrform";
        } else {
            return "redirect:/bmr";
        }
    }


#6 Użytkownik jest niedostępny   Karister 

  • Gaduła
  • PipPipPip
  • Grupa: Forumowicze
  • Postów: 385
  • Dołączył: Nd, 14 Wrz 08

Napisany 19 Marzec 2019 - 20:55

Tak, ma być jedna metoda dla GET i jedna dla POST. Na moje oko masz źle zmapowany th:object w thymleaf i nazwę w @ModelAttribute kontrolera, więc Spring nie ma pojęcia, że to jest to samo.

#7 Użytkownik jest niedostępny   Elzulninho 

  • Gaduła
  • PipPipPip
  • Grupa: Forumowicze
  • Postów: 129
  • Dołączył: Cz, 03 Sty 13

Napisany 19 Marzec 2019 - 22:46

Ale jakby nie miał pojęcia, że to to samo to by przypadkiem nie zwracał wyniku liczenia? Bo wszystko działa oprócz walidacji

#8 Użytkownik jest niedostępny   Karister 

  • Gaduła
  • PipPipPip
  • Grupa: Forumowicze
  • Postów: 385
  • Dołączył: Nd, 14 Wrz 08

Napisany 20 Marzec 2019 - 02:20

Masz różne błędy, które na siebie wpływają i ciężko jest coś wywróżyć bez całego kodu. Do tego polecam dbać o formatowanie kodu i nazewnictwo zmiennych, bo to ułatwia życie.


Po pierwsze object w thymleaf i argument @ModelAttribute w kontrolerze muszą być takie same. Po drugie kolejność argumentów w metodach kontrolera ma znaczenie - bindingResult musi być po modelu formularza, którego dotyczy.
<form class="list-inline" th:object="${bmrFormData}" th:action="@{/bmr}" th:method="post">
(...)
</form>

    @RequestMapping("/bmr")
    public String showForm(Model model) {
        model.addAttribute("bmrFormData", new BmrCalculatorForm());
        return "bmrform";
    }

    @RequestMapping(path = "/bmr", method = RequestMethod.POST)
    public String calculate(@Valid @ModelAttribute("bmrFormData") BmrCalculatorForm bmrCalculatorForm,
                      BindingResult bindingResult,
                      Model model) {

        if (bindingResult.hasErrors()) {
            return "bmrform";
        }

        double result = bmrCalculator.calculate(bmrCalculatorForm.getHeight(), bmrCalculatorForm.getBodyWeight(), bmrCalculatorForm.getAge());
        model.addAttribute("result", result);
        return "redirect:/bmr";
    }

Kolejna rzecz, to jakieś zasady walidacji.
public class BmrCalculatorForm {

    @NotNull(message = "Puste pole")
    private Integer height;
    @NotNull(message = "Puste pole")
    private Integer bodyWeight;
    @NotNull(message = "Puste pole")
    @Min(value = 10, message = "Minimum 10")
    private Integer age;

    // get / set
}


I to wszystko, co jest potrzebne w standardowym przypadku. Ty używasz wzorca post-redirect-get, który uniemożliwia wielokrotne wysłanie formularza, co jest bardzo dobrą praktyką, ale ma swoje konsekwencje. W przypadku udanego obsłużenia POST w metodzie calculate wymuszone jest od przeglądarki wysłanie kolejnego zapytania GET: return "redirect:/bmr;". Co za tym idzie, użytkownik zobaczy stronę wygenerowaną przez metodę showBmrForm, a tam nic nie wiadomo o warości result. Można sobie z tym poradzić modyfikując fragment powyższego kodu:
    @RequestMapping(path = "/bmr", method = RequestMethod.POST)
    public String calculate(@Valid @ModelAttribute("bmrFormData") BmrCalculatorForm bmrCalculatorForm,
                      BindingResult bindingResult,
                      RedirectAttributes redirectAttributes) {

        if (bindingResult.hasErrors()) {
            return "bmrform";
        }

        double result = bmrCalculator.calculate(bmrCalculatorForm.getHeight(), bmrCalculatorForm.getBodyWeight(), bmrCalculatorForm.getAge());
        redirectAttributes.addFlashAttribute("result", result);
        return "redirect:/bmr";
    }

Ten post był edytowany przez Karister dnia: 20 Marzec 2019 - 02:35


Strona 1 z 1
  • Nie możesz rozpocząć nowego tematu
  • Nie możesz odpowiadać w tym temacie

1 Użytkowników czyta ten temat
0 użytkowników, 1 gości, 0 anonimowych