Can't access session attributes in Thymeleaf - java

I'm using Thymeleaf with Springboot2.1.2 and I have problem accessing session attributes in the templates.
Here's the code:
This is one of the controllers:
#GetMapping("/profile")
public String getProfile(HttpServletRequest request) {
HttpSession session = request.getSession(false);
String email = (String) session.getAttribute("userId");
User user = userService.getProfile(email);
session.setAttribute("user", user);
return "user/profile";
}
And the corresponding view(html):
<body th:object="${session.user}">
//some code using the user object here...
</body>
When I run the application, I got the exception:
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'session' available as request attribute
I've also tried for #session and something else, they didn't work. However, in another controller, I can access the object by using Model:
#GetMapping("/register/user")
public String registerUser(Model model) {
model.addAttribute("user", new User());
return "user/register";
}
And the view is like:
<form th:object="${user}" method="post" action="#" th:action="#{/register/user}">
//some code using the user object...
</form>
It's driving me crazy since all the tutorials I can find tell me I can access session attributes by ${session.something}, in reality, it doesn't work.
Could you help me?

You are saving the information in the session, this is not visible by thymeleaf. you need to create a model for your thymeleaf template and add the attribute (or the session) to the model and then return that.
#GetMapping("/profile")
public ModelAndView getProfile(HttpServletRequest request) {
User user = userService.getProfile(email);
ModelAndView model = new ModelAndView(NAME_OF_THYMELEAF_PROFILE_FILE);
model.addObject("user",user);
return model;
}
Beware that for the thymeleaf to see the template it needs to be in a default path (resources/templates) or you need to define where your templates are stored.
If you want to use session again the solution is similar.
#GetMapping("/profile")
public ModelAndView getProfile(HttpServletRequest request) {
HttpSession session = request.getSession(false);
User user = userService.getProfile(email);
session.setAttribute("user", user);
ModelAndView model = new
ModelAndView(NAME_OF_THYMELEAF_PROFILE_FILE);
model.addObject("session",session);
return model;
}
UPDATE use model and return String:
#GetMapping("/profile")
public String getProfile(HttpServletRequest request, Model model) {
HttpSession session = request.getSession(false);
String email = (String) session.getAttribute("userId");
User user = userService.getProfile(email);
session.setAttribute("user", user);
model.addAttribute("session", session);
return "user/profile";
}
I used ModelAndView, you can do the same with Model, just instead of addObject() you must use addAttribute().

You should be using Spring-Security with thymeleaf extensions to accomplish what you want. Here is an example of what you want to do. If you follow the example you can access user information as follows:
<div sec:authentication="name"><!-- Display UserName Here --></div>
Please note that for spring-boot 2.1.X you should use the following dependency:
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
</dependency>

Related

Model Attribute After posting DTO Object on Spring Boot

