How Spring Boot understand on what exactly custom object is need to map fields from html? - spring-boot

In Spring boot application:
Here repo:
import org.springframework.data.repository.CrudRepository;
import myproject.eshop.model.User;
// Use JPQL
public interface UserRepository extends CrudRepository<User, Long> {
User findByUsername(String username);
}
Here controller:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import myproject.eshop.model.Role;
import myproject.eshop.model.User;
import myproject.eshop.repo.UserRepository;
import java.util.Collections;
#Controller
public class RegistrationController {
#Autowired
private UserRepository userRepository;
#GetMapping("/registration.html")
public String registration(Model model) {
logger.info("open_registration.html");
model.addAttribute("appName", appName);
return "registration.html";
}
#PostMapping("/registration.html")
public String registartionNewUser(User user, Model model, #RequestParam(name = "retypePassword", required = true) String retypePassword) {
logger.info("retypePassword = " + retypePassword + ", user = " + user);
if (user.getUsername().trim().isEmpty()
|| user.getPassword().trim().isEmpty()
) {
model.addAttribute("registrationError", "Аll fields are required!");
return "registration.html";
}
user.setActive(true);
user.setRoles(Collections.singleton(Role.USER));
User userFromDb = userRepository.findByUsername(user.getUsername());
if (userFromDb != null) {
model.addAttribute("registrationError", "User already exist!");
return "registration.html";
}
userRepository.save(user);
return "redirect:/login.html";
}
}
here template:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title th:text="${appName}">Template title</title>
<link th:href="#{/public/style.css}" rel="stylesheet"/>
</head>
<body>
<div id="container">
<h2 align="center">Registration new user</h2>
<form th:action="#{/registration.html}" method="post">
<label for="username">Username</label>
<input type="text" id="username" name="username" autofocus="autofocus"/>
<label for="password">Password</label>
<input type="password" id="password" name="password"/>
<label for="retypePassword">Retype password</label>
<input type="password" id="retypePassword" name="retypePassword"/>
<input id="submit" type="submit" value="Registration"/>
</form>
<p th:if="${registrationError}" th:text="${registrationError}" class="error"></p>
</div>
</body>
</html>
Here my custom object User:
import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.util.Set;
#Entity
#Table(name = "usr") // PostgreSQL not work with table "user"
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
#NotNull
private String username;
#NotNull
private String password;
#NotNull
private boolean active;
#NotNull
#ElementCollection(targetClass = Role.class, fetch = FetchType.EAGER)
#CollectionTable(name = "user_role", joinColumns = #JoinColumn(name = "user_id"))
#Enumerated(EnumType.STRING)
private Set<Role> roles;
When open registration.html filled all fields and click submit button then call method registartionNewUser
And param user is correct filled (from form registration.html).
How Spring Boot link form registration.html with my customer object User ?
In registration.html no link to my customer object User

Basically you're implemented hibernate or jpa in backend which handle this things for you.
Notice that you column names are same as your name which you pass by html.
So that they accept the requested object get individual variable and create empty object of User class and place on exect match in User entity class and this way create User object.
For cross verification change it to capital or something it gives an 400 error.
This process is not that much easy as we discuss. You modify this as your way using javax library annotations.
For more detail this link,
https://howtodoinjava.com/hibernate-tutorials/

Have you tried make use of #ModelAttribute annotation which will map your custom made
object User to a model attribute and then exposes it to a web view.
<form th:action="#{/registration.html}" modelAttribute= "user" method="post">
<label for="username">Username</label>
<input type="text" id="username" name="username" path = "username"
autofocus="autofocus"/>
<label for="password">Password</label>
<input type="password" id="password" name="password" path = "password"/>
<label for="retypePassword">Retype password</label>
<input type="password" id="retypePassword" name="retypePassword"/>
<input id="submit" type="submit" value="Registration"/>
</form>
And then you bind it in the controller class:
#GetMapping( "/registration.html")
public String registration( #ModelAttribute("user") User user, Model model) {
logger.info("open_registration.html");
model.addAttribute("appName", appName);
return "registration.html";
}

Related

Missing values between GET and POST method

