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

Java基础:Stream流常用方法

获取Stream流的方式
java.util.stream.Stream 是Java 8新加入的流接口。(并不是一个函数式接口)
获取一个流非常简单,有以下几种常用的方式:

  • 所有 Collection 集合都可通过 stream 默认方法获取流(顺序流)
  • 所有 Collection 集合都可通过parallelStream获取并行流
  • Stream 接口的静态方法 of 可以获取数组对应的流。
  • Arrays的静态方法stream也可以获取流

根据Collection获取流

public static void main(String[] args) {List<String> list = new ArrayList<>();Stream<String> stream1 = list.stream();Set<String> set = new HashSet<>();Stream<String> stream2 = set.stream();Vector<String> vector = new Vector<>();// ...
}   

根据Map获取流

public static void main(String[] args) {Map<String, String> map = new HashMap<>();Stream<String> keyStream = map.keySet().stream();Stream<String> valueStream = map.values().stream();Stream<Map.Entry<String, String>> entryStream = map.entrySet().stream();
}

根据数组获取流

如果使用的不是集合或映射而是数组,由于数组对象不可能添加默认方法,所以 Stream 接口中提供了静态方法of ,使用很简单:

public static void main(String[] args) {//使用 Stream.ofString[] array = { "张无忌", "张翠山", "张三丰", "张一元" };Stream<String> stream = Stream.of(array);//使用Arrays的静态方法Arrays.stream(array)
}

Stream流中的常用方法

方法可分成两种:

  • 延迟方法:返回值类型仍然是 Stream 接口自身类型的方法,因此支持链式调用。(除终结方法外,其余方法均为延迟方法)
  • 终结方法:返回值类型不是 Stream 接口自身类型的方法,因此不再支持类似 StringBuilder 那样的链式调用。本节中,终结方法包括 count 和 forEach 方法。

1.forEach(终结方法)

用于遍历的方法,参数传入一个函数式接口:Consumer

public static void main(String[] args) {Stream<String> stream = Stream.of("张无忌", "张三丰", "周芷若");stream.forEach(name‐> System.out.println(name));
}

2.过滤:filter

可用于过滤。可通过 filter 方法将一个流转换成另一个子集流。

public static void main(String[] args) {//创建一个流Stream<String> stream = Stream.of( "刘德华", "张国荣", "彭于晏", "纳什", "吴彦祖");//对流中元素过滤,只要姓张的人Stream<String> stream2 = stream.filter(name -> {return name.startsWith("张");});//遍历过滤后的流stream2.forEach(name -> System.out.println(name));
}

3.映射(转换):map

如果需要将流中的元素映射到另一个流中,可用 map 方法。

该接口需要一个 Function 函数式接口参数

