清朝云资源网

作者: 清朝云

  • 11月26日,星期二, 每天60秒读懂全世界!

    百度热搜新闻

    新闻来源:百度热搜榜

    1. 外交部回应“要求中日双方面免签” 25日外交部例行记者会上,发言人毛宁回应中日双方面免签提问时称,中方高度重视提升两国人员往来便利化水平,希望双方共同努力。

    2. 私家车撞上军用装甲车 现场曝光 近日,有网友发布了一则私家车撞上装甲车的视频。视频中私家车的车门都被撞掉了,而装甲车却毫发无损,私家车车主脸上一脸无奈。

    3. “链”味十足 向“新”前行 由中国贸促会主办的第二届中国国际供应链促进博览会将于11月26日至30日在北京举行,主题是“链接世界,共创未来”。

    4. 39岁失业后在菜市场重启人生 近日,谭家志在接受采访时提及39岁被辞退,考察后决定在菜市场重启人生,并表示为每一个经历低谷后敢于重新开始的人点赞加油。

    5. 女子发现家门锁上被贴了“磁铁” 近日,一女子发视频称自己家门锁上被贴了“磁铁”,猜测是被人踩点了;还提醒大家回家检查自己家门。

    6. 马斯克:现在还有傻子生产F-35呢 24日,马斯克在社交平台转发了中国无人机蜂群的视频,并发文:“与此同时,一些傻子还在生产F-35这样的载人战斗机。”

    7. 网友调侃黄子韬颜值被卡在了海关 近日,黄子韬在社交媒体晒出自己与多年前的对比照,并表示“下次一定比上面那个更帅”。网友:颜值被卡在了海关。

    8. 女子杀害家暴丈夫获子女和公婆谅解 日前,一女子遭丈夫近2小时殴打,持刀杀死丈夫后自首,引发讨论。因获被害人子女和公婆谅解,依法从轻处罚,法院判其入狱五年。

    9. 关晓彤一天穿了四套高定

    10. 有家暴倾向的人大多有这些特征 情绪暴力是一种隐形的家暴,容易发生情绪暴力的人一般有以下表现:只索取,不给予;爱控制,很多疑;情绪化,很反复。

    —- 百度热搜新闻 End —-

    知乎新闻

    新闻来源:知乎日榜

    标题: 什么是藻类的第二次内共生?
    链接: https://daily.zhihu.com/story/9776984
    ———————-
    标题: 为什么人类喝地球的水需要过滤,而其他任何一种地球的生物可以直接喝地球的水?
    链接: https://daily.zhihu.com/story/9777107
    ———————-
    标题: 一些病原体是如何做到操控宿主行为的?
    链接: https://daily.zhihu.com/story/9777114
    ———————-
    标题: 瞎扯 · 如何正确地吐槽
    链接: https://daily.zhihu.com/story/9777202
    ———————-

    —- 知乎新闻 End —-

    IT之家新闻

    新闻来源:ITHome之家科技新闻

    标题: 网易云音乐喊话 QQ 音乐:少一点跟随式“更新”,多一点真正的创新
    发布时间: 2024-11-25T12:46:33.683
    新闻简介: 网易云音乐今天午间发布致 QQ 音乐的公开信,要求后者“少一点跟随式“更新”,多一点真正的创新”。
    ———————-
    标题: 一抓一放、张手就来:华为 Mate 70 / X6 系列手机、MatePad Pro 13.2 英寸平板 2025 全新手势交互功能预热
    发布时间: 2024-11-25T09:17:31.113
    新闻简介: 视频中,多位角色使用了“抓握”手势,将屏幕中的画面进行截取,并最终流转至其他设备。由此来看,预计该功能将支持多设备之间的文件传输。
    ———————-
    标题: 小米:升级澎湃 OS 2 后系统将自动对应用进行重新编译,可能会造成短期内的功耗增加
    发布时间: 2024-11-25T17:07:13.543
    新闻简介: 小米澎湃 OS 官方今日发布答网友问(第二集),就澎湃 OS 的部分功能与使用体验进行解答。
    ———————-
    标题: 特斯拉 Model Y 限时交付尾款立减 1 万元,23.99 万元起
    发布时间: 2024-11-25T08:33:13.56
    新闻简介: 特斯拉中国官微今日宣布,Model Y限时交付尾款立减10000元,可叠加五年0息政策,用户需要在2024年11月25日起至12月31日(含)订购并完成交付,该活动适用于后轮驱动版、长续航全轮驱动版车型。
    ———————-
    标题: 小米 SUV 新谍照曝光:并非采用对开门设计
    发布时间: 2024-11-25T15:29:52.3
    新闻简介: 在 SU7 取得巨大成功之后,人们对小米即将到来的 SUV 也充满了期待。早前有传闻称,小米 SUV 将采用独特的对开门设计。然而最新曝光的小米 SUV 实车谍照显示,该车并未采用这一设计,至少并非所有版本都会配备对开门。
    ———————-
    标题: 小米 REDMI K80 系列手机影像配置细节公布:小米 15 同款浮动长焦、标准版主摄和 PRO 拉齐
    发布时间: 2024-11-25T10:45:53.133
    新闻简介: REDMI 产品经理胡馨心今日发文介绍了小米 REDMI K80 系列手机影像配置细节信息,她表示,新机本次相机的交付目标,就是全面对标小米 15,除了徕卡,能给的都给了。
    ———————-
    标题: 何小鹏:感谢雷军,他曾对我说“我觉得小鹏最大的问题在于你”
    发布时间: 2024-11-25T14:52:09.297
    新闻简介: 媒体“凤凰网财经”今天公布了采访小鹏汽车董事长兼CEO何小鹏的内容。何小鹏透露,自己曾在约两年前向数名行业内的朋友“取经”,目前要特别感谢小米董事长兼CEO雷军,因为他“当时讲得最直接”。
    ———————-
    标题: 网易云音乐控诉 QQ 音乐抄袭,酷狗音乐称播放器 DIY 功能是自己先做的
    发布时间: 2024-11-25T15:40:13.18
    新闻简介: 网易云音乐今天早些时候发长文公开喊话 QQ 音乐,要求后者停止剽窃式“创新”。此事引发热议后,今天下午另一个音乐平台酷狗音乐发文称:“话说,自定义播放器背景的 DIY 功能不是我先做的么,DIY 播放器大赛我也做了啊,我这个算什么式创新?”
    ———————-
    标题: 网易云音乐称正在加大力度持续扩充版权库,近期已下线大量广告位
    发布时间: 2024-11-25T16:57:09.587
    新闻简介: 针对用户关注的版权、广告及产品体验等问题,“网易云音乐小秘书”在网易云音乐评论区进行了回应。
    ———————-
    标题: 小米:K80 Pro 手机搭载全焦段旗舰三摄,达成 REDMI 影像史上三大最强
    发布时间: 2024-11-25T09:07:46.597
    新闻简介: 小米今日官宣 REDMI K80 Pro 手机搭载全焦段旗舰三摄,达成 REDMI 影像史上三大最强:最强高动态主摄,最强旗舰级浮动长焦,最强高像素超广角。
    ———————-
    标题: 显卡新王者:英伟达 RTX 5090 明年登场,4K 游戏性能被曝较 4090 提升 50~70%
    发布时间: 2024-11-25T10:32:51.24
    新闻简介: 消息源 Moore’s Law is Dead 在最新一期视频中,曝料称英伟达将于 2025 年 1 月下旬发售 GeForce RTX 5080 和 RTX 5090 两款显卡,并暗示 5090 显卡的售价低于 1999 美元。
    ———————-
    标题: 苹果 CEO 库克年内第三次来华:没有中国伙伴就没有公司今天的成就
    发布时间: 2024-11-25T10:31:17.12
    新闻简介: 据“玉渊谭天”消息,中国贸促会主办的第二届中国国际供应链促进博览会今日在北京举行。美国苹果公司首席执行官库克首次现身链博会,而这也是他在今年内第三次来华。
    ———————-

    —- IT之家新闻 End —-

  • 11月26日,星期二, 每天60秒读懂全世界!

    百度热搜新闻

    新闻来源:百度热搜榜

    1. 外交部回应“要求中日双方面免签” 25日外交部例行记者会上,发言人毛宁回应中日双方面免签提问时称,中方高度重视提升两国人员往来便利化水平,希望双方共同努力。

    2. 私家车撞上军用装甲车 现场曝光 近日,有网友发布了一则私家车撞上装甲车的视频。视频中私家车的车门都被撞掉了,而装甲车却毫发无损,私家车车主脸上一脸无奈。

    3. “链”味十足 向“新”前行 由中国贸促会主办的第二届中国国际供应链促进博览会将于11月26日至30日在北京举行,主题是“链接世界,共创未来”。

    4. 39岁失业后在菜市场重启人生 近日,谭家志在接受采访时提及39岁被辞退,考察后决定在菜市场重启人生,并表示为每一个经历低谷后敢于重新开始的人点赞加油。

    5. 女子发现家门锁上被贴了“磁铁” 近日,一女子发视频称自己家门锁上被贴了“磁铁”,猜测是被人踩点了;还提醒大家回家检查自己家门。

    6. 马斯克:现在还有傻子生产F-35呢 24日,马斯克在社交平台转发了中国无人机蜂群的视频,并发文:“与此同时,一些傻子还在生产F-35这样的载人战斗机。”

    7. 网友调侃黄子韬颜值被卡在了海关 近日,黄子韬在社交媒体晒出自己与多年前的对比照,并表示“下次一定比上面那个更帅”。网友:颜值被卡在了海关。

    8. 女子杀害家暴丈夫获子女和公婆谅解 日前,一女子遭丈夫近2小时殴打,持刀杀死丈夫后自首,引发讨论。因获被害人子女和公婆谅解,依法从轻处罚,法院判其入狱五年。

    9. 关晓彤一天穿了四套高定

    10. 有家暴倾向的人大多有这些特征 情绪暴力是一种隐形的家暴,容易发生情绪暴力的人一般有以下表现:只索取,不给予;爱控制,很多疑;情绪化,很反复。

    —- 百度热搜新闻 End —-

    知乎新闻

    新闻来源:知乎日榜

    标题: 什么是藻类的第二次内共生?
    链接: https://daily.zhihu.com/story/9776984
    ———————-
    标题: 为什么人类喝地球的水需要过滤,而其他任何一种地球的生物可以直接喝地球的水?
    链接: https://daily.zhihu.com/story/9777107
    ———————-
    标题: 一些病原体是如何做到操控宿主行为的?
    链接: https://daily.zhihu.com/story/9777114
    ———————-
    标题: 瞎扯 · 如何正确地吐槽
    链接: https://daily.zhihu.com/story/9777202
    ———————-

    —- 知乎新闻 End —-

    IT之家新闻

    新闻来源:ITHome之家科技新闻

    标题: 网易云音乐喊话 QQ 音乐:少一点跟随式“更新”,多一点真正的创新
    发布时间: 2024-11-25T12:46:33.683
    新闻简介: 网易云音乐今天午间发布致 QQ 音乐的公开信,要求后者“少一点跟随式“更新”,多一点真正的创新”。
    ———————-
    标题: 一抓一放、张手就来:华为 Mate 70 / X6 系列手机、MatePad Pro 13.2 英寸平板 2025 全新手势交互功能预热
    发布时间: 2024-11-25T09:17:31.113
    新闻简介: 视频中,多位角色使用了“抓握”手势,将屏幕中的画面进行截取,并最终流转至其他设备。由此来看,预计该功能将支持多设备之间的文件传输。
    ———————-
    标题: 小米:升级澎湃 OS 2 后系统将自动对应用进行重新编译,可能会造成短期内的功耗增加
    发布时间: 2024-11-25T17:07:13.543
    新闻简介: 小米澎湃 OS 官方今日发布答网友问(第二集),就澎湃 OS 的部分功能与使用体验进行解答。
    ———————-
    标题: 特斯拉 Model Y 限时交付尾款立减 1 万元,23.99 万元起
    发布时间: 2024-11-25T08:33:13.56
    新闻简介: 特斯拉中国官微今日宣布,Model Y限时交付尾款立减10000元,可叠加五年0息政策,用户需要在2024年11月25日起至12月31日(含)订购并完成交付,该活动适用于后轮驱动版、长续航全轮驱动版车型。
    ———————-
    标题: 小米 SUV 新谍照曝光:并非采用对开门设计
    发布时间: 2024-11-25T15:29:52.3
    新闻简介: 在 SU7 取得巨大成功之后,人们对小米即将到来的 SUV 也充满了期待。早前有传闻称,小米 SUV 将采用独特的对开门设计。然而最新曝光的小米 SUV 实车谍照显示,该车并未采用这一设计,至少并非所有版本都会配备对开门。
    ———————-
    标题: 小米 REDMI K80 系列手机影像配置细节公布:小米 15 同款浮动长焦、标准版主摄和 PRO 拉齐
    发布时间: 2024-11-25T10:45:53.133
    新闻简介: REDMI 产品经理胡馨心今日发文介绍了小米 REDMI K80 系列手机影像配置细节信息,她表示,新机本次相机的交付目标,就是全面对标小米 15,除了徕卡,能给的都给了。
    ———————-
    标题: 何小鹏:感谢雷军,他曾对我说“我觉得小鹏最大的问题在于你”
    发布时间: 2024-11-25T14:52:09.297
    新闻简介: 媒体“凤凰网财经”今天公布了采访小鹏汽车董事长兼CEO何小鹏的内容。何小鹏透露,自己曾在约两年前向数名行业内的朋友“取经”,目前要特别感谢小米董事长兼CEO雷军,因为他“当时讲得最直接”。
    ———————-
    标题: 网易云音乐控诉 QQ 音乐抄袭,酷狗音乐称播放器 DIY 功能是自己先做的
    发布时间: 2024-11-25T15:40:13.18
    新闻简介: 网易云音乐今天早些时候发长文公开喊话 QQ 音乐,要求后者停止剽窃式“创新”。此事引发热议后,今天下午另一个音乐平台酷狗音乐发文称:“话说,自定义播放器背景的 DIY 功能不是我先做的么,DIY 播放器大赛我也做了啊,我这个算什么式创新?”
    ———————-
    标题: 网易云音乐称正在加大力度持续扩充版权库,近期已下线大量广告位
    发布时间: 2024-11-25T16:57:09.587
    新闻简介: 针对用户关注的版权、广告及产品体验等问题,“网易云音乐小秘书”在网易云音乐评论区进行了回应。
    ———————-
    标题: 小米:K80 Pro 手机搭载全焦段旗舰三摄,达成 REDMI 影像史上三大最强
    发布时间: 2024-11-25T09:07:46.597
    新闻简介: 小米今日官宣 REDMI K80 Pro 手机搭载全焦段旗舰三摄,达成 REDMI 影像史上三大最强:最强高动态主摄,最强旗舰级浮动长焦,最强高像素超广角。
    ———————-
    标题: 显卡新王者:英伟达 RTX 5090 明年登场,4K 游戏性能被曝较 4090 提升 50~70%
    发布时间: 2024-11-25T10:32:51.24
    新闻简介: 消息源 Moore’s Law is Dead 在最新一期视频中,曝料称英伟达将于 2025 年 1 月下旬发售 GeForce RTX 5080 和 RTX 5090 两款显卡,并暗示 5090 显卡的售价低于 1999 美元。
    ———————-
    标题: 苹果 CEO 库克年内第三次来华:没有中国伙伴就没有公司今天的成就
    发布时间: 2024-11-25T10:31:17.12
    新闻简介: 据“玉渊谭天”消息,中国贸促会主办的第二届中国国际供应链促进博览会今日在北京举行。美国苹果公司首席执行官库克首次现身链博会,而这也是他在今年内第三次来华。
    ———————-

    —- IT之家新闻 End —-

  • 设计模式之三种工厂模式


    共计 5742 个字符,预计需要花费 15 分钟才能阅读完成。

    前言

    工厂模式是一种创建对象的设计模式,它提供了一个统一的接口来实例化对象,而不需要通过直接调用构造函数来创建。工厂模式可以根据不同的条件返回不同类的实例,从而实现对象的灵活创建。

    常见的工厂模式包括:简单工厂模式、工厂方法模式和抽象工厂模式。

    详解

    1. 简单工厂模式

    简单工厂模式,就像它的名字一样,非常简单。只需要创建一个工厂类,根据传入的参数或条件,工厂类决定实例化哪个具体类的对象并返回。

    1.1 模式结构

    • Factory:工厂角色 – 工厂角色负责实现创建所有实例的内部逻辑
    • Product:抽象产品角色 – 抽象产品角色是所创建的所有对象的父类,负责描述所有实例所共有的公共接口
    • ConcreteProduct:具体产品角色 – 具体产品角色是创建目标,所有创建的对象都充当这个角色的某个具体类的实例。

    设计模式之三种工厂模式

    />

    1.2 代码分析

    // 产品接口
    interface Product {
        void use();
    }
    
    // 具体产品A
    class ConcreteProductA implements Product {
        @Override
        public void use() {
            System.out.println("使用具体产品A");
        }
    }
    
    // 具体产品B
    class ConcreteProductB implements Product {
        @Override
        public void use() {
            System.out.println("使用具体产品B");
        }
    }
    
    // 简单工厂类
    class SimpleFactory {
        public static Product createProduct(String type) {
            if (type.equalsIgnoreCase("A")) {
                return new ConcreteProductA();
            } else if (type.equalsIgnoreCase("B")) {
                return new ConcreteProductB();
            }
            throw new IllegalArgumentException("Invalid product type: " + type);
        }
    }
    
    // 客户端代码
    public class Client {
        public static void main(String[] args) {
            Product productA = SimpleFactory.createProduct("A");
            productA.use();
    
            Product productB = SimpleFactory.createProduct("B");
            productB.use();
        }
    }

    1.3 优点

    • 工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象。
    • 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量。
    • 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。

    1.4 缺点

    • 由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。
    • 使用简单工厂模式将会增加系统中类的个数,在一定程序上增加了系统的复杂度和理解难度。
    • 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
    • 简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。

    1.5 适用

    简单工厂适用于需要创建的类比较少,比较确定所需要创建的产品种类。

    2. 工厂方法模式

    工厂方法模式中,只需要定义一个用于创建对象的接口,但是具体的对象的创建由子类来决定。

    解决了工厂模式中每新增一个产品,都需要修改工厂对象,在工厂方法模式只需要新增具体的工厂类和产品类即可。

    2.1 模式结构

    工厂方法模式包含如下角色:

    • Product:抽象产品
    • ConcreteProduct:具体产品
    • Factory:抽象工厂
    • ConcreteFactory:具体工厂

    设计模式之三种工厂模式

    />

    2.2 代码分析

    // 定义产品接口
    interface Product {
        void doSomething();
    }
    
    // 具体产品类A
    class ConcreteProductA implements Product {
        @Override
        public void doSomething() {
            System.out.println("ConcreteProductA: doSomething");
        }
    }
    
    // 具体产品类B
    class ConcreteProductB implements Product {
        @Override
        public void doSomething() {
            System.out.println("ConcreteProductB: doSomething");
        }
    }
    
    // 工厂抽象类
    abstract class Factory {
        // 工厂方法,由子类实现
        abstract Product createProduct();
    
        // 一些公共逻辑
        void commonMethod() {
            System.out.println("Common Method");
        }
    
        // 客户端代码调用的方法
        void doSomething() {
            // 创建产品
            Product product = createProduct();
    
            // 调用产品方法
            product.doSomething();
    
            // 执行其他逻辑
            commonMethod();
        }
    }
    
    // 具体工厂类A
    class ConcreteFactoryA extends Factory {
        @Override
        Product createProduct() {
            return new ConcreteProductA();
        }
    }
    
    // 具体工厂类B
    class ConcreteFactoryB extends Factory {
        @Override
        Product createProduct() {
            return new ConcreteProductB();
        }
    }
    
    // 客户端代码
    public class Main {
        public static void main(String[] args) {
            // 创建具体工厂A
            Factory factoryA = new ConcreteFactoryA();
            // 客户端通过工厂A创建产品
            factoryA.doSomething();
    
            // 创建具体工厂B
            Factory factoryB = new ConcreteFactoryB();
            // 客户端通过工厂B创建产品
            factoryB.doSomething();
        }
    }

    2.3 优点

    • 在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节,用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名。
    • 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够使工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,是因为所有的具体工厂类都具有同一抽象父类。
    • 使用工厂方法模式的另一个优点是在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了。这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。

    2.4 缺点

    • 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
    • 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。

    2.5 适用

    工厂模式方法适用于当一个类不知道它所必须创建的对象的类时,比如日志工厂,使用工厂模式方法可以适应以后出现的日志实现。

    如果你说上面简单工厂为什么也能实现根据类名创建对应的 Conntion 类,因为它是使用的反射的方法。

    3. 抽象工厂模式

    抽象工厂模式是一种创建型设计模式,它提供了一种方法来创建相关或依赖对象的系列,而无需指定具体类。在抽象工厂模式中,客户端代码通过使用抽象接口或抽象类创建一组相关的产品对象,而不是通过直接实例化具体类来创建这些对象。

    3.1 模式结构

    • AbstractFactory:抽象工厂
    • ConcreteFactory:具体工厂
    • AbstractProduct:抽象产品
    • Product:具体产品

    设计模式之三种工厂模式

    />

    3.2 代码分析

    // 抽象产品A
    interface AbstractProductA {
        void operationA();
    }
    
    // 具体产品A1
    class ConcreteProductA1 implements AbstractProductA {
        @Override
        public void operationA() {
            System.out.println("具体产品A1的操作");
        }
    }
    
    // 具体产品A2
    class ConcreteProductA2 implements AbstractProductA {
        @Override
        public void operationA() {
            System.out.println("具体产品A2的操作");
        }
    }
    
    // 抽象产品B
    interface AbstractProductB {
        void operationB();
    }
    
    // 具体产品B1
    class ConcreteProductB1 implements AbstractProductB {
        @Override
        public void operationB() {
            System.out.println("具体产品B1的操作");
        }
    }
    
    // 具体产品B2
    class ConcreteProductB2 implements AbstractProductB {
        @Override
        public void operationB() {
            System.out.println("具体产品B2的操作");
        }
    }
    
    // 抽象工厂
    interface AbstractFactory {
        AbstractProductA createProductA();
        AbstractProductB createProductB();
    }
    
    // 具体工厂1
    class ConcreteFactory1 implements AbstractFactory {
        @Override
        public AbstractProductA createProductA() {
            return new ConcreteProductA1();
        }
    
        @Override
        public AbstractProductB createProductB() {
            return new ConcreteProductB1();
        }
    }
    
    // 具体工厂2
    class ConcreteFactory2 implements AbstractFactory {
        @Override
        public AbstractProductA createProductA() {
            return new ConcreteProductA2();
        }
    
        @Override
        public AbstractProductB createProductB() {
            return new ConcreteProductB2();
        }
    }
    
    // 客户端代码
    public class Client {
        public static void main(String[] args) {
            // 创建具体工厂1
            AbstractFactory factory1 = new ConcreteFactory1();
            // 使用工厂1创建产品A和产品B
            AbstractProductA productA1 = factory1.createProductA();
            AbstractProductB productB1 = factory1.createProductB();
            productA1.operationA();  // 输出:具体产品A1的操作
            productB1.operationB();  // 输出:具体产品B1的操作
    
            // 创建具体工厂2
            AbstractFactory factory2 = new ConcreteFactory2();
            // 使用工厂2创建产品A和产品B
            AbstractProductA productA2 = factory2.createProductA();
            AbstractProductB productB2 = factory2.createProductB();
            productA2.operationA();  // 输出:具体产品A2的操作
            productB2.operationB();  // 输出:具体产品B2的操作
        }
    }

    3.3 优点

    • 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易。所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。另外,应用抽象工厂模式可以实现高内聚低耦合的设计目的,因此抽象工厂模式得到了广泛的应用。
    • 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。这对一些需要根据当前环境来决定其行为的软件系统来说,是一种非常实用的设计模式。
    • 增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。

    3.4 缺点

    • 在添加新的产品对象时,难以扩展抽象工厂来生产新种类的产品,这是因为在抽象工厂角色中规定了所有可能被创建的产品集合,要支持新种类的产品就意味着要对该接口进行扩展,而这将涉及到对抽象工厂角色及其所有子类的修改,显然会带来较大的不便。
    • 开闭原则的倾斜性(增加新的工厂和产品族容易,增加新的产品等级结构麻烦)。

    3.5 适用

    适用于系统中有多于一个的产品族,而每次只使用其中某一产品族,并且属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。

    比如在很多软件系统中需要更换界面主题,要求界面中的按钮、文本框、背景色等一起发生改。

    提醒:本文发布于494天前,文中所关联的信息可能已发生改变,请知悉!

    Tips:清朝云网络工作室

  • 工具类 Optional 用法详解


    共计 3537 个字符,预计需要花费 9 分钟才能阅读完成。

    Optional 类是 Java 8 中引入的一个用于避免空指针异常的工具类,请注意它是 java.util 包下的一个工具类。

    它提供了一系列方法,用于对可能为 null 的对象进行操作,以便更加安全地访问对象的属性和方法。

    Optional 里面几乎全部都围绕其中的一个成员变量 value 在运作。

    下面是 Optional 类中常用的方法及其用法:

    1. of 方法

    创建一个包含指定对象的 Optional 对象,如果指定对象为 null,则抛出 NullPointerException 异常。

    String str = "Hello, world!";
    Optional<String> opt = Optional.of(str);
    1. ofNullable 方法

    创建一个包含指定对象的 Optional 对象,如果指定对象为 null,则返回一个空的 Optional 对象。

    String str = null;
    Optional<String> opt = Optional.ofNullable(str);
    1. empty 方法

    创建一个空的 Optional 对象。

    Optional<String> opt = Optional.empty();
    1. get 方法

    获取 Optional 对象中的值,如果对象为空,则抛出 NoSuchElementException 异常。

    Optional<String> opt = Optional.of("Hello, world!");
    String str = opt.get();
    1. isPresent 方法

    判断 Optional 对象中是否包含非 null 的值。

    Optional<String> opt = Optional.of("Hello, world!");
    if (opt.isPresent()) {
        System.out.println(opt.get()); // 输出:Hello, world!
    }
    1. orElse 方法

    获取 Optional 对象中的值,如果对象为空,则返回指定的默认值。

    Optional<String> opt1 = Optional.ofNullable(null);
    String str1 = opt1.orElse("default value");
    System.out.println(str1); // 输出:default value
    
    Optional<String> opt2 = Optional.of("Hello, world!");
    String str2 = opt2.orElse("default value");
    System.out.println(str2); // 输出:Hello, world!
    1. orElseGet 方法

    获取 Optional 对象中的值,如果对象为空,则使用指定的 Supplier 函数生成一个默认值。

    Optional<String> opt1 = Optional.ofNullable(null);
    String str1 = opt1.orElseGet(() -> "default value");
    System.out.println(str1); // 输出:default value
    
    Optional<String> opt2 = Optional.of("Hello, world!");
    String str2 = opt2.orElseGet(() -> "default value");
    System.out.println(str2); // 输出:Hello, world!
    1. orElseThrow 方法

    获取 Optional 对象中的值,如果对象为空,则抛出指定的异常。

    Optional<String> opt1 = Optional.ofNullable(null);
    String str1 = opt1.orElseThrow(() -> new RuntimeException("Object is null")); //  运行抛出异常
    
    Optional<String> opt2 = Optional.of("Hello, world!");
    String str2 = opt2.orElseThrow(() -> new RuntimeException("Object is null"));
    1. ifPresent 方法

    上面提到过 ifPresent 方法,这个方法是重载方法,需要传递一个Consumer 接口的实现类进去。如果 Optional 对象中包含非 null 的值,则执行指定的操作。

    Consumer 接口是 Java 8 中引入的一个函数式接口,它表示一个接受单个输入参数并且不返回任何结果的操作。它定义了一个名为 accept 的抽象方法,用于执行操作。Consumer 接口常常用于对集合或流中的元素进行迭代,并对它们进行特定的处理,比如打印、修改或过滤等。

    Optional<String> opt = Optional.of("Hello, world!");
    opt.ifPresent(System.out::println); // 输出:Hello, world!

    源码中可以看见,判读值不为空则执行传递进来的函数。

    public void ifPresent(Consumer<? super T> consumer) {
        if (value != null)
            consumer.accept(value);
    }
    1. filter 方法

    该方法接收一个 Predicate 接口的实现类,对 Optional 对象中的值进行过滤,返回一个新的 Optional 对象。

    Predicate 接口是 Java 8 中引入的一个函数式接口,它表示一个能够接受一个输入参数并返回一个布尔值的操作。Predicate 接口定义了一个名为 test 的抽象方法,用于执行操作。test 方法接受一个泛型参数 T,表示要测试的对象,返回一个布尔值表示测试结果。

    Optional<String> opt1 = Optional.of("Hello, world!");
    Optional<String> opt2 = opt1.filter(s -> s.contains("o"));

    源码中可以看见如果 test 方法返回为 true,则返回自身,否则返回一个空的 Optional。

    public Optional<T> filter(Predicate<? super T> predicate) {
        Objects.requireNonNull(predicate);
        if (!isPresent())
            return this;
        else
            return predicate.test(value) ? this : empty();
    }
    1. map 方法

    该方法接收一个 Function 接口的实现类,对 Optional 对象中的值进行映射,返回一个新的 Optional 对象。

    Function 接口是 Java 8 中引入的一个函数式接口,它表示一个能够接受一个输入参数并返回一个结果的操作。Function 接口定义了一个名为 apply 的抽象方法,用于执行操作。apply 方法接受一个泛型参数 T,表示输入参数的类型,返回一个泛型参数 R,表示操作的结果类型。

    Optional<String> opt1 = Optional.of("Hello, world!");
    Optional<Integer> opt2 = opt1.map(String::length);
    System.out.println(opt2.get()); // 输出:13

    源码中可以看见,将函数的返回值赋值给了 ofNullable 方法,而这个方法会返回一个 新的 Optional 对象,所以这也是什么 Optional 的泛型指定可以改变的原因。

    public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
        Objects.requireNonNull(mapper);
        if (!isPresent())
            return empty();
        else {
            return Optional.ofNullable(mapper.apply(value));
        }
    }
    
    public static <T> Optional<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }
    
    public static <T> Optional<T> of(T value) {
        return new Optional<>(value);
    }
    1. flatMap 方法

    flatMap 方法也受一个函数作为参数,该函数定义了如何将 Optional 对象中的值进行转换,但是该函数返回值必须是另一个 Optional 对象。

    Optional<String> opt1 = Optional.of("Hello, world!");
    Optional<Integer> opt2 = opt1.flatMap(s -> Optional.of(s.length()));

    提醒:本文发布于494天前,文中所关联的信息可能已发生改变,请知悉!

    Tips:清朝云网络工作室

  • Stream 流用法详解


    共计 5918 个字符,预计需要花费 15 分钟才能阅读完成。

    简介

    Stream 是 Java 8 引入的一个功能强大的流式处理 API。它允许我们以声明性的方式操作集合(数组、集合等)的元素。通过使用 Stream,我们可以将多个操作连接起来,形成一个流水线,从而简化代码并提高可读性。

    Stream 类中包含的方法,可以进行数据筛选、转换、排序、去重、限制、跳过、归约、统计、匹配、查找和遍历等操作。

    数据筛选和转换:

    • filter(Predicate<T> predicate):根据指定条件过滤流中的元素。
    • map(Function<T, R> mapper):对流中的元素进行映射操作,转换为另一种类型。
    • flatMap(Function<T, Stream<R>> mapper):对流中的元素进行映射操作,将每个元素映射为一个流,并将所有流的元素合并成一个流。

    数据排序和去重:

    • sorted():对流中的元素进行排序操作。
    • distinct():去除流中的重复元素。

    数据归约和统计:

    • count():返回流中的元素数量。
    • reduce(BinaryOperator<T> accumulator):对流中的元素进行归约操作,得到一个最终结果。
    • collect(Collector<T, A, R> collector):将流中的元素收集到一个集合或其他数据结构中。

    数据匹配和查找:

    • max(Comparator<T> comparator):返回流中的最大元素。
    • min(Comparator<T> comparator):返回流中的最小元素。
    • findFirst():返回流中的第一个元素。
    • findAny():返回流中的任意一个元素。
    • anyMatch(Predicate<T> predicate):检查流中是否存在满足条件的元素。
    • allMatch(Predicate<T> predicate):检查流中的所有元素是否都满足条件。
    • noneMatch(Predicate<T> predicate):检查流中是否没有任何元素满足条件。

    数据限制和跳过:

    • limit(long maxSize):限制流中元素的数量。
    • skip(long n):跳过流中的前 n 个元素。

    其他方法:

    • forEach(Consumer<T> action):对流中的每个元素执行指定的操作。

    使用

    1. 数据筛选和转换

    数据的筛选和转换用得最多的当属 filter 和 map 方法。

    1.1 filter

    根据指定的条件过滤流中的元素。

    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
    List<Integer> evenNumbers = numbers.stream()
                                       .filter(n -> n % 2 == 0)
                                       .collect(Collectors.toList());
    System.out.println(evenNumbers); // 输出结果:[2, 4, 6]

    1.2 map

    对流中的元素进行映射操作,将其转换为另一种类型。

    List<String> names = Arrays.asList("John", "Jane", "Tom");
    List<Integer> nameLengths = names.stream()
                                     .map(String::length)
                                     .collect(Collectors.toList());
    System.out.println(nameLengths); // 输出结果:[4, 4, 3]

    2. 数据排序和去重

    数据的排序和去重用得也是比较多的方法。

    2.1 sorted

    对流中的元素进行排序操作。

    List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 6);
    List<Integer> sortedNumbers = numbers.stream()
                                         .sorted()
                                         .collect(Collectors.toList());
    System.out.println(sortedNumbers);v // 输出结果:[1, 2, 5, 6, 8]

    2.2 distinct

    去除流中重复的元素。

    List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3, 4, 5);
    List<Integer> distinctNumbers = numbers.stream()
                                           .distinct()
                                           .collect(Collectors.toList());
    System.out.println(distinctNumbers); // 输出结果:[1, 2, 3, 4, 5]

    3. 数据归约和统计

    3.1 count

    返回流中的元素数量。

    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    long count = numbers.stream()
                        .count();
    System.out.println(count); // 输出结果:5

    3.2 reduce

    对流中的元素进行归约操作,将流中的元素通过指定的操作进行组合,得到一个最终结果。

    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    Optional<Integer> sum = numbers.stream()
                                   .reduce((a, b) -> a + b);
    System.out.println(sum.orElse(0)); // 输出结果:15

    3.3 collect

    用于将流中的元素收集到一个集合或其他数据结构中。

    将流元素收集到 List 中

    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    List<Integer> collectedList = numbers.stream()
                                         .collect(Collectors.toList());
    System.out.println(collectedList);

    将流元素收集到 Set 中

    List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3, 4, 5);
    Set<Integer> collectedSet = numbers.stream()
                                       .collect(Collectors.toSet());
    System.out.println(collectedSet);

    将流元素收集到 Map 中

    List<String> names = Arrays.asList("John", "Jane", "Tom");
    Map<String, Integer> nameLengthMap = names.stream()
                                              .collect(Collectors.toMap(
                                                  name -> name,
                                                  name -> name.length()
                                              ));
    System.out.println(nameLengthMap); // 输出结果:{John=4, Jane=4, Tom=3}

    根据某个属性对流中的元素进行分组

    Person 类

    public class Person {
        private String name;
        private int age;
    
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public int getAge() {
            return age;
        }
    
        @Override
        public String toString() {
            return "Person{name='" + name + "', age=" + age + "}";
        }
    }

    可以根据年龄对 Person 对象进行分组:

    List<Person> persons = Arrays.asList(
        new Person("John", 25),
        new Person("Jane", 30),
        new Person("Tom", 22),
        new Person("Alice", 30)
    );
    
    Map<Integer, List<Person>> ageGroupMap = persons.stream()
                                                    .collect(Collectors.groupingBy(Person::getAge));
    
    System.out.println(ageGroupMap); // 输出结果:{22=[Person{name='Tom', age=22}], 25=[Person{name='John', age=25}], 30=[Person{name='Jane', age=30}, Person{name='Alice', age=30}]}
    

    将流元素收集到自定义的容器中

    自定义的容器类 PersonContainer

    public class PersonContainer {
        private List<Person> persons = new ArrayList<>();
    
        public void addPerson(Person person) {
            persons.add(person);
        }
    
        public List<Person> getPersons() {
            return persons;
        }
    }

    示例代码:

    List<Person> persons = Arrays.asList(
        new Person("John", 25),
        new Person("Jane", 30),
        new Person("Tom", 22)
    );
    
    PersonContainer container = persons.stream()
                                       .collect(
                                           PersonContainer::new,
                                           PersonContainer::addPerson,
                                           PersonContainer::addPerson
                                       );
    
    List<Person> collectedPersons = container.getPersons();
    System.out.println(collectedPersons); // 输出结果:[Person{name='John', age=25}, Person{name='Jane', age=30}, Person{name='Tom', age=22}]

    4. 数据匹配和查找

    4.1 max

    返回流中的最大的元素,返回是一个 Optional 类。

    List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 6);
    Optional<Integer> maxNumber = numbers.stream()
                                         .max(Integer::compareTo);
    System.out.println(maxNumber.orElse(0)); // 输出 8

    4.2 min

    返回流中的最小的元素,返回是一个 Optional 类。

    List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 6);
    Optional<Integer> minNumber = numbers.stream()
                                         .min(Integer::compareTo);
    System.out.println(minNumber.orElse(0)); // 输出 1

    4.3 findFirst

    返回流中的第一个元素(按照流的遍历顺序),返回是一个 Optional 类。

    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    Optional<Integer> firstNumber = numbers.stream()
                                           .findFirst();
    System.out.println(firstNumber.orElse(0)); // 输出 1

    4.4 findAny

    返回流中的任意一个元素,返回是一个 Optional 类。

    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    Optional<Integer> anyNumber = numbers.stream()
                                         .findAny();
    System.out.println(anyNumber.orElse(0)); // 输出结果:1(可能的结果因为随机性而有所不同)

    4.5 anyMatch

    检查流中是否存在满足给定条件的元素,返回是一个布尔值。

    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    boolean hasEvenNumber = numbers.stream()
                                   .anyMatch(n -> n % 2 == 0);
    System.out.println(hasEvenNumber); // 输出结果:true

    4.6 anyMatch

    检查流中的所有元素是否都满足给定条件,返回是一个布尔值。

    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    boolean allEvenNumbers = numbers.stream()
                                    .allMatch(n -> n % 2 == 0);
    System.out.println(allEvenNumbers); // 输出结果:false

    4.7 noneMatch

    检查流中是否没有任何元素满足给定条件。

    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    boolean noNegativeNumbers = numbers.stream()
                                       .noneMatch(n -> n < 0);
    System.out.println(noNegativeNumbers); // 输出结果:true

    5. 数据限制和跳过

    5.1 limit

    限制流中元素的数量。

    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    List<Integer> limitedNumbers = numbers.stream()
                                          .limit(3)
                                          .collect(Collectors.toList());
    System.out.println(limitedNumbers); // 输出结果:[1, 2, 3]

    5.2 skip

    跳过流中的前 n 个元素。

    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
    List<Integer> skippedNumbers = numbers.stream()
                                          .skip(2)
                                          .collect(Collectors.toList());
    System.out.println(skippedNumbers);

    6. 其他方法

    6.1 forEach

    对流中的每个元素执行指定的操作。

    List<String> names = Arrays.asList("John", "Jane", "Tom");
    names.stream()
         .forEach(System.out::println);

    提醒:本文发布于494天前,文中所关联的信息可能已发生改变,请知悉!

    Tips:清朝云网络工作室

  • 11月25日,星期一, 每天60秒读懂全世界!

    百度热搜新闻

    新闻来源:百度热搜榜

    1. 央视曝光羽绒骗局!你的孩子可能在穿 近日,一部分“假羽绒制品”在市场上肆意泛滥,消费者直呼“坑人”,央视已曝光此羽绒骗局,一起来看看!

    2. 全网寻找的豫P7A525找到了 11月23日,“急寻豫P7A525”的找车视频引发持续关注,全城出动了3万条留言帮忙寻找,24日下午,这辆车终于被找到了。

    3. 特色文旅释放消费“新”热潮 初冬时节,银杏逐渐进入了最佳观赏期,叶片由绿变黄,“秋冬限定色”成为一道亮丽的风景线,内蒙古根河打造冬季特色文旅 “驯鹿游”引客来,全国各地特色文旅释放消费“新”热潮。

    4. 叶嘉莹逝世 享年100岁 11月24日,记者从南开大学获悉,古典文学研究学者、南开大学讲席教授叶嘉莹去世,享年100岁。

    5. 年底前你的工资卡或多这几笔钱 2024年只剩下一个多月时间了,岁末年初有几笔钱将要到账,提醒大家别忘了!

    6. “最听劝的局长”拟获提拔

    7. 王楚钦横扫张本智和夺冠 24日,日本福冈WTT总决赛,中国选手王楚钦以4-0的比分战胜日本选手张本智和,夺得男单冠军。

    8. 女子称花12万整形后被说老了10岁 近日,杭州一女士在一家医院花费12万元整形,整形后反而被周围人评价:“看起来老了10岁”。

    9. 李子柒穿绿色唐朝襦裙太绝了

    10. 清华厨师的画被外交部永久收藏

    —- 百度热搜新闻 End —-

    知乎新闻

    新闻来源:知乎日榜

    标题: 有哪些没有一定语言学知识的人不会相信的语言学上的事实?
    链接: https://daily.zhihu.com/story/9776983
    ———————-
    标题: 植物的光合作用可以被取代吗?
    链接: https://daily.zhihu.com/story/9777087
    ———————-
    标题: 癌细胞为何非要杀人?为什么不能和正常细胞和平共处呢?
    链接: https://daily.zhihu.com/story/9777092
    ———————-
    标题: 从进化上来看,最早使用「花」作为生殖器官的植物是什么?
    链接: https://daily.zhihu.com/story/9777102
    ———————-

    —- 知乎新闻 End —-

    IT之家新闻

    新闻来源:ITHome之家科技新闻

    标题: 纯血鸿蒙版微信 App 消息推送使用华为 Push 服务,新版本预埋功能后续分批放量可用
    发布时间: 2024-11-24T13:58:23.513
    新闻简介: 纯血鸿蒙版微信 1.0.1.40 版本已上架华为应用市场应用尝鲜专区,腾讯 WXG(微信事业群)员工 @客村小蒋 称应用的新消息推送使用华为 Push;微信的不同版本会有一些新功能会预埋,后续分批放量可用。
    ———————-
    标题: 华为鸿蒙 HarmonyOS NEXT 系统游戏中心发布新游预告,含《使命召唤手游体验服》《元气骑士》等
    发布时间: 2024-11-24T10:51:37.793
    新闻简介: 华为鸿蒙 HarmonyOS NEXT 系统游戏中心近日发布新游预告,后续将带来多款游戏,包括《使命召唤手游体验服》《元气骑士》等。
    ———————-
    标题: 5919 元:苹果 16G 内存 + M2 10 核版 MacBook Air 国补后 6.76 折探底
    发布时间: 2024-11-24T10:33:34.57
    新闻简介: 苹果 M2 / M3 版 MacBook Air 今年 10 月 30 日标配升级至 16GB 内存,M2 10 核版 MacBook Air 16+256GB售价降至 8749 元。
    ———————-
    标题: 小米王腾预热 REDMI K80 Pro 手机:4K 档最全能的充电续航组合和最强的影像体验
    发布时间: 2024-11-24T15:50:24.067
    新闻简介: 小米 REDMI 品牌总经理王腾今日发文称:“游戏体验上,量产机 K80 Pro 比友商同游戏条件下,功耗更低、温度更低,大家可以等上市后测试。同时有 4K 档最全能的充电续航组合和最强的影像体验”。
    ———————-
    标题: 中国移动 30 元面额话费充值在福建等六省份微信、支付宝下架
    发布时间: 2024-11-24T10:49:30.323
    新闻简介: 近日,腾讯手机充值客服帮助中心发布通知,接到中国移动通知要求,即日起,“30 元话费面额”在福建、河北、河南、山东、安徽、江西六个省份下架,暂无法提供 30 元面额话费充值服务。其他话费面额不受影响。
    ———————-
    标题: 政府补贴 7.9 元:小米智能插座 3 自营 44.8 元 ,支持电量统计
    发布时间: 2024-11-24T17:20:13.673
    新闻简介: 小米米家智能插座 3 于 2022 年 8 月上市,支持语音控制、远程控制、电量统计和过载保护,官方售价 59 元。
    ———————-
    标题: 小米 Redmi 新机“2409BRN2CC”入网:直角边框设计、配居中圆形相机模组
    发布时间: 2024-11-24T06:47:26.773
    新闻简介: 新机今日还现身电信设备终端网,尺寸为 171.88×77.80×8.22mm、重约 211.97g。该机屏幕分辨率为 720×1640、尺寸为 6.88 英寸、支持 1600 万色显示。
    ———————-
    标题: 荣耀 300 / Pro / Ultra 手机续航规格曝光:5300mAh 电池 + 100W 快充
    发布时间: 2024-11-24T09:40:30.243
    新闻简介: 博主 @熊猫很禿然 今日曝光了荣耀 300 / Pro手机的续航规格以及外围参数:荣耀 300 标准版:5300mAh 电池 + 100W 有线快充,6.97mm*181g;荣耀 300 Pro:5300mAh 电池 + 100W 有线快充 + 无线充电,7.7mm*187g。
    ———————-
    标题: 2024 款苹果 M4 MacBook Pro 拆解:内部结构变化不大,散热器尺寸略有增加
    发布时间: 2024-11-24T17:48:51.457
    新闻简介: iFixit 对新款苹果 M4 MacBook Pro 进行了拆解,发现其内部结构与 M3 系列 MacBook Pro 几乎没有区别。尽管 M4 MacBook Pro 在外观上增加了一个 Thunderbolt 端口,但在内部,除了散热器略有增大以及部分小芯片的位置有所调整外,其余部分与上代几乎完全相同,包括双风扇设计和电池容量。
    ———————-
    标题: 小米 Redmi 智能电视 X 2025 系列、米家立式学习灯 Pro 等新品 11 月 27 日发布
    发布时间: 2024-11-24T17:06:43.4
    新闻简介: 今日早些时候,小米智能生态官宣四大品类、四款新品将于 11 月 27 日发布,现在官方陆续公布新品名称。
    ———————-
    标题: 比亚迪 30 周年大抽奖完成兑奖,王传福交付 90 台汽车使用权
    发布时间: 2024-11-24T11:39:05.04
    新闻简介: 11 月 23 日,比亚迪成立 30 周年感恩回馈大抽奖活动的兑奖仪式,在比亚迪全球总部举行。比亚迪股份有限公司董事长兼总裁王传福现场向 60 位幸运车主和 30 位幸运员工分别交付 30 台仰望 U8、30 台腾势 Z9GT 和 30 台方程豹豹 8 的使用权。
    ———————-
    标题: 保时捷回应合作方与货运平台工作人员纠纷:双方已和解,作为品牌方对引发纠纷及其中出现的不当处理表示歉意
    发布时间: 2024-11-24T09:30:37.343
    新闻简介: #保时捷公开道歉#保时捷 11 月 23 日晚发布声明,回应合作方与货运平台工作人员纠纷。声明称,涉事人员是合作方的正式员工,合作方确认其员工与货运平台员工的纠纷已在相关部门的介入下进一步处理,双方已于当日达成和解。作为品牌方,保时捷对引发这一纠纷及其中出现的不当处理表示歉意。
    ———————-

    —- IT之家新闻 End —-

  • WebSecurityConfigurerAdapter 详解


    共计 5860 个字符,预计需要花费 15 分钟才能阅读完成。

    简介

    WebSecurityConfigurerAdapter 是 Spring Security 中的一个抽象类,实现了WebSecurityConfigurer接口,用于配置 Spring Security 的安全性设置。

    类图如下:

    WebSecurityConfigurerAdapter 详解

    />

    通过继承WebSecurityConfigurerAdapter并覆盖其中的方法,可以自定义应用程序的安全性配置。

    常用配置

    下面贴一下WebSecurityConfigurerAdapter在项目中的常用配置

    /**
     * spring security配置
     *
     */
    @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        /**
         * 自定义用户认证逻辑
         */
        @Autowired
        private UserDetailsService userDetailsService;
    
        /**
         * 认证失败处理类
         */
        @Autowired
        private AuthenticationEntryPointImpl unauthorizedHandler;
    
        /**
         * 退出处理类
         */
        @Autowired
        private LogoutSuccessHandlerImpl logoutSuccessHandler;
    
        /**
         * token认证过滤器
         */
        @Autowired
        private JwtAuthenticationTokenFilter authenticationTokenFilter;
    
        /**
         * 跨域过滤器
         */
        @Autowired
        private CorsFilter corsFilter;
    
        /**
         * 解决 无法直接注入 AuthenticationManager
         *
         * @return
         * @throws Exception
         */
        @Bean
        @Override
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
        }
    
        /**
         * 强散列哈希加密实现
         */
        @Bean
        public BCryptPasswordEncoder bCryptPasswordEncoder() {
    
            return new BCryptPasswordEncoder();
        }
    
        /**
         * 身份认证接口
         */
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    
            //在这里关联数据库和security
            auth.userDetailsService(userDetailsService)
                .passwordEncoder(bCryptPasswordEncoder());
        }
    
        /**
         * anyRequest          |   匹配所有请求路径
         * access              |   SpringEl表达式结果为true时可以访问
         * anonymous           |   匿名可以访问
         * denyAll             |   用户不能访问
         * fullyAuthenticated  |   用户完全认证可以访问(非remember-me下自动登录)
         * hasAnyAuthority     |   如果有参数,参数表示权限,则其中任何一个权限可以访问
         * hasAnyRole          |   如果有参数,参数表示角色,则其中任何一个角色可以访问
         * hasAuthority        |   如果有参数,参数表示权限,则其权限可以访问
         * hasIpAddress        |   如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问
         * hasRole             |   如果有参数,参数表示角色,则其角色可以访问
         * permitAll           |   用户可以任意访问
         * rememberMe          |   允许通过remember-me登录的用户访问
         * authenticated       |   用户登录后可访问
         */
        @Override
        protected void configure(HttpSecurity httpSecurity) throws Exception {
    
            httpSecurity
                    // CSRF禁用,因为不使用session
                    .csrf().disable()
                    // 认证失败处理类
                    .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
                    // 基于token,所以不需要session
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                    // 过滤请求
                    .authorizeRequests()
                    // 对于登录login 验证码captchaImage 允许匿名访问
                    .antMatchers("/login", "/captchaImage").anonymous()
                    .antMatchers("/swagger-ui.html").permitAll()
                    .antMatchers("/swagger-resources/**").permitAll()
                    // 除上面外的所有请求全部需要鉴权认证
                    .anyRequest().authenticated()
                    .and()
                    .headers().frameOptions().disable();
            httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);
            // 添加JWT filter
            httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
            // 添加CORS filter
            httpSecurity.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class);
            httpSecurity.addFilterBefore(corsFilter, LogoutFilter.class);
        }
    
        /***
         * 核心过滤器配置方法
         * @param web
         * @throws Exception
         */
        @Override
        public void configure(WebSecurity web) throws Exception {
            super.configure(web);
        }
    }

    重要方法

    1. configure(HttpSecurity http)

    这是最常用的方法之一,用于配置基于HTTP请求的安全性。您可以通过该方法定义哪些URL路径需要被保护,哪些路径不需要认证,以及对不同角色的用户授予不同的访问权限。

    此外还可以定义登录 url 和登出 url,还可以添加自定义过滤器等。

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/public/**").permitAll()
                .antMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
            .logout()
                .permitAll();
    }

    HttpSecurity 使用了builder 的构建方式来灵活制定访问策略。最早基于 XML 标签对 HttpSecurity 进行配置。现在大部分使用 javaConfig方式。

    常用的方法解读如下:

    方法 说明
    openidLogin() 用于基于 OpenId 的验证
    headers() 将安全标头添加到响应,比如说简单的 XSS 保护
    cors() 配置跨域资源共享( CORS )
    sessionManagement() 允许配置会话管理
    portMapper() 允许配置一个PortMapper(HttpSecurity#(getSharedObject(class))),其他提供SecurityConfigurer的对象使用 PortMapper 从 HTTP 重定向到 HTTPS 或者从 HTTPS 重定向到 HTTP。默认情况下,Spring Security使用一个PortMapperImpl映射 HTTP 端口8080到 HTTPS 端口8443,HTTP 端口80到 HTTPS 端口443
    jee() 配置基于容器的预认证。 在这种情况下,认证由Servlet容器管理
    x509() 配置基于x509的认证
    rememberMe() 允许配置“记住我”的验证
    authorizeRequests() 允许基于使用HttpServletRequest限制访问
    requestCache() 允许配置请求缓存
    exceptionHandling() 允许配置错误处理
    securityContext() 在HttpServletRequests之间的SecurityContextHolder上设置SecurityContext的管理。 当使用WebSecurityConfigurerAdapter时,这将自动应用
    servletApi() 将HttpServletRequest方法与在其上找到的值集成到SecurityContext中。 当使用WebSecurityConfigurerAdapter时,这将自动应用
    csrf() 添加 CSRF 支持,使用WebSecurityConfigurerAdapter时,默认启用
    logout() 添加退出登录支持。当使用WebSecurityConfigurerAdapter时,这将自动应用。默认情况是,访问URL”/ logout”,使HTTP Session无效来清除用户,清除已配置的任何#rememberMe()身份验证,清除SecurityContextHolder,然后重定向到”/login?success”
    anonymous() 允许配置匿名用户的表示方法。 当与WebSecurityConfigurerAdapter结合使用时,这将自动应用。 默认情况下,匿名用户将使用org.springframework.security.authentication.AnonymousAuthenticationToken表示,并包含角色 “ROLE_ANONYMOUS”
    formLogin() 指定支持基于表单的身份验证。如果未指定FormLoginConfigurer#loginPage(String),则将生成默认登录页面
    oauth2Login() 根据外部OAuth 2.0或OpenID Connect 1.0提供程序配置身份验证
    requiresChannel() 配置通道安全。为了使该配置有用,必须提供至少一个到所需信道的映射
    httpBasic() 配置 Http Basic 验证
    addFilterBefore() 在指定的Filter类之前添加过滤器
    addFilterAt() 在指定的Filter类的位置添加过滤器
    addFilterAfter() 在指定的Filter类的之后添加过滤器
    and() 连接以上策略的连接器,用来组合安全策略。实际上就是”而且”的意思
    1. configure(AuthenticationManagerBuilder auth)

    方法用于配置用户认证的细节,例如用户的来源,密码加密方式以及自定义认证提供者。

    /**
     * 自动注入 UserDetailsService
     */
    @Autowired
    UserDetailsService  userDetailsService;
    
    /**
     * 强散列哈希加密实现
     */
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
    
        return new BCryptPasswordEncoder();
    }
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService)
            .passwordEncoder(bCryptPasswordEncoder())
        /** 
         * {noop} 代表不使用加密,并且不设置角色即没有设置权限会报错
        auth.inMemoryAuthentication()
                .withUser("user").password("{noop}password").roles("USER")
                .and()
                .withUser("admin").password("{noop}adminpassword").roles("ADMIN");
         */
    }
    1. configure(WebSecurity web)

    该方法用于配置WebSecurity,主要用于忽略一些静态资源或路径,这些资源不需要经过Spring Security的过滤器链进行验证。

    @Override
    public void configure(WebSecurity web) throws Exception {
        // 需要实现WebMvcConfigurer接口指定静态资源文件夹
        web.ignoring()
            .antMatchers("/static/**"); 
        /**
         * 默认静态资源文件夹:
            classpath:/static
            classpath:/public
            classpath:/resources
            classpath:/META-INF/resources
         */
    }

    WebConfig.java

    @Configuration
    public class WebConfig implements WebMvcConfigurer {
    
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            // 配置静态资源路径
            registry.addResourceHandler("/static/**")
                    .addResourceLocations("classpath:/static/"); 
        }
    }

    提醒:本文发布于492天前,文中所关联的信息可能已发生改变,请知悉!

    Tips:清朝云网络工作室

  • Spring Security 详解以及认证过程


    共计 6621 个字符,预计需要花费 17 分钟才能阅读完成。

    简介

    Spring Security 是基于 Spring 实现的一个安全框架,其中包括非常多的过滤器,主要进行攻击防护、认证授权等功能。

    过滤器链

    Spring Security 常用的过滤器有15个,如下图所示:

    Spring Security 详解以及认证过程

    />

    在 FilterChainProxy 类中的 doFilterInternal 方法打断点可以看见。

    1.org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter

    此过滤器用于继承 SecurityContext 到 Spring 异步执行机制中的 WebAsyncManager,和 spring 整合必须的。

    2.org.springframework.security.web.context.SecurityContextPersistenceFilter

    非常重要的一个过滤器,主要是使用 SecurityContextRepository 在 session 中保存或更新一个 SecurityContext,并将 SecurityContext 给以后的过滤器使用,来为后续 filter 建立所需的上下文,SecurityContext 中存储了当前用户的认证和权限信息。

    3.org.springframework.security.web.header.HeaderWriterFilter

    向请求的 header 中添加响应的信息,可以在 http 标签内部使用 security:headers 来控制。

    4.org.springframework.security.web.csrf.CsrfFilter

    Csrf 又称跨域请求伪造,SpringSecurity 会对所有 post 请求验证是否包含系统生成的 csrf 的 token 信息,如果不包含则报错,起到防止 csrf 攻击的效果.

    这里需要提到的是,csrf 在前后端分离的项目中一般都会关闭,因为天然不怕 csrf 攻击,毕竟该攻击是基于 session 的,而前后端分离项目一般都是使用 token,将 token 放在请求头。

    5.org.springframework.security.web.authentication.logout.LogoutFilter

    匹配 URL 为 /logout 的请求,实现用户退出,清除认证信息。

    6.org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter

    认证过滤器,下面将详细讲解该过滤器,默认匹配URL为 /login 且必须为 POST 请求。

    7.org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter

    如果没有在配置文件中指定认证页面,则由该过滤器生成一个默认的认证界面。

    8.org.springframework.security.web.authentication.ui.DefaultLogoutPageGeneratingFilter

    此过滤器生成一个默认的退出登录页面。

    9.org.springframework.security.web.authentication.www.BasicAuthenticationFilter

    此过滤器会自动解析HTTP请求中头部名字为 Authentication,且以 Basic 开头的头部信息。

    10.org.springframework.security.web.savedrequest.RequestCacheAwareFilter

    通过HttpSessionRequestCache内部维护一个RequestCache,用于缓存HttpServletRequest。

    11.org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter

    针对 ServletRequest 进行一次包装,使得 request 具有更加丰富的API。

    12.org.springframework.security.web.authentication.AnonymousAuthenticationFilter

    当 SecurityContextHolder 中认证信息为空,则会创建一个匿名用户存储到 SecurityContextHolder 中,SpringSecurity 为了兼容未登录的访问,也走了一套认证流程,只不过是一个匿名的身份。

    13.org.springframework.security.web.session.SessionManagementFilter

    SecurityContextRepository限制同一个用户开启多个会话的数量。

    14.org.springframework.security.web.access.ExceptionTranslationFilter

    异常转换过滤器位于整个 SpringSecurityFilterChain 的后方,用来转换整个链路中出现的异常。

    15.org.springframework.security.web.access.intercept.FilterSecurityInterceptor

    获取所有配置资源的访问授权信息,根据 SecurityContextHolder 中存储的用户信息来决定其是否有权限。

    认证过程

    认证过程如下:

    Spring Security 详解以及认证过程

    />

    1.在过滤器链的初始阶段,用户名和密码会被封装成 UsernamePasswordAuthenticationToken,也就是 Authentication 对象,因为继承于它。

    2.过滤器会调用 authenticate 方法将 Authentication 对象传递给 AuthenticationManager(认证管理器)。但是它不会进行对用户信息的认证,通过委托多个 AuthenticationProvider 来完成身份验证,只要有一个 AuthenticationProvider 验证成功,就会返回一个已经填充了用户认证信息的 Authentication 对象。

    3.在 AuthenticationManager 中,这里是真正对用户信息进行认证的地方。认证管理器会调用 UserDetailsService 接口来获取用户的详细信息。UserDetailsService 是 Spring Security 用于获取用户信息的接口,它需要实现一个 loadUserByUsername()方法,根据用户名查询用户信息。

    4.UserDetailsService 返回一个实现了 UserDetails 接口的对象,该对象包含了用户的详细信息,如用户名、密码和权限等。

    5.在 AuthenticationProvider 中将 Authentication 对象的密码与用 PasswordEncoder 加密 UserDetails 的密码进行验证是否正确。正确则返回 UserDetails 的权限设置到 Authentication 对象中,并返回。

    6.认证成功后,Spring Security 会将认证信息存储在 SecurityContext 中。SecurityContext 是一个线程本地的容器,用于存储当前用户的认证信息。

    7.可以配置一个认证成功处理器来处理认证成功的逻辑,例如,更新用户在数据库中的登录失败次数和上次登录时间等等。

    自定义认证

    需要注意的是,配置文件中需要 HttpSecurity 调用 formLogin 方法,过滤器链才会注入 UsernamePasswordAuthenticationFilter、DefaultLoginPageGeneratingFilter 和 DefaultLogoutPageGeneratingFilter,否则将没有认证过程,那么除了开放的所有请求,其他的请求都将是 403,因为 SecurityContextHolder 里面没有内容。

    在实际项目中,登录的接口一般都是自定义,毕竟除了验证账户密码还需要进行一些其他的操作,比如用 jwt 生成 token,放入 redis 并将 token 返回。

    而 Spring security 的默认过滤器并不能做到,于是需要在配置文件中手动注入 AuthenticationManager,在自定义的登录接口注入该对象,并调用 authenticate 方法进行认证。所以此时又回到了刚刚所说的认证流程,还是能调用到重写的 loadUserByUsername 方法。

    @Service
    public class LoginServcieImpl implements ILoginServcie {
    
        @Resource
        private AuthenticationManager authenticationManager;
    
        @Resource
        private RedisCache redisCache;
    
        @Override
        public ResponseResult login(User user) {
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user.getUserName(),user.getPassword());
            // 这里会去调用 UserDetailsService 的 loadUserByUsername,如果认证失败将抛出异常 BadCredentialsException
            Authentication authenticate = authenticationManager.authenticate(authenticationToken);
    
            //如果认证没通过,给出对应的提示
            if(Objects.isNull(authenticate)){
                throw new RuntimeException("登录失败");
            }
            //如果认证通过了,使用userid生成一个jwt jwt存入ResponseResult返回
            LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
            String userid = loginUser.getUser().getId().toString();
            String jwt = JwtUtil.createJWT(userid);
            Map<String,String> map = new HashMap<>();
            map.put("token",jwt);
            //把完整的用户信息存入redis  userid作为key
            redisCache.setCacheObject("login:"+userid,loginUser);
            return new ResponseResult(200,"登录成功",map);
        }
    }

    登录接口返回了 token,那么接下来调用其他的接口时就需要将该 token 给带上,比如放在请求头。

    虽然说认证已经通过了,但是传递 token 后,程序怎么就能判断用户是否有权限呢?答案是自定义过滤器。

    自定义过滤器需要做的事情有:

    1.判断请求头是否带有 token,如果没有 token 就放行,除了放行的请求不用担心其他请求会顺利通过,因为接下来的权限拦截器 FilterSecurityInterceptor 会校验权限,并返回 403。

    2.如果请求头带有 token,需要解析 token 得到用户 id,并通过用户 id 获取 redis 中用户信息。

    3.获取到用户信息,将权限信息封装到 Authentication 对象中,再将 Authentication 放入 SecurityContextHolder,这样所有过滤器都能获取到 Authentication 对象,包括其中的权限信息,到后面的权限过滤器根据其权限判断拦截或放行。

    @Component
    public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    
        @Autowired
        private RedisCache redisCache;
    
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
            //获取token
            String token = request.getHeader("token");
            if (!StringUtils.hasText(token)) {
                //放行
                filterChain.doFilter(request, response);
                return;
            }
            //解析token
            String userid;
            try {
                Claims claims = JwtUtil.parseJWT(token);
                userid = claims.getSubject();
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException("token非法");
            }
            //从redis中获取用户信息
            String redisKey = "login:" + userid;
            LoginUser loginUser = redisCache.getCacheObject(redisKey);
            if(Objects.isNull(loginUser)){
                throw new RuntimeException("用户未登录");
            }
            //存入SecurityContextHolder
            //TODO 获取权限信息封装到Authentication中
            UsernamePasswordAuthenticationToken authenticationToken =
                    new UsernamePasswordAuthenticationToken(loginUser,null,loginUser.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
            //放行
            filterChain.doFilter(request, response);
        }
    }

    注意配置过滤器后,需要在配置文件中添加该过滤器。

    @EnableWebSecurity
    @EnableGlobalMethodSecurity(prePostEnabled=true)
    public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
    
        @Resource
        JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
    
        @Bean
        public PasswordEncoder passwordEncoder(){
            return new BCryptPasswordEncoder();
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
    
            http.csrf().disable()
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and()
                    .authorizeRequests()
                    //不通过Session获取SecurityContext
                        .antMatchers("/user/login").permitAll()
                        .anyRequest().authenticated()
                    .and().cors();
            //添加过滤器
            http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
        }
    }

    提醒:本文发布于490天前,文中所关联的信息可能已发生改变,请知悉!

    Tips:清朝云网络工作室

  • 11月24日,星期日, 每天60秒读懂全世界!

    百度热搜新闻

    新闻来源:百度热搜榜

    1. 王楚钦谈与张本智和争冠 23日,2024WTT福冈总决赛男单半决赛,王楚钦晋级决赛将对阵张本智和,王楚钦:自己肯定会全力以赴,至于结果交给当下。

    2. 俄飞行员驾驶苏-57经停太原买买买 21日,俄罗斯飞行员博格丹驾驶苏-57离开珠海返回俄罗斯,途中经停山西太原。落地当晚继续“扫货”买买买。

    3. 聆听大国外交的铿锵足音 拉美之行,是大国外交的又一次生动实践。与时俱进、担当有为、开放包容的中国特色、中国风格、中国气派愈加彰显。跟随习近平主席的出访足迹,聆听大国外交的铿锵足音。

    4. 两位抗癌网红先后去世 近期曾通话 11月22日,网红“努力坚强的湘妹子-阿妹”因胃癌去世。据悉,湘妹子几天前还和陈班长视频通话,如今两位抗癌网红先后去世。

    5. 故意冲撞石山舰 17人被抓

    6. 小伙被两年前经常投喂的流浪狗认出 11月22日,广东深圳一小伙重逢两年前常投喂的流浪狗,狗狗认出后亲密撒娇。当事人:没想到它们还认识,感动得快哭了。

    7. 前员工曝光火锅店用僵尸肉 近日,一火锅店前员工曝光火锅店用僵尸肉:废肉打成肉末做牛肉丸,后厨卫生堪忧,引发广泛关注。

    8. 男子打赏女主播400万自己啃馒头 近日,浙江宁波一男子打赏女主播400万,引发热议。该男子表示:平时饿了就啃点馒头,就想听那一声声“哥哥”。

    9. 9条具体措施稳外贸 11月21日,商务部从三个方面,共推出9条具体措施。连线中国宏观经济研究院研究员张燕生,解读相关问题。

    10. 中国名将王聪遭裸绞

    —- 百度热搜新闻 End —-

    知乎新闻

    新闻来源:知乎日榜

    标题: 人类语言各不相通,那历史上第一个翻译是如何做到的呢?
    链接: https://daily.zhihu.com/story/9777061
    ———————-
    标题: 在生活中该如何判断一个人有没有说谎?
    链接: https://daily.zhihu.com/story/9776974
    ———————-
    标题: 如果把一根压紧的弹簧放进酸里溶解,它的弹性势能到哪里去了?
    链接: https://daily.zhihu.com/story/9777071
    ———————-
    标题: 白蚁为什么要啃木头?
    链接: https://daily.zhihu.com/story/9777080
    ———————-

    —- 知乎新闻 End —-

    IT之家新闻

    新闻来源:ITHome之家科技新闻

    标题: 史诗级更新,微信 PC 版 4.0.1 内测支持发布朋友圈
    发布时间: 2024-11-23T15:11:12.357
    新闻简介: 微信 PC 版 4.0.1 内测需要获得内测资格才可以登录,因此大家可以等待后续版本更新。
    ———————-
    标题: “时代旗舰”11 月 26 日登场,鸿蒙智行公布尊界 S800 豪华轿车官图
    发布时间: 2024-11-23T14:57:11.22
    新闻简介: 今天下午,鸿蒙智行官微公布了华为、江淮合作打造的“百万级”豪华轿车——尊界S800的官图, 海报上的宣传语为“时代旗舰”,该车将于 11 月 26 日华为 Mate 70 系列手机发布会公开亮相。
    ———————-
    标题: 小米 REDMI Watch 5 手表支持 1500nits 全局亮度、60Hz 刷新率
    发布时间: 2024-11-23T10:19:05.257
    新闻简介: 小米 REDMI Watch 5 手表将于 11 月 27 日 19:00 发布,新品配备 2.07 英寸 AMOLED 大屏,支持 1500nits 全局亮度、60Hz 刷新率,配备高质感金属表框、不锈钢旋转表冠。
    ———————-
    标题: 京东 11 月 27 日起下线京享值 6000 以上“运费双免”服务,PLUS 会员“免费退换货”不受影响
    发布时间: 2024-11-23T14:43:11.81
    新闻简介: 据京东会员页面,京东宣布“京享值 6000 以上“运费双免”专属服务计划于 2024 年 11 月 27 日停止服务”,而 PLUS 会员的“免费退换货”权益不受影响。
    ———————-
    标题: 消息称明年部分新机搭载 7000mAh 电池,快充有望支持百瓦
    发布时间: 2024-11-23T17:15:31.07
    新闻简介: 博主 @数码闲聊站 今日发文称,从供应链物料看,明年好几家新机会上 7000mAh,旗舰机也会用,高倍率电芯的快充有望干到百瓦;中端线容量一路疾驰,NPI(新产品导入)7500mAh-8000mAh。
    ———————-
    标题: 华为轮值董事长徐直军:鸿蒙生态就是基于 OpenHarmony 共建共享的生态
    发布时间: 2024-11-23T16:02:48.983
    新闻简介: 2024 年 11 月 23 日,华为轮值董事长徐直军在“新生态・新机遇”首届鸿蒙生态大会上发表题为“共建鸿蒙原生生态共创产业星辰大海”的致辞。
    ———————-
    标题: 张国全:小米 14 系列手机已全量推送澎湃 OS 2
    发布时间: 2024-11-23T14:50:08.793
    新闻简介: 小米手机系统软件部总监张国全昨晚发文确认,小米 14 系列手机已全量推送澎湃 OS 2。IT之家注意到,小米澎湃 OS 2 正式版于 11 月 9 日起面向小米 14 系列(小米 14 / Pro / Pro 钛金属版 / Ultra)开始推送。
    ———————-
    标题: 消息称苹果 iPhone 17/17 Air 手机依然没有 5 倍光学变焦镜头
    发布时间: 2024-11-23T06:47:54.757
    新闻简介: 支持 5 倍光学变焦的四棱镜相机系统将在明年的 iPhone 17 / Pro 系列中继续为 Pro 系列独享,这意味着将仅在 iPhone 17 Pro 和 iPhone 17 Pro Max 上提供。(The Elec)
    ———————-
    标题: 消息称英伟达 RTX 5090 显卡 GPU 尺寸比 RTX 4090 的大 22%,仅次于 TU102
    发布时间: 2024-11-23T08:58:37.143
    新闻简介: 爆料称,RTX 5090 显卡搭载的 GB202 GPU 尺寸为 24*31mm,也就是 744mm²。而目前英伟达 RTX 4090 搭载的 AD102 GPU 尺寸为 608 mm²。
    ———————-
    标题: 荣耀 300 Ultra 手机外观曝光:曲面屏设计,镜头 Deco 印有红色标识
    发布时间: 2024-11-23T10:04:38.607
    新闻简介: 在荣耀 300 标准版、Pro 版外观相继公布之后,博主 @数码闲聊站 还曝光了一款荣耀 300 Ultra 手机外观。
    ———————-
    标题: 苹果 iPhone 16 获 DxOMark 147 分超三星 Galaxy S24 Ultra:HDR 照片明亮有活力、肤色自然准确
    发布时间: 2024-11-23T19:41:05.237
    新闻简介: IT之家 11 月 23 日消息,DxOMARK 公布了 苹果 iPhone 16的影像测试得分。经过测试,苹果 iPhone 16以 147 分的总分位列排行榜第 20 名。
    ———————-
    标题: 【IT之家评测室】努比亚 Z70 Ultra 上手:不一样、不跟随、不无聊的真全面屏旗舰
    发布时间: 2024-11-23T13:48:26.06
    新闻简介: 努比亚 Z70 Ultra 非常适合那些热衷于“不跟随”的用户,“与众不同”是他们的人生信仰,那么这款产品也是如此
    ———————-

    —- IT之家新闻 End —-

  • Docker 搭建 nas 导航 heimdall


    共计 579 个字符,预计需要花费 2 分钟才能阅读完成。

    如果玩 nas,肯定有一堆的 web 应用,那么就要记非常多的端口号,这是一件非常麻烦的事情。

    今天介绍的 heimdall 是一款专为 nas 设计的导航程序,你只需要简单安装即可使用,并且非常美观,甚至应用的图标都是内置的,省去了非常多的麻烦。

    搭建命令如下:

    docker run -d \
    --name=heimdall \
    -p 80:80 \
    -p 443:443 \
    -v /home/docker/heimdall/config:/config \
    --restart unless-stopped \
    linuxserver/heimdall:latest

    打开页面,看见红色的提示不要慌,这是提示还没有添加任何的应用。

    Docker 搭建 nas 导航 heimdall

    />

    点击右下角的设置,这里可以设置语言、背景图片等等,清朝云这里将其修改为中文。

    Docker 搭建 nas 导航 heimdall

    />

    如果要添加应用,那么点击右侧的应用列表即可添加。

    Docker 搭建 nas 导航 heimdall

    />

    进入添加界面后,直接输入应用名称和网址,并可以选择颜色,如果你喜欢的话,并且可以在这挑选你的应用图标。

    比如,清朝云准备添加一个 jellyfin 的导航应用,其实 heimdall 能够自动识别常用的,比如我这里只需要选择它提示的 jellyfin,那么它就可以自动填充图标和应用描述等等。

    Docker 搭建 nas 导航 heimdall

    />

    此外,针对特殊的应用,还可以进行特殊的配置,比如配置账号密码,让点击即可登录,或者配置密钥可以在 heimdall 获取一些展示数据等。

    Docker 搭建 nas 导航 heimdall

    />

    然后输入网址,点击保存即可,效果如图所示:

    Docker 搭建 nas 导航 heimdall

    提醒:本文发布于479天前,文中所关联的信息可能已发生改变,请知悉!

    />

    Tips:清朝云网络工作室