2017年3月29日
最近在網(wǎng)上看到的相關(guān)材料都比較陳舊,也太簡(jiǎn)略,參看了一下其他人的內(nèi)容,針對(duì)Hive2.1.1做點(diǎn)分享:
1)下載apache-hive-2.1.1-bin.tar.gz
2)解壓縮,下面的命令行如啟動(dòng)報(bào)錯(cuò),請(qǐng)自行查略Hive啟動(dòng)配置
3)啟動(dòng)
hiveserver2 (非必須,使用jdbc訪(fǎng)問(wèn)的時(shí)候才使用)
bin目錄下
hive --service hiveserver2 -p10001來(lái)啟動(dòng)hiveserver2 服務(wù)(默認(rèn)為10000端口)
nohup hive --service hiverserver2 -p10001可以在后臺(tái)跑
4)
hive腳本運(yùn)行流程bin目錄下,使用命令方法為:
./hive <parameters> --service serviceName <service parameters>
舉例:hive --debug :
查看bin/hive文件
流程中會(huì)判斷$1=‘--debug’則$DEBUG=‘--debug’
if [ "$DEBUG" ]; then
if [ "$HELP" ]; then //如還有--help,就會(huì)執(zhí)行debug_help方法。
debug_help
exit 0
else
get_debug_params "$DEBUG"
export HADOOP_CLIENT_OPTS="$HADOOP_CLIENT_OPTS $HIVE_MAIN_CLIENT_DEBUG_OPTS"http://設(shè)置HIVE_MAIN_CLIENT_DEBUG_OPTS的參數(shù)中加入debug相應(yīng)參數(shù)
fi
fi
if [ "$SERVICE" = "" ] ; then
if [ "$HELP" = "_help" ] ; then
SERVICE="help"
else
SERVICE="cli" //默認(rèn)賦值cli
fi
fi
這個(gè)shell腳本很多變量應(yīng)該是在其他sh文件中定義,其中$SERVICE_LIST就是其他很多sh文件的最開(kāi)始形成的:export SERVICE_LIST="${SERVICE_LIST}${THISSERVICE} "
hive腳本最后的$TORUN "$@" ,默認(rèn)情況下TORUN其實(shí)就是cli,即執(zhí)行/ext/cli.sh腳本,該腳本中主要是調(diào)用/ext/util/execHiveCmd.sh 來(lái)執(zhí)行最后的CliDriver。
【
shell腳本中的$*,$@和$#舉例說(shuō):
腳本名稱(chēng)叫test.sh 入?yún)⑷齻€(gè): 1 2 3
運(yùn)行test.sh 1 2 3后
$*為"1 2 3"(一起被引號(hào)包住)
$@為"1" "2" "3"(分別被包住)
$#為3(參數(shù)數(shù)量)
】即exec $HADOOP jar ${HIVE_LIB}/$JAR $CLASS $HIVE_OPTS "$@" //1
其中:
$HADOOP=$HADOOP_HOME/bin/hadoop 【hive腳本中定義HADOOP=$HADOOP_HOME/bin/hadoop】
$CLASS=org.apache.hadoop.hive.cli.CliDriver【傳入的第一個(gè)參數(shù),在cli.sh中有定義】
hadoop腳本(2.7.3為例)中最終會(huì)執(zhí)行:
# Always respect HADOOP_OPTS and HADOOP_CLIENT_OPTS
HADOOP_OPTS="$HADOOP_OPTS $HADOOP_CLIENT_OPTS"
#make sure security appender is turned off
HADOOP_OPTS="$HADOOP_OPTS -Dhadoop.security.logger=${HADOOP_SECURITY_LOGGER:-INFO,NullAppender}"
export CLASSPATH=$CLASSPATH
exec "$JAVA" $JAVA_HEAP_MAX $HADOOP_OPTS $CLASS "$@" //2
hive的debug參數(shù)就是在啟動(dòng)hive腳本時(shí)放到HADOOP_OPTS中的
1和2處結(jié)合可得到最終的運(yùn)行命令,查看一下運(yùn)行結(jié)果:ps -ef|grep CliDriver
/usr/java/jdk1.8.0_101/bin/java -Xmx256m -Djava.net.preferIPv4Stack=true -Dhadoop.log.dir=.. -Dhadoop.log.file=hadoop.log -Dhadoop.home.dir=.. -Dhadoop.id.str=root -Dhadoop.root.logger=INFO,console -Djava.library.path=.. -Dhadoop.policy.file=hadoop-policy.xml -Djava.net.preferIPv4Stack=true -Xmx512m -Dproc_hivecli -XX:+UseParallelGC -agentlib:jdwp=transport=dt_socket,server=y,address=8000,suspend=y -Dlog4j.configurationFile=hive-log4j2.properties -Djava.util.logging.config.file=..
-Dhadoop.security.logger=INFO,NullAppender org.apache.hadoop.util.RunJar /yuxh/app/apache-hive-2.*/lib/hive-cli-2.*.jar org.apache.hadoop.hive.cli.CliDriver
2015年9月23日
2015年7月22日
appfuse3.5使用Hibernate4.3.6, 而Hibernate日志框架使用了jboss-logging,想在后臺(tái)打出sql的參數(shù)一直無(wú)法生效。
檢查配置文件,框架里面的兩個(gè)配置文件,src/test/resources/log4j2.xml(單元測(cè)試時(shí)配置),src/main/resources/log4j2.xml(運(yùn)行時(shí)配置)
搞清log4j2的配置后,各種修改(主要是
<Logger name="org.hibernate.SQL" level="trace"/>
<Logger name="org.hibernate.type" level="trace"/>)
用junit測(cè)試任然無(wú)法打印出真實(shí)參數(shù)。根據(jù)這些實(shí)踐,確定log4j2是使用無(wú)誤生效的,只是org.hibernate這部分的logger一直未起效
參考國(guó)內(nèi)外網(wǎng)站,一直無(wú)人回答hibernate4的這個(gè)問(wèn)題,有人指出這部分Hibernate官方文檔只是提了一句,一直未更新相關(guān)內(nèi)容。最后有人提到應(yīng)該是 jboss-logging 的LoggerProviders這個(gè)類(lèi)的問(wèn)題,看實(shí)現(xiàn)對(duì)log4j2已經(jīng)做支持。最后發(fā)現(xiàn) jboss-logging使用的是3.2.0.beta,對(duì)比相關(guān)類(lèi)的源代碼,更改為3.2.0.Final,生效!
P.S 把這個(gè)問(wèn)題提交給Appfuse官網(wǎng),issue APF-1478,作者標(biāo)志為4.0版本修復(fù)。
2015年6月2日
新電腦裝上eclipse4.4.2,導(dǎo)入maven項(xiàng)目之后,依賴(lài)庫(kù)總是有很多錯(cuò)誤。最后搜索到可能是eclipse的bug(據(jù)說(shuō)是
JAVA_HOME沒(méi)有正確傳遞
),查看到eclipse默認(rèn)的是安裝的jre目錄,修改到j(luò)dk目錄下,依賴(lài)問(wèn)題解決。
不過(guò)目前版本仍然沒(méi)有解決pom文件的“Plugin execution not covered by lifecycle configuration”錯(cuò)誤,暫時(shí)忽略不管吧。
2012年5月31日
本打算繼承一個(gè)API中的Parent類(lèi)(Parent繼承自GrandParent類(lèi)),重寫(xiě)其中的service方法,copy了Parent的service方法。不過(guò)發(fā)現(xiàn)Parent的service中也有super.service方法。當(dāng)時(shí)考慮直接調(diào)用GrandParent的service方法。。。未遂(包括反射也不行)。正好看到老外寫(xiě)的一篇文章,翻譯:
在Son類(lèi)里面寫(xiě)一個(gè)test方法:
public void test() {
super.test();
this.test();
}
反編譯之后:
public void test()
{
// 0 0:aload_0
// 1 1:invokespecial #2 <Method void Parent.test()>
// 2 4:aload_0
// 3 5:invokevirtual #3 <Method void test()>
// 4 8:return
}
使用ASM可以完成對(duì)GrandParent方法的調(diào)用
public class GrandParent {
public void test() {
System.out.println("test of GrandParent");
}
}
public class Parent extends GrandParent{
public void test() {
System.out.println("test of Parent");
}
}
public class Son extends Parent{
public void test() {
System.out.println("test of Son");
}
}
調(diào)用Son實(shí)例的test方法只會(huì)執(zhí)行Son的test方法。而ASM可以修改class,先寫(xiě)一個(gè)Example類(lèi)繼承Son,重寫(xiě)test方法
1 import java.io.FileOutputStream;
2
3 import org.objectweb.asm.ClassWriter;
4 import org.objectweb.asm.MethodVisitor;
5 import org.objectweb.asm.Opcodes;
6
7 public class ASMByteCodeManipulation extends ClassLoader implements Opcodes {
8
9 public static void main(String args[]) throws Exception {
10 ClassWriter cw = new ClassWriter(0);
11 cw.visit(V1_1, ACC_PUBLIC, "Example", null, "Son", null);
12
13 // creates a MethodWriter for the (implicit) constructor
14 MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null,null);
15 mw.visitVarInsn(ALOAD, 0);
16 mw.visitMethodInsn(INVOKESPECIAL, "Son", "<init>", "()V");
17 mw.visitInsn(RETURN);
18 mw.visitMaxs(1, 1);
19 mw.visitEnd();
20
21 // creates a MethodWriter for the 'test' method
22 mw = cw.visitMethod(ACC_PUBLIC, "test", "()V", null, null);
23 mw.visitFieldInsn(GETSTATIC, "java/lang/System", "out","Ljava/io/PrintStream;");
24 mw.visitLdcInsn("test of AI3");
25 mw.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println",
26 "(Ljava/lang/String;)V");
27 //Call test() of GrandParent
28 mw.visitVarInsn(ALOAD, 0);
29 mw.visitMethodInsn(INVOKESPECIAL, "GrandParent", "test", "()V");
30 //Call test() of GrandParent
31 mw.visitVarInsn(ALOAD, 0);
32 mw.visitMethodInsn(INVOKESPECIAL, "Parent", "test", "()V");
33 //Call test() of GrandParent
34 mw.visitVarInsn(ALOAD, 0);
35 mw.visitMethodInsn(INVOKESPECIAL, "Son", "test", "()V");
36 mw.visitInsn(RETURN);
37 mw.visitMaxs(2, 1);
38 mw.visitEnd();
39
40 byte[] code = cw.toByteArray();
41 FileOutputStream fos = new FileOutputStream("Example.class");
42 fos.write(code);
43 fos.close();
44
45 ASMByteCodeManipulation loader = new ASMByteCodeManipulation();
46 Class<?> exampleClass = loader.defineClass("Example", code, 0,
47 code.length);
48 Object obj = exampleClass.newInstance();
49 exampleClass.getMethod("test", null).invoke(obj, null);
50
51 }
52 }
輸出:
test of AI3
test of GrandParent
test of Parent
test of Son
看看怎樣實(shí)現(xiàn)的,11行定義一個(gè)新的類(lèi)Example繼承Son。22行,Example重寫(xiě)test方法,先打印“test of AI3”,再分別在29、32、35行調(diào)用
GrandParent、Parent、Son的test方法。 main方法中,45行創(chuàng)建Example的實(shí)例,再用反射調(diào)他的test方法。
使用invokespecial這種方式也有局限,只能從子類(lèi)調(diào)用。否則報(bào)錯(cuò):
Exception in thread "main" java.lang.VerifyError: (class: Example, method: test1 signature: (LAI2;)V) Illegal use of nonvirtual function call
2012年5月30日
使用Google calendar v3 API的時(shí)候,大量發(fā)現(xiàn)Builder使用。比如Credential類(lèi),查了查Builder模式的講解,始終感覺(jué)代碼的實(shí)現(xiàn)和標(biāo)準(zhǔn)定義不太相同。最后發(fā)現(xiàn)這種實(shí)現(xiàn)方式是《Effective java 2nd》中的一種實(shí)現(xiàn)(Item 2: Consider a builder when faced with many constructor parameters)。靜態(tài)工廠(chǎng)和構(gòu)造器都有一個(gè)通病:對(duì)于存在大量可選構(gòu)造參數(shù)的對(duì)象,擴(kuò)展性不好。經(jīng)典的解決方案是提供多個(gè)構(gòu)造函數(shù),第一個(gè)構(gòu)造函數(shù)只有必須的參數(shù),第二個(gè)構(gòu)造函數(shù)除了必須參數(shù)還有一個(gè)可選參數(shù),第三個(gè)除了必須參數(shù)還有兩個(gè)可選參數(shù)。。。這樣下去知道最后一個(gè)可選參數(shù)出現(xiàn)(
telescoping constructor)。這種方案的問(wèn)題是,當(dāng)構(gòu)建對(duì)象的時(shí)候很容易把其中兩個(gè)參數(shù)的位置放反。。。。
(難發(fā)現(xiàn)的bug)。
另一種解決方案是JavaBean 模式,先調(diào)用無(wú)參構(gòu)造函數(shù)再調(diào)用各個(gè)set方法來(lái)組裝對(duì)象。這種方案的問(wèn)題是不能強(qiáng)制一致性。如果沒(méi)有set某些必須的參數(shù)的話(huà),對(duì)象可能處于不一致(
inconsistent)的狀態(tài)(難發(fā)現(xiàn)的bug)。另外一個(gè)缺點(diǎn)是JavaBean模式不能讓類(lèi)immutable,需要程序員額外工作保證線(xiàn)程安全。
第三種方式就是Builder設(shè)計(jì)模式。這種方式混合了
telescoping constructor模式的安全性和JavaBean模式的可讀性。客戶(hù)端調(diào)用有所有必填參數(shù)的構(gòu)造器(或靜態(tài)工廠(chǎng)),得到一個(gè)builder對(duì)象。然后調(diào)用builder對(duì)象的方法去set各個(gè)選填參數(shù)。最后調(diào)用無(wú)參的build方法產(chǎn)生一個(gè)immutable的對(duì)象實(shí)例。immutable對(duì)象有非常多優(yōu)點(diǎn)而且可能很有用。builder的set方法都是返回builder本身,所以調(diào)用也是可以chained。如:
GoogleCredential credentialNew = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY).setClientSecrets(clientSecrets)
.addRefreshListener(new CredentialStoreRefreshListener(userID, new DBCredentialStore())).build()
.setAccessToken(accessToken).setRefreshToken(refreshToken)
客戶(hù)端代碼很好寫(xiě),更重要的是易讀。Builder模式模擬了在Ada和Python語(yǔ)言里的命名可選參數(shù)(
named optional parameters)。
同時(shí)Builder類(lèi)設(shè)置為static也是對(duì)Item 22:Favor static member classes over nonstatic的實(shí)踐
2012年5月8日
以典型的客戶(hù)端-服務(wù)器端授權(quán)為例
一 基本流程
使用Google Calendar v3 ,如果以servlet作為代理,可以使用官方示例,自己寫(xiě)一個(gè)類(lèi)A.java繼承AbstractAuthorizationCodeServlet類(lèi),這個(gè)類(lèi)主要用于跳轉(zhuǎn)到google提供的授權(quán)頁(yè)面,如果用戶(hù)同意授權(quán),則根據(jù)A類(lèi)中的URL(這個(gè)必須和注冊(cè)的google 回調(diào)路徑相同,比如oauth_callback否則報(bào)錯(cuò))重定向到B類(lèi),B.java 繼承AbstractAuthorizationCodeCallbackServlet類(lèi),這個(gè)訪(fǎng)問(wèn)路徑類(lèi)似http://www.example.com/oauth_callback?code=ABC1234。這里我配置oauth_callback為servlet的訪(fǎng)問(wèn)路徑,B類(lèi)中的
onSuccess方法將根據(jù)獲得的access Token(這是根據(jù)傳過(guò)來(lái)的code獲得的)做業(yè)務(wù)操作。
二 需要參數(shù)的情況
有些業(yè)務(wù)需要用戶(hù)傳參數(shù),
直接傳參數(shù)給A,再試圖在B中獲取是不行的!B類(lèi)中只能獲取某些
固定的參數(shù),如code。要想傳用戶(hù)參數(shù),我們可以在A中先獲取,把幾個(gè)參數(shù)組裝為json格式字符串(還可以繼續(xù)base64編碼),把這個(gè)字符串作為state的值,再重定向到授權(quán)頁(yè)面,同意后state參數(shù)可以傳到B類(lèi),取值解析json字符串(或先base64解碼),得到參數(shù)。
由于API中AuthorizationCodeRequestUrl有處理state的方法,而AbstractAuthorizationCodeServlet已經(jīng)直接封裝,為了使用setState,直接在A類(lèi)中繼承HttpServlet重寫(xiě)service方法,復(fù)制大部分AbstractAuthorizationCodeServlet的內(nèi)容,稍作修改:
resp.sendRedirect(flow.newAuthorizationUrl()
.setState(json).setRedirectUri(redirectUri).build());
三 關(guān)于refresh token
默認(rèn)情況下,用戶(hù)授權(quán)之后token會(huì)有一個(gè)小時(shí)的有效期,之后你可以通過(guò)refresh token再重新獲取token。所以,如果不需要用戶(hù)再次授權(quán),可以在第一次,保存好token、refresh token、ExpirationTime。實(shí)例中用了JDO來(lái)實(shí)現(xiàn),自己如果使用數(shù)據(jù)庫(kù)保存,可類(lèi)似寫(xiě)一個(gè)類(lèi)實(shí)現(xiàn)CredentialStore類(lèi)。使用的時(shí)候,現(xiàn)在數(shù)據(jù)庫(kù)中取出,再創(chuàng)建credential,如:
GoogleCredential credentialNew = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
.setJsonFactory(JSON_FACTORY).setClientSecrets(clientSecrets)
.addRefreshListener(new CredentialStoreRefreshListener(userID, new DBCredentialStore())).build()
.setAccessToken(accessToken).setRefreshToken(refreshToken)
.setExpirationTimeMilliseconds(expirationTimeMilliseconds);
在無(wú)效的情況下,Listener會(huì)自動(dòng)去用refresh token請(qǐng)求。
2012年3月12日
Andriod 到3.2版本為止,webview方式下使用<input type="file" />點(diǎn)擊后都沒(méi)有反應(yīng)。實(shí)際上頂層是有隱含的接口沒(méi)實(shí)現(xiàn)的,可以自己重寫(xiě)這個(gè)方法來(lái)實(shí)現(xiàn)。以phonegap為例:
public class App extends DroidGap {
private ValueCallback<Uri> mUploadMessage;
private final static int FILECHOOSER_RESULTCODE = 1;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.init();
// WebView wv = new WebView(this);
// wv.setWebViewClient(new WebViewClient());
this.appView.setWebChromeClient(new CordovaChromeClient(App.this) {
// For Android 3.0+
public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
App.this.startActivityForResult(Intent.createChooser(i, "File Chooser"), FILECHOOSER_RESULTCODE);
}
// The undocumented magic method override
// Eclipse will swear at you if you try to put @Override here
public void openFileChooser(ValueCallback<Uri> uploadMsg) {
mUploadMessage = uploadMsg;
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
i.addCategory(Intent.CATEGORY_OPENABLE);
i.setType("image/*");
App.this.startActivityForResult(Intent.createChooser(i, "File Chooser"), App.FILECHOOSER_RESULTCODE);
}
});
// setContentView(wv);
super.loadUrl("file:///android_asset/www/login.html");
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (requestCode == FILECHOOSER_RESULTCODE) {
if (null == mUploadMessage)
return;
Uri result = intent == null || resultCode != RESULT_OK ? null : intent.getData();
mUploadMessage.onReceiveValue(result);
mUploadMessage = null;
}
}
}
如果直接的webview方式,extends WebChromeClient即可。
參考:http://stackoverflow.com/questions/5907369/file-upload-in-webview
2011年10月24日
1. Code first approach:可能不能完全發(fā)揮框架和web services的能量,但能完成目標(biāo)。減少了學(xué)習(xí)曲線(xiàn),不用非常透徹了解web services概念,只要對(duì)某個(gè)框架有一定了解就能完成任務(wù)。
2.Contract first approach:根據(jù)服務(wù)先寫(xiě)WSDL文件,寫(xiě)好之后使用框架的工具把WSDL轉(zhuǎn)換為依賴(lài)框架的代碼。
一 介紹
當(dāng)客戶(hù)端調(diào)用你的web service的時(shí)候,他會(huì)發(fā)送一個(gè)消息過(guò)來(lái)(可能是soap 消息),如:
<foo:concatRequest>
<s1>abc</s1>
<s2>123</s2>
</foo:concatRequest>
這時(shí)候如果有一個(gè)轉(zhuǎn)換器把這個(gè)soap消息轉(zhuǎn)換成java對(duì)象,然后調(diào)用你提供的java對(duì)象(方法)的話(huà)將會(huì)是非常方便的。幾個(gè)最流行的庫(kù)就是充當(dāng)了這種轉(zhuǎn)換器功能,比如CXF, Axis2 , Metro (jdk6自帶的有)。
手動(dòng)創(chuàng)建WSDL文件比較容易出錯(cuò),可以使用eclipse進(jìn)行可視化編輯。
二 生成服務(wù)代碼
像CXF這樣的 web service庫(kù)可以創(chuàng)建轉(zhuǎn)換器把進(jìn)來(lái)的SOAP 消息轉(zhuǎn)換為Java對(duì)象,然后作為參數(shù)傳給方法。生成這些代碼,只需創(chuàng)建一個(gè)main:
1 CXF方式:
public static void main(String[] args) {
WSDLToJava.main(new String[] {
"-server",
"-d", "src/main/java",
"src/main/resources/SimpleService.wsdl" });
System.out.println("Done!");
}
運(yùn)行后會(huì)生成service endpoint interface(SEI),我們?cè)賹?xiě)一個(gè)類(lèi)(比如SimpleServiceImpl)來(lái)實(shí)現(xiàn)這個(gè)接口,寫(xiě)入自己的業(yè)務(wù)。還會(huì)生成傳入消息對(duì)應(yīng)的java對(duì)象。同時(shí)生成一個(gè)服務(wù)器類(lèi):
public class SimpleService_P1_Server {
protected SimpleService_P1_Server() throws Exception {
System.out.println("Starting Server");
Object implementor = new SimpleServiceImpl();
String address = "http://localhost:8080/ss/p1";
Endpoint.publish(address, implementor);
}
public static void main(String args[]) throws Exception {
new SimpleService_P1_Server();
System.out.println("Server ready...");
Thread.sleep(5 * 60 * 1000);
System.out.println("Server exiting");
System.exit(0);
}
}
運(yùn)行這個(gè)類(lèi)你的web service就可以服務(wù)了。
2 Axis2 方式
用類(lèi)似的寫(xiě)main方法,或者配置eclipse的axis2插件可生成:在WSDL文件上,右鍵->web service->generate java bean skeleton
界面的上半部分針對(duì)服務(wù)端,可以根據(jù)需要調(diào)整生成的級(jí)別,下半部分是生成客戶(hù)端。具體的級(jí)別可參考eclipse的幫助文檔。一路下一步,最后根據(jù)命名空間生成包路徑的文件,里面有XXSkeletonInterface.java 文件(如果生成的時(shí)候選擇了生成接口的話(huà)),還有一個(gè)XXSkeleton實(shí)現(xiàn)了這個(gè)接口,也是我們需要修改這部分代碼完成我們業(yè)務(wù)的地方。實(shí)際上有一個(gè)XXMessageReceiverInOut.java的類(lèi)接收請(qǐng)求的消息,并調(diào)用XXSkeletonInterface。使用eclipse的axis2插件的時(shí)候,會(huì)自動(dòng)在web-inf文件夾下生成service\xx(你的wsdl服務(wù)名),這下面還要一個(gè)meta-inf文件夾裝有wsd文件和一個(gè)services.xml配置文件。services.xml文件可配置包括XXMessageReceiverInOut類(lèi)在內(nèi)的選項(xiàng)。
二 生成客戶(hù)端代碼
為了調(diào)用這些web service,同樣可以用CXF這些庫(kù)來(lái)生成在客戶(hù)端運(yùn)行的轉(zhuǎn)換器(稱(chēng)為service stub)。當(dāng)調(diào)用stub里的方法的時(shí)候,他會(huì)把你的數(shù)據(jù)/對(duì)象 轉(zhuǎn)換為正確的XML格式,然后發(fā)送給真正的web service。當(dāng)他收到響應(yīng)的時(shí)候,又會(huì)把XML轉(zhuǎn)回Java。
1 CXF 方式
和生成服務(wù)器端類(lèi)似,使用方法
WSDLToJava.main(new String[] {
"-client",
"-d", "src/main/java",
"src/main/resources/SimpleService.wsdl" });
運(yùn)行后會(huì)生成客戶(hù)端代碼:
public final class SimpleService_P1_Client {
private static final QName SERVICE_NAME = new QName("http://ttdev.com/ss",
"SimpleService");
private SimpleService_P1_Client() {}
public static void main(String args[]) throws Exception {
URL wsdlURL = SimpleService_Service.WSDL_LOCATION;
if (args.length > 0) {
File wsdlFile = new File(args[0]);
try {
if (wsdlFile.exists()) {
wsdlURL = wsdlFile.toURI().toURL();
} else {
wsdlURL = new URL(args[0]);
}
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
SimpleService_Service ss =
new SimpleService_Service(wsdlURL, SERVICE_NAME);
SimpleService port = ss.getP1();
{
System.out.println("Invoking concat...");
com.ttdev.ss.ConcatRequest _concat_parameters = null;
java.lang.String _concat__return = port.concat(_concat_parameters);
System.out.println("concat.result=" + _concat__return);
}
System.exit(0);
}
}
SimpleService_Service是創(chuàng)建的service stub,他模擬了客戶(hù)端的服務(wù)。我們需要修改這個(gè)類(lèi)中的_concat_parameters部分,加入?yún)?shù):
com.ttdev.ss.ConcatRequest _concat_parameters = new ConcatRequest();
_concat_parameters.setS1("abc");
_concat_parameters.setS2("123");
現(xiàn)在就可以運(yùn)行客戶(hù)端代碼了。SEI中有一些注解,可以修改,不細(xì)說(shuō)。
2 Axis2 方式
和生成服務(wù)端類(lèi)似,利用eclipse插件直接生成,包路徑類(lèi)似,有一個(gè)XXStub類(lèi),這個(gè)類(lèi)里面有包括請(qǐng)求和應(yīng)答消息在內(nèi)的內(nèi)部類(lèi)。使用的時(shí)候,先對(duì)請(qǐng)求消息參數(shù)類(lèi)按業(yè)務(wù)需求賦值,最后調(diào)用Stub的請(qǐng)求方法。可以使用Stub的構(gòu)造函數(shù)指定目標(biāo)endpoint。
2011年10月8日
有兩種SOAP message風(fēng)格,document 和RPC,他們定義了SOAP message body的格式。使用document風(fēng)格時(shí)(包括wrapped和unwrapped),在wsdl中有一個(gè)非空的types部分,這個(gè)部分用XML Schema language定義了web service要用到的類(lèi)型。wsgen工具從SIB(有SEI就足夠了)中生成與XSD對(duì)應(yīng)的java類(lèi)。用java代碼生成WSDL文件的時(shí)候需要一些java類(lèi),wsgen工具可以生成這些Java類(lèi),生成的這些java類(lèi)被稱(chēng)為wsgen artifacts,底層的JWS類(lèi)庫(kù)會(huì)用到這些類(lèi),特別是JAX-B系列的包,會(huì)用來(lái)轉(zhuǎn)換(marshal)java類(lèi)實(shí)例(that is, Java in-memory objects)為XML類(lèi)型的XML實(shí)例(滿(mǎn)足XML Schema document的XML文檔實(shí)例),
The inverse operation is used to convert (unmarshal) an XML document instance to an in-memory
object, an object of a Java type or a comparable type in some other language。因此wsgen工具生成的artifacts,支持了Java為基礎(chǔ)的web service的互操作性。JAX-B類(lèi)庫(kù)提供了Java和XSD類(lèi)型轉(zhuǎn)換的底層支持。
For the most part, the wsgen utility can be used without our bothering to inspect the artifacts that it produces. For the most part, JAX-B remains unseen infrastructure.
wsgen artifacts實(shí)際上是wsdl message的數(shù)據(jù)類(lèi)型,他們和XML Schema type綁定,每個(gè)message的XML Schema types從這些java類(lèi)型得來(lái)的。注:在當(dāng)前的jdk1.6.24中,已經(jīng)融入wsgen自動(dòng)生成的過(guò)程,不需手動(dòng)調(diào)用。
wsgen工具可用來(lái)生成wsdl文件,如:% wsgen -cp "." -wsdl ch01.ts.TimeServerImpl 。這為T(mén)imeServer服務(wù)生成了wsdl。用wsgen生成的wsdl和通過(guò)訪(fǎng)問(wèn)發(fā)布的服務(wù)生成的wsdl 有個(gè)很大的區(qū)別:wsgen生成的沒(méi)有endpoint,因?yàn)檫@個(gè)URL是在發(fā)布服務(wù)的時(shí)候決定的。其他地方兩個(gè)wsdl是相同的。
wsimport(以前叫wsdl2java和 java2wsdl更形象)工具可使用WSDL生成用來(lái)幫助寫(xiě)客戶(hù)端的artifacts .
1 先契約再編碼方式
一個(gè)例子:得到一個(gè)tempConvert.wsdl文件,使用命令 wsimport -keep -p ch02.tc tempConvert.wsdl ,命令根據(jù)wsdl的portType生成一個(gè)SEI類(lèi),把SEI的interface換為class,再把方法改為實(shí)現(xiàn)就可變?yōu)镾IB。把該SIB發(fā)布,再使用命令wsimport -keep -p clientTC http://localhost:5599/tc?wsdl,來(lái)生成客戶(hù)端輔助類(lèi)
2 編碼優(yōu)先
服務(wù)被發(fā)布之后,會(huì)自動(dòng)生成WSDL供客戶(hù)端使用。然而,使用annotations可以控制WSDL或WSDL-generated artifacts的生成。