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

Spring Security实战(一)——基于内存和数据库模型的认证与授权

目录

简介

一、初识Spring Security(入门案例)

(1)新建project

(2)选择依赖

(3)编写一个 HelloController

(4)启动项目,访问localhost:8080

(5)自定义用户名和密码

 二、表单认证

1. 自定义表单登录页

2. 配置spring security

3. 重启项目

​编辑

三、认证与授权

1. 资源准备

(1)新建两个controller

(2)资源授权的配置

(3)重启服务访问

 2. 基于内存的多用户支持

(1)在内存中配置用户

 (2)访问测试

  3. 基于默认数据库模型的认证与授权

(1)创建数据库表

(2)引入jdbc依赖,配置数据库

(3)配置spring securiy授权

 4. 基于自定义数据库模型的认证与授权

(1)数据库准备

 (2)编写实体类User

(3)编写自定义的UserDetailsServiceImpl

(4)编写Mapper

(5)spring security 配置

(6)测试


简介

​ 一般Web应用的需要进行认证授权

​ 认证:验证当前访问系统的是不是本系统的用户,并且要确认具体是哪个用户

​ 授权:经过认证后判断当前用户是否有权限进行某个操作

​ 而认证和授权也是SpringSecurity作为安全框架的核心功能。

(1)前后端分离项目登录校验流程:

 (2)Spring Security 完整流程

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

一、初识Spring Security(入门案例)

(1)新建project

(2)选择依赖

(3)编写一个 HelloController

@RestController
@RequestMapping("/")
public class HelloController {@GetMapping("/hello")public String hello() {return "hello spring security!";}
}

(4)启动项目,访问localhost:8080

即使没有任何配置,在引入Spring Security后,要访问对应的 URL 资源需要经过HTTP基本认证

启动后,控制台会打印一个初始密码,如图:

 访问localhost:8080,填写登录信息(这就是HTTP基本认证),填写用户名 user

(5)自定义用户名和密码

在配置文件 application.yml 中配置用户名和密码,重启项目之后使用该用户名和密码即可登录。

spring:security:user:name: zypassword: abc

入门案例总结:

 

Authentication接口: 它的实现类,表示当前访问系统的用户,封装了用户相关信息。

AuthenticationManager接口:定义了认证Authentication的方法

UserDetailsService接口:加载用户特定数据的核心接口。里面定义了一个根据用户名查询用户信息的方法。

UserDetails接口:提供核心用户信息。通过UserDetailsService根据用户名获取处理的用户信息要封装成UserDetails对象返回。然后将这些信息封装到Authentication对象中。

步骤:

(1)提交用户名和密码之后,会将用户名和密码传给UsernamePasswordAuthenticationFilter

        UsernamePasswordAuthenticationFilter是Spring Security中一个非常重要的过滤器,它负责处理基于表单的身份验证,即当用户提交包含用户名和密码的表单时,该过滤器会从该请求中提取用户名和密码并进行身份验证。 

(2)UsernamePasswordAuthenticationFilter调用authenticate() 方法进行认证

        执行该方法时,它会获取请求中的用户名和密码参数,然后调用 AuthenticationManager 对象的 authenticate() 方法来进行身份验证。如果身份验证成功,则创建一个 Authentication 对象并将其传递给 SecurityContextHolder 中。如果身份验证失败,则会抛出 AuthenticationException。

 (3)AuthenticationManager 会继续调用DaoAuthenticationProvider的authenticate() 进行验证

        DaoAuthenticationProvider是一个AuthenticationProvider的实现类,用于处理用户名和密码验证的过程。当AuthenticationManager调用authenticate()方法时,实际上是委托给了DaoAuthenticationProvider来处理认证请求。

(4)DaoAuthenticationProvider也会调用 loadUserByUsername() 方法查询用户

        在DaoAuthenticationProvider的authenticate()方法中,会先调用UserDetailsService的loadUserByUsername()方法获取用户信息,(这里根据实际情况可能去内存中查找,也可以去数据库查找)然后再将获取到的用户信息与用户输入的密码进行比较,最终确定用户是否通过认证。因此,在认证流程中,loadUserByUsername()方法是一个非常重要的环节。

