Coding & Life

求知若饥,虚心若愚

CentOS默认允许任何用户通过ssh登入,但是在企业应用中为了保证服务器的安全性一般不允许用户直接通过root用户登录,而是通过普通用户登录然后切换到root或者使用sudo权限来执行root用户命令

创建用户

创建普通用户

1
useradd wangweiye

为普通用户设置密码

1
passwd wangweiye

将普通用户移入wheel用户组

1
usermod -G wheel wangweiye

在Linux中wheel组类似于管理员组

这样就可以使用普通用户wangweiye来进行登录了,而且该用户拥有sudo权限

在一般情况下,一般用户通过执行su命令、输入正确的root密码,可以登录为root用户来对系统进行管理员级别的配置。但是,为了更进一步加强系统的安全性,有必要建立一个管理员的组,只允许这个组的用户来执行su命令登录为root用户,而让其他组的用户即使执行su输入了正确的root密码,也无法登录为root用户。在UNIX下,这个组的名称通常为wheel

如何配置只有wheel组的用户才能登录root用户呢?

  1. /etc/pam.d/su中的#auth required /lib/security/$ISA/pam_wheel.so use_uid注释去掉

  2. SU_WHEEL_ONLY yes添加到/etc/login.defs文件行末

禁止root用户ssh登录

修改配置文件

修改/etc/ssh/sshd_configPermitRootLogin设置为no即可

重启ssh服务

systemctl restart sshd.service重启ssh服务

给用户分配sudo权限

如果只想给用户sudo权限而不能切换root用户登录(不加入wheel组)

1
vim /etc/sudoers

pic
用ssh连接服务器经常遇到长时间不操作而被服务器踢出的情况,提示如下

Write failed: Broken pipe

方案一:客户端配置

/etc/ssh/ssh_config中添加配置

1
ServerAliveInterval 60

之后,当使用ssh时每隔60s客户端都会向服务端发送一个KeepAlive请求,避免被踢

方案二:服务端配置

/etc/ssh/sshd_config中添加配置

1
ClientAliveInterval 60

重启服务器后设置生效
注意:这种方式每一个连接服务器的客户端都受到影响,安全性会有一定的下降

pic

场景

客户端A想要免密登录服务器B

客户端A

生成SSH KEY

1
ssh-keygen -t rsa -C "your_email@example.com"

查看客户端公钥

1
cat ~/.ssh/id_rsa.pub

服务端B

生成SSH KEY

1
ssh-keygen -t rsa -C "your_email@example.com"

连接A-B

复制A的公钥到B的

1
~/.ssh/authorized_keys

重新登录

持续集成是什么?

互联网软件的开发和发布,已经形成了一套标准流程,最重要的组成部分就是持续集成(Continuous integration,简称CI)

持续集成的目的

让产品可以快速迭代,同时还能保持高质量

Jenkins是什么?

Jenkins是一个用Java编写的开源的持续集成工具,因此安装Jenkins必须有Java运行环境

Jenkins安装

官网下载Jenkins安装包,按照官网提示进行安装

安装常用插件

常用插件

创建密码

创建密码

注意:需要防火墙打开8080端口,Jenkins默认使用8080端口

Jenkins的配置

全局工具配置

  • 配置jdk
  • 配置maven

插件安装

Jenkins有很多插件已经被安装,其中Git plugin和Maven Integration plugin,publish over SSH是部署Spring Boot项目必备的插件

配置Credentials

配置成功后可以用ssh协议拉取git上的代码

问题:在mybatis中,0被认为是空字符串
解决:普通判断1. != null 2. != ‘’。当类型为Integer类型时只进行方式1的判断

数据安全高于一切

有时我们为了节省开支,并不会购买云数据库而是选择自建数据库,这时数据安全就极为重要。数据备份是保证安全最有效的方式

编写数据备份脚本

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
# /bin/bash
DB_NAME="exchange"
DB_USER="root"
DB_PASSWORD="abc123"
BIN_DIR="/usr/bin"
BACK_DIR="/root/data"
DATE="mysql-`date +'%Y%m%d-%H:%M:%S'`"
LogFile="$BACK_DIR"/dbbakup.log
BackNewFile=$DATE.sql

$BIN_DIR/mysqldump -u$DB_USER -p$DB_PASSWORD $DB_NAME > $BACK_DIR/$DATE.sql

echo -----------------"$(date +"%y-%m-%d %H:%M:%S")"------------------ >> $LogFile

echo createFile:"$BackNewFile" >> $LogFile

find "/root/data/" -ctime +0 -type f -name "*.sql" -print > deleted.txt

echo -e "delete files:\n" >> $LogFile

cat deleted.txt | while read LINE
do
rm -rf $LINE
echo $LINE>> $LogFile
done

echo "---------------------------------------------------------------" >> $LogFile

利用cron定时执行

利用cron服务定时执行数据备份脚本。该脚本会自动删除过期的sql文件
例如 每天12:50定时执行mysqlback.sh脚本:

1
50 12 * * * /root/mysqlback.sh

linux导入sql

1
mysql -h [host] -u [userName] -p [databaseName] < [data].sql

linux导出库

1
mysqldump -h [host] -u [username] -p --databases [databasename] > [fileName].sql

linux导出单表

1
mysqldump -h [host] -u [username] -p [dabaseName] [tableName] > [fileName].sql

更新了系统后,使用git命令,提示错误如下:

1
xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun

原因

因为每次更新系统之后xcode就被卸载了,因此需要重新安装一次

解决方案

终端执行

1
xcode-select --install

什么是sequence

序列,在Oracle数据库中,什么是序列呢?它的用途是什么?序列(SEQUENCE)其实是序列号生成器,可以为表中的行自动生成序列号,产生一组等间隔的数值(类型为数字)。其主要的用途是生成表的主键值,可以在插入语句中引用,也可以通过查询检查当前值,或使序列增至下一个值。

mysql没有内置sequence,需要自己实现

创建sequence表

1
2
3
4
5
6
CREATE TABLE sequence (
name VARCHAR(50) NOT NULL,
current_value INT NOT NULL,
increment INT NOT NULL DEFAULT 1,
PRIMARY KEY (name)
)

获取当前序列值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CREATE FUNCTION currval (seq_name VARCHAR(50))
RETURNS INTEGER
LANGUAGE SQL
DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
DECLARE value INTEGER;
SET value = 0;
SELECT current_value INTO value
FROM sequence
WHERE name = seq_name;
RETURN value;
END

获取下一个序列

1
2
3
4
5
6
7
8
9
10
11
12
13
CREATE FUNCTION nextval (seq_name VARCHAR(50))
RETURNS INTEGER
LANGUAGE SQL
DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
UPDATE sequence
SET current_value = current_value + increment
WHERE name = seq_name;
RETURN currval(seq_name);
END

重置序列值

1
2
3
4
5
6
7
8
9
10
11
12
13
CREATE FUNCTION setval (seq_name VARCHAR(50), value INTEGER)
RETURNS INTEGER
LANGUAGE SQL
DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
UPDATE sequence
SET current_value = value
WHERE name = seq_name;
RETURN currval(seq_name);
END

应用

1
2
3
4
5
6
7
// 在序列表中新建一条序列(参数依次为:序列名称、序列开始值、序列递增步长)
INSERT INTO sequence VALUES ('TestSeq', 0, 1);
// 设置序列开始值(参数依次为:序列名称、序列开始值)
SELECT SETVAL('TestSeq', 10);
SELECT CURRVAL('TestSeq');
// 获得下一个序列值
SELECT NEXTVAL('TestSeq');

server服务端

主线程

构建页面

创建serverSocket

添加send按钮的点击事件

子线程

死循环接收消息

服务端代码如下:

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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/**
* 主线程发送消息
* 子线程接收消息
*/
package com.yatai.web;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

