只是想从 Java Applet 将数据写入串行端口?

2024-04-13

几天来我一直在抓狂地想弄清楚为什么这似乎永远不起作用!首先,这是我的配置:

Windows 7 x64
JDK 7 x86
JRE 7 x86
火狐 x86
由 Thin 提供服务的 Rails 3
Java 设置使得“下一代插件”不处于活动状态(但它会以某种方式不断重新激活自己!!!)

起初我尝试了 RXTX 但我不断收到“未找到类”错误。我现在已经转向 winjcom。我现在得到的错误是这样的:java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "loadLibrary.winjcom").

我还注意到我的服务器日志根据我使用的浏览器而有所不同。如果我使用 Firefox,则当浏览器尝试加载小程序时,不会显示任何 GET 日志(即,当小程序加载失败时,不会再下载任何内容)。如果我在 IE9 中尝试,除了“PortWriter.class”GET 日志之外,所有日志都在那里……这意味着由于某种原因它没有被检索。

当我避免使用 JNLP 时,我会弹出安全警告,并且没有任何错误...当然,运行“发送”方法时出现的安全访问错误除外。然而,当我使用 JNLP 时,IE 加载它很好,并且仍然给出错误......但是当我关闭它时崩溃(我必须结束 iexplorer 进程)。 Firefox 只是不加载页面...它停在进度条上。

UPDATE- 我的情况是,如果我通过java的安全策略文件绕过安全性,小程序就会工作。但是,JNLP 无法工作 - 我认为这就是为什么在运行小程序标签时通常会发生安全错误的原因。当我直接访问 JNLP 文件时,出现错误,指出找不到“PortWriter”类。我的罐子有问题吗?我注意到其他 jar 具有其文件夹布局,使得目录结构与其包布局完全匹配(例如,如果包是 com.myname.serialport.PortWriter,则为“com\myname\serialport\PortWriter.jar”) 。但是,我的 jar 布局复制了我的物理文件夹布局(例如,“D:\Files\Websites\pos\assets\java\PortWriter.jar”)。这是导致错误的原因吗?我已经手动更改了 jar 内容(包括清单文件)以匹配根目录,但也许我做错了什么。我还更新了此问题中的 JNLP 布局,以说明我的最新更改,这些更改已由 JaNeLa 验证。

这是我的 .java 文件:

import com.engidea.comm.CommPort;
import com.engidea.comm.CommPortIdentifier;
import com.engidea.comm.SerialPort;
import com.engidea.comm.SerialPortEvent;
import com.engidea.comm.SerialPortEventListener;
import com.engidea.win32jcom.WinjcomIdentifier;
import java.io.*;
import java.util.Iterator;
import java.util.List;
import java.applet.*;
import java.security.*;

/*
  WinJcom is a native interface to serial ports in java.
  Copyright 2007 by Damiano Bolla, [email protected] /cdn-cgi/l/email-protection

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.
  This can be used with commercial products and you are not obliged 
  to share your work with anybody.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Library General Public License for more details.

  You should have received a copy of the GNU Library General Public
  License along with this library; if not, write to the Free
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/**
 * Simple class that can list system ports and allow IO
 */
