Java SE基础知识详解第[14]期—日志框架、阶段项目

写在前面:

        每一个不曾起舞的日子,都是对生命的辜负。

        希望看到这里的每一个人都能努力学习,不负韶华,成就更好的自己。


        以下仅是个人学习过程中的一些想法与感悟,Java知识博大精深,作为初学者,个人能力有限,哪里写的不够清楚、明白,还请各位不吝指正,欢迎交流与讨论。如果有朋友因此了解了一些知识或对Java有了更深层次的理解,从而进行更进一步的学习,那么这篇文章的意义也就达到了。

目录

1.日志框架

1.1日志技术的概述

1.2日志技术体系结构

1.3Logback概述

1.4Logback快速入门

1.5Logback配置详解-输出位置、格式设置

1.6Logback配置详解-日志级别设置

2.阶段项目实战

2.1电影购票系统简介

2.2日志框架搭建、系统角色分析

2.3首页设计、登录、商家界面、用户界面实现

2.4商家-详情页设计、影片上架、退出

2.5商家-影片下架、影片修改

2.6用户-展示全部影片

2.7用户-购票功能


日志框架、阶段项目

1.日志框架

1.1日志技术的概述

日志技术具备的优势

        可以将系统执行的信息选择性的记录到指定的位置(控制台、文件中、数据库中)。

        可以随时开关的形式控制是否记录日志,无需修改源代码。

日志技术的具体优势

输出语句

日志技术

输出位置

只能是控制台

可以将日志信息写入到文件或者数据库中

取消日志

需要修改代码,灵活性较差

不需要修改代码,灵活性较好

多线程

性能较差

性能较好

1.2日志技术体系结构

        日志体系结构如下图所示。

Java SE基础知识详解第[14]期—日志框架、阶段项目_第1张图片

        日志规范:一些接口,提供给日志的实现框架设计的标准。

        日志框架:者第三方公司已经做好的日志记录实现代码,后来者直接可以拿去使用。

1.3Logback概述

        Logback是基于slf4j的日志规范实现的框架。

Logback主要分为三个技术模块:

        logback-core:logback-core 模块为其他两个模块奠定了基础,必须有。

        logback-classic:它是log4j的一个改良版本,同时它完整实现了slf4j API。

        logback-access:logback-access模块与 Tomcat 和 Jetty 等 Servlet 容器集成,以提供 HTTP 访问日志功能。

1.4Logback快速入门

        需求:导入Logback日志技术到项目中,用于纪录系统的日志信息。

分析:

        ①:在项目下新建文件夹lib(lib代表依赖库,其中存放项目中可能会用到的jar包文件)导入Logback的相关jar包到该文件夹下,并添加到项目依赖库中去。

导入jar包具体步骤如下:

        1):如下图所示,在要导入的工程中新建文件夹,起名为”lib”。

Java SE基础知识详解第[14]期—日志框架、阶段项目_第2张图片 

        2):如下图所示,将提前下载好的jar包文件全部复制,粘贴到lib文件夹下。

 

        如下图所示,在弹出的【复制】对话框中选择”重构”即可完成导入。

Java SE基础知识详解第[14]期—日志框架、阶段项目_第3张图片 

        3):如下图所示,全部选中导入的jar包,右键选择”添加为库”。

Java SE基础知识详解第[14]期—日志框架、阶段项目_第4张图片 

        在弹出的【Creat Library】对话框中选择”确定”即可完成将jar包添加到项目依赖库。

Java SE基础知识详解第[14]期—日志框架、阶段项目_第5张图片 

        4):如下图所示,每个jar包前都有下拉菜单按钮,且能查看其中详细文件,代表jar包整合进工程成功。

Java SE基础知识详解第[14]期—日志框架、阶段项目_第6张图片 

        ②:将Logback的核心配置文件logback.xml(xml文件是项目的核心配置文件,其中进行相关功能的配置和控制)直接拷贝到src目录下(必须是src下)

        ③:如下图所示,在代码中获取日志的对象。

        ④:使用日志对象LOGGER调用不同的方法在控制台/文件中输出不同的日志信息。

注:jar包是什么?

        简单来说,jar包是对写好的类进行了打包。我们可以通过将jar包放到lib目录下使用这些jar包中的类、属性和方法

        专业解释,JAR文件是Java Archive File-java档案文件的简称,是与平台无关的文件格式,基于zip文件格式将许多文件合成一个压缩文件.jar,区别是比zip多了一个 META-INF/MANIFEST.MF 文件,这个文件是在生成 JAR 文件的时候自动创建的。[1]

