SpringBoot学习(六)-SpringBoot整合Shiro

12、Shiro

12.1概述

12.1.1简介

Apache Shiro是一个强大且易用的Java安全框架

可以完成身份验证、授权、密码和会话管理

Shiro 不仅可以用在 JavaSE 环境中,也可以用在 JavaEE 环境

官网: http://shiro.apache.org/

12.1.2 功能

在这里插入图片描述

Authentication:身份认证/登录,验证用户是不是拥有相应的身份;

Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限;

Session Manager:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境的,也可以是如Web环境的;

Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;

Web Support:Web支持,可以非常容易的集成到Web环境;

Caching:**缓存,**比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率;

Concurrency:shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;

Testing:提供测试支持

Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;

Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了。

12.1.3从外部看

在这里插入图片描述

应用代码直接交互的对象是Subject,也就是说Shiro的对外API核心就是Subject;其每个API的含义:

Subject:主体,代表了当前“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如网络爬虫,机器人等;即一个抽象概念;所有Subject都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager;可以把Subject认为是一个门面;SecurityManager才是实际的执行者

SecurityManager安全管理器;即所有与安全有关的操作都会与SecurityManager交互;且它管理着所有Subject;可以看出它是Shiro的核心,它负责与后边介绍的其他组件进行交互,如果学习过SpringMVC,你可以把它看成DispatcherServlet前端控制器

Realm,Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源

也就是说对于我们而言,最简单的一个Shiro应用

应用代码通过Subject来进行认证和授权,而Subject又委托给SecurityManager;
我们需要给Shiro的SecurityManager注入Realm,从而让SecurityManager能得到合法的用户及其权限进行判断。
从以上也可以看出,Shiro不提供维护用户/权限,而是通过Realm让开发人员自己注入

12.1.4外部架构

在这里插入图片描述

Subject:主体,可以看到主体可以是任何可以与应用交互的“用户”;

SecurityManager:相当于SpringMVC中的DispatcherServlet或者Struts2中的FilterDispatcher;是Shiro的心脏所有具体的交互都通过SecurityManager进行控制;它管理着所有Subject、且负责进行认证和授权、及会话、缓存的管理

Authenticator认证器负责主体认证的,这是一个扩展点,如果用户觉得Shiro默认的不好,可以自定义实现;其需要认证策略(Authentication Strategy),即什么情况下算用户认证通过了;

Authrizer授权器,或者访问控制器,用来决定主体是否有权限进行相应的操作;即控制着用户能访问应用中的哪些功能;

Realm:可以有1个或多个Realm,可以认为是安全实体数据源,即用于获取安全实体的;可以是JDBC实现,也可以是LDAP实现,或者内存实现等等;由用户提供;注意:Shiro不知道你的用户/权限存储在哪及以何种格式存储;所以我们一般在应用中都需要实现自己的Realm

SessionManager:如果写过Servlet就应该知道Session的概念,Session呢需要有人去管理它的生命周期,这个组件就是SessionManager;而Shiro并不仅仅可以用在Web环境,也可以用在如普通的JavaSE环境、EJB等环境;所有呢,Shiro就抽象了一个自己的Session来管理主体与应用之间交互的数据;这样的话,比如我们在Web环境用,刚开始是一台Web服务器;接着又上了台EJB服务器;这时想把两台服务器的会话数据放到一个地方,这个时候就可以实现自己的分布式会话(如把数据放到Memcached服务器);

SessionDAO:DAO大家都用过,数据访问对象,用于会话的CRUD,比如我们想把Session保存到数据库,那么可以实现自己的SessionDAO,通过如JDBC写到数据库;比如想把Session放到Memcached中,可以实现自己的Memcached SessionDAO;另外SessionDAO中可以使用Cache进行缓存,以提高性能;

CacheManager缓存控制器,来管理如用户、角色、权限等的缓存的;因为这些数据基本上很少去改变,放到缓存中后可以提高访问的性能

Cryptography密码模块,Shiro提高了一些常见的加密组件用于如密码加密/解密

12.1.5认证流程

在这里插入图片描述

用户 提交 身份信息、凭证信息 封装成 令牌 交由 安全管理器 认证

