SpringSecurity安全授权

目录

前言

正文

1.基本流程

2.基本用法

3.配置项 

4.HttpSecurity 方式和内存认证方式 

5.认证流程

6.基于数据库查询的登录验证

7.多种角色权限认证 

8.自定义权限认证 

总结


前言

安全对于任何系统来说都是非常重要的,权限的分配和管理一直都是开发者需要特别重视的。一旦缺乏基本和有力的授权验证,一些别有用心之人就会利用这个漏洞对开发者的 Web 应用或者其他软件进行不法侵害。Spring Boot 技术中有许多优秀的安全框架和认证授权方案,本次将介绍比较流行的框架技术 Spring Security 及其实践应用。


正文

Spring Security 是 Spring Boot 中一款功能强大基于 Spring 的企业级应用的提供安全访问权限的安装框架,在实际工程项目中也会经常用到。通过依赖注入的方式,可以使用 Spring Security 库提供声明式的安全访问控制功能。它和 Spring Boot 以及其他 Spring 模块紧密相连。

1.基本流程

Spring Security 的原理其实就是一个过滤器链,内部包含了提供各种功能的过滤器。 

图中只展示了核心过滤器,其它的非核心过滤器并没有在图中展示

  • UsernamePasswordAuthenticationFilter:负责处理我们在登页面填写了用户名密码后的登陆请求。入门案例的认证工作主要有它负责。
  • ExceptionTranslationFilter: 外理过滤器中抛出的任 AccessDeniedException 和 AuthenticationException。
  • FilterSecuritylnterceptor: 负责权限校验的过滤器 

通过 debug 查看当前的过滤器链

package org.example;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;@SpringBootApplication
public class Main {public static void main(String[] args) {ConfigurableApplicationContext run = SpringApplication.run(Main.class, args);System.out.println(run);//在此处打上断点}
}

打开表达式计算面板 

run.getBean(DefaultSecurityFilterChain.class)

计算求值:

2.基本用法

安装,在 pom.xml 中导入依赖即可

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency>

在项目中编写一个测试的接口 /testHi,代码如下:

package org.example.controller;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class HiController {@GetMapping("/hi")public String hi(){return "Hi";}
}

编写一个类,更好的配置管理。

package org.example.config;import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;/*** Security 配置类*/
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {/***  认证* @param auth* @throws Exception*/@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()).withUser("freejava").password(new BCryptPasswordEncoder().encode("123456")).roles("VIP1");}/*** 授权* @param http* @throws Exception*/@Overrideprotected void configure(HttpSecurity http) throws Exception {//设置匹配的资源白名单访问http.authorizeRequests().antMatchers("/","/asserts/**","/pages/login.html","/userlogin").permitAll().antMatchers("/level1/**").hasRole("VIP1").antMatchers("/level2/**").hasRole("VIP2").antMatchers("/level3/**").hasRole("VIP3").anyRequest().authenticated();//剩余任何资源必须认证//开启登录页http.formLogin();//开启自动注销http.logout().logoutSuccessUrl("/login");//注销之后来到登录页http.csrf().disable();}
}

最后运行会出现如下界面:

3.配置项 

如果想要修改默认的账号和密码,可以在 application.properties 文件中加入下面的配置项。

spring.security.user.name=freejava
spring.security.user.password=123456
spring.security.user.roles[]=admin

4.HttpSecurity 方式和内存认证方式 

所谓内存认证就是自定义配置类,该配置类继承 WebSecurityConfigurerAdapter,需要实现一些自定义配置和方法,具体代码如下:

package org.example.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;@EnableWebSecurity
public class RealSecurityConfig extends WebSecurityConfigurerAdapter {@BeanPasswordEncoder passwordEncoder(){//NoOpPasswordEncoder  在高版本的Spring Boot 中已被弃用,不建议使用return new BCryptPasswordEncoder();}@Autowired PasswordEncoder passwordEncoder;@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.inMemoryAuthentication().passwordEncoder(passwordEncoder)//使用对应的加密.withUser("admin").password(passwordEncoder.encode("123456"))//使用对应的解密.roles("ADMIN","USER").and().withUser("freephp").password(passwordEncoder.encode("123456")).roles("USER");}
}

上面这段代码中,inMemoryAuthentication 代表把这个配置保存在内存中,然后使用 withUser 方法增加授权账号,用 password 方法设置密码,用 roles 来设置账号所属的权限群组。

HttpSecurity 是另外一种认证方式,也是使用 configure 方法,具体代码如下:

@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/admin/**").hasRole("ADMIN").antMatchers("/user/**").access("hasAnyRole('ADMIN','USER')").anyRequest().authenticated()//任意登录的用户都可以访问.and().formLogin().loginProcessingUrl("/login").permitAll().and().csrf().disable();}

使用 andMatcher 设置需要被授权的 URL 路径,access 方法给予某些角色访问权限,代码如下:。

package org.example.controller;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class SwagController {@GetMapping("/user/sayHi")public String myUser(){return "Hi,user";}@GetMapping("/admin/hello")public String admin(){return "admin page";}@GetMapping("/hello")public String hello(){return "hello,man";}
}

运行项目后,访问 http://localhost:8080/admin/hello, 则会要求输入账号和密码,使用 admin 账号,密码输入 123456,即可进入后台 /admin/hello 页面,如图。

5.认证流程

  • Authentication接口: 它的实现类,表示当前访问系统的用户,封装了用户相关信息。
  • AuthenticationManager接口: 定义了认证Authentication的方法。
  • UserDetailsService接口: 加载用户特定数据的核心接口。里面定义了一个根据用户名查询用户信息的方法。
  • UserDetails接口: 提供核心用户信息。通过UserDetailsService根据用户名获取处理的用户信息要封装成UserDetails对象返回,然后将这些信息封装到Authentication对象中。

所以接下来如果要使用数据库做登录验证,只要把实现类 InMemoryUserDetailsManager 做一个替换,DaoAuthenticationProvider 调用自定义的实现类。让其不再使用内存做认证进入数据库查询,实现 UserDetailsService 接口即可。

6.基于数据库查询的登录验证

之前都是使用内存来存储认证数据,其实可以考虑使用数据库进行持久化数据存储。这样更加方便进行账号管理,也更符合实际项目开发的需求。 

创建一个 roles 库,然后创建用户表、角色权限表、用户和角色权限关系表。

create database     r_security;
use r_security;
-- 用户表
CREATE TABLE  `r_users`(`id` int(11) unsigned NOT NULL AUTO_INCREMENT primary key COMMENT '主键',`username` varchar(50) not null  comment '账号名',`password` varchar(300) not null comment '密码',`status` tinyint(11) not null comment '账号状态,1:正常、2:被封',`created` int (11) not null comment '创建时间,时间戳');
-- 角色权限表
create table `r_roles`(`id` int(11) unsigned not null auto_increment comment '主键',`name` varchar(50) not null  comment '角色名',`permission_path` varchar(500) not null  comment '权限路径,如/admin/*',primary key (id)
);
-- 用户角色权限关系表
create table `r_user_roles`(`id` int(11) unsigned not null auto_increment comment '主键',`user_id` int(11) unsigned not null  comment '用户ID',`role_id` int(11) unsigned not null comment '角色ID',primary key (`id`),key `user_id` (`user_id`),key `role_id` (`role_id`),constraint `role_id` foreign key  (`role_id`) references `r_roles`(`id`) ondelete  restrict ,constraint `user_id` foreign key (`user_id`) references `r_users`(`id`) ondelete  restrict
)

为了方便测试,先插入几条测试数据,r_users 的数据如图

R_roles的数据如图,插入三条数据,有三种角色,一是管理员角色,二是 root 权限,也就是超级管理员。三是 dba,数据管理员。这三种角色可以访问不同的 URL。 

用户角色表中插入数据

为了生成上面 r_users 表中加密后的密码,攥写了使用 Bcrypt 加密的程序,代码如下: 

import java.util.ArrayList;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
public class BcryptTest {public static void main(String[] args) {ArrayList<String> passwordArr = new ArrayList<>();passwordArr.add("123456");getUsersEncodePasswords(passwordArr);}private static void getUsersEncodePasswords(ArrayList<String> passwordArr) {for (String pass :passwordArr){//密码加密BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();String newPassword = passwordEncoder.encode(pass);System.out.println(" 原始密码是:"+pass+",加密密码为:"+newPassword);//对比这两个密码是不是同一个密码boolean match = passwordEncoder.matches(pass,newPassword);System.out.println("两个密码一致:"+match);}}
}

运行结果如图:

Bcrpt 加密算法非常安全,此算法自身实现了随机盐生成,很难被逆向破解。 

创建一个新的项目,导入依赖,pom.xml代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>Security2</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.5.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!--     引入security依赖   --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.3.5.RELEASE</version></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.1.1</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.10</version></dependency><!-- mysql --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope><exclusions><exclusion><groupId>org.junit.vintage</groupId><artifactId>junit-vintage-engine</artifactId></exclusion></exclusions></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>test</scope></dependency></dependencies></project>

r_roles 表对应的部分实体类对象

package org.example.entity;import lombok.Data;@Data
public class Role {// 主键 IDprivate Integer id;// 名称private String name;//权限路径private String permission_path;
}

创建 r_users 对应的 POJO 对象 User,继承自 UserDetails 接口,代码如下:

package org.example.entity;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;import java.util.ArrayList;
import java.util.Collection;
import java.util.List;@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements UserDetails {//主键 idprivate Integer id;//用户名private String username;//密码private String password;// 状态 1:正常,2:封禁private int status;// 创建时间private int created;private List<Role> roles;@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {List<SimpleGrantedAuthority> authorities = new ArrayList<>();for(Role role : roles){authorities.add(new SimpleGrantedAuthority(role.getName()));}return authorities;}@Overridepublic String getPassword() {return password;}@Overridepublic String getUsername() {return username;}@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return status != 2;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return status == 1;}
}

Java 类 User 实现了 Spring Security 中的 UserDetails 接口,这是因为 Spring Security 需要具体的用户信息来进行认证和授权。通过实现 UserDetails 接口,User 类可以与 Spring Security 框架集成,允许 Spring Security 使用该类的实例来获取用户的安全相关信息。

  • getAuthorities():返回授予用户的权限列表。在这个 User 类中,它遍历用户的角色列表 roles 并为每个角色创建一个 SimpleGrantedAuthority 对象,最终返回权限集合。
  • getPassword():返回用户的密码。在这个 User 类中,这个方法返回 User 对象的 password 字段。
  • getUsername():返回用户的用户名。在这个 User 类中,这个方法返回 User 对象的 `username` 字段。
  • isAccountNonExpired():检查用户的账户是否已过期。在这个 User 类中,这个方法硬编码返回 true,这意味着账户被认为永远不会过期,在数据库设计中没有该字段,所以默认返回 true。在实际的应用程序中,你可能需要添加一些逻辑来判断账户是否真的过期了。
  • isAccountNonLocked():检查用户是否未被锁定,返回 false 代表被锁定,true 没有被锁定。
  • isCredentialsNonExpired():检查用户证书(密码)是否未过期。在这个 User 类中,这个方法返回 true,表明证书永远不会过期。但在实际应用中,你可能会根据业务逻辑添加相应的实现代码。
  • isEnabled():检查用户是否被启用。在这个 User 类中,如果 status 字段的值为 1,代表用户状态正常,方法返回 true;否则返回 false。

Mapper 的编写如下:

package org.example.mapper;import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.example.entity.Role;
import org.example.entity.User;import java.util.List;@Mapper
public interface Usermapper {@Select("select * from r_roles as r join r_user_roles as ur on r.id = ur.user_id where ur.user_id = #{id}")List<Role> getUserRoleByUserId(Integer id);@Select("select * from r_users where username = #{username}")User getUserByUsername(String username);
}

UserService 如下:

package org.example.service;import org.example.entity.User;
import org.example.mapper.Usermapper;
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;@Service
public class UserService implements UserDetailsService {@Autowiredprivate Usermapper usermapper;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {User user = usermapper.getUserByUsername(username);if (user == null){throw new UsernameNotFoundException("该账户不存在");}//根据 user id 获取用户的角色信息user.setRoles(usermapper.getUserRoleByUserId(user.getId()));return user;}
}

UserService 类实现了 Spring Security 中的 UserDetailsService 接口,这个接口主要用于在认证过程中通过用户名查找用户及其权限。在 loadUserByUsername 方法中,你使用了 Usermapper 来获取具体的 User 对象以及相关的角色信息。 

为了测试方便编写 controller:

package org.example.controller;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class UserController {@GetMapping("/dba/hi")public String dba(){return "Hi,dba page";}@GetMapping("/user/hi")public String user(){return "Hi,user";}@GetMapping("/admin/hi")public String admin(){return "Hi,admin";}@GetMapping("/test/Hi")public String testHi(){return "Hi,just for test";}
}

最后对Spring Security 进行配置编写,代码如下: 

package org.example.config;import org.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@AutowiredUserService userService;@AutowiredPasswordEncoder passwordEncoder;@BeanPasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userService).passwordEncoder(passwordEncoder);}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/bda/**").access("hasAnyAuthority('dba','admin','root')")//"hasAnyRole('dba','admin','root')")  会自动拼接头,Role_为头加上对应权限.antMatchers("/admin/**").access("hasAnyAuthority('root','admin')")//不会拼接头,直接认证。.and().formLogin().loginProcessingUrl("/login")/*.and().anonymous()//未登录才可以访问 permitAll 所有都可以访问*/.and().csrf().disable();http//访问被拒绝走以下.exceptionHandling().accessDeniedHandler(new AccessDeniedHandler() {@Overridepublic void handle(HttpServletRequest request,HttpServletResponse response,AccessDeniedException accessDeniedException)throws IOException, ServletException {// 自定义响应逻辑response.sendRedirect("/access-denied");}});//如果需要跨域使用这里,并配置spring WebMVCconfighttp.cors();}
}

