I'm trying to understand principle of interaction between JSP (with JavaScript) and Java controller using JSON. For example, I have an entity
public class Greeting {
private final long id;
private final String content;
// other part omitted
}
And controller
#Controller
public class GreetingController {
private final AtomicLong counter = new AtomicLong();
#RequestMapping("/")
public String redirect() {
return "redirect:/greeting";
}
#RequestMapping(value = "/greeting")
#ResponseBody
public Greeting greeting(#RequestParam("name") String name) {
return new Greeting(counter.incrementAndGet(), String.format("Hello, %s!", name));
}
}
How to modify this code to send GET request using JavaSctipt to controller and retrieve JSON answer by JavaScript on jsp page?
I would be appreciated for some examples :) or for some tutorial's links.
You can use jQuery to make a ajax get call to the controller. See https://api.jquery.com/jQuery.ajax/. You will have to specify the output type as JSON.
e.g.,
$.ajax({
type: 'GET',
url: '<Your URL>',
cache: false,
dataType: 'json',
// Your input parameters go here
data: {name: 'someValue'},
success: function(data, textStatus){
},
error: function(xhr, textStatus, errorThrown){
}
});
The below link explains how to return JSON object from controller:
http://www.mkyong.com/spring-mvc/spring-3-mvc-and-json-example/
Related
Sorry for asking repeated question but I have tried many solutions but none works,
So I have this class and table Draft, in the index.html I have a table containing many data, I want to use ajax to pass all of that data to Controller class in back-end to save that data in the draft table in the database which equivalent to class Draft.
But this error happened Request method 'POST' not supported.
The problem is GET does not return this error and I want to use POST to pass data.
This is my Draft controller class
#Controller
#Secured({"ADMIN","SUPER_ADMIN"})
public class DraftController {
#Autowired
private DraftService draftService;
#PostMapping("/newdraft")
public #ResponseBody Draft AddDraft(#RequestBody Draft draft, BindingResult result) {
draftService.save(draft); // save the draft to database
return draft;
}
}
This is my ajax function
$("#draftFormSubmit").on('click',function(e) {
e.preventDefault();
call_draft();
});
function call_draft() {
var draft = {
"id": 1,
"user_id":5,
"lowest_cost_found":3,
"paper_used":3,
"print_type":3,
"actual_ups_per_paper":3,
"quantity":3,
"color":3,
"size":3,
"gloss_lam":3,
"matt_lam":3,
"water_based":3,
"uv":3,
"varnish":3,
"spot_uv":3,
"emboss_deboss":3,
"hot_stamping":3,
"diecut":3,
"creasing_line":3,
"total_price":3,
"markup":3,
"final_price":3
}
$.ajax({
type: "POST",
contentType: "application/json",
url: "/newdraft",
data: JSON.stringify(draft),
dataType: 'json',
success: function(data) {
alert("success");
console.log(data)
},
error: function() {
alert("failed");
}
});
}
Only in this project the error occurs, when I write a simple POST on another project it does not have this error.
Thank you in advance!
Try to add the following
#Controller
#RequestMapping("/") // <------------
#Secured({"ADMIN","SUPER_ADMIN"})
public class DraftController {
and check again
I am trying to post a json using ajax to my spring mvc controller I am using code like this in my js file:
$('#regist').click(function () {
$.ajax({
url: 'user/regist',
contentType: "application/json; charset=utf-8",
type: 'post',
dataType: 'json',
success: function (data) {
var json = JSON.stringify(data);
alert(json);
},
fail: function (errMsg) {
alert(errMsg);
},
data: JSON.stringify({
'IDCard': '1234567890'
})
})
});
the signature of my controller function is like this:
#RequestMapping(value = "/regist", method = RequestMethod.POST)
#ResponseBody
public ResultJson regist(HttpSession session, #RequestBody RegistFormJson json)
the RegistFormJson goes like this:
public class RegistFormJson {
private String IDCard;
public String getIDCard() {
return IDCard;
}
public void setiDCard(String IDCard) {
this.IDCard = IDCard;
}
}
now when I send my request, and what I get from my controller using
logger.info(json.getIDCard);
is null.When I change my bean propertity to idCard and change my other code as well ,I can get the result successfully. Who can tell me why ? And If I want to use IDCard in my code, how can I get the result .Thanks
Spring comes with Jackson API which uses Standard Java Code Convention to map JSON properties to Java models.
Since IDCard is not in lower camel case, Jackson API is not able to map the JSON property.
To overcome this you need to specify a #JsonProperty("IDCard") annotation on a Java attribute in order to use IDCard for your JSON property.
Likewise, you can set the PropertyNamingStrategy on the ObjectMapper to overcome this issue.
I am capturing a hierarchical data using Jquery based Jstree library.Data is in a JSON format, I want to capture and bind this data to my bean class(JstreeJson.java).Here is what I have tried so far..
Ajax call :
function getJSON() {
var jstree = $('#jstree1').jstree(true).get_json('#', {flat:true});
console.log(JSON.stringify(jstree));
$.ajax({
type:"POST",
url:"createObjective",
data : { jstree: jstree },
dataType :"json",
success : function(result) {
console.log(jstree);
console.log(result);
},
error: function(jqXHR, textStatus, errorThrown) {
console.log(jqXHR);
console.log(textStatus, errorThrown);
}
});
}
console.log output:
[{"id":"j1_1","text":"Simple root node","icon":true,"li_attr":{"id":"j1_1"},"a_attr":{"href":"#","id":"j1_1_anchor"},"state":{"loaded":true,"opened":false,"selected":false,"disabled":false},"data":{},"parent":"#"}]
controller
#RequestMapping(value="/createObjective",method=RequestMethod.POST)
public #ResponseBody String createObjective(#RequestBody JstreeJson jstree)
{
System.out.println(jstree);
return "done";
}
Bean class
public class JstreeJson
{
private String id;
private String text;
private String parent;
// getters and setter
}
I have tried adding consumes and Headers but it didnt have any effect on my output
#RequestMapping(value="/createObjective",method=RequestMethod.POST,consumes="application/json",headers = "content-type=application/x-www-form-urlencoded")
Try this #RequestMapping:-
#RequestMapping(value="/createObjective" method = RequestMethod.POST,consumes= {"application/json;charset=UTF-8"}, produces={"application/json;charset=UTF-8"})
public #ResponseBody String createObjective(#RequestBody JstreeJson jstree)
{
System.out.println(jstree);
return "done";
}
Or you can keep #RequestMapping simple as bellow:
#RequestMapping(value="/createObjective")
Spring will take care rest of the attributes of #RequestMapping depending on request.
I ma using Spring MVC and trying to use jQuery. I have this on my web page:
$(document).ready(function () {
var entity = {mag: "status_key", paper: "View10"};
$("#btn").click(function () {
$.ajax({
url: "ajaxJsonPost",
type: 'post',
dataType: 'json',
data: JSON.stringify(entity),
contentType: 'application/json',
});
});
});
Spring server has this:
#RequestMapping(value = "ajaxJsonPost", method = RequestMethod.POST)
public void postJson(#RequestBody Entity en) throws IOException {
System.out.println("writing entity: " + en.toString());
}
OK, Entity cames to server. BUT browser console prints 404 not found. I know that my POST request needs any response. In the Internet I've found solution which recommends me to return ResponseEntity object, OR use annotation #ResponseStatus. They both return HttpStatus well, but I don't know in which cases I should use them. What is the best way?
#Controller
#RequestMapping("/apipath")
public class SomeController {
#RequestMapping(value = "/ajaxJsonPost", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public String postJson(#RequestBody final Entity en) {
System.out.println(en.toString());
//assuming you have a class "EntityService" and
//it has a method postData
//which takes Entity object as parameter and pushes into database.
EntityService.postData(en);
System.out.println("added");
return "success";
}
}
Entity object on the Server side
#JsonAutoDetect
public class Entity {
private String mag;
private String paper;
public String getMag() {
return mag;
}
public void setMag(final String mag) {
this.mag = mag;
}
public String getPaper() {
return paper;
}
public void setPaper(final String paper)
this.paper = paper;
}
}
ajax
$(document).ready(function () {
var entity = {mag: "status_key", paper: "View10"};
$("#btn").click(function () {
$.ajax({
url: "/apipath/ajaxJsonPost",
type: 'post',
dataType: 'json',
data: JSON.stringify(entity),
contentType: 'application/json',
success : function(response) {
alert(response);
},
error : function() {
alert('error');
}
});
});
});
And as far as why and when to use #ResponseStatus and #ResponseEntity, there is already a short and simple answer here by #Sotirios Delimanolis. When use #ResponseEntity .
It says :
ResponseEntity is meant to represent the entire HTTP response. You can
control anything that goes into it: status code, headers, and body.
#ResponseBody is a marker for the HTTP response body and
#ResponseStatus declares the status code of the HTTP response.
#ResponseStatus isn't very flexible. It marks the entire method so you
have to be sure that your handler method will always behave the same
way. And you still can't set the headers. You'd need the
HttpServletResponse or a HttpHeaders parameter.
Basically, ResponseEntity lets you do more.
I'm developing a Web App using Spring 4 MVC. I want to know If I can validate JSON request objects with javax.validation API. For example I have this chunk of my entity code:
...
#JsonProperty("cheFecha")
#NotNull
#Column(name = "che_fecha")
#Temporal(TemporalType.DATE)
#DateTimeFormat(style = "M-")
private Date SsiCheque.cheFecha;
#JsonProperty("cheMonto")
#NotNull
#JsonSerialize(using = CurrencySerializer.class)
#Column(name = "che_monto", precision = 10, scale = 2)
private BigDecimal SsiCheque.cheMonto;
...
I have the controller code:
#RequestMapping(value = "/addCheck", method = RequestMethod.POST)
public #ResponseBody SsiCheque addChecks(#Valid SsiCheque ssiCheque, BindingResult result) {
//ssiCheque.persist();
System.out.println("add" + result.getErrorCount());// Zero when there are errors
return ssiCheque;
}
And finally I have the jQuery code:
var formData = $("#formAddChecks :input").serializeArray();
$.ajax({
type: "POST",
url: "addCheck",
data: formData,
beforeSend: function ( xhr ) {
console.log("before Send");
},
error: function (request, status, error) {
console.log('Error ' + "\n" + status + "\n" + error);
},
success: function(data) {
console.log(data);
}
});
The JSON object is arriving correctly to the controller but I want to validate the JSON with the entity javax.annotations API. What I have seen is only using custom validators and "rewrite" the validation code.
Is this the only way to validate JSON?
Thanks in advance!
UPDATE 1
I followed the #James Massey suggestions and my code looks like this right now:
Controller
#RequestMapping(value = "/addCheck", method = RequestMethod.POST)
#ResponseBody
public SsiCheque addChecks(#Valid #RequestBody SsiCheque ssiCheque, BindingResult result) {
//ssiCheque.persist();
System.out.println("agregar " + result.getErrorCount());
return ssiCheque;
}
Javascript file
var ssiCheque = {
cheNumero : $("#formAddChecks cheNumero").val(),
cheRecepto : $("#formAddChecks cheReceptor").val(),
cheMonto : $("#formAddChecks cheMonto").val(),
cheFecha : $("#formAddChecks cheFecha").val(),
cheConcepto : $("#formAddChecks cheConcepto").val()
};
$.ajax({
type: "POST",
contentType: "application/json",
url: "addCheck",
data: ssiCheque,
dataType: "json",
beforeSend: function ( xhr ) {
console.log("before Send");
},
error: function (request, status, error) {
console.log('Error ' /*+ request.responseText*/ + "\n" + status + "\n" + error);
},
success: function(data) {
console.log(data);
}
});
But I'm getting an 400 Error (Incorrect request) when I submit the form and execute the Ajax function. I have faced this error before when the json object format and the controller specs were incompatible, but in this time I don't know why can be the error.
Thanks again!
I have solved my validations in another way. Suppose I have and Agent Object:
public class Agent {
public int userID;
public String name;
public boolean isVoiceRecorded;
public boolean isScreenRecorded;
public boolean isOnCall;
}
I would like to validate :
(1) userID>0
(2) name is mandatory
(3) isVoiceRecorded and isScreenRecorded can be true only if isOnCall is true.
In order to do so I need to add dependency :
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
Now look how Agents class looks like:
#NoArgsConstructor
#ToString
#EqualsAndHashCode(of = "userID")
#CheckBools
public class Agent {
#Min(0)
public int userID;
#NotNull(message = "Name cannot be null")
public String name;
public boolean isVoiceRecorded;
public boolean isScreenRecorded;
public boolean isOnCall;
public LocalDateTime startEventDateTime;
}
(1) #Min(0) - solves userID>0
(2) #NotNull(message = "Name cannot be null") - solves name is mandatory, and you have example how to specify error message
(3) #CheckBools annotation defined by me, at the class level which checks isVoiceRecorded and isScreenRecorded can be true only if isOnCall is true.
#Documented
#Constraint(validatedBy = MyConstraintValidator.class)
#Target({TYPE, ANNOTATION_TYPE})
#Retention(RUNTIME)
public #interface CheckBools {
String message() default "'isVoiceRecorded' or 'isScreenRecorded' can be true only if you are on call";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
In the following class you define the rule
public class MyConstraintValidator implements ConstraintValidator<CheckBools, Agent> {
#Override
public void initialize(CheckBools constraintAnnotation) {
}
#Override
public boolean isValid(Agent value, ConstraintValidatorContext context) {
if (!value.isOnCall && (value.isVoiceRecorded || value.isScreenRecorded))
return false;
else return true;
}
}
At the controller level :
#RestController
#RequestMapping("Myteamview")
public class MyteamviewController {
#Autowired
AgentInfo agentInfo;
#RequestMapping(path = "agents", method = RequestMethod.POST)
public ResponseEntity<Boolean> addOrUpdateAgent(#Valid #RequestBody Agent agent) {
ResponseEntity<Boolean> responseEntity = new ResponseEntity<>(agentInfo.addAgent(agent),HttpStatus.OK);
return responseEntity;
}
}
Note: The important is that you specify #Valid before #RequestBody Agent
There appear to be a few problems here:
Your object structure seems weird. Why are your fields referencing an object type? private Date SsiCheque.cheFecha seems to be a totally non-sensical field.
You generally design your UI to send through a JSON object that can be mapped directly into your Java object. So if your object looked like this:
public class Example {
#NotNull
#Digits(fraction = 2, integer = 10)
private Integer foo;
#NotEmpty
private String bar;
#NotEmpty
private String[] baz;
}
Then your JSON structure would be something like this:
{
"example": {
"foo": 1,
"bar": "Pineapple",
"baz": [
"This is a string",
"So is this"
]
}
}
Which can be used by Jackson to map straight into your object.
You would then write your controller method like this assuming that you had the Jackson JAR included in your project classpath:
#RequestMapping(value = "/example", method = RequestMethod.POST)
#ResponseBody
public Example(#Valid #RequestBody Example example, BindingResult result) {
if(result.hasErrors()){
//A validation has failed, return an error response to the UI
} else {
exampleService.createOrUpdate(example);
return example;
}
}
The important part is that your object is the request body and you use the #RequestBody annotation, as Jackson uses this as a signal to construct your object using the JSON present in your HTTP Request Body. The only downside to this method is that you may have to construct your request JSON programmatically. This is trivial to do with JavaScript however.
(I'm going to assume some sensible input id defaults here, and that you are familiar with the jQuery DOM manipulation/selection syntax)
var bazArray = [];
$.forEach($("#bazContainer"), function (baz, i){
bazArray.push(baz);
});
var example = {
foo: $("#fooInput").val(),
bar: $("#barInput").val(),
baz: bazArray
};
You pass in your example object to your request in the data field, and if you specify that it is of type application/json then jQuery will automatically call JSON.stringify on your example object.
Hopefully this all makes sense.
SOLUTION (Updated by questioner: Jessai)
I checked this question: Spring MVC 400 Bad Request Ajax.
In summary what I did:
Create an object to be parsed with JSON.stringify and send it to the controller.
In the controller I set the method with #ResponseBody and #RequestBody as #James Massey said.
In the entity I added #JSONProperty (I had these already) and #JSONIgnore (I added to cheId field) annotations to the fields.
Javascript:
var ssiCheque = {
cheNumero : $("#formAddChecks #cheNumero").val(),
cheRecepto : $("#formAddChecks #cheReceptor").val(),
cheMonto : $("#formAddChecks #cheMonto").val(),
cheFecha : $("#formAddChecks #cheFecha").val(),
cheConcepto : $("#formAddChecks #cheConcepto").val()
};
$.ajax({
type: "POST",
contentType: "application/json",
url: "addCheck",
data: JSON.stringify(ssiCheque),
dataType: "json",
beforeSend: function ( xhr ) {
console.log("before Send");
},
error: function (request, status, error) {
console.log('Error ' /*+ request.responseText*/ + "\n" + status + "\n" + error);
},
success: function(data) {
console.log(data);
}
});
Controller
#RequestMapping(value = "/addCheck", method = RequestMethod.POST)
#ResponseBody
public SsiCheque addChecks(#Valid #RequestBody SsiCheque ssiCheque, BindingResult result) {
//ssiCheque.persist();
System.out.println("agregar " + result.getErrorCount());
return ssiCheque;
}
Thanks!