在记事本中选择密码行和粘贴会显示密码

时间:2012-01-08 10:17:28

标签: java swing

我在最近创建的java应用程序中遇到了上述问题。即使我清楚地将该字段设置为JPasswordField并试图用星号掩盖密码,我仍然面临这个问题。当我们编辑密码字段时,只有在您选择行时才会出现问题。例如,我连续有2列,如果我选择整行并尝试复制粘贴记事本中的行,则会出现密码。我是java编程世界的新手,如果有人可以提供帮助将会有很大的帮助。

4 个答案:

答案 0 :(得分:3)

你想要的是相当合乎逻辑的。从表中复制粘贴数据时,应该尊重渲染。

标准复制操作将使用模型中可用的数据,其中密码以纯文本形式提供。我们可以开始讨论是否要让您的模型包含密码作为纯文本,而不应用任何哈希......但这不能回答您的问题。

对于您的问题,您应该修改JTable的剪切/复制操作的行为。看看拖放Swing教程,更具体地说是Adding Cut, Copy and Paste section。不幸的是,我没有立即找到一个参考的例子。

修改

在下面找到一个JXTable的示例,它使用渲染值进行复制操作(我没有复制粘贴导入)。关于代码的一点注意事项:

  1. 它使用SwingX来说明kleopatra的内容
  2. 示例TableModel及其元素相当愚蠢。为了避免过多的工作,我需要类似于我们真实产品的东西来复制一些代码
  3. SpeedStringValueAltitudeStringValue类在返回StringValue时违反null接口。我懒得定义一个新接口,我在SwingX StringValue上设置的DefaultTableRenderer实例根据文档行为。我认为,将StringValue个实例分别用于将特定类转换为String的知识是SwingX
  4. 中缺少的真实用例
  5. TransferHandler重用StringValue逻辑来创建仅包含Table个实例的String,然后再回到默认的JTable行为。这允许重用渲染器中实现的逻辑,并允许复制视觉值而不是模型值。我不确定这是否是最好的解决方案,但它确实有效。如果类似的行为在SwingX中是标准的,那就好了,因为它们已经有了基础设施
  6. 代码缺少评论,因为它已经足够长了。如果有什么不清楚的地方,请发表评论,我会尽力澄清

    public class TableTransferHandlerDemo {
    
      public static void main( String[] args ) throws InvocationTargetException, InterruptedException {
        EventQueue.invokeAndWait( new Runnable() {
          public void run() {
            JFrame frame = new JFrame( "TestFrame" );
    
            JPanel contentPane = new JPanel( new BorderLayout(  ) );
            contentPane.add( createTable(), BorderLayout.CENTER );
            frame.getContentPane().add( contentPane );
    
            frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
            frame.pack();
            frame.setVisible( true );
          }
        } );
      }
    
      private static CompositeStringValue createStringValue() {
        CompositeStringValue stringValue = new CompositeStringValue();
        stringValue.delegates.add( new AltitudeStringValue() );
        stringValue.delegates.add( new SpeedStringValue() );
        return stringValue;
      }
    
      public static JXTable createTable(){
        final JXTable table = new JXTable(  );
        table.setSelectionMode( ListSelectionModel.MULTIPLE_INTERVAL_SELECTION );
        table.setModel( createTableModel() );
        CompositeStringValue stringValue = createStringValue();
        table.setDefaultRenderer( Object.class, new DefaultTableRenderer( stringValue ) );
        table.setTransferHandler( new TableTransferHandler( table, stringValue ) );
        //make sure ctrl-c triggers a copy
        InputMap inputMap = table.getInputMap( JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT );
        inputMap.put( KeyStroke.getKeyStroke( KeyEvent.VK_C, InputEvent.CTRL_MASK ), "copyAction" );
        table.getActionMap().put( "copyAction", new AbstractAction() {
          public void actionPerformed( ActionEvent e ) {
            ActionEvent event = new ActionEvent( table, e.getID(), e.getActionCommand(), e.getWhen(), e.getModifiers() );
            TransferHandler.getCopyAction().actionPerformed( event );
          }
        } );
        return table;
      }
    
      public static class Speed{
        public double speed;
        public String unit = "km/h";
        public Speed( double speed ){ this.speed = speed;}
      }
      public static class Altitude{
        public double altitude;
        public String unit = "m";
        public Altitude( double altitude ){ this.altitude = altitude; }
      }
      public static class SpeedStringValue implements StringValue{
        public String getString( Object o ) {
          if ( o instanceof Speed ){
            return ( ( Speed ) o ).speed + ( ( Speed ) o ).unit;
          }
          return null;
        }
      }
      public static class AltitudeStringValue implements StringValue{
        public String getString( Object o ) {
          if ( o instanceof Altitude ){
            return ( ( Altitude ) o ).altitude + ( ( Altitude ) o ).unit;
          }
          return null;
        }
      }
      public static class CompositeStringValue implements StringValue{
        public List<StringValue> delegates = new ArrayList<StringValue>(  );
        public String getString( Object o ) {
          for ( StringValue stringValue : delegates ) {
            String string = stringValue.getString( o );
            if ( string != null ) return string;
          }
          return o != null ? o.toString() : "null";
        }
      }
      public static TableModel createTableModel(){
        return new DefaultTableModel(
            new Object[][]{ new Object[]{ new Speed( 10 ), new Altitude( 100 )},
                new Object[]{ new Speed( 20 ), new Altitude( 200 ) }},
            new Object[]{"Speed", "Altitude"} );
      }
      public static class TableTransferHandler extends TransferHandler{
        private JXTable table;
        private StringValue stringValue;
    
        public TableTransferHandler( JXTable aTable, StringValue aStringValue ) {
          table = aTable;
          stringValue = aStringValue;
        }
        @Override
        public void exportToClipboard( JComponent aComponent, Clipboard aClipboard, int aAction ) throws IllegalStateException {
          JTable table = createTable();
          table.getTransferHandler().exportToClipboard( table, aClipboard, aAction );
        }
        @Override
        public void exportAsDrag( JComponent aComponent, InputEvent aEvent, int aAction ) {
          JTable table = createTable();
          table.getTransferHandler().exportAsDrag( table, aEvent, aAction );
        }
        @Override
        protected Transferable createTransferable( JComponent c ) {
          //this transfer handler should not create any transferables
          return null;
        }
        /**
         * Create a table, representing the JXTable containing only Strings
         */
        private JTable createTable() {
          JTable table = new JTable( new StringTableModel( this.table, stringValue ) );
          table.setSelectionModel( this.table.getSelectionModel() );//make sure the selection is synced
          return table;
        }
      }
    
      private static class StringTableModel extends AbstractTableModel {
        private JXTable delegateTable;
        private StringValue stringValue;
    
        private StringTableModel( JXTable aTable, StringValue aStringValue ) {
          delegateTable = aTable;
          stringValue = aStringValue;
        }
    
        public int getRowCount() {
          return delegateTable.getModel().getRowCount();
        }
    
        public int getColumnCount() {
          return delegateTable.getModel().getColumnCount();
        }
    
        public Object getValueAt( int aRowIndex, int aColumnIndex ) {
          return stringValue.getString( delegateTable.getValueAt( aRowIndex, aColumnIndex ) );
        }
      }
    }
    

