spring mvc and ajax get 400 error - ajax

My model as below and add use the spring mvc.
#Entity
#Table(name="audit_report")
public class AuditReport implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "audit_report_id")
private int auditReportId;
#ManyToOne(fetch=FetchType.LAZY,optional = false,cascade=CascadeType.ALL)
#JoinColumn(name="audit_factory_id")
private AuditFactory auditFactory;
#Column(name = "report_id")
private String reportId;
#Column(name = "editor")
private String editor;
#Column(name = "engineer_name")
#NotNull
private String engineerName;
#Column(name="service_date")
#DateTimeFormat(pattern="MM/dd/yyyy")
private Date serviceDate;
#Column(name="audit_date")
#DateTimeFormat(pattern="MM/dd/yyyy")
private Date auditDate;
#OneToMany(cascade = CascadeType.ALL ,fetch = FetchType.LAZY, mappedBy = "auditReport")
#Fetch(FetchMode.SUBSELECT)
private List<Printer> printers;
controller as below,it will get the model and save it.
#ResponseBody
#RequestMapping(value = "/saveAuditReport",method = RequestMethod.POST)
public Map<String,String> newAuditReport(HttpServletRequest request,#RequestBody AuditReport report){
ajax, it get the 400 error if add the serviceDate and it will ok after remove the serviceDate
$.ajax({
type:"post",
url:"<%=path%>/audit/saveAuditReport.do",
contentType : 'application/json; charset=utf-8',
data:JSON.stringify({'serviceDate':pnDate,'engineerName':engineer,'reportId':reportId,"auditReportId":auditReportId,"printers":array,"auditFactory":{"auditFactoryId":factoryId}}),
dataType:'json',
success:function(data, textStatus){
if(data!=null){
if(data.error==null){
layer.msg(data.ok,1,9);
layer.close(pageii);
searchReportById(factoryId,obj);
}else{
layer.msg(data.error);
}
}
},
error : function(XMLHttpRequest, textStatus, errorThrown) {
}
});
ajax, it get the 400 error if add the serviceDate and it will ok after remove the serviceDate

First of all, Your model should have setters and getters. Then, One possible problem is auditReportId field in your model. You used #Id and #GeneratedValue annotations for it. This means that the auditReportId should not be provided by user and hibernate will generate it automatically. But you assigned it manually. So you should remove "auditReportId":auditReportId part from your json data. Try this and if problem not resolved, post exact exception stack trace for better helping.

You have date parsing error ... so add #JsonSerialize(using = DateSerializer.class) annotation above your date field in your model class
#DateTimeFormat(pattern="MM/dd/yyyy")
#JsonSerialize(using = DateSerializer.class)
private Date serviceDate;

Related

Why does not delete data in rest api

I am working on rest api. I got error while delete data by id. All code is complete but don't know why postman fire error. I can map two table with unidirectional mapping using hibernate.
Here down is error in postman:
"message": "Required request body is missing: public org.springframework.http.ResponseEntity<org.springframework.http.HttpStatus> com.rest.RestApiPojo.Controller.PojoController.deleteAddressPerson(com.rest.RestApiPojo.Entity.Person,java.lang.Integer)"
Here down is my code:
Entity
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer person_id;
private String name;
#JsonManagedReference
#OneToOne(cascade = CascadeType.ALL, mappedBy = "person")
private Address address;
// getter setter
}
#Table(name = "address_master")
public class Address {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer address_id;
private String city;
private String country;
#JsonBackReference
#OneToOne(cascade=CascadeType.ALL, targetEntity = Person.class)
#JoinColumn(name = "person_id")
private Person person;
// getter setter
}
SeviceImpl
#Override
public void deleteAddressPerson(Integer personId) {
personRepo.deleteById(personId);
}
Controller
#RequestMapping(value = "/dltpersonaddress/{personId}", method = RequestMethod.DELETE)
public ResponseEntity<HttpStatus> deleteAddressPerson(#RequestBody Person person, #PathVariable Integer personId)
{
pojoService.deleteAddressPerson(personId);
return new ResponseEntity<>(HttpStatus.OK);
}
You have an unused #RequestBody Person person parameter in your controller method.
#RequestMapping(value = "/dltpersonaddress/{personId}", method = RequestMethod.DELETE)
public ResponseEntity<HttpStatus> deleteAddressPerson(#RequestBody Person person, #PathVariable Integer personId)
{
pojoService.deleteAddressPerson(personId);
return new ResponseEntity<>(HttpStatus.OK);
}
The error message explains that this param is obligatory, and requests without it wont be processed.
Remove the param to solve the issue.

Spring + Hibernate without lazy = LazyInitializationException

I want to load all objects from a table without a lazy objects/children and list them on the page (Thymeleaf template), but I get a LazyInitializationException every time. I tried to convert Hibernate entity objects into a POJO that doesnt contains a lazy/unwanted object but with the same result. I also tried open-in-view parameter set to false...
Simple example:
Parent:
#Entity
public class DocumentDbe implements Serializable {
public DocumentDbe(){
}
#Id
#Column(name = "id", updatable = false, nullable = false)
private Long id;
#OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
private DocumentFileDbe documentFile;
....
}
Child:
#Entity
public class DocumentFileDbe implements Serializable {
public DocumentFileDbe(){}
#Id
#Column(name = "id", updatable = false, nullable = false)
private Long id;
#Column
#Lob
private byte[] documentData;
...
}
POJO:
public class DocumentDto implements Serializable {
public DocumentDto(){
}
public DocumentDto(DocumentDbe doc){
this.id = doc.getId();
}
....
}
Controller:
#GetMapping("/list")
String getList(Model model) {
List<DocumentDbe> docs;
List<DocumentDto> data = new ArrayList<>();
try (Session ses = sessionFactory.openSession()) {
docs = ses.createQuery("FROM DocumentDbe").list();
docs.forEach(doc -> {
data.add(new DocumentDto(doc));
});
}
model.addAttribute(MODEL_LIST_DATA, data);
return "list";
}
EDIT: Thrown exception:
org.thymeleaf.exceptions.TemplateInputException: An error happened during template parsing (template: "class path resource [templates/list.html]")] with root cause
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
EDIT2:
In DocumentDbe is relation with another object (EAGER this time so I was not paying attention to it) , which has reference to DocumentDbe again.. chained relationship and LazyInitializationException is created...
EDIT3:
Although
This is modified and working controller, without POJO:
#GetMapping("/list")
String getList(Model model) {
List<DocumentDbe> docs;
try (Session ses = sessionFactory.openSession()) {
docs = ses.createQuery("FROM DocumentDbe ORDER BY id DESC").list();
docs.forEach(doc -> {
doc.setDocumentFile(null);
doc.getHistory().forEach(log ->{
log.setDocument(null);
});
});
}
model.addAttribute(MODEL_ADMIN_DATA, docs);
return "list";
}
In class DocumentDbe you have mark relation as Lazy. In default relation #ManyToOne and #OneToOne is as EAGER, so if you don't want Lazy, you have to change
#OneToOne(cascade = CascadeType.PERSIST)
If you want have #lob also as eager:
#Lob
#Basic( fetch = FetchType.EAGER )

Use #RequestBody to receive data from ajax and binding it to 'User', but failed

I used AJAX to submit data to the spring boot backend with the #RequestBody annotation to accept it. However, when doing that, it showed the followinng error, which confuses me:
Required String parameter 'username' is not present
Console output
Resolved [org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'username' is not present]
AJAX code
$("#submitBTN").click(
function(){
$.ajax({
type:"post",
async:false,
url:"/user/doSignIn?verification="+$("input[name='verificationCode']").val(),
contentType: "application/json;charset=utf-8",//必须加
data: JSON.stringify({
'username': $("input[name='username']").val(),
'password':$("input[name='password']").val(),
'email': $("input[name='email']").val()
}),
success:function(r){
if(r.code==window.ResponseStatus.OK){
$(window).attr('location',+'/index');
}else{
console.log(r.msg);
}
}
});
}
);
Entity User
#Entity
public class User {
// 自增id
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
// 用户名
#Pattern(regexp = "^.{4,14}$",groups = UserSignUp.class)
#Column(length = 14)
private String username;
// 密码
#Pattern(regexp = "^[0-9a-zA-Z!##$%^&*.]{6,25}$")
#Column(length = 25)
private String password;
// 邮箱
#Email
private String email;
// 电话号码
#Pattern(regexp = "^\\d{11}$",groups = UserSignUp.class)
#Column(length = 11)
private String phoneNumber;
// 所属用户组
private byte userGroup;
RequestHandler code
#PostMapping(value = "/doSignUp")
public FOResponse doSignUp(#RequestBody User user,
BindingResult result,
#RequestParam String verificationCode,
HttpSession session){...}

Ajax gets only the first object from a list got from the controller

I just started working with Java for web and I have this basic Quizz project where I integrated ajax.
In spring I have a controller which returns a list of answer objects based on a question id.
#RequestMapping(value = "/view-answers/{id}", method = RequestMethod.GET, produces = "application/json")
#SuppressWarnings("unchecked")
public #ResponseBody List<Answer> viewAnswers(#PathVariable int id, Model model){
// TODO: Get all quizzes
List<Answer> answers = answerService.findByQuestionId(id);
return answers;
}
Using this ajax fuction I retrieve the data from the controller with only one problem: It gets only the first object in full and the rest of the objects are just ID`s of the objects.
// DO GET
function ajaxGet(){
var questionID = $(".questionID").val();
$.ajax({
type : "GET",
url : "/view-answers/"+questionID,
dataType: 'json',
headers: {
Accept: 'application/json'
},
success: function(answers){
$('#answersList .answersUl').empty();
var ansList = "";
console.log(answers);
$.each(answers, function(i, answer){
var answer = i + "." + answer.answer + "<br />";
$('#answersList .answersUl ').append(answer);
});
console.log("Success: ", answers);
},
error : function(e) {
$("#getResultDiv").html("<strong>Error! Something went wrong.</strong>");
console.log("ERROR: ", e);
}
});
}
It can be a problem with my controller function? The findByQuestionId function is this:
#Override
public List<Answer> findByQuestionId(int question_id) {
Session session = sessionFactory.openSession();
session.beginTransaction();
Question question = session.find(Question.class, question_id);
List<Answer> answers = question.getAnswers();
session.getTransaction().commit();
//Close the session
session.close();
return answers;
}
This is what I'm getting with ajax right now:
The important part of my entities:
Quizz:
#Entity
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "quizz_id")
public class Quizz {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int quizz_id;
private String title;
private String description;
private int nr_participanti;
private int timp_disp;
private int nr_intrebari;
#OneToMany(mappedBy = "quizz", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#Fetch(value = FetchMode.SUBSELECT)
private List<Question> questions;
Question:
#Entity
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class Question {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String titlu;
#ManyToOne
private Quizz quizz;
#OneToMany(mappedBy = "question", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#Fetch(value = FetchMode.SUBSELECT)
private List<Answer> answers;
Answer:
#Entity
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "answer_id")
public class Answer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int answer_id;
private String answer;
private boolean corect;
#ManyToOne
private Question question;
I assume that it's a problem of lazy loading the related Answer objects in your service bean. Since you seem to use Hibernate the list of answers returned by question.getAnswers() may not eagerly fetch all answers related to the question. Hibernate loads one-to-many relations lazily by default. You close the Hibernate session at the end of the service method findByQuestionId and therefore it is not possible to load the remaining answers as soon as the list is iterated on when generating the response of the controller.
You could try the following in your service:
List<Answer> answers = question.getAnswers();
List<Answer> loadedAnswers = answers.stream().collect(Collectors.toList());
This will iterate the list of answers returned for the question relation immediately and add all answers to another transient list. Then it is safe to close the Hibernate session afterwards.
For anyone that has the same problem or somehow finds this question. The problem was indeed in my Entities.
For each entity I had to add two annotations:
#JsonManagedReference is the forward part of reference – the one that gets serialized normally.
#JsonBackReference is the back part of reference – it will be omitted from serialization.
Therefore, I annotate ManyToOne objects with #JsonManagedReference and OneToMany lists objects with #JsonBackReference. This was the only part that was missing in order for this to work.

Tapestry 5.4 URL rewriting and SEO URLs

i'm writing a web application in tapestry.
In my application i want to use friendly urls. Now i'm able to to render the url page like this:
http://localhost:8080/page/page-name
wat i want to do is to render URLs like this:
http://localhost:8080/page-name
All pages are stored on a Postgresql DB.
I'm currently using Tapestry 5.4-beta16 and i've already read the tapestry documentation:
http://tapestry.apache.org/url-rewriting.html
http://blog.tapestry5.de/index.php/2010/09/06/new-url-rewriting-api/
Now, this is the Class for list all pages stored on the DB (Only for test)
public class Pages {
#Inject
private Session session;
#Property
List<it.garuti.tapestrycms.entities.Pagine> pagine;
#Property
private it.garuti.tapestrycms.entities.Pagine pagina;
void setupRender() {
pagine = session.createCriteria(it.garuti.tapestrycms.entities.Pagine.class).list();
}
}
And this is the class for show the page content:
public class Page {
#Property
private Page page;
#Inject
private Logger logger;
#Inject
private Session session;
#Inject
Request request;
#InjectPage
Index index;
#Property
private String slug;
void onActivate(String slug) {
this.slug = slug;
}
Object onActivate() {
if (session.createCriteria(Pagine.class)
.add(Restrictions.eq("slug", slug)).uniqueResult() == null)
return new HttpError(404, "Resource not found");
return null;
}
String onPassivate() {
return slug;
}
void setupRender() {
page = (Pages) session.createCriteria(Pages.class)
.add(Restrictions.eq("slug", slug)).uniqueResult();
}
}
And finally the Entity for Pages:
#Entity
#Table(name = "pages", schema = "public")
public class Pages implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "pagine_seq")
#SequenceGenerator( name= "pagine_seq", sequenceName = "pagine_id_seq")
#Column(name = "id", unique = true, nullable = false)
private long id;
#Column(name = "titolo", nullable = false, length = 60, unique = true)
private String titolo;
#Column(name = "slug", nullable = false, length = 60, unique = true)
private String slug;
#Column(name = "contenuto", nullable = false, columnDefinition = "TEXT")
private String contenuto;
#Column(name = "data_creazione", nullable = false)
private Date dataCreazione;
#Column(name = "data_modifica")
private Date dataModifica;
#Column(name = "stato", nullable = false)
private String stato;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "utente_id", nullable = false)
private Users user;
getter and setter...
....
}
Tank You
Lorenzo
There's a special case in tapestry when your page class has the name Index it will not include the page name in the URL. So if you rename the class Page to Index I think you'll achieve what you want without requiring any explicit url rewriting

Resources