,Java 这两类我都接触过,但要先区分运行环境,因为“蓝牙打印 / 扫码枪”在 Java 里实现方式差别很大:
1. 先说结论
蓝牙打印
Java 可以对接,但要看你是:
Android Java
最常见,支持最好。
通过BluetoothAdapter / BluetoothDevice / BluetoothSocket连接蓝牙打印机,然后按打印机指令集发送数据:ESC/POS:小票打印机最常见
CPCL / TSPL / ZPL:标签打印机常见
Java SE(Windows/Linux/macOS 桌面端)
也能做,但比 Android 麻烦。通常有几种方式:通过系统已配对的蓝牙串口(SPP)通信
用第三方库访问串口/蓝牙
如果打印机安装成系统打印机,也可走
javax.print
扫码枪
扫码枪更简单,因为很多扫码枪本质上是键盘输入设备,或者串口设备:
USB 扫码枪(键盘口/HID)
Java 基本不用专门对接
光标在哪,扫码结果就像键盘输入到哪
一般监听文本框回车即可
串口扫码枪
Java 用串口库读取数据即可
常见库:
jSerialCommRXTXnrjavaserial
蓝牙扫码枪
如果蓝牙扫码枪工作在 HID 模式:和键盘一样处理
如果工作在 SPP 串口模式:按串口/蓝牙流读取
2. 我实际会怎么判断方案
如果你问“Java 能不能做”,我一般先确认这几个问题:
对蓝牙打印机
是 Android App 还是 桌面 Java 程序?
打印机品牌型号是什么?
指令集是什么?
ESC/POS
TSPL
CPCL
ZPL
连接方式是什么?
蓝牙 classic
USB
WiFi / 网口
打印内容是什么?
纯文字小票
二维码/条码
标签
对扫码枪
扫码枪是 USB、蓝牙、还是 串口?
当前电脑/设备识别成什么?
键盘
COM 串口
扫码后输出格式是什么?
是否自动回车
是否有前后缀
运行环境是:
Java Swing
JavaFX
Spring Boot + 本地客户端
Android
3. 蓝牙打印:Java 常见做法
3.1 Android Java 对接蓝牙打印机
这是最常见的场景。
核心流程:
获取蓝牙适配器
搜索/选择已配对设备
建立
BluetoothSocket获取
OutputStream发送 ESC/POS 或标签指令
关闭连接
示例思路
javaCopy
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(macAddress);
BluetoothSocket socket = device.createRfcommSocketToServiceRecord(UUID.fromString(SPP_UUID));
socket.connect();
OutputStream os = socket.getOutputStream();
// 发送 ESC/POS 指令
os.write(new byte[]{0x1B, 0x40}); // 初始化打印机
os.write("Hello Printer\n".getBytes("GBK"));
os.write(new byte[]{0x0A, 0x0A, 0x1D, 0x56, 0x42, 0x00}); // 走纸+切纸
os.flush();
os.close();
socket.close();
注意点
安卓 12 以后蓝牙权限变了,要申请:
BLUETOOTH_CONNECTBLUETOOTH_SCAN
很多小票打印机中文编码要用:
GBK有些也支持
UTF-8,但不一定稳定
不同打印机切纸、二维码、图片命令可能不完全一致
3.2 Java SE 桌面端蓝牙打印
桌面端要看打印机暴露的是什么能力。
方式 A:如果蓝牙打印机映射成串口
Java 可以直接按串口写数据。
比如用 jSerialComm:
javaCopy
import com.fazecast.jSerialComm.SerialPort;
import java.nio.charset.Charset;
public class PrinterDemo {
public static void main(String[] args) {
SerialPort port = SerialPort.getCommPort("COM5");
port.setBaudRate(9600);
if (port.openPort()) {
byte[] init = new byte[]{0x1B, 0x40};
port.writeBytes(init, init.length);
byte[] text = "测试打印\n".getBytes(Charset.forName("GBK"));
port.writeBytes(text, text.length);
port.closePort();
}
}
}
方式 B:作为系统打印机
如果系统里已经安装好了打印机驱动,也可以通过 Java Print Service:
javaCopy
PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null);
for (PrintService service : services) {
System.out.println(service.getName());
}
然后把内容发送给指定打印服务。
但要注意:
javax.print更适合普通文档打印对小票打印机的精细控制,不如直接发 ESC/POS 灵活
4. 扫码枪:Java 常见做法
4.1 扫码枪是键盘模式(最常见)
这种最简单。
扫码枪扫完码后,相当于键盘输入:
6901234567890然后自动回车
你只要在输入框监听即可。
Swing 示例
javaCopy
JTextField textField = new JTextField();
textField.addActionListener(e -> {
String code = textField.getText();
System.out.println("扫描结果: " + code);
textField.setText("");
});
JavaFX 示例
javaCopy
TextField textField = new TextField();
textField.setOnAction(e -> {
String code = textField.getText();
System.out.println("扫描结果: " + code);
textField.clear();
});
适用特点
开发成本最低
不需要设备驱动开发
基本所有业务系统都这么接
4.2 串口扫码枪
如果扫码枪输出到 COM 口,就要监听串口数据。
jSerialComm 示例
javaCopy
import com.fazecast.jSerialComm.SerialPort;
public class ScannerDemo {
public static void main(String[] args) {
SerialPort port = SerialPort.getCommPort("COM3");
port.setBaudRate(9600);
port.setNumDataBits(8);
port.setNumStopBits(1);
port.setParity(SerialPort.NO_PARITY);
if (port.openPort()) {
byte[] buffer = new byte[1024];
while (true) {
int len = port.readBytes(buffer, buffer.length);
if (len > 0) {
String data = new String(buffer, 0, len);
System.out.println("扫描数据: " + data);
}
}
}
}
}
注意点
要处理一条码数据的结束符:
\r\n\r\n
有的扫码枪支持配置前缀/后缀
需要做缓冲拼包,不能假设一次 read 就是一整条码
4.3 蓝牙扫码枪
蓝牙扫码枪一般两种模式:
HID 模式
配对后像蓝牙键盘
Java 侧不用特殊 SDK
就按输入法/文本框处理
SPP 模式
配对后形成虚拟串口
Java 侧按串口读数据
5. 实战里最容易踩的坑
蓝牙打印常见坑
打印乱码
中文编码不对
打印机字库不支持
安卓权限不全
尤其 Android 12+
蓝牙连接不稳定
连接超时、配对失效、socket 被占用
不同品牌指令不兼容
虽然都说支持 ESC/POS,但细节会有差异
图片打印慢
要做位图压缩、二值化
扫码枪常见坑
以为要接 SDK,其实只是键盘输入
回车/后缀没处理好
焦点丢失导致扫不到输入框
串口参数不匹配
波特率、校验位、停止位
蓝牙扫码枪模式搞错
HID 和 SPP 处理方式完全不同
6. 我建议的落地方案
如果你是做收银/仓储/PDA
打印
Android:直接蓝牙 socket + ESC/POS/TSPL
桌面端:优先 USB / 网口打印,其次蓝牙串口
因为桌面端蓝牙兼容性通常不如 Android
扫码
优先键盘模式
最稳、最省开发
如果必须拿到底层数据,再走串口模式