Java实验二 货物进销管理系统

实验二  货物进销管理系统

    编写一个Inventory.java完成以下功能:

    1.程序首先打开并读取Inventory.txt中记录的所有库存记录,然后读取Transactions.txt,处理这个文件中包含的事务,记录发货记录到Shipping.txt,并记录错误信息到Errors.txt中。最后更新库存到另外一个文件NewInventory.txt中。

    2.文件Inventory.txt和NewInventory.txt的每行包含一个存货记录,每条记录包含下面一些字段息,这些字段之间用一个tab分开(见后面的文件格式):

      

    3.字段Items按照从小到大的顺序写入文件的。注意Item号不必连续,如Item号为752的后面可能是800。

    4.文件Transactions.txt包含几个不同的处理记录(每行一条记录)。每条记录前面以一个大写字母开头,表示这条记录是什么类型的事务。在不同的大写字母后面是不同的信息格式。所有的字段也是以tab键分开的(见Transactions.txt文件格式)。

5.以'O'开头(Order的首字母)的事务表示这是一个发货订单,即某一种货物应该发给特定的客户。Item number和Quantity的格式如上面表格定义。Custom编号和上面的Supplier编号一致。处理一条定单记录(以'O'开头的事务)意味着从减少库存记录中相应货物的数量(减少的数量=发货单中的数量),记录发货信息到Shipping.txt中。注意:Inventory.txt中的quantity不应该小于0,如果对于某一种货物,库存的数量小于发货单的数量的话,系统应该停止处理发货单,并记录出错信息到Errors.txt。如果对于某一种货物有多个发货单,而且库存总量小于这些发货单的总和的话,系统应该按照发货单中的数量从小到大的有限原则满足客户。也就是说,对于某一种货物如果一个数量Quantity少的发货单没有处理之前,数量Quantity多的发货单永远不会被处理。(这种处理原则不受发货单记录在Transactions.txt的先后顺序影响)

6.以'R'开头的事务表示这是一个到货单记录,在'R'后面是Item number和它的数量Quanlity。处理一条到货单意味着增加库存中相应货物的数量(增加的数量=到货单中的数量)。注意:如果在Transactions.txt文件中,到货单出现在发货单之后,到货单中的货物数量可以用来填补发货单中的数量(可以理解成在Transactions.txt中,优先处理到货单)。

7.以'A'开头的事务表示向库存中增加一种新的货物(即这种货物以前库存中没有),在'A'后面是Item number,供应商supplier以及货物的描述description。处理一个新增货物记录意味着向库存中增加一个数量Quantity为0的新的Item。你可以假设在一个Transactions.txt中,新增货物记录总是出现在第一个到货单之前。

8.以'D'开头的事务表示从库存中删除一种货物,在'D'后面是Item号。删除操作总是在所有的事物处理之后才被处理,以保证对于可能出现的同一种货物的发货单的操作能在删除之前被正确处理。如果要删除的某种货物的库存量Quantity不为0的话,系统应该向Errors.txt记录出错信息。

9.文件Shipping.txt中的每一行代表给某一客户的发货信息。Shipping.txt中的每一行分别是客户编号、Item号、货物数量,它们之间用tab键分隔。如果发货单中有两条客户编号和Item编号一样的记录,在Shipping.txt中应该将这两条发货信息合并(即将它们的数量相加)。

10.Errors.txt文件包含未发送的发货记录和库存量大于0的删除记录。Errors.txt每一行包含Custom编号、Item编号以及发货单上的数量Quantity。对于删除操作,Custom编号为0,数量Quntity为库存中的Quantity.

11.实验测试数据:

Inventory.txt

Transactions.txt

需求分析:

1、首先是读入Inventory.txt文件中的库存信息,文本格式为

Itemnumber(varchar) \t Quanlity(int) \t Supplier(varchar) \t Description \r\n

既然老师贴心给出提示:在IO文件读写内容没有学习的情况下,可以将上述两个文件的每行字符串通过add()方法分别增加到两个Vector对象 stringVectorInv, stringVectorTra,然后编程实现后面的实验要求。

