Oracle存储过程如何调用java程序并发送Http请求
项目中有个需求是数据库自动定时扫描数据库,给符合要求的用户发送推送消息,这就需要在存储过程中自动调用发送推送的程序,由于程序复杂,所以利用orcle 的pl/sql发送http请求来间接调用外部程序。
1.首先,在orcle中创建发送http请求的java代码。
java source文件夹是用来存放java方法的,里面的代码通过orale中的jdk编译,可以在存储过程中直接运行。
在文件夹中新建类HttpInvoker,其实就是普通的HttpClient发送post请求的java方法,注意开头要写create or replace and compile java source named httpinvoker as。
create or replace and compile java source named httpinvoker as
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.URL;
import java.net.HttpURLConnection;
import java.net.URLConnection;
import java.util.*;
import java.net.URLEncoder;
public class HttpInvoker
{
public static String sendRequest(String name, String userId,String orderNum) throws Exception{
//处理参数
String re="";
re="订单‘"+name+"’已选中你,快去接单吧";
Map<String,String> p=new HashMap<String,String>();
//全体发送pushtype为ALL,不写target
p.put("pushType","ALIAS");
p.put("alert",re);
p.put("target",userId);
p.put("msgCode","1005");
p.put("orderNum",orderNum);
//活动id
p.put("activityId","");
String s="";
for (Map.Entry<String, String> entry : p.entrySet()) {
s+="&"+entry.getKey()+"="+entry.getValue();
}
s=s.substring(1);
//请求地址
String url="http://112.64.35.222:9002/itcast/jpush/push";
//请求参数
String param=s;
//发送post请求代码开始
PrintWriter out = null;
BufferedReader in = null;
String result = "";
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestProperty("accept", "application/json, text/javascript, */*; q=0.01");
conn.setRequestProperty("Accept-Encoding", "gzip, deflate");
conn.setRequestProperty("Connection", "keep-alive");
conn.setRequestProperty("Accept-Language", "zh-CN,zh;q=0.8");
conn.setRequestProperty("Content-Length", "80");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36");
conn.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
// 获取URLConnection对象对应的输出流
OutputStreamWriter outWriter = new OutputStreamWriter(conn.getOutputStream(), "utf-8");
out = new PrintWriter(outWriter);
// 发送请求参数
out.print(param);
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
in = new BufferedReader(
new InputStreamReader(conn.getInputStream(),"UTF-8"));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送 POST 请求出现异常!"+e);
e.printStackTrace();
result=e.getMessage();
}
//使用finally块来关闭输出流、输入流
finally{
try{
if(out!=null){
out.close();
}
if(in!=null){
in.close();
}
}
catch(IOException ex){
ex.printStackTrace();
}
}
return result;
}
}
2.在functions文件夹中创建调用java程序的过程
function 和procedure存储过程很像,不过function必须返回一个结果,procedure可以返回也可以不反回
create or replace function HttpInvoker(name VARCHAR2, userId VARCHAR2 ,orderNum VARCHAR2) return VARCHAR2
as language java name
--加密函数
'HttpInvoker.sendRequest (java.lang.String,java.lang.String,java.lang.String) return java.lang.String';
注意我创建的是function,所以必须返回结果,如果你创建的是procedure,则可以不返回
3.在你的存储过程代码中调用function
IV_RESULT:=HttpInvoker(orderInfo.order_name,IV_TAKER_USER_ID,orderInfo.order_num);
在需要调用的地方调用,传入参数即可
4.这时你test测试时会发现connection连接时报错,根本发送不出去,这是因为没有给用户配置权限
java.security.AccessControlException: the Permission (java.net.SocketPermission localhost:10000 listen,resolve) has not been granted to RADIUS. The PL/SQL to grant this is dbms_java.grant_permission( 'RADIUS', 'SYS:java.net.SocketPermission', 'localhost:10000', 'listen,resolve' )
解决办法:https://blog.csdn.net/*g861/article/details/80618382
5.如果还不行,可能是acl的问题
定义ACL,若没有ACL,则无法访问网络。
- --定义ACL 取名:httprequestpermission.xml
- BEGIN
- dbms_network_acl_admin.create_acl(acl => 'httprequestpermission.xml',
- DESCRIPTION => 'Normal Access',
- principal => 'CONNECT',
- is_grant => TRUE,
- PRIVILEGE => 'connect',
- start_date => NULL,
- end_date => NULL);
- END;
- --查看ACL是否增加成功
- SELECT any_path
- FROM resource_view
- where any_path like '/sys/acls/%.xml'
- ;
- --给用户增加acl权限,这里是 SD_JY 注意是大写,小写不识别
- begin dbms_network_acl_admin.add_privilege(acl => 'httprequestpermission.xml',
- principal => 'SD_JY',
- is_grant => TRUE,
- privilege => 'connect',
- start_date => null,
- end_date => null);
- end;
- --添加对应主机 ,将对应主机和端口添加到ACL。这里是 192.168.0.156 和 8080 ,这个ip和端口要和上面存储过程中定义的地址一致
- begin
- dbms_network_acl_admin.assign_acl(acl => 'httprequestpermission.xml',
- host => '192.168.0.156',
- lower_port => 8080,
- upper_port => NULL);
- end;
ACL的增加过程为:建立新的acl文件,对该文件中,用户授权,对该文件中,URL和端口授权。
可查看对应的ACL信息是否添加上
- SELECT acl,
- principal,
- privilege,
- is_grant,
- TO_CHAR(start_date, 'DD-MON-YYYY') AS start_date,
- TO_CHAR(end_date, 'DD-MON-YYYY') AS end_date
- FROM dba_network_acl_privileges;
上一篇: MongoDB下载安装,可视化工具下载安装基本操作(一)
下一篇: 微信支付流程总结