成功 

7.多种角色权限认证 

有时候一个账号的权限可能是多个,如 freejava 即使 admin 又是 dba。那么在配置中可以增加显示权限包含关系的代码,可以在 Spring Secuirty 中配置代码如下: 

    @BeanRoleHierarchy roleHierarchy(){RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();String hierarchy = "ROLE_dba > ROLE_user ROLE_admin > ROLE_dba";roleHierarchy.setHierarchy(hierarchy);return roleHierarchy;}

该配置生效后,具有 ROLE_admin 的角色的用户可以访问所有资源,而 ROLE_dba 的角色用户可以访问自身权限的资源和 ROLE_user 的角色的用户资源。 

8.自定义权限认证 

如果我们不想使用默认提供的权限认证,或面对复杂的业务需要时,可能需要采取自定义认证方式实现权限认证。

自定义一个类

package org.example.expression;import org.example.entity.Role;
import org.example.entity.User;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;import java.util.ArrayList;
import java.util.List;@Component("ex")
public class U_Define_Expression {public boolean hasAutority(String authority){//获取当前用户的权限Authentication authentication = SecurityContextHolder.getContext().getAuthentication();User LoginUser = (User) authentication.getPrincipal();List<Role> roles = LoginUser.getRoles();List<String> permissions = new ArrayList<>();for(Role role :roles){permissions.add(role.getName());}//判断用户权限集合中是否存在 authorityreturn permissions.contains(authority);}
}

在需要使用的 controller 前加上 @PreAuthorize("@ex.hasAutority('dba')") 表示访问前的验证

补充 

HttpSecurity 是 Spring Security 的关键部分,用于配置 Web 安全性的详细内容。以下是在 Spring Security 中常用的 HttpSecurity 方法的概览:

