DCOM简单示例(05)

本篇文章介绍了如何写一个简单的DCOM客户端(CSharp)。

1、首先要导入COM组件编译时生成的TBL文件,ATLService.tlb

2、然后用下面的代码就可以调用了,好简单哦

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using ATLServiceLib;

namespace CSTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Type justATestType = System.Type.GetTypeFromProgID("ATLService.JustATestSvc","172.16.172.3");
            IJustATestSvc svc = (IJustATestSvc)System.Activator.CreateInstance(justATestType);
            int c = svc.Add(1, 2);
            System.Console.WriteLine(c);
            String retValue = svc.SayHiTo("dcom");
            System.Console.WriteLine(retValue);
            System.Console.Read();
        }
    }
}

DCOM简单示例(04)

本篇文章介绍了如何写一个简单的DCOM客户端(CPP)。

首先是本地调用:
代码中展示了三种获取CLSID的方式,任选一种就好了。

#include "stdafx.h"
#include "windows.h"
#include <iostream>

#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
        const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}

MIDL_DEFINE_GUID(CLSID, CLSID_JustATestExe,0xD49F1BFF,0x60FB,0x4A43,0xA9,0xAA,0x49,0x93,0xD5,0x55,0x95,0x74);

int _tmain(int argc, _TCHAR* argv[])
{
    // COM 初始化
    ::CoInitialize(NULL);       

    // 通过 ProgID 得到 CLSID
    CLSID clsid;                
    HRESULT hr = ::CLSIDFromProgID(L"ATLExe.JustATestExe.1", &clsid);
    if(!SUCCEEDED(hr))
    {
        std::cout << "clsid not found" << std::endl;
        getchar();
        return -1;
    }

    // 由 CLSID 启动组件,并得到 IDispatch 指针
    IDispatch * pDisp = NULL;   
    hr = ::CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_IDispatch, (LPVOID *)&pDisp);

    /*
    // 从ATLExe_i.c获取GUID
    // 由 CLSID 启动组件,并得到 IDispatch 指针
    IDispatch * pDisp = NULL;   
    hr = ::CoCreateInstance(CLSID_JustATestExe, NULL, CLSCTX_ALL, IID_IDispatch, (LPVOID *)&pDisp);
    */
    
    /*
    // 通过CLSIDFromString获取CLSID
    LPWSTR guidstr = L("{D49F1BFF-60FB-4A43-A9AA-4993D5559574}");
    GUID guid;
    hr = CLSIDFromString(guidstr, (LPCLSID)&guid);
    if (!SUCCEEDED(hr))
    {
        std::cout << "CLSIDFromString failed";
        DWORD d = GetLastError();
        getchar();
        return -1;
    }

    // 由 CLSID 启动组件,并得到 IDispatch 指针
    IDispatch * pDisp = NULL;
    hr = ::CoCreateInstance(guid, NULL, CLSCTX_ALL, IID_IDispatch, (LPVOID *)&pDisp);
    */

    if (!SUCCEEDED(hr))
    {
        std::cout << "IDispatch not found" << std::endl;
        DWORD d = GetLastError();
        getchar();
        return -1;
    }

    LPOLESTR pwFunNameAdd = L"Add";     // 准备取得 Add 函数的序号 DispID
    DISPID dispIDAdd;                   // 取得的序号,准备保存到这里
    hr = pDisp->GetIDsOfNames(          // 根据函数名,取得序号的函数
        IID_NULL,
        &pwFunNameAdd,                  // 函数名称的数组
        1,                              // 函数名称数组中的元素个数
        LOCALE_SYSTEM_DEFAULT,          // 使用系统默认的语言环境
        &dispIDAdd);                    // 返回值
    if (!SUCCEEDED(hr))
    {
        std::cout << "Add not found" << std::endl;
        getchar();
        return -1;
    }

    VARIANTARG vAdd[2];                             // 调用 Add(1,2) 函数所需要的参数
    vAdd[0].vt = VT_I4; vAdd[0].lVal = 2;           // 第二个参数,整数2
    vAdd[1].vt = VT_I4; vAdd[1].lVal = 1;           // 第一个参数,整数1

    DISPPARAMS dispParamsAdd = {vAdd, NULL, 2, 0 }; // 把参数包装在这个结构中
    VARIANT vResultAdd;                             // 函数返回的计算结果

    hr = pDisp->Invoke(         // 调用函数
        dispIDAdd,              // 函数由 dispID 指定
        IID_NULL,
        LOCALE_SYSTEM_DEFAULT,  // 使用系统默认的语言环境
        DISPATCH_METHOD,        // 调用的是方法,不是属性
        &dispParamsAdd,         // 参数
        &vResultAdd,            // 返回值
        NULL,                   // 不考虑异常处理
        NULL);                  // 不考虑错误处理
    if (!SUCCEEDED(hr))
    {
        std::cout << "Invoke failed" << std::endl;
        getchar();
        return -1;
    }
    std::cout << vResultAdd.lVal << std::endl;

    LPOLESTR pwFunNameSayHiTo = L"SayHiTo"; // 准备取得 SayHiTo 函数的序号 DispID
    DISPID dispIDSayHiTo;                   // 取得的序号,准备保存到这里
    hr = pDisp->GetIDsOfNames(              // 根据函数名,取得序号的函数
        IID_NULL,
        &pwFunNameSayHiTo,                  // 函数名称的数组
        1,                                  // 函数名称数组中的元素个数
        LOCALE_SYSTEM_DEFAULT,              // 使用系统默认的语言环境
        &dispIDSayHiTo);                    // 返回值
    if (!SUCCEEDED(hr))
    {
        std::cout << "SayHiTo not found" << std::endl;
        getchar();
        return -1;
    }

    VARIANTARG vSayHiTo[1];                                     // 调用 vSayHiTo("dcom") 函数所需要的参数
    vSayHiTo[0].vt = VT_BSTR;   vSayHiTo[0].bstrVal = L"dcom";  // 第一个参数,字符串dcom

    DISPPARAMS dispParamsSayHiTo = { vSayHiTo, NULL, 1, 0 };    // 把参数包装在这个结构中
    VARIANT vResultSayHiTo;                                     // 函数返回的计算结果

    hr = pDisp->Invoke(         // 调用函数
        dispIDSayHiTo,          // 函数由 dispID 指定
        IID_NULL,
        LOCALE_SYSTEM_DEFAULT,  // 使用系统默认的语言环境
        DISPATCH_METHOD,        // 调用的是方法,不是属性
        &dispParamsSayHiTo,     // 参数
        &vResultSayHiTo,        // 返回值
        NULL,                   // 不考虑异常处理
        NULL);                  // 不考虑错误处理
    if (!SUCCEEDED(hr))
    {
        std::cout << "Invoke failed" << std::endl;
        getchar();
        return -1;
    }

    std::wcout << vResultSayHiTo.bstrVal<< std::endl;

    pDisp->Release();       // 释放接口指针
    ::CoUninitialize();     // 释放 COM

    getchar();
    return 0;
}

