SpringBoot 使用 Sa-Token 完成路由拦截鉴权

一、需求分析

在前文,我们详细的讲述了在 Sa-Token 如何使用注解进行权限认证,注解鉴权虽然方便,却并不适合所有鉴权场景。

假设有如下需求:项目中所有接口均需要登录认证校验,只有 “登录接口” 本身对外开放。

如果我们对项目所有接口都加上 @SaCheckLogin 注解,会显得非常冗余且没有必要,在这个需求中我们真正需要的是一种基于路由拦截的鉴权模式,那么在 Sa-Token 怎么实现路由拦截鉴权呢?

Sa-Token 是一个轻量级 java 权限认证框架,主要解决登录认证、权限认证、单点登录、OAuth2、微服务网关鉴权 等一系列权限相关问题。
Gitee 开源地址:http://gitee.com/dromara/sa-token

二、注册 Sa-Token 路由拦截器

首先在项目中引入 Sa-Token 依赖:

<!-- Sa-Token 权限认证 -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-spring-boot-starter</artifactId>
    <version>1.34.0</version>
</dependency>

注:如果你使用的是 SpringBoot 3.x,只需要将 sa-token-spring-boot-starter 修改为 sa-token-spring-boot3-starter 即可。

新建配置类SaTokenConfigure.java

@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
	// 注册拦截器
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		// 注册 Sa-Token 拦截器,校验规则为 StpUtil.checkLogin() 登录校验。
		registry.addInterceptor(new SaInterceptor(handle -> StpUtil.checkLogin()))
				.addPathPatterns("/**")
				.excludePathPatterns("/user/doLogin"); 
	}
}

以上代码,我们注册了一个基于 StpUtil.checkLogin() 的登录校验拦截器,并且排除了/user/doLogin接口用来开放登录(除了/user/doLogin以外的所有接口都需要登录才能访问)。

SaInterceptor 是新版本提供的拦截器,点此 查看旧版本代码迁移示例。

三、校验函数详解

自定义认证规则:new SaInterceptor(handle -> StpUtil.checkLogin()) 是最简单的写法,代表只进行登录校验功能。

我们可以往构造函数塞一个完整的 lambda 表达式,来定义详细的校验规则,例如:

@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		// 注册 Sa-Token 拦截器,定义详细认证规则 
		registry.addInterceptor(new SaInterceptor(handler -> {
			// 指定一条 match 规则
			SaRouter
				.match("/**")	// 拦截的 path 列表,可以写多个 */
				.notMatch("/user/doLogin")		// 排除掉的 path 列表,可以写多个 
				.check(r -> StpUtil.checkLogin());		// 要执行的校验动作,可以写完整的 lambda 表达式
				
			// 根据路由划分模块,不同模块不同鉴权 
			SaRouter.match("/user/**", r -> StpUtil.checkPermission("user"));
			SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin"));
			SaRouter.match("/goods/**", r -> StpUtil.checkPermission("goods"));
			SaRouter.match("/orders/**", r -> StpUtil.checkPermission("orders"));
			SaRouter.match("/notice/**", r -> StpUtil.checkPermission("notice"));
			SaRouter.match("/comment/**", r -> StpUtil.checkPermission("comment"));
		})).addPathPatterns("/**");
	}
}

SaRouter.match() 匹配函数有两个参数:

  • 参数一:要匹配的path路由。
  • 参数二:要执行的校验函数。

在校验函数内不只可以使用 StpUtil.checkPermission("xxx") 进行权限校验,你还可以写任意代码,例如:

@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {
	// 注册 Sa-Token 的拦截器
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		// 注册路由拦截器,自定义认证规则 
		registry.addInterceptor(new SaInterceptor(handler -> {
			
			// 登录校验 -- 拦截所有路由,并排除/user/doLogin 用于开放登录 
			SaRouter.match("/**", "/user/doLogin", r -> StpUtil.checkLogin());

			// 角色校验 -- 拦截以 admin 开头的路由,必须具备 admin 角色或者 super-admin 角色才可以通过认证 
			SaRouter.match("/admin/**", r -> StpUtil.checkRoleOr("admin", "super-admin"));

			// 权限校验 -- 不同模块校验不同权限 
			SaRouter.match("/user/**", r -> StpUtil.checkPermission("user"));
			SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin"));
			SaRouter.match("/goods/**", r -> StpUtil.checkPermission("goods"));
			SaRouter.match("/orders/**", r -> StpUtil.checkPermission("orders"));
			SaRouter.match("/notice/**", r -> StpUtil.checkPermission("notice"));
			SaRouter.match("/comment/**", r -> StpUtil.checkPermission("comment"));
			
			// 甚至你可以随意的写一个打印语句
			SaRouter.match("/**", r -> System.out.println("----啦啦啦----"));

            // 连缀写法
            SaRouter.match("/**").check(r -> System.out.println("----啦啦啦----"));
			
		})).addPathPatterns("/**");
	}
}

四、匹配特征详解

除了上述示例的 path 路由匹配,还可以根据很多其它特征进行匹配,以下是所有可匹配的特征:

// 基础写法样例:匹配一个path,执行一个校验函数 
SaRouter.match("/user/**").check(r -> StpUtil.checkLogin());

// 根据 path 路由匹配   ——— 支持写多个path,支持写 restful 风格路由 
// 功能说明: 使用 /user , /goods 或者 /art/get 开头的任意路由都将进入 check 方法
SaRouter.match("/user/**", "/goods/**", "/art/get/{id}").check( /* 要执行的校验函数 */ );

// 根据 path 路由排除匹配 
// 功能说明: 使用 .html , .css 或者 .js 结尾的任意路由都将跳过, 不会进入 check 方法
SaRouter.match("/**").notMatch("*.html", "*.css", "*.js").check( /* 要执行的校验函数 */ );

// 根据请求类型匹配 
SaRouter.match(SaHttpMethod.GET).check( /* 要执行的校验函数 */ );

// 根据一个 boolean 条件进行匹配 
SaRouter.match( StpUtil.isLogin() ).check( /* 要执行的校验函数 */ );

// 根据一个返回 boolean 结果的lambda表达式匹配 
SaRouter.match( r -> StpUtil.isLogin() ).check( /* 要执行的校验函数 */ );

// 多个条件一起使用 
// 功能说明: 必须是 Get 请求 并且 请求路径以 `/user/` 开头 
SaRouter.match(SaHttpMethod.GET).match("/user/**").check( /* 要执行的校验函数 */ );

// 可以无限连缀下去 
// 功能说明: 同时满足 Get 方式请求, 且路由以 /admin 开头, 路由中间带有 /send/ 字符串, 路由结尾不能是 .js 和 .css
SaRouter
	.match(SaHttpMethod.GET)
	.match("/admin/**")
	.match("/**/send/**") 
	.notMatch("/**/*.js")
	.notMatch("/**/*.css")
	// ....
	.check( /* 只有上述所有条件都匹配成功,才会执行最后的check校验函数 */ );

五、提前退出匹配链

使用 SaRouter.stop() 可以提前退出匹配链,例:

registry.addInterceptor(new SaInterceptor(handler -> {
	SaRouter.match("/**").check(r -> System.out.println("进入1"));
	SaRouter.match("/**").check(r -> System.out.println("进入2")).stop();
	SaRouter.match("/**").check(r -> System.out.println("进入3"));
	SaRouter.match("/**").check(r -> System.out.println("进入4"));
	SaRouter.match("/**").check(r -> System.out.println("进入5"));
})).addPathPatterns("/**");

如上示例,代码运行至第2条匹配链时,会在stop函数处提前退出整个匹配函数,从而忽略掉剩余的所有match匹配

除了stop()函数,SaRouter还提供了 back() 函数,用于:停止匹配,结束执行,直接向前端返回结果

