初学时,有了想法却完全不知道该从何下指,此序列将抛砖引玉,与大家共同学习进步。

  一个程序的初始,必然是启动。

  我的要求:

  1、应用程序保持单例;

  2、从配置文件加载一些基础数据进行初始化;

  3、显示软件的LOGO页面;

  4、判断应用程序是否有更新;

  4、进入用户登录界面;

  5、用户成功登录后显示主界面。

  

  如上图,基本达成目标,这个项目也是很简单的结构:

看窗体名称就知道各自的用途了。主要的Program.cs代码如下:

    static class Program
{
public static bool 切换用户 = false; /// <summary>
/// 主体框架应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
string 实例标识 = Assembly.GetExecutingAssembly().GetName().Name + "_SingtonB20";
Mutex mutex = new Mutex(true, 实例标识, out bool 单实例);
if (!单实例)
{
唤醒进程(实例标识);
return;
} Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.DoEvents(); //初始化全局DS
if (GlbInfo.DSGlb == null) GlbInfo.DSGlb = new System.Data.DataSet();
else
{
GlbInfo.DSGlb.Clear();
GlbInfo.DSGlb.Tables.Clear();
} //加载全局多语言资源
try
{
AppInit.CreateDT_MulLang(AppInfo.GetFile(AppInfo.AppFile.MulMessage), "Message_Core");
AppInit.CreateDT_MulLang(AppInfo.GetFile(AppInfo.AppFile.MulSurface), "Surface_Core");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
Environment.Exit();
} //展示闪屏窗体
Fm20Splash 闪屏窗 = new Fm20Splash();
闪屏窗.ShowDialog(); //系统检测正常则显示登录界面,否则退出应用
if (闪屏窗.DialogResult == DialogResult.OK)
{
显示登录:
切换用户 = false;
Fm20Login fmLogin = new Fm20Login();
fmLogin.ShowDialog();
if (fmLogin.DialogResult == DialogResult.OK)
{
Application.Run(new Fm20Main());
}
else
{
Application.Exit();
}
//当关闭主程序的时候会执行这个代码,在关闭主程序的时候需要给IsLogin 设置成true
//重新回到登录窗口.
if (切换用户)
{
goto 显示登录;
} }
else
{
Application.Exit();
} }
public static void 唤醒进程(string 进程名称)
{
try
{
Process proc = Process.GetCurrentProcess(); string assemblyName = Assembly.GetExecutingAssembly().GetName().Name + 进程名称; foreach (Process 进程 in Process.GetProcessesByName(进程名称))
{
if (proc.Id != 进程.Id)
{
IntPtr hWnd = 进程.MainWindowHandle;
if (WinAPI.IsIconic(hWnd))
{
WinAPI.ShowWindowAsync(hWnd, WinAPIConst.SW_RESTORE);
}
WinAPI.SetForegroundWindow(hWnd);
return;
}
}
}
catch
{
}
} }

Program.cs

一、第一个被运行的窗体(闪屏窗口):

    /// <summary>