/**
* @author 王伟业 2014年5月28日
*/
public class ChatServer implements ActionListener, Runnable {
// 用来存放客户端连接数量
public static ArrayList<Socket> socketList = new ArrayList<Socket>();
// 显示历史聊天记录
private JTextArea showArea;
// 待发送的字符区域
private JTextField msgText;
// 窗口
private JFrame mainJframe;
// 发送按钮
private JButton sentBtn;
// 滚动面板
private JScrollPane JSPane;
// 普通面板
private JPanel pane;
// 最大的容器
private Container con;
// 线程处理信息
private Thread thread = null;
private ServerSocket serverSocket;
private Socket connectToClient;
private DataInputStream inFromClient;
private DataOutputStream outToClient;

/**
* 构造函数用来设置界面,处理事件
*/
public ChatServer() {
// TODO Auto-generated constructor stub
// 设置页面
mainJframe = new JFrame("服务器端");
// 初始化容器
con = mainJframe.getContentPane();
showArea = new JTextArea();
showArea.setEditable(false); // 历史聊天窗口中的文字域不能编辑,只供查看
showArea.setLineWrap(true); // 自动换行
JSPane = new JScrollPane(showArea);
// 待发送文字区域
msgText = new JTextField();
msgText.setColumns(35);
// 事件监听
msgText.addActionListener(this);
sentBtn = new JButton("Send");
sentBtn.addActionListener(this);
// 界面下部
pane = new JPanel();
pane.setLayout(new FlowLayout());
pane.add(msgText);
pane.add(sentBtn);

con.add(JSPane, BorderLayout.CENTER);
con.add(pane, BorderLayout.SOUTH);
mainJframe.setSize(500, 400);
mainJframe.setLocation(600, 200);
mainJframe.setVisible(true);
mainJframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

try {
serverSocket = new ServerSocket(8888);
showArea.append(" 正在等待对话请求\n");
// 监听端口
connectToClient = serverSocket.accept();
inFromClient = new DataInputStream(connectToClient.getInputStream());
outToClient = new DataOutputStream(connectToClient.getOutputStream());
// 启动线程
thread = new Thread(this);
thread.setPriority(Thread.MIN_PRIORITY);
thread.start();
} catch (IOException e) {
// TODO Auto-generated catch block
// 出现此异常说明服务器未创建成功
showArea.append(" 对不起,不能创建服务器\n");
// 待发送文字区域不能编辑
msgText.setEditable(false);
// 发送按钮不可用
sentBtn.setEnabled(false);
}

}

/*
* (non-Javadoc)
*
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
// TODO Auto-generated method stub
// 此线程用来接收客户端传来的信息
while (true) {
try {
showArea.append(" 对方说:" + inFromClient.readUTF() + "\n");
Thread.sleep(1000);
} catch (IOException | InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}

/*
* (non-Javadoc)
*
* @see
* java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
// 响应按钮事件
String s = msgText.getText();
// 如果待发送文字区域存在文字
if (s.length() > 0) {
try {
// 将文字写入到流中
outToClient.writeUTF(s);
outToClient.flush();
// 历史聊天记录增添内容
showArea.append(" 我说:" + msgText.getText() + "\n");
// 待发送文字区域设为空
msgText.setText(null);
} catch (IOException e1) {
// TODO Auto-generated catch block
// 出现此异常说明消息未发送成功
showArea.append(" 你的消息:" + "“" + msgText.getText() + "”" + "未能发送成功\n");
}
}
}

public static void main(String[] args) {
// 主线程用来发送消息
new ChatServer();
}

}

client客户端

主线程

构建页面

连接serverSocket

添加send按钮的监听事件

子线程

死循环接收消息

客户端代码如下:

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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/**
*
*/
package com.yatai.web;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

/**
* @author 王伟业 2014年5月28日
*/
public class ChatClient implements ActionListener, Runnable {
// 相同的界面形式
private JTextArea showArea;
private JTextField msgText;
private JFrame mainJframe;
private JButton sentBtn;
private JScrollPane JSPane;
private JPanel pane;
private Container con;
// 相似的处理方法
private Thread thread = null;
private Socket connectToServer;
private DataInputStream inFromServer;
private DataOutputStream outToServer;

/**
*
*/
public ChatClient() {
// TODO Auto-generated constructor stub
// 构造函数下完成以下内容
mainJframe = new JFrame("客户端");
con = mainJframe.getContentPane();
showArea = new JTextArea();
showArea.setEditable(false);
showArea.setLineWrap(true);
showArea.setWrapStyleWord(true);
JSPane = new JScrollPane(showArea);
msgText = new JTextField();
msgText.setColumns(35);
msgText.addActionListener(this);
sentBtn = new JButton("Send");
sentBtn.addActionListener(this);
pane = new JPanel();
pane.setLayout(new FlowLayout());
pane.add(msgText);
pane.add(sentBtn);
con.add(JSPane, BorderLayout.CENTER);
con.add(pane, BorderLayout.SOUTH);
mainJframe.setSize(500, 400);
mainJframe.setLocation(80, 200);
mainJframe.setVisible(true);
mainJframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

try {
connectToServer = new Socket("localhost", 8888);
inFromServer = new DataInputStream(connectToServer.getInputStream());
outToServer = new DataOutputStream(connectToServer.getOutputStream());
showArea.append(" 连接成功,可以通信\n");

// 创建线程
thread = new Thread(this);
thread.setPriority(Thread.MIN_PRIORITY);
thread.start();
} catch (IOException e) {
// TODO Auto-generated catch block
// 出现异常说明连接失败
// 向历史聊天区域打印提示信息
showArea.append(" 对不起,连接服务器失败\n");
// 异常连接时输入框不可用
msgText.setEditable(false);
msgText.setEnabled(false);
}
}

/*
* (non-Javadoc)
*
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
// TODO Auto-generated method stub
// 该线程用来接收传来的消息
while (true) {
try {
showArea.append(" 对方说:" + inFromServer.readUTF() + "\n");
Thread.sleep(1000);
} catch (IOException | InterruptedException e) {
// TODO Auto-generated catch block
// 此处异常处理。。。。
e.printStackTrace();
}
}
}

/*
* (non-Javadoc)
*
* @see
* java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
// 响应事件
String s = msgText.getText();
// 如果待发送文字区域存在文字
if (s.length() > 0) {
try {
// 将文字写入到流中
outToServer.writeUTF(s);
outToServer.flush();
// 历史聊天记录增添内容
showArea.append(" 我说:" + msgText.getText() + "\n");
// 待发送文字区域设为空
msgText.setText(null);
} catch (IOException e1) {
// TODO Auto-generated catch block
// 出现此异常说明消息未发送成功
showArea.append(" 你的消息:" + "“" + msgText.getText() + "”" + "未能发送成功\n");
}
}
}

public static void main(String[] args) {
new ChatClient();
}
}
0%