springmvc+jpa采购订单模块

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

  1. 如果是下拉列表:一般是多对一,一对一
    如果是复选框:一般是多对多,一对多
  2. 在一个页面同时操作2张表采购订单和采购订单明细
  3. 组合关系映射配置要求
    整体和部分,整体和部分不能分割,本质还是双向一对多
    一方(主表):
@OneToMany(cascade = CascadeType.ALL, mappedBy = "bill", fetch = FetchType.LAZY, orphanRemoval = true)
private List<purchasebillitem> items = new ArrayList<purchasebillitem>();

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<Purchasebillitem> items = new ArrayList<Purchasebillitem>();

…
@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页面
<table id="purchasebillGrid" class="easyui-datagrid" enableHeaderClickMenu="true"
       data-options="url:'/purchasebill/page',fitColumns:true,onRowContextMenu:showMenu,singleSelect:true,pagination:true,fit:true,toolbar:'#gridTools'">
    <thead>
    <tr>
        <th width="20" field="vdate" sortable="true">交易时间</th>
        <th width="20" field="totalnum">总数量</th>
        <th width="20" field="totalamount">总金额</th>
        <th width="20" field="status" sortable="true" data-options="formatter:statusFormat">订单状态</th>
        <th width="20" field="supplier" sortable="true" data-options="formatter:nameFormat">供应商</th>
        <th width="20" field="inputUser" sortable="true" data-options="formatter:nameFormat">录入员</th>
        <th width="20" field="buyer" sortable="true" data-options="formatter:nameFormat">采购员</th>
    </tr>
    </thead>
</table>
  • 解决没有展示数据的问题
    在这里插入图片描述
    发现数据是有的但是出现了死循环,管理对象相互查询。。
  • 解决方法:在字段上加上注解
 @JsonIgnore //生成json的时候忽略这个属性
  private Purchasebill bill;// 组合关系,非空
  • 有了展示数据,展示的是object,怎么展示对象的数据
    增加formatter方法
data-options="formatter:nameFormat"

在js中调用方法展示数据,展示出关联对象的名称

function statusFormat(v) {
    if (v==0){
        return `<span style="color: mediumvioletred">待审</span>`
    }else if (v==-1){
        return `<span style="color: grey"><s style="color: #1e282c">删除</s></span>`
    } else if (v==1){
        return `<span style="color: greenyellow">已审核</span>`
    }
}
function nameFormat(v) {
    //判断名字是否存在,员工的名字是username
    return v?v.name || v.username:"";
}

展示效果
在这里插入图片描述添加高级查询

<%--grid顶部工具栏--%>
<div id="gridTools" style="padding:5px;height:auto">
    <%--功能条--%>
    <div style="margin-bottom:5px">
        <a href="#" data-method="add" class="easyui-linkbutton" iconCls="icon-add" plain="true">添加</a>
        <a href="#" data-method="update" class="easyui-linkbutton" iconCls="icon-edit" plain="true">修改</a>
        <a href="#" data-method="del" class="easyui-linkbutton" iconCls="icon-remove" plain="true">删除</a>
    </div>
    <%--高级查询查询条--%>
    <form id="querySearch">
        时间: <input name="beginDate" class="easyui-datebox" style="width:150px">
        -<input name="endDate" class="easyui-datebox" style="width:150px">
        审核状态:
        <select class="easyui-combobox" name="status"
                data-options="panelHeight:'auto',width:150"
        >
            <option value=""></option>
            <option value="0">待审</option>
            <option value="-1">作废</option>
            <option value="1">已审</option>
        </select>
        <%--点击查询触发js  绑定函数   发送请求数据  高级查询条件封装成对象--%>
        <a href="#" data-method="search" class="easyui-linkbutton" iconCls="icon-search">查询</a>
    </form>
</div>

查询的是时间的区间,添加了两个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<Purchasebill> spec = Specifications.<Purchasebill>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
<%--添加和修改的弹出模态框--%>
<div id="editDialog" class="easyui-dialog" title="功能编辑" style="width:900px;"
     data-options="iconCls:'icon-save',resizable:true,modal:true,closed:true">
    <form id="editForm" method="post">
        <input id="purchasebillId" type="hidden" name="id">
        <table cellpadding="5">
            <tr>
                <td>交易时间:</td>
                <td><input class="easyui-datebox" type="text" name="vdate"></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/findBuyer'">
                </td>
            </tr>
        </table>
    </form>
    <div style="text-align:center;padding:5px">
        <a href="javascript:void(0)" class="easyui-linkbutton" data-method="save">提交</a>
        <a href="javascript:void(0)" class="easyui-linkbutton" data-method="closeDialog">关闭</a>
    </div>
