diff --git a/lib/bcpkix-jdk15on-1.59.jar b/lib/bcpkix-jdk15on-1.59.jar new file mode 100644 index 0000000..7279816 Binary files /dev/null and b/lib/bcpkix-jdk15on-1.59.jar differ diff --git a/lib/bcprov-ext-jdk15on-1.59.jar b/lib/bcprov-ext-jdk15on-1.59.jar new file mode 100644 index 0000000..3f03fda Binary files /dev/null and b/lib/bcprov-ext-jdk15on-1.59.jar differ diff --git a/lib/bcprov-jdk15on-1.59.jar b/lib/bcprov-jdk15on-1.59.jar new file mode 100644 index 0000000..9049e56 Binary files /dev/null and b/lib/bcprov-jdk15on-1.59.jar differ diff --git a/lib/commons-beanutils-1.8.3.jar b/lib/commons-beanutils-1.8.3.jar new file mode 100644 index 0000000..218510b Binary files /dev/null and b/lib/commons-beanutils-1.8.3.jar differ diff --git a/lib/commons-codec-1.11.jar b/lib/commons-codec-1.11.jar new file mode 100644 index 0000000..2245120 Binary files /dev/null and b/lib/commons-codec-1.11.jar differ diff --git a/lib/commons-collections-3.2.1.jar b/lib/commons-collections-3.2.1.jar new file mode 100644 index 0000000..c35fa1f Binary files /dev/null and b/lib/commons-collections-3.2.1.jar differ diff --git a/lib/commons-lang-2.6.jar b/lib/commons-lang-2.6.jar new file mode 100644 index 0000000..98467d3 Binary files /dev/null and b/lib/commons-lang-2.6.jar differ diff --git a/lib/commons-logging-1.1.3.jar b/lib/commons-logging-1.1.3.jar new file mode 100644 index 0000000..ab51254 Binary files /dev/null and b/lib/commons-logging-1.1.3.jar differ diff --git a/lib/ezmorph-1.0.6.jar b/lib/ezmorph-1.0.6.jar new file mode 100644 index 0000000..30fad12 Binary files /dev/null and b/lib/ezmorph-1.0.6.jar differ diff --git a/lib/json-lib-2.4-jdk15.jar b/lib/json-lib-2.4-jdk15.jar new file mode 100644 index 0000000..68d4f3b Binary files /dev/null and b/lib/json-lib-2.4-jdk15.jar differ diff --git a/pom.xml b/pom.xml index 4a08061..8afc483 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.xkrs - fire_point + fire_point_allinpay 0.0.1 fire_point 火点项目 @@ -253,6 +253,18 @@ 1.1.1 + + com.google.zxing + core + 3.4.1 + + + + com.google.zxing + javase + 3.4.1 + + diff --git a/src/main/java/com/xkrs/allinpay/SybPayController.java b/src/main/java/com/xkrs/allinpay/SybPayController.java new file mode 100644 index 0000000..4a442b5 --- /dev/null +++ b/src/main/java/com/xkrs/allinpay/SybPayController.java @@ -0,0 +1,375 @@ +package com.xkrs.allinpay; + + +import cn.hutool.core.util.StrUtil; +import com.xkrs.allinpay.model.*; +import com.xkrs.allinpay.utils.QRCodeUtils; +import com.xkrs.allinpay.utils.SybConstants; +import com.xkrs.allinpay.utils.SybUtil; +import com.xkrs.common.encapsulation.PromptMessageEnum; +import com.xkrs.common.tool.TokenUtil; +import com.xkrs.dao.SysUserDao; +import com.xkrs.dao.TranNotifyDao; +import com.xkrs.dao.TranQueryDao; +import com.xkrs.dao.UnitOrderPayDao; +import com.xkrs.model.entity.SysUserEntity; +import com.xkrs.websocket.pay.PayWebSocketUsers; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.persistence.criteria.Predicate; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.stream.Collectors; + +import static com.xkrs.common.encapsulation.OutputEncapsulation.outputEncapsulationObject; + +@RestController +@RequestMapping(value = "/pay") +public class SybPayController { + + public static Logger log = LoggerFactory.getLogger(SybPayController.class); + private final Locale locale = LocaleContextHolder.getLocale(); + + private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + @Value("${qrCode.saveDirPath}") + public String qrCodeSaveDirPath; + + @Value("${qrCode.accessDirPath}") + public String qrCodeAccessDirPath; + + @Value("${pay.notifyUrl}") + public String payNotifyUrl; + + @Resource + private SysUserDao sysUserDao; + + @Resource + private UnitOrderPayDao unitOrderPayDao; + + @Resource + private TranNotifyDao tranNotifyDao; + + @Resource + private TranQueryDao tranQueryDao; + + @GetMapping("/notify1") + public String getNotify(HttpServletRequest request) { + return outputEncapsulationObject(PromptMessageEnum.SUCCESS, "get method,no deal", locale); + } + + @PostMapping("/notify") + public String postNotify(HttpServletRequest request) throws ServletException, IOException { + System.out.println("收到用户支付通知"); + request.setCharacterEncoding("UTF-8");//通知传输的编码为GBK + + TreeMap notifyMap = new TreeMap(); + Map params = request.getParameterMap(); + for (Object key : params.keySet()) { + String value = ((String[]) params.get(key))[0]; + System.out.println(key + ";" + value); + notifyMap.put(key.toString(), value); + } + + try { + String appkey = ""; + if ("RSA".equals(notifyMap.get("signtype"))) appkey = SybConstants.SYB_RSATLPUBKEY; + else if ("SM2".equals(notifyMap.get("signtype"))) appkey = SybConstants.SYB_SM2TLPUBKEY; + else appkey = SybConstants.SYB_MD5_APPKEY; + boolean isSign = SybUtil.validSign(notifyMap, appkey, notifyMap.get("signtype"));// 接受到推送通知,首先验签 + System.out.println("验签结果:" + isSign); + //验签完毕进行业务处理 + + //收到的支付通知 + TranNotifyEntity tranNotifyEntity = TranNotifyUtils.getEntityByMap(notifyMap); + //保存(或更新)交易通知 + saveAndUpdateTranNotify(tranNotifyEntity); + + //再查一下订单 + final String trxid = tranNotifyEntity.getTrxid(); + SybPayService service = new SybPayService(); + Map queryMap = service.query("", trxid); + TranQueryEntity tranQueryEntity = TranQueryUtils.getEntityByMap(queryMap); + UnitOrderPayEntity unitOrderPay = getUnitOrderPayByTranQuery(tranQueryEntity); + if (unitOrderPay != null) { + tranQueryEntity.setOrderid(unitOrderPay.getId()); + } + //保存(或更新)交易查询 + saveAndUpdateTranQuery(tranQueryEntity); + + //判断用户支付成功 + if ("0000".equals(tranNotifyEntity.getTrxstatus())) { + if (unitOrderPay != null) { + unitOrderPay.setPayResult("支付成功"); + unitOrderPayDao.saveAndFlush(unitOrderPay); + } + //通知前端支付成功 + log.info("支付成功"); + String retMsg = outputEncapsulationObject(PromptMessageEnum.SUCCESS, "支付成功", locale); + PayWebSocketUsers.sendMessageToUsersByText(retMsg); + return "success"; + } + if (unitOrderPay != null) { + unitOrderPay.setPayResult("支付失败"); + unitOrderPayDao.saveAndFlush(unitOrderPay); + } + //通知前端支付失败 + log.info("支付失败"); + String retMsg = outputEncapsulationObject(PromptMessageEnum.PROCESS_FAIL, "支付失败", locale); + PayWebSocketUsers.sendMessageToUsersByText(retMsg); + return "fail"; + } catch (Exception e) {//处理异常 + e.printStackTrace(); + log.info(e.getMessage()); + return "fail"; + } + + } + + private void saveAndUpdateTranNotify(TranNotifyEntity newTranNotify) throws Exception { + + final String cusid = newTranNotify.getCusid(); + final String appid = newTranNotify.getAppid(); + final String trxid = newTranNotify.getTrxid(); + final String cusorderid = newTranNotify.getCusorderid(); + + Specification notifySpecification = (root, criteriaQuery, criteriaBuilder) -> { + //查询条件集合 + List predicateList = new ArrayList<>(); + + predicateList.add(criteriaBuilder.equal(root.get("cusid").as(String.class), cusid)); + predicateList.add(criteriaBuilder.equal(root.get("appid").as(String.class), appid)); + predicateList.add(criteriaBuilder.equal(root.get("trxid").as(String.class), trxid)); + predicateList.add(criteriaBuilder.equal(root.get("cusorderid").as(String.class), cusorderid)); + + Predicate[] predicateArray = new Predicate[predicateList.size()]; + return criteriaBuilder.and(predicateList.toArray(predicateArray)); + }; + + List oldTranNotifyList = tranNotifyDao.findAll(notifySpecification); + if (oldTranNotifyList.isEmpty()) { + System.out.println("用户支付通知成功"); + tranNotifyDao.saveAndFlush(newTranNotify); + } else if (oldTranNotifyList.size() == 1) { + //TODO 用户支付重复通知一次 + System.out.println("用户支付重复通知一次"); + TranNotifyEntity oldTranNotify = oldTranNotifyList.get(0); + TranNotifyUtils.updateEntity(newTranNotify, oldTranNotify); + tranNotifyDao.saveAndFlush(oldTranNotify); + } else { + //TODO 用户支付重复通知多次 + System.out.println("用户支付重复通知多次"); + for (TranNotifyEntity oldTranNotify : oldTranNotifyList) { + TranNotifyUtils.updateEntity(newTranNotify, oldTranNotify); + tranNotifyDao.saveAndFlush(oldTranNotify); + } + } + + } + + private void saveAndUpdateTranQuery(TranQueryEntity newTranQuery) throws Exception { + + String cusid = newTranQuery.getCusid(); + String appid = newTranQuery.getAppid(); + String trxid = newTranQuery.getTrxid(); + String reqsn = newTranQuery.getReqsn(); + + Specification querySpecification = (root, criteriaQuery, criteriaBuilder) -> { + //查询条件集合 + List predicateList = new ArrayList<>(); + + predicateList.add(criteriaBuilder.equal(root.get("cusid").as(String.class), cusid)); + predicateList.add(criteriaBuilder.equal(root.get("appid").as(String.class), appid)); + predicateList.add(criteriaBuilder.equal(root.get("trxid").as(String.class), trxid)); + predicateList.add(criteriaBuilder.equal(root.get("reqsn").as(String.class), reqsn)); + + Predicate[] predicateArray = new Predicate[predicateList.size()]; + return criteriaBuilder.and(predicateList.toArray(predicateArray)); + }; + + List oldTranQueryList = tranQueryDao.findAll(querySpecification); + if (oldTranQueryList.isEmpty()) { + System.out.println("用户支付查询成功"); + tranQueryDao.saveAndFlush(newTranQuery); + } else if (oldTranQueryList.size() == 1) { + //TODO 用户支付重复查询一次 + System.out.println("用户支付重复查询一次"); + TranQueryEntity oldTranQuery = oldTranQueryList.get(0); + TranQueryUtils.updateEntity(newTranQuery, oldTranQuery); + tranQueryDao.saveAndFlush(oldTranQuery); + } else { + //TODO 用户支付重复查询多次 + System.out.println("用户支付重复查询多次"); + for (TranQueryEntity oldTranQuery : oldTranQueryList) { + TranQueryUtils.updateEntity(newTranQuery, oldTranQuery); + tranQueryDao.saveAndFlush(oldTranQuery); + } + } + + } + + /** + * 通过查询记录找到订单记录 + */ + private UnitOrderPayEntity getUnitOrderPayByTranQuery(TranQueryEntity tranQueryEntity) { + + String cusid = tranQueryEntity.getCusid(); + String appid = tranQueryEntity.getAppid(); + String trxid = tranQueryEntity.getTrxid(); + String reqsn = tranQueryEntity.getReqsn(); + + Specification orderSpecification = (root, criteriaQuery, criteriaBuilder) -> { + //查询条件集合 + List predicateList = new ArrayList<>(); + + predicateList.add(criteriaBuilder.equal(root.get("cusid").as(String.class), cusid)); + predicateList.add(criteriaBuilder.equal(root.get("appid").as(String.class), appid)); + predicateList.add(criteriaBuilder.equal(root.get("trxid").as(String.class), trxid)); + predicateList.add(criteriaBuilder.equal(root.get("reqsn").as(String.class), reqsn)); + + Predicate[] predicateArray = new Predicate[predicateList.size()]; + return criteriaBuilder.and(predicateList.toArray(predicateArray)); + }; + + List orderList = unitOrderPayDao.findAll(orderSpecification); + if (orderList.isEmpty()) { + System.out.println("用户更新订单不存在"); + return null; + } + if (orderList.size() == 1) { + System.out.println("用户更新订单成功"); + return orderList.get(0); + } + System.out.println("用户支付重复查询多次"); + return orderList.get(0); + + } + + /** + * 统一下单支付 + */ + @PostMapping("/unitorderpay") + public String unitOrderPay(@RequestHeader(value = "Authorization") String token, @RequestBody UnitOrderPayQo unitOrderPayQo) { + try { + // 验证token + String tokenUserName = TokenUtil.getTokenUserName(token); + SysUserEntity sysUserEntity = sysUserDao.selectByUserName(tokenUserName); + if (sysUserEntity == null) { + return outputEncapsulationObject(PromptMessageEnum.PROCESS_FAIL, "您还没有注册登录,请先注册登录", locale); + } + String trxAmtYuan = unitOrderPayQo.getTrxAmtYuan(); + String payType = unitOrderPayQo.getPayType(); + String body = unitOrderPayQo.getBody(); + long trxAmt = (long) (Double.parseDouble(trxAmtYuan) * 100); + if ((!"W01".equals(payType)) && (!"A01".equals(payType))) { + return outputEncapsulationObject(PromptMessageEnum.PROCESS_FAIL, null, locale); + } + SybPayService service = new SybPayService(); + long currentTimeMillis = System.currentTimeMillis(); + String reqsn = String.valueOf(currentTimeMillis); + Map resultMap = service.pay(trxAmt, reqsn, payType, body, "备注", "", "120", payNotifyUrl, "", "", "", "", "", "", "", "", "", "", "", ""); + + if ("SUCCESS".equals(resultMap.get("retcode")) && "0000".equals(resultMap.get("trxstatus"))) { + UnitOrderPayEntity entity = UnitOrderPayUtils.getEntityByMap(resultMap); + String path = QRCodeUtils.generateQRCodeImage(entity.getPayinfo(), 350, 350, qrCodeSaveDirPath, qrCodeAccessDirPath, reqsn + "_" + trxAmt + ".png"); + if (StrUtil.isEmpty(path)) { + return outputEncapsulationObject(PromptMessageEnum.PROCESS_FAIL, null, locale); + } + entity.setUserId(sysUserEntity.getId()); + entity.setCreateTime(dateFormat.format(new Date(currentTimeMillis))); + entity.setBody(body); + entity.setQrCodePath(path); + unitOrderPayDao.saveAndFlush(entity); + return outputEncapsulationObject(PromptMessageEnum.SUCCESS, entity, locale); + } + return outputEncapsulationObject(PromptMessageEnum.PROCESS_FAIL, null, locale); + } catch (Exception e) { + e.printStackTrace(); + return outputEncapsulationObject(PromptMessageEnum.PROCESS_FAIL, null, locale); + } + } + + /** + * 查询用户订单 + */ + @GetMapping("/queryorder") + public String queryOrder(@RequestHeader(value = "Authorization") String token,//token + @RequestParam(value = "userName", required = false) String userName,//要查询的用户名 + @RequestParam(value = "pageNum", required = false) String pageNum,//分页第几页,可以不填 + @RequestParam(value = "pageSize", required = false) String pageSize,//分页每页有多少条,可以不填 + @RequestParam(value = "startTime", required = false) String startTime,//开始时间,可以不填 + @RequestParam(value = "endTime", required = false) String endTime//结束时间,可以不填 + ) { + // 验证token + String tokenUserName = TokenUtil.getTokenUserName(token); + SysUserEntity sysUserEntity = sysUserDao.selectByUserName(tokenUserName); + if (sysUserEntity == null) { + return outputEncapsulationObject(PromptMessageEnum.USER_LOGIN_ERROR, "您还没有注册登录,请先注册登录", locale); + } + //分页查询 + int pageNumInt = 1; + int pageSizeInt = 10; + if (StrUtil.isNotEmpty(pageNum) && StrUtil.isNotEmpty(pageSize)) { + pageNumInt = Integer.parseInt(pageNum); + pageSizeInt = Integer.parseInt(pageSize); + } + //查询交易记录 + List> queryTranVoList = new LinkedList<>(); + if ("管理员".equals(sysUserEntity.getAccountType())) { + System.out.println("管理员查" + (StrUtil.isEmpty(userName) ? "全部" : userName)); + List> list = tranQueryDao.queryTranByAdmin(StrUtil.isEmpty(userName) ? "" : userName, pageNumInt, pageSizeInt); + queryTranVoList.addAll(list); + } else { + System.out.println(sysUserEntity.getUserName() + "查自己"); + List> list = tranQueryDao.queryTran(sysUserEntity.getId(), pageNumInt, pageSizeInt); + queryTranVoList.addAll(list); + } + List collect = queryTranVoList.stream().map(TranQueryUtils::transform).collect(Collectors.toList()); + return outputEncapsulationObject(PromptMessageEnum.SUCCESS, collect, locale); + } + + /** + * 统一下单退款 + */ + @PostMapping("/unitorderrefund") + public String unitOrderRefund(@RequestBody UnitOrderRefundQo unitOrderRefundQo) { + try { + String trxAmtYuan = unitOrderRefundQo.getTrxAmtYuan(); + String oldReqSn = unitOrderRefundQo.getOldReqSn(); + long trxAmt = (long) (Double.parseDouble(trxAmtYuan) * 100); + SybPayService service = new SybPayService(); + String reqsn = String.valueOf(System.currentTimeMillis()); + Map map = service.refund(trxAmt, reqsn, "", oldReqSn); + return outputEncapsulationObject(PromptMessageEnum.SUCCESS, map, locale); + } catch (Exception e) { + e.printStackTrace(); + return outputEncapsulationObject(PromptMessageEnum.PROCESS_FAIL, null, locale); + } + + } + + /** + * 统一下单查询 + */ + @GetMapping("/unitorderquery") + public String unitOrderQuery(@RequestParam(value = "trxId") String trxId) { + try { + SybPayService service = new SybPayService(); + Map map = service.query("", trxId); + return outputEncapsulationObject(PromptMessageEnum.SUCCESS, map, locale); + } catch (Exception e) { + e.printStackTrace(); + return outputEncapsulationObject(PromptMessageEnum.PROCESS_FAIL, null, locale); + } + } + +} diff --git a/src/main/java/com/xkrs/allinpay/SybPayService.java b/src/main/java/com/xkrs/allinpay/SybPayService.java new file mode 100644 index 0000000..b3bf2e4 --- /dev/null +++ b/src/main/java/com/xkrs/allinpay/SybPayService.java @@ -0,0 +1,182 @@ +package com.xkrs.allinpay; + +import com.xkrs.allinpay.utils.HttpConnectionUtil; +import com.xkrs.allinpay.utils.SybConstants; +import com.xkrs.allinpay.utils.SybUtil; + +import java.util.Map; +import java.util.TreeMap; + +public class SybPayService { + + public Map pay(long trxamt, String reqsn, String paytype, String body, String remark, String acct, String validtime, String notify_url, String limit_pay, String idno, String truename, String asinfo, String sub_appid, String goods_tag, String benefitdetail, String chnlstoreid, String subbranch, String extendparams, String cusip, String fqnum) throws Exception { + HttpConnectionUtil http = new HttpConnectionUtil(SybConstants.SYB_APIURL + "/pay"); + http.init(); + TreeMap params = new TreeMap(); + if (!SybUtil.isEmpty(SybConstants.SYB_ORGID)) params.put("orgid", SybConstants.SYB_ORGID); + params.put("cusid", SybConstants.SYB_CUSID); + params.put("appid", SybConstants.SYB_APPID); + params.put("version", "11"); + params.put("trxamt", String.valueOf(trxamt)); + params.put("reqsn", reqsn); + params.put("paytype", paytype); + params.put("randomstr", SybUtil.getValidatecode(8)); + params.put("body", body); + params.put("remark", remark); + params.put("validtime", validtime); + params.put("acct", acct); + params.put("notify_url", notify_url); + params.put("limit_pay", limit_pay); + params.put("sub_appid", sub_appid); + params.put("goods_tag", goods_tag); + params.put("benefitdetail", benefitdetail); + params.put("chnlstoreid", chnlstoreid); + params.put("subbranch", subbranch); + params.put("extendparams", extendparams); + params.put("cusip", cusip); + params.put("fqnum", fqnum); + params.put("idno", idno); + params.put("truename", truename); + params.put("asinfo", asinfo); + params.put("signtype", SybConstants.SIGN_TYPE); + String appkey = ""; + if (SybConstants.SIGN_TYPE.equals("RSA")) appkey = SybConstants.SYB_RSACUSPRIKEY; + else if (SybConstants.SIGN_TYPE.equals("SM2")) appkey = SybConstants.SYB_SM2PPRIVATEKEY; + else appkey = SybConstants.SYB_MD5_APPKEY; + params.put("sign", SybUtil.unionSign(params, appkey, SybConstants.SIGN_TYPE)); + byte[] bys = http.postParams(params, true); + String result = new String(bys, "UTF-8"); + Map resultMap = handleResult(result); + return resultMap; + + } + + public Map cancel(long trxamt, String reqsn, String oldtrxid, String oldreqsn) throws Exception { + HttpConnectionUtil http = new HttpConnectionUtil(SybConstants.SYB_APIURL + "/cancel"); + http.init(); + TreeMap params = new TreeMap(); + if (!SybUtil.isEmpty(SybConstants.SYB_ORGID)) params.put("orgid", SybConstants.SYB_ORGID); + params.put("cusid", SybConstants.SYB_CUSID); + params.put("appid", SybConstants.SYB_APPID); + params.put("version", "11"); + params.put("trxamt", String.valueOf(trxamt)); + params.put("reqsn", reqsn); + params.put("oldtrxid", oldtrxid); + params.put("oldreqsn", oldreqsn); + params.put("randomstr", SybUtil.getValidatecode(8)); + params.put("signtype", SybConstants.SIGN_TYPE); + String appkey = ""; + if (SybConstants.SIGN_TYPE.equals("RSA")) appkey = SybConstants.SYB_RSACUSPRIKEY; + else if (SybConstants.SIGN_TYPE.equals("SM2")) appkey = SybConstants.SYB_SM2PPRIVATEKEY; + else appkey = SybConstants.SYB_MD5_APPKEY; + params.put("sign", SybUtil.unionSign(params, appkey, SybConstants.SIGN_TYPE)); + byte[] bys = http.postParams(params, true); + String result = new String(bys, "UTF-8"); + Map map = handleResult(result); + return map; + } + + public Map refund(long trxamt, String reqsn, String oldtrxid, String oldreqsn) throws Exception { + HttpConnectionUtil http = new HttpConnectionUtil(SybConstants.SYB_APIURL + "/refund"); + http.init(); + TreeMap params = new TreeMap(); + if (!SybUtil.isEmpty(SybConstants.SYB_ORGID)) params.put("orgid", SybConstants.SYB_ORGID); + params.put("cusid", SybConstants.SYB_CUSID); + params.put("appid", SybConstants.SYB_APPID); + params.put("version", "11"); + params.put("trxamt", String.valueOf(trxamt)); + params.put("reqsn", reqsn); + params.put("oldreqsn", oldreqsn); + params.put("oldtrxid", oldtrxid); + params.put("randomstr", SybUtil.getValidatecode(8)); + params.put("signtype", SybConstants.SIGN_TYPE); + String appkey = ""; + if (SybConstants.SIGN_TYPE.equals("RSA")) appkey = SybConstants.SYB_RSACUSPRIKEY; + else if (SybConstants.SIGN_TYPE.equals("SM2")) appkey = SybConstants.SYB_SM2PPRIVATEKEY; + else appkey = SybConstants.SYB_MD5_APPKEY; + params.put("sign", SybUtil.unionSign(params, appkey, SybConstants.SIGN_TYPE)); + byte[] bys = http.postParams(params, true); + String result = new String(bys, "UTF-8"); + Map map = handleResult(result); + return map; + } + + public Map query(String reqsn, String trxid) throws Exception { + HttpConnectionUtil http = new HttpConnectionUtil(SybConstants.SYB_APIURL + "/query"); + http.init(); + TreeMap params = new TreeMap(); + if (!SybUtil.isEmpty(SybConstants.SYB_ORGID)) params.put("orgid", SybConstants.SYB_ORGID); + params.put("cusid", SybConstants.SYB_CUSID); + params.put("appid", SybConstants.SYB_APPID); + params.put("version", "11"); + params.put("reqsn", reqsn); + params.put("trxid", trxid); + params.put("randomstr", SybUtil.getValidatecode(8)); + params.put("signtype", SybConstants.SIGN_TYPE); + String appkey = ""; + if (SybConstants.SIGN_TYPE.equals("RSA")) appkey = SybConstants.SYB_RSACUSPRIKEY; + else if (SybConstants.SIGN_TYPE.equals("SM2")) appkey = SybConstants.SYB_SM2PPRIVATEKEY; + else appkey = SybConstants.SYB_MD5_APPKEY; + params.put("sign", SybUtil.unionSign(params, appkey, SybConstants.SIGN_TYPE)); + byte[] bys = http.postParams(params, true); + String result = new String(bys, "UTF-8"); + Map map = handleResult(result); + return map; + } + + @SuppressWarnings({"rawtypes", "unchecked"}) + public static Map handleResult(String result) throws Exception { + System.out.println("ret:" + result); + Map map = SybUtil.json2Obj(result, Map.class); + if (map == null) { + throw new Exception("返回数据错误"); + } + if ("SUCCESS".equals(map.get("retcode"))) { + TreeMap tmap = new TreeMap(); + tmap.putAll(map); + String appkey = ""; + if (SybConstants.SIGN_TYPE.equals("RSA")) appkey = SybConstants.SYB_RSATLPUBKEY; + else if (SybConstants.SIGN_TYPE.equals("SM2")) appkey = SybConstants.SYB_SM2TLPUBKEY; + else appkey = SybConstants.SYB_MD5_APPKEY; + if (SybUtil.validSign(tmap, appkey, SybConstants.SIGN_TYPE)) { + System.out.println("签名成功"); + return map; + } else { + throw new Exception("验证签名失败"); + } + + } else { + throw new Exception(map.get("retmsg").toString()); + } + } + + public Map scanPay(long trxamt, String reqsn, String body, String remark, String authcode, String limit_pay, String idno, String truename, String asinfo) throws Exception { + // TODO Auto-generated method stub + HttpConnectionUtil http = new HttpConnectionUtil(SybConstants.SYB_APIURL + "/scanqrpay"); + http.init(); + TreeMap params = new TreeMap(); + if (!SybUtil.isEmpty(SybConstants.SYB_ORGID)) params.put("orgid", SybConstants.SYB_ORGID); + params.put("cusid", SybConstants.SYB_CUSID); + params.put("appid", SybConstants.SYB_APPID); + params.put("version", "11"); + params.put("trxamt", String.valueOf(trxamt)); + params.put("reqsn", reqsn); + params.put("randomstr", SybUtil.getValidatecode(8)); + params.put("body", body); + params.put("remark", remark); + params.put("authcode", authcode); + params.put("limit_pay", limit_pay); + params.put("asinfo", asinfo); + params.put("signtype", SybConstants.SIGN_TYPE); + String appkey = ""; + if (SybConstants.SIGN_TYPE.equals("RSA")) appkey = SybConstants.SYB_RSACUSPRIKEY; + else if (SybConstants.SIGN_TYPE.equals("SM2")) appkey = SybConstants.SYB_SM2PPRIVATEKEY; + else appkey = SybConstants.SYB_MD5_APPKEY; + params.put("sign", SybUtil.unionSign(params, appkey, SybConstants.SIGN_TYPE)); + byte[] bys = http.postParams(params, true); + String result = new String(bys, "UTF-8"); + Map map = handleResult(result); + return map; + } + +} diff --git a/src/main/java/com/xkrs/allinpay/model/QueryTran.java b/src/main/java/com/xkrs/allinpay/model/QueryTran.java new file mode 100644 index 0000000..391dc39 --- /dev/null +++ b/src/main/java/com/xkrs/allinpay/model/QueryTran.java @@ -0,0 +1,80 @@ +package com.xkrs.allinpay.model; + +public class QueryTran { + + private String trxid; + private String reqsn; + private String username; + private String reallyname; + private String body; + private String trxamt; + private String fintime; + private String trxstatus; + + public QueryTran() { + } + + public String getTrxid() { + return trxid; + } + + public void setTrxid(String trxid) { + this.trxid = trxid; + } + + public String getReqsn() { + return reqsn; + } + + public void setReqsn(String reqsn) { + this.reqsn = reqsn; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getReallyname() { + return reallyname; + } + + public void setReallyname(String reallyname) { + this.reallyname = reallyname; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + public String getTrxamt() { + return trxamt; + } + + public void setTrxamt(String trxamt) { + this.trxamt = trxamt; + } + + public String getFintime() { + return fintime; + } + + public void setFintime(String fintime) { + this.fintime = fintime; + } + + public String getTrxstatus() { + return trxstatus; + } + + public void setTrxstatus(String trxstatus) { + this.trxstatus = trxstatus; + } +} diff --git a/src/main/java/com/xkrs/allinpay/model/TranNotifyEntity.java b/src/main/java/com/xkrs/allinpay/model/TranNotifyEntity.java new file mode 100644 index 0000000..dd567fb --- /dev/null +++ b/src/main/java/com/xkrs/allinpay/model/TranNotifyEntity.java @@ -0,0 +1,415 @@ +package com.xkrs.allinpay.model; + +import javax.persistence.*; +import java.io.Serializable; + +/** + * 支付通知实体类 + */ +@Entity +@Table(name = "tran_notify") +public class TranNotifyEntity implements Serializable { + + /** + * 指定主键,建立自增序列,主键值取自序列 + */ + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "tran_notify_seq_gen") + @SequenceGenerator(name = "tran_notify_seq_gen", sequenceName = "tran_notify_id_seq", allocationSize = 1) + private Long id; + /** + * 收银宝APPID + */ + private String appid; + /** + * 第三方交易号 + */ + private String outtrxid; + /** + * 交易类型 + */ + private String trxcode; + /** + * 收银宝交易单号 + */ + private String trxid; + /** + * 原始下单金额 + */ + private String initamt; + /** + * 交易金额 + */ + private String trxamt; + /** + * 交易请求日期 + */ + private String trxdate; + /** + * 交易完成时间 + */ + private String paytime; + /** + * 渠道流水号 + */ + private String chnltrxid; + /** + * 交易结果码 + */ + private String trxstatus; + /** + * 商户编号 + */ + private String cusid; + /** + * 终端编号 + */ + private String termno; + /** + * 终端批次号 + */ + private String termbatchid; + /** + * 终端流水号 + */ + private String termtraceno; + /** + * 终端授权码 + */ + private String termauthno; + /** + * 终端参考号 + */ + private String termrefnum; + /** + * 业务关联内容 + */ + private String trxreserved; + /** + * 原交易流水 + */ + private String srctrxid; + /** + * 业务流水 + */ + private String cusorderid; + /** + * 交易账号 + */ + private String acct; + /** + * 手续费 + */ + private String fee; + /** + * 签名类型 + */ + private String signtype; + /** + * 渠道子商户号 + */ + private String cmid; + /** + * 渠道号 + */ + private String chnlid; + /** + * 渠道信息 + */ + private String chnldata; + /** + * 借贷标识 + */ + private String accttype; + /** + * 发卡行 + */ + private String bankcode; + /** + * 用户账号 + */ + private String logonid; + /** + * 分期数 + */ + private String fqnum; + /** + * 结算周期 + */ + private String feecycle; + /** + * 通联渠道侧OPENID + */ + private String tlopenid; + /** + * 基础营销权益抵扣明细 + */ + private String mktresult; + + public TranNotifyEntity() { + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getAppid() { + return appid; + } + + public void setAppid(String appid) { + this.appid = appid; + } + + public String getOuttrxid() { + return outtrxid; + } + + public void setOuttrxid(String outtrxid) { + this.outtrxid = outtrxid; + } + + public String getTrxcode() { + return trxcode; + } + + public void setTrxcode(String trxcode) { + this.trxcode = trxcode; + } + + public String getTrxid() { + return trxid; + } + + public void setTrxid(String trxid) { + this.trxid = trxid; + } + + public String getInitamt() { + return initamt; + } + + public void setInitamt(String initamt) { + this.initamt = initamt; + } + + public String getTrxamt() { + return trxamt; + } + + public void setTrxamt(String trxamt) { + this.trxamt = trxamt; + } + + public String getTrxdate() { + return trxdate; + } + + public void setTrxdate(String trxdate) { + this.trxdate = trxdate; + } + + public String getPaytime() { + return paytime; + } + + public void setPaytime(String paytime) { + this.paytime = paytime; + } + + public String getChnltrxid() { + return chnltrxid; + } + + public void setChnltrxid(String chnltrxid) { + this.chnltrxid = chnltrxid; + } + + public String getTrxstatus() { + return trxstatus; + } + + public void setTrxstatus(String trxstatus) { + this.trxstatus = trxstatus; + } + + public String getCusid() { + return cusid; + } + + public void setCusid(String cusid) { + this.cusid = cusid; + } + + public String getTermno() { + return termno; + } + + public void setTermno(String termno) { + this.termno = termno; + } + + public String getTermbatchid() { + return termbatchid; + } + + public void setTermbatchid(String termbatchid) { + this.termbatchid = termbatchid; + } + + public String getTermtraceno() { + return termtraceno; + } + + public void setTermtraceno(String termtraceno) { + this.termtraceno = termtraceno; + } + + public String getTermauthno() { + return termauthno; + } + + public void setTermauthno(String termauthno) { + this.termauthno = termauthno; + } + + public String getTermrefnum() { + return termrefnum; + } + + public void setTermrefnum(String termrefnum) { + this.termrefnum = termrefnum; + } + + public String getTrxreserved() { + return trxreserved; + } + + public void setTrxreserved(String trxreserved) { + this.trxreserved = trxreserved; + } + + public String getSrctrxid() { + return srctrxid; + } + + public void setSrctrxid(String srctrxid) { + this.srctrxid = srctrxid; + } + + public String getCusorderid() { + return cusorderid; + } + + public void setCusorderid(String cusorderid) { + this.cusorderid = cusorderid; + } + + public String getAcct() { + return acct; + } + + public void setAcct(String acct) { + this.acct = acct; + } + + public String getFee() { + return fee; + } + + public void setFee(String fee) { + this.fee = fee; + } + + public String getSigntype() { + return signtype; + } + + public void setSigntype(String signtype) { + this.signtype = signtype; + } + + public String getCmid() { + return cmid; + } + + public void setCmid(String cmid) { + this.cmid = cmid; + } + + public String getChnlid() { + return chnlid; + } + + public void setChnlid(String chnlid) { + this.chnlid = chnlid; + } + + public String getChnldata() { + return chnldata; + } + + public void setChnldata(String chnldata) { + this.chnldata = chnldata; + } + + public String getAccttype() { + return accttype; + } + + public void setAccttype(String accttype) { + this.accttype = accttype; + } + + public String getBankcode() { + return bankcode; + } + + public void setBankcode(String bankcode) { + this.bankcode = bankcode; + } + + public String getLogonid() { + return logonid; + } + + public void setLogonid(String logonid) { + this.logonid = logonid; + } + + public String getFqnum() { + return fqnum; + } + + public void setFqnum(String fqnum) { + this.fqnum = fqnum; + } + + public String getFeecycle() { + return feecycle; + } + + public void setFeecycle(String feecycle) { + this.feecycle = feecycle; + } + + public String getTlopenid() { + return tlopenid; + } + + public void setTlopenid(String tlopenid) { + this.tlopenid = tlopenid; + } + + public String getMktresult() { + return mktresult; + } + + public void setMktresult(String mktresult) { + this.mktresult = mktresult; + } +} diff --git a/src/main/java/com/xkrs/allinpay/model/TranNotifyUtils.java b/src/main/java/com/xkrs/allinpay/model/TranNotifyUtils.java new file mode 100644 index 0000000..9958217 --- /dev/null +++ b/src/main/java/com/xkrs/allinpay/model/TranNotifyUtils.java @@ -0,0 +1,83 @@ +package com.xkrs.allinpay.model; + +import java.util.Map; + +public class TranNotifyUtils { + + public static TranNotifyEntity getEntityByMap(Map map) { + TranNotifyEntity entity = new TranNotifyEntity(); + + entity.setAppid(map.get("appid")); + entity.setOuttrxid(map.get("outtrxid")); + entity.setTrxcode(map.get("trxcode")); + entity.setTrxid(map.get("trxid")); + entity.setInitamt(map.get("initamt")); + entity.setTrxamt(map.get("trxamt")); + entity.setTrxdate(map.get("trxdate")); + entity.setPaytime(map.get("paytime")); + entity.setChnltrxid(map.get("chnltrxid")); + entity.setTrxstatus(map.get("trxstatus")); + entity.setCusid(map.get("cusid")); + entity.setTermno(map.get("termno")); + entity.setTermbatchid(map.get("termbatchid")); + entity.setTermtraceno(map.get("termtraceno")); + entity.setTermauthno(map.get("termauthno")); + entity.setTermrefnum(map.get("termrefnum")); + entity.setTrxreserved(map.get("trxreserved")); + entity.setSrctrxid(map.get("srctrxid")); + entity.setCusorderid(map.get("cusorderid")); + entity.setAcct(map.get("acct")); + entity.setFee(map.get("fee")); + entity.setSigntype(map.get("signtype")); + entity.setCmid(map.get("cmid")); + entity.setChnlid(map.get("chnlid")); + entity.setChnldata(map.get("chnldata")); + entity.setAccttype(map.get("accttype")); + entity.setBankcode(map.get("bankcode")); + entity.setLogonid(map.get("logonid")); + entity.setFqnum(map.get("fqnum")); + entity.setFeecycle(map.get("feecycle")); + entity.setTlopenid(map.get("tlopenid")); + entity.setMktresult(map.get("mktresult")); + + return entity; + } + + public static void updateEntity(TranNotifyEntity newTranNotify, TranNotifyEntity oldTranNotify) { + + oldTranNotify.setAppid(newTranNotify.getAppid()); + oldTranNotify.setOuttrxid(newTranNotify.getOuttrxid()); + oldTranNotify.setTrxcode(newTranNotify.getTrxcode()); + oldTranNotify.setTrxid(newTranNotify.getTrxid()); + oldTranNotify.setInitamt(newTranNotify.getInitamt()); + oldTranNotify.setTrxamt(newTranNotify.getTrxamt()); + oldTranNotify.setTrxdate(newTranNotify.getTrxdate()); + oldTranNotify.setPaytime(newTranNotify.getPaytime()); + oldTranNotify.setChnltrxid(newTranNotify.getChnltrxid()); + oldTranNotify.setTrxstatus(newTranNotify.getTrxstatus()); + oldTranNotify.setCusid(newTranNotify.getCusid()); + oldTranNotify.setTermno(newTranNotify.getTermno()); + oldTranNotify.setTermbatchid(newTranNotify.getTermbatchid()); + oldTranNotify.setTermtraceno(newTranNotify.getTermtraceno()); + oldTranNotify.setTermauthno(newTranNotify.getTermauthno()); + oldTranNotify.setTermrefnum(newTranNotify.getTermrefnum()); + oldTranNotify.setTrxreserved(newTranNotify.getTrxreserved()); + oldTranNotify.setSrctrxid(newTranNotify.getSrctrxid()); + oldTranNotify.setCusorderid(newTranNotify.getCusorderid()); + oldTranNotify.setAcct(newTranNotify.getAcct()); + oldTranNotify.setFee(newTranNotify.getFee()); + oldTranNotify.setSigntype(newTranNotify.getSigntype()); + oldTranNotify.setCmid(newTranNotify.getCmid()); + oldTranNotify.setChnlid(newTranNotify.getChnlid()); + oldTranNotify.setChnldata(newTranNotify.getChnldata()); + oldTranNotify.setAccttype(newTranNotify.getAccttype()); + oldTranNotify.setBankcode(newTranNotify.getBankcode()); + oldTranNotify.setLogonid(newTranNotify.getLogonid()); + oldTranNotify.setFqnum(newTranNotify.getFqnum()); + oldTranNotify.setFeecycle(newTranNotify.getFeecycle()); + oldTranNotify.setTlopenid(newTranNotify.getTlopenid()); + oldTranNotify.setMktresult(newTranNotify.getMktresult()); + + } + +} diff --git a/src/main/java/com/xkrs/allinpay/model/TranQueryEntity.java b/src/main/java/com/xkrs/allinpay/model/TranQueryEntity.java new file mode 100644 index 0000000..542013c --- /dev/null +++ b/src/main/java/com/xkrs/allinpay/model/TranQueryEntity.java @@ -0,0 +1,331 @@ +package com.xkrs.allinpay.model; + +import javax.persistence.*; +import java.io.Serializable; + +/** + * 统一查询实体类 + */ +@Entity +@Table(name = "tran_query") +public class TranQueryEntity implements Serializable { + + /** + * 指定主键,建立自增序列,主键值取自序列 + */ + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "tran_query_seq_gen") + @SequenceGenerator(name = "tran_query_seq_gen", sequenceName = "tran_query_id_seq", allocationSize = 1) + private Long id; + /** + * 订单ID + */ + private Long orderid; + /** + * 商户号 + */ + private String cusid; + /** + * 应用ID + */ + private String appid; + /** + * 交易单号 + */ + private String trxid; + /** + * 支付渠道交易单号 + */ + private String chnltrxid; + /** + * 商户订单号 + */ + private String reqsn; + /** + * 交易类型 + */ + private String trxcode; + /** + * 交易金额 + */ + private String trxamt; + /** + * 交易状态 + */ + private String trxstatus; + /** + * 支付平台用户标识 + */ + private String acct; + /** + * 交易完成时间 + */ + private String fintime; + /** + * 随机字符串 + */ + private String randomstr; + /** + * 错误原因 + */ + private String errmsg; + /** + * 渠道子商户号 + */ + private String cmid; + /** + * 渠道号 + */ + private String chnlid; + /** + * 原交易金额 + */ + private String initamt; + /** + * 手续费 + */ + private String fee; + /** + * 渠道信息 + */ + private String chnldata; + /** + * 借贷标识 + */ + private String accttype; + /** + * 所属银行 + */ + private String bankcode; + /** + * 买家账号 + */ + private String logonid; + /** + * 分期数 + */ + private String fqnum; + /** + * 结算周期 + */ + private String feecycle; + /** + * 交易备注 + */ + private String trxreserve; + /** + * 通联渠道侧OPENID + */ + private String tlopenid; + + public TranQueryEntity() { + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getOrderid() { + return orderid; + } + + public void setOrderid(Long orderid) { + this.orderid = orderid; + } + + public String getCusid() { + return cusid; + } + + public void setCusid(String cusid) { + this.cusid = cusid; + } + + public String getAppid() { + return appid; + } + + public void setAppid(String appid) { + this.appid = appid; + } + + public String getTrxid() { + return trxid; + } + + public void setTrxid(String trxid) { + this.trxid = trxid; + } + + public String getChnltrxid() { + return chnltrxid; + } + + public void setChnltrxid(String chnltrxid) { + this.chnltrxid = chnltrxid; + } + + public String getReqsn() { + return reqsn; + } + + public void setReqsn(String reqsn) { + this.reqsn = reqsn; + } + + public String getTrxcode() { + return trxcode; + } + + public void setTrxcode(String trxcode) { + this.trxcode = trxcode; + } + + public String getTrxamt() { + return trxamt; + } + + public void setTrxamt(String trxamt) { + this.trxamt = trxamt; + } + + public String getTrxstatus() { + return trxstatus; + } + + public void setTrxstatus(String trxstatus) { + this.trxstatus = trxstatus; + } + + public String getAcct() { + return acct; + } + + public void setAcct(String acct) { + this.acct = acct; + } + + public String getFintime() { + return fintime; + } + + public void setFintime(String fintime) { + this.fintime = fintime; + } + + public String getRandomstr() { + return randomstr; + } + + public void setRandomstr(String randomstr) { + this.randomstr = randomstr; + } + + public String getErrmsg() { + return errmsg; + } + + public void setErrmsg(String errmsg) { + this.errmsg = errmsg; + } + + public String getCmid() { + return cmid; + } + + public void setCmid(String cmid) { + this.cmid = cmid; + } + + public String getChnlid() { + return chnlid; + } + + public void setChnlid(String chnlid) { + this.chnlid = chnlid; + } + + public String getInitamt() { + return initamt; + } + + public void setInitamt(String initamt) { + this.initamt = initamt; + } + + public String getFee() { + return fee; + } + + public void setFee(String fee) { + this.fee = fee; + } + + public String getChnldata() { + return chnldata; + } + + public void setChnldata(String chnldata) { + this.chnldata = chnldata; + } + + public String getAccttype() { + return accttype; + } + + public void setAccttype(String accttype) { + this.accttype = accttype; + } + + public String getBankcode() { + return bankcode; + } + + public void setBankcode(String bankcode) { + this.bankcode = bankcode; + } + + public String getLogonid() { + return logonid; + } + + public void setLogonid(String logonid) { + this.logonid = logonid; + } + + public String getFqnum() { + return fqnum; + } + + public void setFqnum(String fqnum) { + this.fqnum = fqnum; + } + + public String getFeecycle() { + return feecycle; + } + + public void setFeecycle(String feecycle) { + this.feecycle = feecycle; + } + + public String getTrxreserve() { + return trxreserve; + } + + public void setTrxreserve(String trxreserve) { + this.trxreserve = trxreserve; + } + + public String getTlopenid() { + return tlopenid; + } + + public void setTlopenid(String tlopenid) { + this.tlopenid = tlopenid; + } +} diff --git a/src/main/java/com/xkrs/allinpay/model/TranQueryUtils.java b/src/main/java/com/xkrs/allinpay/model/TranQueryUtils.java new file mode 100644 index 0000000..1226eb9 --- /dev/null +++ b/src/main/java/com/xkrs/allinpay/model/TranQueryUtils.java @@ -0,0 +1,106 @@ +package com.xkrs.allinpay.model; + +import java.text.DecimalFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Map; + +public class TranQueryUtils { + + public static TranQueryEntity getEntityByMap(Map map) { + TranQueryEntity entity = new TranQueryEntity(); + + entity.setCusid(map.get("cusid")); + entity.setAppid(map.get("appid")); + entity.setTrxid(map.get("trxid")); + entity.setChnltrxid(map.get("chnltrxid")); + entity.setReqsn(map.get("reqsn")); + entity.setTrxcode(map.get("trxcode")); + entity.setTrxamt(map.get("trxamt")); + entity.setTrxstatus(map.get("trxstatus")); + entity.setAcct(map.get("acct")); + entity.setFintime(map.get("fintime")); + entity.setRandomstr(map.get("randomstr")); + entity.setErrmsg(map.get("errmsg")); + entity.setCmid(map.get("cmid")); + entity.setChnlid(map.get("chnlid")); + entity.setInitamt(map.get("initamt")); + entity.setFee(map.get("fee")); + entity.setChnldata(map.get("chnldata")); + entity.setAccttype(map.get("accttype")); + entity.setBankcode(map.get("bankcode")); + entity.setLogonid(map.get("logonid")); + entity.setFqnum(map.get("fqnum")); + entity.setFeecycle(map.get("feecycle")); + entity.setTrxreserve(map.get("trxreserve")); + entity.setTlopenid(map.get("tlopenid")); + + return entity; + } + + public static void updateEntity(TranQueryEntity newTranQuery, TranQueryEntity oldTranQuery) { + + oldTranQuery.setCusid(newTranQuery.getCusid()); + oldTranQuery.setAppid(newTranQuery.getAppid()); + oldTranQuery.setTrxid(newTranQuery.getTrxid()); + oldTranQuery.setChnltrxid(newTranQuery.getChnltrxid()); + oldTranQuery.setReqsn(newTranQuery.getReqsn()); + oldTranQuery.setTrxcode(newTranQuery.getTrxcode()); + oldTranQuery.setTrxamt(newTranQuery.getTrxamt()); + oldTranQuery.setTrxstatus(newTranQuery.getTrxstatus()); + oldTranQuery.setAcct(newTranQuery.getAcct()); + oldTranQuery.setFintime(newTranQuery.getFintime()); + oldTranQuery.setRandomstr(newTranQuery.getRandomstr()); + oldTranQuery.setErrmsg(newTranQuery.getErrmsg()); + oldTranQuery.setCmid(newTranQuery.getCmid()); + oldTranQuery.setChnlid(newTranQuery.getChnlid()); + oldTranQuery.setInitamt(newTranQuery.getInitamt()); + oldTranQuery.setFee(newTranQuery.getFee()); + oldTranQuery.setChnldata(newTranQuery.getChnldata()); + oldTranQuery.setAccttype(newTranQuery.getAccttype()); + oldTranQuery.setBankcode(newTranQuery.getBankcode()); + oldTranQuery.setLogonid(newTranQuery.getLogonid()); + oldTranQuery.setFqnum(newTranQuery.getFqnum()); + oldTranQuery.setFeecycle(newTranQuery.getFeecycle()); + oldTranQuery.setTrxreserve(newTranQuery.getTrxreserve()); + oldTranQuery.setTlopenid(newTranQuery.getTlopenid()); + + } + + private static final SimpleDateFormat dateFormat1 = new SimpleDateFormat("yyyyMMddHHmmss"); + private static final SimpleDateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + private static final DecimalFormat decimalFormat = new DecimalFormat("0.00"); + + public static QueryTran transform(Map queryTranVo) { + + String trxid = queryTranVo.get("trxid"); + String reqsn = queryTranVo.get("reqsn"); + String username = queryTranVo.get("username"); + String reallyname = queryTranVo.get("reallyname"); + String body = queryTranVo.get("body"); + String trxamt = queryTranVo.get("trxamt"); + String fintime = queryTranVo.get("fintime"); + String trxstatus = queryTranVo.get("trxstatus"); + + String finishTime = ""; + try { + finishTime = dateFormat2.format(dateFormat1.parse(fintime)); + } catch (ParseException e) { + throw new RuntimeException(e); + } + + QueryTran queryTran = new QueryTran(); + + queryTran.setTrxid(trxid); + queryTran.setReqsn(reqsn); + queryTran.setUsername(username); + queryTran.setReallyname(reallyname); + queryTran.setBody(body); + queryTran.setTrxamt("¥" + decimalFormat.format(Long.parseLong(trxamt) / 100.0D)); + queryTran.setFintime(finishTime); + queryTran.setTrxstatus("0000".equals(trxstatus) ? "支付成功" : "支付失败"); + + return queryTran; + } + +} diff --git a/src/main/java/com/xkrs/allinpay/model/UnitOrderPayEntity.java b/src/main/java/com/xkrs/allinpay/model/UnitOrderPayEntity.java new file mode 100644 index 0000000..37fbe81 --- /dev/null +++ b/src/main/java/com/xkrs/allinpay/model/UnitOrderPayEntity.java @@ -0,0 +1,196 @@ +package com.xkrs.allinpay.model; + +import javax.persistence.*; +import java.io.Serializable; + +/** + * 订单实体类 + */ +@Entity +@Table(name = "unit_order_pay") +public class UnitOrderPayEntity implements Serializable { + + /** + * 指定主键,建立自增序列,主键值取自序列 + */ + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "unit_order_pay_seq_gen") + @SequenceGenerator(name = "unit_order_pay_seq_gen", sequenceName = "unit_order_pay_id_seq", allocationSize = 1) + private Long id; + + /** + * 用户ID + */ + private Integer userId; + + /** + * 订单创建时间 + */ + private String createTime; + + /** + * 订单标题 + */ + private String body; + + /** + * 支付结果 + */ + private String payResult; + + /** + * 二维码路径 + */ + private String qrCodePath; + + private String cusid; + private String appid; + private String trxid; + private String chnltrxid; + private String reqsn; + private String randomstr; + private String trxstatus; + private String fintime; + private String errmsg; + private String payinfo; + private String trxcode; + + public UnitOrderPayEntity() { + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Integer getUserId() { + return userId; + } + + public void setUserId(Integer userId) { + this.userId = userId; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + public String getPayResult() { + return payResult; + } + + public void setPayResult(String payResult) { + this.payResult = payResult; + } + + public String getQrCodePath() { + return qrCodePath; + } + + public void setQrCodePath(String qrCodePath) { + this.qrCodePath = qrCodePath; + } + + public String getCusid() { + return cusid; + } + + public void setCusid(String cusid) { + this.cusid = cusid; + } + + public String getAppid() { + return appid; + } + + public void setAppid(String appid) { + this.appid = appid; + } + + public String getTrxid() { + return trxid; + } + + public void setTrxid(String trxid) { + this.trxid = trxid; + } + + public String getChnltrxid() { + return chnltrxid; + } + + public void setChnltrxid(String chnltrxid) { + this.chnltrxid = chnltrxid; + } + + public String getReqsn() { + return reqsn; + } + + public void setReqsn(String reqsn) { + this.reqsn = reqsn; + } + + public String getRandomstr() { + return randomstr; + } + + public void setRandomstr(String randomstr) { + this.randomstr = randomstr; + } + + public String getTrxstatus() { + return trxstatus; + } + + public void setTrxstatus(String trxstatus) { + this.trxstatus = trxstatus; + } + + public String getFintime() { + return fintime; + } + + public void setFintime(String fintime) { + this.fintime = fintime; + } + + public String getErrmsg() { + return errmsg; + } + + public void setErrmsg(String errmsg) { + this.errmsg = errmsg; + } + + public String getPayinfo() { + return payinfo; + } + + public void setPayinfo(String payinfo) { + this.payinfo = payinfo; + } + + public String getTrxcode() { + return trxcode; + } + + public void setTrxcode(String trxcode) { + this.trxcode = trxcode; + } +} diff --git a/src/main/java/com/xkrs/allinpay/model/UnitOrderPayQo.java b/src/main/java/com/xkrs/allinpay/model/UnitOrderPayQo.java new file mode 100644 index 0000000..58d22ea --- /dev/null +++ b/src/main/java/com/xkrs/allinpay/model/UnitOrderPayQo.java @@ -0,0 +1,52 @@ +package com.xkrs.allinpay.model; + +/** + * 订单参数 + */ +public class UnitOrderPayQo { + + /** + * 交易金额(元) + */ + private String trxAmtYuan; + + /** + * 支付方式 + * W01 微信扫码支付 + * A01 支付宝扫码支付 + */ + private String payType; + + /** + * 订单标题 + * 订单商品名称,空则以商户名作为商品名称 + */ + private String body; + + public UnitOrderPayQo() { + } + + public String getTrxAmtYuan() { + return trxAmtYuan; + } + + public void setTrxAmtYuan(String trxAmtYuan) { + this.trxAmtYuan = trxAmtYuan; + } + + public String getPayType() { + return payType; + } + + public void setPayType(String payType) { + this.payType = payType; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } +} diff --git a/src/main/java/com/xkrs/allinpay/model/UnitOrderPayUtils.java b/src/main/java/com/xkrs/allinpay/model/UnitOrderPayUtils.java new file mode 100644 index 0000000..7f8c3f2 --- /dev/null +++ b/src/main/java/com/xkrs/allinpay/model/UnitOrderPayUtils.java @@ -0,0 +1,106 @@ +package com.xkrs.allinpay.model; + +import java.util.Map; + +public class UnitOrderPayUtils { + + public static UnitOrderPayEntity getEntityByMap(Map map) { + UnitOrderPayEntity entity = new UnitOrderPayEntity(); + entity.setCusid(map.get("cusid")); + entity.setAppid(map.get("appid")); + entity.setTrxid(map.get("trxid")); + entity.setChnltrxid(map.get("chnltrxid")); + entity.setReqsn(map.get("reqsn")); + entity.setRandomstr(map.get("randomstr")); + entity.setTrxstatus(map.get("trxstatus")); + entity.setFintime(map.get("fintime")); + entity.setErrmsg(map.get("errmsg")); + entity.setPayinfo(map.get("payinfo")); + entity.setTrxcode(map.get("trxcode")); + return entity; + } + + private static String getTrxStatusDesc(String trxStatus) { + return null; + } + + private static String getTrxCodeDesc(String trxCode) { + if ("VSP501".equals(trxCode)) { + return "微信支付"; + } + if ("VSP502".equals(trxCode)) { + return "微信支付撤销"; + } + if ("VSP503".equals(trxCode)) { + return "微信支付退款"; + } + if ("VSP511".equals(trxCode)) { + return "支付宝支付"; + } + if ("VSP512".equals(trxCode)) { + return "支付宝支付撤销"; + } + if ("VSP513".equals(trxCode)) { + return "支付宝支付退款"; + } + if ("VSP541".equals(trxCode)) { + return "扫码支付"; + } + if ("VSP542".equals(trxCode)) { + return "扫码撤销"; + } + if ("VSP543".equals(trxCode)) { + return "扫码退货"; + } + if ("VSP551".equals(trxCode)) { + return "银联扫码支付"; + } + if ("VSP552".equals(trxCode)) { + return "银联扫码撤销"; + } + if ("VSP553".equals(trxCode)) { + return "银联扫码退货"; + } + if ("VSP907".equals(trxCode)) { + return "差错借记调整"; + } + if ("VSP908".equals(trxCode)) { + return "差错贷记调整"; + } + if ("VSP611".equals(trxCode)) { + return "数字货币支付"; + } + if ("VSP612".equals(trxCode)) { + return "数字货币撤销"; + } + if ("VSP613".equals(trxCode)) { + return "数字货币退货"; + } + if ("VSP621".equals(trxCode)) { + return "分期支付"; + } + if ("VSP622".equals(trxCode)) { + return "分期撤销"; + } + if ("VSP623".equals(trxCode)) { + return "分期退货"; + } + if ("300002".equals(trxCode)) { + return "充值"; + } + if ("VSP681".equals(trxCode)) { + return "微信订单预消费"; + } + if ("VSP682".equals(trxCode)) { + return "微信订单退款"; + } + if ("VSP683".equals(trxCode)) { + return "微信订单完成"; + } + if ("VSP684".equals(trxCode)) { + return "微信订单完成退款"; + } + return null; + } + +} diff --git a/src/main/java/com/xkrs/allinpay/model/UnitOrderRefundQo.java b/src/main/java/com/xkrs/allinpay/model/UnitOrderRefundQo.java new file mode 100644 index 0000000..5835d93 --- /dev/null +++ b/src/main/java/com/xkrs/allinpay/model/UnitOrderRefundQo.java @@ -0,0 +1,34 @@ +package com.xkrs.allinpay.model; + +public class UnitOrderRefundQo { + + /** + * 交易金额(元) + */ + private String trxAmtYuan; + + /** + * 原交易订单号 + */ + private String oldReqSn; + + public UnitOrderRefundQo() { + } + + public String getTrxAmtYuan() { + return trxAmtYuan; + } + + public void setTrxAmtYuan(String trxAmtYuan) { + this.trxAmtYuan = trxAmtYuan; + } + + public String getOldReqSn() { + return oldReqSn; + } + + public void setOldReqSn(String oldReqSn) { + this.oldReqSn = oldReqSn; + } + +} diff --git a/src/main/java/com/xkrs/allinpay/test/ApiTestV2.java b/src/main/java/com/xkrs/allinpay/test/ApiTestV2.java new file mode 100644 index 0000000..3c8e34e --- /dev/null +++ b/src/main/java/com/xkrs/allinpay/test/ApiTestV2.java @@ -0,0 +1,112 @@ +package com.xkrs.allinpay.test; + +import com.xkrs.allinpay.SybPayService; + +import java.util.Map; + +public class ApiTestV2 { + public static void main(String[] args) throws Exception { +// testPay();//统一下单,异步类交易 +// testScanPay();//统一扫码,被扫交易 +// testCancel();//撤销 + testRefund();//退款 +// testQuery();//查询 + } + + /** + * chnlid;205299480 + * randomstr;281692226001 + * trxcode;VSP501 + * sign;S3+78r3sPP/F1EV9ICo+fBu4UKC8nY47QAcTyVJSrzGX4/advm7B2lqrzjzGiMmrNpFiRy8zrNmBjPV94q484Q== + * errmsg;缺少必要字段 terminal_info(UP01A5100) + * cmid;625141525 + * trxid;250310119743017937 + * trxstatus;3045 + * accttype;99 + * reqsn;1741585763289 + * fintime;20250310134920 + * cusid;990440148166000 + * appid;00000003 + * initamt;1 + * acct;000000 + * bankcode;0000 + * trxamt;1 + * retcode;SUCCESS + */ + public static void testScanPay() throws Exception { + SybPayService service = new SybPayService(); + String reqsn = String.valueOf(System.currentTimeMillis()); + Map map = service.scanPay(1, reqsn, "标题", "备注", "134775931316089668", "", "", "", ""); + print(map); + } + + /** + * chnlid;205299480 + * randomstr;134591333810 + * trxcode;VSP501 + * sign;UZwP/m6ZbZhSkjgpa27a0VdKElbzR1OgTH+BwPtUcLRy9v34DaQKb1C55Sd06+f6kkQ+VsrgEN8ocFtEiRd7TA== + * errmsg;缺少必要字段 terminal_info(UP01A5100) + * cmid;625141525 + * trxid;250310119743017937 + * trxstatus;3045 + * accttype;99 + * reqsn;1741585763289 + * fintime;20250310134920 + * cusid;990440148166000 + * appid;00000003 + * initamt;1 + * acct;000000 + * bankcode;0000 + * trxamt;1 + * retcode;SUCCESS + */ + public static void testQuery() throws Exception { + SybPayService service = new SybPayService(); + Map map = service.query("", "250310119743017937"); + print(map); + } + + public static void testRefund() throws Exception { + SybPayService service = new SybPayService(); + String reqsn = String.valueOf(System.currentTimeMillis()); +// Map map = service.refund(1, reqsn, "", "1742278978287"); + Map map = service.refund(1, reqsn, "250326129022241524", ""); + print(map); + } + + public static void testCancel() throws Exception { + SybPayService service = new SybPayService(); + String reqsn = String.valueOf(System.currentTimeMillis()); + Map map = service.cancel(1, reqsn, "1741655699800", ""); + print(map); + } + + /** + * randomstr;319561317577 + * trxcode;VSP501 + * cusid;990440148166000 + * appid;00000003 + * sign;twRKyHVn5prsyy469n+/XfZ/SGsPwfJwQGu0MbWZHV83sxOuFBIJ78QYyRIWg/QdBIkxRuuCSlnhg7rZk6TFEw== + * payinfo;https://syb.allinpay.com/apiweb/h5unionpay/native?key=GCnOxovaUMsSEXeDw8RhG%2Fcy + * trxid;250310112843002292 + * trxstatus;0000 + * reqsn;1741585650888 + * retcode;SUCCESS + */ + public static void testPay() throws Exception { + SybPayService service = new SybPayService(); + String reqsn = String.valueOf(System.currentTimeMillis()); + Map map = service.pay(1, reqsn, "W01", "标题", "备注", "", "123", "http://8.142.26.238:6801/pay/notify", "", "", "", "", "", "", "", "", "", "", "", ""); + print(map); + } + + public static void print(Map map) { + System.out.println("返回数据如下:"); + if (map != null) { + for (String key : map.keySet()) { + System.out.println(key + ";" + map.get(key)); + } + } + } + +} diff --git a/src/main/java/com/xkrs/allinpay/utils/FileUploadPath.java b/src/main/java/com/xkrs/allinpay/utils/FileUploadPath.java new file mode 100644 index 0000000..adc6b85 --- /dev/null +++ b/src/main/java/com/xkrs/allinpay/utils/FileUploadPath.java @@ -0,0 +1,33 @@ +package com.xkrs.allinpay.utils; + +public class FileUploadPath { + + /** + * 上传路径 + */ + private String uploadPath; + + /** + * 访问路径 + */ + private String accessPath; + + public FileUploadPath() { + } + + public String getUploadPath() { + return uploadPath; + } + + public void setUploadPath(String uploadPath) { + this.uploadPath = uploadPath; + } + + public String getAccessPath() { + return accessPath; + } + + public void setAccessPath(String accessPath) { + this.accessPath = accessPath; + } +} \ No newline at end of file diff --git a/src/main/java/com/xkrs/allinpay/utils/FileUploadUtils.java b/src/main/java/com/xkrs/allinpay/utils/FileUploadUtils.java new file mode 100644 index 0000000..e83229f --- /dev/null +++ b/src/main/java/com/xkrs/allinpay/utils/FileUploadUtils.java @@ -0,0 +1,58 @@ +package com.xkrs.allinpay.utils; + +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.StrUtil; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.IOException; +import java.util.UUID; + +public class FileUploadUtils { + + /** + * 上传文件 + * + * @param file 文件 + * @param baseDirPath Base文件夹 + * @param dirPath 自定义配置文件夹,会在Base文件夹的下层 + * @param fileName 自定义文件名 + * @return 映射后的文件路径 + */ + public static String uploadFile(MultipartFile file, FileUploadPath baseDirPath, String dirPath, String fileName) throws IOException { + + //确定新的文件名 + String newFileName = fileName; + if (StrUtil.isEmpty(fileName)) { + newFileName = UUID.randomUUID().toString() + "." + FileUtil.extName(file.getOriginalFilename()); + } + //确定上传到哪个目录 + File uploadDir; + if (StrUtil.isEmpty(dirPath)) { + uploadDir = new File(baseDirPath.getUploadPath()); + } else { + uploadDir = new File(baseDirPath.getUploadPath(), dirPath); + } + if ((!uploadDir.exists()) || (!uploadDir.isDirectory())) { + boolean mkdirs = uploadDir.mkdirs(); + System.out.println("新建文件夹" + (mkdirs ? "成功" : "失败") + ":" + uploadDir.getAbsolutePath()); + } + //删除重复文件 + File uploadFile = new File(uploadDir, newFileName); + if (uploadFile.exists() && uploadFile.isFile()) { + boolean delete = uploadFile.delete(); + System.out.println("删除旧文件" + (delete ? "成功" : "失败") + ":" + uploadFile.getAbsolutePath()); + } + //上传 + file.transferTo(uploadFile); + //生成映射文件路径 + File accessDir; + if (StrUtil.isEmpty(dirPath)) { + accessDir = new File(baseDirPath.getAccessPath()); + } else { + accessDir = new File(baseDirPath.getAccessPath(), dirPath); + } + return new File(accessDir, newFileName).getPath(); + } + +} diff --git a/src/main/java/com/xkrs/allinpay/utils/HttpConnectionUtil.java b/src/main/java/com/xkrs/allinpay/utils/HttpConnectionUtil.java new file mode 100644 index 0000000..fb3aa70 --- /dev/null +++ b/src/main/java/com/xkrs/allinpay/utils/HttpConnectionUtil.java @@ -0,0 +1,115 @@ +package com.xkrs.allinpay.utils; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSession; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLEncoder; +import java.util.Map; + +public class HttpConnectionUtil { + private HttpURLConnection conn; + private String connectUrl; + + public HttpConnectionUtil(String connectUrl) { + this.connectUrl = connectUrl; + } + + public void init() throws Exception { + URL url = new URL(connectUrl); + System.setProperty("java.protocol.handler.pkgs", "javax.net.ssl"); + HostnameVerifier hv = new HostnameVerifier() { + public boolean verify(String urlHostName, SSLSession session) { + return urlHostName.equals(session.getPeerHost()); + } + }; + HttpsURLConnection.setDefaultHostnameVerifier(hv); + URLConnection conn = url.openConnection(); + conn.setDoInput(true); + conn.setDoOutput(true); + conn.setReadTimeout(60000); + conn.setConnectTimeout(30000); + if (conn instanceof HttpsURLConnection) { + HttpsURLConnection httpsConn = (HttpsURLConnection) conn; + httpsConn.setSSLSocketFactory(SSLUtil.getInstance().getSSLSocketFactory()); + } else if (conn instanceof HttpURLConnection) { + HttpURLConnection httpConn = (HttpURLConnection) conn; + } else { + throw new Exception("不是http/https协议的url"); + } + this.conn = (HttpURLConnection) conn; + initDefaultPost(); + } + + public void destory() { + try { + if (this.conn != null) { + this.conn.disconnect(); + } + } catch (Exception e) { + } + } + + private void initDefaultPost() throws Exception { + conn.setDoOutput(true); + conn.setDoInput(true); + conn.setRequestMethod("POST"); + conn.setUseCaches(false); + conn.setInstanceFollowRedirects(true); + conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + } + + public byte[] postParams(Map params, boolean readreturn) throws IOException { + StringBuilder outBuf = new StringBuilder(); + boolean isNotFirst = false; + for (Map.Entry entry : params.entrySet()) { + if (isNotFirst) outBuf.append('&'); + isNotFirst = true; + outBuf.append(entry.getKey()).append('=').append(URLEncoder.encode(entry.getValue(), "UTF-8")); + } + System.out.println("参数:" + outBuf.toString()); + return postParams(outBuf.toString(), readreturn); + } + + public byte[] postParams(String message, boolean readreturn) throws IOException { + DataOutputStream out = new DataOutputStream(conn.getOutputStream()); + out.write(message.getBytes("UTF-8")); + out.close(); + if (readreturn) { + return readBytesFromStream(conn.getInputStream()); + } else { + return null; + } + } + + public byte[] postParams(byte[] message, boolean readreturn) throws IOException { + DataOutputStream out = new DataOutputStream(conn.getOutputStream()); + out.write(message); + out.close(); + if (readreturn) { + return readBytesFromStream(conn.getInputStream()); + } else { + return null; + } + } + + private byte[] readBytesFromStream(InputStream is) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + int readLen; + byte[] tmpBuf = new byte[4096]; + while ((readLen = is.read(tmpBuf)) > 0) baos.write(tmpBuf, 0, readLen); + is.close(); + return baos.toByteArray(); + } + + public HttpURLConnection getConn() { + return conn; + } + +} diff --git a/src/main/java/com/xkrs/allinpay/utils/QRCodeUtils.java b/src/main/java/com/xkrs/allinpay/utils/QRCodeUtils.java new file mode 100644 index 0000000..238fc91 --- /dev/null +++ b/src/main/java/com/xkrs/allinpay/utils/QRCodeUtils.java @@ -0,0 +1,64 @@ +package com.xkrs.allinpay.utils; + +import com.google.zxing.BarcodeFormat; +import com.google.zxing.EncodeHintType; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.qrcode.QRCodeWriter; +import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.File; +import java.util.HashMap; +import java.util.Map; + +public class QRCodeUtils { + + /** + * 生成二维码 + * + * @param content 二维码内容 + * @param width 宽度 + * @param height 高度 + * @param saveDirPath 保存目录 + * @param accessDirPath 访问目录 + * @param fileName 文件名 + * @return 访问路径 + */ + public static String generateQRCodeImage(String content, int width, int height, String saveDirPath, String accessDirPath, String fileName) { + try { + QRCodeWriter qrCodeWriter = new QRCodeWriter(); + Map hints = new HashMap<>(); + hints.put(EncodeHintType.CHARACTER_SET, "UTF-8"); // 设置字符编码 + hints.put(EncodeHintType.MARGIN, 1); // 设置二维码边缘与内容的间隙 + hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.L); + BitMatrix bitMatrix = qrCodeWriter.encode(content, BarcodeFormat.QR_CODE, width, height, hints); + + BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + bufferedImage.createGraphics(); + + Graphics2D graphics = (Graphics2D) bufferedImage.getGraphics(); + graphics.setColor(java.awt.Color.WHITE); + graphics.fillRect(0, 0, width, height); + graphics.setColor(java.awt.Color.BLACK); + + for (int i = 0; i < width; i++) { + for (int j = 0; j < height; j++) { + if (bitMatrix.get(i, j)) { + graphics.fillRect(i, j, 1, 1); + } + } + } + File saveDir = new File(saveDirPath); + if ((!saveDir.exists()) || (!saveDir.isDirectory())) { + boolean mkdirs = saveDir.mkdirs(); + } + ImageIO.write(bufferedImage, "png", new File(saveDir, fileName)); + return new File(accessDirPath, fileName).getPath(); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } +} diff --git a/src/main/java/com/xkrs/allinpay/utils/SSLUtil.java b/src/main/java/com/xkrs/allinpay/utils/SSLUtil.java new file mode 100644 index 0000000..c337702 --- /dev/null +++ b/src/main/java/com/xkrs/allinpay/utils/SSLUtil.java @@ -0,0 +1,56 @@ +package com.xkrs.allinpay.utils; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +/** + * SSL管理助手类 + * + * @author Administrator + */ +public class SSLUtil implements X509TrustManager { + private SSLSocketFactory sslFactory = null; + + private SSLUtil() { + } + + public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { + } + + public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { + } + + public X509Certificate[] getAcceptedIssuers() { + return null; + } + + /** + * 获取SSL Socket工厂 + */ + public SSLSocketFactory getSSLSocketFactory() { + return sslFactory; + } + + private static SSLUtil _instance = null; + + /** + * 获取SSL管理助手类实例 + */ + synchronized public static SSLUtil getInstance() throws NoSuchAlgorithmException, KeyManagementException { + if (_instance == null) { + _instance = new SSLUtil(); +// SSLContext sc = SSLContext.getInstance("SSLv3"); + SSLContext sc = SSLContext.getInstance("TLSv1.2"); + sc.init(null, new TrustManager[]{new SSLUtil()}, null); + _instance.sslFactory = sc.getSocketFactory(); + } + return _instance; + } + +} diff --git a/src/main/java/com/xkrs/allinpay/utils/SmUtil.java b/src/main/java/com/xkrs/allinpay/utils/SmUtil.java new file mode 100644 index 0000000..9171a28 --- /dev/null +++ b/src/main/java/com/xkrs/allinpay/utils/SmUtil.java @@ -0,0 +1,146 @@ +package com.xkrs.allinpay.utils; + +import org.apache.commons.codec.binary.Base64; +import org.bouncycastle.asn1.ASN1EncodableVector; +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.DERSequence; +import org.bouncycastle.jcajce.spec.SM2ParameterSpec; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.*; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Arrays; + +public class SmUtil { + static { + Security.addProvider(new BouncyCastleProvider()); + } + + /** + * 算法常量:SM3withSM2 + */ + public static final String ALGORITHM_SM3SM2_BCPROV = "SM3withSM2"; + private final static int SM3withSM2_RS_LEN = 32; + + public static void main(String[] args) throws Exception { + /**商户平台分配的appid,也是签名的certid**/ + String appid = "00000156"; + /**商户sm2私钥,用于向通联发起请求前进行签名**/ + String cusPrivateKey = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgjj4Rk+b0YjwO+UwXofnHf4bK+kaaY5Btkd8nMP2VimmgCgYIKoEcz1UBgi2hRANCAAQqlALW4qGC3bP1x3wo5QsKxaCMEZJ2ODTTwOQ+d8UGU7GoK/y/WMBQWf5upMnFU06p5FxGooXYYoBtldgm03hq"; + /**商户sm2公钥,需要配置到通联商户平台**/ + String cusPubKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEKpQC1uKhgt2z9cd8KOULCsWgjBGSdjg008DkPnfFBlOxqCv8v1jAUFn+bqTJxVNOqeRcRqKF2GKAbZXYJtN4ag=="; + + /**通联平台sm2公钥,用于请求返回或者通联通知的验签**/ + String tlPubKey = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE/BnA8BawehBtH0ksPyayo4pmzL/u1FQ2sZcqwOp6bjVqQX4tjo930QAvHZPJ2eez8sCz/RYghcqv4LvMq+kloQ=="; + + String blankStr = "请求待签名数据"; + PrivateKey privkey = privKeySM2FromBase64Str(cusPrivateKey); + String sign = signSM3SM2RetBase64(privkey, appid, blankStr.getBytes("UTF-8"));//签名 + System.out.println(sign); + + String rspBlankStr = "返回待验签数据";//通联返回的明文 + String rspSign = "AovBKQGUe0xuJ0ox7FgIIX+yB3DzbudgUsnNvJmDV0IdHZtU2Y8vdeUY1pd2vmPUf08hNgdkoz+4WP/D/ktOcA==";//通联返回的签名 + PublicKey publicKey = pubKeySM2FromBase64Str(tlPubKey); + boolean isOk = verifySM3SM2(publicKey, "Allinpay", Base64.decodeBase64(rspSign), rspBlankStr.getBytes("UTF-8")); + System.out.println("验签结果:" + isOk); + + + } + + /** + * 签名并BASE64编码-SM3WithSM2 + */ + public static String signSM3SM2RetBase64(final PrivateKey privateKey, String certid, final byte[] data) throws Exception { + return Base64.encodeBase64String(signSM3SM2(privateKey, certid, data)); + } + + /** + * 签名-SM3WithSM2 + */ + public static byte[] signSM3SM2(final PrivateKey privateKey, String certid, final byte[] data) throws Exception { + SM2ParameterSpec parameterSpec = new SM2ParameterSpec(certid.getBytes()); + Signature signer = Signature.getInstance(ALGORITHM_SM3SM2_BCPROV, "BC"); + signer.setParameter(parameterSpec); + signer.initSign(privateKey, new SecureRandom()); + signer.update(data); + return byteAsn12BytePlain(signer.sign()); + } + + /** + * 验证签名-SM3WithSM2 + */ + public static boolean verifySM3SM2(final PublicKey publicKey, String certid, final byte[] signData, final byte[] srcData) throws Exception { + SM2ParameterSpec parameterSpec = new SM2ParameterSpec(certid.getBytes()); + Signature verifier = Signature.getInstance(ALGORITHM_SM3SM2_BCPROV, "BC"); + verifier.setParameter(parameterSpec); + verifier.initVerify(publicKey); + verifier.update(srcData); + return verifier.verify(bytePlain2ByteAsn1(signData)); + } + + /** + * 从字符串读取私钥-目前支持PKCS8(keystr为BASE64格式) + */ + public static PrivateKey privKeySM2FromBase64Str(String keystr) throws Exception { + KeyFactory keyFactory = KeyFactory.getInstance("EC"); + return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(Base64.decodeBase64(keystr))); + } + + /** + * 从字符串读取RSA公钥(keystr为BASE64格式) + */ + public static PublicKey pubKeySM2FromBase64Str(String keystr) throws Exception { + KeyFactory keyFactory = KeyFactory.getInstance("EC"); + return keyFactory.generatePublic(new X509EncodedKeySpec(Base64.decodeBase64(keystr))); + } + + /** + * 将普通字节数组转换为ASN1字节数组 适用于SM3withSM2验签时验签明文转换 + */ + private static byte[] bytePlain2ByteAsn1(byte[] data) { + if (data.length != SM3withSM2_RS_LEN * 2) throw new RuntimeException("err data. "); + BigInteger r = new BigInteger(1, Arrays.copyOfRange(data, 0, SM3withSM2_RS_LEN)); + BigInteger s = new BigInteger(1, Arrays.copyOfRange(data, SM3withSM2_RS_LEN, SM3withSM2_RS_LEN * 2)); + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(new ASN1Integer(r)); + v.add(new ASN1Integer(s)); + try { + return new DERSequence(v).getEncoded("DER"); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * 将ASN1字节数组转换为普通字节数组 适用于SM3withSM2签名时签名结果转换 + */ + private static byte[] byteAsn12BytePlain(byte[] dataAsn1) { + ASN1Sequence seq = ASN1Sequence.getInstance(dataAsn1); + byte[] r = bigIntToFixexLengthBytes(ASN1Integer.getInstance(seq.getObjectAt(0)).getValue()); + byte[] s = bigIntToFixexLengthBytes(ASN1Integer.getInstance(seq.getObjectAt(1)).getValue()); + byte[] result = new byte[SM3withSM2_RS_LEN * 2]; + System.arraycopy(r, 0, result, 0, r.length); + System.arraycopy(s, 0, result, SM3withSM2_RS_LEN, s.length); + return result; + } + + private static byte[] bigIntToFixexLengthBytes(BigInteger rOrS) { + byte[] rs = rOrS.toByteArray(); + if (rs.length == SM3withSM2_RS_LEN) return rs; + else if (rs.length == SM3withSM2_RS_LEN + 1 && rs[0] == 0) return Arrays.copyOfRange(rs, 1, SM3withSM2_RS_LEN + 1); + else if (rs.length < SM3withSM2_RS_LEN) { + byte[] result = new byte[SM3withSM2_RS_LEN]; + Arrays.fill(result, (byte) 0); + System.arraycopy(rs, 0, result, SM3withSM2_RS_LEN - rs.length, rs.length); + return result; + } else { + throw new RuntimeException("err rs: " + Hex.toHexString(rs)); + } + } + +} diff --git a/src/main/java/com/xkrs/allinpay/utils/SybConstants.java b/src/main/java/com/xkrs/allinpay/utils/SybConstants.java new file mode 100644 index 0000000..69ca1fb --- /dev/null +++ b/src/main/java/com/xkrs/allinpay/utils/SybConstants.java @@ -0,0 +1,16 @@ +package com.xkrs.allinpay.utils; + +public class SybConstants { + + public static final String SYB_ORGID = "";//集团/机构模式下该参数不为空,且appid与key是与次参数对应 + public static final String SYB_CUSID = "660452048163877"; + public static final String SYB_APPID = "00343859"; + public static final String SYB_MD5_APPKEY = "a0ea3fa20dbd3bb4d5abf1d56d63bae8"; + public static final String SYB_APIURL = "https://vsp.allinpay.com/apiweb/unitorder";//生产环境 + public static final String SIGN_TYPE = "RSA"; + public static final String SYB_RSACUSPRIKEY = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCz8RM/Rmvc5XJSGHV1t9HMfnN8nroYY6tUgvJdH1gamPiEX/lm2QYYoQ5nsZRUaHC4GDUOQhsrhaKmyqo2aIJqYoKEzbmt1/pLi0P9j24jEcKOfYMPoBHKxVldxigF8c6H45GRGM/P/gutdZuDo7C7EpHtExEeoZSgTHPFdQgMQC/3gYaHmQtiYcSBeBHoVokFnZqQI9Bn8LQkTn2lYR4coILEv3wtdlIHrsPpMc5V5ue+T0ooj1WzY9I+vZEHU+2wMaE2jPTr8r09xvtWprqungy2aYU91FNUVpEKF0xdWQFQAhqthGEYRMi1jMe916Hwm0e4V0Ts3x41XrjeAqaNAgMBAAECggEAE6SgQ4LKQRO6Glypq+dca3ytWkAQlBuDR0dBMmm6yjKDRJ4egXv1BqjERA0WYm2BSpN37T3JrgNZWWhb0vMvM3JcCafUmnXukKMcEbi/3uuwJ7JrZYAFmTNYeVxpn5aBQ4PT7vk8rFmxCCdDygfLQey5yd3QO14LtcEKzVYkggOrcpsJ5HF/czQtl55vlbUNYrR1UFGT+dHixAAXKRahc+B572my1P57AP6w7gPeJLpF6MjUWvggm2p2e4HuZychnT0HcnIWBfMxfI4DKsSuB/j8C6yR6gKmB9NEf1Yik6w/N83RrWnRJOG906rYRXp80fU7rlBFegm+jcqbJQsLsQKBgQD3g/Qota5IM3cwo7tyvXUHurms0n8nOjJ+XbF0Ooz/BCAJPIytqwm8RiOQBBx6OH5TuBDocJroXg5+soMGwH63AXgRxZpEoGYW0TStT5wN9D+mXLSHYraJR8uFXPAOTUUDRxwmhcZwGpBHL01r1dJN/C1oxDWFxAjEBjUAemrp0QKBgQC6HCKQP2quZ3CXiopdxOK8eiyTh/RtqE3yb7qLAfllmMSvCA4VqnaIX8TVdNJWVsWCscdKh4zQnIw63hgaLwSiYoUdIjBH9/0QfmQ1XO9lvPitX7SYSIClplYhBq+2cYV0dyl6DjqbZm2Mxb9CIYzs9KIOKuPuJjnn8ipN1MIj/QKBgQDSIiWsViojRAZBtg/S5sOvjzhJX9/xlrf9jl+0dGz1qDPmg5BPdLDsNYPFpafjn4ioXNGF9OuesROPPtB8b/pkNgwQ0nkZIC/r2SrmpHqxYhaTj4r4kba0r846Z9+p1LHtiXZ9wf7pd7Pbq24ISdyktp56nnFuIjLq8PYYdNXFsQKBgFfEyvwSHEKRn8Sn3mcoYfGXAIy28iwA0nnB/UxvKumh6SfOea34DRx1ZcNw630yQMVJB/56/IqpOWzNrroycFIQekxqAjD+n8b2hFWyNWhafUBuQSIMFzeHwVij6Zv134U0aUgZi8QbwxA/ddo/LlHVcNOToJiASJC9YPwBmWkVAoGALcumHYi4rr7CfE52PJblMlI/oKJ+I54SszSBMVRa25ltxZXLFHV65Us3bO3c4Nm2o8jqaMkvwiLAsTIB+Wu9CG47crhC9iJ9/CDF4ALP2cR0TnMyYpA89oIXtVxs18NvyS8RxAIFLB2JMPuNSD4y+tHFqrUqZin6S+if2Neaklo="; + public static final String SYB_RSATLPUBKEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCm9OV6zH5DYH/ZnAVYHscEELdCNfNTHGuBv1nYYEY9FrOzE0/4kLl9f7Y9dkWHlc2ocDwbrFSm0Vqz0q2rJPxXUYBCQl5yW3jzuKSXif7q1yOwkFVtJXvuhf5WRy+1X5FOFoMvS7538No0RpnLzmNi3ktmiqmhpcY/1pmt20FHQQIDAQAB"; + public static final String SYB_SM2PPRIVATEKEY = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQg28au4QWNMGLD4qwMTDb2rFIHPoC4+ZFudX/qsC8DirygCgYIKoEcz1UBgi2hRANCAATmdMFOdBiAYlipVwxtQMFwAdK97hMjdaoFZ53bA0SdwJ2oYMLncUpYXe+e/DI/qTwW8lyo3li/+BAwcOSvzT7g"; + public static final String SYB_SM2TLPUBKEY = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEBQicgWm0KAMqhO3bdqMUEDrKQvYg8cCXHhdGwq7CGE6oJDzJ1P/94HpuVdBf1KidmPxr7HOH+0DAnpeCcx9TcQ=="; + +} diff --git a/src/main/java/com/xkrs/allinpay/utils/SybUtil.java b/src/main/java/com/xkrs/allinpay/utils/SybUtil.java new file mode 100644 index 0000000..992b903 --- /dev/null +++ b/src/main/java/com/xkrs/allinpay/utils/SybUtil.java @@ -0,0 +1,206 @@ +package com.xkrs.allinpay.utils; + +import net.sf.json.JSONObject; +import org.apache.commons.codec.binary.Base64; + +import java.security.*; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Map; +import java.util.Random; +import java.util.TreeMap; + +public class SybUtil { + /** + * js转化为实体 + * + * @param + * @param jsonstr + * @param cls + * @return + */ + public static T json2Obj(String jsonstr, Class cls) { + JSONObject jo = JSONObject.fromObject(jsonstr); + T obj = (T) JSONObject.toBean(jo, cls); + return obj; + } + + /** + * md5 + * + * @param b + * @return + */ + public static String md5(byte[] b) { + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + md.reset(); + md.update(b); + byte[] hash = md.digest(); + StringBuffer outStrBuf = new StringBuffer(32); + for (int i = 0; i < hash.length; i++) { + int v = hash[i] & 0xFF; + if (v < 16) { + outStrBuf.append('0'); + } + outStrBuf.append(Integer.toString(v, 16).toLowerCase()); + } + return outStrBuf.toString(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + return new String(b); + } + } + + /** + * 判断字符串是否为空 + * + * @param s + * @return + */ + public static boolean isEmpty(String s) { + if (s == null || "".equals(s.trim())) return true; + return false; + } + + /** + * 生成随机码 + * + * @param n + * @return + */ + public static String getValidatecode(int n) { + Random random = new Random(); + String sRand = ""; + n = n == 0 ? 4 : n;// default 4 + for (int i = 0; i < n; i++) { + String rand = String.valueOf(random.nextInt(10)); + sRand += rand; + } + return sRand; + } + + public static boolean validSign(TreeMap param, String appkey, String signType) throws Exception { + if (param != null && !param.isEmpty()) { + if (!param.containsKey("sign")) return false; + String sign = param.remove("sign"); + if ("MD5".equals(signType)) {// 如果是md5则需要把md5的key加入到排序 + param.put("key", appkey); + } + StringBuilder sb = new StringBuilder(); + for (Map.Entry entry : param.entrySet()) { + if (entry.getValue() != null && entry.getValue().length() > 0) { + sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&"); + } + } + if (sb.length() > 0) { + sb.deleteCharAt(sb.length() - 1); + } + if ("MD5".equals(signType)) { + return sign.toLowerCase().equals(md5(sb.toString().getBytes("UTF-8")).toLowerCase()); + } else if ("SM2".equals(signType)) { + PublicKey publicKey = SmUtil.pubKeySM2FromBase64Str(appkey); + return SmUtil.verifySM3SM2(publicKey, "Allinpay", Base64.decodeBase64(sign), sb.toString().getBytes("UTF-8")); + } else { + return rsaVerifyPublickey(sb.toString(), sign, appkey, "UTF-8"); + } + } + return false; + } + + public static boolean rsaVerifyPublickey(String content, String sign, String publicKey, String charset) throws Exception { + try { + PublicKey pubKey = getPublicKeyFromX509("RSA", Base64.decodeBase64(publicKey.getBytes())); + return rsaVerifyPublickey(content, sign, pubKey, charset); + } catch (Exception e) { + e.printStackTrace(); + throw new Exception("RSAcontent = " + content + ",sign=" + sign + ",charset = " + charset, e); + } + } + + public static boolean rsaVerifyPublickey(String content, String sign, PublicKey pubKey, String charset) throws Exception { + try { + java.security.Signature signature = java.security.Signature.getInstance("SHA1WithRSA"); + + signature.initVerify(pubKey); + + if (charset == null || "".equals(charset)) { + signature.update(content.getBytes()); + } else { + signature.update(content.getBytes(charset)); + } + + return signature.verify(Base64.decodeBase64(sign.getBytes())); + } catch (Exception e) { + throw e; + } + } + + public static String unionSign(TreeMap params, String appkey, String signType) throws Exception { + // TODO Auto-generated method stub + + params.remove("sign"); + if ("MD5".equals(signType)) {// 如果是md5则需要把md5的key加入到排序 + params.put("key", appkey); + } + StringBuilder sb = new StringBuilder(); + for (Map.Entry entry : params.entrySet()) { + if (entry.getValue() != null && entry.getValue().length() > 0) { + sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&"); + } + } + if (sb.length() > 0) { + sb.deleteCharAt(sb.length() - 1); + } + String sign = ""; + if ("MD5".equals(signType)) { + System.out.println(sb.toString()); + sign = md5(sb.toString().getBytes("UTF-8"));// 记得是md5编码的加签 + params.remove("key"); + } else if ("SM2".equals(signType)) { + System.out.println(sb.toString()); + PrivateKey privkey = SmUtil.privKeySM2FromBase64Str(appkey); + sign = SmUtil.signSM3SM2RetBase64(privkey, params.get("appid"), sb.toString().getBytes("UTF-8"));//签名 + } else { + System.out.println(sb.toString()); + sign = rsaSign(sb.toString(), appkey, "UTF-8"); + } + return sign; + } + + public static String rsaSign(String content, String privateKey, String charset) throws Exception { + PrivateKey priKey = getPrivateKeyFromPKCS8("RSA", Base64.decodeBase64(privateKey.getBytes())); + return rsaSign(content, priKey, charset); + } + + public static String rsaSign(String content, byte[] privateKey, String charset) throws Exception { + PrivateKey priKey = getPrivateKeyFromPKCS8("RSA", privateKey); + return rsaSign(content, priKey, charset); + } + + public static String rsaSign(String content, PrivateKey priKey, String charset) throws Exception { + java.security.Signature signature = java.security.Signature.getInstance("SHA1WithRSA"); + signature.initSign(priKey); + if (charset == null || "".equals(charset)) { + signature.update(content.getBytes()); + } else { + signature.update(content.getBytes(charset)); + } + byte[] signed = signature.sign(); + + return new String(Base64.encodeBase64(signed)); + } + + public static PrivateKey getPrivateKeyFromPKCS8(String algorithm, byte[] encodedKey) throws Exception { + + KeyFactory keyFactory = KeyFactory.getInstance(algorithm); + + return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey)); + } + + public static PublicKey getPublicKeyFromX509(String algorithm, byte[] encodedKey) throws Exception { + KeyFactory keyFactory = KeyFactory.getInstance(algorithm); + + return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey)); + } +} diff --git a/src/main/java/com/xkrs/common/config/WebSecurityConfig.java b/src/main/java/com/xkrs/common/config/WebSecurityConfig.java index ab0b486..f749dc9 100644 --- a/src/main/java/com/xkrs/common/config/WebSecurityConfig.java +++ b/src/main/java/com/xkrs/common/config/WebSecurityConfig.java @@ -34,6 +34,7 @@ class WebSecurityConfig extends WebSecurityConfigurerAdapter { // 所有OPTIONS请求都放行 .antMatchers(HttpMethod.OPTIONS).permitAll() .antMatchers("/global/configuration/**").permitAll() + .antMatchers("/websocket/**").permitAll()//支付结果通知前端 .antMatchers("/push/**").permitAll() .antMatchers("/debug").permitAll() .antMatchers("/queryFirePoint").permitAll() diff --git a/src/main/java/com/xkrs/dao/TranNotifyDao.java b/src/main/java/com/xkrs/dao/TranNotifyDao.java new file mode 100644 index 0000000..cc6d9bf --- /dev/null +++ b/src/main/java/com/xkrs/dao/TranNotifyDao.java @@ -0,0 +1,10 @@ +package com.xkrs.dao; + +import com.xkrs.allinpay.model.TranNotifyEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.stereotype.Component; + +@Component +public interface TranNotifyDao extends JpaRepository, JpaSpecificationExecutor { +} diff --git a/src/main/java/com/xkrs/dao/TranQueryDao.java b/src/main/java/com/xkrs/dao/TranQueryDao.java new file mode 100644 index 0000000..03fc781 --- /dev/null +++ b/src/main/java/com/xkrs/dao/TranQueryDao.java @@ -0,0 +1,37 @@ +package com.xkrs.dao; + +import com.xkrs.allinpay.model.TranQueryEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; + +@Component +public interface TranQueryDao extends JpaRepository, JpaSpecificationExecutor { + + /** + * 普通用户查询订单 + * + * @param userId + * @param pageNum + * @param pageSize + * @return + */ + @Query(value = "SELECT q.trxid, q.reqsn, u.user_name AS username, u.really_name AS reallyname, o.body, q.trxamt, q.fintime, q.trxstatus FROM tran_query AS q LEFT JOIN unit_order_pay AS o ON q.orderid = o.id LEFT JOIN sys_user AS u ON o.user_id = u.id WHERE u.id = ?1 ORDER BY q.fintime DESC LIMIT ?3 OFFSET (?2 - 1) * ?3", nativeQuery = true) + List> queryTran(int userId, int pageNum, int pageSize); + + /** + * 管理员查询订单 + * + * @param userName + * @param pageNum + * @param pageSize + * @return + */ + @Query(value = "SELECT q.trxid, q.reqsn, u.user_name AS username, u.really_name AS reallyname, o.body, q.trxamt, q.fintime, q.trxstatus FROM tran_query AS q LEFT JOIN unit_order_pay AS o ON q.orderid = o.id LEFT JOIN sys_user AS u ON o.user_id = u.id WHERE u.user_name LIKE %?1% ORDER BY q.fintime DESC LIMIT ?3 OFFSET (?2 - 1) * ?3", nativeQuery = true) + List> queryTranByAdmin(String userName, int pageNum, int pageSize); + +} diff --git a/src/main/java/com/xkrs/dao/UnitOrderPayDao.java b/src/main/java/com/xkrs/dao/UnitOrderPayDao.java new file mode 100644 index 0000000..d2b7730 --- /dev/null +++ b/src/main/java/com/xkrs/dao/UnitOrderPayDao.java @@ -0,0 +1,10 @@ +package com.xkrs.dao; + +import com.xkrs.allinpay.model.UnitOrderPayEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.stereotype.Component; + +@Component +public interface UnitOrderPayDao extends JpaRepository, JpaSpecificationExecutor { +} diff --git a/src/main/java/com/xkrs/websocket/SemaphoreUtils.java b/src/main/java/com/xkrs/websocket/SemaphoreUtils.java new file mode 100644 index 0000000..e066ca2 --- /dev/null +++ b/src/main/java/com/xkrs/websocket/SemaphoreUtils.java @@ -0,0 +1,49 @@ +package com.xkrs.websocket; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.Semaphore; + +/** + * 信号量相关处理 + * + * @author ruoyi + */ +public class SemaphoreUtils { + + /** + * SemaphoreUtils 日志控制器 + */ + private static final Logger LOGGER = LoggerFactory.getLogger(SemaphoreUtils.class); + + /** + * 获取信号量 + * + * @param semaphore + * @return + */ + public static boolean tryAcquire(Semaphore semaphore) { + boolean flag = false; + try { + flag = semaphore.tryAcquire(); + } catch (Exception e) { + LOGGER.error("获取信号量异常", e); + } + return flag; + } + + /** + * 释放信号量 + * + * @param semaphore + */ + public static void release(Semaphore semaphore) { + try { + semaphore.release(); + } catch (Exception e) { + LOGGER.error("释放信号量异常", e); + } + } + +} diff --git a/src/main/java/com/xkrs/websocket/WebSocketConfig.java b/src/main/java/com/xkrs/websocket/WebSocketConfig.java new file mode 100644 index 0000000..6f16cf7 --- /dev/null +++ b/src/main/java/com/xkrs/websocket/WebSocketConfig.java @@ -0,0 +1,20 @@ +package com.xkrs.websocket; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.socket.server.standard.ServerEndpointExporter; + +/** + * websocket 配置 + * + * @author ruoyi + */ +@Configuration +public class WebSocketConfig { + + @Bean + public ServerEndpointExporter serverEndpointExporter() { + return new ServerEndpointExporter(); + } + +} diff --git a/src/main/java/com/xkrs/websocket/WebSocketServer.java b/src/main/java/com/xkrs/websocket/WebSocketServer.java new file mode 100644 index 0000000..0869d55 --- /dev/null +++ b/src/main/java/com/xkrs/websocket/WebSocketServer.java @@ -0,0 +1,93 @@ +package com.xkrs.websocket; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import javax.websocket.*; +import javax.websocket.server.ServerEndpoint; +import java.util.concurrent.Semaphore; + +/** + * websocket 消息处理 + * + * @author ruoyi + */ +@Component +@ServerEndpoint("/websocket/message") +public class WebSocketServer { + + /** + * WebSocketServer 日志控制器 + */ + private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketServer.class); + + /** + * 默认最多允许同时在线人数100 + */ + public static int socketMaxOnlineCount = 100; + + private static Semaphore socketSemaphore = new Semaphore(socketMaxOnlineCount); + + /** + * 连接建立成功调用的方法 + */ + @OnOpen + public void onOpen(Session session) throws Exception { + boolean semaphoreFlag = false; + // 尝试获取信号量 + semaphoreFlag = SemaphoreUtils.tryAcquire(socketSemaphore); + if (!semaphoreFlag) { + // 未获取到信号量 + LOGGER.error("\n 当前在线人数超过限制数- {}", socketMaxOnlineCount); + WebSocketUsers.sendMessageToUserByText(session, "当前在线人数超过限制数:" + socketMaxOnlineCount); + session.close(); + } else { + // 添加用户 + WebSocketUsers.put(session.getId(), session); + LOGGER.info("\n 建立连接 - {}", session); + LOGGER.info("\n 当前人数 - {}", WebSocketUsers.getUsers().size()); + WebSocketUsers.sendMessageToUserByText(session, "连接成功"); + } + } + + /** + * 连接关闭时处理 + */ + @OnClose + public void onClose(Session session) { + LOGGER.info("\n 关闭连接 - {}", session); + // 移除用户 + WebSocketUsers.remove(session.getId()); + // 获取到信号量则需释放 + SemaphoreUtils.release(socketSemaphore); + } + + /** + * 抛出异常时处理 + */ + @OnError + public void onError(Session session, Throwable exception) throws Exception { + if (session.isOpen()) { + // 关闭连接 + session.close(); + } + String sessionId = session.getId(); + LOGGER.info("\n 连接异常 - {}", sessionId); + LOGGER.info("\n 异常信息 - {}", exception); + // 移出用户 + WebSocketUsers.remove(sessionId); + // 获取到信号量则需释放 + SemaphoreUtils.release(socketSemaphore); + } + + /** + * 服务器接收到客户端消息时调用的方法 + */ + @OnMessage + public void onMessage(String message, Session session) { + String msg = message.replace("你", "我").replace("吗", ""); + WebSocketUsers.sendMessageToUserByText(session, msg); + } + +} diff --git a/src/main/java/com/xkrs/websocket/WebSocketUsers.java b/src/main/java/com/xkrs/websocket/WebSocketUsers.java new file mode 100644 index 0000000..4ec84b6 --- /dev/null +++ b/src/main/java/com/xkrs/websocket/WebSocketUsers.java @@ -0,0 +1,120 @@ +package com.xkrs.websocket; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.websocket.Session; +import java.io.IOException; +import java.util.Collection; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** + * websocket 客户端用户集 + * + * @author ruoyi + */ +public class WebSocketUsers { + + /** + * WebSocketUsers 日志控制器 + */ + private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketUsers.class); + + /** + * 用户集 + */ + private static Map USERS = new ConcurrentHashMap(); + + /** + * 存储用户 + * + * @param key 唯一键 + * @param session 用户信息 + */ + public static void put(String key, Session session) { + USERS.put(key, session); + } + + /** + * 移除用户 + * + * @param session 用户信息 + * @return 移除结果 + */ + public static boolean remove(Session session) { + String key = null; + boolean flag = USERS.containsValue(session); + if (flag) { + Set> entries = USERS.entrySet(); + for (Map.Entry entry : entries) { + Session value = entry.getValue(); + if (value.equals(session)) { + key = entry.getKey(); + break; + } + } + } else { + return true; + } + return remove(key); + } + + /** + * 移出用户 + * + * @param key 键 + */ + public static boolean remove(String key) { + LOGGER.info("\n 正在移出用户 - {}", key); + Session remove = USERS.remove(key); + if (remove != null) { + boolean containsValue = USERS.containsValue(remove); + LOGGER.info("\n 移出结果 - {}", containsValue ? "失败" : "成功"); + return containsValue; + } else { + return true; + } + } + + /** + * 获取在线用户列表 + * + * @return 返回用户集合 + */ + public static Map getUsers() { + return USERS; + } + + /** + * 群发消息文本消息 + * + * @param message 消息内容 + */ + public static void sendMessageToUsersByText(String message) { + Collection values = USERS.values(); + for (Session value : values) { + sendMessageToUserByText(value, message); + } + } + + /** + * 发送文本消息 + * + * @param session 自己的用户 + * @param message 消息内容 + */ + public static void sendMessageToUserByText(Session session, String message) { + if (session != null) { + try { + session.getBasicRemote().sendText(message); + } catch (IOException e) { + LOGGER.error("\n[发送消息异常]", e); + } + } else { + LOGGER.info("\n[你已离线]"); + } + } + +} diff --git a/src/main/java/com/xkrs/websocket/pay/PaySemaphoreUtils.java b/src/main/java/com/xkrs/websocket/pay/PaySemaphoreUtils.java new file mode 100644 index 0000000..8e7e9d6 --- /dev/null +++ b/src/main/java/com/xkrs/websocket/pay/PaySemaphoreUtils.java @@ -0,0 +1,49 @@ +package com.xkrs.websocket.pay; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.Semaphore; + +/** + * 信号量相关处理 + * + * @author ruoyi + */ +public class PaySemaphoreUtils { + + /** + * SemaphoreUtils 日志控制器 + */ + private static final Logger LOGGER = LoggerFactory.getLogger(PaySemaphoreUtils.class); + + /** + * 获取信号量 + * + * @param semaphore + * @return + */ + public static boolean tryAcquire(Semaphore semaphore) { + boolean flag = false; + try { + flag = semaphore.tryAcquire(); + } catch (Exception e) { + LOGGER.error("获取信号量异常", e); + } + return flag; + } + + /** + * 释放信号量 + * + * @param semaphore + */ + public static void release(Semaphore semaphore) { + try { + semaphore.release(); + } catch (Exception e) { + LOGGER.error("释放信号量异常", e); + } + } + +} diff --git a/src/main/java/com/xkrs/websocket/pay/PayWebSocketServer.java b/src/main/java/com/xkrs/websocket/pay/PayWebSocketServer.java new file mode 100644 index 0000000..876a25e --- /dev/null +++ b/src/main/java/com/xkrs/websocket/pay/PayWebSocketServer.java @@ -0,0 +1,95 @@ +package com.xkrs.websocket.pay; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import javax.websocket.*; +import javax.websocket.server.ServerEndpoint; +import java.util.concurrent.Semaphore; + +/** + * websocket 消息处理 + * + * @author ruoyi + *

+ * ws://8.142.26.238:7801/websocket/pay + */ +@Component +@ServerEndpoint("/websocket/pay") +public class PayWebSocketServer { + + /** + * WebSocketServer 日志控制器 + */ + private static final Logger LOGGER = LoggerFactory.getLogger(PayWebSocketServer.class); + + /** + * 默认最多允许同时在线人数100 + */ + public static int socketMaxOnlineCount = 100; + + private static Semaphore socketSemaphore = new Semaphore(socketMaxOnlineCount); + + /** + * 连接建立成功调用的方法 + */ + @OnOpen + public void onOpen(Session session) throws Exception { + boolean semaphoreFlag = false; + // 尝试获取信号量 + semaphoreFlag = PaySemaphoreUtils.tryAcquire(socketSemaphore); + if (!semaphoreFlag) { + // 未获取到信号量 + LOGGER.error("\n 当前在线人数超过限制数- {}", socketMaxOnlineCount); + PayWebSocketUsers.sendMessageToUserByText(session, "当前在线人数超过限制数:" + socketMaxOnlineCount); + session.close(); + } else { + // 添加用户 + PayWebSocketUsers.put(session.getId(), session); + LOGGER.info("\n 建立连接 - {}", session); + LOGGER.info("\n 当前人数 - {}", PayWebSocketUsers.getUsers().size()); + PayWebSocketUsers.sendMessageToUserByText(session, "连接成功"); + } + } + + /** + * 连接关闭时处理 + */ + @OnClose + public void onClose(Session session) { + LOGGER.info("\n 关闭连接 - {}", session); + // 移除用户 + PayWebSocketUsers.remove(session.getId()); + // 获取到信号量则需释放 + PaySemaphoreUtils.release(socketSemaphore); + } + + /** + * 抛出异常时处理 + */ + @OnError + public void onError(Session session, Throwable exception) throws Exception { + if (session.isOpen()) { + // 关闭连接 + session.close(); + } + String sessionId = session.getId(); + LOGGER.info("\n 连接异常 - {}", sessionId); + LOGGER.info("\n 异常信息 - {}", exception); + // 移出用户 + PayWebSocketUsers.remove(sessionId); + // 获取到信号量则需释放 + PaySemaphoreUtils.release(socketSemaphore); + } + + /** + * 服务器接收到客户端消息时调用的方法 + */ + @OnMessage + public void onMessage(String message, Session session) { + String msg = message.replace("你", "我").replace("吗", ""); + PayWebSocketUsers.sendMessageToUserByText(session, msg); + } + +} diff --git a/src/main/java/com/xkrs/websocket/pay/PayWebSocketUsers.java b/src/main/java/com/xkrs/websocket/pay/PayWebSocketUsers.java new file mode 100644 index 0000000..4c47850 --- /dev/null +++ b/src/main/java/com/xkrs/websocket/pay/PayWebSocketUsers.java @@ -0,0 +1,120 @@ +package com.xkrs.websocket.pay; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.websocket.Session; +import java.io.IOException; +import java.util.Collection; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** + * websocket 客户端用户集 + * + * @author ruoyi + */ +public class PayWebSocketUsers { + + /** + * WebSocketUsers 日志控制器 + */ + private static final Logger LOGGER = LoggerFactory.getLogger(PayWebSocketUsers.class); + + /** + * 用户集 + */ + private static Map USERS = new ConcurrentHashMap(); + + /** + * 存储用户 + * + * @param key 唯一键 + * @param session 用户信息 + */ + public static void put(String key, Session session) { + USERS.put(key, session); + } + + /** + * 移除用户 + * + * @param session 用户信息 + * @return 移除结果 + */ + public static boolean remove(Session session) { + String key = null; + boolean flag = USERS.containsValue(session); + if (flag) { + Set> entries = USERS.entrySet(); + for (Map.Entry entry : entries) { + Session value = entry.getValue(); + if (value.equals(session)) { + key = entry.getKey(); + break; + } + } + } else { + return true; + } + return remove(key); + } + + /** + * 移出用户 + * + * @param key 键 + */ + public static boolean remove(String key) { + LOGGER.info("\n 正在移出用户 - {}", key); + Session remove = USERS.remove(key); + if (remove != null) { + boolean containsValue = USERS.containsValue(remove); + LOGGER.info("\n 移出结果 - {}", containsValue ? "失败" : "成功"); + return containsValue; + } else { + return true; + } + } + + /** + * 获取在线用户列表 + * + * @return 返回用户集合 + */ + public static Map getUsers() { + return USERS; + } + + /** + * 群发消息文本消息 + * + * @param message 消息内容 + */ + public static void sendMessageToUsersByText(String message) { + Collection values = USERS.values(); + for (Session value : values) { + sendMessageToUserByText(value, message); + } + } + + /** + * 发送文本消息 + * + * @param session 自己的用户 + * @param message 消息内容 + */ + public static void sendMessageToUserByText(Session session, String message) { + if (session != null) { + try { + session.getBasicRemote().sendText(message); + } catch (IOException e) { + LOGGER.error("\n[发送消息异常]", e); + } + } else { + LOGGER.info("\n[你已离线]"); + } + } + +}