Spring RedirectAttributes clears session after redirect - spring

In my Spring i have used RedirectAttributes to display the message after login success or failure
and i have one SessionAttribute. I set SessionAttributes in two times first one is when i click the menu
i set Object to SessionAttribute and second one is after login success
what my problem is the SessionAttribute which i set after login success is not working if i remove the
RedirectAttributes means it is working fine.
when i searched i found this
addFlashAttribute actually stores the attributes in a flashmap (which is internally maintained in the
users session and removed once the next redirected request gets fulfilled)
when i debug it alwys shows the default one not show the value set after login.
this is for login
#RequestMapping(value = "/sample-client", method = RequestMethod.POST)
public String getClient(HttpServletRequest request, Model model, final RedirectAttributes redirectAttributes) {
String userName = request.getParameter("userName");
String password = request.getParameter("password");
Client client = createClient(userName, password);
if (client != null) {
model.addAttribute("clientObject", client);
redirectAttributes.addFlashAttribute("message", "Logined Successfully");
return "redirect:" + "/sample/user";
} else {
redirectAttributes.addFlashAttribute("error", "true");
return "redirect:" + "/sample/login";
}
}
after login
#RequestMapping(value = "/byName", method = RequestMethod.GET)
public
#ResponseBody
String getUserByName(HttpServletRequest request, #ModelAttribute("clientObject") User user) {
String firstName = request.getParameter("firstName");
String lastName = request.getParameter("lastName");
Integer page = Integer.parseInt(request.getParameter("page"));
return sample.getUserSearchByName(user, firstName, lastName, page);
}
when i checked the clientObject here it shows the default one.

Related

Trouble while trying to return page with error messages from entity fields

I have field like this:
#Min(value = 0, message = "Amount must be positive")
private double amount;
When I populate form and insert for example -1 for that field I get message on stack trace that I entered wrong value and this on HTML page: This application has no explicit mapping for /error, so you are seeing this as a fallback. So that works fine, but I want to create a error for user so he actually know what error he got, I want to display error on HTML page for him.
Followed by some tutorial in my Thymeleaf I have added this:
<div>
<label for="amount">Amount</label> <input type="text" th:field="*{amount}" id="amount">
<p th:if="${#fields.hasErrors('amount')}"
th:class="${#fields.hasErrors('amount')}? error">Invalid amount</p>
</div>
And in my controller I have this:
if (result.hasErrors()) {
return "new_transaction";
}
Now I will provide both controllers, one for showing form and one for processing form.
Controller to show form:
#GetMapping("/showNewTransactionForm/{id}")
public String showNewTransactionForm(#PathVariable(value = "id") long id, Transaction transaction, Model model) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
UserDetailsImpl user = (UserDetailsImpl) authentication.getPrincipal();
long userId = user.getId();
model.addAttribute("userId", userId);
model.addAttribute("transaction", transaction);
model.addAttribute("transactionType", TransactionType.values());
model.addAttribute("expenseCategories", ExpenseCategories.values());
model.addAttribute("incomeCategories", IncomeCategories.values());
return "new_transaction";
}
Controller to process form:
#PostMapping("/saveExpense/{walletId}")
public String saveExpense(#PathVariable(value = "walletId") long walletId,
#ModelAttribute("wallets") Transaction transaction, BindingResult result) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
UserDetailsImpl user = (UserDetailsImpl) authentication.getPrincipal();
long userId = user.getId();
if (result.hasErrors()) {
return "new_transaction";
}
Wallet wallet = walletService.getWalletById(walletId);
transaction.setWallet(wallet);
transactionService.saveExpense(transaction, walletId, userId);
return "redirect:/api/wallet/userWallet/balance/" + userId;
}
And I obviously have a problem to return a right point here:
if (result.hasErrors()) {
return "new_transaction";
}
Instead of new_transaction I tried with return "redirect:/api/transaction/showNewTransactionForm/" + userId; but as before I get a error message in stacktrace but on html is Whitelabel Error Page

SPRING MVC: Defined HttpSession in One Method is Not Available to Another Method

