JWT工具模块

文章目录

    • JWT工具模块
    • 测试

JWT工具模块

如果要想在项目之中去使用JWT技术,那么就必须结合到已有的模块之中,最佳的做法就是将JWT的相关的处理
操作做为一个自动的starter组件进行接入

1、【microcloud项目】既然要开发一个starter组件,最佳的做法就是开发一个新的模块,模块名称:“yootk-starter.jwt ”

2、【microcloud 项目】需要为“yootk-starter-jwt”模块配置所需要的依赖库,这些依赖库包括

implementation group: 'org.springframework.boot', name: 'spring-boot-configuration-processor', version: '2.5.5'
compileOnly group: 'javax.servlet', name: 'javax.servlet-api', version: '4.0.1'
implementation group: 'commons-codec', name: 'commons-codec', version: '1.15'
implementation group: 'io.jsonwebtoken', name: 'jjwt', version: '0.9.1'
implementation group: 'javax.xml.bind', name: 'jaxb-api', version: '2.3.1'
implementation group: 'com.sun.xml.bind', name: 'jaxb-impl', version: '2.3.0'
implementation group: 'com.sun.xml.bind', name: 'jaxb-core', version: '2.3.0'

3、【microcloud项目】既然已经确定了所需要的项目依赖库,随后就可以修改“dependencies.gradle”配置文件,定义所依赖模块的配置。

ext.versions = [                // 定义全部的依赖库版本号servlet              : '4.0.1', // Servlet的依赖库commonsCodec         : '1.15', // codec依赖库jjwt                 : '0.9.1', // jwt依赖库jaxb                 : '2.3.0', // JAXB依赖库  JDK11需要加的
]
ext.libraries = [// 以下的配置为JWT的服务整合'servlet-api'                       : "javax.servlet:javax.servlet-api:${versions.servlet}",'commons-codec'                     : "commons-codec:commons-codec:${versions.commonsCodec}",'jjwt'                              : "io.jsonwebtoken:jjwt:${versions.jjwt}",'jaxb-api'                          : "javax.xml.bind:jaxb-api:${versions.jaxb}",'jaxb-impl'                         : "com.sun.xml.bind:jaxb-impl:${versions.jaxb}",'jaxb-core'                         : "com.sun.xml.bind:jaxb-core:${versions.jaxb}",
]

4、【microcloud项目】修改build.gradle配置文件,添加相关的依赖

project(":yootk-starter-jwt") { // JWT的实现组件dependencies {annotationProcessor('org.springframework.boot:spring-boot-configuration-processor')implementation(libraries.'servlet-api')implementation(libraries.'commons-codec')// 以下的组件会被其他的模块继续引用,所以必须将其的编译范围配置为compilecompile(libraries.'jjwt')compile(libraries.'jaxb-api')compile(libraries.'jaxb-impl')compile(libraries.'jaxb-core')}
}

5、【yootk-starter-jwt子模块】由于该模块最终需要进行编译处理,所以此时要修改build.gradle配置文件,进行任务配置。

jar { enabled = true} // 允许打包为jar文件
bootJar { enabled = false } // 不允许打包为Boot执行文件
javadocJar { enabled = false } // 不需要打包为jar文件
javadocTask { enabled = false } // 不需要打包为doc文件

6、【yootk-starter-jwt子模块】为了便于用户的信息的相应,创建一个JWT响应代码枚举类。

package com.yootk.jwt.code;import javax.servlet.http.HttpServletResponse;public enum JWTResponseCode { // 定义为一个枚举类SUCCESS_CODE(HttpServletResponse.SC_OK, "Token数据正确,服务正常访问!"),TOKEN_TIMEOUT_CODE(HttpServletResponse.SC_BAD_REQUEST, "Token信息已经失效,需要重新申请!"),NO_AUTH_CODE(HttpServletResponse.SC_NOT_FOUND, "没有找到匹配的Token信息,无法进行服务访问!");private int code; // 响应的代码private String message; // 响应信息private JWTResponseCode(int code, String message) {this.code = code;this.message = message;}public String toString() {  // 直接将数据以JSON的形式返回return "{\"code\":" + this.code + ",\"message\":" + this.message + "}";}
}

7、 【yootk-starter-jwt】此时的yootk-starter-jwt模块最终是一个自动装配的组件,那么既然是组件就需要通过一个配置类来读取引用该模块时所添加的配置信息,那么创建一个JWTConfigProperties 配置类。

package com.yootk.jwt.config;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;@Data // Lombok直接生成的所有代码
@ConfigurationProperties(prefix = "yootk.security.config.jwt") // 配置项的前缀
public class JWTConfigProperties { // JWT配置类private String sign; // 保存签名信息private String issuer; // 证书签发者private String secret; // 加密的密钥private long expire; // 失效时间
}

8、【yootk-starter-jwt子模块】创建ITokenService服务处理接口,专门实现JWT数据的相关处理。

package com.yootk.jwt.service;import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.JwtException;import javax.crypto.SecretKey;
import java.util.Map;public interface ITokenService { // 创建一个JWT的操作接口public SecretKey generalKey(); // 获取当前JWT数据的加密KEY// 创建Token的数据内容,同时要求保存用户的id以及所需要的附加数据public String createToken(String id, Map<String, Object> subject);public Jws<Claims> parseToken(String token) throws JwtException; // 解析Token数据public boolean verifyToken(String token); // 验证Token有效性public String refreshToken(String token); // 刷新Token内容
}

9.【yootk-starter-jwt子模块】创建TokenServicelmpl实现子类,很多的数据需要通过JSON实现传递。

package com.yootk.jwt.service.impl;import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yootk.jwt.config.JWTConfigProperties;
import com.yootk.jwt.service.ITokenService;
import io.jsonwebtoken.*;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
// 此时的组件中的代码需要被其他的模块去引用,所以未必会与扫描包相同
public class TokenServiceImpl implements ITokenService {@Autowired // SpringBoot容器启动时会自动提供Jackson 实例private ObjectMapper objectMapper; // Jackson的数据处理类对象@Autowiredprivate JWTConfigProperties jwtConfigProperties; // 获取JWT的相关配置属性@Value("${spring.application.name}") // 通过SpEL进行配置注入private String applicationName; // 应用名称private SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; // 签名算法@Overridepublic SecretKey generalKey() {byte [] encodeKey = Base64.decodeBase64(Base64.encodeBase64(this.jwtConfigProperties.getSecret().getBytes()));SecretKey key = new SecretKeySpec(encodeKey, 0, encodeKey.length, "AES"); // 获取加密KEYreturn key;}@Overridepublic String createToken(String id, Map<String, Object> subject) {// 使用JWT数据结构进行开发,目的之一就是不需要进行JWT数据的分布式存储,所以所谓的缓存组件、数据库都用不到// 所有的Token都存在有保存时效的问题,所以就需要通过当前时间来进行计算Date nowDate = new Date(); // 获取当前的日期时间Date expireDate = new Date(nowDate.getTime() + this.jwtConfigProperties.getExpire() * 1000); // 证书过期时间Map<String, Object> cliams = new HashMap<>(); // 保存所有附加数据cliams.put("site", "www.yootk.com"); // 视频下载地址,顶部有一个下载资源cliams.put("msg", "世界上爆可爱的老师 —— 爆可爱的小李老师"); // 随便添加内容cliams.put("nice", "Good Good Good");Map<String, Object> headers = new HashMap<>(); // 保存头信息headers.put("author", "李兴华"); // 作者,也可以通过配置处理// 后续由于很多的模块都会引用此组件,所以为了后续的安全,最佳的做法就是设置一个模块名称的信息headers.put("module", this.applicationName);JwtBuilder builder = null;try {builder = Jwts.builder()    // 进行JWTBuilder对象实例化.setClaims(cliams) // 保存附加的数据内容.setHeader(headers) // 保存头信息.setId(id)// 保存ID信息.setIssuedAt(nowDate) // 签发时间.setIssuer(this.jwtConfigProperties.getIssuer()) // 设置签发者.setSubject(this.objectMapper.writeValueAsString(subject)) // 所要传递的数据转为JSON.signWith(this.signatureAlgorithm, this.generalKey()) // 获取签名算法.setExpiration(expireDate); // 配置失效时间} catch (JsonProcessingException e) {e.printStackTrace();}return builder.compact(); // 创建Token}@Overridepublic Jws<Claims> parseToken(String token) throws JwtException {if (this.verifyToken(token)) {  // 只有正确的时候再进行Token解析Jws<Claims> claims = Jwts.parser().setSigningKey(this.generalKey()).parseClaimsJws(token);return claims;}return null; // 解析失败返回null}@Overridepublic boolean verifyToken(String token) {try {Jwts.parser().setSigningKey(this.generalKey()).parseClaimsJws(token).getBody();return true; // 没有异常就返回true} catch (Exception e) {}return false;}@Overridepublic String refreshToken(String token) {if (this.verifyToken(token)) {Jws<Claims> jws = this.parseToken(token); // 解析Token数据return this.createToken(jws.getBody().getId(), this.objectMapper.readValue(jws.getBody().getSubject(), Map.class));}return null;}
}

