Java 示例
此示例基于 Spring RestTemplate,包含签名、POST JSON、GET Query,以及代收下单、代付下单、商户信息查询三个接口。
java
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
public class SkynetClient {
private final String baseUrl;
private final int mchId;
private final String apiToken;
private final RestTemplate restTemplate = new RestTemplate();
public SkynetClient(String baseUrl, int mchId, String apiToken) {
this.baseUrl = baseUrl;
this.mchId = mchId;
this.apiToken = apiToken;
}
public Map<String, Object> createCollectOrder() {
Map<String, Object> params = new HashMap<>();
params.put("trans_id", "ORDER-" + Instant.now().getEpochSecond());
params.put("currency", "VND");
params.put("amount", "100.00");
params.put("channel", "bank");
params.put("callback_url", "https://merchant.example.com/callback/collect");
params.put("return_url", "https://merchant.example.com/payment/result");
params.put("remarks", "collect demo");
return post("/api/v1/mch/pmt-orders", params);
}
public Map<String, Object> createPayoutOrder() {
Map<String, Object> params = new HashMap<>();
params.put("trans_id", "WDL-" + Instant.now().getEpochSecond());
params.put("channel", "bank");
params.put("amount", "100.00");
params.put("currency", "VND");
params.put("account_no", "2333667799212341");
params.put("account_name", "NGUYEN XUAN HUNG");
params.put("account_org", "PVCOMBANK");
params.put("account_org_code", "970412");
params.put("callback_url", "https://merchant.example.com/callback/payout");
params.put("remarks", "payout demo");
return post("/api/v1/mch/wdl-orders", params);
}
public Map<String, Object> getMerchantInfo() {
return get("/api/v1/mch/info", new HashMap<>());
}
private Map<String, Object> post(String path, Map<String, Object> params) {
Map<String, Object> signedParams = withSignature(params);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
ResponseEntity<Map> response = restTemplate.postForEntity(
baseUrl + path,
new HttpEntity<>(signedParams, headers),
Map.class
);
return parseResponse(response);
}
private Map<String, Object> get(String path, Map<String, Object> params) {
Map<String, Object> signedParams = withSignature(params);
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseUrl + path);
signedParams.forEach(builder::queryParam);
ResponseEntity<Map> response = restTemplate.exchange(
builder.toUriString(),
HttpMethod.GET,
HttpEntity.EMPTY,
Map.class
);
return parseResponse(response);
}
private Map<String, Object> withSignature(Map<String, Object> params) {
Map<String, Object> signedParams = new HashMap<>(params);
signedParams.put("mch_id", mchId);
signedParams.put("nonce", UUID.randomUUID().toString().replace("-", "").substring(0, 12));
signedParams.put("timestamp", Instant.now().getEpochSecond());
signedParams.put("sign", sign(signedParams));
return signedParams;
}
private String sign(Map<String, Object> params) {
List<String> keys = new ArrayList<>(params.keySet());
keys.sort(String::compareTo);
StringBuilder source = new StringBuilder(apiToken);
for (String key : keys) {
Object value = params.get(key);
if ("sign".equals(key) || value == null || value.toString().isEmpty()) {
continue;
}
source.append("&").append(key).append("=").append(value);
}
return md5(source.toString());
}
private String md5(String input) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(input.getBytes(StandardCharsets.UTF_8));
StringBuilder hex = new StringBuilder();
for (byte b : digest) {
hex.append(String.format("%02x", b));
}
return hex.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private Map<String, Object> parseResponse(ResponseEntity<Map> response) {
if (!response.getStatusCode().is2xxSuccessful()) {
throw new RuntimeException("HTTP request failed: " + response.getStatusCode());
}
Map<String, Object> body = response.getBody();
if (body == null || !Objects.equals(body.get("code"), 200)) {
throw new RuntimeException("API request failed: " + body);
}
Object payload = body.get("payload");
return payload instanceof Map ? (Map<String, Object>) payload : new HashMap<>();
}
public static void main(String[] args) {
SkynetClient client = new SkynetClient(
"https://api.example.com",
10001,
"demo_key_123456"
);
Map<String, Object> collectOrder = client.createCollectOrder();
Map<String, Object> payoutOrder = client.createPayoutOrder();
Map<String, Object> merchantInfo = client.getMerchantInfo();
}
}