// 执行back函数后将停止匹配,也不会进入Controller,而是直接将 back参数 作为返回值输出到前端
SaRouter.match("/user/back").back("要返回到前端的内容");

stop() 与 back() 函数的区别在于:

  • SaRouter.stop() 会停止匹配,进入Controller。
  • SaRouter.back() 会停止匹配,直接返回结果到前端。

六、使用free打开一个独立的作用域

// 进入 free 独立作用域 
SaRouter.match("/**").free(r -> {
	SaRouter.match("/a/**").check(/* --- */);
	SaRouter.match("/b/**").check(/* --- */).stop();
	SaRouter.match("/c/**").check(/* --- */);
});
// 执行 stop() 函数跳出 free 后继续执行下面的 match 匹配 
SaRouter.match("/**").check(/* --- */);

free() 的作用是:打开一个独立的作用域,使内部的 stop() 不再一次性跳出整个 Auth 函数,而是仅仅跳出当前 free 作用域。

七、使用注解忽略掉路由拦截校验

我们可以使用 @SaIgnore 注解,忽略掉路由拦截认证:

1、先配置好了拦截规则:

@Override
public void addInterceptors(InterceptorRegistry registry) {
	registry.addInterceptor(new SaInterceptor(handler -> {
		// 根据路由划分模块,不同模块不同鉴权 
		SaRouter.match("/user/**", r -> StpUtil.checkPermission("user"));
		SaRouter.match("/admin/**", r -> StpUtil.checkPermission("admin"));
		SaRouter.match("/goods/**", r -> StpUtil.checkPermission("goods"));
		// ... 
	})).addPathPatterns("/**");
}

2、然后在 Controller 里又添加了忽略校验的注解

@SaIgnore
@RequestMapping("/user/getList")
public SaResult getList() {
	System.out.println("------------ 访问进来方法"); 
	return SaResult.ok(); 
}

请求将会跳过拦截器的校验,直接进入 Controller 的方法中。

注意点:此注解的忽略效果只针对 SaInterceptor拦截器 和 AOP注解鉴权 生效,对自定义拦截器与过滤器不生效。

八、关闭注解校验

SaInterceptor 只要注册到项目中,默认就会打开注解校验,如果要关闭此能力,需要:

@Override
public void addInterceptors(InterceptorRegistry registry) {
	registry.addInterceptor(
		new SaInterceptor(handle -> {
			SaRouter.match("/**").check(r -> StpUtil.checkLogin());
		}).isAnnotation(false)  // 指定关闭掉注解鉴权能力,这样框架就只会做路由拦截校验了 
	).addPathPatterns("/**");
}

参考资料

  • Sa-Token 文档:http://sa-token.cc
  • Gitee 仓库地址:http://gitee.com/dromara/sa-token
  • GitHub 仓库地址:http://github.com/dromara/sa-token
本文转载于网络 如有侵权请联系删除

