Procházet zdrojové kódy

feat(server): 支付对接

Go před 6 roky
rodič
revize
4946c981b0
67 změnil soubory, kde provedl 7055 přidání a 0 odebrání
  1. 53 0
      front/project/Constant.js
  2. 27 0
      server/data/src/main/java/com/qxgmat/data/constants/enums/QuestionGroup.java
  3. 14 0
      server/data/src/main/java/com/qxgmat/data/constants/enums/trade/PayChannel.java
  4. 4 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/request/UserFeedbackErrorDto.java
  5. 13 0
      server/gateway-api/src/main/java/com/qxgmat/dto/request/ExaminationRestartDto.java
  6. 4 0
      server/gateway-api/src/main/java/com/qxgmat/dto/request/PayProductDto.java
  7. 61 0
      server/gateway-api/src/main/java/com/qxgmat/help/PayHelp.java
  8. 8 0
      server/gateway-api/src/main/java/com/qxgmat/service/annotation/PayModule.java
  9. 90 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/PayService.java
  10. 295 0
      server/tools/src/main/java/com/nuliji/tools/pay/Alipay.java
  11. 18 0
      server/tools/src/main/java/com/nuliji/tools/pay/PaySource.java
  12. 239 0
      server/tools/src/main/java/com/nuliji/tools/pay/WechatPay.java
  13. 79 0
      server/tools/src/main/java/com/nuliji/tools/pay/common/PayInfo.java
  14. 116 0
      server/tools/src/main/java/com/nuliji/tools/pay/common/ResultInfo.java
  15. 14 0
      server/tools/src/main/java/com/nuliji/tools/pay/data/PayRequestData.java
  16. 10 0
      server/tools/src/main/java/com/nuliji/tools/pay/data/PayResponseData.java
  17. 32 0
      server/tools/src/main/java/com/nuliji/tools/pay/enums/TradeStatus.java
  18. 64 0
      server/tools/src/main/java/com/tencent/Main.java
  19. 151 0
      server/tools/src/main/java/com/tencent/WXPay.java
  20. 125 0
      server/tools/src/main/java/com/tencent/bridge/IBridge.java
  21. 156 0
      server/tools/src/main/java/com/tencent/business/DownloadBillBusiness.java
  22. 162 0
      server/tools/src/main/java/com/tencent/business/RefundBusiness.java
  23. 197 0
      server/tools/src/main/java/com/tencent/business/RefundQueryBusiness.java
  24. 422 0
      server/tools/src/main/java/com/tencent/business/ScanPayBusiness.java
  25. 170 0
      server/tools/src/main/java/com/tencent/business/UnifiedOrderBusiness.java
  26. 132 0
      server/tools/src/main/java/com/tencent/common/Configure.java
  27. 196 0
      server/tools/src/main/java/com/tencent/common/HttpsRequest.java
  28. 59 0
      server/tools/src/main/java/com/tencent/common/Log.java
  29. 59 0
      server/tools/src/main/java/com/tencent/common/MD5.java
  30. 28 0
      server/tools/src/main/java/com/tencent/common/RandomStringGenerator.java
  31. 120 0
      server/tools/src/main/java/com/tencent/common/Signature.java
  32. 120 0
      server/tools/src/main/java/com/tencent/common/Util.java
  33. 86 0
      server/tools/src/main/java/com/tencent/common/XMLParser.java
  34. 40 0
      server/tools/src/main/java/com/tencent/common/report/ReportRunable.java
  35. 31 0
      server/tools/src/main/java/com/tencent/common/report/Reporter.java
  36. 21 0
      server/tools/src/main/java/com/tencent/common/report/ReporterFactory.java
  37. 232 0
      server/tools/src/main/java/com/tencent/common/report/protocol/ReportReqData.java
  38. 38 0
      server/tools/src/main/java/com/tencent/common/report/protocol/ReportResData.java
  39. 67 0
      server/tools/src/main/java/com/tencent/common/report/service/ReportService.java
  40. 51 0
      server/tools/src/main/java/com/tencent/protocol/ResData.java
  41. 137 0
      server/tools/src/main/java/com/tencent/protocol/downloadbill_protocol/DownloadBillReqData.java
  42. 29 0
      server/tools/src/main/java/com/tencent/protocol/downloadbill_protocol/DownloadBillResData.java
  43. 128 0
      server/tools/src/main/java/com/tencent/protocol/pay_protocol/AppReqData.java
  44. 128 0
      server/tools/src/main/java/com/tencent/protocol/pay_protocol/JsReqData.java
  45. 291 0
      server/tools/src/main/java/com/tencent/protocol/pay_protocol/NoticeResData.java
  46. 230 0
      server/tools/src/main/java/com/tencent/protocol/pay_protocol/ScanPayReqData.java
  47. 209 0
      server/tools/src/main/java/com/tencent/protocol/pay_protocol/ScanPayResData.java
  48. 239 0
      server/tools/src/main/java/com/tencent/protocol/pay_protocol/UnifiedOrderReqData.java
  49. 127 0
      server/tools/src/main/java/com/tencent/protocol/pay_protocol/UnifiedOrderResData.java
  50. 127 0
      server/tools/src/main/java/com/tencent/protocol/pay_query_protocol/ScanPayQueryReqData.java
  51. 260 0
      server/tools/src/main/java/com/tencent/protocol/pay_query_protocol/ScanPayQueryResData.java
  52. 192 0
      server/tools/src/main/java/com/tencent/protocol/refund_protocol/RefundReqData.java
  53. 168 0
      server/tools/src/main/java/com/tencent/protocol/refund_protocol/RefundResData.java
  54. 100 0
      server/tools/src/main/java/com/tencent/protocol/refund_query_protocol/RefundOrderData.java
  55. 160 0
      server/tools/src/main/java/com/tencent/protocol/refund_query_protocol/RefundQueryReqData.java
  56. 187 0
      server/tools/src/main/java/com/tencent/protocol/refund_query_protocol/RefundQueryResData.java
  57. 127 0
      server/tools/src/main/java/com/tencent/protocol/reverse_protocol/ReverseReqData.java
  58. 104 0
      server/tools/src/main/java/com/tencent/protocol/reverse_protocol/ReverseResData.java
  59. 42 0
      server/tools/src/main/java/com/tencent/service/BaseService.java
  60. 46 0
      server/tools/src/main/java/com/tencent/service/DownloadBillService.java
  61. 20 0
      server/tools/src/main/java/com/tencent/service/IServiceRequest.java
  62. 36 0
      server/tools/src/main/java/com/tencent/service/RefundQueryService.java
  63. 33 0
      server/tools/src/main/java/com/tencent/service/RefundService.java
  64. 33 0
      server/tools/src/main/java/com/tencent/service/ReverseService.java
  65. 34 0
      server/tools/src/main/java/com/tencent/service/ScanPayQueryService.java
  66. 32 0
      server/tools/src/main/java/com/tencent/service/ScanPayService.java
  67. 32 0
      server/tools/src/main/java/com/tencent/service/UnifiedOrderService.java

+ 53 - 0
front/project/Constant.js

