Spring Boot - redirect to a different controller method - spring-boot

I am creating a very basic application with SpringBoot and Thymeleaf. In the controller I have 2 methods as follows:
Method1 - This method displays all the data from the database:
#RequestMapping("/showData")
public String showData(Model model)
{
model.addAttribute("Data", dataRepo.findAll());
return "show_data";
}
Method2 - This method adds data to the database:
#RequestMapping(value = "/addData", method = RequestMethod.POST)
public String addData(#Valid Data data, BindingResult bindingResult, Model model) {
if (bindingResult.hasErrors()) {
return "add_data";
}
model.addAttribute("data", data);
investmentTypeRepo.save(data);
return "add_data.html";
}
HTML files are present corresponding to these methods i.e. show_data.html and add_data.html.
Once the addData method completes, I want to display all the data from the database. However, the above redirects the code to the static add_data.html page and the newly added data is not displayed. I need to somehow invoke the showData method on the controller so I need to redirect the user to the /showData URL. Is this possible? If so, how can this be done?

Try this:
#RequestMapping(value = "/addData", method = RequestMethod.POST)
public String addData(#Valid Data data, BindingResult bindingResult, Model model) {
//your code
return "redirect:/showData";
}

sparrow's solution did not work for me. It just rendered the text "redirect:/"
I was able to get it working by adding HttpServletResponse httpResponse to the controller method header.
Then in the code, adding httpResponse.sendRedirect("/"); into the method.
Example:
#RequestMapping("/test")
public String test(#RequestParam("testValue") String testValue, HttpServletResponse httpResponse) throws Exception {
if(testValue == null) {
httpResponse.sendRedirect("/");
return null;
}
return "<h1>success: " + testValue + "</h1>";
}

Below Solution worked for me.
getAllCategory() method displays the data and createCategory() method add data to the database. Using return "redirect:categories";, will redirect to the getAllCategory() method.
#GetMapping("/categories")
public String getAllCategory(Model model) {
model.addAttribute("categories",categoryRepo.findAll());
return "index";
}
#PostMapping("/categories")
public String createCategory(#Valid Category category) {
categoryRepo.save(category);
return "redirect:categories";
}
OR using ajax jQuery also it is possible.

You should return a http status code 3xx from your addData request and put the redirct url in the response.

Related

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 send JSON response from controller?

