package com.tourguide.common.huifu; import com.alibaba.fastjson.JSONObject; import com.huifu.bspay.sdk.opps.core.utils.RsaUtils; import com.tourguide.common.huifu.properties.HuiFuProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; /** * 斗拱回调入口。 * * 备注:该控制器只做参数校验、验签和日志记录,订单状态落库应在后续服务层按 req_seq_id 幂等处理。 */ @RestController @RequestMapping("/base/dougong") public class DouGongNotifyController { private static final Logger log = LoggerFactory.getLogger(DouGongNotifyController.class); @Autowired private HuiFuProperties huiFuProperties; @PostMapping("/pay-notify") public String payNotify(HttpServletRequest request) { return handleNotify("dougong-pay", request); } @PostMapping("/refund-logistics") public String refundLogistics(HttpServletRequest request) { return handleNotify("dougong-refund-logistics", request); } @PostMapping("/refund-crosscity") public String refundCrossCity(HttpServletRequest request) { return handleNotify("dougong-refund-crosscity", request); } @PostMapping("/encashment") public String encashment(HttpServletRequest request) { return handleNotify("dougong-encashment", request); } private String handleNotify(String bizName, HttpServletRequest request) { String sign = request.getParameter("sign"); String respData = request.getParameter("resp_data"); if (!StringUtils.hasText(sign) || !StringUtils.hasText(respData)) { log.warn("{} missing params, sign={}, resp_data={}", bizName, sign, respData); return "FAIL"; } // 备注:斗拱回调可能把括号转义为带空格的 HTML 实体,验签前必须恢复原文,否则签名会不一致。 String normalizedRespData = respData.replaceAll("& #40;", "(").replaceAll("& #41;", ")"); boolean verified = RsaUtils.verify(normalizedRespData, huiFuProperties.getRsaPublicKey(), sign); if (!verified) { log.warn("{} signature verify failed, resp_data={}", bizName, normalizedRespData); return "FAIL"; } JSONObject body = JSONObject.parseObject(normalizedRespData); // 备注:当前阶段先记录回调关键流水,后续订单支付确认、退款确认、提现确认都应从这里分发到幂等服务。 log.info("{} verified, req_seq_id={}, org_req_seq_id={}, trans_stat={}, body={}", bizName, body.getString("req_seq_id"), body.getString("org_req_seq_id"), body.getString("trans_stat"), body); return "200"; } }