若依源码分析

一.登录

1.1 生成验证码

基本思路

在这里插入图片描述

  • 后端生成一个表达式,7+4=?@11

  • 7+4=?转成图片,传到前端进行展示

  • 将结果11存入redis

    在这里插入图片描述

  • 前端代码实现:

    在这里插入图片描述

    请求后端地址:http://localhost/dev-api/captchaImage,通过反向代理解决前后端跨域问题,将请求路径变为:http://localhost:8080/captchaImage

    在这里插入图片描述

  • 后端代码实现:

    /**
     * 生成验证码
     */
    @GetMapping("/captchaImage")
    public AjaxResult getCode(HttpServletResponse response) throws IOException
    {
        AjaxResult ajax = AjaxResult.success();
        boolean captchaEnabled = configService.selectCaptchaEnabled();
        ajax.put("captchaEnabled", captchaEnabled);
        if (!captchaEnabled)
        {
            return ajax;
        }
    
        // 保存验证码信息
        String uuid = IdUtils.simpleUUID();
        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
    
        String capStr = null, code = null;
        BufferedImage image = null;
    
        // 生成验证码
        String captchaType = RuoYiConfig.getCaptchaType();
        if ("math".equals(captchaType))
        {
            String capText = captchaProducerMath.createText();
            capStr = capText.substring(0, capText.lastIndexOf("@"));
            code = capText.substring(capText.lastIndexOf("@") + 1);
            image = captchaProducerMath.createImage(capStr);
        }
        else if ("char".equals(captchaType))
        {
            capStr = code = captchaProducer.createText();
            image = captchaProducer.createImage(capStr);
        }
    
        redisCache.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
        // 转换流信息写出
        FastByteArrayOutputStream os = new FastByteArrayOutputStream();
        try
        {
            ImageIO.write(image, "jpg", os);
        }
        catch (IOException e)
        {
            return AjaxResult.error(e.getMessage());
        }
    
        ajax.put("uuid", uuid);
        ajax.put("img", Base64.encode(os.toByteArray()));
        return ajax;
    }
    

1.2 登录

  • 后端

    • 1.校验验证码
    • 2.校验用户名和密码
    • 3.生成ToKen
    /**
     * 登录方法
     * 
     * @param loginBody 登录信息
     * @return 结果
     */
    @PostMapping("/login")
    public AjaxResult login(@RequestBody LoginBody loginBody)
    {
        AjaxResult ajax = AjaxResult.success();
        // 生成令牌
        String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
                                          loginBody.getUuid());
        ajax.put(Constants.TOKEN, token);
        return ajax;
    }
    

    使用异步任务管理器,结合线程池,实现了异步的操作日志记录,和业务逻辑实现异步解耦合.

1.3 获取用户信息

/**
 * 获取用户信息
 * 
 * @return 用户信息
 */
@GetMapping("getInfo")
public AjaxResult getInfo()
{
    SysUser user = SecurityUtils.getLoginUser().getUser();
    // 角色集合
    Set<String> roles = permissionService.getRolePermission(user); // 超级管理员
    // 权限集合
    Set<String> permissions = permissionService.getMenuPermission(user); // *:*:*
    AjaxResult ajax = AjaxResult.success();
    ajax.put("user", user);
    ajax.put("roles", roles);
    ajax.put("permissions", permissions);
    return ajax;
}

获取当前用户的角色和权限信息,存储到Vuex中

1.4 获取路由信息

根据当前用户的权限信息获取动态路由,最终完成动态菜单的展示

/**
 * 获取路由信息
 * 
 * @return 路由信息
 */
@GetMapping("getRouters")
public AjaxResult getRouters()
{
    Long userId = SecurityUtils.getUserId();
    List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
    return AjaxResult.success(menuService.buildMenus(menus));
}

二.首页加载

在这里插入图片描述

在这里插入图片描述

当用户登录成功以后我们可以根据路由看出,默认跳转到路由/viees/index.vue页面

三.用户管理

3.1 查询

流程:加载vue页面 -> 请求后台数据

