设计模式之责任链模式(Chain Of Responsibility)

news2024/12/22 11:07:50

一、责任链模式介绍

1、责任链模式介绍

      职责链模式(chain of responsibility pattern) 定义: 避免将一个请求的发送者与接收者耦合在

      一起,让多个对象都有机会处理请求。将接收请求的对象连接成一条链,并且沿着这条链

     传递请求,直到有一个对象能够处理它为止。

     在职责链模式中,多个处理器(也就是刚刚定义中说的“接收对象”)依次处理同一个请 求。

     一个请求先经过 A 处理器处理,然后再把请求传递给 B 处理器,B 处理器处理完后再 传递

     给 C 处理器,以此类推,形成一个链条。链条上的每个处理器各自承担各自的处理职 责,

     所以叫作职责链模式。如下图所示:

             

二、责任链模式原理

1、责任链模式结构

      责任链模式结构图如下:

              

      责任链模式包含如下角色:

             1)抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和

                   一个后继连接(链上的每个处理者都有一个成员变量来保存对于下一处理者的引用,

                   比如上图中的successor) 。

             2)具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否

                   处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。

             3)客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不

                  关心处理细节和请求的传递过程。

2、责任链模式用代码表示

      责任链模式的实现非常简单,每一个具体的处理类都会保存在它之后的下一个处理类。

      当处理完成后,就会调用设置好的下一个处理类,直到最后一个处理类不再设置下一个

      处理类,这时处理链条全部完成。   

/*******************************************************
 * 封装请求数据
 *
 * @author lbf
 * 
 *******************************************************/
public class RequestData {
    private String data;

    public RequestData(String data) {
        this.data = data;
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }
}


/*******************************************************
 * 抽象处理者类
 *
 * @author lbf
 * 
 *******************************************************/
public abstract class Handler {

    //下一处理者的引用
    protected Handler successor = null;

    public void setSuccessor(Handler successor){
        this.successor = successor;
    }

    //抽象方法,由具体处理者实现,
    // 每个具体处里者的行为可能都不相同
    public abstract void handle(RequestData requestData);
}



/*******************************************************
 * 具体处里者A
 * @author lbf
 * @date 2024-11-10 21:26
 *******************************************************/
public class HandlerA extends Handler{

    @Override
    public void handle(RequestData requestData) {
        System.out.println("HandlerA 执行代码逻辑! 处理: " + requestData.getData());

        requestData.setData(requestData.getData().replace("A",""));

        if(successor != null){
            successor.handle(requestData);
        }else{
            System.out.println("执行中止!");
        }
    }
}

/*******************************************************
 * 具体处理者B
 * @author lbf
 * 
 *******************************************************/
public class HandlerB extends Handler{

    @Override
    public void handle(RequestData requestData) {
        System.out.println("HandlerB 执行代码逻辑! 处理: " + requestData.getData());

        requestData.setData(requestData.getData().replace("B",""));

        if(successor != null){
            successor.handle(requestData);
        }else{
            System.out.println("执行中止!");
        }
    }
}


/*******************************************************
 * 具体处理者C
 * @author lbf
 *
 *******************************************************/
public class HandlerC extends Handler{

    @Override
    public void handle(RequestData requestData) {
        System.out.println("HandlerC 执行代码逻辑! 处理: " + requestData.getData());

        requestData.setData(requestData.getData());

        if(successor != null){
            successor.handle(requestData);
        }else{
            System.out.println("执行中止!");
        }
    }
}



/*******************************************************
 *
 * @author lbf
 * 
 *******************************************************/
public class Test {

    public static void main(String[] args) {
        Handler h1 = new HandlerA();
        Handler h2 = new HandlerB();
        Handler h3 = new HandlerC();
        h1.setSuccessor(h2);
        h2.setSuccessor(h3);
        RequestData requestData = new RequestData("请求数据ABCDE");
        h1.handle(requestData);
    }
}

三、责任链模式使用示例

       下面以业务审批流程为例,来看下责任链模式的使用:

        审批的过程会有不同级别的负责人加入进行审批(平常系统上线只需三级负责人审批即可,

        但在一些特殊日期会有其他层级的人临时加入审批,如:双十一前后需要二级或一级审核

       人参与审批),接下来我们就使用职责链模式来设计一下此功能。

1、不使用设计模式实现

      多个负责人的审批流程都在一个方法中按先后顺序完成,示例代码如下:

/*******************************************************
 * 审核信息
 * @author lbf
 * 
 *******************************************************/
public class AuthInfo {

    private String code;

    private String info ="";

    public AuthInfo(String code, String... infos) {
        this.code = code;
        for (String str : infos) {
            info = this.info.concat(str +" ");
        }
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getInfo() {
        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }

    @Override
    public String toString() {
        return "AuthInfo{" +
                "code='" + code + '\'' +
                ", info='" + info + '\'' +
                '}';
    }
}



/*******************************************************
 * 模拟审核服务
 * @author lbf
 * 
 *******************************************************/
public class AuthService {

    //审批信息 审批人Id+申请单Id
    private static Map<String, Date> authMap = new HashMap<String, Date>();

    /**
     * 审核流程
     * @param uId    审核人id
     * @param orderId  审核单id
     */
    public static void auth(String uId, String orderId){
        System.out.println("进入审批流程,审批人ID: " + uId);
        authMap.put(uId.concat(orderId),new Date());
    }

    //查询审核结果
    public static Date queryAuthInfo(String uId, String orderId){
        return authMap.get(uId.concat(orderId)); //key=审核人id+审核单子id
    }
}


/*******************************************************
 * 审核接口
 * @author lbf
 * 
 *******************************************************/
public class AuthController {

    //审核
    public AuthInfo doAuth(String name, String orderId, Date authDate) throws ParseException {

        //三级审批
        Date date = null;
        //查询是否存在审核信息,查询条件: 审核人ID+订单ID,返回Map集合中的Date
        date = AuthService.queryAuthInfo("1000013", orderId);

        //如果为空,封装AuthInfo信息(待审核)返回
        if(date == null){
            return new AuthInfo("0001","单号: "+orderId,"状态: 等待三级审批负责人进行审批");
        }

        //二级审批
        SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");// 时间格式化
        //二级审核人主要审核双十一之前, 11-01 ~ 11-10号的请求,所以要对传入的审核时间进行判断
        //审核时间 大于 2022-11-01 并且  小于 2022-11-10,Date1.after(Date2),当Date1大于Date2时,返回TRUE,Date1.before(Date2),当Date1小于Date2时,返回TRUE
        if(authDate.after(f.parse("2022-11-01 00:00:00")) && authDate.before(f.parse("2022-11-10 00:00:00"))){
            //条件成立,查询二级审核的审核信息
            date = AuthService.queryAuthInfo("1000012",orderId);

            //如果为空,还是待二级审核人审核状态
            if(date == null){
                return new AuthInfo("0001","单号: "+orderId,"状态: 等待二级审批负责人进行审批");
            }
        }

        //一级审批
        //审核范围是在11-11日 ~ 11-31日
        if(authDate.after(f.parse("2022-11-11 00:00:00")) && authDate.before(f.parse("2022-11-31 00:00:00"))){
            date = AuthService.queryAuthInfo("1000011",orderId);
            if(date == null){
                return new AuthInfo("0001","单号: "+orderId,"状态: 等待一级审批负责人进行审批");
            }
        }


        return new AuthInfo("0001","单号: "+orderId,"申请人:"+ name +", 状态: 审批完成!");
    }
}


/*******************************************************
 * 模拟客户端测试
 * @author lbf
 * 
 *******************************************************/
public class Test {