10、【yootk-starter-jwt子模块】定义一个加密的属性配置

package com.yootk.jwt.config;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;@Data
@ConfigurationProperties(prefix = "yootk.security.config.password.encrypt") // 配置前缀
public class EncryptConfigProperties { // 加密配置属性private Integer repeat; // 定义重复的次数private String salt; // 加密的盐值
}

11、【yootk-starter-jwt子模块】既然所有的用户的信息都要保存在数据表里面,那么就需要进行密码的加密处理。

package com.yootk.jwt.service;public interface IEncryptService { // 密码加密public String getEncryptPassword(String password); // 得到一个加密后的密码
}

12、【yootk-starter-jwt子模块】定义具体的实现子类

package com.yootk.jwt.service.impl;import com.yootk.jwt.config.EncryptConfigProperties;
import com.yootk.jwt.service.IEncryptService;
import org.springframework.beans.factory.annotation.Autowired;import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;public class EncryptServiceImpl implements IEncryptService {@Autowiredprivate EncryptConfigProperties encryptConfigProperties; // 属性配置private static MessageDigest MD5_DIGEST; // MD5加密处理private static final Base64.Encoder BASE64_ENCODER = Base64.getEncoder(); // 加密器static {    // 初始化操作try {MD5_DIGEST = MessageDigest.getInstance("MD5");} catch (NoSuchAlgorithmException e) {e.printStackTrace();}}@Overridepublic String getEncryptPassword(String password) {String saltPassword = "{" + this.encryptConfigProperties.getSalt() + "}" + password;for (int x = 0 ; x < this.encryptConfigProperties.getRepeat(); x ++) {saltPassword = BASE64_ENCODER.encodeToString(MD5_DIGEST.digest(saltPassword.getBytes()));}return saltPassword;}
}

13、【yootk-starter-jwt子模块】创建JWT自动配置类

package com.yootk.jwt.autoconfig;import com.yootk.jwt.config.EncryptConfigProperties;
import com.yootk.jwt.config.JWTConfigProperties;
import com.yootk.jwt.service.IEncryptService;
import com.yootk.jwt.service.ITokenService;
import com.yootk.jwt.service.impl.EncryptServiceImpl;
import com.yootk.jwt.service.impl.TokenServiceImpl;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
@EnableConfigurationProperties({JWTConfigProperties.class, EncryptConfigProperties.class}) // 配置注入属性
public class JWTAutoConfiguration {@Bean("tokenService")public ITokenService getTokenServiceBean() {return new TokenServiceImpl();}@Bean("encryptService")public IEncryptService getEncryptServiceBean() {return new EncryptServiceImpl();}
}

14、【yootk-starter-jwt子模块】在“src/main/resources”目录之中创建“META-INF/spring.factories”配置文件

org.springframework.boot.autoconfigure.EnableAutoConfiguration= com.yootk.jwt.autoconfig.JWTAutoConfiguration

15、【yootk-starter-jwt子模块】模块开发完成之后来进行编译: gradle build

