将Excel文件数据导入数据到SQL数据库中

存储过程/*
将Excel文件数据导入数据到SQL数据库中
导出的表存在则直接插入数据,如果不存在则创建表
*/

CREATE PROCEDURE dbo.ImportExcel
--declare
@path nvarchar(1000),       --文件存放目录
@fname nvarchar(250),      --文件名
@sheetname varchar(250),     --要导入的工作表名
@strGetFields varchar(1000) = '*',   --要导入的字段名称
@strWhere  varchar(1500) = '',   --导入时合法条件 
@strWhere2 varchar(1500) = '',   --查找不符合导入数据的条件
@table varchar(250),    --要导入的表名
@rowCount int,     --要导入的记录集的数量
@ret int output,
@retRow int output

as
set nocount on
declare @constr nvarchar(1000),@sql varchar(8000),@fdlist varchar(8000)
declare @factcount int

--select @path='C:/Documents and Settings/Administrator/桌面'
--select @table='aa'
--select @fname='stockoutimei'
--select @sheetname='Sheet1'


--参数检测
set @path=rtrim(@path)
if right(@path,1)<>'/'
 begin
  set @path=@path+'/'
 end
set @fname=@fname+'.xls'

set @sql='openrowset(''MICROSOFT.JET.OLEDB.4.0'',''Excel 8.0;HDR=YES;DATABASE='+@path+@fname+''','+@sheetname+'$)'

--检查要导入的数据数目和Excel内能导入的数据数目是否相等
--exec('select '+ @factcount +'=count(*) from '+ @sql +' where 1>0'+ @strWhere +'')

create table #temptab (rcount int)
exec('insert into #temptab select count(*) as rcount from '+ @sql +' where 1>0'+ @strWhere +'')

select @factcount=rcount from #temptab
drop table #temptab

if @factcount<>@rowCount
 begin
  --导入数量和实际数量不等
  --返回不符合条件的记录

  set @ret=-1  --不能执行导入
  --exec('select * from '+ @sql + ' where 1>0'+ @strWhere2 +'')
 end
else
 begin
  --导入数据
  --判断要接收数据的表是否存在

  if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].['+@table+']') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
   begin
    --print('insert into '+@table+' select ClientName, IMEI, OutTime, ProductName, ReceiveAddr from '+@sql+' where IMEI<>''''')
    exec('insert into '+@table+'('+ @strGetFields +') select '+ @strGetFields +' from '+@sql+' where 1>0'+ @strWhere +'')
    --SET ANSI_NULLS ON
    --SET ANSI_WARNINGS ON

    set @ret=1  --执行成功
   end
  else
   begin
    set @ret=0  --没有表
   end
 end

set @retRow=@factcount --返回Excel文件中实际可用行数
return @factcount

GO

 