然后是远程调用:

#include "stdafx.h"
#include "windows.h"
#include <iostream>


int _tmain(int argc, _TCHAR* argv[])
{
    // COM 初始化
    ::CoInitialize(NULL);       

    // 通过 ProgID 得到 CLSID
    CLSID clsid;                
    HRESULT hr = ::CLSIDFromProgID(L"ATLService.JustATestSvc", &clsid);
    if(!SUCCEEDED(hr))
    {
        std::cout << "clsid not found" << std::endl;
        getchar();
        return -1;
    }

    // 由 CLSID 启动组件,并得到 IDispatch 指针
    //IDispatch * pDisp = NULL; 
    //hr = ::CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_IDispatch, (LPVOID *)&pDisp);

    COSERVERINFO coServerInfo;
    ZeroMemory(&coServerInfo, sizeof(COSERVERINFO));
    coServerInfo.pwszName = TEXT("127.0.0.1");
    coServerInfo.pAuthInfo = NULL;
    coServerInfo.dwReserved1 = 0;
    coServerInfo.dwReserved2 = 0;
    MULTI_QI mqi;
    ZeroMemory(&mqi, sizeof(MULTI_QI));
    mqi.pIID=&IID_IDispatch;
    mqi.pItf=NULL;
    mqi.hr=0;
    hr = CoCreateInstanceEx(clsid,
                            NULL,
                            CLSCTX_ALL,
                            &coServerInfo,
                            1,
                            &mqi);

    IDispatch * pDisp = (IDispatch*)mqi.pItf;

    if (!SUCCEEDED(hr))
    {
        std::cout << "IDispatch not found" << std::endl;
        DWORD d = GetLastError();
        getchar();
        return -1;
    }

    LPOLESTR pwFunNameAdd = L"Add";     // 准备取得 Add 函数的序号 DispID
    DISPID dispIDAdd;                   // 取得的序号,准备保存到这里
    hr = pDisp->GetIDsOfNames(          // 根据函数名,取得序号的函数
        IID_NULL,
        &pwFunNameAdd,                  // 函数名称的数组
        1,                              // 函数名称数组中的元素个数
        LOCALE_SYSTEM_DEFAULT,          // 使用系统默认的语言环境
        &dispIDAdd);                    // 返回值
    if (!SUCCEEDED(hr))
    {
        std::cout << "Add not found" << std::endl;
        getchar();
        return -1;
    }

    VARIANTARG vAdd[2];                             // 调用 Add(1,2) 函数所需要的参数
    vAdd[0].vt = VT_I4; vAdd[0].lVal = 2;           // 第二个参数,整数2
    vAdd[1].vt = VT_I4; vAdd[1].lVal = 1;           // 第一个参数,整数1

    DISPPARAMS dispParamsAdd = {vAdd, NULL, 2, 0 }; // 把参数包装在这个结构中
    VARIANT vResultAdd;                             // 函数返回的计算结果

    hr = pDisp->Invoke(         // 调用函数
        dispIDAdd,              // 函数由 dispID 指定
        IID_NULL,
        LOCALE_SYSTEM_DEFAULT,  // 使用系统默认的语言环境
        DISPATCH_METHOD,        // 调用的是方法,不是属性
        &dispParamsAdd,         // 参数
        &vResultAdd,            // 返回值
        NULL,                   // 不考虑异常处理
        NULL);                  // 不考虑错误处理
    if (!SUCCEEDED(hr))
    {
        std::cout << "Invoke failed" << std::endl;
        getchar();
        return -1;
    }
    std::cout << vResultAdd.lVal << std::endl;

    LPOLESTR pwFunNameSayHiTo = L"SayHiTo"; // 准备取得 SayHiTo 函数的序号 DispID
    DISPID dispIDSayHiTo;                   // 取得的序号,准备保存到这里
    hr = pDisp->GetIDsOfNames(              // 根据函数名,取得序号的函数
        IID_NULL,
        &pwFunNameSayHiTo,                  // 函数名称的数组
        1,                                  // 函数名称数组中的元素个数
        LOCALE_SYSTEM_DEFAULT,              // 使用系统默认的语言环境
        &dispIDSayHiTo);                    // 返回值
    if (!SUCCEEDED(hr))
    {
        std::cout << "SayHiTo not found" << std::endl;
        getchar();
        return -1;
    }

    VARIANTARG vSayHiTo[1];                                         // 调用 vSayHiTo("dcom") 函数所需要的参数
    vSayHiTo[0].vt = VT_BSTR;   vSayHiTo[0].bstrVal = TEXT("dcom"); // 第一个参数,字符串dcom

    DISPPARAMS dispParamsSayHiTo = { vSayHiTo, NULL, 1, 0 };        // 把参数包装在这个结构中
    VARIANT vResultSayHiTo;                                         // 函数返回的计算结果

    hr = pDisp->Invoke(         // 调用函数
        dispIDSayHiTo,          // 函数由 dispID 指定
        IID_NULL,
        LOCALE_SYSTEM_DEFAULT,  // 使用系统默认的语言环境
        DISPATCH_METHOD,        // 调用的是方法,不是属性
        &dispParamsSayHiTo,     // 参数
        &vResultSayHiTo,        // 返回值
        NULL,                   // 不考虑异常处理
        NULL);                  // 不考虑错误处理
    if (!SUCCEEDED(hr))
    {
        std::cout << "Invoke failed" << std::endl;
        getchar();
        return -1;
    }

    std::wcout << vResultSayHiTo.bstrVal<< std::endl;

    pDisp->Release();       // 释放接口指针
    ::CoUninitialize();     // 释放 COM

    getchar();
    return 0;
}