In my Spring boot project, Passed a DTO object to my view which is then posted after submission. eg. How do I access the "randomKey" after the form is posted?
#GetMapping("/{userId}/edit/feature/")
public String showEditFeature(#PathVariable("userId") Long userId, UserDto userDto,
Model model)
{
User user = userService.get(userId);
model.addAttribute("user", user);
model.addAttribute("randomKEy", "AnyObject");
return "user/edit/profile";
}
Then My post function.
#PostMapping("profile_update")
public String watchFeatureUpdate(#Valid UserProfileDto UserProfileDto,
BindingResult result,
RedirectAttributes redirectAttributes, Model model)
{
Long userId = userService.updateUserProfile(userProfileDto);
redirectAttributes.addFlashAttribute("message", "Profile features updated
successfully!");
redirectAttributes.addFlashAttribute("alertClass", "alert-success");
return "redirect:/user/view/" + userId + "/profile";
}
You need to include in your HTML page "user/edit/profile" as a hidden input every object property value so they are sent back when the form is submitted.
<input type="hidden" name="randomKEy" value="${randomKEy}">
Note that HTML content is still manipulable by the user even not being visible in the rendered web page.

Spring MVC 4 display an error message [duplicate]

My objective is to pass model attributes from controller to JSP page during a redirect and avoid the attribute being displayed in URL. The source code below is validating login from datastore using java data objects.
Controller:
#Controller
public class LoginController {
int count;
PersistenceManager pm = PMF.get().getPersistenceManager();
//Instance of data class
User user;
ModelAndView modelAndView=new ModelAndView();
#RequestMapping(value="/Login",method = RequestMethod.POST)
public ModelAndView loginValidate(HttpServletRequest req){
//Getting login values
String uname=req.getParameter("nameLogin");
String pswd1=req.getParameter("pswdLogin");
count=0;
user=new User();
//Generating Query
Query q = pm.newQuery(User.class);
q.setFilter("userName == userNameParam");
q.declareParameters("String userNameParam");
try{
List<User> results = (List<User>) q.execute(uname);
for (User u: results) {
String userName=u.getUserName();
if(userName.equals(uname)){
System.out.println(u.getPassword());
if(u.getPassword().equals(pswd1)){
count=count+1;
modelAndView.setViewName("redirect:welcome");
modelAndView.addObject("USERNAME",uname);
return modelAndView;
}
//rest of the logic
}
JSP:
<h1>Welcome ${USERNAME} </h1>
My current URL is /welcome?USERNAME=robin
My goal is to display it as /welcome
Also, my page is supposed to display "Welcome robin" whereas it displays only Welcome.
RedirectAttributes only work with RedirectView, please follow the same
#RequestMapping(value="/Login",method = RequestMethod.POST)
public RedirectView loginValidate(HttpServletRequest req, RedirectAttributes redir){
...
redirectView= new RedirectView("/foo",true);
redir.addFlashAttribute("USERNAME",uname);
return redirectView;
}
Those flash attributes are passed via the session (and are destroyed immediately after being used - see Spring Reference Manual for details). This has two interests :
they are not visible in URL
you are not restricted to String, but may pass arbitrary objects.
You need to be careful here because I think what are you trying to do is not supported for a good reason. The "redirect" directive will issue a GET request to your controller. The GET request should only retrieve existing state using request parameters, this is the method contract. That GET request should not rely on a previous interaction or on any object stored some where in the session as a result of it. GET request is designed to retrieve existing (persisted) state. Your original (POST) request should have persisted everything you need for you GET request to retrieve a state.
RedirectAttributes are not designed to support you in this case, and even if you managed to correctly use it it will only work once and then they will be destroyed. If you then refresh the browser you will get an application error because it cannot find your attributes anymore.

Retrieving Session Attributes after Session Times Out

I have a Spring MVC project setup where I define several model attributes & session attributes when a user accesses the home page home.html.
HomeController.java
#RequestMapping(value = "/getHomepage", produces = "text/html", method = RequestMethod.GET)
protected ModelAndView getHomepage(HttpSession session) {
ModelAndView mav = new ModelAndView("home");
// do some stuff
session.setAttribute("attr1", "cool");
session.setAttribute("attr2", "attributes");
return mav;
}
I grab these session attributes on a separate orderForm.html (I'm using Thymeleaf as my template engine)
Session Attribute 1: <div th:text="${session.attr1}"></div>
Session Attribute 2: <div th:text="${session.attr2}"></div>
This works fine until my session is timed out/invalidated and the user is still on orderForm.html - they lose scope of the session attributes as they're defined only on the Home #Controller
Can I retrieve my session attributes without first hitting the homepage and without setting them on every view #Controller in my project?

Dispatching web service caller with Response object

I need to dispatch a web service caller to a new page using Response object:
#Path("controller")
#Stateless
public class ControllerEJB {
HttpSession session;
User user;
String url;
#POST
public Response registerUser(
#QueryParam("fornamn") String fornamn,
#QueryParam("efternamn") String efternamn,
#QueryParam("epost") String epost,
#QueryParam("epost2") String epost2,
#QueryParam("password") String password,
#Context HttpServletRequest request
){
session = request.getSession();
if(user == null)
user = new User();
user.setEmail(epost);
user.setPassword(password);
user.setFornamn(fornamn);
user.setEfternamn(efternamn);
session.setAttribute("user", user);
return Response.status(200)...... // e.g. url is a .jsp
}
What method should I be using?
JAX-RS is designed to build REST services.
REST services should return data, generally serialized using XML or JSON.
I wouldn't recommend to forward JAX-RS requests to a view layer such as JSP or JSF.
That said, i'm not sure you can forward the same way RequestDispatcher.forward(req, res) does.
But you can send a redirection using the following:
return Response.seeOther(new URI("/path/to/your/resource")).build();
But as the documenation says, this should be used in a POST/redirect/GET pattern: you may redirect a POST request to another REST resource using the GET method.
But again, redirecting REST resource to a JSP page is an awkward design.

Spring ModelAttribute show old value after logout

I am developing an application using Spring. I have a trouble about login and logout. I logged in application using a login credentials(e.g. userName:john, pass: doe) and go to Admin page and than I logged out from application. But this time I used different login credentials(e.g. userName: jack, pass: white) for login. When I go to Admin page and debug my application #ModelAttribute(value = "myUser") User loggedInUser at AdminController shows old user value. I couldn't understand why this occurs. Anyone can help?
My source codes are below:
#Controller
#RequestMapping("/LoginController")
#SessionAttributes({"myUser"})
public class LoginController
{
private static String LOGIN_URL = "login/login_";
private static String INDEX_URL = "main/index";
#Autowired
private IUserService userService = null;
#RequestMapping("/login")
public ModelAndView login(#RequestParam(value="userName", required=false) String argUserName, #RequestParam(value="password", required=false) String argPassword, HttpServletRequest req)
{
ModelAndView modelAndView = new ModelAndView();
// Assume argUserName and argPassword not null
User loginUser = this.userService.getUser(argUserName, argPassword);
HttpSession ses = req.getSession();
// Assume loginUser not null
ses.setAttribute("myUser", loginUser);
modelAndView.setViewName(LoginController.INDEX_URL);
return modelAndView;
}
#RequestMapping("/logout")
public String logout(HttpServletRequest argReq, HttpServletResponse argResp) throws ServletException, IOException
{
HttpSession session = argReq.getSession(false);
Enumeration<?> attributeNames = session.getAttributeNames();
while(attributeNames.hasMoreElements())
{
String attrName = (String)attributeNames.nextElement();
if(session.getAttribute(attrName) != null)
{
session.setAttribute(attrName,null);
//session.removeAttribute(attrName);
attributeNames = session.getAttributeNames();
}
}
// close session
session.invalidate();
return LoginController.LOGIN_URL;
}
}
AdminController
#Controller
#RequestMapping("/AdminController")
#SessionAttributes({"myUser"})
public class AdminController
{
private static String SETTINGS_PAGE = "settings/index";
#RequestMapping("/index")
public ModelAndView index(#ModelAttribute(value = "myUser") User loggedInUser, HttpSession ses)
{
ModelAndView modelAndView = new ModelAndView();
Map<String, Object> map = new HashMap<String, Object>();
map.put("loggedInUserId", loggedInUser.getUserID());
map.put("userName", loggedInUser.getUserName());
modelAndView.addAllObjects(map);
modelAndView.setViewName(AdminController.SETTINGS_PAGE);
return modelAndView;
}
}
Remove this annotation
#SessionAttributes({"myUser"})
For starters #SessionAttributes isn't designed to store data in the session between different controllers. Its intended use is only to store data for the same controller in between requests. If you want to store items in the session between requests store them in the session yourself and don't rely on #SessionAttributes. This is also mentioned in the javadoc of the annotation (although a bit cryptic maybe).
If you want to remove object cached by #SessionAttributes you cannot simply clear the session but you would have to use the SessionStatus object (which you can add as an argument) to mark the use of these objects complete.
Your logout method is way to verbose, simply calling session.invalidate() should be enough, but I guess this was one of your attempts to fix things. Also when you are on a Servlet 3.0 container simply calling request.logout() could be enough (or call it in conjunction with session.invalidate())
My final advice would be to use Spring Security instead of trying to develop your own security solution.

Categories

Resources