JavaアプレットからCOMポートにアクセスする

みなさんこんにちは。 少し前に発生した1つの問題の解決策を共有したいと思います。 それは、ユーザーのコンピューターのCOMポートを介して、Webサービスに何らかのデバイス(私の場合はカードリーダー)にアクセスして情報を交換する機会を与える必要があるという事実にありました。 これを行うために、Javaアプレットを使用することが決定されましたが、実装の過程でいくつかの困難がありました。その解決策を記事で説明します。 インターネットでは、問題を解決する方法に関する「最初から最後まで」の単一のガイドを見つけることができなかったので、誰かが私の記事を数時間節約できることを願っています。



問題の声明



comポートへの情報の読み取りと書き込みが可能なサイトからブラウザーによってロードされたJavaアプレットを作成する必要があります。 この場合の主な要件は、ユーザーにとっての使いやすさ、複雑な設定がないこと、そして可能であればユーザーのシステムに追加のライブラリまたはプログラムをインストールする必要があることです。

ユーザーコンピューターの要件:
1. Microsoft Windows XP、Vista、7
2. Javaアプレットをサポートする最新のブラウザ。IE、Firefoxが主な重点
3. JRE1.6をインストールしました。

JavaアプレットからCOMポートにアクセスするための利用可能なメソッドの概要



ご存知のように、標準JREにはCOMポートへのアクセスを許可するクラスやメソッドは含まれていません。 最も人気のある2つの外部ライブラリであるjavax.commRXTXを見つけました 。 それらに関する情報を見た後、RXTXを使用することにしました。 javax.commは現在開発されていません。さらに、RXTXにはサポートされているオペレーティングシステムの範囲が広いため、将来役立つかもしれません。

両方のライブラリは、ネイティブライブラリを使用してCOMポートにアクセスします。 RXTXの場合、これはrxtxSerial.dllライブラリです。

COMポートを操作するための機能に関しては、両方のライブラリに同じクラスのセットがあります。

COMポートを操作するためのテストアプレット



アプレットのコードを提供します。これを「配布」します。 このアプレットは、当然私のプロジェクトで使用したものではなく、この記事専用に作成しました。 だから:

package cardreaders;

import java.applet.Applet;
import java.awt.Graphics;

import java.net.URL;
import java.io.InputStream;
import java.io.File;
import java.io.FileOutputStream;

import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;

public class CardReader extends Applet {

Graphics gg;
int pos;

public void init() {
// TODO start asynchronous download of heavy resources
}

public void paint(Graphics g)
{
gg = g;
pos = 14;

text( "INITIALIZATION..." );

java.util.Enumeration<CommPortIdentifier> portEnum = CommPortIdentifier.getPortIdentifiers();
while ( portEnum.hasMoreElements() )
{
CommPortIdentifier portIdentifier = portEnum.nextElement();
if ( portIdentifier.getPortType() == CommPortIdentifier.PORT_SERIAL)
text( "FOUND PORT " + portIdentifier.getName());
}
}

public void text(String t)
{
gg.drawString(t, 10, pos);
pos += 14;
}
}

* This source code was highlighted with Source Code Highlighter .
package cardreaders;

import java.applet.Applet;
import java.awt.Graphics;

import java.net.URL;
import java.io.InputStream;
import java.io.File;
import java.io.FileOutputStream;

import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;

public class CardReader extends Applet {

Graphics gg;
int pos;

public void init() {
// TODO start asynchronous download of heavy resources
}

public void paint(Graphics g)
{
gg = g;
pos = 14;

text( "INITIALIZATION..." );

java.util.Enumeration<CommPortIdentifier> portEnum = CommPortIdentifier.getPortIdentifiers();
while ( portEnum.hasMoreElements() )
{
CommPortIdentifier portIdentifier = portEnum.nextElement();
if ( portIdentifier.getPortType() == CommPortIdentifier.PORT_SERIAL)
text( "FOUND PORT " + portIdentifier.getName());
}
}

public void text(String t)
{
gg.drawString(t, 10, pos);
pos += 14;
}
}

* This source code was highlighted with Source Code Highlighter .
package cardreaders;

import java.applet.Applet;
import java.awt.Graphics;

import java.net.URL;
import java.io.InputStream;
import java.io.File;
import java.io.FileOutputStream;

import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;

