I'm making a spring web calculator, that receives input in template named "calculator" , post-s it to the back-end, validates it, and if the input matches the pattern it calculates the result and shows it in another template named "result" The problem is, if my input does not match the pattern, it must return a error message. For this purpose i used "th:if". But instead, it throws 400 bad request error. This is my code: Controller `
@Controller
public class CalculationController implements WebMvcConfigurer {
@GetMapping("/")
public String showForm(CalculatorForm calculatorForm) {
//model.addAttribute("calculatorForm", new CalculatorForm());
return "calculator";
}
@PostMapping("/")
public String checkCalcValue(@Valid CalculatorForm calculatorForm, Model model, Errors errors) {
if(errors.hasErrors()){
return "calculator";
}
CalculationService service = new CalculationService();
calculatorForm.setCalculationResult(service.calculate(calculatorForm.getCalculationValue()));
System.out.println(calculatorForm.getCalculationValue());
model.addAttribute("calculatorForm", calculatorForm);
return "result";
}
}
**Service**
public class CalculationService {
public double calculate(String toCalculate) {
ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression(toCalculate);
Double result = exp.getValue(Double.class);
return result;
}
}
**Model**
public class CalculatorForm {
@NotEmpty
@Pattern(regexp="([0-9]|[\\- */]) ",message="only math expressions")
private String calculationValue;
private Double calculationResult;
public String getCalculationValue() {
return calculationValue;
}
public void setCalculationValue(String newCalculationValue){
calculationValue = newCalculationValue;
}
public void setCalculationResult(Double newCalculationResult){
calculationResult = newCalculationResult;
}
public Double getCalculationResult(){
return calculationResult;
}
}
**Calculator template**
<html xmlns:th="https://www.thymeleaf.org">
<head>
<title>Your first Spring application</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p><a href="/calculator">Calculator</a></p>
<form action="#" th:action="@{/}" th:object="${calculatorForm}" method="post">
<table>
<tr>
<td>Calculator:</td>
<td><input value="" type="text" th:field="*{calculationValue}" name="calculationValue" id="calculationValue"/></td>
<td th:if="${#fields.hasErrors('calculationValue')}" th:errors="*{calculationValue}">Calculation Error</td>
</tr>
<tr>
<br/>
<input type="button" onclick="input(this);" id="buttonOne" value="1"></input>
<input type="button" onclick="input(this);" id="buttonTwo" value="2"></input>
<input type="button" onclick="input(this);" id="buttonThree" value="3"></input>
<br/>
<input type="button" onclick="input(this);" id="buttonFour" value="4"></input>
<input type="button" onclick="input(this);" id="buttonFive" value="5"></input>
<input type="button" onclick="input(this);" id="buttonSix" value="6"></input>
<br/>
<input type="button" onclick="input(this);" id="buttonSeven" value="7"></input>
<input type="button" onclick="input(this);" id="buttonEight" value="8"></input>
<input type="button" onclick="input(this);" id="buttonNine" value="9"></input>
<br/>
<input type="button" onclick="input(this);" id="buttonZero" value="0"></input>
<input type="button" onclick="input(this);" id="buttonPlus" value=" "></input>
<input type="button" onclick="input(this);" id="buttonMinus" value="-"></input>
<br/>
<input type="button" onclick="input(this);" id="buttonMultiply" value="*"></input>
<input type="button" onclick="input(this);" id="buttonDivide" value="/"></input>
<input type="button" onclick="remove();" id="remove" value="<-"></input>
<br/>
</tr>
<tr>
<td><button type="submit">Submit</button></td>
</tr>
<input type="button" onclick="delAll();" id="delete" value="DEL"></input>
</table>
</form>
<script>
function input(button){
let calculationValue = document.getElementById("calculationValue");
calculationValue.value = button.value;
}
function remove(){
let calculationValue = document.getElementById("calculationValue");
calculationValue.value = calculationValue.value.substring(0, calculationValue.value.length - 1);
}
function delAll(){
let calculationValue = document.getElementById("calculationValue");
calculationValue.value = "";
}
</script>
</body>
</html>
**Result template**
<html xmlns:th="https://www.thymeleaf.org">
<head>
<title>Your first Spring application</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p><a href="/calculator">Calculator</a></p>
<form action="#" th:action="@{/}" th:object="${calculatorForm}" method="post">
<table>
<tr>
<td>Calculator:</td>
<td><input value="" type="text" th:field="*{calculationValue}" name="calculationValue" id="calculationValue"/></td>
<td th:if="${#fields.hasErrors('calculationValue')}" th:errors="*{calculationValue}">Calculation Error</td>
</tr>
<tr>
<br/>
<input type="button" onclick="input(this);" id="buttonOne" value="1"></input>
<input type="button" onclick="input(this);" id="buttonTwo" value="2"></input>
<input type="button" onclick="input(this);" id="buttonThree" value="3"></input>
<br/>
<input type="button" onclick="input(this);" id="buttonFour" value="4"></input>
<input type="button" onclick="input(this);" id="buttonFive" value="5"></input>
<input type="button" onclick="input(this);" id="buttonSix" value="6"></input>
<br/>
<input type="button" onclick="input(this);" id="buttonSeven" value="7"></input>
<input type="button" onclick="input(this);" id="buttonEight" value="8"></input>
<input type="button" onclick="input(this);" id="buttonNine" value="9"></input>
<br/>
<input type="button" onclick="input(this);" id="buttonZero" value="0"></input>
<input type="button" onclick="input(this);" id="buttonPlus" value=" "></input>
<input type="button" onclick="input(this);" id="buttonMinus" value="-"></input>
<br/>
<input type="button" onclick="input(this);" id="buttonMultiply" value="*"></input>
<input type="button" onclick="input(this);" id="buttonDivide" value="/"></input>
<input type="button" onclick="remove();" id="remove" value="<-"></input>
<br/>
</tr>
<tr>
<td><button type="submit">Submit</button></td>
</tr>
<input type="button" onclick="delAll();" id="delete" value="DEL"></input>
</table>
</form>
<script>
function input(button){
let calculationValue = document.getElementById("calculationValue");
calculationValue.value = button.value;
}
function remove(){
let calculationValue = document.getElementById("calculationValue");
calculationValue.value = calculationValue.value.substring(0, calculationValue.value.length - 1);
}
function delAll(){
let calculationValue = document.getElementById("calculationValue");
calculationValue.value = "";
}
</script>
</body>
</html>
`
I tried debugging with a breakpoint in the Controller, the "if(errors.hasErrors())" line. If the input matches the pattern, it returns zero errors and the compilation continues, but the interesting thing is if the input does not match the pattern, it doesn't reach the breakpoint - which has post mapping annotation, that means that something stops the compilation and throws 400 error before it reaches the part of the code where it must return a error message.
CodePudding user response:
From the Web MVC reference documentation:
You must declare an
Errors
, orBindingResult
argument immediately after the validated method argument.
You put your Model
argument between the validated form and the Errors
.