12.2. 快速入门

将案例拷贝:

按照官网提示找到 快速入门案例

GitHub地址:shiro/samples/quickstart/

在这里插入图片描述

从GitHub 的文件中可以看出这个快速入门案例是一个 Maven 项目

1.新建一个 Maven 工程,删除其 src 目录,将其作为父工程

2.在父工程中新建一个 Maven 模块

3.复制快速入门案例 POM.xml 文件中的依赖 (版本号自选)

在这里插入图片描述

4.把快速入门案例中的 resource 下的log4j.properties 复制下来

在这里插入图片描述

在这里插入图片描述

log4j.rootLogger=INFO, stdoutlog4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n# General Apache libraries
log4j.logger.org.apache=WARN# Spring
log4j.logger.org.springframework=WARN# Default Shiro logging
log4j.logger.org.apache.shiro=INFO# Disable verbose logging
log4j.logger.org.apache.shiro.util.ThreadContext=WARN
log4j.logger.org.apache.shiro.cache.ehcache.EhCache=WARN

5、复制一下 shiro.ini 文件

在这里插入图片描述

[users]
# user 'root' with password 'secret' and the 'admin' role
root = secret, admin
# user 'guest' with the password 'guest' and the 'guest' role
guest = guest, guest
# user 'presidentskroob' with password '12345' ("That's the same combination on
# my luggage!!!" ;)), and role 'president'
presidentskroob = 12345, president
# user 'darkhelmet' with password 'ludicrousspeed' and roles 'darklord' and 'schwartz'
darkhelmet = ludicrousspeed, darklord, schwartz
# user 'lonestarr' with password 'vespa' and roles 'goodguy' and 'schwartz'
lonestarr = vespa, goodguy, schwartz# -----------------------------------------------------------------------------
# Roles with assigned permissions
#
# Each line conforms to the format defined in the
# org.apache.shiro.realm.text.TextConfigurationRealm#setRoleDefinitions JavaDoc
# -----------------------------------------------------------------------------
[roles]
# 'admin' role has all permissions, indicated by the wildcard '*'
admin = *
# The 'schwartz' role can do anything (*) with any lightsaber:
schwartz = lightsaber:*
# The 'goodguy' role is allowed to 'drive' (action) the winnebago (type) with
# license plate 'eagle5' (instance specific id)
goodguy = winnebago:drive:eagle5

6、安装插件ini

需要下载ini插件,如果在setting中无法下载,就去官网下载对应版本的然后导入

ini插件安装和配置

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

7、导入quickstart.java

在这里插入图片描述

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class Quickstart {private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class);public static void main(String[] args) {// The easiest way to create a Shiro SecurityManager with configured// realms, users, roles and permissions is to use the simple INI config.// We'll do that by using a factory that can ingest a .ini file and// return a SecurityManager instance:// Use the shiro.ini file at the root of the classpath// (file: and url: prefixes load from files and urls respectively):DefaultSecurityManager defaultSecurityManager=new DefaultSecurityManager();IniRealm iniRealm=new IniRealm("classpath:shiro.ini");defaultSecurityManager.setRealm(iniRealm);// for this simple example quickstart, make the SecurityManager// accessible as a JVM singleton.  Most applications wouldn't do this// and instead rely on their container configuration or web.xml for// webapps.  That is outside the scope of this simple quickstart, so// we'll just do the bare minimum so you can continue to get a feel// for things.SecurityUtils.setSecurityManager(defaultSecurityManager);// Now that a simple Shiro environment is set up, let's see what you can do:// get the currently executing user:Subject currentUser = SecurityUtils.getSubject();// Do some stuff with a Session (no need for a web or EJB container!!!)Session session = currentUser.getSession();session.setAttribute("someKey", "aValue");String value = (String) session.getAttribute("someKey");if (value.equals("aValue")) {log.info("Retrieved the correct value! [" + value + "]");}// let's login the current user so we can check against roles and permissions:if (!currentUser.isAuthenticated()) {UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");token.setRememberMe(true);try {currentUser.login(token);} catch (UnknownAccountException uae) {log.info("There is no user with username of " + token.getPrincipal());} catch (IncorrectCredentialsException ice) {log.info("Password for account " + token.getPrincipal() + " was incorrect!");} catch (LockedAccountException lae) {log.info("The account for username " + token.getPrincipal() + " is locked.  " +"Please contact your administrator to unlock it.");}// ... catch more exceptions here (maybe custom ones specific to your application?catch (AuthenticationException ae) {//unexpected condition?  error?}}//say who they are://print their identifying principal (in this case, a username):log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");//test a role:if (currentUser.hasRole("schwartz")) {log.info("May the Schwartz be with you!");} else {log.info("Hello, mere mortal.");}//test a typed permission (not instance-level)if (currentUser.isPermitted("lightsaber:wield")) {log.info("You may use a lightsaber ring.  Use it wisely.");} else {log.info("Sorry, lightsaber rings are for schwartz masters only.");}//a (very powerful) Instance Level permission:if (currentUser.isPermitted("winnebago:drive:eagle5")) {log.info("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'.  " +"Here are the keys - have fun!");} else {log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");}//all done - log out!currentUser.logout();System.exit(0);}
}

