0%

JWT结构

在其紧凑形式中,JSON Web Tokens 由三部分组成,以点 (.) 分隔,它们是:

  • Header
  • Payload
  • Signature

因此,JWT 通常如下所示。

1
xxxxx.yyyyy.zzzzz

标头通常由两部分组成:令牌的类型,即 JWT,以及正在使用的签名算法,例如 HMAC SHA256 或 RSA。

例如:

1
2
3
4
{
"alg": "HS256",
"typ": "JWT"
}

然后,这个 JSON 被 Base64Url 编码以形成 JWT 的第一部分。

Payload

令牌的第二部分是负载,其中包含声明。声明是关于实体(通常是用户)和附加数据的说明。共有三种类型的声明:已注册声明、公共声明和私有声明。

  • Registered claims: 这些是一组预定义的声明,这些声明不是强制性的,而是推荐的,以提供一组有用的、可互操作的声明。其中一些是:iss(发行者)、exp(到期时间)、sub(主题)、aud(受众)等。.

  • Public claims: 这些可以由使用 JWT 的人随意定义。但是为了避免冲突,它们应该在 IANA JSON Web Token Registry中定义,或者定义为包含抗冲突命名空间的 URI。

  • Private claims: These are the custom claims created to share information between parties that agree on using them and are neither registered or public claims.

An example payload could be:

1
2
3
4
5
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}

payload 进行 Base64Url 编码以形成 JSON Web Token的第二部分

注意:

​ 对于已签名的令牌,此信息虽然受到防篡改保护,但任何人都可以读取。除非加密,否则不要将机密信息放入 JWT 的负载或标头元素中。

Signature

要创建签名部分,您必须获取--------被编码过的标头、被编码过的有效载荷、secret、标头中指定的算法,并对其进行签名。

例如,如果要使用 HMAC SHA256 算法,则签名将通过以下方式创建:

1
2
3
4
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)

签名用于验证消息在此过程中没有更改,并且在使用私钥签名的令牌的情况下,它还可以验证 JWT 的发送者是它所说的那个人。

Putting all together

输出是三个由点分隔的 Base64-URL 字符串,可以在 HTML 和 HTTP 环境中轻松传递,同时与基于 XML 的标准(如 SAML)相比更加紧凑。

下面显示了一个 JWT

JWT如何工作

每当用户想要访问受保护的路由或资源时,用户代理应该发送 JWT,typically in the Authorization header using the Bearer schema

标题的内容应如下所示:

1
Authorization: Bearer <token>

两个浮点数加减,会出现精度丢失。

原因:计算机不能准确表示每一个浮点数的值,很多浮点数表示的是一个很接近该浮点数的值。

这里只是简略举个例子。

比如0.1这个浮点数

​ 0.1 X 2 = 0.2 0
​ 0.2 X 2 = 0.4 0
​ 0.4 X 2 = 0.8 0
​ 0.8 X 2 = 1.6 1
​ (1.6 - 1 = 0.6)
​ 0.6 X 2 = 1.2 1
​ (1.2 - 1 = 0.2)
​ 0.2 X 2 = 0.4 0
​ 0.4 X 2 = 0.8 0
​ 0.8 X 2 = 1.6 1
​ (1.6 - 1 = 0.6)
​ 0.6 X 2 = 1.2 1
​ (1.2 - 1 = 0.2)
​ 0.2 X 2 = 0.4 0
​ 0.4 X 2 = 0.8 0
​ 0.8 X 2 = 1.6 1

​ ······

​ // 无限循环下去

在idea运行一下,之所以第一个能直接输出0.1

是因为System.out.println(0.1);这句,先把浮点数转换成字符串,再输出。

首先,在用之前一定要知道,想要时间能够被自动填充,xxxmapper必须要继承BaseMapper《T》,然后使用basemapper中的方法(自己写的insert sql语句,时间不会被自动填充)

1.在需要被填充的字段上加上@TableField

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public enum FieldFill {
/**
* 默认不处理
*/
DEFAULT,
/**
* 插入填充字段
*/
INSERT,
/**
* 更新填充字段
*/
UPDATE,
/**
* 插入和更新填充字段
*/
INSERT_UPDATE
}
1
2
@TableField(fill = FieldFill.INSERT)
private LocalDateTime operTime;
创建时间,一般用FieldFill.INSERT即可,更新时间一般用FieldFill.INSERT_UPDATE(因为第一次更新时没有数据,是插入)

2.自定义实现类MyMetaObjectHandler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐)
}

@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "updateTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐)

}
}

3.如果有多个要填充的字段(比如在这里,为了兼容不同开发者不同的时间字段)

1
2
3
4
5
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "operTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐)
this.strictInsertFill(metaObject, "createTime", () -> LocalDateTime.now(), LocalDateTime.class); // 起始版本 3.3.3(推荐)
}

