Commit a64988a8 authored by Menethil's avatar Menethil
Browse files

添加服务端物流信息查询,添加小程序物流查询

parent 5b4fc210
package org.linlinjava.litemall.core.express;
import org.linlinjava.litemall.core.express.config.ExpressConfig;
import org.linlinjava.litemall.core.util.TinymallRequestUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Map;
/**
* 快鸟物流查询服务
* <p>
* 3831775044640 韵达快递(YD)
*/
@Service
public class ExpressService {
//请求url
private String ReqURL = "http://api.kdniao.cc/Ebusiness/EbusinessOrderHandle.aspx";
@Autowired
ExpressConfig config;
/**
* 获取物流供应商名
*
* @param vendooCode
* @return
*/
public String getVendorName(String vendooCode) {
for (Map<String, String> item : config.getVendors()) {
if (item.get("code").equals(vendooCode))
return item.get("name");
}
return null;
}
/**
* Json方式 查询订单物流轨迹
*
* @throws Exception
*/
public String getOrderTracesByJson(String expCode, String expNo) throws Exception {
String requestData = "{'OrderCode':'','ShipperCode':'" + expCode + "','LogisticCode':'" + expNo + "'}";
Map<String, String> params = new HashMap<String, String>();
params.put("RequestData", urlEncoder(requestData, "UTF-8"));
params.put("EBusinessID", config.getAppId());
params.put("RequestType", "1002");
String dataSign = encrypt(requestData, config.getAppKey(), "UTF-8");
params.put("DataSign", urlEncoder(dataSign, "UTF-8"));
params.put("DataType", "2");
String result = TinymallRequestUtil.sendPost(ReqURL, params);
//根据公司业务处理返回的信息......
return result;
}
/**
* MD5加密
*
* @param str 内容
* @param charset 编码方式
* @throws Exception
*/
@SuppressWarnings("unused")
private String MD5(String str, String charset) throws Exception {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(str.getBytes(charset));
byte[] result = md.digest();
StringBuffer sb = new StringBuffer(32);
for (int i = 0; i < result.length; i++) {
int val = result[i] & 0xff;
if (val <= 0xf) {
sb.append("0");
}
sb.append(Integer.toHexString(val));
}
return sb.toString().toLowerCase();
}
/**
* base64编码
*
* @param str 内容
* @param charset 编码方式
* @throws UnsupportedEncodingException
*/
private String base64(String str, String charset) throws UnsupportedEncodingException {
String encoded = base64Encode(str.getBytes(charset));
return encoded;
}
@SuppressWarnings("unused")
private String urlEncoder(String str, String charset) throws UnsupportedEncodingException {
String result = URLEncoder.encode(str, charset);
return result;
}
/**
* 电商Sign签名生成
*
* @param content 内容
* @param keyValue Appkey
* @param charset 编码方式
* @return DataSign签名
* @throws UnsupportedEncodingException ,Exception
*/
@SuppressWarnings("unused")
private String encrypt(String content, String keyValue, String charset) throws UnsupportedEncodingException, Exception {
if (keyValue != null) {
return base64(MD5(content + keyValue, charset), charset);
}
return base64(MD5(content, charset), charset);
}
private static char[] base64EncodeChars = new char[]{
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '+', '/'};
private static String base64Encode(byte[] data) {
StringBuffer sb = new StringBuffer();
int len = data.length;
int i = 0;
int b1, b2, b3;
while (i < len) {
b1 = data[i++] & 0xff;
if (i == len) {
sb.append(base64EncodeChars[b1 >>> 2]);
sb.append(base64EncodeChars[(b1 & 0x3) << 4]);
sb.append("==");
break;
}
b2 = data[i++] & 0xff;
if (i == len) {
sb.append(base64EncodeChars[b1 >>> 2]);
sb.append(base64EncodeChars[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]);
sb.append(base64EncodeChars[(b2 & 0x0f) << 2]);
sb.append("=");
break;
}
b3 = data[i++] & 0xff;
sb.append(base64EncodeChars[b1 >>> 2]);
sb.append(base64EncodeChars[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]);
sb.append(base64EncodeChars[((b2 & 0x0f) << 2) | ((b3 & 0xc0) >>> 6)]);
sb.append(base64EncodeChars[b3 & 0x3f]);
}
return sb.toString();
}
}
package org.linlinjava.litemall.core.express.config;
import org.linlinjava.litemall.core.util.YmlPropertyFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Component
@Configuration
@PropertySource(value = {"classpath:application.yaml"}, factory = YmlPropertyFactory.class)
@ConfigurationProperties(prefix = "express")
public class ExpressConfig {
private String appId;
private String appKey;
private List<Map<String, String>> vendors = new ArrayList<>();
public List<Map<String, String>> getVendors() {
return vendors;
}
public void setVendors(List<Map<String, String>> vendors) {
this.vendors = vendors;
}
public String getAppKey() {
return appKey;
}
public void setAppKey(String appKey) {
this.appKey = appKey;
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
}
/**
* Copyright 2018 bejson.com
*/
package org.linlinjava.litemall.core.express.dao;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;
/**
* Auto-generated: 2018-07-19 22:27:22
*
* @author bejson.com (i@bejson.com)
* @website http://www.bejson.com/java2pojo/
*/
public class ExpressInfo {
@JsonProperty("LogisticCode")
private String LogisticCode;
@JsonProperty("ShipperCode")
private String ShipperCode;
@JsonProperty("Traces")
private List<Traces> Traces;
@JsonProperty("State")
private String State;
@JsonProperty("EBusinessID")
private String EBusinessID;
@JsonProperty("Success")
private boolean Success;
public void setLogisticCode(String LogisticCode) {
this.LogisticCode = LogisticCode;
}
public String getLogisticCode() {
return LogisticCode;
}
public void setShipperCode(String ShipperCode) {
this.ShipperCode = ShipperCode;
}
public String getShipperCode() {
return ShipperCode;
}
public void setTraces(List<Traces> Traces) {
this.Traces = Traces;
}
public List<Traces> getTraces() {
return Traces;
}
public void setState(String State) {
this.State = State;
}
public String getState() {
return State;
}
public void setEBusinessID(String EBusinessID) {
this.EBusinessID = EBusinessID;
}
public String getEBusinessID() {
return EBusinessID;
}
public void setSuccess(boolean Success) {
this.Success = Success;
}
public boolean getSuccess() {
return Success;
}
}
\ No newline at end of file
/**
* Copyright 2018 bejson.com
*/
package org.linlinjava.litemall.core.express.dao;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Auto-generated: 2018-07-19 22:27:22
*
* @author bejson.com (i@bejson.com)
* @website http://www.bejson.com/java2pojo/
*/
public class Traces {
@JsonProperty("AcceptStation")
private String AcceptStation;
@JsonProperty("AcceptTime")
private String AcceptTime;
public void setAcceptStation(String AcceptStation) {
this.AcceptStation = AcceptStation;
}
public String getAcceptStation() {
return AcceptStation;
}
public void setAcceptTime(String AcceptTime) {
this.AcceptTime = AcceptTime;
}
public String getAcceptTime() {
return AcceptTime;
}
}
\ No newline at end of file
package org.linlinjava.litemall.core.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
/**
* 向指定 URL 发送POST方法的请求
*
* @return 远程资源的响应结果
*/
public class TinymallRequestUtil {
/**
* 向指定 URL 发送POST方法的请求
*
* @param url 发送请求的 URL
* @param params 请求的参数集合
* @return 远程资源的响应结果
*/
@SuppressWarnings("unused")
public static String sendPost(String url, Map<String, String> params) {
OutputStreamWriter out = null;
BufferedReader in = null;
StringBuilder result = new StringBuilder();
try {
URL realUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
// POST方法
conn.setRequestMethod("POST");
// 设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.connect();
// 获取URLConnection对象对应的输出流
out = new OutputStreamWriter(conn.getOutputStream(), "UTF-8");
// 发送请求参数
if (params != null) {
StringBuilder param = new StringBuilder();
for (Map.Entry<String, String> entry : params.entrySet()) {
if (param.length() > 0) {
param.append("&");
}
param.append(entry.getKey());
param.append("=");
param.append(entry.getValue());
//System.out.println(entry.getKey()+":"+entry.getValue());
}
//System.out.println("param:"+param.toString());
out.write(param.toString());
}
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
in = new BufferedReader(
new InputStreamReader(conn.getInputStream(), "UTF-8"));
String line;
while ((line = in.readLine()) != null) {
result.append(line);
}
} catch (Exception e) {
e.printStackTrace();
}
//使用finally块来关闭输出流、输入流
finally {
try {
if (out != null) {
out.close();
}
if (in != null) {
in.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return result.toString();
}
}
package org.linlinjava.litemall.core.util;
import org.springframework.boot.env.PropertySourcesLoader;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertySourceFactory;
import java.io.IOException;
/**
* 某些情况下外部依赖导致 yaml 配置未能正确注入时,@PropertySource(value = {"classpath:application-wx.yaml"}, factory = YmlPropertyFactory.class) 手动注入配置文件
*/
public class YmlPropertyFactory implements PropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
return name != null ? new PropertySourcesLoader().load(resource.getResource(), name, null) : new PropertySourcesLoader().load(
resource.getResource(), getNameForResource(resource.getResource()), null);
}
private static String getNameForResource(Resource resource) {
String name = resource.getDescription();
if (!org.springframework.util.StringUtils.hasText(name)) {
name = resource.getClass().getSimpleName() + "@" + System.identityHashCode(resource);
}
return name;
}
}
......@@ -38,4 +38,36 @@ WXNotifyConfig:
NotifyPoolConfig:
corePoolSize: 5
maxPoolSize: 100
queueCapacity: 50
\ No newline at end of file
queueCapacity: 50
#快鸟物流查询配置
express:
appId: "XXXXXXXXX"
appKey: "XXXXXXXXXXXXXXXXXXXXXXXXX"
vendors:
- code: "ZTO"
name: "中通快递"
- code: "YTO"
name: "圆通速递"
- code: "YD"
name: "韵达速递"
- code: "YZPY"
name: "邮政快递包裹"
- code: "EMS"
name: "EMS"
- code: "DBL"
name: "德邦快递"
- code: "FAST"
name: "快捷快递"
- code: "ZJS"
name: "宅急送"
- code: "TNT"
name: "TNT快递"
- code: "UPS"
name: "UPS"
- code: "DHL"
name: "DHL"
- code: "FEDEX"
name: "FEDEX联邦(国内件)"
- code: "FEDEX_GJ"
name: "FEDEX联邦(国际件)"
\ No newline at end of file
package org.linlinjava.litemall.wx.web;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.linlinjava.litemall.core.express.ExpressService;
import org.linlinjava.litemall.core.express.dao.ExpressInfo;
import org.linlinjava.litemall.core.util.JacksonUtil;
import org.linlinjava.litemall.core.util.ResponseUtil;
import org.linlinjava.litemall.wx.annotation.LoginUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
/**
* 物流信息查询接口
*/
@RestController
@RequestMapping("/wx/express")
public class WxExpressController {
@Autowired
ExpressService expressService;
@PostMapping("query")
public Object query(@LoginUser Integer userId, @RequestBody String body) {
if (userId == null) {
return ResponseUtil.unlogin();
}
String expCode = JacksonUtil.parseString(body, "expCode");
String expNo = JacksonUtil.parseString(body, "expNo");
try {
String result = expressService.getOrderTracesByJson(expCode, expNo);
ObjectMapper objMap = new ObjectMapper();
ExpressInfo ei = objMap.readValue(result, ExpressInfo.class);
Map<String, Object> data = new HashMap<>();
data.put("expCode", ei.getLogisticCode());
data.put("expNo", ei.getShipperCode());
data.put("expName", expressService.getVendorName(expCode));
data.put("Traces", ei.getTraces());
return ResponseUtil.ok(data);
} catch (Exception e) {
e.printStackTrace();
}
return ResponseUtil.badArgument();
}
}
package org.linlinjava.litemall.wx;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.linlinjava.litemall.core.express.ExpressService;
import org.linlinjava.litemall.core.express.dao.ExpressInfo;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
@WebAppConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
public class ExpressTest {
@Test
public void test() {
ExpressService expressService = new ExpressService();
String result = null;
try {
result = expressService.getOrderTracesByJson("YTO", "800669400640887922");
ObjectMapper objMap = new ObjectMapper();
ExpressInfo ei = objMap.readValue(result, ExpressInfo.class);
ei.getTraces();
} catch (Exception e) {
e.printStackTrace();
}
System.out.print(result);
}
}
......@@ -69,7 +69,9 @@ module.exports = {
AddressSave: WxApiRoot + 'address/save', //保存收货地址
AddressDelete: WxApiRoot + 'address/delete', //保存收货地址
RegionList: WxApiRoot + 'region/list', //获取区域列表
ExpressQuery: WxApiRoot + 'express/query',//物流查询
RegionList: WxApiRoot + 'region/list', //获取区域列表
OrderSubmit: WxApiRoot + 'order/submit', // 提交订单
OrderPrepay: WxApiRoot + 'order/prepay', // 订单的预支付会话
......
......@@ -6,6 +6,8 @@ Page({
orderId: 0,
orderInfo: {},
orderGoods: [],
expressInfo: {},
flag: false,
handleOption: {}
},
onLoad: function (options) {
......@@ -15,6 +17,27 @@ Page({
});
this.getOrderDetail();
},
getOrderExpress: function() {
let that = this;
util.request(api.ExpressQuery, {
expCode: that.data.orderInfo.expCode,
expNo: that.data.orderInfo.expNo
}, 'POST').then(function(res) {
if (res.errno === 0) {
that.setData({
expressInfo: res.data
});
console.log(that.data.expressInfo);
}
});
},
expandDetail: function() {
let that = this;
this.setData({
flag: !that.data.flag
})
},
getOrderDetail: function () {
let that = this;
util.request(api.OrderDetail, {
......@@ -27,6 +50,11 @@ Page({
orderGoods: res.data.orderGoods,
handleOption: res.data.orderInfo.handleOption
});
// 请求物流信息,仅当订单状态为发货时才请求
if (that.data.handleOption.confirm) {
that.getOrderExpress();
}
}
});
},
......
......@@ -40,6 +40,27 @@
</view>
</view>
</view>
<!-- 物流信息,仅收货状态下可见 -->
<view class="order-express" bindtap="expandDetail" wx:if="{{ handleOption.confirm }}">
<view class="order-express">
<view class="title">
<view class="t">快递公司:{{expressInfo.expNo}}</view>
<view class="b">物流单号:{{expressInfo.expCode}}</view>
</view>
</view>
</view>
<!-- 展开 -->
<view class="data-expand p10 border-bottom" wx:if="{{ flag }}">
<view class="order-express">
<view class="traces" wx:for="{{expressInfo.Traces}}" wx:key="item" wx:for-item="iitem">
<view class="trace">
<view class="acceptTime">{{iitem.AcceptTime}}</view>
<view class="acceptStation">{{iitem.AcceptStation}}</view>
</view>
</view>
</view>
</view>
</view>
<view class="order-bottom">
......
......@@ -270,4 +270,65 @@ page{
display: inline-block;
width: 140rpx;
color: #b4282d;
}
\ No newline at end of file
}
.order-express {
margin-top: 20rpx;
padding-left: 31.25rpx;
height: auto;
}
.order-express .title {
width: 750rpx;
height: 108rpx;
background: #fff;
margin-bottom: 20rpx;
}
.order-express .title.t {
float: left;
width: 600rpx;
height: 108rpx;
line-height: 108rpx;
font-size: 29rpx;
margin-left: 31.25rpx;
}
.order-express .title.b {
float: left;
width: 600rpx;
height: 108rpx;
line-height: 108rpx;
font-size: 29rpx;
margin-left: 31.25rpx;
}
.order-express .traces {
height: auto;
padding-bottom: 17.5rpx;
padding-top: 17.5rpx;
border-bottom: 1px solid #f4f4f4;
}
.order-express .traces.trace {
height: 180rpx;
padding-bottom: 17.5rpx;
padding-top: 17.5rpx;
border-bottom: 1px solid #f4f4f4;
}
.order-express .traces.trace.acceptTime {
display: inline-block;
height: 35rpx;
width: 140rpx;
line-height: 35rpx;
font-size: 24rpx;
}
.order-express .traces.trace.acceptStation {
display: inline-block;
height: 35rpx;
line-height: 35rpx;
font-size: 24rpx;
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment