注意:代码仅供参考,需要根据具体的设备做调整
同系列文章:
依赖关系:
- FaceIdProtocolCodecFactory.jar
- mina-core-2.0.9.jar
- slf4j-api-1.7.13.jar
- slf4j-simple-1.7.13.jar
演示程序界面
源代码
TcpServerDemo.java
package Splash; import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.scene.image.Image; import javafx.stage.Stage; import javafx.stage.WindowEvent; public class TcpServerDemo extends Application { @Override public void start(Stage stage) throws Exception { FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml")); Parent root = loader.load(); Scene scene = new Scene(root); stage.setScene(scene); // 设置窗体标题 stage.setTitle("TcpServerDemo"); // 设置窗体图标 stage.getIcons().add(new Image(getClass().getResourceAsStream("FireEyes.png"))); // 设置到屏幕中心 stage.centerOnScreen(); // 设置窗口关闭处理函数 stage.setOnCloseRequest((WindowEvent e) -> { FXMLDocumentController controller = loader.getController(); if(controller.mTcpServer != null) { controller.mTcpServer.dispose(true); controller.mTcpServer = null; } }); // 显示窗体 stage.show(); } /** * @param args the command line arguments */ public static void main(String[] args) { launch(args); } }
FXMLDocumentController.java
/* ---------------------------------------------------------- * 文件名称:FXMLDocumentController.java * * 作者:秦建辉 * * QQ:36748897 * * 博客:http://www.firstsolver.com/wordpress/ * * 开发环境: * NetBeans 8.1 * JDK 8u66 * * 版本历史: * V1.0 2015年12月10日 * 验证服务器端 ------------------------------------------------------------ */ package Splash; import Com.FirstSolver.FaceId.FaceIdProtocolCodecFactory; import Com.FirstSolver.FaceId.FaceId_Item; import Com.FirstSolver.FaceId.Utils; import java.io.IOException; import java.net.Inet4Address; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.net.URL; import java.util.Enumeration; import java.util.LinkedList; import java.util.List; import java.util.ResourceBundle; import javafx.collections.FXCollections; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.Button; import javafx.scene.control.ComboBox; import javafx.scene.control.TextArea; import javafx.scene.control.TextField; import org.apache.mina.core.service.IoAcceptor; import org.apache.mina.core.service.IoHandlerAdapter; import org.apache.mina.core.session.AttributeKey; import org.apache.mina.core.session.IoSession; import org.apache.mina.filter.codec.ProtocolCodecFilter; import org.apache.mina.transport.socket.nio.NioSocketAcceptor; public class FXMLDocumentController extends IoHandlerAdapter implements Initializable { // 序列号属性键 private static final AttributeKey KEY_SERIALNUMBER = new AttributeKey(FXMLDocumentController.class, "SerialNumber"); private final String DeviceCharset = "GBK"; private boolean IsServerRunning = false; public IoAcceptor mTcpServer = null; @FXML private ComboBox comboBoxServerIP; @FXML private TextField textFieldServerPort; @FXML private TextField textFieldSecretKey; @FXML private TextArea textAreaRecords; @FXML private Button buttonStartListener; @FXML private void handleButtonClearAction(ActionEvent event) { textAreaRecords.clear(); } @FXML private void handleButtonStartListenerAction(ActionEvent event) throws IOException, Exception { if(IsServerRunning) { if(mTcpServer != null) { mTcpServer.dispose(true); mTcpServer = null; } IsServerRunning = false; buttonStartListener.setText("开始侦听"); } else { // 创建侦听服务器 mTcpServer = new NioSocketAcceptor(); mTcpServer.getFilterChain().addLast("codec", new ProtocolCodecFilter(new FaceIdProtocolCodecFactory(DeviceCharset))); mTcpServer.setHandler(this); mTcpServer.bind(new InetSocketAddress(InetAddress.getByName(comboBoxServerIP.getValue().toString()), Integer.parseInt(textFieldServerPort.getText()))); IsServerRunning = true; buttonStartListener.setText("停止侦听"); } } @Override public void sessionOpened(IoSession session) throws Exception { String SecretKey = textFieldSecretKey.getText(); if (!Utils.IsNullOrEmpty(SecretKey)) { FaceIdProtocolCodecFactory.setEncoderKey(session, SecretKey); FaceIdProtocolCodecFactory.setDecoderKey(session, SecretKey); } } @Override public void messageReceived(IoSession session, Object message) throws Exception { // 显示消息内容 String Answer = message.toString(); textAreaRecords.appendText(Answer + "\r\n"); if(Answer.startsWith("PostRecord")) { // 获取设备序列号 String SerialNumber = FaceId_Item.GetKeyValue(Answer, "sn"); session.setAttribute(KEY_SERIALNUMBER, SerialNumber); // 服务器回应,不上传照片 session.write("Return(result=\"success\" postphoto=\"false\")"); } else if(Answer.startsWith("PostEmployee")) { // 准备上传人员信息 // 服务器回应 session.write("Return(result=\"success\")"); } else if(Answer.startsWith("Record")) { // 获取设备序列号 String SerialNumber = session.getAttribute(KEY_SERIALNUMBER).toString(); // 处理卡点数据 // 服务器回应 session.write("Return(result=\"success\")"); } else if(Answer.startsWith("Employee")) { // 读取人员信息 // 服务器回应 session.write("Return(result=\"success\")"); } else if(Answer.startsWith("GetRequest")) { // 处理命令下发 session.write("GetDeviceInfo()"); // 下发命令:获取设备信息 } else if(Answer.startsWith("Quit")) { // 结束会话 session.close(true); } } @Override public void initialize(URL url, ResourceBundle rb) { // 设置服务器地址 try { List<String> IPList = new LinkedList<>(); Enumeration<NetworkInterface> InterfaceList = NetworkInterface.getNetworkInterfaces(); while (InterfaceList.hasMoreElements()) { NetworkInterface iFace = InterfaceList.nextElement(); if(iFace.isLoopback() || iFace.isVirtual() || iFace.isPointToPoint() || !iFace.isUp()) continue; Enumeration<InetAddress> AddrList = iFace.getInetAddresses(); while (AddrList.hasMoreElements()) { InetAddress address = AddrList.nextElement(); if (address instanceof Inet4Address) { IPList.add(address.getHostAddress()); } } } if (!IPList.isEmpty()) { comboBoxServerIP.setItems(FXCollections.observableList(IPList)); comboBoxServerIP.setValue(IPList.get(0)); } } catch (SocketException ex) { // 异常处理 } } }
FXMLDocument.fxml
<?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.text.*?> <?import javafx.scene.effect.*?> <?import javafx.geometry.*?> <?import java.lang.*?> <?import java.util.*?> <?import javafx.scene.*?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <AnchorPane id="AnchorPane" minWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Splash.FXMLDocumentController"> <children> <GridPane minWidth="600.0"> <columnConstraints> <ColumnConstraints /> </columnConstraints> <rowConstraints> <RowConstraints /> <RowConstraints /> <RowConstraints /> </rowConstraints> <children> <GridPane GridPane.hgrow="ALWAYS" GridPane.rowIndex="0"> <columnConstraints> <ColumnConstraints /> <ColumnConstraints hgrow="ALWAYS" /> </columnConstraints> <rowConstraints> <RowConstraints /> <RowConstraints /> <RowConstraints /> </rowConstraints> <children> <Label text="考勤数据接收服务器地址" GridPane.columnIndex="0" GridPane.halignment="RIGHT" GridPane.rowIndex="0"> <GridPane.margin> <Insets bottom="4.0" left="4.0" right="4.0" top="4.0" /> </GridPane.margin> </Label> <Label text="考勤数据接收服务器端口" GridPane.columnIndex="0" GridPane.halignment="RIGHT" GridPane.rowIndex="1"> <GridPane.margin> <Insets bottom="4.0" left="4.0" right="4.0" top="4.0" /> </GridPane.margin> </Label> <Label text="通信密钥" GridPane.columnIndex="0" GridPane.halignment="RIGHT" GridPane.rowIndex="2"> <GridPane.margin> <Insets bottom="4.0" left="4.0" right="4.0" top="4.0" /> </GridPane.margin> </Label> <ComboBox fx:id="comboBoxServerIP" minWidth="200.0" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" GridPane.rowIndex="0"> <GridPane.margin> <Insets bottom="4.0" left="4.0" right="4.0" top="4.0" /> </GridPane.margin> </ComboBox> <TextField fx:id="textFieldServerPort" text="9900" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" GridPane.rowIndex="1"> <GridPane.margin> <Insets bottom="4.0" left="4.0" right="4.0" top="4.0" /> </GridPane.margin> </TextField> <TextField fx:id="textFieldSecretKey" text="" GridPane.columnIndex="1" GridPane.hgrow="ALWAYS" GridPane.rowIndex="2" GridPane.vgrow="ALWAYS"> <GridPane.margin> <Insets bottom="4.0" left="4.0" right="4.0" top="4.0" /> </GridPane.margin> </TextField> </children> </GridPane> <GridPane GridPane.rowIndex="1"> <columnConstraints> <ColumnConstraints /> <ColumnConstraints /> </columnConstraints> <rowConstraints> <RowConstraints /> </rowConstraints> <children> <Button fx:id="buttonClear" minHeight="40.0" minWidth="80.0" onAction="#handleButtonClearAction" text="清空" GridPane.columnIndex="0" GridPane.halignment="LEFT" GridPane.hgrow="ALWAYS"> <GridPane.margin> <Insets bottom="4.0" left="4.0" right="4.0" top="4.0" /> </GridPane.margin> </Button> <Button fx:id="buttonStartListener" minHeight="40.0" minWidth="80.0" onAction="#handleButtonStartListenerAction" text="开启侦听" GridPane.columnIndex="1" GridPane.halignment="RIGHT" GridPane.hgrow="ALWAYS"> <GridPane.margin> <Insets bottom="4.0" left="4.0" right="4.0" top="4.0" /> </GridPane.margin> </Button> </children> </GridPane> <TextArea fx:id="textAreaRecords" editable="false" minHeight="400.0" minWidth="600.0" wrapText="true" GridPane.hgrow="ALWAYS" GridPane.rowIndex="2" GridPane.vgrow="ALWAYS"> <GridPane.margin> <Insets bottom="4.0" left="4.0" right="4.0" top="4.0" /> </GridPane.margin> </TextArea> </children> </GridPane> </children> </AnchorPane>