所以我们可以通过BufferedReader中的readLine()方法读取txt中的每一行,add到stringVectorInv数组。接着我们设计一个类,goods.java,这个类的对象就是Inventory.txt的其中每一行货物信息,

成员属性包括Itemnumber、Quanlity、Supplier、Description,成员方法是将自身信息写入文件。

然后我们可以通过在goods.java中实现一个使用stringVectorInv中存储的每一行信息来实例化对象的构造函数,这个构造函数的思路:形参是stringVectorInv其中一个元素(String),将这个元素也就是信息字符串通过\t分割开,形成strings[]数组,然后因为在Inventory.txt中存储字段的格式比较固定吧,我们应该可以直接指定this.Item_number = strings[0]、this.Supplier = strings[2]、          this.Quanlitty = Integer.parseInt(strings[1])......

货物类的设计,goods.java:

package utils;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class goods {
    public String Item_number;
    public int Quantity;
    public String description;
    public String Supplier;

    //从文本中初始化货物清单的构造函数
    public goods(String information){
        String[] strings = information.split("\t");
        this.Item_number = strings[0];
        this.Supplier = strings[2];
        this.description = strings[3];
        this.Quantity = Integer.parseInt(strings[1]);
    }

    //处理A事务的构造函数
    public goods(String item_number,String supplier,String description){
        this.Item_number = item_number;
        this.Quantity = 0;
        this.Supplier = supplier;
        this.description = description;
    }

    public void deleterror() throws IOException {
        FileWriter fw = new FileWriter("Errors.txt",true);
        BufferedWriter bw = new BufferedWriter(fw);
        StringBuffer buffer = new StringBuffer();
        buffer.append(0).append("\t").append(this.Item_number).append("\t").append(this.Quantity).append("\r\n");
        bw.write(buffer.toString());
        bw.close();
        fw.close();
    }

    public void NewInventorywrite() throws IOException {
        FileWriter fw = new FileWriter("NewInventory.txt",true);
        BufferedWriter bw = new BufferedWriter(fw);
        StringBuffer buffer = new StringBuffer();
        buffer.append(this.Item_number).append("\t").append(this.Quantity).append("\t").append(this.Supplier).append("\t").append(this.description).append("\r\n");
        bw.write(buffer.toString());
        bw.close();
        fw.close();
    }
}

 其实两个工具类的代码重复段落有点多,我都不好意思介绍了,还是能跑就行。。。成员属性其实可以都设置成private,通过设置get方法返回值,这样才能更好的体现类的封装性。这两个类的成员方法也有点呆,因为明明可以在主类中直接写入文件的。

我们在主类运行时可以定义一个Vector<goods> goodslist = new Vector<>();

利用循环将goodslist对象数组new出来,把信息一条一条填充进去,实例化出一个一个货物对象。

for(int i = 0;i <goodsnum;i++){
    goodslist.add(new goods(stringVectorInv.get(i)));
}

这样我们就拿到一个库存中货物清单。

2、接着就是需求中比较复杂的部分。事务transaction.txt文件我们如法炮制,先定义一个事务类,类名transaction.java,读取每一行并生成对应的事务对象,根据读入的strings[0]的type初始化不同的成员属性,这里提一句transaction.java的成员属性我是这么设置的:

type(varchar)、Item_number(varchar)、 supplier(varchar); Quantity(int);  Custom(varchar); description(varchar);

但是实际上不同的事务类型(O、R、A、D)对应的字段不同

O(发货事务)Item_number(varchar)、Quantity(int)、Custom(varchar)

R(到货事务)Item_number(varchar)、Quantity(int)

A(增货事务)Item_number(varchar)、 supplier(varchar)、 description(varchar)

D(删货事务)Item_number(varchar)

所以我采取的策略是在构造函数中先对读入的type属性进行判断,然后再根据不同的事务类型去决定要赋值给当前对象哪些成员属性,但其实大家都是事务对象。

