Handle form submission in SpringBoot - spring

Here is my controller:
#Controller
#RequestMapping("/accounts/*")
public class AccountController {
#Autowired
private AccountService accountService;
#GetMapping
public ModelAndView home() {
final ModelAndView modelAndView = new ModelAndView();
final List<Account> accountsForCurrentUser = this.accountService.getAccountsForCurrentUser();
modelAndView.addObject("accounts", accountsForCurrentUser);
modelAndView.setViewName("pages/accounts/index");
return modelAndView;
}
#GetMapping("create")
public ModelAndView create() {
final ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("account", new Account());
modelAndView.setViewName("pages/accounts/create");
return modelAndView;
}
#PostMapping("create")
public ModelAndView createSubmit(#Valid #ModelAttribute(name = "account") Account account, BindingResult bindingResult, ModelAndView modelAndView) {
if (bindingResult.hasErrors()) {
return modelAndView;
}
return new ModelAndView("redirect:/accounts");
}
}
What I'd like to do is redirecting user to /accounts/ when the form is validated but taking him back to /accounts/create/ with errors shown if errors has been reported.
But, on error, I have:
Error resolving template "accounts/create", template might not exist or might not be accessible by any of the configured Template Resolvers

You also need set model and view name in post/create method.
By the way, handling methods with ModelAndView is valid but I think it would be better to use the String approach. It's much better to read and a standart way. So your controller will look like:
#Controller
#RequestMapping("/accounts")
public class AccountController {
#Autowired
private AccountService accountService;
#GetMapping("")
public String home(Model Model) {
List<Account> accountsForCurrentUser = this.accountService.getAccountsForCurrentUser();
model.addAttribute("accounts", accountsForCurrentUser);
return "pages/accounts/index";
}
#GetMapping("/new")
public String newAccount(Model model) {
model.addAttribute("account", new Account());
return "pages/accounts/create";
}
#PostMapping("/new")
public String createAccount(#Valid #ModelAttribute Account account, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return "pages/accounts/create";
}
"redirect:/accounts";
}
}

Related

Is there a way, value defined in one main controller, can be accessed from all the other spring mvc controller?

