一、获得顺丰电子面单SDK
https://qiao.sf-express.com/index.html 丰桥系统中,文档中心->SDK使用说明->运单自助打印SDK
支持的开发环境: Java sdk 支持1.8及以上
二、启动SDK本地服务:
1.windows环境:
①将csim_waybill_print_service_V1.0.3.jar和RUN-SF-PRINTER.bat置于同一目录下,双击RUN-SF-PRINTER.bat文件即可开启本地运单打印服务。(这种情况也有可能开启不成功,建议使用下面命令的方式)
②java -jar path [port]
例:(不填写端口,则默认为4040)
2.linux环境:
①linux下安装jdk1.8,执行命令:yum -y install java
②创建文件夹sf-service将csim_waybill_print_service_V1.0.3.jar放在文件夹中
③执行命令:chmod 777 csim_waybill_print_service_V1.0.3.jar 进行授权
④linux下进入sf-service文件,执行命令:nohup java -jar csim_waybill_print_service_V1.0.3.jar &
(注:nohup <程序名> &:命令在Unix/Linux中,普通进程用“&”符号放到后台运行,则控制台logout后,进程仍然继续运行,起到守护进程的作用,使用nohup命令后,原程序的的标准输出被自动改向到当前目录下的nohup.out文件,起到了log的作用)。
3.验证服务器运行情况:
浏览器:http://localhost:4040/servertest.html(4040为启动端口),显示“OK!”则表示启动成功
4.Linux系统下需安装黑体字体!!!
①查看安装了哪些中文字体,命令:fc-list :lang=zh(如果命令不存在,则yum安装fontconfig,命令:yum -y install fontconfig)
②cd /usr/share/fonts(没有目录则创建,命令:mkdir /usr/share/fonts)
③将顺丰sdk里带的黑体字体放到该文件夹下
④chmod 755 *.ttf(linux命令chmod 755的含义)
⑤建立字体缓存
mkfontscal (如果命令不存在,则yum安装mkfontscale,命令:yum install mkfontscale)
mkfontdir (如果命令不存在,则yum安装mkfontscale,命令:yum install mkfontdir)
fc-cache -fv
⑥让字体生效
source /etc/profile
fc-match (查看设置是否生效)
三、项目中引用顺丰jar包
方法一:将sf-csim-printer-api-1.0.3.jar包放在项目lib目录下,并add as library(使用maven的不建议这样做)
方法二:将sf-csim-printer-api-1.0.3.jar包放到maven私服上,并在项目中引用依赖
<dependency>
<groupId>sf-csim</groupId>
<artifactId>printer-api</artifactId>
<version>1.0.3</version>
</dependency>
四、调用demo
1.使用210面单,使用SDK中生成图片url和调用打印机url
/**
* 调用打印机 弹出窗口 可选择份数 适用于单张打印【三联单】
*/
private static String printUrl =
"http://localhost:4040/sf/waybill/print?type=V3.0_poster_100mm210mm&output=print";
/**
* 直接输出图片的BASE64编码字符串 可以使用html标签直接转换成图片【三联单】
*/
private static String imageUrl =
"http://localhost:4040/sf/waybill/print?type=V3.0_poster_100mm210mm&output=image";
2.打印电子面单方法
(注:打印url方法无需接返回的byte[],自动会调起打印机)
@Override
public byte[] sfPrintWaybill(Map<String, Object> params, Integer printType) throws Exception {
logger.info("进入顺丰打印快递面单接口:params={},printType={}",
JSONObject.toJSONString(params),printType);
//1.根据业务需求确定请求地址
String reqURL = "";
if (printType == 1){
reqURL = imageUrl;
} else if (printType == 2){
reqURL = printUrl;
}
//2.电子面单顶部是否需要logo true:需要logo false:不需要logo
boolean topLogo = false;
if(reqURL.contains("V2.0")&&topLogo){
reqURL=reqURL.replace("V2.0", "V2.1");
}
if(reqURL.contains("V3.0")&&topLogo){
reqURL=reqURL.replace("V3.0", "V3.1");
}
//3.构建WaybillDtoList
List<WaybillDto> waybillDtoList = bulidWaybillDto(params);
HttpURLConnection httpConn = buildHttpConn(reqURL);
ObjectMapper objectMapper = new ObjectMapper();
StringWriter stringWriter = new StringWriter();
objectMapper.writeValue(stringWriter,waybillDtoList);
httpConn.getOutputStream().write(stringWriter.toString().getBytes());
httpConn.getOutputStream().flush();
httpConn.getOutputStream().close();
InputStream in = httpConn.getInputStream();
BufferedReader in2=new BufferedReader(new InputStreamReader(in));
String y="";
String strImg="";
while((y=in2.readLine())!=null){
strImg=y.substring(y.indexOf("[")+1,y.length()-"]".length()-1);
if(strImg.startsWith("\"")){
strImg=strImg.substring(1,strImg.length());
}
if(strImg.endsWith("\"")){
strImg=strImg.substring(0,strImg.length()-1);
}
}
//将换行全部替换成空
strImg=strImg.replace("\\n", "");
byte[] bytes = (new Base64()).decode(strImg);
return bytes;
}
3.构建WaybillDtoList
private List<WaybillDto> bulidWaybillDto(Map<String, Object> params) throws Exception{
List<WaybillDto> waybillDtoList = new ArrayList<>();
WaybillDto dto = new WaybillDto();
//对应clientCode
dto.setAppId(clientCode);
//对应checkWord
dto.setAppKey(checkword);
//快递单号
String mailNo = (String) params.get("mailNo");
dto.setMailNo(mailNo);
//收件人信息
String receiverProvince = (String) params.get("receiverProvince");
String receiverCity = (String) params.get("receiverCity");
String receiverCounty = (String) params.get("receiverCounty");
String receiverAddress = (String) params.get("receiverAddress");
String receiverMobile = (String) params.get("receiverMobile");
String receiverName = (String) params.get("receiverName");
dto.setConsignerProvince(receiverProvince);
dto.setConsignerCity(receiverCity);
dto.setConsignerCounty(receiverCounty);
dto.setConsignerAddress(receiverAddress); //详细地址建议最多38个字,字段过长可能影响打印效果
dto.setConsignerCompany(d_company);
dto.setConsignerMobile(receiverMobile);
dto.setConsignerName(receiverName);
//寄件人信息
dto.setDeliverProvince(j_province);
dto.setDeliverCity(j_city);
dto.setDeliverCounty(j_county);
dto.setDeliverCompany(j_company);
dto.setDeliverAddress(j_address);//详细地址建议最多38个字,字段过长可能影响打印效果
dto.setDeliverName(j_contact);
dto.setDeliverMobile(j_tel);
//原寄地代码(下订单接口顺丰会返回,需要保存)
String originCode = (String) params.get("originCode");
dto.setZipCode(originCode);
//目的地代码(下订单接口顺丰会返回,需要保存)
String destCode = (String) params.get("destCode");
dto.setDestCode(destCode);
//快递类型
//1 :标准快递 2.顺丰特惠 3: 电商特惠 5:顺丰次晨 6:顺丰即日 7.电商速配 15:生鲜速配
dto.setExpressType(1);
//陆运E标示
//业务类型为“电商特惠、顺丰特惠、电商专配、陆运件”则必须打印E标识,用以提示中转场分拣为陆运
dto.setElectric("E");
// 1-寄付 2-到付 3-第三方支付
dto.setPayMethod(1);
//加密项
//加密寄件人及收件人名称
dto.setEncryptCustName(true);
//加密寄件人及收件人联系手机
dto.setEncryptMobile(true);
//物品信息
String orderNo = (String) params.get("orderNo");
List<CargoInfoDto> cargoInfoList = new ArrayList<>();
List<OrderDetailOutputDto> orderDetailList =
(List<OrderDetailOutputDto>) params.get("orderDetailList");
for (OrderDetailOutputDto orderDetail : orderDetailList){
CargoInfoDto cargo = new CargoInfoDto();
cargo.setCargo(orderDetail.getCommodityName());
cargo.setCargoCount(orderDetail.getNum());
cargo.setCargoUnit("双");
cargo.setSku(orderDetail.getSkuNo());
cargo.setRemark(orderNo);
cargoInfoList.add(cargo);
}
dto.setCargoInfoDtoList(cargoInfoList);
waybillDtoList.add(dto);
logger.info("生成电子运单请求参数: "+ MyJsonUtil.object2json(dto));
return waybillDtoList;
4.构建Http连接
private HttpURLConnection buildHttpConn(String reqURL) throws Exception{
/**注意 需要使用对应业务场景的url **/
URL myURL = new URL(reqURL);
HttpURLConnection httpConn = (HttpURLConnection) myURL.openConnection();
httpConn.setDoOutput(true);
httpConn.setDoInput(true);
httpConn.setUseCaches(false);
httpConn.setRequestMethod("POST");
httpConn.setRequestProperty("Content-Type", "application/json;charset=utf-8");
httpConn.setConnectTimeout(10000);
httpConn.setReadTimeout(2 * 5000);
return httpConn;
}
五、controller层调用及前端
//预览打印快递单
byte[] imageByte = orderBackgroundApi.printWaybill(order,orderDeatilList,
orderAddressList.get(0),orderConsignList.get(0),printType);
return JSONObject.toJSONString(imageByte);
controller层调用api,并返回byte数组给前端,前端页面中使用<img>标签,并使用src="https://img-blog.csdnimg.cn/2022010708272582793.png"方式来展示二进制图片(需要对二进制数组进行base64编码,顺丰接口返回给我们的已经是经过base64编码的字符串)
function printWaybill(orderId,orderNo) {
layer.load(2);
$.ajax({
url:"/order/printWaybill.sc",
type:"post",
data:{orderId:orderId,orderNo:orderNo,printType:1},
dataType:"json",
success:function (data) {
layer.closeAll();
layer.open({
type:1,
title: '预览',
closeBtn:1,
area:['850px','600px'],
content:'<img src="https://img-blog.csdnimg.cn/2022010708272582793.png'+data+'" style="width:850px;"/>',
btn: ['打印'],
yes:function (index, layero) {
$.ajax({
url: "/order/printWaybill.sc",
type: "post",
data: {orderId: orderId, orderNo: orderNo, printType:2},
dataType: "json",
success:function (data) {
mmGrid.load();
}
});
}
});
}
})
}