    public static void main(String[] args) throws ParseException {

        AuthController controller = new AuthController();

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = sdf.parse("2022-11-12 00:00:00");

        //设置申请流程

        //三级审核
        //1.调用doAuth方法,模拟发送申请人相关信息
        AuthInfo info1 = controller.doAuth("研发小周", "100001000010000", date);
        System.out.println("当前审核状态:  " + info1.getInfo());

        /**
         * 2.模拟进行审核操作, 虚拟审核人ID: 1000013
         * 调用auth() 方法进行审核操作, 就是向Map中添加一个 审核人ID和申请单ID
         */
        AuthService.auth("1000013", "100001000010000");
        System.out.println("三级负责人审批完成,审批人: 王工");

        System.out.println("===========================================================================");

        //二级审核
        //1.调用doAuth方法,模拟发送申请人相关信息
        AuthInfo info2 = controller.doAuth("研发小周", "100001000010000", date);
        System.out.println("当前审核状态:  " + info2.getInfo());

        /**
         * 2.模拟进行审核操作, 虚拟审核人ID: 1000012
         * 调用auth() 方法进行审核操作, 就是向Map中添加一个 审核人ID和申请单ID
         */
        AuthService.auth("1000012", "100001000010000");
        System.out.println("二级负责人审批完成,审批人: 张经理");

        System.out.println("===========================================================================");

        //一级审核
        //1.调用doAuth方法,模拟发送申请人相关信息
        AuthInfo info3 = controller.doAuth("研发小周", "100001000010000", date);
        System.out.println("当前审核状态:  " + info3.getInfo());

        /**
         * 2.模拟进行审核操作, 虚拟审核人ID: 1000012
         * 调用auth() 方法进行审核操作, 就是向Map中添加一个 审核人ID和申请单ID
         */
        AuthService.auth("1000011", "100001000010000");
        System.out.println("一级负责人审批完成,审批人: 罗总");
    }
}

2、使用责任链模式优化上边的代码

      统一抽象类AuthLink 下 有三个子类,将三个子类的执行通过编排,模拟出一条链路,这个

      链路就是业务中的责任链。如下图所示:

             

      示例代码如下:

/*******************************************************
 * 抽象审核练类
 * @author lbf
 * 
 *******************************************************/
public abstract class AuthLink {
    protected Logger logger = LoggerFactory.getLogger(AuthLink.class);

    protected SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    protected String levelUserId;      //审核人ID
    protected String levelUserName;   //审核人姓名
    protected AuthLink next;          //持有下一个处理类的引用

    public AuthLink(String levelUserId, String levelUserName) {
        this.levelUserId = levelUserId;
        this.levelUserName = levelUserName;
    }

    //获取下一个处理类
    public AuthLink getNext() {
        return next;
    }

    //责任链中添加处理类
    public AuthLink appendNext(AuthLink next) {
        this.next = next;
        return this;
    }

    //抽象审核方法
    //审核方法
    public abstract AuthInfo doAuth(String uId, String orderId, Date authDate);
}



/*******************************************************
 * 一级负责人--具体处理者1
 * @author lbf
 * 
 *******************************************************/
public class Level1AuthLink extends AuthLink{

    private Date beginDate = f.parse("2020-11-11 00:00:00");
    private Date endDate = f.parse("2020-11-31 23:59:59");

    public Level1AuthLink(String levelUserId, String levelUserName) throws ParseException {
        super(levelUserId, levelUserName);
    }

    @Override
    public AuthInfo doAuth(String uId, String orderId, Date authDate) {
        Date date = AuthService.queryAuthInfo(levelUserId, orderId);
        if (null == date) {
            return new AuthInfo("0001", "单号:", orderId, " 状态:待一级审批负责人 ", levelUserName);
        }
        AuthLink next = super.getNext();
        if (null == next) {
            return new AuthInfo("0000", "单号:", orderId, " 状态:一级审批完成", " 时间:", f.format(date), " 审批人:", levelUserName);
        }
        if (authDate.before(beginDate) || authDate.after(endDate)) {
            return new AuthInfo("0000", "单号:", orderId, " 状态:一级审批完成", " 时间:", f.format(date), " 审批人:", levelUserName);
        }
        return next.doAuth(uId, orderId, authDate);
    }
}




/*******************************************************
 * 二级负责人--具体处理者2
 * @author lbf
 * 
 *******************************************************/
public class Level2AuthLink extends AuthLink{

    private Date beginDate = f.parse("2020-11-11 00:00:00");
    private Date endDate = f.parse("2020-11-31 23:59:59");

    public Level2AuthLink(String levelUserId, String levelUserName) throws ParseException {
        super(levelUserId, levelUserName);
    }