8、日志选择

shiro自带的日志:commons-logging

在这里插入图片描述

去掉test的运行时

在这里插入图片描述

正常日志输出

在这里插入图片描述

  • 最好还是使用log4j

12.2.2. shiro的分析案例

1.通过 SecurityUtils 获取当前执行的用户 Subject

Subject currentUser = SecurityUtils.getSubject();

在这里插入图片描述

2.通过 当前用户拿到 Session,shiro的session

Session session = currentUser.getSession();

3.用 Session 存值取值

session.setAttribute("someKey", "aValue");String value = (String) session.getAttribute("someKey");

在这里插入图片描述

测试:

在这里插入图片描述

4.判断用户是否被认证

currentUser.isAuthenticated()

5.执行登录操作

 currentUser.login(token);

在这里插入图片描述

6.打印其标识主体

currentUser.getPrincipal()

7.注销

currentUser.logout();

在这里插入图片描述

12.3.Springboot集成Shiro

1、SpringBoot整合Shiro环境搭建

下面是编写配置文件
Shiro 三大要素

subject -> ShiroFilterFactoryBean ----当前用户
securityManager -> DefaultWebSecurityManager ----管理所有用户
Realm
实际操作中对象创建的顺序 : realm -> securityManager -> subject ----连接数据

①引入thymeleaf模板引擎和SpringBoot-shiro的集成jar

在这里插入图片描述

<!--thymeleaf模板引擎-->
<dependency><groupId>org.thymeleaf</groupId><artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency><groupId>org.thymeleaf.extras</groupId><artifactId>thymeleaf-extras-java8time</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>

在这里插入图片描述

<!--SpringBoot 和 Shiro 整合包--><!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring-boot-web-starter --><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring-boot-web-starter</artifactId><version>1.6.0</version></dependency>

②自定义UserRealm类(1)

在这里插入图片描述

public class UserRealm extends AuthorizingRealm {//授权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {System.out.println("执行了授权方法");return null;}//认证@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {System.out.println("执行了认证方法");return null;}
}

②创建ShiroConfig配置三个元素

在这里插入图片描述

三个元素都需要作为spring的bean被spring托管

在这里插入图片描述

点击查看源码,发现securityManager是ShiroFilterFactoryBean的属性

在这里插入图片描述

按照1-3的顺序,设置构建Shiro的三要素

在这里插入图片描述

<1>根据前面提供的顺序,先编写realm类:

    //1:创建realm对象,需要自定义@Bean(name = "userRealm")public UserRealm userRealm(){return new UserRealm();}

<2>创建用户管理,这里需要用到前面创建的realm,因此在realm之后进行编写

    //2:创建管理用户需要用到@Beanpublic DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();securityManager.setRealm(userRealm);return securityManager;}