16、【yootk-starter-jwt子模块】既然已经成功的实现了模块的编译处理,随后就需要进行一些环境上的测试,创建SpringBoot的配置文件: application.yml

yootk:security:config:jwt:sign: muyanissuer: Muyansecret: yootkexpire: 100 # 单位:秒password:encrypt:repeat: 5salt: yootkspring:application:name: JWT-TEST          

测试

17、【yootk-starter-jwt子模块】创建一个程序启动的主类,主要是进行测试用的

package com.yootk.jwt;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class StartJWTConfiguration {public static void main(String[] args) {SpringApplication.run(StartJWTConfiguration.class, args);}
}

18、【yootk-starter-jwt子模块】编写测试程序进行TokenService测试

package com.yootk.test;import com.yootk.jwt.StartJWTConfiguration;
import com.yootk.jwt.service.ITokenService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.JwsHeader;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.web.WebAppConfiguration;import java.util.HashMap;
import java.util.Map;
import java.util.UUID;@ExtendWith(SpringExtension.class)
@WebAppConfiguration
@SpringBootTest(classes = StartJWTConfiguration.class) // 随便写的测试类
public class TestTokenService { // 代码测试@Autowiredprivate ITokenService tokenService;private String jwt = "eyJhdXRob3IiOiLmnY7lhbTljY4iLCJtb2R1bGUiOiJKV1QtVEVTVCIsImFsZyI6IkhTMjU2In0.eyJtc2ciOiLkuJbnlYzkuIrniIblj6_niLHnmoTogIHluIgg4oCU4oCUIOeIhuWPr-eIseeahOWwj-adjuiAgeW4iCIsInN1YiI6IntcInJpZHNcIjpcIlVTRVI7QURNSU47REVQVDtFTVA7Uk9MRVwiLFwibmFtZVwiOlwi5rKQ6KiA56eR5oqAIOKAlOKAlCDmnY7lhbTljY5cIixcIm1pZFwiOlwibXV5YW5cIn0iLCJzaXRlIjoid3d3Lnlvb3RrLmNvbSIsImlzcyI6Ik11eWFuWW9vdGsiLCJleHAiOjE2MzM2NzE3NjcsImlhdCI6MTYzMzU3MTc2NywibmljZSI6Ikdvb2QgR29vZCBHb29kIiwianRpIjoieW9vdGstMDgwNGI3NDQtNTBjZC00NjI2LTgzNmEtNjA1MmFiZWMyYzQ4In0.O71QGGPtWYwL7Tyhx8iOLQFAWc1DmVlAS4i0N99OJJk"; // 测试解析使用的@Testpublic void testCreateToken() {Map<String, Object> map = new HashMap<>(); // 测试生成map.put("mid", "muyan");map.put("name", "沐言科技 —— 李兴华");map.put("rids", "USER;ADMIN;DEPT;EMP;ROLE"); // 用户角色信息String id = "yootk-" + UUID.randomUUID(); // 随意生成一个JWT-ID数据System.out.println(this.tokenService.createToken(id, map));}@Testpublic void testParseToken() {  // 解析Token数据内容Jws<Claims> jws = this.tokenService.parseToken(jwt);System.out.println("JWT签名数据:" + jws.getSignature()); // 获取签名数据JwsHeader headers = jws.getHeader(); // 获取头信息headers.forEach((headerName, headerValue) -> {System.out.println("【JWT头信息】" + headerName + " = " + headerValue);});Claims claims = jws.getBody();claims.forEach((bodyName, bodyValue) -> {System.out.println("【JWT数据】" + bodyName + " = " + bodyValue);});} @Testpublic void testVerifyJWT() {System.out.println("【JWT数据验证】" + this.tokenService.verifyToken(jwt));}@Testpublic void testRefreshJWT() {System.out.println("【JWT数据刷新】" + this.tokenService.refreshToken(jwt));}
}

19、【yootk-starter-jwt子模块】随后进行密码加密的测试