Something like this:
#Controller
public class HomeController {
public String getCurrentUserDetails() {
String username = "testuser";
return username;
}
}
#Controller
public class DashboardController {
#RequestMapping("/admin/dashboard")
public ModelAndView showDashbard() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("username", GET username FROM HOME CONTROLLER [HomeController's getCurrentUserDetails]);
modelAndView.setViewName("/admin/dashboard");
return modelAndView;
}
}
#Controller
public class ProfileController {
#RequestMapping("/admin/profile")
public ModelAndView showProfile() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("username", GET username FROM HOME CONTROLLER [HomeController's getCurrentUserDetails]);
modelAndView.setViewName("/profile/dashboard");
return modelAndView;
}
}
Yes I know I can instantiate the HomeController and get the object. But making object in every controller is hectic.
I just want the value of one controller available in all other controllers.

Spring Java how to use controller

I'm completely new to Spring framework. and I have a task to make phone book application on spring. I need to make registration and authorization and also my phone book. I have 2 controllers for that, first UserController that controls authorization and registration
#Controller
public class UserController {
#Autowired
private UserService userService;
#Autowired
private SecurityService securityService;
#Autowired
private UserValidator userValidator;
#RequestMapping(value = "/registration", method = RequestMethod.GET)
public String registration(Model model) {
model.addAttribute("userForm", new User());
return "registration";
}
#RequestMapping(value = "/registration", method = RequestMethod.POST)
public String registration(#ModelAttribute("userForm")
User userForm, BindingResult bindingResult, Model model) {
userValidator.validate(userForm, bindingResult);
if (bindingResult.hasErrors()) {
return "registration";
}
userService.save(userForm);
securityService.autoLogin(userForm.getUsername(), userForm.getConfirmPassword());
return "redirect:/welcome";
}
#RequestMapping(value = "/login", method = RequestMethod.GET)
public String login(Model model, String error, String logout) {
if(error!=null) {
model.addAttribute("error", "Username or password is incorrect.");
}
if (logout!=null) {
model.addAttribute("message", "logged out successfully");
}
return "login";
}
#RequestMapping(value = {"/", "/welcome"}, method = RequestMethod.GET)
public String welcome(Model model) {
return "welcome";
}
#RequestMapping(value = "/admin", method = RequestMethod.GET)
public String admin(Model model) {
return "admin";
}
}
and ContactController that controls my fuctionality(adding, removing, editing and shows contacts)
#Controller
public class ContactController {
private ContactService contactService;
#Autowired(required = true)
#Qualifier(value = "contactService")
public void setContactService(ContactService contactService) {
this.contactService = contactService;
}
#RequestMapping(value = {"admin", "welcome"}, method = RequestMethod.GET)
public String listContactsForAdmin(Model model) {
model.addAttribute("contact", new Contact());
model.addAttribute("listContacts", this.contactService.listContacts());
return "admin";
}
#RequestMapping(value = "admin/add", method = RequestMethod.POST)
public String addContact(#ModelAttribute("contact") Contact contact) {
if (contact.getId() == 0) {
this.contactService.addContact(contact);
} else {
this.contactService.updateContact(contact);
}
return "redirect:/admin";
}
#RequestMapping("/remove/{id}")
public String removeContact(#PathVariable("id") int id) {
this.contactService.removeContact(id);
return "redirect:/admin";
}
#RequestMapping("/edit/{id}")
public String editBook(#PathVariable("id") int id, Model model) {
model.addAttribute("contact", this.contactService.getContactById(id));
model.addAttribute("listContacts", this.contactService.listContacts());
return "admin";
}
#RequestMapping("contactData/{id}")
public String contactData(#PathVariable("id") int id, Model model) {
model.addAttribute("contact", this.contactService.getContactById(id));
return "contactData";
}
}
when i try to authenticate or registr. new user I have such error:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalStateException: Ambiguous handler methods mapped for HTTP path 'http://localhost:8087/admin': {public java.lang.String kz.adilka.springsecurity.app.controller.UserController.admin(org.springframework.ui.Model), public java.lang.String kz.adilka.springsecurity.app.controller.ContactController.listContactsForAdmin(org.springframework.ui.Model)}
it says that I have problem with mapping admin page. but for me it seems to be ok, or maybe I missed smth
The reason is that you do not set the controller value for your controllers and they have the same RequestMapping method
#Controller // do not have identifier here
public class UserController {
#Autowired
private UserService userService;
#Autowired
private SecurityService securityService;
#Autowired
private UserValidator userValidator;
#RequestMapping(value = "/admin", method = RequestMethod.GET)
public String admin(Model model) {
return "admin";
}
}
#Controller // do not have identifier here
public class ContactController {
private ContactService contactService;
#RequestMapping(value = {"admin", "welcome"},
method = RequestMethod.GET)
public String listContactsForAdmin(Model model) {
model.addAttribute("contact", new Contact());
model.addAttribute("listContacts",
this.contactService.listContacts());
return "admin";
}
}
One possible solution is the set RequestMapping for each Controller method:
#Controller(value = "user")
public class UserController {
#Autowired
private UserService userService;
#Autowired
private SecurityService securityService;
#Autowired
private UserValidator userValidator;
#RequestMapping(value = "/admin", method = RequestMethod.GET)
public String admin(Model model) {
return "admin";
}
}
#Controller(value = "contact")
public class ContactController {
private ContactService contactService;
#RequestMapping(value = {"admin", "welcome"}, method = RequestMethod.GET)
public String listContactsForAdmin(Model model) {
model.addAttribute("contact", new Contact());
model.addAttribute("listContacts", this.contactService.listContacts());
return "admin";
}
}

localhost:8080/ returns status 404 - Spring

This is my code:
#Controller
#RequestMapping("/")
public class MerchantsController {
#Autowired
MerchantsService merchantsService;
#Autowired
ProductsService productsService;
#Autowired
OrdersService ordersService;
#RequestMapping(value = "/merchants", method = RequestMethod.GET)
public ModelAndView showMerchantsList() {
ModelAndView modelAndView = new ModelAndView("merchantsList");
List<Merchant> merchants = merchantsService.getMerchantsList();
for (Merchant merchant : merchants) {
if(merchant.getOrder_type() == OrderType.NO_ORDERING){
merchant.setOrderUntil(Time.valueOf("00:00:00"));
}
}
modelAndView.addObject("merchants", merchants);
return modelAndView;
}
As I understand when I send request to localhost:8080/ it should open localhost:8080/merchants, but it is not working. Anyone has any suggestions?
Your showMerchantsList method will be called when you send request to localhost:8080/merchants. And this method will you redirect again localhost:8080/merchants. But if you want send request as localhost:8080/ and direct you to localhost:8080/merchants, then you should create another method as this:
#RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView showMerchantsListWithoutRequestMapping() {
ModelAndView modelAndView = new ModelAndView("merchantsList");
List<Merchant> merchants = merchantsService.getMerchantsList();
for (Merchant merchant : merchants) {
if(merchant.getOrder_type() == OrderType.NO_ORDERING){
merchant.setOrderUntil(Time.valueOf("00:00:00"));
}
}
modelAndView.addObject("merchants", merchants);
return modelAndView;
}
This method will redirect you to localhost:8080/merchants, when you called localhost:8080/
Normal way you should use
#Controller
public class MerchantsController {
#Autowired
MerchantsService merchantsService;
#Autowired
ProductsService productsService;
#Autowired
OrdersService ordersService;
#RequestMapping(value = "/merchants", method = RequestMethod.GET)
public ModelAndView showMerchantsList() {
ModelAndView modelAndView = new ModelAndView("merchantsList");
List<Merchant> merchants = merchantsService.getMerchantsList();
for (Merchant merchant : merchants) {
if(merchant.getOrder_type() == OrderType.NO_ORDERING){
merchant.setOrderUntil(Time.valueOf("00:00:00"));
}
}
modelAndView.addObject("merchants", merchants);
return modelAndView;
}
As i understand your requirement silly way:
#Controller
public class MerchantsController {
#Autowired
MerchantsService merchantsService;
#Autowired
ProductsService productsService;
#Autowired
OrdersService ordersService;
#RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView showMerchantsList() {
ModelAndView model=new ModelAndView("redirect:/merchants");
return model;
}
#RequestMapping(value = "/merchants", method = RequestMethod.GET)
public ModelAndView showMerchantsList() {
ModelAndView modelAndView = new ModelAndView("merchantsList");
List<Merchant> merchants = merchantsService.getMerchantsList();
for (Merchant merchant : merchants) {
if(merchant.getOrder_type() == OrderType.NO_ORDERING){
merchant.setOrderUntil(Time.valueOf("00:00:00"));
}
}
modelAndView.addObject("merchants", merchants);
return modelAndView;
}
Note: Because / always denotes to root.

How mock BindingResult in/with Mockito

I have a controller method like this:
#RequestMapping(value = "/{userId}/edit", method = RequestMethod.POST)
public ModelAndView updateUser(#PathVariable(USER_ID_PATH_VAR) final long userId, #Valid #ModelAttribute(MODEL_USER_WEB) final User user, BindingResult bindingResult,
final Principal principal, final Model model, #RequestParam(value = "otherLocation", required = false) Boolean isOnlyOneLocation) {
if (bindingResult.hasErrors()) {
return new ModelAndView(URL_EDIT_USER);
}
// do something ...
return new ModelAndView(URL_FINISH_USER);
}
my test looks like this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes={ManageUsersControllerTestConfig.class})
public class ManageUserControllerTest {
#Autowired
private ManageUserController userController;
#Autowired
private Model model;
private MockMvc mockMvc;
#Autowired
private BindingResult bindingResult;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".html");
mockMvc = MockMvcBuilders
.standaloneSetup(userController)
.setViewResolvers(viewResolver)
.build();
}
#Test
public void testUpdateInstitutionWithErrors() throws Exception {
when(bindingResult.hasErrors()).thenReturn(false);
mockMvc.perform(post(WebSecurityConfig.URL_USER_OVERVIEW + "/" + USER_ID + "/" + URL_PART_EDIT)
.param(USER_ID_PATH_VAR, USER_ID))
.andExpect(status().isOk())
.andDo(print());
}
}
only thing what i want is to mock the bindingresult, the bindingResult.hasErrors() method should return false. Everytime i run this test the method return true.
Any suggestions how can i fix this error?
Thanks in advance
Use this instead:
#MockBean
private BindingResult bindingResult;
You cannot and that is not how Mock MVC works.
You should submit a valid request... Mocking doesn't work.
I had something similar situation I found bindingResult in getModelAndView
Example
ModelAndView mockResult=mockMvc
.perform(MockMvcRequestBuilders.post(YOURL_URL))
.andReturn().getModelAndView();
BindingResult BindingResult= (BindingResult)mockResult.getModel().get("org.springframework.validation.BindingResult.YourForm")