  • authorizeRequests():开始请求级安全配置,允许你指定 URL 访问规则。

  • antMatchers(String... antPatterns):使用 Ant 风格的路径模式定义安全限制。

  • access(String):设置访问特定路径所需的权限表达式。

  • hasAuthority(String)hasAnyAuthority(String...):指定用户必须具有的权限以访问特定路径。

  • hasRole(String)hasAnyRole(String...):指定用户必须具有的角色才能访问特定路径。这通常自动添加 “ROLE_” 前缀。

  • formLogin():启用基于表单的身份验证。

  • loginProcessingUrl(String):定义处理登录请求的 URL。

  • permitAll():允许所有用户(即使未经认证)访问使用 antMatchers 定义的路径。

  • anonymous() 表示可以被未登录的用户(即匿名用户)访问。

  • anyRequest():应用于所有剩余的 URL。

  • authenticated():要求在处理给定的请求之前进行身份验证。

  • csrf():用于配置 CSRF(跨站请求伪造)保护。

  • disable():禁用 csrf 保护或其他配置。

  • exceptionHandling():配置异常处理。

  • accessDeniedHandler(AccessDeniedHandler):自定义处理访问被拒绝的情况的策略。

  • httpBasic():启用 HTTP 基本认证。

  • logout():配置注销功能。

