SpringBoot security 安全认证(一)——登录验证

本节内容:使用springboot自动security模块实现用户登录验证功能;
登录过程如下图:
在这里插入图片描述
AuthenticationManager内容实现用户账号密码验证,还可以对用户状态(启用/禁用),逻辑删除,账号是否被锁定等判断。密码加密方式内置了好几种,我使用的是BCryptPasswordEncoder。那么我们在用户注册时密码要使用 new BCryptPasswordEncoder().encode(pwd)进行加密。

代码实现过程:
1、引入相关依赖;
2、创建UserDetails实现类LoginUser;
3、创建UserDetailsService实现类UserDetailsServiceImpl;
4、SecurityConfiguration配置,将UserDetailsServiceImpl注入相关对象,并配置加密算法;
5、实现账号密码验证;

pom.xml引入依赖

<dependencies><!-- 实现对 Spring MVC 的自动化配置 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- spring security 安全认证 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><!-- Token生成与解析--><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency><!-- 解析客户端操作系统、浏览器等 --><dependency><groupId>eu.bitwalker</groupId><artifactId>UserAgentUtils</artifactId><version>1.21</version></dependency>
<!-- String工具类 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.12.0</version></dependency><!-- 阿里JSON解析器 --><dependency><groupId>com.alibaba.fastjson2</groupId><artifactId>fastjson2</artifactId><version>2.0.34</version></dependency><!-- 方便等会写单元测试 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><!-- 引入 Swagger 依赖 --><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version></dependency><!-- 引入 Swagger UI 依赖,以实现 API 接口的 UI 界面 --><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>2.9.2</version></dependency></dependencies>

UserDetails的实现类LoginUser

是数据库用户到Spring用户的转换,提供给Spring内部获取用户账号、状态等的。

package com.luo.chengrui.labs.lab04.model;import com.alibaba.fastjson2.annotation.JSONField;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;import java.util.Collection;/*** 登录用户身份权限** @author ruoyi*/
public class LoginUser implements UserDetails {private static final long serialVersionUID = 1L;/*** 用户ID*/private String userId;/*** 用户唯一标识*/private String token;/*** 登录时间*/private Long loginTime;/*** 过期时间*/private Long expireTime;/*** 登录IP地址*/private String ipaddr;/*** 登录地点*/private String loginLocation;/*** 浏览器类型*/private String browser;/*** 操作系统*/private String os;//数据库用户映射表private SysUser user;public LoginUser(String userId, SysUser user) {this.userId = userId;this.user = user;}public static long getSerialVersionUID() {return serialVersionUID;}public String getUserId() {return userId;}public void setUserId(String userId) {this.userId = userId;}public String getToken() {return token;}public void setToken(String token) {this.token = token;}public Long getLoginTime() {return loginTime;}public void setLoginTime(Long loginTime) {this.loginTime = loginTime;}public Long getExpireTime() {return expireTime;}public void setExpireTime(Long expireTime) {this.expireTime = expireTime;}public String getIpaddr() {return ipaddr;}public void setIpaddr(String ipaddr) {this.ipaddr = ipaddr;}public String getLoginLocation() {return loginLocation;}public void setLoginLocation(String loginLocation) {this.loginLocation = loginLocation;}public String getBrowser() {return browser;}public void setBrowser(String browser) {this.browser = browser;}public String getOs() {return os;}public void setOs(String os) {this.os = os;}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {return null;}@JSONField(serialize = false)@Overridepublic String getPassword() {return user.getPassword();}@Overridepublic String getUsername() {return user.getUsername();}//账号未过期 @JSONField(serialize = false)@Overridepublic boolean isAccountNonExpired() {return true;}//账号未被锁定@JSONField(serialize = false)@Overridepublic boolean isAccountNonLocked() {return true;}//密码未过期@JSONField(serialize = false)@Overridepublic boolean isCredentialsNonExpired() {return true;}/*** 是否可用 ,禁用的用户不能身份验证** @return*/@JSONField(serialize = false)@Overridepublic boolean isEnabled() {return true;}
}

LoginUser类看着字段较多,基本都是和业务相关,比如记录登录用户的IP,地址,登录时间等的。看实际情况,可以优化掉的,仅保留SysUser对象也是完全可以的。

UserDetailsService接口实现类 UserDetailsServiceImpl

实现根据用户名获取用户信息,提供给spring内部调用的。