processFormSubmission not being called

I am new to spring. I am creating a simple login page. But the processFormSubmission() is not being called. But the showForm() is working.
public class LoginController extends SimpleFormController
{
private LoginService loginService;
private String loginView;
public LoginService getLoginService() {
return loginService;
}
public void setLoginService(LoginService loginService) {
this.loginService = loginService;
}
public String getLoginView() {
return loginView;
}
public void setLoginView(String loginView) {
this.loginView = loginView;
}
public LoginController() {
setBindOnNewForm(true);
}
#Override
protected ModelAndView processFormSubmission(HttpServletRequest request,
HttpServletResponse response, Object command, BindException errors)
throws Exception
{
TraceUser tr = (TraceUser) command;
System.out.println(tr);
//loginService.
return super.processFormSubmission(request, response, command, errors);
}
#Override
protected ModelAndView showForm(HttpServletRequest request,
HttpServletResponse response, BindException errors)
throws Exception {
ModelAndView mav = new ModelAndView();
mav.addObject("traceUser", new TraceUser());
mav.setViewName(getLoginView());
return mav;
}
}
And please help me out with how should the ModelAndView object should be processed further.
First of all, the use of the Controller API has been left aside in favor of the new annotation-based controllers (see the #RequestMapping annotation) and classes like SimpleFormController have been deprecated since quite a while now.
However, to answer your question, I assume your form does not declare method="post" and by default, the SFC will consider only POST requests as form submissions (see the isFormSubmission() method in AbstractFormController). Is this the case ?

Resources