I'm learning Spring Boot and I have a problem. I'm creating an Order in one form and then adding the user's details in the second. The second form's GET method has the parameter NewOrder and it's received well (checked using a debugger). Then in this form I'm creating OrderDetails, in which is saved NewOrder and some Strings. Then I'm passing it to the repository using POST method, but in created OrderDetails, there're only Strings and NewOrder is null. How could I resolve it?
First POST method (from the first controller):
#PostMapping
public String processOrder( #ModelAttribute NewOrder order, final RedirectAttributes redirectAttributes) {
redirectAttributes.addFlashAttribute("order", order);
ordersProxy.addOrder(order);
return "redirect:/sendOrder";
}
Second controller (POST and GET):
#GetMapping
public String showSendOrderForm(Model model, #ModelAttribute("order") NewOrder order) {
model.addAttribute("details", new OrderDetails(order) );
model.addAttribute("companies", companyProxy.getCompanies());
return "orderDetails";
}
#PostMapping
public String processTaco( OrderDetails details) {
detailsProxy.addOrderDetails(details);
return "orderDetails";
}
And here, the OrderDetails details in Post Order is null.
orderDetails.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<title>Taco Cloud</title>
<link rel="stylesheet" th:href="#{/styles.css}" />
</head>
<body>
<form method="POST" th:object="${details}">
<a th:href="#{/design}" id="another">Order</a><br/>
<h3>Deliver to...</h3>
<label for="name">Name: </label>
<input type="text" th:field="*{name}"/>
<br/>
<label for="surname">Surname: </label>
<input type="text" th:field="*{surname}"/>
<br/>
<label for="room">Room: </label>
<input type="text" th:field="*{room}"/>
<br/>
<br/>
<h2>Please, choose your company:</h2>
<select th:field="*{company}">
<option th:each="i : ${companies}" th:value="${i.id}" th:text="${i.name}">
</option>
</select>
</div>
</div>
<input type="submit" value="Submit Order"/>
</form>
</body>
</html>
OderDetails class:
#Data
#Entity
#RequiredArgsConstructor
#NoArgsConstructor(access=AccessLevel.PRIVATE, force=true)
public class OrderDetails {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
private String surname;
private String room;
#OneToOne
private final NewOrder order;
#ManyToOne
private Company company;
}
I have also tried to pass NewOrder directly to POSTmethod and there add order to details, but it was still null.
Adding #RequestBody should work for null OrderDetails. Check out this for more about it: https://www.baeldung.com/spring-request-response-body
#PostMapping
public String processTaco(#RequestBody OrderDetails details) {
detailsProxy.addOrderDetails(details);
return "orderDetails";
}

Can't pass an object from one Thymeleaf view to another Thymeleaf view

