feat: 订单

pull/1121/head
梁宇奇 2025-04-16 16:05:16 +08:00
parent c81c175925
commit dd42483eae
16 changed files with 637 additions and 50 deletions

View File

@ -6,7 +6,7 @@ import com.ruoyi.common.core.domain.R;
import com.ruoyi.web.controller.xkt.vo.express.ExpressRegionTreeNodeVO;
import com.ruoyi.xkt.dto.express.ExpressRegionTreeNodeDTO;
import com.ruoyi.xkt.manager.ExpressManager;
import com.ruoyi.xkt.manager.impl.ZtExpressManagerImpl;
import com.ruoyi.xkt.manager.impl.ZtoExpressManagerImpl;
import com.ruoyi.xkt.service.IExpressService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@ -32,7 +32,7 @@ public class ExpressController extends XktBaseController {
@Autowired
private List<ExpressManager> expressManagers;
@Autowired
private ZtExpressManagerImpl ztExpressManager;
private ZtoExpressManagerImpl ztoExpressManager;
@PreAuthorize("@ss.hasPermi('system:express:query')")
@ApiOperation("获取行政规划树")

View File

@ -171,10 +171,12 @@ express:
county: 510114
# 中通配置
zt:
zto:
appKey: 95dc4ecf72fce1a2fbe79
appSecret: 694ea7e3ea89e3b6aa21aea1a0285d25
gatewayUrl: https://japi-test.zto.com/
accountId: test
accountPassword: ZTO123
# 支付宝配置
alipay:

View File

@ -0,0 +1,74 @@
package com.ruoyi.xkt.dto.express;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author liangyq
* @date 2025-04-16 15:24
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ExpressShipReqDTO {
/**
*
*/
private String expressReqNo;
/**
* -
*/
private String originContactName;
/**
* -
*/
private String originContactPhoneNumber;
/**
* -
*/
private String originProvinceCode;
private String originProvinceName;
/**
* -
*/
private String originCityCode;
private String originCityName;
/**
* -
*/
private String originCountyCode;
private String originCountyName;
/**
* -
*/
private String originDetailAddress;
/**
* -
*/
private String destinationContactName;
/**
* -
*/
private String destinationContactPhoneNumber;
/**
* -
*/
private String destinationProvinceCode;
private String destinationProvinceName;
/**
* -
*/
private String destinationCityCode;
private String destinationCityName;
/**
* -
*/
private String destinationCountyCode;
private String destinationCountyName;
/**
* -
*/
private String destinationDetailAddress;
}

View File

@ -11,7 +11,7 @@ import lombok.Getter;
@AllArgsConstructor
public enum EExpressChannel {
ZT(1, "中通", 1L, "ZT");
ZTO(1, "中通", 1L, "ZTO");
private final Integer value;
private final String label;

View File

@ -1,5 +1,6 @@
package com.ruoyi.xkt.manager;
import com.ruoyi.xkt.dto.express.ExpressShipReqDTO;
import com.ruoyi.xkt.enums.EExpressChannel;
/**
@ -14,4 +15,12 @@ public interface ExpressManager {
*/
EExpressChannel channel();
/**
*
*
* @param shipReqDTO
* @return
*/
String shipStoreOrder(ExpressShipReqDTO shipReqDTO);
}

View File

@ -1,34 +0,0 @@
package com.ruoyi.xkt.manager.impl;
import com.ruoyi.xkt.enums.EExpressChannel;
import com.ruoyi.xkt.manager.ExpressManager;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* @author liangyq
* @date 2025-04-15 15:45
*/
@Slf4j
@Component
public class ZtExpressManagerImpl implements ExpressManager {
private static final String CREATE_ORDER_URI = "zto.open.createOrder";
private static final String STRUCTURE_ADDRESS_URI = "zto.innovate.structureNamePhoneAddress";
@Value("${zt.appKey:}")
private String appKey;
@Value("${zt.appSecret:}")
private String appSecret;
@Value("${zt.gatewayUrl:}")
private String gatewayUrl;
@Override
public EExpressChannel channel() {
return EExpressChannel.ZT;
}
}

View File

@ -0,0 +1,120 @@
package com.ruoyi.xkt.manager.impl;
import cn.hutool.core.lang.Assert;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.xkt.dto.express.ExpressShipReqDTO;
import com.ruoyi.xkt.enums.EExpressChannel;
import com.ruoyi.xkt.manager.ExpressManager;
import com.ruoyi.xkt.thirdpart.zto.EncryptionType;
import com.ruoyi.xkt.thirdpart.zto.ZopClient;
import com.ruoyi.xkt.thirdpart.zto.ZopPublicRequest;
import com.ruoyi.xkt.thirdpart.zto.ZtoCreateOrderReqDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* @author liangyq
* @date 2025-04-15 15:45
*/
@Slf4j
@Component
public class ZtoExpressManagerImpl implements ExpressManager {
private static final String CREATE_ORDER_URI = "zto.open.createOrder";
private static final String STRUCTURE_ADDRESS_URI = "zto.innovate.structureNamePhoneAddress";
@Value("${zto.appKey:}")
private String appKey;
@Value("${zto.appSecret:}")
private String appSecret;
@Value("${zto.gatewayUrl:}")
private String gatewayUrl;
@Value("${zto.accountId:}")
private String accountId;
@Value("${zto.accountPassword:}")
private String accountPassword;
@Override
public EExpressChannel channel() {
return EExpressChannel.ZTO;
}
@Override
public String shipStoreOrder(ExpressShipReqDTO shipReqDTO) {
Assert.notNull(shipReqDTO);
Assert.notEmpty(shipReqDTO.getExpressReqNo());
ZtoCreateOrderReqDTO createOrderReq = trans2CreateOrderReq(shipReqDTO);
ZopClient client = new ZopClient(appKey, appSecret);
ZopPublicRequest request = new ZopPublicRequest();
request.setBody(JSONUtil.toJsonStr(createOrderReq));
request.setUrl(gatewayUrl + CREATE_ORDER_URI);
request.setEncryptionType(EncryptionType.MD5);
try {
String bodyStr = client.execute(request);
log.info("中通订单创建返回信息: {}", bodyStr);
JSONObject bodyJson = JSONUtil.parseObj(bodyStr);
boolean success = bodyJson.getBool("status");
if (success) {
return bodyJson.getJSONObject("result").getStr("billCode");
}
} catch (Exception e) {
log.error("中通订单创建异常", e);
}
throw new ServiceException("中通订单创建失败");
}
private ZtoCreateOrderReqDTO trans2CreateOrderReq(ExpressShipReqDTO expressShipReqDTO) {
ZtoCreateOrderReqDTO reqDTO = new ZtoCreateOrderReqDTO();
//合作模式 1集团客户2非集团客户
reqDTO.setPartnerType("2");
//partnerType为1时orderType1全网件 2预约件。 partnerType为2时orderType1全网件 2预约件返回运单号 3预约件不返回运单号 4星联全网件
reqDTO.setOrderType("1");
//合作商订单号
reqDTO.setPartnerOrderCode(expressShipReqDTO.getExpressReqNo());
//账号信息
ZtoCreateOrderReqDTO.AccountInfo accountInfo = new ZtoCreateOrderReqDTO.AccountInfo();
reqDTO.setAccountInfo(accountInfo);
//电子面单账号partnerType为2orderType传1,2,4时必传
accountInfo.setAccountId(accountId);
//电子面单密码测试环境传ZTO123
accountInfo.setAccountPassword(accountPassword);
//单号类型:1.普通电子面单74.星联电子面单默认是1
accountInfo.setType(1);
//集团客户编码partnerType传1时必传
accountInfo.setCustomerId(null);
//发件人信息
ZtoCreateOrderReqDTO.SenderInfo senderInfo = new ZtoCreateOrderReqDTO.SenderInfo();
reqDTO.setSenderInfo(senderInfo);
senderInfo.setSenderName(expressShipReqDTO.getOriginCountyName());
senderInfo.setSenderPhone(expressShipReqDTO.getOriginContactPhoneNumber());
senderInfo.setSenderProvince(expressShipReqDTO.getOriginProvinceName());
senderInfo.setSenderCity(expressShipReqDTO.getOriginCityName());
senderInfo.setSenderDistrict(expressShipReqDTO.getOriginCountyName());
senderInfo.setSenderAddress(expressShipReqDTO.getOriginDetailAddress());
//收件人信息
ZtoCreateOrderReqDTO.ReceiveInfo receiveInfo = new ZtoCreateOrderReqDTO.ReceiveInfo();
reqDTO.setReceiveInfo(receiveInfo);
receiveInfo.setReceiverName(expressShipReqDTO.getDestinationContactName());
receiveInfo.setReceiverPhone(expressShipReqDTO.getDestinationContactPhoneNumber());
receiveInfo.setReceiverProvince(expressShipReqDTO.getDestinationProvinceName());
receiveInfo.setReceiverCity(expressShipReqDTO.getDestinationCityName());
receiveInfo.setReceiverDistrict(expressShipReqDTO.getDestinationCountyName());
receiveInfo.setReceiverAddress(expressShipReqDTO.getDestinationDetailAddress());
return reqDTO;
}
}

View File

@ -93,8 +93,8 @@ public interface IStoreOrderService {
* @param operatorId
* @return
*/
StoreOrderExt prepareShipOrderByPlatform(Long storeOrderId, List<Long> storeOrderDetailIds, Long expressId,
Long operatorId);
StoreOrderExt shipOrderByPlatform(Long storeOrderId, List<Long> storeOrderDetailIds, Long expressId,
Long operatorId);
/**
*

View File

@ -17,6 +17,7 @@ import com.ruoyi.common.utils.bean.BeanValidators;
import com.ruoyi.xkt.domain.*;
import com.ruoyi.xkt.dto.express.ExpressContactDTO;
import com.ruoyi.xkt.dto.express.ExpressRegionDTO;
import com.ruoyi.xkt.dto.express.ExpressShipReqDTO;
import com.ruoyi.xkt.dto.order.*;
import com.ruoyi.xkt.dto.storeProductFile.StoreProdMainPicDTO;
import com.ruoyi.xkt.enums.*;
@ -564,10 +565,10 @@ public class StoreOrderServiceImpl implements IStoreOrderService {
@Transactional(rollbackFor = Exception.class)
@Override
public StoreOrderExt prepareShipOrderByPlatform(Long storeOrderId, List<Long> storeOrderDetailIds, Long expressId,
Long operatorId) {
public StoreOrderExt shipOrderByPlatform(Long storeOrderId, List<Long> storeOrderDetailIds, Long expressId,
Long operatorId) {
Assert.notEmpty(storeOrderDetailIds);
// ExpressManager expressManager = getExpressManager(expressId);
ExpressManager expressManager = getExpressManager(expressId);
Express express = expressService.getById(expressId);
if (!BeanValidators.exists(express) || !express.getSystemDeliverAccess()) {
throw new ServiceException("快递[" + expressId + "]不可用");
@ -600,10 +601,8 @@ public class StoreOrderServiceImpl implements IStoreOrderService {
if (orderSuccess == 0) {
throw new ServiceException(Constants.VERSION_LOCK_ERROR_COMMON_MSG);
}
//生成请求号
String expressReqNo = IdUtil.simpleUUID();
List<Long> orderDetailIdList = new ArrayList<>(orderDetails.size());
for (StoreOrderDetail orderDetail : orderDetails) {
//校验明细状态
if (!BeanValidators.exists(orderDetail)) {
throw new ServiceException("订单明细[" + orderDetail.getId() + "]不存在");
}
@ -613,12 +612,20 @@ public class StoreOrderServiceImpl implements IStoreOrderService {
if (!EOrderStatus.PENDING_SHIPMENT.getValue().equals(orderDetail.getDetailStatus())) {
throw new ServiceException("订单明细[" + order.getId() + "]当前状态无法发货");
}
}
//发货
ExpressShipReqDTO shipReq = trans2ShipReq(order, orderDetails);
String expressWaybillNo = expressManager.shipStoreOrder(shipReq);
List<Long> orderDetailIdList = new ArrayList<>(orderDetails.size());
for (StoreOrderDetail orderDetail : orderDetails) {
//明细->已发货
orderDetail.setDetailStatus(EOrderStatus.SHIPPED.getValue());
orderDetail.setExpressId(expressId);
orderDetail.setExpressType(EExpressType.PLATFORM.getValue());
orderDetail.setExpressStatus(EExpressStatus.PLACING.getValue());
orderDetail.setExpressReqNo(expressReqNo);
orderDetail.setExpressStatus(EExpressStatus.PLACED.getValue());
orderDetail.setExpressReqNo(shipReq.getExpressReqNo());
orderDetail.setExpressWaybillNo(expressWaybillNo);
int orderDetailSuccess = storeOrderDetailMapper.updateById(orderDetail);
if (orderDetailSuccess == 0) {
throw new ServiceException(Constants.VERSION_LOCK_ERROR_COMMON_MSG);
@ -897,6 +904,27 @@ public class StoreOrderServiceImpl implements IStoreOrderService {
throw new ServiceException("未知物流渠道");
}
private ExpressShipReqDTO trans2ShipReq(StoreOrder order, List<StoreOrderDetail> orderDetails) {
ExpressShipReqDTO reqDTO = BeanUtil.toBean(order, ExpressShipReqDTO.class);
//生成请求号
reqDTO.setExpressReqNo(IdUtil.simpleUUID());
//行政区划信息
Map<String, ExpressRegionDTO> regionMap = expressService.getRegionMapCache();
reqDTO.setDestinationProvinceName(Optional.ofNullable(regionMap.get(order.getDestinationProvinceCode()))
.map(ExpressRegionDTO::getParentRegionName).orElse(null));
reqDTO.setDestinationCityName(Optional.ofNullable(regionMap.get(order.getDestinationCityCode()))
.map(ExpressRegionDTO::getParentRegionName).orElse(null));
reqDTO.setDestinationCountyName(Optional.ofNullable(regionMap.get(order.getDestinationCountyCode()))
.map(ExpressRegionDTO::getParentRegionName).orElse(null));
reqDTO.setOriginProvinceName(Optional.ofNullable(regionMap.get(order.getOriginProvinceCode()))
.map(ExpressRegionDTO::getParentRegionName).orElse(null));
reqDTO.setOriginCityName(Optional.ofNullable(regionMap.get(order.getOriginCityCode()))
.map(ExpressRegionDTO::getParentRegionName).orElse(null));
reqDTO.setOriginCountyName(Optional.ofNullable(regionMap.get(order.getOriginCountyCode()))
.map(ExpressRegionDTO::getParentRegionName).orElse(null));
return reqDTO;
}
@Data
@AllArgsConstructor
@NoArgsConstructor

View File

@ -0,0 +1,12 @@
package com.ruoyi.xkt.thirdpart.zto;
/**
* Created By WangWei on 2022/1/18 9:27
*/
public enum EncryptionType {
MD5,
SHA256,
HmacSHA256
}

View File

@ -0,0 +1,61 @@
package com.ruoyi.xkt.thirdpart.zto;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
public class ZopClient {
private final ZopProperties properties;
public ZopClient(ZopProperties properties) {
this.properties = properties;
}
public ZopClient(String appKey, String appSecret) {
this.properties = new ZopProperties(appKey, appSecret);
}
public String execute(ZopPublicRequest request) throws IOException {
String jsonBody = request.getBody();
if (jsonBody == null) {
Map<String, String> params = request.getParams();
StringBuilder queryBuilder = new StringBuilder();
StringBuilder strToDigestBuilder = new StringBuilder();
for (Map.Entry<String, String> e : params.entrySet()) {
strToDigestBuilder.append(e.getKey()).append("=").append(e.getValue()).append("&");
queryBuilder.append(urlEncode(e.getKey())).append("=").append(urlEncode(e.getValue())).append("&");
}
String queryString = queryBuilder.substring(0, queryBuilder.length() - 1);
String strToDigest = strToDigestBuilder.substring(0, strToDigestBuilder.length() - 1);
strToDigest = strToDigest + properties.getKey();
Map<String, String> headers = new HashMap<String, String>();
headers.put("x-companyid", properties.getCompanyId());
headers.put("x-datadigest", ZopDigestUtil.digest(strToDigest, request.getBase64(), request.getEncryptionType(), request.getTimestamp(), request.getSecretKey()));
if (request.getTimestamp() != null) {
headers.put("x-timestamp", String.valueOf(request.getTimestamp()));
}
return ZtoHttpUtil.post(request.getUrl(), headers, queryString);
} else {
Map<String, String> headers = new HashMap<>();
String strToDigest = jsonBody + properties.getKey();
headers.put("x-companyid", properties.getCompanyId());
headers.put("x-datadigest", ZopDigestUtil.digest(strToDigest, request.getBase64(), request.getEncryptionType(), request.getTimestamp(), request.getSecretKey()));
if (request.getTimestamp() != null) {
headers.put("x-timestamp", String.valueOf(request.getTimestamp()));
}
return ZtoHttpUtil.postJson(request.getUrl(), headers, jsonBody);
}
}
private String urlEncode(String str) {
try {
return URLEncoder.encode(str, "UTF-8");
} catch (UnsupportedEncodingException e) {
return str;
}
}
}

View File

@ -0,0 +1,60 @@
package com.ruoyi.xkt.thirdpart.zto;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
public class ZopDigestUtil {
private static final String HMAC_SHA_256 = "HmacSHA256";
private static final Map<String, Mac> MAC_MAP = new ConcurrentHashMap<>();
public static String digest(String str, Boolean isBase64, EncryptionType encryptionType, Long timestamp, String secretKey) {
if (timestamp != null) {
str = timestamp + str;
}
boolean base64 = isBase64 == null || isBase64;
switch (encryptionType) {
case SHA256:
return base64 ? Base64.encodeBase64String(DigestUtils.sha256(str)) : DigestUtils.sha256Hex(str);
case HmacSHA256:
return base64 ? Base64.encodeBase64String(hmacSha256(secretKey, str)) : hmacSha256Str(secretKey, str);
default:
return base64 ? Base64.encodeBase64String(DigestUtils.md5(str)) : DigestUtils.md5Hex(str);
}
}
public static String hmacSha256Str(String key, String body) {
return Hex.encodeHexString(hmacSha256(key, body));
}
public static byte[] hmacSha256(String key, String body) {
if (Objects.isNull(key)) {
key = "";
}
Mac mac = MAC_MAP.get(key);
if (mac == null) {
try {
mac = Mac.getInstance(HMAC_SHA_256);
SecretKey secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), HMAC_SHA_256);
mac.init(secretKey);
MAC_MAP.put(key, mac);
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
throw new RuntimeException(e);
}
}
return mac.doFinal(body.getBytes(StandardCharsets.UTF_8));
}
}