public class CardReader extends Applet {

Graphics gg;
int pos;

public void init() {
// TODO start asynchronous download of heavy resources
}

public void paint(Graphics g)
{
gg = g;
pos = 14;

text( "INITIALIZATION..." );

java.util.Enumeration<CommPortIdentifier> portEnum = CommPortIdentifier.getPortIdentifiers();
while ( portEnum.hasMoreElements() )
{
CommPortIdentifier portIdentifier = portEnum.nextElement();
if ( portIdentifier.getPortType() == CommPortIdentifier.PORT_SERIAL)
text( "FOUND PORT " + portIdentifier.getName());
}
}

public void text(String t)
{
gg.drawString(t, 10, pos);
pos += 14;
}
}

* This source code was highlighted with Source Code Highlighter .


このコードは、システムで見つかったすべてのCOMポートのリストを表示するだけです(これにより、アプレットが再描画されるたびにこの操作が実行されます)。

RXTXライブラリーの追加



問題の声明に基づいて、ユーザーにとってアプレットをできるだけ単純にする必要があります。 また、アプレットとRXTXライブラリの両方を含む単一のjarファイルよりも簡単なものはありません。 ライブラリをjarに統合するには、まずソースコードをダウンロードします

srcフォルダーからダウンロードしたアーカイブで、すべての.javaファイルを取得してプロジェクトに追加します。 私のように、NetBeansを使用している場合は、プロジェクトのsrc-folderにgnu / ioディレクトリ構造を作成するだけで、そこに上記のファイルを配置します。

1つのアプレットでコンパイルした後、コードとRXTXライブラリはすぐにマージされます。

rxtxSerial.dllネイティブライブラリの追加



上記のように、RXTXはネイティブライブラリrxtxSerial.dllを使用して、WindowsのCOMポートにアクセスします。 このライブラリーは、 System.loadLibrary()メソッドを介してRXTXクラスとともにロードされます。
したがって、アプレットを機能させるには、rxtxSerial.dllライブラリをユーザーのコンピューター上、およびRXTXがロードできるディレクターの1つに配置する必要があります。 java.library.pathに登録されているディレクトリ内。 そのようなディレクトリの1つは、JREインストールフォルダ内のbinディレクトリです。

最も明白な方法は、指定されたディレクトリにrxtxSerial.dllライブラリを事前インストールすることですが、これにはユーザーからの追加のアクションが必要であるため(常に修飾されていない)、別のソリューションが適用されました。

dllライブラリを含む任意のファイルを、リソースとしてjarファイルに含めることができます。 NetBeansでこれを行うには、アプレットの.javaファイルがあるディレクトリにリソースフォルダを作成し、そこにrxtxSerial.dllを配置します。 しかし、今それを接続する方法は? ここで説明されている方法が助けになります。

説明されているメソッドを考えると、アプレットのソースコードは次のようになります。

package cardreaders;

import java.applet.Applet;
import java.awt.Graphics;

import java.net.URL;
import java.io.InputStream;
import java.io.File;
import java.io.FileOutputStream;

import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;

public class CardReader extends Applet {

Graphics gg;
int pos;

static {
try {
System. out .println( "CardReader {}" );
/* Get DLL from JAR file */
URL res = CardReader. class .getResource( "resources/rxtxSerial.dll" );
InputStream is = res.openStream();

/* Define the destination file */
File dll = File.createTempFile( "rxtxSerial" , ".dll" );

/* Open the destination file */
FileOutputStream fos = new FileOutputStream(dll);

/* Copy the DLL fro the JAR to the filesystem */
byte [] array = new byte [1024];
for ( int i= is .read(array);
i!=-1;
i= is .read(array)
) {
fos.write(array,0,i);
}

/* Close all streams */
fos.close();
is .close();

/* Load the DLL from the filesystem */
System.load(dll.getAbsolutePath());
System. out .println( "CardReader loaded" );
}
catch (Throwable e)
{
e.printStackTrace();
}
}

public void init() {
// TODO start asynchronous download of heavy resources
}

public void paint(Graphics g)
{
gg = g;
pos = 14;

text( "INITIALIZATION..." );

java.util.Enumeration<CommPortIdentifier> portEnum = CommPortIdentifier.getPortIdentifiers();
while ( portEnum.hasMoreElements() )
{
CommPortIdentifier portIdentifier = portEnum.nextElement();
if ( portIdentifier.getPortType() == CommPortIdentifier.PORT_SERIAL)
text( "FOUND PORT " + portIdentifier.getName());
}
}

public void text(String t)
{
gg.drawString(t, 10, pos);
pos += 14;
}
}

* This source code was highlighted with Source Code Highlighter .
package cardreaders;

import java.applet.Applet;
import java.awt.Graphics;

import java.net.URL;
import java.io.InputStream;
import java.io.File;
import java.io.FileOutputStream;

