目录
组合关系
强聚合,聚合就是双向多对一,一对多
强:最强级联,一方放弃关系维护
单据都会用到组合关系
保存方法的时候双方都能找到对象
注意:金钱使用BigDecimal
一方的配置
cascade = CascadeType.ALL:包含所有级联(增删改)
orphanRemoval = true:孤儿删除
mappedBy = "bill":放弃关系维护
@OneToMany(cascade = CascadeType.ALL, mappedBy = "bill", fetch = FetchType.LAZY, orphanRemoval = true)
private List<Purchasebillitem> items = new ArrayList<Purchasebillitem>();
多方的配置
@ManyToOne(fetch = FetchType.LAZY, optional = false)@JoinColumn(name = "bill_id")@JsonIgnore
private Purchasebill bill;// 组合关系,非空
2.组合关系完整代码
@Entity//订单
@Table(name="purchasebill")
public class Purchasebill extends BaseDomain {
private Date vdate;//交易时间
private BigDecimal totalamount;//总金额
private BigDecimal totalnum;//数量
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone ="GMT+8" )
private Date inputtime=new Date();//录入时间
private Date auditortime;//审核时间
private Integer status=0;//单据状态
// 0 待审 1已审 -1作废 节约数据库空间
@ManyToOne(fetch = FetchType.LAZY,optional = false)
@JoinColumn(name = "supplier_id")
private Supplier supplier;//供应商
@ManyToOne(fetch = FetchType.LAZY,optional = false)
@JoinColumn(name = "auditor_id")
private Employee auditor;//审核人
@ManyToOne(fetch = FetchType.LAZY,optional = false)
@JoinColumn(name = "inputUser_id")
private Employee inputUser;//录入人
//多对一
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "buyer_id")
private Employee buyer;//采购员
// 一般组合关系使用List
@OneToMany(cascade = CascadeType.ALL, mappedBy = "bill", fetch = FetchType.LAZY, orphanRemoval = true)
//所有 级联 懒加载 解除一方的关系到多方的关系
private List<Purchasebillitem> items = new ArrayList<Purchasebillitem>();
//get set省略
}
@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)
@JoinColumn(name = "product_id")
private Product product;//产品
//多对一
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "bill_id")
@JsonIgnore //生成json的时候忽略这个属性
private Purchasebill bill;
}
//get set省略
3.页面的展示数据
#JSP
<table id="purchasebillGrid" class="easyui-datagrid" data-options="fit:true,
fixed:true,fitColumns:true,toolbar:'#tb',singleSelect:true "
url="/purchasebill/page"
iconCls="icon-save"
enableHeaderClickMenu="true"
rownumbers="true" pagination="true" >
<thead>
<tr>
<th width="20" field="vdate" sortable="true">交易时间</th>
<th width="20" field="totalamount" sortable="true">总金额</th>
<th width="20" field="totalnum" sortable="true">总数量</th>
<th width="20" field="inputtime" sortable="true">录入时间</th>
<th width="20" field="auditortime" sortable="true">审核时间</th>
<th width="20" field="status"sortable="true"
data-options="formatter:formatStatus">状态</th>
<th width="20" field="supplier"sortable="true"
data-options="formatter:formatName">供应商</th>
<th width="20" field="auditor" sortable="true">审核人</th>
<th width="20" field="inputUser" sortable="true" data-options="formatter:formatName">录入人</th>
<th width="20" field="buyer" sortable="true" data-options="formatter:formatName">采购员</th>
</tr>
</thead>
#JS
function formatName(value,row,index) {
return value?(value.name||value.username):"";
}
function formatStatus(value,row,index){
if(value==0){
return "<span style='color:red'>待审</span>";
}else if(value ==1){
return "<span style='color:green'>已审</span>";
}else{
return "<s style='color: rgba(0,0,0,0.33);'>作废</s>";
}
}
4.高级查询
1.添加按钮
<!-- 这部门是查询的功能 -->
<div id="cc" class="easyui-calendar"></div>
<form id="searchForm" action="/purchasebill/download" method="post">
日期 : <input name="beginDate" class="easyui-datebox" style="height:32px" sharedCalendar="#cc">
- <input name="endDate" class="easyui-datebox" style="height:32px" sharedCalendar="#cc">
状态 :<select class="easyui-combobox" name="status"
data-options="panelHeight:'auto'">
<option value="">--请选择--</option>
<option value="0">待审</option>
<option value="-1">作废</option>
<option value="1">已审</option>
</select>
<a href="#" data-method="search" class="easyui-linkbutton" iconCls="icon-search">查找</a>
</form>
2.补全条件拼接
public class PurchasebillQuery extends BaseQuery {
//SpringMVC接收日期的格式设置(建议写在setter上)
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date beginDate; //开始时间
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date endDate;
private Integer status;//状态
@Override
public Specification createSpecification(){
//结束时间加一天
Date tempDate = null;
if(endDate!=null){
tempDate= DateUtils.addDays(endDate,1);
}
//根据条件把数据返回即可
Specification<Purchasebill> spec = Specifications.<Purchasebill>and()
.eq(status!=null,"status",status )//等于
.ge(beginDate!=null, "vdate",beginDate) //大于等于
.lt(endDate!=null, "vdate",endDate) //小于等于
.build();
return spec;
}
//省略set/get
3.解决查询日期问题:加一天
方案一:直接结算
if(endDate != null) {
Date date = new Date(endDate.getTime() + 24 * 60 * 60 * 1000);
System.out.println("date:" + date.toLocaleString());
}
方案二:JDK
if(endDate != null) {
System.out.println("endDate:"+this.endDate.toLocaleString());
//打印结束时间
Calendar calendar = Calendar.getInstance();//Calendar日历
calendar.setTime(endDate);
//设置时间
calendar.add(Calendar.DAY_OF_MONTH, 1);
//获取到日历月中的天数加1
System.out.println("endDate:"+calendar.getTime().toLocaleString());
}
方案三:
if(endDate != null) {
Date date = DateUtils.addDays(endDate, 1);
}
5.添加采购订单
1.弹出相应的功能框
<div id="purchasebillDialog" class="easyui-dialog" title="数据操作" data-options="closed:true,modal:true" style="width:730px;padding:20px">
<form id="purchasebillForm" method="post">
<input id="purchasebillId" type="hidden" name="id">
<table cellpadding="5">
<tr>
<td>交易时间:</td>
<td><input class="easyui-datebox"name="vdate" data-options="required:true"></input>
</td>
<td>供应商:</td>
<td><input class="easyui-combobox" name="supplier.id"data-options="valueField:'id',textField:'name',
panelHeight:'auto',url:'/util/findAllSupplier'">
</td>
<td>采购员:</td>
<td><input class="easyui-combobox" name="buyer.id"data-options="valueField:'id',
textField:'username',url:'/util/getBuyer'">
</td>
</table>
</form>
</div>
<%--弹出框(表单)操作--%>
<div id="formBtns" style="float: right" >
<a href="javascript:;" data-method="save" class="easyui-linkbutton c1">确认</a>
<a href="javascript:;" onclick="$('#purchasebillDialog').dialog('close')" class="easyui-linkbutton c5">取消</a>
</div>
2.后台支持
//返回所有的供应商
@RequestMapping("/findAllSupplier")
@ResponseBody
public List<Supplier> findAllSupplier() {
return supplierService.findAll();
}
//采购员
@Query("select o from Employee o where o.department.name=?1")
List<Employee> getEmpByDept(String deptName);
List<Employee> getBuyer();
@Override
public List<Employee> getBuyer() {
return employeeRepository.getEmpByDept("采购部");
}
@RequestMapping("/getBuyer")
@ResponseBody
public List<Employee> getBuyer() {
return employeeService.getBuyer();
}
3.解决保存数据时报错
//添加
@RequestMapping("/save")
@ResponseBody
public Map<String,Object> save(Purchasebill purchasebill){
//加上当前登录用户##########################################
Employee loginUser = UserContext.getUser();
purchasebill.setInputUser(loginUser);
return saveOrUpdate(purchasebill);
}
4.数据回显
edit:function () {
//弹出表单窗口
//选中了某一条数据才删除
var row = purchasebillGrid.datagrid("getSelected");
if(row) {
//隐藏有data-save属性的元素
$("*[data-save]").hide();
//禁用有data-save属性的input元素的验证功能
$("*[data-save] input").validatebox("disableValidation");
//打开对话框
purchasebillDialog.dialog("center").dialog("open");
purchasebillForm.form("clear");//清除数据
//供应商 采购员单独 回显
if(row.supplier){
row["supplier.id"] = row.supplier.id;
}
if(row.buyer){
row["buyer.id"] = row.buyer.id;
}
//完成修改回显
purchasebillForm.form("load",row);
//单独加载咱们的数据
//复制一条数据(保证不会影响到原来的数据)
var newItems = [...row.items];
dg.datagrid("loadData",newItems);
}else{
$.messager.alert('提示信息','请选择一行再进行修改!','info');
}
},
6.明细数据的操作
http://www.easyui-extlib.com/ ->Datagrid-Edit -单元格编辑
1.引入js文件
<%--解决咱们可编辑的grid的问题(easyui一定要用我这个版本)--%>
<script src="/easyui/plugin/cellEdit/jeasyui.extensions.datagrid.getColumnInfo.js"></script>
<script src="/easyui/plugin/cellEdit/jeasyui.extensions.datagrid.editors.js"></script>
<script src="/easyui/plugin/cellEdit/jeasyui.extensions.datagrid.edit.cellEdit.js"></script>
2.拷贝,基本数据的展示
#js
var dg = $("#itemEditGrid"),
defaultRow = { product: "", productColor: "", productImage: "", num: "", price: "", amount: "", descs: "" },
insertPosition = "bottom";
//表格初始化操作
var dgInit = function () {
//表格中的列表信息
var getColumns = function () {
var result = [];
var normal = [
{
field: 'product', title: '产品', width: 180,
editor: {
type: "combobox",//编辑器类型
options: {
valueField:'id',
textField:'name',
panelHeight:'auto',
url:'/util/productList',
required: true
}
},
formatter:function(v){
return v?v.name:"";}
},
{
field: 'productColor', title: '颜色', width: 180,
formatter:function(v,r,i){
if(r && r.product){
return `<div style='width: 20px;height: 20px;background-color: ${r.product.color}'></div>`;
}
}
},
{
field: 'productImage', title: '图片', width: 180,
formatter:function(v,r,i){
if(r && r.product){
return `<img alt="没有图片" width="30px" src="${r.product.smallPic}">`;
}
}
},
{
field: 'num', title: '数量', width: 280,
editor: {
type: "numberbox",
options: {
required: false,
precision:2
}
}
},
{
field: 'price', title: '价格', width: 180,
editor: {
type: "numberbox",
precision:2
}
},
{
field: 'amount', title: '小计', width: 180,
formatter:function(v,r,i){
if(r.num && r.price){
//toFixed:保留两位小数
return (r.num * r.price).toFixed(2);
}
}
},
{
field: 'descs', title: '描述', width: 180,
editor: {
type: "text",
}
}
];
result.push(normal);
return result;
};
//这个grid的所有属性
var options = {
idField: "ID",
rownumbers: true,//行号
fitColumns: true,//自适应
//fit: true, //自适应父容器
border: true,//边框
toolbar:"#formBtns", //按钮
singleSelect: true,//单选
columns: getColumns(),//获取到grid中的列//表示开启单元格编辑功能
enableCellEdit: true
};
dg.datagrid(options);
};
//获取每次插入航的索引
//dg.datagrid("getRows").length:拿到最后一行的索引
var getInsertRowIndex = function () {
return insertPosition == "top" ? 0 : dg.datagrid("getRows").length;
}
//绑定按钮的事件
var buttonBindEvent = function () {
//添加一个注册事件
$("#btnInsert").click(function () {
//拿到要添加的数据的索引位置
var targetIndex = getInsertRowIndex(), targetRow = $.extend({}, defaultRow, { ID: $.util.guid() });
dg.datagrid("insertRow", { index: targetIndex, row: targetRow });
//index:第几行 field:操作那个字段
dg.datagrid("editCell", { index: targetIndex, field: "product" });
});
//注册一个删除事件
$("#btnRemove").click(function () {
//获取到你选中的行
var row = dg.datagrid("getSelected");
if(row){
var index = dg.datagrid("getRowIndex",row);
//把它直接从当前grid中干掉 deleteRow(index):删除一行
dg.datagrid("deleteRow",index);
}
});
};
//先执行两个方法
dgInit();
buttonBindEvent();
#Jsp:
<!-- 弹出相应的功能框 -->
<div id="purchasebillDialog" class="easyui-dialog" title="数据操作" data-options="closed:true,modal:true" style="width:730px;padding:20px">
<form id="purchasebillForm" method="post">
<input id="purchasebillId" type="hidden" name="id">
<table cellpadding="5">
<tr>
<td>交易时间:</td>
<td><input class="easyui-datebox"name="vdate" data-options="required:true"></input></td>
<td>供应商:</td>
<td><input class="easyui-combobox" name="supplier.id"
data-options="valueField:'id',textField:'name',panelHeight:'auto',url:'/util/findAllSupplier'">
</td>
<td>采购员:</td>
<td><input class="easyui-combobox" name="buyer.id"
data-options="valueField:'id',textField:'username',url:'/util/getBuyer'">
</td>
</table>
<%--##########################################################################################--%>
<table id="itemEditGrid" style="width: 650px;height: 250px">
<div id="editGridTools">
<a id="btnInsert" class="easyui-linkbutton" data-options="iconCls:'icon-add',plain:true">添加</a>
<a id="btnRemove" class="easyui-linkbutton" data-options="iconCls:'icon-remove',plain:true">删除</a>
</div>
</table>
</form>
</div>
<%--弹出框(表单)操作--%>
<div id="formBtns" style="float: right" >
<a href="javascript:;" data-method="save" class="easyui-linkbutton c1">确认</a>
<a href="javascript:;" onclick="$('#purchasebillDialog').dialog('close')" class="easyui-linkbutton c5">取消</a>
</div>
#产品下拉框支持
//拿到所有产品
@RequestMapping("/productList")
@ResponseBody
public List<Product> getProduct() {
return productService.findAll();
}
7.采购单保存----->注意处理事件提交问题(注解)
1.提交数据-->额外参数
save:function () {
var url = "/purchasebill/save";
var id = $("#purchasebillId").val();
if(id){
url = "/purchasebill/update?cmd=update";
}
purchasebillForm.form('submit', {
url:url,
// param:提交额外参数提交
onSubmit: function(param){
//1.拿到编辑明细的所有数据
var rows = dg.datagrid("getRows");
//2.遍历所有数据,拼接成咱们需要的格式的参数
//items[0].product.id=1
for(let i=0;i<rows.length;i++){
var json = rows[i];
param[`items[${i}].product.id`] = json.product.id;
param[`items[${i}].num`] = json.num;
param[`items[${i}].price`] = json.price;
param[`items[${i}].descs`] = json.descs;
}
// return false to prevent submit; 返回false阻止提交
return $(this).form('validate');
},
success:function(data){
var result = JSON.parse(data);//转成相应的json数据
if(result.success) {
//成功后刷新
$('#purchasebillGrid').datagrid('reload');
//关闭窗口
purchasebillDialog.dialog("close");
}else{
$.messager.alert('提示信息','操作失败!,原因:'+result.msg,"error");
}
purchasebillDialog.dialog('close');
}
})
}
2.后台支持
//添加或者修改 注意类型BgiDecimal
private Map<String,Object> saveOrUpdate( Purchasebill purchasebill){
Map<String,Object> map = new HashMap<>();
try {
//purchasebill(一方,采购订单)
List<Purchasebillitem> items = purchasebill.getItems();
//①.准备一个总金额与总数量
BigDecimal totalAmount = new BigDecimal("0");
BigDecimal totalNum = new BigDecimal("0");
//System.out.println("一方找多方:"+items);
for (Purchasebillitem item : items) {
item.setBill(purchasebill);
//System.out.println("多方找一方:"+item.getBill());
//multiply:乘法
item.setAmount(item.getPrice().multiply(item.getNum()));
//②.总金额与总数量相加
totalAmount=totalAmount.add(item.getAmount());
totalNum = totalNum.add(item.getNum());
}
//③.保存前设置金额与数量
purchasebill.setTotalamount(totalAmount);
purchasebill.setTotalnum(totalNum);
purchasebillService.save(purchasebill);
map.put(SUCCESS, true);
} catch (Exception e) {
e.printStackTrace();
//代表出错
map.put(SUCCESS, false);
map.put("msg", e.getMessage());
}
return map;
}
8.细节处理
1.添加时清除明细
add:function () {
//隐藏有data-save属性的元素
$("*[data-save]").show();
//禁用有data-save属性的input元素的验证功能
$("*[data-save] input").validatebox("enableValidation");
//弹出表单窗口
purchasebillForm.form("clear");//清除数据
purchasebillDialog.dialog("center").dialog("open");
//每次打开表格先清空
dg.datagrid("loadData",[]);
},
2.修改时回显明细
edit:function () {
//弹出表单窗口
//选中了某一条数据才删除
var row = purchasebillGrid.datagrid("getSelected");
if(row) {
//隐藏有data-save属性的元素
$("*[data-save]").hide();
//禁用有data-save属性的input元素的验证功能
$("*[data-save] input").validatebox("disableValidation");
//打开对话框
purchasebillDialog.dialog("center").dialog("open");
purchasebillForm.form("clear");//清除数据
//回显
if(row.supplier){
row["supplier.id"] = row.supplier.id;
}
if(row.buyer){
row["buyer.id"] = row.buyer.id;
}
//完成修改回显
purchasebillForm.form("load",row);
//单独加载咱们的数据
//复制一条数据(保证不会影响到原来的数据)
var newItems = [...row.items];
dg.datagrid("loadData",newItems);
}else{
$.messager.alert('提示信息','请选择一行再进行修改!','info');
}
},
3.n-to-n
//这里准备一个方法,所有方法执行前都会执行它
@ModelAttribute("editPurchasebill")
public Purchasebill beforeEdit(Long id, String cmd){
//有id的时候-> 修改功能
if(id!=null && "update".equals(cmd)) {
Purchasebill purchasebill = purchasebillService.findOne(id);
//把这个要修改的关联对象设置为null,可以解决n-to-n的问题
//把有关系的对象移除
purchasebill.setSupplier(null);
purchasebill.setBuyer(null);
purchasebill.getItems().clear();
return purchasebill;
}
return null;
}
9.Spring获取与设置日期
get -> @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
set -> @DateTimeFormat(pattern = "yyyy-MM-dd")