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

SpringBoot整合Shiro实现登录认证,鉴权授权

文章目录

  • 前言
  • 一、shiro简介
  • 二、环境搭建
    • 2.1.数据库
      • 2.1.1user用户表
      • 2.1.2user_role用户角色关系表
      • 2.1.3role角色表
      • 2.1.4role_permission角色权限关系表
      • 2.1.5permission权限表
    • 2.2导坐标
    • 2.3实体类
      • 2.3.1User
      • 2.3.2Role
      • 2.3.3Permission
    • 2.4MVC三层
      • 2.4.1User
        • 2.4.1.1mapper层
        • 2.4.1.2service层
        • 2.4.1.3controller层
      • 2.4.2Role
        • 2.4.2.1mapper层
        • 2.4.2.2service层
        • 2.4.2.3controller层
      • 2.3.3Permission
        • 2.4.3.1mapper层
        • 2.4.3.2service层
        • 2.4.3.3controller层
    • 2.5.加密工具类
    • 2.6.全局异常处理器
    • 2.7自定义Realm
    • 2.8shiro配置类
  • 三、案例演示
    • 3.1 登录认证
    • 3.2 权限认证
  • 总结


前言

近期对Springboot框架的学习中,为了更好的学习理解Springsecurity中间件,先学习了一下“老派”的shiro安全框架,本文章将通过注解的方式实现基础的用户认证和角色授权案例

一、shiro简介

Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。

二、环境搭建

2.1.数据库

2.1.1user用户表

在这里插入图片描述

2.1.2user_role用户角色关系表

在这里插入图片描述

2.1.3role角色表

在这里插入图片描述

2.1.4role_permission角色权限关系表

在这里插入图片描述

2.1.5permission权限表

在这里插入图片描述

2.2导坐标

<properties><java.version>1.8</java.version><!--shiro--><shiro.version>1.3.2</shiro.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.29</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.3</version></dependency><!-- SECURITY begin --><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>${shiro.version}</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>${shiro.version}</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-web</artifactId><version>${shiro.version}</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-ehcache</artifactId><version>${shiro.version}</version></dependency><!-- SECURITY end --></dependencies>

2.3实体类

2.3.1User

@TableName("pe_user")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {@TableId(value = "id",type = IdType.AUTO)private int id;private String username;private String password;private String salt;@TableField(exist = false)private Set<Role> roles;
}

2.3.2Role

@TableName("pe_role")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Role {@TableId(value = "id",type = IdType.AUTO)private int id;private String name;private String code;private String description;@TableField(exist = false)private Set<Permission> permissions;
}

2.3.3Permission

@TableName("pe_permission")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Permission {@TableId(value = "id",type = IdType.AUTO)private int id;private String name;private String code;private String description;
}

2.4MVC三层

2.4.1User

2.4.1.1mapper层

public interface UserMapper extends BaseMapper<User> {@Select("select * from pe_user where username = #{name}")User findUserByName(String name);//级联查询@Results({@Result(column = "id",property = "id"),@Result(column = "username",property = "username"),@Result(column = "password",property = "password"),@Result(column = "salt",property = "salt"),@Result(column = "id",property = "roles",many=@Many(select = "com.apesource.shirostudy_demo_05.dao.RoleMapper.findRoleIdsByUserId"))})@Select("select * from pe_user where id = #{id}")User findUserDetailById(@Param("id") int id);
}

2.4.1.2service层