public class PortWriter extends Applet
  {

  private CommPortIdentifier portIdentifier;
  private SerialPort serport;

  public void init () {System.out.println("Booting...");}
  @SuppressWarnings("unchecked")
  public void Sends(String port, String message) throws Exception
    {

    final String com_port = port;
    final String send_message = message;

    AccessController.doPrivileged(new PrivilegedAction() {
    public Object run() {

        System.out.println("Begin...");
        portIdentifier = new WinjcomIdentifier(0);
        System.out.println("Selecting Port...");
        selectComport(com_port);
        new Thread(new PortReader()).start();
        System.out.println("Sending...");
        typeSendBytes(send_message);

    return true;}
    });
    }

  private void typeSendBytes( String message )
    {  
    try
      {
      System.out.println("Trying To Send...");
      BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
      String aStr = "";
      while (aStr != null) 
        {
        aStr = message + "\r\n";
        // WARNING: be careful, you shoulod select the encoding !
        // This will timeout if you have FLOW CONTROL and theline is stuck !
        byte []buf = aStr.getBytes();
        serport.write(buf,0,buf.length );
        }
      }
    catch ( Exception exc )
      {
      exc.printStackTrace();
      }
    }

  private SerialPort openPort ( String portName )
    {
    try 
      {
      CommPort aPort = portIdentifier.getCommPort(portName);
      aPort.open();
      return (SerialPort)aPort;
      }
    catch ( Exception exc )
      {
      System.out.println("exc="+exc);
      exc.printStackTrace();
      }

    return null;
    }

  private void selectComport ( String portName )
    {
    try 
      {
      serport = openPort(portName);
      serport.setSerialPortParams(9600,8, SerialPort.STOPBITS_2, SerialPort.PARITY_NONE);
      serport.enableReceiveTimeout(20000);
      serport.setEventListener(new EventListener());

      serport.notifyOnDSR(true);
      serport.notifyOnCarrierDetect(true);
      serport.notifyOnCTS(true);
      } 
    catch (IOException exc) 
      {
      System.out.println("Exc="+exc);
      exc.printStackTrace();
      }
    }


private final class EventListener implements SerialPortEventListener
  {
  public void serialEvent(SerialPortEvent ev)
    {
    System.out.println("Got event="+ev);
    }
  }


private final class PortReader implements Runnable
  {
  public void run()
    {
    try
      {
      // This will timeout if nothing is received in the specified time.
      byte []buff = new byte[1];
      while (  serport.read(buff,0,buff.length) > 0 )
        {
        // NOTE: you should be checking the encoding !
        System.out.print(new String(buff));
        }
      }
    catch ( Exception exc )
      {
      exc.printStackTrace();
      }
    }
  }


}

...和我的 JNLP 文件:

<?xml version="1.0" encoding="utf-8"?>
<jnlp codebase="http://localhost/assets/" href="PortWriter.jnlp">
    <information>
        <title>RS232 Communication Applet</title>
        <vendor>My Company</vendor>
        <description>RS232 Applet for communicating with POS Display Pole</description>
        <offline-allowed />
    </information>
    <security>
    <all-permissions/>
    </security>
    <update check="background" />
    <resources>
    <jar href="PortWriter.jar" part="com" main="true" />
    <jar href="winjcom.jar" part="com" />
    <nativelib href="jcomport.jar" part="com" />
    </resources>
    <applet-desc
         name="RS232 Communication Applet"
         main-class="PortWriter"
         width="1" height="1" />
</jnlp>

...和我的 HTML:

<applet id="SerialPort" width="1" height="1" codebase="/assets/" code="PortWriter.class" archive="PortWriter.jar">
        <param name="jnlp_href" value="PortWriter.jnlp" />
    </applet>

我如何让这些东西发挥作用?我是一个 Java 新手,但我只想得到一个可行的解决方案。这是我在 Rails 中制作的公司 POS。

最终文件为:

在 /assets/java/ 的服务器上:
1)jcomport.jar(未签名...)
2) PortWriter.class(以及所有关联的类文件)
3)PortWriter.jar
4)PortWriter.jnlp

在本地硬盘上的%java home%/
1)/lib/ext/jcomport.jar(未签名)
2)/bin/winjcom.dll


好吧,神圣的永恒的废话。当我最初决定关闭 Java 控制台中的“下一代插件”选项以使我的小程序在 Firefox 中运行时,我无意中禁用了 JNLP。我只是通过“尝试一些东西......任何东西”的最后手段才发现这一点。重新打开后,jnlp在IE中完美运行。 Firefox 当然是我的 POS 需要使用的浏览器(因为有 jsprint 插件)...但它当然不起作用。它不会下载 JNLP 文件,如果是,则说明出现了问题。它只是挂着。没有显示任何内容,但我的服务器日志显示正在下载所有图像和 html。但不是 jnlp 或任何 jar 文件。所以要么关闭下一代插件就会出现安全问题,要么打开它就无法使用Firefox。我可以做些什么而无需更改策略文件吗?

