I have a form which should send user input via ajax to my spring mvc controller.
But I always get an Error as you can see below. I implemented into getSearchResultViaAjax a System.out.println("in getSearchResultViaAjax");
but it is never called in the console. Any idea how I could fix that?
Error Message:
{
"readyState": 4,
"responseText": "{\"timestamp\":\"2018-03-24T18:33:14.749+0000\",\"status\":404,\"error\":\"Not Found\",\"message\":\"No message available\",\"path\":\"/$%7Bhome%7D/search/api/getSearchResult\"}",
"responseJSON": {
"timestamp": "2018-03-24T18:33:14.749+0000",
"status": 404,
"error": "Not Found",
"message": "No message available",
"path": "/$%7Bhome%7D/search/api/getSearchResult"
},
"status": 404,
"statusText": "error"
}
I tried in AJAX also paths like:
url: "/search/api/getSearchResult"
url: "search/api/getSearchResult"
and get this then for example
{
"readyState": 4,
"responseText": "{\"timestamp\":\"2018-03-24T19:48:43.638+0000\",\"status\":500,\"error\":\"Internal Server Error\",\"message\":\"Error resolving template \\\"search/api/getSearchResult\\\", template might not exist or might not be accessible by any of the configured Template Resolvers\",\"path\":\"/search/api/getSearchResult\"}",
"responseJSON": {
"timestamp": "2018-03-24T19:48:43.638+0000",
"status": 500,
"error": "Internal Server Error",
"message": "Error resolving template \"search/api/getSearchResult\", template might not exist or might not be accessible by any of the configured Template Resolvers",
"path": "/search/api/getSearchResult"
},
"status": 500,
"statusText": "error"
}
Controller:
#Controller
#RequestMapping("")
public class View {
#Autowired
PController controller;
List<User> users;
/**
* After user coin choice is filled with details, it arrives here.
*
* #param httpEntity the http entity
* #return the string
*/
#RequestMapping(method = RequestMethod.POST)
public String arriveAfterSetup(
HttpEntity<String> httpEntity,
#RequestParam(required = false, value = "name") String name,
#RequestParam(required = false, value = "age") String age,
final ModelMap modelMap
) {
modelMap.put("elementList", controller.getDatabase().getPersonLinkedList());
return "main/mainpage";
}
#RequestMapping(method = RequestMethod.GET)
public String exchangeViewAfterEdit(ModelMap modelMap
) {
modelMap.put("elementList", controller.getDatabase().getPersonLinkedList());
return "main/mainpage";
}
#RequestMapping(value = "/edit/{id}", method = RequestMethod.POST)
public void editPerson(ModelMap modelMap,
#PathVariable String id,
#RequestParam("name") String name,
#RequestParam("age") Double age
) {
//update db
}
// #RequestBody - Convert the json data into object (SearchCriteria) mapped by field name.
// #JsonView(Views.Public.class) - Optional, limited the json data display to client.
#JsonView(Views.Public.class)
#RequestMapping(value = "/search/api/getSearchResult")
public AjaxResponseBody getSearchResultViaAjax(#RequestBody SearchCriteria search) {
System.out.println("in getSearchResultViaAjax");
AjaxResponseBody result = new AjaxResponseBody();
if (isValidSearchCriteria(search)) {
List<User> users = findByUserNameOrEmail(search.getUsername(), search.getEmail());
if (users.size() > 0) {
result.setCode("200");
result.setMsg("");
result.setResult(users);
} else {
result.setCode("204");
result.setMsg("No user!");
}
} else {
result.setCode("400");
result.setMsg("Search criteria is empty!");
}
//AjaxResponseBody will be converted into json format and send back to client.
return result;
}
private boolean isValidSearchCriteria(SearchCriteria search) {
boolean valid = true;
if (search == null) {
valid = false;
}
if ((StringUtils.isEmpty(search.getUsername())) && (StringUtils.isEmpty(search.getEmail()))) {
valid = false;
}
return valid;
}
// Init some users for testing
#PostConstruct
private void iniDataForTesting() {
users = new ArrayList<User>();
User user1 = new User("mkyong", "pass123", "mkyong#yahoo.com", "012-1234567", "address 123");
User user2 = new User("yflow", "pass456", "yflow#yahoo.com", "016-7654321", "address 456");
User user3 = new User("laplap", "pass789", "mkyong#yahoo.com", "012-111111", "address 789");
users.add(user1);
users.add(user2);
users.add(user3);
}
// Simulate the search function
private List<User> findByUserNameOrEmail(String username, String email) {
List<User> result = new ArrayList<User>();
for (User user : users) {
if ((!StringUtils.isEmpty(username)) && (!StringUtils.isEmpty(email))) {
if (username.equals(user.getUsername()) && email.equals(user.getEmail())) {
result.add(user);
continue;
} else {
continue;
}
}
if (!StringUtils.isEmpty(username)) {
if (username.equals(user.getUsername())) {
result.add(user);
continue;
}
}
if (!StringUtils.isEmpty(email)) {
if (email.equals(user.getEmail())) {
result.add(user);
continue;
}
}
}
return result;
}
}
JS
$(document).ready(function () {
$('#myModal').on('shown.bs.modal', function () {
$('#myInput').focus();
});
$("#search-form").submit(function(event) {
// Disble the search button
enableSearchButton(false);
// Prevent the form from submitting via the browser.
event.preventDefault();
searchViaAjax();
});
});
function searchViaAjax() {
var search = {}
search["username"] = $("#username").val();
search["email"] = $("#email").val();
$.ajax({
type: "POST",
contentType: "application/json",
url: "${home}/search/api/getSearchResult",
data: JSON.stringify(search),
dataType: 'json',
timeout: 100000,
success: function (data) {
console.log("SUCCESS: ", data);
display(data);
},
error: function (e) {
console.log("ERROR: ", e);
display(e);
},
done: function (e) {
console.log("DONE");
enableSearchButton(true);
}
});
}
function enableSearchButton(flag) {
$("#btn-search").prop("disabled", flag);
}
function display(data) {
var json = "<h4>Ajax Response</h4><pre>"
+ JSON.stringify(data, null, 4) + "</pre>";
$('#feedback').html(json);
}
function searchAjax() {
var data = {}
data["query"] = $("#query").val();
$.ajax({
type: "POST",
contentType: "application/json",
url: "${home}search/api/getSearchResult",
data: JSON.stringify(data),
dataType: 'json',
timeout: 100000,
success: function (data) {
console.log("SUCCESS: ", data);
display(data);
},
error: function (e) {
console.log("ERROR: ", e);
display(e);
},
done: function (e) {
console.log("DONE");
}
});
}
Thank you a lot!
"${home}/search/api/getSearchResult" in searchViaAjax seems very odd.
${home} looks like a template string, but it's not being replaced, you can tell since your error message says: "path": "/$%7Bhome%7D/search/api/getSearchResult"
Related
I'm trying to save data using ajax in MVC 5. When I'm posting form data without #Html.AntiForgeryToken(), it's working nicely. But it's showing me Object reference not set to an instance of an object error for using #Html.AntiForgeryToken(). Here is my ajax code:
$.ajax({
type: "POST",
url: "/Employees/Create",
data: data,
async: false,
success: function (result) {
if (result == 1) {
window.location.href = '/Employees';
}
else {
$('#error-span').html('Error in insert.');
}
},
error: function () {
alert('Failed');
}
});
Here is my controller method:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Address,JoinDate,DoB,Gender,BloodGroup,Email,LastName,FirstName,Mobile,UpdateDate,UpdatedBy,Status,EmployeeType,CreatedBy,CreateDate,DesignationId")] EmpDetail empDetail)
{
try
{
Regex rgx = new Regex("[^a-zA-Z0-9 - .]");
empDetail.FirstName = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(rgx.Replace(empDetail.FirstName, "").ToLower()).Trim();
empDetail.LastName = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(rgx.Replace(empDetail.LastName, "").ToLower()).Trim();
empDetail.Email = empDetail.Email.ToLower().Trim();
empDetail.UpdateDate = DateTime.Now;
empDetail.CreatedBy = 234;
empDetail.CreateDate = DateTime.Now;
empDetail.UpdatedBy = 234;
empDetail.Status = 1;
if (ModelState.IsValid)
{
db.EmpDetails.Add(empDetail);
db.SaveChanges();
return Json(1);
}
else
{
return Json(2);
}
}
catch (Exception e)
{
return Json(e.Message);
}
}
This is happening because the data is being sent via JSON instead of HTML Form data. You should try to pass the token in the headers. For example:
View:
<script>
#functions{
public string TokenHeaderValue()
{
string cookieToken, formToken;
AntiForgery.GetTokens(null, out cookieToken, out formToken);
return cookieToken + ":" + formToken;
}
}
$.ajax("api/values", {
type: "post",
contentType: "application/json",
data: { }, // JSON data goes here
dataType: "json",
headers: {
'RequestVerificationToken': '#TokenHeaderValue()'
}
});
</script>
Controller:
void ValidateRequestHeader(HttpRequestMessage request)
{
string cookieToken = "";
string formToken = "";
IEnumerable<string> tokenHeaders;
if (request.Headers.TryGetValues("RequestVerificationToken", out tokenHeaders))
{
string[] tokens = tokenHeaders.First().Split(':');
if (tokens.Length == 2)
{
cookieToken = tokens[0].Trim();
formToken = tokens[1].Trim();
}
}
AntiForgery.Validate(cookieToken, formToken);
}
Source: https://www.asp.net/web-api/overview/security/preventing-cross-site-request-forgery-csrf-attacks
var form_data = {
itemid: globalSourceItem.substr(globalSourceItem.indexOf("-") + 1),
columnName: jqInputs[0].value,
displayName: jqInputs[1].value,
format: jqInputs[2].value,
KBE: jqInputs[3].value,
dgroup: jqInputs[4].value,
dupkey: jqInputs[5].value ,
measurement: jqInputs[6].value ,
times: new Date().getTime()
};
// console.log(form_data);
// console.log($("#tourl").html());
$.ajax({
url: $("#tourl").html(),
type: 'POST',
datatype: 'json',
data: form_data,
success: function(message) {
var j_obj = $.parseJSON(message);
// console.log(j_obj);return false;
if (j_obj.hasOwnProperty('success')) {
toastr.info('Item updated successfully');
setTimeout(function(){
window.location.reload();
},1000);
} else {
toastr.info('There was a problem.');
}
},
error: function(xhr, textStatus, errorThrown)
{
toastr.info('There seems to be a network problem. Please try again in some time.');
}
});
}
Hii friends , this code is working for php and i need to send the same data to the spring mvc through the ajax , can anyone please help me with the exact solution where to make changes as Iam struckup with the same doubt for like 2 weeks...
public class TestController {
#RequestMapping(value = "url", method = RequestMethod.POST)
public ModelAndView action(#RequestBody FormData formData) {
...
}
}
public class FormData {
private String itemid;
public String getItemid() {
return itemid;
}
public void setItemid(String itemid) {
this.itemid = itemid;
}
//...
}
Try sth like this. You should be able to map JSON Object to Java Object.
Maybe you could use annotation #ResponseBody and convert JSONObject to String:
#RequestMapping(value = "/ajax", method = RequestMethod.POST, produces="application/json")
#ResponseBody
public String ajax(#RequestBody ListDataDefinition listDataDefinition) {
System.out.println("id="+listDataDefinition.getItemid());
int i=SchemaDAOI.updateldd(listDataDefinition);
String message="success";
JSONObject obj = new JSONObject();
try {
obj.put("success", "success");
}
catch (JSONException e) {
e.printStackTrace();
}
if(i==1){
System.out.println("success");
}
else{
System.out.println("failure");
}
return obj.toString();
}
}
If you send String to View as ResponseBody and set produces as JSON it should be treated as pure JSON RQ.
I have ajax function
$.ajax({
....
type: "POST",
url: "",
data: "",
success: function(){
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
}
});
& controller code is
public #ResponseBody
GenericResponse abc() {
try {
....
} catch (Exception ex) {
ex.printStackTrace();
return new GenericResponse("Failed", ex.getMessage(), 500);
}
return new GenericResponse("Success", "", 200);
}
where GenericResponse is
public class GenericResponse
{
private String status;
private String error;
private int code;
public GenericResponse(String s, String e, int c)
{
this.status = s;
this.error = e;
this.code = c;
}
....
}
So for success & failure I am sending genericresponse with status but for both it goes inside success callback function.
I understand that it is gennericResponse so ajax would consider it as success only . If exception comes
I want it to go to error callback function. How to do that?
Instead of returning a GenericResponse, try returning a ResponseEntity instead.
You would do:
return new ResponseEntity<GenericResponse>(successGenericResponse, HttpStatus.OK);
or
return new ResponseEntity<GenericResponse>(failGenericResponse, HttpStatus.INTERNAL_SERVER_ERROR);
I'm trying to setup my controllers so that they can use http error codes to send the responses to ajax calls. So for example I have my login ajax call and controller action:
[System.Web.Mvc.HttpPost, System.Web.Mvc.AllowAnonymous]
public ActionResult Login(string userName, string password, bool rememberMe, string returnUrl)
{
[...]
var loginError = new HttpResponseMessage(HttpStatusCode.Unauthorized)
{
Content = new StringContent("Lorem ipsum 2 " + ErrorMessages.LOGINERROR),
ReasonPhrase = "Lorem ipsum 2 " + ErrorMessages.LOGINERROR
};
throw new HttpResponseException(loginError);
}
$.ajax({
type: "POST",
url: url,
data: data,
dataType: "text",
success: callBack,
error: function () { console.log("Error..."); },
statusCode : {
401: function (result) {
console.log("Login failed (401): " + result);
}
}
});
I'm thinking there are a couple of things I'm not doing right, if someone can point them out that would be lovely!
Thanks!
Look at this solution: ASP.NET MVC Ajax Error handling
Darin Dimitrov write very nice solutions with action filter:
public class MyErrorHandlerAttribute : FilterAttribute, IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
filterContext.ExceptionHandled = true;
filterContext.Result = new JsonResult
{
Data = new { success = false, error = filterContext.Exception.ToString() },
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
}
Then you could write your client error handling for all status codes and use it for ajax requests.
Instead of throw exception just return ActionResult that provide some content and setup response code. For your case you can create something that I call ExtendedJsonResult:
public class ExtendedJsonResult : JsonResult
{
public ExtendedJsonResult(object data)
{
base.Data = data;
}
public int StatusCode { get; set; }
public override void ExecuteResult(ControllerContext context)
{
context.HttpContext.Response.StatusCode = this.StatusCode;
base.ExecuteResult(context);
}
}
and then in controller
return new ExtendedJsonResult("Some error")
{
StatusCode = 401,
};
You can also just return existing HttpStatusCodeResult.
I want to post a form via ajax call also model will be passed into the action method, but want to get Model errors via json. How can I do this?
You could write a custom action filter:
public class HandleJsonErrors : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var modelState = (filterContext.Controller as Controller).ModelState;
if (!modelState.IsValid)
{
// if the model is not valid prepare some JSON response
// including the modelstate errors and cancel the execution
// of the action.
// TODO: This JSON could be further flattened/simplified
var errors = modelState
.Where(x => x.Value.Errors.Count > 0)
.Select(x => new
{
x.Key,
x.Value.Errors
});
filterContext.Result = new JsonResult
{
Data = new { isvalid = false, errors = errors }
};
}
}
}
and then put it into action.
Model:
public class MyViewModel
{
[StringLength(10, MinimumLength = 5)]
public string Foo { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
[HandleJsonErrors]
public ActionResult Index(MyViewModel model)
{
// if you get this far the model was valid => process it
// and return some result
return Json(new { isvalid = true, success = "ok" });
}
}
and finally the request:
$.ajax({
url: '#Url.Action("Index")',
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify({
foo: 'abc'
}),
success: function (result) {
if (!result.isvalid) {
alert(result.errors[0].Errors[0].ErrorMessage);
} else {
alert(result.success);
}
}
});
Something like this?
$.ajax({
type: "POST",
url: $('#dialogform form').attr("action"),
data: $('#dialogform form').serialize(),
success: function (data) {
if(data.Success){
log.info("Successfully saved");
window.close();
}
else {
log.error("Save failed");
alert(data.ErrorMessage);
},
error: function(data){
alert("Error");
}
});
[HttpPost]
public JsonResult SaveServiceReport(Model model)
{
try
{
//
}
catch(Exception ex)
{
return Json(new AdminResponse { Success = false, ErrorMessage = "Failed" }, JsonRequestBehavior.AllowGet);
}