    public AuthInfo doAuth(String uId, String orderId, Date authDate) {
        Date date = AuthService.queryAuthInfo(levelUserId, orderId);
        if (null == date) {
            return new AuthInfo("0001", "单号:", orderId, " 状态:待二级审批负责人 ", levelUserName);
        }
        AuthLink next = super.getNext();
        if (null == next) {
            return new AuthInfo("0000", "单号:", orderId, " 状态:二级审批完成", " 时间:", f.format(date), " 审批人:", levelUserName);
        }

        if (authDate.before(beginDate) || authDate.after(endDate) ) {
            return new AuthInfo("0000", "单号:", orderId, " 状态:二级审批完成", " 时间:", f.format(date), " 审批人:", levelUserName);
        }

        return next.doAuth(uId, orderId, authDate);
    }
}



/*******************************************************
 * 三级负责人--具体处理者3
 * @author lbf
 * 
 *******************************************************/
public class Level3AuthLink extends AuthLink{

    public Level3AuthLink(String levelUserId, String levelUserName) {
        super(levelUserId, levelUserName);
    }

    public AuthInfo doAuth(String uId, String orderId, Date authDate) {
        Date date = AuthService.queryAuthInfo(levelUserId, orderId);
        if (null == date) {
            return new AuthInfo("0001", "单号:", orderId, " 状态:待三级审批负责人 ", levelUserName);
        }
        AuthLink next = super.getNext();
        if (null == next) {
            return new AuthInfo("0000", "单号:", orderId, " 状态:三级审批完成", " 时间:", f.format(date), " 审批人:", levelUserName);
        }

        return next.doAuth(uId, orderId, authDate);
    }
}



/*******************************************************
 * 模拟客户类测试
 * @author lbf
 * 
 *******************************************************/
public class Test {

    protected static Logger logger = LoggerFactory.getLogger(Test.class);
    public static void main(String[] args) throws ParseException {

        AuthLink authLink = new Level3AuthLink("1000013", "王工")
                .appendNext(new Level2AuthLink("1000012", "张经理"))
                .appendNext(new Level1AuthLink("1000011", "段总"));

        SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date currentDate = f.parse("2020-11-18 23:49:46");

        logger.info("测试结果:{}", JSON.toJSONString(authLink.doAuth("研发牛马", "1000998004813441", currentDate)));

        // 模拟三级负责人审批
        AuthService.auth("1000013", "1000998004813441");
        logger.info("测试结果:{}", "模拟三级负责人审批,王工");
        logger.info("测试结果:{}", JSON.toJSONString(authLink.doAuth("研发牛马", "1000998004813441", currentDate)));

        // 模拟二级负责人审批
        AuthService.auth("1000012", "1000998004813441");
        logger.info("测试结果:{}", "模拟二级负责人审批,张经理");
        logger.info("测试结果:{}", JSON.toJSONString(authLink.doAuth("研发牛马", "1000998004813441", currentDate)));

        // 模拟一级负责人审批
        AuthService.auth("1000011", "1000998004813441");
        logger.info("测试结果:{}", "模拟一级负责人审批,段总");
        logger.info("测试结果:{}", JSON.toJSONString(authLink.doAuth("研发牛马", "1000998004813441", currentDate)));
    }
}

       当工作流程发生变化,可以动态地改变链内的成员或者修改它们的次序,也可动态地新增

       或者删除责任。并且每个类只需要处理自己该处理的工作,不能处理的传递给下一个对象

       完成,明确各类的责任范围,符合类的单一职责原则。

四、责任链模式总结

1、责任链模式优点

      1)降低了对象之间的耦合度,该模式降低了请求发送者和接收者的耦合度。

      2)增强了系统的可扩展性,可以根据需要增加新的请求处理类,满足开闭原则。

      3)增强了给对象指派职责的灵活性,当工作流程发生变化,可以动态地改变链内的成员

            或者修改它们的次序,也可动态地新增或者删除责任。

      4)责任链简化了对象之间的连接,个对象只需保持一个指向其后继者的引用,不需保持

           其他所有处理者的引用,这避免了使用众多的 if 或者 if···else 语句。

      5)责任分担,每个类只需要处理自己该处理的工作,不能处理的传递给下一个对象完成,

            明确各类的责任范围,符合类的单一职责原则。

2、责任链模式缺点

      1)不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定

            会被处理,该请求可能一直传到链的末端都得不到处理。

      2)对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。

      3)职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链

           的错误设置而导致系统出错,如可能会造成循环调用。

      

