当前位置: 首页 > news >正文

若依前后端分离版,快速上手

 哈喽~大家好,这篇来看看若依前后端分离版,快速上手(肝了挺久的)

 🥇个人主页:个人主页​​​​​                                     

🥈 系列专栏:【Springboot和Vue全栈开发】

🥉与这篇相关的文章:                                   

JAVA进程和线程JAVA进程和线程-CSDN博客
HttpClient 入门使用示例HttpClient 入门使用示例-CSDN博客
Spring Task 快速入门Spring Task 快速入门-CSDN博客

目录

一、前言

1、什么是若依?

二、验证码

1、验证码前端实现

2、验证码后端实现

3、反向代理

三、登录后端实现

四、获取用户角色和权限

1、getInfo前端实现

2、getInfo后端实现

五、获取动态菜单路由

1、前端实现

2、后端实现

六、首页数据加载

七、用户数据分页

八、部门树状图

九、添加用户数据

1、回显数据

2、新增操作

十、修改用户信息

十一、删除用户

十二、异步任务管理器

十三、代码自动生成器


一、前言

1、什么是若依?

若依框架(RuoYi)是一套基于Java开发的快速开发框架,它提供了许多常用的功能模块和工具,包括用户管理、部门管理、角色管理、菜单管理、字典管理、系统监控、定时任务等。若依框架采用了MVC(Model-View-Controller)的架构模式,使用了Spring Boot、MyBatis等流行的开源框架,可以帮助开发者快速搭建企业级的后台管理系统。若依框架还提供了许多可视化的操作界面,使得开发者可以方便地进行系统配置和管理。

二、验证码

1、验证码前端实现

在运行成功之后前端会自动进入到后台管理系统界面,然后发送一个验证码的一个请求“captchaImage”,打开前端代码login.vue里面的created方法。

之后执行getCodeImg生成一张图片显示在网页上。

验证码的验证规则是怎样的呢?

在后端会直接生成一个表达式,例如:1+1=2,那么就会将这个格式转换为 1+1=?@2 ,1+1=? 转成图片,传到前端进行展示,而将2 存入 Reids里面,我们看看后端代码。

2、验证码后端实现

在CaptchaController控制器类中的getCode方法大哥断点,这里就显示的将1+1=2的格式转为1+1=?@2。

然后将key(就是verifyKey)与value(是code)还有设置验证码有效期(分钟)、存储到redis里面,前端验证验证码就直接从redis里面进行验证。

3、反向代理

前端代码是80端口,后台代码是8080端口,但是我们F12打开控制台来查看,为什么localhost没有带端口号呢?为什么又多了一个dev-api的路径呢?