.VB后台文件'执行DataGrid事件 - 导入/删除IMEI
    Private Sub DgSHOW_ItemCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridCommandEventArgs) Handles DgSHOW.ItemCommand
        Dim ret As Integer
        Dim strNotice As String
        Dim fname As String = e.Item.Cells(2).Text
        Dim lstrFileFolder As String = Server.MapPath("../InIMEI").ToString()

       '//数据准备
        '-------------------------------

        Me.ImportObj.path = lstrFileFolder
        Me.ImportObj.fname = fname
        Me.ImportObj.sheetname = "Sheet1"
        Me.ImportObj.strGetFields = "Date_Code,Bar_Code,Start_Date,End_Date"
        Me.ImportObj.table = "BarCode_DateCode"
        Me.ImportObj.IMEIfield = "Bar_Code"
        Me.ImportObj.strWhere = " AND Date_Code IS NOT NULL AND Bar_Code IS NOT NULL"
        Me.ImportObj.strWhere2 = " AND (Date_Code IS NULL OR Bar_Code IS NULL)"
        Me.ImportObj.SN = e.Item.Cells(0).Text
        '-------------------------------

        If (e.CommandName = "Import") Then  ' Excute Import IMEI
            '=============================================
            '///<summary> Excute Import IMEI </summary>///
            '=============================================   

            Me.ImportObj.rowCount = CType(e.Item.FindControl("txtCount"), HtmlInputText).Value

            If InStrRev(fname.ToUpper, ".XLS") = 0 Then
                Response.Write("<script>alert('文件格式不对,不能导入!');</script>")
                Exit Sub
            End If

           '调用判断方法
            ret = Me.ImportObj.JudgeExcel()
            If ret <> 0 Then
                If ret = -1 Then
                    strNotice = "请查证要导入的Excel中Sheet1表是否存在!"
                ElseIf ret = -2 Then
                    strNotice = "Excel中字段个数不符,请确认后再导入!"
                ElseIf ret = -3 Then
                    strNotice = "Excel中字段名称不符,请确认后再导入!"
                End If
                Response.Write("<script language='javascript'>alert('" & strNotice & "');</script>")
                Exit Sub
            End If

           '执行导入
            ret = Me.ImportObj.ImportBarCode()
            If ret = 1 Then
                strNotice = "导入成功!"
            ElseIf ret = 0 Then
                strNotice = "要导入接收数据的表不存在!"
            ElseIf ret <> -321 Then '非系统执行错误
                strNotice = "/n导入数量和实际能够导入数量【" & ret / 100 & "】行不等/n/n 并请确认要导入的Excel的数据格式为文本格式!"
            End If
            Response.Write("<script language='javascript'>alert('" & strNotice & "');</script>")
            Me.DGBind()

        ElseIf (e.CommandName = "Delete") Then ' Excute Delete IMEI
            '=============================================
            '///<summary> Excute Delete IMEI </summary>///
            '=============================================

            If File.Exists(lstrFileFolder & "/" & fname) = False Then
                Response.Write("<script language='javascript'>alert('未能找到数据文件" & fname & "!');</script>")
                Exit Sub
            End If

            '调用判断方法
            ret = Me.ImportObj.JudgeExcel()
            If ret <> 0 And ret <> -321 Then
                If ret = -1 Then
                    strNotice = "请查证Excel中Sheet1表是否存在!"
                ElseIf ret = -2 Then
                    strNotice = "Excel中字段个数不符,请确认!"
                ElseIf ret = -3 Then
                    strNotice = "Excel中字段名称不符,请确认!"
                End If
                Response.Write("<script language='javascript'>alert('" & strNotice & "');</script>")
                Exit Sub
            End If

           '执行条码删除
            ret = Me.ImportObj.DelBarCode()
            If ret = 1 Then
                Me.DGBind()
            End If
        End If
    End Sub

 

