群控系统服务端开发模式-应用开发-登录退出发送邮件

一、登录成功发送邮件

        在根目录下app文件夹下controller文件夹下common文件夹下,修改Login.php,代码如下

<?php
/*** 登录退出操作* User: 龙哥·三年风水* Date: 2024/10/29* Time: 15:53*/
namespace app\controller\common;
use app\controller\Emptys;
use app\model\permission\Admin;
use app\model\param\System as SystemModel;
use Email\EmailSender;
use Redis\Redis;
use app\model\common\Token as TokenModel;
use Encipher\Encrypt;
class Login extends Emptys
{//验证码展示public function getCode(){$re = app()->make(\Other\Captcha::class)->create();$base64 = 'data:image/png;base64,' . base64_encode($re->getData());return succ('SUCCESS',$base64);}//登录public function doLogin(){$param = $this->request->param();$validate = new \app\validate\common\Login;$result = $validate->check($param);//参数验证if (!$result) return err($validate->getError());//验证码的正确性if (!app()->make(\Other\Captcha::class)->check($param['captcha_code'])) return err('验证码错误');if (time() + 5 < strtotime($param['login_time'])) return err('非法登录');$resData = Admin::dataFind(['email' => trim($param['username'])], 'id,realname,password,ip,status', true);//用户信息的正确性if (empty($resData) && empty($resData['id'])) return err('用户不存在');if ($resData['status'] !== 1) return err('该账号已被禁用');$systemParam = SystemModel::dataFind(['id' => 1],'security_password,platform_token_expira');if ($resData['password'] !== sha1($param['password'] . $systemParam['security_password'])) return err('账号对应的密码错误');if(!empty($resData['ip'])){if($resData['ip'] != $this->request->header('x-real-ip'))return err('禁止访问,不在IP白名单中');}//写入Token日志$data['token_type'] = 1;$data['menu_name'] = 'CommonLoginDoLogin';$data['admin_id'] = $resData['id'];$data['random_number'] = alnum();$data['create_time'] = date('Y-m-d',strtotime($param['login_time']));$data['login_time'] = $param['login_time'];$data['expire_time'] = strtotime($param['login_time']) + $systemParam['platform_token_expira'];$token = $data['admin_id'] . $data['random_number'];$data['token'] = sha1(sha1($token) . strtotime($data['login_time']));TokenModel::save($data,[]);//加入跨站攻击验证队列Redis::select(config('cache.stores.redis.token_db'))->setex('token_' . $data['token'],$systemParam['platform_token_expira'],$resData['id']);Redis::select(config('cache.stores.redis.token_db'))->setex('token_' . $resData['id'],$systemParam['platform_token_expira'],Encrypt::encryptRsa($data['token']));$emailSender = new EmailSender();$emailSender::send($param['username'],'登录系统',$resData['realname'].'于'.$param['login_time'].'登录系统');return succ('登录成功',Encrypt::encryptRsa($token));}
}

二、退出成功发送邮件

        1、更改前端apijs文件

                在根目录下src文件夹下api文件夹下,修改common.js文件,代码如下:

// 退出
export function logout() {return request({url: '/permission/member/logout',method: 'post'})
}

        2、后端api更改路由

                在根目录下route文件夹下,修改app.php文件,代码如下:

