import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.client.RestTemplate;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@Controller
public class PayController {
private Logger logger = LoggerFactory.getLogger(PayController.class);
@Autowired
private PayResultValidator payResultValidator;
@Autowired
private PlatformPayer platformPayer;
@Autowired
private OrderService orderService;
@Value("${signkey}")
private String signkey;
@Autowired
private RestTemplate restTemplate;
/**
* payWay: 支付方式,暂时只有一个 WeiXin ZhiFuBao
* orderNumber: 订单的编号
*
* @param payWay
* @return
*/
@RequestMapping(value = "/mc/pay/{payWay}", method = RequestMethod.POST)
public ResponseDto pay(@PathVariable PayWay payWay,
@RequestParam String orderNumber,
@RequestParam String sign, String tradeType, HttpServletRequest httpServletRequest
) throws IOException {
Map<String, String> params = new HashMap<>();
params.put("orderNumber", orderNumber);
params.put("signkey", signkey);
if (!SignUtils.verification(params, sign)) {
throw new RuntimeException("请求签名失败");
}
String clientIp = httpServletRequest.getHeader("X-Forwarded-For").split(",")[0];
PayDto payDto = platformPayer.pay(payWay, Long.valueOf(orderNumber), tradeType, clientIp, null);
return new ResponseDto().success(payDto);
}
@RequestMapping(value = "/mi/pay/notify/{payWay}")
public void payNotify(@PathVariable PayWay payWay, HttpServletRequest request) {
Map<String, Object> map = XmlUtils.getParameterMap(request);
// payResultValidator.validate(map);
String orderNumber = map.get("orderNo").toString();
Double orderPrice = Double.valueOf(map.get("orderPrice").toString());
orderService.handlePayResult(payWay, orderNumber, orderPrice);
}
@RequestMapping(value = "/mc/h5pay/{payWay}", method = RequestMethod.POST)
public ResponseDto h5Pay(@PathVariable PayWay payWay,
@RequestParam String orderNumber, @RequestParam String tradeType, HttpServletRequest request
) throws IOException {
//生产环境和测试使用这个
String clientIp = request.getHeader("X-Forwarded-For").split(",")[0];
//本地使用这个
// String clientIp = WebUtils.clientIp(request);
PayDto payDto = platformPayer.pay(payWay, Long.valueOf(orderNumber), tradeType, clientIp, null);
return new ResponseDto().success(payDto);
}
@RequestMapping(value = "/mc/public/number/{payWay}", method = RequestMethod.POST)
public ResponseDto publicNumber(@PathVariable PayWay payWay,
@RequestParam String orderNumber, @RequestParam String tradeType, HttpServletRequest request, HttpSession session
) throws IOException {
//生产环境和测试使用这个
String clientIp = request.getHeader("X-Forwarded-For").split(",")[0];
//本地使用这个
// String clientIp = WebUtils.clientIp(request);
String openId = String.valueOf(session.getAttribute("openId"));
PayDto payDto = platformPayer.pay(payWay, Long.valueOf(orderNumber), tradeType, clientIp, openId);
return new ResponseDto().success(payDto);
}
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import java.util.Date;
import java.util.Map;
@Component
public class PlatformPayer {
private static final Logger logger = LoggerFactory.getLogger(PlatformPayer.class);
@Autowired
private RestTemplate restTemplate;
@Autowired
private SellerRepository sellerRepository;
@Value("${pay.notify.url}")
private String notifyUrl;
@Value("${pay.create.ip}")
private String createIp;
@Value("${pay.url}")
private String url;
@Value("${h5.pay.url}")
private String H5PayUrl;
protected OrderService orderService = SpringUtils.getBean(OrderService.class);
@SuppressWarnings("unchecked")
public PayDto pay(PayWay payWay, Long orderNumber, String tradeType, String clientIp, String openId) {
//校验传入的订单
Order order = orderService.findByOrderNumber(orderNumber);
if (order == null) {
throw new Exception("未能找到订单,检查订单号");
}
if (!OrderStatus.WaitPay.equals(order.getStatus())) {
throw new Exception("订单已支付");
}
Seller seller = sellerRepository.findOne(order.getSellerId());
String goodsNames = orderService.findAllGoodsNames(String.valueOf(orderNumber));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
headers.add("X-Requested-With", "XMLHttpRequest");
MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
//todo 公众号支付的payKey
params.add("payKey", seller.getPayKey());
params.add("productName", goodsNames);
params.add("orderIp", clientIp);
params.add("payWayCode", payWay.getCode());
params.add("orderNo", String.valueOf(orderNumber));
String orderTimeStr = Utils.toDateText(new Date(), MonkeyUtils.DEFAULT_DATE_TIME_FORMAT);
params.add("orderTime", orderTimeStr);
params.add("orderPeriod", "60");
params.add("orderPrice", String.valueOf(order.getShouldPay()));
params.add("notifyUrl", notifyUrl + "/" + payWay.name() + ".htm");
params.add("remark", "商品订单");
if (Utils.isNotEmpty(tradeType)) {
params.add("tradeType", tradeType);
}
if ("JSAPI".equals(tradeType)) {
params.add("openId", openId);
}
params.add("sign", MerchantApiUtil.getSign(params.toSingleValueMap(), seller.getPaySecret()));
logger.info("app支付,传递参数:{}", params);
logger.info("app支付,传递参数:{}", params);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(params, headers);
String body = "";
if (Utils.isEmpty(tradeType)) {
body = restTemplate.postForObject(url, requestEntity, String.class);
} else {
body = restTemplate.postForObject(H5PayUrl, requestEntity, String.class);
}
logger.info("微信支付返回:{}", body);
logger.info("微信支付返回:{}", body);
JSONObject data = JSON.parseObject(body);
if (!data.getBoolean("success")) {
throw new Exception("支付平台异常,请稍后重试");
}
PayDto payDto;
if (PayWay.ZhiFuBao.equals(payWay)) {
payDto = new PayDto(PayWay.ZhiFuBao);
payDto.setZhiFuBaoResponse(data.getString("data"));
} else {
JSONObject object = JSON.parseObject(data.getString("data"));
payDto = new PayDto(payWay);
payDto.setWeiXinResponse((Map<String, String>) object.get("appWakeUp"));
}
return payDto;
}
}
public enum PayWay {
None("未知"),
WeiXin("微信") {
@Override
public void sign(String key, Map<String, String> map) {
Map<String, String> params = SignUtils.paraFilter(map);
StringBuilder buf = new StringBuilder((params.size() + 1) * 10);
SignUtils.buildPayParams(buf, params, false);
String preStr = buf.toString();
String sign = MD5.sign(preStr, "&key=" + key, Constants.ENCODING);
map.put("sign", sign);
}
@Override
public String getCode() {
return "WEIXIN";
}
},
ZhiFuBao("支付宝") {
@Override
public String getCode() {
return "ALIPAY";
}
},
WeiXinH5("微信H5支付"){
@Override
public String getCode() {
return "WEIXIN";
}
};
private String label;
PayWay(String label) {
this.label = label;
}
public String getLabel() {
return label;
}
public void sign(String key, Map<String, String> map) {
throw new UnsupportedOperationException();
}
public String getCode() {
throw new UnsupportedOperationException();
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import java.util.Date;
@Component
public class RefundManager {
private Logger logger = LoggerFactory.getLogger(RefundManager.class);
@Autowired
private RestTemplate restTemplate;
@Value("${refund.notify.url}")
private String notifyUrl;
@Value("${refund.url}")
private String url;
@Autowired
private AfterSaleServerService afterSaleServerService;
@Autowired
private OrderService orderService;
@Autowired
private SellerRepository sellerRepository;
public void refund(Long afterSaleId, String remark) {
AfterSaleServer afterSaleServer = afterSaleServerService.findOne(afterSaleId);
Order order = orderService.findOne(afterSaleServer.getOrderId());
if (order == null) {
throw new Exception("未能找到订单,检查订单号");
}
if (OrderStatus.WaitPay.equals(order.getStatus())) {
throw new Exception("订单未支付");
}
Seller seller = sellerRepository.findOne(order.getSellerId());
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
headers.add("X-Requested-With", "XMLHttpRequest");
MultiValueMap<String, Object> params = new LinkedMultiValueMap<>();
params.add("payKey", seller.getPayKey());
params.add("orderNo", order.getNumber());
params.add("refundOrderNo", afterSaleServer.getNumber());
params.add("refundRequestTime", Utils.toDateText(new Date(), MonkeyUtils.DEFAULT_DATE_TIME_FORMAT));
params.add("refundAmount", String.valueOf(afterSaleServer.getAmountOfRefund()));
params.add("notifyUrl", notifyUrl + "/" + order.getPayWay().name() + ".htm");
params.add("refundReason", afterSaleServer.getProblemDes());
params.add("remark", remark);
params.add("sign", MerchantApiUtil.getSign(params.toSingleValueMap(), seller.getPaySecret()));
logger.info("market info: {}", params);
System.out.println("============================");
System.out.println(url);
System.out.println(JSON.toJSONString(params));
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(params, headers);
String body = restTemplate.postForObject(url, requestEntity, String.class);
System.out.println("============================");
System.out.println(body);
JSONObject data = JSON.parseObject(body);
if (!data.getBoolean("success")) {
System.out.println(body);
throw new Exception("支付平台异常,请稍后重试");
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
public class PlatformPayResultValidator implements PayResultValidator {
@Autowired
private OrderService orderService;
@Autowired
private SellerService sellerService;
@Override
public void validate(Map<String, Object> params) {
String payKey = params.get("payKey").toString();
String orderNo = params.get("orderNo").toString();
Order order = orderService.findByOrderNumber(Long.valueOf(orderNo));
Seller seller = sellerService.findOne(order.getSellerId());
if (!seller.getPayKey().equals(payKey)) {
throw new ValidateFailException("支付key 不正确,接收到的key: " + payKey + ", 商户key: " + seller.getPayKey());
}
String tradeStatus = params.get("tradeStatus").toString();
if (!"SUCCESS".equals(tradeStatus)) {
throw new ValidateFailException("支付平台订单状态不是SUCCESS,tradeStatus:" + tradeStatus);
}
String sign = params.get("sign").toString();
params.remove("sign");
if (!MerchantApiUtil.isRightSign(params, seller.getPaySecret(), sign)) {
throw new ValidateFailException("订单签名异常,sign:" + sign);
}
if (order == null) {
throw new ValidateFailException("订单编号不对,orderNo:" + orderNo);
}
Double orderPrice = Double.valueOf(params.get("orderPrice").toString());
if (!orderPrice.equals(order.getShouldPay())) {
throw new ValidateFailException("订单价格不对,orderPrice:" + orderPrice);
}
}
}
public class ValidateFailException extends RuntimeException {
public ValidateFailException() {
}
public ValidateFailException(String message) {
super(message);
}
}
参考文档: http://blog.51cto.com/sihai/2131168