关于Thrift

下面是来自百度百科关于Thrift的介绍:

thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发。它结合了功能强大的软件堆栈和引擎,以构建在 C++, Java, Go,Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 这些编程语言间无缝结合的、高效的服务。

Apache开源地址:http://thrift.apache.org/

Thrift也是.Net平台上一款不错的RPC框架,更何况可以实现与众多编程语言之间的远程调用。下面具体介绍下Thrift在.Net上的用法。

首先,下载Thrift工具,这里选择windows平台的,下载地址:http://www.apache.org/dyn/closer.cgi?path=/thrift/0.11.0/thrift-0.11.0.exe

其次,下载具体的Thrift Sdk包,http://www.apache.org/dyn/closer.cgi?path=/thrift/0.11.0/thrift-0.11.0.tar.gz

内部包含了所支持的语言源码,这里,我们选择csharp目录里的内容,用VS打开,编译生成DLL文件,可供后续使用。

其次,编写Thrift文件,内容如下,这里定义了一个User类,包含一个Int32类型的ID和一个string类型的Name属性,同时,在定义了一个服务,UserService,其中包含GetUserByID和GetAllUser两个方法。  、

struct User {
1: i32 ID
2: string Name
} service UserService {
User GetUserByID(1:i32 userID)
list<User> GetAllUser()
}      

  然后,通过上面下载的Thrif.exe命令行工具,进行代码的生成,windows平台,cmd进入thrift.exe所在目录,执行如下命令:

thrift --gen csharp user.thrift

 命令格式如:

thrift --gen <language> <Thrift filename>

也可以把thrift.exe放到指定目录或C盘位置,配置环境变量Path,然后可以直接执行以上命令。

执行完以上命令后,会在当前目录下,生成一个名为gen-csharp的文件夹,里面包含了2个类(User.cs和UserService.cs)。

User.cs代码如下:

/**
* Autogenerated by Thrift Compiler (0.11.0)
*
* DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
* @generated
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.IO;
using Thrift;
using Thrift.Collections;
using System.Runtime.Serialization;
using Thrift.Protocol;
using Thrift.Transport; #if !SILVERLIGHT
[Serializable]
#endif
public partial class User : TBase
{
private int _ID;
private string _Name; public int ID
{
get
{
return _ID;
}
set
{
__isset.ID = true;
this._ID = value;
}
} public string Name
{
get
{
return _Name;
}
set
{
__isset.Name = true;
this._Name = value;
}
} public Isset __isset;
#if !SILVERLIGHT
[Serializable]
#endif
public struct Isset {
public bool ID;
public bool Name;
} public User() {
} public void Read (TProtocol iprot)
{
iprot.IncrementRecursionDepth();
try
{
TField field;
iprot.ReadStructBegin();
while (true)
{
field = iprot.ReadFieldBegin();
if (field.Type == TType.Stop) {
break;
}
switch (field.ID)
{
case 1:
if (field.Type == TType.I32) {
ID = iprot.ReadI32();
} else {
TProtocolUtil.Skip(iprot, field.Type);
}
break;
case 2:
if (field.Type == TType.String) {
Name = iprot.ReadString();
} else {
TProtocolUtil.Skip(iprot, field.Type);
}
break;
default:
TProtocolUtil.Skip(iprot, field.Type);
break;
}
iprot.ReadFieldEnd();
}
iprot.ReadStructEnd();
}
finally
{
iprot.DecrementRecursionDepth();
}
} public void Write(TProtocol oprot) {
oprot.IncrementRecursionDepth();
try
{
TStruct struc = new TStruct("User");
oprot.WriteStructBegin(struc);
TField field = new TField();
if (__isset.ID) {
field.Name = "ID";
field.Type = TType.I32;
field.ID = 1;
oprot.WriteFieldBegin(field);
oprot.WriteI32(ID);
oprot.WriteFieldEnd();
}
if (Name != null && __isset.Name) {
field.Name = "Name";
field.Type = TType.String;
field.ID = 2;
oprot.WriteFieldBegin(field);
oprot.WriteString(Name);
oprot.WriteFieldEnd();
}
oprot.WriteFieldStop();
oprot.WriteStructEnd();
}
finally
{
oprot.DecrementRecursionDepth();
}
} public override string ToString() {
StringBuilder __sb = new StringBuilder("User(");
bool __first = true;
if (__isset.ID) {
if(!__first) { __sb.Append(", "); }
__first = false;
__sb.Append("ID: ");
__sb.Append(ID);
}
if (Name != null && __isset.Name) {
if(!__first) { __sb.Append(", "); }
__first = false;
__sb.Append("Name: ");
__sb.Append(Name);
}
__sb.Append(")");
return __sb.ToString();
} }

  UserService.cs代码如下:

/**
* Autogenerated by Thrift Compiler (0.11.0)
*
* DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
* @generated
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.IO;
using Thrift;
using Thrift.Collections;
using System.Runtime.Serialization;
using Thrift.Protocol;
using Thrift.Transport; public partial class UserService {
public interface ISync {
User GetUserByID(int userID);
List<User> GetAllUser();
} public interface Iface : ISync {
#if SILVERLIGHT
IAsyncResult Begin_GetUserByID(AsyncCallback callback, object state, int userID);
User End_GetUserByID(IAsyncResult asyncResult);
#endif
#if SILVERLIGHT
IAsyncResult Begin_GetAllUser(AsyncCallback callback, object state);
List<User> End_GetAllUser(IAsyncResult asyncResult);
#endif
} public class Client : IDisposable, Iface {
public Client(TProtocol prot) : this(prot, prot)
{
} public Client(TProtocol iprot, TProtocol oprot)
{
iprot_ = iprot;
oprot_ = oprot;
} protected TProtocol iprot_;
protected TProtocol oprot_;
protected int seqid_; public TProtocol InputProtocol
{
get { return iprot_; }
}
public TProtocol OutputProtocol
{
get { return oprot_; }
} #region " IDisposable Support "
private bool _IsDisposed; // IDisposable
public void Dispose()
{
Dispose(true);
} protected virtual void Dispose(bool disposing)
{
if (!_IsDisposed)
{
if (disposing)
{
if (iprot_ != null)
{
((IDisposable)iprot_).Dispose();
}
if (oprot_ != null)
{
((IDisposable)oprot_).Dispose();
}
}
}
_IsDisposed = true;
}
#endregion #if SILVERLIGHT
public IAsyncResult Begin_GetUserByID(AsyncCallback callback, object state, int userID)
{
return send_GetUserByID(callback, state, userID);
} public User End_GetUserByID(IAsyncResult asyncResult)
{
oprot_.Transport.EndFlush(asyncResult);
return recv_GetUserByID();
} #endif public User GetUserByID(int userID)
{
#if !SILVERLIGHT
send_GetUserByID(userID);
return recv_GetUserByID(); #else
var asyncResult = Begin_GetUserByID(null, null, userID);
return End_GetUserByID(asyncResult); #endif
}
#if SILVERLIGHT
public IAsyncResult send_GetUserByID(AsyncCallback callback, object state, int userID)
#else
public void send_GetUserByID(int userID)
#endif
{
oprot_.WriteMessageBegin(new TMessage("GetUserByID", TMessageType.Call, seqid_));
GetUserByID_args args = new GetUserByID_args();
args.UserID = userID;
args.Write(oprot_);
oprot_.WriteMessageEnd();
#if SILVERLIGHT
return oprot_.Transport.BeginFlush(callback, state);
#else
oprot_.Transport.Flush();
#endif
} public User recv_GetUserByID()
{
TMessage msg = iprot_.ReadMessageBegin();
if (msg.Type == TMessageType.Exception) {
TApplicationException x = TApplicationException.Read(iprot_);
iprot_.ReadMessageEnd();
throw x;
}
GetUserByID_result result = new GetUserByID_result();
result.Read(iprot_);
iprot_.ReadMessageEnd();
if (result.__isset.success) {
return result.Success;
}
throw new TApplicationException(TApplicationException.ExceptionType.MissingResult, "GetUserByID failed: unknown result");
} #if SILVERLIGHT
public IAsyncResult Begin_GetAllUser(AsyncCallback callback, object state)
{
return send_GetAllUser(callback, state);
} public List<User> End_GetAllUser(IAsyncResult asyncResult)
{
oprot_.Transport.EndFlush(asyncResult);
return recv_GetAllUser();
} #endif public List<User> GetAllUser()
{
#if !SILVERLIGHT
send_GetAllUser();
return recv_GetAllUser(); #else
var asyncResult = Begin_GetAllUser(null, null);
return End_GetAllUser(asyncResult); #endif
}
#if SILVERLIGHT
public IAsyncResult send_GetAllUser(AsyncCallback callback, object state)
#else
public void send_GetAllUser()
#endif
{
oprot_.WriteMessageBegin(new TMessage("GetAllUser", TMessageType.Call, seqid_));
GetAllUser_args args = new GetAllUser_args();
args.Write(oprot_);
oprot_.WriteMessageEnd();
#if SILVERLIGHT
return oprot_.Transport.BeginFlush(callback, state);
#else
oprot_.Transport.Flush();
#endif
} public List<User> recv_GetAllUser()
{
TMessage msg = iprot_.ReadMessageBegin();
if (msg.Type == TMessageType.Exception) {
TApplicationException x = TApplicationException.Read(iprot_);
iprot_.ReadMessageEnd();
throw x;
}
GetAllUser_result result = new GetAllUser_result();
result.Read(iprot_);
iprot_.ReadMessageEnd();
if (result.__isset.success) {
return result.Success;
}
throw new TApplicationException(TApplicationException.ExceptionType.MissingResult, "GetAllUser failed: unknown result");
} }
public class Processor : TProcessor {
public Processor(ISync iface)
{
iface_ = iface;
processMap_["GetUserByID"] = GetUserByID_Process;
processMap_["GetAllUser"] = GetAllUser_Process;
} protected delegate void ProcessFunction(int seqid, TProtocol iprot, TProtocol oprot);
private ISync iface_;
protected Dictionary<string, ProcessFunction> processMap_ = new Dictionary<string, ProcessFunction>(); public bool Process(TProtocol iprot, TProtocol oprot)
{
try
{
TMessage msg = iprot.ReadMessageBegin();
ProcessFunction fn;
processMap_.TryGetValue(msg.Name, out fn);
if (fn == null) {
TProtocolUtil.Skip(iprot, TType.Struct);
iprot.ReadMessageEnd();
TApplicationException x = new TApplicationException (TApplicationException.ExceptionType.UnknownMethod, "Invalid method name: '" + msg.Name + "'");
oprot.WriteMessageBegin(new TMessage(msg.Name, TMessageType.Exception, msg.SeqID));
x.Write(oprot);
oprot.WriteMessageEnd();
oprot.Transport.Flush();
return true;
}
fn(msg.SeqID, iprot, oprot);
}
catch (IOException)
{
return false;
}
return true;
} public void GetUserByID_Process(int seqid, TProtocol iprot, TProtocol oprot)
{
GetUserByID_args args = new GetUserByID_args();
args.Read(iprot);
iprot.ReadMessageEnd();
GetUserByID_result result = new GetUserByID_result();
try
{
result.Success = iface_.GetUserByID(args.UserID);
oprot.WriteMessageBegin(new TMessage("GetUserByID", TMessageType.Reply, seqid));
result.Write(oprot);
}
catch (TTransportException)
{
throw;
}
catch (Exception ex)
{
Console.Error.WriteLine("Error occurred in processor:");
Console.Error.WriteLine(ex.ToString());
TApplicationException x = new TApplicationException (TApplicationException.ExceptionType.InternalError," Internal error.");
oprot.WriteMessageBegin(new TMessage("GetUserByID", TMessageType.Exception, seqid));
x.Write(oprot);
}
oprot.WriteMessageEnd();
oprot.Transport.Flush();
} public void GetAllUser_Process(int seqid, TProtocol iprot, TProtocol oprot)
{
GetAllUser_args args = new GetAllUser_args();
args.Read(iprot);
iprot.ReadMessageEnd();
GetAllUser_result result = new GetAllUser_result();
try
{
result.Success = iface_.GetAllUser();
oprot.WriteMessageBegin(new TMessage("GetAllUser", TMessageType.Reply, seqid));
result.Write(oprot);
}
catch (TTransportException)
{
throw;
}
catch (Exception ex)
{
Console.Error.WriteLine("Error occurred in processor:");
Console.Error.WriteLine(ex.ToString());
TApplicationException x = new TApplicationException (TApplicationException.ExceptionType.InternalError," Internal error.");
oprot.WriteMessageBegin(new TMessage("GetAllUser", TMessageType.Exception, seqid));
x.Write(oprot);
}
oprot.WriteMessageEnd();
oprot.Transport.Flush();
} } #if !SILVERLIGHT
[Serializable]
#endif
public partial class GetUserByID_args : TBase
{
private int _userID; public int UserID
{
get
{
return _userID;
}
set
{
__isset.userID = true;
this._userID = value;
}
} public Isset __isset;
#if !SILVERLIGHT
[Serializable]
#endif
public struct Isset {
public bool userID;
} public GetUserByID_args() {
} public void Read (TProtocol iprot)
{
iprot.IncrementRecursionDepth();
try
{
TField field;
iprot.ReadStructBegin();
while (true)
{
field = iprot.ReadFieldBegin();
if (field.Type == TType.Stop) {
break;
}
switch (field.ID)
{
case 1:
if (field.Type == TType.I32) {
UserID = iprot.ReadI32();
} else {
TProtocolUtil.Skip(iprot, field.Type);
}
break;
default:
TProtocolUtil.Skip(iprot, field.Type);
break;
}
iprot.ReadFieldEnd();
}
iprot.ReadStructEnd();
}
finally
{
iprot.DecrementRecursionDepth();
}
} public void Write(TProtocol oprot) {
oprot.IncrementRecursionDepth();
try
{
TStruct struc = new TStruct("GetUserByID_args");
oprot.WriteStructBegin(struc);
TField field = new TField();
if (__isset.userID) {
field.Name = "userID";
field.Type = TType.I32;
field.ID = 1;
oprot.WriteFieldBegin(field);
oprot.WriteI32(UserID);
oprot.WriteFieldEnd();
}
oprot.WriteFieldStop();
oprot.WriteStructEnd();
}
finally
{
oprot.DecrementRecursionDepth();
}
} public override string ToString() {
StringBuilder __sb = new StringBuilder("GetUserByID_args(");
bool __first = true;
if (__isset.userID) {
if(!__first) { __sb.Append(", "); }
__first = false;
__sb.Append("UserID: ");
__sb.Append(UserID);
}
__sb.Append(")");
return __sb.ToString();
} } #if !SILVERLIGHT
[Serializable]
#endif
public partial class GetUserByID_result : TBase
{
private User _success; public User Success
{
get
{
return _success;
}
set
{
__isset.success = true;
this._success = value;
}
} public Isset __isset;
#if !SILVERLIGHT
[Serializable]
#endif
public struct Isset {
public bool success;
} public GetUserByID_result() {
} public void Read (TProtocol iprot)
{
iprot.IncrementRecursionDepth();
try
{
TField field;
iprot.ReadStructBegin();
while (true)
{
field = iprot.ReadFieldBegin();
if (field.Type == TType.Stop) {
break;
}
switch (field.ID)
{
case 0:
if (field.Type == TType.Struct) {
Success = new User();
Success.Read(iprot);
} else {
TProtocolUtil.Skip(iprot, field.Type);
}
break;
default:
TProtocolUtil.Skip(iprot, field.Type);
break;
}
iprot.ReadFieldEnd();
}
iprot.ReadStructEnd();
}
finally
{
iprot.DecrementRecursionDepth();
}
} public void Write(TProtocol oprot) {
oprot.IncrementRecursionDepth();
try
{
TStruct struc = new TStruct("GetUserByID_result");
oprot.WriteStructBegin(struc);
TField field = new TField(); if (this.__isset.success) {
if (Success != null) {
field.Name = "Success";
field.Type = TType.Struct;
field.ID = 0;
oprot.WriteFieldBegin(field);
Success.Write(oprot);
oprot.WriteFieldEnd();
}
}
oprot.WriteFieldStop();
oprot.WriteStructEnd();
}
finally
{
oprot.DecrementRecursionDepth();
}
} public override string ToString() {
StringBuilder __sb = new StringBuilder("GetUserByID_result(");
bool __first = true;
if (Success != null && __isset.success) {
if(!__first) { __sb.Append(", "); }
__first = false;
__sb.Append("Success: ");
__sb.Append(Success== null ? "<null>" : Success.ToString());
}
__sb.Append(")");
return __sb.ToString();
} } #if !SILVERLIGHT
[Serializable]
#endif
public partial class GetAllUser_args : TBase
{ public GetAllUser_args() {
} public void Read (TProtocol iprot)
{
iprot.IncrementRecursionDepth();
try
{
TField field;
iprot.ReadStructBegin();
while (true)
{
field = iprot.ReadFieldBegin();
if (field.Type == TType.Stop) {
break;
}
switch (field.ID)
{
default:
TProtocolUtil.Skip(iprot, field.Type);
break;
}
iprot.ReadFieldEnd();
}
iprot.ReadStructEnd();
}
finally
{
iprot.DecrementRecursionDepth();
}
} public void Write(TProtocol oprot) {
oprot.IncrementRecursionDepth();
try
{
TStruct struc = new TStruct("GetAllUser_args");
oprot.WriteStructBegin(struc);
oprot.WriteFieldStop();
oprot.WriteStructEnd();
}
finally
{
oprot.DecrementRecursionDepth();
}
} public override string ToString() {
StringBuilder __sb = new StringBuilder("GetAllUser_args(");
__sb.Append(")");
return __sb.ToString();
} } #if !SILVERLIGHT
[Serializable]
#endif
public partial class GetAllUser_result : TBase
{
private List<User> _success; public List<User> Success
{
get
{
return _success;
}
set
{
__isset.success = true;
this._success = value;
}
} public Isset __isset;
#if !SILVERLIGHT
[Serializable]
#endif
public struct Isset {
public bool success;
} public GetAllUser_result() {
} public void Read (TProtocol iprot)
{
iprot.IncrementRecursionDepth();
try
{
TField field;
iprot.ReadStructBegin();
while (true)
{
field = iprot.ReadFieldBegin();
if (field.Type == TType.Stop) {
break;
}
switch (field.ID)
{
case 0:
if (field.Type == TType.List) {
{
Success = new List<User>();
TList _list0 = iprot.ReadListBegin();
for( int _i1 = 0; _i1 < _list0.Count; ++_i1)
{
User _elem2;
_elem2 = new User();
_elem2.Read(iprot);
Success.Add(_elem2);
}
iprot.ReadListEnd();
}
} else {
TProtocolUtil.Skip(iprot, field.Type);
}
break;
default:
TProtocolUtil.Skip(iprot, field.Type);
break;
}
iprot.ReadFieldEnd();
}
iprot.ReadStructEnd();
}
finally
{
iprot.DecrementRecursionDepth();
}
} public void Write(TProtocol oprot) {
oprot.IncrementRecursionDepth();
try
{
TStruct struc = new TStruct("GetAllUser_result");
oprot.WriteStructBegin(struc);
TField field = new TField(); if (this.__isset.success) {
if (Success != null) {
field.Name = "Success";
field.Type = TType.List;
field.ID = 0;
oprot.WriteFieldBegin(field);
{
oprot.WriteListBegin(new TList(TType.Struct, Success.Count));
foreach (User _iter3 in Success)
{
_iter3.Write(oprot);
}
oprot.WriteListEnd();
}
oprot.WriteFieldEnd();
}
}
oprot.WriteFieldStop();
oprot.WriteStructEnd();
}
finally
{
oprot.DecrementRecursionDepth();
}
} public override string ToString() {
StringBuilder __sb = new StringBuilder("GetAllUser_result(");
bool __first = true;
if (Success != null && __isset.success) {
if(!__first) { __sb.Append(", "); }
__first = false;
__sb.Append("Success: ");
__sb.Append(Success);
}
__sb.Append(")");
return __sb.ToString();
} } }

  最后,我们新建3个项目,一个Server,一个Client,一个Service(定义的服务),结构如下:

让我们先看看ThrifServer服务端吧。

        /// <summary>
///
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{ Console.Title = "Thrift服务端-Server";
TServerSocket serverTransport = new TServerSocket(8080, 0, false);
UserService.Processor processor = new UserService.Processor(new Services.TheUserService());
TServer server = new TSimpleServer(processor, serverTransport);
Console.WriteLine("启动服务器,监听端口8080 ...");
server.Serve();
}

  这里启动服务。在服务端,我们定义了一个TheUserService类,来实现Service中定义的成员。

 /// <summary>
/// 用户服务
/// </summary>
public class TheUserService:Iface
{
/// <summary>
///
/// </summary>
/// <param name="userID"></param>
/// <returns></returns>
public User GetUserByID(int userID)
{
return new User() { ID = 1, Name = "lichaoqiang" };
} /// <summary>
///
/// </summary>
/// <returns></returns>
public List<User> GetAllUser()
{
List<User> users = new List<User>(){
new User() { ID = 1, Name = "lichaoqiang" },
new User() { ID = 2, Name = "yuyuangfang" }
};
return users;
}
}  

Thrift客户端:

        /// <summary>
///
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
Console.Title = "Thrift客户端-Client";
TTransport transport = new TSocket("10.10.10.12", 8080); TProtocol protocol = new TJSONProtocol(transport);
UserService.Client client = new UserService.Client(protocol);
transport.Open();
//var users = client.GetAllUser(); //users.ForEach(u => Console.WriteLine(string.Format("User ID : {0}, User Name {1}", u.ID, u.Name)));
var user = client.GetUserByID(1);
Console.WriteLine("------------------");
Console.WriteLine(string.Format("User ID : {0}, User Name {1}", user.ID, user.Name));
Console.ReadLine();
}

  完成以上步骤后,让我们启动服务端和客户端,来看看效果吧!

.Net RPC框架Thrift的用法的更多相关文章

  1. RPC框架Thrift例子-PHP调用C++后端程序

    更新 2016-02-22: Response对象不用主动创建. 前言 前段时间用了一下Facebook的开源RPC框架Thrift,做PHP客户端调用C++后端程序,真心觉得Thrift不错! 本文 ...

  2. rpc框架: thrift/avro/protobuf 之maven插件生成java类

    thrift.avro.probobuf 这几个rpc框架的基本思想都差不多,先定义IDL文件,然后由各自的编译器(或maven插件)生成目标语言的源代码,但是,根据idl生成源代码这件事,如果每次都 ...

  3. rpc框架thrift

    跨语言的rpc框架 新建一个thrift文件 # ping service demoservice PingService { string ping(), ping函数的返回类型是字符串} serv ...

  4. [development][thrift] RPC框架 thrift

    一: wiki:https://zh.wikipedia.org/wiki/Thrift 二: 来自IBM的介绍:https://www.ibm.com/developerworks/cn/java/ ...

  5. cygwin上编译RPC框架thrift

    cygwin的配置就不多说了,缺什么就通过安装器安装好了. 在thrift的官网下载 thrift-0.11.0源码,通过cmake编译,生成Makefile之后,make出现编译错误 /cygdri ...

  6. RPC框架 - thrift 客户端

    -------客户端程序 ------ 下载    下载 thrift 源代码包    下载 thrift 的bin包 准备描述文件(使用源代码包的示例文件)    \thrift-0.10.0\tu ...

  7. RPC框架 - thrift 服务端

    -------服务端程序 ------ 下载    下载 thrift 源代码包    下载 thrift 的bin包 准备描述文件(使用源代码包的示例文件)    \thrift-0.10.0\tu ...

  8. C#使用Thrift作为RPC框架入门(三)之三层架构

    前言 这是我们讲解Thrift框架的第三篇文章,前两篇我们讲了Thrift作为RPC框架的基本用法以及架构的设计.为了我们更好的使用和理解Thrift框架,接下来,我们将来学习一下Thrift框架提供 ...

  9. rpc框架之 thrift 学习 1 - 安装 及 hello world

    thrift是一个facebook开源的高效RPC框架,其主要特点是跨语言及二进制高效传输(当然,除了二进制,也支持json等常用序列化机制),官网地址:http://thrift.apache.or ...

随机推荐

  1. iOS之Safari调试webView/H5页面

    之前做过混合开发,用的是JavaScriptCore+OC+UIWebView. Safari调试功能真的很有用,通过它可以轻松定位问题的所在,下面说说怎么调试. 开启Safari开发菜单 在Mac的 ...

  2. 手动添加jar包到本地maven仓库

    我们都知道使用maven管理jar包的时候,我们需要到远程仓库下载相关的jar包到本地仓库,但是如果远程仓库没有这个jar包呢?这时候我们就需要手动将jar包添加到本地仓库. 起因是我想用百度的富文本 ...

  3. WebApi上传文件

    上网搜了下Web Api上传文件的功能,发现都写的好麻烦,就自己写了一个,比较简单,直接上传文件就可以,可以用Postman测试. 简单的举例 /// <summary> /// 超级简单 ...

  4. SQL Server XML 查询

    [参考1] 18个小实例入门SQLServer XML查询 [参考2] 转载---SQL Server XML基础学习之<5>--XQuery(query)

  5. Quartz.Net进阶之二:关于触发器的更多信息

    与作业一样,触发器相对容易使用,但是在您可以充分利用Quartz.NET之前,确实需要了解和理解各种可自定义的选项. 此外,如前所述,您可以选择不同类型的触发器来满足不同的调度需求. 1.常见触发器属 ...

  6. c#NPOI读取excel 比interop和Microsoft.Jet.OLEDB.4.0 之类 的好的多

    今天下午开始整理excel这块, 微软弄的那些库简直是个坑, 什么com注册之类的净是些报错. 在网上搜资料偶然碰见npoi ,好东西,值得使用 NPOI是指构建在POI 3.x版本之上的一个程序,N ...

  7. 20172306《Java程序设计与数据结构》第一周总结

    20172306<Java程序设计>第一周学习总结 教材学习内容总结 本周主要学习<Android和Java>书中的第二十三章和第二十六章. 第二十三章:Android简介 A ...

  8. webplus知识点小结

    1.返回首页,要在首页栏目里面加链接,直接预览站点的时候地址栏那个地址就行 2.上传图片变色问题,要传jpg格式,不要png 3.留言板制作:后台组件管理->留言板->获取链接 然后在留言 ...

  9. Linux配置ntp时间服务器(全)

    时间服务器作用: 大数据产生与处理系统是各种计算设备集群的,计算设备将统一.同步的标准时间用于记录各种事件发生时序, 如E-MAIL信息.文件创建和访问时间.数据库处理时间等. 大数据系统内不同计算设 ...

  10. Nodejs之路:非I/O的异步API

    本篇主要介绍setTimeout,setInterval,setImmediate和process.nextTick. 1,定时器 Node中的定时器和浏览器中用法一致.区别在于:在Node中,执行到 ...