public interface IUserService extends IService<User> {User findUserByName(String name);User findUserDetailById(int id);
}@Service
@SuppressWarnings("all")
public class UserServiceImp extends ServiceImpl<UserMapper, User> implements IUserService {@AutowiredUserMapper userMapper;@AutowiredIRoleService roleService;@Overridepublic User findUserByName(String name) {User user = userMapper.findUserByName(name);return user;}@Overridepublic User findUserDetailById(int id) {//根据userid查询userUser user = userMapper.findUserDetailById(id);//返回return user;}
}

2.4.1.3controller层

@RestController
public class UserController {@Autowiredprivate IUserService userService;//个人主页@RequiresPermissions("user-home")@RequestMapping(value = "/user/home")public String home() {return "访问个人主页成功";}//根据名字查询用户基本信息@RequiresPermissions("user-find")@RequestMapping(value = "/user/userByName/{name}")public String findUserByName(@PathVariable String name) {System.out.println(name);User user = userService.findUserByName(name);return user.toString();}//更新@RequiresPermissions("user-update")@RequestMapping(value = "/user/{id}", method = RequestMethod.PUT)public String update(@PathVariable String id) {return "更新用户成功";}//删除@RequiresPermissions("user-delete")@RequestMapping(value = "/user/{id}", method = RequestMethod.DELETE)public String delete(@PathVariable String id) {return "删除用户成功";}//根据id查询用户详细信息@RequiresPermissions("user-find")@RequestMapping(value = "/user/userById/{id}")public String findUserDetailById(@PathVariable int id) {return userService.findUserDetailById(id).toString();}//登录页面@RequestMapping(value = "/login")public String login(User user) {try {//1.构造登录令牌UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());//2.//2.获取subjectSubject subject = SecurityUtils.getSubject();//3.调用subject进行登录subject.login(token);return "登录成功!!!";} catch (AuthenticationException e) {return "用户名或密码错误!!!";}}//未登陆与未授权页面@RequestMapping(value = "/autherror")public String autherror() {return "未登录";}}

2.4.2Role

2.4.2.1mapper层

public interface RoleMapper extends BaseMapper<Role> {@Results({@Result(column = "id",property = "id"),@Result(column = "name",property = "name"),@Result(column = "code",property = "code"),@Result(column = "description",property = "description"),@Result(column = "id",property = "permissions",many =@Many(select = "com.apesource.shirostudy_demo_05.dao.PermissionMapper.findPermissionIdsByRoleId"))})@Select("SELECT * FROM pe_role WHERE id IN (SELECT role_id FROM pe_user_role WHERE user_id = #{id})")Set<Role> findRoleIdsByUserId(int id);
}

2.4.2.2service层

public interface IRoleService extends IService<Role> {Set<Role> findRoleIdsByUserId(int id);
}
@Service
@SuppressWarnings("all")
public class RoleServiceImp extends ServiceImpl<RoleMapper, Role> implements IRoleService {@AutowiredRoleMapper roleMapper;@AutowiredIPermissionService permissionService;@Overridepublic Set<Role> findRoleIdsByUserId(int id) {Set<Role> roles = roleMapper.findRoleIdsByUserId(id);return roles;}
}

2.4.2.3controller层

由于不演示,无。

2.3.3Permission

2.4.3.1mapper层

public interface PermissionMapper extends BaseMapper<Permission> {@Results({@Result(column = "id",property = "id"),@Result(column = "name",property = "name"),@Result(column = "code",property = "code"),@Result(column = "description",property = "description"),})@Select("SELECT * FROM pe_permission WHERE id IN (SELECT permission_id FROM pe_role_permission WHERE role_id = #{id} ) ")Set<Permission> findPermissionIdsByRoleId(int id);
}

2.4.3.2service层

public interface IPermissionService extends IService<Permission> {Set<Permission> findPermissionIdsByRoleId(int id);
}
@Service
public class PermissionServiceImp extends ServiceImpl<PermissionMapper, Permission> implements IPermissionService {@Autowired(required = false)PermissionMapper permissionMapper;@Overridepublic Set<Permission> findPermissionIdsByRoleId(int id) {Set<Permission> permissionIds = permissionMapper.findPermissionIdsByRoleId(id);return permissionIds;}
}

2.4.3.3controller层

由于不演示,无。

2.5.加密工具类

public class DigestsUtil {public static final String SHA1 = "SHA-1";public static final Integer COUNTS =369;/*** @Description sha1方法* @param input 需要散列字符串* @param salt 盐字符串* @return*/public static String show(String input, String salt) {return new SimpleHash(SHA1, input, salt,COUNTS).toString();}/*** @Description 随机获得salt字符串* @return*/public static String generateSalt(){SecureRandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();return randomNumberGenerator.nextBytes().toHex();}/*** @Description 生成密码字符密文和salt密文* @param* @return*/public static Map<String,String> entryptPassword(String passwordPlain) {Map<String,String> map = new HashMap<>();String salt = generateSalt();String password =show(passwordPlain,salt);map.put("salt", salt);map.put("password", password);return map;}
}

2.6.全局异常处理器

@ControllerAdvice
public class BaseExceptionHandler {@ExceptionHandler(value = AuthorizationException.class)@ResponseBodypublic String error(HttpServletRequest request, HttpServletResponse response, AuthorizationException e){return "未授权!!!";}
}

2.7自定义Realm

public class MyRealm extends AuthorizingRealm {@AutowiredIUserService userService;@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {int userId = (int) principalCollection.getPrimaryPrincipal();User user = userService.findUserDetailById(userId);Set<String> roles = new HashSet<>();Set<String> permissions = new HashSet<>();user.getRoles().stream().forEach(role -> {roles.add(role.getCode());role.getPermissions().stream().forEach(permission -> {permissions.add(permission.getCode());});});SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();info.addRoles(roles);info.addStringPermissions(permissions);return info;}/*** 认证方法*  参数:传递的用户名密码*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {//1.获取登录的用户名密码(token)UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;String username = token.getUsername();//2.根据用户名查询数据库//mybatis情景下:user对象中包含ID,name,pwd(匿名)User user = userService.findUserByName(username);if(user != null){SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user.getId(),user.getPassword(), ByteSource.Util.bytes(user.getSalt()),"myRealm");return info;}return null;}/*** @Description 自定义密码比较器* @param* @return* bean标签 init-method属性*/@PostConstructpublic void initCredentialsMatcher() {//指定密码算法HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(DigestsUtil.SHA1);//指定迭代次数hashedCredentialsMatcher.setHashIterations(DigestsUtil.COUNTS);//生效密码比较器setCredentialsMatcher(hashedCredentialsMatcher);}
}

2.8shiro配置类

@Configuration
public class ShiroConfiguration {/*** 1.创建shiro自带cookie对象*/@Beanpublic SimpleCookie sessionIdCookie(){SimpleCookie simpleCookie = new SimpleCookie();simpleCookie.setName("ShiroSession");return simpleCookie;}//2.创建realm@Beanpublic MyRealm getRealm(){return new MyRealm();}/*** 3.创建会话管理器*/@Beanpublic DefaultWebSessionManager sessionManager(){DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();sessionManager.setSessionValidationSchedulerEnabled(false);sessionManager.setSessionIdCookieEnabled(true);sessionManager.setSessionIdCookie(sessionIdCookie());sessionManager.setGlobalSessionTimeout(3600000);return sessionManager;}//4.创建安全管理器@Beanpublic SecurityManager defaultWebSecurityManager() {DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();securityManager.setRealm(getRealm());securityManager.setSessionManager(sessionManager());return securityManager;}/*** 5.保证实现了Shiro内部lifecycle函数的bean执行*/@Bean(name = "lifecycleBeanPostProcessor")public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {return new LifecycleBeanPostProcessor();}/*** 6.开启对shiro注解的支持*   AOP式方法级权限检查*/@Bean@DependsOn("lifecycleBeanPostProcessor")public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);return defaultAdvisorAutoProxyCreator;}/*** 7.配合DefaultAdvisorAutoProxyCreator事项注解权限校验*/@Beanpublic AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor() {AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();authorizationAttributeSourceAdvisor.setSecurityManager(defaultWebSecurityManager());return authorizationAttributeSourceAdvisor;}//8.配置shiro的过滤器工厂再web程序中,shiro进行权限控制全部是通过一组过滤器集合进行控制@Beanpublic ShiroFilterFactoryBean shiroFilter() {//1.创建过滤器工厂ShiroFilterFactoryBean filterFactory = new ShiroFilterFactoryBean();//2.设置安全管理器filterFactory.setSecurityManager(defaultWebSecurityManager());//3.通用配置(跳转登录页面,为授权跳转的页面)filterFactory.setLoginUrl("/autherror");//跳转url地址//4.设置过滤器集合//key = 拦截的url地址//value = 过滤器类型Map<String,String> filterMap = new LinkedHashMap<>();//key:请求规则   value:过滤器名称filterMap.put("/login","anon");//当前请求地址可以匿名访问filterMap.put("/user/**","authc");//当前请求地址必须认证之后可以访问//在过滤器工程内设置系统过滤器filterFactory.setFilterChainDefinitionMap(filterMap);return filterFactory;}}

三、案例演示

用户密码均是123456加密后保存至数据库

3.1 登录认证

成功登录:
在这里插入图片描述
失败登录:
在这里插入图片描述

3.2 权限认证

由于刚刚登录的信息有管理员和员工的身份,所以其所有功能都能使用。
有权限时:在这里插入图片描述
无权限时:在这里插入图片描述
无权限时会被全局异常处理器拦截,并作出响应的响应。


总结

通过对shrio的学习,更好的理解了安全认证以及鉴权授权的流程,大概了解了安全认证的机制,对我之后学习理解Springsecurity有更好的帮助。

相关文章:

SpringBoot整合Shiro实现登录认证,鉴权授权

文章目录 前言一、shiro简介二、环境搭建2.1.数据库2.1.1user用户表2.1.2user_role用户角色关系表2.1.3role角色表2.1.4role_permission角色权限关系表2.1.5permission权限表 2.2导坐标2.3实体类2.3.1User2.3.2Role2.3.3Permission 2.4MVC三层2.4.1User2.4.1.1mapper层2.4.1.2s…...

Airbnb开源数据可视化工具Visx

一、什么是visx visx 是用于 React 的富有表现力的底层可视化组件集合,结合了 d3 的强大功能来生成可视化,以及 React 更新 DOM 的诸多优势。 在 Airbnb 内部,visx 的目标是统一整个公司的可视化堆栈,在此过程中,创建了 visx 项目,从而有效的将 D3 的强大功能与 React …...

VR仿真实训系统编辑平台赋予老师更多自由和灵活性

为了降低院校教师在VR虚拟现实方面应用的门槛&#xff0c;VR公司深圳华锐视点融合多年的VR虚拟仿真实训系统制作经验&#xff0c;制作了VR动物课件编辑器&#xff0c;正在逐渐受到师生们的关注和应用。 简单来说&#xff0c;VR畜牧专业课件编辑器是一种可以制作虚拟现实动物教学…...

父类对象转成子类对象

import org.springframework.beans.BeanUtils; import java.util.ArrayList; import java.util.List; public class Test {public static void main(String[] args) {List<B> bList new ArrayList<>();B b new B("a","这是a","b",…...

Spring Boot中如何使用Flyway进行数据库迁移

在本文中&#xff0c;我们将了解如何使用 Flyway 来管理 Spring Boot 应用程序中的 SQL 数据库架构。 在本文中&#xff0c;我们将了解如何使用 Flyway 来管理Spring Boot应用程序中的SQL 数据库架构。 Flyway是一个数据库迁移工具&#xff0c;它提供迁移历史和回滚的功能&…...

web在线编辑器(vue版)

目录 前言一、monaco-editor1、源码2、体积优化 二、ace-editor&#xff1f;1、源码2、体积优化 总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 例如&#xff1a;随着人工智能的不断发展&#xff0c;机器学习这门技术也越来越重要&#xff0c;很多…...

【论文阅读】 Model Sparsity Can Simplify Machine Unlearning

Model Sparsity Can Simplify Machine Unlearning 背景主要内容Contribution Ⅰ&#xff1a;对Machine Unlearning的一个全面的理解Contribution Ⅱ&#xff1a;说明model sparsity对Machine Unlearning的好处Pruning方法的选择sparse-aware的unlearning framework Experiments…...

Spring Clould 部署 - Docker

视频地址&#xff1a;微服务&#xff08;SpringCloudRabbitMQDockerRedis搜索分布式&#xff09; 初识Docker-什么是Docker&#xff08;P42&#xff0c;P43&#xff09; 微服务虽然具备各种各样的优势&#xff0c;但服务的拆分通用给部署带来了很大的麻烦。 分布式系统中&…...

linux--链表动态创建

头插法&#xff1a; 核心代码&#xff1a; s->next head->next; head->next s; 尾插法 核心代码&#xff1a; tail head; s->next NULL; tail->next s; tail s; 当用头插法依次插入值分别为1,2,3,4,5的结点后&#xff0c; 单链表顺序为&#xff1a; he…...

iBooker 布客技术评论 20230818

一、程序员自检手册 为了避免焦虑&#xff0c;你首先需要做的就是梳理你的业务&#xff1a; &#xff08;1&#xff09;你所在的行业是轻资产还是重资产&#xff1f; 重资产就是人绕着机器转&#xff0c;创业需要买一大堆设备。如果是重资产&#xff0c;赶紧换一个。 &…...

CK-A60180、CK-B1542、CK-L3095单向离合器

CK-A1542、CK-A1747、CK-A2052、CK-A2652、CK-A3072、CK-A3580、CK-A4090、CK-A45100、CK-A450110、CK-A60130、CK-A65140、CK-A70150、CK-A75160、CK-A80170、CK-A1250、CK-A1855、CK-A2060、CK-A2563、CK-A2563T、CK-A2870、CK-A3080T、CK-A3585、CK-A35100、CK-A35140、CK-A…...

单因素多变量方差分析

多变量方差分析&#xff1a;是对多个独立变量是否受单个或多个因素影响而进行的方差分析。它不仅能够分析多个因素对观测变量的独立影响&#xff0c;更能够分析多个因素的交互作用能否对观测变量产生影响。本章以单因素多变量分析为例&#xff0c;即一个分组变量和多个欲分析的…...

Python Web:Django、Flask和FastAPI框架对比

原文&#xff1a;百度安全验证 Django、Flask和FastAPI是Python Web框架中的三个主要代表。这些框架都有着各自的优点和缺点&#xff0c;适合不同类型和规模的应用程序。 1. Django&#xff1a; Django是一个全功能的Web框架&#xff0c;它提供了很多内置的应用程序和工具&am…...

【CI/CD】Rancher K8s

Rancher & K8s Rancher 和 K8s 的关系是什么&#xff1f;K8s 全称为 Kubernetes&#xff0c;它是一个开源的&#xff0c;用于管理云平台中多个主机上的容器化的应用。而 Rancher 是一个完全开源的企业级多集群 Kubernetes 管理平台&#xff0c;实现了 Kubernetes 集群在混合…...

nodejs 之 express 实现下载网络图片并上传到七牛云对象存储oss空间

为方便阅读&#xff0c;本文将所有逻辑放在一个函数里&#xff0c;可根据自己的情况拆分。 安装依赖 在项目根目录下运行以下命令安装依赖 npm install express qiniu axios业务逻辑 在项目根目录下创建一个名为 app.js 的文件&#xff0c;并添加以下内容 const express re…...

综合能源系统(7)——综合能源综合评估技术

综合能源系统关键技术与典型案例  何泽家&#xff0c;李德智主编 综合能源系统是多种能源系统非线性耦合的、多时间与空间尺度耦合的“源-网-荷一储”一体化系统&#xff0c;通过能源耦合、多能互补&#xff0c;能够实现能源的高效利用&#xff0c;并提高新能源的利用水平。对…...

【JS 线性代数算法之向量与矩阵】

线性代数算法 一、向量的加减乘除1. 向量加法2. 向量减法3. 向量数乘4. 向量点积5. 向量叉积 二、矩阵的加减乘除1. 矩阵加法2. 矩阵减法3. 矩阵数乘4. 矩阵乘法 常用数学库 线性代数是数学的一个分支&#xff0c;用于研究线性方程组及其解的性质、向量空间及其变换的性质等。在…...

配置 yum/dnf 置您的系统以使用默认存储库

题目 给系统配置默认存储库&#xff0c;要求如下&#xff1a; YUM 的 两 个 存 储 库 的 地 址 分 别 是 &#xff1a; ftp://host.domain8.rhce.cc/dvd/BaseOS ftp://host.domain8.rhce.cc/dvd/AppStream vim /etc/yum.repos.d/redhat.repo [base] namebase baseurlftp:/…...

Docker容器与虚拟化技术:Docker资源控制、数据管理

目录 一、理论 1.资源控制 2.Docker数据管理 二、实验 1.Docker资源控制 2.Docker数据管理 三、问题 1.docker容器故障导致大量日志集满&#xff0c;造成磁盘空间满 2、当日志占满之后如何处理 四、总结 一、理论 1.资源控制 (1) CPU 资源控制 cgroups&#xff0…...

python生成器有几种写法,python生成器函数例子

大家好&#xff0c;小编来为大家解答以下问题&#xff0c;python生成器有几种写法&#xff0c;python生成器函数例子&#xff0c;今天让我们一起来看看吧&#xff01; 本文部分参考&#xff1a;Python迭代器&#xff0c;生成器–精华中的精华 https://www.cnblogs.com/deeper/p…...

动态动画弹窗样式css

点击下载图片素材 html <div class"popWin"> </div> <div class"popPic"><div class"popWinBtn01">查看证书</div><div class"wintips01">恭喜您已完成训练营学习任务&#xff0c;荣誉证书已发放…...

数据生成 | MATLAB实现WGAN生成对抗网络数据生成

数据生成 | MATLAB实现WGAN生成对抗网络数据生成 目录 数据生成 | MATLAB实现WGAN生成对抗网络数据生成生成效果基本描述程序设计参考资料 生成效果 基本描述 1.WGAN生成对抗网络&#xff0c;数据生成&#xff0c;样本生成程序&#xff0c;MATLAB程序&#xff1b; 2.适用于MATL…...

PHP实现每日蛋白质摄入量计算器

1.laravel 路由 //每日蛋白质摄入计算器Route::get(api/protein/intake, FormulaControllerproteinIntakeCal); 2.代码 /*** 每日蛋白质摄入计算器*/public function proteinIntakeCal(){$number intval($this->request(number));$goalFactor array(0.8, 1.16, 0.8, 1.16,…...

vue elment 表格内表单校验代码

<p v-if"scope.row.id">{{ scope.row.bidderCode }}</p><el-form-itemclass"formitem"v-else:prop"bidderCode scope.row.id":rules"getValidationRules(投标人/供应商代码, scope.row.id)"><el-input v-model&…...

如何在Stream流中分组统计

上面是今天碰到需求,之前就做过类似的分组统计,这个相对来说比较简单,统计的也少,序号和总预约人数这两部分交给前端了,不需要由后端统计,后端统计一下预约日期和检查项目和预约人数就行; Overridepublic List<ItemStatisticsVo> statistics(ItemStatisticsModel itemSta…...

windows程序基础

一、windows程序基础 1. Windows程序的特点 1&#xff09;用户界面统一、友好 2&#xff09;支持多任务:允许用户同时运行多个应用程序(窗口) 3&#xff09;独立于设备的图形操作 使用图形设备接口( GDI, Graphics Device Interface )屏蔽了不同硬件设备的差异&#…...

【LeetCode】买卖股票的最佳时机最多两次购买机会

买卖股票的最佳时机 题目描述算法分析程序代码 链接: 买卖股票的最佳时机 题目描述 算法分析 程序代码 class Solution { public:int maxProfit(vector<int>& prices) {int n prices.size();vector<vector<int>> f(n,vector<int>(3,-0x3f3f3f))…...

【C++ 记忆站】命名空间

文章目录 命名空间概念命名空间的定义1、正常的命名空间定义2、命名空间可以嵌套3、同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中 命名空间的使用1、加命名空间名称及作用域限定符2、使用using将命名空间中某个成员引入3、使用using namespac…...

《离散数学及其应用(原书第8版)》ISBN978-7-111-63687-8 第11章 11.1.3 树的性质 节 第664页的例9说明

《离散数学及其应用&#xff08;原书第8版&#xff09;》ISBN978-7-111-63687-8 第11章 11.1.3 树的性质 节 第664页的定理3的引申 定理3 带有i个内点的m叉树含有nmi1个顶点 见本人博文 内点定义不同的讨论 如果对于一个m叉正则树&#xff0c;即任意分支节点的儿子恰好有m个&am…...

【云原生】K8S存储卷:PV、PVC详解

目录 一、emptyDir存储卷二、hostPath存储卷三、nfs共享存储卷四、PVC 和 PV4.1 NFS使用PV和PVC4.2创建动态PV 一、emptyDir存储卷 容器磁盘上的文件的生命周期是短暂的&#xff0c;这就使得在容器中运行重要应用时会出现一些问题。首先&#xff0c;当容器崩溃时&#xff0c;ku…...