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(入门案例) (1)新建project (2)选择依赖 (3)编写一个 HelloController (4)启动项目,访问localhost:8080…...

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

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

【李老师云计算】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 讲师:尚硅谷-宋红康(江湖人称:康师傅) 官网:http://www.atguigu.com 本章专题与脉络 1. 字符串相关类之不可变字符序列:String 1.1 String的特性 java.lang.String 类代表字符串…...

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

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

C++类的理解与类型名,类的成员,两种定义方式,类的访问限定符,成员访问,作用域与实例化对象
面向过程和面向对象初步认识 C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题 C是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成 面向…...

【华为OD机试真题 C++】1051 - 处理器问题 | 机试题+算法思路+考点+代码解析
文章目录 一、题目🔸题目描述🔸输入输出🔸样例1🔸样例2 二、题目解析三、代码参考 作者:KJ.JK 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 &…...

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

Git使用教程
Git 目标 Git简介【了解】 使用Git管理文件版本【重点】 远程仓库使用【掌握】 分支管理【重点】 远程仓库【掌握】 一、Git简介 1、版本控制系统简介 1.1、版本控制前生今世 版本控制系统Version Control Systems,简称 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
代码地址:https://github.com/ xiangwang1223/disentangled_graph_collaborative_filtering Background: 现有模型在很大程度上以统一的方式对用户-物品关系进行建模(将模型看做黑盒,历史交互作为输入,Embedding作为输出。)&…...

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

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

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

九龙证券|光模块概念股封单资金超3亿元,传媒板块涨停潮来袭
今天A股三大股指低开低走。沪深两市收盘共37股涨停。剔除4只ST股,合计33股涨停。另外,10股封板未遂,整体封板率为78.72%。 涨停战场: 华工科技封单资金超3亿元 从收盘涨停板封单量来看,同方股份封单量最高࿰…...

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

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

Python 人工智能:16~20
原文:Artificial Intelligence with Python 协议:CC BY-NC-SA 4.0 译者:飞龙 本文来自【ApacheCN 深度学习 译文集】,采用译后编辑(MTPE)流程来尽可能提升效率。 不要担心自己的形象,只关心如何…...

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

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

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文件,访问以下地址: http://localhost:8080/webappName/index.jsp 实际上访问这个index.jsp文件,底层执行的是: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.前言 在网上各种教程和介绍中,搭建网页都会借助各种软件的帮助,比如…...

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

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

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

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