若依源码分析

一.登录

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(){@Overridepublic 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)]

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

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

相关文章

【注解和反射】--03 类的加载、ClassLoader

反射 【Class】哪些类型可以有Class对象&#xff1f; class&#xff1a;外部类&#xff0c;成员(成员内部类&#xff0c;静态内部类)&#xff0c;局部内部类&#xff0c;匿名内部类interface&#xff1a;接口[]&#xff1a;数组enum&#xff1a;枚举annotation&#xff1a;注…

Windows系统下载安装并连接Redis

首先 我们访问地址 https://github.com/tporadowski/redis/releases 这里 我们根据自己的系统选择下载 我是 Windows msi安装包 下载下来之后 我们双击它运行 然后下一步 然后这里要同意它的条款 反正不同意不给用嘛 就这么简单 勾选之后 选择下一步 这里 我们要选一下他的安装…

探讨前端技术的未来:创新与适应的必要性

一、引言 2023年&#xff0c;IT圈似乎被一种悲观的论调所笼罩&#xff0c;那就是“Java 已死、前端已凉”。然而&#xff0c;真相是否如此呢&#xff1f;本文将围绕这一主题&#xff0c;探讨前端的现状和未来发展趋势。 二、为什么会出现“前端已死”的言论 这一言论的出现并…

紫禁城的雪花飞舞

在寂静的冬日&#xff0c;紫禁城迎来了它最美丽的时刻。一场突如其来的大雪&#xff0c;将故宫的每一砖每一瓦都覆盖在白色的雪被之下&#xff0c;仿佛将历史的痕迹都掩藏在一片纯净之中。 雪花纷纷扬扬&#xff0c;宛如历史的画卷在眼前徐徐展开。每一片雪花都像是从古人的诗…

嵌入式系统挑战赛---多线程并发打印奇偶数

一、题目要求 编写一个C语言程序&#xff0c;实现多线程并发打印奇偶数。要求使用两个线程&#xff0c;一个线程打印奇数&#xff0c;另一个线程打印偶数&#xff0c;打印范围为1到100。要求奇数线程先打印&#xff0c;偶数线程后打印&#xff0c;且要保证线程按次序交替进行。…

神通数据库字段空与非空

神通数据库可以在建表时指定字段非空或可空&#xff0c; -- 指定column1字段非空 CREATE TABLE SYSDBA.tmp_test1(column1 varchar(100) NOT NULL)--尝试向column1字段插入空值 INSERT INTO SYSDBA.tmp_test1(column1) VALUES(NULL) 会收到插入失败的提示&#xff1a; 而如果…

Three.js中文网1-12入门案例

Three.js中文网 <template><div id"webgl"></div> </template><script setup> import * as THREE from three; import { OrbitControls } from three/addons/controls/OrbitControls.js;// 创建3D场景对象Scene const scene new THR…

我对迁移学习的一点理解——领域适应(系列3)

文章目录 1. 领域适应&#xff08;Domain Adaptation&#xff09;的基本概念2.领域适应&#xff08;Domain Adaptation&#xff09;的目标3.领域适应&#xff08;Domain Adaptation&#xff09;的实现方法4.领域适应&#xff08;Domain Adaptation&#xff09;的可以解决的问题…

JVM的内存分区以及垃圾收集

1.JVM的内存分区 1.1方法区 方法区(永久代&#xff09;主要用来存储已在虚拟机加载的类的信息、常量、静态变量以及即时编译器编译后的代码信息。该区域是被线程共享的。 1.2虚拟机栈 虚拟机栈也就是我们平时说的栈内存&#xff0c;它是为java方法服务的。每个方法在执行的…

vue2项目vue-qrcode-reader 扫一扫二维码插件

vue2项目 vue-qrcode-reader 扫一扫二维码插件 问题所在解决办法成功展示 问题所在 今天在引导师弟做扫二维码功能&#xff0c;发现通过npm install --save vue-qrcode-reade安装死活就是报错TypeError: Object...) is not a function 解决办法 百度了很多大牛的博客&#…

LeetCode(61)删除链表的倒数第 N 个结点【链表】【中等】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 删除链表的倒数第 N 个结点 1.题目 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5]示例…

如何用Adobe Audition 检测波形的pop和卡顿

在Adobe Audition中&#xff0c;检测卡顿和pop的方法各有不同&#xff1a; 1. **检测卡顿**&#xff1a; - 使用“诊断”面板中的“删除静音”或“标记音频”选项可以帮助识别音频中的静音段落&#xff0c;这可能表明存在卡顿。 - 配置诊断设置&#xff0c;指定静音的振…