@@ -10,6 +10,8 @@ export const AskTarget = [{ label: '题目', value: 'question' }, { label: '官
 
 export const PreviewStatus = [{ label: '全部', value: 0 }, { label: '未开始', value: 1 }, { label: '进行中', value: 2 }, { label: '已结束', value: 3 }];
 
+export const PreviewMode = [{ label: '指定作业', value: 0 }, { label: '系统作业', value: 1 }];
+
 export const ServiceKey = [{ label: 'VIP', value: 'vip' }, { label: '机经', value: 'textbook' }, { label: '千行CAT', value: 'qx_cat' }];
 
 export const SwitchSelect = [{ value: 0, label: '否' }, { value: 1, label: '是' }];
@@ -63,6 +65,14 @@ export const SentenceOption = [{ label: '平行', value: 'parallel' }, { label:
 //   options: [],
 // };
 
+// 答案分布
+// const answerDistributed = {
+//   questions: [{
+//     single: [0, 1],
+//     double: [[0, 1], [11, 22]],
+//   }],
+// };
+
 // 备考统计字段格式
 // const PrepareStat = {
 //   status: [{ key: '', value: '' }],
@@ -94,4 +104,47 @@ export const SentenceOption = [{ label: '平行', value: 'parallel' }, { label:
 //   info: { times: '', finishTime: '', userTime: '', time: '', questionNumber: '', userNumber: '', userCorrect: '', totalNumber: '', totalCorrect: '', totalTime: '', correctTime: '', incorrectTime: '' },
 // };
 
+// 模考卷子结果及报告
+// const examinationPaperDetail = {
+//   score: { total: 123, quant: 123, ir: 123, verbial: 123 },
+//
+// };
+
 // 每日统计
+
+// 首页设置:
+// const index = {
+//   class: [{
+//     title: '',
+//     image: '',
+//     link: '',
+//   }],
+//   activity: [{
+//     image: '',
+//     link: '',
+//   }],
+//   evaluation: [{
+//     nickname: '',
+//     avatar: '',
+//     content: '',
+//   }],
+//   prepare: {
+//     first: '',
+//     continue: '',
+//     classJunior: '',
+//     classMiddle: '',
+//     classSenior: '',
+//   },
+//   user: {
+//     numberOffline: 0,
+//     number700: 0,
+//     numberScore: 0,
+//   },
+//   contact: {
+//     phone: '',
+//     email: '',
+//     wechat: '',
+//     wechatImage: '',
+//     weiboImage: '',
+//   },
+// };

+ 27 - 0
server/data/src/main/java/com/qxgmat/data/constants/enums/QuestionGroup.java

@@ -0,0 +1,27 @@
+package com.qxgmat.data.constants.enums;
+
+/**
+ * Created by gaojie on 2017/11/19.
+ */
+public enum QuestionGroup {
+    SC("sc", "语法"),
+    RC("rc", "阅读"),
+    CR("cr","逻辑"),
+    PS("ps", "数学"),
+    DS("ds", "数学"),
+    IR("ir", "综合推理"),
+    AWA("awa", "作文");
+    final static public String message = "题目类型";
+
+    public String key;
+    public String title;
+    private QuestionGroup(String key, String title){
+        this.key = key;
+        this.title = title;
+    }
+
+    public static QuestionGroup ValueOf(String name){
+        if (name == null) return null;
+        return QuestionGroup.valueOf(name.toUpperCase());
+    }
+}

+ 14 - 0
server/data/src/main/java/com/qxgmat/data/constants/enums/trade/PayChannel.java

@@ -0,0 +1,14 @@
+package com.qxgmat.data.constants.enums.trade;
+
+/**
+ * Created by gaojie on 2017/11/20.
+ */
+public enum PayChannel {
+    OFFLINE("offline"), ALIPAY("alipay"), WECHAT("wechat");
+    final static public String message = "支付类型";
+
+    public String key ;
+    private PayChannel(String value){
+        this.key = value;
+    }
+}

+ 4 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/admin/request/UserFeedbackErrorDto.java

@@ -0,0 +1,4 @@
+package com.qxgmat.dto.admin.request;
+
+public class UserFeedbackErrorDto {
+}

+ 13 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/request/ExaminationRestartDto.java

@@ -0,0 +1,13 @@
+package com.qxgmat.dto.request;
+
+public class ExaminationRestartDto {
+    private Integer userPaperId;
+
+    public Integer getUserPaperId() {
+        return userPaperId;
+    }
+
+    public void setUserPaperId(Integer userPaperId) {
+        this.userPaperId = userPaperId;
+    }
+}

+ 4 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/request/PayProductDto.java

@@ -0,0 +1,4 @@
+package com.qxgmat.dto.request;
+
+public class PayProductDto {
+}

+ 61 - 0
server/gateway-api/src/main/java/com/qxgmat/help/PayHelp.java

@@ -0,0 +1,61 @@
+package com.qxgmat.help;
+
+import com.nuliji.tools.third.OauthData;
+import com.nuliji.tools.third.wechat.MessageListener;
+import com.nuliji.tools.third.wechat.WechatClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+@Service
+public class PayHelp {
+    private WechatClient wechatPc;
+
+    @Autowired
+    private void getWechatPc(@Value("${third.wechat.pc.appId}") String appId,
+                           @Value("${third.wechat.pc.appSecret}") String appSecret) {
+        this.wechatPc = new WechatClient(appId, appSecret);
+    }
+
+    private WechatClient wechat;
+
+    @Autowired
+    private void getWechat(@Value("${third.wechat.native.appId}") String appId,
+                           @Value("${third.wechat.native.appSecret}") String appSecret) {
+        this.wechat = new WechatClient(appId, appSecret);
+    }
+
+    public OauthData oauthPc(String code) {
+        return wechatPc.webAuthorize(code);
+    }
+
+    public OauthData oauthNative(String code){
+        return wechat.webAuthorize(code);
+    }
+
+    public OauthData refreshNative(String refreshToken) {
+        return wechat.refreshWebAccessToken(refreshToken);
+    }
+
+    public String redirectPc(String redirectUrl, String state){
+        return wechatPc.getOAuthUrl(redirectUrl, state);
+    }
+    public String redirectNative(String redirectUrl, String state){
+        return wechat.getOAuthUrl(redirectUrl, state);
+    }
+
+    public String receiveMessage(String body){
+        wechat.ReceiveMessage(body, new MessageListener() {
+            @Override
+            public void OnScan(String openId, int sceneId) {
+
+            }
+
+            @Override
+            public void OnSubscribe(String openId) {
+
+            }
+        });
+        return "";
+    }
+}

+ 8 - 0
server/gateway-api/src/main/java/com/qxgmat/service/annotation/PayModule.java

@@ -0,0 +1,8 @@
+package com.qxgmat.service.annotation;
+
+/**
+ * Created by gaojie on 2017/5/11.
+ */
+public interface PayModule {
+    public String getModuleId();
+}

+ 90 - 0
server/gateway-api/src/main/java/com/qxgmat/service/inline/PayService.java

@@ -0,0 +1,90 @@
+package com.qxgmat.service.inline;
+
+import com.github.pagehelper.Page;
+import com.nuliji.tools.AbstractService;
+import com.nuliji.tools.exception.ParameterException;
+import com.nuliji.tools.exception.SystemException;
+import com.nuliji.tools.mybatis.Example;
+import com.qxgmat.data.dao.RankMapper;
+import com.qxgmat.data.dao.entity.Rank;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.Collection;
+import java.util.List;
+
+@Service
+public class PayService extends AbstractService {
+    private static final Logger logger = LoggerFactory.getLogger(PayService.class);
+
+    @Resource
+    private RankMapper rankMapper;
+
+    public List<Rank> all(){
+        return select(rankMapper);
+    }
+
+    /**
+     * 计算考分
+     * @param totalScore
+     * @param quantScore
+     * @return
+     */
+    public Rank compute(Number totalScore, Number quantScore){
+        Example example = new Example(Rank.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("totalScore", totalScore)
+                        .andEqualTo("quantScore", quantScore)
+        );
+
+        return one(rankMapper, example);
+    }
+
+    public Rank add(Rank rank){
+        int result = insert(rankMapper, rank);
+        rank = one(rankMapper, rank.getId());
+        if(rank == null){
+            throw new SystemException("添加失败");
+        }
+        return rank;
+    }
+
+    public Rank edit(Rank rank){
+        Rank in = one(rankMapper, rank.getId());
+        if(in == null){
+            throw new ParameterException("排名不存在");
+        }
+        int result = update(rankMapper, rank);
+        return rank;
+    }
+
+    public boolean delete(Number id){
+        Rank in = one(rankMapper, id);
+        if(in == null){
+            throw new ParameterException("排名不存在");
+        }
+        int result = delete(rankMapper, id);
+        return result > 0;
+    }
+
+    public Rank get(Number id){
+        Rank in = one(rankMapper, id);
+
+        if(in == null){
+            throw new ParameterException("排名不存在");
+        }
+        return in;
+    }
+
+    public Page<Rank> select(int page, int pageSize){
+        return select(rankMapper, page, pageSize);
+    }
+
+    public List<Rank> select(Collection ids){
+        return select(rankMapper, ids);
+    }
+
+}

+ 295 - 0
server/tools/src/main/java/com/nuliji/tools/pay/Alipay.java

@@ -0,0 +1,295 @@
+package com.qxgmat.service.pay;
+
+import com.alibaba.fastjson.JSON;
+import com.alipay.api.AlipayApiException;
+import com.alipay.api.AlipayClient;
+import com.alipay.api.DefaultAlipayClient;
+import com.alipay.api.domain.AlipayTradeAppPayModel;
+import com.alipay.api.internal.util.AlipaySignature;
+import com.alipay.api.request.AlipayTradeAppPayRequest;
+import com.alipay.api.request.AlipayTradeQueryRequest;
+import com.alipay.api.response.AlipayTradeAppPayResponse;
+import com.alipay.api.response.AlipayTradeQueryResponse;
+import com.nuliji.pay.common.PayInfo;
+import com.nuliji.pay.common.ResultInfo;
+import com.nuliji.util.Configure;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.http.HttpServletRequest;
+import java.math.BigDecimal;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Created by gaojie on 2017/5/10.
+ */
+public class Alipay implements PaySource{
+    //添加一个日志器
+    private static final Logger logger = LoggerFactory.getLogger(Alipay.class);
+    private static Alipay instance = null;
+    private AlipayClient alipayClient = null;
+    static{
+        instance = new Alipay();
+    }
+    public static Alipay getInstance(){
+        return instance;
+    }
+    public Alipay(){
+        alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", Configure.alipayAppId(), Configure.alipayAppKey(), "json", "utf-8", Configure.alipayAppPublicKey(), "RSA2");
+    }
+    @Override
+    public ResultInfo notifyTrade(HttpServletRequest request) throws Exception{
+        //获取支付宝POST过来反馈信息
+        Map<String,String> params = new HashMap<String,String>();
+        Map requestParams = request.getParameterMap();
+        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) {
+            String name = (String) iter.next();
+            String[] values = (String[]) requestParams.get(name);
+            String valueStr = "";
+            for (int i = 0; i < values.length; i++) {
+                valueStr = (i == values.length - 1) ? valueStr + values[i]
+                        : valueStr + values[i] + ",";
+            }
+            //乱码解决,这段代码在出现乱码时使用。
+            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
+            params.put(name, valueStr);
+        }
+        logger.debug("alipay notify:"+params.toString());
+//切记alipaypublickey是支付宝的公钥,请去open.alipay.com对应应用下查看。
+//boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
+        boolean flag = AlipaySignature.rsaCheckV1(params, Configure.alipayAppPublicKey(), "utf-8", "RSA2");
+        ResultInfo info = new ResultInfo();
+        info.setResponse(params);
+        if(!flag){
+            info.setStatus("system");
+            info.setMessage("签名校验错误");
+            return info;
+        }
+
+        String status = params.get("trade_status");
+        if(Objects.equals(status, "WAIT_BUYER_PAY")){
+            info.setStatus("wait");
+        }else if(Objects.equals(status, "TRADE_CLOSE")){
+            info.setStatus("close");
+        }else if(Objects.equals(status, "TRADE_SUCCESS")){
+            info.setStatus("success");
+        }else if(Objects.equals(status, "TRADE_FINISHED")){
+            info.setStatus("finish");
+        }
+        info.setId(params.get("out_trade_no"));
+        info.setTransaction_no(params.get("trade_no"));
+        info.setMoney(BigDecimal.valueOf(Float.valueOf(params.get("total_amount"))));
+        info.setOpen_id(params.get("buyer_user_id"));
+        info.setMessage("success");
+        info.setAppId(Configure.alipayAppId());
+        info.setPid(params.get("seller_id"));
+        return info;
+    }
+
+    @Override
+    public ResultInfo returnTrade(ResultInfo info) {
+        Map<String,String> response = (Map)info.getResponse();
+        if(response.get("code").isEmpty()){
+            // 手机返回
+            // let {out_trade_no, trade_no, app_id, total_amount, seller_id, msg, charset, timestamp, code} = content;
+            switch(response.get("code")){
+                case "9000":
+                    info.setStatus("wait");
+                    info.setId(response.get("out_trade_no"));
+                    info.setTransaction_no(response.get("trade_no"));
+                    info.setMoney(BigDecimal.valueOf(Float.valueOf(response.get("total_amount"))));
+                    break;
+                case "6004":
+                case "8000":
+                    info.setStatus("wait");
+                    info.setMessage("支付处理中");
+                    break;
+                case "4000":
+                    info.setStatus("error");
+                    info.setMessage("支付失败");
+                    break;
+                case "6001":
+                    info.setStatus("system");
+                    info.setMessage("用户取消支付");
+                    break;
+                case "6002":
+                    info.setStatus("system");
+                    info.setMessage("网络链接错误");
+                    break;
+                case "5000":
+                default:
+                    info.setStatus("system");
+                    info.setMessage("请联系管理员");
+            }
+        }else{
+            // wap返回
+            // let {app_id, method, sign_type, sign, charset, timestamp, version, out_trade_no, trade_no, total_amount, seller_id} = content;
+            info.setId(response.get("out_trade_no"));
+            info.setTransaction_no(response.get("trade_no"));
+            info.setMoney(BigDecimal.valueOf(Float.valueOf(response.get("total_amount"))));
+            info.setMessage("success");
+            info.setStatus("wait");
+        }
+        return info;
+    }
+
+    @Override
+    public boolean validTrade(ResultInfo info, PayInfo payInfo) {
+        if(info.getAppId() != payInfo.getAppId()) return false;
+//        if(info.getPid() != payInfo.getPid()) return false;
+
+        return true;
+    }
+
+    @Override
+    public PayInfo appTrade(String payId, String pid, BigDecimal money, String subject, String body, String notifyUrl, String ip) throws Exception{
+        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
+//SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
+        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
+        model.setBody(body);
+        model.setSubject(subject);
+        model.setOutTradeNo(payId);
+        model.setTimeoutExpress("30m");
+        model.setTotalAmount(money.toString());
+        model.setProductCode("QUICK_MSECURITY_PAY");
+        request.setBizModel(model);
+        request.setNotifyUrl(notifyUrl);
+
+        PayInfo payInfo = new PayInfo();
+        payInfo.setPid(pid);
+        payInfo.setAppId(Configure.alipayAppId());
+        payInfo.setMoney(money);
+
+        try {
+            //这里和普通的接口调用不同,使用的是sdkExecute
+            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
+//            System.out.println(response.getBody());//就是orderString 可以直接给客户端请求,无需再做处理。
+            payInfo.setRequest(response.getBody());
+            payInfo.setStatus("ok");
+        } catch (AlipayApiException e) {
+            e.printStackTrace();
+            payInfo.setStatus("fail");
+            payInfo.setRequest(request);
+        }
+        return payInfo;
+    }
+
+    @Override
+    public ResultInfo getTrade(String payId, String transactionNo, String pid) throws Exception {
+        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
+        request.setBizContent("{" +
+                "    \"out_trade_no\":\""+payId+"\"," +
+                "    \"trade_no\":\""+transactionNo+"\"" +
+                "  }");
+        AlipayTradeQueryResponse response = alipayClient.execute(request);
+        logger.debug("alipay getTrade:"+ JSON.toJSONString(response));
+
+        ResultInfo info = parseResult(response, "ok");
+        String status = info.getStatus();
+        if(Objects.equals(status, "ok")) {
+            String trade_status = response.getTradeStatus();
+            logger.debug(trade_status);
+            // 交易状态:WAIT_BUYER_PAY(交易创建,等待买家付款)、TRADE_CLOSED(未付款交易超时关闭,或支付完成后全额退款)、TRADE_SUCCESS(交易支付成功)、TRADE_FINISHED(交易结束,不可退款)
+            if(Objects.equals(trade_status, "WAIT_BUYER_PAY")){
+                info.setStatus("wait");
+            }else if(Objects.equals(trade_status, "TRADE_CLOSE")){
+                info.setStatus("close");
+            }else if(Objects.equals(trade_status, "TRADE_SUCCESS")){
+                info.setStatus("success");
+            }else if(Objects.equals(trade_status, "TRADE_FINISHED")){
+                info.setStatus("finish");
+            }
+            logger.debug(info.getStatus());
+        }
+        logger.debug("alipay getTrade:"+ JSON.toJSONString(info));
+        return info;
+    }
+
+    private ResultInfo parseResult(AlipayTradeQueryResponse response, String status){
+        ResultInfo info = new ResultInfo();
+        info.setAppId(Configure.alipayAppId());
+        info.setResponse(response);
+        info.setId(response.getOutTradeNo());
+        info.setMoney(BigDecimal.valueOf(Float.valueOf(response.getTotalAmount())));
+        info.setOpen_id(response.getOpenId());
+        info.setTransaction_no(response.getTradeNo());
+
+        if (response == null || response.getCode() == null) {
+            return formatInfo(info, "system", "请求错误");
+        }
+        switch(response.getCode()){
+            case "10000": // 调用接口成功
+                return formatInfo(info, status, "");
+            case "40004": // 业务处理失败
+                switch(response.getSubCode()){
+                    case "ACQ.EXIST_FORBIDDEN_WORD":
+                        return formatInfo(info, "error", response.getSubMsg());
+                    case "ACQ.TRADE_HAS_SUCCESS":
+                        return formatInfo(info, "success", "");
+                    case "ACQ.TRADE_HAS_CLOSE":
+                        return formatInfo(info, "close", "当前订单已关闭,请重新支付");
+                    case "ACQ.BUYER_BALANCE_NOT_ENOUGH":
+                        return formatInfo(info, "error", "用户余额不足");
+                    case "ACQ.BUYER_BANKCARD_BALANCE_NOT_ENOUGH":
+                        return formatInfo(info, "error", "用户余额不足");
+                    case "ACQ.ERROR_BALANCE_PAYMENT_DISABLE":
+                        return formatInfo(info, "error", "余额支付需开启");
+                    case "ACQ.BUYER_SELLER_EQUAL":
+                        return formatInfo(info, "error", "买卖家不能相同");
+                    case "ACQ.TRADE_BUYER_NOT_MATCH":
+                        return formatInfo(info, "error", "交易买家不匹配");
+                    case "ACQ.BUYER_ENABLE_STATUS_FORBID":
+                        return formatInfo(info, "error", "用户状态非法");
+                    case "ACQ.PULL_MOBILE_CASHIER_FAIL":
+                        return formatInfo(info, "error", "请重新支付");
+                    case "ACQ.MOBILE_PAYMENT_SWITCH_OFF":
+                        return formatInfo(info, "error", "请开启无线支付功能");
+                    case "ACQ.PAYMENT_FAIL":
+                        return formatInfo(info, "error", "系统错误,请重新支付");
+                    case "ACQ.BUYER_PAYMENT_AMOUNT_DAY_LIMIT_ERROR":
+                        return formatInfo(info, "error", "买家付款日限额超限");
+                    case "ACQ.BEYOND_PAY_RESTRICTION":
+                        return formatInfo(info, "error", "商家收款额度超限");
+                    case "ACQ.BEYOND_PER_RECEIPT_RESTRICTION":
+                        return formatInfo(info, "error", "商家月收款额度超限");
+                    case "ACQ.BUYER_PAYMENT_AMOUNT_MONTH_LIMIT_ERROR":
+                        return formatInfo(info, "error", "买家月支付额度超限");
+                    case "ACQ.SELLER_BEEN_BLOCKED":
+                        return formatInfo(info, "error", "商家账号被冻结");
+                    case "ACQ.ERROR_BUYER_CERTIFY_LEVEL_LIMIT":
+                        return formatInfo(info, "error", "买家未通过人行认证");
+                    case "ACQ.PAYMENT_REQUEST_HAS_RISK":
+                        return formatInfo(info, "error", "支付方式存在风险");
+                    case "ACQ.NO_PAYMENT_INSTRUMENTS_AVAILABLE":
+                        return formatInfo(info, "error", "没有可用的支付工具");
+                    case "ACQ.USER_FACE_PAYMENT_SWITCH_OFF":
+                        return formatInfo(info, "error", "请开启当面付款开关");
+                    case "ACQ.SELLER_BALANCE_NOT_ENOUGH":
+                        return formatInfo(info, "error", "商户的支付宝账户中无足够的资金进行撤销");
+                    case "ACQ.REASON_TRADE_BEEN_FREEZEN":
+                        return formatInfo(info, "exception", "当前交易被冻结,不允许进行撤销");
+                    case "ACQ.TRADE_NOT_EXIST"://query
+                        return formatInfo(info, "close", "查询的交易不存在,请重新支付");
+                    default:
+                        return formatInfo(info, "system", response.getSubMsg());
+                }
+            case "20000":// 服务不可用
+                return formatInfo(info, "wait", "等待支付处理");
+            case "20001":// 授权权限不足
+            case "40001":// 缺少必要参数
+            case "40002":// 非法参数
+            case "40006":// 权限不足
+            default:
+                return formatInfo(info, "system", response.getMsg());
+        }
+    }
+
+    private ResultInfo formatInfo(ResultInfo info, String status, String message){
+        info.setStatus(status);
+        info.setMessage(message);
+        return info;
+    }
+}

+ 18 - 0
server/tools/src/main/java/com/nuliji/tools/pay/PaySource.java

@@ -0,0 +1,18 @@
+package com.qxgmat.service.pay;
+
+import com.nuliji.pay.common.PayInfo;
+import com.nuliji.pay.common.ResultInfo;
+
+import javax.servlet.http.HttpServletRequest;
+import java.math.BigDecimal;
+
+/**
+ * Created by gaojie on 2017/5/10.
+ */
+public interface PaySource {
+    public ResultInfo notifyTrade(HttpServletRequest request) throws Exception;
+    public ResultInfo returnTrade(ResultInfo info);
+    public boolean validTrade(ResultInfo info, PayInfo payInfo);
+    public PayInfo appTrade(String payId, String pid, BigDecimal money, String subject, String body, String notifyUrl, String ip) throws Exception;
+    public ResultInfo getTrade(String payId, String transactionNo, String pid) throws Exception;
+}

+ 239 - 0
server/tools/src/main/java/com/nuliji/tools/pay/WechatPay.java

@@ -0,0 +1,239 @@
+package com.nuliji.tools.pay;
+
+import com.alibaba.fastjson.JSON;
+import com.nuliji.tools.pay.common.PayInfo;
+import com.nuliji.tools.pay.common.ResultInfo;
+import com.tencent.WXPay;
+import com.tencent.common.Signature;
+import com.tencent.common.Util;
+import com.tencent.protocol.ResData;
+import com.tencent.protocol.pay_protocol.AppReqData;
+import com.tencent.protocol.pay_protocol.NoticeResData;
+import com.tencent.protocol.pay_protocol.UnifiedOrderReqData;
+import com.tencent.protocol.pay_protocol.UnifiedOrderResData;
+import com.tencent.protocol.pay_query_protocol.ScanPayQueryReqData;
+import com.tencent.protocol.pay_query_protocol.ScanPayQueryResData;
+import com.tencent.service.ScanPayQueryService;
+import com.tencent.service.UnifiedOrderService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Created by gaojie on 2017/5/10.
+ */
+public class WeixinPay implements PaySource {
+    //添加一个日志器
+    private static final Logger logger = LoggerFactory.getLogger(WeixinPay.class);
+
+    private String appId = "";
+    private String appKey = "";
+    private String pid = "";
+
+    public WeixinPay(String appId, String appKey, String pid){
+        this.appId = appId;
+        this.appKey = appKey;
+        this.pid = pid;
+
+        WXPay.initSDKConfiguration(appKey,
+                appId,
+                pid,
+                "","",""
+        );
+    }
+
+    @Override
+    public ResultInfo notifyTrade(HttpServletRequest request) throws Exception {
+        InputStream is = request.getInputStream();
+        BufferedReader br = request.getReader();
+
+        String str;
+        StringBuilder content = new StringBuilder();
+        while((str = br.readLine()) != null){
+            content.append(str);
+        }
+        logger.debug("weixin notify:"+content);
+        // 支付完成才会发送异步通知
+        NoticeResData noticeResData = (NoticeResData) Util.getObjectFromXML(content.toString(), NoticeResData.class);
+
+        String sign = noticeResData.getSign();
+        noticeResData.setSign("");
+        boolean flag = checkSign(noticeResData.toMap(), sign);
+        ResultInfo info = new ResultInfo();
+        info.setResponse(noticeResData);
+        if(!flag){
+            info.setStatus("system");
+            info.setMessage("签名校验错误");
+            return info;
+        }
+        info = parseResult(noticeResData, "success");
+        info.setMessage("<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>");
+        return info;
+    }
+
+    @Override
+    public ResultInfo returnTrade(ResultInfo info) {
+        String response = info.getResponse().toString();
+        if(response.indexOf("get_brand_wcpay_request") == 0){
+            // wap返回
+            switch(response){
+                case "get_brand_wcpay_request:ok":
+                    info.setStatus("wait");
+                    break;
+                case "get_brand_wcpay_request:fail":
+                    info.setStatus("system");
+                    break;
+                case "get_brand_wcpay_request:cancel":
+                    info.setStatus("system");
+                    break;
+                default:
+                    info.setStatus("system");
+            }
+        }else{
+            // app返回
+            switch(response){
+                case "0":
+                    info.setStatus("wait");
+                    break;
+                case "-1":
+                    info.setStatus("system");
+                    break;
+                case "-2":
+                    info.setStatus("system");
+                    break;
+                default:
+                    info.setStatus("system");
+            }
+        }
+        return info;
+    }
+
+    @Override
+    public boolean validTrade(ResultInfo info, PayInfo payInfo) {
+        if(info.getAppId() != payInfo.getAppId()) return false;
+        if(info.getPid() != payInfo.getPid()) return false;
+
+        return true;
+    }
+
+    @Override
+    public PayInfo appTrade(String payId, String pid, BigDecimal money, String subject, String body, String notifyUrl, String ip) throws Exception{
+        UnifiedOrderReqData unifiedOrderReqData = new UnifiedOrderReqData(body, "", payId, (int)(money.floatValue() * 100), "", ip, "", "", "", notifyUrl, "APP");
+        //接受API返回
+        String payServiceResponseString;
+        UnifiedOrderService unifiedOrderService = new UnifiedOrderService();
+        payServiceResponseString = unifiedOrderService.request(unifiedOrderReqData);
+
+        //将从API返回的XML数据映射到Java对象
+        UnifiedOrderResData unifiedOrderResData = (UnifiedOrderResData) Util.getObjectFromXML(payServiceResponseString, UnifiedOrderResData.class);
+        logger.debug(JSON.toJSONString(unifiedOrderResData));
+
+        PayInfo payInfo = new PayInfo();
+        payInfo.setPid(pid);
+        payInfo.setAppId(appId);
+        payInfo.setMoney(money);
+        String prepayid = unifiedOrderResData.getPrepay_id();
+        if(prepayid!=null){
+            AppReqData appReqData = new AppReqData(prepayid);
+            payInfo.setRequest(appReqData);
+            payInfo.setStatus("ok");
+        }else{
+            payInfo.setStatus("fail");
+            payInfo.setRequest(unifiedOrderResData);
+        }
+
+        return payInfo;
+    }
+
+    @Override
+    public ResultInfo getTrade(String payId, String transactionNo, String pid) throws Exception{
+        String payQueryServiceResponseString;
+
+        ScanPayQueryService scanPayQueryService = new ScanPayQueryService();
+
+        ScanPayQueryReqData scanPayQueryReqData = new ScanPayQueryReqData("", payId);
+        payQueryServiceResponseString = scanPayQueryService.request(scanPayQueryReqData);
+
+        logger.debug("weixin getTrade:"+payQueryServiceResponseString);
+
+        //将从API返回的XML数据映射到Java对象
+        ScanPayQueryResData scanPayQueryResData = (ScanPayQueryResData) Util.getObjectFromXML(payQueryServiceResponseString, ScanPayQueryResData.class);
+
+        ResultInfo info = parseResult(scanPayQueryResData, "ok");
+        if(info.getStatus() == "ok"){
+            /**
+             * SUCCESS—支付成功
+             REFUND—转入退款
+             NOTPAY—未支付
+             CLOSED—已关闭
+             REVOKED—已撤销(刷卡支付)
+             USERPAYING--用户支付中
+             PAYERROR--支付失败(其他原因,如银行返回失败)
+             */
+            switch(scanPayQueryResData.getTrade_state()){
+                case "SUCCESS":
+                    info.setStatus("success");
+                    break;
+                case "REFUND":
+                    info.setStatus("refund");
+                    break;
+                case "NOTPAY":
+                    info.setStatus("wait");
+                    break;
+                case "REVOKED":
+                    info.setStatus("cancel");
+                    break;
+                case "USERPAYING":
+                    info.setStatus("wait");
+                    break;
+                case "PAYERROR":
+                    info.setStatus("error");
+                    break;
+            }
+        }
+        return info;
+    }
+
+    private ResultInfo parseResult(ResData response, String status){
+        ResultInfo info = new ResultInfo();
+        info.setAppId(response.getAppid());
+        info.setPid(response.getMch_id());
+        info.setResponse(response);
+        info.setNo(response.getOut_trade_no());
+        info.setMoney(BigDecimal.valueOf(Float.valueOf(response.getTotal_fee())/100));
+        info.setOpen_id(response.getOpenid());
+        info.setTransaction_no(response.getTransaction_id());
+
+        if (response == null || response.getReturn_code() == null) {
+            return formatInfo(info, "system", "请求错误");
+        }
+
+        if (response.getReturn_code().equals("FAIL")) {
+            return formatInfo(info, "system", response.getReturn_msg());
+        } else {
+            if (response.getResult_code().equals("SUCCESS")) {//业务层成功
+                return formatInfo(info, status, "");
+            } else {
+                return formatInfo(info, "error", response.getErr_code_des());
+            }
+        }
+    }
+
+    private ResultInfo formatInfo(ResultInfo info, String status, String message){
+        info.setStatus(status);
+        info.setMessage(message);
+        return info;
+    }
+
+    private boolean checkSign(Map param, String sign){
+        String signNow = Signature.getSign(param);
+        logger.debug(sign);
+        return Objects.equals(signNow.trim(), sign.trim());
+    }
+}

+ 79 - 0
server/tools/src/main/java/com/nuliji/tools/pay/common/PayInfo.java

@@ -0,0 +1,79 @@
+package com.qxgmat.service.pay.common;
+
+import java.math.BigDecimal;
+
+/**
+ * 统一支付信息
+ * Created by gaojie on 2017/5/11.
+ */
+public class PayInfo {
+
+    private String appId = "";
+    private String pid = "";
+    private Object request = null;
+    private String transaction_no = "";
+    private BigDecimal money = null;
+    private String status = "";
+
+    public PayInfo(){
+
+    }
+
+    public PayInfo(String status, String appId, String pid, Object request, String id, String transaction_no, BigDecimal money){
+        this.status = status;
+        this.appId = appId;
+        this.pid = pid;
+        this.request = request;
+        this.transaction_no = transaction_no;
+        this.money = money;
+    }
+
+
+    public Object getRequest() {
+        return request;
+    }
+
+    public void setRequest(Object request) {
+        this.request = request;
+    }
+
+    public String getTransaction_no() {
+        return transaction_no;
+    }
+
+    public void setTransaction_no(String transaction_no) {
+        this.transaction_no = transaction_no;
+    }
+
+    public BigDecimal getMoney() {
+        return money;
+    }
+
+    public void setMoney(BigDecimal money) {
+        this.money = money;
+    }
+
+    public String getAppId() {
+        return appId;
+    }
+
+    public void setAppId(String appId) {
+        this.appId = appId;
+    }
+
+    public String getPid() {
+        return pid;
+    }
+
+    public void setPid(String pid) {
+        this.pid = pid;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+}

+ 116 - 0
server/tools/src/main/java/com/nuliji/tools/pay/common/ResultInfo.java

@@ -0,0 +1,116 @@
+package com.qxgmat.service.pay.common;
+
+import java.math.BigDecimal;
+
+/**
+ * 统一结果信息
+ * Created by gaojie on 2017/5/11.
+ */
+public class ResultInfo {
+
+    private String appId = "";
+    private String pid = "";
+    private String status = "";
+    private String message = "";
+    private Object response = null;
+    private Object request = null;
+    private String id = "";
+    private String transaction_no = "";
+    private BigDecimal money = null;
+    private String open_id = "";
+
+    public ResultInfo(){
+
+    }
+
+    public ResultInfo(String status, String message, Object response, Object request, String id, String transaction_no, BigDecimal money, String open_id){
+        this.status = status;
+        this.message = message;
+        this.response = response;
+        this.request = request;
+        this.id = id;
+        this.transaction_no = transaction_no;
+        this.money = money;
+        this.open_id = open_id;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public Object getResponse() {
+        return response;
+    }
+
+    public void setResponse(Object response) {
+        this.response = response;
+    }
+
+    public Object getRequest() {
+        return request;
+    }
+
+    public void setRequest(Object request) {
+        this.request = request;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getTransaction_no() {
+        return transaction_no;
+    }
+
+    public void setTransaction_no(String transaction_no) {
+        this.transaction_no = transaction_no;
+    }
+
+    public BigDecimal getMoney() {
+        return money;
+    }
+
+    public void setMoney(BigDecimal money) {
+        this.money = money;
+    }
+
+    public String getOpen_id() {
+        return open_id;
+    }
+
+    public void setOpen_id(String open_id) {
+        this.open_id = open_id;
+    }
+
+    public String getAppId() {
+        return appId;
+    }
+
+    public void setAppId(String appId) {
+        this.appId = appId;
+    }
+
+    public String getPid() {
+        return pid;
+    }
+
+    public void setPid(String pid) {
+        this.pid = pid;
+    }
+}

+ 14 - 0
server/tools/src/main/java/com/nuliji/tools/pay/data/PayRequestData.java

@@ -0,0 +1,14 @@
+package com.nuliji.tools.pay.data;
+
+import java.math.BigDecimal;
+
+/**
+ * Created by gaojie on 2017/5/11.
+ */
+public class PayRequestData {
+    public String userId = "";
+    public BigDecimal money = BigDecimal.valueOf(0);
+    public String channel = "";
+    public String subject = "";
+    public String body = "";
+}

+ 10 - 0
server/tools/src/main/java/com/nuliji/tools/pay/data/PayResponseData.java

@@ -0,0 +1,10 @@
+package com.nuliji.tools.pay.data;
+
+/**
+ * Created by gaojie on 2017/5/11.
+ */
+public class PayResponseData {
+    public String status = "";
+    public Object request = "";
+    public String payId = "";
+}

+ 32 - 0
server/tools/src/main/java/com/nuliji/tools/pay/enums/TradeStatus.java

@@ -0,0 +1,32 @@
+package com.nuliji.tools.pay.enums;
+
+/**
+ * Created by gaojie on 2017/5/11.
+ */
+public class TradeStatus {
+
+    public static final short WAIT_BUYER_PAY = 0;
+    public static final short SUCCESS = 1;
+    public static final short CANCEL = 2;
+    public static final short FINISH = 3;
+    public static final short ERROR = 4;
+    public static final short CLOSE = 5;
+    public static final short SYSTEM = 6;
+    public static final short EXCEPTION = 7;
+
+    public static boolean isPayed(int status){
+        return status == SUCCESS || status == FINISH;
+    }
+
+    public static boolean isPaying(int status){
+        return status == WAIT_BUYER_PAY || status == ERROR;
+    }
+
+    public static boolean isInvalid(int status){
+        return status == CLOSE || status == CANCEL || status == SYSTEM || status == EXCEPTION;
+    }
+
+    public static boolean isError(int status){
+        return status == ERROR;
+    }
+}

+ 64 - 0
server/tools/src/main/java/com/tencent/Main.java

@@ -0,0 +1,64 @@
+package com.nuliji.tools.third.tencent;
+
+import com.tencent.common.Util;
+
+public class Main {
+
+    public static void main(String[] args) {
+
+        try {
+
+            //--------------------------------------------------------------------
+            //温馨提示,第一次使用该SDK时请到com.tencent.common.Configure类里面进行配置
+            //--------------------------------------------------------------------
+
+
+
+            //--------------------------------------------------------------------
+            //PART One:基础组件测试
+            //--------------------------------------------------------------------
+
+            //1)https请求可用性测试
+            //HTTPSPostRquestWithCert.test();
+
+            //2)测试项目用到的XStream组件,本项目利用这个组件将Java对象转换成XML数据Post给API
+            //XStreamTest.test();
+
+
+            //--------------------------------------------------------------------
+            //PART Two:基础服务测试
+            //--------------------------------------------------------------------
+
+            //1)测试被扫支付API
+            //PayServiceTest.test();
+
+            //2)测试被扫订单查询API
+            //PayQueryServiceTest.test();
+
+            //3)测试撤销API
+            //温馨提示,测试支付API成功扣到钱之后,可以通过调用PayQueryServiceTest.test(),将支付成功返回的transaction_id和out_trade_no数据贴进去,完成撤销工作,把钱退回来 ^_^v
+            //ReverseServiceTest.test();
+
+            //4)测试退款申请API
+            //RefundServiceTest.test();
+
+            //5)测试退款查询API
+            //RefundQueryServiceTest.test();
+
+            //6)测试对账单API
+            //DownloadBillServiceTest.test();
+
+
+            //本地通过xml进行API数据模拟的时候,先按需手动修改xml各个节点的值,然后通过以下方法对这个新的xml数据进行签名得到一串合法的签名,最后把这串签名放到这个xml里面的sign字段里,这样进行模拟的时候就可以通过签名验证了
+           // Util.log(Signature.getSignFromResponseString(Util.getLocalXMLString("/test/com/tencent/business/refundqueryserviceresponsedata/refundquerysuccess2.xml")));
+
+            //Util.log(new Date().getTime());
+            //Util.log(System.currentTimeMillis());
+
+        } catch (Exception e){
+            Util.log(e.getMessage());
+        }
+
+    }
+
+}

+ 151 - 0
server/tools/src/main/java/com/tencent/WXPay.java

@@ -0,0 +1,151 @@
+package com.nuliji.tools.third.tencent;
+
+import com.tencent.business.DownloadBillBusiness;
+import com.tencent.business.RefundBusiness;
+import com.tencent.business.RefundQueryBusiness;
+import com.tencent.business.ScanPayBusiness;
+import com.tencent.common.Configure;
+import com.tencent.protocol.downloadbill_protocol.DownloadBillReqData;
+import com.tencent.protocol.pay_protocol.ScanPayReqData;
+import com.tencent.protocol.pay_protocol.UnifiedOrderReqData;
+import com.tencent.protocol.pay_query_protocol.ScanPayQueryReqData;
+import com.tencent.protocol.refund_protocol.RefundReqData;
+import com.tencent.protocol.refund_query_protocol.RefundQueryReqData;
+import com.tencent.protocol.reverse_protocol.ReverseReqData;
+import com.tencent.service.*;
+
+/**
+ * SDK总入口
+ */
+public class WXPay {
+
+    /**
+     * 初始化SDK依赖的几个关键配置
+     * @param key 签名算法需要用到的秘钥
+     * @param appID 公众账号ID
+     * @param mchID 商户ID
+     * @param sdbMchID 子商户ID,受理模式必填
+     * @param certLocalPath HTTP证书在服务器中的路径,用来加载证书用
+     * @param certPassword HTTP证书的密码,默认等于MCHID
+     */
+    public static void initSDKConfiguration(String key,String appID,String mchID,String sdbMchID,String certLocalPath,String certPassword){
+        Configure.setKey(key);
+        Configure.setAppID(appID);
+        Configure.setMchID(mchID);
+//        Configure.setSubMchID(sdbMchID);
+//        Configure.setCertLocalPath(certLocalPath);
+//        Configure.setCertPassword(certPassword);
+    }
+
+    /**
+     * 请求统一下单
+     * @param unifiedOrderReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的数据
+     * @throws Exception
+     */
+    public static String requestUnifiedOrderService(UnifiedOrderReqData unifiedOrderReqData) throws Exception{
+        return new UnifiedOrderService().request(unifiedOrderReqData);
+    }
+    /**
+     * 请求支付服务
+     * @param scanPayReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的数据
+     * @throws Exception
+     */
+    public static String requestScanPayService(ScanPayReqData scanPayReqData) throws Exception{
+        return new ScanPayService().request(scanPayReqData);
+    }
+
+    /**
+     * 请求支付查询服务
+     * @param scanPayQueryReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的XML数据
+     * @throws Exception
+     */
+	public static String requestScanPayQueryService(ScanPayQueryReqData scanPayQueryReqData) throws Exception{
+		return new ScanPayQueryService().request(scanPayQueryReqData);
+	}
+
+    /**
+     * 请求退款服务
+     * @param refundReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的XML数据
+     * @throws Exception
+     */
+    public static String requestRefundService(RefundReqData refundReqData) throws Exception{
+        return new RefundService().request(refundReqData);
+    }
+
+    /**
+     * 请求退款查询服务
+     * @param refundQueryReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的XML数据
+     * @throws Exception
+     */
+	public static String requestRefundQueryService(RefundQueryReqData refundQueryReqData) throws Exception{
+		return new RefundQueryService().request(refundQueryReqData);
+	}
+
+    /**
+     * 请求撤销服务
+     * @param reverseReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的XML数据
+     * @throws Exception
+     */
+	public static String requestReverseService(ReverseReqData reverseReqData) throws Exception{
+		return new ReverseService().request(reverseReqData);
+	}
+
+    /**
+     * 请求对账单下载服务
+     * @param downloadBillReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的XML数据
+     * @throws Exception
+     */
+    public static String requestDownloadBillService(DownloadBillReqData downloadBillReqData) throws Exception{
+        return new DownloadBillService().request(downloadBillReqData);
+    }
+
+    /**
+     * 直接执行被扫支付业务逻辑(包含最佳实践流程)
+     * @param scanPayReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @param resultListener 商户需要自己监听被扫支付业务逻辑可能触发的各种分支事件,并做好合理的响应处理
+     * @throws Exception
+     */
+    public static void doScanPayBusiness(ScanPayReqData scanPayReqData, ScanPayBusiness.ResultListener resultListener) throws Exception {
+        new ScanPayBusiness().run(scanPayReqData, resultListener);
+    }
+
+    /**
+     * 调用退款业务逻辑
+     * @param refundReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @param resultListener 业务逻辑可能走到的结果分支,需要商户处理
+     * @throws Exception
+     */
+    public static void doRefundBusiness(RefundReqData refundReqData, RefundBusiness.ResultListener resultListener) throws Exception {
+        new RefundBusiness().run(refundReqData,resultListener);
+    }
+
+    /**
+     * 运行退款查询的业务逻辑
+     * @param refundQueryReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @param resultListener 商户需要自己监听被扫支付业务逻辑可能触发的各种分支事件,并做好合理的响应处理
+     * @throws Exception
+     */
+    public static void doRefundQueryBusiness(RefundQueryReqData refundQueryReqData,RefundQueryBusiness.ResultListener resultListener) throws Exception {
+        new RefundQueryBusiness().run(refundQueryReqData,resultListener);
+    }
+
+    /**
+     * 请求对账单下载服务
+     * @param downloadBillReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @param resultListener 商户需要自己监听被扫支付业务逻辑可能触发的各种分支事件,并做好合理的响应处理
+     * @return API返回的XML数据
+     * @throws Exception
+     */
+    public static void doDownloadBillBusiness(DownloadBillReqData downloadBillReqData,DownloadBillBusiness.ResultListener resultListener) throws Exception {
+        new DownloadBillBusiness().run(downloadBillReqData,resultListener);
+    }
+
+
+}

+ 125 - 0
server/tools/src/main/java/com/tencent/bridge/IBridge.java

@@ -0,0 +1,125 @@
+package com.nuliji.tools.third.tencent.bridge;
+
+/**
+ * User: rizenguo
+ * Date: 2014/12/1
+ * Time: 17:11
+ */
+public interface IBridge {
+
+    /**
+     * 获取auth_code,这个是扫码终端设备从用户手机上扫取到的支付授权号,这个号是跟用户用来支付的银行卡绑定的,有效期是1分钟
+     * @return 授权码
+     */
+    public String getAuthCode();
+
+    /**
+     * 获取out_trade_no,这个是商户系统内自己可以用来唯一标识该笔订单的字符串,可以包含字母和数字,不超过32位
+     * @return 订单号
+     */
+    public String getOutTradeNo();
+
+    /**
+     * 获取body:要支付的商品的描述信息,用户会在支付成功页面里看到这个信息
+     * @return 描述信息
+     */
+    public String getBody();
+
+
+    /**
+     * 获取attach:支付订单里面可以填的附加数据,API会将提交的这个附加数据原样返回,有助于商户自己可以注明该笔消费的具体内容,方便后续的运营和记录
+     * @return 附加数据
+     */
+    public String getAttach();
+
+    /**
+     * 获取订单总额
+     * @return 订单总额
+     */
+    public int getTotalFee();
+
+    /**
+     * 获取device_info:商户自己定义的扫码支付终端设备号,方便追溯这笔交易发生在哪台终端设备上
+     * @return 支付终端设备号
+     */
+    public String getDeviceInfo();
+
+    /**
+     * 获取机器的ip地址
+     * @return 机器设备的ip地址
+     */
+    public String getUserIp();
+
+    /**
+     * 获取spBillCreateIP:订单生成的机器IP
+     * @return 订单生成的机器IP
+     */
+    public String getSpBillCreateIP();
+
+    /**
+     * 获取time_start:订单生成时间
+     * @return 订单生成时间
+     */
+    public String getTimeStart();
+
+    /**
+     * 获取time_end:订单生成时间
+     * @return 订单失效时间
+     */
+    public String getTimeExpire();
+
+    /**
+     * 获取goods_tag:商品标记,微信平台配置的商品标记,用于优惠券或者满减使用
+     * @return 商品标记
+     */
+    public String getGoodsTag();
+
+    /**
+     * 获取transaction_id:微信平台支付成功时给分配的唯一交易号,一般只要有这个tracnsacion_id,后续的查询、撤销、退款都建议优先用这个,而不是商户自己的那个out_trade_no
+     * @return 微信平台官方分配的交易号
+     */
+    public String getTransactionID();
+
+    /**
+     * 获取out_refund_no:商户系统内部的退款单号,商户系统内部唯一,同一退款单号多次请求只退一笔
+     * @return 商户系统内部的退款单号
+     */
+    public String getOutRefundNo();
+
+    /**
+     * 获取refund_fee:获取本次退款请求所要退的具体金额,这个金额不能比这个订单的total_fee(总金额)还大
+     * @return 本次退款请求所要退的具体金额
+     */
+    public int getRefundFee();
+
+    /**
+     * 获取refund_id:微信平台退款成功时给分配的唯一退款号,一般只要有这个refund_id,后续的查询建议优先用这个
+     * @return 微信平台官方分配的退款号
+     */
+    public String getRefundID();
+
+    /**
+     * 获取bill_date:获取对账单API需要的日期,格式是yyyyMMdd
+     * @return 要查询对账单的日期
+     */
+    public String getBillDate();
+
+    /**
+     * 获取bill_type:获取对账单API需要的数据类型,这些类型在DownloadBillService里面有定义
+     * @return 要查询对账单的类型
+     */
+    public String getBillType();
+
+    /**
+     * 获取操作员的ID,默认等于商户号
+     * @return 返回操作员的ID
+     */
+    public String getOpUserID();
+
+    /**
+     * 获取退款货币类型,符合ISO 4217标准的三位字母代码,默认为CNY(人民币)
+     * @return 获取退款货币类型
+     */
+    public String getRefundFeeType();
+
+}

+ 156 - 0
server/tools/src/main/java/com/tencent/business/DownloadBillBusiness.java

@@ -0,0 +1,156 @@
+package com.nuliji.tools.third.tencent.business;
+
+import com.tencent.common.Configure;
+import com.tencent.common.Log;
+import com.tencent.common.Util;
+import com.tencent.common.report.ReporterFactory;
+import com.tencent.common.report.protocol.ReportReqData;
+import com.tencent.common.report.service.ReportService;
+import com.tencent.protocol.downloadbill_protocol.DownloadBillReqData;
+import com.tencent.protocol.downloadbill_protocol.DownloadBillResData;
+import com.tencent.service.DownloadBillService;
+import com.thoughtworks.xstream.io.StreamException;
+import org.slf4j.LoggerFactory;
+
+/**
+ * User: rizenguo
+ * Date: 2014/12/3
+ * Time: 10:45
+ */
+public class DownloadBillBusiness {
+
+    public DownloadBillBusiness() throws IllegalAccessException, ClassNotFoundException, InstantiationException {
+        downloadBillService = new DownloadBillService();
+    }
+
+    public interface ResultListener{
+        //API返回ReturnCode不合法,支付请求逻辑错误,请仔细检测传过去的每一个参数是否合法,或是看API能否被正常访问
+        void onFailByReturnCodeError(DownloadBillResData downloadBillResData);
+
+        //API返回ReturnCode为FAIL,支付API系统返回失败,请检测Post给API的数据是否规范合法
+        void onFailByReturnCodeFail(DownloadBillResData downloadBillResData);
+
+        //下载对账单失败
+        void onDownloadBillFail(String response);
+
+        //下载对账单成功
+        void onDownloadBillSuccess(String response);
+
+    }
+
+    //打log用
+    private static Log log = new Log(LoggerFactory.getLogger(DownloadBillBusiness.class));
+
+    //执行结果
+    private static String result = "";
+
+    private DownloadBillService downloadBillService;
+
+    /**
+     * 请求对账单下载服务
+     * @param downloadBillReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @param resultListener 商户需要自己监听被扫支付业务逻辑可能触发的各种分支事件,并做好合理的响应处理
+     * @return API返回的XML数据
+     * @throws Exception
+     */
+
+    public void run(DownloadBillReqData downloadBillReqData,ResultListener resultListener) throws Exception {
+
+        //--------------------------------------------------------------------
+        //构造请求“对账单API”所需要提交的数据
+        //--------------------------------------------------------------------
+
+        //API返回的数据
+        String downloadBillServiceResponseString;
+
+        long costTimeStart = System.currentTimeMillis();
+
+        //支持加载本地测试数据进行调试
+
+        log.i("对账单API返回的数据如下:");
+        downloadBillServiceResponseString = downloadBillService.request(downloadBillReqData);
+
+
+        long costTimeEnd = System.currentTimeMillis();
+        long totalTimeCost = costTimeEnd - costTimeStart;
+        log.i("api请求总耗时:" + totalTimeCost + "ms");
+
+        log.i(downloadBillServiceResponseString);
+
+        DownloadBillResData downloadBillResData;
+
+        String returnCode = "";
+        String returnMsg = "";
+
+        try {
+            //注意,这里失败的时候是返回xml数据,成功的时候反而返回非xml数据
+            downloadBillResData = (DownloadBillResData) Util.getObjectFromXML(downloadBillServiceResponseString, DownloadBillResData.class);
+
+            if (downloadBillResData == null || downloadBillResData.getReturn_code() == null) {
+                setResult("Case1:对账单API请求逻辑错误,请仔细检测传过去的每一个参数是否合法,或是看API能否被正常访问",Log.LOG_TYPE_ERROR);
+                resultListener.onFailByReturnCodeError(downloadBillResData);
+                return;
+            }
+            if (downloadBillResData.getReturn_code().equals("FAIL")) {
+                ///注意:一般这里返回FAIL是出现系统级参数错误,请检测Post给API的数据是否规范合法
+                setResult("Case2:对账单API系统返回失败,请检测Post给API的数据是否规范合法",Log.LOG_TYPE_ERROR);
+                resultListener.onFailByReturnCodeFail(downloadBillResData);
+                returnCode = "FAIL";
+                returnMsg = downloadBillResData.getReturn_msg();
+            }
+        } catch (StreamException e) {
+            //注意,这里成功的时候是直接返回纯文本的对账单文本数据,非XML格式
+            if (downloadBillServiceResponseString.equals(null) || downloadBillServiceResponseString.equals("")) {
+                setResult("Case4:对账单API系统返回数据为空",Log.LOG_TYPE_ERROR);
+                resultListener.onDownloadBillFail(downloadBillServiceResponseString);
+            } else {
+                setResult("Case3:对账单API系统成功返回数据",Log.LOG_TYPE_INFO);
+                resultListener.onDownloadBillSuccess(downloadBillServiceResponseString);
+            }
+            returnCode = "SUCCESS";
+        } finally {
+
+            ReportReqData reportReqData = new ReportReqData(
+                    downloadBillReqData.getDevice_info(),
+                    Configure.DOWNLOAD_BILL_API,
+                    (int) (totalTimeCost),//本次请求耗时
+                    returnCode,
+                    returnMsg,
+                    "",
+                    "",
+                    "",
+                    "",
+                    Configure.getIP()
+            );
+
+            long timeAfterReport;
+            if(Configure.isUseThreadToDoReport()){
+                ReporterFactory.getReporter(reportReqData).run();
+                timeAfterReport = System.currentTimeMillis();
+                Util.log("pay+report总耗时(异步方式上报):"+(timeAfterReport-costTimeStart) + "ms");
+            }else{
+                ReportService.request(reportReqData);
+                timeAfterReport = System.currentTimeMillis();
+                Util.log("pay+report总耗时(同步方式上报):"+(timeAfterReport-costTimeStart) + "ms");
+            }
+        }
+    }
+
+    public void setDownloadBillService(DownloadBillService service) {
+        downloadBillService = service;
+    }
+
+    public String getResult() {
+        return result;
+    }
+
+    public void setResult(String result) {
+        DownloadBillBusiness.result = result;
+    }
+
+    public void setResult(String result,String type){
+        setResult(result);
+        log.log(type,result);
+    }
+
+}

+ 162 - 0
server/tools/src/main/java/com/tencent/business/RefundBusiness.java

@@ -0,0 +1,162 @@
+package com.nuliji.tools.third.tencent.business;
+
+import com.tencent.common.Configure;
+import com.tencent.common.Log;
+import com.tencent.common.Signature;
+import com.tencent.common.Util;
+import com.tencent.common.report.ReporterFactory;
+import com.tencent.common.report.protocol.ReportReqData;
+import com.tencent.common.report.service.ReportService;
+import com.tencent.protocol.refund_protocol.RefundReqData;
+import com.tencent.protocol.refund_protocol.RefundResData;
+import com.tencent.service.RefundService;
+import org.slf4j.LoggerFactory;
+
+/**
+ * User: rizenguo
+ * Date: 2014/12/2
+ * Time: 17:51
+ */
+public class RefundBusiness {
+
+    public RefundBusiness() throws IllegalAccessException, ClassNotFoundException, InstantiationException {
+        refundService = new RefundService();
+    }
+
+    public interface ResultListener{
+        //API返回ReturnCode不合法,支付请求逻辑错误,请仔细检测传过去的每一个参数是否合法,或是看API能否被正常访问
+        void onFailByReturnCodeError(RefundResData refundResData);
+
+        //API返回ReturnCode为FAIL,支付API系统返回失败,请检测Post给API的数据是否规范合法
+        void onFailByReturnCodeFail(RefundResData refundResData);
+
+        //支付请求API返回的数据签名验证失败,有可能数据被篡改了
+        void onFailBySignInvalid(RefundResData refundResData);
+
+        //退款失败
+        void onRefundFail(RefundResData refundResData);
+
+        //退款成功
+        void onRefundSuccess(RefundResData refundResData);
+
+    }
+
+    //打log用
+    private static Log log = new Log(LoggerFactory.getLogger(RefundBusiness.class));
+
+    //执行结果
+    private static String result = "";
+
+    private RefundService refundService;
+
+    /**
+     * 调用退款业务逻辑
+     * @param refundReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @param resultListener 业务逻辑可能走到的结果分支,需要商户处理
+     * @throws Exception
+     */
+    public void run(RefundReqData refundReqData,ResultListener resultListener) throws Exception {
+
+        //--------------------------------------------------------------------
+        //构造请求“退款API”所需要提交的数据
+        //--------------------------------------------------------------------
+
+        //API返回的数据
+        String refundServiceResponseString;
+
+        long costTimeStart = System.currentTimeMillis();
+
+
+        log.i("退款查询API返回的数据如下:");
+        refundServiceResponseString = refundService.request(refundReqData);
+
+
+        long costTimeEnd = System.currentTimeMillis();
+        long totalTimeCost = costTimeEnd - costTimeStart;
+        log.i("api请求总耗时:" + totalTimeCost + "ms");
+
+        log.i(refundServiceResponseString);
+
+        //将从API返回的XML数据映射到Java对象
+        RefundResData refundResData = (RefundResData) Util.getObjectFromXML(refundServiceResponseString, RefundResData.class);
+
+
+        ReportReqData reportReqData = new ReportReqData(
+                refundResData.getDevice_info(),
+                Configure.REFUND_API,
+                (int) (totalTimeCost),//本次请求耗时
+                refundResData.getReturn_code(),
+                refundResData.getReturn_msg(),
+                refundResData.getResult_code(),
+                refundResData.getErr_code(),
+                refundResData.getErr_code_des(),
+                refundResData.getOut_trade_no(),
+                Configure.getIP()
+        );
+
+        long timeAfterReport;
+        if(Configure.isUseThreadToDoReport()){
+            ReporterFactory.getReporter(reportReqData).run();
+            timeAfterReport = System.currentTimeMillis();
+            Util.log("pay+report总耗时(异步方式上报):"+(timeAfterReport-costTimeStart) + "ms");
+        }else{
+            ReportService.request(reportReqData);
+            timeAfterReport = System.currentTimeMillis();
+            Util.log("pay+report总耗时(同步方式上报):"+(timeAfterReport-costTimeStart) + "ms");
+        }
+
+        if (refundResData == null || refundResData.getReturn_code() == null) {
+            setResult("Case1:退款API请求逻辑错误,请仔细检测传过去的每一个参数是否合法,或是看API能否被正常访问",Log.LOG_TYPE_ERROR);
+            resultListener.onFailByReturnCodeError(refundResData);
+            return;
+        }
+
+        //Debug:查看数据是否正常被填充到scanPayResponseData这个对象中
+        //Util.reflect(refundResData);
+
+        if (refundResData.getReturn_code().equals("FAIL")) {
+            ///注意:一般这里返回FAIL是出现系统级参数错误,请检测Post给API的数据是否规范合法
+            setResult("Case2:退款API系统返回失败,请检测Post给API的数据是否规范合法",Log.LOG_TYPE_ERROR);
+            resultListener.onFailByReturnCodeFail(refundResData);
+        } else {
+            log.i("退款API系统成功返回数据");
+            //--------------------------------------------------------------------
+            //收到API的返回数据的时候得先验证一下数据有没有被第三方篡改,确保安全
+            //--------------------------------------------------------------------
+
+            if (!Signature.checkIsSignValidFromResponseString(refundServiceResponseString)) {
+                setResult("Case3:退款请求API返回的数据签名验证失败,有可能数据被篡改了",Log.LOG_TYPE_ERROR);
+                resultListener.onFailBySignInvalid(refundResData);
+                return;
+            }
+
+            if (refundResData.getResult_code().equals("FAIL")) {
+                log.i("出错,错误码:" + refundResData.getErr_code() + "     错误信息:" + refundResData.getErr_code_des());
+                setResult("Case4:【退款失败】",Log.LOG_TYPE_ERROR);
+                //退款失败时再怎么延时查询退款状态都没有意义,这个时间建议要么再手动重试一次,依然失败的话请走投诉渠道进行投诉
+                resultListener.onRefundFail(refundResData);
+            } else {
+                //退款成功
+                setResult("Case5:【退款成功】",Log.LOG_TYPE_INFO);
+                resultListener.onRefundSuccess(refundResData);
+            }
+        }
+    }
+
+    public void setRefundService(RefundService service) {
+        refundService = service;
+    }
+
+    public String getResult() {
+        return result;
+    }
+
+    public void setResult(String result) {
+        RefundBusiness.result = result;
+    }
+
+    public void setResult(String result,String type){
+        setResult(result);
+        log.log(type,result);
+    }
+}

+ 197 - 0
server/tools/src/main/java/com/tencent/business/RefundQueryBusiness.java

@@ -0,0 +1,197 @@
+package com.nuliji.tools.third.tencent.business;
+
+import com.tencent.common.*;
+import com.tencent.common.report.ReporterFactory;
+import com.tencent.common.report.protocol.ReportReqData;
+import com.tencent.common.report.service.ReportService;
+import com.tencent.protocol.refund_query_protocol.RefundOrderData;
+import com.tencent.protocol.refund_query_protocol.RefundQueryReqData;
+import com.tencent.protocol.refund_query_protocol.RefundQueryResData;
+import com.tencent.service.RefundQueryService;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * User: rizenguo
+ * Date: 2014/12/2
+ * Time: 18:51
+ */
+public class RefundQueryBusiness {
+
+    public RefundQueryBusiness() throws IllegalAccessException, ClassNotFoundException, InstantiationException {
+        refundQueryService = new RefundQueryService();
+    }
+
+    public interface ResultListener{
+        //API返回ReturnCode不合法,支付请求逻辑错误,请仔细检测传过去的每一个参数是否合法,或是看API能否被正常访问
+        void onFailByReturnCodeError(RefundQueryResData refundQueryResData);
+
+        //API返回ReturnCode为FAIL,支付API系统返回失败,请检测Post给API的数据是否规范合法
+        void onFailByReturnCodeFail(RefundQueryResData refundQueryResData);
+
+        //支付请求API返回的数据签名验证失败,有可能数据被篡改了
+        void onFailBySignInvalid(RefundQueryResData refundQueryResData);
+
+        //退款查询失败
+        void onRefundQueryFail(RefundQueryResData refundQueryResData);
+
+        //退款查询成功
+        void onRefundQuerySuccess(RefundQueryResData refundQueryResData);
+
+    }
+
+    //打log用
+    private static Log log = new Log(LoggerFactory.getLogger(RefundQueryBusiness.class));
+
+    //执行结果
+    private static String result = "";
+
+    //查询到的结果
+    private static String orderListResult = "";
+
+    private RefundQueryService refundQueryService;
+
+    public String getOrderListResult() {
+        return orderListResult;
+    }
+
+    public void setOrderListResult(String orderListResult) {
+        RefundQueryBusiness.orderListResult = orderListResult;
+    }
+
+    /**
+     * 运行退款查询的业务逻辑
+     * @param refundQueryReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @param resultListener 商户需要自己监听被扫支付业务逻辑可能触发的各种分支事件,并做好合理的响应处理
+     * @throws Exception
+     */
+    public void run(RefundQueryReqData refundQueryReqData,RefundQueryBusiness.ResultListener resultListener) throws Exception {
+
+        //--------------------------------------------------------------------
+        //构造请求“退款查询API”所需要提交的数据
+        //--------------------------------------------------------------------
+
+        //接受API返回
+        String refundQueryServiceResponseString;
+
+        long costTimeStart = System.currentTimeMillis();
+
+        //表示是本地测试数据
+        log.i("退款查询API返回的数据如下:");
+        refundQueryServiceResponseString = refundQueryService.request(refundQueryReqData);
+
+        long costTimeEnd = System.currentTimeMillis();
+        long totalTimeCost = costTimeEnd - costTimeStart;
+        log.i("api请求总耗时:" + totalTimeCost + "ms");
+
+        log.i(refundQueryServiceResponseString);
+
+        //将从API返回的XML数据映射到Java对象
+        RefundQueryResData refundQueryResData = (RefundQueryResData) Util.getObjectFromXML(refundQueryServiceResponseString, RefundQueryResData.class);
+
+        ReportReqData reportReqData = new ReportReqData(
+                refundQueryReqData.getDevice_info(),
+                Configure.REFUND_QUERY_API,
+                (int) (totalTimeCost),//本次请求耗时
+                refundQueryResData.getReturn_code(),
+                refundQueryResData.getReturn_msg(),
+                refundQueryResData.getResult_code(),
+                refundQueryResData.getErr_code(),
+                refundQueryResData.getErr_code_des(),
+                refundQueryResData.getOut_trade_no(),
+                Configure.getIP()
+        );
+
+        long timeAfterReport;
+        if(Configure.isUseThreadToDoReport()){
+            ReporterFactory.getReporter(reportReqData).run();
+            timeAfterReport = System.currentTimeMillis();
+            Util.log("pay+report总耗时(异步方式上报):"+(timeAfterReport-costTimeStart) + "ms");
+        }else{
+            ReportService.request(reportReqData);
+            timeAfterReport = System.currentTimeMillis();
+            Util.log("pay+report总耗时(同步方式上报):"+(timeAfterReport-costTimeStart) + "ms");
+        }
+
+
+        if (refundQueryResData == null || refundQueryResData.getReturn_code() == null) {
+            setResult("Case1:退款查询API请求逻辑错误,请仔细检测传过去的每一个参数是否合法,或是看API能否被正常访问",Log.LOG_TYPE_ERROR);
+            resultListener.onFailByReturnCodeError(refundQueryResData);
+            return;
+        }
+
+        //Debug:查看数据是否正常被填充到scanPayResponseData这个对象中
+        //Util.reflect(refundQueryResData);
+
+        if (refundQueryResData.getReturn_code().equals("FAIL")) {
+            ///注意:一般这里返回FAIL是出现系统级参数错误,请检测Post给API的数据是否规范合法
+            setResult("Case2:退款查询API系统返回失败,请检测Post给API的数据是否规范合法",Log.LOG_TYPE_ERROR);
+            resultListener.onFailByReturnCodeFail(refundQueryResData);
+        } else {
+            log.i("退款查询API系统成功返回数据");
+            //--------------------------------------------------------------------
+            //收到API的返回数据的时候得先验证一下数据有没有被第三方篡改,确保安全
+            //--------------------------------------------------------------------
+
+            if (!Signature.checkIsSignValidFromResponseString(refundQueryServiceResponseString)) {
+                setResult("Case3:退款查询API返回的数据签名验证失败,有可能数据被篡改了",Log.LOG_TYPE_ERROR);
+                resultListener.onFailBySignInvalid(refundQueryResData);
+                return;
+            }
+
+            if (refundQueryResData.getResult_code().equals("FAIL")) {
+                Util.log("出错,错误码:" + refundQueryResData.getErr_code() + "     错误信息:" + refundQueryResData.getErr_code_des());
+                setResult("Case4:【退款查询失败】",Log.LOG_TYPE_ERROR);
+                resultListener.onRefundQueryFail(refundQueryResData);
+                //退款失败时再怎么延时查询退款状态都没有意义,这个时间建议要么再手动重试一次,依然失败的话请走投诉渠道进行投诉
+            } else {
+                //退款成功
+                getRefundOrderListResult(refundQueryServiceResponseString);
+                setResult("Case5:【退款查询成功】",Log.LOG_TYPE_INFO);
+                resultListener.onRefundQuerySuccess(refundQueryResData);
+            }
+        }
+    }
+
+    /**
+     * 打印出服务器返回的订单查询结果
+     * @param refundQueryResponseString 退款查询返回API返回的数据
+     * @throws ParserConfigurationException
+     * @throws SAXException
+     * @throws IOException
+     */
+    private void getRefundOrderListResult(String refundQueryResponseString) throws ParserConfigurationException, SAXException, IOException {
+        List<RefundOrderData> refundOrderList = XMLParser.getRefundOrderList(refundQueryResponseString);
+        int count = 1;
+        for(RefundOrderData refundOrderData : refundOrderList){
+            Util.log("退款订单数据NO" + count + ":");
+            Util.log(refundOrderData.toMap());
+            orderListResult += refundOrderData.toMap().toString();
+            count++;
+        }
+        log.i("查询到的结果如下:");
+        log.i(orderListResult);
+    }
+
+    public void setRefundQueryService(RefundQueryService service) {
+        refundQueryService = service;
+    }
+
+    public String getResult() {
+        return result;
+    }
+
+    public void setResult(String result) {
+        RefundQueryBusiness.result = result;
+    }
+
+    public void setResult(String result,String type){
+        setResult(result);
+        log.log(type,result);
+    }
+
+}

+ 422 - 0
server/tools/src/main/java/com/tencent/business/ScanPayBusiness.java

@@ -0,0 +1,422 @@
+package com.nuliji.tools.third.tencent.business;
+
+import com.tencent.common.Configure;
+import com.tencent.common.Log;
+import com.tencent.common.Signature;
+import com.tencent.common.Util;
+import com.tencent.common.report.ReporterFactory;
+import com.tencent.common.report.protocol.ReportReqData;
+import com.tencent.common.report.service.ReportService;
+import com.tencent.protocol.pay_protocol.ScanPayReqData;
+import com.tencent.protocol.pay_protocol.ScanPayResData;
+import com.tencent.protocol.pay_query_protocol.ScanPayQueryReqData;
+import com.tencent.protocol.pay_query_protocol.ScanPayQueryResData;
+import com.tencent.protocol.reverse_protocol.ReverseReqData;
+import com.tencent.protocol.reverse_protocol.ReverseResData;
+import com.tencent.service.ReverseService;
+import com.tencent.service.ScanPayQueryService;
+import com.tencent.service.ScanPayService;
+import org.slf4j.LoggerFactory;
+
+import static java.lang.Thread.sleep;
+
+/**
+ * User: rizenguo
+ * Date: 2014/12/1
+ * Time: 17:05
+ */
+public class ScanPayBusiness {
+
+    public ScanPayBusiness() throws IllegalAccessException, ClassNotFoundException, InstantiationException {
+        scanPayService = new ScanPayService();
+        scanPayQueryService = new ScanPayQueryService();
+        reverseService = new ReverseService();
+    }
+
+    public interface ResultListener {
+
+        //API返回ReturnCode不合法,支付请求逻辑错误,请仔细检测传过去的每一个参数是否合法,或是看API能否被正常访问
+        void onFailByReturnCodeError(ScanPayResData scanPayResData);
+
+        //API返回ReturnCode为FAIL,支付API系统返回失败,请检测Post给API的数据是否规范合法
+        void onFailByReturnCodeFail(ScanPayResData scanPayResData);
+
+        //支付请求API返回的数据签名验证失败,有可能数据被篡改了
+        void onFailBySignInvalid(ScanPayResData scanPayResData);
+
+
+        //用户用来支付的二维码已经过期,提示收银员重新扫一下用户微信“刷卡”里面的二维码
+        void onFailByAuthCodeExpire(ScanPayResData scanPayResData);
+
+        //授权码无效,提示用户刷新一维码/二维码,之后重新扫码支付"
+        void onFailByAuthCodeInvalid(ScanPayResData scanPayResData);
+
+        //用户余额不足,换其他卡支付或是用现金支付
+        void onFailByMoneyNotEnough(ScanPayResData scanPayResData);
+
+        //支付失败
+        void onFail(ScanPayResData scanPayResData);
+
+        //支付成功
+        void onSuccess(ScanPayResData scanPayResData);
+
+    }
+
+    //打log用
+    private static Log log = new Log(LoggerFactory.getLogger(ScanPayBusiness.class));
+
+    //每次调用订单查询API时的等待时间,因为当出现支付失败的时候,如果马上发起查询不一定就能查到结果,所以这里建议先等待一定时间再发起查询
+
+    private int waitingTimeBeforePayQueryServiceInvoked = 5000;
+
+    //循环调用订单查询API的次数
+    private int payQueryLoopInvokedCount = 3;
+
+    //每次调用撤销API的等待时间
+    private int waitingTimeBeforeReverseServiceInvoked = 5000;
+
+    private ScanPayService scanPayService;
+
+    private ScanPayQueryService scanPayQueryService;
+
+    private ReverseService reverseService;
+
+    /**
+     * 直接执行被扫支付业务逻辑(包含最佳实践流程)
+     *
+     * @param scanPayReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @param resultListener 商户需要自己监听被扫支付业务逻辑可能触发的各种分支事件,并做好合理的响应处理
+     * @throws Exception
+     */
+    public void run(ScanPayReqData scanPayReqData, ResultListener resultListener) throws Exception {
+
+        //--------------------------------------------------------------------
+        //构造请求“被扫支付API”所需要提交的数据
+        //--------------------------------------------------------------------
+
+        String outTradeNo = scanPayReqData.getOut_trade_no();
+
+        //接受API返回
+        String payServiceResponseString;
+
+        long costTimeStart = System.currentTimeMillis();
+
+
+        log.i("支付API返回的数据如下:");
+        payServiceResponseString = scanPayService.request(scanPayReqData);
+
+        long costTimeEnd = System.currentTimeMillis();
+        long totalTimeCost = costTimeEnd - costTimeStart;
+        log.i("api请求总耗时:" + totalTimeCost + "ms");
+
+        //打印回包数据
+        log.i(payServiceResponseString);
+
+        //将从API返回的XML数据映射到Java对象
+        ScanPayResData scanPayResData = (ScanPayResData) Util.getObjectFromXML(payServiceResponseString, ScanPayResData.class);
+
+        //异步发送统计请求
+        //*
+
+        ReportReqData reportReqData = new ReportReqData(
+                scanPayReqData.getDevice_info(),
+                Configure.PAY_API,
+                (int) (totalTimeCost),//本次请求耗时
+                scanPayResData.getReturn_code(),
+                scanPayResData.getReturn_msg(),
+                scanPayResData.getResult_code(),
+                scanPayResData.getErr_code(),
+                scanPayResData.getErr_code_des(),
+                scanPayResData.getOut_trade_no(),
+                scanPayReqData.getSpbill_create_ip()
+        );
+        long timeAfterReport;
+        if (Configure.isUseThreadToDoReport()) {
+            ReporterFactory.getReporter(reportReqData).run();
+            timeAfterReport = System.currentTimeMillis();
+            log.i("pay+report总耗时(异步方式上报):" + (timeAfterReport - costTimeStart) + "ms");
+        } else {
+            ReportService.request(reportReqData);
+            timeAfterReport = System.currentTimeMillis();
+            log.i("pay+report总耗时(同步方式上报):" + (timeAfterReport - costTimeStart) + "ms");
+        }
+
+        if (scanPayResData == null || scanPayResData.getReturn_code() == null) {
+            log.e("【支付失败】支付请求逻辑错误,请仔细检测传过去的每一个参数是否合法,或是看API能否被正常访问");
+            resultListener.onFailByReturnCodeError(scanPayResData);
+            return;
+        }
+
+        if (scanPayResData.getReturn_code().equals("FAIL")) {
+            //注意:一般这里返回FAIL是出现系统级参数错误,请检测Post给API的数据是否规范合法
+            log.e("【支付失败】支付API系统返回失败,请检测Post给API的数据是否规范合法");
+            resultListener.onFailByReturnCodeFail(scanPayResData);
+            return;
+        } else {
+            log.i("支付API系统成功返回数据");
+            //--------------------------------------------------------------------
+            //收到API的返回数据的时候得先验证一下数据有没有被第三方篡改,确保安全
+            //--------------------------------------------------------------------
+            if (!Signature.checkIsSignValidFromResponseString(payServiceResponseString)) {
+                log.e("【支付失败】支付请求API返回的数据签名验证失败,有可能数据被篡改了");
+                resultListener.onFailBySignInvalid(scanPayResData);
+                return;
+            }
+
+            //获取错误码
+            String errorCode = scanPayResData.getErr_code();
+            //获取错误描述
+            String errorCodeDes = scanPayResData.getErr_code_des();
+
+            if (scanPayResData.getResult_code().equals("SUCCESS")) {
+
+                //--------------------------------------------------------------------
+                //1)直接扣款成功
+                //--------------------------------------------------------------------
+
+                log.i("【一次性支付成功】");
+                resultListener.onSuccess(scanPayResData);
+            }else{
+
+                //出现业务错误
+                log.i("业务返回失败");
+                log.i("err_code:" + errorCode);
+                log.i("err_code_des:" + errorCodeDes);
+
+                //业务错误时错误码有好几种,商户重点提示以下几种
+                if (errorCode.equals("AUTHCODEEXPIRE") || errorCode.equals("AUTH_CODE_INVALID") || errorCode.equals("NOTENOUGH")) {
+
+                    //--------------------------------------------------------------------
+                    //2)扣款明确失败
+                    //--------------------------------------------------------------------
+
+                    //对于扣款明确失败的情况直接走撤销逻辑
+                    doReverseLoop(outTradeNo);
+
+                    //以下几种情况建议明确提示用户,指导接下来的工作
+                    if (errorCode.equals("AUTHCODEEXPIRE")) {
+                        //表示用户用来支付的二维码已经过期,提示收银员重新扫一下用户微信“刷卡”里面的二维码
+                        log.w("【支付扣款明确失败】原因是:" + errorCodeDes);
+                        resultListener.onFailByAuthCodeExpire(scanPayResData);
+                    } else if (errorCode.equals("AUTH_CODE_INVALID")) {
+                        //授权码无效,提示用户刷新一维码/二维码,之后重新扫码支付
+                        log.w("【支付扣款明确失败】原因是:" + errorCodeDes);
+                        resultListener.onFailByAuthCodeInvalid(scanPayResData);
+                    } else if (errorCode.equals("NOTENOUGH")) {
+                        //提示用户余额不足,换其他卡支付或是用现金支付
+                        log.w("【支付扣款明确失败】原因是:" + errorCodeDes);
+                        resultListener.onFailByMoneyNotEnough(scanPayResData);
+                    }
+                } else if (errorCode.equals("USERPAYING")) {
+
+                    //--------------------------------------------------------------------
+                    //3)需要输入密码
+                    //--------------------------------------------------------------------
+
+                    //表示有可能单次消费超过300元,或是免输密码消费次数已经超过当天的最大限制,这个时候提示用户输入密码,商户自己隔一段时间去查单,查询一定次数,看用户是否已经输入了密码
+                    if (doPayQueryLoop(payQueryLoopInvokedCount, outTradeNo)) {
+                        log.i("【需要用户输入密码、查询到支付成功】");
+                        resultListener.onSuccess(scanPayResData);
+                    } else {
+                        log.i("【需要用户输入密码、在一定时间内没有查询到支付成功、走撤销流程】");
+                        doReverseLoop(outTradeNo);
+                        resultListener.onFail(scanPayResData);
+                    }
+                } else {
+
+                    //--------------------------------------------------------------------
+                    //4)扣款未知失败
+                    //--------------------------------------------------------------------
+
+                    if (doPayQueryLoop(payQueryLoopInvokedCount, outTradeNo)) {
+                        log.i("【支付扣款未知失败、查询到支付成功】");
+                        resultListener.onSuccess(scanPayResData);
+                    } else {
+                        log.i("【支付扣款未知失败、在一定时间内没有查询到支付成功、走撤销流程】");
+                        doReverseLoop(outTradeNo);
+                        resultListener.onFail(scanPayResData);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * 进行一次支付订单查询操作
+     *
+     * @param outTradeNo    商户系统内部的订单号,32个字符内可包含字母, [确保在商户系统唯一]
+     * @return 该订单是否支付成功
+     * @throws Exception
+     */
+    private boolean doOnePayQuery(String outTradeNo) throws Exception {
+
+        sleep(waitingTimeBeforePayQueryServiceInvoked);//等待一定时间再进行查询,避免状态还没来得及被更新
+
+        String payQueryServiceResponseString;
+
+        ScanPayQueryReqData scanPayQueryReqData = new ScanPayQueryReqData("",outTradeNo);
+        payQueryServiceResponseString = scanPayQueryService.request(scanPayQueryReqData);
+
+        log.i("支付订单查询API返回的数据如下:");
+        log.i(payQueryServiceResponseString);
+
+        //将从API返回的XML数据映射到Java对象
+        ScanPayQueryResData scanPayQueryResData = (ScanPayQueryResData) Util.getObjectFromXML(payQueryServiceResponseString, ScanPayQueryResData.class);
+        if (scanPayQueryResData == null || scanPayQueryResData.getReturn_code() == null) {
+            log.i("支付订单查询请求逻辑错误,请仔细检测传过去的每一个参数是否合法");
+            return false;
+        }
+
+        if (scanPayQueryResData.getReturn_code().equals("FAIL")) {
+            //注意:一般这里返回FAIL是出现系统级参数错误,请检测Post给API的数据是否规范合法
+            log.i("支付订单查询API系统返回失败,失败信息为:" + scanPayQueryResData.getReturn_msg());
+            return false;
+        } else {
+            if (scanPayQueryResData.getResult_code().equals("SUCCESS")) {//业务层成功
+                if (scanPayQueryResData.getTrade_state().equals("SUCCESS")) {
+                    //表示查单结果为“支付成功”
+                    log.i("查询到订单支付成功");
+                    return true;
+                } else {
+                    //支付不成功
+                    log.i("查询到订单支付不成功");
+                    return false;
+                }
+            } else {
+                log.i("查询出错,错误码:" + scanPayQueryResData.getErr_code() + "     错误信息:" + scanPayQueryResData.getErr_code_des());
+                return false;
+            }
+        }
+    }
+
+    /**
+     * 由于有的时候是因为服务延时,所以需要商户每隔一段时间(建议5秒)后再进行查询操作,多试几次(建议3次)
+     *
+     * @param loopCount     循环次数,至少一次
+     * @param outTradeNo    商户系统内部的订单号,32个字符内可包含字母, [确保在商户系统唯一]
+     * @return 该订单是否支付成功
+     * @throws InterruptedException
+     */
+    private boolean doPayQueryLoop(int loopCount, String outTradeNo) throws Exception {
+        //至少查询一次
+        if (loopCount == 0) {
+            loopCount = 1;
+        }
+        //进行循环查询
+        for (int i = 0; i < loopCount; i++) {
+            if (doOnePayQuery(outTradeNo)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    //是否需要再调一次撤销,这个值由撤销API回包的recall字段决定
+    private boolean needRecallReverse = false;
+
+    /**
+     * 进行一次撤销操作
+     *
+     * @param outTradeNo    商户系统内部的订单号,32个字符内可包含字母, [确保在商户系统唯一]
+     * @return 该订单是否支付成功
+     * @throws Exception
+     */
+    private boolean doOneReverse(String outTradeNo) throws Exception {
+
+        sleep(waitingTimeBeforeReverseServiceInvoked);//等待一定时间再进行查询,避免状态还没来得及被更新
+
+        String reverseResponseString;
+
+        ReverseReqData reverseReqData = new ReverseReqData("",outTradeNo);
+        reverseResponseString = reverseService.request(reverseReqData);
+
+        log.i("撤销API返回的数据如下:");
+        log.i(reverseResponseString);
+        //将从API返回的XML数据映射到Java对象
+        ReverseResData reverseResData = (ReverseResData) Util.getObjectFromXML(reverseResponseString, ReverseResData.class);
+        if (reverseResData == null) {
+            log.i("支付订单撤销请求逻辑错误,请仔细检测传过去的每一个参数是否合法");
+            return false;
+        }
+        if (reverseResData.getReturn_code().equals("FAIL")) {
+            //注意:一般这里返回FAIL是出现系统级参数错误,请检测Post给API的数据是否规范合法
+            log.i("支付订单撤销API系统返回失败,失败信息为:" + reverseResData.getReturn_msg());
+            return false;
+        } else {
+            if (reverseResData.getResult_code().equals("FAIL")) {
+                log.i("撤销出错,错误码:" + reverseResData.getErr_code() + "     错误信息:" + reverseResData.getErr_code_des());
+                if (reverseResData.getRecall().equals("Y")) {
+                    //表示需要重试
+                    needRecallReverse = true;
+                    return false;
+                } else {
+                    //表示不需要重试,也可以当作是撤销成功
+                    needRecallReverse = false;
+                    return true;
+                }
+            } else {
+                //查询成功,打印交易状态
+                log.i("支付订单撤销成功");
+                return true;
+            }
+        }
+    }
+
+
+    /**
+     * 由于有的时候是因为服务延时,所以需要商户每隔一段时间(建议5秒)后再进行查询操作,是否需要继续循环调用撤销API由撤销API回包里面的recall字段决定。
+     *
+     * @param outTradeNo    商户系统内部的订单号,32个字符内可包含字母, [确保在商户系统唯一]
+     * @throws InterruptedException
+     */
+    private void doReverseLoop(String outTradeNo) throws Exception {
+        //初始化这个标记
+        needRecallReverse = true;
+        //进行循环撤销,直到撤销成功,或是API返回recall字段为"Y"
+        while (needRecallReverse) {
+            if (doOneReverse(outTradeNo)) {
+                return;
+            }
+        }
+    }
+
+    /**
+     * 设置循环多次调用订单查询API的时间间隔
+     *
+     * @param duration 时间间隔,默认为10秒
+     */
+    public void setWaitingTimeBeforePayQueryServiceInvoked(int duration) {
+        waitingTimeBeforePayQueryServiceInvoked = duration;
+    }
+
+    /**
+     * 设置循环多次调用订单查询API的次数
+     *
+     * @param count 调用次数,默认为三次
+     */
+    public void setPayQueryLoopInvokedCount(int count) {
+        payQueryLoopInvokedCount = count;
+    }
+
+    /**
+     * 设置循环多次调用撤销API的时间间隔
+     *
+     * @param duration 时间间隔,默认为5秒
+     */
+    public void setWaitingTimeBeforeReverseServiceInvoked(int duration) {
+        waitingTimeBeforeReverseServiceInvoked = duration;
+    }
+
+    public void setScanPayService(ScanPayService service) {
+        scanPayService = service;
+    }
+
+    public void setScanPayQueryService(ScanPayQueryService service) {
+        scanPayQueryService = service;
+    }
+
+    public void setReverseService(ReverseService service) {
+        reverseService = service;
+    }
+
+}

+ 170 - 0
server/tools/src/main/java/com/tencent/business/UnifiedOrderBusiness.java

@@ -0,0 +1,170 @@
+package com.nuliji.tools.third.tencent.business;
+
+import com.tencent.common.Configure;
+import com.tencent.common.Log;
+import com.tencent.common.Signature;
+import com.tencent.common.Util;
+import com.tencent.common.report.ReporterFactory;
+import com.tencent.common.report.protocol.ReportReqData;
+import com.tencent.common.report.service.ReportService;
+import com.tencent.protocol.pay_protocol.UnifiedOrderReqData;
+import com.tencent.protocol.pay_protocol.UnifiedOrderResData;
+import com.tencent.service.UnifiedOrderService;
+import org.slf4j.LoggerFactory;
+
+/**
+ * User: gaojie
+ * Date: 2017/05/10
+ * Time: 16:42
+ */
+public class UnifiedOrderBusiness {
+
+    public UnifiedOrderBusiness() throws IllegalAccessException, ClassNotFoundException, InstantiationException {
+        unifiedOrderService = new UnifiedOrderService();
+    }
+
+    public interface ResultListener {
+
+        //API返回ReturnCode不合法,支付请求逻辑错误,请仔细检测传过去的每一个参数是否合法,或是看API能否被正常访问
+        void onFailByReturnCodeError(UnifiedOrderResData unifiedOrderResData);
+
+        //API返回ReturnCode为FAIL,支付API系统返回失败,请检测Post给API的数据是否规范合法
+        void onFailByReturnCodeFail(UnifiedOrderResData unifiedOrderResData);
+
+        //支付请求API返回的数据签名验证失败,有可能数据被篡改了
+        void onFailBySignInvalid(UnifiedOrderResData unifiedOrderResData);
+
+
+        //用户用来支付的二维码已经过期,提示收银员重新扫一下用户微信“刷卡”里面的二维码
+        void onFailByAuthCodeExpire(UnifiedOrderResData unifiedOrderResData);
+
+        //授权码无效,提示用户刷新一维码/二维码,之后重新扫码支付"
+        void onFailByAuthCodeInvalid(UnifiedOrderResData unifiedOrderResData);
+
+        //用户余额不足,换其他卡支付或是用现金支付
+        void onFailByMoneyNotEnough(UnifiedOrderResData unifiedOrderResData);
+
+        //支付失败
+        void onFail(UnifiedOrderResData unifiedOrderResData);
+
+        //支付成功
+        void onSuccess(UnifiedOrderResData unifiedOrderResData);
+
+    }
+
+    //打log用
+    private static Log log = new Log(LoggerFactory.getLogger(UnifiedOrderBusiness.class));
+
+    private UnifiedOrderService unifiedOrderService;
+
+    /**
+     * 直接执行被扫支付业务逻辑(包含最佳实践流程)
+     *
+     * @param unifiedOrderReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @param resultListener 商户需要自己监听被扫支付业务逻辑可能触发的各种分支事件,并做好合理的响应处理
+     * @throws Exception
+     */
+    public void run(UnifiedOrderReqData unifiedOrderReqData, ResultListener resultListener) throws Exception {
+
+        //--------------------------------------------------------------------
+        //构造请求“被扫支付API”所需要提交的数据
+        //--------------------------------------------------------------------
+
+        String outTradeNo = unifiedOrderReqData.getOut_trade_no();
+
+        //接受API返回
+        String payServiceResponseString;
+
+        long costTimeStart = System.currentTimeMillis();
+
+
+        log.i("支付API返回的数据如下:");
+        payServiceResponseString = unifiedOrderService.request(unifiedOrderReqData);
+
+        long costTimeEnd = System.currentTimeMillis();
+        long totalTimeCost = costTimeEnd - costTimeStart;
+        log.i("api请求总耗时:" + totalTimeCost + "ms");
+
+        //打印回包数据
+        log.i(payServiceResponseString);
+
+        //将从API返回的XML数据映射到Java对象
+        UnifiedOrderResData unifiedOrderResData = (UnifiedOrderResData) Util.getObjectFromXML(payServiceResponseString, UnifiedOrderResData.class);
+
+        //异步发送统计请求
+        //*
+
+        ReportReqData reportReqData = new ReportReqData(
+                unifiedOrderResData.getDevice_info(),
+                Configure.UNIFIED_ORDER_API,
+                (int) (totalTimeCost),//本次请求耗时
+                unifiedOrderResData.getReturn_code(),
+                unifiedOrderResData.getReturn_msg(),
+                unifiedOrderResData.getResult_code(),
+                unifiedOrderResData.getErr_code(),
+                unifiedOrderResData.getErr_code_des(),
+                "",
+                unifiedOrderReqData.getSpbill_create_ip()
+        );
+        long timeAfterReport;
+        if (Configure.isUseThreadToDoReport()) {
+            ReporterFactory.getReporter(reportReqData).run();
+            timeAfterReport = System.currentTimeMillis();
+            log.i("pay+report总耗时(异步方式上报):" + (timeAfterReport - costTimeStart) + "ms");
+        } else {
+            ReportService.request(reportReqData);
+            timeAfterReport = System.currentTimeMillis();
+            log.i("pay+report总耗时(同步方式上报):" + (timeAfterReport - costTimeStart) + "ms");
+        }
+
+        if (unifiedOrderResData == null || unifiedOrderResData.getReturn_code() == null) {
+            log.e("【支付失败】支付请求逻辑错误,请仔细检测传过去的每一个参数是否合法,或是看API能否被正常访问");
+            resultListener.onFailByReturnCodeError(unifiedOrderResData);
+            return;
+        }
+
+        if (unifiedOrderResData.getReturn_code().equals("FAIL")) {
+            //注意:一般这里返回FAIL是出现系统级参数错误,请检测Post给API的数据是否规范合法
+            log.e("【支付失败】支付API系统返回失败,请检测Post给API的数据是否规范合法");
+            resultListener.onFailByReturnCodeFail(unifiedOrderResData);
+            return;
+        } else {
+            log.i("支付API系统成功返回数据");
+            //--------------------------------------------------------------------
+            //收到API的返回数据的时候得先验证一下数据有没有被第三方篡改,确保安全
+            //--------------------------------------------------------------------
+            if (!Signature.checkIsSignValidFromResponseString(payServiceResponseString)) {
+                log.e("【支付失败】支付请求API返回的数据签名验证失败,有可能数据被篡改了");
+                resultListener.onFailBySignInvalid(unifiedOrderResData);
+                return;
+            }
+
+            //获取错误码
+            String errorCode = unifiedOrderResData.getErr_code();
+            //获取错误描述
+            String errorCodeDes = unifiedOrderResData.getErr_code_des();
+
+            if (unifiedOrderResData.getResult_code().equals("SUCCESS")) {
+
+                //--------------------------------------------------------------------
+                //1)直接扣款成功
+                //--------------------------------------------------------------------
+
+                log.i("【提交成功】");
+                resultListener.onSuccess(unifiedOrderResData);
+            }else{
+
+                //出现业务错误
+                log.i("业务返回失败");
+                log.i("err_code:" + errorCode);
+                log.i("err_code_des:" + errorCodeDes);
+            }
+        }
+    }
+
+    public void setScanPayService(UnifiedOrderService service) {
+        unifiedOrderService = service;
+    }
+
+
+}

+ 132 - 0
server/tools/src/main/java/com/tencent/common/Configure.java

@@ -0,0 +1,132 @@
+package com.nuliji.tools.third.tencent.common;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/29
+ * Time: 14:40
+ * 这里放置各种配置数据
+ */
+public class Configure {
+//这个就是自己要保管好的私有Key了(切记只能放在自己的后台代码里,不能放在任何可能被看到源代码的客户端程序中)
+	// 每次自己Post数据给API的时候都要用这个key来对所有字段进行签名,生成的签名会放在Sign这个字段,API收到Post数据的时候也会用同样的签名算法对Post过来的数据进行签名和验证
+	// 收到API的返回的时候也要用这个key来对返回的数据算下签名,跟API的Sign数据进行比较,如果值不一致,有可能数据被第三方给篡改
+
+	private static String key = "";
+
+	//微信分配的公众号ID(开通公众号之后可以获取到)
+	private static String appID = "";
+
+	//微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到)
+	private static String mchID = "";
+
+	//受理模式下给子商户分配的子商户号
+	private static String subMchID = "";
+
+	//HTTPS证书的本地路径
+	private static String certLocalPath = "";
+
+	//HTTPS证书密码,默认密码等于商户号MCHID
+	private static String certPassword = "";
+
+	//是否使用异步线程的方式来上报API测速,默认为异步模式
+	private static boolean useThreadToDoReport = true;
+
+	//机器IP
+	private static String ip = "";
+
+	//以下是几个API的路径:
+	//1)被扫支付API
+	public static String PAY_API = "https://api.mch.weixin.qq.com/pay/micropay";
+
+	//2)被扫支付查询API
+	public static String PAY_QUERY_API = "https://api.mch.weixin.qq.com/pay/orderquery";
+
+	//3)退款API
+	public static String REFUND_API = "https://api.mch.weixin.qq.com/secapi/pay/refund";
+
+	//4)退款查询API
+	public static String REFUND_QUERY_API = "https://api.mch.weixin.qq.com/pay/refundquery";
+
+	//5)撤销API
+	public static String REVERSE_API = "https://api.mch.weixin.qq.com/secapi/pay/reverse";
+
+	//6)下载对账单API
+	public static String DOWNLOAD_BILL_API = "https://api.mch.weixin.qq.com/pay/downloadbill";
+
+	//7) 统计上报API
+	public static String REPORT_API = "https://api.mch.weixin.qq.com/payitil/report";
+
+	//8) 统一下单API
+	public static String UNIFIED_ORDER_API = "https://api.mch.weixin.qq.com/pay/unifiedorder";
+
+	public static boolean isUseThreadToDoReport() {
+		return useThreadToDoReport;
+	}
+
+	public static void setUseThreadToDoReport(boolean useThreadToDoReport) {
+		Configure.useThreadToDoReport = useThreadToDoReport;
+	}
+
+	public static String HttpsRequestClassName = "com.tencent.common.HttpsRequest";
+
+	public static void setKey(String key) {
+		Configure.key = key;
+	}
+
+	public static void setAppID(String appID) {
+		Configure.appID = appID;
+	}
+
+	public static void setMchID(String mchID) {
+		Configure.mchID = mchID;
+	}
+
+	public static void setSubMchID(String subMchID) {
+		Configure.subMchID = subMchID;
+	}
+
+	public static void setCertLocalPath(String certLocalPath) {
+		Configure.certLocalPath = certLocalPath;
+	}
+
+	public static void setCertPassword(String certPassword) {
+		Configure.certPassword = certPassword;
+	}
+
+	public static void setIp(String ip) {
+		Configure.ip = ip;
+	}
+
+	public static String getKey(){
+		return key;
+	}
+	
+	public static String getAppid(){
+		return appID;
+	}
+	
+	public static String getMchid(){
+		return mchID;
+	}
+
+	public static String getSubMchid(){
+		return subMchID;
+	}
+	
+	public static String getCertLocalPath(){
+		return certLocalPath;
+	}
+	
+	public static String getCertPassword(){
+		return certPassword;
+	}
+
+	public static String getIP(){
+		return ip;
+	}
+
+	public static void setHttpsRequestClassName(String name){
+		HttpsRequestClassName = name;
+	}
+
+}

+ 196 - 0
server/tools/src/main/java/com/tencent/common/HttpsRequest.java

@@ -0,0 +1,196 @@
+package com.nuliji.tools.third.tencent.common;
+
+import com.tencent.service.IServiceRequest;
+import com.thoughtworks.xstream.XStream;
+import com.thoughtworks.xstream.io.xml.DomDriver;
+import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.conn.ConnectTimeoutException;
+import org.apache.http.conn.ConnectionPoolTimeoutException;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.net.SocketTimeoutException;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/29
+ * Time: 14:36
+ */
+public class HttpsRequest implements IServiceRequest{
+
+    public interface ResultListener {
+
+
+        public void onConnectionPoolTimeoutError();
+
+    }
+
+    private static Log log = new Log(LoggerFactory.getLogger(HttpsRequest.class));
+
+    //表示请求器是否已经做了初始化工作
+    private boolean hasInit = false;
+
+    //连接超时时间,默认10秒
+    private int socketTimeout = 10000;
+
+    //传输超时时间,默认30秒
+    private int connectTimeout = 30000;
+
+    //请求器的配置
+    private RequestConfig requestConfig;
+
+    //HTTP请求器
+    private CloseableHttpClient httpClient;
+
+    public HttpsRequest() throws UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException {
+        init();
+    }
+
+    private void init() throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException {
+
+//        KeyStore keyStore = KeyStore.getInstance("PKCS12");
+//        FileInputStream instream = new FileInputStream(new File(Configure.getCertLocalPath()));//加载本地的证书进行https加密传输
+//        try {
+//            keyStore.load(instream, Configure.getCertPassword().toCharArray());//设置证书密码
+//        } catch (CertificateException e) {
+//            e.printStackTrace();
+//        } catch (NoSuchAlgorithmException e) {
+//            e.printStackTrace();
+//        } finally {
+//            instream.close();
+//        }
+//
+//        // Trust own CA and all self-signed certs
+//        SSLContext sslcontext = SSLContexts.custom()
+//                .loadKeyMaterial(keyStore, Configure.getCertPassword().toCharArray())
+//                .build();
+//        // Allow TLSv1 protocol only
+//        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
+//                sslcontext,
+//                new String[]{"TLSv1"},
+//                null,
+//                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
+
+        httpClient = HttpClients.custom()
+//                .setSSLSocketFactory(sslsf)
+                .build();
+
+        //根据默认超时限制初始化requestConfig
+        requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();
+
+        hasInit = true;
+    }
+
+    /**
+     * 通过Https往API post xml数据
+     *
+     * @param url    API地址
+     * @param xmlObj 要提交的XML数据对象
+     * @return API回包的实际数据
+     * @throws IOException
+     * @throws KeyStoreException
+     * @throws UnrecoverableKeyException
+     * @throws NoSuchAlgorithmException
+     * @throws KeyManagementException
+     */
+
+    public String sendPost(String url, Object xmlObj) throws IOException, KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, KeyManagementException {
+
+        if (!hasInit) {
+            init();
+        }
+
+        String result = null;
+
+        HttpPost httpPost = new HttpPost(url);
+
+        //解决XStream对出现双下划线的bug
+        XStream xStreamForRequestPostData = new XStream(new DomDriver("UTF-8", new XmlFriendlyNameCoder("-_", "_")));
+
+        //将要提交给API的数据对象转换成XML格式数据Post给API
+        String postDataXML = xStreamForRequestPostData.toXML(xmlObj);
+
+        Util.log("API,POST过去的数据是:");
+        Util.log(postDataXML);
+
+        //得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别
+        StringEntity postEntity = new StringEntity(postDataXML, "UTF-8");
+        httpPost.addHeader("Content-Type", "text/xml");
+        httpPost.setEntity(postEntity);
+
+        //设置请求器的配置
+        httpPost.setConfig(requestConfig);
+
+        Util.log("executing request" + httpPost.getRequestLine());
+
+        try {
+            HttpResponse response = httpClient.execute(httpPost);
+
+            HttpEntity entity = response.getEntity();
+
+            result = EntityUtils.toString(entity, "UTF-8");
+
+        } catch (ConnectionPoolTimeoutException e) {
+            log.e("http get throw ConnectionPoolTimeoutException(wait time out)");
+
+        } catch (ConnectTimeoutException e) {
+            log.e("http get throw ConnectTimeoutException");
+
+        } catch (SocketTimeoutException e) {
+            log.e("http get throw SocketTimeoutException");
+
+        } catch (Exception e) {
+            log.e("http get throw Exception");
+
+        } finally {
+            httpPost.abort();
+        }
+
+        return result;
+    }
+
+    /**
+     * 设置连接超时时间
+     *
+     * @param socketTimeout 连接时长,默认10秒
+     */
+    public void setSocketTimeout(int socketTimeout) {
+        socketTimeout = socketTimeout;
+        resetRequestConfig();
+    }
+
+    /**
+     * 设置传输超时时间
+     *
+     * @param connectTimeout 传输时长,默认30秒
+     */
+    public void setConnectTimeout(int connectTimeout) {
+        connectTimeout = connectTimeout;
+        resetRequestConfig();
+    }
+
+    private void resetRequestConfig(){
+        requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();
+    }
+
+    /**
+     * 允许商户自己做更高级更复杂的请求器配置
+     *
+     * @param requestConfig 设置HttpsRequest的请求器配置
+     */
+    public void setRequestConfig(RequestConfig requestConfig) {
+        requestConfig = requestConfig;
+    }
+}

+ 59 - 0
server/tools/src/main/java/com/tencent/common/Log.java

@@ -0,0 +1,59 @@
+package com.nuliji.tools.third.tencent.common;
+
+import org.slf4j.Logger;
+
+/**
+ * User: rizenguo
+ * Date: 2014/11/12
+ * Time: 14:32
+ */
+public class Log {
+
+    public static final String LOG_TYPE_TRACE = "logTypeTrace";
+    public static final String LOG_TYPE_DEBUG = "logTypeDebug";
+    public static final String LOG_TYPE_INFO = "logTypeInfo";
+    public static final String LOG_TYPE_WARN = "logTypeWarn";
+    public static final String LOG_TYPE_ERROR = "logTypeError";
+
+    //打印日志
+    private Logger logger;
+
+    public Log(Logger log){
+        logger = log;
+    }
+
+    public void t(String s){
+        logger.trace(s);
+    }
+
+    public void d(String s){
+        logger.debug(s);
+    }
+
+    public void i(String s){
+        logger.info(s);
+    }
+
+    public void w(String s){
+        logger.warn(s);
+    }
+
+    public void e(String s){
+        logger.error(s);
+    }
+
+    public void log(String type,String s){
+        if(type.equals(Log.LOG_TYPE_TRACE)){
+            t(s);
+        }else if(type.equals(Log.LOG_TYPE_DEBUG)){
+            d(s);
+        }else if(type.equals(Log.LOG_TYPE_INFO)){
+            i(s);
+        }else if(type.equals(Log.LOG_TYPE_WARN)){
+            w(s);
+        }else if(type.equals(Log.LOG_TYPE_ERROR)){
+            e(s);
+        }
+    }
+
+}

+ 59 - 0
server/tools/src/main/java/com/tencent/common/MD5.java

@@ -0,0 +1,59 @@
+package com.nuliji.tools.third.tencent.common;
+
+import java.security.MessageDigest;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/23
+ * Time: 15:43
+ */
+public class MD5 {
+    private final static String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7",
+            "8", "9", "a", "b", "c", "d", "e", "f"};
+
+    /**
+     * 转换字节数组为16进制字串
+     * @param b 字节数组
+     * @return 16进制字串
+     */
+    public static String byteArrayToHexString(byte[] b) {
+        StringBuilder resultSb = new StringBuilder();
+        for (byte aB : b) {
+            resultSb.append(byteToHexString(aB));
+        }
+        return resultSb.toString();
+    }
+
+    /**
+     * 转换byte到16进制
+     * @param b 要转换的byte
+     * @return 16进制格式
+     */
+    private static String byteToHexString(byte b) {
+        int n = b;
+        if (n < 0) {
+            n = 256 + n;
+        }
+        int d1 = n / 16;
+        int d2 = n % 16;
+        return hexDigits[d1] + hexDigits[d2];
+    }
+
+    /**
+     * MD5编码
+     * @param origin 原始字符串
+     * @return 经过MD5加密之后的结果
+     */
+    public static String MD5Encode(String origin) {
+        String resultString = null;
+        try {
+            resultString = origin;
+            MessageDigest md = MessageDigest.getInstance("MD5");
+            resultString = byteArrayToHexString(md.digest(resultString.getBytes("utf-8")));
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return resultString;
+    }
+
+}

+ 28 - 0
server/tools/src/main/java/com/tencent/common/RandomStringGenerator.java

@@ -0,0 +1,28 @@
+package com.nuliji.tools.third.tencent.common;
+
+import java.util.Random;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/29
+ * Time: 14:18
+ */
+public class RandomStringGenerator {
+
+    /**
+     * 获取一定长度的随机字符串
+     * @param length 指定字符串长度
+     * @return 一定长度的字符串
+     */
+    public static String getRandomStringByLength(int length) {
+        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
+        Random random = new Random();
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0; i < length; i++) {
+            int number = random.nextInt(base.length());
+            sb.append(base.charAt(number));
+        }
+        return sb.toString();
+    }
+
+}

+ 120 - 0
server/tools/src/main/java/com/tencent/common/Signature.java

@@ -0,0 +1,120 @@
+package com.nuliji.tools.third.tencent.common;
+
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Map;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/29
+ * Time: 15:23
+ */
+public class Signature {
+    /**
+     * 签名算法
+     * @param o 要参与签名的数据对象
+     * @return 签名
+     * @throws IllegalAccessException
+     */
+    public static String getSign(Object o) throws IllegalAccessException {
+        ArrayList<String> list = new ArrayList<String>();
+        Class cls = o.getClass();
+        Field[] fields = cls.getDeclaredFields();
+        for (Field f : fields) {
+            f.setAccessible(true);
+            if (f.get(o) != null && f.get(o) != "") {
+                list.add(f.getName() + "=" + f.get(o) + "&");
+            }
+        }
+        int size = list.size();
+        String [] arrayToSort = list.toArray(new String[size]);
+        Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
+        StringBuilder sb = new StringBuilder();
+        for(int i = 0; i < size; i ++) {
+            sb.append(arrayToSort[i]);
+        }
+        String result = sb.toString();
+        result += "key=" + Configure.getKey();
+        Util.log("Sign Before MD5:" + result);
+        result = MD5.MD5Encode(result).toUpperCase();
+        Util.log("Sign Result:" + result);
+        return result;
+    }
+
+    public static String getSign(Map<String,Object> map){
+        ArrayList<String> list = new ArrayList<String>();
+        for(Map.Entry<String,Object> entry:map.entrySet()){
+            if(entry.getValue()!=""){
+                list.add(entry.getKey() + "=" + entry.getValue().toString().trim() + "&");
+            }
+        }
+        int size = list.size();
+        String [] arrayToSort = list.toArray(new String[size]);
+        Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
+        StringBuilder sb = new StringBuilder();
+        for(int i = 0; i < size; i ++) {
+            sb.append(arrayToSort[i]);
+        }
+        String result = sb.toString();
+        result += "key=" + Configure.getKey();
+        Util.log("Sign Before MD5:" + result);
+        result = MD5.MD5Encode(result).toUpperCase();
+        Util.log("Sign Result:" + result);
+        return result;
+    }
+
+    /**
+     * 从API返回的XML数据里面重新计算一次签名
+     * @param responseString API返回的XML数据
+     * @return 新鲜出炉的签名
+     * @throws ParserConfigurationException
+     * @throws IOException
+     * @throws SAXException
+     */
+    public static String getSignFromResponseString(String responseString) throws IOException, SAXException, ParserConfigurationException {
+        Map<String,Object> map = XMLParser.getMapFromXML(responseString);
+        //清掉返回数据对象里面的Sign数据(不能把这个数据也加进去进行签名),然后用签名算法进行签名
+        map.put("sign","");
+        //将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较
+        return Signature.getSign(map);
+    }
+
+    /**
+     * 检验API返回的数据里面的签名是否合法,避免数据在传输的过程中被第三方篡改
+     * @param responseString API返回的XML数据字符串
+     * @return API签名是否合法
+     * @throws ParserConfigurationException
+     * @throws IOException
+     * @throws SAXException
+     */
+    public static boolean checkIsSignValidFromResponseString(String responseString) throws ParserConfigurationException, IOException, SAXException {
+
+        Map<String,Object> map = XMLParser.getMapFromXML(responseString);
+        Util.log(map.toString());
+
+        String signFromAPIResponse = map.get("sign").toString();
+        if(signFromAPIResponse=="" || signFromAPIResponse == null){
+            Util.log("API返回的数据签名数据不存在,有可能被第三方篡改!!!");
+            return false;
+        }
+        Util.log("服务器回包里面的签名是:" + signFromAPIResponse);
+        //清掉返回数据对象里面的Sign数据(不能把这个数据也加进去进行签名),然后用签名算法进行签名
+        map.put("sign","");
+        //将API返回的数据根据用签名算法进行计算新的签名,用来跟API返回的签名进行比较
+        String signForAPIResponse = Signature.getSign(map);
+
+        if(!signForAPIResponse.equals(signFromAPIResponse)){
+            //签名验不过,表示这个API返回的数据有可能已经被篡改了
+            Util.log("API返回的数据签名验证不通过,有可能被第三方篡改!!!");
+            return false;
+        }
+        Util.log("恭喜,API返回的数据签名验证通过!!!");
+        return true;
+    }
+
+}

+ 120 - 0
server/tools/src/main/java/com/tencent/common/Util.java

@@ -0,0 +1,120 @@
+package com.nuliji.tools.third.tencent.common;
+
+import com.thoughtworks.xstream.XStream;
+import org.slf4j.LoggerFactory;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.util.Map;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/23
+ * Time: 14:59
+ */
+public class Util {
+
+    //打log用
+    private static Log logger = new Log(LoggerFactory.getLogger(Util.class));
+
+    /**
+     * 通过反射的方式遍历对象的属性和属性值,方便调试
+     *
+     * @param o 要遍历的对象
+     * @throws Exception
+     */
+    public static void reflect(Object o) throws Exception {
+        Class cls = o.getClass();
+        Field[] fields = cls.getDeclaredFields();
+        for (int i = 0; i < fields.length; i++) {
+            Field f = fields[i];
+            f.setAccessible(true);
+            Util.log(f.getName() + " -> " + f.get(o));
+        }
+    }
+
+    public static byte[] readInput(InputStream in) throws IOException {
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        int len = 0;
+        byte[] buffer = new byte[1024];
+        while ((len = in.read(buffer)) > 0) {
+            out.write(buffer, 0, len);
+        }
+        out.close();
+        in.close();
+        return out.toByteArray();
+    }
+
+    public static String inputStreamToString(InputStream is) throws IOException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        int i;
+        while ((i = is.read()) != -1) {
+            baos.write(i);
+        }
+        return baos.toString();
+    }
+
+
+    public static InputStream getStringStream(String sInputString) {
+        ByteArrayInputStream tInputStringStream = null;
+        if (sInputString != null && !sInputString.trim().equals("")) {
+            tInputStringStream = new ByteArrayInputStream(sInputString.getBytes());
+        }
+        return tInputStringStream;
+    }
+
+    public static Object getObjectFromXML(String xml, Class tClass) {
+        //将从API返回的XML数据映射到Java对象
+        XStream xStreamForResponseData = new XStream();
+        xStreamForResponseData.alias("xml", tClass);
+        xStreamForResponseData.ignoreUnknownElements();//暂时忽略掉一些新增的字段
+        return xStreamForResponseData.fromXML(xml);
+    }
+
+    public static String getStringFromMap(Map<String, Object> map, String key, String defaultValue) {
+        if (key == "" || key == null) {
+            return defaultValue;
+        }
+        String result = (String) map.get(key);
+        if (result == null) {
+            return defaultValue;
+        } else {
+            return result;
+        }
+    }
+
+    public static int getIntFromMap(Map<String, Object> map, String key) {
+        if (key == "" || key == null) {
+            return 0;
+        }
+        if (map.get(key) == null) {
+            return 0;
+        }
+        return Integer.parseInt((String) map.get(key));
+    }
+
+    /**
+     * 打log接口
+     * @param log 要打印的log字符串
+     * @return 返回log
+     */
+    public static String log(Object log){
+        logger.d(log.toString());
+        //System.out.println(log);
+        return log.toString();
+    }
+
+    /**
+     * 读取本地的xml数据,一般用来自测用
+     * @param localPath 本地xml文件路径
+     * @return 读到的xml字符串
+     */
+    public static String getLocalXMLString(String localPath) throws IOException {
+        return Util.inputStreamToString(Util.class.getResourceAsStream(localPath));
+    }
+
+}
+

+ 86 - 0
server/tools/src/main/java/com/tencent/common/XMLParser.java

@@ -0,0 +1,86 @@
+package com.nuliji.tools.third.tencent.common;
+
+import com.tencent.protocol.refund_query_protocol.RefundOrderData;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * User: rizenguo
+ * Date: 2014/11/1
+ * Time: 14:06
+ */
+public class XMLParser {
+
+    /**
+     * 从RefunQueryResponseString里面解析出退款订单数据
+     * @param refundQueryResponseString RefundQuery API返回的数据
+     * @return 因为订单数据有可能是多个,所以返回一个列表
+     */
+    public static List<RefundOrderData> getRefundOrderList(String refundQueryResponseString) throws IOException, SAXException, ParserConfigurationException {
+        List list = new ArrayList();
+
+        Map<String,Object> map = XMLParser.getMapFromXML(refundQueryResponseString);
+
+       int count = Integer.parseInt((String) map.get("refund_count"));
+       Util.log("count:" + count);
+
+        if(count<1){
+            return list;
+        }
+
+        RefundOrderData refundOrderData;
+
+        for(int i=0;i<count;i++){
+            refundOrderData = new RefundOrderData();
+
+            refundOrderData.setOutRefundNo(Util.getStringFromMap(map,"out_refund_no_" + i,""));
+            refundOrderData.setRefundID(Util.getStringFromMap(map,"refund_id_" + i,""));
+            refundOrderData.setRefundChannel(Util.getStringFromMap(map,"refund_channel_" + i,""));
+            refundOrderData.setRefundFee(Util.getIntFromMap(map,"refund_fee_" + i));
+            refundOrderData.setCouponRefundFee(Util.getIntFromMap(map,"coupon_refund_fee_" + i));
+            refundOrderData.setRefundStatus(Util.getStringFromMap(map,"refund_status_" + i,""));
+            list.add(refundOrderData);
+        }
+
+        return list;
+    }
+
+    public static Map<String,Object> getMapFromXML(String xmlString) throws ParserConfigurationException, IOException, SAXException {
+
+        //这里用Dom的方式解析回包的最主要目的是防止API新增回包字段
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        DocumentBuilder builder = factory.newDocumentBuilder();
+        InputStream is =  Util.getStringStream(xmlString);
+        Document document = builder.parse(is);
+
+        //获取到document里面的全部结点
+        NodeList allNodes = document.getFirstChild().getChildNodes();
+        Node node;
+        Map<String, Object> map = new HashMap<String, Object>();
+        int i=0;
+        while (i < allNodes.getLength()) {
+            node = allNodes.item(i);
+            if(node instanceof Element){
+                map.put(node.getNodeName(),node.getTextContent());
+            }
+            i++;
+        }
+        return map;
+
+    }
+
+
+}

+ 40 - 0
server/tools/src/main/java/com/tencent/common/report/ReportRunable.java

@@ -0,0 +1,40 @@
+package com.nuliji.tools.third.tencent.common.report;
+
+import com.tencent.common.report.service.ReportService;
+
+import java.io.IOException;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+
+/**
+ * User: rizenguo
+ * Date: 2014/12/3
+ * Time: 16:34
+ */
+public class ReportRunable implements Runnable {
+
+    private ReportService reportService ;
+
+    ReportRunable(ReportService rs){
+        reportService = rs;
+    }
+
+    @Override
+    public void run() {
+        try {
+            reportService.request();
+        } catch (UnrecoverableKeyException e) {
+            e.printStackTrace();
+        } catch (KeyManagementException e) {
+            e.printStackTrace();
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        } catch (KeyStoreException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+}

+ 31 - 0
server/tools/src/main/java/com/tencent/common/report/Reporter.java

@@ -0,0 +1,31 @@
+package com.nuliji.tools.third.tencent.common.report;
+
+import com.tencent.common.report.protocol.ReportReqData;
+import com.tencent.common.report.service.ReportService;
+
+/**
+ * User: rizenguo
+ * Date: 2014/12/3
+ * Time: 11:42
+ */
+public class Reporter {
+
+    private ReportRunable r;
+    private Thread t;
+    private ReportService rs;
+
+    /**
+     * 请求统计上报API
+     * @param reportReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     */
+    public Reporter(ReportReqData reportReqData){
+        rs = new ReportService(reportReqData);
+    }
+
+    public void run(){
+        r = new ReportRunable(rs);
+        t = new Thread(r);
+        t.setDaemon(true);  //后台线程
+        t.start();
+    }
+}

+ 21 - 0
server/tools/src/main/java/com/tencent/common/report/ReporterFactory.java

@@ -0,0 +1,21 @@
+package com.nuliji.tools.third.tencent.common.report;
+
+import com.tencent.common.report.protocol.ReportReqData;
+
+/**
+ * User: rizenguo
+ * Date: 2014/12/3
+ * Time: 17:44
+ */
+public class ReporterFactory {
+
+    /**
+     * 请求统计上报API
+     * @param reportReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return 返回一个Reporter
+     */
+    public static Reporter getReporter(ReportReqData reportReqData){
+        return new Reporter(reportReqData);
+    }
+
+}

+ 232 - 0
server/tools/src/main/java/com/tencent/common/report/protocol/ReportReqData.java

@@ -0,0 +1,232 @@
+package com.nuliji.tools.third.tencent.common.report.protocol;
+
+import com.tencent.common.Configure;
+import com.tencent.common.RandomStringGenerator;
+import com.tencent.common.Signature;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * User: rizenguo
+ * Date: 2014/11/12
+ * Time: 17:05
+ */
+public class ReportReqData {
+
+    //每个字段具体的意思请查看API文档
+    private String appid;
+    private String mch_id;
+    private String sub_mch_id;
+    private String device_info;
+    private String nonce_str;
+    private String sign;
+
+    //上报对应的接口的完整URL,类似:https://api.mch.weixin.qq.com/pay/unifiedorder
+    private String interface_url;
+    //接口耗时情况,单位为毫秒
+    private int execute_time_cost;
+    //发起接口调用时的机器IP
+    private String user_ip;
+    //上报该统计请求时的系统时间,格式为yyyyMMddHHmmss
+    private String time;
+
+    //以下是API接口返回的对应数据
+    private String return_code;
+    private String return_msg;
+    private String result_code;
+    private String err_code;
+    private String err_code_des;
+    private String out_trade_no;
+
+    /**
+     * 请求统计上报API
+     * @param deviceInfo 微信支付分配的终端设备号,商户自定义
+     * @param interfaceUrl 上报对应的接口的完整URL,类似: https://api.mch.weixin.qq.com/pay/unifiedorder
+     * @param executeTimeCost 接口耗时情况,单位为毫秒
+     * @param returnCode API返回的对应字段
+     * @param returnMsg API返回的对应字段
+     * @param resultCode API返回的对应字段
+     * @param errCode API返回的对应字段
+     * @param errCodeDes API返回的对应字段
+     * @param outTradeNo API返回的对应字段
+     * @param userIp 发起接口调用时的机器IP
+     */
+    public ReportReqData(String deviceInfo, String interfaceUrl,int executeTimeCost, String returnCode,String returnMsg,String resultCode,String errCode,String errCodeDes, String outTradeNo,String userIp){
+        //微信分配的公众号ID(开通公众号之后可以获取到)
+        setAppid(Configure.getAppid());
+
+        //商户系统自己生成的唯一的订单号
+        setOut_trade_no(outTradeNo);
+
+        //微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到)
+        setMch_id(Configure.getMchid());
+        setSub_mch_id(Configure.getSubMchid());
+        setDevice_info(deviceInfo);
+        setInterface_url(interfaceUrl);
+        setExecute_time_cost(executeTimeCost);
+        setReturn_code(returnCode);
+        setReturn_msg(returnMsg);
+        setResult_code(resultCode);
+        setErr_code(errCode);
+        setErr_code_des(errCodeDes);
+        setUser_ip(userIp);
+        setTime(getTime());
+
+        //随机字符串,不长于32 位
+        setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
+
+        //根据API给的签名规则进行签名
+        String sign = Signature.getSign(toMap());
+        setSign(sign);//把签名数据设置到Sign这个属性中
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getSub_mch_id() {
+        return sub_mch_id;
+    }
+
+    public void setSub_mch_id(String sub_mch_id) {
+        this.sub_mch_id = sub_mch_id;
+    }
+
+    public String getDevice_info() {
+        return device_info;
+    }
+
+    public void setDevice_info(String device_info) {
+        this.device_info = device_info;
+    }
+
+    public String getNonce_str() {
+        return nonce_str;
+    }
+
+    public void setNonce_str(String nonce_str) {
+        this.nonce_str = nonce_str;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public String getInterface_url() {
+        return interface_url;
+    }
+
+    public void setInterface_url(String interface_url) {
+        this.interface_url = interface_url;
+    }
+
+    public int getExecute_time_cost() {
+        return execute_time_cost;
+    }
+
+    public void setExecute_time_cost(int execute_time) {
+        this.execute_time_cost = execute_time;
+    }
+
+    public String getReturn_code() {
+        return return_code;
+    }
+
+    public void setReturn_code(String return_code) {
+        this.return_code = return_code;
+    }
+
+    public String getReturn_msg() {
+        return return_msg;
+    }
+
+    public void setReturn_msg(String return_msg) {
+        this.return_msg = return_msg;
+    }
+
+    public String getResult_code() {
+        return result_code;
+    }
+
+    public void setResult_code(String result_code) {
+        this.result_code = result_code;
+    }
+
+    public String getErr_code() {
+        return err_code;
+    }
+
+    public void setErr_code(String err_code) {
+        this.err_code = err_code;
+    }
+
+    public String getErr_code_des() {
+        return err_code_des;
+    }
+
+    public void setErr_code_des(String err_code_des) {
+        this.err_code_des = err_code_des;
+    }
+
+    public String getOut_trade_no() {
+        return out_trade_no;
+    }
+
+    public void setOut_trade_no(String out_trade_no) {
+        this.out_trade_no = out_trade_no;
+    }
+
+    public String getUser_ip() {
+        return user_ip;
+    }
+
+    public void setUser_ip(String user_ip) {
+        this.user_ip = user_ip;
+    }
+
+    public String getTime() {
+        return time;
+    }
+
+    public void setTime(String time) {
+        this.time = time;
+    }
+
+    public Map<String,Object> toMap(){
+        Map<String,Object> map = new HashMap<String, Object>();
+        Field[] fields = this.getClass().getDeclaredFields();
+        for (Field field : fields) {
+            Object obj;
+            try {
+                obj = field.get(this);
+                if(obj!=null){
+                    map.put(field.getName(), obj);
+                }
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+        }
+        return map;
+    }
+
+}

+ 38 - 0
server/tools/src/main/java/com/tencent/common/report/protocol/ReportResData.java

@@ -0,0 +1,38 @@
+package com.nuliji.tools.third.tencent.common.report.protocol;
+
+/**
+ * User: rizenguo
+ * Date: 2014/11/12
+ * Time: 17:06
+ */
+public class ReportResData {
+
+    //以下是API接口返回的对应数据
+    private String return_code;
+    private String return_msg;
+    private String result_code;
+
+    public String getReturn_code() {
+        return return_code;
+    }
+
+    public void setReturn_code(String return_code) {
+        this.return_code = return_code;
+    }
+
+    public String getReturn_msg() {
+        return return_msg;
+    }
+
+    public void setReturn_msg(String return_msg) {
+        this.return_msg = return_msg;
+    }
+
+    public String getResult_code() {
+        return result_code;
+    }
+
+    public void setResult_code(String result_code) {
+        this.result_code = result_code;
+    }
+}

+ 67 - 0
server/tools/src/main/java/com/tencent/common/report/service/ReportService.java

@@ -0,0 +1,67 @@
+package com.nuliji.tools.third.tencent.common.report.service;
+
+import com.tencent.common.*;
+import com.tencent.common.report.protocol.ReportReqData;
+
+import java.io.IOException;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * User: rizenguo
+ * Date: 2014/11/12
+ * Time: 17:07
+ */
+public class ReportService {
+
+    private ReportReqData reqData ;
+
+    /**
+     * 请求统计上报API
+     * @param reportReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     */
+    public ReportService(ReportReqData reportReqData){
+        reqData = reportReqData;
+    }
+
+    public String request() throws UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException {
+        String responseString = new HttpsRequest().sendPost(Configure.REPORT_API, reqData);
+
+        Util.log("   report返回的数据:" + responseString);
+
+        return responseString;
+    }
+
+    /**
+     * 请求统计上报API
+     * @param reportReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的数据
+     * @throws Exception
+     */
+    public static String request(ReportReqData reportReqData) throws Exception {
+
+        //--------------------------------------------------------------------
+        //发送HTTPS的Post请求到API地址
+        //--------------------------------------------------------------------
+        String responseString = new HttpsRequest().sendPost(Configure.REPORT_API, reportReqData);
+
+        Util.log("report返回的数据:" + responseString);
+
+        return responseString;
+    }
+
+    /**
+     * 获取time:统计发送时间,格式为yyyyMMddHHmmss,如2009年12 月25 日9 点10 分10 秒表示为20091225091010。时区为GMT+8 beijing。
+     * @return 订单生成时间
+     */
+    private static String getTime(){
+        //订单生成时间自然就是当前服务器系统时间咯
+        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
+        return simpleDateFormat.format(new Date());
+    }
+
+}

+ 51 - 0
server/tools/src/main/java/com/tencent/protocol/ResData.java

@@ -0,0 +1,51 @@
+package com.nuliji.tools.third.tencent.protocol;
+
+/**
+ * Created by gaojie on 2017/5/26.
+ */
+public interface ResData {
+    public String getReturn_code();
+
+    public String getReturn_msg();
+    public String getAppid();
+
+    public String getMch_id();
+
+    public String getSub_mch_id();
+
+    public String getNonce_str();
+
+    public String getSign();
+
+    public String getResult_code();
+
+    public String getErr_code();
+
+    public String getErr_code_des();
+
+    public String getTrade_state();
+
+    public String getDevice_info();
+
+    public String getOpenid();
+
+    public String getIs_subscribe();
+
+    public String getTrade_type();
+
+    public String getBank_type();
+
+    public String getTotal_fee();
+
+    public String getCoupon_fee();
+
+    public String getFee_type();
+
+    public String getTransaction_id();
+
+    public String getOut_trade_no();
+
+    public String getAttach();
+
+    public String getTime_end();
+}

+ 137 - 0
server/tools/src/main/java/com/tencent/protocol/downloadbill_protocol/DownloadBillReqData.java

@@ -0,0 +1,137 @@
+package com.nuliji.tools.third.tencent.protocol.downloadbill_protocol;
+
+import com.tencent.common.Configure;
+import com.tencent.common.RandomStringGenerator;
+import com.tencent.common.Signature;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/25
+ * Time: 16:48
+ */
+public class DownloadBillReqData {
+    //每个字段具体的意思请查看API文档
+    private String appid = "";
+    private String mch_id = "";
+    private String device_info = "";
+    private String nonce_str = "";
+    private String sign = "";
+    private String bill_date = "";
+    private String bill_type = "";
+
+    /**
+     * 请求对账单下载服务
+     * @param deviceInfo 商户自己定义的扫码支付终端设备号,方便追溯这笔交易发生在哪台终端设备上
+     * @param billDate 下载对账单的日期,格式:yyyyMMdd 例如:20140603
+     * @param billType 账单类型
+     *                 ALL,返回当日所有订单信息,默认值
+    SUCCESS,返回当日成功支付的订单
+    REFUND,返回当日退款订单
+    REVOKED,已撤销的订单
+     */
+    public DownloadBillReqData(String deviceInfo,String billDate,String billType){
+
+        //微信分配的公众号ID(开通公众号之后可以获取到)
+        setAppid(Configure.getAppid());
+
+        //微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到)
+        setMch_id(Configure.getMchid());
+
+        //商户自己定义的扫码支付终端设备号,方便追溯这笔交易发生在哪台终端设备上
+        setDevice_info(deviceInfo);
+
+        setBill_date(billDate);
+
+        setBill_type(billType);
+
+
+        //随机字符串,不长于32 位
+        setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
+
+        //根据API给的签名规则进行签名
+        String sign = Signature.getSign(toMap());
+        setSign(sign);//把签名数据设置到Sign这个属性中
+
+
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getDevice_info() {
+        return device_info;
+    }
+
+    public void setDevice_info(String device_info) {
+        this.device_info = device_info;
+    }
+
+    public String getNonce_str() {
+        return nonce_str;
+    }
+
+    public void setNonce_str(String nonce_str) {
+        this.nonce_str = nonce_str;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public String getBill_date() {
+        return bill_date;
+    }
+
+    public void setBill_date(String bill_date) {
+        this.bill_date = bill_date;
+    }
+
+    public String getBill_type() {
+        return bill_type;
+    }
+
+    public void setBill_type(String bill_type) {
+        this.bill_type = bill_type;
+    }
+
+    public Map<String,Object> toMap(){
+        Map<String,Object> map = new HashMap<String, Object>();
+        Field[] fields = this.getClass().getDeclaredFields();
+        for (Field field : fields) {
+            Object obj;
+            try {
+                obj = field.get(this);
+                if(obj!=null){
+                    map.put(field.getName(), obj);
+                }
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+        }
+        return map;
+    }
+
+}

+ 29 - 0
server/tools/src/main/java/com/tencent/protocol/downloadbill_protocol/DownloadBillResData.java

@@ -0,0 +1,29 @@
+package com.nuliji.tools.third.tencent.protocol.downloadbill_protocol;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/25
+ * Time: 16:48
+ */
+public class DownloadBillResData {
+
+    //协议层
+    private String return_code = "";
+    private String return_msg = "";
+
+    public String getReturn_code() {
+        return return_code;
+    }
+
+    public void setReturn_code(String return_code) {
+        this.return_code = return_code;
+    }
+
+    public String getReturn_msg() {
+        return return_msg;
+    }
+
+    public void setReturn_msg(String return_msg) {
+        this.return_msg = return_msg;
+    }
+}

+ 128 - 0
server/tools/src/main/java/com/tencent/protocol/pay_protocol/AppReqData.java

@@ -0,0 +1,128 @@
+package com.nuliji.tools.third.tencent.protocol.pay_protocol;
+
+/**
+ * User: gaojie
+ * Date: 2017/05/10
+ * Time: 16:42
+ */
+
+import com.tencent.common.Configure;
+import com.tencent.common.RandomStringGenerator;
+import com.tencent.common.Signature;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * app发送
+ */
+public class AppReqData {
+
+    //每个字段具体的意思请查看API文档
+    private String appid = "";
+    private String partnerid = "";
+    private String prepayid = "";
+    private String _package = "Sign=WXPay";
+    private String noncestr = "";
+    private String timestamp = "";
+    private String sign = "";
+
+    public AppReqData(String prepayid){
+        setPrepayid(prepayid);
+
+        //微信分配的公众号ID(开通公众号之后可以获取到)
+        setAppid(Configure.getAppid());
+
+        //微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到)
+        setPartnerid(Configure.getMchid());
+
+        int timestamp = Math.toIntExact(System.currentTimeMillis() / 1000);
+        setTimestamp(String.valueOf(timestamp));
+
+        //随机字符串,不长于32 位
+        setNoncestr(RandomStringGenerator.getRandomStringByLength(32));
+
+        //根据API给的签名规则进行签名
+        String sign = Signature.getSign(toMap());
+        setSign(sign);//把签名数据设置到Sign这个属性中
+
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getNoncestr() {
+        return noncestr;
+    }
+
+    public void setNoncestr(String noncestr) {
+        this.noncestr = noncestr;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public Map<String,Object> toMap(){
+        Map<String,Object> map = new HashMap<String, Object>();
+        Field[] fields = this.getClass().getDeclaredFields();
+        for (Field field : fields) {
+            Object obj;
+            try {
+                obj = field.get(this);
+                if(obj!=null){
+                    String name = field.getName();
+                    if(name == "_package") name = "package";
+                    map.put(name, obj);
+                }
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+        }
+        return map;
+    }
+
+    public String getPartnerid() {
+        return partnerid;
+    }
+
+    public void setPartnerid(String partnerid) {
+        this.partnerid = partnerid;
+    }
+
+    public String getPrepayid() {
+        return prepayid;
+    }
+
+    public void setPrepayid(String prepayid) {
+        this.prepayid = prepayid;
+    }
+
+    public String get_package() {
+        return _package;
+    }
+
+    public void set_package(String _package) {
+        this._package = _package;
+    }
+
+    public String getTimestamp() {
+        return timestamp;
+    }
+
+    public void setTimestamp(String timestamp) {
+        this.timestamp = timestamp;
+    }
+}

+ 128 - 0
server/tools/src/main/java/com/tencent/protocol/pay_protocol/JsReqData.java

@@ -0,0 +1,128 @@
+package com.tencent.protocol.pay_protocol;
+
+/**
+ * User: gaojie
+ * Date: 2017/05/10
+ * Time: 16:42
+ */
+
+import com.tencent.common.Configure;
+import com.tencent.common.RandomStringGenerator;
+import com.tencent.common.Signature;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * app发送
+ */
+public class AppReqData {
+
+    //每个字段具体的意思请查看API文档
+    private String appid = "";
+    private String partnerid = "";
+    private String prepayid = "";
+    private String _package = "Sign=WXPay";
+    private String noncestr = "";
+    private String timestamp = "";
+    private String sign = "";
+
+    public AppReqData(String prepayid){
+        setPrepayid(prepayid);
+
+        //微信分配的公众号ID(开通公众号之后可以获取到)
+        setAppid(Configure.getAppid());
+
+        //微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到)
+        setPartnerid(Configure.getMchid());
+
+        int timestamp = Math.toIntExact(System.currentTimeMillis() / 1000);
+        setTimestamp(String.valueOf(timestamp));
+
+        //随机字符串,不长于32 位
+        setNoncestr(RandomStringGenerator.getRandomStringByLength(32));
+
+        //根据API给的签名规则进行签名
+        String sign = Signature.getSign(toMap());
+        setSign(sign);//把签名数据设置到Sign这个属性中
+
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getNoncestr() {
+        return noncestr;
+    }
+
+    public void setNoncestr(String noncestr) {
+        this.noncestr = noncestr;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public Map<String,Object> toMap(){
+        Map<String,Object> map = new HashMap<String, Object>();
+        Field[] fields = this.getClass().getDeclaredFields();
+        for (Field field : fields) {
+            Object obj;
+            try {
+                obj = field.get(this);
+                if(obj!=null){
+                    String name = field.getName();
+                    if(name == "_package") name = "package";
+                    map.put(name, obj);
+                }
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+        }
+        return map;
+    }
+
+    public String getPartnerid() {
+        return partnerid;
+    }
+
+    public void setPartnerid(String partnerid) {
+        this.partnerid = partnerid;
+    }
+
+    public String getPrepayid() {
+        return prepayid;
+    }
+
+    public void setPrepayid(String prepayid) {
+        this.prepayid = prepayid;
+    }
+
+    public String get_package() {
+        return _package;
+    }
+
+    public void set_package(String _package) {
+        this._package = _package;
+    }
+
+    public String getTimestamp() {
+        return timestamp;
+    }
+
+    public void setTimestamp(String timestamp) {
+        this.timestamp = timestamp;
+    }
+}

+ 291 - 0
server/tools/src/main/java/com/tencent/protocol/pay_protocol/NoticeResData.java

@@ -0,0 +1,291 @@
+package com.nuliji.tools.third.tencent.protocol.pay_protocol;
+
+/**
+ * User: gaojie
+ * Date: 2017/05/10
+ * Time: 16:42
+ */
+
+import com.tencent.protocol.ResData;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 异步通知提交的数据
+ */
+public class NoticeResData implements ResData {
+
+    private String return_code = "";
+    private String return_msg = "";
+
+    //协议返回的具体数据(以下字段在return_code 为SUCCESS 的时候有返回)
+    private String appid = "";
+    private String mch_id = "";
+    private String sub_mch_id = "";//新增
+    private String nonce_str = "";
+    private String sign = "";
+    private String result_code = "";
+    private String err_code = "";
+    private String err_code_des = "";
+
+    //以下字段在return_code 和result_code 都为SUCCESS 的时候有返回
+    private String trade_state = "";
+
+    //trade_state的几种可能取值:
+    //    SUCCESS--支付成功
+    //    REFUND--转入退款
+    //    NOTPAY--未支付
+    //    CLOSED--已关闭
+    //    REVOKED--已撤销
+    //    USERPAYING--用户支付中
+    //    NOPAY--未支付(确认支付超时)
+    //    PAYERROR--支付失败(其他原因,
+    //            如银行返回失败)
+
+    //以下字段在trade_state 为SUCCESS 或者REFUND 的时候有返回
+    private String device_info = "";
+    private String openid = "";
+    private String is_subscribe = "";
+    private String trade_type = "";
+    private String bank_type = "";
+    private String total_fee = "";
+    private String coupon_fee = "";
+    private String fee_type = "";
+    private String transaction_id = "";
+    private String out_trade_no = "";
+    private String attach = "";
+    private String time_end = "";
+
+    private String cash_fee = "";
+    private String cash_fee_type = "";
+    private String coupon_count = "";
+
+    public String getReturn_code() {
+        return return_code;
+    }
+
+    public void setReturn_code(String return_code) {
+        this.return_code = return_code;
+    }
+
+    public String getReturn_msg() {
+        return return_msg;
+    }
+
+    public void setReturn_msg(String return_msg) {
+        this.return_msg = return_msg;
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getSub_mch_id() {
+        return sub_mch_id;
+    }
+
+    public void setSub_mch_id(String sub_mch_id) {
+        this.sub_mch_id = sub_mch_id;
+    }
+
+    public String getNonce_str() {
+        return nonce_str;
+    }
+
+    public void setNonce_str(String nonce_str) {
+        this.nonce_str = nonce_str;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public String getResult_code() {
+        return result_code;
+    }
+
+    public void setResult_code(String result_code) {
+        this.result_code = result_code;
+    }
+
+    public String getErr_code() {
+        return err_code;
+    }
+
+    public void setErr_code(String err_code) {
+        this.err_code = err_code;
+    }
+
+    public String getErr_code_des() {
+        return err_code_des;
+    }
+
+    public void setErr_code_des(String err_code_des) {
+        this.err_code_des = err_code_des;
+    }
+
+    public String getTrade_state() {
+        return trade_state;
+    }
+
+    public void setTrade_state(String trade_state) {
+        this.trade_state = trade_state;
+    }
+
+    public String getDevice_info() {
+        return device_info;
+    }
+
+    public void setDevice_info(String device_info) {
+        this.device_info = device_info;
+    }
+
+    public String getOpenid() {
+        return openid;
+    }
+
+    public void setOpenid(String openid) {
+        this.openid = openid;
+    }
+
+    public String getIs_subscribe() {
+        return is_subscribe;
+    }
+
+    public void setIs_subscribe(String is_subscribe) {
+        this.is_subscribe = is_subscribe;
+    }
+
+    public String getTrade_type() {
+        return trade_type;
+    }
+
+    public void setTrade_type(String trade_type) {
+        this.trade_type = trade_type;
+    }
+
+    public String getBank_type() {
+        return bank_type;
+    }
+
+    public void setBank_type(String bank_type) {
+        this.bank_type = bank_type;
+    }
+
+    public String getTotal_fee() {
+        return total_fee;
+    }
+
+    public void setTotal_fee(String total_fee) {
+        this.total_fee = total_fee;
+    }
+
+    public String getCoupon_fee() {
+        return coupon_fee;
+    }
+
+    public void setCoupon_fee(String coupon_fee) {
+        this.coupon_fee = coupon_fee;
+    }
+
+    public String getFee_type() {
+        return fee_type;
+    }
+
+    public void setFee_type(String fee_type) {
+        this.fee_type = fee_type;
+    }
+
+    public String getTransaction_id() {
+        return transaction_id;
+    }
+
+    public void setTransaction_id(String transaction_id) {
+        this.transaction_id = transaction_id;
+    }
+
+    public String getOut_trade_no() {
+        return out_trade_no;
+    }
+
+    public void setOut_trade_no(String out_trade_no) {
+        this.out_trade_no = out_trade_no;
+    }
+
+    public String getAttach() {
+        return attach;
+    }
+
+    public void setAttach(String attach) {
+        this.attach = attach;
+    }
+
+    public String getTime_end() {
+        return time_end;
+    }
+
+    public void setTime_end(String time_end) {
+        this.time_end = time_end;
+    }
+
+    public Map<String,Object> toMap(){
+        Map<String,Object> map = new HashMap<String, Object>();
+        Field[] fields = this.getClass().getDeclaredFields();
+        for (Field field : fields) {
+            Object obj;
+            try {
+                obj = field.get(this);
+                if(obj!=null){
+                    map.put(field.getName(), obj);
+                }
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+        }
+        return map;
+    }
+
+    public String getCash_fee() {
+        return cash_fee;
+    }
+
+    public void setCash_fee(String cash_fee) {
+        this.cash_fee = cash_fee;
+    }
+
+    public String getCash_fee_type() {
+        return cash_fee_type;
+    }
+
+    public void setCash_fee_type(String cash_fee_type) {
+        this.cash_fee_type = cash_fee_type;
+    }
+
+    public String getCoupon_count() {
+        return coupon_count;
+    }
+
+    public void setCoupon_count(String coupon_count) {
+        this.coupon_count = coupon_count;
+    }
+}

+ 230 - 0
server/tools/src/main/java/com/tencent/protocol/pay_protocol/ScanPayReqData.java

@@ -0,0 +1,230 @@
+package com.nuliji.tools.third.tencent.protocol.pay_protocol;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/22
+ * Time: 21:29
+ */
+
+import com.tencent.common.Configure;
+import com.tencent.common.RandomStringGenerator;
+import com.tencent.common.Signature;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 请求被扫支付API需要提交的数据
+ */
+public class ScanPayReqData {
+
+    //每个字段具体的意思请查看API文档
+    private String appid = "";
+    private String mch_id = "";
+    private String device_info = "";
+    private String nonce_str = "";
+    private String sign = "";
+    private String body = "";
+    private String attach = "";
+    private String out_trade_no = "";
+    private int total_fee = 0;
+    private String spbill_create_ip = "";
+    private String time_start = "";
+    private String time_expire = "";
+    private String goods_tag = "";
+    private String auth_code = "";
+
+    /**
+     * @param authCode 这个是扫码终端设备从用户手机上扫取到的支付授权号,这个号是跟用户用来支付的银行卡绑定的,有效期是1分钟
+     * @param body 要支付的商品的描述信息,用户会在支付成功页面里看到这个信息
+     * @param attach 支付订单里面可以填的附加数据,API会将提交的这个附加数据原样返回
+     * @param outTradeNo 商户系统内部的订单号,32个字符内可包含字母, 确保在商户系统唯一
+     * @param totalFee 订单总金额,单位为“分”,只能整数
+     * @param deviceInfo 商户自己定义的扫码支付终端设备号,方便追溯这笔交易发生在哪台终端设备上
+     * @param spBillCreateIP 订单生成的机器IP
+     * @param timeStart 订单生成时间, 格式为yyyyMMddHHmmss,如2009年12 月25 日9 点10 分10 秒表示为20091225091010。时区为GMT+8 beijing。该时间取自商户服务器
+     * @param timeExpire 订单失效时间,格式同上
+     * @param goodsTag 商品标记,微信平台配置的商品标记,用于优惠券或者满减使用
+     */
+    public ScanPayReqData(String authCode,String body,String attach,String outTradeNo,int totalFee,String deviceInfo,String spBillCreateIP,String timeStart,String timeExpire,String goodsTag){
+
+        //微信分配的公众号ID(开通公众号之后可以获取到)
+        setAppid(Configure.getAppid());
+
+        //微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到)
+        setMch_id(Configure.getMchid());
+
+        //这个是扫码终端设备从用户手机上扫取到的支付授权号,这个号是跟用户用来支付的银行卡绑定的,有效期是1分钟
+        //调试的时候可以在微信上打开“钱包”里面的“刷卡”,将扫码页面里的那一串14位的数字输入到这里来,进行提交验证
+        //记住out_trade_no这个订单号可以将这一笔支付进行退款
+        setAuth_code(authCode);
+
+        //要支付的商品的描述信息,用户会在支付成功页面里看到这个信息
+        setBody(body);
+
+        //支付订单里面可以填的附加数据,API会将提交的这个附加数据原样返回,有助于商户自己可以注明该笔消费的具体内容,方便后续的运营和记录
+        setAttach(attach);
+
+        //商户系统内部的订单号,32个字符内可包含字母, 确保在商户系统唯一
+        setOut_trade_no(outTradeNo);
+
+        //订单总金额,单位为“分”,只能整数
+        setTotal_fee(totalFee);
+
+        //商户自己定义的扫码支付终端设备号,方便追溯这笔交易发生在哪台终端设备上
+        setDevice_info(deviceInfo);
+
+        //订单生成的机器IP
+        setSpbill_create_ip(spBillCreateIP);
+
+        //订单生成时间, 格式为yyyyMMddHHmmss,如2009年12 月25 日9 点10 分10 秒表示为20091225091010。时区为GMT+8 beijing。该时间取自商户服务器
+        setTime_start(timeStart);
+
+        //订单失效时间,格式同上
+        setTime_expire(timeExpire);
+
+        //商品标记,微信平台配置的商品标记,用于优惠券或者满减使用
+        setGoods_tag(goodsTag);
+
+        //随机字符串,不长于32 位
+        setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
+
+        //根据API给的签名规则进行签名
+        String sign = Signature.getSign(toMap());
+        setSign(sign);//把签名数据设置到Sign这个属性中
+
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getDevice_info() {
+        return device_info;
+    }
+
+    public void setDevice_info(String device_info) {
+        this.device_info = device_info;
+    }
+
+    public String getNonce_str() {
+        return nonce_str;
+    }
+
+    public void setNonce_str(String nonce_str) {
+        this.nonce_str = nonce_str;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public String getBody() {
+        return body;
+    }
+
+    public void setBody(String body) {
+        this.body = body;
+    }
+
+    public String getAttach() {
+        return attach;
+    }
+
+    public void setAttach(String attach) {
+        this.attach = attach;
+    }
+
+    public String getOut_trade_no() {
+        return out_trade_no;
+    }
+
+    public void setOut_trade_no(String out_trade_no) {
+        this.out_trade_no = out_trade_no;
+    }
+
+    public int getTotal_fee() {
+        return total_fee;
+    }
+
+    public void setTotal_fee(int total_fee) {
+        this.total_fee = total_fee;
+    }
+
+    public String getSpbill_create_ip() {
+        return spbill_create_ip;
+    }
+
+    public void setSpbill_create_ip(String spbill_create_ip) {
+        this.spbill_create_ip = spbill_create_ip;
+    }
+
+    public String getTime_start() {
+        return time_start;
+    }
+
+    public void setTime_start(String time_start) {
+        this.time_start = time_start;
+    }
+
+    public String getTime_expire() {
+        return time_expire;
+    }
+
+    public void setTime_expire(String time_expire) {
+        this.time_expire = time_expire;
+    }
+
+    public String getGoods_tag() {
+        return goods_tag;
+    }
+
+    public void setGoods_tag(String goods_tag) {
+        this.goods_tag = goods_tag;
+    }
+
+    public String getAuth_code() {
+        return auth_code;
+    }
+
+    public void setAuth_code(String auth_code) {
+        this.auth_code = auth_code;
+    }
+
+    public Map<String,Object> toMap(){
+        Map<String,Object> map = new HashMap<String, Object>();
+        Field[] fields = this.getClass().getDeclaredFields();
+        for (Field field : fields) {
+            Object obj;
+            try {
+                obj = field.get(this);
+                if(obj!=null){
+                    map.put(field.getName(), obj);
+                }
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+        }
+        return map;
+    }
+
+}

+ 209 - 0
server/tools/src/main/java/com/tencent/protocol/pay_protocol/ScanPayResData.java

@@ -0,0 +1,209 @@
+package com.nuliji.tools.third.tencent.protocol.pay_protocol;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/22
+ * Time: 16:42
+ */
+
+/**
+ * 被扫支付提交Post数据给到API之后,API会返回XML格式的数据,这个类用来装这些数据
+ */
+public class ScanPayResData {
+    //协议层
+    private String return_code = "";
+    private String return_msg = "";
+
+    //协议返回的具体数据(以下字段在return_code 为SUCCESS 的时候有返回)
+    private String appid = "";
+    private String mch_id = "";
+    private String nonce_str = "";
+    private String sign = "";
+    private String result_code = "";
+    private String err_code = "";
+    private String err_code_des = "";
+
+    private String device_info = "";
+
+    //业务返回的具体数据(以下字段在return_code 和result_code 都为SUCCESS 的时候有返回)
+    private String openid = "";
+    private String is_subscribe = "";
+    private String trade_type = "";
+    private String bank_type = "";
+    private String total_fee = "";
+    private String coupon_fee = "";
+    private String fee_type = "";
+    private String transaction_id = "";
+    private String out_trade_no = "";
+    private String attach = "";
+    private String time_end = "";
+
+    public String getReturn_code() {
+        return return_code;
+    }
+
+    public void setReturn_code(String return_code) {
+        this.return_code = return_code;
+    }
+
+    public String getReturn_msg() {
+        return return_msg;
+    }
+
+    public void setReturn_msg(String return_msg) {
+        this.return_msg = return_msg;
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getDevice_info() {
+        return device_info;
+    }
+
+    public void setDevice_info(String device_info) {
+        this.device_info = device_info;
+    }
+
+    public String getNonce_str() {
+        return nonce_str;
+    }
+
+    public void setNonce_str(String nonce_str) {
+        this.nonce_str = nonce_str;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public String getResult_code() {
+        return result_code;
+    }
+
+    public void setResult_code(String result_code) {
+        this.result_code = result_code;
+    }
+
+    public String getErr_code() {
+        return err_code;
+    }
+
+    public void setErr_code(String err_code) {
+        this.err_code = err_code;
+    }
+
+    public String getErr_code_des() {
+        return err_code_des;
+    }
+
+    public void setErr_code_des(String err_code_des) {
+        this.err_code_des = err_code_des;
+    }
+
+    public String getOpenid() {
+        return openid;
+    }
+
+    public void setOpenid(String openid) {
+        this.openid = openid;
+    }
+
+    public String getIs_subscribe() {
+        return is_subscribe;
+    }
+
+    public void setIs_subscribe(String is_subscribe) {
+        this.is_subscribe = is_subscribe;
+    }
+
+    public String getTrade_type() {
+        return trade_type;
+    }
+
+    public void setTrade_type(String trade_type) {
+        this.trade_type = trade_type;
+    }
+
+    public String getBank_type() {
+        return bank_type;
+    }
+
+    public void setBank_type(String bank_type) {
+        this.bank_type = bank_type;
+    }
+
+    public String getTotal_fee() {
+        return total_fee;
+    }
+
+    public void setTotal_fee(String total_fee) {
+        this.total_fee = total_fee;
+    }
+
+    public String getCoupon_fee() {
+        return coupon_fee;
+    }
+
+    public void setCoupon_fee(String coupon_fee) {
+        this.coupon_fee = coupon_fee;
+    }
+
+    public String getFee_type() {
+        return fee_type;
+    }
+
+    public void setFee_type(String fee_type) {
+        this.fee_type = fee_type;
+    }
+
+    public String getTransaction_id() {
+        return transaction_id;
+    }
+
+    public void setTransaction_id(String transaction_id) {
+        this.transaction_id = transaction_id;
+    }
+
+    public String getOut_trade_no() {
+        return out_trade_no;
+    }
+
+    public void setOut_trade_no(String out_trade_no) {
+        this.out_trade_no = out_trade_no;
+    }
+
+    public String getAttach() {
+        return attach;
+    }
+
+    public void setAttach(String attach) {
+        this.attach = attach;
+    }
+
+    public String getTime_end() {
+        return time_end;
+    }
+
+    public void setTime_end(String time_end) {
+        this.time_end = time_end;
+    }
+
+}

+ 239 - 0
server/tools/src/main/java/com/tencent/protocol/pay_protocol/UnifiedOrderReqData.java

@@ -0,0 +1,239 @@
+package com.nuliji.tools.third.tencent.protocol.pay_protocol;
+
+/**
+ * User: gaojie
+ * Date: 2017/05/10
+ * Time: 16:42
+ */
+
+import com.tencent.common.Configure;
+import com.tencent.common.RandomStringGenerator;
+import com.tencent.common.Signature;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 请求被扫支付API需要提交的数据
+ */
+public class UnifiedOrderReqData {
+
+    //每个字段具体的意思请查看API文档
+    private String appid = "";
+    private String mch_id = "";
+    private String device_info = "WEB";
+    private String nonce_str = "";
+    private String sign = "";
+    private String body = "";
+    private String attach = "";
+    private String out_trade_no = "";
+    private int total_fee = 0;
+    private String spbill_create_ip = "";
+    private String time_start = "";
+    private String time_expire = "";
+    private String goods_tag = "";
+    private String notify_url = "";
+    private String trade_type = "";
+
+    /**
+     * @param body 要支付的商品的描述信息,用户会在支付成功页面里看到这个信息
+     * @param attach 支付订单里面可以填的附加数据,API会将提交的这个附加数据原样返回
+     * @param outTradeNo 商户系统内部的订单号,32个字符内可包含字母, 确保在商户系统唯一
+     * @param totalFee 订单总金额,单位为“分”,只能整数
+     * @param deviceInfo 商户自己定义的扫码支付终端设备号,方便追溯这笔交易发生在哪台终端设备上
+     * @param spBillCreateIP 订单生成的机器IP
+     * @param timeStart 订单生成时间, 格式为yyyyMMddHHmmss,如2009年12 月25 日9 点10 分10 秒表示为20091225091010。时区为GMT+8 beijing。该时间取自商户服务器
+     * @param timeExpire 订单失效时间,格式同上
+     * @param goodsTag 商品标记,微信平台配置的商品标记,用于优惠券或者满减使用
+     * @param notify_url 异步通知接口
+     * @param trade_type 交易类型:APP
+     */
+    public UnifiedOrderReqData(String body, String attach, String outTradeNo, int totalFee, String deviceInfo, String spBillCreateIP, String timeStart, String timeExpire, String goodsTag, String notify_url, String trade_type){
+
+        //微信分配的公众号ID(开通公众号之后可以获取到)
+        setAppid(Configure.getAppid());
+
+        //微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到)
+        setMch_id(Configure.getMchid());
+
+        //要支付的商品的描述信息,用户会在支付成功页面里看到这个信息
+        setBody(body);
+
+        //支付订单里面可以填的附加数据,API会将提交的这个附加数据原样返回,有助于商户自己可以注明该笔消费的具体内容,方便后续的运营和记录
+        setAttach(attach);
+
+        //商户系统内部的订单号,32个字符内可包含字母, 确保在商户系统唯一
+        setOut_trade_no(outTradeNo);
+
+        //订单总金额,单位为“分”,只能整数
+        setTotal_fee(totalFee);
+
+        //商户自己定义的扫码支付终端设备号,方便追溯这笔交易发生在哪台终端设备上
+        setDevice_info(deviceInfo);
+
+        //订单生成的机器IP
+        setSpbill_create_ip(spBillCreateIP);
+
+        //订单生成时间, 格式为yyyyMMddHHmmss,如2009年12 月25 日9 点10 分10 秒表示为20091225091010。时区为GMT+8 beijing。该时间取自商户服务器
+        setTime_start(timeStart);
+
+        //订单失效时间,格式同上
+        setTime_expire(timeExpire);
+
+        //商品标记,微信平台配置的商品标记,用于优惠券或者满减使用
+        setGoods_tag(goodsTag);
+
+        //随机字符串,不长于32 位
+        setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
+
+        setNotify_url(notify_url);
+
+        setTrade_type(trade_type);
+
+        //根据API给的签名规则进行签名
+        String sign = Signature.getSign(toMap());
+        setSign(sign);//把签名数据设置到Sign这个属性中
+
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getDevice_info() {
+        return device_info;
+    }
+
+    public void setDevice_info(String device_info) {
+        this.device_info = device_info;
+    }
+
+    public String getNonce_str() {
+        return nonce_str;
+    }
+
+    public void setNonce_str(String nonce_str) {
+        this.nonce_str = nonce_str;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public String getBody() {
+        return body;
+    }
+
+    public void setBody(String body) {
+        this.body = body;
+    }
+
+    public String getAttach() {
+        return attach;
+    }
+
+    public void setAttach(String attach) {
+        this.attach = attach;
+    }
+
+    public String getOut_trade_no() {
+        return out_trade_no;
+    }
+
+    public void setOut_trade_no(String out_trade_no) {
+        this.out_trade_no = out_trade_no;
+    }
+
+    public int getTotal_fee() {
+        return total_fee;
+    }
+
+    public void setTotal_fee(int total_fee) {
+        this.total_fee = total_fee;
+    }
+
+    public String getSpbill_create_ip() {
+        return spbill_create_ip;
+    }
+
+    public void setSpbill_create_ip(String spbill_create_ip) {
+        this.spbill_create_ip = spbill_create_ip;
+    }
+
+    public String getTime_start() {
+        return time_start;
+    }
+
+    public void setTime_start(String time_start) {
+        this.time_start = time_start;
+    }
+
+    public String getTime_expire() {
+        return time_expire;
+    }
+
+    public void setTime_expire(String time_expire) {
+        this.time_expire = time_expire;
+    }
+
+    public String getGoods_tag() {
+        return goods_tag;
+    }
+
+    public void setGoods_tag(String goods_tag) {
+        this.goods_tag = goods_tag;
+    }
+
+    public String getNotify_url() {
+        return notify_url;
+    }
+
+    public void setNotify_url(String notify_url) {
+        this.notify_url = notify_url;
+    }
+
+    public String getTrade_type() {
+        return trade_type;
+    }
+
+    public void setTrade_type(String trade_type){
+        this.trade_type = trade_type;
+    }
+
+    public Map<String,Object> toMap(){
+        Map<String,Object> map = new HashMap<String, Object>();
+        Field[] fields = this.getClass().getDeclaredFields();
+        for (Field field : fields) {
+            Object obj;
+            try {
+                obj = field.get(this);
+                if(obj!=null && obj!=""){
+                    map.put(field.getName(), obj);
+                }
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+        }
+        return map;
+    }
+
+}

+ 127 - 0
server/tools/src/main/java/com/tencent/protocol/pay_protocol/UnifiedOrderResData.java

@@ -0,0 +1,127 @@
+package com.nuliji.tools.third.tencent.protocol.pay_protocol;
+
+/**
+ * User: gaojie
+ * Date: 2017/05/10
+ * Time: 16:42
+ */
+
+/**
+ * 被扫支付提交Post数据给到API之后,API会返回XML格式的数据,这个类用来装这些数据
+ */
+public class UnifiedOrderResData {
+    //协议层
+    private String return_code = "";
+    private String return_msg = "";
+
+    //协议返回的具体数据(以下字段在return_code 为SUCCESS 的时候有返回)
+    private String appid = "";
+    private String mch_id = "";
+    private String nonce_str = "";
+    private String sign = "";
+    private String result_code = "";
+    private String err_code = "";
+    private String err_code_des = "";
+
+    private String device_info = "";
+
+    //业务返回的具体数据(以下字段在return_code 和result_code 都为SUCCESS 的时候有返回)
+    private String trade_type = "";
+    private String prepay_id = "";
+
+    public String getReturn_code() {
+        return return_code;
+    }
+
+    public void setReturn_code(String return_code) {
+        this.return_code = return_code;
+    }
+
+    public String getReturn_msg() {
+        return return_msg;
+    }
+
+    public void setReturn_msg(String return_msg) {
+        this.return_msg = return_msg;
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getDevice_info() {
+        return device_info;
+    }
+
+    public void setDevice_info(String device_info) {
+        this.device_info = device_info;
+    }
+
+    public String getNonce_str() {
+        return nonce_str;
+    }
+
+    public void setNonce_str(String nonce_str) {
+        this.nonce_str = nonce_str;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public String getResult_code() {
+        return result_code;
+    }
+
+    public void setResult_code(String result_code) {
+        this.result_code = result_code;
+    }
+
+    public String getErr_code() {
+        return err_code;
+    }
+
+    public void setErr_code(String err_code) {
+        this.err_code = err_code;
+    }
+
+    public String getErr_code_des() {
+        return err_code_des;
+    }
+
+    public void setErr_code_des(String err_code_des) {
+        this.err_code_des = err_code_des;
+    }
+
+    public String getTrade_type() {
+        return trade_type;
+    }
+
+    public void setTrade_type(String trade_type) {
+        this.trade_type = trade_type;
+    }
+
+    public String getPrepay_id() {
+        return prepay_id;
+    }
+
+    public void setPrepay_id(String prepay_id) {
+        this.prepay_id = prepay_id;
+    }
+}

+ 127 - 0
server/tools/src/main/java/com/tencent/protocol/pay_query_protocol/ScanPayQueryReqData.java

@@ -0,0 +1,127 @@
+package com.nuliji.tools.third.tencent.protocol.pay_query_protocol;
+
+import com.tencent.common.Configure;
+import com.tencent.common.RandomStringGenerator;
+import com.tencent.common.Signature;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/25
+ * Time: 13:54
+ */
+public class ScanPayQueryReqData {
+
+    //每个字段具体的意思请查看API文档
+    private String appid = "";
+    private String mch_id = "";
+    private String transaction_id = "";
+    private String out_trade_no = "";
+    private String nonce_str = "";
+    private String sign = "";
+
+    /**
+     * 请求支付查询服务
+     * @param transactionID 是微信系统为每一笔支付交易分配的订单号,通过这个订单号可以标识这笔交易,它由支付订单API支付成功时返回的数据里面获取到。建议优先使用
+     * @param outTradeNo 商户系统内部的订单号,transaction_id 、out_trade_no 二选一,如果同时存在优先级:transaction_id>out_trade_no
+     * @return API返回的XML数据
+     * @throws Exception
+     */
+    public ScanPayQueryReqData(String transactionID, String outTradeNo){
+
+        //--------------------------------------------------------------------
+        //以下是测试数据,请商户按照自己的实际情况填写具体的值进去
+        //--------------------------------------------------------------------
+
+        //微信分配的公众号ID(开通公众号之后可以获取到)
+        setAppid(Configure.getAppid());
+
+        //微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到)
+        setMch_id(Configure.getMchid());
+
+        //transaction_id是微信系统为每一笔支付交易分配的订单号,通过这个订单号可以标识这笔交易,它由支付订单API支付成功时返回的数据里面获取到。
+        setTransaction_id(transactionID);
+
+        //商户系统自己生成的唯一的订单号
+        setOut_trade_no(outTradeNo);
+
+        //随机字符串,不长于32 位
+        setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
+
+        //根据API给的签名规则进行签名
+        String sign = Signature.getSign(toMap());
+        setSign(sign);//把签名数据设置到Sign这个属性中
+
+
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getTransaction_id() {
+        return transaction_id;
+    }
+
+    public void setTransaction_id(String transaction_id) {
+        this.transaction_id = transaction_id;
+    }
+
+    public String getOut_trade_no() {
+        return out_trade_no;
+    }
+
+    public void setOut_trade_no(String out_trade_no) {
+        this.out_trade_no = out_trade_no;
+    }
+
+    public String getNonce_str() {
+        return nonce_str;
+    }
+
+    public void setNonce_str(String nonce_str) {
+        this.nonce_str = nonce_str;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public Map<String,Object> toMap(){
+        Map<String,Object> map = new HashMap<String, Object>();
+        Field[] fields = this.getClass().getDeclaredFields();
+        for (Field field : fields) {
+            Object obj;
+            try {
+                obj = field.get(this);
+                if(obj!=null){
+                    map.put(field.getName(), obj);
+                }
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+        }
+        return map;
+    }
+}

+ 260 - 0
server/tools/src/main/java/com/tencent/protocol/pay_query_protocol/ScanPayQueryResData.java

@@ -0,0 +1,260 @@
+package com.nuliji.tools.third.tencent.protocol.pay_query_protocol;
+
+import com.tencent.protocol.ResData;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/25
+ * Time: 13:54
+ */
+public class ScanPayQueryResData implements ResData {
+
+    //协议层
+    private String return_code = "";
+    private String return_msg = "";
+
+    //协议返回的具体数据(以下字段在return_code 为SUCCESS 的时候有返回)
+    private String appid = "";
+    private String mch_id = "";
+    private String sub_mch_id = "";//新增
+    private String nonce_str = "";
+    private String sign = "";
+    private String result_code = "";
+    private String err_code = "";
+    private String err_code_des = "";
+
+    //以下字段在return_code 和result_code 都为SUCCESS 的时候有返回
+    private String trade_state = "";
+
+    //trade_state的几种可能取值:
+    //    SUCCESS--支付成功
+    //    REFUND--转入退款
+    //    NOTPAY--未支付
+    //    CLOSED--已关闭
+    //    REVOKED--已撤销
+    //    USERPAYING--用户支付中
+    //    NOPAY--未支付(确认支付超时)
+    //    PAYERROR--支付失败(其他原因,
+    //            如银行返回失败)
+
+    //以下字段在trade_state 为SUCCESS 或者REFUND 的时候有返回
+    private String device_info = "";
+    private String openid = "";
+    private String is_subscribe = "";
+    private String trade_type = "";
+    private String bank_type = "";
+    private String total_fee = "";
+    private String coupon_fee = "";
+    private String fee_type = "";
+    private String transaction_id = "";
+    private String out_trade_no = "";
+    private String attach = "";
+    private String time_end = "";
+
+    public String getReturn_code() {
+        return return_code;
+    }
+
+    public void setReturn_code(String return_code) {
+        this.return_code = return_code;
+    }
+
+    public String getReturn_msg() {
+        return return_msg;
+    }
+
+    public void setReturn_msg(String return_msg) {
+        this.return_msg = return_msg;
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getSub_mch_id() {
+        return sub_mch_id;
+    }
+
+    public void setSub_mch_id(String sub_mch_id) {
+        this.sub_mch_id = sub_mch_id;
+    }
+
+    public String getNonce_str() {
+        return nonce_str;
+    }
+
+    public void setNonce_str(String nonce_str) {
+        this.nonce_str = nonce_str;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public String getResult_code() {
+        return result_code;
+    }
+
+    public void setResult_code(String result_code) {
+        this.result_code = result_code;
+    }
+
+    public String getErr_code() {
+        return err_code;
+    }
+
+    public void setErr_code(String err_code) {
+        this.err_code = err_code;
+    }
+
+    public String getErr_code_des() {
+        return err_code_des;
+    }
+
+    public void setErr_code_des(String err_code_des) {
+        this.err_code_des = err_code_des;
+    }
+
+    public String getTrade_state() {
+        return trade_state;
+    }
+
+    public void setTrade_state(String trade_state) {
+        this.trade_state = trade_state;
+    }
+
+    public String getDevice_info() {
+        return device_info;
+    }
+
+    public void setDevice_info(String device_info) {
+        this.device_info = device_info;
+    }
+
+    public String getOpenid() {
+        return openid;
+    }
+
+    public void setOpenid(String openid) {
+        this.openid = openid;
+    }
+
+    public String getIs_subscribe() {
+        return is_subscribe;
+    }
+
+    public void setIs_subscribe(String is_subscribe) {
+        this.is_subscribe = is_subscribe;
+    }
+
+    public String getTrade_type() {
+        return trade_type;
+    }
+
+    public void setTrade_type(String trade_type) {
+        this.trade_type = trade_type;
+    }
+
+    public String getBank_type() {
+        return bank_type;
+    }
+
+    public void setBank_type(String bank_type) {
+        this.bank_type = bank_type;
+    }
+
+    public String getTotal_fee() {
+        return total_fee;
+    }
+
+    public void setTotal_fee(String total_fee) {
+        this.total_fee = total_fee;
+    }
+
+    public String getCoupon_fee() {
+        return coupon_fee;
+    }
+
+    public void setCoupon_fee(String coupon_fee) {
+        this.coupon_fee = coupon_fee;
+    }
+
+    public String getFee_type() {
+        return fee_type;
+    }
+
+    public void setFee_type(String fee_type) {
+        this.fee_type = fee_type;
+    }
+
+    public String getTransaction_id() {
+        return transaction_id;
+    }
+
+    public void setTransaction_id(String transaction_id) {
+        this.transaction_id = transaction_id;
+    }
+
+    public String getOut_trade_no() {
+        return out_trade_no;
+    }
+
+    public void setOut_trade_no(String out_trade_no) {
+        this.out_trade_no = out_trade_no;
+    }
+
+    public String getAttach() {
+        return attach;
+    }
+
+    public void setAttach(String attach) {
+        this.attach = attach;
+    }
+
+    public String getTime_end() {
+        return time_end;
+    }
+
+    public void setTime_end(String time_end) {
+        this.time_end = time_end;
+    }
+
+    public Map<String,Object> toMap(){
+        Map<String,Object> map = new HashMap<String, Object>();
+        Field[] fields = this.getClass().getDeclaredFields();
+        for (Field field : fields) {
+            Object obj;
+            try {
+                obj = field.get(this);
+                if(obj!=null){
+                    map.put(field.getName(), obj);
+                }
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+        }
+        return map;
+    }
+}

+ 192 - 0
server/tools/src/main/java/com/tencent/protocol/refund_protocol/RefundReqData.java

@@ -0,0 +1,192 @@
+package com.nuliji.tools.third.tencent.protocol.refund_protocol;
+
+import com.tencent.common.Configure;
+import com.tencent.common.RandomStringGenerator;
+import com.tencent.common.Signature;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/25
+ * Time: 16:12
+ */
+public class RefundReqData {
+
+    //每个字段具体的意思请查看API文档
+    private String appid = "";
+    private String mch_id = "";
+    private String device_info = "";
+    private String nonce_str = "";
+    private String sign = "";
+    private String transaction_id = "";
+    private String out_trade_no = "";
+    private String out_refund_no = "";
+    private int total_fee = 0;
+    private int refund_fee = 0;
+    private String refund_fee_type = "CNY";
+    private String op_user_id = "";
+
+    /**
+     * 请求退款服务
+     * @param transactionID 是微信系统为每一笔支付交易分配的订单号,通过这个订单号可以标识这笔交易,它由支付订单API支付成功时返回的数据里面获取到。建议优先使用
+     * @param outTradeNo 商户系统内部的订单号,transaction_id 、out_trade_no 二选一,如果同时存在优先级:transaction_id>out_trade_no
+     * @param deviceInfo 微信支付分配的终端设备号,与下单一致
+     * @param outRefundNo 商户系统内部的退款单号,商户系统内部唯一,同一退款单号多次请求只退一笔
+     * @param totalFee 订单总金额,单位为分
+     * @param refundFee 退款总金额,单位为分,可以做部分退款
+     * @param opUserID 操作员帐号, 默认为商户号
+     * @param refundFeeType 货币类型,符合ISO 4217标准的三位字母代码,默认为CNY(人民币)
+     */
+    public RefundReqData(String transactionID,String outTradeNo,String deviceInfo,String outRefundNo,int totalFee,int refundFee,String opUserID,String refundFeeType){
+
+        //微信分配的公众号ID(开通公众号之后可以获取到)
+        setAppid(Configure.getAppid());
+
+        //微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到)
+        setMch_id(Configure.getMchid());
+
+        //transaction_id是微信系统为每一笔支付交易分配的订单号,通过这个订单号可以标识这笔交易,它由支付订单API支付成功时返回的数据里面获取到。
+        setTransaction_id(transactionID);
+
+        //商户系统自己生成的唯一的订单号
+        setOut_trade_no(outTradeNo);
+
+        //微信支付分配的终端设备号,与下单一致
+        setDevice_info(deviceInfo);
+
+        setOut_refund_no(outRefundNo);
+
+        setTotal_fee(totalFee);
+
+        setRefund_fee(refundFee);
+
+        setOp_user_id(opUserID);
+
+        //随机字符串,不长于32 位
+        setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
+
+        //根据API给的签名规则进行签名
+        String sign = Signature.getSign(toMap());
+        setSign(sign);//把签名数据设置到Sign这个属性中
+
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getDevice_info() {
+        return device_info;
+    }
+
+    public void setDevice_info(String device_info) {
+        this.device_info = device_info;
+    }
+
+    public String getNonce_str() {
+        return nonce_str;
+    }
+
+    public void setNonce_str(String nonce_str) {
+        this.nonce_str = nonce_str;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public String getTransaction_id() {
+        return transaction_id;
+    }
+
+    public void setTransaction_id(String transaction_id) {
+        this.transaction_id = transaction_id;
+    }
+
+    public String getOut_trade_no() {
+        return out_trade_no;
+    }
+
+    public void setOut_trade_no(String out_trade_no) {
+        this.out_trade_no = out_trade_no;
+    }
+
+    public String getOut_refund_no() {
+        return out_refund_no;
+    }
+
+    public void setOut_refund_no(String out_refund_no) {
+        this.out_refund_no = out_refund_no;
+    }
+
+    public int getTotal_fee() {
+        return total_fee;
+    }
+
+    public void setTotal_fee(int total_fee) {
+        this.total_fee = total_fee;
+    }
+
+    public int getRefund_fee() {
+        return refund_fee;
+    }
+
+    public void setRefund_fee(int refund_fee) {
+        this.refund_fee = refund_fee;
+    }
+
+    public String getOp_user_id() {
+        return op_user_id;
+    }
+
+    public void setOp_user_id(String op_user_id) {
+        this.op_user_id = op_user_id;
+    }
+
+    public String getRefund_fee_type() {
+        return refund_fee_type;
+    }
+
+    public void setRefund_fee_type(String refund_fee_type) {
+        this.refund_fee_type = refund_fee_type;
+    }
+
+    public Map<String,Object> toMap(){
+        Map<String,Object> map = new HashMap<String, Object>();
+        Field[] fields = this.getClass().getDeclaredFields();
+        for (Field field : fields) {
+            Object obj;
+            try {
+                obj = field.get(this);
+                if(obj!=null){
+                    map.put(field.getName(), obj);
+                }
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+        }
+        return map;
+    }
+
+}

+ 168 - 0
server/tools/src/main/java/com/tencent/protocol/refund_protocol/RefundResData.java

@@ -0,0 +1,168 @@
+package com.nuliji.tools.third.tencent.protocol.refund_protocol;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/25
+ * Time: 16:12
+ */
+public class RefundResData {
+
+    //协议层
+    private String return_code = "";
+    private String return_msg = "";
+
+    //协议返回的具体数据(以下字段在return_code 为SUCCESS 的时候有返回)
+    private String appid = "";
+    private String mch_id = "";
+    private String sub_mch_id = "";
+    private String device_info = "";
+    private String nonce_str = "";
+    private String sign = "";
+    private String result_code = "";
+    private String err_code = "";
+    private String err_code_des = "";
+
+
+    private String transaction_id = "";
+    private String out_trade_no = "";
+    private String out_refund_no = "";
+    private String refund_id = "";
+    private String refund_fee = "";
+    private String coupon_refund_fee = "";
+
+    public String getReturn_code() {
+        return return_code;
+    }
+
+    public void setReturn_code(String return_code) {
+        this.return_code = return_code;
+    }
+
+    public String getReturn_msg() {
+        return return_msg;
+    }
+
+    public void setReturn_msg(String return_msg) {
+        this.return_msg = return_msg;
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getSub_mch_id() {
+        return sub_mch_id;
+    }
+
+    public void setSub_mch_id(String sub_mch_id) {
+        this.sub_mch_id = sub_mch_id;
+    }
+
+    public String getDevice_info() {
+        return device_info;
+    }
+
+    public void setDevice_info(String device_info) {
+        this.device_info = device_info;
+    }
+
+    public String getNonce_str() {
+        return nonce_str;
+    }
+
+    public void setNonce_str(String nonce_str) {
+        this.nonce_str = nonce_str;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public String getResult_code() {
+        return result_code;
+    }
+
+    public void setResult_code(String result_code) {
+        this.result_code = result_code;
+    }
+
+    public String getErr_code() {
+        return err_code;
+    }
+
+    public void setErr_code(String err_code) {
+        this.err_code = err_code;
+    }
+
+    public String getErr_code_des() {
+        return err_code_des;
+    }
+
+    public void setErr_code_des(String err_code_des) {
+        this.err_code_des = err_code_des;
+    }
+
+    public String getTransaction_id() {
+        return transaction_id;
+    }
+
+    public void setTransaction_id(String transaction_id) {
+        this.transaction_id = transaction_id;
+    }
+
+    public String getOut_trade_no() {
+        return out_trade_no;
+    }
+
+    public void setOut_trade_no(String out_trade_no) {
+        this.out_trade_no = out_trade_no;
+    }
+
+    public String getOut_refund_no() {
+        return out_refund_no;
+    }
+
+    public void setOut_refund_no(String out_refund_no) {
+        this.out_refund_no = out_refund_no;
+    }
+
+    public String getRefund_id() {
+        return refund_id;
+    }
+
+    public void setRefund_id(String refund_id) {
+        this.refund_id = refund_id;
+    }
+
+    public String getRefund_fee() {
+        return refund_fee;
+    }
+
+    public void setRefund_fee(String refund_fee) {
+        this.refund_fee = refund_fee;
+    }
+
+    public String getCoupon_refund_fee() {
+        return coupon_refund_fee;
+    }
+
+    public void setCoupon_refund_fee(String coupon_refund_fee) {
+        this.coupon_refund_fee = coupon_refund_fee;
+    }
+}

+ 100 - 0
server/tools/src/main/java/com/tencent/protocol/refund_query_protocol/RefundOrderData.java

@@ -0,0 +1,100 @@
+package com.nuliji.tools.third.tencent.protocol.refund_query_protocol;
+
+import java.lang.reflect.Field;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * User: rizenguo
+ * Date: 2014/11/1
+ * Time: 14:09
+ * 用来存放退款订单数据
+ */
+public class RefundOrderData {
+
+    private String outRefundNo = "";//商户退款单号
+    private String refundID = "";//微信退款单号
+    private String refundChannel = "";//退款渠道
+//    IGINAL--原路退款
+//    BALANCE--退回到余额
+    private int refundFee = 0;//退款金额
+    private int couponRefundFee = 0;//企业红包退款金额
+    private String refundStatus = "";//退款状态
+
+    public String getOutRefundNo() {
+        return outRefundNo;
+    }
+
+    public void setOutRefundNo(String outRefundNo) {
+        this.outRefundNo = outRefundNo;
+    }
+
+    public String getRefundID() {
+        return refundID;
+    }
+
+    public void setRefundID(String refundID) {
+        this.refundID = refundID;
+    }
+
+    public String getRefundChannel() {
+        return refundChannel;
+    }
+
+    public void setRefundChannel(String refundChannel) {
+        this.refundChannel = refundChannel;
+    }
+
+    public int getRefundFee() {
+        return refundFee;
+    }
+
+    public void setRefundFee(int refundFee) {
+        this.refundFee = refundFee;
+    }
+
+    public int getCouponRefundFee() {
+        return couponRefundFee;
+    }
+
+    public void setCouponRefundFee(int couponRefundFee) {
+        this.couponRefundFee = couponRefundFee;
+    }
+
+    public String getRefundStatus() {
+        return refundStatus;
+    }
+
+    public void setRefundStatus(String refundStatus) {
+        this.refundStatus = refundStatus;
+    }
+
+    public String toMap(){
+        Map<String,Object> map = new LinkedHashMap<String, Object>();
+        Field[] fields = this.getClass().getDeclaredFields();
+        StringBuilder s=new StringBuilder("{");
+        
+        for (Field field : fields) {
+            Object obj;
+            try {
+                obj = field.get(this);
+                if(obj!=null){
+                	if(s.length()>0){
+                		s.append(" ");
+                	}
+                	s.append(field.getName());
+                	s.append("=");
+                	s.append(obj.toString());
+//                    map.put(field.getName(), obj);
+                }
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+        }
+        s.append("}");
+        return s.toString();
+    }
+
+}

+ 160 - 0
server/tools/src/main/java/com/tencent/protocol/refund_query_protocol/RefundQueryReqData.java

@@ -0,0 +1,160 @@
+package com.nuliji.tools.third.tencent.protocol.refund_query_protocol;
+
+import com.tencent.common.Configure;
+import com.tencent.common.RandomStringGenerator;
+import com.tencent.common.Signature;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/25
+ * Time: 16:35
+ */
+public class RefundQueryReqData {
+    //每个字段具体的意思请查看API文档
+    private String appid = "";
+    private String mch_id = "";
+    private String device_info = "";
+    private String nonce_str = "";
+    private String sign = "";
+    private String transaction_id = "";
+    private String out_trade_no = "";
+
+    /**
+     * 请求退款查询服务
+     * @param transactionID 是微信系统为每一笔支付交易分配的订单号,通过这个订单号可以标识这笔交易,它由支付订单API支付成功时返回的数据里面获取到。建议优先使用
+     * @param outTradeNo 商户系统内部的订单号,transaction_id 、out_trade_no 二选一,如果同时存在优先级:transaction_id>out_trade_no
+     * @param deviceInfo 微信支付分配的终端设备号,与下单一致
+     * @param outRefundNo 商户系统内部的退款单号,商户系统内部唯一,同一退款单号多次请求只退一笔
+     * @param refundID 来自退款API的成功返回,微信退款单号refund_id、out_refund_no、out_trade_no 、transaction_id 四个参数必填一个,如果同事存在优先级为:refund_id>out_refund_no>transaction_id>out_trade_no
+     */
+
+    public RefundQueryReqData(String transactionID,String outTradeNo,String deviceInfo,String outRefundNo,String refundID){
+
+        //微信分配的公众号ID(开通公众号之后可以获取到)
+        setAppid(Configure.getAppid());
+
+        //微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到)
+        setMch_id(Configure.getMchid());
+
+        //transaction_id是微信系统为每一笔支付交易分配的订单号,通过这个订单号可以标识这笔交易,它由支付订单API支付成功时返回的数据里面获取到。
+        setTransaction_id(transactionID);
+
+        //商户系统自己生成的唯一的订单号
+        setOut_trade_no(outTradeNo);
+
+        //微信支付分配的终端设备号,与下单一致
+        setDevice_info(deviceInfo);
+
+        setOut_refund_no(outRefundNo);
+
+        //商户系统自己管理的退款号,商户自身必须保证这个号在系统内唯一
+        setRefund_id(refundID);
+
+        //随机字符串,不长于32 位
+        setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
+
+        //根据API给的签名规则进行签名
+        String sign = Signature.getSign(toMap());
+        setSign(sign);//把签名数据设置到Sign这个属性中
+
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getDevice_info() {
+        return device_info;
+    }
+
+    public void setDevice_info(String device_info) {
+        this.device_info = device_info;
+    }
+
+    public String getNonce_str() {
+        return nonce_str;
+    }
+
+    public void setNonce_str(String nonce_str) {
+        this.nonce_str = nonce_str;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public String getTransaction_id() {
+        return transaction_id;
+    }
+
+    public void setTransaction_id(String transaction_id) {
+        this.transaction_id = transaction_id;
+    }
+
+    public String getOut_trade_no() {
+        return out_trade_no;
+    }
+
+    public void setOut_trade_no(String out_trade_no) {
+        this.out_trade_no = out_trade_no;
+    }
+
+    public String getOut_refund_no() {
+        return out_refund_no;
+    }
+
+    public void setOut_refund_no(String out_refund_no) {
+        this.out_refund_no = out_refund_no;
+    }
+
+    public String getRefund_id() {
+        return refund_id;
+    }
+
+    public void setRefund_id(String refund_id) {
+        this.refund_id = refund_id;
+    }
+
+    private String out_refund_no;
+    private String refund_id;
+
+    public Map<String,Object> toMap(){
+        Map<String,Object> map = new HashMap<String, Object>();
+        Field[] fields = this.getClass().getDeclaredFields();
+        for (Field field : fields) {
+            Object obj;
+            try {
+                obj = field.get(this);
+                if(obj!=null){
+                    map.put(field.getName(), obj);
+                }
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+        }
+        return map;
+    }
+
+}

+ 187 - 0
server/tools/src/main/java/com/tencent/protocol/refund_query_protocol/RefundQueryResData.java

@@ -0,0 +1,187 @@
+package com.nuliji.tools.third.tencent.protocol.refund_query_protocol;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/25
+ * Time: 16:36
+ */
+public class RefundQueryResData {
+    //协议层
+    private String return_code = "";
+    private String return_msg = "";
+
+    //协议返回的具体数据(以下字段在return_code 为SUCCESS 的时候有返回)
+    private String result_code = "";
+    private String err_code = "";
+    private String err_code_des = "";
+    private String appid = "";
+    private String mch_id = "";
+    private String nonce_str = "";
+    private String sign = "";
+
+
+    private String device_info = "";
+    private String transaction_id = "";
+    private String out_trade_no = "";
+    private int refund_count = 0;
+
+    //TODO 这里要用对象来装,因为有可能出现多个数据
+    private String out_refund_no = "";
+    private String refund_id = "";
+    private String refund_channel = "";
+    private String refund_fee = "";
+    private String coupon_refund_fee = "";
+    private String refund_status = "";
+
+    public String getReturn_code() {
+        return return_code;
+    }
+
+    public void setReturn_code(String return_code) {
+        this.return_code = return_code;
+    }
+
+    public String getReturn_msg() {
+        return return_msg;
+    }
+
+    public void setReturn_msg(String return_msg) {
+        this.return_msg = return_msg;
+    }
+
+    public String getResult_code() {
+        return result_code;
+    }
+
+    public void setResult_code(String result_code) {
+        this.result_code = result_code;
+    }
+
+    public String getErr_code() {
+        return err_code;
+    }
+
+    public void setErr_code(String err_code) {
+        this.err_code = err_code;
+    }
+
+    public String getErr_code_des() {
+        return err_code_des;
+    }
+
+    public void setErr_code_des(String err_code_des) {
+        this.err_code_des = err_code_des;
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getNonce_str() {
+        return nonce_str;
+    }
+
+    public void setNonce_str(String nonce_str) {
+        this.nonce_str = nonce_str;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public String getDevice_info() {
+        return device_info;
+    }
+
+    public void setDevice_info(String device_info) {
+        this.device_info = device_info;
+    }
+
+    public String getTransaction_id() {
+        return transaction_id;
+    }
+
+    public void setTransaction_id(String transaction_id) {
+        this.transaction_id = transaction_id;
+    }
+
+    public String getOut_trade_no() {
+        return out_trade_no;
+    }
+
+    public void setOut_trade_no(String out_trade_no) {
+        this.out_trade_no = out_trade_no;
+    }
+
+    public int getRefund_count() {
+        return refund_count;
+    }
+
+    public void setRefund_count(int refund_count) {
+        this.refund_count = refund_count;
+    }
+
+    public String getOut_refund_no() {
+        return out_refund_no;
+    }
+
+    public void setOut_refund_no(String out_refund_no) {
+        this.out_refund_no = out_refund_no;
+    }
+
+    public String getRefund_id() {
+        return refund_id;
+    }
+
+    public void setRefund_id(String refund_id) {
+        this.refund_id = refund_id;
+    }
+
+    public String getRefund_channel() {
+        return refund_channel;
+    }
+
+    public void setRefund_channel(String refund_channel) {
+        this.refund_channel = refund_channel;
+    }
+
+    public String getRefund_fee() {
+        return refund_fee;
+    }
+
+    public void setRefund_fee(String refund_fee) {
+        this.refund_fee = refund_fee;
+    }
+
+    public String getCoupon_refund_fee() {
+        return coupon_refund_fee;
+    }
+
+    public void setCoupon_refund_fee(String coupon_refund_fee) {
+        this.coupon_refund_fee = coupon_refund_fee;
+    }
+
+    public String getRefund_status() {
+        return refund_status;
+    }
+
+    public void setRefund_status(String refund_status) {
+        this.refund_status = refund_status;
+    }
+}

+ 127 - 0
server/tools/src/main/java/com/tencent/protocol/reverse_protocol/ReverseReqData.java

@@ -0,0 +1,127 @@
+package com.nuliji.tools.third.tencent.protocol.reverse_protocol;
+
+import com.tencent.common.Configure;
+import com.tencent.common.RandomStringGenerator;
+import com.tencent.common.Signature;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/25
+ * Time: 16:42
+ */
+public class ReverseReqData {
+    //每个字段具体的意思请查看API文档
+    private String appid = "";
+    private String mch_id = "";
+    private String transaction_id = "";
+    private String out_trade_no = "";
+    private String nonce_str = "";
+    private String sign = "";
+
+    /**
+     * 请求撤销服务
+     * @param transactionID 是微信系统为每一笔支付交易分配的订单号,通过这个订单号可以标识这笔交易,它由支付订单API支付成功时返回的数据里面获取到。建议优先使用
+     * @param outTradeNo 商户系统内部的订单号,transaction_id 、out_trade_no 二选一,如果同时存在优先级:transaction_id>out_trade_no
+     * @return API返回的XML数据
+     * @throws Exception
+     */
+
+    public ReverseReqData(String transactionID,String outTradeNo){
+
+        //--------------------------------------------------------------------
+        //以下是测试数据,请商户按照自己的实际情况填写具体的值进去
+        //--------------------------------------------------------------------
+
+        //微信分配的公众号ID(开通公众号之后可以获取到)
+        setAppid(Configure.getAppid());
+
+        //微信支付分配的商户号ID(开通公众号的微信支付功能之后可以获取到)
+        setMch_id(Configure.getMchid());
+
+        //transaction_id是微信系统为每一笔支付交易分配的订单号,通过这个订单号可以标识这笔交易,它由支付订单API支付成功时返回的数据里面获取到。
+        setTransaction_id(transactionID);
+
+        //商户系统自己生成的唯一的订单号
+        setOut_trade_no(outTradeNo);
+
+        //随机字符串,不长于32 位
+        setNonce_str(RandomStringGenerator.getRandomStringByLength(32));
+
+        //根据API给的签名规则进行签名
+        String sign = Signature.getSign(toMap());
+        setSign(sign);//把签名数据设置到Sign这个属性中
+
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getTransaction_id() {
+        return transaction_id;
+    }
+
+    public void setTransaction_id(String transaction_id) {
+        this.transaction_id = transaction_id;
+    }
+
+    public String getOut_trade_no() {
+        return out_trade_no;
+    }
+
+    public void setOut_trade_no(String out_trade_no) {
+        this.out_trade_no = out_trade_no;
+    }
+
+    public String getNonce_str() {
+        return nonce_str;
+    }
+
+    public void setNonce_str(String nonce_str) {
+        this.nonce_str = nonce_str;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public Map<String,Object> toMap(){
+        Map<String,Object> map = new HashMap<String, Object>();
+        Field[] fields = this.getClass().getDeclaredFields();
+        for (Field field : fields) {
+            Object obj;
+            try {
+                obj = field.get(this);
+                if(obj!=null){
+                    map.put(field.getName(), obj);
+                }
+            } catch (IllegalArgumentException e) {
+                e.printStackTrace();
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            }
+        }
+        return map;
+    }
+
+}

+ 104 - 0
server/tools/src/main/java/com/tencent/protocol/reverse_protocol/ReverseResData.java

@@ -0,0 +1,104 @@
+package com.nuliji.tools.third.tencent.protocol.reverse_protocol;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/25
+ * Time: 16:43
+ */
+public class ReverseResData {
+
+    //协议层
+    private String return_code = "";
+    private String return_msg = "";
+
+    //协议返回的具体数据(以下字段在return_code 为SUCCESS 的时候有返回)
+    private String result_code = "";
+    private String err_code = "";
+    private String err_code_des = "";
+    private String sign = "";
+    private String appid = "";
+    private String mch_id = "";
+    private String nonce_str = "";
+
+    private String recall = "";
+
+    public String getReturn_code() {
+        return return_code;
+    }
+
+    public void setReturn_code(String return_code) {
+        this.return_code = return_code;
+    }
+
+    public String getReturn_msg() {
+        return return_msg;
+    }
+
+    public void setReturn_msg(String return_msg) {
+        this.return_msg = return_msg;
+    }
+
+    public String getResult_code() {
+        return result_code;
+    }
+
+    public void setResult_code(String result_code) {
+        this.result_code = result_code;
+    }
+
+    public String getErr_code() {
+        return err_code;
+    }
+
+    public void setErr_code(String err_code) {
+        this.err_code = err_code;
+    }
+
+    public String getErr_code_des() {
+        return err_code_des;
+    }
+
+    public void setErr_code_des(String err_code_des) {
+        this.err_code_des = err_code_des;
+    }
+
+    public String getAppid() {
+        return appid;
+    }
+
+    public void setAppid(String appid) {
+        this.appid = appid;
+    }
+
+    public String getMch_id() {
+        return mch_id;
+    }
+
+    public void setMch_id(String mch_id) {
+        this.mch_id = mch_id;
+    }
+
+    public String getNonce_str() {
+        return nonce_str;
+    }
+
+    public void setNonce_str(String nonce_str) {
+        this.nonce_str = nonce_str;
+    }
+
+    public String getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    public String getRecall() {
+        return recall;
+    }
+
+    public void setRecall(String recall) {
+        this.recall = recall;
+    }
+}

+ 42 - 0
server/tools/src/main/java/com/tencent/service/BaseService.java

@@ -0,0 +1,42 @@
+package com.nuliji.tools.third.tencent.service;
+
+import com.tencent.common.Configure;
+
+import java.io.IOException;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+
+/**
+ * User: rizenguo
+ * Date: 2014/12/10
+ * Time: 15:44
+ * 服务的基类
+ */
+public class BaseService{
+
+    //API的地址
+    private String apiURL;
+
+    //发请求的HTTPS请求器
+    private IServiceRequest serviceRequest;
+
+    public BaseService(String api) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
+        apiURL = api;
+        Class c = Class.forName(Configure.HttpsRequestClassName);
+        serviceRequest = (IServiceRequest) c.newInstance();
+    }
+
+    protected String sendPost(Object xmlObj) throws UnrecoverableKeyException, IOException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
+        return serviceRequest.sendPost(apiURL,xmlObj);
+    }
+
+    /**
+     * 供商户想自定义自己的HTTP请求器用
+     * @param request 实现了IserviceRequest接口的HttpsRequest
+     */
+    public void setServiceRequest(IServiceRequest request){
+        serviceRequest = request;
+    }
+}

+ 46 - 0
server/tools/src/main/java/com/tencent/service/DownloadBillService.java

@@ -0,0 +1,46 @@
+package com.nuliji.tools.third.tencent.service;
+
+import com.tencent.common.Configure;
+import com.tencent.protocol.downloadbill_protocol.DownloadBillReqData;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/29
+ * Time: 16:04
+ */
+public class DownloadBillService extends BaseService{
+
+    public DownloadBillService() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
+        super(Configure.DOWNLOAD_BILL_API);
+    }
+
+    //ALL,返回当日所有订单信息,默认值
+    public static final String BILL_TYPE_ALL = "ALL";
+
+    //SUCCESS,返回当日成功支付的订单
+    public static final String BILL_TYPE_SUCCESS = "SUCCESS";
+
+    //REFUND,返回当日退款订单
+    public static final String BILL_TYPE_REFUND = "REFUND";
+
+    //REVOKED,已撤销的订单
+    public static final String BILL_TYPE_REVOKE = "REVOKE";
+
+
+    /**
+     * 请求对账单下载服务
+     * @param downloadBillReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的XML数据
+     * @throws Exception
+     */
+    public String request(DownloadBillReqData downloadBillReqData) throws Exception {
+
+        //--------------------------------------------------------------------
+        //发送HTTPS的Post请求到API地址
+        //--------------------------------------------------------------------
+        String responseString = sendPost(downloadBillReqData);
+
+        return responseString;
+    }
+
+}

+ 20 - 0
server/tools/src/main/java/com/tencent/service/IServiceRequest.java

@@ -0,0 +1,20 @@
+package com.nuliji.tools.third.tencent.service;
+
+import java.io.IOException;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+
+/**
+ * User: rizenguo
+ * Date: 2014/12/10
+ * Time: 15:16
+ * 这里定义服务层需要请求器标准接口
+ */
+public interface IServiceRequest {
+
+    //Service依赖的底层https请求器必须实现这么一个接口
+    public String sendPost(String api_url, Object xmlObj) throws UnrecoverableKeyException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, IOException;
+
+}

+ 36 - 0
server/tools/src/main/java/com/tencent/service/RefundQueryService.java

@@ -0,0 +1,36 @@
+package com.nuliji.tools.third.tencent.service;
+
+import com.tencent.common.Configure;
+import com.tencent.protocol.refund_query_protocol.RefundQueryReqData;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/29
+ * Time: 16:04
+ */
+public class RefundQueryService extends BaseService{
+
+    public RefundQueryService() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
+        super(Configure.REFUND_QUERY_API);
+    }
+
+    /**
+     * 请求退款查询服务
+     * @param refundQueryReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的XML数据
+     * @throws Exception
+     */
+    public String request(RefundQueryReqData refundQueryReqData) throws Exception {
+
+        //--------------------------------------------------------------------
+        //发送HTTPS的Post请求到API地址
+        //--------------------------------------------------------------------
+        String responseString = sendPost(refundQueryReqData);
+
+        return responseString;
+    }
+
+
+
+
+}

+ 33 - 0
server/tools/src/main/java/com/tencent/service/RefundService.java

@@ -0,0 +1,33 @@
+package com.nuliji.tools.third.tencent.service;
+
+import com.tencent.common.Configure;
+import com.tencent.protocol.refund_protocol.RefundReqData;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/29
+ * Time: 16:04
+ */
+public class RefundService extends BaseService{
+
+    public RefundService() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
+        super(Configure.REFUND_API);
+    }
+
+    /**
+     * 请求退款服务
+     * @param refundReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的XML数据
+     * @throws Exception
+     */
+    public String request(RefundReqData refundReqData) throws Exception {
+
+        //--------------------------------------------------------------------
+        //发送HTTPS的Post请求到API地址
+        //--------------------------------------------------------------------
+        String responseString = sendPost(refundReqData);
+
+        return responseString;
+    }
+
+}

+ 33 - 0
server/tools/src/main/java/com/tencent/service/ReverseService.java

@@ -0,0 +1,33 @@
+package com.nuliji.tools.third.tencent.service;
+
+import com.tencent.common.Configure;
+import com.tencent.protocol.reverse_protocol.ReverseReqData;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/29
+ * Time: 16:04
+ */
+public class ReverseService extends BaseService{
+
+    public ReverseService() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
+        super(Configure.REVERSE_API);
+    }
+
+    /**
+     * 请求撤销服务
+     * @param reverseReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的XML数据
+     * @throws Exception
+     */
+    public String request(ReverseReqData reverseReqData) throws Exception {
+
+        //--------------------------------------------------------------------
+        //发送HTTPS的Post请求到API地址
+        //--------------------------------------------------------------------
+        String responseString = sendPost(reverseReqData);
+
+        return responseString;
+    }
+
+}

+ 34 - 0
server/tools/src/main/java/com/tencent/service/ScanPayQueryService.java

@@ -0,0 +1,34 @@
+package com.nuliji.tools.third.tencent.service;
+
+import com.tencent.common.Configure;
+import com.tencent.protocol.pay_query_protocol.ScanPayQueryReqData;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/29
+ * Time: 16:04
+ */
+public class ScanPayQueryService extends BaseService{
+
+    public ScanPayQueryService() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
+        super(Configure.PAY_QUERY_API);
+    }
+
+    /**
+     * 请求支付查询服务
+     * @param scanPayQueryReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的XML数据
+     * @throws Exception
+     */
+    public String request(ScanPayQueryReqData scanPayQueryReqData) throws Exception {
+
+        //--------------------------------------------------------------------
+        //发送HTTPS的Post请求到API地址
+        //--------------------------------------------------------------------
+        String responseString = sendPost(scanPayQueryReqData);
+
+        return responseString;
+    }
+
+
+}

+ 32 - 0
server/tools/src/main/java/com/tencent/service/ScanPayService.java

@@ -0,0 +1,32 @@
+package com.nuliji.tools.third.tencent.service;
+
+import com.tencent.common.*;
+import com.tencent.protocol.pay_protocol.ScanPayReqData;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/29
+ * Time: 16:03
+ */
+public class ScanPayService extends BaseService{
+
+    public ScanPayService() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
+        super(Configure.PAY_API);
+    }
+
+    /**
+     * 请求支付服务
+     * @param scanPayReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的数据
+     * @throws Exception
+     */
+    public String request(ScanPayReqData scanPayReqData) throws Exception {
+
+        //--------------------------------------------------------------------
+        //发送HTTPS的Post请求到API地址
+        //--------------------------------------------------------------------
+        String responseString = sendPost(scanPayReqData);
+
+        return responseString;
+    }
+}

+ 32 - 0
server/tools/src/main/java/com/tencent/service/UnifiedOrderService.java

@@ -0,0 +1,32 @@
+package com.nuliji.tools.third.tencent.service;
+
+import com.tencent.common.Configure;
+import com.tencent.protocol.pay_protocol.UnifiedOrderReqData;
+
+/**
+ * User: rizenguo
+ * Date: 2014/10/29
+ * Time: 16:03
+ */
+public class UnifiedOrderService extends BaseService{
+
+    public UnifiedOrderService() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
+        super(Configure.UNIFIED_ORDER_API);
+    }
+
+    /**
+     * 请求支付服务
+     * @param unifiedOrderReqData 这个数据对象里面包含了API要求提交的各种数据字段
+     * @return API返回的数据
+     * @throws Exception
+     */
+    public String request(UnifiedOrderReqData unifiedOrderReqData) throws Exception {
+
+        //--------------------------------------------------------------------
+        //发送HTTPS的Post请求到API地址
+        //--------------------------------------------------------------------
+        String responseString = sendPost(unifiedOrderReqData);
+
+        return responseString;
+    }
+}