DCOM简单示例(03)

本篇文章介绍了如何写一个简单的DCOM客户端(VBS)。

1、testDCOM.vbs

'发生错误时,继续运行
On Error Resume Next

'清除错误状态
Err.Clear

'本地调用
'Set Obj=CreateObject("ATLExe.JustATestExe")
'Set Obj=CreateObject("ATLExe.JustATestExe.1")
'远程调用
Set Obj=CreateObject("ATLExe.JustATestExe","127.0.0.1")
'Set Obj=CreateObject("ATLExe.JustATestExe.1","127.0.0.1")

'输出错误信息
If Err.Number <> 0 Then
    WScript.Echo "Error: " & Err.Number
    WScript.Echo "Error (Hex): " & Hex(Err.Number)
    WScript.Echo "Source: " &  Err.Source
    WScript.Echo "Description: " &  Err.Description
    'Err.Clear
    '退出程序
    WScript.Quit(Err.Number)
End If

'On Error Goto 0

WScript.Echo obj.Add(1,2)
WScript.Echo obj.SayHiTo("dcom")

set obj=Nothing

2、运行

cscript testDCOM.vbs

3、如果是本机测试,一般不会遇到权限问题,但如果是远程测试的话,要先进行配置的,我之前写过这样的文章,打开可以参考一下。

