如何使用postman进行API测试

最近接触了Postman API测试,业务上是需要写出来Postman脚本。以前可以说是从来都没有听说过脚本的事情,虽说也其实这个工具有一点了解,但是在这回实践之后才有了更多的理解。首先推荐大家学习一个Pluralsight的视频Postman Fundamentals,我只是有针对性的看了前一部分,就感觉收获良多。一个好的入门课程其实也是很重要的。

这里我就举例说一个spring security的用户验证的测试,其他的测试过程也是很相似的。

认证测试:

  • step1 在地址栏中输入自己API的地址(例子中是用户登陆认证的一个form)
  • step2 选择请求的方式,这个postman里面有很多,我这里选择的是POST
  • step3 在headers我们可以把Content-Type设置出来
  • step4 在body中加入需要请求的key和对应的value(这个例子中就是username、password,因为spring secutity的登陆认证机制只有验证登陆后才可以进行后续操作,否则就会报401未认证)
  • step5 在Tests中可以编写一些测试语句,以检查得到的Response body是否是你需要的

这个例子的Tests如下:

编写好测试界面中的测试语句,然后点击send,可以在下面的Tests Results中查看测试是否通过,例子中的就是测试全部通过了,如果有错误,下面的提示中会告知你哪个测试出错,以及为什么出错。

下面说一下这几个简单测试语句:

我想在开始之前提醒大家一件事,postman测试语句是需要很精准的,也就是说你写的测试语句需要可以精准的、直观的测试出返回的response是否符合预期,你的测试需要着眼于关键点。

状态码测试:

1
2
3
pm.test("Status code is 200", function () {
pm.response.to.have.status(200);
});

第一行中的”Status code is 200”是可以自己修改的,这一行字符串会在下面的控制台输出(可参照上图),这里建议要取一些有意义的字符串,可以见名知义那种。

第二行中的 200,就是你期望得到的状态码。

是否得到认证的测试:

第二行就是定义jsonData接受response中json数据,然后就是进行判断返回的字段是否是预期的。

1
2
3
4
pm.test("Your test user is authenticated", function () {
var jsonData = pm.response.json();
pm.expect(jsonData.authenticated).to.eql(true);
});

那么对比验证一下认证失败的情况:

我随便的设置了登录的用户名和密码,可以看到下方的Test results中3条都fail了,并且还有返回值的对比说明。

希望以上能对大家有所帮助。

如何在spring security中对用户密码进行加密

最近在实践中接触了spring security密码加密的相关内容。

以前在数据库中存入用户密码的时侯,选择的都是明文密码,没有任何的安全性,这种方式其实非常的危险。所以我们需要在用户注册时就对用户键入的密码进行加密,然后存储到数据库中。之后在用户登录的时候再对数据中的加密密码和用户键入的密码进行一个对比的验证。

这里不推荐使用spring security自带的PasswordEncoder方法进行加密,因为这样很容易被破解掉。推荐编写自己的加密方法,可以选择SHA-1,SHA-256等算法,然后也可以在密码加密之前中加入盐值salt。然后写自己的MyPasswordEncoder方法然后重写PasswordEncoder,实现encode,matches方法。

spring security自带的PasswordEncoder方法如下所示:

1
2
3
4
5
public interface PasswordEncoder {

String encode(CharSequence rawPassword);

boolean matches(CharSequence rawPassword, String encodedPassword);

我们可以看到这个PasswordEncoder接口有两个方法,encode的方法是加密,matches方法是比较初始密码加密后是否等于加密后的密码。

下面展示一个小的例子:新建自己的MyPasswordEncoder方法实现PasswordEncoder接口中的两个方法,这里我就写了一个encode的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class MyPasswordEncoder implements PasswordEncoder {

//加密算法
private static MyDigestAlgorithm myDigestAlgorithm;

String encodedPassword = "";
// add salt
String saltedPassword = Common.SALT + rawPassword.toString();
try {
//encrypt the password
encodedPassword = MyDigestAlgorithm.toHexString(MyAlgorithm.getSHA(saltedPassword));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}

return encodedPassword;
}
}
}

有了加密方法之后,就可以在service编写业务代码:简单来说就是,存入数据库之前把用户键入的密码加密,然后再存入数据库。例子如下所示:

1
2
3
4
5
6
public void addAccounts(Account account) {

account.setPassword(myPasswordEncoder.encode(account.getPassword()));
accountMapper.addAccounts(account);

}

因为我们是自己重写的PasswordEncoder方法,所以在spring security的config中,需要注入我们的加密类,否则登陆的时候就会认证失败。例子如下:

1
2
3
4
5
@Bean
public MyPasswordEncoder myPasswordEncoder(){

return new MyPasswordEncoder();
}

希望能对您有所帮助。

matlab运行速度优化

当我们需要处理较大数据量,或者程序中有一些较为复杂的逻辑。这个时候就需要对程序进行一定的优化,以下是一些小技巧与例子的展示。

硬件方面

1.提升电脑的配置

2.在Matlab软件中设置,分配更多的运行内存

代码方面:

  1. 数据格式double转成single

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    A_length = length(A);
    numbers = 50;
    for k = 1:numbers
    for i = 1:A_length
    for j = 1:A_length
    A(i,j) = A(i,j)*rand;
    end
    end
    end


    矩阵维度:1000*1000
    double:时间已过 1.700172 秒
    single:时间已过 1.546184 秒。

    矩阵维度:5000*5000
    double:时间已过 50.057981 秒。
    single:时间已过 45.139951 秒。
  1. 避免for循环

    code1:

    1
    2
    3
    4
    5
    6
    7
    y =[];
    number = 100000;
    for i =1:number
    y = [y sin(i)];
    end

    % 时间已过 2.749184 秒。

    code2:

    1
    2
    3
    4
    y =[];
    number = 100000;
    y = sin([1:1:number]);
    时间已过 0.001548 秒。
  1. 预先声明变量长度

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    number = 1000; %5000
    %%新建一个矩阵
    %这一句就是原先声明变量的长度
    A = zeros([number number]);

    for i =1:number
    for j =1:number
    if rand >0.5
    A(i,j) = 1;
    end
    end
    end


    1000*1000
    未声明:时间已过 0.237895 秒。
    已声明:时间已过 0.041581 秒。

    5000*5000
    未声明:时间已过 41.466290 秒。
    已声明:时间已过 0.962321 秒。

经过测试,可以看到预先分配数组的大小和避免使用for循环对运行速度的提升效果是非常好的,特别是当数据量越大的时候,效果也就越好。

希望对大家有所帮助。

解决Spring Boot入门遇到的一些问题

最近在Spring Boot入门学习中遇到了一些问题:

1: Your ApplicationContext is unlikely to start due to a @ComponentScan of the default package

需要把所有的代码移至其自己的包中。 如图所示:将所有的.java文件移至src / main / java / com / example中,并且在每个文件的顶部添加com.example包。我一开始就是偷懒了,所以报了错。

示例

2:This application has no explicit mapping for /error, so you are seeing this as a fallback.

这个问题就是:Application启动类的位置不对。需要要将Application类放在最外侧,即包含所有子包(如上图所示)

原因:Spring Boot会自动加载启动类所在包下及其子包下的所有组件.

解决centos7下报错:net/http: TLS handshake timeout

最近在使用CentOS 7按照官方网站的文档安装docker时遇到了一个问题:

当我运行这一句时

1
sudo docker run hello-world

出现了bug:

1
net/http: TLS handshake timeout

解决方案:

配置镜像,修改 /etc/docker/daemon.json 文件,如果没有可以新建一个文件,然后加入以下的docker镜像地址:

1
2
3
4
5
6
{
"registry-mirrors": [
"https://dockerhub.azk8s.cn",
"https://hub-mirror.c.163.com"
]
}

保存退出
然后重启docker

1
sudo systemctl restart docker

这里可以检查一下配置的镜像是否生效:

1
docker info

如果显示的配置信息的末尾部分出现如下字样,说明配置完成:

镜像字样示例

再次运行:

1
sudo docker run hello-world

出现以下的信息,证明问题已经解决了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
https://hub.docker.com/

For more examples and ideas, visit:
https://docs.docker.com/get-started/

软件开发实习生面经

视频面试是群面,挺新奇的。虽然这些信息我已经提前查到,但还是很紧张的。

每个人自我介绍:

每个人一分钟左右英文自我介绍。直接给我排第一个,而且这块明显练习不够,卡了好几次壳。

第一轮提问(接着自我介绍提问,英文):

因为我提到了闲暇时候写一些博客,面试官直接让发一下博客地址,并且问我github账号,也发一下。这一轮没有问我问题,问其他人的就是自我介绍时提到的一些内容,偏向于测评综合素质。

第二轮提问(中文):

这次是技术性的提问,一个人大概两三道问题。

问的其实有些深入,需要以前对这些问题进行过思考,只会应用是不够的。

问我的:

matlab还能用吗?(这个。。。)

路由器端口转发功能工作原理

Java int常量池的范围?

Exception父类是什么?

两道代码题:装箱拆箱、==、equals

最后问大家有什么问题想问的(就我问了一个问题)

