仅尝试从Java小程序将数据写入串行端口?

3
我已经苦恼了好几天,试图找出为什么这似乎从来没有起作用!首先,这是我的配置:
Windows 7 x64 JDK 7 x86 JRE 7 x86 Firefox x86 Rails 3由Thin提供服务 Java设置是"下一代插件"未激活(但它总是以某种方式重新激活自己!!!)
起初我尝试使用RXTX,但我一直收到“未找到类”错误。现在我转向winjcom。我现在得到的错误是:java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "loadLibrary.winjcom")。
我还注意到我的服务器日志因我使用的浏览器而异。如果我使用Firefox,当浏览器尝试加载小程序时,不会显示任何GET日志(即,当小程序加载失败时,没有进一步下载)。如果我在IE9中尝试,则所有日志都在那里,除了“PortWriter.class” GET日志……这意味着由于某种原因未检索到它。
当我避免使用JNLP时,我会得到安全警告弹出窗口,并且没有错误……当然,在运行“发送”方法时会出现安全访问错误。但是,当我使用JNLP时,IE可以正常加载它并仍然给出错误……但是当我关闭它时会崩溃(我必须结束iexplorer进程)。 Firefox只是不加载页面……它在进度条处停止。
更新-我已经将事情推到了一个点,如果我通过java的安全策略文件绕过安全性,则小程序将起作用。但是,JNLP不起作用-我认为这就是通常在通过小程序标记运行时出现安全错误的原因。当我直接访问JNLP文件时,我会收到一个错误,指出无法找到“PortWriter”类。我的jar有问题吗?我注意到其他jar的文件夹布局与其包布局完全匹配(例如,“com\myname\serialport\PortWriter.jar”,如果包是com.myname.serialport.PortWriter)。但是,我的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, Jcomm@engidea.com

  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新手,但我只想得到一个可行的解决方案。这是为了我们公司的POS,我正在用Rails制作。
最终文件为:
在服务器上的 /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

JNLP文件无效。请尝试使用JaNeLA进行验证。 - Andrew Thompson
我做了,最终得到了我回答中指定的布局...虽然那不一定是问题所在。 - SnakeWasTheNameTheyGaveMe
2个回答

2
当我最初决定在Java控制台中关闭“下一代插件”选项以使我的小程序在Firefox中工作时,我无意中禁用了JNLP。只有在最后一次尝试“尝试任何事情”的努力之后,我才发现了这一点。重新打开它后,在IE中运行jnlp非常完美。当然,Firefox是我需要使用POS的浏览器(因为jsprint插件)......但当然它不起作用。它不会下载JNLP文件,或者如果正在下载,则出现问题。它只是挂起。什么都没有显示出来,但我的服务器日志显示所有图像和html都被下载了。但没有下载jnlp或任何jar文件。因此,要么关闭下一代插件并存在安全问题,要么打开它并不能使用Firefox。是否有任何方法可以做到这一点而不必诉诸于更改策略文件?
顺便说一句,我将把这个标记为解决方案,并在其他地方开始一个关于我的最新问题的新线程。以下是获取该死的东西工作所需的所有内容的最新更新内容(除了Firefox):
首先,请确保在Windows中设置了PATH和CLASSPATH环境变量。 PATH应为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中指定main-class,则不需要此Manifest.txt文件。): Main-Class: 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, Jcomm@engidea.com

  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文件进行了"打包"并使用相同的证书文件进行了签名。我确保cd到了与winjcom在同一目录下,这样它就会位于.jar文件的根目录中。我还拿了winjcom作者提供的jcomport.jar文件,并使用相同的证书文件重新签名了它。也就是说,所有的.jar文件都使用了相同的证书文件进行了签名。

希望这能帮助那些像我一样遇到麻烦的人。


0
为了使用Java的包(推荐),请将PortWriter.java放置在java/x/y/z中,并在第一行添加:
package x.y.z;

随处使用的类名:

x.y.z.PortWriter

在服务器上,我只期望有一个包含PortWriter类的jar文件。 你可以添加一些不使用DLL的Test.java来验证它是否可行。


这并没有任何帮助 :( 它仍然找不到该类。我从资产文件夹中删除了除新jar文件之外的所有文件...我只更改了我的JNLP以引用该jar,并从我的applet标记中删除了“archive”属性。 它只是告诉我它找不到它!顺便说一句,在jar中的文件夹目录仍然模仿我的本地文件系统。 我已经尝试在“javac”中设置classpath选项,但是当我转到“jar”时(没有classpath选项),它会按照上述方式创建子目录。 - SnakeWasTheNameTheyGaveMe
补充说明:将Windows环境变量“PATH”(指向Java目录)和“CLASSPATH”(指向我的类主目录,不包括包目录)添加到系统中可以创建我所需的JAR结构。但是仍然无法找到该类:\ - SnakeWasTheNameTheyGaveMe
另外,我注意到它无法找到类,因为它试图直接下载类文件...它没有查找jar文件来找到它们(我已经查看了我的服务器日志)。 - SnakeWasTheNameTheyGaveMe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接