springmvc+jpa采购订单模块

一、采购订单的模型分析关系

  1. 如果是下拉列表:一般是多对一,一对一
    如果是复选框:一般是多对多,一对多
  2. 在一个页面同时操作2张表采购订单和采购订单明细
  3. 组合关系映射配置要求
    整体和部分,整体和部分不能分割,本质还是双向一对多
    一方(主表):
@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;// 组合关系,非空
  1. 页面管理:一方和多方同时管理

二、实体关系

  • 一个采购员buyer_id可以下采购多张采购订单,需要选择框
  • 一个制单员inputUser_id可以填写多张采购订单,录入人就是当前登录用户
  • 一个采购经理auditor_id可以审核多张采购订单,外键可以为空,审核的当前登录用户

三、组合关系,实体类

  • 3.1.Purchasebill组合关系的一方
/**
 * 
 * 采购订单:组合关系的一方
 * 
 */
@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”)

  • 3.2.purchasebillitem组合关系的多方实体类配置
/**
 * 
 * 采购订单明细:组合关系的多方
 * 
 */
@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;// 组合关系,非空
  • 供应商Supplier 实体类
@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;
    }

}

四、查询,展示页面

  • jsp页面
交易时间 总数量 总金额 订单状态 供应商 录入员 采购员
  • 解决没有展示数据的问题
    springmvc+jpa采购订单模块_第1张图片
    发现数据是有的但是出现了死循环,管理对象相互查询。。
  • 解决方法:在字段上加上注解
 @JsonIgnore //生成json的时候忽略这个属性
  private Purchasebill bill;// 组合关系,非空
  • 有了展示数据,展示的是object,怎么展示对象的数据
    增加formatter方法
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顶部工具栏--%>
<%--功能条--%> <%--高级查询查询条--%>
时间: - 审核状态: <%--点击查询触发js 绑定函数 发送请求数据 高级查询条件封装成对象--%> 查询

查询的是时间的区间,添加了两个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;
    }
    。。。。
    }
  • 注意时间的修改
    • 应该把vdate设计为date类型(yyyy-MM-dd),而不是datetime时间戳
    • 1.前端的日期时分秒按照0:00:00来处理,如果不对日期+1处理,结束时间是不能成功获取查询的值.
    • 如下单时间是09-30 15:00:00,而endDate输入09-30,后台获取到09-30 0:00:00
    • 2.加了一天之后进行查询,不能写<=,只能写<,如果是<=就会查询到第二天去
  • 解决方法
    org.apache.commons.lang.time.DateUtils对时间进行修改
    完成了订单的高级查询和展示

五、采购订单的添加

  • 基础添加,之加入订单,先不加入明细
    弹出模态框,展示数据是对象点属性,设置datebox和下拉框combobox
<%--添加和修改的弹出模态框--%>
交易时间: 供应商: 采购员:

效果
在这里插入图片描述下拉框的数据动态加载
查询出部门是采购部的所有员工,因为明确是采购部的员工,直接查询的时候就可以写入条件
订单的业务层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();
    }

点击提交保存,现在只能提交订单,所以需要加上订单明细数据
但是报错了
springmvc+jpa采购订单模块_第2张图片
在这里插入图片描述
因为我们设置了录入员(当前登陆)不能为空,但是前台保存的时候并没有保存所以保存

  • 解决方法
    保存的时候将当前用户存到purchasebill对象中
PurchasebillService
@Override
public void save(Purchasebill purchasebill) {
    Employee user = UserContext.getUser();
    //当前系统登陆用户就是录入员
    purchasebill.setInputUser(user);
    super.save(purchasebill);
}

六、明细的添加,明细数据的操作

  • 添加明细模块的结构
    找到easyui扩展库下载扩展插件http://www.easyui-extlib.com/ ->Datagrid-Edit -单元格编辑把相应的示例与js代码拷备下来
  • 在添加的模态框中引入即可
<%--明细数据--%>
        

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?`

效果展示
springmvc+jpa采购订单模块_第3张图片测试
保存的时候成功保存,但是没有保存产品明细
因为表单中并没有传参
springmvc+jpa采购订单模块_第4张图片
要想将明细也保存到订单对象中成功封装需要在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

springmvc+jpa采购订单模块_第5张图片
点击保存报错了
springmvc+jpa采购订单模块_第6张图片
原因是级联操作的时候双方都要找得到对方,才可以在保存订单的时候也同时将明细保存成功,现在只有一方找得到多方,订单可以找到订单明细,但是订单明细找不到订单,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);
        }

你可能感兴趣的:(springmvc+jpa采购订单模块)