【实验7-2】商城进货记录交易
【任务介绍】
1.任务描述
每个商城都需要进货,而这些进货记录整理起来很不方便,本案例要求编写一个商城进货记录交易的程序,使用字节流将商场的进货信息记录在本地的csv文件中。程序具体要求如下:
当用户输入商品编号时,后台会根据商品编号查询到相应商品信息,并打印商品信息。接着让用户输入需要进货的商品数量,程序将原有的库存数量与输入的数量相加作为商品最新的库存数量,并将商品进货的记录保存至本地的csv文件中。在csv文件中,每条记录包含商品编号、商品名称、购买数量、单价、总价、联系人等数据,每条记录的数据之间直接用英文逗号或空格分隔,每条记录之间由换行符分隔。文件命名格式为“进货记录”加上当天日期加上“.csv”后缀,如进货记录“20210611.csv”。保存文件时,需要判断本地是否存在当天的数据,如果存在则追加,不存在则新建。
2.运行结果
任务运行结果如图7-1所示。
图7-1 运行结果
运行结束后在本地生成一个“进货记录20210611.csv”文件,用Excel方式打开此文件,如图7-1所示。
【实现思路】
- 为了方便保存商品的相关信息,可以将商品信息封装为一个实体类。商品进货过程中可能会打印商品相关信息,所以需要对该实体类的toString()方法进行重写,使其能更清晰地显示商品信息,商品每次进货后要修改库存数量,需要在实体类中编写一个操作库存数量的方法。
- 对于一个超市,首先会有很多商品,商品需要不断进货。这里我们需要创建一个集合用于模拟超市仓库,然后向集合中添加有具体信息的商品对象,这样一个超市就有了商品。
- 管理员进货是通过在控制台键盘输入商品编号和购买数量的方式进行的,如果商品编号正确,且购买数量也正常,则商品进货成功,并将此商品的进货信息保存到csv文件中,同时要将库存数量增加。
- 查询商品信息时,可以通过Scanner类的nextInt()方法从控制台获取商品编号,之后根据这个编号到库存中查询此商品的信息,如果查到了商品的信息,从控制台获取进货的数量之后,将此商品的所有信息进行封装。
- 将商品的销售信息写入到csv文件之前,需先拼凑好csv文件名,再判断本地是否已存在此文件,这里可通过输入流尝试获取此文件的字节流,如果获取成功,则证明这个文件已存在,那么就通过输出流向文件末尾追加销售信息,如果获取失败,即异常,说明之前并没有生成当日的销售信息,则需要新建此文件。
- 将封装的信息写入csv文件中时,csv格式的文件以纯文本形式存储表格数据,写入文件时可以用图7-1的格式写入,当此类文件用Excel格式打开的时候,展现信息如图7-2所示。
- 在拼凑csv文件名时,需要获取当日的日期。这里可以通过以下代码来获取并拼凑csv文件名:
DateFormat format = new SimpleDateFormat("yyyyMMdd");// 定义日期格式
String name = "进货记录" + format.format(date) + ".csv";// 拼接文件名
【实现代码】
(1)将商品信息封装成一个实体类Good,具体如文件7-1所示。
文件7-1 Good.java
- package chapter0702;
- public class Good {
- int id;
- String name; //商品的价格
- double price; //商品的单价
- int number; //进货的数量
- double money; //总价
- String people; //审批人
- public Good(int id, String name, double price, int number, double
- money, String people) {
- this.id = id;
- this.name = name;
- this.price = price;
- this.number = number;
- this.money = money;
- this.people = people;
- }
- @Override
- public String toString() {
- String message="进货记录编号:"+id+"\n商品名称:"+name+"" +
- "\n联系人:"+people+"\n单价:"+price+"\n库存数量:"+number+"\n";
- return message;
- }
- public void setNumber(int number) {
- this.number=number;
- }
- }
在文件7-1中,第3~8行代码定义了用于标识商品的信息各种字段,,第9~17行代码定义了一个有参的构造方法,用于对象的创建和初始化,在第18~23行,重写了toString()方法,用于返回商品的详细信息。第24~26行的代码定义了一个setNumber()的方法,用于修改商品的库存量。
(2)定义RecordGoodOrder类来记录和操作商品信息,具体如文件7-2所示。
文件7-2 RecordGoodOrder.java
- package chapter0702;
- import java.util.ArrayList;
- import java.util.Scanner;
- public class RecordGoodOrder {
- //创建商品库存
- static ArrayList<Good> goodsList=new ArrayList<Good>();
- public static void main(String[] args) {
- init(); //初始化商品库存
- //将书架上所以商品信息打印出来
- for (int i = 0; i < goodsList.size(); i++) {
- System.out.println(goodsList.get(i));
- }
- while(true) {
- //获取控制台输入的信息
- Scanner scan=new Scanner(System.in);
- System.out.println("请输入商品编号");
- int goodId=scan.nextInt();
- Good stockGood=getGoodsById(goodId);
- if (stockGood != null) {// 判断是否存在此商品
- System.out.println("当前商品库存信息" + stockGood);
- System.out.print("请输入进货数量:");
- int goodNumber = scan.nextInt();
- // 将输入信息封装成Good对象
- Good good = new Good(stockGood.id, stockGood.name,
- stockGood.price, goodNumber, stockGood.price
- * goodNumber, stockGood.people);
- FileUtil.saveGoods(good);// 将本条数据保存至本地文件
- // 修改库存
- stockGood.setNumber(stockGood.number + goodNumber);
- } else {
- System.out.println("商品编号输入错误!");
- }
- }
- }
- /*
- * 初始化商品库存的信息 将商品存入库存
- */
- private static void init() {
- Good good1=new Good(1001,"百事可乐",4.5,100,450,"张三");
- Good good2=new Good(1002,"可口可乐",4,100,400,"李四");
- Good good3=new Good(1003,"百事雪碧",3.8,100,380,"张三");
- goodsList.add(good1);
- goodsList.add(good2);
- goodsList.add(good3);
- }
- /*
- * 根据输入的商品编号查找商品信息,循环遍历库存中商品信息,找到商品编号相等的取出
- */
- private static Good getGoodsById(int goodId) {
- for (int i = 0; i < goodsList.size(); i++) {
- Good thisGood=goodsList.get(i);
- if (goodId==thisGood.id) {
- return thisGood;
- }
- }
- return null;
- }
- }
在文件7-8中,第6行代码创建了ArrayList类型的全局变量作为商品的仓库。第39~46代码,初始化了商品信息,向ArrayList中添加了3种商品的信息,并在第10~12行代码中,通过for循环进行展示。第13~34行代码使用while循环来获取和处理用户输入信息,每次循环先由第16~17行代码,从控制台获取商品编号的数据,再由第49~57行的代码,根据商品编号查询到商品信息,当获得的商品信息不为空时,可从第21~22代码获得购买的数量,可通过24~29的代码,将所有数据封装,再利用第27行代码,调用FileUtil类中的saveGoods()方法,将其保存至本地。最后在第29行代码中调用setNumber()方法,修改库存。
(3)定义工具类FileUtil保存商品信息,具体如文件7-3所示。
文件7-3 FileUtil.java
- package chapter0702;
- import java.io.BufferedOutputStream;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.text.DateFormat;
- import java.text.SimpleDateFormat;
- import java.util.Date;
- /**
- * 工具类
- */
- public class FileUtil {
- public static final String SEPARATE_FIELD = ",";// 字段分隔 英文逗号
- public static final String SEPARATE_LINE = "\r\n";// 行分隔
- /**
- * 保存商品信息
- */
- public static void saveGoods(Good good) {
- // 判断本地是否存在此文件
- Date date = new Date();
- // 定义日期格式
- DateFormat format = new SimpleDateFormat("yyyyMMdd");
- // 拼接文件名
- String name = "进货记录" + format.format(date) + ".csv";
- InputStream in = null;
- try {
- in = new FileInputStream(name);// 判断本地是否存在此文件
- if (in != null) {
- in.close();// 关闭输入流
- // 可获取输入流,则存在文件,采取修改文件方式
- createFile(name, true, good);
- }
- } catch (FileNotFoundException e) {
- // 输入流获取失败,则不存在文件,采取新建新文件方式
- createFile(name, false, good);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- /**
- * 将进货记录的信息保存到本地,可通过label标识来判断是修改文件还是新建文件
- * @param name 文件名
- * @param label 文件已存在的标识 true:已存在则修改; false:不存在则新建
- * @param good 商品信息
- */
- public static void createFile(String name,boolean label,Good good) {
- BufferedOutputStream out = null;
- StringBuffer sbf = new StringBuffer();// 拼接内容
- try {
- if (label) {// 当已存在当天的文件,则在文件内容后追加
- // 创建输出流,用于追加文件
- out = new BufferedOutputStream(new FileOutputStream(name, true));
- } else {// 不存在当天文件,则新建文件
- // 创建输出流,用于保存文件
- out = new BufferedOutputStream(new FileOutputStream(name));
- String[] fieldSort = new String[] { "商品编号", "商品名称", "购买数量",
- "单价", "总价", "联系人" };// 创建表头
- for (String fieldKye : fieldSort) {
- // 新建时,将表头存入本地文件
- sbf.append(fieldKye).append(SEPARATE_FIELD);
- }
- }
- sbf.append(SEPARATE_LINE);// 追加换行符号
- sbf.append(good.id).append(SEPARATE_FIELD);
- sbf.append(good.name).append(SEPARATE_FIELD);
- sbf.append(good.number).append(SEPARATE_FIELD);
- sbf.append((double) good.price).append(SEPARATE_FIELD);
- sbf.append((double) good.money).append(SEPARATE_FIELD);
- sbf.append(good.people).append(SEPARATE_FIELD);
- String str = sbf.toString();
- byte[] b = str.getBytes();
- for (int i = 0; i < b.length; i++) {
- out.write(b[i]);// 将内容写入本地文件
- }
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- try {
- if (out != null)
- out.close();// 关闭输出流
- } catch (Exception e2) {
- e2.printStackTrace();
- }
- }
- }
- }
在文件7-3中,当saveGoods()方法被调用时,获取当前日期并格式化后,拼出了文件名,再通过第29行代码尝试获取此文件的字节输入流。当能够获取输入流时,可通过第30~34行代码,先关闭输入流,再在文件末尾追加信息。当不能获取输入流时则抛出异常,在异常处理中调用第37行代码的createFile()方法,可以通过此方法中的label参数来区分,是新建文件还是在已有文件中追加内容,如果label值是true则追加内容,如果label值是false则新建文件,并写入表头,其中进行追加还是新建操作,由构造函数的append参数来定义。然后利用65~72行代码拼出一行数据,且在每次拼接之前都要加上换行符“\r\n”,每个字段之间通过“,”分隔字段,再利用第73~76行的代码写入文件。最后80~86行代码关闭了输出流。