在网上查了很多资料都是一知半解很多坑,今天抽空把这个文章整理出来提供给有需要的人,上项目的时候乙方的开发人员搞了个半成品而且编译都不能通过,与其他系统集成的时候非常痛苦,其他系统已经有标准的WEBAPI,结果我们还要去开发个webservice,今天狠下心来自己搞定这个问题,下面我把详细的步骤和遇到的注意事项整理出来。
环境: GP5.30 (这个版本对应的jdk是1.6),特别注意
JAR: apache httpcomponents-client-4.5.14 (jdk 1.6的环境)
注意:除了apache httpcomponents外还有OKhttp3可以拿来用,Okhttp3需要基于jdk1.6重新编译,为了节约时间我采用的apache httpcomponents-client-4.5.14,OKhttp3平时在做android开发的时候用的较多,都是封装好了的工具并且支持SSL。
具体步骤:
- 基于apache httpcomponents-client-4.5.14开发一个处理http请求的jar包负责处理来自tiptop的请求并返回结果,支持post和get两种方式,打包后的文件为tiptop-webapihttp.jar,如果需要对SSL的兼容自己去研究我就不再花时间写了,jar的开发过程我就不写了吧,开发工具IDEA或者Eclipse,甚至直接可以在记事本里面写了直接用java 命令打包也可以,建议打包好了的jar包在本地项目中新建个java项目引用刚才的tiptop-webapihttp.jar包测试一下确保其http jar包功能正常。(tiptop-webapihttp.jar 是我自己命名不重要)。
- 部署jar包,这个是个细活要注意
1、将开发好的iptop-webapihttp.jar文件和apache httpcomponents-client-4.5.14依赖jar文件一起上传到
TIPTOP服务器,注意路径:u1/topprod/tiptop/ds4gl2/bin/javaad/jar
- jar包环境变量设置
首先切换到root账号,修改环境变量 tiptop_env文件中的jar包引用路径。tiptop_env位置:/u1/topprod/tiptop/bin/tiptop_env,可使用VI直接进行编辑CLASSPATH,然后保存。(注意:多个环境变量以 冒号 隔开,最后一个环境变量时用 分号 结束),环境变量包括引用tiptop-webapihttp.jar以及依赖jar包。
注意:修改前备份一下tiptop_env。
- 环境变量刷新
命令:source /u1/topprod/tiptop/bin/tiptop_env
三、4GL程序测试程序开发
1、为了方便我们封装了一个lib函数cl_webapi.4gl,负责调用tiptop-webapihttp.jar中的方法与web通讯并接收及处理返回结果, 关于json的处理方法就不再详细赘述了,自己看代码用到net.sf.json.JSON的jar包。
cl_webapi.4gl代码
# Prog. Version..: '5.25.11-12.12.11(00010)' #
#<-------------------------------------------------------------------------------------------------------------->
# Library name.....: cl_web_api.4gl
# Descriptions.....: 4GL提交Json到Web,获取Web返回的对象,并进行解析.(4GL调用外部Web API)
# Memo.............: Two days,so funny. Where there is a will,there is a way..Ha-Ha-Ha..
# Usage............: CALL cl_web_api(p_Url,p_Post_Json,p_Type,p_Nouse2) RETURNING p_Temp_Tab/object
# param_In_1.......: p_Url , type=String
# <--Example-->: p_Url = "http://xxx.xxx.x.xx/2wm/public/index.php/api/Index/uploadTest?a=test"
# param_In_2.......: p_Post_Json , type=String
# <--Example-->: p_Post_Json = 'postData=[{"rec_id": "1","name": "Evan"},{"rec_id": "2","name": "Bluts"}]'
# param_In_3.......: p_Type , type= Integer (type = 1 返回表名 type = 2 返回对象 )
# param_In_4.......: p_Nouse2 , type=String
#
# param_Out_1......: p_Temp_Tab, type = String, Create temp table with random.
#
# Date & Authors...: 2024-07-23/24 By Evan & Andrew
#<-------------------------------------------------------------------------------------------------------------->
IMPORT os
IMPORT com
IMPORT JAVA net.sf.json.JSON
IMPORT JAVA net.sf.json.JSONArray
IMPORT JAVA net.sf.json.JSONObject
IMPORT JAVA net.tainetwork.IHttpUtil
IMPORT util
DATABASE ds
GLOBALS "../../config/top.global"
FUNCTION cl_webapi(p_Url,p_Post_Json,p_Type,p_Nouse2)
DEFINE p_Url STRING,
p_Post_Json STRING,
g_success STRING,
p_Type INTEGER ,
p_Nouse2 STRING
DEFINE l_rData STRING,
l_i INTEGER,
l_i_i INTEGER
DEFINE w net.sf.json.JSONObject #获取接口回传的对象
DEFINE jsony,jsonykey net.sf.json.JSONArray
DEFINE jsonwx net.sf.json.JSONObject
DEFINE l_str STRING
DEFINE l_tab_colum STRING,
l_tem_tab_name STRING,
l_json_values STRING,
l_ins_values STRING
DEFINE l_ins_sql ,l_msg STRING
#组合URL,提交参数的JSON格式,返回对象 w
LET l_tab_colum = " "
LET g_success = 'Y'
TRY
CALL IHttpUtil.appget(p_Url) RETURNING w
DISPLAY 'cl_ktwebapi RETURNING:',w
RETURN l_msg
CATCH
LET l_msg = "ERROR :",STATUS,"==>API接口通讯失败!"
CALL cl_err(l_msg,"!",1)
IF p_Type = 1 THEN
RETURN " "
ELSE
RETURN w
END IF
END TRY
IF p_Type = 2 THEN
RETURN w
END IF
#web端固定回传对象为rData
LET l_rData = w.getString("rData")
CALL cl_err(l_rData,'!',1)
#根据回传对象rData解析为数组
LET jsony = w.getJSONArray("rData")
IF jsony.size()=0 THEN
CALL cl_err("获取回传值失败!",'!',1)
RETURN " "
END IF
#begin----------------------------------create temp table------------------------------------------
#循环json的key值作为字段创建一个临时表:l_tem_tab_name.临时表字段统一用varhcar(4000)顶额
LET jsonwx = JSONObject.fromObject(jsony.getString(0))
LET jsonykey = jsonwx.names() #json key获取 array
FOR l_i_i = 0 TO jsonykey.size()-1
IF cl_null(jsonykey.getString(l_i_i)) THEN
CALL cl_err("服务器回传的JSON格式key值为空,这是不允许的!","!",1)
LET g_success = 'N'
EXIT FOR
END IF
LET l_tab_colum = l_tab_colum,' ',
jsonykey.getString(l_i_i),' VARCHAR(4000)',','
END FOR
IF g_success = 'N' THEN
RETURN " "
END IF
CALL cl_operation_str(l_tab_colum) RETURNING l_tab_colum
CALL cl_create_temp_table(l_tab_colum) RETURNING l_tem_tab_name
IF cl_null(l_tem_tab_name ) THEN
RETURN " "
END IF
#end----------------------------------create temp table------------------------------------------
#begin----------------------------------insert data into temp table------------------------------
#两层循环,获取key对应的value值:l_values,组合出插入临时表的value值('column1','column2'.......),并写入临时表
FOR l_i = 0 TO jsony.size()-1
LET jsonwx = JSONObject.fromObject(jsony.getString(l_i))
LET jsonykey = jsonwx.names() #json key获取 array
LET l_ins_values = " "
LET l_json_values = " "
FOR l_i_i = 0 TO jsonykey.size()-1
LET l_json_values = jsonwx.getString(jsonykey.getString(l_i_i)) #根据json key 获取对应的value值
IF cl_null(l_json_values) THEN
LET l_json_values = " "
END IF
LET l_ins_values = l_ins_values," ","'",l_json_values,"'","," #json key对应的values可能有特殊符号待处理?
END FOR
CALL cl_operation_str(l_ins_values) RETURNING l_ins_values
LET l_ins_sql = " INSERT INTO ",l_tem_tab_name," ",
" VALUES ",l_ins_values
PREPARE l_ins_sql_pb FROM l_ins_sql
EXECUTE l_ins_sql_pb
IF STATUS THEN
CALL cl_err("写入临时表失败!","1",1)
RETURN " "
END IF
END FOR
#end----------------------------------insert data into temp table------------------------------
RETURN l_tem_tab_name
END FUNCTION
FUNCTION cl_create_temp_table(p_tab_colum)
DEFINE p_tab_colum STRING
DEFINE l_cre_temp_tab_sql STRING,
l_tab_name STRING,
l_random INTEGER,
l_ymd VARCHAR(20),
ls_time STRING ,
g_prog STRING
CALL util.Math.rand(10000) RETURNING l_random
LET ls_time = TIME
LET l_tab_name = g_prog CLIPPED, "_",
TODAY USING "YYMMDD", "_",
ls_time.subString(1,2), ls_time.subString(4,5), ls_time.subString(7,8),'_',l_random
CALL cl_replace_str(l_tab_name,' ','') RETURNING l_tab_name
LET l_cre_temp_tab_sql = " Create Global Temporary Table ", #两种方式创建临时表1,会话类型;2,事务类型
" ",l_tab_name," ",
" ",p_tab_colum," On Commit Preserve Rows " #本次选择会话类型创建
PREPARE l_cre_temp_tab_pb FROM l_cre_temp_tab_sql
EXECUTE l_cre_temp_tab_pb
IF STATUS THEN
CALL cl_err("创建临时表出错"||l_tab_name,'!',1)
RETURN " "
END IF
RETURN l_tab_name
END FUNCTION
FUNCTION cl_operation_str(p_str)
DEFINE p_str STRING
LET p_str = p_str.substring(3,length(p_str)) #去掉开头的空格
LET p_str = p_str.substring(1,length(p_str)-1) #去掉最后一个逗号
LET p_str = '(',p_str,')' #外层加上括号
RETURN p_str
END FUNCTION
- 上传编译cl_webapi.4gl
- 在其他程序中调用测试
测试结果:
附:为了测试方便发一个web测试工具p_http效果如下:
p_http.4gl
# Prog. Version..: '5.30.23-16.12.05' #
#
# Pattern name...: p_http.4gl
# Descriptions...: Web 请求测试工具
# Date & Author..: 2024/11/19 Evan
#
IMPORT os
IMPORT com
IMPORT JAVA net.sf.json.JSON
IMPORT JAVA net.sf.json.JSONArray
IMPORT JAVA net.sf.json.JSONObject
IMPORT JAVA net.tainetwork.IHttpUtil
IMPORT util
DATABASE ds
GLOBALS "../../config/top.global"
DEFINE tm RECORD
g_wc STRING,
g_url STRING, #请求地址
g_type STRING, #请求类型 1:POST 2:GET
g_parms STRING, #当请g_type = 2 的时候g_parms必须为json字符串
g_response STRING #返回的结果
END RECORD
MAIN
OPTIONS
INPUT NO WRAP
DEFER INTERRUPT
IF (NOT cl_user()) THEN
EXIT PROGRAM
END IF
WHENEVER ERROR CALL cl_err_msg_log
IF (NOT cl_setup("CZZ")) THEN
EXIT PROGRAM
END IF
OPEN WINDOW p_http_w WITH FORM "czz/42f/p_http"
ATTRIBUTE (STYLE = g_win_style CLIPPED)
CALL cl_ui_init()
LET g_action_choice = ""
CALL http_menu()
CLOSE WINDOW p_http_w
CALL cl_used(g_prog,g_time,2) RETURNING g_time
END MAIN
FUNCTION http_menu()
MENU ""
ON ACTION query
LET g_action_choice="query"
IF cl_chk_act_auth() THEN
CALL http_q()
END IF
ON ACTION help
CALL cl_show_help()
ON ACTION exit
LET g_action_choice = "exit"
EXIT MENU
ON ACTION controlg
CALL cl_cmdask()
ON ACTION locale
CALL cl_dynamic_locale()
CALL cl_show_fld_cont()
CONTINUE MENU
ON IDLE g_idle_seconds
CALL cl_on_idle()
ON ACTION about
CALL cl_about()
ON ACTION CLOSE
LET INT_FLAG=FALSE
LET g_action_choice = "exit"
EXIT MENU
END MENU
END FUNCTION
FUNCTION http_q()
MESSAGE ""
CLEAR FORM
CALL http_askkey()
MESSAGE " SEARCHING ! "
CALL http_show()
MESSAGE " "
END FUNCTION
FUNCTION http_askkey()
CALL cl_opmsg('p')
INITIALIZE tm.* TO NULL
WHILE TRUE
DIALOG ATTRIBUTES(UNBUFFERED)
INPUT BY NAME tm.g_url,tm.g_type,tm.g_parms,tm.g_response
ATTRIBUTE(WITHOUT DEFAULTS=TRUE)
BEFORE INPUT
DISPLAY '开始查询'
ON ACTION locale
CALL cl_show_fld_cont()
LET g_action_choice = "locale"
EXIT DIALOG
ON ACTION CONTROLZ
CALL cl_show_req_fields()
ON ACTION CONTROLG
CALL cl_cmdask()
ON IDLE g_idle_seconds
CALL cl_on_idle()
CONTINUE DIALOG
ON ACTION about
CALL cl_about()
ON ACTION help
CALL cl_show_help()
ON ACTION exit
LET INT_FLAG = 1
EXIT DIALOG
END INPUT
END DIALOG
IF INT_FLAG THEN
LET INT_FLAG = 0 CLOSE WINDOW p_http_w
RETURN
END IF
IF g_action_choice = "locale" THEN
LET g_action_choice = ""
CALL cl_dynamic_locale()
CONTINUE WHILE
END IF
ERROR ""
EXIT WHILE
END WHILE
IF INT_FLAG THEN
LET INT_FLAG = 0
RETURN
END IF
CALL http_show()
END FUNCTION
FUNCTION http_show()
DEFINE l_str STRING
CALL IHttpUtil.appget(tm.g_url) RETURNING l_str
LET tm.g_response = l_str
DISPLAY 'tm.g_response ',l_str
DISPLAY l_str to tm.g_response
END FUNCTION
下期分享基于java的多数据源用法