Java:汉王人证通/人脸仪数据接收示例

同系列文章

演示程序界面

源代码
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>

Comments are closed.