新增功能

This commit is contained in:
2026-02-10 14:56:16 +08:00
parent 743bbc9e34
commit fb0cbea2dc
63 changed files with 5831 additions and 0 deletions

View File

@ -0,0 +1,135 @@
package com.fuint.utils;
import com.sun.org.apache.xerces.internal.impl.dv.util.HexBin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
/**
* AES对称加/解密工具类
*
* Created by FSQ
* CopyRight https://www.fuint.cn
*/
public class AESUtil {
private static final Logger logger = LoggerFactory.getLogger(AESUtil.class);
//密钥生成算法
private static String KEY_AES = "AES";
//密钥长度
private static int KEY_LENGTH = 128;
//默认字符集
private static final String CHARSET = "UTF-8";
/**
* AES加密
*
* @param data 待加密的内容
* @param password 加密密码
* @return byte[]
*/
public static String encrypt(byte[] data, String password) {
try {
SecretKeySpec key = getKey(password);
Cipher cipher = Cipher.getInstance(KEY_AES);// 创建密码器
cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
return HexBin.encode(cipher.doFinal(data));
} catch (NoSuchAlgorithmException e) {
logger.error(e.getMessage(), e);
} catch (IllegalBlockSizeException e) {
logger.error(e.getMessage(), e);
} catch (InvalidKeyException e) {
logger.error(e.getMessage(), e);
} catch (BadPaddingException e) {
logger.error(e.getMessage(), e);
} catch (NoSuchPaddingException e) {
logger.error(e.getMessage(), e);
}
return null;
}
/**
* AES加密
*
* @param data 待加密的内容
* @param password 加密密码
* @return String
*/
public static String encrypt(String data, String password) {
try {
return encrypt(data.getBytes(CHARSET), password);
} catch (UnsupportedEncodingException e) {
logger.error(e.getMessage(), e);
}
return null;
}
/**
* AES解密
*
* @param data 待解密内容
* @param password 解密密钥
* @return byte[]
*/
public static byte[] decrypt(byte[] data, String password) {
try {
SecretKeySpec key = getKey(password);
Cipher cipher = Cipher.getInstance(KEY_AES);// 创建密码器
cipher.init(Cipher.DECRYPT_MODE, key);// 初始化
return cipher.doFinal(HexBin.decode(new String(data, CHARSET)));
} catch (NoSuchAlgorithmException e) {
logger.error(e.getMessage(), e);
} catch (IllegalBlockSizeException e) {
logger.error(e.getMessage(), e);
} catch (InvalidKeyException e) {
logger.error(e.getMessage(), e);
} catch (BadPaddingException e) {
logger.error(e.getMessage(), e);
} catch (NoSuchPaddingException e) {
logger.error(e.getMessage(), e);
} catch (UnsupportedEncodingException e) {
logger.error(e.getMessage(), e);
}
return null;
}
/**
* AES解密
*
* @param data 待解密内容
* @param password 解密密钥
* @return String
*/
public static String decrypt(String data, String password) {
try {
byte[] bytes = decrypt(data.getBytes(CHARSET), password);
return new String(bytes, CHARSET);
} catch (UnsupportedEncodingException e) {
logger.error(e.getMessage(), e);
}
return null;
}
/**
* 通过密码计算key
*
* @param password 对称密码
* @return SecretKeySpec 计算的128位随机key
* @throws NoSuchAlgorithmException
*/
private static SecretKeySpec getKey(String password) throws NoSuchAlgorithmException {
KeyGenerator kgen = KeyGenerator.getInstance(KEY_AES);
kgen.init(KEY_LENGTH, new SecureRandom(password.getBytes()));
SecretKey secretKey = kgen.generateKey();
byte[] enCodeFormat = secretKey.getEncoded();
return new SecretKeySpec(enCodeFormat, KEY_AES);
}
}

View File