我问了一下,面试官对于从事软件开发工作及发展的一些建议:他说尽量往全栈方向发展,可以偏向后端或者前端,但是如果只偏重某一个方向可能会对以后的发展有有所影响。。

总结:

英语口语还得练习,自我介绍需要多次练习。

Github要好好弄,blog是自己的脸面,提到了博客就好好的展示。

基础知识掌握的不足。

做项目、做比赛需要多考虑、多反思,不要实现功能就完事大吉。

如何对复杂网络建模所需要的数据进行预处理

上一篇文章介绍了如何构建Space L实体网络的模型,这一篇是对上一篇文章的一个补充优化。

以下部分摘自上一篇文章:如何建立复杂网络实体网络的Space L模型

地铁网络,一般都有三四百个节点,线路十几条左右,看地铁图的是一个眼花缭乱。若是人工统计出来数据也是一项大工程。看着就想放弃,但其实掌握一定的方法并没有那么的费劲。

  1. 按线路进行节点的统计,先编号,然后去除掉重合的节点
  2. 统计连接关系时有一定的规则:比如从左往右统计、从上往下统计,这样可以避免重复统计
  3. 不要直接列出邻接矩阵,先统计出连接关系生成邻接表,然后再转成邻接矩阵
  4. 关于邻接表,最好再检查一遍
  5. 以上工作最好分成数天进行,否则负荷工作效率低且出错率较高

可以看到,建模时候最头疼的就是数据的处理问题,运用以上的经验可以提升我们的效率,但是治标不治本,依旧会浪费掉我们大量的时间。其实,如果不考虑换乘站(重复节点),连接关系还是比较好统计的,比如一条线路有10个站点,按顺序分别为a、b、c….j,那么连接关系可以表示为下图的1-9列:

线路转化邻接表

最近有一个需求,要统计某市的公交网络,有300多条线路,大概有3000多节点。如果此时还按之前的办法:人工统计线路中的站点,然后进行编号的话,那整个工程量不仅巨大,并且在统计过程中也很容易出错。

所以可以让程序帮助我们去识别站点名称,然后依次给它们编号,这样就可以生成直接使用邻接表。

具体处理方式,可以大概分为以下几个步骤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
% 1.从xls文件中,读取数据(或者直接新建数据)
% rawDataNum是读取到的数值,可以是权重,数据类型:double
% rawDataStr是读取到的字符串,是邻接表,数据类型:cell

% 2.用b接收rawDataStr中的所有不重复的字符串,数据类型 cell

% 3.因为cell类型矩阵中存储的是字符串数据,不好处理
% 所以需要把b和rawDataStr转换为string数组b_str和raw_str
% 注意这里可以检查一下b_str中的字符串

%4.进行数据处理
test = [];

for i = 1:length(b_str)
for j = 1:length(raw_str)
%判断条件
if(raw_str(j,1) == b_str(i,1))
test(j,1) = i;
end


%判断条件
if(raw_str(j,2) == b_str(i,1))
test(j,2) = i;
end

end
end
%这时就可以得到邻接表test

%判断是否为无权网络,判断标准rawDataNum是否为空,这与你的初始数据有关
if(length(rawDataNum) ~= 0)
test = [test rawDataNum];
else
disp('无权网络')
end

%这一步就是把邻接表test直接转换为邻接矩阵A,
%可以参照:如何建立复杂网络实体网络的Space L模型中的函数
A = ainc2adj( test );
% 判断是否有孤立节点
if(length(find(~sum(A))))
disp('存在孤立节点')
end

测试邻接表:

结果:

邻接表

节点编号与名称对应关系:

可以看到效果还是不错的,而且不仅限于交通网络。对于一些较大型的实体网络,比如作者合作网络、社交网络,应该也会有不错的效果。欢迎大家与我进行交流,

该文章首发于:XuXing’s blog

复杂网络相关内容可以访问:复杂网络

如何建立复杂网络实体网络的Space L模型

复杂网络是一个非常庞大的研究领域,有众多研究方法与研究对象,社交网络、科学家网络、生物网络、交通网络、生物网络等等。在进行仿真时候,有的网络过于庞大无法用实际的数据进行仿真,例如社交网络。而有一些网络规模较小,就需要用实际的数据进行仿真了,例如交通网络。

那么无论网络规模大小,对这些网络进行研究的时候,第一步往往是建模,只有模型建好了后续的研究、仿真才好进行下去。建模后,可以对网络指标进行分析,可以分析网络的抗毁性等等。总之,建模总是第一步的。

下面我就分享一下,自己对于复杂网络中实体网络建模的一些经验,以地铁网络为例:

建模方法,一般有Space L、Space P、Space B、Space C法,比较常用的建模规则是Space L法。

地铁网络,一般都有三四百个节点,线路十几条左右,看地铁图的是一个眼花缭乱。若是人工统计出来数据也是一项大工程。看着就想放弃,但其实掌握一定的方法并没有那么的费劲。

  1. 按线路进行节点的统计,先编号,然后去除掉重合的节点
  2. 统计连接关系时有一定的规则:比如从左往右统计、从上往下统计,这样可以避免重复统计
  3. 不要直接列出邻接矩阵,先统计出连接关系生成邻接表,然后再转成邻接矩阵
  4. 关于邻接表,最好再检查一遍
  5. 以上工作最好分成数天进行,否则负荷工作效率低且出错率较高

下面给出 邻接表 转成 邻接矩阵的matlab函数代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function b  = ainc2adj( x )
% x为邻接表(可在工作区中新建数据),输出的b为邻接矩阵
% 此函数是通过邻接表生成临接矩阵的
if min(x(:))==0;
x=x+1;
end
d=length(x);
a=max(max(x));
b=zeros(a,a);

for i=1:d
if x(i,1)==x(i,2);
b(x(i,1),x(i,2))=0;
else
b(x(i,1),x(i,2))=1;
b(x(i,2),x(i,1))=1;
end
end

一般来讲生成邻接矩阵,我们就得到了实体网络的节点连接情况。但我们都知道,人工统计的难免会有一些错漏,而这个时候需要用Gephi软件帮助我们进行进一步的检验。关于Gephi如何导入数据,可以参考这一篇文章。导入之后,你会得到一张拓扑图,如下图所示:

但是这样的图,我们没有办法看出网络可能存有什么问题,需要进一步的操作。

点击布局中的,选择一个布局。选择Force Atlas,选择运行,图会发生变化:

我们会发现红圈部分的点与整体网络没有任何联系,而交通网络是一个整体,那就说明这几个节点的连接关系一定都有问题。那么如何查看这几个点是哪几个点呢?点击预览,然后打开显示标签,最后点下方的刷新,就显示出来了节点标号。

然后可以用鼠标滚轮放大,调节左侧的节点编号显示的颜色,就可以大概看出来是那些节点出现问题了。然后回去对着连接图和节点编号去找就可以了

这个软件生成的图也是非常漂亮的,大家可以试一试,节点颜色、大小,边的颜色、大小,都可以自己调节,还有很多计算网络指标的功能。那么这次的分享就到这里,感谢大家的时间。

欢迎大家与我交流。

matlab实现随机攻击网络边+蓄意攻击网络连边(3)

其实在前面已经介绍过随机进攻节点和蓄意进攻节点的原理,今天和大家说一下边攻击。其实原理都是类似的,只要改动之前的一些代码就可以完成这个操作的。如果没有看过前两篇文章,那么建议你先看一下,有助于理解原理。

前两篇地址:

matlab实现随机攻击网络节点+蓄意攻击网络节点(1)附github完整工程地址

matlab实现随机攻击网络节点+蓄意攻击网络节点(2)

我们首先应该了解删除连边和删除的节点的区别:

删除节点:删除该节点及与该节点所有相连的边。

删除连边:只删除该连边,而不改变节点的状态。

如果结合维度为N*N邻接矩阵A来说:

删除节点a:要删除A(a,:)和A(:,a)这一列一行,矩阵A变为(N-1)*(N-1)维度

删除节点a和节点b的连边:A(a,b) = 0;A(b,a) = 0;(邻接矩阵的对称性),矩阵A还是N*N维度。

知道了具体逻辑,那么下面就是代码实现了:

之前我们删除节点的代码片段为:

1
2
3
4
5
6
7
8
9
10
for i = 1:numDelete
A( Name_Struct.Node_Key_Degree(i),: ) = 0; %% 删除节点 Node_Key_Degree(i),用 0 占位,不能置空
A( :,Name_Struct.Node_Key_Degree(i) ) = 0;
AA = A;
AA( sum(A)==0,: ) = [];
AA( :,sum(A)==0 ) = [];
Con_Index_NetEff = testEglob( AA );

Eglob(i) = Con_Index_NetEff.Net_Eff_Mymod;
end

边攻击需要的数据准备:

邻接表:也就是网络中的所有连边关系 也就是下面的代码片段中的 biao(2*edge_number的矩阵)
边的排序关系:(可以是随机排序,可以是按某种参数进行的排序)下面的代码片段中的Node_edge_bet(1*edge_number的矩阵),就是根据边介数参数得到的边的排序

