Can't pass param when redirect - spring-boot

In my spring boot app I want to pass param errorMessage when user is admin.
snippet:
#Controller
public class UsersController {
#GetMapping("/users")
public String getAllUsers(Model model, RedirectAttributes redirectAttributes) {
logger.info("getAllUsers: model = " + model + ", redirectAttributes= " + redirectAttributes);
Set<Role> roleSet = new HashSet<>();
roleSet.add(Role.ADMIN);
adminsList = userRepository.findAllByRolesIn(roleSet);
model.addAttribute("usersList", userRepository.findAll());
model.addAttribute("adminsList", adminsList);
model.addAttribute("appName", appName);
return "users";
}
#RequestMapping("user/delete/{id}")
public String deleteUser(#PathVariable("id") int id, RedirectAttributes redirectAttributes) {
logger.info("user_id_to_delete = " + id);
Optional<User> userAdmin = adminsList.stream()
.filter(user -> user.getId() == id)
.findFirst();
if (userAdmin.isPresent() && adminsList.size() == 1) {
String errorMessage = "In system must have at least one administrator";
logger.error(errorMessage);
redirectAttributes.addAttribute("errorMessage", errorMessage);
} else {
userRepository.deleteById(id);
}
return "redirect:/users";
}
after try to delete user (method deleteUser) success call
redirectAttributes.addAttribute("errorMessage", errorMessage);
And after that success call method getAllUsers. But param redirectAttributes is empty.

Based on the api documentation
A RedirectAttributes model is empty when the method is called and is
never used unless the method returns a redirect view name or a
RedirectView.
After the redirect, attributes are automatically added to the model of
the controller that serves the target URL.
The errorMessage will be available in the model of getAllUsers() after the redirect .

Related

How to redirect from one controller method to another method with model data in spring boot application

In this example I am trying to redirect from handleSaveContact() controller method from contactSuccessMsg() controller method but after transfer I need to display success or update or failure msg to the UI which is only possible if I transfer Model data from 1st method to 2nd.
Could any one please suggest me how I can trasfer model data from one controller method to another controller method.
#GetMapping(value={"/", "/loadForm"})
public String loadContactForm(Model model) {
model.addAttribute("contact", new Contact());
return "index";
}
#PostMapping("/saveContact")
public String handleSaveContact(Contact contact, Model model) {
String msgTxt = null;
if(contact.getContactId()==null) {
msgTxt = "Contact Saved Successfully..!!";
}else {
msgTxt = "Contact Updated Successfully..!!";
}
contact.setIsActive("Y");
boolean isSaved = contactService.saveContact(contact);
if(isSaved) {
model.addAttribute("successMsg", msgTxt);
}else {
model.addAttribute("errorMsg", "Failed To Save Contact..!!");
}
return "redirect:/contactSuccessMsg";
}
/**
* To resolve Double Posting problem, redirecting the post req method to get request.
* #param contact
* #param model
* #return
*/
#GetMapping(value="/contactSuccessMsg")
public String contactSuccessMsg(Model model) {
model.addAttribute("contact", new Contact());
return "index";
}
I used Spring 3.2.3
1.)Added RedirectAttributes redirectAttributes to the method parameter list in controller1.
public String controlMapping1(
#ModelAttribute("mapping1Form") final Object mapping1FormObject,
final BindingResult mapping1BindingResult,
final Model model,
final RedirectAttributes redirectAttributes)
Inside the method added code to add flash attribute to redirectAttributes
redirectAttributes.addFlashAttribute("mapping1Form", mapping1FormObject);
Then, in the second contoller use method parameter annotated with #ModelAttribute to access redirect Attributes :
#ModelAttribute("mapping1Form") final Object mapping1FormObject
Here is the sample code from Controller 1:
#RequestMapping(value = { "/mapping1" }, method = RequestMethod.POST)
public String controlMapping1(
#ModelAttribute("mapping1Form") final Object mapping1FormObject,
final BindingResult mapping1BindingResult,
final Model model,
final RedirectAttributes redirectAttributes) {
redirectAttributes.addFlashAttribute("mapping1Form", mapping1FormObject);
return "redirect:mapping2";
}
From Contoller 2:
#RequestMapping(value = "/mapping2", method = RequestMethod.GET)
public String controlMapping2(
#ModelAttribute("mapping1Form") final Object mapping1FormObject,
final BindingResult mapping1BindingResult,
final Model model) {
model.addAttribute("transformationForm", mapping1FormObject);
return "new/view";
}