<3> 创建subject,需要传入一个securityManager,因此最后进行编写(是不是很像套娃)

    @Beanpublic ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager securityManager){ShiroFilterFactoryBean subject = new ShiroFilterFactoryBean();//设置安全管理器bean.setSecurityManager(securityManager);return subject;}

③首页、add、update页面和controller

thymeleaf的命名空间

xmlns:th="http://www.thymeleaf.org"

在这里插入图片描述

update页面

在这里插入图片描述

add页面

在这里插入图片描述

设置controller

在这里插入图片描述

测试:正常跳转访问页面

2、shiro实现登录拦截

①在ShiroFilterFactoryBean中添加shiro的内置过滤器

将拦截信息存放在map中

在这里插入图片描述

测试:
在这里插入图片描述

②无查看权限跳转到login页面

设置controller
在这里插入图片描述

login页面
在这里插入图片描述

设置登录的请求

在这里插入图片描述

测试:

在这里插入图片描述

3、Shiro实现登录认证

①在controller中封装前端数据生成一个令牌

在这里插入图片描述

    @RequestMapping("/login")public String login(@RequestParam("username") String username,@RequestParam("password") String password,Model model) {//获取当前的用户Subject subject = SecurityUtils.getSubject();//封装用户的登录数据UsernamePasswordToken token = new UsernamePasswordToken(username, password);try {subject.login(token);//执行登录的方法,如果没有异常return "index";} catch (UnknownAccountException e) {model.addAttribute("msg", "用户名错误");return "login";} catch (IncorrectCredentialsException e) {model.addAttribute("msg", "密码错误");return "login";}}

②login页面,提示信息

在这里插入图片描述

测试:会经过UserRealm的认证

在这里插入图片描述

③在UserRealm中设置认证

查看源码

在这里插入图片描述

取出令牌中封装的数据与数据库中的数据进行比对

在这里插入图片描述

使用复杂参数类型的方法进行密码认证

在这里插入图片描述

密码认证Shiro自己做和SpringSecurity中的一样

在这里插入图片描述

    @Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {System.out.println("执行了认证方法");String name="root";String password="123456";UsernamePasswordToken userToken = (UsernamePasswordToken)token;if(!userToken.getUsername().equals(name)){return null;}return new SimpleAuthenticationInfo("",password,"");}

测试:

在这里插入图片描述

不需要看上面图片的红字

4、Shiro整合Mybatis

1.首先导入需要的所有的maven依赖

①mysql-connect ②druid ③log4j ④Mybatis-spring-boot-starter

        <dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.2</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.28</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.8</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency>
2.编写配置文件application.properties或者application.yaml

在这里插入图片描述

在这里插入图片描述

# 应用名称
spring.application.name=springboot-shiro
# 应用服务 WEB 访问端口
server.port=8081
spring:datasource:username: rootpassword: "20000215"driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/mybatis?serverTimezone=GMT%2B8&useSSL=false&useUnicode=true&characterEncoding=UTF-8#Spring Boot 默认是不注入这些属性值的,需要自己绑定#druid 数据源专有配置initialSize: 5minIdle: 5maxActive: 20maxWait: 60000timeBetweenEvictionRunsMillis: 60000minEvictableIdleTimeMillis: 300000validationQuery: SELECT 1 FROM DUALtestWhileIdle: truetestOnBorrow: falsetestOnReturn: falsepoolPreparedStatements: true#配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入#如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority#则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4jfilters: stat,wall,log4jmaxPoolPreparedStatementPerConnectionSize: 20useGlobalDataSourceStat: trueconnectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
3、SpingMVC

①实体类

在这里插入图片描述

②Mapper接口

在这里插入图片描述

③Mapper接口对应的xml

在这里插入图片描述

④Service层

在这里插入图片描述

Service的实现类

在这里插入图片描述

4、获取数据库数据进行认证

①设置认证

在这里插入图片描述

②查看加密方式

在这里插入图片描述

MD5加密、MD5盐值加密

在这里插入图片描述

在这里插入图片描述

默认使用SimpleCredentialsMatcher简单加密

在这里插入图片描述

MD5加密继承Hash加密,Hash加密继承简单加密,所以可以MD5属于自定义加密方式

在这里插入图片描述

5、Shiro请求授权实现

①设置未经授权,跳转的页面

在这里插入图片描述

②设置授权的perms,有这个perms才可以跳转页面

在这里插入图片描述

设置未授权时,跳转的页面url

测试:

在这里插入图片描述

③设置授权

登陆就会出现认证,跳转页面需要授权

在这里插入图片描述

在这个授权设置里面,需要编写授权的条件,否则写死代码,就所有用户都有授权了,还需要结合从数据库中查出信息

④新增数据库字段,设置perms

在这里插入图片描述

实体类对应数据库字段

在这里插入图片描述

⑤修改授权

<1>想到了两个:①sessionprincipal:用户当前对象的属性来取get方法或(点属性)

我们在认证中,最后new了一个SimpleAuthenticationInfo的当前认证对象,之前里面要传递三个参数分别为:
(资源,密码,realmName)

需要解决:如何将 认证封装的对象(数据库中有这个用户情况下)传递授权 中,这里使用principal来保存

拿到的当前登录的对象,使用getprincipal()来获取通过认证的用户对象

<2>把获取到的user传入到资源中去。

return new SimpleAuthenticationInfo(user,user.getPwd(),"");

这样一来,user这个资源就传递到了当前用户subject整体资源中,通过当前subject获取资源来获取到这个user

<3>先获取subject当前用户

Subject subject = SecurityUtils.getSubject();

<4>然后通过subject获取到资源

User currentUser = (User) subject.getPrincipal();

<5>再给当前用户添加user中对应的权限名,注意方法名是addStringPermission权限

info.addStringPermission(currentUser.getPerms());

<6>最后返回当前权限info

在这里插入图片描述

注:根据数据库中查出来的具体的perms,设置当前用户的permission,当用户请求url通过过滤器的时候,这个当前用户的perms会和过滤器中规定的授权的perms比较,如果一样,就可以授权,如果不一样,就处于未授权状态

在这里插入图片描述

在这里插入图片描述

    //授权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {System.out.println("执行了授权方法");SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();Subject subject = SecurityUtils.getSubject();User currentUser = (User) subject.getPrincipal();//设置当前用户的权限info.addStringPermission(currentUser.getPerms());return info;}

退出功能就和之前security的logout一样,设置一下退出的路径就可

好现在基本需求都完了,但是想和之前security一样实现没有权限的就不要显示,就需要和thymeleaf结合

6、Shiro整合Thymeleaf

①首先要导入Shiro和thymeleaf结合的依赖

<!-- https://mvnrepository.com/artifact/com.github.theborakompanioni/thymeleaf-extras-shiro -->
<dependency><groupId>com.github.theborakompanioni</groupId><artifactId>thymeleaf-extras-shiro</artifactId><version>2.0.0</version>
</dependency>

②先整合shiro和thymeleaf

在这里插入图片描述

③设置命名空间,才可以使用专属标签

下面是spring-security的命名空间

xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5"

shiro的:

xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro"

在这里插入图片描述

前端代码:

<p th:text="${msg}"></p>
<hr>
<a><a th:href="@{/toLogin}">登录</a>
<div shiro:hasPermission="user:add"><a th:href="@{/user/add}">add</a>
</div><div shiro:hasPermission="user:update">
<a th:href="@{/user/update}">update</a>
</div>

④登录按钮,登录后不显示,未登录显示

<1>方式1(未实现):可以通过设置session中的用户对象,来判断。

如下面:

在这里插入图片描述

注:session对象是在浏览器中保存的,在dispatchservlet和controller之上的

<2>方式2(已实现):只要判断授不授权就可以控制显示

解释一下就是判断一下当前的用户是否有当前的权限如果有则显示没有不显示

登录按钮无权限时显示:

<div shiro:notAuthenticated><a th:href="@{/toLogin}">登录</a>
</div>

测试:

在这里插入图片描述

SpringBoot学习(六)-SpringBoot整合Shiro 开发的学习笔记到此完结,笔者归纳、创作不易,大佬们给个3连再起飞吧

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

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

相关文章

DFS-体积

DFS-体积 题目&#xff1a; 给出n件物品&#xff0c;每件物品有一个体积Vi&#xff0c;求从中取若干件物品能够组成不同的体积和有多少种可能。例如&#xff0c;n3&#xff0c;Vi(1,3,4),那么输出6,6种不同的体积分别为1,3,4,5,7,8 输入格式&#xff1a; 第一行一个正整数&…

一文讲透Python数据分析可视化之直方图(柱状图)

直方图&#xff08;Histogram&#xff09;又称柱状图&#xff0c;是一种统计报告图&#xff0c;由一系列高度不等的纵向条纹或线段表示数据分布的情况。一般用横轴表示数据类型&#xff0c;纵轴表示分布情况。通过绘制直方图可以较为直观地传递有关数据的变化信息&#xff0c;使…

关于“Python”的核心知识点整理大全65

目录 20.2.19 设置 SECRET_KEY 20.2.20 将项目从 Heroku 删除 注意 20.3 小结 附录 A 安装Python A.1.1 确定已安装的版本 A.1.2 在 Linux 系统中安装 Python 3 A.2 在 OS X 系统中安装 Python A.2.1 确定已安装的版本 A.2.2 使用 Homebrew 来安装 Python 3 注意 …

ejs默认配置 原型链污染

文章目录 ejs默认配置 造成原型链污染漏洞背景漏洞分析漏洞利用 例题 [SEETF 2023]Express JavaScript Security ejs默认配置 造成原型链污染 参考文章 漏洞背景 EJS维护者对原型链污染的问题有着很好的理解&#xff0c;并使用非常安全的函数清理他们创建的每个对象 利用Re…

高校选课系统需求分析开发源码

高校学生选课报名系统包括学生、教师和管理员三方的功能需求&#xff0c;学生的需求是查询院系的课程、选课情况及个人信息修改&#xff1b;教师则需要查看和查询所有课程信息及自己的课程信息以及教师信息的修改&#xff1b;管理员则负责更为复杂的任务&#xff0c;包括对学生…

opencv007 图像运算——加减乘除

今天学习图像处理的基础——加减乘除&#xff0c;总体来说比较好理解&#xff0c;不过生成的图片千奇百怪哈哈哈哈 opencv中图像的运算本质是矩阵的运算 加法 做加法之前要求两张图片形状&#xff0c;长宽&#xff0c;通道数完全一致 cv2.add(img1, img2) add的规则是两个图…

HTML 使用 ruby 给汉字加拼音

使用 ruby 给汉字加拼音 兼容性 使用 ruby 给汉字加拼音 大家有没有遇到过要给汉字头顶上加拼音的需求? 如果有的话, 你是怎么解决的呢? 如果费尽心思, 那么你可能走了很多弯路, 因为 HTML 原生就有这样的标签来帮我们实现类似的需求. <ruby> ruby 本身是「红宝石」…

leetcode 每日一题 2023年12月30日 一周中的第几天

题目 给你一个日期&#xff0c;请你设计一个算法来判断它是对应一周中的哪一天。 输入为三个整数&#xff1a;day、month 和 year&#xff0c;分别表示日、月、年。 您返回的结果必须是这几个值中的一个 {"Sunday", "Monday", "Tuesday", &qu…

transforms图像增强(二)

一、图像变换 1、transforms.Pad transforms.Pad是一个用于对图像边缘进行填充的数据转换操作。 参数&#xff1a; padding&#xff1a;设置填充大小。可以是单个整数&#xff0c;表示在上下左右四个方向上均填充相同数量的像素&#xff1b;也可以是一个包含两个整数的元组…

【Xilinx FPGA】异步 FIFO 的复位

FIFO&#xff08;First-In-First_Out&#xff0c;先入先出&#xff09;是一种的存储器类型&#xff0c;在 FPGA 开发中通常用于数据缓存、位宽转换或者跨时钟域&#xff08;多 bit 数据流&#xff09;。在使用异步 FIFO 时&#xff0c;应注意复位信号是否遵循相关要求和规范&am…

MySQL Mysqldump 一致性备份与大数据库备份 与 PG MYSQL 到底谁是NO.1

这开头还是介绍一下群&#xff0c;如果感兴趣PolarDB ,MongoDB ,MySQL ,PostgreSQL ,Redis, Oceanbase, Sql Server等有问题&#xff0c;有需求都可以加群群内&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;&#xff08;共1830人左右 1 2 3 4 5&#xf…

C/C++ 位段

目录 什么是位段&#xff1f; 位段的内存分配 位段的跨平台问题 什么是位段&#xff1f; 位段的声明与结构是类似的&#xff0c;但是有两个不同&#xff1a; 位段的成员必须是 int、unsigned int 或signed int 等整型家族。位段的成员名后边有一个冒号和一个数字 这是一个…

im6ull学习总结(三-3)freetype

1、Freetype简介 FreeType是一个开源的字体渲染引擎&#xff0c;主要用于将字体文件转换为位图或矢量图形&#xff0c;并在屏幕上渲染出高质量的字体。它提供了一组API&#xff0c;使开发者能够在自己的应用程序中使用和呈现字体。 FreeType最初是作为一个独立项目开发的&…

[Excel]如何找到非固定空白格數列的條件數據? 以月份報價表單為例

在群組中看到上述問題&#xff0c;研判應是一份隨月份變動的產品報價表單&#xff0c;空白欄可能表示該月份價格與上個月份一致。這個問題是需要取得最近一次單價和倒數第二次單價&#xff0c;常用且實務的excel案例值得紀錄。 最近一次單價: INDEX($B2:$G2,1,LARGE(IF(ISBLAN…

SpringSecurity集成JWT实现后端认证授权保姆级教程-环境搭建篇

&#x1f341; 作者&#xff1a;知识浅谈&#xff0c;CSDN签约讲师&#xff0c;CSDN博客专家&#xff0c;华为云云享专家&#xff0c;阿里云专家博主 &#x1f4cc; 擅长领域&#xff1a;全栈工程师、爬虫、ACM算法 &#x1f492; 公众号&#xff1a;知识浅谈 &#x1f525;网站…

跨平台开发教学:构建同时支持iOS和Android的教育网校APP

当下&#xff0c;教育行业也逐渐迎来了数字化转型的时代。构建一款支持iOS和Android的教育网校APP&#xff0c;不仅可以提供更好的用户体验&#xff0c;还能扩大应用的覆盖面&#xff0c;满足不同用户群体的需求。 一、选择合适的跨平台开发框架 在开始构建教育网校APP之前&a…

MidTool图文创作-GPT-4与DALL·E 3的结合

GPT-4与DALLE 3的结合 GPT-4是由OpenAI开发的最新一代语言预测模型&#xff0c;它在前代模型的基础上进行了大幅度的改进&#xff0c;不仅在文本生成的连贯性、准确性上有了显著提升&#xff0c;还在理解复杂语境和执行多步骤指令方面表现出了更高的能力。而DALLE 3则是一个创…

构建异地企业网络互联的高效路径

在当今数字化浪潮中&#xff0c;企业的业务拓展已不再受限于地理位置。为了在全球竞争中立于不败之地&#xff0c;越来越多的企业选择在不同城市设立分支机构&#xff0c;构建异地网络&#xff0c;实现高效的协同办公。本文将深入探讨在北上广等经济发达地区&#xff0c;如何通…

Linux部署Yearning并结合内网穿透工具实现公网访问本地web管理界面

文章目录 前言1. Linux 部署Yearning2. 本地访问Yearning3. Linux 安装cpolar4. 配置Yearning公网访问地址5. 公网远程访问Yearning管理界面6. 固定Yearning公网地址 前言 Yearning 简单, 高效的MYSQL 审计平台 一款MYSQL SQL语句/查询审计工具&#xff0c;为DBA与开发人员使用…

计算机毕业设计——SpringBoot 个人博客管理系统(附源码)

1&#xff0c;绪论 1.1 背景调研 在互联网飞速发展的今天&#xff0c;互联网已经成为人们快速获取、发布和传递信息的重要渠道&#xff0c;它在人们政治、经济、生活等各个方面发挥着重要的作用。互联网上发布信息主要是通过网站来实现的&#xff0c;获取信息也是要在互联网中…