import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;

public class CardReader extends Applet {

Graphics gg;
int pos;

static {
try {
System. out .println( "CardReader {}" );
/* Get DLL from JAR file */
URL res = CardReader. class .getResource( "resources/rxtxSerial.dll" );
InputStream is = res.openStream();

/* Define the destination file */
File dll = File.createTempFile( "rxtxSerial" , ".dll" );

/* Open the destination file */
FileOutputStream fos = new FileOutputStream(dll);

/* Copy the DLL fro the JAR to the filesystem */
byte [] array = new byte [1024];
for ( int i= is .read(array);
i!=-1;
i= is .read(array)
) {
fos.write(array,0,i);
}

/* Close all streams */
fos.close();
is .close();

/* Load the DLL from the filesystem */
System.load(dll.getAbsolutePath());
System. out .println( "CardReader loaded" );
}
catch (Throwable e)
{
e.printStackTrace();
}
}

public void init() {
// TODO start asynchronous download of heavy resources
}

public void paint(Graphics g)
{
gg = g;
pos = 14;

text( "INITIALIZATION..." );

java.util.Enumeration<CommPortIdentifier> portEnum = CommPortIdentifier.getPortIdentifiers();
while ( portEnum.hasMoreElements() )
{
CommPortIdentifier portIdentifier = portEnum.nextElement();
if ( portIdentifier.getPortType() == CommPortIdentifier.PORT_SERIAL)
text( "FOUND PORT " + portIdentifier.getName());
}
}

public void text(String t)
{
gg.drawString(t, 10, pos);
pos += 14;
}
}

* This source code was highlighted with Source Code Highlighter .
package cardreaders;

import java.applet.Applet;
import java.awt.Graphics;

import java.net.URL;
import java.io.InputStream;
import java.io.File;
import java.io.FileOutputStream;

import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;

public class CardReader extends Applet {

Graphics gg;
int pos;

static {
try {
System. out .println( "CardReader {}" );
/* Get DLL from JAR file */
URL res = CardReader. class .getResource( "resources/rxtxSerial.dll" );
InputStream is = res.openStream();

/* Define the destination file */
File dll = File.createTempFile( "rxtxSerial" , ".dll" );

/* Open the destination file */
FileOutputStream fos = new FileOutputStream(dll);

/* Copy the DLL fro the JAR to the filesystem */
byte [] array = new byte [1024];
for ( int i= is .read(array);
i!=-1;
i= is .read(array)
) {
fos.write(array,0,i);
}

/* Close all streams */
fos.close();
is .close();

/* Load the DLL from the filesystem */
System.load(dll.getAbsolutePath());
System. out .println( "CardReader loaded" );
}
catch (Throwable e)
{
e.printStackTrace();
}
}

public void init() {
// TODO start asynchronous download of heavy resources
}

public void paint(Graphics g)
{
gg = g;
pos = 14;

text( "INITIALIZATION..." );

java.util.Enumeration<CommPortIdentifier> portEnum = CommPortIdentifier.getPortIdentifiers();
while ( portEnum.hasMoreElements() )
{
CommPortIdentifier portIdentifier = portEnum.nextElement();
if ( portIdentifier.getPortType() == CommPortIdentifier.PORT_SERIAL)
text( "FOUND PORT " + portIdentifier.getName());
}
}

public void text(String t)
{
gg.drawString(t, 10, pos);
pos += 14;
}
}

* This source code was highlighted with Source Code Highlighter .



しかし、それだけではありません。 RXTXライブラリーは、 System.loadLibrary()を使用してrxtxSerial.dllをロードしようとしていますが、もちろん失敗します。 この問題を解決するために、java.library.pathディレクトリの1つにdllを保存することは可能ですが、ソースコードでは、RXTXはライブラリのロード行をコメントアウトしました(まだCardReaderクラスでロードされています)。

アプレット署名



アプレットはユーザーのコンピューターでファイル操作を実行しようとしているため、デジタル署名が必要です。 インターネットでこれを行う方法については多くの指示があります 。たとえば、 ここに記載されているとおりに行うことができます

まとめ



私たちから配布されたアプレットは、COMポートを操作する機会を得たと同時に、必要なものはすべて単一のjarファイルに含まれています。 ユーザーのコンピューターにライブラリーは必要ありません。 ユーザーはアプレットのあるページに移動するだけです(この場合、表示されるウィンドウでアプレットを起動する許可を確認します)。

PS記事を適切なブログに転送するのに十分なカルマがありません。

Source: https://habr.com/ru/post/J71072/


All Articles