package com.luo.chengrui.labs.lab04.service;import com.luo.chengrui.labs.lab04.model.LoginUser;
import com.luo.chengrui.labs.lab04.model.SysUser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;import java.util.Objects;/*** 用户验证处理** @author ruoyi*/
@Service
public class UserDetailsServiceImpl implements UserDetailsService {private static final Logger log = LoggerFactory.getLogger(UserDetailsServiceImpl.class);@Autowiredprivate UserService userService;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {SysUser user = userService.selectUserByUserName(username);if (user == null) {log.info("登录用户:{} 不存在.", username);throw new RuntimeException("登录用户:" + username + " 不存在");} else if (Objects.equals(1, user.getDelFlag())) {log.info("登录用户:{} 已被删除.", username);throw new RuntimeException("对不起,您的账号:" + username + " 已被删除");} else if (Objects.equals(0, user.getStatus())) {log.info("登录用户:{} 已被停用.", username);throw new RuntimeException ("对不起,您的账号:" + username + " 已停用");}return createLoginUser(user);}public UserDetails createLoginUser(SysUser user) {return new LoginUser(user.getUserId(),user);}
}

1、以上判断用户状态和是否被删除等操作也可以交由spring去做,你只要在LoginUser类中相关方法中返回结果即可。在这里可以做额外的合法性判断。(如这个账号登录次数超限了,并且可以提示相关登录失败信息)
2、实现了根据用户账号查询用户信息方法,最后返回了我们上面定义的LoginUser对象。

LoginUservice登录实现

package com.luo.chengrui.labs.lab04.service;import com.luo.chengrui.labs.lab04.model.LoginUser;
import com.luo.chengrui.labs.lab04.utils.UUID;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;/*** @author* @version 1.0.0* @description* @createTime 2024/01/05*/
@Service
public class LoginService {@Resourceprivate AuthenticationManager authenticationManager;private static final String secret = "abcdefghijklmnopqrstuvwxyz";public String login(String username, String password) {// 用户验证Authentication authentication = null;try {UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);authentication = authenticationManager.authenticate(authenticationToken);} catch (Exception e) {//这里应该按不同异常类型分别捕获,更精确的提示用户登录失败的原因。看业务需要throw new RuntimeException("用户名或密码错误");} finally {}LoginUser loginUser = (LoginUser) authentication.getPrincipal();// 生成tokenreturn createToken(loginUser);}/*** 创建令牌** @param loginUser 用户信息* @return 令牌*/public String createToken(LoginUser loginUser) {String token = UUID.fastUUID().toString();loginUser.setToken(token);Map<String, Object> claims = new HashMap<>();claims.put("LOGIN_USER_KEY", token);return createToken(claims);}private String createToken(Map<String, Object> claims) {String token = Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS512, secret).compact();return token;}/*** 刷新令牌有效期,是指刷新缓存中存储的token信息。我们本示例中暂不做缓存。** @param loginUser 登录信息*/public void refreshToken(LoginUser loginUser) {loginUser.setLoginTime(System.currentTimeMillis());loginUser.setExpireTime(loginUser.getLoginTime() + 30 * 60 * 1000);}
}

SecurityConfig

1、创建鉴权管理器:AuthenticationManager ;
2、设置请求过滤;
3、设置密码加密算法;
4、设置用户获取对象;

package com.luo.chengrui.labs.lab04.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.filter.CorsFilter;/*** spring security配置** @author */
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {/*** 自定义用户认证逻辑*/@Autowiredprivate UserDetailsService userDetailsService;/*** 解决 无法直接注入 AuthenticationManager** @return* @throws Exception*/@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}/*** anyRequest          |   匹配所有请求路径*/@Overrideprotected void configure(HttpSecurity httpSecurity) throws Exception {httpSecurity// CSRF禁用,因为不使用session.csrf().disable()// 过滤请求.authorizeRequests()// 所有请求均以放行.anyRequest().permitAll().and().headers().frameOptions().disable();}/*** 强散列哈希加密实现*/@Beanpublic BCryptPasswordEncoder bCryptPasswordEncoder() {return new BCryptPasswordEncoder();}/*** 设置密码加密算法*/@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());}
}

到此,使用Spring security登录验证的核心代码就写完了。再一个实现UserService类实现从数据库查询用户

UserServiceImpl

package com.luo.chengrui.labs.lab04.service;import com.luo.chengrui.labs.lab04.model.SysUser;
import com.luo.chengrui.labs.lab04.utils.SecurityUtils;
import com.luo.chengrui.labs.lab04.utils.StringUtils;
import org.springframework.stereotype.Service;import java.util.*;
import java.util.stream.Collectors;/*** @author* @version 1.0.0* @description* @createTime 2024/01/31*/
@Service
public class UserService {private static final Map<String, SysUser> userMap = new HashMap<>();static {userMap.put("admin", new SysUser("1", "admin", SecurityUtils.encryptPassword("admin123"), 1));}public List<SysUser> selectUser() {return userMap.entrySet().stream().map(item -> item.getValue()).collect(Collectors.toList());}public SysUser selectUserByUserName(String username) {SysUser user = userMap.get(username);if (user == null) {throw new RuntimeException("用户不存在");}return user;}public SysUser registerUser(SysUser user) {if (user == null) {throw new RuntimeException("用户信息不能为空");}if (StringUtils.isEmpty(user.getUsername())) {throw new RuntimeException("用户名不能为空");}if (StringUtils.isEmpty(user.getPassword())) {throw new RuntimeException("密码不能为空");}if (userMap.get(user.getUsername()) != null) {throw new RuntimeException("用户名已经存在");}user.setUserId(UUID.randomUUID().toString());user.setStatus(1);user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));userMap.put(user.getUserId(), user);return user;}public SysUser selectUser(String username) {return userMap.get(username);}
}