答案 1 :(得分:2)

像其他人一样玩猜谜游戏(描述是......缺乏; - )

因此,假设一个包含用户名和密码的两列tableModel,分别在JTable中呈现,拖拽已启用为true且默认为transferHandler。假设JTable中的密码呈现以某种方式被“屏蔽”,但在c&amp; p中显示为明文。

@Robin已经检测到了根本原因:默认的transferHandler只是使用getValueAt(...)。toString()来创建transferable。这导致泄露密码字符串,它就是存储在模型中的内容。

一个简单的出路(与更好的Transferhandler相反,@ Robin已经提到过:使用呈现的值而不是toString。请注意自己:SwingX的文件任务)for for not 存储普通密码但是包装对象:

public class Password {
    private final String password;

    public Password(String password) {
       this.password = password;
    }

    // api as needed to make it worthwile ...

    public boolean isValid(String password) {
        ...
    }

    // for the sake of c&p, override the toString
    // for the lazy, this is the string rep used by the default renderer
    @Override
    public String toString() {
        return "******************";
    }
}

附录(这是特定的SwingX,将我的评论扩展到@ Robin的例子)

实际上我喜欢这种方法作为复制的快速解决方案。只是“修复”包装模型以充分利用当前的api,即将table.getStringAt(...)用于String表示。有了这个,就没有必要在几个地方传递StringValue,内部会在适当的时候处理它。

private static class StringTableModel extends AbstractTableModel {
    private JXTable delegateTable;

    private StringTableModel(JXTable aTable) {
        delegateTable = aTable;
    }

    @Override
    public int getRowCount() {
        return delegateTable.getRowCount();
    }

    @Override
    public int getColumnCount() {
        return delegateTable.getColumnCount();
    }

    @Override
    public Object getValueAt(int aRowIndex, int aColumnIndex) {
        return delegateTable.getStringAt(aRowIndex, aColumnIndex);
    }
}

在框架层面上,SwingX应该支持WYSIWYE(你看到的是什么导出),就像它的其他WYSIWYX:X = M匹配,X = S for sort, X = F表示滤波器。提升issue 1477 in the SwingX issue tracker

答案 2 :(得分:1)

您是否尝试在密码列上禁用单元格编辑?

您可以通过扩展JTable类并使用您自己的实现替换 isCellEditable 函数来实现此目的。

答案 3 :(得分:1)

使用显示here的示例,我可以粘贴密码,但不能复制或剪切密码。无论echoChar设置的可见性如何,都会发生这种情况。你看到不同的结果吗?