How to map both json and form submit requests to the same controller? - spring

If I send data like this :
$.ajax({
url: $fooForm.action,
data: $fooForm.serialize(),
type: 'POST',
success: function(data) { console.log(data); }
});
This can be received by a controller that has the following signature :
public ResponseEntity<Map<String, Object>> checkEligibility( Person person )
At another instance, I am sending the request like this :
$.ajax({
url: $fooForm.action,
data: $fooForm.serialize(),
dataType: 'json',
type: 'POST',
success: function(data) { console.log(data); }
});
This can be received by a controller with the following signature :
public ResponseEntity<Map<String, Object>> checkEligibility(#RequestBody Person person )
I want to write a single method that can accept both the json POST as well as the simple POST, and give me the same Person object

If the x-www-form-urlencoded POST is part of a browser-based HTML forms application, DO NOT DO THIS
You should be using the POST-Redirect-GET pattern with HTML forms. Otherwise, when a user hits refresh in their browser they get that annoying popup.
And this is fundamentally at odds with patterns of a REST API

You can use polymorphism to make this feature work.
So, you need to create a BaseController.
#Controller
public class BaseController
public ResponseEntity<Map<String, Object>> checkEligibility(final Person person) {
Map<String, Object> body = new HashMap<String, Object>();
body.put("person", person);
ResponseEntity<Map<String, Object>> entity = new ResponseEntity<Map<String,Object>>(body, HttpStatus.OK);
// write some logic here ...
return entity;
}
Next, you need to create RestController
#Controller
#RequestMapping(value = "/eligibility")
public class RestController extends BaseController {
#Override
#ResponseBody
#RequestMapping(method = RequestMethod.POST, headers = { "content-type=application/json" })
public ResponseEntity<Map<String, Object>> checkEligibility(final #RequestBody Person person) {
return super.checkEligibility(person);
}
}
After that, create Standart controller
#Controller
#RequestMapping(value = "/eligibility")
public class StandartController extends BaseController {
#Override
#ResponseBody
#RequestMapping(method = RequestMethod.POST)
public ResponseEntity<Map<String, Object>> checkEligibility(final #ModelAttribute Person person) {
return super.checkEligibility(person);
}
}
Now this should work.

Related

Hibernate how to return Json value?

Hi I have this controller method that returns a list of customers and displays it using a model.
#Controller
public class timesheetController
{
#Autowired
private CustomerDAO customerDAO;
#GetMapping("/getCustomers")
public String getCustomers(Model view)
{
//get customers from dao
List<Customer> results = customerDAO.getCustomers();
//add the customers to the model
view.addAttribute("customers", results);
return "list-customers";
}
}
However I would like to return the list as a json to get an output like
{
"Customer_Code": T77A,
"Customer_Name": CustomerName1
},
{
"Customer_Code": T77B,
"Customer_Name": CustomerName2
}
I tried just returning the list as follows
#Controller
public class timesheetController
{
#Autowired
private CustomerDAO customerDAO;
#GetMapping("/getCustomers")
public List<Customer> getCustomers()
{
//get customers from dao
List<Customer> results = customerDAO.getCustomers();
return results;
}
}
but then I get this error as it seems to be expecting a view. How can I return the desired json output?
well you are trying to call getCustomers.jsp. What you want, instead, is not a JSP page but a JSON response. So you should make an AJAX call (by using JQuery or other framework or native JS)
So what I would do is change your Controller class in this way:
#Controller
public class timesheetController
{
#Autowired
private CustomerDAO customerDAO;
#GetMapping("/getCustomers", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = {MediaType.APPLICATION_JSON_UTF8_VALUE })
public ResponseEntity<List<Customer>> getCustomers()
{
List<Customer> payload = customerDAO.getCustomers();
return ResponseEntity
.ok()
.contentType(MediaType.APPLICATION_JSON_UTF8)
.body(payload);
}
}
Then I would make the JSON call (I'm using JQuery in this example):
var baseUrl = YOUR_WEB_APP_CONTEXT/getCustomers;
$.ajax({
type: "GET",
url: baseUrl,
success: function(data) {
//All OK.. you should have the JSON response
},
error: function() {
//Something was wrong; you chould check
}
});

Spring - Stop redirection on error

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.

How to call controller method from jsp using ajax

I am using spring boot, maven 3.2.5.
I am working on simple maven webapp using spring boot following mvc pattern.
i am trying to call controller method from jsp suing ajax.
this is my jsp javascript method look like , which call the ajax call to call the controller method.
function listExistingUser()
{
alert("listExistingUser");
$.ajax({
type : "GET",
url : '${home}/loginController/listExistingUser',
dataType : "json",
crossDomain:true,
success : function(data) {
//console.log(data);
//alert(data.toString());
checkValidUser(data);
},
error : function(data) {
}
});
}
Bellow is my controller class.
#Controller
#RequestMapping("/loginController")
public class LoginController {
#Autowired
LoginService loginService;
#RequestMapping(value = "/listExistingUser", method = RequestMethod.GET)
#ResponseBody
public Object getAuthentication(#ModelAttribute("studentId") int studentId,
HttpServletRequest request, HttpServletResponse response)
{
System.out.println("listExistingUser is called in controller");
}
}
when I run my application, I am able to access login.jsp from the bellow url
http://localhost:9090/seperation-management/pages/login.jsp
when i hit submit button my jsp page javascript method is also getting called that is alert("listExistingUser");
but i am not able to called my controller method.
where I am making mistake. can anyone help me.
there's some changes to be made in the contoller method
#RequestMapping(value = "/listExistingUser", method = RequestMethod.GET)
#ResponseBody
public ResponseEntity<Object> getAuthentication(){
System.out.println("listExistingUser is called in controller");
return new ResponseEntity<Object>(object,HttpStatus.OK);
}
you dont need to have #modelAttribute annotation since you are not binding any object with the request. and it is a good practise to return ResponseEntity instead of returning an Object.
if you need to get an id from an incoming request
like this siteName/listExistingUser/1 then use this method.
#RequestMapping(value = "/listExistingUser/{id}", method = RequestMethod.GET)
#ResponseBody
public ResponseEntity<Object> getAuthentication(#PathVariable("id") int id){}
if you want to get values from a url like this
siteName/listExistingUser?id=1 then use this method instead.
#RequestMapping(value = "/listExistingUser", method = RequestMethod.GET)
#ResponseBody
public ResponseEntity<Object> getAuthentication(#RequestParam("id") int id){}
This example is working in my Application:
JSP:
<script type="text/javascript" charset="utf-8">
function getDesc() {
$.getJSON("desclist.json", {
sel1Id : $('select#COMPSNT_NM').val()
}, function(data) {
var html = '';
var len = data.length;
for (var i = 0; i < len; i++) {
html += '<option value="' + data[i] + '">'
+ data[i] + '</option>';
}
$('select#COMPSNT_DS').html(html);
});
}
$(document).ready(function() {
$('#COMPSNT_NM').change(function() {
getDesc();
});
});
</script>
Controller:
#RequestMapping(value = "desclist.json")
#ResponseStatus(HttpStatus.OK)
public #ResponseBody List<String> sectionList(#RequestParam(value = "sel1Id", required = true) String sel1Id,
ModelMap modelMap) {
List<PARAM_SEQ_2> list = new ArrayList<>();
List<String> list2 = new ArrayList<>();
list = paramSeq2Service.findByField2(sel1Id);
for (PARAM_SEQ_2 prm : list) {
list2.add(prm.getCOMPSNT_DS());
}
return list2;
}

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.

Resources