I'm new to Spring, and I'm working on a Spring MVC + Thymeleaf application that tracks personal expenses. I have a page that shows the list of expenses, and upon clicking "Update" on any given expense, it would show a pre-populated form, on another page, with that expense's information. The problem I'm having is that I want to pass that expense object forward to this second page, but since the data was already fetched from the database in my first page, I wouldn't want to fetch it again from my Spring Data JPA repository.
I think the unusual part of my objective is that I'm trying to pass the object like this:
Controller -> Thymeleaf -> Controller -> Thymeleaf
While the controller has sent an Expenses object to the list of expenses page, I'm trying to resend that same object (or just the one Expense, even better) back to the controller, so it would populate the model in my second form page.
My Expense entity:
package com.williampoletto.expensetracker.entity;
import java.time.LocalDate;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Setter
#EqualsAndHashCode(of= "id")
#ToString(exclude="categories")
#Entity
#Table
public class Expense {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY )
private int id;
#NotBlank
private String description;
#NotNull
private double value;
#NotNull
private LocalDate date;
private String note;
#ManyToOne
private User user;
#ManyToMany(cascade=CascadeType.PERSIST)
#JoinTable(
name="expense_category",
joinColumns=#JoinColumn(name="expense_id"),
inverseJoinColumns=#JoinColumn(name="category_id"))
private Set<Category> categories;
public void addCategory(Category category) {
categories.add(category);
}
public void removeCategory(Category category) {
categories.remove(category);
}
public Expense(int id, #NotBlank String description, #NotNull double value, #NotNull LocalDate date,
String note, Set<Category> categories) {
super();
this.id = id;
this.description = description;
this.value = value;
this.date = date;
this.note = note;
this.categories = categories;
}
}
My thymeleaf table:
<table class="table table-bordered table-striped">
<thead class="thead-dark">
<tr>
<th>Description</th>
<th>Value</th>
<th>Category</th>
<th>Note</th>
<th>Date</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr th:each="expense : ${expenses}">
<td th:text="${expense.description}"/>
<td th:text="${expense.value}"/>
<td>
<div th:each="category : ${expense.categories}">
<p th:text ="${category.name}"></p>
</div>
</td>
<td th:text="${expense.note}"/>
<td th:text="${expense.date}"/>
<td>
<form th:action="#{/expenses/showUpdateForm}" th:object="${expense}" method="POST">
<input type="text" name="expense" th:value="${expense.id}">
<input type="text" name="expenseDescription" th:value="${expense.description}">
<input type="text" name="expenseValue" th:value="${expense.value}">
<input type="text" name="expenseDate" th:value="${expense.date}">
<input type="text" name="expenseNote" th:value="${expense.note}">
<input type="text" name="expenseCategories" th:value="${expense.categories}">
<button th:if="${expense.user != null}" type="submit" class="btn btn-info btn-sm">Update</button>
</form>
<a th:href="#{/expenses/delete(expenseId=${expense.id})}"
class="btn btn-danger btn-sm"
onclick="if (!(confirm('Are you sure you want to delete this expense?'))) return false">Delete</a>
</td>
</tbody>
</table>
My /list and /showUpdateForm code for the controller:
#GetMapping("/list")
public String list(#AuthenticationPrincipal UserDetailsImpl userDetails, Model model) {
Set<Expense> expenses = expenseService.findAll(userDetails.getUserId());
model.addAttribute("expenses", expenses);
return "expenses";
}
#PostMapping("/showUpdateForm")
public String showFormForUpdate(#RequestParam("expenseId") int expenseId,
#RequestParam("expenseDescription") String expenseDescription,
#RequestParam("expenseValue") double expenseValue,
#RequestParam("expenseDate") String expenseDate,
#RequestParam("expenseNote") String expenseNote,
#RequestParam("expenseCategories") Set<Category> expenseCategories,
Model model) {
Expense expense = new Expense
(expenseId, expenseDescription, expenseValue, expenseDate, expenseNote, expenseCategories);
model.addAttribute("expense", expense);
return "/expense-form";
}
My final form page:
<form th:action="#{/expenses/save}" th:object="${expense}" method="POST">
<input type="hidden" th:field="*{id}">
<label>Description</label>
<input type="text" th:field="*{description}" class="form-control mb-4 col-4" placeholder="Description">
<label>Value</label>
<input type="text" th:field="*{value}" class="form-control mb-4 col-4" placeholder="Value">
<label>Date</label>
<input type="text" th:field="*{date}" class="form-control mb-4 col-4" placeholder="Date">
<label>Note</label>
<input type="text" th:field="*{note}" class="form-control mb-4 col-4" placeholder="Note">
<label>Categories</label>
<input type="hidden"
th:each="category : *{categories}"
th:value="${category.id}"
th:field="*{categories}"
th:text="${category.name}"/>
<button type="submit" class="btn btn-success col-2 mb-2">Save</button>
</form>
What I have tried:
Instead of sending an object, sending individual values as you can see in my thymeleaf table. The problem with this is that my Expense entity has a LocalDate, User (another entity) and Set attributes, so I had trouble converting these to an Expense object on the controller side. Ideally I would want to write something like this to simply pass on the object, but this example sends a toString:
<form th:action="#{/expenses/showUpdateForm}" th:object="${expense}" method="POST">
<input type="text" name="expense" th:value="${expense}">
</form>
Tried to use an argument to /showUpdateForm to hopefully get the expenses object from the model:
#RequestAttribute("expenses") Set<Expense> expenses
Tried to retrieve the object like this in /showUpdateForm, with the same intent as 2:
Set<Expense> expenses = (Set<Expense>) model.getAttribute("expenses");
Tried to use RedirectAttributes in the controller, which I saw can be useful for passing objects between controllers, but maybe not in my case:
#GetMapping("/showUpdateForm")
public String showFormForUpdate(Model model, RedirectAttributes attributes) {
attributes.addAttribute("expenses");
return "/expense-form";
}
Anyway, I have no idea how to achieve this, I would appreciate any light on the subject! I know that I can easily fix this by simply sending an id from view to controller, then I could perform a repository search of the object with that ID, but that would be cumbersome to the database since the data already exists and was fetched in the previous page.

How to POST data using API in Postman