1.5Logback配置详解-输出位置、格式设置

        Logback日志系统的特性都是通过核心配置文件logback.xml控制的。

Logback日志输出位置、格式设置:

        通过logback.xml 中的标签可以设置输出位置和日志信息的详细格式

        通常可以设置2个日志输出位置:一个是控制台、一个是系统文件中。

        输出到控制台的配置标志如下图所示。

        输出到系统文件的配置标志如下图所示。

        logback.xml文件示例代码如下:



    
    
        
        System.out
        
            
            %d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] %c [%thread] : %msg%n
        
    

    
    
        
            %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
            utf-8
        
        
        C:/code/itheima-data.log
        
        
            
            C:/code/itheima-data2-%d{yyyy-MMdd}.log%i.gz
            
            1MB
        
    

    
    
        
        
        
    

1.6Logback配置详解-日志级别设置

日志级别

        级别程度依次是:TRACE< DEBUG< INFO

        作用:用于控制系统中哪些日志级别是可以输出的,只输出级别不低于设定级别的日志信息。

        ALL 和 OFF分别是打开全部日志信息及关闭全部日志信息。

        日志级别具体在标签的level属性中设置。 可以包含零个或多个元素,标识这个输出位置将会被本日志级别控制,可按需求在此处配置关联打印位置(控制台或文件),否则不会打印

2.阶段项目实战

2.1电影购票系统简介

电影购票系统技术选型分析:

(1)面向对象编程

        系统包含了电影对象,商家对象,客户对象,需要用到继承、多态等语法知识。

(2)使用集合容器

        系统需要提供不同的容器分别存储系统注册的用户,以及当前商家发布的电影信息。

(3)程序流程控制

        需要结合分支、循环、跳转关键字等相关操作控制程序的业务逻辑。

(4)使用常见API

        登录信息的内容比较,业务数据的分析、处理,日期时间的处理等。

2.2日志框架搭建、系统角色分析

        日志框架搭建、系统角色分析具体步骤如下:

        ① 集成日志框架、用于后期记录日志信息。

        ② 定义一个电影类Movie类,Movie类包含:片名、主演、评分、时长、票价、余票。

        ③ 系统包含2个用户角色:客户、商家。存在大量相同属性信息。

        ④ 定义User类作为父类,属性:登录名称、密码、真实名称、性别、电话、账户金额。

        ⑤ 定义Business类代表商家角色,属性:店铺名称、地址。

        ⑥ 定义Customer类代表客户角色,属性:。

        ⑦ 定义集合List用户存放系统注册的用户对象信息。

        ⑧ 定义集合Map>存放商家和其排片信息。

        ⑨ 准备一些测试数据。

2.3首页设计、登录、商家界面、用户界面实现

        首页、登录、商家界面、用户界面设计步骤如下:

        ① 首页需要包含登录,商家入驻,客户注册功能。

        ② 商家和客户可以共用一个登录功能。

        ③ 判断登录成功的用户的真实类型,根据用户类型完成对应的操作界面设计。

2.4商家-详情页设计、影片上架、退出

        商家功能-展示详情、影片上架、退出步骤如下:

        ① 展示本商家的信息和其排片情况。

        ② 提供影片上架功能:就是创建一个影片对象,存入到商家的集合中去。

        ③ 退出,需要回到登录的首页。

易混淆点:

        迭代器方法操作中间变量或原变量都不会改变原来变量的值;

        非迭代器方法会改变原来变量的值。

详细理解为:

        1、add(),remove(),set()方法操作中间变量会改变原变量的值。

        2、iterator,stream()迭代器方法操作中间变量不会改变原变量的值,

        3、需要注意,如果中间变量是基本数据类型,对这些基本数据类型的操作也不会改变原来变量的值。

        如:原变量A为:Map A,中间变量为 List B = A.get();对B的操作会改变A的值,如果再下一层中间变量Integer C=B.get(),则对C的操作不会改变B和A。

2.5商家-影片下架、影片修改

        商家功能-影片下架、影片修改步骤如下:

        ① 提供影片下架功能:其实就是从商家的集合中删除影片对象。

        ② 影片修改功能:拿到需要修改的影片对象,修改里面的数据。

2.6用户-展示全部影片

        用户功能-展示全部影片信息步骤如下:

        ①遍历全部商家和其排片信息并展示出来