在这里插入图片描述

  • 获取用户信息后端

    /**
     * 获取用户列表
     */
    @PreAuthorize("@ss.hasPermi('system:user:list')")
    @GetMapping("/list")
    public TableDataInfo list(SysUser user)
    {
        startPage(); // 做分页
        List<SysUser> list = userService.selectUserList(user); // 查询数据
        return getDataTable(list); // 返回结果
    }
    
  • 获取树状图后端

    /**
     * 获取部门树列表
     */
    @PreAuthorize("@ss.hasPermi('system:user:list')")
    @GetMapping("/deptTree")
    public AjaxResult deptTree(SysDept dept)
    {
        return success(deptService.selectDeptTreeList(dept));
    }
    

3.2 添加用户

  • 前端
/** 新增按钮操作 */
handleAdd() {
    this.reset();// 清空表单
    getUser().then(response => {
        this.postOptions = response.posts;// 岗位
        this.roleOptions = response.roles;// 角色
        this.open = true;
        this.title = "添加用户";
        this.form.password = this.initPassword;
    });
},
    /** 提交按钮 */
    submitForm: function() {
        this.$refs["form"].validate(valid => {
            if (valid) {
                if (this.form.userId != undefined) {
                    updateUser(this.form).then(response => {
                        this.$modal.msgSuccess("修改成功");
                        this.open = false;
                        this.getList();
                    });
                } else {
                    addUser(this.form).then(response => {
                        this.$modal.msgSuccess("新增成功");
                        this.open = false;
                        this.getList();
                    });
                }
            }
        });
    },
  • 后端
/**
 * 根据用户编号获取详细信息
 */
@PreAuthorize("@ss.hasPermi('system:user:query')")
@GetMapping(value = { "/", "/{userId}" })
public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId)
{
    userService.checkUserDataScope(userId);
    AjaxResult ajax = AjaxResult.success();
    List<SysRole> roles = roleService.selectRoleAll();
    ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
    ajax.put("posts", postService.selectPostAll());
    if (StringUtils.isNotNull(userId))
    {
        SysUser sysUser = userService.selectUserById(userId);
        ajax.put(AjaxResult.DATA_TAG, sysUser);
        ajax.put("postIds", postService.selectPostListByUserId(userId));
        ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList()));
    }
    return ajax;
}

/**
 * 新增用户
 */
@PreAuthorize("@ss.hasPermi('system:user:add')")
@Log(title = "用户管理", businessType = BusinessType.INSERT)
@PostMapping
public AjaxResult add(@Validated @RequestBody SysUser user)
{
    if (!userService.checkUserNameUnique(user))
    {
        return error("新增用户'" + user.getUserName() + "'失败,登录账号已存在");
    }
    else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
    {
        return error("新增用户'" + user.getUserName() + "'失败,手机号码已存在");
    }
    else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
    {
        return error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在");
    }
    user.setCreateBy(getUsername());
    user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
    return toAjax(userService.insertUser(user));
}

修改和删除查看源码步骤相同,这里省略

四.异步任务管理器

这里选取一段代码作示例:com.ruoyi.framework.web.service.SysLoginService

AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));

通过异步任务管理器记录登录日志

  • AsyncManager.me():获取一个AsyncManager对象
  • 执行execute方法,传入的是一个Task对象,实现了Runnable接口表示是一个任务,由线程Thread去执行
/**
 * 记录登录信息
 * 
 * @param username 用户名
 * @param status 状态
 * @param message 消息
 * @param args 列表
 * @return 任务task
 */
public static TimerTask recordLogininfor(final String username, final String status, final String message,
                                         final Object... args)
{
    final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
    final String ip = IpUtils.getIpAddr();
    return new TimerTask()
    {
        @Override
        public void run()
        {
            String address = AddressUtils.getRealAddressByIP(ip);
            StringBuilder s = new StringBuilder();
            s.append(LogUtils.getBlock(ip));
            s.append(address);
            s.append(LogUtils.getBlock(username));
            s.append(LogUtils.getBlock(status));
            s.append(LogUtils.getBlock(message));
            // 打印信息到日志
            sys_user_logger.info(s.toString(), args);
            // 获取客户端操作系统
            String os = userAgent.getOperatingSystem().getName();
            // 获取客户端浏览器
            String browser = userAgent.getBrowser().getName();
            // 封装对象
            SysLogininfor logininfor = new SysLogininfor();
            logininfor.setUserName(username);
            logininfor.setIpaddr(ip);
            logininfor.setLoginLocation(address);
            logininfor.setBrowser(browser);
            logininfor.setOs(os);
            logininfor.setMsg(message);
            // 日志状态
            if (StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER))
            {
                logininfor.setStatus(Constants.SUCCESS);
            }
            else if (Constants.LOGIN_FAIL.equals(status))
            {
                logininfor.setStatus(Constants.FAIL);
            }
            // 插入数据
            SpringUtils.getBean(ISysLogininforService.class).insertLogininfor(logininfor);
        }
    };
}

