同系列文章
源代码
build.gradle
/* 开发环境: jdk 8u152 IntelliJ IDEA 2017.2.5 Gradle 4.3 Gradle 命令集合 gradle clean gradle build gradle run gradle uploadArchives 参考资料: Gradle Build Language Reference https://docs.gradle.org/4.3/dsl/ */ group 'Com.FirstSolver' version '1.0.0.1' apply plugin: 'application' // 打包成 zip 和 tar apply plugin: 'java' // 使用 java 插件 sourceCompatibility = 1.8 // JDK8 targetCompatibility = 1.8 // JDK8 [compileJava, compileTestJava]*.options*.encoding = 'UTF-8' repositories { // 阿里云 maven 镜像 maven { url 'http://maven.aliyun.com/mvn/repository/' } // mavenCentral() } // 声明项目依赖 dependencies { // 编译项目源代码时依赖 compile "org.slf4j:slf4j-api:1.7.25" compile "org.slf4j:slf4j-simple:1.7.25" compile "com.alibaba:fastjson:1.2.41" compile "org.apache.mina:mina-core:2.0.16" // 本地依赖 dependencies { compile fileTree(dir:'libs',include:['*.jar'])} } // 指定 application 主类 mainClassName = 'Splash.MinaTcpServerDemo' // 输出 jar 文件名定义 jar { baseName = 'MinaTcpServerDemo' version = '1.0.0.1' manifest { // 设置 jar 主类 attributes 'Main-Class': 'Splash.MinaTcpServerDemo' } // 将引用的包打入 jar 包 // from configuration.compile.collect { zipTree it} } // 版本发布地址 uploadArchives { repositories { flatDir { dirs 'repos' } } } // 指定资源文件源目录 sourceSets { main { resources { srcDirs = ["src/main/java"] // 资源文件和 .java 文件放置在同一个目录下 excludes = ["**/*.java"] } } } // 指定资源文件目标目录 processResources { into "$buildDir" // 资源文件和 .class 文件打包到同一个目录下 } /* // 打包授权文件 task copyLicense { outputs.file new File("$buildDir/LICENSE") doLast { copy { from "LICENSE" into "$buildDir" } } } applicationDistribution.from(copyLicense) { into "" } */
MinaTcpServerDemo.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 MinaTcpServerDemo extends Application { @Override public void start(Stage stage) throws Exception { FXMLLoader loader = new FXMLLoader(getClass().getResource("MinaTcpServerDemo.fxml")); Parent root = loader.load(); Scene scene = new Scene(root); stage.setScene(scene); // 设置窗体标题 stage.setTitle("汉王人证通/人脸仪数据接收示例 By 秦建辉"); // 设置窗体图标 stage.getIcons().add(new Image(getClass().getResourceAsStream("FireEyes.png"))); // 设置到屏幕中心 stage.centerOnScreen(); // 设置窗口关闭处理函数 stage.setOnCloseRequest((WindowEvent e) -> { try { MinaTcpServerDemoController controller = loader.getController(); controller.close(); } catch (Exception exception) { // 忽视异常 } }); // 显示窗体 stage.show(); } public static void main(String[] args) { launch(args); } }
MinaTcpServerDemoController.java
/* ---------------------------------------------------------- * 文件名称:MinaTcpServerDemoController.java * * 作者:秦建辉 * * 微信:splashcn * * 博客:http://www.firstsolver.com/wordpress/ * * 开发环境: * IntelliJ IDEA 2017.2.5 * JDK 8u152 * * 版本历史: * V1.0 2017年12月04日 * 汉王人证通/人脸仪通信SDK-服务器端数据接收演示示例 ------------------------------------------------------------ */ package Splash; import Com.FirstSolver.Splash.COMMAND_PCIR_TYPE; import Com.FirstSolver.Splash.FaceReaderProtocolCodecFactory; import Com.FirstSolver.Splash.PARAM_REPLY_PCIR_TYPE; import Com.FirstSolver.Splash.REPLY_PCIR_TYPE; import Com.FirstSolver.Splash.SM2UserInformation; import com.alibaba.fastjson.JSON; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.util.Enumeration; import java.util.LinkedList; import java.util.List; import javafx.collections.FXCollections; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.control.CheckBox; 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.IoSession; import org.apache.mina.filter.codec.ProtocolCodecFilter; import org.apache.mina.transport.socket.nio.NioSocketAcceptor; public class MinaTcpServerDemoController extends IoHandlerAdapter implements AutoCloseable { // 用于密钥交换的服务器端证书 private final SM2UserInformation SM2ServerInfo = new SM2UserInformation( "Com.FirstSolver.Splash", "DE078F1052116A4F706288AB9EC8E10009EAA510B68B68D917AA63F3D07B3876", "59C9ADD36106ABD5D26CCF7F92D8BBAD33A0C55D0CF9F644CF97D340EDDFB949", "D781D3BBD4F1B8263DBF68613CF7E830BBD6CC569740303D4DDEAEB5216AE639" ); private boolean IsServerRunning = false; private IoAcceptor mTcpServer = null; @FXML private ComboBox comboBoxServerIP; @FXML private TextField textFieldServerPort; @FXML private CheckBox checkBoxPassiveEncryption; @FXML private TextArea textAreaRecords; @FXML private Button buttonStartListener; // 初始化 public void initialize() { // 设置服务器地址 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) || (address instanceof Inet6Address)) { IPList.add(address.getHostAddress()); } } } if (!IPList.isEmpty()) { comboBoxServerIP.setItems(FXCollections.observableList(IPList)); comboBoxServerIP.setValue(IPList.get(0)); } } catch (SocketException ex) { // 异常处理 } } @Override public void close() throws Exception { if (mTcpServer != null) { mTcpServer.dispose(true); mTcpServer = null; } } @FXML private void handleButtonClearAction(ActionEvent event) { textAreaRecords.clear(); } @FXML private void handleButtonStartListenerAction(ActionEvent event) throws Exception { if (IsServerRunning) { close(); IsServerRunning = false; buttonStartListener.setText("开始侦听"); } else { // 创建侦听服务器 mTcpServer = new NioSocketAcceptor(); mTcpServer.getFilterChain().addLast("codec", new ProtocolCodecFilter(new FaceReaderProtocolCodecFactory(checkBoxPassiveEncryption.isSelected(), null))); 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 { FaceReaderProtocolCodecFactory.EnablePassiveEncryption(session, true, SM2ServerInfo); } @Override public void messageReceived(IoSession session, Object message) throws Exception { // 显示消息内容 textAreaRecords.appendText(message.toString() + "\r\n"); COMMAND_PCIR_TYPE A = JSON.parseObject(message.toString(), COMMAND_PCIR_TYPE.class); if ("RecogniseResult".equals(A.COMMAND)) { // 注意:保存数据然后进行回复 REPLY_PCIR_TYPE M = new REPLY_PCIR_TYPE(); M.RETURN = "RecogniseResult"; M.PARAM = new PARAM_REPLY_PCIR_TYPE(); M.PARAM.result = "success"; session.write(JSON.toJSONString(M)); } } }
MinaTcpServerDemo.fxml
<?xml version="1.0" encoding="UTF-8"?> <?import javafx.geometry.*?> <?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.MinaTcpServerDemoController"> <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> <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> <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" editable="false" text="9910" 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> </children> </GridPane> <GridPane GridPane.rowIndex="1"> <columnConstraints> <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> <CheckBox fx:id="checkBoxPassiveEncryption" text="强制通信加密?" GridPane.columnIndex="1" /> <Button fx:id="buttonStartListener" minHeight="40.0" minWidth="80.0" onAction="#handleButtonStartListenerAction" text="开启侦听" GridPane.columnIndex="2" 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>