FWIW,我会将其标记为解决方案,并在其他地方启动关于我最新问题的新线程。以下是让这该死的东西正常工作所需的一切的最新内容(Firefox 除外):


首先,确保在 Windows 中设置 PATH 和 CLASSPATH 环境变量。路径应该是C:\Program Files (x86)\Java\jdk1.7.0_01\bin(如果你有不同的版本,请更改为你自己的jdk目录)。 CLASSPATH 应该位于您创建 Java 类的位置。我的是D:\Files\Java\Classes。如果不设置 PATH 变量,则无法从任何目录运行“java”、“javac”或“jarsigner”。你必须在jdk的bin目录中。为您的用户帐户创建这些变量...而不是系统(因为可能已经有像这样命名的环境变量)。


接下来,为了签署您的小程序,请创建您的密钥库:

keytool -genkey -dname "cn=My Company, ou=Whatever, o=My Company, c=CA" -alias mycompany -keystore "D:\Files\Java\Certificates\certfile" -storepass MY_PASSWORD -validity 180

查看在线教程,确保您了解每个参数的用途。


我制作的 .BAT 文件是为了从 .java 文件轻松创建必要的 .jar 文件并对其进行签名。只需创建快捷方式或运行 .bat 文件,而不必每次更改 .java 文件时都手动执行此操作

@echo off

set certificate_password=MY_PASSWORD
set certificate_alias=myalias
set package=mycompany
set class_file=PortWriter
rem class_path is where my .java file resides (...\java\Classes\mycompany\PortWriter.java)
set class_path=D:\Files\Java\Classes
set certificate_loc=D:\Files\Java\Certificates\certfile
rem final_loc is the assets folder where the .jar file will reside
set final_loc=D:\Files\Websites\pos\app\assets\java

cd "%class_path%"
rem Change to "D:" otherwise Windows won't *actually* change directories from C: to D:
D:

javac -Xlint:unchecked "%package%\%class_file%.java"
pause
jar cfm "%final_loc%\%class_file%.jar" "%package%\Mainfest.txt" "%package%\*.class"
pause
del "%package%\*.class"
jarsigner -keystore "%certificate_loc%" -storepass %certificate_password% "%final_loc%\%class_file%.jar" %certificate_alias%
pause

Mainfest.txt(确保“Main-Class”行后面有一个回车符。如果您想在 JNLP 中指定主类,则不需要此 Manifest.txt 文件。): 主类:mycompany.PortWriter


Java 文件:

package mycompany;

import com.engidea.comm.CommPort;
import com.engidea.comm.CommPortIdentifier;
import com.engidea.comm.SerialPort;
import com.engidea.comm.SerialPortEvent;
import com.engidea.comm.SerialPortEventListener;
import com.engidea.win32jcom.WinjcomIdentifier;
import java.io.*;
import java.util.Iterator;
import java.util.List;
import java.applet.*;
import java.security.*;

/*
  WinJcom is a native interface to serial ports in java.
  Copyright 2007 by Damiano Bolla, [email protected] /cdn-cgi/l/email-protection

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.
  This can be used with commercial products and you are not obliged 
  to share your work with anybody.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Library General Public License for more details.

  You should have received a copy of the GNU Library General Public
  License along with this library; if not, write to the Free
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/**
 * Simple class that can list system ports and allow IO
 */
public class PortWriter extends Applet {

    private CommPortIdentifier portIdentifier;
    private SerialPort serport;

    public static void main(String[] args) {}
    public void init() {
    System.out.println("Booting RS232 Java Applet...");
    }