封装了登录用户的信息,执行添加操作,这里不会执行,而是将任务交给线程对象来执行

异步任务管理器,内部定义了一个线程池,然后根据业务创建添加日志的任务,交给线程池来处理,这样做到日志和业务的抽象,解耦合,日志全部统一处理.

五.代码自动生成

5.1 创建数据表

use ry_vue;
create table test_user
(
    id       int primary key auto_increment,
    name     varchar(11),
    password varchar(11)
);

5.2 系统工具–>代码生成

在这里插入图片描述

5.2.1 导入数据表

在这里插入图片描述

5.2.2 编辑数据表

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

5.2.3 点击生成代码

在这里插入图片描述

5.2.4 解压压缩包

在这里插入图片描述

5.2.5 导入代码,重启项目
  • 后端

在这里插入图片描述

  • 前端

在这里插入图片描述

  • 数据库

2364434953)]

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

038.Python面向对象_三大特性综合案例1

我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448; 入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448; 虚 拟 环 境 搭 建 &#xff1a;&#x1f449;&…

开源贡献世纪榜评选揭晓,TDengine 成功入选并亮相 FICC 开源计算机系统大会

12 月 3-6 日&#xff0c;2023 国际测试委员会智能计算机与芯片联邦大会&#xff08;FICC&#xff09;在海南三亚举行&#xff0c;本次大会主要分为四个会议&#xff1a;芯片大会&#xff0c;智能计算机、算法与应用大会&#xff0c;开源计算机系统大会&#xff0c;测试基准与标…

注册与回调

C 再论无处不在的回调机制---注册与回调 回调函数的作用和用途&#xff0c;我就不多说了&#xff0c;之前也讨论过&#xff0c; 现在再来熟悉一下与回调函数相关的程序。 我们知道&#xff0c; 回调机制&#xff0c; 就是通过函数指针来实现的。 说白了&#xff0c; 就是注册与…

算法-05-二分查找

二分查找&#xff08;Binary Search&#xff09;算法&#xff0c;也叫折半查找算法&#xff0c;是一种针对有序数据集合的查找算法。 1-二分查找的思想 我们生活中猜数字的游戏&#xff0c;告诉你一个数据范围&#xff0c;比如0-100&#xff0c;然后你说出一个数字&#xff0c…

【lesson8】表的约束(1)

文章目录 表的约束的介绍空属性约束&#xff08;null&#xff09;和非空属性约束测试建表插入测试 默认值约束测试建表测试 建表查看默认行为建表插入测试 表的约束的介绍 真正约束字段的是数据类型&#xff0c;但是数据类型约束很单一&#xff0c;需要有一些额外的约束&#…

LeetCode-交换链表中节点的问题

两两交换链表中的节点 题目描述&#xff1a; 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。 思路&#xff1a; 首先将整个链…

MinGW编译Ptyhon至pyd踩坑整理

注意需要魔法 用scoop自动安装配置MinGw 需要魔法&#xff0c;不需要手动配置mingw scoop install mingw安装Cython&#xff0c;Setuptools第三方库 关闭魔法&#xff0c;使用清华源 pip install setuptools -i https://pypi.tuna.tsinghua.edu.cn/simple pip install cyt…

800万纯AI战士年末大集结,硬核干货与音乐美食12月28日准时开炫

回望2023年&#xff0c;大语言模型或许将是科技史上最浓墨重彩的一笔。从技术、产业到生态&#xff0c;大语言模型在突飞猛进中加速重构万物。随着理解、生成、逻辑、记忆四大能力显著提升&#xff0c;大语言模型为通用人工智能带来曙光。 AI开发者们正在用算法和代码书写一个美…

Python简单网抑云数据采集 JS逆向

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 环境使用: Python 3.10 Pycharm 模块使用: requests -> pip install requests execjs -> pip install execjs 爬虫实现基本思路流程: 一. 数据来源分析: 明确需求: 明确采集的网站以及数据内容 网址: https://mu…