I am creating an API by using spring boot. Basically, this API does CRUD operations. And also I created a client that consumes my own API. At first I use Postman to POST data, it successfully insert data to the database and gives me 200 OK code. Then I created web page and I use my API as form action. Then I tried to insert data using the API. But, couldn't. Then I removed #RequestBody from the method and after that I was able to insert data. But the thing is now I can't insert data using Postman. When I try to insert data using Postman, it gives me 200 OK, but nothing insert to the database.
How can I Fix this ??
package com.kisalka.pacrestapi.controller;
import java.util.List;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import com.kisalka.pacrestapi.repository.ImRepository;
import com.kisalka.pacrestapi.model.ImModel;
#RestController
#RequestMapping("/api")
public class ImController {
#Autowired
private ImRepository TaskRepository;
#RequestMapping(method=RequestMethod.POST, value="/tasks")
public ImModel createNote(ImModel note) {
return TaskRepository.save(note);
}
}
My web page.
<form class="form-horizontal" method="POST" action="">
<div class="form-group">
<label class="control-label col-md-3">Project Name</label>
<div class="col-md-7">
<input type="text" class="form-control" name="pname" id="txtPname"/>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-3">Developer Name</label>
<div class="col-md-7">
<input type="text" class="form-control" name="devname" id="txtDevname"/>
</div>
</div>
<div class="form-group">
<input type="submit" class="btn btn-primary" value="Save" id="btnRegister"/>
</div>
</form>
In one of your #Configuration classes or #EnableAutoConfiguration class create a bean of CommonsRequestLoggingFilter, paste the code. This will log every incoming request
#Bean
public CommonsRequestLoggingFilter logFilter() {
CommonsRequestLoggingFilter filter
= new CommonsRequestLoggingFilter();
filter.setIncludeQueryString(true);
filter.setIncludePayload(true);
filter.setMaxPayloadLength(10000);
filter.setIncludeHeaders(false);
filter.setAfterMessagePrefix("REQUEST DATA : ");
return filter;
}
And in your application.properties file set logging level to DEBUG using logging.level.org.springframework.web.filter.CommonsRequestLoggingFilter=
DEBUG
All set! now call your endpoint from the WEB/Postman and check if you find the missing piece.
You need to use #RequestBody :
#RequestMapping(method=RequestMethod.POST, value="/tasks")
public ImModel createNote(#RequestBody ImModel note) {
return TaskRepository.save(note);
}
use the code written below.You need to add #RequestBody before ImModel note
#RequestMapping(method=RequestMethod.POST, value="/tasks")
public ImModel createNote(#RequestBody ImModel note) {
return TaskRepository.save(note);
}

Why can't I go to other Controller rather than HomeController in Spring framework?

I created a Spring project with STS, using MySql with MyBatis.
I'm trying to make a function for Members to Sign up, but it only keep visiting Homecontroller.java instead of MemberController, when I click the submit button.
This is the arrangement of my files and codes.
This is from index.jsp
<%# page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%# page session="false" %>
<html>
<head>
<title>Home</title>
</head>
<body>
<P> The time on the server is ${serverTime}. </P>
<h1> This is the first page to Log In</h1>
<form id="form1" action="members/logIn">
LogIn <p>
ID: <input type="text" name="id" id="id">
Password: <input type="password" name="pwd" id="pwd">
<input type="button" onclick="logIn()" value="press to LogIn">
</form>
<p><br><br><h3>Move to SignUp page</h3>
<input type="button" onclick="window.location='views/signUp.jsp'" value="Move to Sign Up page">
<h1> This is to Sign Up </h1>
<form id="form2" action="members/join">
ID:
<input type="text" placeholder="Insert ID">
Name:
<input type="text" placeholder="Insert Name"> <p>
PWD:
<input type="text" placeholder="Insert your PWD"> <p>
PWD Check:
<input type="text" placeholder="Confirm your PWD"><p>
Address:
<input type="text" placeholder="Insert Address."> <p>
<input type="submit" value="Sign Up">
</form>
</body>
</html>
and HomeController.java
package kr.co.promptech.controller;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* Handles requests for the application home page.
*/
#Controller
public class HomeController {
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
/**
* Simply selects the home view to render by returning its name.
*/
#RequestMapping(value = "", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
logger.info("Welcome home! The client locale is {}.", locale);
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
String formattedDate = dateFormat.format(date);
model.addAttribute("serverTime", formattedDate );
System.out.println("Arrived at HomeController.");
return "index";
}
}
MemberController.java
package kr.co.promptech.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import kr.co.promptech.model.Members;
import kr.co.promptech.service.MemberService;
#Controller
#RequestMapping(value="/members")
public class MemberController {
#Autowired
private MemberService memberService;
#RequestMapping(value="join")
public String memberJoin(#RequestParam("id") String id, #RequestParam("pwd") String pwd,
#RequestParam("name") String name, #RequestParam("address") String address){
System.out.println("We have arrived at MemberController");
memberService.memberJoin(new Members(id, pwd, name, address));
return "main";
}
}
Why the Sign Up button keep brings me to HomeController instead MemberController?
also, can anyone help me how to make a button that brings me to main.jsp from index.jsp?
this is not working...
Hope someone can help me here...
OMG, I just found out that all the tags of index.jsp did not have name properties.
It was all my faults... sorry, and Thanks for your answer,