/*** stream流的map方法练习* map方法可以将流中的元素映射到另一个流中* map方法的参数是一个Function函数式接口*/@Testpublic void test(){//创建一个流,里面是字符串类型的整数Stream<String> stream1 = Stream.of("2", "32", "2", "33", "2");//把stream1流中的整数全部转成int类型Stream<Integer> stream2 = stream1.map((String s) -> {return Integer.parseInt(s);});//遍历stream2.forEach((i)-> System.out.println(i));}

4.统计个数:count(终结方法)

正如旧集合 Collection 当中的 size 方法一样,流提供 count 方法来数一数其中的元素个数:

该方法返回一个long值代表元素个数(不像旧集合那样是int值)。

public class Demo09StreamCount {public static void main(String[] args) {Stream<String> original = Stream.of("张无忌", "张三丰", "周芷若");//筛选姓张的Stream<String> result = original.filter(s ‐> s.startsWith("张"));//输出个数System.out.println(result.count()); // 2}
}

5.取用前几个(截取):limit

limit 方法可对流进行截取,只取用前n个。

参数是一个long型,如果集合当前长度大于参数则进行截取;否则不进行操作。

public class Demo10StreamLimit {public static void main(String[] args) {Stream<String> original = Stream.of("张无忌", "张三丰", "周芷若");//截取前两个Stream<String> result = original.limit(2);System.out.println(result.count()); // 2}
}

6.跳过前几个元素:skip

如果希望跳过前几个元素,可用 skip 方法获取一个截取后的新流:

如果流的当前长度大于n,则跳过前n个;否则将会得到一个长度为0的空流。

public class Demo11StreamSkip {public static void main(String[] args) {Stream<String> original = Stream.of("张无忌", "张三丰", "周芷若");//跳过前两个,返回一个新的流Stream<String> result = original.skip(2);System.out.println(result.count()); // 1}
}

7.组合(合并流):concat

如果有两个流,希望合并为一个流,可以用 Stream 接口的静态方法 concat :

public class Demo12StreamConcat {public static void main(String[] args) {Stream<String> streamA = Stream.of("张无忌");Stream<String> streamB = Stream.of("张翠山");//合并成一个新的流Stream<String> result = Stream.concat(streamA, streamB);}
}

8.筛选:distinct

去除流中重复元素(使用hashcode和equals方法来对比)

9.映射(打开后再转换):flatMap

内部传入一个Function函数式接口,跟map的区别就是这个会把流中的元素打开,再组合成一个新的流

// map和flatMap的练习
public class StreamDemo {@Testpublic void test(){List<String> list = Arrays.asList("aa","bb","cc","dd");// 练习1 (map) 输出的全是大写list.stream().map(s -> s.toUpperCase()).forEach(System.out::println);System.out.println("----------");// 练习2(map)流里还有流,需要两个遍历才行看到里面内容Stream<Stream<Character>> streamStream = list.stream().map(StreamDemo::fromStringToStream);streamStream.forEach(s -> {s.forEach(System.out::println);});System.out.println("---------");// 练习3(flatMap)流里还有流,使用flatMap可以直接把里面的流打开,一次遍历就可以了Stream<Character> characterStream = list.stream().flatMap(StreamDemo::fromStringToStream);characterStream.forEach(System.out::println);}/***  将字符串中的多个字符构成的集合转换为对应的stream* @param str* @return*/public static Stream<Character> fromStringToStream(String str){ArrayList<Character> list = new ArrayList();// 将字符串转成字符数组,并遍历加入list集合for(Character c : str.toCharArray()){list.add(c);}// 返回list集合的stream流return list.stream();}
}

10.自然排序:sorted

看下一条里的代码

11.定制排序:sorted(Comparator com)

 /*** 排序的练习*/@Testpublic void test2(){List<Integer> integers = List.of(124, 2, 15, 12, 51, -5, 5);// 按照自然排序integers.stream().sorted().forEach(System.out::println);System.out.println("---------");List<Integer> integers2 = List.of(124, 2, 15, 12, 51, -5, 5);// 定制排序(大到小),需要传入Comparator接口(如果流中的是引用类型,只能用定制排序)// 简写:integers2.stream().sorted((e1,e2) -> e2-e1).forEach(System.out::println);integers2.stream().sorted((e1,e2) -> {return e2-e1;}).forEach(System.out::println);}

12.检测匹配(终结方法):

返回一个Boolean值

是否全部匹配:allMatch

是否至少匹配一个:anyMatch

是否没有匹配的:noneMatch

 /*** 匹配的练习*/@Testpublic void test3(){List<Integer> integers = List.of(124, 2, 15, 12, 51, -5, 5);// 判断是否全部大于5boolean b = integers.stream().allMatch(i -> i > 5);// 结束输出falseSystem.out.println(b);System.out.println("-------");List<Integer> integers2 = List.of(124, 2, 15, 12, 51, -5, 5);// 检测是否匹配至少一个元素boolean b1 = integers2.stream().anyMatch(i -> i > 5);// 输出trueSystem.out.println(b1);System.out.println("-------");List<Integer> integers3 = List.of(124, 2, 15, 12, 51, -5, 5);// 检查是否没有匹配的元素boolean b2 = integers3.stream().noneMatch(i -> i > 1000);// 输出true,全部不匹配System.out.println(b2);}

13.查找元素(终结方法)

查找第一个元素:findFirst,返回Optional类型

查找其中一个元素:findAny,返回Optional类型

public void test4(){List<Integer> integers = List.of(124, 2, 15, 12, 51, -5, 5);// 输出第一个元素Optional<Integer> first = integers.stream().findFirst();// 输出结果是Optional[124]System.out.println(first);System.out.println("-------------");List<Integer> integers2 = List.of(124, 2, 15, 12, 51, -5, 5);// 返回其中一个元素Optional<Integer> any = integers2.stream().findAny();System.out.println(any);}

14.查找最大最小值(终结方法)

max(comparator c)

min(comparator c)

 /*** 查找最大最小值*/@Testpublic void test5(){List<Person> list = new ArrayList<>();list.add(new Person("马化腾",25,3000));list.add(new Person("李彦宏",27,2545));list.add(new Person("雷军",35,4515));list.add(new Person("马云",55,9877));//  查找年龄最大的人Optional<Person> max = list.stream().max((e1, e2) -> e1.getAge() - e2.getAge());// 返回马云,55岁年龄最大System.out.println(max.get());System.out.println("--------");

15.规约(终结方法)

reduce(T identity ,BinaryOperator) 第一个参数是初始值,第二个参数是一个函数式接口

reduce(BinaryOperator) 参数是一个函数式接口

/*** 归约的练习*/@Testpublic void test6(){List<Integer> integers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);// 求集合里数字的和(归约)reduce第一个参数是初始值。Integer sum = integers.stream().reduce(0, Integer::sum);System.out.println(sum);System.out.println("-------");List<Person> list = new ArrayList<>();list.add(new Person("马化腾",25,3000));list.add(new Person("李彦宏",27,2545));list.add(new Person("雷军",35,4515));list.add(new Person("马云",55,9877));// 求所有人的工资和(归约)// 不用方法引用写法:Optional<Integer> reduce = list.stream().map(person -> person.getSalary()).reduce((e1, e2) -> e1 + e2);Optional<Integer> reduce = list.stream().map(Person::getSalary).reduce(Integer::sum);// 输出Optional[19937]System.out.println(reduce);}

16.收集(终结方法)

collect(Collector c):将流转化为其他形式,接收一个Collector接口的实现

/*** 收集的练习*/@Testpublic void test7(){List<Person> list = new ArrayList<>();list.add(new Person("马化腾",25,3000));list.add(new Person("李彦宏",27,2545));list.add(new Person("雷军",35,4515));list.add(new Person("马云",55,9877));// 把年龄大于30岁的人,转成一个list集合List<Person> collect = list.stream().filter(person -> person.getAge() > 30).collect(Collectors.toList());// 遍历输出(输出雷军和马云)for (Person person : collect) {System.out.println(person);}System.out.println("----------");List<Person> list2 = new ArrayList<>();list2.add(new Person("马化腾",25,3000));list2.add(new Person("李彦宏",27,2545));list2.add(new Person("雷军",35,4515));list2.add(new Person("马云",55,9877));// 把姓马的人,转成Set集合Set<Person> set = list2.stream().filter(person -> person.getName().startsWith("马")).collect(Collectors.toSet());// 输出马云和马化腾set.forEach(System.out::println);}

17.迭代:iterate

可以使用Stream.iterate创建流值,即所谓的无限流。

//Stream.iterate(initial value, next value)Stream.iterate(0, n -> n + 1).limit(5).forEach(x -> System.out.println(x));

输出:

0
1
2
3
4   

18.查看:peek

peek接收的是一个Consumer函数,peek 操作会按照 Consumer 函数提供的逻辑去消费流中的每一个元素,同时有可能改变元素内部的一些属性

@Testpublic void test1(){List<String> collect = Stream.of("one", "two", "three", "four").filter(e -> e.length() > 3).peek(e -> System.out.println("查看一下刚过滤出的值:" + e)).map(String::toUpperCase).peek(e -> System.out.println("查看一下转大写之后的值:" + e)).collect(Collectors.toList());System.out.println("-----分割线-----");// 遍历过滤后的集合for (String s : collect) {System.out.println(s);}}

输出:

查看一下刚过滤出的值:three
查看一下转大写之后的值:THREE
查看一下刚过滤出的值:four
查看一下转大写之后的值:FOUR
-----分割线-----
THREE
FOUR

Srtream流中方法的使用练习

/*** 	1. 第一个队伍只要名字为3个字的成员姓名;存储到一个新集合中。*	2. 第一个队伍筛选之后只要前3个人;存储到一个新集合中。*	3. 第二个队伍只要姓张的成员姓名;存储到一个新集合中。*	4. 第二个队伍筛选之后不要前2个人;存储到一个新集合中。*	5. 将两个队伍合并为一个队伍;存储到一个新集合中。*	6. 根据姓名创建 Person 对象;存储到一个新集合中。*	7. 打印整个队伍的Person对象信息。*/
public class Demo3 {public static void main(String[] args) {//第一支队伍ArrayList<String> one = new ArrayList<>();one.add("迪丽热巴");one.add("宋远桥");one.add("苏星河");one.add("石破天");one.add("石中玉");one.add("老子");one.add("庄子");one.add("洪七公");//第一个队伍只要名字为3个字的成员姓名;存储到一个新集合中。//第一个队伍筛选之后只要前3个人;存储到一个新集合中。Stream<String> stream = one.stream();Stream<String> stream1 = stream.filter(name -> name.length() == 3).limit(3);//第二支队伍ArrayList<String> two = new ArrayList<>();two.add("古力娜扎");two.add("张无忌");two.add("赵丽颖");two.add("张三丰");two.add("尼古拉斯赵四");two.add("张天爱");two.add("张二狗");//第二个队伍只要姓张的成员姓名;存储到一个新集合中。//第二个队伍筛选之后不要前2个人;存储到一个新集合中。Stream<String> stream2 = two.stream();Stream<String> stream3 = stream2.filter(name -> name.startsWith("张")).skip(2);//合并两个队伍Stream<String> concat = Stream.concat(stream1, stream3);//把合并后的队伍根据姓名创建Person对象,并存入新的集合中,然后打印concat.map(name -> new Person(name)).forEach(p -> System.out.println(p));}
}

相关文章:

Java基础:Stream流常用方法

获取Stream流的方式 java.util.stream.Stream 是Java 8新加入的流接口。&#xff08;并不是一个函数式接口&#xff09; 获取一个流非常简单&#xff0c;有以下几种常用的方式&#xff1a; 所有 Collection 集合都可通过 stream 默认方法获取流&#xff08;顺序流&#xff09;…...

ImageNet使用方法(细节)自用!

学习记录&#xff0c;自用。 1. 下载数据集 点击以下链接下载种子文件&#xff0c;然后使用迅雷进行下载&#xff0c;仅下载勾选的文件即可。 https://hyper.ai/datasets/4889/c107755f6de25ba43c190f37dd0168dbd1c0877e 2. 解压 找到下载好的ILSVRC2012_img_train.tar 和…...

C/C++外观模式解析:简化复杂子系统的高效方法

C外观模式揭秘&#xff1a;简化复杂子系统的高效方法 引言设计模式的重要性外观模式简介与应用场景外观模式在现代软件设计中的地位与价值 外观模式基本概念外观模式的定义与核心思想提供简单接口隐藏复杂子系统设计原则与外观模式的关系外观模式实现外观模式的UML图 外观模式的…...

追梦之旅【数据结构篇】——详解小白如何使用C语言实现堆数据结构

详解小白如何使用C语言实现堆数据结构 “痛”撕堆排序~&#x1f60e; 前言&#x1f64c;什么是堆&#xff1f;堆的概念及结构 堆的性质&#xff1a;堆的实现堆向下调整算法画图分析&#xff1a;堆向下调整算法源代码分享&#xff1a;向下调整建小堆向下调整建大堆 堆向上调整算…...

cocoscreator性能优化4-Sprite颜色数据去除

前言 Sprite是游戏内容的一个基本组成元素&#xff0c;包括ui、道具、立绘等各种地方都会用到。大部分情况下美术会帮我们调好图片颜色&#xff0c;我们只要把图片直接放到游戏里就行了。Sprite默认的渲染顶点数据中包含了颜色数据&#xff0c;由于我们并不需要去修改颜色&…...

系统接口幂等性设计探究

前言&#xff1a; 刚开始工作的时候写了一个带UI页面的工具&#xff0c;需要设计登录功能&#xff0c;登录功能也很简单&#xff0c;输入用户名密码点击登录&#xff0c;触发后台查询并比对密码&#xff0c;如果登录成功则返回消息给前端&#xff0c;前端把消息弹出提示一下。…...

C learning_7

目录 1.for循环 1.虽然while循环和for循环本质上都可以实现循环&#xff0c;但是它们在使用方法和场合上还是有一些区别的。 2.while循环中存在循环的三个必须条件&#xff0c;但是由于风格的问题使得三个部分很可能偏离较远&#xff0c;这样 查找修改就不够集中和方便。所以…...

PageRank算法介绍

互联网上有数百亿个网页&#xff0c;可以分为这么几类&#xff1a;不含有用信息的&#xff0c;比如垃圾邮件&#xff1b;少数人比较感兴趣的&#xff0c;但范围不是很广的&#xff0c;比如个人博客、婚礼公告或家庭像册&#xff1b;很多人感兴趣的并且十分有用的&#xff0c;比…...

springboot+vue职称评审管理系统(源码+文档)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的职称评审管理系统。项目源码请联系风歌&#xff0c;文末附上联系信息 。 目前有各类成品java毕设&#xff0c;需要请看文末联系方式 …...

腾讯云4核8G轻量服务器12M支持多少访客同时在线?并发数怎么算?

腾讯云轻量4核8G12M轻量应用服务器支持多少人同时在线&#xff1f;通用型-4核8G-180G-2000G&#xff0c;2000GB月流量&#xff0c;系统盘为180GB SSD盘&#xff0c;12M公网带宽&#xff0c;下载速度峰值为1536KB/s&#xff0c;即1.5M/秒&#xff0c;假设网站内页平均大小为60KB…...

图片英文翻译成中文转换器-中文翻译英文软件

您正在准备一份重要的英文资料或文件&#xff0c;但是您还不是很熟练地掌握英文&#xff0c;需要翻译才能完成您的任务吗&#xff1f;哪个软件能够免费把英文文档翻译成中文&#xff1f;让我们带您了解如何使用我们的翻译软件来免费翻译英文文档为中文。 我们的翻译软件是一款功…...

月薪10k和40k的程序员差距有多大?

程序员的薪资一直是大家关注的焦点&#xff0c;相较于其他行业&#xff0c;程序员的高薪也是有目共睹的&#xff0c;而不同等级的程序员处理问题的方式与他们的薪资直接挂钩。 接下来就一起看一下月薪10k、20k、30k、40k的程序员面对问题都是怎么处理的吧&#xff01; 场景一 …...

gateway整合knife4j(微服务在线文档)

文章目录 knife4j 微服务整合一、微服务与单体项目文档整合的区别二、开始整合1. 搭建一个父子maven模块的微服务,并引入gateway2.开始整合文档 总结 knife4j 微服务整合 由于单个服务的knife4j 整合之前已经写过了,那么由于效果比较好,然后微服务的项目中也想引入,所以开始微…...

ASP.NET 记录 HttpRequest HttpResponse HttpServerUtility

纯属个人记录,会有错误 HttpRequest Browser是获取客户端浏览器的信息 Cookies是获取客户端的Cookies QueryString是获取客户端提交的数据 ServerVariables是获取服务器端或客户端的环境变量信息 Browser 语法格式: Request.Browser[“浏览器特性名”] 常见的特性名 名称说…...

Python 人工智能:11~15

原文&#xff1a;Artificial Intelligence with Python 协议&#xff1a;CC BY-NC-SA 4.0 译者&#xff1a;飞龙 本文来自【ApacheCN 深度学习 译文集】&#xff0c;采用译后编辑&#xff08;MTPE&#xff09;流程来尽可能提升效率。 不要担心自己的形象&#xff0c;只关心如何…...

辉煌优配|军工板块逆市上涨,16只概念股已披露一季度业绩预喜

今日&#xff0c;军工股逆市上涨。 4月21日&#xff0c;A股三大股指低开低走&#xff0c;半导体、AI使用、信创工业、软件等科技属性概念领跌&#xff0c;国防军工、食品饮料和电力设备等板块上涨。 工业互联网中心工业规模超1.2万亿元 据央视新闻报道&#xff0c;本年是《工业…...

看板与 Scrum:有什么区别?

看板和Scrum是项目管理方法论&#xff0c;以小增量完成项目任务并强调持续改进。但是他们用来实现这些目标的过程是不同的。看板以可视化任务和连续流程为中心&#xff0c;而Scrum更多是关于为每个交付周期实施时间表和分配设定角色。 在看板和Scrum之间做出选择并不总是必要…...

零代码是什么?零代码平台适合谁用?

随着信息技术的发展&#xff0c;软件开发领域也不断发生变革&#xff0c;零代码&#xff08;No-Code&#xff09;开发模式越来越受到关注。 零代码到底是什么&#xff0c;能不能用通俗的话来说&#xff1f;这就来给大家讲一讲&#xff01; 01 零代码为什么出现&#xff1f; 随…...

CNStack 云服务云组件:打造丰富的云原生技术中台生态

作者&#xff1a;刘裕惺 CNStack 相关阅读&#xff1a; CNStack 多集群服务&#xff1a;基于OCM 打造完善的集群管理能力 CNStack 虚拟化服务&#xff1a;实现虚拟机和容器资源的共池管理 CNStack 云边协同平台&#xff1a;实现原生边缘竟能如此简单 01 前言 CNStack 2.0…...

#PythonPytorch 1.如何入门深度学习模型

我之前也写过一篇关于Keras的深度学习入门blog&#xff0c;#Python&Keras 1.如何从无到有在自己的数据集上实现深度学习模型&#xff08;入门&#xff09;&#xff0c;里面也有介绍了一下一点点机器学习的概念和理解深度学习的输入&#xff0c;如果对这方面有疑惑的朋友可以…...

java 实现excel文件转pdf | 无水印 | 无限制

文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端

&#x1f31f; 什么是 MCP&#xff1f; 模型控制协议 (MCP) 是一种创新的协议&#xff0c;旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议&#xff0c;它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

基于当前项目通过npm包形式暴露公共组件

1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹&#xff0c;并新增内容 3.创建package文件夹...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

【生成模型】视频生成论文调研

工作清单 上游应用方向&#xff1a;控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

【Linux】Linux 系统默认的目录及作用说明

博主介绍&#xff1a;✌全网粉丝23W&#xff0c;CSDN博客专家、Java领域优质创作者&#xff0c;掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围&#xff1a;SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...

vue3 daterange正则踩坑

<el-form-item label"空置时间" prop"vacantTime"> <el-date-picker v-model"form.vacantTime" type"daterange" start-placeholder"开始日期" end-placeholder"结束日期" clearable :editable"fal…...

spring Security对RBAC及其ABAC的支持使用

RBAC (基于角色的访问控制) RBAC (Role-Based Access Control) 是 Spring Security 中最常用的权限模型&#xff0c;它将权限分配给角色&#xff0c;再将角色分配给用户。 RBAC 核心实现 1. 数据库设计 users roles permissions ------- ------…...