简单模拟了根据账号查询用户的接口,实际是事先在userMap中放了一个admin用户而已。

SysUser数据库对象

package com.luo.chengrui.labs.lab04.model;/*** @author* @version 1.0.0* @description* @createTime 2024/01/31*/
public class SysUser {private String userId;private String username;private String password;private Integer delFlag;private Integer status;public SysUser() {}public SysUser(String userId, String username, String password,  Integer status) {this.userId = userId;this.username = username;this.password = password;this.status = status;}public String getUserId() {return userId;}public void setUserId(String userId) {this.userId = userId;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public Integer getDelFlag() {return delFlag;}public void setDelFlag(Integer delFlag) {this.delFlag = delFlag;}public Integer getStatus() {return status;}public void setStatus(Integer status) {this.status = status;}
}

controller

package com.luo.chengrui.labs.lab04.controller;import com.luo.chengrui.labs.lab04.model.AjaxResult;
import com.luo.chengrui.labs.lab04.model.LoginBody;
import com.luo.chengrui.labs.lab04.service.LoginService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;/*** @author* @version 1.0.0* @description* @createTime 2023/07/17*/
@RestController
@Api(tags = "用户 API 接口")
public class LoginController {@AutowiredLoginService loginService;@ApiOperation(value = "用户登录 ", notes = "目前仅仅是作为测试,所以返回用户全列表")@PostMapping("/login")public AjaxResult login(@RequestBody LoginBody loginBody) {AjaxResult ajax = AjaxResult.success();// 生成令牌String token = loginService.login(loginBody.getUsername(), loginBody.getPassword());ajax.put("token", token);return ajax;}}

swagger配置

package com.luo.chengrui.labs.lab04.config;import com.luo.chengrui.labs.lab04.service.TokenService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;import java.util.ArrayList;
import java.util.List;/*** 访问地址:/swagger-ui.html** @author* @version 1.0.0* @description* @createTime 2023/07/17*/
@Configuration
@EnableSwagger2
public class SwaggerConfiguration {@AutowiredTokenService tokenService;@Beanpublic Docket createRestApi() {/* 让swagger页面上的每个接口都添加一个Header参数,用来传递token参数*/ParameterBuilder ticketPar = new ParameterBuilder();List<Parameter> pars = new ArrayList<Parameter>();ticketPar.name(tokenService.getHeader()).description("user ticket")//Token 以及Authorization 为自定义的参数,session保存的名字是哪个就可以写成那个.modelRef(new ModelRef("string")).parameterType("header").required(false).build(); //header中的ticket参数非必填,传空也可以pars.add(ticketPar.build()); //根据每个方法名也知道当前方法在设置什么参数// 创建 Docket 对象return new Docket(DocumentationType.SWAGGER_2) // 文档类型,使用 Swagger2.apiInfo(this.apiInfo()) // 设置 API 信息// 扫描 Controller 包路径,获得 API 接口.select().apis(RequestHandlerSelectors.basePackage("com.luo.chengrui.labs.lab04.controller")).paths(PathSelectors.any())// 构建出 Docket 对象.build().globalOperationParameters(pars);}/*** 创建 API 信息*/private ApiInfo apiInfo() {return new ApiInfoBuilder().title("测试接口文档示例").description("我是一段描述").version("1.0.0") // 版本号.contact(new Contact("XX", "http://localhost", "luodz@gmail.com")) // 联系人.build();}
}

Swaager请求示例:
在这里插入图片描述
响应结果:
在这里插入图片描述

后台方法调用:
1、调用 UserDetailsServiceImpl.LoadUserByUsername方法,获取用户信息;
在这里插入图片描述

2、判断用户各种可用状态和密码合法性。
在这里插入图片描述
小结:本节主要演示了如何使用Spring去实现登录验证
1、创建UserDetails接口实现类,UserDetails是Spring内部定义的登录用户信息,包含账号、密码、删除状态、禁用状态、锁定状态、密码过期状态;
2、创建UserDetailsService接口实现类,实现loadUserByUsername(String username)方法;
3、用户合法性验证,仅一行代码即可完成用户合法性验证:

Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
LoginUser loginUser = (LoginUser) authentication.getPrincipal();

下一节,咱们可以实现对接口访问的拦截了。

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

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

相关文章

IPSec VPN与NQA联动实现主备对等体和主备链路快速切换案例

知识改变命运&#xff0c;技术就是要分享&#xff0c;有问题随时联系&#xff0c;免费答疑&#xff0c;欢迎联系&#xff01; 厦门微思网络​​​​​​https://www.xmws.cn 华为认证\华为HCIA-Datacom\华为HCIP-Datacom\华为HCIE-Datacom Linux\RHCE\RHCE 9.0\RHCA\ Oracle OC…

java设计模式:策略模式

在平常的开发工作中&#xff0c;经常会用到不同的设计模式&#xff0c;合理的使用设计模式&#xff0c;可以提高开发效率&#xff0c;提高代码质量&#xff0c;提高代码的可拓展性和维护性。今天来聊聊策略模式。 策略模式是一种行为型设计模式&#xff0c;运行时可以根据需求动…

记录 arm 开发板上 nginx 配置 http 服务注意事项

1. 自定义项目&#xff0c;需要在 conf.d 目录中增加一个 .conf 配置文件&#xff1a; server {listen 9200; # 端口号server_name localhost; # 服务名称location / {root /home/imx6q/media; # 项目根目录&#xff08;需要修改 n…

redis布隆过滤器(Bloom)详细使用教程

文章目录 布隆过滤器1. 原理2. 结构和操作3. 特点和应用场景4. 缺点和注意事项 应用-redis插件布隆过滤器使用详细过程安装以及配置springboot项目使用redis布隆过滤器下面是布隆过滤器的一些基础命令 扩展 布隆过滤器 Bloom 过滤器是一种概率型数据结构&#xff0c;用于快速判…

AcWing算法学习笔记:贪心(区间问题 + Huffman树 + 排序不等式 + 绝对值不等式 + 推公式)

贪心 一、区间问题①区间选点②最大不相交区间数量③区间分组④区间覆盖 二、Huffman树&#xff08;合并果子&#xff09;三、排序不等式&#xff08;排队打水&#xff09;四、绝对值不等式&#xff08;货仓选址&#xff09;五、推公式&#xff08;耍杂技的牛&#xff09; 一、…

常见API

文章目录 Math类1.1 概述1.2 常见方法 System类2.1 概述2.2 常见方法 Runtime3.1 概述3.2 常见方法 Object类4.1 概述4.2 常见方法 Objects类5.1 概述5.2 常见方法 BigInteger类6.1 引入6.2 概述6.3 常见方法6.4 底层存储方式&#xff1a; 7 BigDecimal类7.1 引入7.2 概述7.3 常…

leetcode 1.两数之和(C++)DAY1(待补充哈希表法)

文章目录 1.题目描述示例提示 2.解答思路3.实现代码结果4.总结 1.题目描述 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&…

猫用空气净化器真的能除菌吗?除毛可以用宠物空气净化器吗?

猫咪给我们带来了无尽的欢乐&#xff0c;但它们换毛时家里到处都是猫毛。我们会在地板、沙发上发现一大堆&#xff0c;甚至衣服也难逃其影响。这些浮毛中可能携带着微生物和尘螨等。对于免疫力较低的老年人、孩子和孕妇来说&#xff0c;他们更容易感染这些微生物。而对于鼻炎患…

openlayers加载天地图

申请天地图key 官方&#xff1a;https://www.tianditu.gov.cn/ 申请key&#xff1a;https://sso.tianditu.gov.cn/login?servicehttps%3A%2F%2Fconsole.tianditu.gov.cn%2F 进去之后&#xff0c;先登录&#xff0c;如果没账号先注册一个就行。 可以创建个应用&#xff0c;…

Unity制作随风摇摆的植物

今天记录一下如何实现随风摇摆的植物&#xff0c;之前项目里面的植物摇摆实现是使用骨骼动画实现的&#xff0c;这种方式太消耗性能&#xff0c;植物这种东西没必要&#xff0c;直接使用顶点动画即可。 准备 植物不需要使用标准的PBR流程&#xff0c;基础的颜色贴图加上法向贴…

153基于matlab的滚动轴承故障诊断

基于matlab的滚动轴承故障诊断&#xff0c;基于小波包分解&#xff0c;得到数据峭度值&#xff0c;以正常与故障数据峭度差值进行最大尺度重构&#xff0c;对重构信号进行包络谱分析。程序已调通&#xff0c;可直接运行。 153matlab 信号重构 包络谱分析 故障诊断 (xiaohongshu…

网络流数据集处理(深度学习数据处理基础)

一、数据集处理 处理数据集是一个文件夹 一个文件夹处理的&#xff0c;将原网络流数据集 放入一个文件夹 处理转换成 Json文件。&#xff08;数据预处理&#xff09;然后将这些文件处理成目标文件格式 再分割成训练集和测试集。每次运行只会处理一个文件夹。 运行train.py 导入…

html,css,js速成

准备&#xff1a;vscode配好c&#xff0c;python&#xff0c;vue环境&#xff0c;并下载live server插件。 1. html hypertext markup language(超文本标记语言) 1. 基础语法 一个html元素由开始标签&#xff0c;填充文本&#xff0c;结束标签构成。 常见标签说明<b>…

VC++中使用OpenCV绘制直线、矩形、圆和文字

VC中使用OpenCV绘制直线、矩形、圆和文字 在VC中使用OpenCV绘制直线、矩形、圆和文字非常简单&#xff0c;分别使用OpenCV中的line、rectangle、circle、putText这四个函数即可。具体可以参考OpenCV官方文档&#xff1a;https://docs.opencv.org/4.x/index.html 下面的代码展…

微信小程序实现时间轴效果

目录 引言时间轴效果的应用场景微信小程序的优势时间轴效果的设计思路时间轴界面布局数据结构设计实现时间轴效果WXML结构设计WXSS样式设计JavaScript逻辑实现说明引言 时间轴效果的应用场景 时间轴效果作为一种独特且直观的信息展示形式,已经被广泛应用于各种场景中,提供了…

【EI会议征稿通知】第四届光学与图像处理国际学术会议(ICOIP 2024)

第四届光学与图像处理国际学术会议&#xff08;ICOIP 2024&#xff09; 2024 4th International Conference on Optics and Image Processing 光学器件的实用化、图像处理的更优化等话题深受国内外专家、学者们关注。为推动光学与图像处理的发展&#xff0c;促进该领域学术交…

Flutter 和 Android原生(Activity、Fragment)相互跳转、传参

前言 本文主要讲解 Flutter 和 Android原生之间&#xff0c;页面相互跳转、传参&#xff0c; 但其中用到了两端相互通信的知识&#xff0c;非常建议先看完这篇 讲解通信的文章&#xff1a; Flutter 与 Android原生 相互通信&#xff1a;BasicMessageChannel、MethodChannel、…

命名空间(namespace)及其应用技巧

C 命名空间及其应用技巧 文章目录 C 命名空间及其应用技巧引言代码案例一&#xff1a;不同命名空间的变量和自定义类型代码案例二&#xff1a;命名空间的嵌套和using的使用代码案例三&#xff1a;不连续的同名命名空间代码案例四&#xff1a;命名空间和局部、全局变量的优先级总…

使用Ettus USRP X440对雷达和EW系统进行原型验证

概览 无论是保障己方平台的生存能力&#xff0c;还是扰乱敌方频谱使用&#xff0c;以电磁(EM)频谱为主导都是任务成功的主要因素。电磁频谱操作(Electromagnetic Spectrum Operation, EMSO)需要使用战术系统来监测敌方的频谱活动、定位其发射器并帮助己方制定行动计划。软件无…

大数据 - Spark系列《二》- 关于Spark在Idea中的一些常用配置

上一篇&#xff1a; 大数据 - Spark系列《一》- 从Hadoop到Spark&#xff1a;大数据计算引擎的演进-CSDN博客 目录 1. &#x1f959;Idea中配置Live Templates来快速生成代码片段 2. &#x1f959;Idea中配置文件模板自定义初始代码 3.&#x1f959;设置spark-submit提交程…