最近要做一个监控oracle数据库中某张表变动后往另一个数据库中写入数据的应用。
思路:数据库某张表数据变动时需要把这些数据写入另外一个数据库的表中,写一个http接口,在数据库表中有数据变动时将数据传给http接 口,并进行相应业务操作。
主要问题:数据存在中文时,会报错或乱码问题,网上很多处理的文章但是都描述的都比较模糊或者复杂,总结了网上很多方法,在此做一下记录。
1.首先是数据库层面的操作,这些网上一大堆,就单纯做下记录吧。
借鉴自:oracle通过触发器发送http请求
---创建触发器
create or replace trigger Test
after insert
on hip_nis_message --监听该张表的insert操作
for each row
declare
json varchar(4000);
begin
--将参数拼接成JSON字符串并赋值给json变量,传入P_TEST存储过程
json := '{"method":"NIS_MSG","mid":"'||:new.MESSAGEID||'","sendUsr":"'||:new.SENDUSR||'"}';
P_TEST(json);--执行存储过程
end Test;
------------------------------------------------------
--创建存储过程调用http接口
create or replace procedure P_TEST(json in varchar2) as
begin
DECLARE
req UTL_HTTP.REQ;
resp UTL_HTTP.RESP;
value VARCHAR2(1024); -- 缓存
v_url VARCHAR2(4000) :='http://127.0.0.1:8086/test-http/MessageService/p?param='||**UTL_RAW.CAST_TO_RAW(json)**; --将json参数进行16进制编码,否则中文会报异常或者乱码
v_param VARCHAR2(4000) := '1'; --本来是做为请求报文的,现在请求报文拼接到url地址上去了
v_param_length NUMBER := LENGTHB(v_param);--长度设置
BEGIN
DBMS_OUTPUT.ENABLE (buffer_size=>null);
req := UTL_HTTP.BEGIN_REQUEST (url=> v_url,method => 'POST');
UTL_HTTP.SET_BODY_CHARSET('UTF-8');
UTL_HTTP.SET_HEADER (r => req,name => 'Content-Type',value => 'application/x-www-form-urlencoded');
UTL_HTTP.SET_HEADER(req,'Keep-Alive','timeout=1'); --超时设置
UTL_HTTP.SET_HEADER (r => req,name => 'Content-Length',value => v_param_length);
UTL_HTTP.WRITE_RAW (r => req,data => UTL_RAW.CAST_TO_RAW(v_param));--UTL_RAW.CAST_TO_RAW这个好像不能省略,没有详细测试
resp := UTL_HTTP.GET_RESPONSE(req);
LOOP
UTL_HTTP.READ_LINE(resp, value, TRUE);
DBMS_OUTPUT.PUT_LINE(value);
END LOOP;
UTL_HTTP.END_RESPONSE(resp);
EXCEPTION
WHEN UTL_HTTP.END_OF_BODY THEN
UTL_HTTP.END_RESPONSE(resp);
END;
end P_TEST;
--------------------------------------------------------------
---ACL授权,必须使用数据库sys级别的账号执行
begin
dbms_network_acl_admin.create_acl ( -- 创建访问控制文件(ACL)
acl => 'utl_http.xml', -- 文件名称
description => 'HTTP Access', -- 描述
principal => 'TEST01', -- 授权或者取消授权账号,大小写敏感
is_grant => TRUE, -- 授权还是取消授权
privilege => 'connect', -- 授权或者取消授权的权限列表
start_date => null, -- 起始日期
end_date => null -- 结束日期
);
dbms_network_acl_admin.add_privilege ( -- 添加访问权限列表项
acl => 'utl_http.xml', -- 刚才创建的acl名称
principal => 'TEST01', -- 授权或取消授权用户,大小写敏感
is_grant => TRUE, -- 与上同
privilege => 'resolve', -- 权限列表
start_date => null,
end_date => null
);
dbms_network_acl_admin.assign_acl ( -- 使用oracle网络访问包,所允许访问的目的主机,及其端口范围。
acl => 'utl_http.xml',
host => '127.0.0.1', -- ip地址或者域名,需要使用ip,不要使用localhost,oracle不是本机安装会异常
lower_port => 8080, -- 允许访问的起始端口号
upper_port => Null -- 允许访问的截止端口号
);
commit;
end;
-------------------------------------------------------------
--移除ACL
begin
dbms_network_acl_admin.unassign_acl(
acl => 'nis_utl_http.xml',
host => '127.0.0.1',
lower_port => 8080,
upper_port => Null
);
end;
--删除用户的权限
begin
dbms_network_acl_admin.delete_privilege(
'utl_http.xml', 'PINGTAI', NULL, 'resolve'
);
end;
-- 删除acl配置文件
begin
dbms_network_acl_admin.drop_acl(
'utl_http.xml'
);
end;
- java代码部分
/**16进制参数转换回原字符串文本
param s 16进制参数
*/
public static String toStringHex(String s){
String result = "";
byte[] baKeyword = new byte[s.length() / 2];
for (int i = 0; i < baKeyword.length; i++) {
try {
baKeyword[i] = (byte) (0xff & Integer.parseInt(s.substring(
i * 2, i * 2 + 2), 16));
} catch (Exception e) {
e.printStackTrace();
}
}
try {
result = new String(baKeyword, "GBK");
} catch (Exception e1) {
e1.printStackTrace();
}
return result;
}
*借鉴了网上很多大神的文章,如有问题请提醒我!