package com.yootk.test;import com.yootk.jwt.StartJWTConfiguration;
import com.yootk.jwt.service.IEncryptService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.web.WebAppConfiguration;@ExtendWith(SpringExtension.class)
@WebAppConfiguration
@SpringBootTest(classes = StartJWTConfiguration.class) // 随便写的测试类
public class TestEncryptService {@Autowiredprivate IEncryptService encryptService;@Testpublic void testCreatePassword() {System.out.println(this.encryptService.getEncryptPassword("hello"));}
}

此时已经成功的开发出了一套完整的与JWT相关的应用组件模块,使用的时候直接导入依赖库即可应用。

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

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

相关文章

分布式架构--基本思想汇总

转载自 分布式架构&#xff0d;&#xff0d;基本思想汇总 在互联网大行其道的今天&#xff0c;各种分布式系统已经司空见惯。搜索引擎、电商网站、微博、微信、O2O平台。。凡是涉及到大规模用户、高并发访问的&#xff0c;无一不是分布式。 关于分布式系统&#xff0c;并没有…

花了100多去KTV不是唱歌,竟然是……

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。老师&#xff0c;歌词可以实现&#xff0c;不过比较麻烦~也还行你这样 准备几首歌的歌词就行到时候只演示这几首歌如果是其他的哥的话&#xff0c;就显示暂无歌词行&#xff0c;有时间就试…

jzoj4272-序章-弗兰德的秘密【树形dp】

正题 大意 两棵树&#xff0c;它们的相似值是它们留下最多的节点使它们的结构相同。求相似值。 这两颗树就是结构相同的&#xff0c;相似值是8。 解题思路 就是树形dp。可以用f[i][j]f[i][j]表示树1的第ii号节点和它的子树与树2的j" role="presentation" s…

从NIO到Netty开发

转载自 从NIO到Netty开发 1. 从传统BIO到NIO的升级 Client/Server模型是网络编程的基本模型&#xff0c;服务端提供位置信息&#xff0c;客户端通过连接操作向服务端发起连接请求&#xff0c;通过三次握手建立连接&#xff0c;如果连接建立成功&#xff0c;双方就可以通过网…

jzoj4273-圣章-精灵使的魔法语【线段树】

正题 大意 有n个括号&#xff0c;有左有右&#xff0c;求一个区间内有多少个括号不能相互匹配。中间会改变某些括号的方向。 解题思路 线段树维护两个数lm(left moreleftmore),rm(right morerightmore)分别表示这个区间内多余的左括号和多余的右括号&#xff08;是能相互匹配…

Orleans入门例子

Orleans是微软开源的分布式actor模型框架.actor模型的原理网络上有很多文章.有许多理论性的文章,深刻地我都不知道怎么应用.在这里我就不赘述了.既然是博客,就说说自己的理解。 对于编程来说&#xff0c;不管是前台还是后台&#xff0c;在现在的计算机环境下&#xff0c;多线程…

JavaScript常用单词整理总结

第一章object对象undefined未定义变量boolean布尔类型sort()对数组排序charAt返回在指定位置的字符toLowerCase()把字符串转换为小写button按钮break结束循环toUpperCase()把字符串转换为大写split(str)将字符串分割为字符串数组length获取数组的长度continue结束当前循环&…

JWT 应用

文章目录JWT工具模块Token认证微服务JWT授权监测网关认证过滤消费端获取JWTJWT工具模块 如果要想在项目之中去使用JWT技术&#xff0c;那么就必须结合到已有的模块之中,最佳的做法就是将JWT的相关的处理 操作做为一个自动的starter组件进行接入 1、【microcloud项目】既然要开…

淘宝秒杀系统设计的几个注意点

转载自 淘宝秒杀系统设计的几个注意点 还记得2013年的小米秒杀吗&#xff1f;三款小米手机各11万台开卖&#xff0c;走的都是大秒系统&#xff0c;3分钟后成为双十一第一家也是最快破亿的旗舰店。经过日志统计&#xff0c;前端系统双11峰值有效请求约60w以上的QPS &#xff0…

.NET Core 2.0 开源Office组件 NPOI

前言 去年 12 月&#xff0c;我移植了大家所熟知 NPOI 到 .NET Core 版本&#xff0c;这里是当时发的博客&#xff0c;当时得到了很多同学的支持&#xff0c;社区反应也很好&#xff0c;在这里非常感谢当时推荐的朋友们。 去年的那个版本是针对于 .NET Core 1.0 的&#xff0…