那么改动后的边攻击代码片段为:

1
2
3
4
5
6
7
8
9
10
11
A = A_Init;          %% 网络邻接矩阵 A
% numDelete:删除连边的数量
for i = 1:numDelete
%把要删除的边置为0
A( biao(1,Node_edge_bet(i)),biao(2,Node_edge_bet(i)) ) = 0;
%把对称位置的边也置为0
A( biao(2,Node_edge_bet(i)),biao(1,Node_edge_bet(i)) ) = 0;
AA = A;
Con_Index_NetEff = testEglob( AA );
Eglob_edge_bet(i) = Con_Index_NetEff.Net_Eff;
end

经过分析之后,我们可以得到一个推测或者说是结论:那就是边攻击每次只攻击一个边,对网络的影响较小(相对于节点攻击来说)。

感谢大家的时间,并希望以上的内容会对大家有所帮助。

算法学习笔记1:面向对象的数组

算法学习的笔记1,关于对象数组的一个工具类
该工具类可实现以下功能

获取数组的长度

在数组的末尾添加一个元素

打印所有元素到控制台

删除数组中的某个元素

获取某个元素

在指定位置插入一个元素

替换指定位置的元素

github工程地址

工具类代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package class3_array.utils;

import java.util.Arrays;

public class MyArray {
/*
用于存储数据的数组
*/
private int[] elements;

public MyArray(){
elements = new int[0];
}

/**
* 获取数组的长度
* @return
*/
public int size(){
return elements.length;
}

/**
* 往数组的末尾添加一个数
*/
public void add(int element){
//创建一个新的数组
int[] newArr = new int[elements.length + 1];

//把原数组中的元素复制到新数组中
for (int i = 0; i < elements.length; i++) {
newArr[i] = elements[i];
}

//把添加的元素放入新的数组中
newArr[newArr.length-1] = element;

//新数组替换旧数组
elements = newArr;
}

/**
* 打印所有元素到控制台
*/

public void show(){
System.out.println(Arrays.toString(elements));
}

/**
* 删除数组中的某个元素
*/
public void delete(int index){
//判断传入的下标
if (index < 0 || index > elements.length - 1){
throw new RuntimeException("下标越界");
}
//创建一个新的数组
int[] newArr = new int[elements.length -1];

//把原来数组删除之后的元素赋值给新的数组
for (int i = 0; i < newArr.length; i++) {
//想要删除元素前面的元素
if (i < index){
newArr[i] = elements[i];
//想要删除元素后面的元素
}else {
newArr[i] = elements[i + 1];
}
}

//把新数组替换旧数组
elements = newArr;
}

/**
* 获取某个元素
*
*/
public int get(int index){
//判断是否下标越界
if (index < 0 || index > elements.length - 1){
throw new RuntimeException("下标越界");
}
return elements[index];
}

/**
* 插入一个元素到指定位置
*/
public void insert(int index,int element){
//判断是否下标越界
if (index < 0 || index > elements.length){
throw new RuntimeException("下标越界");
}

//新建一个数组
int[] newArr = new int[elements.length + 1];

//把原有数组中的值复制到新数组中
for (int i = 0; i < elements.length; i++) {
//插入元素之前的元素
if (i < index){
newArr[i] = elements[i];
//插入位置之后的元素
}else {

newArr[i + 1] = elements[i];
}

}
//把要插入的元素方到指定位置
newArr[index] = element;

//新数组替换旧数组
elements = newArr;
}

/**
* 替换指定位置的元素
*/
public void set(int index,int element){
//判断是否下标越界
if (index < 0 || index > elements.length - 1){
throw new RuntimeException("下标越界");
}
elements[index] = element;
}
}

测试类代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package class3_array;

import class3_array.utils.MyArray;

public class TestMyArray {
public static void main(String[] args) {
//创建一个可变的数组
MyArray myArray = new MyArray();

//获取长度
int size = myArray.size();
myArray.show();

//往可变数组中添加一个元素
myArray.add(99);
myArray.add(98);
myArray.add(97);
//显示所有元素到控制台
myArray.show();

//删除某个元素
myArray.delete(1);
myArray.show();

//取出指定位置的元素
int element = myArray.get(1);
System.out.println(element);
System.out.println("=============");

//在指定位置插入元素
myArray.insert(2,96);
myArray.show();
System.out.println("============");

//替换指定位置的元素
myArray.set(0,100);
myArray.show();
System.out.println(myArray.size());
}
}

希望能对您有所帮助。

欢迎大家访问我的个人博客

© 2021 XuXing's blog All Rights Reserved. 本站访客数人次 本站总访问量
Theme by hiero