dsoframer控件学习小结

根据自己对dsoframer控件的学习,想把dsoframer控件进行简单的包装为C#的usercontrol,大体需要作如下:(创建windows的usercontrol的步骤就不再说了。。。)
我们暂时不对dso打开网络文件的功能和上传文件功能作过多研究,一来由于我自己不用它提供的这个功能,二来确实觉得它的这方面功能不是很强大而且使用起来比较
麻烦,呵呵,请见谅!
1.使用前注册该dsoframer控件,我把该dso控件当作嵌入资源,用学习笔记1中的方法注册即可
/// <summary>
/// usercontrol控件初始化
/// </summary>
/// <param name=”_sFilePath”>本地文件全路径</param>
public void Init(string _sFilePath)
{
try
{
RegControl();//注册控件
if(!CheckFile(_sFilePath))//判断是否为所支持的office文件
{
throw new ApplicationException(“文件不存在或未标识的文件格式!”);
}
AddOfficeControl();//这里一定要先把dso控件加到界面上才能初始化dso控件,这个dso控件在没有被show出来之前是不能进行初始化操作的,很奇怪为什

//么作者这样考虑…..
InitOfficeControl(_sFilePath);
}
catch(Exception ex)
{
throw ex;
}
}

public bool RegControl()
{
try
{
Assembly thisExe = Assembly.GetExecutingAssembly();
System.IO.Stream myS = thisExe.GetManifestResourceStream(“NameSpaceName.dsoframer.ocx”);

string sPath = “该ocx文件的实际路径”+ @”/dsoframer.ocx”;
ProcessStartInfo psi = new ProcessStartInfo(“regsvr32″,”/s ” +sPath);
Process.Start(psi);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
return true;
}

2.动态向usercontrol添加dsoframer实例
private AxDSOFramer.AxFramerControl m_axFramerControl = new AxDSOFramer.AxFramerControl();
/// <summary>
/// 添加控件
/// </summary>
private void AddOfficeControl()
{
try
{
this.m_Panel_Control.Controls.Add(m_axFramerControl);
m_axFramerControl.Dock = DockStyle.Fill;
}
catch(Exception ex)
{
throw ex;
}
}
3.初始化dsoframer控件 ,我这里用已经有的文件进行dso初始化,
/// <summary>
/// 初始化office控件
/// </summary>
/// <param name=”_sFilePath”>本地文档路径</param>
private void InitOfficeControl(string _sFilePath)
{
try
{
if(m_axFramerControl == null)
{
throw new ApplicationException(“请先初始化office控件对象!”);
}

//this.m_axFramerControl.SetMenuDisplay(48);//这个方法很特别,一个组合菜单控制方法,我还没有找到参数的规律,有兴趣的朋友可以研究一下
string sExt = System.IO.Path.GetExtension(_sFilePath).Replace(“.”,””);
//this.m_axFramerControl.CreateNew(this.LoadOpenFileType(sExt));//创建新的文件
this.m_axFramerControl.Open(_sFilePath,false,this.LoadOpenFileType(sExt),””,””);//打开文件
//隐藏标题
this.m_axFramerControl.Titlebar = false;
}
catch(Exception ex)
{
throw ex;
}
}

下面这个方法是dso打开文件时需要的一个参数,代表office文件类型
/// <summary>
/// 根据后缀名得到打开方式
/// </summary>
/// <param name=”_sExten”></param>
/// <returns></returns>
private string LoadOpenFileType(string _sExten)
{
try
{
string sOpenType = “”;
switch (_sExten.ToLower())
{
case “xls”:
sOpenType = “Excel.Sheet”;
break;
case “doc”:
sOpenType = “Word.Document”;
break;
case “ppt”:
sOpenType = “PowerPoint.Show”;
break;
case “vsd”:
sOpenType = “Visio.Drawing”;
break;
default:
sOpenType = “Word.Document”;
break;
}
return sOpenType;

}
catch (Exception ex)
{
throw ex;
}
}

4.我觉的最重要的一步,就是公布dso当前的活动对象,因为自己做这个usercontrol功能不强,但是不能把人家dso功能给杀掉,给使用者留一个更大的空间。。。。
/// <summary>
/// 获取当前操作的文档
/// </summary>
public object ActiveDocument
{
get
{
return this.m_axFramerControl.ActiveDocument;
}
}

/// <summary>
/// 获取当前控件对象
/// </summary>
public AxDSOFramer.AxFramerControl OfficeObject
{
get
{
return this.m_axFramerControl;
}
}
5.公布了一些简单的excel和word操作方法,
#region public word method,这几个方法只对word文档有效

/// <summary>
/// 设置保留修改痕迹(可以通过word工具栏的审批修改,此方法仅仅是提供初始化)
/// 这个方法挺好,可以模拟键盘按键,很巧啊.(以前很长时间都不知道可以这样…)
/// </summary>
/// <param name=”_bIs”></param>
public void WordSetSaveTrace()
/// <summary>
/// 替换标签下
/// </summary>
/// <param name=”_sMark”></param>
/// <param name=”_sReplaceText”></param>
/// <param name=”_IsD”>替换后是否突出显示</param>
/// <returns></returns>
public bool WordReplace(string _sMark,string _sReplaceText,bool _IsD)
/// <summary>
/// 文本替换
/// </summary>
/// <param name=”_sOrialText”></param>
/// <param name=”_sReplaceText”></param>
/// <returns></returns>
public bool WordReplace(string _sOrialText,string _sReplaceText)
#endregion

#region public excel method

/// <summary>
/// 向固定位置填值
/// </summary>
/// <param name=”_sValue”>填写内容</param>
/// <param name=”_iBeginRow”>开始行</param>
/// <param name=”_iBeginCol”>开始列</param>
public void ExcelFillValue(string _sValue,int _iBeginRow,int _iBeginCol)
/// <summary>
/// 向固定位置填值
/// </summary>
/// <param name=”_sValue”>填写对象</param>
/// <param name=”_iBeginRow”>开始行</param>
/// <param name=”_iBeginCol”>开始列</param>
public void ExcelFillValue(Object _sValue,int _iBeginRow,int _iBeginCol)
/// <summary>
/// 向固定位置填值
/// </summary>
/// <param name=”_ds”>填写内容</param>
/// <param name=”_iBeginRow”>开始行</param>
/// <param name=”_iBeginCol”>开始列</param>
public void ExcelFillValue(System.Data.DataSet _ds,int _iBeginRow,int _iBeginCol,bool _IsTitle)
/// <summary>
/// 清空excel文档
/// </summary>
public void ExcelClear()
/// <summary>
/// 清空固定位置的内容
/// </summary>
/// <param name=”_iBeginRow”>开始行</param>
/// <param name=”_iBeginCol”>开始列</param>
public void ExcelClear(int _iBeginRow,int _iBeginCol)
/// <summary>
/// 清空指定区域的内容
/// </summary>
/// <param name=”_iBeginRow”>开始行</param>
/// <param name=”_iBeginCol”>开始列</param>
/// <param name=”_iEndRow”>结束行</param>
/// <param name=”_iEndCol”>结束列</param>
public void ExcelClear(int _iBeginRow,int _iBeginCol,int _iEndRow,int _iEndCol)

#endregion
以上这些都是对excel和word文档操作的小儿科,害怕贴出来各位大虾见笑,不敢贴了…..

6.公布一些简单的方法(保存和另存为方法是防止菜单和工具栏被隐藏的情况下不能保存),这类应该有很多方法,我目前只用了这些个所以….
/// <summary>
/// 保存
/// </summary>
public void Save()
{
try
{
//先保存
this.m_axFramerControl.Save(true,true,””,””);
}
catch(Exception ex)
{
throw ex;
}
}
/// <summary>
/// 另存为
/// </summary>
public void SaveAs()
{
try
{
//另存为
SaveFileDialog sfd = new SaveFileDialog();
string sExt = System.IO.Path.GetExtension(this.m_sFilePath).Replace(“.”,””);
sfd.Filter = sExt;
if(sfd.ShowDialog() == DialogResult.OK)
{
string sSavePath = sfd.FileName;
if(System.IO.File.Exists(sSavePath))
{
System.IO.File.Delete(sSavePath);
}
this.m_axFramerControl.SaveAs(sSavePath,this.LoadOpenFileType(sExt));
}
}
catch(Exception ex)
{
throw ex;
}
}

/// <summary>
/// 关闭当前界面
/// </summary>
public void Close()
{
try
{
if(this.m_axFramerControl != null)
{
this.m_axFramerControl.Close();
}
}
catch(Exception ex)
{
throw ex;
}
}

最后如果想把该dso控件的注册去掉也可以,因为我没有办法得到该控件是否在机器上注册过,所以每次初始化都要注册,不知道园子里的各位朋友有没有办法检测,还请赐教?

好了,一个简单的可以用于windows程序的office在线编辑控件完成了.

基于DsoFramer控件的Office编辑控件

微软提供了一个叫dsoframer的控件,它是免费的.而且据说EDrawOffice控件也是基于这个控件搞的,至于是否属实就不清楚了.我们还是先看看如何使用dsoframer控件吧,在园子里找了相关资料,但很少有个完整的示例,因此,趁周末时搞了下,弄个demo出来,方便大家哈.额,不说废话了,我们开始吧

先说下控件的版本,是V2.2.1.2的,我也不知道从什么地方下的,是一个哥们发给我的.已经在我提供的下载文件中,大家直接使用即可.

1.WinForm环境下使用

我们首先要对控件注册,注册成功后,才能够被net作为类库使用.下载文件中提供了一个reg.bat的批处理文件,直接运行即可.成功以后,在我们建好的应用程序里,新建一控件tab页面,然后选择”浏览”文件,如图-1所示.控件加载成功,就会出现如图-2所示

clip_image002

clip_image003

OK,我们开始真正使用它.这里只实现了最基本的操作,如图-3所示.这里以操作Word文档为例.

clip_image004

 

需要注意的地方就是打开文档时,并不是直接打开文档,而是将文档复制一份临时文件,打开的是临时文件,这样在保存时就可以直接保存了.如果直接打开文件的话,保存时被报错,提示该文件正在被占用.不知道大家注意没有,我们在打开Word文档时,会立刻生成一个临时文件,应该也是这个原因吧.

其次就是保存至Db的代码了,这里使用的是SQLServer2005的环境,保存文档的字段数据类型是image,Oracle中对应的就是Blob或Clob了.保存使用的是实体方式,如图-4所示

clip_image006

 

图-4

最后,再说下从Db中读取Image字段类型,转为Word文档,再展示至控件中.代码也不复杂,如图-5所示

clip_image008

 

图-5

2.WebForm环境下使用

在此环境下,有个地方需要屏蔽下,如图-6所示.可能这个控件不支持标准的W3C要求.其他操作基本的WinForm下面的代码相同,在此就不多说了.直接看demo就可以了.

clip_image010

 

图-6

用于保存Office文档的Db语句,放在ReferDll文件夹里了,直接运行即可

dsoframer.ocx 实现在线的word编辑

关于 dsoframer.ocx 的资料和API 我这里就不多说了。。百度 google 有很多

 

但是都是简单的介绍api 对于刚刚接触的人还是很难入手的。

 

所以我这里主要讲下如何来具体的使用,分享给大家,希望对大家帮助啊:

 

经过几天的研究,嘎嘎。。战果如下:

这里说明下 各个文件

dsoframer.ocx

大家都认识吧,微软提供的

dsoframer.js

封装了对 dsoframer.ocx 的操作

dsoframer.jsp

显示word的业务界面

dsoframer.CAB

这个是重头戏啊,引用这个文件,

可以在让 dsoframer.ocx 在浏览器中自动下载并注册 当初可弄了老半天的)

至于如何签名自己的 ocx,使其下载并注册,网页也有很多资料。

我这里也提供一个:http://blog.csdn.net/xjzdr/article/details/5991585

流程都好看。最要命的是 里面的 inf 安装文件别写错了,否则就安装失败了,所以要千万记着。

这里偷偷的告诉你们一个秘密: 我是把别人公司的 CAB 安装解压,让回一步一步的模仿写出来的。。嘎嘎

具体是哪个公司,嘿嘿,,不好说。。秘密!  你们可以拷贝我的就好了啊。。

还有一点就是要注意  写版本 FileVersion=2,0,0,0  的时候 是逗号而不是点,不然报错!

下面看具体代码

 

dsoframer.jsp  界面:

Html代码  
  1. <%@ page language=”java” pageEncoding=”UTF-8″ contentType=”text/html; charset=UTF-8″ %>
  2. <%
  3. String path = request.getContextPath();
  4. String basePath = request.getScheme()+”://”+request.getServerName()+”:”+request.getServerPort()+path+”/”;
  5. String id = “1”;
  6. %>
  7. <html>
  8.     <head>
  9.         <title>调查报告</title>
  10.         <script language=”javascript” src=”dsoframer.js”></script>
  11.         <script type=”text/javascript”>
  12.             /*用法说明:
  13.               1,创建 word对象
  14.               2,设置文件上传url
  15.               3,在页面加载时,打开word文档,根据是否传人docUrl参数,决定是本地新建,还是从服务器端获取
  16.               4,在页面关闭时,执行上传操作。
  17.             */
  18.              var word = new word();
  19.              //决定路径
  20.              word.setUploadUrl(“http://127.0.0.1:8070/word/upload_handle.jsp”);
  21.              var docurl = “”;
  22.              function load(){
  23.                  //方法:openDoc(docName, docUrl)
  24.                  // docName:必填,本地保存的文件名, 也为上传到服务器上时的文件名
  25.                  // docUrl: 填时,为从服务器端获取doc文档的路径, 不填时,表示本地新建doc文档
  26.                  word.openDoc(‘1.doc’,”http://127.0.0.1:8070/word/upload/1.doc”);
  27.                  /**
  28.                   //这里实现读取服务器的模板,并保存到服务器的业务路径中
  29.                  $.post(“/ZsytpServlet”,{type:”ajaxWord”,id:<%=id%>},function(result){
  30.                         var dataObj=eval(“(“+result+”)”);//转换为json对象
  31.                         docurl = dataObj.docurl;
  32.                         if(docurl == “”){
  33.                             word.openDoc(‘<%=id%>.doc’,”<%=basePath%>/webapps/zsytp/templ/”+dataObj.fhtk+”.doc”);
  34.                             document.getElementById(‘oframe’).SetFieldValue(“f_name”,dataObj.f_name,””);
  35.                             document.getElementById(‘oframe’).SetFieldValue(“m_name”,dataObj.m_name,””);
  36.                             document.getElementById(‘oframe’).SetFieldValue(“town”,dataObj.town,””);
  37.                             document.getElementById(‘oframe’).SetFieldValue(“f_name1″,dataObj.f_name,””);
  38.                             document.getElementById(‘oframe’).SetFieldValue(“m_name1″,dataObj.m_name,””);
  39.                             document.getElementById(‘oframe’).SetFieldValue(“sqsj”,dataObj.sqsj,””);
  40.                             document.getElementById(‘oframe’).SetFieldValue(“f_name2″,dataObj.f_name,””);
  41.                             document.getElementById(‘oframe’).SetFieldValue(“f_birthday”,dataObj.f_birthday,””);
  42.                             document.getElementById(‘oframe’).SetFieldValue(“f_hjdz”,dataObj.f_hjdz,””);
  43.                             document.getElementById(‘oframe’).SetFieldValue(“m_name2″,dataObj.m_name,””);
  44.                             document.getElementById(‘oframe’).SetFieldValue(“m_birthday”,dataObj.m_birthday,””);
  45.                             document.getElementById(‘oframe’).SetFieldValue(“m_hjdz”,dataObj.m_hjdz,””);
  46.                         }else{
  47.                         //实现读取业务路径的内容,并修改
  48.                             word.openDoc(‘<%=id%>.doc’,”<%=basePath%>/webapps/zsytp/word/”+docurl);
  49.                         }
  50.                  });
  51.                  **/
  52.              }
  53.              //为了简化,我定义关闭窗口的时候,保存到服务器上面,并且删除本地的临时文件
  54.              function unload(){
  55.                  word.saveDoc();
  56.                  word.close();
  57.              }
  58.              //给书签赋值
  59.              function setFileVal(){
  60.                 document.getElementById(‘oframe’).SetFieldValue(“dm”,”2006-03-16 22:22:22″,””);
  61.              }
  62.              //插入红头文件
  63.              //等等。。网上都有 API
  64.              //真正开发的时候,,需要用到的方法,保存文件到服务器上
  65.              //可以查看里面的 document.getElementById(‘oframe’).HttpAddPostString(“id”,id); 等向后台穿参数
  66.              function uploadFile(){
  67.                 //word.saveDocAndParm(‘1’,docurl);
  68.              }
  69.         </script>
  70.     </head>
  71.     <body onload=”load();” onunload=”unload();”>
  72.        <input  type=”button” value=”保存文件到服务器” onclick=”uploadFile()” >
  73.        <hr/>
  74.        <!–
  75.        <object classid=”clsid:00460182-9E5E-11d5-B7C8-B8269041DD57″ codebase=”dsoframer.ocx” id=”oframe” width=”100%” height=”100%”>
  76.          <param name=”BorderStyle” value=”1″>
  77.          <param name=”TitlebarColor” value=”52479″>
  78.          <param name=”TitlebarTextColor” value=”0″>
  79.        </object>
  80.       –>
  81.       <object classid=”clsid:00460182-9E5E-11d5-B7C8-B8269041DD57″ codebase=”dsoframer.CAB#Version=2.0.0.0″ id=”oframe” width=”100%” height=”100%”>
  82.              <param name=”BorderStyle” value=”1″>
  83.              <param name=”TitlebarColor” value=”52479″>
  84.              <param name=”TitlebarTextColor” value=”0″>
  85.        </object>
  86.     </body>
  87. </html>

upload_handle.jsp 上传的业务代码。。可以自己修改吧。。嘎嘎

 

Java代码  
  1. <%@ page language=”java” import=”java.util.*” pageEncoding=”UTF-8″ contentType=”text/html; charset=UTF-8″%>
  2. <%@page import=”org.apache.commons.fileupload.servlet.ServletFileUpload”%>
  3. <%@page import=”org.apache.commons.fileupload.disk.DiskFileItemFactory”%>
  4. <%@page import=”java.io.File”%>
  5. <%@page import=”org.apache.commons.fileupload.FileItem”%>
  6. <%@page import=”java.text.SimpleDateFormat”%>
  7. <%@page import=”java.io.BufferedInputStream”%>
  8. <%@page import=”java.io.BufferedOutputStream”%>
  9. <%@page import=”java.io.FileOutputStream”%>
  10. <%@page import=”org.apache.commons.fileupload.util.Streams”%>
  11. <%
  12.     try{
  13.         // 解析 request,判断是否有上传文件
  14.         boolean isMultipart = ServletFileUpload.isMultipartContent(request);
  15.         System.out.println(“———“+isMultipart);
  16.         if (isMultipart) {
  17.             Date date = new Date();//获取当前时间
  18.             SimpleDateFormat sdfFolder = new SimpleDateFormat(“yyMM”);
  19.             String fileRealPath = “”;//文件存放真实地址
  20.             String fileRealResistPath = “”;//文件存放真实相对路径
  21.             String id=”1″;//id
  22.             String docUrl=””; //路径
  23.             String firstFileName=””;
  24.             String yyMM = sdfFolder.format(date);
  25.             //上传文件夹绝对路径
  26.             String physicsPath = request.getRealPath(“”)
  27.                     + “\\upload\\” + yyMM + “\\”;
  28.             File file = new File(physicsPath);
  29.             if (!file.isDirectory()) {
  30.                 file.mkdir();
  31.             }
  32.             // 创建磁盘工厂,利用构造器实现内存数据储存量和临时储存路径
  33.             DiskFileItemFactory factory = new DiskFileItemFactory();
  34.             // 设置最多只允许在内存中存储的数据,单位:字节
  35.             // factory.setSizeThreshold(4096);
  36.             // 设置文件临时存储路径
  37.             // factory.setRepository(new File(“D:\\Temp”));
  38.             // 产生一新的文件上传处理程式
  39.             ServletFileUpload upload = new ServletFileUpload(factory);
  40.             // 设置路径、文件名的字符集
  41.             upload.setHeaderEncoding(“UTF-8”);
  42.             // 设置允许用户上传文件大小,单位:字节
  43.             upload.setSizeMax(-1);
  44.             //upload.setSizeMax(1024 * 1024);
  45.             // 解析请求,开始读取数据
  46.             // Iterator<FileItem> iter = (Iterator<FileItem>) upload.getItemIterator(request);
  47.             // 得到所有的表单域,它们目前都被当作FileItem
  48.             BufferedInputStream in = null;
  49.             List fileItems = upload.parseRequest(request);
  50.             // 依次处理请求
  51.             Iterator iter = fileItems.iterator();
  52.             while (iter.hasNext()) {
  53.                 FileItem item = (FileItem) iter.next();
  54.                 if (item.isFormField()) {
  55.                     // 如果item是正常的表单域
  56.                     String name = item.getFieldName();
  57.                     String value = item.getString(“UTF-8”);
  58.                     if(name.equals(“id”))
  59.                         id=value;//附件标题赋值
  60.                     else if(name.equals(“docUrl”))
  61.                         docUrl=value;//附件ID赋值
  62.                 } else {
  63.                     // 如果item是文件上传表单域
  64.                     // 获得文件名及路径
  65.                     String fileName = item.getName();
  66.                     if (fileName != null) {
  67.                         firstFileName=item.getName().substring(item.getName().lastIndexOf(“\\”)+1);
  68.                         in = new BufferedInputStream(item.getInputStream());// 获得文件输入流
  69.                     }
  70.                 }
  71.             }
  72.             String formatName = firstFileName.substring(firstFileName.lastIndexOf(“.”));//获取文件后缀名
  73.             if(docUrl != null && !””.equals(docUrl.trim())){
  74.                 fileRealPath = request.getRealPath(“”) + “\\word\\” + docUrl;//文件存放真实地址
  75.             }else{
  76.                 fileRealPath = physicsPath + id+ formatName;//文件存放真实地址
  77.                 docUrl = yyMM + “/” + id + formatName;
  78.             }
  79.             BufferedOutputStream outStream = new BufferedOutputStream(new FileOutputStream(new File(fileRealPath)));// 获得文件输出流
  80.             Streams.copy(in, outStream, true);// 开始把文件写到你指定的上传文件夹
  81.             //上传成功,则插入数据库
  82.             if (new File(fileRealPath).exists()) {
  83.                 //虚拟路径赋值
  84.                 fileRealResistPath=sdfFolder.format(date)+”/”+fileRealPath.substring(fileRealPath.lastIndexOf(“\\”)+1);
  85.                 //DB db=new DB();
  86.                 //System.out.println(“!!!”+(String) session.getAttribute(“fpsssn”)+”&&”+v07.can.myname(session));
  87.                 //int count = db.executeUpdate(“update   zy_zsytp  set  docurl ='”+docUrl+”‘  where  id ='”+id+”‘”);
  88.                 //if(count>0){
  89.                 //  response.setContentType(“text/html;charset=UTF-8”);
  90.                 //  out.print(“<script>alert(‘上传成功!’);</script>”);
  91.                 //}
  92.                 //db.destroy();
  93.                 //保存到数据库
  94.             }
  95.         }
  96.     }catch(Exception e){
  97.         e.printStackTrace();
  98.         //response.setContentType(“text/html;charset=UTF-8”);
  99.         //out.print(“<script>window.alert(‘上传失败!文件大小超过1MB!’);</script>”);
  100.     }
  101. %>

 

效果图:

搭建高可用mongodb集群(一)——配置mongodb

在大数据的时代,传统的关系型数据库要能更高的服务必须要解决高并发读写、海量数据高效存储、高可扩展性和高可用性这些难题。不过就是因为这些问题Nosql诞生了。

NOSQL有这些优势:

大数据量,可以通过廉价服务器存储大量的数据,轻松摆脱传统mysql单表存储量级限制。

高扩展性,Nosql去掉了关系数据库的关系型特性,很容易横向扩展,摆脱了以往老是纵向扩展的诟病。

高性能,Nosql通过简单的key-value方式获取数据,非常快速。还有NoSQL的Cache是记录级的,是一种细粒度的Cache,所以NoSQL在这个层面上来说就要性能高很多。

灵活的数据模型,NoSQL无需事先为要存储的数据建立字段,随时可以存储自定义的数据格式。而在关系数据库里,增删字段是一件非常麻烦的事情。如果是非常大数据量的表,增加字段简直就是一个噩梦。

高可用,NoSQL在不太影响性能的情况,就可以方便的实现高可用的架构。比如mongodb通过mongos、mongo分片就可以快速配置出高可用配置。

在nosql数据库里,大部分的查询都是键值对(key、value)的方式。MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中最像关系数据库的。支持类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。所以这个非常方便,我们可以用sql操作MongoDB,从关系型数据库迁移过来,开发人员学习成本会大大减少。如果再对底层的sql API做一层封装,开发基本可以感觉不到mongodb和关系型数据库的区别。同样MongoDB也是号称自己能够快速搭建一个高可用可扩展的的分布式集群,网上有很多搭建的文章,在我们搭建的时候还需要查找修改很多东西,所以把自己实战的步骤记录下来以备忘。我们看看如何一步一步搭建这个东东。

一、mongodb单实例。这种配置只适合简易开发时使用,生产使用不行,因为单节点挂掉整个数据业务全挂,如下图。

mongodb1

虽然不能生产使用,但这个模式可以快速搭建启动,并且能够用mongodb的命令操作数据库。下面列出在linux下安装单节点mongodb的步骤

1、建立mongodb测试文件夹

1
2
3
4
5
6
7
8
#存放整个mongodb文件
mkdir-p/data/mongodbtest/single

#存放mongodb数据文件
mkdir-p/data/mongodbtest/single/data

#进入mongodb文件夹
cd/data/mongodbtest/single

2、下载mongodb的安装程序包

1
2
3
4
5
6
7
wget http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.4.6.tgz

#解压下载的压缩包
tar xvzf mongodb-linux-x86_64-2.4.6.tgz

#进入mongodb程序执行文件夹
cd mongodb-linux-x86_64-2.4.6/bin/

3、启动单实例mongodb

1
mongod –dbpath/data/mongodbtest/single/data

输出日志如下,成功!

[initandlisten] db version v2.4.6
……..
[initandlisten] waiting for connections on port 27017
[websvr] admin web console waiting for connections on port 28017

mongodb默认自带提供了web访问接口,通过 IP + 端口的形式可以访问。

http://192.168.0.1:28017/

mongodb2

二、主从模式。使用mysql数据库时大家广泛用到,采用双机备份后主节点挂掉了后从节点可以接替主机继续服务。所以这种模式比单节点的高可用性要好很多。

mongodb3

下面看一下怎么一步步搭建一个mongodb的主从复制节点:

  • 1、准备两台机器 192.168.0.1 和 192.168.0.2。 192.168.0.1 当作主节点, 192.168.0.2作为从节点
  • 2、分别下载mongodb安装程序包。在192.168.0.1上建立文件夹 /data/mongodbtest/master,192.168.0.2建立文件夹/data/mongodbtest/slave
  • 3、在192.168.0.1启动mongodb主节点程序。注意后面的这个 “ –master ”参数,标示主节点。

    mongod –dbpath /data/mongodbtest/master –master

     

输出日志如下,成功!

[initandlisten] MongoDB starting : pid=18285 port=27017 dbpath=/data/mongodbtest/master master=1
#日志显示主节点参数
[initandlisten] options: { dbpath: “/data/mongodbtest/master”, master: true }
……..
[initandlisten] waiting for connections on port 27017

4、在192.168.0.2启动mongodb从节点程序。关键配置,指定主节点ip地址和端口 –source 192.168.0.1:27017 和 标示从节点 –source 参数。

mongod –dbpath /data/mongodbtest/slave –slave –source 192.168.0.1:27017

输出日志如下,成功!

[initandlisten] MongoDB starting : pid=17888 port=27017 dbpath=/data/mongodbtest/slave slave=1
……..
#日志显示从节点参数
[initandlisten] options: { dbpath: “/data/mongodbtest/slave”, slave: true, source: “192.168.0.1:27017″ }
……..
[initandlisten] waiting for connections on port 27017
#日志显示从节点 从主节点同步复制数据
[replslave] repl: from host:192.168.0.1:27017

5、测试主从复制。

在主节点上连接到终端:

1
2
3
4
5
6
7
8
9
10
11
mongo 127.0.0.1

#建立test 数据库。
use test;

往testdb表插入数据。
> db.testdb.insert({“test1″:”testval1”})

查询testdb数据看看是否成功。
> db.testdb.find();
{“_id” : ObjectId(“5284e5cb1f4eb215b2ecc463”), “test1” : “testval1”}

可以看到主机的同步日志

[initandlisten] connection accepted from 192.168.0.2:37285 #3 (2 connections now open)
[slaveTracking] update local.slaves query: { _id: ObjectId(’5284e6268ed115d6238bdb39′), config: { host: “192.168.0.2:35271″, upgradeNeeded: true }, ns: “local.oplog.$main” } update: { $set: { syncedTo: Timestamp 1384441570000|1 } } nscanned:1 nupdated:1 fastmod:1 keyUpdates:0 locks(micros) w:132015 132ms

检查从主机的数据。

mongo 127.0.0.1

查看当前数据库。

1
2
3
4
5
6
7
> show dbs;
local 0.203125GB
test 0.203125GB

use test;
db.testdb.find();
{“_id” : ObjectId(“5284e5cb1f4eb215b2ecc463”), “test1” : “testval1”}

查询后数据已经同步过来了。再看看日志,发现从主机确实从主机同步了数据。

1
2
Thu Nov 1423:05:13[replslave] repl: checkpoint applied 15 operations
Thu Nov 1423:05:13[replslave] repl: syncedTo: Nov 1423:08:10 5284e75a:1

查看服务状态

1
2
3
4
5
> db.printReplicationInfo();
this is a slave, printing slave replication info.
source: 192.168.0.1:27017
syncedTo: Sun Nov 17201316:04:02 GMT+0800 (CST)
= -54 secs ago (-0.01hrs)

到此主从结构的mongodb搭建好了。

故障转移测试,现在两台服务器如果主服务器挂掉了,从服务器可以正常运转吗?

a、先测试下从服务器可以当成主服务器吗,也就是往从服务器里写能够同步主服务器吗?

 

在192.168.0.2上连接mongodb。

1
2
3
mongo 127.0.0.1:27017
> db.testdb.insert({“test3″:”testval3”});
not master

可以看到 mongodb的从节点是不能提供写操作的,只能提供读操作。

 

b、如果从服务器挂掉,主服务器还可以提供服务。如果主服务器挂掉了从服务器能否自动变为可写。
测试一下!

先杀掉原来的mongodb主服务器。

1
kill-3`ps-ef|grep mongod|grep-vgrep|awk'{print $2}’`

测试从服务器能否可写。在192.168.0.2上连接mongodb测试。

1
2
> db.testdb.insert({“test3″:”testval3”});
not master

看起来从服务器没有自动接替主服务器的功能,只有手工处理了!

停止从服务器,在原数据文件启动并添加主服务器标示。

1
mongod –dbpath/data/mongodbtest/slave –master

等到启动成功(时间有点长)。在192.168.0.2 上 连接

1
mongo 192.168.0.2:27017

1
2
3
> db.testdb.find();
{“_id” : ObjectId(“5288629e9b0318be4b20bd4c”), “test1” : “testval1”}
{“_id” : ObjectId(“528862d69b0318be4b20bd4d”), “test2” : “testval2”}

成功!

多个从节点。现在只是一个数据库服务器又提供写又提供读,机器承载会出现瓶颈。大家还记得mysql里的读写分离吗?把20%的写放到主节点,80%的读放到从节点分摊了减少了服务器的负载。但是大部分应用都是读操作带来的压力,一个从节点压力负载不了,可以把一个从节点变成多个节点。那mongodb的一主多从可以支持吗?答案是肯定的。

mongodb4

为了方便测试,在192.168.0.2上再建立一个文件夹 /data/mongodbtest/slave2 作为另一个slave服务器。
启动slave2服务,

1
mongod –dbpath/data/mongodbtest/slave1 –slave–port27017–source 192.168.0.1:27017。

成功启动后通过mongodb连接测试:

1
2
3
> db.testdb.find();
{“_id” : ObjectId(“5288629e9b0318be4b20bd4c”), “test1” : “testval1”}
{“_id” : ObjectId(“528862d69b0318be4b20bd4d”), “test2” : “testval2”}

搭建了这套主从复制系统是不是就很稳健了,其实不然。。。看看这几个问题?

  • 主节点挂了能否自动切换连接?目前需要手工切换。
  • 主节点的写压力过大如何解决?
  • 从节点每个上面的数据都是对数据库全量拷贝,从节点压力会不会过大?
  • 就算对从节点路由实施路由访问策略能否做到自动扩展?

还有这么多问题,有其他解决方案吗?下一篇接着弄。

参考:
NoSQL开篇——为什么要使用NoSQL http://www.infoq.com/cn/news/2011/01/nosql-why/
mongodb手册 http://cn.docs.mongodb.org/manual/single/

DSOframer 的简单介绍和资源整理

dsoframer是微软提供一款开源的用于在线编辑、调用Word、 Excel 、PowerPoint等的ActiveX控件。国内很多著名的OA中间件,电子印章,签名留痕等大多数是依此改进而来的。虽然博主的公司已经用了新的office控件【NTKO】取代了【dsoframer】,但免费的控件是更多人的选择,所以还是在此和大家分享一下【dsoframer】的常用功能。

相关资源下载地址:
注意:应该是官方提供的安装包,里面包含”DSOframer.ocx”控件及源码,VB版、VB.NET版、Web版等3个Demo
注意:博主将”DsoFramer_KB311765_x86.exe”中的”DSOframer.ocx”,打包成了DSOframer.CAB,以便在Web中引用时可以自动下载。
注意:博主公司之前使用的版本,貌似修改了一些office2007兼容性问题,如果上面那个用着有问题,可以下载这个试试
如果大家没有下载安装”DsoFramer_KB311765_x86.exe”,可以点击下面链接看Web版Demo的效果。
注意:因为涉及ActiveX控件调用本地Office操作,所以需要把”www.jialisi.net”加入受信站点才能正常演示Demo,或下载Demo到本地演示。Demo下载地址
如上图所示,Demo中除了包含官方VBscript和Javascript两个版本的Demo,还有DSOframer常用操作的代码范例。
还包含:DSOframer2007.CAB,DSOframer.CAB,DsoFramer_KB311765_x86.exe,Demo下载地址
如果你想找到更多的word接口如何使用,或者想了解更多的office其他产品的开发接口,请下载office2007开发参考及hxs阅读工具,如下图所示:
网上讲解 DSOframer 开发的博文已经有很多了,个人觉得比较有价值的帖子有:
2.《win7 64位在线编辑dsoframer控件的安装和使用配置》http://yaya123.blog.51cto.com/341518/710339
3.《如何给DSOFramer添加自己的接口》http://shingpha.i.sohu.com/blog/view/111370970.htm

C# 导出Excel的示例

概要:

excel导出在C#代码中应用己经很广泛了,我这里就做些总结,供自己和读者学习用。

Excel知识点。
一、添加引用和命名空间
添加Microsoft.Office.Interop.Excel引用,它的默认路径是C:\Program Files\Microsoft Visual Studio 9.0\Visual Studio Tools for Office\PIA\Office12\Microsoft.Office.Interop.Excel.dll
代码中添加引用using Microsoft.Office.Interop.Excel;
二、Excel类的简单介绍
此命名空间下关于Excel类的结构分别为:
ApplicationClass – 就是我们的excel应用程序。
Workbook – 就是我们平常见的一个个excel文件,经常是使用Workbooks类对其进行操作。
Worksheet – 就是excel文件中的一个个sheet页。
Worksheet.Cells[row, column] – 就是某行某列的单元格,注意这里的下标row和column都是从1开始的,跟我平常用的数组或集合的下标有所不同。
知道了上述基本知识后,利用此类来操作excel就清晰了很多。
三、Excel的操作
任何操作Excel的动作首先肯定是用excel应用程序,首先要new一个ApplicationClass 实例,并在最后将此实例释放。

1
2
3
4
5
ApplicationClass xlsApp = new ApplicationClass(); // 1. 创建Excel应用程序对象的一个实例,相当于我们从开始菜单打开Excel应用程序。
if (xlsApp == null)
{
//对此实例进行验证,如果为null则表示运行此代码的机器可能未安装Excel
}

 

1. 打开现有的Excel文件

1
2
3
Workbook workbook = xlsApp.Workbooks.Open(excelFilePath, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
Worksheet mySheet = workbook.Sheets[1] as Worksheet; //第一个sheet页
mySheet.Name = "testsheet"; //这里修改sheet名称

2.复制sheet页

1
mySheet.Copy(Type.Missing, workbook.Sheets[1]); //复制mySheet成一个新的sheet页,复制完后的名称是mySheet页名称后加一个(2),这里就是testsheet(2),复制完后,Worksheet的数量增加一个

注意 这里Copy方法的两个参数,指是的复制出来新的sheet页是在指定sheet页的前面还是后面,上面的例子就是指复制的sheet页在第一个sheet页的后面。
3.删除sheet页

1
2
xlsApp.DisplayAlerts = false; //如果想删除某个sheet页,首先要将此项设为fasle。
(xlsApp.ActiveWorkbook.Sheets[1] as Worksheet).Delete();

4.选中sheet页

1
(xlsApp.ActiveWorkbook.Sheets[1] as Worksheet).Select(Type.Missing); //选中某个sheet页

5.另存excel文件

1
2
workbook.Saved = true;
workbook.SaveCopyAs(filepath);

6.释放excel资源

1
2
3
4
workbook.Close(true, Type.Missing, Type.Missing);
workbook = null;
xlsApp.Quit();
xlsApp = null;

 

 

一般的我们传入一个DataTable生成Excel代码

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
/// <summary>
///
/// </summary>
/// <param name="dt"></param>
protected void ExportExcel(DataTable dt)
{
    if (dt == null||dt.Rows.Count==0) return;
    Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
    if (xlApp == null)
    {
        return;
    }
    System.Globalization.CultureInfo CurrentCI = System.Threading.Thread.CurrentThread.CurrentCulture;
    System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
    Microsoft.Office.Interop.Excel.Workbooks workbooks = xlApp.Workbooks;
    Microsoft.Office.Interop.Excel.Workbook workbook = workbooks.Add(Microsoft.Office.Interop.Excel.XlWBATemplate.xlWBATWorksheet);
    Microsoft.Office.Interop.Excel.Worksheet worksheet = (Microsoft.Office.Interop.Excel.Worksheet)workbook.Worksheets[1];
    Microsoft.Office.Interop.Excel.Range range;
    long totalCount = dt.Rows.Count;
    long rowRead = 0;
    float percent = 0;
    for (int i = 0; i < dt.Columns.Count; i++)
    {
        worksheet.Cells[1, i + 1] = dt.Columns[i].ColumnName;
        range = (Microsoft.Office.Interop.Excel.Range)worksheet.Cells[1, i + 1];
        range.Interior.ColorIndex = 15;
        range.Font.Bold = true;
    }
    for (int r = 0; r < dt.Rows.Count; r++)
    {
        for (int i = 0; i < dt.Columns.Count; i++)
        {
            worksheet.Cells[r + 2, i + 1] = dt.Rows[r][i].ToString();
        }
        rowRead++;
        percent = ((float)(100 * rowRead)) / totalCount;
    }
    xlApp.Visible = true;
}

 

 

如果要在excel中插入图片,我们需要把代码加入一行即可,如下所示

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
protected void ExportExcel(DataTable dt)
{
    if (dt == null || dt.Rows.Count == 0) return;
    Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
    if (xlApp == null)
    {
        return;
    }
    System.Globalization.CultureInfo CurrentCI = System.Threading.Thread.CurrentThread.CurrentCulture;
    System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
    Microsoft.Office.Interop.Excel.Workbooks workbooks = xlApp.Workbooks;
    Microsoft.Office.Interop.Excel.Workbook workbook = workbooks.Add(Microsoft.Office.Interop.Excel.XlWBATemplate.xlWBATWorksheet);
    Microsoft.Office.Interop.Excel.Worksheet worksheet = (Microsoft.Office.Interop.Excel.Worksheet)workbook.Worksheets[1];
    Microsoft.Office.Interop.Excel.Range range;
    long totalCount = dt.Rows.Count;
    long rowRead = 0;
    float percent = 0;
    for (int i = 0; i < dt.Columns.Count; i++)
    {
        worksheet.Cells[1, i + 1] = dt.Columns[i].ColumnName;
        range = (Microsoft.Office.Interop.Excel.Range)worksheet.Cells[1, i + 1];
        range.Interior.ColorIndex = 15;
    }
    for (int r = 0; r < dt.Rows.Count; r++)
    {
        for (int i = 0; i < dt.Columns.Count; i++)
        {
            try
            {
                worksheet.Cells[r + 2, i + 1] = dt.Rows[r][i].ToString();
            }
            catch
            {
                worksheet.Cells[r + 2, i + 1] = dt.Rows[r][i].ToString().Replace("=", "");
            }
        }
        rowRead++;
        percent = ((float)(100 * rowRead)) / totalCount;
    }
    
    worksheet.Shapes.AddPicture("C:\\Users\\spring\\Desktop\\1.gif", Microsoft.Office.Core.MsoTriState.msoFalse, Microsoft.Office.Core.MsoTriState.msoCTrue, 100, 200, 200, 300);
    worksheet.Shapes.AddTextEffect(Microsoft.Office.Core.MsoPresetTextEffect.msoTextEffect1, "123456", "Red", 15, Microsoft.Office.Core.MsoTriState.msoFalse, Microsoft.Office.Core.MsoTriState.msoTrue, 150, 200);
    xlApp.Visible = true;
}

 

 

我们调用如下:

1
2
3
4
5
6
7
8
9
10
11
12
public void GenerateExcel()
{
    DataTable dt = new DataTable();
    dt.Columns.Add("Name", typeof(string));
    dt.Columns.Add("Age", typeof(string));
    DataRow dr = dt.NewRow();
    dr["Name"] = "spring";
    dr["Age"] = "20";
    dt.Rows.Add(dr);
    dt.AcceptChanges();
    ExportExcel(dt);
}

 

 

运行结果如下所示:

image

其中如下代码的作用是

1
worksheet.Shapes.AddPicture("C:\\Users\\spring\\Desktop\\1.gif", Microsoft.Office.Core.MsoTriState.msoFalse, Microsoft.Office.Core.MsoTriState.msoCTrue, 100, 200, 200, 300);

在Excel的指定位置加入图片

1
worksheet.Shapes.AddTextEffect(Microsoft.Office.Core.MsoPresetTextEffect.msoTextEffect1, "123456", "Red", 15, Microsoft.Office.Core.MsoTriState.msoFalse, Microsoft.Office.Core.MsoTriState.msoTrue, 150, 200);

 

在Excel的指定位置加入文本框,和里面的内容.

 

我们可以这样来设计一个ExcelBase的基类:

先创建一个ExcelBE.cs:

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
public class ExcelBE
 {
     private int _row = 0;
     private int _col = 0;
     private string _text = string.Empty;
     private string _startCell = string.Empty;
     private string _endCell = string.Empty;
     private string _interiorColor = string.Empty;
     private bool _isMerge = false;
     private int _size = 0;
     private string _fontColor = string.Empty;
     private string _format = string.Empty;
     public ExcelBE(int row, int col, string text, string startCell, string endCell, string interiorColor, bool isMerge, int size, string fontColor, string format)
     {
         _row = row;
         _col = col;
         _text = text;
         _startCell = startCell;
         _endCell = endCell;
         _interiorColor = interiorColor;
         _isMerge = isMerge;
         _size = size;
         _fontColor = fontColor;
         _format = format;
     }
     public ExcelBE()
     { }
     public int Row
     {
         get { return _row; }
         set { _row = value; }
     }
     public int Col
     {
         get { return _col; }
         set { _col = value; }
     }
     public string Text
     {
         get { return _text; }
         set { _text = value; }
     }
     public string StartCell
     {
         get { return _startCell; }
         set { _startCell = value; }
     }
     public string EndCell
     {
         get { return _endCell; }
         set { _endCell = value; }
     }
     public string InteriorColor
     {
         get { return _interiorColor; }
         set { _interiorColor = value; }
     }
     public bool IsMerge
     {
         get { return _isMerge; }
         set { _isMerge = value; }
     }
     public int Size
     {
         get { return _size; }
         set { _size = value; }
     }
     public string FontColor
     {
         get { return _fontColor; }
         set { _fontColor = value; }
     }
     public string Formart
     {
         get { return _format; }
         set { _format = value; }
     }
 }

 

 

接下来创建ExcelBase.cs:

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
public class ExcelBase
{
    private Microsoft.Office.Interop.Excel.Application app = null;
    private Microsoft.Office.Interop.Excel.Workbook workbook = null;
    private Microsoft.Office.Interop.Excel.Worksheet worksheet = null;
    private Microsoft.Office.Interop.Excel.Range workSheet_range = null;
    public ExcelBase()
    {
        createDoc();
    }
    public void createDoc()
    {
        try
        {
            app = new Microsoft.Office.Interop.Excel.Application();
            app.Visible = true;
            workbook = app.Workbooks.Add(1);
            worksheet = (Microsoft.Office.Interop.Excel.Worksheet)workbook.Sheets[1];
        }
        catch (Exception e)
        {
            Console.Write("Error");
        }
        finally
        {
        }
    }
    public void InsertData(ExcelBE be)
    {
        worksheet.Cells[be.Row, be.Col] = be.Text;
        workSheet_range = worksheet.get_Range(be.StartCell, be.EndCell);
        workSheet_range.MergeCells = be.IsMerge;
        workSheet_range.Interior.Color = GetColorValue(be.InteriorColor);
        workSheet_range.Borders.Color = System.Drawing.Color.Black.ToArgb();
        workSheet_range.ColumnWidth = be.Size;
        workSheet_range.Font.Color = string.IsNullOrEmpty(be.FontColor) ? System.Drawing.Color.White.ToArgb() : System.Drawing.Color.Black.ToArgb();
        workSheet_range.NumberFormat = be.Formart;
    }
    private int GetColorValue(string interiorColor)
    {
        switch (interiorColor)
        {
            case "YELLOW":
                return System.Drawing.Color.Yellow.ToArgb();
            case "GRAY":
                return System.Drawing.Color.Gray.ToArgb();
            case "GAINSBORO":
                return System.Drawing.Color.Gainsboro.ToArgb();
            case "Turquoise":
                return System.Drawing.Color.Turquoise.ToArgb();
            case "PeachPuff":
                return System.Drawing.Color.PeachPuff.ToArgb();
            default:
                return System.Drawing.Color.White.ToArgb();
        }
    }
}

 

 

调用的代码如下:

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
private void btnRun_Click(object sender, EventArgs e)
{
    ExcelBase excel = new ExcelBase();
    //creates the main header
    ExcelBE be = null;
    be = new ExcelBE (5, 2, "Total of Products", "B5", "D5", "YELLOW", true, 10, "n",null);
    excel.InsertData(be);
    //creates subheaders
    be = new ExcelBE (6, 2, "Sold Product", "B6", "B6", "GRAY", true, 10, "",null);
    excel.InsertData(be);
    be=new ExcelBE(6, 3, "", "C6", "C6", "GRAY", true, 10, "",null);
    excel.InsertData(be);
    be=new ExcelBE (6, 4, "Initial Total", "D6", "D6", "GRAY", true, 10, "",null);
    excel.InsertData(be);
    //add Data to cells
    be=new ExcelBE (7, 2, "114287", "B7", "B7",null,false,10,"", "#,##0");
    excel.InsertData(be);
    be=new ExcelBE (7, 3, "", "C7", "C7", null,false,10,"",null);
    excel.InsertData(be);
    be = new ExcelBE(7, 4, "129121", "D7", "D7", null, false, 10, "", "#,##0");
    excel.InsertData(be);
    //add percentage row
    be = new ExcelBE(8, 2, "", "B8", "B8", null, false, 10, "", "");
    excel.InsertData(be);
    be = new ExcelBE(8, 3, "=B7/D7", "C8", "C8", null, false, 10, "", "0.0%");
    excel.InsertData(be);
    be = new ExcelBE(8, 4, "", "D8", "D8", null, false, 10, "", "");
    excel.InsertData(be);
    //add empty divider
    be = new ExcelBE(9, 2, "", "B9", "D9", "GAINSBORO", true, 10, "",null);
    excel.InsertData(be);  
}

 

 

结果如下图所示:

image

 

 

作者:spring yang

出处:http://www.cnblogs.com/springyangwc/

你们以为网络小说1天2万字怎么写得?

这是生成名字工具


按确定,下面名字都是自动生成的


这是日文名字

门派名字


全是自动生成的

——————————————————


荣誉名称

——————————————————

英文地名生成

——————————————————

国家生成

——————————————————

中文地名生成

——————————————————

——————————————————

——————————————————

——————————————————

——————————————————

——————————————————

——————————————————

——————————————————

——————————————————

——————————————————

是的,这些都是完全自动生成的,玄幻小说就这么自动出来了

有人说计算机没法真正写作,其实这些人不知道现在的deep learning和neural network已经达到了什么样的程度。就说电影《魔戒》的工作室,就使用自动化程序完成打斗场景,甚至他们描述拥有智能AI的魔兽士兵会自己找地方躲起来,我随便就提供一个机器写作的思路——构造一个足够虚拟的世界,用文字把这个世界和发生的事情描述下来。

有同学问有没有论文自动生成器?我负责任的说,也!有!
此为数学论文生成器————–> 猛戳
此为计算机科学论文生成器————–> 猛戳


只要填上作者名字


自动生成


自动生成


自动生成

——————————————————


填入作者名字


自动生成

不可不看,马化腾海量信息的内部分享

话说在腾讯 WE 大会前夕,忽然有个马化腾对话柳传志的心灵鸡汤式短文在圈内流传,其中包含”腾讯不看好可穿戴设备”、”语音搜索在微信上用处不大”等猛料,但真假一时难辨。

最近,这个讲话的原文竟然放了出来,原来是马化腾在中国企业家俱乐部的内部分享,企鹅君读了一遍,发现原文的信息简直是海量。

为了方便阅读,企鹅君花了好大力气帮大家梳理了其中关键内容,整理如下:

1. 是微信拯救了腾讯。

似乎,小马哥这一年最主要的工作,就是向内部员工传递危机感。而在私下讲话里,小马哥也不忘说下微信是如何在悬崖边上拯救腾讯的,不过这次手机 QQ 躺枪,被形容为

“两三年前已经达到这个水平了,有创新或甚至差点被颠覆的可能性。”

2. 中国的日活 App 排名:微信、QQ、搜狗输入法、Qzone、和 360。

小马哥表示,因为手机其实本身是一个偏通信的,所以很幸运我们刚好做了通信,这是我们占了先机。但为何微博排不进前五,小马哥总结的原因是:

“微博类虽然是算社交媒体,但它也是属于传播类的,转来转去的,是广播型传播的通信,新浪微博在手机上的活跃度,还进不了前五,但是前十以内。”

3. 斗地主用户数据:日活两千万;节奏大师:日活 1700 万。

小马哥表示手机游戏这个东西,他完全不担心,因为:

“韩国、日本,他们在这方面其实是很早就已经证明这个,我丝毫不担心,这个很容易做成的。”

“往后怎么发展,特别是很深的,重度的、大型的游戏要怎么开发,用户会用,其实这个还不太清楚。”

4. 微信做文字搜索很难,但做语音搜索还是有前途的。小马哥表示:

“微信站内搜索其实很难,觉得还是很难,除非是语音,问他要去哪里,问的问题,让他解答,传统的这种搜索搜资讯,如果没有标准 APP 的话,我觉得还是离不开浏览器的搜索,尤其是在手机上打开浏览器操作模式这样一个流程,相对不会说打开一个搜索引擎。”

“语音搜索突然也觉得这个是好的,但是有时候会觉得未必太好,比如说一个人说我要去干嘛干嘛,好傻,人一多我都不好意思这么说,而且也不私密,宁可按几下。我是觉得按道理我应该是支持,但不知道为什么觉得,你跟他讲半天还什么什么,下次就自己输入算了。所以目前这个某些情况下可能可以用,但是我感觉离实用化还远,但是我相信一定会能解决,但是目前人工智能理解,人讲话的意图还没到这步,但我们自己内部也在研发,这一块。”

而对于百度搜索,小马哥的看法是百度在移动端的商业模式上存在很大问题,但不用太悲观:

“百度股价一度比较低迷,曾经到 80 多块钱,最近到 160 了。一是,搜索行为平移到手机之后,每千次搜索的变现能力会不会降太低,因为以前的数据很悲观,只有1/7,1/10。变现能力,很恐怖的,如果说这个,转过来只剩几分之一,这个变现能力多吓人,现在开始慢慢上来了。

第二,在手机上大家是不是不搜索了?直接有 APP 不就完了吗?确实存在这个问题,因为直接点 APP 好过我在手机上打开浏览器搜索。我们现在看这个可能会有一半或者不到一半,但是即使一半,因为刚才讲了,使用时间多很多,薄利多销,这个盘子分母大,就算乘以1/2,可能总数还是达不到,所以也不用那么悲观。”

5. 不看好穿戴式设备。对于穿戴设备,小马哥的看法是:

“穿戴我们觉得最近有点火,但是我都感觉好像还打动不了我,原来我买健康的设备,我买了好多送人,结果发现我自己不能坚持去戴,虽然可以监测身体状况,生病写了几次,发现原来也就是那样,算了不戴了,好像也很难,包括智能手表这些,我都感觉有个手机也够了,智能手表没什么意思。所以我现在还有点慢慢从很兴奋冷静下来,看形势。语音搜索,我也戴过,而且你戴了之后很反感,你一个人爽,我们所有人都觉得你在监视我,我觉得不太好,我这个是比较保守。”

6. 认可为微生活的会员卡模式和微信支付。

腾讯的 O2O 要怎么做?看得出,小马哥还是很认可微生活的 O2O 模式,他表示:

“O2O 我们现在尝试用公众账号,能不能重新再发明一次会员卡,所有商家的会员卡,放到微信上,好处就是已经做了一些尝试了,效果还不错。过去每个商业都有自己的客户,但他跟客户的联系以前靠发会员卡或者是在所有的 CRM,企业有他的客户群,他的客户关系管理,那能不能把他放到微信、移动互联网上来管理,你跟你的用户是可以直接沟通的、是互动的,不像短期那么单调的,是可以写程序在里面,可以交流,甚至还可以充值。”

小马哥以星巴克举例:

“我们正在比如跟星巴克谈这个合作,星巴克用微信做他的会员卡,充值、储值,储值之后就可以算账、可以消费,微信就在卡里面,在星巴克储值卡里面消费就行了。他节省了大量的发卡成本,而且是传播,成为他会员很容易。”

微信支付在当当的例子:

“你买这个书的时候用微信支付可以在完全没有登录状态下匿名访问当当,可以扫这个东西,这个东西我要买,微信登录,一扫之后,然后把微信里面已经开通的银行账号,微信支付,以及我的地址已经带到微信了,直接过去就拿下,不用再输入地址,这个形式可以给所有网站,这个还是蛮创新的,这样的体验。然后他买完之后,顺带订阅了这个账号,成为当当的粉丝,这个书或者你买的商品什么时候到账,通过这个通道告诉实时通讯,这是一个闭环的体验,而且是开放式的。

7. 微信公众平台到底要开放到何种程度?

微信肯定已不止是广研的微信,而外界也不希望微信仅是腾讯的微信,小马哥首次正面谈到微信的开放:

“这个问题很实际,因为我们在想一个问题。肯定是很开放的,但问题是说开放出来的经营者为什么是你这家,而不是另外一家,因为跟你一样的公司很多,这就涉及到你怎么选择的问题,有可能是多家一起进来。”

小马哥表示 O2O 放出去做比较快:

“就算是 O2O 我们做,我们是扒了第一层皮,第二、第三层是由你们来做,而且是非排他的,家家都可以接入,我觉得这样比较完美一点。我我们电商的部门,这个东西我要自己做,我有时候谈到说,行不行,搞了几个月都没出一个好方案出来,做的很慢,因为我们之前做微生活这个,也是搞了好久,最后出来我说这个体验肯定不行,商家热了一下之后慢慢不行,这个很难坚持很久,为什么?因为你自己一家做的速度太慢了,你还不如放开一点把它介绍给别人,让他们去,有时候他们做出来的东西简直超乎我们想象的。

小马哥剥夺了广研做明星公众号的权力:

“我们原来公众账号为一个接口,以前有了,给一些明星开,讲几句话觉得很好,有粉丝,最后慢慢也不行了,这个意义不是很大,没有意义。直到后面冒出来一个叫陈坤,觉得好酷,这个成为一个标杆应用,是全屏幕的,连论坛粉丝甚至成为他的会员,还要付费,做了全套功能,我们说可以做成这样,我们下一步的时候要接手这个,那微信部门说这个东西由他包下来了,算了,这个你自己不能做,没有这个想象力,或者你都不能拿到这个明星的授权,没办法成为官方的一个战略,凭什么去承包的,因为这些有的还要做客户端,这个做也做不好。”

第三方生态对于微信来说非常重要,但开放的底线在哪里?小马哥表示:

“说是开放具体到哪一层,一到十到底是 2.5 还是 3.5,还是5,或者不同的玩法,所以我们现在还在摸索。(对于微信)所谓的营销公司、营销专家,最后多少粉丝之后可以卖的,这个东西只是钱,应该是有这些产业,所以你稍微不慎就会落入这种圈套,最后正常的用户没用上,钱已经花掉了,其实后面是几个帮派,我们最怕是这样的,一抓就死,所以有时候捏在手上不是说我们不开放,是开放了之后乱套了,外面无法无天,以前还是有刷活动,后来停掉了,真的是你有政策,他们比我们内部所有部门动作都快,连夜都赶出来了。

所以这个时候是我们摸着石头过河,现在要表态开放我没准备好,我觉得冒然开放的话大家都把这个东西搞乱了,因为所有人说要开放的时候,做完了怎么办,有没有想到有千千万万像你这样的公司都提同样的要求我怎么办?如果只优待你的话,或者头两三个,其实也是对其他人的不公平,所以我们有时候还要长远来看。我们两难,一是内部的人有时候不该他做的他抢,我们要适当解决;第二是开放出去之后,也可能有不公平,这个是挺为难的,但是我觉得慢慢摸索,一步步去做。”

8. 腾讯千亿美元市值是因为刘炽平的邮件?

腾讯最近压力山大,原因是公司一下子冲到了千亿美元市值,小马哥表示资本市场看多腾讯有两个原因:

一是微信。小马哥的说法是”资本市场给我们的期望很高,很多是因为微信突出来了,有门票了。微信出来之后,就两个月前,游戏出来了,很多从来不玩游戏的人痴迷于里面。”

二是因为刘炽平的内部邮件。小马哥表示:”因为泄露了那篇文章”千亿美金下的反思”,外面人说看了很震动,我当时觉得很奇怪,为什么这么激进?”

小马哥对这件事的总结是,原来移动战略也可以卖钱:

“所以我们的文章泄露出去之后,不仅是阿里了,很多互联网公司都说要移动为先,一切都以移动来发展,都把这个作为下一阶段极其重要的竞争要领来看待。”最终的结果是投资人买单:”所以有很多的投资者是这样的一个期望,把股价炒的很高,PE 也很高,所以我们压力也很大。”

9. 小马哥谈各个行业的颠覆者:只是将互联网作为工具。

互联网颠覆了某个行业,是小马哥最近最爱说的话题,在 WE 大会上小马哥也在说互联网颠覆金融、音乐、游戏等等,不过这针对的都是行业,而非具体案例。而在这次私下分享中,小马哥难得点评了诸多案例,逐一看下:

京东、唯品会。小马哥的点评:京东做 3C 产品,唯品会做服饰,毛利很高的包括有人专门卖钻石的,看似它是互联网公司,实际上还是传统行业,只是用互联网的方式去实现,一定也要在这个行业扎得很深,得知道你的供应链、货源在哪里,怎么做,服务怎么样,是不是很专业。

搜房网。小马哥点评是:不知不觉市值已经跟三大门户不差了,和新浪差不多了,以前觉得搜房网好像很小,但搜房几千人在不同的城市扎得很细。

58 同、美团。小马哥点评:58 同城和团购网站几千人,看着不像那种互联网的清新,其实都要扎得很深,只不过用互联网的方式去做,本质上剥掉互联网的壳,还是传统行业,看到这些都是”又是颠覆、又是改良”的一种结果。

小米。小马哥点评:做手机还能做成这样,它就是用互联网的方式来做的。因为雷军对互联网很熟悉,所以看到他很多的软件、硬件加服务,加粉丝经营,加用户高度介入生产过程,在微博上搞活动,很多人觉得传统手机商不就在微博发几句话吗?是忽悠吗?以为很简单,实际上背后很多是用互联网的思想来做,甚至说硬件不挣钱,靠服务,靠产生的用户群,因为网络硬件是跟用户连在一块的,不是卖完就丢掉用户,不是一个简单的客服,他是卖完之后生意才刚开始。

特斯拉。小马哥的点评是:电动互联网化的智能汽车,也是一样的,一看也是口碑经营,少数的高端精英用户才可以用,然后很酷,这个电动汽车深圳比亚迪不都也有吗?但是思路又不一样,先做跑车,很互联网化,里面全智能的,全部联上网,你做什么事情,车要不要维修,全部通过智能手机可以感应到,包括很多各地充电的桩都是用服务的形式去做,在网上形成口碑。

10. 移动端的商业模式是个问题

小马哥表示,QQ,门户、微博、搜索引擎等各类商业模式,在移动端,今年的都是 10 倍增长,甚至 70% 流量都来自移动端。但是收入方面,移动端对全行业的贡献不超过 10%-20%,这是为什么?小马哥半年前这样判断三种移动端的商业模式:

(1)搜索引擎难以展现。小马哥:”比如说搜索引擎转到手机上,排满了广告位置,没法排在右边,就那么一列。”

(2) 游戏体验差。小马哥:”微信的游戏出来之前,传统的手游其实大家也不觉得怎么样,这个市场没有人用手机玩游戏玩太长时间,付费欲望估计也不高,因为体验也不是太好,而且用大屏幕电脑玩游戏比较爽。”

(3)广告不适合移动端。小马哥:”手机流量这么贵,还加一个广告,一个大大的图,一个视频。不可想象……”

11. 炒 Facebook 股票的教训:移动端建立商业模式的机会来了。

尽管对移动端商业模式曾有怀疑,但最终小马哥发现移动端并不难创收,这竟然是来自看错 Facebook 股票的教训。小马哥表示:

“Facebook 最初上市的时候,通过私人银行还拿了一些股票,熬啊熬啊到最后还往下掉。”最终 25 块就卖掉了,”当时我都觉得很难的,怎么商业化?他确实厉害,美国互联网尖端企业商业化了,后面的金融广告、社交广告的水平还是全球第一流的,他还真的做到了,当然他也得益于各种各样 APP 需要大量广告的这种需求。”

小马哥表示,Facebook 一下子从 25 块到 50 块,是大家终于看到其在无线上的收入模式开始显现,Google 来自无线的收入增长加速,Facebook 好像 40% 的收入开始来自于手机。原来没敢想手机上能商业化,现在做了发现体验还不错,这个数据出来之后股价开始上涨,从 PE 上给了很高溢价。

12. 微信崛起和诺基亚、微软衰落的经验:给自己多一个准备。

小马哥回顾诺基亚衰落:我们看为什么诺基亚曾经如日中天,2000 亿欧元的市值,后来 47 亿美金卖掉了,我们看到他曾经很坚持说我一定不用安卓,我控制不住,它是别人控制的,我坚决不用,但后来衰落了。微软也是坚持说要维护我的 Windows,还有 Office,这是我的摇钱树,这两个是他最大的收入利润,不肯放弃,现在很被动。

小马哥得到的教训是,要给自己多一个准备,即使是比如你开一个另外的部门、另外一个分支,调一些团队,做一些可能跟现在已经拥有的业务其实是有矛盾的,不妨尝试,因为你不做的话你的对手或者是他想抢你市场的对手一定会做,还不如自己先试一下。

这个教训在腾讯自己身上有所体现,小马哥透露了一段当年往事:

“就像我们当时微信推出来的时候,手机 QQ 部门反对,虽然他也看到方向了,他甚至也有一个团队已经在做一个类似的产品,其实两个团队都在做,只是最后谁跑出来受欢迎了,谁用这个软件,最后是我们手机 QQ 的那个团队失败了,他做出来的不好用,微信出来了。

我记得我们推出的时候,因为我们的无线业务部门做出来的东西不如广州研发中心做 QQ 邮箱的团队做得好,那时候运营商,我记得中国移动正在广西、云南开会,数据部立刻打电话给我们 QQ 无线说,这个东西谁做都可以,腾讯做就不行,因为我们有业务合作,在别的地方可能要惩罚你,不结算,是不是有什么不可以做了,这个压力很大。所以我们第一个版本是没有做通信录匹配的,当时联通说你做了那个就触红线了,不许做,好吧,不给匹配。

然后出来的东西就好像一个简版的 QQ,大家用着没意思,这个东西有什么区别,简版 QQ,阉割版 QQ,没有意思。后来开始竞争了,国内已经好几家出来了,我说不行了,给人罚,给人惩罚我们都不管了,通信录要加入,原来我们导入的是 QQ 好友,再加上手机通讯录,这是个很丰富的实验,大家为什么一加入之后,看到有好朋友冒出来,这是通讯录匹配的结果。

第二是加语音对讲,原来没有这个功能,就看着这个增长曲线,很难看的,平的,用的用户不用了,不就是简版的 QQ 吗?没意思,直到加入这个以后,瞬间就上去了。这个很高科技吗?不高科技吧,十年前我们在 PC 上就做过这个尝试,做完之后没人用把它摘掉了。”

13. 回顾微信的运营商危机:小马哥曾要求运营商禁掉所有 OTT 产品。

微信一路走来面临过不少危机,小马哥回顾了下,有信息安全问题:

“比如说用微信练功,还有摇一摇、查看附近,又成为什么约炮工具了,赶紧给处理掉。”

有运营商危机:

“中国移动意见很大,工信部压力很大,我就问工信部,我说如果你能出一个命令说禁止微信团体用,可以,我还有手机 QQ,我不怕,你能不能把全部封掉,包括国外的那些全部封掉。我说那不就是啊,你不做别人进来做了,如果你能一声令下说会威胁运营商,这个东西一律不准做,也可以”

如今还有了竞争对手:

“网易结合中国电信搞了易信,今天说是全网要免流量的,说是送流量。前两天会议我说我们当年跟旺旺竞争,当时主持人郭广昌说,你就把来往当成一个移动旺旺而已啊?我觉得这还是要跟他自己的淘宝用户、电子商务结合,他的定位用于商家和买家之间的,它很难成为一个消费体的沟通工具,这个过去 PC 时代已经完全沿着这样的路,15 年后又再重演一次。”

分享一个自己写的table表格排序js插件(高效简洁)

在前不久做的一个web项目中,需要实现js表格排序的效果,当时为了省事,就在网上找了几个相关的js插件,像:jQuery的table排序插件(感觉其使用比较麻烦或不清楚其具体用法,就没有使用)、原生态js的table排序插件等,最后比较看了下——采用了一个原生态js的table排序插件,并在其基础上做了些修改,虽有些勉强或有些地方使用不太舒服,但最算是比较好的实现了当时需要的功能。而前两天,对原有表格做了点儿修改——增加隔行换色的功能,问题就出现了,——效果错乱;检查分析了下,问题出在其table排序插件代码上——其原代码写的比较难理解,修改还不如重新自己写一个table排序插件。

说写就写,table排序其实很简单:就是取出所有排序列的值并存放在数组中(并且各列对应行对象也存放到一个数组中),然后对排序列的值数组排序(并对行对象数组排序)。下面贴出table排序插件代码:

按 Ctrl+C 复制代码

按 Ctrl+C 复制代码

其使用如下:

复制代码
 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 2 <html xmlns="http://www.w3.org/1999/xhtml">
 3     <head>
 4     <meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
 5     <title>table表格排序</title>
 6     <style type="text/css">
 7     .fu_list{ width:500px; border:1px solid #ebebeb;line-height:20px; font-size:12px;}
 8     .fu_list thead td{background-color:#ebebeb;}
 9     .fu_list td{padding:5px;}
10     .fu_list a{outline:none;/*ff*/hide-focus:expression(this.hideFocus=true);/*ie*/}
11     .fu_list a:link, .fu_list a:visited, .fu_list a:hover, .fu_list a:active{text-decoration:none;color:#333;}
12     .fu_list thead a{padding-right:15px;}
13     .fu_list thead a.up, .fu_list thead a.down{ background:url() right center no-repeat; }
14     .fu_list thead a.down{background-image:url();}
15     
16     .hoverTr{background-color:Orange;}
17     </style>
18     </head>
19     <body>
20     <table border="0" cellspacing="0" cellpadding="0" class="fu_list" id="idTable">
21     <thead>
22     <tr>
23     <td> <a href="javascript:void(0)" id="idTitle">名称</a> / <a href="javascript:void(0)" id="idExt">类型</a></td>
24     <td width="150" align="center"><a href="javascript:void(0)" id="idAddtime" class="up">上传时间</a></td>
25     <td width="50" align="center"><a href="javascript:void(0)" id="idSize">大小</a></td>
26     </tr>
27     </thead>
28     <tbody>
29     <tr>
30     <td _order="JSCSS">JSCSS</td>
31     <td align="center" _order="2008/9/12 8:51:09">2008/9/12 8:51:09</td>
32     <td align="right" _order="433247">433247</td>
33     </tr>
34     <tr>
35     <td _order="逗你玩">逗你玩</td>
36     <td align="center" _order="2008/3/6 20:12:23">2008/3/6 20:12:23</td>
37     <td align="right" _order="11394">11394</td>
38     </tr>
39     <tr>
40     <td _order="张迪">张迪</td>
41     <td align="center" _order="2008/10/4 20:21:54">2008/10/4 20:21:54</td>
42     <td align="right" _order="351">351</td>
43     </tr>
44     <tr>
45     <td _order="Index">Index</td>
46     <td align="center" _order="2008/10/4 20:24:11">2008/10/4 20:24:11</td>
47     <td align="right" _order="14074">14074</td>
48     </tr>
49     <tr>
50     <td _order="阿波罗">阿波罗</td>
51     <td align="center" _order="2008/10/4 20:24:11">2008/10/4 20:24:11</td>
52     <td align="right" _order="2844">2844</td>
53     </tr>
54     <tr>
55     <td _order="张涛">张涛</td>
56     <td align="center" _order="2012/10/4 20:21:54">2012/10/4 20:21:54</td>
57     <td align="right" _order="1236">1236</td>
58     </tr>
59     <tr>
60     <td _order="jSSon">jSSon</td>
61     <td align="center" _order="2010/12/12 8:51:09">2010/12/12 8:51:09</td>
62     <td align="right" _order="10101">10101</td>
63     </tr>
64     </tbody>
65     </table>
66     <script src="jquery-1.4.1.min.js" type="text/javascript"></script>
67     <script src="TableOrder.js" type="text/javascript"></script>
68     <script src="ZhCN_Pinyin.min.js" type="text/javascript"></script>
69     <script type="text/javascript">
70         TableOrderOper.Init("idTable", 0, {
71             OnShow: function (i, trJqObj, _tbodyObj) {
72                 trJqObj.attr("class", ((i + 1) % 2 == 0 ? "hoverTr" : ""));
73             }
74         });
75         TableOrderOper.SetOrder("idTitle", 0, { ValAttr: "_order", DataType: "string" });
76         TableOrderOper.SetOrder("idAddtime", 1, { ValAttr: "_order", DataType: "date" });
77         TableOrderOper.SetOrder("idSize", 2, { DataType: "int", DefaultOrder: true, OnClick: function () {
78             alert("idSize"); 
79         } });
80     </script>
81     </body>
82     </html>
复制代码

代码中注释我都尽量写的比较清楚了,需要补充说明的是:

1.js使用的是闭包,我强调代码要尽可能的简洁易懂。

2.IsLazyMode属性设置,IsLazyMode=true,适用于当前要排序的表格是不变的,即不会有ajax的增删改行的操作,而且你看代码后就可以看出的一个好处:把要排序列的对应的行对象只一次遍历,并将排序后的行对象数组保存在全局对象中,下次排序时直接通过tdIndex(排序列的索引)取出对应的行对象数组,并将数组反转,即可实现排序的效果,可以在一定程度上提高代码执行效率(性能); IsLazyMode=false, 即适用于当前要排序的表格会改变,如有ajax的增删改行的操作的情况。

3.考虑一般要排序的表格数据量都不大,其中的数组排序使用的是冒泡排序算法。

4.OnShow: null  //排序后表格显示时的方法,params:trIndex,trJqObj,tbodyObj ——可方便用于设置排序后的表格的换行样式等,也出于对性能优化方面的考虑。

好了,最后,附上插件js和demo,目前的实现只能说是能很好的满足我当前项目中的需求或适用于于大多数的场景,如果有没有考虑到或不好的地方,希望各位路过的朋友,能毫不客气的拍砖留言,大家互相交流学习!

Demo下载(2012-12-08最新版:修改了对汉字排序有误的问题,可以实现字母汉字混排(其实现是:将汉字转换为全拼,统一按字母排序))

订单系统开发(仿淘宝和美团网) 之 项目总结

基于公司战略的调整和开发框架的升级换代,也伴随着SOP(面向服务编程)和SOA(面向服务架构)的软件开发思想在公司开发团队中的慢慢深入,最终讨论决定在将现有(旧)的支撑公司业务的项目模块(如:产品,商家和订单…)在进行底层架构升级的同时,要让这个模块在一定程度上可以达到复用性——即它应该可以满足新的栏目(‘同城网购’)的相关需求且适当的考虑未来的需求扩展,它不能跟其它的模块耦合在一起,只负责属于这个模块领域内的数据服务(如:产品模块只用考虑产品相关数据的读写),可以独立公开作为一个服务,且可以满足分布式部署的需求(这个由新的基于CSLA的底层框架管理和决定)。 大概从今年1月份,我决定负责订单系统这块儿的设计和开发,由于中间有一些其它的原因,一直到4月中旬——这期间,我更多的是了解和研究淘宝订单交易的各个流程和相关细节,并做了主体的订单系统领域模型分析,这算是前期’耗时长效率低’的最初版的系统设计,也为后期的详细设计打下了基础和铺垫!

由于之前的订单模块,不是我开发的,也只能负责简单的交易处理,所以除了我从淘宝上做流程和数据分析别无参考;淘宝每天都有很多人在用,我也偶尔上去逛逛买点儿东西,但是如果我不负责这个订单系统的开发,我也不会感受到其流程之“复杂”——复杂背后带来的却是我们热衷使用的良好的“用户体验性”。

淘宝的订单系统很庞大,我目前开发的只仿照了其中65%左右的功能,即:从交易开始到交易结束最主要的的交易流程,像:售后、投诉等暂未实现。相对而言,美团网的订单交易就比较简单,可以算作是包含在淘宝订单交易中的一种特殊订单类型:虚拟物品(代金卷,代金卷即为美团卷)订单。

交易总流程图如下:

点击查看大图

想必你看了上面的总流程图,就会感觉流程之复杂——相对于其它的比较单纯的信息类的数据(如:新闻,产品…),订单这部分的数据都是有状态且有超时时间,这也是订单系统设计和开发的难点!(会在之后的博客中跟大家分享我在做这个订单系统的设计想法)。

我们平时可能会使用到淘宝、美团和京东等多个电子商务网站里的订单系统,对于使用体验一般大部分都大同小异,这样的话,订单系统的开发到底应该要满足或达到什么样的需求标准?
在满足在线交易“方便、快捷”的基本前提下,让买卖双方在订单系统中能自助(可选择)、人性化比较顺畅安全可靠的完成交易中的各个(买家退款等)流程.

这就是我对上面问题的回答,也是我对自己开发订单系统所定的标准。

  电子交易操作的安全基本要求

  • 信息的保密性
  • 交易者身份的认证(确认和鉴别)
  • 不可否认性(交易的确定性)
  • 信息的完整性(信息的准确可靠,不可修改)

这是之前在网上看到的一段内容,同样也是我开发的技术要求指南!

先写到这儿吧,这篇博客算是做个大概的描述;很久没写博客了,这期间一直忙着做这个订单系统的开发,虽然很累,但现在基本上算是开发’成功’结束了,有不少细节需要完善。写此系列的博客,也是希望大家能多提意见并分享你的想法和经验!

 

继上一篇”订单系统开发(仿淘宝和美团网) 之 项目总结(一)”,这篇博客重点想说下订单系统开发的设计和有待优化改进的问题。

 

上图是订单系统数据库设计比较重要的一个——其决定了订单数据的横向切割,而不是将所有的订单数据都存放在一个表中。为什么要这样设计?这样做有什么好处?(看下文便可知晓)  回答上面的疑问,我感觉有必要引出另外一个问题:对于数据库设计,如何能降低并发量 或 提高数据的读写数度?我所知道和比较常见的做法如下:——

1.读写数据库分离,了解数据库的都知道:数据库的(读)共享锁S和(写)排它锁(X)是互斥、无法共存的,即当一个表的数据在被修改时,会阻止其它用户的读取。  

  2.数据库表的横向(行数据)和纵向(数据列)切割。  

  3.对于基本上不会用户查询的多个列,可以使用json或二进制等压缩序列化列字段存放数据,这样有点儿类似于Google的Big Table,有助于提高查询效率。

以上除了第一点在本次订单系统开发中都有使用,而且我相信你看完了上图,你应该会感觉到这样的数据切割:数据的存放(位置)比较清晰,比如:对于‘未付款’的订单数据,它一定是存放于Order_OrderInfo_Temp表中,这样:用户在搜索订单状态为“未付款”的订单时,可以很快方便的从此表中查询;或当用户在进行“取消交易”的操作时,基于上面第一点所提到的,它不会影响到处于’交易中’的订单用户的操作。

写到这儿,感觉有点儿戛然而止——不知道该写点儿啥了;回顾这个项目的开发历程,模糊→清晰→迷茫→纠结→释然,这就是我在项目的各个阶段的感受,用一句话来形容就是:由最开始的感觉高山仰止、举步维艰,到现在的“神马都是浮云”,困难都是暂时的,等你越过去(把它踩在脚下),你也就感觉那算不上什么。

现在只想谈下,有待优化和比较棘手的地方——

1.目前的订单系统跟支付系统的相互依赖程度比较高,以至于订单的各个阶段的操作,如:付款,买家确认收货…,都需要调用支付系统的服务,以保证两边数据的同步。

2.由于支付系统是基于第三方支付平台相关服务方法的封装,即支付系统对“现金”进出操作只相当于是个通道,无法控制和保证每个操作的成功。

3.基于以上两点,订单系统与之交互的操作就比较被动,让人感觉很不舒服,增大了程序的复杂度。

4.订单和退款超时数据的处理,目前没有使用定时器或数据库job,暂时用几个触发点来代替,这样从服务到UI都增加了相应的代码处理。

怎样让订单系统和支付系统尽可能的’解耦’,这将是下一个版本需要重点解决的问题!

就写到这吧,希望有这方面经验的朋友,能提些建议。

 

转自:http://www.cnblogs.com/know/p/3197952.html

.net实现生成及打印条形码功能

.net实现生成及打印条形码功能,下面简单总结了自己的实现方法。
1.引用dll文件
将FLX.WebControls.dll文件拷贝到顶目的bin文件夹目录中;

2.配置web.config文件
之间添加如下代码


3.新建aspx文件,代码如下
前台文件:



打印条形码











后台文件:

protected System.Web.UI.WebControls.Image ImageCode;
protected System.Web.UI.WebControls.Label LblName;
private void Page_Load(object sender, System.EventArgs e)
{
// 在此处放置用户代码以初始化页面
this.LblName.Text =Request.QueryString[“Name”].ToString();
this.ImageCode.ImageUrl =Request.QueryString[“Url”].ToString();
}
引用JS代码:

String.prototype.getQuery = function(name){
var reg = new RegExp(“(^|&)”+ name +”=([^&]*)(&|$)”);
var r = this.substr(this.indexOf(“\?”)+1).match(reg);
if (r != null) return unescape(r[2]);
return null;
}

//创建WebBrowser控件
var createWebBrowser = function(){
document.getElementById(“span”).innerHTML = ‘‘;

}
//创建按钮
var createButton = function(vID,vValue,eventHandler){
var btnButton = document.createElement(“INPUT”);
btnButton.type =”Button”;
btnButton.id = vID;
btnButton.value = vValue;
btnButton.onclick = eventHandler;
document.getElementById(“span”).appendChild(btnButton);
}
//创建标签
var createSpan = function(vID,vValue,eventHandler){
var htmSpan = document.createElement(“span”);
htmSpan.id = vID;
htmSpan.innerHTML = vValue;
if(eventHandler != null)
htmSpan.onclick = eventHandler;
document.getElementById(“span”).appendChild(htmSpan);
}
//创建标签
var createTextBox = function(vID,vValue,eventHandler,width){
var btnButton = document.createElement(“INPUT”);
btnButton.type =”text”;
btnButton.id = vID;
btnButton.value = vValue;
btnButton.width = width;
if(eventHandler != null)
btnButton.onclick = eventHandler;
document.getElementById(“span”).appendChild(btnButton);
}
//按钮事件
var print = function(){
pagesetup_null();
document.all.WebBrowser.ExecWB(6,1);
}
var directPrint = function(){
pagesetup_null();
document.all.WebBrowser.ExecWB(6,6);
}
var PrintSetUp = function(){
pagesetup_null();
document.all.WebBrowser.ExecWB(8,1);
}
var PrintReview = function(){
pagesetup_null();
document.all.WebBrowser.ExecWB(7,1);
}
var PrintFirst = function(){
window.location.href = window.location.href
.replace(/\?PageIndex=(\d)*$/g,””).replace(/\?PageIndex=(\d)*&/g,”?”).replace(/&PageIndex=(\d)*&/g,”&”).replace(/&PageIndex=(\d)*$/g,””)
+”&PageIndex=1″;
}
var PrintLast = function(){
var last = parseInt(window.location.toString().getQuery(‘LastPage’));
window.location.href = window.location.href
.replace(/\?PageIndex=(\d)*$/g,””).replace(/\?PageIndex=(\d)*&/g,”?”).replace(/&PageIndex=(\d)*&/g,”&”).replace(/&PageIndex=(\d)*$/g,””)
+”&PageIndex=”+last;
}
var PrintPre = function(){
var index = parseInt(window.location.toString().getQuery(‘PageIndex’));
if(index>1)
window.location.href = window.location.href
.replace(/\?PageIndex=(\d)*$/g,””).replace(/\?PageIndex=(\d)*&/g,”?”).replace(/&PageIndex=(\d)*&/g,”&”).replace(/&PageIndex=(\d)*$/g,””)
+”&PageIndex=”+(index-1);
else alert(“到头了”);
}
var PrintNext = function(){
var index = parseInt(window.location.toString().getQuery(‘PageIndex’));
var last = parseInt(window.location.toString().getQuery(‘LastPage’));
if((index+1)<=last) window.location.href = window.location.href .replace(/\?PageIndex=(\d)*$/g,"").replace(/\?PageIndex=(\d)*&/g,"?").replace(/&PageIndex=(\d)*&/g,"&").replace(/&PageIndex=(\d)*$/g,"") +"&PageIndex="+(index+1); else alert("到头了"); } var ShowPageIndex= function(){ } var GoPage= function(){ var pageSize = document.getElementById('txtPageSize').value.replace(/\s+/,""); if(/^\d+$/.test(pageSize)) { var href = window.location.href.replace(/\?PageIndex=(\d)*$/g,"").replace(/\?PageIndex=(\d)*&/g,"?").replace(/&PageIndex=(\d)*&/g,"&").replace(/&PageIndex=(\d)*$/g,"") .replace(/\?LastPage=(\d)*$/g,"").replace(/\?LastPage=(\d)*&/g,"?").replace(/&LastPage=(\d)*&/g,"&").replace(/&LastPage=(\d)*$/g,"") .replace(/\?PageSize=(\d)*$/g,"").replace(/\?PageSize=(\d)*&/g,"?").replace(/&PageSize=(\d)*&/g,"&").replace(/&PageSize=(\d)*$/g,"") .replace(/\?pagesize=(\d)*$/g,"").replace(/\?pagesize=(\d)*&/g,"?").replace(/&pagesize=(\d)*&/g,"&").replace(/&pagesize=(\d)*$/g,"") +"&PageSize="+pageSize; window.location.href = href; } else { alert("请输入数字"); document.getElementById('txtPageSize').focus(); } } //设置网页打印的页眉页脚为空 function pagesetup_null(){ var hkey_root,hkey_path,hkey_key; hkey_root="HKEY_CURRENT_USER" hkey_path="\\Software\\Microsoft\\Internet Explorer\\PageSetup\\"; try{ var RegWsh = new ActiveXObject("WScript.Shell"); hkey_key="header"; RegWsh.RegWrite(hkey_root+hkey_path+hkey_key,""); hkey_key="footer"; RegWsh.RegWrite(hkey_root+hkey_path+hkey_key,""); }catch(e){} } window.onload = function(){ document.getElementById('span').innerHTML = ""; createWebBrowser(); createButton("btn0","打印",print); createButton("btn1","直接打印",directPrint); createButton("btn2","页面设置",PrintSetUp); createButton("btn3","打印预览",PrintReview); if(window.location.toString().getQuery('PageSize') != null || window.location.toString().getQuery('pagesize') != null) { createButton("btn4","第一页",PrintFirst); createButton("btn5","上一页",PrintPre); createButton("btn6","下一页",PrintNext); createButton("btn7","末 页",PrintLast); var index = parseInt(window.location.toString().getQuery('PageIndex')); var last = parseInt(window.location.toString().getQuery('LastPage')); createSpan("span0"," 当前第 "+index+"/"+last+" 页 ",null); if(index==1){document.getElementById("btn5").disabled = true;document.getElementById("btn4").disabled = true;} if(index==last){document.getElementById("btn6").disabled = true;document.getElementById("btn7").disabled = true;} if(window.location.toString().getQuery('UserSetSize') != null || window.location.toString().getQuery('usersetsize') != null) { var usersetsize = ""; if(window.location.toString().getQuery('UserSetSize') != null) usersetsize = window.location.toString().getQuery('UserSetSize'); else if(window.location.toString().getQuery('usersetsize') != null) usersetsize = window.location.toString().getQuery('usersetsize'); if(usersetsize.toUpperCase()=='Y') { createSpan("span1","每页显示",null); var pagesize = 0; if(window.location.toString().getQuery('PageSize') != null) pagesize = parseInt(window.location.toString().getQuery('PageSize')); else if(window.location.toString().getQuery('pagesize') != null) pagesize = parseInt(window.location.toString().getQuery('pagesize')); createTextBox("txtPageSize",pagesize,null,40); createButton("PageSizeSet","设 置",GoPage); } } } var mess = "如系统中的打印功能无法正常使用,请更改IE浏览器设置:
“;
mess +=”更改步骤:1、选择IE功能菜单中工具(T)—>Internet选项(O);
“;
mess +=”          2、在弹出的“Internet选项”窗口中,选择“安全”标签;
“;
mess +=”          3、选择“自定义级别(C)”;
“;
mess +=”          4、在弹出的“安全设置”窗口中,找到“ActiveX 控件和插件”项;
“;
mess +=”          5、将其下面所有项选择为“启用”,然后“确定”。
“;
document.getElementById(‘message’).innerHTML = mess;
}

引用样式CSS:

body
{
background-color:White;
font-family:宋体;
font-size:9pt;
color:#3F3F3F;
}

td, div
{
font-family:宋体;
font-size:9pt;
}

a
{
color:#DD3409;
text-decoration:none;
}

a:hover
{
color:#DD3409;
text-decoration:underline;
}

ul
{
list-style-image: url(images/bullet.gif);
list-style-type:square;
list-style-position:outside;
margin-left:18px;
margin-top:5px;
color:#666666;
padding-left:2px;
}

ol
{
list-style-position:outside;
margin-left:25px;
margin-top:5px;
}

h1
{
font-family:宋体;
font-weight:bold;
font-size:18px;
color:#3F3F3F;
margin-top:12px;
margin-bottom:40px;
}

h2
{
font-family:宋体;
font-weight:bold;
font-size:18px;
color:#3F3F3F;
margin-top:15px;
margin-bottom:15px;
}

h3
{
font-family:宋体;
font-weight:bold;
font-size:12px;
margin-top:2px;
margin-bottom:2px;
}

.TopNavLink
{
font-size:9pt;
color:#3F3F3F;
}

.WelcomeTitle
{
font-family:宋体;
font-size:23px;
font-weight:900;
letter-spacing:-0.2mm;
margin-top:9pt;
margin-bottom:20px;
}

.MainText
{
font-size:9pt;
}

.SmallText
{
font-size:9pt;
}

.Hint
{
color:Red;
}

.DemoArea
{
border:1px silver solid;
padding:8px;
background-color:#F6F6F6;
}

.AboutBox
{
border:1px #E6E6E6 solid;
background-color:#DDDDDD;
background-image: url(images/about_background.gif);
}

.SidePanel
{
padding: 9pt;
border:1px;
border-color:#AAAAAA;
border-style: solid;
background-color:#F3F3F3;
font-size:9pt;
color:#666666;
}

.DemosNav
{
padding: 0px;
border:1px;
border-color:#AAAAAA;
border-style: solid;
background-color:#F3F3F3;
}

.DemoCategory
{
color:black;
font-family: 宋体;
font-size: 9pt;
font-weight:bold;
cursor: default;
}

.DemoCategoryOver
{
color:black;
font-family: 宋体;
font-size: 9pt;
font-weight:bold;
text-decoration:underline;
cursor: default;
}

.Demo
{
font-family: 宋体;
font-size: 9pt;
padding: 1px;
padding-left:2px;
padding-right:2px;
border:1px;
border-color:#F3F3F3;
border-style: solid;
cursor: default;
}

.DemoHover
{
font-family: 宋体;
font-size: 9pt;
padding: 1px;
padding-left: 2px;
padding-right: 2px;
background-color:#cccccc;
border:1px;
border-color:gray;
border-style: solid;
cursor: default;
}

.DemoSelected
{
font-family: 宋体;
font-size: 9pt;
padding: 1px;
padding-left: 2px;
padding-right: 2px;
background-color:#FFFFFF;
border:1px;
border-color:gray;
border-style: solid;
cursor: default;
}

input
{
font-family: 宋体;
font-size: 9pt;
}

select
{
font-family:宋体;
font-size:9pt;
}

4.调用此打印页面

5.效果展示

追加:

.NET 条形码控件信息

下载地址:
http://d.download.cobainsoft.com/CobainBarCodeDemo.rar
Web演示地址:
http://product.cobainsoft.com/barcodecontrol/demo.aspx
Web版本中的Request参数说明:
http://support.cobainsoft.com/KB/detail.aspx?id=16

C#基础之数组排序,对象大小比较

从个小例子开始:

1
2
3
int[] intArray = new int[]{2,3,6,1,4,5};
Array.Sort(intArray);
Array.ForEach<int>(intArray,(i)=>Console.WriteLine(i));

这个例子定义了一个int数组,然后使用Array.Sort(arr)静态方法对此数组进行排序,最后输出排序后的数组。以上例子将毫无意外的依次输出1,2,3,4,5,6.

为什么Array的Sort方法可以正确的对int数组进行排序呢,我们自定义类可以吗?试试看,如下代码:

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
public class Student
{
    public int Age { get; set; }
    public string Name { get; set; }
    public int Score { get; set; }
}
static void Main(string[] args)
{
    Student[] students = new Student[]{
        new Student(){Age = 10,Name="张三",Score=70},
        new Student(){Age = 12,Name="李四",Score=97},
        new Student(){Age = 11,Name="王五",Score=80},
        new Student(){Age = 9,Name="赵六",Score=66},
        new Student(){Age = 12,Name="司马",Score=90},
    };
    Console.WriteLine("--------------默认排序输出--------");
    Array.Sort(students);
    Array.ForEach<Student>(students,(s)=>Console.WriteLine(string.Format("{0}{1,2}岁了,他的分数是{2,3}",s.Name,s.Age,s.Score)));
    Console.Read();
}

我们定义了Student类然后同样对他的数组进行排序,程序正确的编译通过,但是运行出错,运行时抛出了异常:System.InvalidOperationException{“Failed to compare two elements in the array.”},这个异常的InnerException是ArgumentException{“At least one object must implement IComparable.”};运行时异常说明:我们要使用Array.Sort(arr)静态方法,必须得保证数组中有一个元素实现IComparable接口。既然如此我们就让Student类实现IComparable接口.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Student :IComparable
{
    public int Age { get; set; }
    public string Name { get; set; }
    public int Score { get; set; }
    /// <summary>
    /// 实现IComparable接口,用Age做比较
    /// </summary>
    /// <param name="obj">比较对象</param>
    /// <returns>比较结果</returns>
    public int CompareTo(object obj)
    {
        if (obj is Student)
        {
           return Age.CompareTo(((Student)obj).Age);
        }
        return 1;
    }
}

在Student类中实现了IComparable接口,在CompareTo方法中比较Student的Age属性,这一次再次编译运行,程序正常的输出了按照年龄排序的Student数组。

假如说我们要对Student的Score属性进行排序该怎么办呢? Student类实现的IComparable接口只能按照一种属性排序呀。

这个是很容易实现的.net的类库开发者早为我们准备了另一个接口IComparer<T>接口用来实现比较类型T的两个实例。如下StudentScoreComparer类实现了对Student按照Score属性比较的IComparer<Student>

1
2
3
4
5
6
7
public class StudentScoreComparer : IComparer<Student>
{
    public int Compare(Student x, Student y)
    {
        return x.Score.CompareTo(y.Score);
    }
}

现在我们可以使用下面代码对Student数组按照Score属性进行排序:

1
2
3
Console.WriteLine("----------按分数排序输出------------");
Array.Sort(students, new StudentScoreComparer());
Array.ForEach<Student>(students, (s) => Console.WriteLine(string.Format("{0}{1,2}岁了,他的分数是{2,3}", s.Name, s.Age, s.Score)));

不过一个简单的按照Score属性排序,再定义一个类是不是有点大题小作呀,有没有更好的办法呢?当然有. .net为我们准备了比较对象大小的委托Comparison<T>我们可以使用拉姆达表达式或者匿名委托直接排序,如下代码实现:

1
2
3
Console.WriteLine("----------按分数排序输出----------");
Array.Sort(students, (s1, s2) => s1.Score.CompareTo(s2.Score));
Array.ForEach<Student>(students, (s) => Console.WriteLine(string.Format("{0}{1,2}岁了,他的分数是{2,3}", s.Name, s.Age, s.Score)));

完整代码示例如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SortingInCSharp
{
class Program
{
public class Student : IComparable
{
public int Age { get; set; }

public string Name { get; set; }

public int Score { get; set; }

/// <summary>
/// 实现IComparable接口,用Age做比较
/// </summary>
/// <param name=”obj”>比较对象</param>
/// <returns>比较结果</returns>
public int CompareTo(object obj)
{
if (obj is Student)
{
return Age.CompareTo(((Student)obj).Age);
}

return 1;
}
}

static void Main(string[] args)
{
Student[] students = new Student[]{
new Student(){Age = 10,Name=”张三”,Score=70},
new Student(){Age = 12,Name=”李四”,Score=97},
new Student(){Age = 11,Name=”王五”,Score=80},
new Student(){Age = 9,Name=”赵六”,Score=66},
new Student(){Age = 12,Name=”司马”,Score=90},
};

Console.WriteLine(“————–默认排序输出——–“);
Array.Sort(students);
Array.ForEach<Student>(students, (s) => Console.WriteLine(string.Format(“{0}{1,2}岁了,他的分数是{2,3}”, s.Name, s.Age, s.Score)));

Console.WriteLine(“———-按分数排序输出————“);
Array.Sort(students, new StudentScoreComparer());
Array.ForEach<Student>(students, (s) => Console.WriteLine(string.Format(“{0}{1,2}岁了,他的分数是{2,3}”, s.Name, s.Age, s.Score)));

Console.WriteLine(“———-按分数排序输出———-“);
Array.Sort(students, (s1, s2) => s1.Score.CompareTo(s2.Score));
Array.ForEach<Student>(students, (s) => Console.WriteLine(string.Format(“{0}{1,2}岁了,他的分数是{2,3}”, s.Name, s.Age, s.Score)));

Console.Read();
}

public class StudentScoreComparer : IComparer<Student>
{
public int Compare(Student x, Student y)
{
return x.Score.CompareTo(y.Score);
}
}
}
}

总结:

在C#中有三个关于比较对象大小的接口,分别是IComparable、IComparable<T>和IComparer<T>。 IComparable和IComparable<T>是类本身实现的在实例之间比较大小的行为定义。IComparer<T>是定义在被比较类之外的专门比较两个T类型对象大小的行为,另外还有一个用于比较的委托定义Comparison<T>可以让我们用拉姆达表达式或者匿名委托或方法更方便的排序。

VMware Workstation下VMnet1等虚拟网卡与主机网卡之间的关系

 1虚拟网络设置

默认情况下,VMware Workstation的虚拟网卡使用192.168.1.0~192.168.254.0范围中的(子网掩码为255.255.255.0)两个网段(对应于第一块虚拟网卡VMnet1和第2块虚拟网卡VMnet8),即使在同一台主机上安装VMware,在每次安装的时候,其使用的网段也不固定。在用VMware Workstation做网络实验的时候,这样很不方便,我个人习惯于把VMware使用的网段“固定”,通常采用下面的原则,如表1所示。
1 VMware虚拟网卡使用网络地址规划表
虚拟网卡名称
使用网段
子网掩码
VMnet1(即host网卡)
192.168.10.0
255.255.255.0
VMnet2(默认没有安装)
192.168.20.0
255.255.255.0
VMnet3(默认没有安装)
192.168.30.0
255.255.255.0
VMnet4(默认没有安装)
192.168.40.0
255.255.255.0
VMnet5(默认没有安装)
192.168.50.0
255.255.255.0
VMnet6(默认没有安装)
192.168.60.0
255.255.255.0
VMnet7(默认没有安装)
192.168.70.0
255.255.255.0
VMnet8(即NAT网卡)
192.168.80.0
255.255.255.0
使用表1的地址只是为了统一和方便,读者可以根据自己的爱好进行规划。另外,在做实验的过程中,这个地址是可以随时修改的。
在使用Team做实验时,Team中的LAN1、LAN2则依次使用192.168.101.0/24、192.168.102.0/24的地址.
 

2虚拟网卡(虚拟交换机)的关系

许多初学者不容易理解VMnet1和VMnet8虚拟网卡的关系,实际上,这与现实生活中的计算机选择接入那个交换机有相似之处。
在现实生活中的计算机,如果有网卡,可以连接到交换机或集线器中,如果现实生活中的计算机所处的环境,有多个交换机(或集线器),可以选择连接到那一个交换机或集线器。
而在使用VMware Workstation创建虚拟机时,创建的虚拟机中可以包括网卡。你可以根据需要选择使用何种虚拟网卡,从而表明想要连接到那个虚拟交换机。在VMware Workstation中,默认有3个虚拟交换机,分别是VMnet0(使用桥接网络)、VMnet1(仅主机网络)和VMnet8(NAT网络),还可以根据需要添加VMnet2~VMnet7和VMnet9等7个虚拟机交换机,而在VMware Workstation 5以后的版本中,还可以使用Team中的提供的虚拟交换机。
【说明】 Team中的虚拟机交换机与VMnet0~VMnet9虚拟交换机不同之处在于,Team中的交换机与主机网络不发生关系,而VMnet0~VMnet9虚拟交换机是与主机相连。并且,Team中的虚拟交换机可以限制网络速度。
下面介绍VMnet0、VMnet1、VMnet8虚拟交换机的关系,这可以在表2中看到。VMnet2等交换机,可以根据需要设置的与VMnet0、VMnet1或VMnet8相同,所以不在介绍。
2  虚拟机网络连接属性意义
选择网络连接属性
意义
Use bridged networking(使用桥接网络)
使用(连接)VMnet0虚拟交换机,此时虚拟机相当于网络上的一台独立计算机,与主机一样,拥有一个独立的IP地址,效果如图2-56所示
Use network address translation(NAT)(使用NAT网络)
使用(连接)VMnet8虚拟交换机,此时虚拟机可以通过主机单向访问网络上的其他工作站(包括Internet网络),其他工作站不能访问虚拟机,效果如图2-57所示
Use Host-Only networking(使用主机网络)
使用(连接)VMnet1虚拟交换机,此时虚拟机只能与虚拟机、主机互连,与网络上的其他工作站不能访问,如图2-58所示
Do not use a network connection
虚拟机中没有网卡,相当于“单机”使用
虚拟机A1、虚拟机A2是主机A中的虚拟机,虚拟机B1是主机B中的虚拟机。在图2-56中,如果A1、A2与B都采用“桥接”模式,则A1、A2、B1与A、B、C任意两台或多台之间都可以互相访问(需要设置为同一网段),这时A1、A2、B1与主机A、B、C处于相同的身份,相当于插在交换机上的一台“联网”的计算机。
图2-56  桥接方式网络关系
【说明】 虚拟机A1、虚拟机A2是主机A中的虚拟机,虚拟机B1是主机B中的虚拟机。其中的“NAT路由器”是只启用了NAT功能的路由器,用来把VMnet8交换机上联接的计算机通过NAT功能连接到VMnet0虚拟交换机。如果B1、A1、A2设置成NAT方式,则A1、A2可以单向访问主机B、C,B、C不能访问A1、A2;B1可以单向访问主机A、C,C、A不能访问B1;A1、A2与A,B1与B可以互访。
 
图2-57  NAT方式网络关系
【说明】
1. 虚拟机A1、虚拟机A2是主机A中的虚拟机,虚拟机B1是主机B中的虚拟机。如果B1、A1、A2设置成host方式,则A1、A2只能与A互相访问,A1、A2不能访问主机B、C,也不能被这些主机访问;B1只能与B互相访问,B1不能访问主机A、C,也不能被这些主机访问。
2. 在使用虚拟机“联网”的过程中,可以随时更改虚拟机连接到的“虚拟交换机”,这相当于在真实的局域网环境中、把网线从一台交换机上插到另一台交换机上一样。当然,在虚拟机中改变网络要比实际上插拔网线方便多了。和真实的环境一样,在更改了虚拟机的联网方式后,还需要修改虚拟机中的IP地址以适应联网方式的改变。例如,在图2-56中,假设主机的VMnet1使用网段地址192.168.10.0,VMnet8使用网段地址为192.168.80.0,网关地址为192.168.80.2(相当于图2-57中“NAT路由器”内网地址),主机网卡使用地址为192.168.1.1。假设虚拟机A1开始被设置成桥接方式,虚拟机A1的IP地址被设置为192.168.1.5。如果虚拟机A1想使用host方式,则修改虚拟机的网卡属性为“Host-Only”,然后在虚拟机中修改IP地址为192.168.10.5即可(也可以设置其他地址,只要网段与host所用网段在同一子网即可,下同);如果虚拟机A1想改用NAT方式,则修改虚拟机的网卡属性为“NAT”,然后在虚拟机中修改IP地址为192.168.80.5,设置网关地址为192.168.80.2即可。
 
图2-58  host方式网络关系

asp.net发布到IIS中出现错误:处理程序“PageHandlerFactory-Integrated”在其模块列表中有一个错误模块“ManagedPipelineHandler”

开发web项目时需要安装IIS,在安装好IIS的Windows7本上发布asp.net网站时,web程序已经映射到了本地IIS上,但运行如下错误提示“处理程序“PageHandlerFactory-Integrated”在其模块列表中有一个错误模块“ManagedPipelineHandler”

 

 我要发布的的web项目开发工具及所用系统

①开发工具:vs2010、数据库:sqlserver

②操作系统:windows7

③IIS:IIS 7.5

 

 

一.上述错误详情图:

二.上述错误分析:

vs2010默认采用的是.NET 4.0框架,4.0框架是独立的CLR,和.NET 2.0的不同,如果想运行.NET 4.0框架的网站,需要用aspnet_regiis注册.NET 4.0框架,然后用.NET 4.0框架的class池,就可以运行.NET 4.0框架的web项目了。

造成上述错误的原因极有可能是:由于先安装.NetFramework v4.0后安装iis 7.5所致。

 

三.如何用aspnet_regiis注册4.0框架?

方法如下:

①找到.NET 4.0框架下aspnet_regiis所在目录,在C盘根目录中搜索aspnet_regiis,找到4.0框架下aspnet_regiis的目录位置,本人本本目录为”C:\Windows\Microsoft.NET\Framework\v4.0.30319″.

 

②以管理员的身份运行DOS命令行,

执行”开始→所有程序→附件→命令提示符(右击选择’以管理员身份运行(A)’)”,弹出”管理员:命令提示符”窗口

 

③执行命令”cd C:\Windows\Microsoft.NET\Framework\v4.0.30319″,进入到”C:\Windows\Microsoft.NET\Framework\v4.0.30319″目录,如图

 

然后执行命令”aspnet_regiis.exe -i”,注册”aspnet_regiis”,稍等片刻,aspnet_regiis成功注册如图

看到图中的界面,就可以在IIS中运行.net4.0部署的网站喽!

VMware网卡设置三种模式

1.bridged(桥接模式)

在这种模式下,VMWare虚拟出来的操作系统就像是局域网中的一台独立的主机,它可以访问网内任何一台机器。在桥接模式下,你需要手工为虚拟系统配置 IP地址、子网掩码,而且还要和宿主机器处于同一网段,这样虚拟系统才能和宿主机器进行通信。同时,由于这个虚拟系统是局域网中的一个独立的主机系统,那 么就可以手工配置它的TCP/IP配置信息,以实现通过局域网的网关或路由器访问互联网。

使用桥接模式的虚拟系统和宿主机器的关系,就像连接在同一个Hub上的两台电脑。想让它们相互通讯,你就需要为虚拟系统配置IP地址和子网掩码,否则就无法通信。

如果你想利用VMWare在局域网内新建一个虚拟服务器,为局域网用户提供网络服务,就应该选择桥接模式。

这种方式最简单,直接将虚拟网卡桥接到一个物理网卡上面,和linux下一个网卡 绑定两个不同地址类似,实际上是将网卡设置为混杂模式,从而达到侦听多个IP的能力。

在此种模式下,虚拟机内部的网卡(例如linux下的eth0)直接连到了物理网卡所在的网络上,可以想象为虚拟机和host机处于对等的地位,在网络关系上是平等的,没有谁在谁后面的问题。

使用这种方式很简单,前提是你可以得到1个以上的地址。对于想进行种种网络实验的朋友 不太适合,因为你无法对虚拟机的网络进行控制,它直接出去了。

2.NAT(网络地址转换模式)

使用NAT模式,就是让虚拟系统借助NAT(网络地址转换)功能,通过宿主机器所在的网络来访问公网。也就是说,使用NAT模式可以实现在虚拟系统里访 问互联网。NAT模式下的虚拟系统的TCP/IP配置信息是由VMnet8(NAT)虚拟网络的DHCP服务器提供的,无法进行手工修改,因此虚拟系统也 就无法和本局域网中的其他真实主机进行通讯。采用NAT模式最大的优势是虚拟系统接入互联网非常简单,你不需要进行任何其他的配置,只需要宿主机器能访问 互联网即可。

这种方式也可以实现Host OS与Guest OS的双向访问。但网络内其他机器不能访问Guest OS,Guest OS可通过Host OS用NAT协议访问网络内其他机器。NAT方式的IP地址配置方法是由VMware的虚拟DHCP服务器中分配一个IP ,在这个IP地址中已经设置好路由,就是指向192.168.138.1的。

如果你想利用VMWare安装一个新的虚拟系统,在虚拟系统中不用进行任何手工配置就能直接访问互联网,建议你采用NAT模式。

这种方式下host内部出现了一个虚拟的网卡vmnet8(默认情况下),如果你有过 做nat服务器的经验,这里的vmnet8就相当于连接到内网的网卡,而虚拟机本身则相当于运 行在内网上的机器,虚拟机内的网卡(eth0)则独立于vmnet8。

你会发现在这种方式下,vmware自带的dhcp会默认地加载到vmnet8界面上,这样虚拟机就可以使用dhcp服务。更为重要的是,vmware自 带了nat服务,提供了从vmnet8到外网的地址转 换,所以这种情况是一个实实在在的nat服务器在运行,只不过是供虚拟机用的。

很显然,如果你只有一个外网地址,此种方式很合适。

host-only(主机模式)

在某些特殊的网络调试环境中,要求将真实环境和虚拟环境隔离开,这时你就可采用host-only模式。在host-only模式中,所有的虚拟系统是可以相互通信的,但虚拟系统和真实的网络是被隔离开的。

提示:在host-only模式下,虚拟系统和宿主机器系统是可以相互通信的,相当于这两台机器通过双绞线互连。

在host-only模式下,虚拟系统的TCP/IP配置信息(如IP地址、网关地址、DNS服务器等),都是由VMnet1(host-only)虚拟网络的DHCP服务器来动态分配的。

如果你想利用VMWare创建一个与网内其他机器相隔离的虚拟系统,进行某些特殊的网络调试工作,可以选择host-only模式。

这应该是最为灵活的方式,有兴趣的话可以进行各种网络实验。和nat唯一的不同的是,此 种方式下,没有地址转换服务,因此,模认情况下,虚拟机只能到主机访问,这也是hostonly的名字的意义。

默认情况下,也会有一个dhcp服务加载到vmnet1上。这样连接到vmnet1上的虚拟机仍然可以设置成dhcp,方便系统的配置.

是不是这种方式就没有办法连接到外网呢,当然不是,事实上,这种方式更为灵活,你可以使用自己的方式,从而达到最理想的配置,例如:
a。使用自己dhcp服务:首先停掉vmware自带的dhcp服务,使dhcp服务更为统一。
b。使用自己的nat,方便加入防火墙。windows host可以做nat的方法很多,简单的如windows xp的internet共享,复杂的如windows server里的nat服务。
c. 使用自己的防火墙。因为你可以完全控制vmnet1,你可以加入(或试验)防火墙在vmnet1和外网的网卡间。

从以上可以看出,hostonly这种模式和普通的nat server带整个内网上网的情形类似,因此你可以方便的进行与之有关的实验,比如防火强的设置等。

 

如果采取NAT方式,必须设置VMWARE VMnet8和Virtual Network Editor中的NAT SubNet在一个网段,比如SubNet设置为192.168.220.0,则Vmnet8的地址设置为192.168.220.1,网关设置为192.168.220.2,这样就能实现宿主和客户机的互访。

如果采取Bridge方式,而且宿主机有两个网卡以上,因为客户机通过宿主机的网络ip出去,必须确定客户机通过哪个IP地址出去,否则可能无法连接外