如何使用 JSoup 根据选择的 JList 下载文件?

How does one download a file based on selection of a JList using JSoup?

假设我有一个 JList,代码如下:

final JList<String> list = new JList<String>(model);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.setToolTipText("Choose Version");
list.setBounds(10, 150, 414, 23);

我想创建一个功能,让用户可以 select 来自托管在网站上的这个 JList 的文件,然后下载它。对于 JList 名称,我将使用托管文件的名称。 (我想通过使用 JSoup 来做到这一点)

到目前为止,我有以下代码来显示姓名:

DefaultListModel<String> model = new DefaultListModel<String>();

        Document doc = null;

        try {
            doc = Jsoup.connect("https://mega.nz/fm/rqwQRKyR").get();
        } catch (IOException e3) {
            // TODO Auto-generated catch block
            e3.printStackTrace();
        }
        for (Element file : doc.select("td.right td a")) {
            model.addElement(file.attr("href"));
        }

在此示例代码中,我从网站获取文件名并将文件名添加到 DefaultListModel。然后,我用这个模型创建了一个新的 JList。

但是,我怎样才能使我的程序能够使用 JSoup 下载所选的特定文件(基于文件名)?

嗯,在阅读了 this 关于如何使用 JSoup 下载图像的问答后,我得到了下面的代码。当您没有指定是要将图像简单地下载到内存中还是保存在本地文件中时,我实现了代码,它同时执行这两种操作(即它首先下载然后提示用户保存它如果he/she想要)。

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import java.awt.Window;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.util.Objects;
import javax.imageio.ImageIO;
import javax.swing.DefaultListModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
import org.jsoup.Jsoup;

public class Main {

    //A JDialog which allows the user to save the downloaded image locally...
    private static class ImageDialog extends JDialog {
        private final BufferedImage bimg;

        private ImageDialog(final Window owner,
                            final String title,
                            final JFileChooser sharedChooser,
                            final BufferedImage bimg) {
            super(owner, title, ModalityType.APPLICATION_MODAL);

            this.bimg = Objects.requireNonNull(bimg);

            final JLabel label = new JLabel(new ImageIcon(bimg), JLabel.CENTER);

            final JScrollPane scroll = new JScrollPane(label);
            scroll.setPreferredSize(new Dimension(600, 600));

            final JList<String> options = new JList<>(ImageIO.getWriterFormatNames());
            options.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

            final JButton save = new JButton("Save");
            save.addActionListener(e -> {
                if (JOptionPane.OK_OPTION == JOptionPane.showConfirmDialog(ImageDialog.this, options, "Select image type", JOptionPane.OK_CANCEL_OPTION)) {
                    final String imageFormat = options.getSelectedValue();
                    if (imageFormat == null)
                        JOptionPane.showMessageDialog(ImageDialog.this, "You have to select an image type first!");
                    else if (sharedChooser.showSaveDialog(ImageDialog.this) == JFileChooser.APPROVE_OPTION) {
                        final File imagePath = sharedChooser.getSelectedFile();
                        if (imagePath.exists()) //I would avoid overwriting files.
                            JOptionPane.showMessageDialog(ImageDialog.this, "You cannot overwrite images! Delete them manually first.", "Oups!", JOptionPane.WARNING_MESSAGE);
                        else {
                            try {
                                ImageIO.write(bimg, imageFormat, imagePath);
                                JOptionPane.showMessageDialog(ImageDialog.this, "Saved image successfully under \"" + imagePath + "\".", "Ok", JOptionPane.INFORMATION_MESSAGE);
                            }
                            catch (final IOException iox) {
                                iox.printStackTrace();
                                JOptionPane.showMessageDialog(ImageDialog.this, "Failed to save image! " + iox, "Error!", JOptionPane.ERROR_MESSAGE);
                            }
                        }
                    }
                }
            });

            final JPanel contents = new JPanel(new BorderLayout());
            contents.add(scroll, BorderLayout.CENTER);
            contents.add(save, BorderLayout.PAGE_END);

            super.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
            super.getContentPane().add(contents);
            super.pack();
            super.setLocationRelativeTo(owner);
        }
    }

    public static void main(final String[] args) {

        //This is where you fill the model:
        final DefaultListModel<String> model = new DefaultListModel<>();
        model.addElement("https://i.stack.imgur.com/PUMHY.png");
        model.addElement("https://i.stack.imgur.com/PUMHY.png");
        model.addElement("https://i.stack.imgur.com/PUMHY.png");
        model.addElement("https://i.stack.imgur.com/PUMHY.png");

        //List creation and initialization:
        final JList<String> list = new JList<>(model);
        list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

        //JScrollPane for list:
        final JScrollPane scroll = new JScrollPane(list);
        scroll.setPreferredSize(new Dimension(400, 400));

        final JFileChooser sharedChooser = new JFileChooser();
        sharedChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
        sharedChooser.setMultiSelectionEnabled(false);

        final JProgressBar bar = new JProgressBar();
        bar.setBorderPainted(false);
        bar.setStringPainted(true);
        bar.setString("Downloading, please wait...");
        bar.setIndeterminate(true);

        //Create an extra panel which will have the progress bar centered in it...
        final JPanel centeredBar = new JPanel(new GridBagLayout());
        centeredBar.add(bar);

        final JButton button = new JButton("Download");

        final JPanel contents = new JPanel(new BorderLayout());
        contents.add(scroll, BorderLayout.CENTER);
        contents.add(button, BorderLayout.PAGE_END);

        //Creating the cards to add in the content pane of the jframe:
        final String cardProgressBar = "PROGRESS_BAR",
                     cardList = "LIST";
        final CardLayout cardl = new CardLayout();
        final JPanel cards = new JPanel(cardl);
        cards.add(contents, cardList);
        cards.add(centeredBar, cardProgressBar);
        cardl.show(cards, cardList);

        final JFrame frame = new JFrame("JList for JSoup");

        button.addActionListener(e -> {
            cardl.show(cards, cardProgressBar);
            new Thread(() -> {
                final String imagePath = list.getSelectedValue();
                if (imagePath == null)
                    JOptionPane.showMessageDialog(frame, "No image selected!");
                else {
                    try {
                        //This is the actual downloading you requested:
                        try (final BufferedInputStream bis = Jsoup.connect(imagePath).ignoreContentType(true).execute().bodyStream()) {
                            final BufferedImage bimg = ImageIO.read(bis);
                            new ImageDialog(frame, imagePath, sharedChooser, bimg).setVisible(true);
                        }
                    }
                    catch (final IOException iox) {
                        iox.printStackTrace();
                        JOptionPane.showMessageDialog(frame, "Failed to download \"" + imagePath + "\"! " + iox);
                    }
                    finally {
                        cardl.show(cards, cardList);
                    }
                }
            }).start();
        });

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(cards);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

您必须使用您在自己的代码中显示的方式来填充您的列表模型。在我上面的示例代码中,我只是多次用一些随机值填充它。

您还可以将调用 Jsoup.connect(imagePath).ignoreContentType(true).execute().bodyStream() 替换为 Jsoup.connect(imagePath).ignoreContentType(true).execute().bodyAsBytes(),这将允许最大 2GB 的文件(因为我猜您不能在 [=22= 中分配大于 Integer.MAX_VALUE 的字节数组]).让我知道这是否是您要找的。