.Class VB后台类'条码导入--判断Excel文件是否符合导入要求
    Public Function JudgeExcel() As Integer
        Dim conn As New EasyConn
        Dim strSQL As String
        Dim ret As Integer = 0 '[-1→Excel中(me._sheetname)表不存在,-2→Excel中字段个数不符,-3→Excel中字段名称不符]

        strSQL = "SELECT TOP 1 * FROM OPENROWSET('MICROSOFT.JET.OLEDB.4.0','Excel 8.0;HDR=YES;DATABASE=" & Me._path & "/" & Me._fname & "'," & Me._sheetname & "$)"

        Dim Myconn As New SqlConnection(conn.CONN_STRING)
        '------------------------------------------------------
        'Dim strConn As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & Me._path & "/" & Me._fname & ";Extended Properties=Excel 8.0;"
        'Dim conn As New OleDbConnection(strConn)
        'conn.Open()
        'Dim cmd As New System.Data.OleDb.OleDbCommand
        'cmd.Connection = conn
        'cmd.CommandText = strSQL
        '------------------------------------------------------

        Try
            Dim cmd As New SqlCommand(strSQL, Myconn)
            Myconn.Open()
            Dim dr As SqlDataReader = cmd.ExecuteReader()
            If dr.FieldCount <> 4 Then
                ret = -2
            Else
                Dim i As Integer
                For i = 0 To dr.FieldCount - 1
                    If InStrRev("," & Me._strGetFields & ",", "," & dr.GetName(i) & ",") = 0 Then
                        ret = -3
                        Return ret
                    End If
                Next
            End If

            dr.Close()
            dr = Nothing
        Catch ex As Exception
            'Throw ex
            ret = -1
        Finally
            conn.Close(Myconn)
        End Try

        Return ret
    End Function

   '导入条码
    Public Function ImportBarCode() As Integer
        Dim Conn As New EasyConn
        Dim RunObj As EasyRun
        Dim MyConn As New SqlConnection
        Dim strSQL As String
        Dim MyPara As EasyRunParameterCache
        Dim returnValue As Integer
        Dim factRow As Integer

        strSQL = "DELETE FROM " & Me._table & " WHERE " & Me._IMEIfield & " IN (SELECT CAST(" & Me._IMEIfield & " AS CHAR) AS " & Me._IMEIfield & " FROM OPENROWSET('MICROSOFT.JET.OLEDB.4.0','Excel 8.0;HDR=YES;DATABASE=" & Me._path & "/" & Me._fname & "'," & Me._sheetname & "$))"

        MyConn = Conn.Open(Conn.CONN_STRING)    '//打开连接

        '//开始事务
        Dim MyTran As SqlTransaction = MyConn.BeginTransaction
        Try
           '------------------------------------------

            If Me._IMEIfield <> "" Then
               '导入前先删除重复的IMEI
                RunObj.ExecuteNonQuery(MyTran, CommandType.Text, strSQL)
            End If
            '------------------------------------------   

            '执行导入
            Dim NewProName As String
            NewProName = "ImportExcel"  '存储过程名

            Dim parms() As SqlParameter
            parms = MyPara.GetCachedParameterSet(Conn.CONN_STRING, NewProName)

            If parms Is Nothing Then
                parms = MyPara.GetSpParameterSet(Conn.CONN_STRING, NewProName)
                MyPara.CacheParameterSet(Conn.CONN_STRING, NewProName, parms)
            End If

            Me._fname = _fname.Replace(".xls", "")
            parms(0).Value = _path          '--文件存放目录
            parms(1).Value = _fname         '--文件名
            parms(2).Value = _sheetname     '--要导入的工作表名
            parms(3).Value = _strGetFields '--要导入的字段名称
            parms(4).Value = _strWhere      '--导入时合法条件  
            parms(5).Value = _strWhere2    '--查找不符合导入数据的条件
            parms(6).Value = _table         '--要导入的表名
            parms(7).Value = _rowCount      '--要导入的记录集的数量           
            parms(8).Value = 0              '--返回值
            parms(9).Value = 0             '--返回的Excel文件中可用行数

            RunObj.ExecuteNonQuery(MyTran, CommandType.StoredProcedure, NewProName, parms)
            returnValue = parms(8).Value
            factRow = parms(9).Value
            '------------------------------------------

           '更新状态
            If returnValue = 1 Then     '[-2→无可用数据,-1→不能导入,1→导入成功,0→没有表]
                ChangeUploadStatus(Me._SN, "1", MyTran, RunObj)
            Else
                ChangeUploadStatus(Me._SN, "2", MyTran, RunObj)
                If returnValue = -1 Then returnValue = factRow * 100 '数量不符,返回实际数量*100
            End If
           '------------------------------------------
            If factRow = 0 Then returnValue = -2 'Excel文件中可用行数为0,即无实际可用数据

            MyTran.Commit() '//提交事务
        Catch ex As Exception
            MyTran.Rollback()  '//回滚事务
            returnValue = -321 '返回-321,表示Catch到System.Excute错误
            Throw ex
        Finally
            Conn.Close(MyConn) '//关闭连接
        End Try

        Return returnValue
    End Function

    '删除条码
    Public Function DelBarCode() As Integer
        Dim Conn As New EasyConn
        Dim RunObj As EasyRun
        Dim MyConn As New SqlConnection
        Dim strSQL As String
        Dim Ret As Integer

        strSQL = "DELETE FROM " & Me._table & " WHERE " & Me._IMEIfield & " IN (SELECT CAST(" & Me._IMEIfield & " AS CHAR) AS " & Me._IMEIfield & " FROM OPENROWSET('MICROSOFT.JET.OLEDB.4.0','Excel 8.0;HDR=YES;DATABASE=" & Me._path & "/" & Me._fname & "'," & Me._sheetname & "$))"

        MyConn = Conn.Open(Conn.CONN_STRING)   '//打开连接

        Dim MyTran As SqlTransaction = MyConn.BeginTransaction  '//开始事务
        Try
            '执行条码删除
            RunObj.ExecuteNonQuery(MyTran, CommandType.Text, strSQL)

           '更新状态
            ChangeUploadStatus(Me._SN, "3", MyTran, RunObj)

            MyTran.Commit() '//提交事务
            Ret = 1
        Catch ex As Exception
            MyTran.Rollback()  '//回滚事务
            Ret = -1
        Finally
            Conn.Close(MyConn)  '//关闭连接
        End Try

        Return Ret
    End Function

 