</div>

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

@Service
public class PurchasebillServiceImpl extends BaseServiceImpl<Purchasebill,Long> implements IPurchasebillService {
    @Autowired
    private EmployeeRepository employeeRepository;
    @Override
    public List<Employee> findBuyer() {
        List<Employee> list = employeeRepository.findBuyer("采购部");
        return list;
    }
    }

UtilController层用于返回展示的下拉框数据

@RequestMapping("/findBuyer")
    @ResponseBody
    public List<Employee> findBuyer(){
        return iPurchasebillService.findBuyer();
    }

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

  • 解决方法
    保存的时候将当前用户存到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代码拷备下来
  • 在添加的模态框中引入即可
<%--明细数据--%>
        <table id="itemsGrid" style="height: 300px"></table>

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?`<div style="width: 20px;height: 20px;background: ${row.product.color};" width="20px" ></div>`:'';
                        }
                    }
                },
                {//加载产品图片,不用传给后台,只做展示,不用对应字段
                    field: 'productImg', title: '图片', width: 100,
                    formatter(value,row,index){
                        if (row && row.product){
                            return row?`<img   src="${row.product.pic}" width="50px" `:'';
                        }
                    }
                },
                {//对应后台字段
                    field: 'num', title: '数量', width: 100,
                    editor: {
                        type: "numberbox",
                        options: {
                            /*只保留两位小数*/
                            precision:2,
                            required: true
                        }
                    }
                },
                {
                    field: 'price', title: '价格', width: 100,
                    editor: {
                        type: "numberbox",
                        options: {
                            precision:2,
                            required: true
                        }
                    }
                },
                {//计算小计
                    field: 'amount', title: '小计', width: 100,
                    formatter(value,row,index){
                        if (row && row.num && row.price){
                                //计算明细,截取小数点
                                return (row.num * row.price).toFixed(2);
                        }
                        return 0;
                    }
                },
                {
                    field: 'descs', title: '备注', width: 100,
                    editor: {
                        type: "text"
                    }
                }
            ];
            result.push(normal);

            return result;
        };
        //准备datagrid组件中的属性
        var options = {
            idField: "ID", //id的字段(唯一的)
            rownumbers: true, // 行号
            //fitColumns: true, //列的自适应
            singleSelect: true,
            columns: getColumns(),
            //添加工具栏
            toolbar:"#itemsTools",
            //表示开启单元格编辑功能
            enableCellEdit: true
        };
        //创建datagrid组件
        dg.datagrid(options);
    };

    //拿到插入的那一行数据的索引
    var getInsertRowIndex = function () {
        return insertPosition == "top" ? 0 : dg.datagrid("getRows").length;
    }

    //定义了一个变量,这个变量也是一个方法
    //button(按键)Bind(绑定)Event(事件)
    var buttonBindEvent = function () {
        //添加一行数据
        $("#btnInsert").click(function () {
            var targetIndex = getInsertRowIndex(), targetRow = $.extend({}, defaultRow, { ID: $.util.guid() });
            dg.datagrid("insertRow", { index: targetIndex, row: targetRow });
            dg.datagrid("editCell", { index: 0, field: "Code" });
        });
        //删除一行数据
        $("#btnRemove").click(function () {
            //获取到选中的行(这一行的数据)
            var row = dg.datagrid("getSelected");
            //这里要的是这一行的行号
            if (row){
                //得到索引
                var index = dg.datagrid("getRowIndex",row);
                dg.datagrid("deleteRow",index);
            }
        });
        /*
        $("#btnSave").click(function () {
            var rows = dg.datagrid("getRows"), len = rows.length;
            for (var i = 0; i < len; i++) {
                dg.datagrid("endEdit", i);
            }
        });
        */
    };

    //把grid初始化与事务绑定完成
    dgInit(); buttonBindEvent();

