Oracle存储过程如何调用java程序并发送Http请求

项目中有个需求是数据库自动定时扫描数据库,给符合要求的用户发送推送消息,这就需要在存储过程中自动调用发送推送的程序,由于程序复杂,所以利用orcle 的pl/sql发送http请求来间接调用外部程序。

1.首先,在orcle中创建发送http请求的java代码。

java source文件夹是用来存放java方法的,里面的代码通过orale中的jdk编译,可以在存储过程中直接运行。

Oracle存储过程如何调用java程序并发送Http请求_第1张图片

在文件夹中新建类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 p=new HashMap();
        //全体发送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 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程序的过程

Oracle存储过程如何调用java程序并发送Http请求_第2张图片

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/lianzhang861/article/details/80618382

5.如果还不行,可能是acl的问题

定义ACL,若没有ACL,则无法访问网络。

[sql]  view plain  copy
  1. --定义ACL 取名:httprequestpermission.xml  
  2.   
  3. BEGIN  
  4.     dbms_network_acl_admin.create_acl(acl         => 'httprequestpermission.xml',  
  5.                                       DESCRIPTION => 'Normal Access',  
  6.                                       principal   => 'CONNECT',  
  7.                                       is_grant    => TRUE,  
  8.                                       PRIVILEGE   => 'connect',  
  9.                                       start_date  => NULL,  
  10.                                       end_date    => NULL);  
  11. END;  
[sql]  view plain  copy
  1. --查看ACL是否增加成功  
  2. SELECT any_path  
  3. FROM resource_view   
  4. where any_path  like '/sys/acls/%.xml'  
  5. ;  
  6.   
  7. --给用户增加acl权限,这里是 SD_JY 注意是大写,小写不识别  
  8. begin  dbms_network_acl_admin.add_privilege(acl     => 'httprequestpermission.xml',  
  9.                                          principal  => 'SD_JY',  
  10.                                          is_grant   => TRUE,  
  11.                                          privilege  => 'connect',  
  12.                                          start_date => null,  
  13.                                          end_date   => null);  
  14. end;  
  15.   
  16.   
  17. --添加对应主机 ,将对应主机和端口添加到ACL。这里是 192.168.0.156 和 8080 ,这个ip和端口要和上面存储过程中定义的地址一致  
  18. begin  
  19.     dbms_network_acl_admin.assign_acl(acl        => 'httprequestpermission.xml',  
  20.                                       host       => '192.168.0.156',  
  21.                                       lower_port => 8080,  
  22.                                       upper_port => NULL);  
  23. end;  

ACL的增加过程为:建立新的acl文件,对该文件中,用户授权,对该文件中,URL和端口授权。

可查看对应的ACL信息是否添加上

[sql]  view plain  copy
  1. SELECT  acl,  
  2.        principal,  
  3.        privilege,  
  4.        is_grant,  
  5.        TO_CHAR(start_date, 'DD-MON-YYYY'AS start_date,  
  6.        TO_CHAR(end_date, 'DD-MON-YYYY'AS end_date  
  7.   FROM dba_network_acl_privileges;  




你可能感兴趣的:(数据库)