Spring - Stop redirection on error - spring

I have a page to manage users and I would like to stay on the page if any error occurs when clicking save.
The only cases I found online where to do with validation.
Also my page requires the userId to be posted so I don't think returning the name of the original page in the controller would work. Also I would loose the changes made in the page.
What I am trying to achieve is stay in the same page, showing a message to the user.
Here is my controller:
#RequestMapping(method = RequestMethod.POST)
public String editUser(#RequestParam("userId") String userId, final Map<String, Object> model) {
User user = spiService.getUser(userId);
model.put("user", user);
configureRoles(model, user);
return "edituser";
}
#RequestMapping(path = "/updateUser", method = RequestMethod.POST)
public String updateUser(#RequestParam("userJson") String userRoles, #RequestParam("userId") String userId, final Map<String, Object> model) throws IOException {
User user = spiService.getUser(userId);
try {
addRoles(JsonUtil.getField(userRoles, "addedRoles"), user.getRoles(), userId);
removeRoles(JsonUtil.getField(userRoles, "removedRoles"), user.getRoles(), userId);
} catch (Exception ex) {
// What now?
}
return "users";
}

Instead of redirecting you can use Ajax calls in your controller. For that you have to create one AjaxPojoClass for exampleAjaxResponseBody as your convenience.
For example
$.ajax({
type : "POST",
contentType : "application/json",
url : "/yourUrl",
data : JSON.stringify(data),
dataType : 'json',
success : function(data) {
window.location.replace("/successUrl")
},
error : function(e) {
display(e);
},
});
AjaxController
#Controller
public class AjaxController {
#ResponseBody
#RequestMapping(value = "/yourUrl")
public AjaxResponseBody getSearchResultViaAjax(#RequestBody SearchCriteria search) {
AjaxResponseBody result = new AjaxResponseBody();
//logic
return result;
}
}

you can use ajax to submit your request.

Related

Return error from spring controller via ajax call

