背景:
windows系统下生成的jar包通过FTP上传到linux服务器,然后通过XShell进行jar包的发布,这样反复了几个月后,开发阶段需要频繁更新包的部署。个人觉得很繁琐,想一键式把这个工作做了,不想经常花时间发布。前几天去了解了下Docker+Jenkins的方式,但是过于麻烦,对我个人学习时间和成本比较高。从而衍生出想用自己比较拿手的C#编写一个小工具解决我这个问题
需求:windows环境jar包部署到linux服务器,一键操作
小工具:
界面
程序构建方式
1.通过Neget安装SSH.NET
2.后端代码
1.设计器代码
1 namespace Deploy
2 {
3 partial class DeployFrm
4 {
5 /// <summary>
6 /// Required designer variable.
7 /// </summary>
8 private System.ComponentModel.IContainer components = null;
9
10 /// <summary>
11 /// Clean up any resources being used.
12 /// </summary>
13 /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
14 protected override void Dispose(bool disposing)
15 {
16 if (disposing && (components != null))
17 {
18 components.Dispose();
19 }
20 base.Dispose(disposing);
21 }
22
23 #region Windows Form Designer generated code
24
25 /// <summary>
26 /// Required method for Designer support - do not modify
27 /// the contents of this method with the code editor.
28 /// </summary>
29 private void InitializeComponent()
30 {
31 this.label1 = new System.Windows.Forms.Label();
32 this.txtLocalFilePath = new System.Windows.Forms.TextBox();
33 this.label2 = new System.Windows.Forms.Label();
34 this.txtServerFilePath = new System.Windows.Forms.TextBox();
35 this.txtPort = new System.Windows.Forms.TextBox();
36 this.label8 = new System.Windows.Forms.Label();
37 this.IP = new System.Windows.Forms.Label();
38 this.label3 = new System.Windows.Forms.Label();
39 this.label4 = new System.Windows.Forms.Label();
40 this.txtPassword = new System.Windows.Forms.TextBox();
41 this.label5 = new System.Windows.Forms.Label();
42 this.txtUserName = new System.Windows.Forms.TextBox();
43 this.txtIP = new System.Windows.Forms.TextBox();
44 this.txtServerDirectory = new System.Windows.Forms.TextBox();
45 this.btnConnection = new System.Windows.Forms.Button();
46 this.btnUpload = new System.Windows.Forms.Button();
47 this.btnRun = new System.Windows.Forms.Button();
48 this.label7 = new System.Windows.Forms.Label();
49 this.txtLog = new System.Windows.Forms.TextBox();
50 this.btnSaveInfo = new System.Windows.Forms.Button();
51 this.btnStop = new System.Windows.Forms.Button();
52 this.SuspendLayout();
53 //
54 // label1
55 //
56 this.label1.AutoSize = true;
57 this.label1.Location = new System.Drawing.Point(23, 164);
58 this.label1.Name = "label1";
59 this.label1.Size = new System.Drawing.Size(89, 12);
60 this.label1.TabIndex = 0;
61 this.label1.Text = "LocalFilePath:";
62 //
63 // txtLocalFilePath
64 //
65 this.txtLocalFilePath.Location = new System.Drawing.Point(127, 157);
66 this.txtLocalFilePath.Name = "txtLocalFilePath";
67 this.txtLocalFilePath.Size = new System.Drawing.Size(125, 21);
68 this.txtLocalFilePath.TabIndex = 1;
69 //
70 // label2
71 //
72 this.label2.AutoSize = true;
73 this.label2.Location = new System.Drawing.Point(23, 200);
74 this.label2.Name = "label2";
75 this.label2.Size = new System.Drawing.Size(95, 12);
76 this.label2.TabIndex = 2;
77 this.label2.Text = "ServerFilePath:";
78 //
79 // txtServerFilePath
80 //
81 this.txtServerFilePath.Location = new System.Drawing.Point(127, 197);
82 this.txtServerFilePath.Name = "txtServerFilePath";
83 this.txtServerFilePath.Size = new System.Drawing.Size(125, 21);
84 this.txtServerFilePath.TabIndex = 3;
85 //
86 // txtPort
87 //
88 this.txtPort.Location = new System.Drawing.Point(127, 42);
89 this.txtPort.Name = "txtPort";
90 this.txtPort.Size = new System.Drawing.Size(125, 21);
91 this.txtPort.TabIndex = 28;
92 //
93 // label8
94 //
95 this.label8.AutoSize = true;
96 this.label8.Location = new System.Drawing.Point(23, 45);
97 this.label8.Name = "label8";
98 this.label8.Size = new System.Drawing.Size(35, 12);
99 this.label8.TabIndex = 27;
100 this.label8.Text = "Port:";
101 //
102 // IP
103 //
104 this.IP.AutoSize = true;
105 this.IP.Location = new System.Drawing.Point(23, 24);
106 this.IP.Name = "IP";
107 this.IP.Size = new System.Drawing.Size(23, 12);
108 this.IP.TabIndex = 19;
109 this.IP.Text = "IP:";
110 //
111 // label3
112 //
113 this.label3.AutoSize = true;
114 this.label3.Location = new System.Drawing.Point(23, 72);
115 this.label3.Name = "label3";
116 this.label3.Size = new System.Drawing.Size(101, 12);
117 this.label3.TabIndex = 20;
118 this.label3.Text = "ServerDirectory:";
119 //
120 // label4
121 //
122 this.label4.AutoSize = true;
123 this.label4.Location = new System.Drawing.Point(23, 97);
124 this.label4.Name = "label4";
125 this.label4.Size = new System.Drawing.Size(59, 12);
126 this.label4.TabIndex = 21;
127 this.label4.Text = "UserName:";
128 //
129 // txtPassword
130 //
131 this.txtPassword.Location = new System.Drawing.Point(127, 124);
132 this.txtPassword.Name = "txtPassword";
133 this.txtPassword.Size = new System.Drawing.Size(125, 21);
134 this.txtPassword.TabIndex = 26;
135 //
136 // label5
137 //
138 this.label5.AutoSize = true;
139 this.label5.Location = new System.Drawing.Point(23, 127);
140 this.label5.Name = "label5";
141 this.label5.Size = new System.Drawing.Size(59, 12);
142 this.label5.TabIndex = 22;
143 this.label5.Text = "Password:";
144 //
145 // txtUserName
146 //
147 this.txtUserName.Location = new System.Drawing.Point(127, 94);
148 this.txtUserName.Name = "txtUserName";
149 this.txtUserName.Size = new System.Drawing.Size(125, 21);
150 this.txtUserName.TabIndex = 25;
151 //
152 // txtIP
153 //
154 this.txtIP.Location = new System.Drawing.Point(127, 16);
155 this.txtIP.Name = "txtIP";
156 this.txtIP.Size = new System.Drawing.Size(125, 21);
157 this.txtIP.TabIndex = 23;
158 //
159 // txtServerDirectory
160 //
161 this.txtServerDirectory.Location = new System.Drawing.Point(127, 67);
162 this.txtServerDirectory.Name = "txtServerDirectory";
163 this.txtServerDirectory.Size = new System.Drawing.Size(125, 21);
164 this.txtServerDirectory.TabIndex = 24;
165 //
166 // btnConnection
167 //
168 this.btnConnection.Location = new System.Drawing.Point(286, 16);
169 this.btnConnection.Name = "btnConnection";
170 this.btnConnection.Size = new System.Drawing.Size(111, 57);
171 this.btnConnection.TabIndex = 29;
172 this.btnConnection.Text = "Connection";
173 this.btnConnection.UseVisualStyleBackColor = true;
174 this.btnConnection.Click += new System.EventHandler(this.btnConnection_Click);
175 //
176 // btnUpload
177 //
178 this.btnUpload.Location = new System.Drawing.Point(434, 16);
179 this.btnUpload.Name = "btnUpload";
180 this.btnUpload.Size = new System.Drawing.Size(117, 57);
181 this.btnUpload.TabIndex = 30;
182 this.btnUpload.Text = "Upload";
183 this.btnUpload.UseVisualStyleBackColor = true;
184 this.btnUpload.Click += new System.EventHandler(this.btnUpload_Click);
185 //
186 // btnRun
187 //
188 this.btnRun.Location = new System.Drawing.Point(440, 97);
189 this.btnRun.Name = "btnRun";
190 this.btnRun.Size = new System.Drawing.Size(111, 60);
191 this.btnRun.TabIndex = 33;
192 this.btnRun.Text = "Run";
193 this.btnRun.UseVisualStyleBackColor = true;
194 this.btnRun.Click += new System.EventHandler(this.btnRun_Click);
195 //
196 // label7
197 //
198 this.label7.AutoSize = true;
199 this.label7.Location = new System.Drawing.Point(29, 272);
200 this.label7.Name = "label7";
201 this.label7.Size = new System.Drawing.Size(29, 12);
202 this.label7.TabIndex = 34;
203 this.label7.Text = "Log:";
204 //
205 // txtLog
206 //
207 this.txtLog.Location = new System.Drawing.Point(127, 240);
208 this.txtLog.Multiline = true;
209 this.txtLog.Name = "txtLog";
210 this.txtLog.Size = new System.Drawing.Size(636, 171);
211 this.txtLog.TabIndex = 35;
212 //
213 // btnSaveInfo
214 //
215 this.btnSaveInfo.Location = new System.Drawing.Point(584, 16);
216 this.btnSaveInfo.Name = "btnSaveInfo";
217 this.btnSaveInfo.Size = new System.Drawing.Size(111, 57);
218 this.btnSaveInfo.TabIndex = 36;
219 this.btnSaveInfo.Text = "SaveInfo";
220 this.btnSaveInfo.UseVisualStyleBackColor = true;
221 this.btnSaveInfo.Click += new System.EventHandler(this.btnSaveInfo_Click);
222 //
223 // btnStop
224 //
225 this.btnStop.Location = new System.Drawing.Point(280, 97);
226 this.btnStop.Name = "btnStop";
227 this.btnStop.Size = new System.Drawing.Size(117, 57);
228 this.btnStop.TabIndex = 37;
229 this.btnStop.Text = "Stop";
230 this.btnStop.UseVisualStyleBackColor = true;
231 this.btnStop.Click += new System.EventHandler(this.btnStop_Click);
232 //
233 // DeployFrm
234 //
235 this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
236 this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
237 this.ClientSize = new System.Drawing.Size(790, 450);
238 this.Controls.Add(this.btnStop);
239 this.Controls.Add(this.btnSaveInfo);
240 this.Controls.Add(this.txtLog);
241 this.Controls.Add(this.label7);
242 this.Controls.Add(this.btnRun);
243 this.Controls.Add(this.btnUpload);
244 this.Controls.Add(this.btnConnection);
245 this.Controls.Add(this.txtPort);
246 this.Controls.Add(this.label8);
247 this.Controls.Add(this.IP);
248 this.Controls.Add(this.label3);
249 this.Controls.Add(this.label4);
250 this.Controls.Add(this.txtPassword);
251 this.Controls.Add(this.label5);
252 this.Controls.Add(this.txtUserName);
253 this.Controls.Add(this.txtIP);
254 this.Controls.Add(this.txtServerDirectory);
255 this.Controls.Add(this.txtServerFilePath);
256 this.Controls.Add(this.label2);
257 this.Controls.Add(this.txtLocalFilePath);
258 this.Controls.Add(this.label1);
259 this.Name = "DeployFrm";
260 this.Text = "DeployFrm";
261 this.Load += new System.EventHandler(this.DeployFrm_Load);
262 this.ResumeLayout(false);
263 this.PerformLayout();
264
265 }
266
267 #endregion
268
269 private System.Windows.Forms.Label label1;
270 private System.Windows.Forms.TextBox txtLocalFilePath;
271 private System.Windows.Forms.Label label2;
272 private System.Windows.Forms.TextBox txtServerFilePath;
273 private System.Windows.Forms.TextBox txtPort;
274 private System.Windows.Forms.Label label8;
275 private System.Windows.Forms.Label IP;
276 private System.Windows.Forms.Label label3;
277 private System.Windows.Forms.Label label4;
278 private System.Windows.Forms.TextBox txtPassword;
279 private System.Windows.Forms.Label label5;
280 private System.Windows.Forms.TextBox txtUserName;
281 private System.Windows.Forms.TextBox txtIP;
282 private System.Windows.Forms.TextBox txtServerDirectory;
283 private System.Windows.Forms.Button btnConnection;
284 private System.Windows.Forms.Button btnUpload;
285 private System.Windows.Forms.Button btnRun;
286 private System.Windows.Forms.Label label7;
287 private System.Windows.Forms.TextBox txtLog;
288 private System.Windows.Forms.Button btnSaveInfo;
289 private System.Windows.Forms.Button btnStop;
290 }
291 }
View Code
2.业务代码
using Renci.SshNet;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Windows.Forms;
namespace Deploy
{
public partial class DeployFrm : Form
{
public DeployFrm()
{
InitializeComponent();
deployBus.TxtLog = this.txtLog;
}
public static DeployBusness deployBus = new DeployBusness();
public Deploy GetDeploy()
{
DateTime dt = DateTime.Parse("2019-09-30");
if (DateTime.Now > dt)
{
throw new Exception("请联系shexun进行版本更新");
}
var deploy = new Deploy(this.txtIP.Text, this.txtPort.Text, this.txtServerDirectory.Text, this.txtUserName.Text, this.txtPassword.Text, this.txtLocalFilePath.Text, this.txtServerFilePath.Text, "");
return deploy;
}
public void LoadInfo()
{
var deploy = deployBus.ReadInfo();
if (deploy != null)
{
this.txtIP.Text = deploy.Host;
this.txtPort.Text = deploy.Port;
this.txtServerDirectory.Text = deploy.ServerDirectory;
this.txtUserName.Text = deploy.UserName;
this.txtPassword.Text = deploy.Password;
this.txtLocalFilePath.Text = deploy.LocalFilePath;
this.txtServerFilePath.Text = deploy.ServerFilePath;
}
}
private void btnUpload_Click(object sender, EventArgs e)
{
try
{
deployBus.Upload(GetDeploy());
}
catch (Exception ex)
{
deployBus.ShowLog(ex.Message);
}
}
private void btnRun_Click(object sender, EventArgs e)
{
try
{
deployBus.Run(GetDeploy());
}
catch (Exception ex)
{
deployBus.ShowLog(ex.Message);
}
}
private void btnSaveInfo_Click(object sender, EventArgs e)
{
try
{
deployBus.SaveInfo(GetDeploy());
}
catch (Exception ex)
{
deployBus.ShowLog(ex.Message);
}
}
private void DeployFrm_Load(object sender, EventArgs e)
{
try
{
LoadInfo();
}
catch (Exception ex)
{
deployBus.ShowLog(ex.Message);
}
}
private void btnStop_Click(object sender, EventArgs e)
{
try
{
deployBus.Stop(GetDeploy());
}
catch (Exception ex)
{
deployBus.ShowLog(ex.Message);
}
}
private void btnBackUp_Click(object sender, EventArgs e)
{
}
private void btnConnection_Click(object sender, EventArgs e)
{
try
{
deployBus.Connection(GetDeploy());
}
catch (Exception ex)
{
deployBus.ShowLog(ex.Message);
}
}
/// <summary>
/// 部署类
/// </summary>
[DataContract]
public class Deploy
{
public Deploy(string Host, string Port, string ServerDirectory, string UserName, string Password, string LocalFilePath, string ServerFilePath, string Log)
{
this.Host = Host != null ? Host.Trim() : null;
this.Port = Port != null ? Port.Trim() : null;
this.ServerDirectory = ServerDirectory != null ? ServerDirectory.Trim() : null;
this.UserName = UserName != null ? UserName.Trim() : null;
this.Password = Password != null ? Password.Trim() : null;
this.LocalFilePath = LocalFilePath != null ? LocalFilePath.Trim() : null;
this.ServerFilePath = ServerFilePath != null ? ServerFilePath.Trim() : null;
this.Log = Log != null ? Log.Trim() : null;
}
[DataMember]
public string Host { get; set; }
[DataMember]
public string Port { get; set; }
[DataMember]
public string ServerDirectory { get; set; }
[DataMember]
public string UserName { get; set; }
[DataMember]
public string Password { get; set; }
[DataMember]
public string LocalFilePath { get; set; }
[DataMember]
public string ServerFilePath { get; set; }
[DataMember]
public string Log { get; set; }
}
public class DeployBusness
{
public TextBox TxtLog { get; set; }
public emAction EmAction { get; set; }
public enum emAction { ___, Connection, Upload, BackUp, Run, Stop, SaveInfo, ReadInfo, Download }
public void ShowLog(string log)
{
string logStr = "";
logStr = EmAction.ToString();
var defaultNull = 10 - logStr.Length;
if (defaultNull > 0)
{
string temp = "";
for (int i = 0; i < defaultNull; i++)
{
temp += " ";
}
logStr += temp;
}
logStr += " => [ " + DateTime.Now.ToString() + " ] ";
logStr += log + "。\r\n";
if (this.TxtLog != null)
{
TxtLog.Text += logStr;
}
EmAction = emAction.___;
}
public bool Connection(Deploy deploy)
{
this.EmAction = emAction.Connection;
using (var client = new SftpClient(deploy.Host, int.Parse(deploy.Port), deploy.UserName, deploy.Password)) //创建连接对象
{
client.Connect(); //连接
this.ShowLog("连接服务器成功");
}
return true;
}
public bool BackUp(Deploy deploy)
{
//对应的服务未停止不能进行上传
this.EmAction = emAction.BackUp;
using (var client = new SftpClient(deploy.Host, int.Parse(deploy.Port), deploy.UserName, deploy.Password)) //创建连接对象
{
client.Connect(); //连接
var fileName = Path.GetFileName(deploy.ServerFilePath);
var changeDir = deploy.ServerFilePath.Replace(fileName, "");
client.ChangeDirectory(changeDir); //切换目录
//复制文件到新的文件目录
using (var fileStream = new FileStream(deploy.LocalFilePath, FileMode.Open))
{
this.ShowLog("正在上传文件,请稍等......");
client.BufferSize = 4 * 1024; // bypass Payload error large
client.UploadFile(fileStream, fileName); //上传文件
this.ShowLog("上传文件成功");
}
}
return true;
}
public bool Upload(Deploy deploy)
{
//对应的服务未停止不能进行上传
this.EmAction = emAction.Upload;
using (var client = new SftpClient(deploy.Host, int.Parse(deploy.Port), deploy.UserName, deploy.Password)) //创建连接对象
{
client.Connect(); //连接
var fileName = Path.GetFileName(deploy.ServerFilePath);
var changeDir = deploy.ServerFilePath.Replace(fileName, "");
client.ChangeDirectory(changeDir); //切换目录
using (var fileStream = new FileStream(deploy.LocalFilePath, FileMode.Open))
{
this.ShowLog("正在上传文件,请稍等......");
client.BufferSize = 4 * 1024; // bypass Payload error large
client.UploadFile(fileStream, fileName); //上传文件
this.ShowLog("上传文件成功");
}
}
return true;
}
public void Run(Deploy deploy)
{
this.EmAction = emAction.Run;
var con = new ConnectionInfo(deploy.Host, int.Parse(deploy.Port), deploy.UserName,
new AuthenticationMethod[]{
// Pasword based Authentication
new PasswordAuthenticationMethod(deploy.UserName,deploy.Password)
});
// Execute (SHELL) Commands
using (var sshclient = new SshClient(con))
{
sshclient.Connect();
this.ShowLog("连接服务器成功");
var psResevice = sshclient.CreateCommand("ps -ef").Execute();
var runList = new List<string>();
string[] lines = psResevice.Split('\n'); //用\n表示换行符 注意是char类型 分割行
var fileName = Path.GetFileName(deploy.ServerFilePath);
foreach (var item in lines)
{
if (item.Contains(fileName))
{
runList.Add(item);
this.ShowLog("找到服务:" + item);
}
}
foreach (var item in runList)
{
var temp = item.Substring(0, 15);
var pid = temp.Substring(4, 15 - 4).Trim();
//获取到PID
var msg = sshclient.CreateCommand("kill -9 " + pid).Execute();
this.ShowLog("关闭服务PID:" + pid);
}
//更新文件 成功后执行命令
var changeDir = deploy.ServerFilePath.Replace(fileName, "").TrimEnd('/');
var command = "nohup java -jar " + fileName + ">>m.out.log 2>&1 &";
var msg2 = sshclient.CreateCommand("cd " + changeDir + ";" + command).Execute();
this.ShowLog("启动服务成功");
}
}
public void Stop(Deploy deploy)
{
this.EmAction = emAction.Stop;
var con = new ConnectionInfo(deploy.Host, int.Parse(deploy.Port), deploy.UserName,
new AuthenticationMethod[]{
// Pasword based Authentication
new PasswordAuthenticationMethod(deploy.UserName,deploy.Password)
});
// Execute (SHELL) Commands
using (var sshclient = new SshClient(con))
{
sshclient.Connect();
var psResevice = sshclient.CreateCommand("ps -ef").Execute();
string[] lines = psResevice.Split('\n'); //用\n表示换行符 注意是char类型 分割行
var fileName = Path.GetFileName(deploy.ServerFilePath);
if (lines != null && lines.Length > 0)
{
this.ShowLog("存在" + lines.Length.ToString() + "个服务");
}
foreach (var item in lines)
{
if (item.Contains(fileName))
{
this.ShowLog("找到服务:" + item);
var temp = item.Substring(0, 15);
var pid = temp.Substring(4, 15 - 4).Trim();
//获取到PID
var msg = sshclient.CreateCommand("kill -9 " + pid).Execute();
}
}
psResevice = sshclient.CreateCommand("ps -ef").Execute();
lines = psResevice.Split('\n'); //用\n表示换行符 注意是char类型 分割行
var stopStatus = false;
foreach (var item in lines)
{
if (item.Contains(fileName))
{
stopStatus = true;
}
}
if (!stopStatus)
{
this.ShowLog("停止服务成功");
}
}
}
/// <summary>
/// 读取信息
/// </summary>
public Deploy ReadInfo()
{
this.EmAction = emAction.ReadInfo;
string path = AppDomain.CurrentDomain.BaseDirectory + @"Temp\Record\";
var defaultFileName = "Info.txt";
string fileFullPath = path + defaultFileName;
//加载对应的文件目录的所有文件
if (File.Exists(fileFullPath))
{
string info = File.ReadAllText(fileFullPath);
this.ShowLog("读取配置成功");
//反序列化
var deploy = MySerializer.JsonToObject<Deploy>(info);
return deploy;
}
return null;
}
/// <summary>
/// 保存信息
/// </summary>
public void SaveInfo(Deploy deploy)
{
this.EmAction = emAction.SaveInfo;
string path = AppDomain.CurrentDomain.BaseDirectory + @"Temp\Record\";
var fileFullPath = path + "Info.txt";
StreamWriter sw;
if (File.Exists(fileFullPath))
{
File.Delete(fileFullPath);
}
var info = MySerializer.ObjectToJson(deploy);
sw = File.CreateText(fileFullPath);
sw.WriteLine(info);
sw.Close();
this.ShowLog("保存配置成功");
}
}
public class MySerializer
{
/// <summary>
/// 将对象序列化为json字符串
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="t">实例</param>
/// <returns>json字符串</returns>
public static string ObjectToJson<T>(T t) where T : class
{
DataContractJsonSerializer formatter = new DataContractJsonSerializer(typeof(T));
using (MemoryStream stream = new MemoryStream())
{
formatter.WriteObject(stream, t);
string result = System.Text.Encoding.UTF8.GetString(stream.ToArray());
return result;
}
}
/// <summary>
/// json字符串转成对象
/// </summary>
/// <typeparam name="T">类型</typeparam>
/// <param name="json">json格式字符串</param>
/// <returns>对象</returns>
public static T JsonToObject<T>(string json) where T : class
{
DataContractJsonSerializer formatter = new DataContractJsonSerializer(typeof(T));
using (MemoryStream stream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(json)))
{
T result = formatter.ReadObject(stream) as T;
return result;
}
}
}
}
}
View Code
总结:此工具我已分享给小组的开发同事一起使用,目前也有考虑在此基础上增加新的小功能,有兴趣的朋友请评论留言。
链接:https://pan.baidu.com/s/15HpNjKDBiuLf7mNgSlbDFw
提取码:pk5n