@ -0,0 +1,205 @@
package net.xpyun.platform.opensdk.service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import net.xpyun.platform.opensdk.util.HttpClientUtil;
import net.xpyun.platform.opensdk.vo.*;
import java.util.List;
/**
* 云打印相关接口封装类
* @author JavaLyl
*/
public class PrintService {
private static String BASE_URL = "https://open.xpyun.net/api/openapi";
/**
* 1.批量添加打印机
* @param restRequest
* @return
*/
public ObjectRestResponse<PrinterResult> addPrinters(AddPrinterRequest restRequest) {
String url = BASE_URL + "/xprinter/addPrinters";
String jsonRequest = JSON.toJSONString(restRequest);
String resp = HttpClientUtil.doPostJSON(url, jsonRequest);
ObjectRestResponse<PrinterResult> result = JSON.parseObject(resp, new TypeReference<ObjectRestResponse<PrinterResult>>(){});
return result;
}
/**
* 2.设置打印机语音类型
* @param restRequest
* @return
*/
public ObjectRestResponse<Boolean> setPrinterVoiceType(SetVoiceTypeRequest restRequest) {
String url = BASE_URL + "/xprinter/setVoiceType";
String jsonRequest = JSON.toJSONString(restRequest);
String resp = HttpClientUtil.doPostJSON(url, jsonRequest);
ObjectRestResponse<Boolean> result = JSON.parseObject(resp, new TypeReference<ObjectRestResponse<Boolean>>(){});
return result;
}
/**
* 3.打印小票订单
* @param restRequest
* @return
*/
public ObjectRestResponse<String> print(PrintRequest restRequest) {
String url = BASE_URL + "/xprinter/print";
String jsonRequest = JSON.toJSONString(restRequest);
String resp = HttpClientUtil.doPostJSON(url, jsonRequest);
ObjectRestResponse<String> result = JSON.parseObject(resp, new TypeReference<ObjectRestResponse<String>>(){});
return result;
}
/**
* 4.打印标签订单
* @param restRequest
* @return
*/
public ObjectRestResponse<String> printLabel(PrintRequest restRequest) {
String url = BASE_URL + "/xprinter/printLabel";
String jsonRequest = JSON.toJSONString(restRequest);
String resp = HttpClientUtil.doPostJSON(url, jsonRequest);
ObjectRestResponse<String> result = JSON.parseObject(resp, new TypeReference<ObjectRestResponse<String>>(){});
return result;
}
/**
* 5.批量删除打印机
* @param restRequest
* @return
*/
public ObjectRestResponse<PrinterResult> delPrinters(DelPrinterRequest restRequest) {
String url = BASE_URL + "/xprinter/delPrinters";
String jsonRequest = JSON.toJSONString(restRequest);
String resp = HttpClientUtil.doPostJSON(url, jsonRequest);
ObjectRestResponse<PrinterResult> result = JSON.parseObject(resp, new TypeReference<ObjectRestResponse<PrinterResult>>(){});
return result;
}
/**
* 6.修改打印机信息
* @param restRequest
* @return
*/
public ObjectRestResponse<Boolean> updPrinter(UpdPrinterRequest restRequest) {
String url = BASE_URL + "/xprinter/updPrinter";
String jsonRequest = JSON.toJSONString(restRequest);
String resp = HttpClientUtil.doPostJSON(url, jsonRequest);
ObjectRestResponse<Boolean> result = JSON.parseObject(resp, new TypeReference<ObjectRestResponse<Boolean>>(){});
return result;
}
/**
* 7.清空待打印队列
* @param restRequest
* @return
*/
public ObjectRestResponse<Boolean> delPrinterQueue(PrinterRequest restRequest) {
String url = BASE_URL + "/xprinter/delPrinterQueue";
String jsonRequest = JSON.toJSONString(restRequest);
String resp = HttpClientUtil.doPostJSON(url, jsonRequest);
ObjectRestResponse<Boolean> result = JSON.parseObject(resp, new TypeReference<ObjectRestResponse<Boolean>>(){});
return result;
}
/**
* 8.查询订单是否打印成功
* @param restRequest
* @return
*/
public ObjectRestResponse<Boolean> queryOrderState(QueryOrderStateRequest restRequest) {
String url = BASE_URL + "/xprinter/queryOrderState";
String jsonRequest = JSON.toJSONString(restRequest);
String resp = HttpClientUtil.doPostJSON(url, jsonRequest);
ObjectRestResponse<Boolean> result = JSON.parseObject(resp, new TypeReference<ObjectRestResponse<Boolean>>(){});
return result;
}
/**
* 9.查询打印机某天的订单统计数
* @param restRequest
* @return
*/
public ObjectRestResponse<OrderStatisResult> queryOrderStatis(QueryOrderStatisRequest restRequest) {
String url = BASE_URL + "/xprinter/queryOrderStatis";
String jsonRequest = JSON.toJSONString(restRequest);
String resp = HttpClientUtil.doPostJSON(url, jsonRequest);
ObjectRestResponse<OrderStatisResult> result = JSON.parseObject(resp, new TypeReference<ObjectRestResponse<OrderStatisResult>>(){});
return result;
}
/**
* 10.查询打印机状态
*
* 0、离线 1、在线正常 2、在线不正常
* 备注异常一般是无纸离线的判断是打印机与服务器失去联系超过30秒
* @param restRequest
* @return
*/
public ObjectRestResponse<Integer> queryPrinterStatus(PrinterRequest restRequest) {
String url = BASE_URL + "/xprinter/queryPrinterStatus";
String jsonRequest = JSON.toJSONString(restRequest);
String resp = HttpClientUtil.doPostJSON(url, jsonRequest);
ObjectRestResponse<Integer> result = JSON.parseObject(resp, new TypeReference<ObjectRestResponse<Integer>>(){});
return result;
}
/**
* 10.批量查询打印机状态
*
* 0、离线 1、在线正常 2、在线不正常
* 备注异常一般是无纸离线的判断是打印机与服务器失去联系超过30秒
* @param restRequest
* @return
*/
public ObjectRestResponse<List<Integer>> queryPrintersStatus(PrintersRequest restRequest) {
String url = BASE_URL + "/xprinter/queryPrintersStatus";
String jsonRequest = JSON.toJSONString(restRequest);
String resp = HttpClientUtil.doPostJSON(url, jsonRequest);
ObjectRestResponse<List<Integer>> result = JSON.parseObject(resp, new TypeReference<ObjectRestResponse<List<Integer>>>(){});
return result;
}
/**
* 11.云喇叭播放语音
* @param restRequest
* @return
*/
public ObjectRestResponse<String> playVoice(VoiceRequest restRequest) {
String url = BASE_URL + "/xprinter/playVoice";
String jsonRequest = JSON.toJSONString(restRequest);
String resp = HttpClientUtil.doPostJSON(url, jsonRequest);
ObjectRestResponse<String> result = JSON.parseObject(resp, new TypeReference<ObjectRestResponse<String>>(){});
return result;
}
/**
* 12.POS指令
* @param restRequest
* @return
*/
public ObjectRestResponse<String> pos(PrintRequest restRequest) {
String url = BASE_URL + "/xprinter/pos";
String jsonRequest = JSON.toJSONString(restRequest);
String resp = HttpClientUtil.doPostJSON(url, jsonRequest);
ObjectRestResponse<String> result = JSON.parseObject(resp, new TypeReference<ObjectRestResponse<String>>(){});
return result;
}
/**
* 13.钱箱控制
* @param restRequest
* @return
*/
public ObjectRestResponse<String> controlBox(PrintRequest restRequest) {
String url = BASE_URL + "/xprinter/controlBox";
String jsonRequest = JSON.toJSONString(restRequest);
String resp = HttpClientUtil.doPostJSON(url, jsonRequest);
ObjectRestResponse<String> result = JSON.parseObject(resp, new TypeReference<ObjectRestResponse<String>>(){});
return result;
}
}