I am trying to develop a spring boot application involving sports, I can not see how to return my error after an ajax call in the error section instead of success, I wonder how I can recuperate all the returns coming from the controller of the Class error in the error section and not in the success section
N.B : Everything work fine in this code, only errors are returned in success part.
Class Error:
public class Error extends Exception{
public String code;
public String message;
}
Class Sport:
public class Sport {
public String id;
public String name;
}
Ajax Call
$.ajax({
type : "GET",
url : "/sports-actions",
data: {"id" : sportId},
contentType: "application/json",
dataType : 'json',
success: function (result) {
console.log(result);
},
error: function (e) {
console.log(e);
}
})
Spring Controller
#RestController
#RequestMapping("/sports-actions")
public class SportController {
#RequestMapping(method = RequestMethod.GET)
public Object deleteSport(#RequestParam("id") String id) {
return new Error(404, "id is not valid");
}
}
Edit
I extended my Error class from Exception, but I have error doing this
throw new Error(400 ,"id is not valid") // I get incompatibale type...
You can do following for testing purpose:
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity<Object> deleteSport(#RequestParam("id") String id) {
if({if id exists}) {
return new ResponseEntity<Object>({your response object}, HttpStatus.OK);
} else {
//If the id doesn't exist.
return new ResponseEntity<Error>(new Error(),HttpStatus.BAD_REQUEST);
}
}
Best Practice
You should use #ControllerAdvice to handle exceptions using #ExceptionHandler on method level.
#ControllerAdvice
public class RestControllerAdvice {
#ExeptionHandler(NotFoundException.class)
public ResponseEntity<Error> handleNotFound(NotFoundException nfe) {
//LOG error
Error error = new Error();
error.setCode(HttpStatus.NOT_FOUND);
error.setMessage("ID not found OR Your custom message or e.getMessage()");
return new ResponseEntity<Error>(error, HttpStatus.NOT_FOUND);
}
}
Your controller method
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity<Object> deleteSport(#RequestParam("id") String id) {
if({if id exists}) {
return new ResponseEntity<Object>({your response object}, HttpStatus.OK);
} else {
throw new NotFoundException("Id not found");
}
}
Above ControllerAdivce method will get invoked, if your NotFoundException is thrown during request processing. You can always customize the error.
Your current implementation of SportController will return HTTP status 200 which will never go into error: function (e) {. You need to throw an exception from the controller in order to get into error block.
#RestController
#RequestMapping("/sports-actions")
public class SportController {
#RequestMapping(method = RequestMethod.GET)
public Object deleteSport(#RequestParam("id") String id) throws Error {
throw new Error("Test exception block");
}
}

Sending ajax response to another controller using Spring MVC

I have a view from where I am sending a request to a Controller and as a result getting response back to the view page. Now I want to pass the ajax response in to the next Controller but I do not know what will be the type of response in Controller
This is my ajax code:
$.ajax({
type: "POST",
url: "<c:url value="/menu/menucheckout/${restaurant_menu.name}"/>",
data : {"amount":amount, "orderoption" :orderoption, "date":date , "time":time ,'menuitemsArray': menuitemsArray ,'menuPriceArray': menuPriceArray , 'menuSpiceeArray': menuSpiceeArray , 'ItemQuantityArray': ItemQuantityArray },
success: function(response){
console.log(response);
window.location.href = "/BistroServicesMenuApp/welcome/getordercheckout/"+response.model;
}
});
Here is the Menu Controller
#Controller
#RequestMapping(value = "/menu")
public class MenuController {
#Autowired
private MenuTypeService menutypeService;
#RequestMapping(value="/menucheckout/{restaurantname}" ,method = RequestMethod.POST )
#ResponseBody
public ModelAndView menucheckout(#PathVariable("restaurantname") String restaurantname , HttpSession session, HttpServletRequest request, HttpServletResponse response) throws SQLException, NamingException, IOException
{
ModelAndView model = new ModelAndView("/welcome/getordercheckout");
System.out.println("COMING IN menucheckout CONTROLLER" + restaurantname);
System.out.println("orderoption" + request.getParameter("orderoption"));
String amount = request.getParameter("amount");
String orderoption = request.getParameter("orderoption");
String date = request.getParameter("date");
String time = request.getParameter("time");
String[] menuitemsArray = request.getParameterValues("menuitemsArray[]");
String[] menuPriceArray = request.getParameterValues("menuPriceArray[]");
String[] menuSpiceeArray = request.getParameterValues("menuSpiceeArray[]");
String[] ItemQuantityArray = request.getParameterValues("ItemQuantityArray[]");
model.addObject("restaurantname", restaurantname);
model.addObject("amount", amount);
model.addObject("orderoption", orderoption);
model.addObject("date", date);
model.addObject("time", time);
model.addObject("menuitemsArray", menuitemsArray);
model.addObject("menuPriceArray", menuPriceArray);
model.addObject("menuSpiceeArray", menuSpiceeArray);
model.addObject("ItemQuantityArray", ItemQuantityArray);
return model;
}
}
Now Here is the Second Controller "OrderController":
#Controller
#RequestMapping("/welcome")
public class OrderController {
#Autowired
private OrderService orderService;
#RequestMapping("/getordercheckout/{response}")
public ModelAndView getOrderCheckOut(#PathVariable("response") ModelAndView response)
{
ModelAndView model = new ModelAndView("/getordercheckout");
model.addObject("response" , response);
System.out.println("Response : " +response);
return model;
}
Now here I want to get the response but I am not sure what will be the datatype of reponse.
The System.out.println prints this error:
ModelAndView: reference to view with name '[object Object]'; model is null
Please Help me out as I am new to the Spring MVC.
Thank You in advance.

#ResourceMapping that accepts JSON from Ajax request

I'm searching how I can interprete a JSON parameter in my #ResourceMapping in Spring Portlet MVC. When I add #RequestBody, I got the message: #RequestBody is not supported... Really stuck on this one.
I have this:
View side:
<portlet:resourceURL var="getTest" id="ajaxTest" ></portlet:resourceURL>
<p>
<button onClick="executeAjaxTest();">Klik mij!</button>
<button onClick="$('#ajaxResponse').html('');">Klik mij!</button>
</p>
<p>
<h3>Hieronder het antwoord:</h3>
<h4 id="ajaxResponse"></h4>
</p>
<script>
function executeAjaxTest() {
var jsonObj = {
user: "Korneel",
password: "testpassword",
type: {
testParam: "test",
}
}
console.debug(JSON.stringify(jsonObj));
$.ajax({
dataType: "json",
contentType:"application/json",
mimeType: 'application/json',
url:"<%=getTest%>",
data:JSON.stringify(jsonObj),
success : function(data) {
$("#ajaxResponse").html(data['testString']);
}
});
}
</script>
Controller side:
#ResourceMapping(value="ajaxTest")
#ResponseBody
public void ajaxTestMethod(ResourceRequest request, ResourceResponse response) throws IOException, ParseException {
LOGGER.debug("ajax method");
JSONObject json = JSONFactoryUtil.createJSONObject();
json.put("testString", "Ik ben succesvol verstuurd geweest!");
response.getWriter().write(json.toString());
}
How can I use the spring magic to auto map this JSON data to my own model?
Note: It's Spring Portlet MVC, not regular Spring MVC..
#ResponseBody annotation is not supported out of the box in Spring MVC portlet framework, but you can implement #ResponseBody handling yourself.
We do it by implementing custom view type and model and view resolver.
Implement custom model and view resolver (ModelAndViewResolver), let's say JsonModelAndViewResolver.
In resolveModelAndView method, check whether controller method has #ResponseBody annotation (or more specific condition to identify JSON output - e.g. annotation + required supported mime type).
If yes, return your custom View implementation - let's say SingleObjectJson view (extending AbstractView).
Pass your to-be-serialized object to the view instance.
The view will serialize the object to JSON format and write it to the response (by using Jackson, Gson or other framework in renderMergedOutputModel method).
Register the new resolver as AnnotationMethodHandlerAdapter.customModelAndViewResolvers.
You need to build your json object like this:
var jsonObj = {
user: "Korneel",
password: "testpassword",
"type.testParam" : "test"
};
$.ajax({
dataType: "json",
contentType:"application/json",
mimeType: 'application/json',
url:"<%=getTest%>",
data:jsonObj,
success : function(data) {
$("#ajaxResponse").html(data['testString']);
}
});
In your Controller you should use the #ModelAttribute annotation:
#ModelAttribute(value = "jsonObj")
public JsonObjCommand obtenerJsonObjCommand() {
JsonObjCommand jsonObjCommand = new JsonObjCommand();
return jsonObjCommand;
}
#ResourceMapping(value = "ajaxTest")
public void ajaxTestMethod(
ResourceRequest request,
ResourceResponse response,
#ModelAttribute(value = "jsonObj") JsonObjCommand jsonObjCommand)
throws IOException, ParseException {
LOGGER.debug("USER: " + jsonObjCommand.getUser());
LOGGER.debug("Password: " + jsonObjCommand.getPassword());
LOGGER.debug("TestParam: " + jsonObjCommand.getType().getTestParam());
LOGGER.debug("ajax method");
JSONObject json = JSONFactoryUtil.createJSONObject();
json.put("testString", "Ik ben succesvol verstuurd geweest!");
response.getWriter().write(json.toString());
}
Don't forget your beans:
public class JsonObjCommand {
private String user;
private String password;
private TypeJson type;
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public TypeJson getType() {
return type;
}
public void setType(TypeJson type) {
this.type = type;
}
}
public class TypeJson {
private String testParam;
public String getTestParam() {
return testParam;
}
public void setTestParam(String testParam) {
this.testParam = testParam;
}
}
According to the documentation, #RequestBody is only supported in Servlet environments, not Portlet environments (same for #ResponseBody). So it seems you can't use that functionality.

JSON Posting to Spring-MVC, Spring is not seeing the data

I am working on a project that the project is going to use Ajax to post JSON object to Springs-MVC. I been making a number of changes and I got it to the point where I dont get any more errors BUT I dont see the data that is getting POSTed to Spring in the object I need it in.
Here is my Spring Controller.
#RequestMapping(value="/AddUser.htm",method=RequestMethod.POST)
public #ResponseBody JsonResponse addUser(#ModelAttribute(value="user") User user, BindingResult result ){
JsonResponse res = new JsonResponse();
if(!result.hasErrors()){
res.setStatus("SUCCESS");
res.setResult(userList);
}else{
res.setStatus("FAIL");
res.setResult(result.getAllErrors());
}
return res;
}
I put a breakpoint in and my USER object never gets the data. next is a copy of my USER object:
public class User {
private String name = null;
private String education = null;
private List<String> nameList = null;
private List<String> educationList = null;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEducation() {
return education;
}
public void setEducation(String education) {
this.education = education;
}
public List<String> getNameList() {
return nameList;
}
public void setNameList(List<String> nameList) {
this.nameList = nameList;
}
public List<String> getEducationList() {
return educationList;
}
public void setEducationList(List<String> educationList) {
this.educationList = educationList;
}
and now for the javascript code that does the Ajax, JSON post:
function doAjaxPost() {
var inData = {};
inData.nameList = ['kurt','johnathan'];
inData.educationList = ['GSM','HardKnocks'];
htmlStr = JSON.stringify(inData);
alert(".ajax:" + htmlStr);
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: contexPath + "/AddUser.htm",
data: inData,
dataType: "json",
error: function(data){
alert("fail");
},
success: function(data){
alert("success");
}
});
};
Please let me now if you can help?? I have to get this working ASAP... thanks
You also need to specify the header in your RequestMapping annotion found in your controller.
#RequestMapping(headers ={"Accept=application/json"}, value="/AddUser.htm", method=RequestMethod.POST)
Also, remove .htm in your URL path. htm is some kind of request type overide. Using .htm specifies the web server to handle the request as a classic html request. Using .json would specify to the webserver that the request expects to be handled as a json request.

Spring MVC 3, forwarding not working when using Ajax

I have very interesting problem. I am making log in page for my web app and I am sending login request via AJAX. If success I want to forward user to another page.
It seems that his is what happens. I send Ajax request, controller forwards me to need view (I see log in debug mode) but I stay on the same page, since I assume the page is waiting for AJAX response and for that reason forwarding does not happen.
I think this is also wrong way to approach this but since I am new to this don't know better. How can I log in and and forward user to next page.
Thank you.
Here is my code:
JS Code:
Page.authenticate = function() {
$.ajax({
url: "/login/authenticate/" + $('#username').val() + "/" + $('#password').val(),
type: "GET",
success: function(poi){
// alert("nesto");
}
});
return true;
}
Controller Class:
#Controller
public class LoginPageController {
private Logger logger = Logger.getLogger(this.getClass());
#Autowired
private UserManagement userManagement;
#RequestMapping(value="/login/authenticate/{username}/{password}", method=RequestMethod.GET)
public String authenticate(#PathVariable("username") String userName, #PathVariable("password") String password, Model model) {
if (userManagement.authenticateUser(userName, password)) {
String forward = "forward:/login/success";
return forward;
} else {
model.addAttribute("errorMessage", "Invalid Username/Password, please try again!");
return "/";
}
}
}
You need to response within #ResponseBody Annotation if you are using AJAX.
#RequestMapping(value="/login/authenticate/{username}/{password}", method=RequestMethod.GET)
public String authenticate(#PathVariable("username") String userName, #PathVariable("password") String password, Model model) {
if (userManagement.authenticateUser(userName, password)) {
String forward = "forward:/login/success";
return forward;
} else {
String forward = "forward:/login/error?message=Invalid Username/Password, please try again!";
return forward;
}
}
#RequestMapping(value="/login/success", method=RequestMethod.GET)
#Responsebody
public String handleMySuccessRedirect() {
return "Logged In successfully"
}
#RequestMapping(value="/login/error", method=RequestMethod.GET)
#Responsebody
public String handleMyExceptionOnRedirect(#RequestParamter("message") String message) {
return message;
}
Update:
#RequestMapping(value="/login/authenticate/{username}/{password}", method=RequestMethod.GET)
#ResponseBody
public String authenticate(#PathVariable("username") String userName, #PathVariable("password") String password, Model model) {
if (userManagement.authenticateUser(userName, password)) {
String response = "Logged Successfully";
return response;
} else {
String response = "Invalid Username/Password, please try again!";
return response;
}
}
There are a couple of things you can do here:
Don't return a view from your controller, instead return json, based on the response in json, set the location appropriately - window.location = 'home.action' - here is an example using ext-js
Let the login page perform a full fledged post, not an AJAX post.

Resources