How to use #ModelAttributes and #SessionAttribute in spring MVC - java

I am doing a simple spring MVC project. There are three jsp pages page 1, page 2 and page 3. In page 1 and page 2 I have user form and I want to print two user's details in page 3. I think it could be solved using spring mvc annotation #ModelAttribute and #SessionAttribute but I don't know how to use them.
If anyone have any idea about my problem, please help me with a simple example

It's documented in Spring Framework's documentation:
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-ann-sessionattrib
#Controller
#SessionAttributes(value = {"user1", "user2"})
public class MyController {
// ...
#GetMapping("/page1")
public String page1(ModelMap model){
model.put("user", new User());
return "page1";
}
#PostMapping("/page1")
public String page1Post(#ModelAttribute("user") User user, ModelMap model{
model.put("user1", user);
model.put("user", new User());
return "page2";
}
#PostMapping("/page2")
public String page2Post(#ModelAttribute("user") User user, ModelMap model{
model.put("user2", user);
return "page3";
}
}
With this user1 and user2 will be available in your page3

Related

Error DefaultHandlerExceptionResolver , concept of forwarding in Spring Boot, status=405

I'm new in concept of forwarding with spring boot and Thymeleaf.
I want to use forwarding in my application from one Controller to another getting sessionAttribute.
I have a placed a form in /home page and when I click on submit button, the for gets submitted to database but the application does not render the next (service.html) page using redirect.
#Controller
#SessionAttributes("user")
public class SavingUser{
#Autowired
private UserRepository userRepository;
#GetMapping("/home")
public String addUser(Model model){
model.addAttribute("user", new Customer());
return "index";
}
#PostMapping("/registerUser")
public Callable <String> userRegistration(#Valid #ModelAttribute("user") Customer user, BindingResult result, Model model, HttpServletRequest request){
---
----
return()->{
if(result.hasErrors()) {
---
}
----
return "redirect:/greetingCustomer";
};
}
Forwarding to another controller -
#Controller
public class GreetingService {
#PostMapping("/greetingCustomer")
public String greetCustomer(#SessionAttribute("user")Customer customer, Model model) throws IOException {
System.out.println("A new user " + customer.getName() + " is trying to request a quote");
model.addAttribute("person",customer.getName());
return "redirect:/service";
}
}
I already have placed the 'service.html' file in classpath.
I used this same concept with JSP and it worked well.
Any idea what the problem is ?
As I can see when you are using return "redirect:/greetingCustomer"; then you can only redirect to the greetingCustomer.
If you want to redirect to the service page the use return "redirect:/service";

Spring MVC Session check before every request

I am developing a web app using spring boot and mvc. I have controllers and in every controller i have to check if session is exist. In example in getAll method i am checking if session is existing but i have to write this check code in every method , every controller. Is there any shortcut to do that?
#Controller
#RequestMapping("/Sale")
public class SaleController
{
#Autowired
private SaleRepository saleRepository;
#GetMapping
public ModelAndView getAll(#SessionAttribute(required=false) User user)
{
if(user==null)
return new ModelAndView("redirect:/");
else
{
ModelAndView modelAndView=new ModelAndView("/view/sales.jsp");
List<Sale> sales=saleRepository.findAll();
modelAndView.addObject("sales",sales);
return modelAndView;
}
}
}
You can use a Filter and apply it to all requests or only those matching a specific pattern.
To check for a session you would use HttpServletRequest.getSession(false) and check for null.

Store User object in session with Spring Security

Based on my understanding, there are a number of different ways to retrieve the authenticated username in Spring Security.
I'm currently grabbing the username by included the Principal as a controller method argument:
#RequestMapping(value = "/dashboard", method = RequestMethod.GET)
public ModelAndView displayHomePage(ModelAndView modelAndView, Principal principal) {
modelAndView.addObject("email", principal.getName());
// Render template located at src/main/resources/templates/dashboard.html
modelAndView.setViewName("dashboard");
return modelAndView;
}
Does Spring Security offer an easy way for me to store the User object into the session so it can be easily retrieved by any controller method?
I want to avoid performing a DB lookup each time:
// Lookup user in database by e-mail
User user = userService.findUserByEmail(principal.getName());
I'm using Spring Security 4.2.
Spring Security provides you with a static method for quickly and easy access:
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String name = auth.getName();
Or
User user = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String name = user.getUsername();
Maybe you would like do this in a base abstract class
public abstract class BaseController {
protected User getCurrentUser() {
return (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
}
...
public YourController extends BaseController {
...
}
Update
If you want to store the current authenticated user in session, then you need store only first time in a object as suggested by #gkatzioura.
#Component
#Scope("session")
public class MySessionInfo {
private User user;
protected User getCurrentUser() {
if (user == null) {
user = userService.findUserByEmail(SecurityContextHolder.getContext().getAuthentication().getPrincipal().getName());
}
return user;
}
}
You can inject this bean in yours controllers like
#Autowired
private MySessionInfo mySessionInfo;
You must take care about cases when user is not logged, but this is another problem.
You can always use the methods that spring security provides to get basic information such as name, authorities and everything provided by the Authentication.class.
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
authentication.getAuthorities();
authentication.getName();
But if you want more information, using a session bean to store the information is also a good idea.
#Component
#Scope("session")
public class UserInfo { .. }

Hibernate #Valid strange behaivor in SpringMVC

First, I'm very new to this, sorry if this question is dumb. I have two controllers with class request mappings and form to validate:
#Controller
#RequestMapping("/creditcard")
public class CreditCardController {
#Autowired
//repositories
#RequestMapping(value = "/addnewcard", method = RequestMethod.POST)
public String addNew(
#ModelAttribute("newCard") #Valid CreditCard creditCard,
BindingResult bindingResult, Principal principal, Model model) {
if (bindingResult.hasErrors()) {
//render error view
}
creditCardService.registerNew(creditCard, principal.getName());
return "redirect:/account";
}
Another
#Controller
#RequestMapping("/account")
public class AccountController {
#Autowired
//repo
#RequestMapping("")
public String showUserProfile(Principal principal, Model model) {
String username = principal.getName();
User user = userService.findByUsername(username);
Account account = user.getAccount();
List<Payment> payers = paymentService
.getAllPaymentsForPayerAccount(account.getId());
model.addAttribute("user", user);
model.addAttribute("account", account);
model.addAttribute("payers", payers);
return "userprofile";
}
}
Form on userprofile.jsp
<form:form cssClass="form-horizontal" modelAttribute="newCard" action="creditcard/addnewcard">
........
</form:form>
And all this works without #Valid. When I add #Valid it works fine, when validation fails ( shows error view with messages), but when it succeeds I get 404 error due to incorrect URI - http://localhost:8080/PaymentSystem/creditcard/creditcard/addnewcard. Here one /creditcard is extra, #Valid somehow adds this to my URI. I found to ways for me to solve this:
1) I moved addNew card method to 'AccountController'
2) I just removed #RequestMapping("/creditcard")
But still I do not found any explanation of such behaviour. Any idea?
I found 3rd way to solve this issue, most suitable in this situation. I just added ${pageContext.request.contextPath} to my action param like this:
<form:form cssClass="form-horizontal" modelAttribute="newCard" action="${pageContext.request.contextPath}/creditcard/addnewcard">
........
</form:form>
But still it don't know the reason of that kind of #Valid behaviour.

Spring 3.0 set and get session attribute

I want to read a domain object (UserVO) from session scope.
I am setting the UserVO in a controller called WelcomeController
#Controller
#RequestMapping("/welcome.htm")
public class WelcomeController {
#RequestMapping(method = RequestMethod.POST)
public String processSubmit(BindingResult result, SessionStatus status,HttpSession session){
User user = loginService.loginUser(loginCredentials);
session.setAttribute("user", user);
return "loginSuccess";
}
}
I am able to use the object in jsp pages <h1>${user.userDetails.firstName}</h1>
But I am not able to read the value from another Controller,
I am trying to read the session attribute as follows:
#Controller
public class InspectionTypeController {
#RequestMapping(value="/addInspectionType.htm", method = RequestMethod.POST )
public String addInspectionType(InspectionType inspectionType, HttpSession session)
{
User user = (User) session.getAttribute("user");
System.out.println("User: "+ user.getUserDetails().getFirstName);
}
}
The code you've shown should work - the HttpSession is shared between the controllers, and you're using the same attribute name. Thus something else is going wrong that you're not showing us.
However, regardless of whether or not it works, Spring provides a more elegant approach to keeping your model objects in the session, using the #SessionAttribute annotation (see docs).
For example (I haven't tested this, but it gives you the idea):
#Controller
#RequestMapping("/welcome.htm")
#SessionAttributes({"user"})
public class WelcomeController {
#RequestMapping(method = RequestMethod.POST)
public String processSubmit(ModelMap modelMap){
User user = loginService.loginUser(loginCredentials);
modelMap.addtAttribute(user);
return "loginSuccess";
}
}
and then
#Controller
#SessionAttributes({"user"})
public class InspectionTypeController {
#RequestMapping(value="/addInspectionType.htm", method = RequestMethod.POST )
public void addInspectionType(InspectionType inspectionType, #ModelAttribute User user) {
System.out.println("User: "+ user.getUserDetails().getFirstName);
}
}
However, if your original code isn't working, then this won't work either, since something else is wrong with your session.
#SessionAttributes works only in context of particular handler, so attribute set in WelcomeController will be visible only in this controller.
Use a parent class to inherit all the controllers and use SessionAttributes over there. Just that this class should be in the package scan of mvc.
May be you have not set your UserVO as Serializable.

Categories