【java】java类/方法冲突解决工具

目录下查找包含特定名称&#xff08;如&#xff1a;类名称&#xff09;的Jar包 上代码&#xff1a; 比如要查找含有类 “org/apache/avro/Schema” 的&#xff1a; # 方法一 # 此方法只能查找到内容&#xff08;比如&#xff1a;类名称&#xff09;。但是不能打印jar名称 fi…

大数据Vue项目必备|Window下安装并使用nvm(含卸载node、卸载nvm、全局安装npm)

大数据Vue项目必备|Window下安装并使用nvm&#xff08;含卸载node、卸载nvm、全局安装npm&#xff09; 一、卸载旧版本 如果已经安装了node&#xff0c;那么需要先卸载node&#xff0c;如果没有安装那可以直接跳过这一步。 卸载&#xff1a;   打开控制面板 -> 打开程序和…

2个实用的快速涨粉视频号数据分析平台

很多人在做视频号的视频总不知道怎么利用视频号进行数据分析以及如何涨粉&#xff1f;今天就说两个视频号数据分析平台 可以查询各项爆款数据&#xff0c;什么账号大火、什么领域热大家都在关心什么快速了解。 1&#xff1a;视频号助手&#xff08;https://channels.weixin.q…

一文了解什么是Selenium自动化测试?

一、Selenium是什么&#xff1f; 用官网的一句话来讲&#xff1a;Selenium automates browsers. Thats it&#xff01;简单来讲&#xff0c;Selenium是一个用于Web应用程序自动化测试工具。Selenium测试直接运行在浏览器中&#xff0c;就像真正的用户在操作浏览器一样。支持的浏…

手把手搭建腾讯云服务器教程(新手必看)

使用腾讯云服务器搭建网站全流程&#xff0c;包括轻量应用服务器和云服务器CVM建站教程&#xff0c;轻量可以使用应用镜像一键建站&#xff0c;云服务器CVM可以通过安装宝塔面板的方式来搭建网站&#xff0c;腾讯云服务器网txyfwq.com分享使用腾讯云服务器建站教程&#xff0c;…

社区团购行业分析:未来在门店拓展上还有很大的发展空间

社区团购是真实居住社区内居民团体的一种互联网线上线下购物消费行为&#xff0c;是依托真实社区的一种区域化、小众化、本地化、网络化的团购形式。简而言之&#xff0c;它是依托社区和团长社交关系实现生鲜商品流通的新零售模式。 社区团购&#xff0c;是指一定数量的消费者通…

Android 蓝牙BluetoothAdapter 相关(一)

Android 蓝牙相关 本文主要讲述android 蓝牙的简单使用. 1: 是否支持蓝牙 /*** 是否支持蓝牙** return*/ private boolean isSupportBluetooth() {BluetoothAdapter bluetoothAdapter BluetoothAdapter.getDefaultAdapter();return bluetoothAdapter ! null; }2: 开启蓝牙 …

消息队列kafka详解:Kafka架构介绍

一. 工作流程 Kafka中消息是以topic进行分类的&#xff0c;Producer生产消息&#xff0c;Consumer消费消息&#xff0c;都是面向topic的。 Topic是逻辑上的改变&#xff0c;Partition是物理上的概念&#xff0c;每个Partition对应着一个log文件&#xff0c;该log文件中存储的就…

智能优化算法应用:基于花授粉算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于花授粉算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于花授粉算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.花授粉算法4.实验参数设定5.算法结果6.参考文…

C++学习笔记(十一)------has_a和use_a关系

文章目录 前言 一、has_a关系 1.1 has_a概念 1.2 has_a中构造和析构的顺序 1.3 has_a对象的内存情况 二、use_a关系&#xff08;友元关系&#xff09; 1.友元函数&#xff1a; 2.友元类 3 使用多文件编程的方式重新编辑上述代码 总结 前言 随着技术的革新&#xff0c;出现各种各…

信奥赛 1310:【例2.2】车厢重组

本题解析&#xff1a;根据上述的要求&#xff0c;转化为程序的解题方案&#xff0c;就是用到了冒泡排序。本题中求的是旋转次数&#xff0c;实际上就是冒泡排序中交换的次数。 本题考察的知识点是&#xff1a;冒泡排序的用法。 参考代码&#xff1a; 上述代码仅供参考&#xff…