3、责任链模式适用场景

      1)在运行时需要动态使用多个关联对象来处理同一次请求时。比如,请假流程、员工入

           职流程、编译打包发布上线流程等。

      2)不想让使用者知道具体的处理逻辑时。比如,做权限校验的登录拦截器。

      3)需要动态更换处理对象时。比如,工单处理系统、网关 API 过滤规则系统等。

      4)职责链模式常被用在框架开发中,用来实现框架的过滤器、拦截器功能,让框架的使用者在不修改源码的情况下,添加新的过滤拦截功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2240853.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【月之暗面kimi-注册/登录安全分析报告】

前言 由于网站注册入口容易被机器执行自动化程序攻击&#xff0c;存在如下风险&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露&#xff0c;不符合国家等级保护的要求。短信盗刷带来的拒绝服务风险 &#xff0c;造成用户无法登陆、注册&#xff0c;大量收到垃圾短信的…

低代码牵手 AI 接口:开启智能化开发新征程

一、低代码与 AI 接口的结合趋势 低代码开发平台近年来在软件开发领域迅速崛起。随着企业数字化转型的需求不断增长&#xff0c;低代码开发平台以其快速构建应用程序的优势&#xff0c;满足了企业对高效开发的需求。例如&#xff0c;启效云低代码平台通过范式化和高颗粒度的可配…

安培环路定理

回忆 静电场中的回路定理&#xff1a;→静电场是保守场 安培环路定理 1、圆形回路包围无限长载流直导线 &#xff08;1&#xff09;回路逆时针 &#xff08;2&#xff09;回路顺时针 规定&#xff1a; 回路正向由右手螺旋定则判断&#xff08;根据回路绕行方向&#xff0c;…

IDEA 2024.3正式版发布,速览新功能!

0 前言 IntelliJ IDEA 2024.3 引入了一系列可以提升您的开发体验的强大新功能。 IDE 现在提供代码逻辑结构的表示&#xff0c;简化了 Kubernetes 应用程序的调试体验&#xff0c;引入了集群范围的 Kubernetes 日志访问。 1 关键亮点 1.1 Structure工具窗口中的 Logical代码结…

LabVIEW 实现 find_nearest_neighbors 功能(二维平面上的最近邻查找)

1. 背景介绍 在数据分析和图像处理领域&#xff0c;经常需要查找给定点的最近邻居点。在LabVIEW中&#xff0c;计算二维平面上多个点之间的欧氏距离&#xff0c;并返回距离最近的几个点是一种常见操作。find_nearest_neighbors 函数用于实现这个功能。 2. 欧氏距离计算 在二维…

LeetCode 单调栈 下一个更大元素 I

下一个更大元素 I nums1 中数字 x 的 下一个更大元素 是指 x 在 nums2 中对应位置 右侧 的 第一个 比 x 大的元素。 给你两个 没有重复元素 的数组 nums1 和 nums2 &#xff0c;下标从 0 开始计数&#xff0c;其中nums1 是 nums2 的子集。 对于每个 0 < i < nums1.length…

vue的组件使用

1.安装element plus组件库 npm install element-plus --save

2024-11-14 算法学习及论文辅导(每日更新,随时联系)

看看学习小群的学习氛围&#x1f447;&#x1f3fb; 很多同学自己学习遇到问题没人解决&#xff0c;最终消耗了时间&#xff0c;精力同时大大消耗了自己对学习的信心&#x1f627; &#x1f973;来看看跟班学习&#xff0c;大家遇到问题的时候是怎么解决的&#xff1a; 首先…

开源三代示波器的高速波形刷新方案开源,支持VNC远程桌面,手机,Pad,电脑均可访问(2024-11-11)

说明&#xff1a; 1、本来这段时间是一年一度Hackaday硬件设计开源盛宴&#xff0c;但hackaday电子大赛在去年终结了。所以我开源个我的吧。 2、三代示波器的高速波形刷新方案&#xff0c;前两年就做好了&#xff0c;这两年忙H7-TOOL的更新比较多&#xff0c;三代示波器的更新…

B-树特点以及插入、删除数据过程

B树&#xff08;B-Tree&#xff09;是一种自平衡的多路查找树&#xff0c;它广泛应用于数据库索引和文件系统中&#xff0c;尤其适用于外部存储设备&#xff08;如磁盘&#xff09;。B树的设计使得它能够高效地存储大量数据并支持高效的插入、删除和查询操作。以下是B树的主要特…

