java项目:文件保险柜#4界面重写(3)

如果要实现存储用户的秘钥,那就得把用户的登录注册界面分开写,在注册时进行账户密码秘钥的存储,在登录时仅仅是判断账号密码,在下载文件时判断秘钥,此秘钥同时进行文件加密的操作,在文件上传时也要能读取。

一旦把注册登录界面分开写,那么就要对动作监听器重新对应,原先的同一界面上的“登录”“注册”按钮,变成“登录”“新用户注册”,而点击新用户注册时跳转另一个注册页面

——>

(点击新用户注册)

同时关闭登录页面,注册完成再跳转会登录页面

之后,我对动作监听器里面的“注册判断”,“写入”方法进行调整

//注册判断
    public void registerUser() {
        String userid = userID.getText();
        String password = new String(userPw.getPassword());// 获取密码字段的文本
        String key = new String(userKey.getText());
        if (userid == null || userid.trim().isEmpty()) {
            System.out.println("账号不能为空");
            return; // 直接返回,不执行注册操作
        }
        if (password == null || password.trim().isEmpty()) {
            System.out.println("密码不能为空");
            return; // 直接返回,不执行注册操作
        }
        if (key == null || userid.trim().isEmpty()) {
            System.out.println("秘钥不能为空");
            return; // 直接返回,不执行注册操作
        }
        if (isUserNameTaken(userid)) {
            System.out.println("用户名已注册,请使用其他用户名");
        } else {
            System.out.println("注册成功");
            writeUserInfo(userid, password, key);
        }
    }
//账号密码秘钥写入txt
    private void writeUserInfo(String userid, String password, String key) {
        try (FileWriter writer = new FileWriter("data\\userinfo.txt", true)) {
            writer.write(userid + ":" + password + ":" + key + "\n");
        } catch (IOException e) {
            System.out.println("出现IO错误");
            e.printStackTrace();//打印异常堆栈跟踪到标准错误流
        }
    }

效果如图

因为调用秘钥情况太多,我就将查找用户秘钥单独写了方法

//查找对应秘钥
    public String getUserKey() {
        String userid =userID.getText();
        try {
            BufferedReader reader = new BufferedReader((new FileReader("data\\userinfo.txt")));
            //为了每一行的进行读取
            String line;//用于存储每一行的内容
            while ((line = reader.readLine()) != null) {//一行一行的从reader中读取,进行while循环
                String[] parts = line.split(":");//split方法以“:”为分割,将每一行的内容存入数组
                if (parts[0].equals(userid)) {
                    newKey= parts[2];
                }
            }
        } catch (IOException e) {
            System.out.println("读取文件时发生错误。");
            e.printStackTrace();
        }
        return newKey;
    }

和检索密码的逻辑相同,只是位置从part[1],变成part[2]。

当让,秘钥是服务于加密的,这里采用异或加密,加密的秘钥和解密的秘钥是同一个,加解密的方法是互补的,也就是只用一个方法就能写出文件加密解密,用一个布尔值区别加密解密(最后好像没用上)。

import java.io.*;

public class XorEncryption {

    /**
     * 对文件进行异或加密。
     *
     * @param inputFile  要加密的文件路径
     * @param outputFile 加密后输出的文件路径
     * @param key        密钥,必须是字节数组
     * @throws IOException 如果读写文件时发生错误
     */
    public static void encryptFile(String inputFile, String outputFile, byte[] key) throws IOException {
        processFile(inputFile, outputFile, key, true);
    }

    /**
     * 对文件进行异或解密。
     *
     * @param inputFile  要解密的文件路径
     * @param outputFile 解密后输出的文件路径
     * @param key        密钥,必须是字节数组
     * @throws IOException 如果读写文件时发生错误
     */
    public static void decryptFile(String inputFile, String outputFile, byte[] key) throws IOException {
        processFile(inputFile, outputFile, key, false);
    }

    /**
     * 对文件进行异或处理,可以是加密或解密。
     *
     * @param inputFile    要处理的文件路径
     * @param outputFile   处理后输出的文件路径
     * @param key         密钥,必须是字节数组
     * @param isEncrypting 布尔值,true表示加密,false表示解密
     * @throws IOException 如果读写文件时发生错误
     */
    private static void processFile(String inputFile, String outputFile, byte[] key, boolean isEncrypting) throws IOException {
        int keyLength = key.length;
        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(inputFile));
             BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(outputFile))) {

            byte[] buffer = new byte[1024];
            int bytesRead;

            while ((bytesRead = bis.read(buffer)) != -1) {
                for (int i = 0; i < bytesRead; i++) {
                    buffer[i] = (byte) (buffer[i] ^ key[i % keyLength]);
                }
                bos.write(buffer, 0, bytesRead);
            }
        }
    }
}

接下来是文件的上传和下载

上次已经写到了打开用户界面时同时加载用户自己的文件夹,把文件遍历在窗体上面,同时加上复选框