I want to pass a boolean value from my controller to javascript using json but couldnot find a way as I am new to spring mvc.
While using servlet we wrote:
response.getWriter().println(somevalue)
and the somevalue can be received using ajax.
Here my controller method is:
#RequestMapping(value = REGISTERACTION , method = RequestMethod.POST)
#ResponseBody
public boolean RegisterUser(#ModelAttribute("register") Register register,HttpServletRequest request, HttpServletResponse response)
{
boolean Registrationsuccess = userService.RegisterUser(register);
return Registrationsuccess;
}
So, here the boolean variable is Registrationsuccess which I want to send to js file and receive it using ajax.
And in my javascipt function which is called using onsubmit event-->
function AccountExists()
{
$.ajax({
type: 'POST',
url: 'registerProcess',
success: function(data){
let detail = JSON.parse(data);
if( data == true)
alert("Success");
else
alert("Not ");
}
});
}
Getting error --
The target resource does not have a current representation that would be acceptable to the user agent, according to the proactive negotiation header fields received in the request, and the server is unwilling to supply a default representation.
You need to use ResponseEntity and #RestController for JSON Response.
Note : #RestController includes both annotations #Controller and #ResponseBody.
Try with this :
#RestController
#RequestMapping("controller")
public class Controller {
#PostMapping("REGISTERACTION")
public ResponseEntity<Boolean> RegisterUser(#ModelAttribute("register") Register register)
{
Boolean registrationSuccess = userService.RegisterUser(register);
return new ResponseEntity<Boolean>(registrationSuccess , HttpStatus.OK);
}
}
Try to use #ResponseBody annotation in your controller's method. And change the return type of the method to Boolean, then return Registrationsuccess instead of ModelAndView.
You can achieve this using 2 approach
Approach 1: Set model attribute and using expression language you can find on jsp
model.addAttribute("test",true);
in Jsp page
${test}
Approach 2: If you are sending ajax request instead of ModelAndView create a object
set any attribute boolean and return object from method #ResponseBody annotation you will get json in Ajax Response
#RequestMapping(value = REGISTERACTION , method = RequestMethod.POST)
public #ResponseBody MyCustomObject RegisterUser(#ModelAttribute("register") Register register,HttpServletRequest request, HttpServletResponse response)
{
boolean Registrationsuccess = userService.RegisterUser(register);
MyCustomObject cusobj=new MyCustomObject();
cusobj.setStatus(true);
return cusobj;
}
Whatever code you have written it will not return json(It is basically form submission approach) so you have to go with first approach.

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;

Spring MVC handle Exceptions and how to show in same view

If I handle exceptions with #ControllerAdvice and #ExceptionHandler How can I show error message to user in the same View. For ex. suppose user in "customer/new" view. and invoke "save" action, then it will go to controller and I call methods service layer. but if internal exception occurred in service layer, I want to show error message on same "customer/new" View.
I have written a separate class to handle exceptions as follow.
#ControllerAdvice
public class DefaultControllerHandler {
#ExceptionHandler({MyProjectException.class, DataAccessException.class})
public ResponseEntity<String> handleInternalErrorException(Exception e) {
logger.error(e.getMessage(), e);
return new ResponseEntity<String>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Appreciate your ideas.
Thanks!
You can use flash redirect attributes.
#RequestMapping(value = "/administrator/users", method = RequestMethod.POST)
public String adminAddUser(#ModelAttribute("user") #Valid User user, BindingResult bindingResult, Model model, RedirectAttributes redirectAttrs) {
String redirectUrl = "/administrator/users";
try {
userService.save(user);
} catch (YourServiceException e) {
redirectAttrs.addFlashAttribute("errorMessage", "error occured: " + e.getMessage());
redirectAttrs.addFlashAttribute("userObject", user);
redirectUrl = "/administrator/users?form"; // If error - return to same view
}
return "redirect:" + redirectUrl;
}
#RequestMapping(value = "/administrator/users", params = "form", method = RequestMethod.GET, produces = "text/html")
public String adminUsersList(#ModelAttribute("errorMessage") final String errorMessage, #ModelAttribute("userObject") final User user Model model) {
if(user == null) {
user = new User();
}
model.addAttribute("user", user);
if(errorMessage != null) {
model.addAttribure("errorMessage", errorMessage);
}
return "administrator/users/create";
}
In that case you must have section on your users.jsp page to show errorMessaage. Something like this:
<c:if test="${not empty errorMessage}">${errorMessage}</c:if>
If you can fetch url path and redirectAttributes from controller method - you can do this through #ControllerAdvice
The only solution I can think about is make your call to the service layer AJAX and then redirect only if there are no errors, if not display the error message.
It might look something like this in your Javascript file
$("#someButton").click(function(){
//make your ajax call
if (noError){
window.location.href = contextPath+"/somePath";
}
else{
//display your error message
}
});

Why isn't my Spring Model getting populated with the proper attributes?

I'm using Spring 3.1.0.RELEASE. For some reason, in my controller, when I POST my form and return the original screen when an error occurs, model attributes are not getting populated like they do when I invoke the page through a GET method. In my controller I have
#Controller
public class StandardsUploadController {
…
#RequestMapping(value = "/upload")
public String getUploadForm(Model model) {
model.addAttribute(new StandardsUploadItem());
model.addAttribute("gradeList", gradeList);
model.addAttribute("subjectList", subjectList);
return "upload/index";
}
#RequestMapping(value = "/upload", method = RequestMethod.POST)
public ModelAndView processFile(final StandardsUploadItem uploadItem,
final BindingResult result,
final HttpServletRequest request,
final HttpServletResponse response) throws InvalidFormatException, CreateException, NamingException {
stdsUploadValidator.validate(uploadItem, result);
if (!result.hasErrors()) {
try {
…
} catch (IOException e) {
LOG.error(e.getMessage(), e);
e.printStackTrace();
}
} // if
return new ModelAndView("upload/index");
}
What am I doing wrong and how can I correct it?
When you return to the upload/index view from the POST, it is not re-populating the Model, since your code to populate the model is done on the GET.
One potential option is to use the #ModelAttribute annotation in your Controller class
You would have, for example, a method that looks like this for the StandardsUploadItem:
#ModelAttribute("uploadItem")
public StandardsUploadItem getStandardsUploadItem(){
return new StandardsUploadItem();
}
You could then remove the line below from your GET method:
model.addAttribute(new StandardsUploadItem());
Since a method annotated with #ModelAttribute and returning an object will automatically be put in the ModelMap, regardless of which Controller RequestMapping method is activated.
Your method signature for the POST method would contain something like this:
..., #ModelAttribute("uploadItem") StandardsUploadItem uploadItem, ...
You would need to do something similar for the other attributes in your model (gradeList, and subjectList), but since you do not seem to need them on the POST, you could do something like add a Model parameter to your POST method signature, and re-populate that Model before you return the ModelAndView in the error case.

Resources