前台验证.aspx
    
// 导入时要求必须输入将导入的记录条数
         function  checkCount(obj)
        
{
            
if(document.all(obj).value=='')
            
{
                alert('请输入要导入的数据实际有效数量!');
                document.all(obj).focus();
                
return false;
            }

            
return true;
        }
前台页面
< asp:datagrid  id ="DgSHOW"  runat ="server"  CssClass ="DataGrid"  Width ="100%"  AutoGenerateColumns ="False" >
                                        
< HeaderStyle  CssClass ="DgRowTitle_C" ></ HeaderStyle >
                                        
< Columns >
                                            
< asp:BoundColumn  Visible ="False"  DataField ="SN"  ReadOnly ="True" ></ asp:BoundColumn >
                                            
< asp:TemplateColumn  HeaderText ="序号" >
                                                
< ItemStyle  HorizontalAlign ="Center" ></ ItemStyle >
                                                
< ItemTemplate >
                                                    
<% # Container.ItemIndex + 1 %>
                                                
</ ItemTemplate >
                                            
</ asp:TemplateColumn >
                                            
< asp:BoundColumn  DataField ="FileName"  ReadOnly ="True"  HeaderText ="文件名" ></ asp:BoundColumn >
                                            
< asp:BoundColumn  DataField ="FileSize"  ReadOnly ="True"  HeaderText ="文件大小" ></ asp:BoundColumn >
                                            
< asp:BoundColumn  DataField ="UpMan"  ReadOnly ="True"  HeaderText ="上传人" ></ asp:BoundColumn >
                                            
< asp:BoundColumn  DataField ="UpTime"  ReadOnly ="True"  HeaderText ="上传时间" ></ asp:BoundColumn >
                                            
< asp:BoundColumn  HeaderText ="状态" ></ asp:BoundColumn >
                                            
< asp:TemplateColumn  HeaderText ="确认导入数量" >
                                                
< ItemStyle  CssClass ="DgTdW" ></ ItemStyle >
                                                
< ItemTemplate >
                                                    
< INPUT  class ="NoBorderW_R"  id ="txtCount"  style ="WIDTH: 100%"  onkeypress ="onlyNumeric()"
                                                        type
="text"  maxLength ="10"  runat ="server" >
                                                
</ ItemTemplate >
                                            
</ asp:TemplateColumn >
                                            
< asp:ButtonColumn  Text ="导入"  HeaderText ="导入"  CommandName ="Import" >
                                                
< ItemStyle  HorizontalAlign ="Center" ></ ItemStyle >
                                            
</ asp:ButtonColumn >
                                            
< asp:ButtonColumn  Text ="删除"  HeaderText ="删除"  CommandName ="Delete" >
                                                
< ItemStyle  HorizontalAlign ="Center" ></ ItemStyle >
                                            
</ asp:ButtonColumn >
                                            
< asp:TemplateColumn >
                                                
< HeaderStyle  Width ="50px" ></ HeaderStyle >
                                                
< ItemStyle  HorizontalAlign ="Center" ></ ItemStyle >
                                                
< HeaderTemplate >
                                                    
< INPUT  id ="chkAll"  onclick ="return select_deselectAll(this.checked, this.id, 'chkDel')"
                                                        type
="checkbox" > 全选
                                                
</ HeaderTemplate >
                                                
< ItemTemplate >
                                                    
< asp:CheckBox  id ="chkDel"  runat ="server"  ToolTip ="选中,表示要删除该文件"  Text ="删除" ></ asp:CheckBox >
                                                
</ ItemTemplate >
                                            
</ asp:TemplateColumn >
                                        
</ Columns >
                                    
</ asp:datagrid >
                                    
< table >
                                        
< tr >
                                            
< td  height ="1" ></ td >
                                        
</ tr >
                                    
</ table >
                                    
< table  class ="ButtonTab"  width ="100%" >
                                        
< tr >
                                            