微信小程序自定义tabbar;禁用某个tab;修改某个tab的样式

微信小程序自定义tabbar&#xff1b;禁用某个tab&#xff1b;修改某个tab的样式 原本使用本身的tabBar就已经很舒服了&#xff0c;很合适了的&#xff0c;但是总有一些脑洞大开的产品和客户&#xff0c;给你搞点多样式&#xff0c;没办法牛马就得去做咯&#xff0c;现在就给大…

操作系统——内存段式和段页式管理

目录 一、为什么要有段式管理&#xff1f; 二、段式管理的实现原理 1、段式虚拟空间 2、段式管理的内存分配与释放 3、段式管理的地址变换 &#xff08;1&#xff09;段表 &#xff08;2&#xff09;动态地址变换 4、段的共享与保护 &#xff08;1&#xff09;共享 &a…

【C#设计模式(10)——装饰器模式(Decorator Pattern)】

前言 装饰器模式可以在运行时为对象添加额外的功&#xff0c;而无需修改原始对象的代码。这种方式比继承更加灵活。 代码 //蛋糕类&#xff08;抽象类&#xff09; public abstract class Cake {public abstract void Create(); } //奶油蛋糕类 public class CreamCake : Cak…

千图网 AI 绘画平台——智能图像创作工具

抖知书老师推荐&#xff1a; ​千图网的AI图像处理工具已经上线有一段时间了&#xff0c;随着AI技术的不断提升&#xff0c;越来越多的设计师和创意工作者开始接受并使用这个高效的工具。最初对于AI会影响创作行业的担忧&#xff0c;现在也逐渐消散了。设计师们依然在创造&…

【前端】技术演进发展简史

一、前端 1、概述 1990 年&#xff0c;第一个web浏览器诞生&#xff0c;Tim 以超文本语言 HTML 为基础在 NeXT 电脑上发明了最原始的 Web 浏览器。 1991 年&#xff0c;WWW诞生&#xff0c;这标志着前端技术的开始。 前端&#xff08;Front-end&#xff09;和后端&#xff08;…

【C#设计模式(4)——构建者模式(Builder Pattern)】

前言 C#设计模式(4)——构建者模式(Builder Pattern) 运行结果 代码 public class Computer {private string part1 "CPU";private string part2 "主板";private string part3 "内存";private string part4 "显卡";private st…

android studio导入OpenCv并改造成.kts版本

1.下载opencv Android版本 2.解压导入android studio,我这里是先导入低版本的,还是gradle,直接导入module,我这里是4.2.0的版本 我的as版本是Android Studio Electric Eel 2022.1.1 Patch 2,我导入直接就能用 //load OpenCV engine and init OpenCV library //这里放在oncreat…

【easily-openJCL】要尝试下用 显卡 做数据对称加密吗?

easily-openJCL 要尝试下用 显卡 做数据对称加密吗&#xff1f; 开源技术栏 本文演示了一个案例&#xff0c;使用显卡进行数据加密哦&#xff0c;加密方法是 XOR 目录 文章目录 easily-openJCL 要尝试下用 显卡 做数据对称加密吗&#xff1f;目录开始导入项目库加密操作解密…

挖到宝了!统一dlp数据防泄漏解决方案有哪些?千字长文带你熟知这6款!

信息外泄、内部疏忽、离职泄密、黑客入侵、系统漏洞、第三方风险&#xff0c;这些司空见惯的企业数据泄漏问题&#xff0c;无一不牵动着企业的神经&#xff0c;考验着企业的数据安全防线。 今天&#xff0c;我们就来深挖几款统一dlp数据防泄漏解决方案&#xff0c;帮助企业筑起…

wflow-web:开源啦 ,高仿钉钉、飞书、企业微信的审批流程设计器,轻松打造属于你的工作流设计器

嗨&#xff0c;大家好&#xff0c;我是小华同学&#xff0c;关注我们获得“最新、最全、最优质”开源项目和高效工作学习方法 wflow-web是一个开源的工作流设计器&#xff0c;它支持可视化拖拽表单组件&#xff0c;动态任意层级结构审批节点&#xff0c;以及复杂流程条件的设置…