/// Splash闪屏窗体
/// </summary>
public partial class Fm20Splash : Fm11Base
{
/// <summary>
/// 创建闪屏窗体
/// </summary>
public Fm20Splash()
{
InitializeComponent();
OINI oINI = new OINI(AppInfo.GetFile(AppInfo.AppFile.ConfigCore));
GlbInfo.Language = oINI.ReadString("Global", "CurrentLang", "LL");
string licCompany = oINI.ReadString("Global", "License_To_" + GlbInfo.Language, "所有人");
LabLicTo.Text = MultiLang.Surface(this, "LabLicTo", "授权给: ") + licCompany;
if (GlbInfo.Language == "LL") LabSysTitle.Text = "IMES (智能制造执行系统)"; else LabSysTitle.Text= "IMES (Intelligent Manufacturing Execution System)";
} private void Fm20Splash_MouseDown(object sender, MouseEventArgs e)
{
WinAPI.ReleaseCapture();
WinAPI.SendMessage(Handle, WinAPIConst.WM_SYSCOMMAND, WinAPIConst.SC_MOVE + WinAPIConst.HTCAPTION, );
} private static bool Delay(int delayTime)
{
DateTime now = DateTime.Now;
int s;
do
{
TimeSpan spand = DateTime.Now - now;
s = spand.Seconds;
Application.DoEvents();
}
while (s < delayTime);
return true;
} private void Fm20Splash_Shown(object sender, EventArgs e)
{
//开始检测系统配置是否符合要求
//检测1:FRAMEWORK
//检测2:检查组件资源
#region 检测1:检测更新
SetMainStatus(MultiLang.Surface(this, "ChkAppVersion","正在检查系统版本..."));
Delay(); string localPath = AppDomain.CurrentDomain.BaseDirectory;
localPath = localPath.Substring(, localPath.Length - );
string updateTxtFile = localPath + @"\UpdateLog.txt";
//当更新指引文件不存在(如调试时),将跳过自动更新检测.
if (File.Exists(updateTxtFile))
{
string[] allLines = File.ReadAllLines(localPath + @"\UpdateLog.txt"); string remotePath = string.Empty;
foreach (string line in allLines)
{
if (line.IndexOf("UpdatePath=") >= )
{
remotePath = line.Substring(line.IndexOf("UpdatePath=") + );
break;
}
} if (NeedUpdate(localPath, remotePath))
{
File.Delete(localPath + "\\" + @"A19.exe");
File.Copy(remotePath + "\\" + @"A19.exe", localPath + "\\" + @"A19.exe", true); string updFile = AppDomain.CurrentDomain.BaseDirectory + @"A19.exe";
Process.Start(updFile);
DialogResult = DialogResult.Cancel;
Application.Exit();
}
}
#endregion #region 清理过期插件版本,只保留最近的一项
//根目录下不存在DLL或EXE原文件,则查找日期最后面的文件作为加载文件
//查找M开头的exe和dll文件,规划M2-M8为模组EXE命名区域.如M22,M88
var modFiles = Directory.GetFiles(AppDomain.CurrentDomain.BaseDirectory).Select(f => new FileInfo(f)).Where(f => ((f.Name.IndexOf("M") == ) && f.Name.IndexOf("--") == ) && (f.Name.IndexOf(".exe") >= || f.Name.IndexOf(".dll") >= )).OrderBy(f => f.Name);
string prevFileSpl = string.Empty;
FileInfo ofi = null;
foreach (var s in modFiles)
{
if (!string.IsNullOrEmpty(prevFileSpl))
{
if (s.Name.Substring(, s.Name.IndexOf("--")) == prevFileSpl.Substring(, prevFileSpl.IndexOf("--")))
{
if (s.LastWriteTime >= ofi.LastWriteTime)
{
ofi.Delete();
}
else
{
s.Delete();
}
}
}
ofi = s;
prevFileSpl = s.Name;
} #endregion DialogResult = DialogResult.OK;
}
/// <summary>
/// 判断程序是否需要更新
/// </summary>
/// <param name="localPath"></param>
/// <param name="remotePath"></param>
/// <returns></returns>
private bool NeedUpdate(string localPath, string remotePath)
{
try
{
FileInfo fiUL = new FileInfo(localPath + @"\UpdateLog.txt");
FileInfo fiUR = new FileInfo(remotePath + @"\UpdateLog.txt");
if (fiUL.LastWriteTime == fiUR.LastWriteTime)
{
SetMainStatus(MultiLang.Surface(this, "ChkAppVersion","正在检查系统版本...") + "OK!");
return false;
}
else
{
return true;
}
}
catch (Exception)
{
//出错将返回false,比如:没有设置好更新路径。
return false;
}
}
}

Fm20Splash.cs

它继承自一个基类窗体Fm11Base,默认会做一些例如加载多语言文本的事情,没这个需求直接继承Form也可以。

二、这个页面通过后(有更新的话会跳到自动更新程序,可以忽略),会进入到登录窗体:

    /// <summary>