2.7用户-购票功能

        用户功能-购票操作步骤如下:

        ① 用户可以选择需要购买票的商家和其电影信息。

        ② 可以选择购买的数量。

        ③ 购买成功后需要支付金额,并更新商家金额和客户金额。

        示例代码如下:

用户类

public class User {
    private String loginName; // 登录名
    private String passWord; // 登陆密码
    private String userName; // 用户姓名
    private char sex; // 性别
    private String phoneNumber; // 联系方式
    private double money; // 账户余额

    public User() {
    }

    public User(String loginName, String passWord, String userName, char sex, String phoneNumber, double money) {
        this.loginName = loginName;
        this.passWord = passWord;
        this.userName = userName;
        this.sex = sex;
        this.phoneNumber = phoneNumber;
        this.money = money;
    }

    public String getLoginName() {
        return loginName;
    }

    public void setLoginName(String loginName) {
        this.loginName = loginName;
    }

    public String getPassWord() {
        return passWord;
    }

    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }
}

商家类

public class Business extends User{
    private String shopName; // 店铺名
    private String shopAddress; // 店铺地址

    public String getShopName() {
        return shopName;
    }

    public void setShopName(String shopName) {
        this.shopName = shopName;
    }

    public String getShopAddress() {
        return shopAddress;
    }

    public void setShopAddress(String shopAddress) {
        this.shopAddress = shopAddress;
    }
}

顾客类

public class Customer extends User{
}

电影类

public class Movie {
    private String name; // 电影名称
    private String actor; // 主演
    private double score; // 评分
    private double time; // 电影时长
    private double price; // 票价
    private int number; // 余票
    private Date startTime; // 放映时间

    public Movie() {
    }