View File

@ -0,0 +1,30 @@
package com.ruoyi.xkt.thirdpart.zto;
public class ZopProperties {
private String companyId;
private String key;
public ZopProperties() {
}
public ZopProperties(String appKey, String appSecret) {
this.companyId = appKey;
this.key = appSecret;
}
public String getCompanyId() {
return companyId;
}
public void setCompanyId(String companyId) {
this.companyId = companyId;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
}

View File

@ -0,0 +1,122 @@
package com.ruoyi.xkt.thirdpart.zto;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import java.util.HashMap;
import java.util.Map;
public class ZopPublicRequest {
private String url;
private Map<String, String> params = new HashMap<String, String>();
// 如果body有值表示使用application/json的方式传值
private String body;
/**
* base64
*/
private Boolean isBase64;
/**
* MD5SHA256
*/
private EncryptionType encryptionType;
/**
* HmacSHA256key
*/
private String secretKey;
/**
* 使
*/
private Long timestamp;
public ZopPublicRequest() {
}
public void setBody(String body){
this.body = body;
}
public String getBody() {
return body;
}
public void addParam(String k, String v) {
params.put(k, v);
}
public void setData(String data) {
try {
JSONObject jsonObject = JSON.parseObject(data);
for (Map.Entry<String, Object> entry : jsonObject.entrySet()) {
params.put(entry.getKey(), entry.getValue().toString());
}
} catch (Exception e) {
throw new RuntimeException("JSON格式不对,请检查数据", e);
}
}
public void setDataObj(Map<String, String> data) {
params.putAll(data);
}
public void addParam(Map<String, String> p) {
for (Map.Entry<String, String> entry : p.entrySet()) {
params.put(entry.getKey(), entry.getValue());
}
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Map<String, String> getParams() {
return params;
}
public void setParams(Map<String, String> params) {
this.params = params;
}
public Boolean getBase64() {
return isBase64;
}
public void setBase64(Boolean base64) {
isBase64 = base64;
}
public EncryptionType getEncryptionType() {
return encryptionType;
}
public void setEncryptionType(EncryptionType encryptionType) {
this.encryptionType = encryptionType;
}
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
public Long getTimestamp() {
return timestamp;
}
public void setTimestamp(Long timestamp) {
this.timestamp = timestamp;
}
}

View File

@ -1,4 +1,4 @@
package com.ruoyi.xkt.dto.express.zt;
package com.ruoyi.xkt.thirdpart.zto;
import lombok.Data;
@ -11,7 +11,7 @@ import java.util.List;
* @date 2025-04-15 19:20
*/
@Data
public class CreateOrderReqDTO {
public class ZtoCreateOrderReqDTO {
/**
* 12
*/

View File

@ -0,0 +1,103 @@
package com.ruoyi.xkt.thirdpart.zto;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Map;
public class ZtoHttpUtil {
private static final int DEFAULT_TIMEOUT = 3000;
public static String post(String interfaceUrl, Map<String, String> headers, String queryString) throws IOException {
URL url = new URL(interfaceUrl);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
con.setDoOutput(true);
con.setConnectTimeout(DEFAULT_TIMEOUT);
con.setReadTimeout(DEFAULT_TIMEOUT);
for (Map.Entry<String, String> e : headers.entrySet()) {
con.setRequestProperty(e.getKey(), e.getValue());
}
DataOutputStream out = null;
BufferedReader in = null;
try {
out = new DataOutputStream(con.getOutputStream());
out.write(queryString.getBytes(Charset.forName("UTF-8")));
out.flush();
in = new BufferedReader(
new InputStreamReader(con.getInputStream(), "UTF-8"));
String inputLine;
StringBuilder content = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
content.append(inputLine);
}
return content.toString();
} finally {
if (out != null) {
try {
out.close();
} catch (Exception ignored) {
}
}
if (in != null) {
try {
in.close();
} catch (Exception ignored) {
}
}
}
}
public static String postJson(String interfaceUrl, Map<String, String> headers, String json) throws IOException {
URL url = new URL(interfaceUrl);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type", "application/json; charset=utf-8");
con.setDoOutput(true);
con.setConnectTimeout(DEFAULT_TIMEOUT);
con.setReadTimeout(DEFAULT_TIMEOUT);
for (Map.Entry<String, String> e : headers.entrySet()) {
con.setRequestProperty(e.getKey(), e.getValue());
}
DataOutputStream out = null;
BufferedReader in = null;
try {
out = new DataOutputStream(con.getOutputStream());
out.write(json.getBytes(Charset.forName("UTF-8")));
out.flush();
in = new BufferedReader(
new InputStreamReader(con.getInputStream(), "UTF-8"));
String inputLine;
StringBuilder content = new StringBuilder();
while ((inputLine = in.readLine()) != null) {
content.append(inputLine);
}
return content.toString();
} finally {
if (out != null) {
try {
out.close();
} catch (Exception ignored) {
}
}
if (in != null) {
try {
in.close();
} catch (Exception ignored) {
}
}
}
}
}