在前端的vue.config.js文件当中,这里的作用是反向代理,路径重写。

    proxy: { // 反向代理,8080 -> 80// detail: https://cli.vuejs.org/config/#devserver-proxy[process.env.VUE_APP_BASE_API]: {target: `http://localhost:8080`,changeOrigin: true,pathRewrite: { // 路径重写['^' + process.env.VUE_APP_BASE_API]: '' // 替换为空,然后再映射}}},

其中里面有一块是VUE_APP_BASE_API,这个开发环境,在其后面添加路径为 /dev-api 。

三、登录后端实现

找到login方法,首先它会进行验证码校验,对当期的用户名进行验证,首先先判断验证码是否为空,然后转载redis里面拿出键值,进行用户输入的验证码与redis取出来的进行对比,输入错误抛出异常,然后发出一个异步请求来记录登录信息(记录打印信息到日志、获取客户端操作系统、获取客户端浏览器、对象)然后将数据插入进去。

然后登录前置校验,检验(用户名或密码为空、密码如果不在指定范围内、IP黑名单校验)。

登录操作查询出来用户存在(账号与密码都正确),然后插入当前用户的操作、记录登录信息、生成token(返回给前端)。

四、获取用户角色和权限

在输入完正确的用户名、密码、验证码,我们可以看到一个名为getInfo的请求。

1、getInfo前端实现

这其实是个全局获取当用户登录之后会立即发送,作用是获取当前用户的角色和权限信息,并且存储到 Vuex 中,这个在permission.js 文件当中。

扩:vue中 router.beforeEach() 的作用——router.beforeEach 是全局钩子函数,它是在路由跳转之前所调用的函数,在实际开发中页面进度条的加载、设置页面标题、判断用户是否已经登录过了等等都可以在该函数中执行。

点击GetInfo进去看看,GetInfo是一个方法其作用是获取用户信息。

货到最上面getInfo是来自/api/login文件下的,进去看看,这里就是发起请求的路径了,方式为get。

2、getInfo后端实现

进入到控制层getInfo方法。

getRolePermission:查询当前用户的角色信息,是管理员add("admin"),不是的话,去数据库里面查找用户。

getMenuPermission:查询用户的权限信息。

如果是管理员就是 *:*:* (获取全部的权限,菜单:目录:按钮),不是的话去数据库里面查找权限。

然后将获取到的user、roles、permissions封装到AjaxResult里面返回给前端。

前端如何解析后端返回的数据呢?

在之前的GetInfo方法里面的commit(将值存储到vuex里面),将信息解析出来,渲染到页面上面。

五、获取动态菜单路由

我们看到左边的菜单栏是动态生成的,不是直接写死在页面上面,不同的用户有不同的权限,就有不同的菜单,这个是如何实现的呢?

1、前端实现

控制台有一个getRouters请求,很明显这个就是实现动态菜单的请求了,而且这个貌似与上面的getInfo一样,是全局路由?

打开permission.js文件很明显GenerateRoutes这个就是我们要找的,进去看看,同样的生成路由,从后端获取信息解析。

但是getRouters是在/api/menu目录下的,去看看,一个发起请求的路径。

2、后端实现

这里猜一下,菜单实现的方法是什么?——递归,我们找的getRouters,来看看。

selectMenuTreeAll:查找管理员的权限对应的菜单数据。

selectMenuTreeByUserId:查找不是管理员的权限对应的菜单数据。

一直追踪selectMenuTreeAll 一直到mapper文件,找到sql,直接cv到navicat 运行看看啥效果。

其中sys_menu 这张表有menu_id与parent_id,这两个就是分辨哪个是哪个的子菜单,parent_id为0的就是父菜单,最最顶上面的。

将查出来的值menus与0(0的值就是parentId,先查找父菜单)传到getChildPerms方法里面。

迭代list里面的值的getParentId,如果等于parentId值,那就是父菜单。

然后开始递归(方法为recursionFn),思路一样,如果list里面的值的getParentId,如果等于parentId值,那就是找到了对应的父菜单;这样一级一级的组成一个类似链表的一个结构,最后返回给控制层一个List<SysMenu>类型的数据,封装成AjaxResult,返回给前端。

前端将AjaxResult一个一个组装成路由字符串,转换为组件对象。

六、首页数据加载

登录完成之后,会直接进入到首页这个是怎么实现的呢?

在handleLogin方法里面,当用户登录成功之后直接重定向到“/”。

这个路径对应到哪呢?

其实是router里面的index.js文件。

点击进去看看

<navbar/> 导航栏

<app-main/>首页

找到Sidebar文件的index.js,里面可以看到有一个v-for,这个就是之前的,动态菜单后端传来的数据通过循环一个一个渲染到页面上面的。

七、用户数据分页

进入到页面之后,我们点击用户管理,其中会发送一个list请求加上分页信息pageNum=1&pageSize=10,这个是如何实现的呢?

找到对应的index文件。

数据在页面加载的时候就出来了,这肯定一初始化有关(created()方法)。

this.getList():获取用户管理数据。

this.getDeptTree():获取旁边的部门信息。

listUser向后端发起请求,后端接收。

找到list。

startPage():设置请求分页数据。

selectUserList():查找用户信息。

getDataTable():响应请求分页数据

利用分页插件(PageHelper)将响应请求分页数据返回给前端。

其中:

1、startPage()

PageHelper 中的 reasonable 对参数进行逻辑处理,保 证参数的正确性, pageNum = 0/-1,pageNum = 1

2、userService.selectUserList(user);

注解 @DataScope(deptAlias = "d", userAlias = "u") 给表设置别名的,sys_dept d,sys_user u

八、部门树状图

在前面写到,当页面初始化的时候,会直接加载三个方法,其中getDeptTree就是查出所有的部门数据。

进入user.js里面,路径是/system/user/deptTree,直接到后端查找。

进入控制层进入到selectDeptTreeList里面看看。

其中selectDeptList方法是查询部门管理数据,buildDeptTreeSelect是构建前端所需要下拉树结构,将selectDeptList查询出来的结果depts传给buildDeptTreeSelect。

其中buildDeptTree是构建前端所需要树结构,里面看到了老面孔——recursionFn,逻辑与前面一样,如果父节点等于子节点,那么子节点就是父节点的子菜单。

recursionFn:递归列表。

然后将结果返回给前端,前端再解析出来。

九、添加用户数据

1、回显数据

在user/index.vue里面找到新增按钮的方法,其中里面有一个名为reset,他的作用是在打开的新增表单重置。

然后里面getUser方法,点进去,很熟悉前面讲过的,只是后面加了个参数(userId),路径为/system/user/userId,传给后端。

后端控制层找到方法GetMapping,接受无路径与有路径为userId

checkUserDataScope:校验用户是否有数据权限。

selectRoleAll:查询所有角色。

selectPostAll:查询所有岗位。

将这些数据回显到页面上去,也就是现在我们能看到的归属部门、岗位、角色所选的下拉列表。

然后再根据用户ID查询用户(selectUserById),然后将数据封装返回给前端。

2、新增操作

将基本信息填写完成之后,点击确定按钮数据提交给后端。

通过点击事件找到方法

新增与修改请求路径如下。

控制层先做判断(登录账号已存在、手机号码已存在、邮箱账号已存在),然后设置登录用户名、对密码进行加密(密码默认的是123456)。

然后直接向DB(sys_user表)插入数据。

然后新增用户岗位关联(insertUserPost)、新增用户与角色管理(insertUserRole)

其实就是对三张表进行新增操作(sys_user、sys_user_post、sys_user_role)。

十、修改用户信息

找到修改按钮然后找到对应的点击事件方法——updateUser,同样的数据回显查询用户详细数据,然后数据回显在页面上,这里就不做过多的描述了。

点击确定,触发updateUser,携带数据到后端路径为/system/user。

点击updateUser,进入到业务层,发现这个不是和新增操作一样吗?对修改的逻辑就是先删除=后进行新增操作。

十一、删除用户

找到删除的点击事件——handleDelete,路径为/system/user/userId,发送给后端,后端接收请求。

首先先判断是否为当前正在操作的用户(也就是本人,本人操作肯定是不能删除的了)。

如果没有问题执行业务层,然后校验用户是否允许操作(checkUserAllowed 结果是     不允许操作超级管理员用户)、校验用户是否有数据权限(checkUserDataScope 结果是   没有权限访问用户数据)、然后删除用户与角色关联(deleteUserRole)、删除用户与岗位关联(deleteUserPost)、批量删除用户信息(deleteUserByIds)。

注意这里的批量删除用户信息不是真的删除而是一个逻辑删除,也就是修改他的状态del_flag为2。

十二、异步任务管理器

打开后端找到login的控制层点击login进入到业务层,在业务层中有一行这样的代码。

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

一看就很高级,那么他有什么作用呢?

给出结论:通过异步任务管理器记录登录日志。

首先AsyncManager进去看看里面有啥?一个异步任务管理器。找到me(),是个静态方法,return 了一个me,看看上面 懒汉式单例模式,分配异步任务。

那么就是AsyncManager.me() 获取一个 AsycnManager 对象。

然后执行 execute 方法,执行任务,传入的是一个 Task 对象(就是AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")),这么大长一段,并设置操作延迟10毫秒。

TimerTask实现了TimerTask接口,由线程 Thread 去执行。

那么recordLogininfor的作用是记录登录信息,将代码cv出来。

    /*** 记录登录信息* * @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);}};}

其实这串代码就是封装了当前登录用户的信息(获取客户端操作系统、获取客户端浏览器等)然后封装对象。插入数据(insertLogininfor)。

但是!这里不会执行,而是将任务交给线程对象来执行,这里只是个任务而已。

找到execute方法,点击进去,然后点击executor,executor是一个成员变量(异步操作任务调度线程池),将我们上面封装的对象交给线程池来执行。

敲两下shift键,将scheduledExecutorService   cv到搜索框中找到scheduledExecutorService的bean。

也就是说AsyncManager 的executor其实就是scheduledExecutorService返回的对象,那么ScheduledThreadPoolExecutor就是在创建线程池,大小为50(corePoolSize)。

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

举个例子,用户登录操作将登录的信息存储日志,同步的话用户登录请求完成之后等待日志插入请求完成,然后再执行用户登录后操作,异步的话将插入日志分离了出来,这样的话,不管是啥操作,都可以通过异步任务管理器,创建一个任务,交给线程池直接去执行(就不用我们去管了,线程池分配了他线程,他就会执行)大大提高了效率。

十三、代码自动生成器

首先先创建数据表

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

建完之后打开若依运行的web,在系统工具里面的代码生成,点击导入按钮。

然后编辑基本信息(带*号的一定要填)。

然后点击生成代码。        

将下载好的压缩包解压出来,main(Java 后端代码),vue(Vue 前端代码),SQL(菜单 SQL),导入代码,重启项目。

注:如果后端抛出 404 异常,rebuild project,重新启动。

效果展示

不积跬步无以至千里,趁年轻,使劲拼,给未来的自己一个交代!向着明天更好的自己前进吧!

相关文章:

若依前后端分离版,快速上手

哈喽~大家好&#xff0c;这篇来看看若依前后端分离版&#xff0c;快速上手&#xff08;肝了挺久的&#xff09;。 &#x1f947;个人主页&#xff1a;个人主页​​​​​ &#x1f948; 系列专栏&#xff1a;【Springboot和Vue全栈开发】…...

Java-抽象类、抽象方法

【1】抽象类和抽象方法的关系&#xff1a; 抽象类中可以定义0-n个抽象方法。 【2】抽象类作用&#xff1a; 在抽象类中定义抽象方法&#xff0c;目的是为了为子类提供一个通用的模板&#xff0c;子类可以在模板的基础上进行开发&#xff0c;先重写父类的抽象方法&#xff0c…...

南京--ChatGPT/GPT4 科研实践应用

2023年随着OpenAI开发者大会的召开&#xff0c;最重磅更新当属GPTs&#xff0c;多模态API&#xff0c;未来自定义专属的GPT。微软创始人比尔盖茨称ChatGPT的出现有着重大历史意义&#xff0c;不亚于互联网和个人电脑的问世。360创始人周鸿祎认为未来各行各业如果不能搭上这班车…...

【VRTK】【VR开发】【Unity】7-配置交互能力和向量追踪

【前情提要】 目前为止,我们虽然设定了手模型和动画,还能够正确根据输入触发动作,不过还未能与任何物体互动。要互动,需要给手部设定相应的Interactor能力。 【配置Interactor的抓取功能】 在Hierarchy中选中[VRTK_CAMERA_RIGS_SETUP] ➤ Camera Rigs, Tracked Alias ➤ …...

【JS】Chapter14-深入面向对象

站在巨人的肩膀上 黑马程序员前端JavaScript入门到精通全套视频教程&#xff0c;javascript核心进阶ES6语法、API、js高级等基础知识和实战教程 &#xff08;十四&#xff09;深入面向对象 1. 编程思想 1.1 面向过程介绍 面向过程就是分析出解决问题所需要的步骤&#xff0c…...

RabbitMQ消息队列快速入门

RabbitMQ消息队列快速入门 初始MQ MQ全称为Message Queue&#xff0c;即消息队列&#xff0c;是在消息的传输过程中保存消息的容器。它是典型的生产者-消费者模型。 生产者不断向消息队列中生产消息&#xff0c;消费者不断的从队列中获取消息。消息的生产和消费都是异步的&am…...

django DRF认证组件

一、学习DRF的认证类&#xff1b; 设计&#xff1a;LoginView不登录就可以访问&#xff0c;UserView和OrderView需要通过认证后才能访问&#xff1b; 1、urls.py urlpatterns [path(login/, views.LoginView.as_view()),path(user/, views.UserView.as_view()),path(order/,…...

操作系统(三)| 进程管理上 进程状态 同步 互斥

目录 1 进程和程序区别 2 进程状态 2.1 进程的5种基本状态 2.2 进程状态之间转换 2.3 七状态模型 3 进程描述 3.1 进程控制块 PCB 3.2 进程块组织方式 4 进程控制 5 进程同步 互斥 5.1 区分进程互斥和同步 5.2 核心方案 5.3 其他方案 方案1 设置锁变量 方案2 严…...

Postman插件如何安装(一)

我们chrome插件网热门推荐的软件之一就是postman。但是postman的适应平台分为&#xff1a;postman chrome应用程序&#xff0c;postman应用程序&#xff0c;postman插件。谷歌应用商店从2018年3月开始停止chrome应用程序的更新。除非继续使用老版本的postman chrome应用程序&am…...

在回调之间共享数据

可以在 App 中为 UI 组件编写回调函数&#xff0c;以指定用户与其交互时的行为方式。 在具有多个相互依赖的 UI 组件的 App 中&#xff0c;回调函数通常必须访问主 App 函数中定义的数据&#xff0c;或与其他回调函数共享数据。例如&#xff0c;如果创建一个具有列表框的 App&a…...

我在CSDN开组会1-蒙特卡洛模拟在矿床学的应用展望

各位老师、同学们&#xff0c;大家好。今天组会的内容是蒙特卡洛模拟在矿床学的应用展望。 为什么要讲蒙特卡洛模拟呢&#xff0c;因为我发现在地质学方面已经有不少应用&#xff0c;但是蒙特卡洛模拟延伸的知识太晦涩了&#xff0c;劝退了很多探究者们。因此&#xff0c;计划…...

Jmeter 性能测试基础!

压力测试 压力测试分两种场景&#xff1a;一种是单场景&#xff0c;压一个接口的&#xff1b;第二种是混合场景&#xff0c;多个有关联的接口。压测时间&#xff0c;一般场景都运行10-15分钟。如果是疲劳测试&#xff0c;可以压一天或一周&#xff0c;根据实际情况来定。 压测任…...

【赠书第6期】MATLAB科学计算从入门到精通

文章目录 前言 1 安装与配置 2 变量定义 3 数据处理 4 绘图 5 算法设计 6 程序调试 7 推荐图书 8 粉丝福利 前言 MATLAB 是一种高级的科学计算和数据可视化平台。它由 MathWorks 公司开发&#xff0c;是科学研究、数据分析和工程实践中非常常用的一种软件工具。本文将…...

Java语言基础第五天

精华笔记&#xff1a; 循环结构&#xff1a; for结构&#xff1a;应用率最高&#xff0c;与次数相关的循环 三种结构如何选择&#xff1a; 先看循环是否与次数相关&#xff1a; 若相关-----------------------------直接上for 若无关&#xff0c;再看要素1与要素3的代码是否相…...

linux网络——HTTPS加密原理

目录 一.HTTPS概述 二.概念准备 三.为什么要加密 四.常⻅的加密⽅式 1.对称加密 2.⾮对称加密 五.数据摘要&#xff0c;数字签名 六.HTTPS的加密过程探究 1.方案一——只使用对称加密 2.方案二——只使⽤⾮对称加密 3.方案三——双⽅都使⽤⾮对称加密 4.方案四——⾮…...

shell 各种括号作用总结

技巧小结&#xff1a; 字符串比较用双中括号[[ ]] 算数比较用单中括号[ ]——左右留空格 算数运算用双小括号(( )) shell命令及输出用小括号( )——左右不留空格 快速替换用花括号{ }——左右留空格 反单引号起着命令替换的作用 一、单括号()&#xff1a; 1、另开命令组——小…...

2023-11-18 mysql-sysbench压测TPS/QPS-记录

摘要: 2023-11-18 mysql-sysbench压测TPS/QPS sysbench压测TPS/QPS 使用 sysbench 压测 TPS/QPS 的基础测试数据是 6 张表,每张表写入 10 万行数据,然后在此基础测试数据上分别进行 300 秒的混合写、更新、删除压测。 sysbench --mysql-host=192.168.41.xxx --mysql-port=3…...

树与二叉树堆:树

目录 树&#xff1a; 树的概念&#xff1a; 树的相关概念&#xff1a; 1、结点的度&#xff1a; 2、叶节点&#xff1a;度为0的节点 3、非终端节点或分支节点&#xff1a; 4、父节点和子节点&#xff1a; 5、兄弟节点&#xff1a; 6、树的度&#xff1a; 7、树的层次或…...

【监控系统】日志可视化监控体系ELK搭建

1.ELK架构是什么 ELK是ElasticsearchLogstashKibana的简称。 Elasticsearch是一个开源的分布式搜索和分析引擎&#xff0c;可以用于全文检索、结构化检索和分析&#xff0c;它构建在Lucene搜索引擎库之上&#xff0c;是当前使用较为广泛的开源搜索引擎之一。 Logstash是一个…...

【Linux】22、CPU 评价指标、性能工具、定位瓶颈、优化方法论:应用程序和系统

文章目录 一、评价 CPU 的指标1.1 CPU 使用率1.2 平均负载&#xff08;Load Average&#xff09;1.3 上下文切换1.4 CPU 缓存命中率 二、性能工具2.1 维度&#xff1a;从 CPU 性能指标出发&#xff0c;即当你查看某性能指标时&#xff0c;要清除知道哪些工具可以做到2.2 维度&a…...

测试微信模版消息推送

进入“开发接口管理”--“公众平台测试账号”&#xff0c;无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息&#xff1a; 关注测试号&#xff1a;扫二维码关注测试号。 发送模版消息&#xff1a; import requests da…...

SciencePlots——绘制论文中的图片

文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了&#xff1a;一行…...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

AtCoder 第409​场初级竞赛 A~E题解

A Conflict 【题目链接】 原题链接&#xff1a;A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串&#xff0c;只有在同时为 o 时输出 Yes 并结束程序&#xff0c;否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

django filter 统计数量 按属性去重

在Django中&#xff0c;如果你想要根据某个属性对查询集进行去重并统计数量&#xff0c;你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求&#xff1a; 方法1&#xff1a;使用annotate()和Count 假设你有一个模型Item&#xff0c;并且你想…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命

在华东塑料包装行业面临限塑令深度调整的背景下&#xff0c;江苏艾立泰以一场跨国资源接力的创新实践&#xff0c;重新定义了绿色供应链的边界。 跨国回收网络&#xff1a;废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点&#xff0c;将海外废弃包装箱通过标准…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

今日科技热点速览

&#x1f525; 今日科技热点速览 &#x1f3ae; 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售&#xff0c;主打更强图形性能与沉浸式体验&#xff0c;支持多模态交互&#xff0c;受到全球玩家热捧 。 &#x1f916; 人工智能持续突破 DeepSeek-R1&…...

深度学习习题2

1.如果增加神经网络的宽度&#xff0c;精确度会增加到一个特定阈值后&#xff0c;便开始降低。造成这一现象的可能原因是什么&#xff1f; A、即使增加卷积核的数量&#xff0c;只有少部分的核会被用作预测 B、当卷积核数量增加时&#xff0c;神经网络的预测能力会降低 C、当卷…...

JavaScript基础-API 和 Web API

在学习JavaScript的过程中&#xff0c;理解API&#xff08;应用程序接口&#xff09;和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能&#xff0c;使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...