DCOM简单示例(02)

本篇文章介绍了如何写一个简单的DCOM服务端(NT服务模式)。

1、VC新建工程,ATL->ATL Project(名称为ATLService)->类型选择Service(EXE)->Finish

2、工程视图,ATLService工程,右键->Add->Class->ATL->ATL Simple Object->类名为JustATestSvr,ProgID为ATLService.JustATestSvr

3、切换到类视图,ATLService项目下的IJustATestSvr接口上右键Add Method
名称:Add
参数1:[in]LONG a
参数2:[in]LONG b
参数3:[out,retval]LONG* c

4、类视图,ATLService项目下的IIJustATestSvr接口上右键Add Method
名称:SayHiTo
参数1:[in]BSTR someOne
参数2:[out,retval]BSTR* retValue

5、打开IJustATestSvr.cpp完成两个函数

STDMETHODIMP CJustATestSvr::Add(LONG a, LONG b, LONG* c)
{
	// TODO: Add your implementation code here
	*c = a+b;

	return S_OK;
}


STDMETHODIMP CJustATestSvr::SayHiTo(BSTR someOne, BSTR* retValue)
{
	// TODO: Add your implementation code here
	CComBSTR sResult("Hi ");
	CComBSTR sName(someOne);
	CComBSTR sMark("!");
	sResult.AppendBSTR(sName);
	sResult.AppendBSTR(sMark);
	*retValue = sResult.Copy();

	return S_OK;
}

6、编辑JustATestSvc.rgs,在TypeLib一行前,增加这样一行

val AppID = s '%APPID%'

这是MS的一个大bug,浪费了我好几个小时。

7、编译

8、注册

ATLService.exe /service

9、运行

net start ATLService

10、停止

net stop ATLService

11、反注册

ATLService.exe /unregserver

DCOM简单示例(01)

本篇文章介绍了如何写一个简单的DCOM服务端(EXE模式)。

1、VC新建工程,ATL->ATL Project(名称为ATLExe)->类型选择Executable(EXE)->Finish

2、工程视图,ATLExe工程,右键->Add->Class->ATL->ATL Simple Object->类名为JustATestExe,ProgID为ATLExe.JustATestExe

3、切换到类视图,ATLExe项目下的IJustATestExe接口上右键Add Method
名称:Add
参数1:[in]LONG a
参数2:[in]LONG b
参数3:[out,retval]LONG* c

4、类视图,ATLExe项目下的IJustATestExe接口上右键Add Method
名称:SayHiTo
参数1:[in]BSTR someOne
参数2:[out,retval]BSTR* retValue

5、打开JustATestExe.cpp完成两个函数

STDMETHODIMP CJustATestExe::Add(LONG a, LONG b, LONG* c)
{
	// TODO: Add your implementation code here
	*c = a+b;

	return S_OK;
}


STDMETHODIMP CJustATestExe::SayHiTo(BSTR someOne, BSTR* retValue)
{
	// TODO: Add your implementation code here
	CComBSTR sResult("Hi ");
	CComBSTR sName(someOne);
	CComBSTR sMark("!");
	sResult.AppendBSTR(sName);
	sResult.AppendBSTR(sMark);
	*retValue = sResult.Copy();

	return S_OK;
}

6、编译

7、注册

ATLExe.exe /regserver

8、反注册

ATLExe.exe /unregserver