(5)返回 UserDetail对象

        loadUserByUsername() 方法主要是根据给定的用户名查询用户信息,并返回一个 UserDetails 对象。该方法的具体实现可能会涉及到访问数据库或其他存储设备,以获取用户的详细信息。在 Spring Security 中,这个方法通常由 UserDetailsService 的实现类来完成。在实现类中,通常会根据用户名查询用户信息,并将其封装为一个 UserDetails 对象,以便后续的身份验证过程中使用。UserDetails 对象包含用户的身份信息、授权信息和其他详细信息,如密码和是否启用等。

(6)通过PasswordEncoder对象对比UserDetail的密码和提交的密码是否一致

        通过PasswordEncoder对象将用户输入的密码加密,然后与UserDetails中存储的加密后的密码进行比较,来验证用户的身份。如果两者一致,则认为用户身份验证通过。PasswordEncoder主要用于将密码进行加密,以提高安全性。

(7)如果正确就把UserDetails中的权限信息设置到Authentication对象中

(8)返回Authentication对象

(9)将认证成功的 Authentication 对象存储在 SecurityContextHolder

        SecurityContextHolder 会使用 ThreadLocal 来存储认证对象,以确保每个线程都有自己的 SecurityContext 实例。在接下来的请求中,其他过滤器可以使用 SecurityContextHolder.getContext().getAuthentication() 方法获取该认证对象。


 二、表单认证

1. 自定义表单登录页

login.html,放在static下

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>Login Page</title><style>/* 样式可以自行修改 */body {background-color: cadetblue;}.login-form {width: 350px;margin: 150px auto;background-color: #fff;padding: 20px;box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);}h1 {font-size: 24px;text-align: center;margin-bottom: 30px;}input[type="text"], input[type="password"] {width: 100%;padding: 10px;margin-bottom: 20px;border: 2px solid #ccc;border-radius: 4px;box-sizing: border-box;}button {background-color: darksalmon;color: white;padding: 12px 20px;border: none;border-radius: 4px;cursor: pointer;width: 100%;}button:hover {background-color: #45a049;}</style>
</head>
<body>
<div class="login-form"><h1>Login Page</h1><form th:action="@{/login}" method="post"><label for="username">Username</label><input type="text" id="username" name="username" placeholder="Enter username"><label for="password">Password</label><input type="password" id="password" name="password" placeholder="Enter password"><button type="submit">Login</button></form>
</div>
</body>
</html>

2. 配置spring security

重写 configure方法,接收一个 HttpSecurity 对象,HttpSecurity提供了而很多配置相关的方法:

(1)authorizeRequests() 是 Spring Security 中的一个配置方法,用于定义哪些请求需要被授权才能被访问。该方法返回一个 ExpressionInterceptUrlRegistry 对象,用于配置针对 URL 的访问授权。

通过这个方法,我们可以使用各种方法来进行 URL 的授权配置,例如:

  • antMatchers() 方法用于匹配 URL,并设置需要的访问权限。
  • hasRole()hasAuthority() 方法用于指定需要的角色或权限。
  • permitAll() 方法用于指定不需要任何访问权限即可访问。

(2)formLogin()

formLogin() 是 Spring Security 中的一个配置方法,用于指定使用表单登录进行身份验证。在默认情况下,如果没有进行任何身份验证,Spring Security 会自动重定向到默认的登录页面。

通过这个方法,我们可以进行如下配置:

  • loginPage() 方法用于指定登录页面的 URL。
  • loginProcessingUrl() 方法用于指定处理登录请求的 URL。
  • usernameParameter()passwordParameter() 方法用于指定表单中用户名和密码的参数名称。
  • successHandler()failureHandler() 方法用于指定登录成功和失败后的处理逻辑。
  • permitAll() 方法用于指定登录页面的访问权限。

(3)csrf() 是 Spring Security 中的一个配置方法,用于配置跨站请求伪造(Cross-Site Request Forgery,CSRF)防护功能。CSRF 攻击是一种恶意攻击方式,攻击者通过某些方式获取到用户的授权信息,然后利用这些信息发送恶意请求,从而实现攻击目的。

在 Spring Security 中,CSRF 防护功能默认是开启的,如果想要关闭它,可以使用 csrf().disable() 方法进行禁用。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated().and().formLogin().loginPage("/login.html").permitAll().and().csrf().disable();}
}