这样即可填充数据库中的oper_time,create_time字段

4.取出的时间有T,加上@JsonFormat( pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")

GMT+8:时间设置为东八区
没加@JsonFormat
1
2
@TableField(fill = FieldFill.INSERT)
private LocalDateTime operTime;

加@JsonFormat
1
2
3
@TableField(fill = FieldFill.INSERT)
@JsonFormat( pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") //加上此注解,去掉时间中的T
private LocalDateTime operTime;

今天在做项目时,有好几个需求都是对成绩进行分段,这些需求只是——表名,id字段名,分数字段名不一样,其他都一样。于是就考虑能不能把表名,id字段名,分数名换成变量,这样就一劳永逸了。而且如果其他伙伴有同样的需求,也可以直接调我的方法。

一.做之前

原本想用mybatis plus做,但是mp太麻烦了。最终还是考虑用mybatis

二.正片

第一次尝试:

1
2
@Select("select count(*) as segCount from #{tbName} where #{idTbName}=#{idValue} and ( #{scoreTbName} between #{val1} and #{val2} ) ")
Integer getSeg(@Param("tbName") String tbName, String idTbName, Long idValue, String scoreTbName, Integer val1, Integer val2);

报错:

Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@d5b549d] was not registered for synchronization because synchronization is not active
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@d5b549d]

错因:

#占位符,告诉 mybatis 使用实际的参数值代替。并使用 PrepareStatement 对象执行 sql 语句, #{…}代替sql 语句的“?”。这样做更安全,更迅速,通常也是首选做法。

$ 字符串替换,告诉 mybatis 使用$包含的“字符串”替换所在位置。使用 Statement 把 sql 语句和${}的内容连接起来。主要用在替换表名,列名,不同列排序等操作。

#{}

#将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。
如:WHERE SID = #{sid},如果传入的值是s01,那么解析成SQL时的值为WHERE SID = "s01"。
#可以防止防止sql注入。

${}

$将传入的数据直接显示生成在sql中。
如:ORDER BY ${sage},如果传入的值是age,那么解析成SQL时的值为ORDER BY age。
$方式一般用于传入数据库对象,例如传入表名,字段名。

第二次尝试:

1
2
@Select("select count(*)  from ${tbName} where ${idTbName}=#{idValue} and ( ${scoreTbName} between #{val1} and #{val2} ) ")
Integer getSeg(@Param("tbName") String tbName, String idTbName, Long idValue, String scoreTbName, Integer val1, Integer val2);

把表名,字段名由#{}换成${}

报错:

Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@d5b549d] was not registered for synchronization because synchronization is not active
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@d5b549d]

错因:

@Param注解的作用是声明参数时,如果使用 #{} 或 ${} 的方式都可以。
不使用@Param注解来声明参数时,必须使用使用 #{}方式,如果使用${} 的方式,会报错。

一、String
1
2
3
4
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {

}

String 是不可变的对象, 因此在每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,性能就会降低。

二、StringBuilder和StringBuffer

和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。

StringBuilder和StringBuffer的区别在于,StringBuilder不是线程安全的。因此 StringBuilder 相较于 StringBuffer 有速度优势,多数情况下建议使用 StringBuilder 类。然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。

三、三者的继承结构

子模块中的pom使用parent,可以直接获得父pom中的依赖,不用自己写

但如果父pom中使用了dependencyManagement,那么子模块需要引入自己需要的依赖,只是不用写版本号,版本号由父pom控制

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

参考:

https://www.cnblogs.com/youzhibing/p/5427130.html

https://www.liaoxuefeng.com/wiki/1252599548343744/1309301243117601

C 运算符的优先级和结合性

符号 操作类型 结合性
[ ] ( ) . -> ++ --(后缀) 表达式 从左到右
sizeof & * + - ~ ! ++ --(前缀) 一元 从右到左
typecasts 一元 从右到左
* / % 乘法 从左到右
+ - 加法 从左到右
<< >> 按位移动 从左到右
< > <= >= 关系 从左到右
== != 相等 从左到右
& 按位“与” 从左到右
^ 按位“异或” 从左到右
| 按位“与或” 从左到右
&& 逻辑“与” 从左到右
|| 逻辑“或” 从左到右
? : 条件表达式 从右到左
= *= /= %= += -= <<= >>= &= ^= |= 简单和复合赋值 从右到左
, 顺序计算 从左到右

1 运算符按优先级的降序顺序列出。 如果多个运算符出现在同一行或一个组中,则它们具有相同的优先级。

2 所有简单的和复合的赋值运算符都有相同的优先级。

参考:

https://docs.microsoft.com/zh-cn/cpp/c-language/precedence-and-order-of-evaluation?view=msvc-170