Ejemplo n.º 1
0
  @SuppressWarnings("rawtypes")
  @Override
  public void run() {

    System.out.println("开始查询是否有短信要发送。");

    while (true) {
      try {

        // 本服务需要被监控,更新当前服务的时间戳
        //				new URL(this.backgroundMonitorUrl +
        // this.getClass().getCanonicalName()).openConnection().getInputStream().close();

        if (this.backgroundMonitorUrl.endsWith("=")) {
          // 默认传递空白监控参数,由服务器产生监控参数(客户端来访IP)
          InputStream is = new URL(this.backgroundMonitorUrl).openConnection().getInputStream();
          byte[] b = new byte[1024 * 1];
          int length = is.read(b);
          is.close();

          // 组合新的监控链接(加上监控参数)
          String s = new String(b, 0, length);
          this.backgroundMonitorUrl +=
              s + "--" + this.getLocalIPForJava() + "--" + this.getClass().getSimpleName();
        }

        // 访问监控链接
        new URL(this.backgroundMonitorUrl).openConnection().getInputStream().close();

      } catch (MalformedURLException e1) {
        e1.printStackTrace();
      } catch (IOException e1) {
        e1.printStackTrace();
      }

      // 以下代码调试用
      //			try
      //			{
      //				Thread.sleep(this.smsSendInterval*1000);
      //			} catch (InterruptedException e) {
      //				e.printStackTrace();
      //			}
      //
      //			if (true)
      //				continue;

      // 从数据库查询待发短信
      // 判断号码是否正确
      // 如果是非系统主动发出的短信(如考勤短信),则添加发送者编号,用于处理短信接收者回复短信
      // 每次查询50条待发短信
      // MHJ 2013-10-15 新增定时发送短信功能,即短信sendtime时间需要小于当前时间,才发送

      String queryString = "select * from t_smsend t where (flag=0) ";

      // MHJ 2013.11.14 因上海莫名/浙江移动 可能封杀了往移动号码发送短信,故增加对发送状态为-3的短信,用集信通进行重发
      // 当使用上海莫名通道进行短信发送时,如果失败,则将状态码设置为-3,等待使用
      // 2013.11.15 浙江省联通要求,如果超过10分钟,收不到来自异网状态通知,则重发该条短信
      //			String queryString = "select * from t_smsend t where (flag=0 or flag=-3 or
      // ((statustime-finaldate)*60*24>10 and flag=1 and not regexp_like (t.destnbr,
      // '861(30|31|32|45|55|56|85|86)[0-9]{8}') ) ) ";

      // 集信通什么短信都发

      // 这里只发送非联通的短信
      //			queryString += " and not regexp_like (t.destnbr, '861(30|31|32|45|55|56|85|86)[0-9]{8}')
      // ";
      // 这里只发送非电信的短信
      //			queryString += " and not regexp_like (t.destnbr, '861(33|80|81|89|53)[0-9]{8}') ";
      // 这里只发送MHJ和喻元的电信号码,用于检测浙江电信通道是否恢复
      //			queryString += " or (t.destnbr='8613392893853' or t.destnbr='8618098903528') ) ";
      //			queryString += " or (t.destnbr='8613392893853') ) ";

      // 这里只发送联通的短信
      queryString += " and regexp_like (t.destnbr, '861(30|31|32|45|55|56|85|86)[0-9]{8}') ";

      // 这里只发送电信的短信
      //			queryString += " and regexp_like (t.destnbr, '861(33|80|81|89|53)[0-9]{8}') ";

      // 这里只发送5分钟内的短信(正常情况下,不会有短信超过5分钟仍发送不出去)
      // 超过10分钟的短信,用备用通道发送,如集信通
      queryString +=
          " and ((sendtime >= SYSDATE - 5 / 24 / 60 AND sendtime <= SYSDATE) or sendtime is null)";
      //			queryString += " and (sysdate-sendtime)*60*24>10 ";

      // 如果指定地区,则追加限制条件
      if (null != this.areaIds && 0 < this.areaIds.length()) {
        queryString +=
            "and t.school_id in (select school_id from t_jcxx_school t where t.area in ("
                + this.areaIds
                + "))";
      }

      // 每次查出最多50条待发短信
      queryString += "  and rownum<50 ";

      queryString += " order by center_id nulls first, id desc ";

      // 定义此变量,用于传入
      final String sql = queryString;

      @SuppressWarnings("unchecked")
      //			List <TSmsend> smsList = this.tSmsendDao.getHibernateTemplate().find(queryString);
      // 直接使用原始SQL查询

      // MHJ 2014.7.31
      // 因贵州服务器内网偶尔会出现网络异常,导致无法顺利从5.2连接到2.2(数据库),故增加异常判断,当执行本查询时恰好出现网络异常,则重新执行一遍
      List<TSmsend> smsList = null;

      try {
        smsList =
            this.tSmsendDao
                .getHibernateTemplate()
                .executeFind(
                    new HibernateCallback() {
                      public Object doInHibernate(Session session)
                          throws SQLException, HibernateException {
                        SQLQuery query = session.createSQLQuery(sql).addEntity(TSmsend.class);
                        return query.list();
                      }
                    });
      } catch (UncategorizedSQLException e) {
        System.out.println("网络异常,重新查询数据库!");

        // 暂停一分钟
        try {
          Thread.sleep(60 * 1000);
        } catch (InterruptedException e1) {
          e1.printStackTrace();
        }

        smsList =
            this.tSmsendDao
                .getHibernateTemplate()
                .executeFind(
                    new HibernateCallback() {
                      public Object doInHibernate(Session session)
                          throws SQLException, HibernateException {
                        SQLQuery query = session.createSQLQuery(sql).addEntity(TSmsend.class);
                        return query.list();
                      }
                    });
      }

      for (TSmsend tSmsend : smsList) {
        // 保存开始提交短信处理的时间。
        tSmsend.setUptime(new Timestamp(System.currentTimeMillis()));

        // TODO 这里用来动态改变短信接收号码
        //				tSmsend.setDestnbr("8613157191037");

        // 使用正则表达式检查号码是否合法
        if (tSmsend.getDestnbr().matches("861[0-9]{10}")) {
          // 如果号码不属于联通号段,则通过代理商发送短信
          // TODO 目前未检测号码是否属于浙江联通号段
          // 如果采用了集信通(tdType=6)来发送短信,则不区分联通或者非联通(主要用于处理队列超时),都统一用集信通来发送短信
          if (tSmsend.getDestnbr().matches("861(30|31|32|45|55|56|85|86)[0-9]{8}")
              && !"6".equalsIgnoreCase(this.tdType))
          //					if (false)
          {
            // 通过浙江联通发送短信
            if (null == this.client) {
              this.initSGIP();
            }

            // 初始化金鹏SGIP短信发送类
            if (null == this.mtClient) {
              this.mtClient = MTClient.getInstance(); // 获取单例的MTClienter
            }
            //						try {

            // MHJ 因2013.11.7日仍出现卡死而无法缓解的现象,初步判断和流控不起作用有关,故暂时不使用流控
            // 而直接每条短信等待50毫秒
            /*
            						// 启用联通短信行业网关发送速度流量控制
            				        if (speedCount == 0)
            				        {
            			                timeFlag = System.currentTimeMillis();
            			            }
            */

            // 因 2013-10-29 日出现浙江联通短信行业网关异常超时,故增加超时检测机制

            // 如果超过30秒没有执行完,则中止,重新启动,重发短信
            SGIPSmsSendTask SgipSmsSendTask = new SGIPSmsSendTask();

            SgipSmsSendTask.setTSmsend(tSmsend);

            Boolean taskResult = false;
            String failReason = null;

            // 短信发送超时检测
            ExecutorService execService = Executors.newCachedThreadPool();

            Future<Boolean> future = execService.submit(SgipSmsSendTask);

            try {
              // 等待计算结果,最长等待 30 秒,30 秒后中止任务
              // 因联通本网不应该会出现超时,所以将超时设置为10秒,而不是之前的30秒
              taskResult = future.get(10, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
              failReason = "主线程等待浙江联通行业网关提交短信时被中断!";
            } catch (ExecutionException e) {
              failReason = "主线程等待浙江联通行业网关提交短信,但抛出异常!";
            } catch (TimeoutException e) {
              failReason =
                  "主线程等待浙江联通行业网关提交短信("
                      + tSmsend.getId()
                      + "/"
                      + tSmsend.getDestnbr()
                      + ")任务超时,因此中断任务线程!"
                      + new Date();
            } finally {
              execService.shutdownNow();

              execService = null;

              if (null != failReason) {
                System.out.println(failReason);

                // MHJ 2013.11.04 因发现近期浙江联通短信行业网关,发送超时后,中止进程,但是仍无法正常继续发送,所以增加等待90秒
                try {
                  System.out.println(
                      "发现浙江联通短信行业网关卡死,再人为等待90秒钟。("
                          + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date())
                          + ")");
                  Thread.sleep(1000 * 90);
                } catch (InterruptedException e) {
                  e.printStackTrace();
                }

                // MHJ 2013.11.05 发现增加人为等待,仍无法缓解,故重新初始化 SGIPClient
                // MHJ 2013.11.08 发现没什么效果,故取消
                //						        	this.client = null;
              }

              System.out.println(
                  "通过联通短信网关发送短信,时间戳:"
                      + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date())
                      + ",接收号码="
                      + tSmsend.getDestnbr());

              // MHJ 因2013.11.7日仍出现卡死而无法缓解的现象,初步判断和流控不起作用有关,故暂时不使用流控
              // MHJ 2013.11.10 将等待时间从50毫秒增加到100毫秒
              // 而直接每条短信等待40毫秒,即每秒最多发送25条短信 MHJ 2013.11.15
              try {
                Thread.sleep(40);
              } catch (InterruptedException e) {
                e.printStackTrace();
              }
            }

            // MHJ 因2013.11.7日仍出现卡死而无法缓解的现象,初步判断和流控不起作用有关,故暂时不使用流控
            // 而直接每条短信等待50毫秒

            /*
            					        // 已发短信计数加一
            				            speedCount++;

            				            // 进行常规短信发送间隔停顿(含流量控制)
            				            calSendSpeed();
            */

            //							this.sendSmsBySGIP(tSmsend);

            //						} catch (IOException e) {
            //							e.printStackTrace();
            //							continue;
            //						}

            //						System.out.println(tSmsend.getDestnbr());
          } else {
            // 短信发送是否成功标识位
            int sendFlag = -1; // -1表示发送失败

            // 如果配置了异网短信代理商调用地址,则通过代理商发送短信(同时验证用户名和Key是否为空)
            if (null != this.smsProxyUrl && 0 < this.smsProxyUrl.length()) {
              if (null != this.smsProxyUsername && 0 < this.smsProxyUsername.length()) {
                if (null != this.smsProxyKey && 0 < this.smsProxyKey.length()) {
                  try {
                    // 短信末尾签名
                    String signature = "【平安校园】";

                    // 通过代理商发送短信,不需要86前缀
                    String destNbr =
                        tSmsend.getDestnbr().startsWith("86")
                            ? tSmsend.getDestnbr().substring(2)
                            : tSmsend.getDestnbr();

                    //										destNbr = "13590132493";

                    String content = tSmsend.getMsgcontent();
                    content = null == content ? "" : content;

                    //										content =
                    // "60个字符60个字符不超过60个字符不超过60个字符不超过60个字符不超过60个字符不超过60个字符不超过60个字符不超过60个字符不超过60个字符不超过60个字符不超过60个字符不超过60个字符不超过60个字符不超过60个字符不超过60个字符不超过60个字符不超过60个字符不超过60个字符不超过60个字符不超过60个字符不超过60个字符不超过60个字符不超过60个字符不超过60个字符不超过60个字符不超过60个字符【平园】";

                    // 如果短信内容已经包含签名,则提取签名
                    if (content.indexOf("【") < content.indexOf("】")) {
                      // 提取签名
                      signature =
                          content.substring(content.lastIndexOf("【"), content.lastIndexOf("】") + 1);
                    }

                    List<String> tmpList = new ArrayList();
                    while (content.length() > 200) {
                      tmpList.add(content.substring(0, 200));
                      content = content.substring(200);
                    }
                    tmpList.add(content);

                    if (1 < tmpList.size()) {
                      int i_Count = tmpList.size();
                      int i_Index = 0;
                      for (String strSms : tmpList) {
                        i_Index++;

                        // 拆分后的短信
                        content = "[" + i_Index + "/" + i_Count + "]" + strSms;

                        // 发送短信
                        sendFlag =
                            sendSmsByProxy(
                                tSmsend.getId().longValue(), destNbr, content, signature);
                      }

                      System.out.println("短信拆分条数:" + i_Count);
                    } else {
                      // 短信不需要拆分

                      // 发送短信
                      sendFlag =
                          sendSmsByProxy(tSmsend.getId().longValue(), destNbr, content, signature);
                    }

                    // 短信通过上海莫名网络科技发展有限公司发送 tdType=7
                    if (null != this.tdType && 0 < this.tdType.length())
                      tSmsend.setTdtype(this.tdType);

                    tmpList.clear();
                    tmpList = null;

                  } catch (MalformedURLException e) {
                    e.printStackTrace();
                  } catch (IOException e) {
                    e.printStackTrace();
                  } catch (NoSuchAlgorithmException e) {
                    e.printStackTrace();
                  } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                  }
                }
              }
            }

            // 保存短信发送状态:通过代理商发送短信
            tSmsend.setFlag(new Integer(sendFlag));

            // 保存提交短信成功的时间。
            tSmsend.setFinaldate(new Timestamp(System.currentTimeMillis()));

            // 保存短信发送状态
            this.tSmsendDao.getHibernateTemplate().update(tSmsend);
          }
        } else {
          // 将所有错误的短信接收号码,设置发送状态为-1(即发送失败)
          tSmsend.setFlag(-1);
          this.tSmsendDao.getHibernateTemplate().saveOrUpdate(tSmsend);
        }
      }

      try {
        Thread.sleep(this.smsSendInterval * 1000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
Ejemplo n.º 2
0
  private void sendSmsBySGIP(TSmsend tSmsend) throws IOException {
    // 该短信发起者的标识号,默认为空,表示是系统短信,如考勤短信
    String srcNo = (null == tSmsend.getSrcnbr()) ? "" : tSmsend.getSrcnbr();

    // 如果长度不足11位,也将转换为系统短信,即设置为默认
    // substring(1) 表示取手机号后10位,用户回复时,再前补1,拼成完整手机号
    srcNo = (11 != srcNo.length()) ? "" : srcNo.substring(1);

    // 如果不是系统短信(如考勤短信),比如老师发送家庭作业等,则追加短信发起者的编号到106xxx后,用于处理用户回复短信 (t_jcxx_accout.id)
    if ("".equalsIgnoreCase(srcNo) && null != tSmsend.getCenterId()) {
      List<TJcxxTeacherinfo> tJcxxTeacherinfoList =
          this.tJcxxTeacherinfoDao.findByTeacherId(tSmsend.getCenterId());

      if (0 < tJcxxTeacherinfoList.size()) {
        TJcxxTeacherinfo tJcxxTeacherinfo = tJcxxTeacherinfoList.get(0);

        if (null != tJcxxTeacherinfo.getMobile()) {
          srcNo = tJcxxTeacherinfo.getMobile().substring(1);
        }
      }
    }

    // 贵州联通不支持通道扩展号
    srcNo = "";

    String content = tSmsend.getMsgcontent();
    content = null == content ? "" : content;

    if (true) {
      // MHJ 2013.11.11
      // 因使用 ZTE 提供的 SGIP 短信发送包<br>
      // 在浙江联通出现僵死现象,返回-3<br>
      // 在广东联通,出现无法连接,返回-5现象<br>
      // 故联系广东联通,获取金鹏SGIP短信开发包<br>

      // 以下是使用金鹏开发包发送短信

      // 以下是发送短信的代码(可多线程调用)
      //			System.out.println("检测浙江联通短信行业网关是否提交短信超时 sendMessage (" + tSmsend.getId() + "/" +
      // tSmsend.getDestnbr()  + ")(" + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date())
      // + ")");
      SendResult[] results = this.mtClient.sendMessage(srcNo, tSmsend.getDestnbr(), content, null);

      //			if ("8618606709366".equalsIgnoreCase(tSmsend.getDestnbr()))
      //					this.mtClient.sendMessage(srcNo, tSmsend.getDestnbr(), content, null);
      //			else
      //				this.mtClient.sendMessage(tSmsend.getDestnbr(), content);

      //			System.out.println("检测浙江联通短信行业网关是否提交短信超时 sendMessage (" + tSmsend.getId() + "/" +
      // tSmsend.getDestnbr()  + ")(" + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date())
      // + ")");
      for (SendResult reslut : results) {
        //				log.info("发送短信,短信序号为:"+ Arrays.toString(reslut.getFlowId()) +
        // "发送结果:"+reslut.getResult());

        // 保存短信发送状态:SGIP返回0,表示短信已成功发送,需将状态设置为1,保存到数据库备查。
        tSmsend.setFlag(new Integer(0 == reslut.getResult() ? 1 : reslut.getResult()));
      }
    } else {
      // 以下是使用中兴开发包发送短信

      SGIPRsp rspHandler = new SGIPRsp();
      SGIPSubmitResp rsp = null;

      this.submit.getHead().setSequenceNo(new SGIPSequenceNo());
      submit.getBody().setSPNumber(this.spNumber + srcNo);
      this.submit.getBody().setUserNumber(tSmsend.getDestnbr());

      // 如果短信内容长度不超过127个字符,则使用标准短信方式发送短信
      if (127 >= content.length()) {
        this.submit.getBody().setTP_udhi(0); // 启用发标准短信

        this.submit.getBody().setMessageContent(content.getBytes("UnicodeBigUnmarked")); // 要发送的短信内容

        System.out.println(
            "检测浙江联通短信行业网关是否提交短信超时 普通短信 sendSubmit ("
                + tSmsend.getId()
                + "/"
                + tSmsend.getDestnbr()
                + ")("
                + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date())
                + ")");
        this.client.sendSubmit(submit, rspHandler);
        System.out.println(
            "检测浙江联通短信行业网关是否提交短信超时 普通短信 waitForSGIPSubmitResp ("
                + tSmsend.getId()
                + "/"
                + tSmsend.getDestnbr()
                + ")("
                + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date())
                + ")");
        rsp = rspHandler.waitForSGIPSubmitResp();
        System.out.println(
            "检测浙江联通短信行业网关是否提交短信超时 普通短信 over ("
                + tSmsend.getId()
                + "/"
                + tSmsend.getDestnbr()
                + ")("
                + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date())
                + ")");
      } else {
        // 短信内容超过127个字符,使用长短信方式,发送短信
        this.submit.getBody().setTP_udhi(1); // 启用发标准短信

        // 因使用长短信方式时,需将原短信,拆分成多条小短信,每条小短信,长度不超过67个字符,
        // 因采用 UnicodeBigUnmarked 编码格式,每个字符,不管英文还是中文,都占用2个字节,
        // 故每小条短信的长度均为67个字符(在Java里),加上短信头6个字节,一共等于140个字节。

        List msgList = new ArrayList();
        while (content.length() > 67) {
          msgList.add(content.substring(0, 67));
          content = content.substring(67);
        }
        msgList.add(content);

        // 计算总条数
        byte totalMsg = (byte) msgList.size();

        // 本条长短信的(随机)序列号
        byte by_seq = (byte) (new Random().nextInt(254) + 1);

        for (int i = 0; i < msgList.size(); i++) {
          String msg = (String) msgList.get(i);
          byte[] byArr = {0x05, 0x00, 0x03, by_seq, totalMsg, (byte) (i + 1)};

          byte[] bb = msg.getBytes("UnicodeBigUnmarked");
          byte[] bb_arr = new byte[bb.length + 6];
          System.arraycopy(byArr, 0, bb_arr, 0, 6);
          System.arraycopy(bb, 0, bb_arr, 6, bb_arr.length - 6);

          this.submit.getBody().setMessageContent(bb_arr); // 每小条要发送的短信内容

          System.out.println(
              "检测浙江联通短信行业网关是否提交短信超时 sendSubmit 长短信 ("
                  + tSmsend.getId()
                  + "/"
                  + tSmsend.getDestnbr()
                  + ")("
                  + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date())
                  + ")");
          this.client.sendSubmit(submit, rspHandler);
          System.out.println(
              "检测浙江联通短信行业网关是否提交短信超时 waitForSGIPSubmitResp 长短信 ("
                  + tSmsend.getId()
                  + "/"
                  + tSmsend.getDestnbr()
                  + ")("
                  + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date())
                  + ")");
          rsp = rspHandler.waitForSGIPSubmitResp();
          System.out.println(
              "检测浙江联通短信行业网关是否提交短信超时 over 长短信 ("
                  + tSmsend.getId()
                  + "/"
                  + tSmsend.getDestnbr()
                  + ")("
                  + new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date())
                  + ")");
        }
      }

      // 保存短信发送状态:SGIP返回0,表示短信已成功发送,需将状态设置为1,保存到数据库备查。
      tSmsend.setFlag(new Integer(0 == rsp.getBody().getResult() ? 1 : rsp.getBody().getResult()));
    }

    // 保存提交短信发送成功的时间。
    tSmsend.setFinaldate(new Timestamp(System.currentTimeMillis()));

    //        System.out.println(new String(this.submit.getBody().getMessageContent(),
    // "UnicodeBigUnmarked"));
    // 保存短信发送状态
    this.tSmsendDao.getHibernateTemplate().update(tSmsend);
  }