欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2024-01-22 22:01:16
...

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

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

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

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

在文件夹中新建类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程序的过程

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

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,则无法访问网络。

[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;