View File

@ -0,0 +1,46 @@
package net.xpyun.platform.opensdk.util;
import net.xpyun.platform.opensdk.vo.RestRequest;
/**
* @author LylJavas
* @create 2021/2/26 15:14
* @description 公共配置类
*/
public class Config {
/**
* *必填*开发者ID 芯烨云后台注册账号即邮箱地址或开发者ID开发者用户注册成功之后登录芯烨云后台在【个人中心=》账号信息】下可查看开发者ID
*
* 当前【xxxxxxxxxxxxxxx】只是样例需修改再使用
*/
public static final String USER_NAME = "zztect@163.com";
/**
* *必填*:开发者密钥 :芯烨云后台注册账号后自动生成的开发者密钥,开发者用户注册成功之后,登录芯烨云后台,在【个人中心=》账号信息】下可查看开发者密钥
*
* 当前【xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx】只是样例需修改再使用
*/
public static final String USER_KEY = "d963972a67dc4dbf820fab428ac851f8";
/**
* *必填*:打印机设备编号,必须要在芯烨云管理后台的【打印管理->打印机管理】下添加打印机或调用API接口添加打印机测试小票机和标签机的时候注意替换打印机编号
* 打印机设备编号获取方式在打印机底部会有带PID或SN字样的二维码且PID或SN后面的一串字符即为打印机编号
*
* 当前【xxxxxxxxxxxxxxx】只是样例需修改再使用此处只是作为测试样例所以打印机编号采用常量化开发者可根据自己的实际需要进行变量化
*/
public static final String OK_PRINTER_SN = "xxxxxxxxxxxxxxx";
/**
* 生成通用的请求头
*
* @param request 所有请求都必须传递的参数。
*/
public static void createRequestHeader(RestRequest request) {
//*必填*:芯烨云平台注册用户名(开发者 ID
request.setUser(USER_NAME);
//*必填*当前UNIX时间戳
request.setTimestamp(System.currentTimeMillis() + "");
//*必填*:对参数 user + UserKEY + timestamp 拼接后(+号表示连接符进行SHA1加密得到签名值为40位小写字符串其中 UserKEY 为用户开发者密钥
request.setSign(HashSignUtil.sign(request.getUser() + USER_KEY + request.getTimestamp()));
//debug=1返回非json格式的数据仅测试时候使用
request.setDebug("0");
}
}

View File

@ -0,0 +1,49 @@
package net.xpyun.platform.opensdk.util;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
/**
* 哈稀签名工具类
*
* @author RabyGao
* @date Aug 9, 2019
*/
public class HashSignUtil {
/**
* 哈稀签名
* @param signSource - 源字符串
* @return
*/
public static String sign(String signSource) {
String signature = "";
try {
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(signSource.getBytes("UTF-8"));
signature = byteToHex(crypt.digest());
}
catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return signature;
}
private static String byteToHex(final byte[] hash) {
Formatter formatter = new Formatter();
for (byte b : hash)
{
formatter.format("%02x", b);
}
String result = formatter.toString();
formatter.close();
return result;
}
}

View File

