今天用springboot+themeleaf+hibernate做项目,用ajax实现前端后台交互,却意外地发现这种错误,搞了一个下午,尝试过百度的多种方法,都宣告失败,直到看到这篇文章才有所觉悟(http://www.cnblogs.com/sxdcgaq8080/p/5765392.html),这只是原因之一;
1 . 错误信息:
at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:149) ~[jackson-databind-2.8.8.jar:2.8.8]
at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:112) ~[jackson-databind-2.8.8.jar:2.8.8]
at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:25) ~[jackson-databind-2.8.8.jar:2.8.8]
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:704) ~[jackson-databind-2.8.8.jar:2.8.8]
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:690) ~[jackson-databind-2.8.8.jar:2.8.8]
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155) ~[jackson-databind-2.8.8.jar:2.8.8]
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:704) ~[jackson-databind-2.8.8.jar:2.8.8]
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:690) ~[jackson-databind-2.8.8.jar:2.8.8]
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155) ~[jackson-databind-2.8.8.jar:2.8.8]
错因分析:
原因1:多对一映射属性混杂
原因2:response回来一个或多个连接数据库的实体类(这是最常见的错因,详细分析看最后)
这样确实是不会报上面开头的错误,但是用完ajax你会发现,有关这个被@JsonIgnore注解的属性在前端返回的是undefined,也就是说,用@JsonIgnore会造成备注解的属性数据丢失,因此,@JsonIgnore根本不是我们想要的解决方案。
请大家看一下这篇文章的作者是怎么想的(http://www.cnblogs.com/sxdcgaq8080/p/5765392.html),看完之后我有所觉悟,我发一下我之前错误时候的代码,看看你们能不能找到错误。
model---OrderdetailVO
public class OrderdetailVO {
private Integer id;
private Integer orderId;
private Integer foodCount;
private Integer foodId;
private FoodVO myFoodVO;
private OrdersVO ordersVO;
/*@JsonIgnore*/
public FoodVO getMyFoodVO() {
return myFoodVO;
}
public void setMyFoodVO(FoodVO myFoodVO) {
this.myFoodVO = myFoodVO;
}
public OrderdetailVO() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getFoodId() {
return foodId;
}
public void setFoodId(Integer foodId) {
this.foodId = foodId;
}
public Integer getOrderId() {
return orderId;
}
public void setOrderId(Integer orderId) {
this.orderId = orderId;
}
public Integer getFoodCount() {
return foodCount;
}
public void setFoodCount(Integer foodCount) {
this.foodCount = foodCount;
}
public OrdersVO getOrdersVO() {
return ordersVO;
}
public void setOrdersVO(OrdersVO ordersVO) {
this.ordersVO = ordersVO;
}
}
public class FoodVO {
private Integer foodid;
private String foodName;
private FoodType foodtype;
private double foodPrice;
private double mprice;
private String remark;
private String foodimg;
public FoodVO() {}
public Integer getFoodid() {
return foodid;
}
public void setFoodid(Integer foodid) {
this.foodid = foodid;
}
public String getFoodName() {
return foodName;
}
public void setFoodName(String foodName) {
this.foodName = foodName;
}
public FoodType getFoodtype() {
return foodtype;
}
public void setFoodtype(FoodType foodtype) {
this.foodtype = foodtype;
}
public double getFoodPrice() {
return foodPrice;
}
public void setFoodPrice(double foodPrice) {
this.foodPrice = foodPrice;
}
public double getMprice() {
return mprice;
}
public void setMprice(double mprice) {
this.mprice = mprice;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public String getFoodimg() {
return foodimg;
}
public void setFoodimg(String foodimg) {
this.foodimg = foodimg;
}
}
@Entity
@Table(name = "foodtype")
public class FoodType implements PO {
@Id
@GeneratedValue
@Column(name = "ID")
private Integer foodTypeId;
@OneToMany(cascade=CascadeType.ALL,mappedBy="foodtype")
private Set foods;
@Column(name = "TYPENAME")
private String foodTypeName;
public FoodType() {}
public Integer getFoodTypeId() {
return foodTypeId;
}
public void setFoodTypeId(Integer foodTypeId) {
this.foodTypeId = foodTypeId;
}
public Set getFoods() {
return foods;
}
public void setFoods(Set foods) {
this.foods = foods;
}
public String getFoodTypeName() {
return foodTypeName;
}
public void setFoodTypeName(String foodTypeName) {
this.foodTypeName = foodTypeName;
}
}
$(".check-order").click(function(){
var orderId = $(this).parent().siblings().eq(0).text();
var htmlString = "";
$("#modal-content").html("");
$.ajax({
type:"POST",
dataType: "json",
async: false,
url:"/orderdetail/"+orderId,
contentType: "application/json;charset=utf-8",
data:{
},
success:function(data){
for(var i=0;i';
htmlString += orderdetail.foodVO.foodname;
htmlString += ' ';*/
/*
htmlString += ' ';
htmlString += ' ';
htmlString += ' ';
htmlString += ' ';*/
}
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert("XMLHttpRequest.status:"+XMLHttpRequest.status+"\n"+"XMLHttpRequest.readyState:"+XMLHttpRequest.readyState+"\n"
+"textStatus:"+textStatus);
}
})
$("#modal-content").html(htmlString);
$("#orderDetail").modal("show");
})
控制器:
@ResponseBody
@RequestMapping(value = "/orderdetail/{orderId}", method = RequestMethod.POST)
public List orderdetail(Model model, @PathVariable Integer orderId) {
List orderdetailVOList = new ArrayList();
List list = orderdetailDAO.getDetailByOrderId(orderId);
for (Orderdetail od : list) {
FoodVO foodVO = new FoodVO();
OrdersVO ordersVO = new OrdersVO();
OrderdetailVO vo = new OrderdetailVO();
BeanUtils.copyProperties(od.getFood(), foodVO);
BeanUtils.copyProperties(od.getOrders(), ordersVO);
// foodVO.setFoodtype(od.getFood().getFoodtype().getFoodTypeId());
vo.setId(od.getId());
vo.setFoodId(od.getFood().getFoodid());
vo.setFoodCount(od.getFoodCount());
vo.setOrderId(od.getOrders().getId());
vo.setMyFoodVO(foodVO); //通过调试知道是卡在这里出现最上面的错误信息,
//到这里,你再看看上面的model之间的联系,知道为什么死循环了吗?
vo.setOrdersVO(ordersVO);
orderdetailVOList.add(vo);
}
for (OrderdetailVO vo : orderdetailVOList) {
System.out.println();
System.out.println("==============================");
System.out.println("detailId:" + vo.getId());
System.out.println("foodcount:" + vo.getFoodCount());
System.out.println("foodId" + vo.getMyFoodVO().getFoodid());
System.out.println("foodname" + vo.getMyFoodVO().getFoodName());
System.out.println("foodprice" + vo.getMyFoodVO().getFoodPrice());
System.out.println("orderId" + vo.getOrdersVO().getId());
System.out.println("==============================");
System.out.println();
}
if (orderdetailVOList.isEmpty()) {
return null;
}
return orderdetailVOList;
}
我的死循环分析:在上面重点提到的vo.setMyFoodVO(foodVO); 那里,foodVO通过BeanUtils复制对象,看似没问题,但再看看FoodVO里面有什么属性?其中有一个private FoodType foodtype;属性,FoodType 类里面有一个private Set
解决:在VO删除不必要的属性或者改属性类型,避免vo之间互相调用,造成死循环。
出现错误,首先要定位到编译器出错位点,使用打印方式也可以,看看编译器走到哪里才会报错,找到报错的那一行,重点查看分析该代码存在的隐患或错误,深入分析该代码及其附属代码,逐步分析打印,直到找到最终结果。
原因2:返回连接数据库的实体类导致此错误,当然前提是ajax数据类型以及同步等等确保没错,ajax参数如下:
正确的ajax示例:
$.ajax({
type:"POST",
dataType:"json",
url:url, //后台url请求,处理传递的参数
async: false,
data:{
},
success:function(data){
//ajax请求成功执行该函数
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert("XMLHttpRequest.status:"+XMLHttpRequest.status+"\n"+"XMLHttpRequest.readyState:"+XMLHttpRequest.readyState+"\n"
+"textStatus:"+textStatus);
}
});
原本报错时候的控制器代码:
解决方案:(map里面放VO对象返回)
解析:由于先前map里面放的是连接数据库的实体类,故而报此错误,现在OrdersVO对象含有Orders对象的所有属性,但没有连接数据库,至于BeanUtils,这是spring自带的方法,用于在两个对象之间属性相同的字段进行复制值,不懂可以百度,现在返回的是VO的List,错误解决;