<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2018 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
use think\facade\Route;Route::get('think', function () {return 'hello,ThinkPHP6!';
});
Route::post('index/index','Index/index');// 测试使用
Route::post('index/generate_rsa','Index/generateRsa');// 生成rsa公私钥文件使用
// 特殊操作
Route::get('login/get_code', 'common.Login/getCode');// 获取验证码使用
Route::post('login/do_login', 'common.Login/doLogin');// 登录提交接口
Route::post('upload/file','common.Upload/file');// 上传文件接口
Route::post('publics/get_info','common.Publics/getInfo');// 获取公有数据接口
Route::group('permission',function (){// 个人资料Route::post('member/personal_data','permission.Member/personalData');// 获取个人信息接口Route::post('member/personal_menu','permission.Member/personalMenu');// 获取个人菜单接口Route::post('member/update_personal','permission.Member/updatePersonal');// 修改个人信息接口Route::post('member/logout', 'permission.Member/logout');// 退出登录接口// 管理员操作Route::get('admin/get_list','permission.Admin/getList');// 获取管理员列表Route::post('admin/get_all','permission.Admin/getAll');// 获取管理员所有数据Route::post('admin/get_info','permission.Admin/getInfo');// 获取管理员单条数据Route::post('admin/save_info','permission.Admin/saveInfo');// 保存管理员数据Route::post('admin/status_info','permission.Admin/statusInfo');// 启禁用管理员Route::post('admin/delete_info','permission.Admin/deleteInfo');// 删除管理员// 角色操作Route::get('role/get_list','permission.Role/getList');// 获取角色列表Route::post('role/get_all','permission.Role/getAll');// 获取所有角色数据Route::post('role/get_info','permission.Role/getInfo');// 获取单个角色数据Route::post('role/save_info','permission.Role/saveInfo');// 保存角色数据Route::post('role/status_info','permission.Role/statusInfo');// 启禁用角色数据Route::post('role/delete_info','permission.Role/deleteInfo');// 删除角色数据// 菜单操作Route::post('menu/get_all','permission.Menu/getAll');// 获取所有菜单数据Route::post('menu/get_info','permission.Menu/getInfo');// 获取单个菜单数据Route::post('menu/save_info','permission.Menu/saveInfo');// 保存菜单数据Route::post('menu/status_info','permission.Menu/statusInfo');// 启禁用菜单数据Route::post('menu/delete_info','permission.Menu/deleteInfo');// 删除菜单数据});
Route::group('param',function (){//系统配置Route::post('system/get_info','param.System/getInfo');// 获取系统参数数据Route::post('system/save_info','param.System/saveInfo');// 保存系统参数数据//上传配置Route::post('upload/get_info','param.Upload/getInfo');// 获取上传参数数据Route::post('upload/save_info','param.Upload/saveInfo');// 保存上传参数数据//短信配置Route::post('channel_sms/get_info','param.ChannelSms/getInfo');// 获取邮箱短信参数数据Route::post('channel_sms/save_info','param.ChannelSms/saveInfo');// 保存邮箱短信参数数据//邮件配置Route::post('channel_email/get_info','param.ChannelEmail/getInfo');// 获取邮箱短信参数数据Route::post('channel_email/save_info','param.ChannelEmail/saveInfo');// 保存邮箱短信参数数据// 图片格式操作Route::get('image/get_list','param.Image/getList');// 获取图片格式列表Route::post('image/get_all','param.Image/getAll');// 获取所有图片格式数据Route::post('image/get_info','param.Image/getInfo');// 获取单个图片格式数据Route::post('image/save_info','param.Image/saveInfo');// 保存图片格式数据Route::post('image/status_info','param.Image/statusInfo');// 启禁用图片格式数据Route::post('image/delete_info','param.Image/deleteInfo');// 删除图片格式数据// 视频格式操作Route::get('video/get_list','param.Video/getList');// 获取视频格式列表Route::post('video/get_all','param.Video/getAll');// 获取所有视频格式数据Route::post('video/get_info','param.Video/getInfo');// 获取单个视频格式数据Route::post('video/save_info','param.Video/saveInfo');// 保存视频格式数据Route::post('video/status_info','param.Video/statusInfo');// 启禁用视频格式数据Route::post('video/delete_info','param.Video/deleteInfo');// 删除视频格式数据// 文件格式操作Route::get('filedoc/get_list','param.Filedoc/getList');// 获取文件格式列表Route::post('filedoc/get_all','param.Filedoc/getAll');// 获取所有文件格式数据Route::post('filedoc/get_info','param.Filedoc/getInfo');// 获取单个文件格式数据Route::post('filedoc/save_info','param.Filedoc/saveInfo');// 保存文件格式数据Route::post('filedoc/status_info','param.Filedoc/statusInfo');// 启禁用文件格式数据Route::post('filedoc/delete_info','param.Filedoc/deleteInfo');// 删除文件格式数据// 部门配置操作Route::get('department/get_list','param.Department/getList');// 获取部门配置列表Route::post('department/get_all','param.Department/getAll');// 获取所有部门配置数据Route::post('department/get_info','param.Department/getInfo');// 获取单个部门配置数据Route::post('department/save_info','param.Department/saveInfo');// 保存部门配置数据Route::post('department/status_info','param.Department/statusInfo');// 启禁用部门配置数据Route::post('department/delete_info','param.Department/deleteInfo');// 删除部门配置数据// 级别配置操作Route::get('grade/get_list','param.Grade/getList');// 获取级别配置列表Route::post('grade/get_all','param.Grade/getAll');// 获取所有级别配置数据Route::post('grade/get_info','param.Grade/getInfo');// 获取单个级别配置数据Route::post('grade/save_info','param.Grade/saveInfo');// 保存级别配置数据Route::post('grade/status_info','param.Grade/statusInfo');// 启禁用级别配置数据Route::post('grade/delete_info','param.Grade/deleteInfo');// 删除级别配置数据// 邮箱配置操作Route::get('sms/get_list','param.Sms/getList');// 获取短信配置列表Route::post('sms/get_all','param.Sms/getAll');// 获取所有短信配置数据Route::post('sms/get_info','param.Sms/getInfo');// 获取单个短信配置数据Route::post('sms/save_info','param.Sms/saveInfo');// 保存短信配置数据Route::post('sms/status_info','param.Sms/statusInfo');// 启禁用短信配置数据Route::post('sms/delete_info','param.Sms/deleteInfo');// 删除短信配置数据
});
Route::miss('Emptys/index');

        3、添加退出方法

                在根目录下app文件夹下controller文件夹下permission文件夹下,修改Member.php文件,代码如下:

<?php
/*** 个人信息控制-也就是登录者信息及角色对外方法* User: 龙哥·三年风水* Date: 2024/10/30* Time: 14:18*/
namespace app\controller\permission;
use app\controller\Base;
use app\model\param\Department as PDModel;
use app\model\param\Grade as PGModel;
use app\model\permission\Role as PRModel;
use app\model\param\System as PSModel;
use app\model\permission\Admin as PAModel;
use Other\Tree;
use Redis\Redis;
use app\model\permission\Menu as PMModel;
use Email\EmailSender;
use app\model\common\Token as TokenModel;
class Member extends Base
{/*** 获取个人信息* User: 龙哥·三年风水* Date: 2024/10/30* Time: 14:23* @ return \think\response\Json*/public function personalData(){$data = [];$data['username'] = $this->username;$data['avatar'] = $this->avatar;$data['email'] = $this->email;$data['realname'] = $this->realname;$data['ip'] = empty($this->ip) ? '' : $this->ip;$departmentTitle = PDModel::dataFind(['id' => $this->departmentId],'title',false);$data['department_title'] = empty($departmentTitle) ? '' : $departmentTitle;$gradeTitle = PGModel::dataFind(['id' => $this->gradeId],'title',false);$data['grade_title'] = empty($gradeTitle) ? '' : $gradeTitle;$data['rolename'] = PRModel::dataFind(['id' => $this->roleId],'rolename',false);$res = $this->getRoleMenu();$data['key'] = $res['key'];$data['butt'] = $res['butts'];return succ('操作成功',$data);}/*** 登录者菜单权限* User: 龙哥·三年风水* Date: 2024/11/5* Time: 17:32* @ return \think\response\Json*/public function personalMenu(){$listMenu = unserialize(Redis::select(config('cache.stores.redis.cache_db'))->get('menu_list'.$this->userId));if($listMenu === false){if(count($this->rules) == 0)$this->setAuth();$listMenu = PMModel::getAll([['id', 'in', $this->rules], ['status', '=', 1], ['is_menu', '=', 1]], 'id,menuname,pid,title,path,component,icon,redirect,always_show,is_hidden,is_icon,is_cache','sort DESC,id DESC');if(empty($listMenu)) return err("该用户没有权限");$seconds = rand(60,120);Redis::select(config('cache.stores.redis.cache_db'))->setex('menu_list'.$this->userId,$seconds,serialize($listMenu));}$data['menu'] = Tree::list_to_tree($listMenu,0, 'id', 'pid', 'children');return succ('操作成功',$data);}/*** 修改个人资料* User: 龙哥·三年风水* Date: 2024/11/5* Time: 9:31*/public function updatePersonal(){$param = $this->request->param();$validate = new \app\validate\permission\UpdateAdmin;$param['id'] = $this->userId;if (!$validate->check($param)) return err($validate->getError());if(!empty($param['password'])){$securityPassword = PSModel::dataFind(['id' => 1],'security_password')['security_password'];$data['password'] = sha1($param['password'] . $securityPassword);}$data['username'] = $param['username'];$data['avatar'] = empty($param['avatar']) ? $this->avatar : $param['avatar'];$data['realname'] = $param['realname'];$data['email'] = $param['email'];PAModel::redisSave($data, $this->userId);return succ('操作成功',[]);}//退出public function logout(){$redisToken = Redis::select(config('cache.stores.redis.token_db'))->get('token_' . $this->token);if(!empty($redisToken)){$emailSender = new EmailSender();$emailSender::send($this->email,'退出系统',$this->realname.'于'.date('Y-m-d H:i:s',time()).'退出系统');TokenModel::save(['expire_time' => time()], ['token' => $this->token]);Redis::select(config('cache.stores.redis.token_db'))->del('token_' . $redisToken);Redis::select(config('cache.stores.redis.token_db'))->del('token_' . $this->token);}return succ('退出成功');}
}

        4、删除登录文件里面的退出方法

                在根目录下app文件夹下controller文件夹下common文件夹下,修改Login.php文件,代码如下:

<?php
/*** 登录退出操作* User: 龙哥·三年风水* Date: 2024/10/29* Time: 15:53*/
namespace app\controller\common;
use app\controller\Emptys;
use app\model\permission\Admin;
use app\model\param\System as SystemModel;
use Email\EmailSender;
use Redis\Redis;
use app\model\common\Token as TokenModel;
use Encipher\Encrypt;
class Login extends Emptys
{//验证码展示public function getCode(){$re = app()->make(\Other\Captcha::class)->create();$base64 = 'data:image/png;base64,' . base64_encode($re->getData());return succ('SUCCESS',$base64);}//登录public function doLogin(){$param = $this->request->param();$validate = new \app\validate\common\Login;$result = $validate->check($param);//参数验证if (!$result) return err($validate->getError());//验证码的正确性if (!app()->make(\Other\Captcha::class)->check($param['captcha_code'])) return err('验证码错误');if (time() + 5 < strtotime($param['login_time'])) return err('非法登录');$resData = Admin::dataFind(['email' => trim($param['username'])], 'id,realname,password,ip,status', true);//用户信息的正确性if (empty($resData) && empty($resData['id'])) return err('用户不存在');if ($resData['status'] !== 1) return err('该账号已被禁用');$systemParam = SystemModel::dataFind(['id' => 1],'security_password,platform_token_expira');if ($resData['password'] !== sha1($param['password'] . $systemParam['security_password'])) return err('账号对应的密码错误');if(!empty($resData['ip'])){if($resData['ip'] != $this->request->header('x-real-ip'))return err('禁止访问,不在IP白名单中');}//写入Token日志$data['token_type'] = 1;$data['menu_name'] = 'CommonLoginDoLogin';$data['admin_id'] = $resData['id'];$data['random_number'] = alnum();$data['create_time'] = date('Y-m-d',strtotime($param['login_time']));$data['login_time'] = $param['login_time'];$data['expire_time'] = strtotime($param['login_time']) + $systemParam['platform_token_expira'];$token = $data['admin_id'] . $data['random_number'];$data['token'] = sha1(sha1($token) . strtotime($data['login_time']));TokenModel::save($data,[]);//加入跨站攻击验证队列Redis::select(config('cache.stores.redis.token_db'))->setex('token_' . $data['token'],$systemParam['platform_token_expira'],$resData['id']);Redis::select(config('cache.stores.redis.token_db'))->setex('token_' . $resData['id'],$systemParam['platform_token_expira'],Encrypt::encryptRsa($data['token']));$emailSender = new EmailSender();$emailSender::send($param['username'],'登录系统',$resData['realname'].'于'.$param['login_time'].'登录系统');return succ('登录成功',Encrypt::encryptRsa($token));}
}

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

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

相关文章

[游戏开发] Unity中使用FlatBuffer

什么是FlatBuffer 官网&#xff1a; GitHub - google/flatbuffers: FlatBuffers: Memory Efficient Serialization LibraryFlatBuffers: Memory Efficient Serialization Library - google/flatbuffershttps://github.com/google/flatbuffers 为什么用FloatBuffer&#xff0c…

MySQL其一,概念学习,可视化软件安装以及增删改查语句

目录 MySQL 1、数据库的概念 2、数据库分类 3、MySQL的安装 4、安装过程中的问题 DataGrip的使用&#xff1a; SQLynx的使用&#xff1a; 5、编写SQL语句 6、DDL语句 7、DML 新增数据&#xff1a; 删除数据&#xff1a; 修改数据&#xff1a; MySQL SQL其实是一门…

05 在 Linux 使用 AXI DMA

DMA简介 DMA 是一种采用硬件实现存储器与存储器之间或存储器与外设之间直接进行高速数据传输的技术&#xff0c;传输过程无需 CPU 参与&#xff08;但是CPU需要提前配置传输规则&#xff09;&#xff0c;可以大大减轻 CPU 的负担。 DMA 存储传输的过程如下&#xff1a; CPU 向…

linux 安装 vsftpd 服务以及配置全攻略,vsftpd 虚拟多用户多目录配置,为每个用户配置不同的使用权限

linux 安装 vsftpd 服务以及配置全攻略&#xff0c;vsftpd 虚拟多用户多目录配置&#xff0c;为每个用户配置不同的使用权限。 linux 安装 vsftpd 服务以及配置全攻略 FTP 是 File Transfer Protocol 的简称&#xff0c;用于 Internet 上的控制文件的双向传输。同时&#xff0…

SQL语句在MySQL中如何执行

MySQL的基础架构 首先就是客户端&#xff0c;其次Server服务层&#xff0c;大多数MySQL的核心服务都在这一层&#xff0c;包括连接、分析、优化、缓存以及所有的内置函数&#xff08;时间、日期、加密函数&#xff09;&#xff0c;所有跨存储引擎功能都在这一层实现&#xff1…

ragflow连不上ollama的解决方案

由于前期wsl默认装在C盘&#xff0c;后期部署好RagFlow后C盘爆红&#xff0c;在连接ollama的时候一直在转圈圈&#xff0c;问其他人没有遇到这种情况&#xff0c;猜测是因为内存不足无法加载模型导致&#xff0c;今天重新在E盘安装wsl 使用wsl装Ubuntu Win11 wsl-安装教程 如…

C#常见错误—空对象错误

System.NullReferenceException&#xff1a;未将对象引用设置到对象的实例 在C#编程中&#xff0c;System.NullReferenceException是一个常见的运行时异常&#xff0c;其错误信息“未将对象引用设置到对象的实例”意味着代码试图访问一个未被初始化或已被设置为null的对象的成…

沁恒CH32V208蓝牙串口透传例程:修改透传的串口;UART-CH32V208-APP代码分析;APP-CH32V208-UART代码分析

从事嵌入式单片机的工作算是符合我个人兴趣爱好的,当面对一个新的芯片我即想把芯片尽快搞懂完成项目赚钱,也想着能够把自己遇到的坑和注意事项记录下来,即方便自己后面查阅也可以分享给大家,这是一种冲动,但是这个或许并不是原厂希望的,尽管这样有可能会牺牲一些时间也有哪天原…

Scala的隐式对象

Scala中&#xff0c;隐式对象&#xff08;implicit object&#xff09;是一种特殊的对象&#xff0c;它可以使得其成员&#xff08;如方法和值&#xff09;在特定的上下文中自动可用&#xff0c;而无需显式地传递它们。隐式对象通常与隐式参数和隐式转换一起使用&#xff0c;以…

矩阵的乘(包括乘方)和除

矩阵的乘分为两种&#xff1a; 一种是高等代数中对矩阵的乘的定义&#xff1a;可以去这里看看包含矩阵的乘。总的来说&#xff0c;若矩阵 A s ∗ n A_{s*n} As∗n​列数和矩阵 B n ∗ t B_{n*t} Bn∗t​的行数相等&#xff0c;则 A A A和 B B B可相乘&#xff0c;得到一个矩阵 …

DVWA亲测sql注入漏洞

LOW等级 我们先输入1 我们加上一个单引号&#xff0c;页面报错 我们看一下源代码&#xff1a; <?php if( isset( $_REQUEST[ Submit ] ) ) { // Get input $id $_REQUEST[ id ]; // Check database $query "SELECT first_name, last_name FROM users WHERE user_id …

机器学习01-发展历史

机器学习01-发展历史 文章目录 机器学习01-发展历史1-传统机器学习的发展进展1. 初始阶段&#xff1a;统计学习和模式识别2. 集成方法和核方法的兴起3. 特征工程和模型优化4. 大规模数据和分布式计算5. 自动化机器学习和特征选择总结 2-隐马尔科夫链为什么不能解决较长上下文问…

想了解操作系统,有什么书籍推荐?

推荐一本操作系统经典书&#xff1a; 操作系统导论 《操作系统导论》虚拟化(virtualization)、并发(concurrency)和持久性(persistence)。这是我们要学习的3个关键概念。通过学习这3个概念&#xff0c;我们将理解操作系统是如何工作的&#xff0c;包括它如何决定接下来哪个程序…

[Collection与数据结构] 位图与布隆过滤器

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏: &#x1f9ca; Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection与…

微信小程序横屏页面跳转后,自定义navbar样式跑了?

文章目录 问题原因&#xff1a;解决方案&#xff1a; 今天刚遇到的问题&#xff0c;横屏的页面完成操作后跳转页面后&#xff0c;自定义的tabbar样式乱了&#xff0c;跑到最顶了&#xff0c;真机调试后发现navbar跑到手机状态栏了&#xff0c;它正常应该跟右边胶囊一行。 知道问…

Vivado ILA数据导出MATLAB分析

目录 ILA数据导出 分析方式一 分析方式二 有时候在系统调试时&#xff0c;数据在VIVADO窗口获取的信息有限&#xff0c;可结合MATLAB对已捕获的数据进行分析处理 ILA数据导出 选择信号&#xff0c;单击右键后&#xff0c;会有export ILA DATA选项&#xff0c;将其保存成CS…

《探索形象克隆:科技与未来的奇妙融合》

目录 一、什么是形象克隆 二、形象克隆的技术原理 三、形象克隆的发展现状 四、形象克隆的未来趋势 五、形象克隆的应用场景 六、形象克隆简单代码案例 Python 实现数字人形象克隆 Scratch 实现角色克隆效果&#xff08;以猫为例&#xff09; JavaScript 实现 Scratc…

MATLAB深度学习(七)——ResNet残差网络

一、ResNet网络 ResNet是深度残差网络的简称。其核心思想就是在&#xff0c;每两个网络层之间加入一个残差连接&#xff0c;缓解深层网络中的梯度消失问题 二、残差结构 在多层神经网络模型里&#xff0c;设想一个包含诺干层自网络&#xff0c;子网络的函数用H(x)来表示&#x…

前端入门之VUE--vue组件化编程

前言 VUE是前端用的最多的框架&#xff1b;这篇文章是本人大一上学习前端的笔记&#xff1b;欢迎点赞 收藏 关注&#xff0c;本人将会持续更新。 文章目录 2、Vue组件化编程2.1、组件2.2、基本使用2.2.1、VueComponent 2、Vue组件化编程 2.1、组件 组件&#xff1a;用来实现…

设计模式-装饰器模式(结构型)与责任链模式(行为型)对比,以及链式设计

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言1.装饰器模式1.1概念1.2作用1.3应用场景1.4特点1.5类与对象关系1.6实现 2责任链模式2.1概念2.2作用2.3应用场景2.4特点2.5类与对象关系2.6实现 3.对比总结 前言…