    public Movie(String name, String actor, double time, double price, int number, Date startTime) { // 评分是用户评价的,不是创建对象时输入的,因此将score去掉
        this.name = name;
        this.actor = actor;
        this.time = time;
        this.price = price;
        this.number = number;
        this.startTime = startTime;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getActor() {
        return actor;
    }

    public void setActor(String actor) {
        this.actor = actor;
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }

    public double getTime() {
        return time;
    }

    public void setTime(double time) {
        this.time = time;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    public Date getStartTime() {
        return startTime;
    }

    public void setStartTime(Date startTime) {
        this.startTime = startTime;
    }
}

测试类

public class MovieSystem {
    // 创建logback日志对象,打印日志,只需要初始化一次,即可被所有程序使用
    public static final Logger LOGGER = LoggerFactory.getLogger(MovieSystem.class);

    // 定义一个静态扫描器,只需要初始化一次,即可被所有程序使用
    public static final Scanner SYS_SC = new Scanner(System.in);

    // 定义静态SimpleDateFormat对象,只需要初始化一次,即可被所有程序使用
    public static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    // 因当前登陆用户最多仅有一个,因此定义静态用户对象,代表当前已经登陆的对象,后续在使用过程中随时调用即可,无需再传User对象参数
    public static User loginUser;

    // 定义系统的数据容器用于存储用户数据
    public static final List ALL_USERS = new ArrayList<>();

    // 定义容器用于存储商家的排片信息
    public static final Map> ALL_MOVIES = new HashMap<>();

    // 准备一些测试数据
    static {
        Customer customer1 = new Customer();
        customer1.setLoginName("abc123");
        customer1.setPassWord("123456");
        customer1.setUserName("张三");
        customer1.setSex('男');
        customer1.setMoney(10000);
        customer1.setPhoneNumber("110110");
        ALL_USERS.add(customer1);

        Customer customer2 = new Customer();
        customer2.setLoginName("xyz123");
        customer2.setPassWord("123456");
        customer2.setUserName("李四");
        customer2.setSex('女');
        customer2.setMoney(500);
        customer2.setPhoneNumber("111111");
        ALL_USERS.add(customer2);

        Business business1 = new Business();
        business1.setLoginName("wcCinema");
        business1.setPassWord("123456");
        business1.setUserName("王五");
        business1.setMoney(0);
        business1.setSex('男');
        business1.setPhoneNumber("110110");
        business1.setShopAddress("火星6号2B二层");
        business1.setShopName("甜甜圈国际影城");
        ALL_USERS.add(business1);
        // 注意,商家一定需要加入到店铺排片信息中去
        List movies = new ArrayList<>();
        ALL_MOVIES.put(business1, movies);

        Business business2 = new Business();
        business2.setLoginName("dbCinema");
        business2.setPassWord("123456");
        business2.setUserName("赵六");
        business2.setMoney(0);
        business2.setSex('女');
        business2.setPhoneNumber("110110");
        business2.setShopAddress("火星8号8B八层");
        business2.setShopName("巧克力国际影城");
        ALL_USERS.add(business2);
        // 注意,商家一定需要加入到店铺排片信息中去
        List movies3 = new ArrayList<>();
        //  public Movie(String name, String actor, double time, double price, int number, Date startTime)
        try {
            Movie movie = new Movie("阿甘正传", "汤姆汉克斯", 120, 100, 10, sdf.parse("2022-05-16 16:30:00"));
            Movie movie2 = new Movie("肖申克的救赎", "安迪", 120, 100, 10, sdf.parse("2022-05-16 16:30:00"));
            movies3.add(movie);
            movies3.add(movie2);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        ALL_MOVIES.put(business2, movies3);
    }


    public static void main(String[] args) {
        showMain();
    }

    /**
     * create by: 全聚德在逃烤鸭、
     * description: 首页展示
     * create time: 2022/5/14 0014 10:38
     *
     * @param
     * @return void
     */
    private static void showMain() {
        System.out.println("========wc电影首页=========");
        while (true) {
            System.out.println("请选择执行功能序号:1登陆\t2用户注册\t商家注册");
            String command = SYS_SC.nextLine();
            switch (command) {
                case "1":
                    // 登陆
                    login();
                    break;
                case "2":
                    // 用户注册
                    register();
                    break;
                case "3":
                    // 商家注册

                    break;
                default:
                    System.out.println("输入命令有误!请重新输入!");
            }
        }


    }

    /**
     * create by: 全聚德在逃烤鸭、
     * description: 用户注册
     * create time: 2022/5/15 0015 21:04
     *
     * @param
     * @return void
     */
    private static void register() {
    }

    /**
     * create by: 全聚德在逃烤鸭、
     * description: 用户登陆
     * create time: 2022/5/14 0014 10:46
     *
     * @param
     * @return void
     */
    private static void login() {
        System.out.println("========用户登陆=========");
        OUT:
        while (true) {
            System.out.println("请输入登陆名");
            String loginName = SYS_SC.nextLine();
            System.out.println("请输入登陆密码");
            String userPassWord = SYS_SC.nextLine();
            // 根据用户名查询用户对象
            User user = getUserByLoginName(loginName);
            if (user != null) {
                // 查询密码是否正确
                if (user.getPassWord().equals(userPassWord)) { // 密码输入正确
                    loginUser = user; // 将登陆成功的对象赋值代表当前登陆对象的给静态成员变量loginUser
                    LOGGER.info(loginUser.getLoginName() + "登陆成功!");
                    // 使用instanceof判断用户类型是用户还是商家
                    if (user instanceof Customer) { // 用户
                        showCustomerMain();
                    } else { // 否则为商家
                        showBusinessMain();
                    }
                    break;
                } else { // 密码输入错误
                    System.out.println("密码错误,请重新登陆!");
                }

            } else {
                System.out.println("用户名不存在!");
                while (true) {
                    System.out.println("请选择执行功能序号:1重新登陆\t2退出到首页");
                    String command = SYS_SC.nextLine();
                    switch (command) {
                        case "1":
                            // 重新登陆
                            continue OUT;
                        case "2":
                            // 退出到首页
                            return;
                        default:
                            System.out.println("输入命令有误!请重新输入!");
                    }
                }
            }
        }
    }

    /**
     * create by: 全聚德在逃烤鸭、
     * description: 商家页面
     * create time: 2022/5/14 0014 11:14
     *
     * @param
     * @return void
     */
    private static void showBusinessMain() {
        while (true) {
            System.out.println("===========wc电影商家界面===================");
            System.out.println(loginUser.getUserName() + (loginUser.getSex() == '男' ? "先生" : "女士" + "欢迎您进入系统"));
            System.out.println("1、展示详情:");
            System.out.println("2、上架电影:");
            System.out.println("3、下架电影:");
            System.out.println("4、修改电影:");
            System.out.println("5、退出:");

            System.out.println("请输入您要操作的命令:");
            String command = SYS_SC.nextLine();
            switch (command) {
                case "1":
                    // 展示全部排片信息
                    showBusinessInfos();
                    break;
                case "2":
                    // 上架电影信息
                    addMovie();
                    break;
                case "3":
                    // 下架电影信息
                    deleteMovie();
                    break;
                case "4":
                    // 修改电影信息
                    updateMovie();
                    break;
                case "5":
                    System.out.println(loginUser.getUserName() + "退出成功!");
                    return;
                default:
                    System.out.println("不存在该命令!!");
                    break;
            }
        }
    }

    /**
     * create by: 全聚德在逃烤鸭、
     * description: 修改上架影片
     * create time: 2022/5/16 0016 9:19
     *
     * @param
     * @return void
     */
    private static void updateMovie() {
        System.out.println("===========wc电影商家修改电影界面===================");
        // 将User对象转换为真正的Business对象(当前对象实际上就是Business对象,不存在转换失败)
        Business business = (Business) loginUser;
        // 根据商家对象作为键提取其对应的值(当前上架的排片信息)
        List movies = ALL_MOVIES.get(business);
        if (movies.size() == 0) {
            System.out.println("影院当前无放映信息");
            return;
        }
        System.out.println("请输入要修改的电影名");
        String movieName = SYS_SC.nextLine();
        // 查询是否有movieName对应的影片
        Movie movieByName = getMovieByNameStrictly(movieName);
        if (movieByName != null) { // 查询到了符合条件的电影对象
            while (true) {
                try {
                    System.out.println("请您输入修改后的电影片名:");
                    String name = SYS_SC.nextLine();
                    System.out.println("请您输入修改后的主演:");
                    String actor = SYS_SC.nextLine();
                    System.out.println("请您输入修改后的电影时长:");
                    String timeStr = SYS_SC.nextLine();
                    double time = Double.parseDouble(timeStr);
                    System.out.println("请您输入修改后的票价:");
                    String priceStr = SYS_SC.nextLine();
                    double price = Double.parseDouble(priceStr);
                    System.out.println("请您输入修改后的票数:");
                    String numberStr = SYS_SC.nextLine();
                    int number = Integer.parseInt(numberStr);
                    System.out.println("请您输入修改后的影片放映时间:");
                    String startTimeStr = SYS_SC.nextLine();
                    Date startTime = sdf.parse(startTimeStr);

                    // 全部数据格式无误,将信息set修改到Movie对象中
                    movieByName.setName(name);
                    movieByName.setActor(actor);
                    movieByName.setTime(time);
                    movieByName.setPrice(price);
                    movieByName.setNumber(number);
                    movieByName.setStartTime(startTime);
                    System.out.println(name + "影片修改成功!");
                    showBusinessInfos();
                    return; // 排片信息修改完毕,退出该方法
                } catch (NumberFormatException e) {
                    e.printStackTrace();
                    LOGGER.error("电影时长/票价/票数格式输入错误");
                } catch (ParseException e) {
                    e.printStackTrace();
                    LOGGER.error("时间格式出现错误");
                }
            }
        } else {
            System.out.println("未查询到" + movieName + "相关的影片信息");
        }


    }

    /**
     * create by: 全聚德在逃烤鸭、
     * description: 根据名称精确查询影片对象
     * create time: 2022/5/16 0016 10:37
     *
     * @param movieName
     * @return com.itheima.bean.Movie
     */
    private static Movie getMovieByNameStrictly(String movieName) {
        // 将User对象转换为真正的Business对象(当前对象实际上就是Business对象,不存在转换失败)
        Business business = (Business) loginUser;
        // 根据商家对象作为键提取其对应的值(当前上架的排片信息)
        List movies = ALL_MOVIES.get(business);
        // 遍历所有的电影对象,查询是否有该名称对应的电影对象
        for (Movie movie : movies) {
            if (movie.getName().equals(movieName)) { // 采用equals精确查询
                return movie;
            }
        }
        return null; // 遍历结束后没有查询到符合条件的影片对象,返回null
    }

    /**
     * create by: 全聚德在逃烤鸭、
     * description: 下架影片
     * create time: 2022/5/16 0016 9:18
     *
     * @param
     * @return void
     */
    private static void deleteMovie() {
        System.out.println("===========wc电影商家下架电影界面===================");
        // 将User对象转换为真正的Business对象(当前对象实际上就是Business对象,不存在转换失败)
        Business business = (Business) loginUser;
        // 根据商家对象作为键提取其对应的值(当前上架的排片信息)
        List movies = ALL_MOVIES.get(business);
        if (movies.size() > 0) {
            System.out.println("请输入要下架的电影名");
            String movieName = SYS_SC.nextLine();
            // 查询是否有movieName对应的影片
            List moviesByName = getMovieByName(movieName);
            if (moviesByName == null || moviesByName.size() == 0) { // 若集合为空或集合长度为0说明未查询到对应的电影对象
                System.out.println("未查询到" + movieName + "相关的影片信息");
            } else { // 否则说明查询到符合条件的电影对象
                System.out.println("查询结果如下:");
                showMovies(moviesByName);
                while (true) {
                    System.out.print("确定要删除");
                    for (int i = 0; i < moviesByName.size(); i++) {
                        System.out.print(i == moviesByName.size() - 1 ? moviesByName.get(i).getName() : moviesByName.get(i).getName() + "、");
                    }
                    System.out.println("的排片信息?请输入是/否?");
                    String command = SYS_SC.nextLine();
                    switch (command) {
                        case "是":
                            // 将查询到的电影从当前上架的排片信息中删除
                            for (Movie movie : moviesByName) {
                                movies.remove(movie);
                            }
                            System.out.print("删除成功,已删除");
                            for (int i = 0; i < moviesByName.size(); i++) {
                                System.out.print(i == moviesByName.size() - 1 ? moviesByName.get(i).getName() : moviesByName.get(i).getName() + "、");
                            }
                            System.out.println("的排片信息!");
                            showBusinessInfos();
                            return;
                        case "否":
                            return;
                        default:
                            System.out.println("输入命令有误,请重新输入!");
                    }
                }
            }

        } else {
            System.out.println("影院当前无放映信息");
        }


    }

    /**
     * create by: 全聚德在逃烤鸭、
     * description: 根据名称模糊查询影片对象
     * create time: 2022/5/16 0016 9:32
     *
     * @param movieName
     * @return java.util.List
     */
    private static List getMovieByName(String movieName) {
        // 将User对象转换为真正的Business对象(当前对象实际上就是Business对象,不存在转换失败)
        Business business = (Business) loginUser;
        // 根据商家对象作为键提取其对应的值(当前上架的排片信息)
        List movies = ALL_MOVIES.get(business);
        // 创建影片map集合,存储所有符合条件的影片
        List moviesByName = new ArrayList<>();
        // 遍历所有的电影对象,查询是否有该名称对应的电影对象
        for (Movie movie : movies) {
            if (movie.getName().contains(movieName)) { // 采用contains查询而不是equals,可以进行模糊查询,输入影片部分名称即可查询出影片,无需精确查询
                moviesByName.add(movie); // 将查询到的影片信息加入到集合中
            }
        }
        return moviesByName; // 遍历结束后将获取的影片集合返回
    }

    /**
     * create by: 全聚德在逃烤鸭、
     * description: 上架影片
     * create time: 2022/5/15 0015 20:26
     *
     * @param
     * @return void
     */
    private static void addMovie() {
        System.out.println("===========wc电影商家上架电影界面===================");
        // 将User对象转换为真正的Business对象(当前对象实际上就是Business对象,不存在转换失败)
        Business business = (Business) loginUser;
        // 根据商家对象作为键提取其对应的值(当前上架的排片信息)
        List movies = ALL_MOVIES.get(business);
        while (true) {
            try {
                System.out.println("请您输入新片名:");
                String name = SYS_SC.nextLine();
                System.out.println("请您输入主演:");
                String actor = SYS_SC.nextLine();
                System.out.println("请您输入电影时长:");
                String timeStr = SYS_SC.nextLine();
                double time = Double.parseDouble(timeStr);
                System.out.println("请您输入票价:");
                String priceStr = SYS_SC.nextLine();
                double price = Double.parseDouble(priceStr);
                System.out.println("请您输入票数:");
                String numberStr = SYS_SC.nextLine();
                int number = Integer.parseInt(numberStr);
                System.out.println("请您输入影片放映时间:");
                String startTimeStr = SYS_SC.nextLine();
                Date startTime = sdf.parse(startTimeStr);

                // 全部数据格式无误,将信息封装成Movie对象,加入到该商家的排片List集合中
                Movie movie = new Movie(name, actor, time, price, number, startTime);
                movies.add(movie); // 引用类型,直接通过地址改变根数据,无需再将更新后的List集合更新到该商家对应的排片信息的map集合中
                System.out.println(name + "影片添加成功!");
                showBusinessInfos();
                return; // 排片信息添加完毕,退出该方法
            } catch (NumberFormatException e) {
                e.printStackTrace();
                LOGGER.error("电影时长/票价/票数格式输入错误");
            } catch (ParseException e) {
                e.printStackTrace();
                LOGGER.error("时间格式出现错误");
            }
        }


    }

    /**
     * create by: 全聚德在逃烤鸭、
     * description: 展示当前登陆商家的详细信息
     * create time: 2022/5/15 0015 19:55
     *
     * @param
     * @return void
     */
    private static void showBusinessInfos() {
        System.out.println("===========wc电影商家详情界面===================");
        // 将User对象转换为真正的Business对象(当前对象实际上就是Business对象,不存在转换失败)
        Business business = (Business) loginUser;
        // 展示商家信息
        System.out.println(business.getShopName() + "\t\t电话:" + business.getPhoneNumber() + "\t\t地址:" + business.getShopAddress()
                + "\t\t余额:" + business.getMoney());
        // 根据商家对象作为键提取其对应的值(当前上架的排片信息)
        List movies = ALL_MOVIES.get(business);
        if (movies.size() > 0) {
            // 展示排片信息
            showMovies(movies);
        } else {
            System.out.println("影院当前无放映信息");
        }
    }

    /**
     * create by: 全聚德在逃烤鸭、
     * description: 展示集合中的电影详细信息
     * create time: 2022/5/16 0016 9:38
     *
     * @param movies
     * @return void
     */
    private static void showMovies(List movies) {
        System.out.println("片名\t\t主演\t\t时长\t\t评分\t\t放映时间\t\t票价\t\t余票数量");
        for (Movie movie : movies) {
            System.out.println(movie.getName() + "\t\t" + movie.getActor() + "\t\t" + movie.getTime() + "\t\t" + movie.getScore() + "\t\t"
                    + sdf.format(movie.getStartTime()) + "\t\t" // 将影片放映时间格式化为提前设定好的格式
                    + movie.getPrice() + "\t\t" + movie.getNumber());
        }
    }

    /**
     * create by: 全聚德在逃烤鸭、
     * description: 普通用户页面
     * create time: 2022/5/14 0014 11:14
     *
     * @param
     * @return void
     */
    private static void showCustomerMain() {
        while (true) {
            System.out.println("============wc电影客户界面===================");
            System.out.println(loginUser.getUserName() + (loginUser.getSex() == '男' ? "先生" : "女士" + "欢迎您进入系统" +
                    "\t余额:" + loginUser.getMoney()));
            System.out.println("请您选择要操作的功能:");
            System.out.println("1、展示全部影片信息功能:");
            System.out.println("2、根据电影名称查询电影信息:");
            System.out.println("3、评分功能:");
            System.out.println("4、购票功能:");
            System.out.println("5、退出系统:");
            System.out.println("请输入您要操作的命令:");
            String command = SYS_SC.nextLine();
            switch (command) {
                case "1":
                    // 展示全部排片信息
                    showAllMovies();
                    break;
                case "2":
                    break;
                case "3":
                    // 评分功能
//                    scoreMovie();
//                    showAllMovies();
                    break;
                case "4":
                    // 购票功能
                    buyMovie();
                    break;
                case "5":
                    return;
                default:
                    System.out.println("不存在该命令!!");
            }
        }
    }

    /**
     * create by: 全聚德在逃烤鸭、
     * description: 用户购票
     * create time: 2022/5/16 0016 11:16
     *
     * @param
     * @return void
     */
    private static void buyMovie() {
        System.out.println("============用户购票界面===================");
        System.out.println("请输入购票门店名称:");
        String shopName = SYS_SC.nextLine();
        // 查询是否存在该商家
        Business business = getBusinessByName(shopName);
        if (business != null) {
            // 查询此商家全部排片信息
            List movies = ALL_MOVIES.get(business);
            if (movies == null || movies.size() == 0) {
                System.out.println("该商家尚未上架任何电影");
            } else {
                System.out.println("请输入购票电影名称:");
                String movieName = SYS_SC.nextLine();
                // 从当前上架上架的电影集合中查询是否存在符合条件的电影对象
                Movie movie = getBusinessMovieByName(movies, movieName);
                // 判断是否有符合条件的电影
                if (movie != null) { // 存在
                    // 开始购买
                    while (true) {
                        try {
                            System.out.println("请输入购买数目:");
                            String numberStr = SYS_SC.nextLine();
                            int number = Integer.parseInt(numberStr);
                            // 判断该电影余票是否足够
                            if (movie.getNumber() >= number) {
//                                double money = movie.getPrice() * number; // 当前购票总费用
                                // double类型直接计算可能会出现精度丢失,使用BigDecimal.valueOf方法转换,再用multiply方法计算,最后在用doubleValue方法转换回double类型
                                double money = BigDecimal.valueOf(movie.getPrice()).multiply(BigDecimal.valueOf(number)).doubleValue(); // 当前购票总费用
                                if (loginUser.getMoney() >= money) {
                                    // 更新电影票剩余数目
                                    int ticketNumber = movie.getNumber() - number;
                                    movie.setNumber(ticketNumber);
                                    // 更新用户余额
                                    double customerMoney = loginUser.getMoney() - money;
                                    loginUser.setMoney(customerMoney);
                                    // 更新商家余额
                                    double businessMoney = business.getMoney() + money;
                                    business.setMoney(businessMoney);
                                    System.out.println(number + "张" + movieName + "电影票购买成功!,总金额为" + money + "元,当前账户余额" + loginUser.getMoney() + "元");
                                } else {
                                    System.out.println("余额不足,无法购买!");
                                }
                            } else {
                                System.out.println(movieName + "余票不足,无法购买");
                            }
                            return;
                        } catch (Exception e) {
                            e.printStackTrace();
                            System.out.println("数据格式有误,请重新输入!");
                            LOGGER.error("数据格式有误");
                        }
                    }
                } else { // 不存在
                    System.out.println("未查询到" + movieName + "相关的影片信息");
                }
            }
        } else {
            System.out.println("该商家不存在");
        }

    }

    /**
     * create by: 全聚德在逃烤鸭、
     * description: 从当前上架上架的电影集合中查询是否存在符合条件的电影对象
     * create time: 2022/5/16 0016 14:22
     *
     * @param movies    该商家当前上架的影片列表
     * @param movieName
     * @return com.itheima.bean.Movie
     */
    private static Movie getBusinessMovieByName(List movies, String movieName) {
        for (Movie movie : movies) {
            if (movie.getName().equals(movieName)) {
                return movie;
            }
        }
        return null;
    }

    /**
     * create by: 全聚德在逃烤鸭、
     * description: 根据名称查询商家对象
     * create time: 2022/5/16 0016 11:22
     *
     * @param shopName
     * @return void
     */
    private static Business getBusinessByName(String shopName) {
//        ALL_MOVIES.forEach((business, movies) -> {
//            if (business.getShopName().equals(shopName)) {
//                return business; // ALL_MOVIES中每个值都是business = {m1, m2, m3, ... }的键值对形式,没有独立的Business对象,不能直接返回,需要取出键集合,再返回
//            }
//        });
        Set businesses = ALL_MOVIES.keySet();
        // 遍历businesses集合,查询是否存在某一商家,店铺名称与输入的名称相同
        for (Business business : businesses) {
            if (business.getShopName().equals(shopName)) {
                return business; // 若存在,则将该商家对象返回
            }
        }
        return null; // 若遍历结束后仍未查询到,说明不存在,返回null
    }

    /**
     * create by: 全聚德在逃烤鸭、
     * description: 展示全部商家及其排片信息
     * create time: 2022/5/16 0016 11:05
     *
     * @param
     * @return void
     */
    private static void showAllMovies() {
        System.out.println("============用户查询全部商家及其排片信息界面===================");
        // 增强for循环仅支持Collection集合使用,map集合使用forEach循环
        ALL_MOVIES.forEach((business, movies) -> {
            System.out.println("影院名称:" + business.getShopName() + "\t\t电话:" + business.getPhoneNumber() + "\t\t地址:" + business.getShopAddress());
            showMovies(movies);
        });
    }

    /**
     * create by: 全聚德在逃烤鸭、
     * description: 根据用户名查询用户对象
     * create time: 2022/5/14 0014 10:53
     *
     * @param loginName
     * @return com.itheima.bean.User
     */
    private static User getUserByLoginName(String loginName) {
        // 遍历ALL_USERS集合,查询是否存在某一用户,用户名与输入的登录名相同
        for (User user : ALL_USERS) {
            if (user.getLoginName().equals(loginName)) {
                return user; // 若存在,则将该User对象返回
            }
        }
        return null; // 若遍历结束后仍未查询到,说明不存在,返回null
    }
}

参考文献

[1]Azoner.jar包的概念及作用[J/OL].https://blog.csdn.net/Azoner/article/details/123954904,2022-04-04/2022-05-12


写在最后:

        感谢读完!

        纵然缓慢,驰而不息!加油!

你可能感兴趣的