ATL三种项目的使用方式

ATL向导允许我们建立三种项目:
1、DLL
2、EXE
3、NT服务

三种项目的使用方式如下:
1、DLL
A、注册

regsvr32 xxx.dll

B、反注册

regsvr32 /u xxx.dll

2、EXE
A、注册

xxx.exe /regserver

B、反注册

xxx.exe /unregserver

3、NT服务
A、注册

xxx.exe /service

B、反注册

xxx.exe /unregserver

DCOM服务授权配置

远程调用DCOM时经常会遇到下面的错误:

Error: 70
Description: Permission denied

这时就要进行授权。

首先是服务端配置:
1、首先在DCOM服务端新建一个用户,比如DCOMTEST

2、在DCOM服务端运行

#32位系统32位COM,64位系统64位COM
dcomcnfg
#64位系统32位COM
comexp.msc -32

3、在“服务组件-》计算机-》我的电脑”右键,属性
默认属性-》确认DCOM服务开启

4、在“服务组件-》计算机-》我的电脑-》DCOM配置”,对应的DCOM组件上,右键,属性
常规-》身份验证级别-》无
安全-》启动与激活权限,添加新增用户DCOMTEST,并授权
安全-》访问权限,添加新增用户DCOMTEST,并授权

然后是客户端配置
1、在客户端,添加服务端的DCOMTEST用户凭证

搞定!

PS:如果还不行的话,再设置下面的内容
1、在“服务组件-》计算机-》我的电脑”右键,属性
默认属性-》将默认身份验证基本修改为无
默认属性-》将默认模拟级别改为匿名
COM安全-》访问权限,添加Everyone及匿名用户
COM安全-》启动与激活权限,添加Everyone及匿名用户
2、然后要修改一下本地安全策略,让匿名用户与Everyone权限相同
3、然后修改本地安全策略,让DCOM可以Everyone操作

ATL NT Service 调用超时

最近发现了VS(VS2008,VS2010,VS2012,VS2013)的一个大Bug,就是在新建ATL项目时,如果直接选择Service,则服务无将法正确调用。其表现为:

在客户端调用CoCreateInstance或CreateObject会返回:

Error: 429
Description: ActiveX 部件不能创建对象

在服务端会返回(CLSID会根据实际情况发生变化):

The server {7A387102-53AE-4A3A-8F28-5EE76C2BC1E4} did not register with DCOM within the required timeout.
服务器 {7A387102-53AE-4A3A-8F28-5EE76C2BC1E4} 没有在限定的时间内用 DCOM 注册。

经过多方排查,最后发现,是在rgs文件中少了一行

val AppID = s '%APPID%'

调整后的rgs文件如下:

HKCR
{
	ATLService.JustATestSvc.1 = s 'JustATestSvc Class'
	{
		CLSID = s '{7A387102-53AE-4A3A-8F28-5EE76C2BC1E4}'
	}
	ATLService.JustATestSvc = s 'JustATestSvc Class'
	{		
		CurVer = s 'ATLService.JustATestSvc.1'
	}
	NoRemove CLSID
	{
		ForceRemove {7A387102-53AE-4A3A-8F28-5EE76C2BC1E4} = s 'JustATestSvc Class'
		{
			ProgID = s 'ATLService.JustATestSvc.1'
			VersionIndependentProgID = s 'ATLService.JustATestSvc'
			ForceRemove Programmable
			LocalServer32 = s '%MODULE%'
			{
				val ServerExecutable = s '%MODULE_RAW%'
			}
			val AppID = s '%APPID%'
			TypeLib = s '{9D5B6B0C-85D6-4DB6-B88A-915180B89038}'
			Version = s '1.0'
		}
	}
}

重新编译后,就可以调用成功了。

好坑啊!

微软MVC实现REST风格编程

1、总体来说很简单,首先新建一个MVC框架的项目,模板选择WebAPI,这样就搞定80%了。

2、WebApiConfig.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;

namespace UrlToPngWebAPI
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

            config.EnableSystemDiagnosticsTracing();
        }
    }
}

3、RouteConfig.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace UrlToPngWebAPI
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
}

4、请求结构
Web2PNGRequest.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Newtonsoft.Json;

namespace UrlToPngWebAPI.Models
{
    public class Web2PNGRequest
    {
        [JsonProperty]
        public String WebURL { get; set; }
        [JsonProperty]
        public String HeaderPath { get; set; }
        [JsonProperty]
        public String FooterPath { get; set; }
    }
}