相关文章

  • java当前时间的时间戳_java获取时间戳和当前时间

    大家好,又见面了,我是你们的朋友全栈君。java中的时间戳是毫秒为单位,13位;unix的时间戳是秒,10位一、java中获取时间戳//方法一System.currentTimeMillis();//方法二Calendar.getInstance().getTimeInMillis();//方法三newDate().getTime();三种方法性能比较:每种方法运行1亿次importjava.text.SimpleDateFormat;importjava.util.Calendar;importjava.util.Date;publicclassTimeStamp{ privatelongcount=10000*10000;publicstaticvoidmain(String[]args){ TimeStamptimeStamp=newTimeStamp();System.out.println(System.currentTimeMillis());System.out.println(Calendar.getInstance().getTimeInMillis());Syste

  • linux中卸载提示设备正忙怎么办?

    执行NFS挂载时,你可能会看到设备繁忙状态。在这种情况下,你必须以适当的方式强制卸载。在这种情况下,我们创建了/var/linoxide安装目录。如果尝试卸载远程分区,则会收到错误消息。#df-h FilesystemSizeUsedAvailUse%Mountedon /dev/vda120G3G18G7%/ devtmpfs236M0236M0%/dev tmpfs245M0245M0%/dev/shm tmpfs245M4M237M4%/run tmpfs245M0245M0%/sys/fs/cgroup tmpfs49M049M0%/run/user/0 1241:/var/linoxide20G3G18G7%/mnt/nfs/linoxide_srv 1241:/home20G3G18G7%/mnt/nfs/home_srv 复制在最后两行中,已安装的文件夹显示在客户端上。以下示例显示由于设备繁忙而导致卸载失败#umount/mnt/nfs/linoxide_srv/ umount.nfs4:/mnt/nfs/linoxide_srv:deviceisbusy 复制使用lso

  • Excel Power Query里的月份排序问题

    小勤:像这种月份的排序问题怎么办?大海:这种排序问题在Excel里面可以直接处理了,像这样:小勤:那如果在PowerQuery里呢?这些数据其实我是在PQ里做了很多其他处理的,最好能直接在PQ里实现。大海:PQ里稍为麻烦一丢丢,在PQ里这样做:Step-01:复制月份列Step-02:将复制出来的列更改为日期类型Step-03:先后对产品和转换后的月份列排序Step-04:排序后删掉复制出来的列就搞定了小勤:嗯,这相当于做个辅助列来排序。大海:对的,这些都是根据实际需要来操作。如果是临时的单一处理,用Excel就非常简单直接,如果是要综合其他内容处理并达到一键刷新,就用PQ。

  • CAM 论文阅读

    LearningDeepFeaturesforDiscriminativeLocalization摘要:重新审视《Networkinnetwork》中提出的全局平均池化层(globalaveragepooling),并阐明了它是如何通过图片标签就能让卷积神经网络具有卓越的定位能力。虽然这项技术以前被当做正则化训练的一种方法,但是我们发现它实际构建了一种通用的适用于各种任务的能定位的深度表示。尽管globalaveragepooling很简单,我们仍然能够在2014年的ILSVRC物体定位比赛中得到37.1%的top-5错误率,与CNN的34.2%top-5错误率非常接近。我们证明了我们的网络能在各种任务中区分图像区域进行定位,尽管没有经过(定位)训练。1Introduction《Objectdetectorsemergeindeepscenecnns》表明CNN的各个层的卷积单元实际上是物体检测器,尽管没有对物体的位置进行监督。尽管卷积层定位物体的能力很出色,但当用全连接层进行分类时,这种能力会丧失。最近,一些流行的全连接层和卷积层的神经网络,比如NetworkinNetwork(NI

  • elasticSearch学习(一)

    ElasticSearch概述Elaticsearch,简称为es,es是一个开源的高扩展的分布式全文检索引擎,它可以近乎实时的存储、检索数据;本身扩展性很好,可以扩展到上百台服务器,处理PB级别(大数据时代)的数据。es也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTfulAPI来隐藏Lucene的复杂性,从而让全文搜索变得简单。据国际权威的数据库产品评测机构DBEngines的统计,在2016年1月,ElasticSearch已超过Solr等,成为排名第一的搜索引擎类应用。历史小故事多年前,一个叫做ShayBanon的刚结婚不久的失业开发者,由于妻子要去伦敦学习厨师,他便跟着也去了。在他找工作的过程中,为了给妻子构建一个食谱的搜索引擎,他开始构建一个早期版本的Lucene。直接基于Lucene工作会比较困难,所以Shay开始抽象Lucene代码以便Java程序员可以在应用中添加搜索功能。他发布了他的第一个开源项目,叫做“Compass”。后来Shay找到一份工作,这份工作处在高性能和内存数据网格的分布式环境中,因此高性能的、

  • Renyi index

    啥是RenyiindexShannon熵在微生物领域应用的已经十分普遍了。Shannonindex作为alpha多样性的表征手段广泛应用于微生物领域的分析中。而Renyi就更厉害了,shannon只是它其中的一种形式。Renyi熵以AlfrédRényi的名字命名。公式为:α=0时为Hartleyormax-entropy,为物种数量的对数。α=1时的极限即为广泛使用的Shannonentropyα=2时为Collisionentropyα趋于正无穷时为Min-entropy,该值永远不会大于shannonentropy.Renyiindex在R中的实现renyi函数计算参数α取不同值时的Renyidiversity或者相应的Hillnumber。>library(vegan) #Usage #renyi(x,scales=c(0,0.25,0.5,1,2,4,8,16,32,64,Inf),hill=FALSE) #scales:Renyi公式中的alpha参数 #hill:是否计算hillnumber >data(BCI) >i<-sample(nrow(B

  • FNV算法实战

    HASH算法介绍Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入(又叫做预映射,pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,而不可能从散列值来唯一地确定输入值。数学表述为:h=H(M),其中H()--单向散列函数,M--任意长度明文,h--固定长度散列值。HASH算法的实际应用-加密常见的哈希加密算法:MD5,SHA-1,SHA-2,SHA-256,SHA-X(系列)1)文件校验:MD5Hash算法的“数字指纹”特性,使它成为目前应用最广泛的一种文件完整性校验和(Checksum)算法,不少Unix系统有提供计算md5checksum的命令;2)数字签名:在这种签名协议中,双方必须事先协商好双方都支持的Hash函数和签名算法。签名方先对该数据文件进行计算其散列值,然后再对很短的散列值结果--如Md5是16个字节,SHA1是20字节,用非对称算法进行数字签名操作。对方在验证签名时,也是先对该数据文件进行计算其散列值,然后再用非对称

  • Java中executors提供的的4种线程池

    前言了解一下线程池的源码实现.ThreadPoolExecutorjdk中关于线程池一个比较核心的类是ThreadPoolExecutor,先来看一下他的实现.构造方法publicThreadPoolExecutor(intcorePoolSize, intmaximumPoolSize, longkeepAliveTime, TimeUnitunit, BlockingQueue<Runnable>workQueue){ this(corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue, Executors.defaultThreadFactory(),defaultHandler); } publicThreadPoolExecutor(intcorePoolSize, intmaximumPoolSize, longkeepAliveTime, TimeUnitunit, BlockingQueue<Runnable>workQueue, ThreadFactorythreadFactory){

  • 深度学习工具根据健身数据,提供个性化锻炼建议

    加州大学圣地亚哥分校的计算机科学家开发了FitRec,这是一种基于深度学习的推荐工具,可以更好地估计跑步者在锻炼期间的心率,并预测和推荐路线。该团队将于5月13日至17日在旧金山举行的WWW19大会上展示该作品。研究人员用超过1000名跑步者的超过250000条锻炼记录的数据集训练FitRec。这使计算机科学家能够建立一个模型,分析过去的表现,预测特定锻炼时间和路线下的速度和心率。FitRec还能够识别影响锻炼效果的重要特征,例如路线是否具有坡度以及用户的健康水平。该工具可以为想要达到特定目标心率的跑步者推荐替代路线。它还能够做出短期预测,例如告诉跑步者什么时候减速,以避免超过期望的最高心率。他们是第一批收集和建模用于学术研究的大型健身数据集团队,但是,开发FitRec绝非易事,因为健身数据集拥有大量的锻炼记录,但每个人只有少量的数据点。加州大学圣地亚哥分校计算机科学与工程系教授JulianMcAuley说,“个性化在健身数据模型中至关重要,因为个体差异很大,包括心率和适应不同运动的能力。建立这种模型的主要挑战是,人们锻炼时的心率动态非常复杂,需要复杂的技术来建模。”为了建立一个有效的

  • Salesforce to Salesforce介绍

    Force.com是一个多租户平台,因此每个客户在一个共享的平台上都有自己的环境(组织)。每个环境都包含客户想要存储的数据。然而有时客户可能想在自己的公司的不同Salesforce系统之间共享数据,或是和两个合作伙伴之间可能想分享相关的数据。 SalesforcetoSalesforce可以用来创建这种数据共享关系。SalesforcetoSalesforce是Force.com平台自身的特性,很容易开启并让合作伙伴之间共享彼此的数据。本文将介绍如何启用SalesforcetoSalesforce,如何在两个不同的环境创建一个连接,以及如何在两个环境中共享数据。启用SalesforcetoSalesforce在你使用SalesforcetoSalesforce(S2S)前,你需要先启用它。而且是双方都需要启用,在你的环境中,以及在你要共享数据的环境中都需开启。系统管理员可以通过设置面板来启用SalesforcetoSalesforce,但是需要注意的是,一旦启用,你将无法关闭它。启用的步骤:Setup->Appsetup->Customize->Salesforcet

  • 微信小程序开发环境搭建

    微信小程序是当前程序员讨论的相当火的一个名词了,当前App开发人员有个担心,微信小程序的到来会不会给移动端App带来一个寒冬。不管微信小程序是否能颠覆当今的开发格局,我们都要以好奇的心态去接收,去学习。不排斥新技术,所以,心动不如行动,赶紧先搭建一个微信小程序开发工具。步骤:1:下载微信小程序开发工具0.7.0版本(下载链接https://pan.baidu.com/s/1bp5MHHl密码:mn87)下载0.7.0版本后直接安装,安装过程很简单,选择安装目录下一步就可以了,安装成功后登陆进入程序出现,需要微信扫码。进入后出现上面界面关闭。2:然后下载0.9.0版本(下载链接:https://pan.baidu.com/s/1mii3Hk0密码:x7iw)下载后直接覆盖安装就可以了(要覆盖安装),安装后先不用打开开发工具,安装程序后需要下载三个js破解文件替换掉我们安装程序的对于目录的对应文件。3:破解JS链接:https://pan.baidu.com/s/1o8TMM2u密码:eqqf下载下图的三个文件,我将工具安装到C盘了,分别找到下面三个目录替换对应文件即可C:\微信web开发

  • 操作系统底层技术——CPU亲和性

    头图是加拿大lakesimcoe自然风光,非常漂亮,基本没有中国游客,适合深度游。这是操作系统底层技术第二篇,前一篇是《Codegen技术学习》CPU亲和性简单地说,CPU亲和性(affinity)就是进程要在某个给定的CPU上尽量长时间地运行而不被迁移到其他处理器的倾向性。 Linux内核进程调度器天生就具有被称为软CPU亲和性(affinity)的特性,这意味着进程通常不会在处理器之间频繁迁移。这种状态正是我们希望的,因为进程迁移的频率小就意味着产生的负载小。2.6版本的Linux内核还包含了一种机制,它让开发人员可以编程实现硬CPU亲和性(affinity)。这意味着应用程序可以显式地指定进程在哪个(或哪些)处理器上运行。原理什么是Linux内核硬亲和性(affinity)?在Linux内核中,所有的进程都有一个相关的数据结构,称为task_struct。这个结构非常重要,原因有很多;其中与亲和性(affinity)相关度最高的是cpus_allowed位掩码。这个位掩码由n位组成,与系统中的n个逻辑处理器一一对应。具有4个物理CPU的系统可以有4位。如果这些CPU都启用了超线程

  • 应用命令和文件执行权限详细

    [TOC]runas命令描述:在某些情况下为了安全起见,大部分公司都会使用域控制器或只会给员工电脑user的用户权限,这样做能大大提高安全性和可控性,但由此也带来了一些困扰,所以在特定规定下要用到特殊权限的用户进行切换.比如:某些特定的部门(如财务,物流)没有管理员权限,但工作又需要使用特定的插件或程序,且该程序或插件又必须以管理员身份运行,在这种情况下,我们如果将用户的权限提升为管理员,那样会增加安全风险而且可能引起很多不可控的情况。在这种情况下我们可以使用runas命令来指定运行某个程序,这个命令是微软系统自有的包括域环境下也能使用。这样一来即解决了软件使用问题,又不会牺牲安全性。用法: RUNAS[[/noprofile|/profile][/env][/savecred|/netonly]]/user:<UserName>program RUNAS[[/noprofile|/profile][/env][/savecred]]/smartcard[/user:<UserName>]program RUNAS/trustlevel:<TrustLev

  • ecshop 报错

    ECShop出现Strict Standards: Only variables should be passed b  (2014-06-0417:00:37) 转载▼ 标签:  ecshop   报错   strictstandards   it 分类: ECshop 今天开始研究ECShop,在安装完成的时候发现首页顶部、左侧和底部出现:   StrictStandards:OnlyvariablesshouldbepassedbyreferenceinF:\wamp\www\ecshop\upload\includes\cls_template.phponline418   的报错信息。   第一种解决方法是杀到cls_template.php文件中发现下面这段代码: 1 $tag_sel=array_shift(explode('',$tag)); 忘记说了,我的PHP版本

  • CopyOnWriteArrayList源码分析

    前言:CopyOnWriteArrayList为ArrayList的线程安全版本,这里来分析下其内部是如何实现的。 注:本文jdk源码版本为jdk1.8.0_172 1.CopyOnWriteArrayList介绍 CopyOnWriteArrayList是ArrayList的线程安全版本,因此其底层数据结构也是数组,但是在写操作的时候都会拷贝一份数据进行修改,修改完后替换掉老数据,从而保证只阻塞写操作,读操作不会阻塞,实现读写分离。 1publicclassCopyOnWriteArrayList<E> 2implementsList<E>,RandomAccess,Cloneable,java.io.Serializable{}复制 2.具体源码分析 底层数据结构: 1/**Thelockprotectingallmutators*/ 2//使用可重入锁进行加锁,保证线程安全 3finaltransientReentrantLocklock=newReentrantLock(); 4 5/**Thearray,accessedonlyviagetAr

  • PyTorch迁移学习-私人数据集上的蚂蚁蜜蜂分类

    1.迁移学习的两个主要场景 微调CNN:使用预训练的网络来初始化自己的网络,而不是随机初始化,然后训练即可 将CNN看成固定的特征提取器:固定前面的层,重写最后的全连接层,只有这个新的层会被训练 下面修改预训练好的resnet18网络在私人数据集上进行训练来分类蚂蚁和蜜蜂 2.数据集下载 这里使用的数据集包含ants和bees训练图片各约120张,验证图片各75张。由于数据样本非常少,如果从0初始化一个网络进行训练很难有令人满意的结果,这时候迁移学习就派上了用场。数据集下载地址,下载后解压到项目目录 3.导入相关包 importtorch importtorch.nnasnn importtorch.optimasoptim importnumpyasnp importtorchvision importtorchvision.transformsastransforms importtime importos importcopy device=torch.device('cuda:0'iftorch.cuda.is_available()else'cpu') 复制 4.加载数

  • C# 杀掉系统中的进程

      杀掉系统进程之前首先要知道进程名称(说了句废话),这里要注意在任务管理器中的进程名称不一定是真实的名称。打个比方,我们开启一个"记事本",任务管理器中进程名称为"记事本",但是实际名为"notepad"。如果不知道在哪里看,可以点开任务管理器中的进程右击属性查看,一般都是xxx.exe形式。   接下来我们开始写代码,可以循环取到系统中所有正在运行的进程,然后根据name和id匹配将要删除的进程,值得注意的是:开启多个"记事本"进程,name是一致的,如果根据name杀进程,那么都会被关闭掉。id是唯一的,但是每次启动"记事本"id会被随机分配。 引用: usingSystem.Diagnostics;复制 代码: ///<summary> ///杀掉FoxitReader进程 ///</summary> ///<paramname="strProcessesByName"></param> publicstaticvoidKillProcess(stringprocessName) { foreach(Processpin

  • (转)Linux free命令 内存介绍

    转:https://www.cnblogs.com/ultranms/p/9254160.html free命令显示系统内存的使用情况,包括物理内存、交换内存(swap)和内核缓冲区内存。 如果加上-h选项,输出的结果会友好很多: 有时我们需要持续的观察内存的状况,此时可以使用-s选项并指定间隔的秒数: $free-h-s3复制 上面的命令每隔3秒输出一次内存的使用情况,直到你按下ctrl+c。 由于free命令本身比较简单,所以本文的重点会放在如何通过free命令了解系统当前的内存使用状况。 输出简介 下面先解释一下输出的内容:Mem 行(第二行)是内存的使用情况。Swap 行(第三行)是交换空间的使用情况。total 列显示系统总的可用物理内存和交换空间大小。used 列显示已经被使用的物理内存和交换空间。free 列显示还有多少物理内存和交换空间可用使用。shared 列显示被共享使用的物理内存大小。buff/cache 列显示被buffer和cache使用的物理内存大小。available 

  • 电视剧随笔记

    ------------恢复内容开始------------ ------------恢复内容开始------------ ------------恢复内容开始------------ ------------恢复内容开始------------ ------------恢复内容开始------------ 中国电视剧的黄金时代是1990年-2010年 张成功编写黑冰黑雾黑洞 天道 冰毒,新型毒品的一种,又名甲基安非他明、去氧麻黄碱,是一种无味或微有苦味的透明结晶体,纯品很像冰糖,形似冰,故俗称冰毒。吸、贩毒者也称之为“ ------------恢复内容结束------------ 张成功黑冰取件链接:https://cowtransfer.com/s/7b39d76e6dac42#失效了或使用取件码:4y3zuj。复制整段文案打开奶牛快传App,获取分享内容更快速哦。 ------------恢复内容结束------------ 郭小鹏黯然道:“我的继父身为高级干部,肯定不会亲手打人。但那种深入骨髓的歧视,那种精神摧残,常人难以想象。那是一种超越阶级仇恨的蔑视。” ---------

  • scrapy爬虫系列之五--CrawlSpider的使用

    功能点:CrawlSpider的基本使用 爬取网站:保监会 主要代码: cf.py #-*-coding:utf-8-*- importscrapy fromscrapy.linkextractorsimportLinkExtractor fromscrapy.spidersimportCrawlSpider,Rule importre classCfSpider(CrawlSpider):#继承自CrawlSpider """主要是介绍CrawlSpider的用法""" name='cf' allowed_domains=['circ.gov.cn'] #第一次请求的url,如果有特殊需求,可以定义一个parse_start_url函数来处理这个url所对应的响应 start_urls=['http://circ.gov.cn/web/site0/tab5240/'] rules=( #LinkExtractor链接提取器,提取url地址 #callback可以没有 #follow当前url的响应是否重新经过rules来提取url #注意点: #1、两个Rule的callba

  • 一个奇葩的SQL题,够强大。

      困惑描述:     现有一张图片表,表里一个sort字段,这个字段是不重复的、不连续的数字。大致结构如下     createtableImgs(       `id`bigint(20)NOTNULLAUTO_INCREMENT,        `src`varchar(255)NOTNULL,       `sort`int(11)DEFAULT'0'     )   注:sqlserver请修改  AUTO_INCREMENT为identity(1,1)   大致数据如下   id        src         sort   1     "../img/1.jpg"     0   2     "../img/2.jpg"     2   3     "../img/101.jpg"    3   4     "../img/tree.jpg"    4   5     "../img/node.jpg"  &

相关推荐

推荐阅读