@OneToMany(cascade = CascadeType.ALL, mappedBy = "bill", fetch = FetchType.LAZY, orphanRemoval = true)
private List items = new ArrayList();
cascade = CascadeType.ALL级联操作最全
mappedBy = "bill"一方放弃管理多方,多方的外键字段bill_id,一方不管
orphanRemoval = true如果在一方解除了和多方的关系,一方是可以删除掉多方
4. 多方(从表)billitem:bill_id配置为非空
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "bill_id")
private Purchasebill bill;// 组合关系,非空
/**
*
* 采购订单:组合关系的一方
*
*/
@Entity
@Table(name = "purchasebill")
public class Purchasebill extends BaseDomain {
private Date vdate;// 交易时间 -> 需要录入(时间set的时候加上@DateTimeFormat(pattern = "yyyy-MM-dd"))
private BigDecimal totalAmount; //总金额 -> 明细计算
private BigDecimal totalNum; //总数量 -> 明细计算
private Date inputTime = new Date(); //录入时间 ->当前系统时间
private Date auditorTime; //审核时间 -> 可以为空,审核时自己生成
/**
* 0待审,1已审,-1作废
*/
private Integer status = 0; //单据状态 -> 默认待审
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "supplier_id")
private Supplier supplier;// 多对一,非空 供应商(需要选择)
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "auditor_id")
private Employee auditor;// 多对一,可以为空
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "inputUser_id")
private Employee inputUser;// 多对一,非空 录入人 -> 登录用户就是录入人
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "buyer_id")
private Employee buyer;// 多对一,非空 采购员 -> 需要
// 一般组合关系使用List
@OneToMany(cascade = CascadeType.ALL, mappedBy = "bill", fetch = FetchType.LAZY, orphanRemoval = true)
private List items = new ArrayList();
…
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
public Date getVdate() {
return vdate;
}
@DateTimeFormat(pattern = "yyyy-MM-dd")
public void setVdate(Date vdate) {
this.vdate = vdate;
}
spring MVC接收封装对象的时间字段应该加上注解
@DateTimeFormat(pattern = “yyyy-MM-dd”)
最强配置级联,将关系维护交给bill字段,懒加载,孤儿删除
@OneToMany(cascade = CascadeType.ALL, mappedBy = "bill", fetch = FetchType.LAZY, orphanRemoval = true)
前台页面取值,在get方法加上注解
@JsonFormat(pattern = “yyyy-MM-dd HH:mm:ss”,timezone = “GMT+8”)
前台页面封装对象调用的set方法加上注解
@DateTimeFormat(pattern = “yyyy-MM-dd”)
/**
*
* 采购订单明细:组合关系的多方
*
*/
@Entity
@Table(name = "purchasebillitem")
public class purchasebillitem extends BaseDomain {
private BigDecimal price; //价格
private BigDecimal num; //数量
private BigDecimal amount; //小计 = 价格*数量
private String descs; //描述
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "product_id")
private Product product;// 多对一,非空 产品
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "bill_id")
@JsonIgnore //生成json的时候忽略这个属性
private Purchasebill bill;// 组合关系,非空
@Entity
@Table(name="supplier")
public class Supplier extends BaseDomain {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
交易时间
总数量
总金额
订单状态
供应商
录入员
采购员
@JsonIgnore //生成json的时候忽略这个属性
private Purchasebill bill;// 组合关系,非空
data-options="formatter:nameFormat"
在js中调用方法展示数据,展示出关联对象的名称
function statusFormat(v) {
if (v==0){
return `待审`
}else if (v==-1){
return `删除`
} else if (v==1){
return `已审核`
}
}
function nameFormat(v) {
//判断名字是否存在,员工的名字是username
return v?v.name || v.username:"";
}
<%--grid顶部工具栏--%>
查询的是时间的区间,添加了两个name属性,但是后台没有这两个字段
在查询对象中增加两个字段,标签打上时间的注解
public class PurchasebillQuery extends BaseQuery{
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date beginDate;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date endDate;
private Integer status;
@Override
public Specification creatSpec(){
Date teampDate=null;
if (endDate!=null){
teampDate = DateUtils.addDays(endDate, 1);
}
Specification spec = Specifications.and()
//property是类对象的属性,beginDate是前台传的值
.eq(status!=null,"status",status)
//小于
.lt(endDate!=null,"vdate",teampDate )
//大于等于
.ge(beginDate!=null,"vdate",beginDate )
.build();
System.out.println(endDate);
System.out.println(beginDate);
return spec;
}
。。。。
}
<%--添加和修改的弹出模态框--%>
效果
下拉框的数据动态加载
查询出部门是采购部的所有员工,因为明确是采购部的员工,直接查询的时候就可以写入条件
订单的业务层PurchasebillServiceImpl
@Service
public class PurchasebillServiceImpl extends BaseServiceImpl implements IPurchasebillService {
@Autowired
private EmployeeRepository employeeRepository;
@Override
public List findBuyer() {
List list = employeeRepository.findBuyer("采购部");
return list;
}
}
UtilController层用于返回展示的下拉框数据
@RequestMapping("/findBuyer")
@ResponseBody
public List findBuyer(){
return iPurchasebillService.findBuyer();
}
点击提交保存,现在只能提交订单,所以需要加上订单明细数据
但是报错了
因为我们设置了录入员(当前登陆)不能为空,但是前台保存的时候并没有保存所以保存
PurchasebillService
@Override
public void save(Purchasebill purchasebill) {
Employee user = UserContext.getUser();
//当前系统登陆用户就是录入员
purchasebill.setInputUser(user);
super.save(purchasebill);
}
<%--明细数据--%>
js动态生成
添加工具栏
//这段代码要写在最后面
/**
* dg: 明细的grid组件
* defaultRow:默认的行数据(表头)
*insertPosition:插入数据的位置 (bottom:下面)
*/
var dg = $("#itemsGrid"),
defaultRow = { id: "", product: "", productColor: "", productImg: "", num: 0, price: 0, amount: 0,descs:"" },
insertPosition = "bottom";
//明细的grid组件的初始化设置
var dgInit = function () {
//datagrid的列数据
var getColumns = function () {
var result = [];
var normal = [
{
field: 'product', title: '商品', width: 180,
editor: {
/*设置为下拉框*/
type: "combobox",
options: {
valueField:'id',
textField:'name',
panelHeight:"auto",
/*加载产品行数据*/
url:'/util/findAllProduct',
required: true
}
},
formatter(v){
return v?v.name:"";
}
},
{
//加载产品颜色不用传给后台,只做展示,不用对应字段
field: 'productColor', title: '颜色', width: 80,
formatter(value,row,index){
if (row && row.product){
return row?``:'';
}
}
},
{//加载产品图片,不用传给后台,只做展示,不用对应字段
field: 'productImg', title: '图片', width: 100,
formatter(value,row,index){
if (row && row.product){
return row?`
效果展示
测试
保存的时候成功保存,但是没有保存产品明细
因为表单中并没有传参
要想将明细也保存到订单对象中成功封装需要在js中,保存提交表单的时候增加参数
save(){
/*如果有id则是提交表单到修改的controller*/
var purchasebillId = $("#purchasebillId").val();
url="/purchasebill/save";
if(purchasebillId){
url="/purchasebill/update?cmd=_update";
}
/*easyui的表单提交 在form中找的方法。。*/
editForm.form('submit', {
url:url,
onSubmit: function(parma){
//得到提交表单中的所有数据
var rows = dg.datagrid("getRows")
console.debug(rows)
for(var i = 0;i
取得所有的行,遍历,发送正确参数
for(var i = 0;i
点击保存报错了
原因是级联操作的时候双方都要找得到对方,才可以在保存订单的时候也同时将明细保存成功,现在只有一方找得到多方,订单可以找到订单明细,但是订单明细找不到订单,controller层的数据测试
解决办法
在保存的时候将一方存入多方
purchasebill.getItems().forEach(e->
e.setBill(purchasebill)
);
然后就可以保存
多方明细表中添加成功,并且关联了一方ID
前台将明细封装成了一个集合,封装到了订单对象中,里面是一个个明细对象
遍历明细,并且计算每一条明细的总价,数量
然后添加到改订单中保存
//保存的controller
@RequestMapping("/save")
@ResponseBody
public SuccessBoolean save(Purchasebill purchasebill){
return saveOrUpdate(purchasebill);
}
//修改
@RequestMapping("/update")
@ResponseBody
public SuccessBoolean update(@ModelAttribute("editPurchasebill")Purchasebill purchasebill){
return saveOrUpdate(purchasebill);
}
public SuccessBoolean saveOrUpdate(Purchasebill purchasebill){
System.out.println(purchasebill);
List items = purchasebill.getItems();
BigDecimal totalNum=new BigDecimal("0");
BigDecimal totalAmonut=new BigDecimal("0");
for (Purchasebillitem item:items){
//将 一方存入多方
item.setBill(purchasebill);
//计算单个明细的小计
BigDecimal amount = item.getNum().multiply(item.getPrice());
item.setAmount(amount);
//计算产品的总数量和总价
totalNum=totalNum.add(item.getNum());
totalAmonut=totalAmonut.add(amount);
}
//将总数量与总价存入订单中
purchasebill.setTotalamount(totalAmonut);
purchasebill.setTotalnum(totalNum);
try {
//int a= 1/0;
System.out.println(purchasebill);
iPurchasebillService.save(purchasebill);
return new SuccessBoolean();
} catch (Exception e) {
e.printStackTrace();
//获取错误信息
return new SuccessBoolean(false,e.getMessage());
}
}
数据丢失问题
修改的时候,
提交表单只提交了一部分数据
但是后台的方法是save,这个是更新方法,jpa后台就更新了信息
将没有设置参数的修改为了null
解决方法:在controller层添加方法,所有操作包括修改之前都会执行先查出数据
每一次传id的方法都会先执行这个方法,很浪费性能,解决方法 js 提交请求的时候传一个String过来 判断是否有才继续执行
@ModelAttribute("editPurchasebill")
public Purchasebill beforEdit(Long id,String cmd){
if (id!=null&&"_update".equals(cmd)){
Purchasebill one = iPurchasebillService.findOne(id);
//解决n-to-n 把关联对象设置为null
one.setInputUser(null);
one.setAuditor(null);
one.setBuyer(null);
one.getItems().clear();
one.setSupplier(null);
return one;
}
return null;
}
解决了数据丢失,封装的对象变成了持久化对象,关联对象也变成了持久化对象
无法修改报错n-to-n
解决方法:将关联对象设置为空
在js中的修改方法中
如果点击了添加或者修改但是没有保存
下一次点开就有缓存数据在表单中
解决方法
加载本地数据的方法,但是本地数据为空,就相当于清空
var date =[];
dg.datagrid(“loadData”,date)
解决回显时,添加不保存会影响修改的回显
先复制一份选择的这一行
var items = […rows.items];
dg.datagrid(“loadData”,items);
加载数据的时候要注意是加载的外层grid还是内存的表单数据
修改的js代码
update(){
var rows = purchasebillGrid.datagrid("getSelected");
if(!rows){
$.messager.alert('注意','请选中再操作');
return;
}
/*先清空再回显*/
editForm.form("clear")
//加载本地数据,清空再显示,相当于删除缓存数据
/* 如果有部门,添加属性为department.id,和表单的department属性对应*/
if(rows.supplier){
/*添加属性*/
rows["supplier.id"]=rows.supplier.id;
}
if(rows.buyer){
/*添加属性*/
rows["buyer.id"]=rows.buyer.id;
}
/*将密码框组件禁用 验证禁用 */
$("*[data-edit] input").validatebox("disable");
/*将密码框的表单隐藏*/
$("*[data-edit]").hide();
//加载外层回显
editForm.form("load",rows)
editDialog.dialog("center").dialog("open");
var items = [...rows.items];
dg.datagrid("loadData",items);
}