事务类的设计:transaction.java

package utils;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class transaction {
    public String type;
    public String Item_number;
    public String supplier;
    public int Quantity;
    public String Custom;
    public String description;

    public transaction(String information) {
        String[] strings = information.split("\t");
        this.type = strings[0];
        switch (type){
            case "O":
                this.Item_number = strings[1];
                this.Quantity = Integer.parseInt(strings[2]);
                this.Custom = strings[3];
                break;
            case "R":
                this.Item_number = strings[1];
                this.Quantity = Integer.parseInt(strings[2]);
                break;
            case "A":
                this.Item_number = strings[1];
                this.supplier = strings[2];
                this.description = strings[3];
                break;
            case "D":
                this.Item_number = strings[1];
                break;
        }
    }

    public void OError() throws IOException {
        FileWriter fw = new FileWriter("Errors.txt",true);
        BufferedWriter bw = new BufferedWriter(fw);
        StringBuffer buffer = new StringBuffer();
        buffer.append(this.Custom).append("\t").append(this.Item_number).append("\t").append(this.Quantity).append("\r\n");
        bw.write(buffer.toString());
        bw.close();
        fw.close();
    }

    public void order() throws IOException {
        FileWriter fw = new FileWriter("Shipping.txt",true);
        BufferedWriter bw = new BufferedWriter(fw);
        StringBuffer buffer = new StringBuffer();
        buffer.append(this.Custom).append("\t").append(this.Item_number).append("\t").append(this.Quantity).append("\r\n");
        bw.write(buffer.toString());
        bw.close();
        fw.close();
    }


}
Vector<transaction> transactionlist = new Vector<>();
for(int i = 0;i<transactionnum;i++){
    transactionlist.add(new transaction(stringVectorTra.get(i)));
}

在主类中循环new出事务对象,这样我们就获得了一个事务清单 transactionlist。

仔细阅读需求,发现事务中有这么几条特殊的规则:

(1)新增货物记录(A事务)总是出现在第一个到货单之前。(2)到货单(R事务)出现在发货单之后,到货单中的货物数量可以用来填补发货单中的数量 。(3)发货(O事务)优先处理少的,库存总量小于发货单数量停止发货,并记录到Errors.txt中 (4)删除(D事务)最后处理,以保证对于可能出现的同一种货物的发货单的操作能在删除之前被正确处理。而且如果删除时货物数量不为0,要写入Error.txt中。

所以你会发现事务的处理也是有优先级的,顺序依次为 A、R、O、D。

我在主类Inventory.java中的实现顺序也是如此。

主类的事务实现这一部分内容大家可以看一看代码了,写的应该比较清楚。

先匹配A事务,增加goodslist的对象。再处理R事务,遍历goodlists查找对应要补货的goods对象,给他们的Quanlity增加补货数量。

接着是O事务,先把要发货的事务拿出来单独组成一个发货清单,再根据Quanlity字段进行排序(优先处理少的),依次遍历查找要发货的goods对象,先判断发货要求数和库存数的关系,如果库存数>=发货需求数量,可以发货就给他们的Quanlity减少发货数,记录到成功发货清单中;不能发货,也就是库存数<发货需求数量就写入Errors.txt中。

将成功发货清单中发给同一客户同一货物的记录合并,最后写入Shipping.txt中。

再然后是处理D事务,将要删除的货物删掉,如果数量不为0写入Errors.txt中。

最后根据Itemnumber字段由小到大进行排序,将goodslist写入新文件NewInventory,txt中。

接着是一些丑陋的代码,但我觉得逻辑还算清晰。

这是主类Inventory类。

//@2023.10.1 . 21:08:50
//@Author:wangyu
//log:因为一些系统配置原因,暂时无法打断点debug,会显示虚拟机断开连接,导致我查看中途变量都是sout打印出来的,T-T,不然的话我可以在控制台查看这些对象数组中的值的。