< td >< uc1:submitimg  id ="SubmitImg2"  runat ="server" ></ uc1:submitimg >< asp:button  id ="btnDel"  runat ="server"  CssClass ="SubmitButton"  Text ="确定删除"  ToolTip ="删除服务器目录中不再需要的Excel文件" ></ asp:button > &nbsp;&nbsp;&nbsp;
                                                
< uc1:resetimg  id ="ResetImg2"  runat ="server" ></ uc1:resetimg >< input  class ="SubmitButton"  id ="btnCancel"  type ="reset"  value =" 取 消 "  name ="btnCancel"
                                                    runat
="server" >
                                            
</ td >
                                        
</ tr >
                                    
</ table >
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
我们今天以企业用户常用的CRM系统,来看一看标准的SaaSCRM应该是一个什么样子。   实际上,很多用户对于CRM并不陌生,早在2000年的时候,有一些企业就已经开始尝试CRM系统。在很多人眼,CRM就是一套C/S或者B/S的应用系统。   而当CRM进入了SaaS,他在架构上会是一个什么样子呢?我们以361CRM为例,来看一下SaaSCRM的架构。   361CRM系统采用分布式架构。采用企业级的多层次、多应用的系统结构的SaaS在线CRM平台平台架构从大的层次上来分主要为四层,根据调用关系依次为应用层、缓冲层、服务层以及存储层,如下图所示:   应用层   从浏览器发送过来的请求,直接由应用层来进直接响应;   平台是多租赁用户的在线多应用来实现的,由于每个用户的具体业务需求不同,因此每个租赁用户的应用是相互隔离的,但应用层的结构却都是相同,从上到下主要分为业务展现层、业务逻辑层、业务模型层、实体访问层;   业务展现层主要为用户数据的不同视图表现,为用户呈现各种易于浏览、便于理解的各种数据表现方式,如表单、表格、报表、图表等;   业务逻辑层主要是业务逻辑的具体实现层,对于用户动作、触发事件以及工作流程等由业务逻辑层来实现业务的处理以及响应,通过业务逻辑层对下层业务模型的访问来实现具体的逻辑处理;   业务模型层主要是业务对象的具体定义与封装,是对于现实业务在平台的最直接的映射;   实体访问层是对于业务逻辑层对于业务模型操作的封装,业务模型的实体状态的更新、删除、查询等都是通过实体访问层来实现。   缓冲层   缓冲层主要对于静态资源以及动态数据的缓存。静态资源主要是指应用层展现层所要使用到的静态资源文件,以及由用户在业务操作产生的文件等,如图片、上传的文件等;   而动态数据是指用户在使用平台的过程所产生的业务数据,在实现业务,这部分数据大部分都是读操作比较多,而写操作比较少,因此可以针对这部分数据根据特定的缓存失效策略机制来进相应的缓存;   缓冲层的缓存针对应用层是透明的,而且针对多应用也是透明的,因此缓冲层具有更大的弹性与灵活性。   服务层   服务主要是指平台的核心服务,核心服务分为业务共通服务以及平台共通服务,平台共通服务是指与业务无关且是平台最基础的服务,如任务调度、消息队列、邮件服务、图片处   理、工作流引擎等;而业务共通服务指基于平台共通服务,而对于所有业务具有共通性的服务,如日志审核、操作回滚、数据安全、全文检索、权限角色等;   服务层是对于平台运营、维护最核心的服务实现,是平台正常运的基础。   存储层   存储主要分为两部分:分布式文件存储以及分布式的数据存储;   由于是多应用的平台,因此随着平台的运营,会产生海量的业务数据以及资源文件,因此伴随着海量的数据而来的问题就是存储、检索、分析以及统计等问题;   针对上述问题,361CRM平台采用了分布式的存储系统,基于Map-Reduce来进相应的检索、分析以及统计,实现了对于海量数据的统一操作。   这种结构能做到真正的分布式网络计算,有效降低网络流量,减轻客户端负担,还能安全、方便地与互联网接口。另外公司员工或客户分布或走于全国各地,通常都有移动办公需求。   REST 架构   REST是基于HTTP的,因此天生就有在互联网上穿透防火墙的能力,REST可以简单地认为它是轻量级的WebService,但是它具有自己的一些显著特点:   所有的资源通过统一的接口访问(HTTP/HTTPSGET、POST、PUT、ELETE),而且接口比较统一,便于与第三方的集成;   因为是基于HTTP/HTTPS的,因此可以将资源(响应)分为可缓存的和不可缓存的,以及采用浏览器的标准压缩方式,有效地提升网络效能。也可以在客户和资源之间插入不同的间组件来提升性能和安全等,如,代理服务,缓存服务,网关服务等;   因为是基于HTTP/HTTPS的资源请求,因此本次连接和下一次到服务器的连接之间没有状态。由于361CRM平台采用了REST架构,因此也就决定了361CRM平台天然就具备以下几方面的优势:   由于REST本身无状态的特性,361CRM平台天然就是分布式的,决定了后台通过根据业务量而弹性地增加服务器就可以实现平台计算能力的线性增加;   所有的请求都是统一通过RESTAPI进相应的资源与服务的请求,这样就能够保证系统提供的服务都是解耦的,极大的简化了系统,从而改善了系统的交互性和可重用性,同时也能够根据业务进相应统一且透明的内存缓存   客户端浏览器能够轻松通过Ajax实现REST资源的异步调用处理,同时也可以有效地减少应用服务器地压力   通过提供开放的RESTAPI,能够轻松实现与第三方的集成   平台服务   平台服务层的调用是通过RESTAPI进的,由于REST的特点,通过在URI添加资源路径以及版本信息,很方便地能够实现平台的平滑升级以及数据兼容性问题。   平台服务层实现的都是共通的服务,服务之间是独立的,而且是插件式的方式来实现的,平台选用了面向分布式计算的Erlang语言来实现的,因此保证了这些插件式的服务能够热拔插地部署,实现真正地不宕机地部署与更新。   平台服务层的插件式架构,决定了平台的无限扩展能力,能够根据不断变化地用户需求而进平台的不断地在线迭代与更新,与用户的需求形成一个良性的循环。配置定制平台通过服务器(Apache)的自定义开发,实现了企业用户应用的透明隔离,因此平台具有面向不同企业用户根据不同需求进个性化定制的能力。不同的企业用户,一般主要有几方面的自定义需求:业务对象、工作流程、报表、布局等,而361CRM平台的平台框架就决定着能够很好地满足用户的自定义需求,主要分为以下几个方面:   由于用户使用的是文档数据库,有着松散的数据结构,因此用户根据需求,而可以随意自定义自己的业务对象;   361CRM平台后台的平台服务层,有相应的实时的工作流引擎,提供给用户强大的自定义工作流程功能;   361CRM平台有业内是丰富的报表模板,用户只需要根据自己的需要来选择即可,针对一些自定义的动态数据,还提供模板的再定义功能,能够很好地满足用户的报表需求;   由于平台是应用隔离的,因此针对着页面的布局,可以很容易地实现个性化地定制;   361CRM平台的配置功能的强大,并不以损失平台应用的易用性为基础,361CRM平台在操作上采用引导式操作,以及提供方便易用的在线帮助,大大地降低了系统使用的复杂度,使系统更加地人性化、简易化。   实时即时   361CRM平台的平台服务层与通常的应用服务不同,它是实时运的服务,平台服务层有相应的任务调度机制,邮件服务、消息队列以及实时的工作流引擎等,这些服务都是实时运的,因此当企业用户的业务对象或者业务流程发生变化时,通过这些平台服务就可以把即时的状态消息(通过邮件、短信或者其它的IM工具)推送给用户,让用户真正了解到业务的即时与实时的状态信息。   而通常的应用服务是静态的,只有当用户登录时,才会进相应的业务状态的检查,这样就严重影响了业务处理的速度,对于即时性业务,就会带来很大的损失。   多级负载   平台是一个多租赁用户的在线SaaS系统,因此会给平台带来大量的高并发的请求,361CRM平台是一个多层次的结构,而且采用了REST架构,REST天生就是分布式,因此通过物理部署就可以实现高并发带的负载均衡。   四层负载在链路层解决来自互联网的并发请求压力,使用LVS+Heartbeat的主从双备的架构,保证不会出现单点故障;   Web应用的大部分压力都来自于资源的请求,如图片,静态文件,样式表等文件的请求,服务器压力的70%都来自于这些资源的请求,因此对于这些静态资源的请求,通过静态资源缓冲层就能够很好解决这些请求对于后台造成的压力;   经过实测,经过一段时间稳定运之后,静态资源缓冲层能够命前台请求的80%以上,有效地缓解了应用服务器的压力;   七层负载层主要是做业务、以及资源的请求分流,把负载均衡到多台文件服务器以及应用服务器上;   文件服务器与应用服务器是分布式的,通过Map-Reduce进任务的拆分与结果的合并,充分利用多台服务器的并计算能力,提升整体平台的运性能;   文件缓存采用多级缓存策略,解决命率高的文件的频繁请求。而数据缓存则通过业务标签以及时效性策略进数据的缓存,并且进缓存的增量更新,有效地解决了对于后台的   数据读写压力;   分布式的存储系统有效地解决了海量数据的存储、检索、分析以及统计等问题。   可见,当传统的CRM系统转换为SaaS服务后,其架构方面还是发生了不少的变动的,也只有这样的变动,才使得CRM能够在SaaS平台上更好的为客户所服务。   附:什么是REST架构   REST软件架构是当今世界上最成功的互联网的超媒体分布式系统。它让人们真正理解我们的网络协议HTTP本来面貌。它正在成为网络服务的主流技术,同时也正在改变互联网的网络软件开发的全新思维方式。AJAX技术和Rails框架把REST软件架构思想真正地在实际很好表现出来。今天微软也已经应用REST并且提出把我们现有的网络变成为一个语义网,这种网络将会使得搜索更加智能化。   REST与HTTP协议   REST软件架构是由RoyThomasFielding博士在2000年首次提出的。他为我们描绘了开发基于互联网的网络软件的蓝图。REST软件架构是一个抽象的概念,是一种为了实现这一互联网的超媒体分布式系统的动指南。利用任何的技术都可以实现这种理念。而实现这一软件架构最著名的就是HTTP协议。通常我们把REST也写作为REST/HTTP,在实际往往把REST理解为基于HTTP的REST软件架构,或者更进一步把REST和HTTP看作为等同的概念。   今天,HTTP是互联网上应用最广泛的计算机协议。HTTP不是一个简单的运载数据的协议,而是一个具有丰富内涵的网络软件的协议。它不仅仅能够对于互联网资源进唯一定位,而且还能告诉我们对于该资源进怎样运作。这也是REST软件架构当最重要的两个理念。而REST软件架构理念是真正理解HTTP协议而形成的。有了REST软件架构理念出现,才使得软件业避免了对HTTP协议的片面理解。只有正确的理论指导,才能避免在软件开发的实际工作过程少走弯路。   REST与URI(资源定位)   REST软件架构之所以是一个超媒体系统,是因为它可以把网络上所有资源进唯一的定位,不管你的文件是图片、文件Word还是视频文件,也不管你的文件是txt文件格式、xml文件格式还是其它文本文件格式。它利用支持HTTP的TCP/IP协议来确定互联网上的资源。   REST与CRUD原则   REST软件架构遵循了CRUD原则,该原则告诉我们对于资源(包括网络资源)只需要四种为:创建、获取(Read)、更新和销毁就可以完成对其操作和处理了。其实世界万物都是遵循这一规律:生、变、见、灭。所以计算机世界也不例外。这个原则是源自于我们对于数据库表的数据操作:(生)、select(见)、(变)和(灭),所以有时候CRUD也写作为RUDI,其的I就是,这四个操作是一种原子操作,即一种无法再分的操作,通过它们可以构造复杂的操作过程,正如数学上四则运算是数字的最基本的运算一样。   REST与网络服务   尽管在Java语言世界网络服务目前是以SOAP技术为主,但是REST将是是网络服务的另一选择,并且是真正意义上的网络服务。基于REST思想的网络服务不久的将来也会成为是网络服务的主流技术。REST不仅仅把HTTP作为自己的数据运输协议,而且也作为直接进数据处理的工具。而当前的网络服务技术都需要使用其它手段来完成数据处理工作,它们完全独立于HTTP协议来进的,这样增加了大量的复杂软件架构设计工作。REST的思想充分利用了现有的HTTP技术的网络能力。在德国电视台上曾经出现过一个这样的五十万欧元智力题:如何实现网络服务才能充分利用现有的HTTP协议?该问题给出了四个答案:去问微软;WSDL2.0/SOAP1.2;WS-Transfer;根本没有。这个问题告诉我们HTTP并不是一个简单的数据传来传去的协议,而是一个聪明的会表现自己的协议,这也许是REST=RepresentationalStateTransfer的真正含义。   实际上目前很多大公司已经采用了REST技术作为网络服务,如Google、Amazon等。在Java语言重要的两个以SOAP技术开始的网络服务框架XFire和Axis也把REST作为自己的另一种选择。它们的新的项目分别是ApacheCXF和Axis2.Java语言也制定关于REST网络服务规范:JAX-RS:JavaAPIforRESTfulWebServices(JSR311)。相信还会出现更多与REST相关的激动人心的信息。   REST与AJAX技术   尽管AJAX技术的出现才不到两年时间,但是AJAX技术遵循了REST的一些重要原则。AJAX技术充分利用了HTTP来获取网络资源并且实现了HTTP没有的对于异步数据传输的功能。AJAX技术还使得软件更好地实现分布性功能,在一个企业内只要一个人下载了AJAX引擎,其它企业内部的人员,就可以共享该资源了。AJAX技术遵守REST准则的应用程序简单和可伸缩的架构,凡是采用AJAX技术的页面简洁而又丰富,一个页面表现了丰富多彩的形态。   AJAX技术还使用了一种不同于XML格式的JSON文件格式,这个意义在哪里呢?在REST软件架构下我们不能对于XML文件序列化处理,这样程序员必须要使用自己的XML绑定框架。而以序列化的JavaScript对象为基础的JSON已经获得了广泛认可,它被认为能以远比XML更好的方式来序列化和传输简单数据结构,而且它更简洁。这对REST是一个极大贡献和补充。   当前的网络应用软件还违背了REST的“无状态服务器”约束。REST服务器只知道自己的状态。REST不关心客户端的状态,客户端的状态自己来管理,这是AJAX技术的应用之地。通过AJAX技术,可以发挥有状态网络客户机的优势。而REST的服务器关心的是从所有网络客户端发送到服务器操作的顺序。这样使得互联网这样一个巨大的网络得到有序的管理。   REST与Rails框架   RubyonRails框架(简称Rails或者Rails框架)是一个基于Ruby语言的越来越流的网络应用软件开发框架。它提供了关于REST最好的支持,也是当今应用REST最成功的一个软件开发框架。Rails框架(从版本1.2.x起)成为了第一个引入REST作为核心思想的主流网络软件开发框架。在Rails框架的充分利用了REST软件架构之后,人们更加坚信REST的重要性和必要性。Rails利用REST软件架构思想对网络服务也提供了一流的支持。从最直观的角度看待REST,它是网络服务最理想的手段,但是Rails框架把REST带到了网络应用软件开发框架。这是一次飞跃,让REST的思想从网络服务的应用提升到了网络应用软件开发。利用REST思想的simply_restful插件已经成为了Rails框架的核心内容。   REST安全性   我们把现有基于SOAP的网络服务和基于REST/HTTP网络服务作个比喻,前者是一种传统的寄信方式,而后者是现代网络的电子邮件方式。要是是寄信和电子邮件都有病毒存在的话,传统的寄信被送到对方就很危险,而电子邮件是开发的,电子邮件供应商比如Google为我们检查了电子邮件是否有病毒。这里并不是说明SOAP网络服务消息包含义病毒,而是说明HTTP是无法处理SOAP信息包究竟好不好,需要额外的软件工具解决这一问题,包括防火墙也用不上和管不了。   REST/HTTP网络服务的信息包可以被防火墙理解和控制。你可以按照操作和链接进过滤信息包,如你可以规定从外部来的只能读取(GET操作)自己服务器的资源。这样对于系统管理员而言使得软件管理更为简单。REST的安全性还可以利用传输安全协议SSL/TLS、基本和摘要式认证(BasicundDigestAuthentication)。除了这些REST自身的安全性功能外,还可以利用像基于信息的WebServicesSecurity(JSR155)作为REST不错的补充。   我曾经遇到一个求职者,他的简历看起来不错,基本上没有大问题,但他就是没有收到任何回复。一天我半开玩笑似的问他是不是电话写错了,我一检查,果不其然。他改正后,立即收到了他所期望去的公司的面试电话。从这个故事我们得到一点教训:哪怕只剩最后一秒钟,也要检查你的联系方式两遍。这是理所当然应该做到的细节,早做比晚做好。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值