Spring Security 4 : Request method 'POST' not supported

The issue is that when I click on submit I get
Etat HTTP 405 - Request method 'POST' not supported
Here is the controller :
#RequestMapping(value = "/admin/login", method = RequestMethod.GET)
public ModelAndView login(
#RequestParam(value = "error", required = false) String error,
#RequestParam(value = "logout", required = false) String logout) {
LOGGER.debug("admin login page");
ModelAndView model = new ModelAndView();
if (error != null) {
model.addObject("error", "Invalid username and password!");
}
if (logout != null) {
model.addObject("msg", "You've been logged out successfully.");
}
model.setViewName("/admin/index");
LOGGER.debug("returning admin login page");
return model;
}
And the form :
<form class="m-t" role="form" th:action="#{/admin/login}" method="POST" autocomplete="off">
<div th:if="${param.error}" class="alert alert-danger">Invalid username and password.</div>
<div th:if="${param.logout}" class="alert alert-success">You have been logged out.</div>
<div class="form-group">
<input type="text" class="form-control" id="username" name="username" placeholder="Username" required="" />
</div>
<div class="form-group">
<input type="password" class="form-control" id="username" name="username" placeholder="Username" required="" />
</div>
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
<button type="submit" class="btn btn-primary block full-width m-b">Login</button>
<small>Forgot password?</small>
<p class="text-muted text-center">
<small>Do not have an account?</small>
</p>
<a class="btn btn-sm btn-white btn-block" href="register.html">Create an account</a>
</form>
It seems like csrf field not working.
I explain, I have normal users website which I refer here by and admin part which is /admin
The login form is correctly displayed. But I when I click submit I get Etat HTTP 405 - Request method 'POST' not supported
Any idea please ?
Here is my security configuration class :
package com.mintad.spring.security;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
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;
/**
* #author Sofiane HAMMAMI
*/
#Configuration
#EnableWebSecurity
#ComponentScan
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
DataSource dataSource;
#Autowired
#Qualifier("customUserDetailsService")
UserDetailsService userDetailsService;
#Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.antMatchers("/admin/**").permitAll()
// .antMatchers("/admin/**").access("hasRole('ADMIN')")
.and().formLogin().loginPage("/login")
.defaultSuccessUrl("/welcome").usernameParameter("username").passwordParameter("password")
.and().exceptionHandling().accessDeniedPage("/404");
}
}
In controller , you defined the form as GET:
#RequestMapping(value = "/admin/login", method = RequestMethod.GET)
and in the form, you are calling it as POST:
form class="m-t" role="form" th:action="#{/admin/login}" method="POST"
change one of these, either at controller or in the form.
If you want to change at controller, replace existing line with:
#RequestMapping(value = "/admin/login", method = RequestMethod.POST)
or you can do it by modifying call from form like
form class="m-t" role="form" th:action="#{/admin/login}" method="GET"
Change your security config to use /admin/login as your login page:
...
.formLogin().loginPage("/admin/login")
Reason you get 405 is, you are trying to submit your form with http post method and defined the end point with http get method.
You need to change your request mapping to method as POST like:
#RequestMapping(value = "/admin/login", method = RequestMethod.POST)
OR you could do vice versa (which is not recommend by security reasons) in your form like:
<form class="m-t" role="form" th:action="#{/admin/login}" method="GET" autocomplete="off">

Resources