/// 登录窗体
/// </summary>
public partial class Fm20Login : Fm11Base
{
bool IsLogin = false;
protected internal string SelAccountNO ;
protected internal string SelAccountName ;
private static readonly string DftAESKeyOfDlls = @"James/Wang/"; private bool m_aeroEnabled;
private static Fm20LoginTitle fm20LoginTitle; public string UserID
{
get { return TxtUserID.Text; }
set { TxtUserID.Text = value; }
} public Fm20Login()
{
m_aeroEnabled = false;
InitializeComponent();
fm20LoginTitle = new Fm20LoginTitle(); } #region 无边框窗体处理
/// <summary>
/// 拖动无边框窗体
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnFormDrag(object sender, MouseEventArgs e)
{
WinAPI.ReleaseCapture();
WinAPI.SendMessage(Handle, WinAPIConst.WM_SYSCOMMAND, WinAPIConst.SC_MOVE + WinAPIConst.HTCAPTION, );
} protected override CreateParams CreateParams
{
get
{
m_aeroEnabled = CheckAeroEnabled();
CreateParams cp = base.CreateParams;
if (!m_aeroEnabled)
cp.ClassStyle |= WinAPIConst.CS_DropSHADOW;
return cp;
}
} private bool CheckAeroEnabled()
{
if (Environment.OSVersion.Version.Major >= )
{
int enabled = ;
WinAPI.DwmIsCompositionEnabled(ref enabled);
return (enabled == ) ? true : false;
}
return false;
} protected override void WndProc(ref Message m)
{
base.WndProc(ref m); switch (m.Msg)
{
case WinAPIConst.WM_NCPAINT:
if (m_aeroEnabled)
{
var v = ;
WinAPI.DwmSetWindowAttribute(this.Handle, , ref v, );
WinAPIConst.MARGINS margins = new WinAPIConst.MARGINS()
{
bottomHeight = ,
leftWidth = ,
rightWidth = ,
topHeight =
};
WinAPI.DwmExtendFrameIntoClientArea(this.Handle, ref margins); }
break;
default:
break;
} if (m.Msg == WinAPIConst.WM_NCHITTEST && (int)m.Result == WinAPIConst.HTCLIENT)
m.Result = (IntPtr)WinAPIConst.HTCAPTION; } #endregion private void MitClose_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
} private void MitMini_Click(object sender, EventArgs e)
{
WindowState = FormWindowState.Minimized;
} private void Fm20Login_Shown(object sender, EventArgs e)
{
if (!fm20LoginTitle.Visible)
{
fm20LoginTitle.Show(this);
}
else
{
fm20LoginTitle.BringToFront();
}
fm20LoginTitle.Left = this.Left + this.Width / - fm20LoginTitle.Width / ;
fm20LoginTitle.Top = this.Top + SplPnlMain.Panel1.Height - fm20LoginTitle.Height / ;
} private void Fm20Login_Move(object sender, EventArgs e)
{
fm20LoginTitle.Left = this.Left + this.Width / - fm20LoginTitle.Width / ;
fm20LoginTitle.Top = this.Top + SplPnlMain.Panel1.Height - fm20LoginTitle.Height / ;
} private void Fm20Login_Load(object sender, EventArgs e)
{
try
{
LabStsVersion.Text = "Version: " + this.ProductVersion;
TstMILangLL.Checked = (GlbInfo.Language == "LL");
TstMILangLI.Checked = !TstMILangLL.Checked;
PicLogo.Image = Image.FromFile(AppInfo.GetPath(AppInfo.AppPath.Image) + @"\App\LoginLd.png");
//读取上一次记住的用户名
OINI oPIniFile = new OINI(AppInfo.GetFile(AppInfo.AppFile.ConfigCore));
TxtUserID.Text = oPIniFile.ReadString("Login", "LastUserID", string.Empty);
SetMainStatus("..");
}
catch (Exception)
{
}
} private void TxtUserCode_TextChanged(object sender, EventArgs e)
{
CmdClearUser.Visible = !(string.IsNullOrEmpty(TxtUserID.Text.Trim()));
} private void TxtUserCode_Enter(object sender, EventArgs e)
{
PicFeedUser.BackgroundImage= Properties.Resources.LoginUserB;
} private void TxtUserCode_Leave(object sender, EventArgs e)
{
PicFeedUser.BackgroundImage = Properties.Resources.LoginUserH;
} private void TxtUserPass_TextChanged(object sender, EventArgs e)
{
CmdClearPwd.Visible = !(string.IsNullOrEmpty(TxtUserPass.Text.Trim()));
} private void TxtUserPass_Enter(object sender, EventArgs e)
{
PicFeedLock.BackgroundImage = Properties.Resources.LoginPwdB;
} private void TxtUserPass_Leave(object sender, EventArgs e)
{
PicFeedLock.BackgroundImage = Properties.Resources.LoginPwdH;
} private void CmdClearUser_Click(object sender, EventArgs e)
{
TxtUserID.Clear();
} private void CmdClearPwd_Click(object sender, EventArgs e)
{
TxtUserPass.Clear();
}
private void SetLanguage(string tagLang)
{
try
{
OINI oINI = new OINI(AppInfo.GetFile(AppInfo.AppFile.ConfigCore));
oINI.WriteString("Global", "CurrentLang", tagLang);
TstMILangLL.Checked = (tagLang == "LL");
TstMILangLI.Checked = !TstMILangLL.Checked;
GlbInfo.Language = tagLang;
InitObjectsText(this);
}
catch (Exception)
{
throw;
}
}
private void TstMILangLL_Click(object sender, EventArgs e)
{
SetLanguage("LL");
} private void TstMILangLI_Click(object sender, EventArgs e)
{
SetLanguage("LI"); } private void CmdLogin_Click(object sender, EventArgs e)
{
string tmpSts1 = MultiLang.Surface(this, "VeriUser", "正在验证用户...");
SetMainStatus(tmpSts1); try
{
string postUserID = TxtUserID.Text;
string postUserPass = TxtUserPass.Text;
if (string.IsNullOrEmpty(postUserID) || string.IsNullOrEmpty(postUserPass))
{
MyMsg.Information("T.201001/用户名和密码不能为空.");
TxtUserID.Focus();
return;
}
if ((SelAccountNO == "DEMOH") )
{
MyMsg.Warning("T.201002/此帐套尚未开放,请选择其它帐套.");
return;
} if (SelAccountNO == "DEMO")
{
MyMsg.Warning("T.201003/您登录的是演示库,数据可能随时丢失,如需正式作业,请登录NORMAL正式库.");
}
string connStrCurAct = GetConnStrFromCfg(SelAccountNO, "ConnStr");
string connStrExt1 = GetConnStrFromCfg(SelAccountNO, "ConnStrExt1");
string connStrExt2 = GetConnStrFromCfg(SelAccountNO, "ConnStrExt2");
string connStrExt3 = GetConnStrFromCfg(SelAccountNO, "ConnStrExt3");
string connStrExt4 = GetConnStrFromCfg(SelAccountNO, "ConnStrExt4");
string connStrExt5 = GetConnStrFromCfg(SelAccountNO, "ConnStrExt5");
this.Cursor = Cursors.WaitCursor;
#region 用户ERP登录验证部分
DBContext dBContext = new DBContext(connStrCurAct);
if (!dBContext.IsConnected)
{
MyMsg.Error("T.1010/数据库连接已经创建,但无法开启!", dBContext.ConnectErrorMessage);
return;
} postUserPass = OCrypto.AES16Encrypt(postUserPass, DftAESKeyOfDlls);
SqlParameter[] paras = new SqlParameter[]
{
new SqlParameter("@UserID", postUserID),
new SqlParameter("@PasswordHash", postUserPass)
};
string sqlText= "SELECT U.*, D.DeptCode, D.DeptNameLL, D.DeptNameLI FROM SYS_User AS U LEFT OUTER JOIN Base_Department AS D ON U.DeptRKEY = D.DeptRKEY WHERE (U.UserID= @UserID) AND (U.PasswordHash= @PasswordHash)";
DataTable tmpDTUInfo = dBContext.SqlToDT(sqlText, paras);
if (tmpDTUInfo.Rows.Count > )
{
DataRow drUser = tmpDTUInfo.Rows[];
if (!OString.NZ2Bool(drUser["IActived"]))
{
IsLogin = false;
SetMainStatus(MultiLang.Surface(this, "LoginFail1", "登录失败(帐号未激活),请联系管理员!"));
}
else if (OString.NZ2Bool(drUser["ILocked"]))
{
IsLogin = false;
SetMainStatus(MultiLang.Surface(this, "LoginFail2", "登录失败(帐号被锁定),请联系管理员!"));
}
else
{
GlbInfo.User.UserID = OString.NZ2Str(drUser["UserID"]);
GlbInfo.User.UserNameLL = OString.NZ2Str(drUser["UserNameLL"]);
GlbInfo.User.IsAdmin = OString.NZ2Bool(drUser["Hero"]);
GlbInfo.User.RolesUserIDS = OString.NZ2Str(drUser["RolesUserIDS"]);
GlbInfo.User.RightsList.Clear();
IsLogin = true;
}
}
else
{
IsLogin = false;
SetMainStatus(MultiLang.Surface(this, "LoginFail3", "登录失败(帐号不存在),请重新尝试!"));
} if (IsLogin)
{
GlbInfo.ActNO = SelAccountNO;
GlbInfo.ActName = SelAccountName;
GlbInfo.ConnStrCurAct = connStrCurAct;
GlbInfo.ConnStrExt1 = connStrExt1;
GlbInfo.ConnStrExt2 = connStrExt2;
GlbInfo.ConnStrExt3 = connStrExt3;
GlbInfo.ConnStrExt4 = connStrExt4;
GlbInfo.ConnStrExt5 = connStrExt5;
fm20LoginTitle.Close();
if (ChkRemember.Checked)
{
try
{
//记录下登录用户,以便下次不必输入用户名
OINI oPIniFile = new OINI(AppInfo.GetFile(AppInfo.AppFile.ConfigCore));
oPIniFile.WriteString("Login", "LastUserID", postUserID);
}
catch (Exception)
{
}
} DialogResult = DialogResult.OK;
}
else
{
TxtUserPass.Text = string.Empty;
TxtUserPass.Focus();
MyMsg.Warning("T.201004/用户名或密码错误,请检查.");
}
#endregion }
catch (Exception ex)
{
SetMainStatus(tmpSts1 + "出现异常!");
MyMsg.Exclamation(ex.Message);
}
finally
{
this.Cursor = Cursors.Default;
}
} /// <summary>
/// 从配置文件中获取指定帐套数据库连接字符串(已加密)
/// </summary>
/// <param name="actNO">帐套代码</param>
/// <param name="tKey">定义的连接串Key</param>
/// <returns></returns>
private string GetConnStrFromCfg(string actNO, string tKey)
{
try
{
StringCollection Idents = new StringCollection();
OINI oINI = new OINI(AppInfo.GetFile(AppInfo.AppFile.ConfigCore));
return oINI.ReadString("Account:" + actNO, tKey, string.Empty);
}
catch (Exception ex)
{
MyMsg.Error(ex.Message);
return string.Empty;
}
} private void LabChkRemember_DoubleClick(object sender, EventArgs e)
{
try
{
//记录下登录用户,以便下次不必输入用户名
OINI oPIniFile = new OINI(AppInfo.GetFile(AppInfo.AppFile.ConfigCore));
oPIniFile.WriteString("Login", "LastUserID", string.Empty);
MyMsg.Information("已经清除登录历史,下次登录将不再显示当前帐号名称.");
}
catch (Exception)
{
}
}
}

