0%

一、是什么

GETPOST,两者是HTTP协议中发送请求的方法

GET

GET方法请求一个指定资源的表示形式,使用GET的请求应该只被用于获取数据

POST

POST方法用于将实体提交到指定的资源,通常导致在服务器上的状态变化或副作用

本质上都是TCP链接,并无差别

但是由于HTTP的规定和浏览器/服务器的限制,导致他们在应用过程中会体现出一些区别

二、区别

w3schools得到的标准答案的区别如下:

  • GET在浏览器回退时是无害的,而POST会再次提交请求。
  • GET产生的URL地址可以被Bookmark,而POST不可以。
  • GET请求会被浏览器主动cache,而POST不会,除非手动设置。
  • GET请求只能进行url编码,而POST支持多种编码方式。
  • GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
  • GET请求在URL中传送的参数是有长度限制的,而POST没有。
  • 对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
  • GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
  • GET参数通过URL传递,POST放在Request body中
参数位置

貌似从上面看到GETPOST请求区别非常大,但两者实质并没有区别

无论 GET 还是 POST,用的都是同一个传输层协议,所以在传输上没有区别

当不携带参数的时候,两者最大的区别为第一行方法名不同

POST /uri HTTP/1.1 \r\n

GET /uri HTTP/1.1 \r\n

当携带参数的时候,我们都知道GET请求是放在url中,POST则放在body

GET 方法简约版报文是这样的

1
2
GET /index.html?name=qiming.c&age=22 HTTP/1.1
Host: localhost

POST 方法简约版报文是这样的

1
2
3
4
5
POST /index.html HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded

name=qiming.c&age=22

注意:这里只是约定,并不属于HTTP规范,相反的,我们可以在POST请求中url中写入参数,或者GET请求中的body携带参数

参数长度

HTTP 协议没有BodyURL 的长度限制,对 URL 限制的大多是浏览器和服务器的原因

IEURL长度的限制是2083字节(2K+35)。对于其他浏览器,如Netscape、FireFox等,理论上没有长度限制,其限制取决于操作系统的支持

这里限制的是整个URL长度,而不仅仅是参数值的长度

服务器处理长 URL 要消耗比较多的资源,为了性能和安全考虑,会给 URL 长度加限制

安全

POST GET 安全,因为数据在地址栏上不可见

然而,从传输的角度来说,他们都是不安全的,因为 HTTP 在网络上是明文传输的,只要在网络节点上捉包,就能完整地获取数据报文

只有使用HTTPS才能加密安全

数据包

对于GET方式的请求,浏览器会把http headerdata一并发送出去,服务器响应200(返回数据)

对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok

并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次

一.修改redis.conf文件

1.把bind 127.0.0.1 -::1这一行注释掉

2.protected-mode 设置成no

3.将daemonize no 修改为 daemonize yes、

4.在# requirepass foobared下面加上requirepass 123456

二.开放端口

1.linux防火墙开放6379(默认)端口

2.如果是云服务器,在云服务器安全组开放端口


如果还不行,可能是启动redis方式不对(本人就是这样)

启动redis时,后面必须跟上redis的配置文件

下面是官方文件注释

1
2
3
4
# Note that in order to read the configuration file, Redis must be
# started with the file path as first argument:
#
# ./redis-server /path/to/redis.conf

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