3. 重启项目

访问 localhost:8080/hello,会跳转到:http://localhost:8080/login.html

三、认证与授权

1. 资源准备

(1)新建两个controller

一个是只有管理员才能访问的,一个是普通用户访问的。

@RestController
@RequestMapping("/admin/api")
public class AdminController {@GetMapping("/hello")public String helloAdmin() {return "hello Admin!";}
}
@RestController
@RequestMapping("/user/api")
public class UserController {@GetMapping("/hello")public String helloAdmin() {return "hello User!";}
}

(2)资源授权的配置

请求 /admin/api/** 下的资源,需要检查是否有 ADMIN 角色

请求 /user/api/** 下的资源,需要检查是否有 USER角色

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/admin/api/**").hasRole("ADMIN").antMatchers("/user/api/**").hasRole("USER").anyRequest().authenticated().and().formLogin().loginPage("/login.html").permitAll().and().csrf().disable();}
}

(3)重启服务访问

可以看到,访问 http://localhost:8080/hello 可以成功,访问http://localhost:8080/admin/api/hello会被拒绝访问(403错误码)

 2. 基于内存的多用户支持

(1)在内存中配置用户

        下面配置中的两个 configure(HttpSecurity http) configure(AuthenticationManagerBuilder auth)方法是 WebSecurityConfigurerAdapter 中的两个关键方法,它们用于配置Spring Security 的身份验证和授权。

  configure(HttpSecurity http)方法用于配置请求的授权规则,即哪些请求需要什么权限才能访问。

  configure(AuthenticationManagerBuilder auth)方法用于配置身份验证的方式,即如何验证用户身份。在这个示例中,我们使用了内存身份验证,通过调用.inMemoryAuthentication()方法,然后使用.withUser()方法来指定用户名和密码,使用{noop}前缀来表示密码不进行加密,最后使用.roles()方法来指定用户的角色。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/admin/api/**").hasRole("ADMIN").antMatchers("/user/api/**").hasRole("USER").anyRequest().authenticated().and().formLogin().loginPage("/login.html").permitAll().and().csrf().disable();}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.inMemoryAuthentication().withUser("admin").password("{noop}abcd").roles("ADMIN").and().withUser("zy").password("{noop}abc").roles("USER");}
}

 (2)访问测试

使用用户名 admin 密码 abcd ,来登录,可以显示下面内容:

  3. 基于默认数据库模型的认证与授权

(1)创建数据库表

在数据库创建了两个用户,分别是:

user 对应的角色是 ROLE_USER;

admin 对应的角色是ROLE_ADMIN。

CREATE TABLE users (username VARCHAR(50) NOT NULL PRIMARY KEY,password VARCHAR(100) NOT NULL,enabled BOOLEAN NOT NULL
);CREATE TABLE authorities (username VARCHAR(50) NOT NULL,authority VARCHAR(50) NOT NULL,FOREIGN KEY (username) REFERENCES users(username)
);INSERT INTO users (username, password, enabled) VALUES ('user', '12345', true);
INSERT INTO users (username, password, enabled) VALUES ('admin', '12345', true);INSERT INTO authorities (username, authority) VALUES ('user', 'ROLE_USER');
INSERT INTO authorities (username, authority) VALUES ('admin', 'ROLE_ADMIN');

(2)引入jdbc依赖,配置数据库

引入jdbc和MySQL依赖

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.26</version></dependency>

 配置数据库连接:

spring:datasource:url: jdbc:mysql://localhost:3306/security-db?useSSL=falseusername: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driver

(3)配置spring securiy授权

        这里使用了 jdbcAuthentication() 方法来启用基于 JDBC 的用户存储,并通过 dataSource() 方法设置数据源,即连接到数据库的 DataSource。

        接着,使用了 usersByUsernameQuery() 方法设置查询用户名、密码和启用状态的 SQL 语句,该语句会在用户登录时被执行,根据输入的用户名查询数据库中的用户信息,并将查询到的密码和启用状态用于认证。authoritiesByUsernameQuery() 方法用于设置查询用户角色的 SQL 语句。 最后,使用了 passwordEncoder() 方法设置密码加密方式,这里使用了 NoOpPasswordEncoder.getInstance() 方法来禁用密码加密,即直接将从数据库中查询到的密码作为明文进行比对。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Resourceprivate DataSource dataSource;@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/admin/api/**").hasRole("ADMIN").antMatchers("/user/api/**").hasRole("USER").anyRequest().authenticated().and().formLogin().loginPage("/login.html").permitAll().and().csrf().disable();}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.jdbcAuthentication().dataSource(dataSource).usersByUsernameQuery("SELECT username, password, enabled FROM users WHERE username = ?").authoritiesByUsernameQuery("SELECT username, authority FROM authorities WHERE username = ?").passwordEncoder(NoOpPasswordEncoder.getInstance());}
}

 4. 基于自定义数据库模型的认证与授权

上面我们使用了InMemoryUserDetailsManager和JdbcUserDetailsManager两个UserDetailsService实现类。下面我们使用自定义的数据库模型,并且使用自定义的UserDetails实现类。

(1)数据库准备

CREATE TABLE my_users (id INT(11) NOT NULL AUTO_INCREMENT,username VARCHAR(50) NOT NULL,password VARCHAR(100) NOT NULL,enabled TINYINT(1) NOT NULL DEFAULT '1',roles VARCHAR(200) NOT NULL,PRIMARY KEY (id),UNIQUE KEY username_UNIQUE (username)
);

插入两条数据:

 (2)编写实体类User

        这个实体类 User 与之前的表 my_users 是一一对应的,每个属性都对应着表中的一个字段:

  • id 对应着表中的 id 字段,用于唯一标识每个用户
  • username 对应着表中的 username 字段,表示用户的登录名
  • password 对应着表中的 password 字段,表示用户的密码
  • enabled 对应着表中的 enabled 字段,表示用户是否启用
  • roles 对应着表中的 roles 字段,表示用户所拥有的角色

        需要注意的是,这个 User 实体类中还有一个 authorities 属性,这个属性是用于保存用户的权限信息的,它不对应着表中的任何一个字段。这个属性在 UserDetailsServiceImpl 类的 loadUserByUsername 方法中会被设置为用户的权限信息,用于进行认证和授权。为了实现这个功能,User 类中还定义了一个 getAuthorities 方法,用于将 roles 字段解析成一个 List<GrantedAuthority> 类型的集合,并且在需要的时候进行懒加载。

@Data
public class User implements UserDetails {private Long id;private String username;private String password;private boolean enabled;private String roles;private List<GrantedAuthority> authorities;@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return true;}@Overridepublic boolean isCredentialsNonExpired() {return true;}//用于将 roles 字段解析成 List<GrantedAuthority> 类型的集合public List<GrantedAuthority> getAuthorities() {if (authorities == null) {authorities = new ArrayList<>();for (String role : roles.split(",")) {authorities.add(new SimpleGrantedAuthority(role.trim()));}}return authorities;}
}

(3)编写自定义的UserDetailsServiceImpl

        这个 UserDetailsServiceImpl 类实现了 UserDetailsService 接口,是用于加载用户信息的服务类。在 loadUserByUsername 方法中,通过 UserMapper 从数据库中查询到对应的 User 对象,然后构建出该用户对应的 GrantedAuthority 列表,最终将该 User 对象返回。

@Service
public class UserDetailsServiceImpl implements UserDetailsService {@Autowiredprivate UserMapper userMapper;@Overridepublic User loadUserByUsername(String username) throws UsernameNotFoundException {// 从数据库中查询用户信息User user = userMapper.findByUsername(username);if (user == null) {throw new UsernameNotFoundException("用户不存在");}// 构建用户权限信息List<GrantedAuthority> authorities = user.getAuthorities();user.setAuthorities(authorities);return user;}
}

(4)编写Mapper

@Mapper
public interface UserMapper {@Select("SELECT * FROM my_users WHERE username = #{username}")User findByUsername(@Param("username") String username);
}

(5)spring security 配置

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Resourceprivate DataSource dataSource;@Autowiredprivate UserDetailsServiceImpl userDetailsService;@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/admin/api/**").hasRole("ADMIN").antMatchers("/user/api/**").hasRole("USER").anyRequest().authenticated().and().formLogin().loginPage("/login.html").permitAll().and().csrf().disable();}
//使用自定义的数据库模型进行认证和授权@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(NoOpPasswordEncoder.getInstance());}}

(6)测试

打断点调试,可以看到在使用admin用户登录的时候可以获取到两个角色。

 

相关文章:

Spring Security实战(一)——基于内存和数据库模型的认证与授权

目录 简介 一、初识Spring Security&#xff08;入门案例&#xff09; &#xff08;1&#xff09;新建project &#xff08;2&#xff09;选择依赖 &#xff08;3&#xff09;编写一个 HelloController &#xff08;4&#xff09;启动项目&#xff0c;访问localhost:8080…...

轻松掌握FFmpeg编程:从架构到实践

轻松掌握FFmpeg编程&#xff1a;从架构到实践 (Master FFmpeg Programming with Ease: From Architecture to Practice 引言 (Introduction)FFmpeg简介与应用场景 (Brief Introduction and Application Scenarios of FFmpeg)为什么选择FFmpeg进行音视频处理 (Why Choose FFmpeg…...

桌面应用程序开发攻略(初步了解)

什么是桌面应用程序&#xff1f; 桌面应用开发是指为桌面计算机或其他类似设备&#xff08;如服务器&#xff09;开发软件应用程序的过程。桌面应用通常是独立于浏览器运行的&#xff0c;并且可以在操作系统的桌面或应用程序菜单中找到。桌面应用可以使用各种编程语言开发&…...

【李老师云计算】HBase+Zookeeper部署及Maven访问(HBase集群实验)

索引 前言1. Zookeeper1.1 主机下载Zookeeper安装包1.2 主机解压Zookeeper1.3 ★解决解压后文件缺失1.4 主机配置Zookeeper文件1.4.1 配置zoo_sample.cfg文件1.4.2 配置/data/myid文件 1.5 主机传输Zookeeper文件到从机1.6 从机修改Zookeeper文件1.6.1 修改zoo.cfg文件1.6.2 修…...

第11章_常用类和基础API

第11章_常用类和基础API 讲师&#xff1a;尚硅谷-宋红康&#xff08;江湖人称&#xff1a;康师傅&#xff09; 官网&#xff1a;http://www.atguigu.com 本章专题与脉络 1. 字符串相关类之不可变字符序列&#xff1a;String 1.1 String的特性 java.lang.String 类代表字符串…...

Java语言数据类型与c语言数据类型的不同

目录 一、c语言数据类型 1.基本类型&#xff1a; 2.枚举类型&#xff1a; 3.空类型&#xff1a; 4.派生类型&#xff1a; 二、C语言编程需要注意的64位和32机器的区别 三、 不同之处 一、c语言数据类型 首先&#xff0c;先来整体介绍一下C语言的数据类型分类。 1.基…...

C# Replace()、Trim()、Split()、Substring()、IndexOf() 、 LastIndexOf()函数

目录 一、Replace() 二、Trim() 三、Split() 四、Substring() 五、IndexOf() 六、LastIndexOf() 一、Replace() 在C#中&#xff0c;Replace()是一个字符串方法&#xff0c;用于将指定的字符或子字符串替换为另一个字符或字符串。下面是一些Replace()方法的常见用法和示例…...

C++类的理解与类型名,类的成员,两种定义方式,类的访问限定符,成员访问,作用域与实例化对象

面向过程和面向对象初步认识 C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解问题的步骤&#xff0c;通过函数调用逐步解决问题 C是基于面向对象的&#xff0c;关注的是对象&#xff0c;将一件事情拆分成不同的对象&#xff0c;靠对象之间的交互完成 面向…...

【华为OD机试真题 C++】1051 - 处理器问题 | 机试题+算法思路+考点+代码解析

文章目录 一、题目&#x1f538;题目描述&#x1f538;输入输出&#x1f538;样例1&#x1f538;样例2 二、题目解析三、代码参考 作者&#xff1a;KJ.JK &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &…...

Linux 常用操作命令大全

一、基础知识 1.1 Linux系统的文件结构 /bin 二进制文件&#xff0c;系统常规命令 /boot 系统启动分区&#xff0c;系统启动时读取的文件 /dev 设备文件 /etc 大多数配置文件 /home 普通用户的家目录 /lib 32位函数库 /lib64 64位库 /media 手动临时挂载点 /mnt 手动临时挂载点…...

Git使用教程

Git 目标 Git简介【了解】 使用Git管理文件版本【重点】 远程仓库使用【掌握】 分支管理【重点】 远程仓库【掌握】 一、Git简介 1、版本控制系统简介 1.1、版本控制前生今世 版本控制系统Version Control Systems&#xff0c;简称 VCS是将『什么时候、谁、对什么文件…...

substrate中打印调试信息的多种方式详解

目录 1. 获取substrate-node-template代码2. 添加一个用于测试的pallet至依赖到pallets目录3. log方式来输出信息3.1 将log依赖添到cargo.toml文件3.2 log-test/src/lib.rs修改call方法 3.3 polkadot.js.调用测试函数do_something_log_test4. printable trait方式来输出信息4.1…...

Disentangled Graph Collaborative Filtering

代码地址&#xff1a;https://github.com/ xiangwang1223/disentangled_graph_collaborative_filtering Background&#xff1a; 现有模型在很大程度上以统一的方式对用户-物品关系进行建模(将模型看做黑盒&#xff0c;历史交互作为输入&#xff0c;Embedding作为输出。)&…...

Nginx快速上手

Nginx快速上手 OVERVIEW Nginx快速上手一、基本概念1.Nginx初步认识2.正向/反向代理&#xff08;1&#xff09;正向代理&#xff08;2&#xff09;反向代理 二、Nginx 安装和配置1.安装2.Nginx指令3.Nginx配置 三、Nginx的使用1.Web服务器&#xff08;1&#xff09;静态网页存储…...

【设计模式】实际场景解释策略模式与工厂模式的应用

文章目录 前言策略模式概念场景示例 工厂模式概念场景示例 策略模式与工厂模式的比较相同点不同点 总结 前言 策略模式和工厂模式是常见的设计模式&#xff0c;它们可以帮助我们更好地组织和管理代码&#xff0c;提高代码的可维护性和可扩展性。 在本篇博客中&#xff0c;我将…...

外包干了三年,算是废了...

先说一下自己的情况。大专生&#xff0c;19年通过校招进入湖南某软件公司&#xff0c;干了接近3年的测试&#xff0c;今年年上旬&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落&#xff01;而我已经在一个企业干了三年&#xff0c…...

九龙证券|光模块概念股封单资金超3亿元,传媒板块涨停潮来袭

今天A股三大股指低开低走。沪深两市收盘共37股涨停。剔除4只ST股&#xff0c;合计33股涨停。另外&#xff0c;10股封板未遂&#xff0c;整体封板率为78.72%。 涨停战场&#xff1a; 华工科技封单资金超3亿元 从收盘涨停板封单量来看&#xff0c;同方股份封单量最高&#xff0…...

[ES6] 数组

[ES6] 数组 数组的创建类数组对象可迭代对象的转换 扩展方法findfindIndexfillcopyWithinentrieskeysvaluesincludesflatflatMap 扩展运算符复制数组合并数组 数组缓冲区创建数组缓冲区视图创建 定型数组创建通过数组缓冲区生成通过构造函数 定型数组特性 拷贝浅拷贝深拷贝 数组…...

【问题描述】编写一个程序计算出球、圆柱和圆锥的表面积和体积。

【问题描述】 编写一个程序计算出球、圆柱和圆锥的表面积和体积。 要求&#xff1a; &#xff08;1&#xff09;定义一个基类&#xff0c;至少含有一个数据成员半径&#xff0c;并设为保护成员&#xff1b; &#xff08;2&#xff09;定义基类的派生类球、圆柱、圆锥&#…...

Python 人工智能:16~20

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

【华为OD机试真题】最优资源分配(javapython)

最优资源分配 知识点数组贪心Q时间限制:1s空间限制:32MB限定语言:不限 题目描述: 某块业务芯片最小容量单位为1.25G,总容量为M1.25G,对该芯片资源编号为1,2,…,M。该芯片支持3种不同的配置,分别为A、B、C。 配置A:占用容量为1.251=1.25G 配置B:占用容量为1.252=2…...

git的使用——操作流程

一、什么是git git是一个开源的分布式版本控制软件&#xff0c;能够有效并高效的处理很小到非常大的项目。 二、添加SSH公钥 安装下载后&#xff0c;会发现鼠标右击&#xff0c;会出现 Git Bash Here 这个选项&#xff0c;如图所示&#xff0c;点击进入 1.打开git窗口后&…...

Ae:自动定向

Ae 菜单&#xff1a;图层/变换/自动定向 Auto-Orient 快捷键&#xff1a;Ctrl Alt O 自动定向 Auto-Orient是 Ae 图层中的一个附加的、隐藏实现&#xff08;不会在时间轴面板上更改属性的值&#xff09;的功能&#xff0c;它可以使得图层自动旋转或改变方向以朝向指定的运动路…...

ClickHouse入门详解

ClickHouse基础部分详解 一、ClickHouse简介二、ClickHouse单机版安装2.1、ClickHouse安装前准备环境2.2、ClickHouse单机安装2.3、ClickHouse一些默认路径2.4、ClickHouse端口说明 三、ClickHouse数据类型四、ClickHouse的表引擎4.1 MergeTree4.1.1 partition by 分区 五、Cli…...

javaweb笔记2

JSP 1、在webapp的根目录下新建一个index.jsp文件,访问以下地址&#xff1a; http://localhost:8080/webappName/index.jsp 实际上访问这个index.jsp文件&#xff0c;底层执行的是&#xff1a;index_jsp.class这个程序。 这个index.jsp会被tomcat翻译成index_jsp.j…...

【IIS搭建网站】本地电脑做服务器搭建web站点并公网访问「内网穿透」

文章目录 1.前言2.Windows网页设置2.1 Windows IIS功能设置2.2 IIS网页访问测试 3. Cpolar内网穿透3.1 下载安装Cpolar3.2 Cpolar云端设置3.3 Cpolar本地设置 4.公网访问测试5.结语 1.前言 在网上各种教程和介绍中&#xff0c;搭建网页都会借助各种软件的帮助&#xff0c;比如…...

算法训练day2:哈希表

哈希表理论基础 哈希表是根据关键码的值而直接进行访问的数据结构。 当我们遇到了要快速判断一个元素是否出现集合里的时候&#xff0c;就要考虑哈希法。 但是哈希法也是牺牲了空间换取了时间&#xff0c;因为我们要使用额外的数组&#xff0c;set或者是map来存放数据&#…...

Git——利用SSH密钥本地仓库上传远程GitHub库

文章目录 1、前言2、详细步骤2.1 创建密钥2.2 进入密钥文件并复制2.3 在GitHub上添加密钥2.4 回到本地仓库文件夹&#xff0c;连接GitHub并上传 3. 结语 1、前言 现在想要从本地设备将本地仓库上传到GitHub上需要用到SSH密钥&#xff0c;接下来讲解大致的步骤&#xff0c;本文默…...

一起读源码 —— Fastjson 的核心方法及其实现原理

源码介绍 Fastjson 是阿里巴巴开源的一个 Java 工具库&#xff0c;它常常被用来完成 Java 的对象与 JSON 格式的字符串的相互转化。 此文读的源码是撰写此文时 Fastjson 的最新的发布版本&#xff0c;即 1.2.83 下载源码 请前去 github 找到 release 最新版下载后解压&…...

Python实现批量图片下载及去重处理

背景 在爬虫应用开发中&#xff0c;常常需要批量下载图片&#xff0c;并对图片进行去重处理。Python 是一种非常流行的编程语言&#xff0c;也是开发爬虫应用的首选&#xff0c;本文将介绍如何使用 Python 下载图片&#xff0c;并对下载的图片进行去重处理。 内容 首先&…...