Login.cs

登录界面是一个起点,涉及到文件操作以及数据库的连接/存取,下次再分解。

C# Winform下一个热插拔的MIS/MRP/ERP框架11(启航)的更多相关文章

  1. C# Winform下一个热插拔的MIS/MRP/ERP框架13(窗体基类)

    作为一个ERP数据处理框架,大部分的开发场景都差不多. 理想中,对于通用数据处理,我的步骤如下: 1.为窗体指定数据来源(数据表/查询等): 2.拖入编辑控件,指定绑定字段: 3.结束. 为此,我设计 ...

  2. C# Winform下一个热插拔的MIS/MRP/ERP框架15(窗体基类场景1)

    最基础的窗体基类其实是通过应用场景反推的结构. 以下是场景一: 单表应用,普通的数据,比如单位/颜色/特殊字典等使用者少的,无需过多控制的可以使用一个数据表格来管理. 和Excel表格差不多,批量修改 ...

  3. C# Winform下一个热插拔的MIS/MRP/ERP框架14(自动更新)

    对于软件来说,启用自动更新是非常必要的. 根据软件的应用场景,我们可以设计不同的更新模型. 目前,IMES框架运行在.Net framework 4.0下面,使用的Win系统版本在Win7,域内管控, ...

  4. C# Winform下一个热插拔的MIS/MRP/ERP框架12(数据处理基类)

    作为ERP等数据应用程序,数据库的处理是重中之重. 在框架中,我封装了一个数据库的基类,在每个模组启动或窗体启动过程中,实例化一个基类即可调用CRUD操作(create 添加read读取 update ...

  5. C# Winform下一个热插拔的MIS/MRP/ERP框架(通用控件)

    一直对商业控件不感冒, 结合日常工作, 我写了几个常用控件. 一.下拉框控件(仿Access下拉框:F4下拉,自动输入,支持单/多列显示),可在Datagridview中使用. 1.常规: 2.Dat ...

  6. C# Winform下一个热插拔的MIS/MRP/ERP框架(简介)

    Programmer普弱哥们都喜欢玩自己的框架,我也不例外. 理想中,这个框架要易于理解.易于扩展.易于维护:最重要的,易于CODING. 系统是1主体框架+N模组的多个EXE/DLL组成的,在主体框 ...

  7. C# Winform下一个热插拔的MIS/MRP/ERP框架(多语言方案)

    个别时候,我们需要一种多语种切换方案. 我的方案是这样的: 1.使用文本文本存储多语言元素,应用程序启动时加载到内存表中: 2.应用程序启动时从配置文件加载语种定义: 3.所有窗体继承自一个Base基 ...

  8. C# Winform下一个热插拔的MIS/MRP/ERP框架16(窗体基类场景2)

    如果没有特别需求,和场景1一样只变更表名,主键字段,检测字段等名称,不需要写其它代码了. * 清单列表+单笔编辑/保存,适用于大多数基础资料管理以及简单的单据资料录入(当然,排版是要改一改的): * ...

  9. [C#]Winform下回车或Tab键自动切换下一个控件焦点

    满足用户体验,在数据录入时,能在输入完一个信息后通过回车或Tab键自动的切换到下一个控件(字段). 在界面控件设计时,默认可以通过设置控件的TabIndex来实现.但在布局调整时或者是对输入的内容有选 ...

随机推荐

  1. PCA主成分分析 ICA独立成分分析 LDA线性判别分析 SVD性质

    机器学习(8) -- 降维 核心思想:将数据沿方差最大方向投影,数据更易于区分 简而言之:PCA算法其表现形式是降维,同时也是一种特征融合算法. 对于正交属性空间(对2维空间即为直角坐标系)中的样本点 ...

  2. Python中常见的异常处理

    异常和错误 part1:程序中难免出现错误,而错误分成两种 1. 语法错误(这种错误,根本过不了Python解释器的语法检测,必须在程序执行前就改正) # 语法错误示范一 if # 语法错误示范二 d ...

  3. JBPM具体应用之decision节点的使用

    JBPM工作流引擎为我们提供了许多的节点应用,每一个节点都有其不同的作用,其中有四个比较常用的节点,他们分别decision,fork,state和task.在本文中我们先介绍decision节点,余 ...

  4. NMS:Non-maximum Suppression学习笔记

    非极大值抑制可看成一种局部极大值搜索,这里的局部极大值要比他的邻域值都要大.这里的邻域表示有两个参数:维度和n-邻域.维度有1-D,2-D,3-D...:至于n值根据具体情况设置.举个例子:一维的情况 ...

  5. 【278】◀▶ Python 数学函数说明

    参考:Python 数学函数说明 目录: 一.Python 数学函数 二.Python 随机数函数 三.Python 三角函数 四.Python 数学常量 一.Python 数学函数   函数 返回值 ...

  6. css字体属性(font)

    字体名称属性(font-family) 这个属性设定字体名称,如Arial, Tahoma, Courier等.例句如下: .s1 {font-family:Arial}     字体大小属性(fon ...

  7. Codeforces 1109D (树的计数问题)

    思路看这篇博客就行了:https://www.cnblogs.com/zhouzhendong/p/CF1109D.html, 讲的很好 今天学到了prufer编码,这是解决树上计数问题的一大利器,博 ...

  8. 1、 Shiro框架:认证,授权(验权 2. Shiro框架实现权限控制方式:

    1. Shiro框架:认证,授权(验权) a) 认证逻辑:applicationCode—>通过工具类获取subject对象,调用login方法参数令牌信息->安全管理器------> ...

  9. Hadoop 使用Combiner提高Map/Reduce程序效率

    众所周知,Hadoop框架使用Mapper将数据处理成一个<key,value>键值对,再网络节点间对其进行整理(shuffle),然后使用Reducer处理数据并进行最终输出. 在上述过 ...

  10. vuex 数据绑定

    操作文档: 安装vuex: cnpm install vuex --save   文档介绍: https://vuex.vuejs.org/guide/modules.html   import Vu ...