效果展示
在这里插入图片描述测试
保存的时候成功保存,但是没有保存产品明细
因为表单中并没有传参
在这里插入图片描述
要想将明细也保存到订单对象中成功封装需要在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<rows.length;i++){
                        var row = rows[i];
                        console.debug(row)
                        parma[`items[${i}].product.id`]=row.product.id;
                        parma[`items[${i}].num`]=row.num;
                        parma[`items[${i}].price`] = row.price;
                        parma[`items[${i}].descs`]=row.descs;
                    }
                    var isValid = $(this).form('validate');
                    return isValid;	// 返回false终止表单提交
                },
               /* 成功,后台返回结果*/
                success: function(data){
                    var result = JSON.parse(data);
                    if(result.success){
                        purchasebillGrid.datagrid("reload")
                    }
                    else {
                        $.messager.alert('失败',`操作失败了可能是因为:${result.msg}`,"warning");
                    }
                    //关闭弹出框
                    itsource.closeDialog();
                }
            });

        }
取得所有的行,遍历,发送正确参数
for(var i = 0;i<rows.length;i++){
    var row = rows[i];
    parma[`items[${i}].product.id`]=row.product.id;
    parma[`items[${i}].num`]=row.num;
    parma[`items[${i}].price`]=row.price;
    parma[`items[${i}].descs`]=row.descs;
}

在这里插入图片描述
点击保存报错了
在这里插入图片描述
原因是级联操作的时候双方都要找得到对方,才可以在保存订单的时候也同时将明细保存成功,现在只有一方找得到多方,订单可以找到订单明细,但是订单明细找不到订单,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<Purchasebillitem> 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);
        }
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
课程介绍 仓库管理系统主要功能有采购入库,采购退货,销售出库,销售退货,仓库盘点,库存报表,Excel导入导出,按钮级权限控制及系统日志等功能,系统采用SpringBoot ,mybatis,easyui,ajax,mssql数据库等技术开发。提供所有源代码下载,系统功能完善,可直接运行。开发环境项目开发语言:SpringBoot ,mybatis,easyui,ajax,mssql数据库项目运行环境:jdk1.8及以上版本,tomcat8.0及以上版本,sql server2005及以上版本项目开发工具: 本项目开发工具是Intellij Idea课程目标掌握SpringBoot等技术,熟悉仓库管理系统主要功能,采购入库,采购退货,销售出库,销售退货,仓库盘点,系统报表,权限控制及日志等50多门JAVA系列全套课程,包括大一新生到大四毕业的所有JAVA系列技术专业课程,项目实战,商业项目等;基础课程:JAVA初级工程师: 1、计算机基础 2、HTML语言基础 3、C语言从入门到精通+贪吃蛇游戏 4、贪吃蛇游戏 5、SQL SERVER数据库基础 6、JAVA从入门到精通+推箱子游戏+QQ即时通讯软件 7、推箱子游戏; 8、仿QQ即时通讯软件;JAVA中级工程师: 9、SQLSERVER数据库高级 10、SQLSERVER从入门到精通(基础+高级) 11、JavaScript从入门到精通, 12、JSP从入门到精通+点餐系统, 13、JSP从入门到精通+在线视频学习教育平台, 14、JSP从入门到精通+大型电商平台; 15、XML从入门到精通, 16、数据结构(JAVA版),JAVA高级工程师: 17、Oracle数据库从入门到精通, 18、ajax+jquery从入门到精通, 19、EasyUI从入门到精通,SSH框架: 20、Struts2从入门到精通课程, 21、Hibernate从入门到精通课程, 22、Spring从入门到精通课程; 23、Echarts从入门到精通, 24、Excel基于POI的导入导出工作流框架: 25、Activiti流程框架从入门到精通 26、JBPM流程框架从入门到精通SSM框架: 27、MyBatis从入门到精通 28、Spring MVC从入门到精通 29、Spring Boot入门到精通 30、Spring Cloud入门到精通面试题: 31、职业生涯规划及面试题集锦商业项目: 32、微信公众号在线支付系统 33、微信生活缴费在线支付系统 34、支付宝生活缴费在线支付系统 35、在线考试系统 36、人脸识别智能考试系统(人工智能AI) 37、仓库管理及质量追溯系统 38、房屋出租管理系统APP(身份证识别) 39、手机订餐管理系统, 40、CRM客户关系管理系统 41、大型房地产CRM销售管理系统 42、CMPP2,CMPP3移动网关系统 43、仓库管理系统(SpringBoot) 44、影院在线售票系统(仿猫眼电影)人工智能: 45、人脸识别在线考试系统 46、人脸识别系统项目实战 47、车牌识别停车场管理系统 48、身份证识别系统项目实战 49、营业执照识别系统项目实战 50、名片识别管理系统

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值