jzoj4274-终章-剑之魂【位运算,贪心】

正题 大意 有n把剑&#xff0c;每一把剑有一个值aiai&#xff0c;然后两把剑的契合值是ai and ajaiandaj&#xff0c;求最大契合值。 解题思路 先把每个a转换成二进制 我们可以先从高位到低位。如果一个位数有超过一把剑那么这两个剑合在一起的值一定比任何这个位位为0的合在…

老师们一直在……

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。【随便写写】为了了解同学们在公司的情况&#xff0c;和佟老师上了的做了个在线问卷调查&#xff0c;把一些常见的问题设置在调查中&#xff0c;根据调查数据&#xff0c;然后挨个的去解决…

海量数据的分库分表技术演进,最佳实践

转载自 海量数据的分库分表技术演进&#xff0c;最佳实践 每个优秀的程序员和架构师都应该掌握分库分表&#xff0c;移动互联网时代&#xff0c;海量的用户每天产生海量的数量 用户表订单表交易流水表 以支付宝用户为例&#xff0c;8亿&#xff1b;微信用户更是10亿。订单表…

Orleans例子再进一步

步骤 现在我想再添加一个方法,到IGrains项目内,这个方法里面有个延迟3秒,然后返回一个Task<string>.就叫做DelayedMsg吧,如下图所示: 我调用了这个DelayedMsg,同时又调用了SayHello函数,看看效果:注意这个DelayedMsg的调用方法没有await. 虽然我的SayHello的调用时间紧随…

2018/7/12-纪中某C组题【jzoj4272,jzoj4273,jzoj4274】

前言 今天我的想法都是正解&#xff0c;也都写了&#xff0c;结果才160QwQ 今日分数 去掉了十分强大的纪中dalao 正题 T1&#xff1a;jzoj4272-序章-弗兰德的秘密【树形dp】 博客链接&#xff1a;https://blog.csdn.net/mr_wuyongcong/article/details/81021994 T2&#xf…

你,下周可否“报上有名”?

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号【雄雄的小课堂】。一周一次周测&#xff0c;一直在延续&#xff0c;一般情况下不会间断。以前我只要一说&#xff0c;同学们&#xff0c;咱们本周周五考试&#xff0c;下面的同学们就沸腾的不行了&#xff0c;有的说…

Redis的3个高级数据结构

转载自 Redis的3个高级数据结构 平常接触最多的是5个入门级数据结构&#xff1a;String&#xff0c;Hash&#xff0c;List&#xff0c;Set&#xff0c;Sorted Set&#xff0c;本文介绍3个高级数据结构&#xff1a;Bitmaps&#xff0c;Hyperloglogs&#xff0c;GEO。 Bitmap…

SpringCloudConfig整合Nacos

SpringCloudConfig 的作用是可以进行配置的更新处理&#xff0c;这个的确是很好&#xff0c;但是原始的SpringCloudNetflix 架构所提供的动态的抓取配置实在是太繁琐了&#xff0c;包括还要使用到SpringCloudBus进行Actuator处理 SpringCloudAlibaba套件之中是基于Nacos 实现的…

使用VS Code开发调试.NET Core 2.0

使用VS Code 从零开始开发调试.NET Core 2.0。无需安装VS 2017 15.3即可开发调试.NET Core 2.0应用。 VS Code 全称是 Visual Studio Code&#xff0c;Visual Studio Code是一个轻量级的跨平台Web集成开发环境&#xff0c;可以运行在 Linux&#xff0c;Mac 和Windows下&#x…

jzoj3382-七夕祭【贪心,中位数】

正题 大意 有k个摊点&#xff0c;有n行m列&#xff0c;每次只能让摊点移动到相邻的格子&#xff08;如果相邻的有那么就交换&#xff09;。要求最少的移动次数让每行每列的摊点数一样&#xff0c;如果不行就输出只能做到行或只能做到列或都不行。注意最上面一行和最下面一行相…