import utils.goods;
import utils.transaction;
import java.io.*;
import java.util.*;
public class Inventory {
    public static final String Inventory_path = "Inventory.txt";
    public static final String Transactions = "Transactions.txt";

    public static Vector<String> readtxt(String path) throws IOException {
        FileReader fr = new FileReader(path);
        Vector<String> stringVector = new Vector<>();
        BufferedReader bufferedReader = new BufferedReader(fr);
        String inline = bufferedReader.readLine();
        while (inline != null){
            stringVector.add(inline);
            inline = bufferedReader.readLine();
        }
        bufferedReader.close();
        fr.close();
        return stringVector;
    }

    public static class SortHelper implements Comparator {
        @Override
        public int compare(Object o1,Object o2){
            transaction t1 = (transaction) o1;
            transaction t2 = (transaction) o2;
            return t1.Quantity - t2.Quantity;
        }
    }

    public static class ItemSort implements Comparator{
        @Override
        public int compare(Object o1, Object o2) {
            goods g1 = (goods) o1;
            goods g2 = (goods) o2;
            int gi1 = Integer.parseInt(g1.Item_number);
            int gi2 = Integer.parseInt(g2.Item_number);
            return gi1-gi2;
        }
    }

    public static void main(String[] args) throws IOException {
        //读取库存文件中的信息
        Vector<String> stringVectorInv = readtxt(Inventory_path);
        System.out.println(stringVectorInv);
        //拿到库存货物对象清单
        int goodsnum = stringVectorInv.toArray().length;
        Vector<goods> goodslist = new Vector<>();
        for(int i = 0;i <goodsnum;i++){
            goodslist.add(new goods(stringVectorInv.get(i)));
        }
        //读取事务文件中的信息
        Vector<String> stringVectorTra= readtxt(Transactions);
        System.out.println(stringVectorTra);
        //拿到事务对象清单
        int transactionnum = stringVectorTra.toArray().length;
        Vector<transaction> transactionlist = new Vector<>();
        for(int i = 0;i<transactionnum;i++){
            transactionlist.add(new transaction(stringVectorTra.get(i)));
        }

        //开始处理事务
        //1.根据业务逻辑,首先处理A事务,增加新的货物对象
        for (int i=0;i<transactionnum;i++){
            if (transactionlist.get(i).type.equals("A")){
                transaction tr = transactionlist.get(i);
                goodslist.add(new goods(tr.Item_number,tr.supplier,tr.description));
            }
        }

        //2.处理R事务,到货补充货物
        for(int i=0;i<transactionlist.toArray().length;i++){
            if (transactionlist.get(i).type.equals("R")){
                for (int j=0;j<goodslist.toArray().length;j++){
                    if(transactionlist.get(i).Item_number.equals(goodslist.get(j).Item_number)){
                        goodslist.get(j).Quantity+=transactionlist.get(i).Quantity;
                    }
                }
            }
        }


        //3.处理O事务,进行发货
        Vector<transaction> orderlist = new Vector<>();
        for (int i=0;i<transactionnum;i++){
            if (transactionlist.get(i).type.equals("O")){
                //获取一个发货清单
                orderlist.add(transactionlist.get(i));
            }
        }
        orderlist.sort(new SortHelper());

        //对应发货单货号找到仓库中该货号的库存量
        Vector<transaction> successlist = new Vector<>();
        for (int i =0;i<orderlist.toArray().length;i++){
            for (int j =0;j<goodslist.toArray().length;j++){
                if(orderlist.get(i).Item_number.equals(goodslist.get(j).Item_number)){
                    if (orderlist.get(i).Quantity <= goodslist.get(j).Quantity ) {
                        System.out.println("发货成功");
                        //将发货成功的商品另外列一个清单
                        goodslist.get(j).Quantity -= orderlist.get(i).Quantity;
                        successlist.add(orderlist.get(i));
                    }
                    else {
                        //在Error.txt中写入错误信息
                        orderlist.get(i).OError();
                        System.out.println("发货失败,货物数量不足");
                        break;
                    }
                }
            }
        }

        //将给同一客户重复发货的信息合并
        for (int i =0; i<successlist.toArray().length;i++){
            for (int j =i+1;j<successlist.toArray().length;j++){
                if(successlist.get(i).Item_number.equals(successlist.get(j).Item_number)&&
                successlist.get(i).Custom.equals(successlist.get(j).Custom)){
                    successlist.get(j).Quantity +=successlist.get(i).Quantity;
                    successlist.remove(successlist.get(i));
                }
            }
        }

        //将成功发货清单中的信息写入Shipping.txt中
        for(int i=0;i<successlist.toArray().length;i++){
            successlist.get(i).order();
        }


        //处理D事务
        for (int i =0;i<transactionlist.toArray().length;i++){
            if (transactionlist.get(i).type.equals("D")){
                for (int j =0; j<goodslist.toArray().length;j++) {
                    if (transactionlist.get(i).Item_number.equals(goodslist.get(j).Item_number)){
                        if(goodslist.get(j).Quantity != 0 ){
                            System.out.println("删除失败,货物的数量不为0");
                            goodslist.get(j).deleterror();
                        }
                        else{
                            goodslist.remove(goodslist.get(j));
                        }
                    }
                }
            }
        }


        //将重置后的库存写入NewInventory.txt文件中
        //按照Item_number的编号顺序由小到大输出
        goodslist.sort(new ItemSort());
        for (int i =0;i<goodslist.toArray().length;i++){
            goodslist.get(i).NewInventorywrite();
        }
    }
}