spring CRUD DELETE action that return viewmodel or empty body

I want to write a DELETE action that return a no content body if no id error exist. If id not exist I want to redirect to the coresponding GET view.
Controller code:
#RequestMapping(value = "/todo/delete/{id}", method = RequestMethod.GET)
public String getDeleteTodo(Model model, #PathVariable("id") String id)
{
Optional<Todo> todo = todoRepository.findById(Long.decode(id));
if (todo.isEmpty()) {
model.addAttribute("msginfo", "ctl-todo.delete.msginfo.id-not-exist");
model.addAttribute("requestedId", id);
}
else {
model.addAttribute("todo", todo.get());
}
return "v-todo-delete";
}
#RequestMapping(value = "/todo/delete/{id}", method = RequestMethod.DELETE)
public String deleteTodo(#PathVariable String id, RedirectAttributes redirAttrs)
{
boolean exists = todoRepository.existsById(Long.decode(id));
if (exists) {
todoRepository.deleteById(Long.decode(id));
return ""; //here I want to return a no-content body response
}
else {
redirAttrs.addFlashAttribute("msginfo", "ctl-todo.delete.msginfo.id-not-exist");
redirAttrs.addFlashAttribute("requestedId", id);
return "redirect:/todo/delete" + id;
}
}
More informations about the view:
The GET view is juste a view that display the todo entity corresponding to the id. The deletion is make with a button using ajax to call the DELETE method. Then response is return as 204 with no content into the body, i redirect the user with javascript to the main page... If an id not exist in the DELETE method, I want to redirect to the GET method to show an error message.
If someone have an idea to do this.
Thanks in advance.
Try using return type as ResponseEntity with whatever response body along with a response status. Please refer below code changes:
#RequestMapping(value = "/todo/delete/{id}", method = RequestMethod.DELETE)
public ResponseEntity deleteTodo(#PathVariable String id, RedirectAttributes redirAttrs)
{
boolean exists = todoRepository.existsById(Long.decode(id));
if (exists) {
todoRepository.deleteById(Long.decode(id));
return new ResponseEntity(HttpStatus.NO_CONTENT); //This will return No Content status
}
else {
redirAttrs.addFlashAttribute("msginfo", "ctl-todo.delete.msginfo.id-not-exist");
redirAttrs.addFlashAttribute("requestedId", id);
return new ResponseEntity( "redirect:/todo/delete" + id, HttpStatus.OK);
}
}
Final anwser for me:
#RequestMapping(value = "/todo/delete/{id}", method = RequestMethod.DELETE)
public ResponseEntity<?> deleteTodo(#PathVariable String id, RedirectAttributes redirAttrs)
{
boolean exists = todoRepository.existsById(Long.decode(id));
if (exists) {
todoRepository.deleteById(Long.decode(id));
return new ResponseEntity<>(HttpStatus.NO_CONTENT);
}
else {
redirAttrs.addFlashAttribute("msginfo", "ctl-todo.delete.msginfo.id-not-exist");
redirAttrs.addFlashAttribute("requestedId", id);
/* I use CONFLICT here to explain that the entity was possibly deleted
by another user between the moment the user give the view containing
the DELETE ajax link and the moment he click on it. */
return new ResponseEntity<String>( "redirect:/todo/delete" + id, HttpStatus.CONFLICT);
}
}
Thank you Mandar Dharurkar & Jeethesh Kotian for your help ;)

How to pass model data from one controller to another controller spring

I have my controller-A class like this:
#PostMapping("/otp")
public String otpSubmit(#RequestParam("token") String token, HttpSession session, Model model) throws IOException {
Long enrollment = (Long) session.getAttribute("enrollment");
BaseResponse otpResponse = otpRestClient.validateOTP(enrollment, token);
if(otpResponse.getCode().equals("1020")) {
model.addAttribute("object", otpResponse.getPayload());
return "redirect:/password";
}
model.addAttribute("errorCode", otpResponse.getCode());
model.addAttribute("errorMessage", otpResponse.getMessage());
return "/otp";
}
What I want is simple (I think) pass the model.addAttribute("object", otpResponse.getPayload()); to controller-B class so I can access that data in the other view.
How can I inject this into controller-B class?.
By adding redirectAttributes we can pass model data
Here is the Controller one.
public String controlMapping1(
#ModelAttribute("mapping1Form") final Model model,
final RedirectAttributes redirectAttributes) {
redirectAttributes.addFlashAttribute("mapping1Form", model);
return "redirect:mapping2";
}
Here is Controller2
public String controlMapping2(
#ModelAttribute("mapping1Form") final Model model) {
model.addAttribute("transformationForm", model);
return "view_name";
}
you can save this "Object o = otpResponse.getPayload()" object in a global variable so later you can access it from any controller.

Spring MVC variable resets for no reason

For some reason when I execute a GET request to a certain URI the variable that I need to access in that method loses its memory or points to null.
I have a form where a user can update his personal information. But when he enters a duplicate, it redirects him to a page that lets him know
I have : private static volatile User currentUser;
This field is set when a user logs in and the server performs a GET request to a REST API, which I programmed myself, and returns the User containing his info. This works as expected and the user info is displayed on his home screen.
Code for the above:
#RequestMapping(value = "/login", method = RequestMethod.POST)
public String login(#ModelAttribute Credentials credentials,
RedirectAttributes redirect) {
RestTemplate restTemplate = new RestTemplate();
RoleInfo roleInfo = restTemplate.postForObject(
"http://localhost:9090/users/login", credentials,
RoleInfo.class);
if (roleInfo != null) {
if (roleInfo.isAdmin()) {
redirect.addFlashAttribute("credentials", credentials);
return "redirect:/adminHome";
} else {
redirect.addFlashAttribute("credentials", credentials);
return "redirect:/getBasicUser";
}
} else {
return "login_fail";
}
}
#RequestMapping(value = "/getBasicUser", method = RequestMethod.GET)
public <T> String getBasicUser(#ModelAttribute Credentials credentials,
Model model, RedirectAttributes redirect) {
RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:9090/users/getBasicUser?username="
+ credentials.getUsername();
ResponseEntity<User> responseEntity = restTemplate.exchange(
url,
HttpMethod.GET,
new HttpEntity<T>(createHeaders(credentials.getUsername(),
credentials.getPassword())), User.class);
User user;
user = responseEntity.getBody();
currentUser = user;
System.out.println("current user: " + currentUser.getUsername());
if (user != null) {
userName = credentials.getUsername();
passWord = credentials.getPassword();
redirect.addFlashAttribute("credentials", credentials);
redirect.addFlashAttribute("user", user);
return "redirect:/basicHome";
} else {
return "register_fail";
}
}
So on "basicHome" he can view his information. Also on that page is a link to a form where he can edit the information:
#RequestMapping(value = "/edit", method = RequestMethod.GET)
public String getEditProfilePage(Model model) {
model.addAttribute("currentUser", currentUser);
System.out.println("current use firstname: " + currentUser.getFirstname());
model.addAttribute("user", new User());
return "edit_profile";
}
If an edit is successful he is returned back to his home page with the updated information.
The problem comes when he enters invalid info. He should be redirected back to the "/edit" URI and the currentUserfield should still hold his information but is actually null.
Here is the "/edit" PUT function:
#RequestMapping(value = "/edit", method = RequestMethod.PUT)
public <T> String editProfile(#ModelAttribute("user") User user,
#ModelAttribute("credentials") Credentials credentials,
RedirectAttributes redirect) {
RestTemplate restTemplate = new RestTemplate();
String url = "http://localhost:9090/users/update?username=" + userName;
HttpHeaders headers = createHeaders(userName,
passWord);
#SuppressWarnings({ "unchecked", "rawtypes" })
HttpEntity<T> entity = new HttpEntity(user, headers);
ResponseEntity<User> responseEntity = restTemplate.exchange(url,
HttpMethod.PUT, entity, User.class);
User returnedUser = responseEntity.getBody();
currentUser = returnedUser;
if (returnedUser != null) {
redirect.addFlashAttribute("user", returnedUser);
redirect.addFlashAttribute("credentials", credentials);
return "redirect:/basicHome";
} else {
return "redirect:/editFail";
}
}
I figured out what I had to do. I basically made "user" a session object in: #SessionAttributes("user")

Spring : timely/late binding of #ModelAttribute

I'm using the following code to bind the users to the model [to be used in the view/jsp]:
#ModelAttribute("users")
public Collection<User> populateUsers() {
return userService.findAllUsers();
}
But sometimes I just need to load few users with a particular Role, which I'm trying by using the following code:
int role = 2; //this is being set in a Controller within a method #RequestMapping(method = RequestMethod.GET) public String list(
#ModelAttribute("users")
public Collection<User> populateUsers() {
if(role == 2)
return userService.findAllUsersByRole(role);
else
return userService.findAllUsers();
}
but the populateUsers is always called at the start of the controller, before the role is set in list method, Could you please help me on how to set the users [something like late binding]
Regards
-- adding code
#Controller
#RequestMapping("/users")
public class UserController {
#Autowired
UserService userService;
#RequestMapping(method = RequestMethod.POST)
public String create(#Valid User user, BindingResult bindingResult,
Model uiModel, HttpServletRequest httpServletRequest) {
if (bindingResult.hasErrors()) {
uiModel.addAttribute("user", user);
addDateTimeFormatPatterns(uiModel);
return "users/create";
}
uiModel.asMap().clear();
userService.saveUser(user);
return "redirect:/users/"
+ encodeUrlPathSegment(user.getId().toString(),
httpServletRequest);
}
#RequestMapping(params = "form", method = RequestMethod.GET)
public String createForm(Model uiModel) {
uiModel.addAttribute("user", new User());
addDateTimeFormatPatterns(uiModel);
return "users/create";
}
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
public String show(#PathVariable("id") Long id, Model uiModel) {
addDateTimeFormatPatterns(uiModel);
uiModel.addAttribute("user", userService.findUser(id));
return "users/show";
}
#RequestMapping(value = "/{id}", params = "form", method = RequestMethod.GET)
public String updateForm(#PathVariable("id") Long id, Model uiModel) {
uiModel.addAttribute("user", userService.findUser(id));
addDateTimeFormatPatterns(uiModel);
return "users/update";
}
#ModelAttribute("users")
public Collection<User> populateUsers() {
return userService.findAllUsers();
}
#ModelAttribute("userroles")
public Collection<UserRole> populateUserRoles() {
return Arrays.asList(UserRole.class.getEnumConstants());
}
void addDateTimeFormatPatterns(Model uiModel) {
uiModel.addAttribute(
"user_modified_date_format",
DateTimeFormat.patternForStyle("M-",
LocaleContextHolder.getLocale()));
}
}
#PathVariable("id") Long id is the ID I require in populateUsers, hope it is clear.
If role is in the current request, this method binding role to variable role.
#ModelAttribute("users")
public Collection<User> populateUsers(#RequestParam(required=false) Integer role) {
if(role != null && role == 2)
return userService.findAllUsersByRole(role);
else
return userService.findAllUsers();
}
Setting the model attribute in the required method has solved my issue:
model.addAttribute("users", return userService.findAllUsersByRole(role));
Thanks!

Resources