这里我把上传的方案暂定为打开文件选择器,在硬盘中选择文件进行上传,目前有个缺点就是一次只能上传一个文件。

文件加密后要存入自己的文件夹,就涉及到用户名的传送,所以我写了两个构造器

public void jumpID(String userID){
        ID=userID;
        System.out.println("传递的账号ID:"+ID);
    }

    public void jumpPW(String userPW){
        PW=userPW;
        System.out.println("传递的账号PW:"+PW);
    }

这个文件选择后,传入加密,秘钥为用户注册时设置的,加密后传出到用户自己的文件夹中。

 upbtn.addActionListener(e -> {
            uploadAndEncryptFile(ID);

        });



// 上传文件并加密
    public void uploadAndEncryptFile(String userID) {
        JFileChooser fileChooser = new JFileChooser();
        fileChooser.setDialogTitle("选择要上传的文件");
        int result = fileChooser.showOpenDialog(null);

        if (result == JFileChooser.APPROVE_OPTION) {
            File selectedFile = fileChooser.getSelectedFile();
            String filePath = selectedFile.getAbsolutePath();
            String encryptedFilePath = "data/" + userID + "-Dir/" + selectedFile.getName();

            try {
                // 获取用户注册时的秘钥
                String userKey = al.getUserKey();
                byte[] key = userKey.getBytes();

                // 加密文件
                xor.encryptFile(filePath, encryptedFilePath, key);
                System.out.println("文件上传并加密成功");
            } catch (IOException e) {
                System.out.println("文件加密或写入时发生错误");
                e.printStackTrace();
            }
        }
    }

然后就出现了列表不显示刚刚传入的文件的问题,这就涉及到一个页面刷新的问题

最开始,我认为刷新页面只要关闭再打开页面就行,而这样写过之后发现,文件列表依然不存在传入的文件,分析原因大概是文件的链表没有重新载入界面,一次偶然点击发现,关闭用户页面,重新点击登录按钮也可以刷新页面,那就按这个思路,写了一个刷新按钮

// 给刷新按钮添加动作监听器
        flushed.addActionListener(e -> {
            closeUserInfoUI();
            openLoginUI();
            userInfoUI(ID, PW);
            closeLoginUI();
        });

接下来是下载按钮

用户对文件进行复选操作后,点击下载按钮,跳出“请输入秘钥”界面,输入对应秘钥后,进行判断,如果秘钥没问题,则进行解密并下载操作

解密还是调用XOR异或加密类中的方法,传出文件

下载操作呢,我还是使用了一个文件选择器,用来选择下载的位置,同时,文件前缀加上“out-”,标识已经解密

//给下载按钮添加动作监听器
        downbtn.addActionListener(e -> {
            String userKey = al.getUserKey();
            String pwd = JOptionPane.showInputDialog("请输入秘钥:");
            if (pwd.equals(userKey)) {//从文件夹中找到用户存储的秘钥,进行二次判断
                for (int i = 0; i < listModel.getSize(); i++) {
                    JCheckBox jCheckBox = listModel.get(i);
                    if (jCheckBox.isSelected()) {
                        File selectedFile = new File(filePath, jCheckBox.getText());
                        // 打开文件选择对话框,让用户选择保存位置
                        JFileChooser fileChooser = new JFileChooser();
                        fileChooser.setDialogTitle("选择保存文件的位置");
                        fileChooser.setSelectedFile(new File("out-" + selectedFile.getName())); // 设置默认选择的文件名
                        int result = fileChooser.showSaveDialog(jp); // 显示对话框
                        if (result == JFileChooser.APPROVE_OPTION) {
                            File fileToSave = fileChooser.getSelectedFile();
                            // 构建解密后的文件路径
                            String decryptedFilePath = fileToSave.getAbsolutePath();
                            // 获取用户注册时的秘钥
                            byte[] key = userKey.getBytes();
                            // 解密文件
                            try {
                                xor.decryptFile("data/" + ID + "-Dir/" + selectedFile.getName(), decryptedFilePath, key);
                                JOptionPane.showMessageDialog(jp, "下载成功!");
                            } catch (IOException ex) {
                                JOptionPane.showMessageDialog(jp, "文件解密或写入时发生错误");
                                ex.printStackTrace();
                            }
                        }
                    }
                }
            } else {
                JOptionPane.showMessageDialog(jp, "密码错误!");
            }
        });

效果展示

最后,为了使界面的跳转更符合操作,我加上了各种关闭界面和打开界面

    public void openLoginUI() {
        frame.setVisible(true);
    }
    public void closeLoginUI() {
        frame.setVisible(false);
    }
    public void openEnrollUI() {
        enrollUI();
    }
    public void closeEnrollUI() {
        enrollFrame.setVisible(false);
    }
    public void closeUserInfoUI() {
        userFrame.setVisible(false);
    }
    public void openUserInfoUI() {
        userFrame.setVisible(true);
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值