这是一些运行结果,测试样例1就放老师给的吧,虽然这个样例没有同一客户重复订单的情况

测试样例二也就是在测试样例一中增加了一条事务:

O        17        20        4

之前是因为订单需求12+36>库存量42,现在12+20<42,所以可以将12和20发出去,但是36还是不行,根据优先处理少的原则。

运行结果也是如此,但是为什么不是3条发货记录呢?这是因为这两条发货记录是同一客户同一货物,所以在Shipping.txt中将其合并,这个样例同时验证了这两个功能。

新库存中的Item_number17的Quanlity也经过42-12-20=10被写入。

感觉这个用JDBC做来得更好,查询的时候直接select...where....就OK了,感谢观看。

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Java药品进销管理系统是一种基于Java编程语言开发的软件系统,旨在帮助药品企业实现对药品的进货、销售以及库存管理等方面的全面管理和控制。 该系统的设计主要包括以下几个模块:客户管理、供应商管理、药品管理、进货管理、销售管理、库存管理和报表统计。通过这些模块,用户可以方便地进行各项业务操作和数据查询。 在客户管理模块中,用户可以记录并管理各个客户的基本信息,如客户名称、联系方式等。在供应商管理模块中,用户可以管理药品供应商的信息,包括供应商名称、联系方式等。这些信息的录入和修改操作将非常方便,并且可以快速地查询和筛选。 药品管理模块是系统的核心,用户可以通过该模块实现对药品信息的录入、修改、查询和删除等操作。同时,系统还提供了药品信息的分类管理功能,用户可以根据不同的分类精确查询所需的药品。 进货管理模块主要负责对药品的进货操作进行管理和统计,用户可以记录进货的种类、数量、单价等信息,并自动生成进货单和进货报表。销售管理模块则负责对药品销售进行管理和统计,用户可以记录销售的种类、数量、单价等信息,并自动生成销售单和销售报表。 库存管理模块包括药品库存的实时监控和预警功能,系统会根据进货和销售的记录自动计算库存量,并提醒用户及时补货或处理过期药品等情况。 报表统计模块为用户提供了各种报表和统计功能,用户可以根据需要生成药品进货统计表、销售额统计表、库存盘点表等,以帮助用户更好地掌握经营状况和决策分析。 总之,Java药品进销管理系统凭借其功能全面、操作简便、信息准确可靠等优势,将有助于提高药品企业的管理效率和业务拓展能力。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值