I am facing a problem regarding to the Httpsession that I implementing in the Spring MVC project.
First of all, after the user successfully login, I will take the Httpsession object in loginAuthentication controller and set attribute with the name and value I want. (Shown in following figure).
A.java controller file,
#RequestMapping(value="login-authentication", method = RequestMethod.POST)
public String authentication(#Valid #ModelAttribute("systemAccount") SystemAccount systemAccount,
BindingResult bindingResult, Model model, HttpServletRequest request){
if (bindingResult.hasErrors()) {
model.addAttribute(GenericConstant.MessageAttributeName.ERROR_MSG_NAME.toValue(), SystemMessage.SystemException.LOGIN_INCORRECT_USERNAME_PASSWORD.toValue());
model.addAttribute("systemAccount", new SystemAccount());
return "index";
}else {
if (systemAccountService.authenticate(systemAccount.getUsername(), systemAccount.getPassword()) != null &&
!"".equals(systemAccountService.authenticate(systemAccount.getUsername(), systemAccount.getPassword()))) {
SystemAccount dbSystemAccount = systemAccountService.authenticate(systemAccount.getUsername(), systemAccount.getPassword());
request.setAttribute(SessionAttribute.AttributeName.LOGIN_ACC_ID.toValue(),dbSystemAccount.getAccountID());
//check account role
if(dbSystemAccount.getCounterStaff()!= null && !"".equals(dbSystemAccount.getCounterStaff())){
CounterStaff counterStaff = dbSystemAccount.getCounterStaff();
request.setAttribute(SessionAttribute.AttributeName.LOGIN_ACC_NAME.toValue(), counterStaff.getStaffName());
request.setAttribute(SessionAttribute.AttributeName.LOGIN_ACC_ROLE.toValue(), GenericConstant.SystemRole.COUNTER_STAFF.toValue());
}else if(dbSystemAccount.getCustomer()!= null && !"".equals(dbSystemAccount.getCustomer())){
Customer customer = dbSystemAccount.getCustomer();
request.setAttribute(SessionAttribute.AttributeName.LOGIN_ACC_NAME.toValue(), customer.getCustomerName());
request.setAttribute(SessionAttribute.AttributeName.LOGIN_ACC_ROLE.toValue(), GenericConstant.SystemRole.CUSTOMER.toValue());
}else if(dbSystemAccount.getManager()!= null && !"".equals(dbSystemAccount.getManager())){
Manager manager = dbSystemAccount.getManager();
request.setAttribute(SessionAttribute.AttributeName.LOGIN_ACC_NAME.toValue(), manager.getManagerName());
request.setAttribute(SessionAttribute.AttributeName.LOGIN_ACC_ROLE.toValue(), GenericConstant.SystemRole.MANAGER.toValue());
}else if(dbSystemAccount.getDoctor()!= null && !"".equals(dbSystemAccount.getCounterStaff())){
Doctor doctor = dbSystemAccount.getDoctor();
request.setAttribute(SessionAttribute.AttributeName.LOGIN_ACC_NAME.toValue(), doctor.getDoctorName());
request.setAttribute(SessionAttribute.AttributeName.LOGIN_ACC_ROLE.toValue(), GenericConstant.SystemRole.DOCTOR.toValue());
}
request.setAttribute(SessionAttribute.AttributeName.LOGIN_DATE.toValue(), DateTimeUtil.getCurrentDate());
return "mainPage";
}else {
model.addAttribute(GenericConstant.MessageAttributeName.ERROR_MSG_NAME.toValue(), SystemMessage.SystemException.LOGIN_INCORRECT_USERNAME_PASSWORD);
model.addAttribute("systemAccount", new SystemAccount());
return "index";
}
}
}
After everything is ready, the controller will navigate user to the main page and the main page able to access all the defined variable without issue. (The following figure shown the controller that mapped with mainPage).
A.java controller file,
#RequestMapping(value = "/mainPage", method = RequestMethod.GET)
public String renderMainPageView(Model model, HttpServletRequest request) {
if(request.getAttribute(SessionAttribute.AttributeName.LOGIN_CHECK.toValue()) != null) {
model.addAttribute(SessionAttribute.AttributeName.LOGIN_ACC_ID.toValue(),
request.getAttribute(SessionAttribute.AttributeName.LOGIN_ACC_ID.toValue()));
model.addAttribute(SessionAttribute.AttributeName.LOGIN_ACC_NAME.toValue(),
request.getAttribute(SessionAttribute.AttributeName.LOGIN_ACC_NAME.toValue()));
model.addAttribute(SessionAttribute.AttributeName.LOGIN_ACC_ROLE.toValue(),
request.getAttribute(SessionAttribute.AttributeName.LOGIN_ACC_ROLE.toValue()));
model.addAttribute(SessionAttribute.AttributeName.LOGIN_DATE.toValue(),
request.getAttribute(SessionAttribute.AttributeName.LOGIN_DATE.toValue()));
return "mainPage";
}else {
model.addAttribute("systemAccount", new SystemAccount());
return "index";
}
}
In the navigation menu of main page, I click on the selection to direct me to add manager web page. (The following shown the link).
<a href="addManager" target="ifrm" >Add New Account</a>
The controller that mapped with the link (GET) able to detect. However, this controller (renderAddManagerView) does not recognised the HTTP session that I defined earlier when I try to access using the getAttribute method in the if condition. It keep showing null value (Shown in the following figure.
B.java controller file,
#RequestMapping(value = "/addManager", method = RequestMethod.GET)
public String renderAddManagerView(Model model, HttpSession httpSession) {
if(httpSession.getAttribute(SessionAttribute.AttributeName.LOGIN_CHECK.toValue()) != null) {
model.addAttribute("manager", new Manager());
model.addAttribute(FormSelectionValue.FormSelectionAttributeName.COUNTRY_SELECTION.toValue(), FormSelectionValue.COUNTRY_SELECTION_LIST);
model.addAttribute(FormSelectionValue.FormSelectionAttributeName.GENDER_SELECTION.toValue(), FormSelectionValue.GENDER_SELECTION_LIST);
return "addManager";
}else {
model.addAttribute("systemAccount", new SystemAccount());
return "index";
}
}
So I am not sure what is the issue for my code and there is no error message is displayed.
I have solved the issue by using the HttpServletRequest instead of HttpSession.
Now my session will not be loss even redirect or navigate to any pages in JSP.
Something like this:
#RequestMapping("/renderview", method = RequestMethod.GET)
#Controller
public class TestController {
#RequestMapping(method = RequestMethod.GET)
public String myMethod(HttpServletRequest request)
{
request.getSession().setAttribute("mySession", "XXX");
return "jspview";
}
}
Reference: Set session variable spring mvc 3

How to redirect to an external url from spring mvc controller?

This is my code inside the controller class. When the user enters localhost:8080/url, it retrieves the original long url let's say www.google.com saved in the database and then i want it to redirect to www.google.com but instead it redirects to localhost:8080/www.google.com and thus gives en error 500.
#RequestMapping(value="/{url}", method = RequestMethod.GET)
public RedirectView getLongURl(#PathVariable("url") String url) {
String original = database.getLongUrl(UrlShortener.decode(url));
RedirectView redirectview = new RedirectView();
redirectview.setUrl(original);
return redirectview;
}
You should return a ModelAndView
#RequestMapping(value="/{url}", method = RequestMethod.GET)
public ModelAndView method(#PathVariable("url") String url) {
String original = database.getLongUrl(UrlShortener.decode(url));
return new ModelAndView("redirect:" + original);
}
You do not have the option to redirect your request to an outside domain/host like google.com using the RedirectView. As it's name says, it redirects your request to an "another view" in your application.
Refer the docs for more on RedirectView

How to keep request parameters after redirect?

I'm trying to resolve a bug when I send a form with an empty input.
This is my methode:
#RequestMapping(value = "/modifier.html", method = RequestMethod.POST)
public String modifier(ModelMap map, #ModelAttribute("FormObject") FormObject formObject, BindingResult result, HttpServletRequest req) {
formObject.setModif(true);
String idParam = req.getParameter("idTypeOuverture");
if (result.hasErrors()) {
return "redirect:/gestion.html?section=Configuration&panel=4&ouvrir=modifier";
} else {
//Instructions
}
When there are errors (empty input) the controller redirects to this link to tell user to correct errors. The problem is when I check parameters here they look correct (id, name ...), but the id becomes null in the following method:
#Override
public ModelAndView dispatcher(HttpServletRequest request, HttpServletResponse response) throws RorException {
Map<String, Object> myModel = (Map<String, Object>) request.getAttribute(EnumParam.R_MY_MODEL.getKey());
Enumeration<?> keys = request.getParameterNames();
while (keys.hasMoreElements()) {
String paramName = (String) keys.nextElement();
String value = request.getParameter(paramName);
myModel.put(paramName, value);
}
GlobalSession globalSession = (GlobalSession) getApplicationContext().getBean(Utilities.GLOBALSESSION_BEAN_REF);
myModel.put("module", globalSession.getModule().getKeyMessage());
String section = request.getParameter("section");
// This instruction returns null
String idForm = request.getParameter("id");
id = Integer.parseInt(idForm);
// This instruction returns NumberFormatException
ObjectForm of = getForm(id);
// ...
}
Well, I don't know why parameter id changed after redericting? do you have any idea? I tried to redifine parameters in the first method but still got the same NFE.
Thank you in advance.
Thank you
Although the previous answer is accepted, I am adding this answer just for your information.
You can also use RedirectAttributes with and without FlashAttributes also Before issuing redirect, post method should take RedirectAttributes as argument These attributes will be passed as request parameters Look at my code example and see if its helpful.
Way 1 :
#RequestMapping(value={"/requestInfo.html"}, method=RequestMethod.POST)
public String requestInfoPost1(
#ModelAttribute("requestInfoData") RequestInfoData requestInfoData,
BindingResult result,
RedirectAttributes redirectAttributes,
SessionStatus status
) {
// some logic
redirectAttributes.addAttribute("name", requestInfoData.getName());
redirectAttributes.addAttribute("age", requestInfoData.getAge());
// some logic
return "redirect:requestInfoSuccessRedirect";
}
#RequestMapping("requestInfoSuccessRedirect")
public String requestInfoSuccessRedirect()
{
return "requestInfoSuccess";
}
Way 2:
Whatever data is added in flash attribute will be added in session It will be in session only till redirect is successful On redirect, data is retrieved from session and added to Model for new Request. Only after redirect is successful, data is removed
#RequestMapping(value={"/requestInfo.htm"}, method=RequestMethod.POST)
public String requestInfoPost(
#ModelAttribute("requestInfoData") RequestInfoData requestInfoData,
BindingResult result,
RedirectAttributes redirectAttributes,
SessionStatus status
) {
// some logic
redirectAttributes.addFlashAttribute("requestInfoData",
requestInfoData);
// some logic
return "redirect:requestInfoSuccessRedirect";
}
#RequestMapping("requestInfoSuccessRedirect")
public String requestInfoSuccessRedirect()
{
return "requestInfoSuccess";
}
The request parameter is only for one request.
You make a redirect, it means that you make another new "request".
You should add it to the redirect:
return "redirect:/gestion.html?section=Configuration&panel=4&ouvrir=modifier&idTypeOuverture="+idParam;

Adding #ModelAttribute results in 400 (Bad Request) in Delete Request

I can submit a delete request fine with the following:
#RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
public ResponseEntity<Result> deleteTest(#PathVariable String id) {
return new ResponseEntity<>(Result.Success("Hi " + id + "!!!", null), HttpStatus.OK);
}
However, when I add an #ModelAttribute variable, I get 400 (Bad Request) as the http response code:
#RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
public ResponseEntity<Result> deleteTest(#PathVariable String id, #ModelAttribute("authUser") User authUser) {
return new ResponseEntity<>(Result.Success("Hi " + id + "!!!", null), HttpStatus.OK);
}
This #ModelAttribute is working fine with a put request handler I have in my #RestController but not in this delete request.
Here's the #ModelAttribute code:
#ModelAttribute("authUser")
public User authUser(#AuthenticationPrincipal SpringAuthUser springAuthUser) throws Exception {
User user = ConstantsHome.userprofileMgr.getUserByUserId(springAuthUser.getUsername(), true, true);
user.updateRights(null);
request.getSession().setAttribute(ConstantsHome.USEROBJECT_KEY, user);
return user;
}
Why would adding #ModelAttribute cause a delete request to return a 400 (Bad Request) http response?
I'm using spring-web-4.1.4 & spring-security-4.0.3
I digged a little and found that specifying a #PathVariable of "id" somehow attaches it to the #ModelAttribute variable (as a Long(!) instead of a String as I specified). I then came across this post that lead me to different ways to resolve the issue :
Values of #PathVariable and #ModelAttribute overlapping.
Ended up with this as a method declaration (replaced "id" with "userId"):
#RequestMapping(value = "/{userId}", method = RequestMethod.DELETE)
public ResponseEntity<Result> deleteUser(#PathVariable String userId,
#ModelAttribute("authUser") User authUser) {
...
}
Hopefully this will help someone else quickly that might run into this issue instead of spending a day trying to figure it out...

Resources