5、返回结构
Web2PNGResponse.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Newtonsoft.Json;

namespace UrlToPngWebAPI.Models
{
    public class Web2PNGResponse
    {
        [JsonProperty]
        public int ErrorCode { get; set; }
        [JsonProperty]
        public String ErrorInfo { get; set; }
        [JsonProperty]
        public String PNGPath { get; set; }
    }
}

6、Controller
Url2PNGController.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Web.Helpers;
using System.Web.Http;
using Newtonsoft.Json;
using UrlToPngCsTest;
using UrlToPngWebAPI.Models;
using UrlToPngWebAPI.Pulgins;

namespace UrlToPngWebAPI.Controllers
{
    public class Url2PNGController : ApiController
    {
        // 返回输入参数示例
        public HttpResponseMessage Get()
        {
            Web2PNGRequest req = new Web2PNGRequest();
            req.WebURL = "webURL";
            req.HeaderPath = "headerPath";
            req.FooterPath = "footerPath";

            String jsonString = JsonConvert.SerializeObject(req);
            HttpResponseMessage result = new HttpResponseMessage { Content = new StringContent(jsonString, Encoding.GetEncoding("UTF-8"), "application/json") };
            return result;
        }

        // GET
        public HttpResponseMessage Get(String WebURL, String HeaderPath, String FooterPath)
        {
            UrlToPng4Web.InitUrlTOPng4CS();

            Web2PNGRequest req = new Web2PNGRequest();
            req.WebURL = WebURL;
            req.HeaderPath = HeaderPath;
            req.FooterPath = FooterPath;
            Web2PNGResponse rsp = UrlToPng4Web.UrlToPNG(req);
            
            String jsonString = JsonConvert.SerializeObject(rsp);
            HttpResponseMessage result = new HttpResponseMessage { Content = new StringContent(jsonString, Encoding.GetEncoding("UTF-8"), "application/json") };
            return result;
        }

        // POST
        public HttpResponseMessage Post(Web2PNGRequest req)
        {
            UrlToPng4Web.InitUrlTOPng4CS();

            Web2PNGResponse rsp = UrlToPng4Web.UrlToPNG(req);

            String jsonString = JsonConvert.SerializeObject(rsp);
            HttpResponseMessage result = new HttpResponseMessage { Content = new StringContent(jsonString, Encoding.GetEncoding("UTF-8"), "application/json") };
            return result;
        }
    }
}

Jersey实现REST风格编程

首先是服务端:
1、增加服务类

package com.neohope.jessery.test;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;

/**
 * Created by Hansen
*/
@Path("neotest")
@Produces(MediaType.APPLICATION_JSON)
public class NeoTest {
    @GET
    @Path("/Add")
    public String Add(@QueryParam("a") int a,@QueryParam("b") int b) {
        return "{\"c\":" + (a+b) + "}";
    }

    @GET
    @Path("/SayHiTo")
    public String sayHiTo(@QueryParam("name") String name) {
        return "{\"msg\":\"hi " + name + "\"}";
    }
}

2、在web.xml里增加配置

    <servlet>
        <servlet-name>Jersey Web Application</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>jersey.config.server.provider.packages</param-name>
            <param-value>com.neohope.jessery.test</param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>Jersey Web Application</servlet-name>
        <url-pattern>/Rest/*</url-pattern>
    </servlet-mapping>

3、然后是客户端

package com.neohope.jessery.test;

import org.glassfish.jersey.client.ClientConfig;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;

/**
 * Created by Hansen
 */
public class ClientTest {
    public static void main(String[] args) {
        ClientConfig clientConfig = new ClientConfig();
        Client client = ClientBuilder.newClient(clientConfig);

        WebTarget target = client.target("http://localhost:8080/Rest/neotest/" + "Add");
        Response response = target.queryParam("a", 1).queryParam("b", 2).request().get();
        System.out.println(response.getStatus());
        System.out.println(response.readEntity(String.class));
        response.close();

        WebTarget target1 = client.target("http://localhost:8080/Rest/neotest/" + "SayHiTo");
        Response response1 = target1.queryParam("name", "neohope").request().get();
        System.out.println(response1.getStatus());
        System.out.println(response1.readEntity(String.class));
        response1.close();
    }
}