@ -0,0 +1,274 @@
package net.xpyun.platform.opensdk.util;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.*;
/**
* 基于 apache httpClient4.5 的HTTP工具类
*
* @author RabyGao
* @date Aug 9, 2019
*/
public class HttpClientUtil {
public static String doGet(String url) {
return doGet(url, null);
}
public static String doGet(String url, Map<String, String> headers) {
CloseableHttpClient httpClient = null;
CloseableHttpResponse response = null;
String result = "";
try {
// 通过址默认配置创建一个httpClient实例
httpClient = HttpClients.createDefault();
// 创建httpGet远程连接实例
HttpGet httpGet = new HttpGet(url);
if (headers != null && headers.size() > 0) {
for(Map.Entry<String, String> entry : headers.entrySet()){
httpGet.addHeader(entry.getKey(), entry.getValue());
}
}
// 设置配置请求参数
// 连接主机服务超时时间、请求超时时间、数据读取超时时间
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(5000).setConnectionRequestTimeout(5000).setSocketTimeout(10000)
.build();
// 为httpGet实例设置配置
httpGet.setConfig(requestConfig);
// 执行get请求得到返回对象
response = httpClient.execute(httpGet);
// 通过返回对象获取返回数据
HttpEntity entity = response.getEntity();
// 通过EntityUtils中的toString方法将结果转换为字符串
result = EntityUtils.toString(entity);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭资源
if (null != response) {
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != httpClient) {
try {
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
public static String doPost(String url, Map<String, Object> paramMap) {
return doPost(url, paramMap, null);
}
public static String doPost(String url, Map<String, Object> paramMap, Map<String, String> headers) {
return doPost(url, paramMap, headers, "application/x-www-form-urlencoded", "UTF-8");
}
public static String doPost(String url, Map<String, Object> paramMap, Map<String, String> headers, String contentType, String charset) {
CloseableHttpClient httpClient = null;
CloseableHttpResponse httpResponse = null;
String result = "";
// 创建httpClient实例
httpClient = HttpClients.createDefault();
// 创建httpPost远程连接实例
HttpPost httpPost = new HttpPost(url);
// 配置请求参数实例
// 连接主机服务超时时间、请求超时时间、数据读取超时时间
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(5000).setConnectionRequestTimeout(5000).setSocketTimeout(10000)
.build();
// 为httpPost实例设置配置
httpPost.setConfig(requestConfig);
// 设置请求头
httpPost.addHeader("Content-Type", contentType);
if (headers != null && headers.size() > 0) {
for(Map.Entry<String, String> entry : headers.entrySet()){
httpPost.addHeader(entry.getKey(), entry.getValue());
}
}
// 封装post请求参数
if (null != paramMap && paramMap.size() > 0) {
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
// 通过map集成entrySet方法获取entity
Set<Map.Entry<String, Object>> entrySet = paramMap.entrySet();
// 循环遍历,获取迭代器
Iterator<Map.Entry<String, Object>> iterator = entrySet.iterator();
while (iterator.hasNext()) {
Map.Entry<String, Object> mapEntry = iterator.next();
nvps.add(new BasicNameValuePair(mapEntry.getKey(), mapEntry.getValue().toString()));
}
// 为httpPost设置封装好的请求参数
try {
httpPost.setEntity(new UrlEncodedFormEntity(nvps, charset));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
try {
// httpClient对象执行post请求,并返回响应参数对象
httpResponse = httpClient.execute(httpPost);
// 从响应对象中获取响应内容
HttpEntity entity = httpResponse.getEntity();
result = EntityUtils.toString(entity);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭资源
if (null != httpResponse) {
try {
httpResponse.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != httpClient) {
try {
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
public static String doPostJSON(String url, String json) {
return doPostJSON(url, json, null);
}
public static String doPostJSON(String url, String json, Map<String, String> headers) {
CloseableHttpClient httpClient = null;
try {
httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(url);
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(5000).setConnectionRequestTimeout(5000).setSocketTimeout(10000).build();
// 为httpPost实例设置配置
httpPost.setConfig(requestConfig);
// 设置请求头
httpPost.addHeader("Content-Type", "application/json;charset=UTF-8");
if (headers != null && headers.size() > 0) {
for (String key:headers.keySet()) {
httpPost.addHeader(key, headers.get(key));
}
}
// 解决中文乱码问题
StringEntity stringEntity = new StringEntity(json, "UTF-8");
stringEntity.setContentEncoding("UTF-8");
httpPost.setEntity(stringEntity);
ResponseHandler<String> responseHandler = new ResponseHandler<String>() {
@Override
public String handleResponse(final HttpResponse response)
throws ClientProtocolException, IOException {
int status = response.getStatusLine().getStatusCode();
if (status >= 200 && status < 300) {
HttpEntity entity = response.getEntity();
return entity != null ? EntityUtils.toString(entity) : null;
} else {
throw new ClientProtocolException("Unexpected response status: " + status);
}
}
};
return httpClient.execute(httpPost, responseHandler);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (httpClient != null) {
try {
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
public static String doPostGetLocation(String url, Map<String, Object> paramMap) {
CloseableHttpResponse httpResponse = null;
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(url);
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(5000).setConnectionRequestTimeout(5000).setSocketTimeout(10000).build();
// 为httpPost实例设置配置
httpPost.setConfig(requestConfig);
httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded");
// 封装post请求参数
if (null != paramMap && paramMap.size() > 0) {
List<NameValuePair> nvps = new ArrayList<NameValuePair>();
Set<Map.Entry<String, Object>> entrySet = paramMap.entrySet();
Iterator<Map.Entry<String, Object>> iterator = entrySet.iterator();
while (iterator.hasNext()) {
Map.Entry<String, Object> mapEntry = iterator.next();
nvps.add(new BasicNameValuePair(mapEntry.getKey(), mapEntry.getValue().toString()));
}
try {
httpPost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
try {
// httpClient对象执行post请求,并返回响应参数对象
httpResponse = httpClient.execute(httpPost);
if (httpResponse.getStatusLine().getStatusCode() == 302 && httpResponse.getHeaders("Location").length > 0) {
return httpResponse.getHeaders("Location")[0].getValue();
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭资源
if (null != httpResponse) {
try {
httpResponse.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (null != httpClient) {
try {
httpClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
}

View File

@ -0,0 +1,278 @@
package net.xpyun.platform.opensdk.util;
import org.apache.commons.lang.StringUtils;
import java.io.UnsupportedEncodingException;
import java.text.DecimalFormat;
/**
* @author LylJavas
* @create 2021/2/26 15:16
* @description 小票格式化器
*/
public class NoteFormatter {
/**
* 58mm 系列打印机每行可以打印的字符数
*/
private static final Integer ROW_MAX_CHAR_LEN = 32;
private static final Integer MAX_NAME_CHAR_LEN = 20;
private static final Integer LAST_ROW_MAX_NAME_CHAR_LEN = 9;
private static final Integer MAX_QUANTITY_CHAR_LEN = 6;
private static final Integer MAX_PRICE_CHAR_LEN = 6;
/**
* 80mm 系列打印机每行可以打印的字符数
*/
private static final Integer ROW_MAX_CHAR_LEN80 = 48;
private static final Integer MAX_NAME_CHAR_LEN80 = 36;
private static final Integer LAST_ROW_MAX_NAME_CHAR_LEN80 = 17;
private static final Integer MAX_QUANTITY_CHAR_LEN80 = 6;
private static final Integer MAX_PRICE_CHAR_LEN80 = 6;
private static String orderNameEmpty = StringUtils.repeat(" ", MAX_NAME_CHAR_LEN);
/**
* 格式化订单数据 80mm打印机使用
*
* @param foodName
* @param quantity
* @param price
* @return
* @throws Exception
*/
public static String formatPrintOrderItemBy4Column(String foodName, Integer quantity, Double singlePrice, Double price) throws Exception {
StringBuilder builder = new StringBuilder();
byte[] itemNames = foodName.getBytes("GBK");
Integer mod = itemNames.length % ROW_MAX_CHAR_LEN;
String quanityStr = quantity.toString();
byte[] itemQuans = quanityStr.getBytes("GBK");
String priceStr = roundByTwo(price);
byte[] itemPrices = (priceStr).getBytes("GBK");
if (mod <= LAST_ROW_MAX_NAME_CHAR_LEN) {
builder.append("<C>").append(foodName).append("</C>");
// 在同一行,留4个英文字符的空格
//if in the same row, fill with 4 spaces at the end of name column
builder.append(StringUtils.repeat(" ", (MAX_NAME_CHAR_LEN - mod)));
builder.append(quanityStr).append(StringUtils.repeat(" ", (MAX_QUANTITY_CHAR_LEN - itemQuans.length)));
builder.append(priceStr).append(StringUtils.repeat(" ", (MAX_PRICE_CHAR_LEN - itemPrices.length)));
} else {
// 对菜名进行猜分
builder.append(foodName);
// 另起新行
// new line
builder.append("<BR>");
builder.append(orderNameEmpty);
builder.append(quanityStr).append(StringUtils.repeat(" ", (MAX_QUANTITY_CHAR_LEN - itemQuans.length)));
builder.append(priceStr).append(StringUtils.repeat(" ", (MAX_PRICE_CHAR_LEN - itemPrices.length)));
}
builder.append("<BR>");
return builder.toString();
}
/**
* 格式化菜名名称,菜名名称打满一行自动换行
*
* @param foodName
* @param quantity
* @param price
* @return
* @throws Exception
*/
public static String formatPrintOrderItemByFull(String foodName, Integer quantity, Double price) throws Exception {
StringBuilder builder = new StringBuilder();
byte[] itemNames = foodName.getBytes("GBK");
Integer mod = itemNames.length % ROW_MAX_CHAR_LEN;
String quanityStr = quantity.toString();
byte[] itemQuans = quanityStr.getBytes("GBK");
String priceStr = roundByTwo(price);
byte[] itemPrices = (priceStr).getBytes("GBK");
if (mod <= LAST_ROW_MAX_NAME_CHAR_LEN) {
builder.append(foodName);
// 在同一行,留4个英文字符的空格
//if in the same row, fill with 4 spaces at the end of name column
builder.append(StringUtils.repeat(" ", (MAX_NAME_CHAR_LEN - mod)));
builder.append(quanityStr).append(StringUtils.repeat(" ", (MAX_QUANTITY_CHAR_LEN - itemQuans.length)));
builder.append(priceStr).append(StringUtils.repeat(" ", (MAX_PRICE_CHAR_LEN - itemPrices.length)));
} else {
// 对菜名进行猜分
builder.append(foodName);
// 另起新行
// new line
builder.append("<BR>");
builder.append(orderNameEmpty);
builder.append(quanityStr).append(StringUtils.repeat(" ", (MAX_QUANTITY_CHAR_LEN - itemQuans.length)));
builder.append(priceStr).append(StringUtils.repeat(" ", (MAX_PRICE_CHAR_LEN - itemPrices.length)));
}
builder.append("<BR>");
return builder.toString();
}
/**
* 格式化菜品列表用于58mm打印机
* 注意:默认字体排版,若是字体宽度倍大后不适用
* 58mm打印机一行可打印32个字符 汉子按照2个字符算
* 分3列 名称20字符一般用16字符4空格填充 数量6字符 单价6字符不足用英文空格填充 名称过长换行
* Format the dish list (for 58 mm printer)
* Note: this is default font typesetting, not applicable if the font width is doubled
* The 58mm printer can print 32 characters per line
* Divided into 3 columns: name(20 characters), quanity(6 characters),price(6 characters)
* The name column is generally filled with 16 your characters and 4 spaces
* Long name column will cause auto line break
*
* @param foodName 菜品名称
* @param quantity 数量
* @param price 价格
* @throws Exception
*/
public static String formatPrintOrderItemForNewLine58(String foodName, Integer quantity, Double price) throws Exception {
StringBuilder builder = new StringBuilder();
byte[] itemNames = foodName.getBytes("GBK");
Integer mod = itemNames.length % ROW_MAX_CHAR_LEN;
if (mod <= LAST_ROW_MAX_NAME_CHAR_LEN) {
builder.append(foodName);
// 在同一行,留4个英文字符的空格
//if in the same row, fill with 4 spaces at the end of name column
builder.append(StringUtils.repeat(" ", (MAX_NAME_CHAR_LEN - mod)));
String quanityStr = quantity.toString();
byte[] itemQuans = quanityStr.getBytes("GBK");
String priceStr = roundByTwo(price);
byte[] itemPrices = (priceStr).getBytes("GBK");
builder.append(quanityStr).append(StringUtils.repeat(" ", (MAX_QUANTITY_CHAR_LEN - itemQuans.length)));
builder.append(priceStr).append(StringUtils.repeat(" ", (MAX_PRICE_CHAR_LEN - itemPrices.length)));
} else {
getFoodNameSplit58(foodName, builder, quantity, price);
}
builder.append("<BR>");
return builder.toString();
}
/**
* 格式化菜品列表用于58mm打印机
* 注意:默认字体排版,若是字体宽度倍大后不适用
* 58mm打印机一行可打印32个字符 汉子按照2个字符算
* 分3列 名称20字符一般用16字符4空格填充 数量6字符 单价6字符不足用英文空格填充 名称过长换行
* Format the dish list (for 58 mm printer)
* Note: this is default font typesetting, not applicable if the font width is doubled
* The 58mm printer can print 32 characters per line
* Divided into 3 columns: name(20 characters), quanity(6 characters),price(6 characters)
* The name column is generally filled with 16 your characters and 4 spaces
* Long name column will cause auto line break
*
* @param foodName 菜品名称
* @param quantity 数量
* @param price 价格
* @throws Exception
*/
public static String formatPrintOrderItemForNewLine80(String foodName, Integer quantity, Double price) throws Exception {
StringBuilder builder = new StringBuilder();
byte[] itemNames = foodName.getBytes("GBK");
Integer mod = itemNames.length % ROW_MAX_CHAR_LEN80;
if (mod <= LAST_ROW_MAX_NAME_CHAR_LEN80) {
builder.append(foodName);
// 在同一行,留4个英文字符的空格
//if in the same row, fill with 4 spaces at the end of name column
builder.append(StringUtils.repeat(" ", (MAX_NAME_CHAR_LEN80 - mod)));
String quanityStr = quantity.toString();
byte[] itemQuans = quanityStr.getBytes("GBK");
String priceStr = roundByTwo(price);
byte[] itemPrices = (priceStr).getBytes("GBK");
builder.append(quanityStr).append(StringUtils.repeat(" ", (MAX_QUANTITY_CHAR_LEN80 - itemQuans.length)));
builder.append(priceStr).append(StringUtils.repeat(" ", (MAX_PRICE_CHAR_LEN80 - itemPrices.length)));
} else {
getFoodNameSplit80(foodName, builder, quantity, price);
}
builder.append("<BR>");
return builder.toString();
}
private static void getFoodNameSplit58(String foodName, StringBuilder builder, Integer quantity, Double price) throws UnsupportedEncodingException {
String[] foodNames = string2StringArray(foodName, LAST_ROW_MAX_NAME_CHAR_LEN);
String quanityStr = quantity.toString();
byte[] itemQuans = quanityStr.getBytes("GBK");
String priceStr = roundByTwo(price);
byte[] itemPrices = (priceStr).getBytes("GBK");
for (int i = 0; i < foodNames.length; i++) {
if (i == 0) {
byte[] itemNames = foodNames[i].getBytes("GBK");
Integer mod = itemNames.length % ROW_MAX_CHAR_LEN;
builder.append(foodNames[i]);
builder.append(StringUtils.repeat(" ", (MAX_NAME_CHAR_LEN - mod)));
builder.append(quanityStr).append(StringUtils.repeat(" ", (MAX_QUANTITY_CHAR_LEN - itemQuans.length)));
builder.append(priceStr).append(StringUtils.repeat(" ", (MAX_PRICE_CHAR_LEN - itemPrices.length)));
} else {
builder.append(foodNames[i]).append("<BR>");
}
}
}
private static void getFoodNameSplit80(String foodName, StringBuilder builder, Integer quantity, Double price) throws UnsupportedEncodingException {
String[] foodNames = string2StringArray(foodName, LAST_ROW_MAX_NAME_CHAR_LEN80);
String quanityStr = quantity.toString();
byte[] itemQuans = quanityStr.getBytes("GBK");
String priceStr = roundByTwo(price);
byte[] itemPrices = (priceStr).getBytes("GBK");
for (int i = 0; i < foodNames.length; i++) {
if (i == 0) {
byte[] itemNames = foodNames[i].getBytes("GBK");
Integer mod = itemNames.length % ROW_MAX_CHAR_LEN80;
builder.append(foodNames[i]);
builder.append(StringUtils.repeat(" ", (MAX_NAME_CHAR_LEN80 - mod)));
builder.append(quanityStr).append(StringUtils.repeat(" ", (MAX_QUANTITY_CHAR_LEN80 - itemQuans.length)));
builder.append(priceStr).append(StringUtils.repeat(" ", (MAX_PRICE_CHAR_LEN80 - itemPrices.length)));
} else {
builder.append(foodNames[i]).append("<BR>");
}
}
}
private static String[] string2StringArray(String src, Integer length) {
if (StringUtils.isBlank(src) || length <= 0) {
return null;
}
int n = (src.length() + length - 1) / length;
String[] splits = new String[n];
for (int i = 0; i < n; i++) {
if (i < (n - 1)) {
splits[i] = src.substring(i * length, (i + 1) * length);
} else {
splits[i] = src.substring(i * length);
}
}
return splits;
}
/**
* 将double格式化为指定小数位的String不足小数位用0补全 (小数点后保留2位)
* Format the double as a String with specified decimal places, fill in with 0 if the decimal place is not enough
*
* @param v - 需要格式化的数字 Number to be formatted
* @return 返回指定位数的字符串 Returns a string with a specified number of digits
*/
public static String roundByTwo(double v) {
return roundByScale(v, 2);
}
/**
* 将double格式化为指定小数位的String不足小数位用0补全
* Format the double as a String with specified decimal places, and use 0 to complete the decimal places
*
* @param v - 需要格式化的数字 number to be formatted
* @param scale - 小数点后保留几位 places after the decimal point
* @return 返回指定位数的字符串 Returns a string with a specified number of digits
*/
public static String roundByScale(double v, int scale) {
if (scale == 0) {
return new DecimalFormat("0").format(v);
}
String formatStr = "0.";
for (int i = 0; i < scale; i++) {
formatStr = formatStr + "0";
}
return new DecimalFormat(formatStr).format(v);
}
}

View File

@ -0,0 +1,24 @@
package net.xpyun.platform.opensdk.vo;
/**
* 添加打印机请求参数
*
* @author RabyGao
* @date Aug 7, 2019
*/
public class AddPrinterRequest extends RestRequest {
public AddPrinterRequestItem[] getItems() {
return items;
}
public void setItems(AddPrinterRequestItem[] items) {
this.items = items;
}
/**
* 请求项集合
*/
private AddPrinterRequestItem[] items;
}

View File

@ -0,0 +1,35 @@
package net.xpyun.platform.opensdk.vo;
/**
* 添加打印机请求项
*
* @author RabyGao
* @date Aug 7, 2019
*/
public class AddPrinterRequestItem {
/**
* 打印机编号
*/
private String sn;
/**
* 打印机名称
*/
private String name;
public String getSn() {
return sn;
}
public void setSn(String sn) {
this.sn = sn;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@ -0,0 +1,23 @@
package net.xpyun.platform.opensdk.vo;
/**
* 删除打印机请求参数
*
* @author RabyGao
* @date Aug 7, 2019
*/
public class DelPrinterRequest extends RestRequest {
/**
* 打印机编号集合
*/
private String[] snlist;
public String[] getSnlist() {
return snlist;
}
public void setSnlist(String[] snlist) {
this.snlist = snlist;
}
}

View File

@ -0,0 +1,95 @@
package net.xpyun.platform.opensdk.vo;
/**
* 返回公共参数
*
* @param <T>
* @author RabyGao
* @date Aug 7, 2019
*/
public class ObjectRestResponse<T> {
public static final String REST_RESPONSE_OK = "ok";
/**
* 返回码正确返回0【注意结果正确与否的判断请用此返回参数】错误返回非零
*/
private int code;
/**
* 结果提示信息正确返回”ok”如果有错误返回错误信息
*/
private String msg;
/**
* 数据类型和内容详看私有返回参数data如果有错误返回null
*/
private T data;
/**
* 服务器程序执行时间,单位:毫秒
*/
private long serverExecutedTime;
public ObjectRestResponse() {
this.setCode(0);
this.setMsg(REST_RESPONSE_OK);
}
public ObjectRestResponse code(int code) {
this.setCode(code);
return this;
}
public ObjectRestResponse data(T data) {
this.setData(data);
return this;
}
public ObjectRestResponse msg(String msg) {
this.setMsg(msg);
return this;
}
public ObjectRestResponse setResult(int code, T data) {
this.setCode(code);
this.setData(data);
return this;
}
public ObjectRestResponse setResult(int code, T data, String msg) {
this.setCode(code);
this.setData(data);
this.setMsg(msg);
return this;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public long getServerExecutedTime() {
return serverExecutedTime;
}
public void setServerExecutedTime(long serverExecutedTime) {
this.serverExecutedTime = serverExecutedTime;
}
}

View File

@ -0,0 +1,36 @@
package net.xpyun.platform.opensdk.vo;
/**
* 订单统计结果
*
* @author RabyGao
* @date Aug 7, 2019
*/
public class OrderStatisResult {
/**
* 已打印订单数
*/
private int printed;
/**
* 等待打印订单数
*/
private int waiting;
public int getPrinted() {
return printed;
}
public void setPrinted(int printed) {
this.printed = printed;
}
public int getWaiting() {
return waiting;
}
public void setWaiting(int waiting) {
this.waiting = waiting;
}
}

View File

@ -0,0 +1,43 @@
package net.xpyun.platform.opensdk.vo;
/**
* 订单状态
*
* @author RabyGao
* @date Aug 8, 2019
*/
public enum OrderStatusType {
/**
* 处理中
*/
Processing(0),
/**
* 完成
*/
Completed(1),
/**
* 失败
*/
Failed(2);
private final int val;
public int getVal() {
return val;
}
OrderStatusType(int num) {
this.val = num;
}
public static OrderStatusType getOrderStatusType(int val) {
for (OrderStatusType type : OrderStatusType.values()) {
if (type.getVal() == val) {
return type;
}
}
return Processing;
}
}

View File

@ -0,0 +1,124 @@
package net.xpyun.platform.opensdk.vo;
/**
* 打印机打印请求参数
*
* @author RabyGao
* @date Aug 7, 2019
*/
public class PrintRequest extends RestRequest {
/**
* 打印机编号
*/
private String sn;
/**
* 打印内容,不能超过5000字节
*/
private String content;
/**
* 打印份数默认为1
*/
private int copies = 1;
/**
* 打印模式默认为0
*/
private int mode = 0;
/**
* 支付方式41~55支付宝 微信 ...
*/
private Integer payType;
/**
* 支付与否59~61退款 到账 消费
*/
private Integer payMode;
/**
* 支付金额
*/
private Double money;
/**
* 声音播放模式0 为取消订单模式1 为静音模式2 为来单播放模式,默认为 2 来单播放模式
*/
private Integer voice;
/**
* 打印接口回调地址对应标识(取值范围 [ 1 - 5 ] 的整数)对于web管理后台 “功能设置” 菜单设置界面的打印接口回调标识。
*/
private Integer backurlFlag;
public String getSn() {
return sn;
}
public void setSn(String sn) {
this.sn = sn;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public int getCopies() {
return copies;
}
public void setCopies(int copies) {
this.copies = copies;
}
public int getMode() {
return mode;
}
public void setMode(int mode) {
this.mode = mode;
}
public Integer getPayType() {
return payType;
}
public void setPayType(Integer payType) {
this.payType = payType;
}
public Integer getPayMode() {
return payMode;
}
public void setPayMode(Integer payMode) {
this.payMode = payMode;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
public Integer getVoice() {
return voice;
}
public void setVoice(Integer voice) {
this.voice = voice;
}
public Integer getBackurlFlag() {
return backurlFlag;
}
public void setBackurlFlag(Integer backurlFlag) {
this.backurlFlag = backurlFlag;
}
}

View File

@ -0,0 +1,23 @@
package net.xpyun.platform.opensdk.vo;
/**
* 打印机请求参数
*
* @author RabyGao
* @date Aug 7, 2019
*/
public class PrinterRequest extends RestRequest {
/**
* 打印机编号
*/
private String sn;
public String getSn() {
return sn;
}
public void setSn(String sn) {
this.sn = sn;
}
}

View File

@ -0,0 +1,57 @@
package net.xpyun.platform.opensdk.vo;
import java.util.ArrayList;
import java.util.List;
/**
* 批量添加或删除打印机结果
*
* @author RabyGao
* @date Aug 7, 2019
*/
public class PrinterResult{
public PrinterResult() {
success = new ArrayList<>();
fail = new ArrayList<>();
failMsg=new ArrayList<>();
}
/**
* 成功的打印机编号集合
*/
private List<String> success;
/**
* 失败的打印机编号集合
*/
private List<String> fail;
/**
* 失败原因集合 设备编号:失败原因
*/
private List<String> failMsg ;
public List<String> getSuccess() {
return success;
}
public void setSuccess(List<String> success) {
this.success = success;
}
public List<String> getFail() {
return fail;
}
public void setFail(List<String> fail) {
this.fail = fail;
}
public List<String> getFailMsg() {
return failMsg;
}
public void setFailMsg(List<String> failMsg) {
this.failMsg = failMsg;
}
}

View File

@ -0,0 +1,43 @@
package net.xpyun.platform.opensdk.vo;
/**
* 打印机状态
*
* @author RabyGao
* @date Aug 8, 2019
*/
public enum PrinterStatusType {
/**
* 离线
*/
Offline(0),
/**
* 在线正常
*/
OnlinNormal(1),
/**
* 在线缺纸
*/
OnlineMissingPaper(2);
private final int val;
public int getVal() {
return val;
}
private PrinterStatusType(int num) {
this.val = num;
}
public static PrinterStatusType getPrinterStatusType(int val) {
for (PrinterStatusType type : PrinterStatusType.values()) {
if (type.getVal() == val) {
return type;
}
}
return Offline;
}
}

View File

@ -0,0 +1,24 @@
package net.xpyun.platform.opensdk.vo;
import java.util.List;
/**
* @author LylJavas
* @create 2021/4/14 18:01
* @description 批量打印机请求参数
*/
public class PrintersRequest extends RestRequest {
/**
* 打印机编号列表
*/
private List<String> snlist;
public List<String> getSnlist() {
return snlist;
}
public void setSnlist(List<String> snlist) {
this.snlist = snlist;
}
}

View File

@ -0,0 +1,23 @@
package net.xpyun.platform.opensdk.vo;
/**
* 查询订单状态请求参数
*
* @author RabyGao
* @date Aug 7, 2019
*/
public class QueryOrderStateRequest extends RestRequest {
/**
* 订单编号
*/
private String orderId;
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
}

View File

@ -0,0 +1,35 @@
package net.xpyun.platform.opensdk.vo;
/**
* 查询订单统计请求参数
*
* @author RabyGao
* @date Aug 7, 2019
*/
public class QueryOrderStatisRequest extends RestRequest {
/**
* 打印机编号
*/
private String sn;
/**
* 查询日期格式YY-MM-DD2016-09-20
*/
private String date;
public String getSn() {
return sn;
}
public void setSn(String sn) {
this.sn = sn;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
}

View File

@ -0,0 +1,59 @@
package net.xpyun.platform.opensdk.vo;
/**
* 请求公共参数
*
* @author RabyGao
* @date Aug 7, 2019
*/
public class RestRequest {
/**
* 芯烨云后台注册用户名
*/
private String user;
/**
* 当前UNIX时间戳10位精确到秒
*/
private String timestamp;
/**
* 对参数 user + UKEY + timestamp 拼接后(+号表示连接符进行SHA1加密得到签名值为40位小写字符串
*/
private String sign;
/**
* debug=1返回非json格式的数据。仅测试时候使用
*/
private String debug;
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getTimestamp() {
return timestamp;
}
public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
}
public String getDebug() {
return debug;
}
public void setDebug(String debug) {
this.debug = debug;
}
}

View File

@ -0,0 +1,37 @@
package net.xpyun.platform.opensdk.vo;
/**
* 设置打印机语音类型请求参数
*
* @author RabyGao
* @date Aug 7, 2019
*/
public class SetVoiceTypeRequest extends RestRequest {
/**
* 打印机编号
*/
private String sn;
/**
* 声音类型: 0真人语音 1真人语音 2真人语音 3 嘀嘀声 4 静音
*/
private Integer voiceType;
public String getSn() {
return sn;
}
public void setSn(String sn) {
this.sn = sn;
}
public Integer getVoiceType() {
return voiceType;
}
public void setVoiceType(Integer voiceType) {
this.voiceType = voiceType;
}
}

View File

@ -0,0 +1,60 @@
package net.xpyun.platform.opensdk.vo;
/**
* 修改打印机请求参数
*
* @author RabyGao
* @date Aug 7, 2019
*/
public class UpdPrinterRequest extends RestRequest {
/**
* 打印机编号
*/
private String sn;
/**
* 打印机名称
*/
private String name;
/**
* 打印机识别码
*/
private String idcode;
/**
* 流量卡号码
*/
private String cardno;
public String getSn() {
return sn;
}
public void setSn(String sn) {
this.sn = sn;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getIdcode() {
return idcode;
}
public void setIdcode(String idcode) {
this.idcode = idcode;
}
public String getCardno() {
return cardno;
}
public void setCardno(String cardno) {
this.cardno = cardno;
}
}

View File

@ -0,0 +1,61 @@
package net.xpyun.platform.opensdk.vo;
/**
* 云喇叭播放语音请求参数
*
* @author RabyGao
* @date Aug 5, 2020
*/
public class VoiceRequest extends RestRequest {
/**
* 打印机编号
*/
private String sn;
/**
* 支付方式41~55支付宝 微信 ...
*/
private Integer payType;
/**
* 支付与否59~61退款 到账 消费
*/
private Integer payMode;
/**
* 支付金额
*/
private Double money;
public String getSn() {
return sn;
}
public void setSn(String sn) {
this.sn = sn;
}
public Integer getPayType() {
return payType;
}
public void setPayType(Integer payType) {
this.payType = payType;
}
public Integer getPayMode() {
return payMode;
}
public void setPayMode(Integer payMode) {
this.payMode = payMode;
}
public Double getMoney() {
return money;
}
public void setMoney(Double money) {
this.money = money;
}
}