    public void Sends(String port, String message) {

    final String com_port = port;
    final String send_message = message;

    AccessController.doPrivileged(new PrivilegedAction<Object>() {
        public Object run() {

        try {
            portIdentifier = new WinjcomIdentifier(0);
            try {
            selectComport(com_port);
            new Thread(new PortReader()).start();
            try {
                System.out.println(com_port + ": " + send_message);
                typeSendBytes(send_message);
            } catch (Exception e) {
                System.out.println("Couldn't send data to " + com_port);
            }
            } catch (IOException e) {
            System.out.println("Couldn't connect to " + com_port);
            }
        } catch (Exception e) {
            System.out.println(e);
        }
        return null;
        }
    });
    }

    private void typeSendBytes( String message ) {  
    try {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        String aStr = "";
        if (aStr != null) {
        aStr = message + "\r\n";
        // WARNING: be careful, you shoulod select the encoding !
        // This will timeout if you have FLOW CONTROL and theline is stuck !
        byte []buf = aStr.getBytes();
        serport.write(buf,0,buf.length);
        }
    } catch ( Exception exc ) {
        exc.printStackTrace();
    }
    }

    private SerialPort openPort ( String portName ) throws IOException {
    try {
        CommPort aPort = portIdentifier.getCommPort(portName);
        aPort.open();
        return (SerialPort)aPort;
    }
    catch ( Exception exc ) {
        //System.out.println("exc="+exc);
        //exc.printStackTrace();
        throw exc;
    }
    }

    private void selectComport ( String portName ) throws IOException {

    try {
        serport = openPort(portName);
        serport.setSerialPortParams(9600,8, SerialPort.STOPBITS_2, SerialPort.PARITY_NONE);
        serport.enableReceiveTimeout(20000);
        serport.setEventListener(new EventListener());

        serport.notifyOnDSR(true);
        serport.notifyOnCarrierDetect(true);
        serport.notifyOnCTS(true);
    } catch (IOException exc) {
        //System.out.println("Exc="+exc);
        //exc.printStackTrace();
        throw exc;
    }

    }


private final class EventListener implements SerialPortEventListener
  {
  public void serialEvent(SerialPortEvent ev)
    {
    System.out.println("Got event="+ev);
    }
  }


private final class PortReader implements Runnable
  {
  public void run()
    {
    try
      {
      // This will timeout if nothing is received in the specified time.
      byte []buff = new byte[1];
      while (  serport.read(buff,0,buff.length) > 0 )
        {
        // NOTE: you should be checking the encoding !
        System.out.print(new String(buff));
        }
      }
    catch ( Exception exc )
      {
      exc.printStackTrace();
      }
    }
  }


}

JNLP 文件:

<?xml version="1.0" encoding="utf-8"?>
<jnlp>
    <information>
        <title>RS232 Communication Applet</title>
        <vendor>My Company</vendor>
        <description>RS232 Applet for communicating with POS Display Pole</description>
        <offline-allowed />
    </information>
    <security>
    <all-permissions/>
    </security>
    <resources>
    <j2se version="1.7.0+" />
    <jar href="PortWriter.jar" part="com" main="true" />
    <jar href="jcomport.jar" part="com" />
    <nativelib href="winjcom.jar" part="com" />
    </resources>
    <applet-desc
         name="RS232 Communication Applet"
         main-class="mycompany.PortWriter"
         width="1" height="1" />
</jnlp>

HTML:

<applet id="SerialPort" width="1" height="1" codebase="/assets/">
    <param name="jnlp_href" value="PortWriter.jnlp">
</applet>

我已经获取了 winjcom.dll 文件并将其“jarred”并使用相同的证书文件对其进行了签名。我确保 cd 到 winjcom 所在的同一目录,以便它位于 .jar 文件的根目录中。我还获取了 winjcom 作者提供的 jcomport.jar 文件,并使用相同的 certfile 对其进行了重新签名。话虽这么说,所有 .jar 文件都已由同一证书文件签名。

我希望这可以帮助那些和我一样遇到麻烦的人。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

只是想从 Java Applet 将数据写入串行端口? 的相关文章

随机推荐