  • logoutUrl(String):设置触发注销操作的 URL。

  • logoutSuccessUrl(String):注销成功后重定向的 URL。

  • and():用于连接配置,使其更易读。

  • cors():配置跨源资源共享(CORS)。

  • headers():配置各种 HTTP 头以增强安全性。

  • rememberMe():启用"记住我"的功能。

  • sessionManagement():配置会话管理。

  • maximumSessions(int):限制同一用户的并发会话数。

  • addFilter(Filter filter):添加过滤器在链中对应的还有 Before 和 After 方法。

除了上述方法,还有一些专门的配置器可以针对不同的模块来配置 HttpSecurity,如 OAuth2, SAML, LDAP 等。

这些 HttpSecurity 方法通常会以链式调用的方式被调用,并最终构成一个安全配置顺序,定义了整个应用的安全策略。这种方法的组合几乎可以支持所有标准的 Web 安全需求。


总结

Spring Security 是一个功能强大且灵活的框架,可帮助开发人员轻松实现应用程序的安全性需求。它提供了丰富的功能和配置选项,可以适应各种安全场景和要求。

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

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

相关文章

C语言——输出菱形

法一&#xff1a; #include<stdio.h> #define N 7 //假设输出7层菱形 int main(){int i;//i控制第几行 int j;//j控制每一行空格的循环个数 int k;//k控制每一行*的循环次数 for(i1;i<4;i){//将图形分为两部分,前四行(第一部分) for(j1;j<4-i;j){//输出第i行的…

echarts双折线图

引用 //反应时长 durationCharts categoryCommonChart(studyBehavior.durationCharts, durationCharts) function categoryCommonChart(odata, dom){var myChart echarts.init(document.getElementById(dom));let oarr []oarr odata.series.map(function(item){let color…

随笔-这都是命吗

我与鹏哥、小付有个小群&#xff0c;前几天&#xff0c;鹏哥在群里发了一个图&#xff0c;是他那个城市准备扶持的高新产业&#xff0c;有元宇宙、量子信息、生物制药、人工智能什么的。 先前的时候鹏哥给我说过&#xff0c;当地准备了六百多亩地&#xff0c;准备发展高新产业…

Linux-进程之间的通信

目录 ​编辑 一.什么是进程之间的通信 二.进程之间的通信所访问的数据 三.进程之间的通信是如何做到的 四.基于内存文件级别的通信方式——管道 1.什么是管道 2.管道的建立过程——匿名管道 a.什么是匿名管道 b.匿名管道特点&#xff1a; c.使用匿名管道的…

风格迁移网络修改流程(自用版)

一. AdaAttN-Revisit Attention Mechanism in Arbitrary Neural Style Transfer&#xff08;ICCV2021&#xff09; 下载vgg_normalised.pth打开visdom python -m visdom.server在 train_adaattn.sh 中配置 content_path、style_path 和 image_encoder_path&#xff0c;分别表…

固态硬盘速度测试:硬盘实际性能是否符合标准?

在进行固态硬盘速度测试之前我们先来了解一下固态硬盘的读写速度是什么。固态硬盘的读写速度主要分为顺序读写和随机读写&#xff08;4K&#xff09;。 ​顺序读写&#xff1a;指的是硬盘在读写连贯、集中大文件时候的速度。比如在读取、拷贝单个视频文件时&#xff0c;就是硬盘…

【项目问题解决】IDEA2020.3 使用 lombok 插件 java: 找不到符号 符号: 方法 builder()

目录 lombok找不到符号问题修改 1.问题描述2.问题原因3.解决思路4.解决方案5.总结6.参考 文章所属专区 项目问题解决 1.问题描述 IDEA2020.3 使用 lombok 插件 java: 找不到符号 符号: 方法 builder()&#xff0c;无法使用lombok下应有的注解&#xff0c;一度怀疑是版本问题 …

使用Inno Setup 打包程序文件 怎么把其中一个文件安装时复制到指定系统文件夹

环境: Inno Setup 6.6 Win10 专业版 问题描述: 使用Inno Setup 打包程序文件 怎么把其中一个文件安装时复制到指定系统文件夹 将文件api-ms-win-shcore-scaling-l1-1-1.dll复制到system32里面 解决方案: 1.由于安全和权限的限制,直接在Inno Setup脚本中复制文件到C:\…

C++新经典模板与泛型编程:用成员函数重载实现std::is_class

用成员函数重载实现is_class std::is_class功能&#xff0c;是一个C11标准中用于判断某个类型是否为一个类类型&#xff08;但不是联合类型&#xff09;的类模板。当时在讲解的时候并没有涉及std::is_class的实现代码&#xff0c;在这里实现一下。简单地书写一个IsClass类模板…

python pydoc生成API文档

pydoc是python内置的一个文档生成模块。 pydoc 模块会根据 Python 模块来自动生成文档。 生成的文档可在控制台中显示为文本页面&#xff0c;提供给 Web 浏览器访问或者保存为 HTML 文件。 对于模块、类、函数和方法&#xff0c;显示的文档内容取自文档字符串&#xff08;即 _…

泰凌微(Telink)8258配置串口收发自定义数据

在官网下载SDK后&#xff08;以Mesh SDK为例&#xff09;使用Eclipse打开&#xff0c;对应MCU的配置文件在app_config_8258.h&#xff0c;默认的HCI接口是HCI_USE_NONE&#xff0c;如果改成HCI_USE_UART后可以通过串口收发数据&#xff0c;此时默认接收函数处理的是以Telink的协…

音视频学习(二十)——rtsp收流(udp方式)

前言 本文主要介绍通过udp方式实现rtsp拉流。 流程图 流程说明&#xff1a; 相较于tcp方式“信令数据”复用同一连接拉流&#xff0c;udp方式拉流“信令数据”采用不同的连接&#xff0c;信令传输采用tcp&#xff0c;流数据传输采用udp&#xff1b;客户端向服务端&#xff0…

数据库增删改查(CRUD)进阶版

目录 数据库约束 约束类型 表的设计 1.一对一 2.一对多 3.多对多 增删查改进阶操作 1. 插入查询结果 2.查询 聚合查询 聚合函数 group by having 联合查询 内连接 外连接 自连接 子查询 合并查询 数据库约束 创建表的时候制定的一些规则&#xff0c;在后续…

智能优化算法应用:基于北方苍鹰算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于北方苍鹰算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于北方苍鹰算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.北方苍鹰算法4.实验参数设定5.算法结果6.参考…

生成式人工智能笔记-AIGC笔记

生成式人工智能笔记-AIGC笔记 十多年前&#xff0c;人工智能还只是一个不被人看好的小众领域&#xff0c;但是现在&#xff0c;它却已经成了街头巷尾的热点谈资&#xff0c;几乎任何事情都可以和人工智能联系在一起。 人工智能包括基础层、技术层和应用层。 基础层是人工智能…

收藏!当今最流行的10 种人工智能算法

人工智能的概念始于1956年的达特茅斯会议&#xff0c;由于受到数据、计算力、智能算法等多方面因素的影响&#xff0c;人工智能技术和应用发展经历了多次高潮和低谷。 2022年以来&#xff0c;以ChatGPT为代表的大模型一夜爆火&#xff0c;它能够基于在预训练阶段所见的模式和统…

Python中如何判断List中是否包含某个元素

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 在Python中&#xff0c;判断一个列表&#xff08;List&#xff09;是否包含某个特定元素是常见的任务之一。在本文中&#xff0c;将深入探讨多种判断List成员包含性的方法&#xff0c;并提供丰富的示例代码&…

每日一题:LeetCode-11.盛水最多的容器

每日一题系列&#xff08;day 13&#xff09; 前言&#xff1a; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f50e…

solidity案例详解(六)服务评价合约

有服务提供商和用户两类实体&#xff0c;其中服务提供商部署合约&#xff0c;默认诚信为true&#xff0c;用户负责使用智能合约接受服务及评价&#xff0c;服务提供商的评价信息存储在一个映射中&#xff0c;可以根据服务提 供商的地址来查找评价信息。用户评价信息&#xff0c…

添加新公司代码的配置步骤-Part1

原文地址&#xff1a;配置公司代码 概述 我们生活在一个充满活力的时代&#xff0c;公司经常买卖子公司。对于已经使用 SAP 的公司来说&#xff0c;增加收购就成为一个项目。我开发了一个电子表格&#xff0c;其中包含向您的结构添加新公司代码所需的所有配置更改。当然&…