全栈工程师工作干货总结(二)

1. linux允许ROOT登录ftp

# 进入vsftpd目录
cd /etc/vsftpd

# 查看该目录包含的文件
ls

# 进入文件vsftpd.ftpusers,在root前加#注释root
vi  vsftpd.ftpusers

# 进入文件vsftpd.user_list,在root前加#注释root
vi vsftpd.user_list

2. 关于只能IP访问,域名不能访问网站的解决

我买的是腾讯云的服务器Cenos 6.5系统,自己配置的DNS域名服务器,nslookup www.xuefeng66.cn能够正常解析为115.159.201.119(若是非权威解析为该结果证明解析还存在问题,需要更改/etc/resolv.conf中的服务器地址,添加你买的域名服务器地址),解析成功后,发现通过IP可以访问,但是通过域名不能访问,终于发现时tomcat的问题

在这里插入图片描述

​​3. RSA简单加密与解密

import java.io.*;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;


public class RSADemo {
    /*
     * 产生秘钥
     */
    public static void generateKey() {
        try {
            // 指定算法
            KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
            // 确定密钥大小
            kpg.initialize(1024);
            // 产生密钥对
            KeyPair kp = kpg.genKeyPair();
            // 获取公钥
            PublicKey publicKey = kp.getPublic();
            // 获取私钥
            PrivateKey privateKey = kp.getPrivate();

            // 保存公钥
            FileOutputStream f1 = new FileOutputStream("publicKey.dat");
            ObjectOutputStream o1 = new ObjectOutputStream(f1);
            o1.writeObject(publicKey);
            o1.close();
            f1.close();

            // 保存私钥
            FileOutputStream f2 = new FileOutputStream("privateKey.dat");
            ObjectOutputStream o2 = new ObjectOutputStream(f2);
            o2.writeObject(privateKey);
            o2.close();
            f2.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /*
     * 加密
     */
    public static void encrypt() {
        // 明文
        String s = "Hello World!";
        try {
            // 获取公钥及参数e,n
            FileInputStream f = new FileInputStream("publicKey.dat");
            ObjectInputStream oos = new ObjectInputStream(f);
            RSAPublicKey publicKey = (RSAPublicKey) oos.readObject();
            BigInteger e = publicKey.getPublicExponent();
            BigInteger n = publicKey.getModulus();
            System.out.println("参数e= " + e);
            System.out.println("参数n= " + n);

            // 获取明文
            byte[] content = s.getBytes("UTF-8");
            BigInteger m = new BigInteger(content);

            // 计算密文
            BigInteger c = m.modPow(e, n);
            System.out.println("密文为:" + c);

            // 保存密文
            String c1 = c.toString();
            BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream("encrypt.dat")));
            out.write(c1, 0, c1.length());
            out.close();//一定要记得关闭,否则会出现空指针异常
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void decrypt() {
        try {
            // 读取密文
            BufferedReader br = new BufferedReader(new InputStreamReader(
                    new FileInputStream("encrypt.dat")));
            String content = br.readLine();
            BigInteger c = new BigInteger(content);
            // 读取私钥
            FileInputStream f1 = new FileInputStream("privateKey.dat");
            ObjectInputStream o1 = new ObjectInputStream(f1);
            RSAPrivateKey privateKey = (RSAPrivateKey) o1.readObject();
            // 获取私钥参数及解密
            BigInteger d = privateKey.getPrivateExponent();
            BigInteger n = privateKey.getModulus();
            System.out.println("参数d=" + d);
            System.out.println("参数n=" + n);
            BigInteger m = c.modPow(d, n);

            // 显示解密结果
            byte[] mt = m.toByteArray();
            for (int i = 0; i < mt.length; i++) {
                System.out.print((char) mt[i]);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        try {
            generateKey();
            encrypt();
            decrypt();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

4. DES对称密码体系加密解密

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;


public class DESDemo {

    /*
     * 将字节数组转换为十六进制字符串
     */
    public static String byteToHexString(byte[] bytes) {
        StringBuffer stringBuffer = new StringBuffer();
        for (int i = 0; i < bytes.length; i++) {
            String string = Integer.toHexString(0XFF & bytes[i]);
            if (string.length() == 1) { // 十六进制占四个字节,
                stringBuffer.append(0);
            }
            stringBuffer.append(string.toUpperCase());
        }
        return stringBuffer.toString();
    }

    /*
     * 加密方法
     */
    public static byte[] DES_CBC_Encrypt(byte[] content, byte[] keyBytes) {
        try {
            // 创建一个 DESKeySpec 对象,使用 key 中的前 8 个字节作为 DES 密钥的密钥内容
            DESKeySpec keySpec = new DESKeySpec(keyBytes);
            // 返回转换指定算法的秘密密钥的 SecretKeyFactory 对象
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            // 根据提供的密钥规范(密钥材料)生成 SecretKey 对象。
            SecretKey key = keyFactory.generateSecret(keySpec);

            // 返回实现指定转换的 Cipher 对象。
            Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
            // 用密钥和一组算法参数初始化此 Cipher。
            cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(keySpec.getKey()));
            // 按单部分操作加密数据
            byte[] result = cipher.doFinal(content);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /*
     * 解密方法
     */
    public static byte[] DES_CBC_Decrypt(byte[] content, byte[] keyBytes) {
        try {
            DESKeySpec keySpec = new DESKeySpec(keyBytes);
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey key = keyFactory.generateSecret(keySpec);

            Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(keyBytes));
            byte[] result = cipher.doFinal(content);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    public static void main(String[] args) {
        String content = "aaaaaaaabbbbbbbbaaaaaaaa";
        String key = "01234567";

        System.out.println("加密前:" + byteToHexString(content.getBytes()));
        byte[] encrypted = DES_CBC_Encrypt(content.getBytes(), key.getBytes());
        System.out.println("加密后:" + byteToHexString(encrypted));
        byte[] decrypted = DES_CBC_Decrypt(encrypted, key.getBytes());
        System.out.println("解密后:" + byteToHexString(decrypted));
    }
}

5. 基于TCP的客户端与服务器端之间的通信

使用说明:把服务器IP地址更改为自己的服务器主机IP地址即可

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

import javax.swing.JFrame;

public class Chat extends JFrame implements Runnable, ActionListener {

	private Panel topPanel_1, downPanel_1, midPanel_left, midPanel_right;
	private Label ipLabel, localNameLabel;
	private TextField ipTextField, localNameField;
	private Button createServer, searchServer, sendMessage;
	private TextArea text1, text2, text3, text4;
	private ServerSocket server;
	private Socket serverSocket, clientSocket;
	private DataOutputStream outputFromClient, outputFromServer;
	private DataInputStream inputToClient, inputToServer;
	private int scan = 2;// scan:便于区分0客户端与1服务器端的文本内容
	private int lock=0;//0:创建服务器  1:停止服务器
	/***************************** 获取主机IP 与 名称 ******************************/
	public String getIp() {
		String ip = null;
		try {
			InetAddress myLocalHost = InetAddress.getLocalHost();
			ip = myLocalHost.getHostAddress();
		} catch (UnknownHostException e) {
			e.printStackTrace();
		}
		return ip;
	}

	public String getName() {
		String name = null;
		try {
			InetAddress myLocalHost = InetAddress.getLocalHost();
			name = myLocalHost.getHostName();
		} catch (UnknownHostException e) {
			e.printStackTrace();
		}
		return name;
	}

	/***************************** 事件监听 *****************************/
	public void message() {
		createServer.addActionListener(this);
		searchServer.addActionListener(this);
		sendMessage.addActionListener(this);
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getSource() == createServer && lock==0) {
			text3.setText("");
			text3.append("服务器名称为:" + getName() + "\n");
			text3.append("服务器IP为:" + getIp() + "\n");
			text3.append("端口号为:6666\n");
			text3.append("服务器已经启动,正在监听.......\n");
			this.startServer();
			scan=1;
		} else if(e.getSource() == createServer && lock==1){
			try {
				serverSocket.close();
				text3.setText("");
				text3.append("服务器关闭成功");
				lock=0;
			} catch (IOException e1) {
				text3.append("服务器关闭异常");
				e1.printStackTrace();
			}			
		}else if (e.getSource() == searchServer) {
			text4.setText("");
			text4.append("正在搜索服务器,请稍等.....\n");
			this.startClient();
			scan=0;
		} else if (e.getSource() == sendMessage) {
			if (scan == 1) {// 服务器端
				try {
					outputFromServer = new DataOutputStream(
							serverSocket.getOutputStream());
					String name = getName();
					if (text2.getText().length() > 0) {
						text1.append(name + "说:   " + text2.getText()
								+ "\n");
						outputFromServer.writeUTF(this.getName()+","+text2.getText());// 写入消息
						text2.setText("");
					} else {
						text2.setText("\n\n请输入内容\n\n");
						Thread.sleep(1000);
						text2.setText("");
					}
				} catch (InterruptedException | IOException e1) {
					e1.printStackTrace();
				}
			} else if (scan == 0 ) {// 客户端
				try {
					outputFromClient = new DataOutputStream(
							clientSocket.getOutputStream());
					String name = getName();
					if (text2.getText().length() > 0 ) {
						text1.append(name + "说:   " + text2.getText()+ "\n");
						outputFromClient.writeUTF(this.getName()+","+text2.getText());// 写入消息
						text2.setText("");
					} else if(text2.getText().length() <= 0) {
						text2.setText("\n\n请输入内容\n\n");
						Thread.sleep(1000);
						text2.setText("");
					}
				} catch (InterruptedException | IOException e1) {
					e1.printStackTrace();
				}
			}
		}
	}

	/***************************** 启动服务器 *************************************/
	public void startServer() {
		try {
			if(lock==0){
				server = new ServerSocket(6666);
				serverSocket = server.accept();
				createServer.setLabel("停止服务器");
				lock=1;
			}
		} catch (IOException e) {
			text3.setText("");
			text3.append("服务器启动错误,请重新设置后启动!\n可能是由于:\n");
			text3.append("1.端口被占用。\n");
			text3.append("2.服务器已经启动。\n");
			e.printStackTrace();
		}
	}

	/***************************** 启动客户端 *************************************/
	public void startClient() {
		try {
			clientSocket = new Socket("192.168.31.125",6666);//更改为自己服务器主机的IP地址即可
			text4.append("连接成功 ");
			searchServer.setLabel("断开连接");
		} catch (Exception e) {
			text4.append("无法连接网络");
			e.printStackTrace();
		}
	}

	/******************************* 对话内容互相显示 *****************************/
	public void messageDisplay() throws IOException {
		// 接收消息
		if (scan == 1) {// 客户端
			inputToClient = new DataInputStream(serverSocket.getInputStream());
			String receive = inputToClient.readUTF();
			String[] message=receive.split(",");
			text1.append(message[0]+"说:   "+message[1]+"\n");
		}else if(scan == 0){//服务器端
			inputToServer = new DataInputStream(clientSocket.getInputStream());
			String receive = inputToServer.readUTF();
			String[] message=receive.split(",");
			text1.append(message[0]+"说:   "+message[1]+"\n");
		}
	}

	/***************************** 创建主界面 *************************************/
	private void launchFrame() {
		// /上面部分/
		topPanel_1 = new Panel();
		ipLabel = new Label("IP地址");// 标签
		ipTextField = new TextField(getIp(), 19);
		localNameLabel = new Label("本机名称");
		localNameField = new TextField(getName(), 19);
		createServer = new Button("创建服务器");
		searchServer = new Button("搜索服务器");

		// /中部部分/
		midPanel_left = new Panel();
		midPanel_right = new Panel();
		text1 = new TextArea(20, 68);
		text2 = new TextArea(3, 68);
		text3 = new TextArea(14, 25);
		text4 = new TextArea(9, 25);

		// /底部部分/
		downPanel_1 = new Panel();
		sendMessage = new Button("发送");

		topPanel_1.add(ipLabel);// 加入面板
		topPanel_1.add(ipTextField);
		topPanel_1.add(localNameLabel);
		topPanel_1.add(localNameField);
		topPanel_1.add(createServer);
		topPanel_1.add(searchServer);

		midPanel_left.setLayout(new BorderLayout());
		midPanel_right.setLayout(new BorderLayout());
		midPanel_left.add(text1, BorderLayout.NORTH);
		midPanel_left.add(text2, BorderLayout.SOUTH);
		midPanel_right.add(text3, BorderLayout.NORTH);
		midPanel_right.add(text4, BorderLayout.SOUTH);

		downPanel_1.add(sendMessage);

		Container container = getContentPane();// 布局管理器
		container.setLayout(new BorderLayout());// 布局声明
		container.add(topPanel_1, BorderLayout.NORTH);
		container.add(midPanel_left, BorderLayout.CENTER);
		container.add(midPanel_right, BorderLayout.EAST);
		container.add(downPanel_1, BorderLayout.SOUTH);
		this.pack();// 调整此窗口的大小,以适合其子组件的首选大小和布局。
		setSize(700, 500);// 设置面板宽与高
		setTitle("点星光聊天");// 设置标题
		setResizable(false);// 大小不可变
		setVisible(true);// 设置面板可见
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// 关闭时释放资源
	}

	public static void main(String[] args) throws IOException {
		Chat chat = new Chat();
		chat.launchFrame();
		chat.message();
		while(true){
			chat.messageDisplay();
		}
	}

	@Override
	public void run() {
		// TODO 自动生成的方法存根

	}
}

6. 红蓝按钮交替移动

编写一个应用程序,除了主线程外,还有两个线程:first和second。first负责模拟一个红色的按钮从坐标(10,60)运动到(100,60);second负责模拟一个绿色的按钮从坐标(100,60)运动到(200,60)。另外还有一个start按钮,当点击start按钮后,红色按钮平行移动从左边移动到右边,当红色按钮移动到绿色按钮位置后,红色按钮停止在绿色按钮起始位置,然后绿色按钮接着移动。当绿色按钮移动到指定位置后,所有按钮位置重置,然后循环执行上述过程。

public class MoveButton extends JFrame implements Runnable, ActionListener {

    private int distance = 10;
    Thread first, second;
    Button redButton, greenButton, startButton;

    public MoveButton() {

        /*
         * 创建线程
         */
        first = new Thread(this);
        second = new Thread(this);
        setLayout(null); // 清除默认布局


        /*
         * 设置红色按钮的颜色
         * 设置起始位置与大小
         * 加入窗体
         */
        redButton = new Button();
        redButton.setBackground(Color.red);
        redButton.setBounds(10, 60, 15, 15);
        add(redButton);

        /*
         * 设置红色按钮的颜色
         * 设置起始位置与大小
         * 加入窗体
         */
        greenButton = new Button();
        greenButton.setBackground(Color.green);
        greenButton.setBounds(100, 60, 15, 15);
        add(greenButton);
        /*
         * 设置开始按钮的起始位置与大小
         * 添加监听器
         * 加入窗体
         */
        startButton = new Button("start");
        startButton.addActionListener(this);
        startButton.setBounds(10, 100, 30, 30);
        add(startButton);
        setBounds(0, 0, 300, 200);// 设置窗体的起始位置与长宽
        setVisible(true);// 设置窗体可见

        /*
         * 关闭窗时释放内存资源
         */
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
    }

    /*
     * 实现按钮的移动
     * synchronized 方法控制对类成员变量的访问
     */

    private synchronized void moveComponent(Button button) {
        if (Thread.currentThread() == first) {
            while (distance > 100 && distance <= 200) {
                try {
                    wait();
                    System.out.println("你好");//线程等待,直到其他线程调用notify或notifyAll方法通知该线程醒来
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            distance += 1;
            button.setLocation(distance, 60);
            if (distance >= 100) {
                if (distance <= 200) {
                    button.setLocation(100, 60);//在蓝色按钮运动期间红色按钮始终位于蓝色按钮最初位置
                } else {
                    button.setLocation(10, 60);//当距离移动距离大于200时,蓝色按钮归位
                }

                notify();//唤醒单个等待的线程(由于约束条件的存在,此程序中势必只有一个等待的线程,故可用此方法替换)
                //notifyAll();//唤起全部等地的线程
            }
        }

        if (Thread.currentThread() == second) {
            while (distance >= 10 && distance < 100) {
                try {
                    wait();//线程等待,直到其他线程调用notify或notifyAll方法通知该线程醒来
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            distance += 1;
            button.setLocation(distance, 60);
            if (distance > 200) {
                button.setLocation(100, 60);//当距离移动距离大于200时,蓝色按钮归位
                distance = 10;//distance置初值
                notify();//
            }
        }
    }


    public void run() {
        while (true) {
            /*
             * 判断当前执行的线程是否为first
             * 如果是,调用moveComponent()方法,移动redButton
             * 线程睡眠20ms
             */
            if (Thread.currentThread() == first) {
                moveComponent(redButton);
                try {
                    Thread.sleep(20);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            /*
             * 判断当前执行的线程是否为second
             * 如果是,调用moveComponent()方法,移动greenButton
             * 线程睡眠10ms
             */
            if (Thread.currentThread() == second) {
                moveComponent(greenButton);
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /*
     * 事件监听,启动线程(由于只对startButton按钮绑定监听器,所以默认监听该按钮)
     */
    public void actionPerformed(ActionEvent e) {
        try {
            first.start();//启动线程
            second.start();
        } catch (Exception e1) {
            e1.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new MoveButton();
    }
}

7. JAVA根据指定URL生成二维码

public class QrCodeUtil {
    public static void main(String[] args) {
        String url = "https://www.baidu.com";
        String path = FileSystemView.getFileSystemView().getHomeDirectory() + File.separator + "testQrcode";
        String fileName = "temp.jpg";
        createQrCode(url, path, fileName);
    }

    public static String createQrCode(String url, String path, String fileName) {
        try {
            Map<EncodeHintType, String> hints = new HashMap<>();
            hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
            BitMatrix bitMatrix = new MultiFormatWriter().encode(url, BarcodeFormat.QR_CODE, 400, 400, hints);
            File file = new File(path, fileName);
            if (file.exists() || ((file.getParentFile().exists() || file.getParentFile().mkdirs()) && file.createNewFile())) {
                writeToFile(bitMatrix, "jpg", file);
                System.out.println("搞定:" + file);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    static void writeToFile(BitMatrix matrix, String format, File file) throws IOException {
        BufferedImage image = toBufferedImage(matrix);
        if (!ImageIO.write(image, format, file)) {
            throw new IOException("Could not write an image of format " + format + " to " + file);
        }
    }

    static void writeToStream(BitMatrix matrix, String format, OutputStream stream) throws IOException {
        BufferedImage image = toBufferedImage(matrix);
        if (!ImageIO.write(image, format, stream)) {
            throw new IOException("Could not write an image of format " + format);
        }
    }

    private static final int BLACK = 0xFF000000;
    private static final int WHITE = 0xFFFFFFFF;

    private static BufferedImage toBufferedImage(BitMatrix matrix) {
        int width = matrix.getWidth();
        int height = matrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE);
            }
        }
        return image;
    }
}

8. ElementPlus中el-select在IOS中无法唤醒软件盘解决方案

项目基于Vue3 + ElementPlus1.3

在main.js代码中

import ElementPlus from 'element-plus'
/* eslint-disable no-new */
window.$vueApp = Vue.createApp(App)
// 给组件每个生命周期,都混入一些公共逻辑, 解决IOS el-select无法唤醒软件盘问题
window.$vueApp.mixin({
  mounted () {
    if (typeof this.$el.className === 'string') {
      if (this.$el.className.split(' ').indexOf('el-select') !== -1) {
        this.$el.children[0].children[0].children[0].removeAttribute('readOnly')
        this.$el.children[0].children[0].children[0].onblur = function () {
          let _this = this
          setTimeout(() => {
            _this.removeAttribute('readOnly')
          }, 200)
        }
      }
    }
  }
})
window.$vueApp.use(ElementPlus)

9. JAVA流实现文件批量打包下载

    @ResponseBody
    public void downloadFiles(HttpServletRequest request, HttpServletResponse response, String[] filePaths) {
        if (filePaths == null || filePaths.length <= 0) {
            return ;
        }

        // 设置响应头
        response.reset();
        response.setCharacterEncoding("utf-8");
        response.setContentType("multipart/form-data");

        // 设置压缩包名称及不同浏览器中文乱码处理
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        LocalDateTime localDateTime = LocalDateTime.now();
        String filename = "电子合同" + formatter.format(localDateTime) + ".zip";

        String agent = request.getHeader("AGENT");
        try {
            if (agent.contains("MSIE") || agent.contains("Trident")) {
                    filename = URLEncoder.encode(filename, "UTF-8");
            } else {
                filename = new String(filename.getBytes("UTF-8"), "ISO-8859-1");
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        response.setHeader("Content-Disposition", "attachment;filename=\"" + filename  + "\""); // key不区分大小写
        
        try {
            // 设置压缩流,直接写入response,实现边压缩边下载
            ZipOutputStream zipOutputStream = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream()));
            zipOutputStream.setMethod(ZipOutputStream.DEFLATED);

            DataOutputStream dataOutputStream = null;
            for (String filePath : filePaths) {
                String subFilename = formatter.format(LocalDateTime.now()) + filePath.substring(filePath.lastIndexOf("/") + 1);
                zipOutputStream.putNextEntry(new ZipEntry(subFilename));

                dataOutputStream = new DataOutputStream(zipOutputStream);
                BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(new File(filePath)));
                byte[] buf = new byte[8192];
                int length = 0;

                while ((length = bufferedInputStream.read(buf)) != -1) {
                    dataOutputStream.write(buf, 0 , length);
                }
                dataOutputStream.flush();
                // dataOutputStream.close(); 若在此关闭,对应资源zipOutputStream也将关闭,则压缩包内仅有一个文件
                bufferedInputStream.close();
                zipOutputStream.closeEntry();
            }

            dataOutputStream.flush();
            dataOutputStream.close();
            zipOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

10. Windows10强制停止Vmmem

wsl --shutdown

11. Windows10强制删除占用端口的进程

# 查看占用端口8082的进程
netstat -ano|findstr 8082

# 强制删除进程20380及子进程
taskkill /T /F /PID 20380

12. PostgreSQL强制删除数据库

12.1 设置数据库为禁止连接

UPDATE pg_database 
SET datallowconn = 'false' 
WHERE datname = 'db_name';

12.2 中断当前库中所有连接会话

SELECT pg_terminate_backend(pid) 
FROM pg_stat_activity 
WHERE datname = 'db_name';

12.3 删除数据库

drop database db_name;

13. 基于seaborn的正太分布图

import matplotlib.pyplot as plt
import seaborn as sns 

# rating_df类型为pandas
sns.kdeplot(rating_df['rating_our'],  fill=True,  shade=True, bw=0.8, color='#FA705C')
sns.kdeplot(rating_df['rating_customer'],  fill=True,  shade=True, bw=0.8, color='red')
plt.show()

14. 微信小程序文件下载两种方式

14.1 基本url方式下载(自定义下载文件名称)

  downloadDailyYear: function() {
    util.get(api.downloadDailyYear).then(function(res) { // 自定义get请求,可忽略
      if (res.code == 200) {
        var fileName = res.data.substring(res.data.lastIndexOf("/") + 1, res.data.indexOf("."));
        wx.downloadFile({
          url: api.appUrl + res.data,     
          // 1. 必须带有这个wx.env.USER_DATA_PATH,表示存储在用户本地 !!!
          // fileName表示自定的文件名称
          // 实际在PC端调试存储位置为类似 C:\Users\SJshe\AppData\Local\微信开发者工具\User Data\WeappFileSystem\o6zAJs3c0u3SeBVn_9MUgG6UZJ1M\wx2efdf4edd8bccb88
          filePath: wx.env.USER_DATA_PATH + "/" + fileName,
          success: function (res) {
            if (res.statusCode === 200) {
              wx.openDocument({
                filePath: res.filePath,
                fileType: ['xlsx'], // 2. 这个必须写合法类型,不然下载不了(个人认为官方应该特别说明) !!!
                success: function (res) {
                  console.log('打开文档成功')
                },
                fail: function(e) {
                  console.log(e.errMsg);
                }
              })
            }
          },
          fail: function(e) { // 强烈建议打印失败原因,便于排查
            console.log(e.errMsg);
          }
        });
      }
    });
  },

14.2 基于后台返回流的方式下载

@GetMapping(value = "/downloadDailyYear")
public BaseResponse<byte[]> downloadDailyYear(HttpSession session, @RequestParam String id, 
		@RequestParam @DateTimeFormat(iso = ISO.DATE) Date startDate, 
		@RequestParam @DateTimeFormat(iso = ISO.DATE) Date endDate) {
}
public class BaseResponse<T> {
    private String code;
    private String message;
    private T data;
    ...
}
downloadDailyYear: function () {
    var name = '';
    wx.getStorage({
      key: 'userInfo',
      success(res) {
        name += res.data.name + res.data.employeeNo;
      }
    })
    
    var year = new Date().getFullYear();
    util.get(api.downloadDailyYear, {
      'id': wx.getStorageSync('userId'),
      'startDate': year + "-" + "01-01", 
      'endDate': year + "-" + "12-31"
    }).then(function (res) {
      if (res.code == 200) {
      	// 1. 必须带有这个wx.env.USER_DATA_PATH,表示存储在用户本地 !!!
        var filePath = wx.env.USER_DATA_PATH + '/' + year + '工作周报-' + name;
        FileSystemManager.writeFile({
          filePath: filePath,
          data: res.data,
          encoding: 'base64', // 2. base64解密写入, 后台返回的byte[]数组是经过base64编码的,其他方式写入文件打开格式不对
          success: function(res) {
            wx.openDocument({
              filePath: wx.env.USER_DATA_PATH + '/' + year + '工作周报-' + name,
              fileType: ['xlsx'], // 3. 这个必须写合法类型,不然下载不了 !!!
              success: function (res) {
                console.log('打开文档成功')
              },
              fail: function (e) {
                console.log(e.errMsg);
              }
            })
          },
          fail: function (e) {
            console.log(e.errMsg);
          }
        });
      }
    });
  },

15. FRP内网映射家用服务器至公网访问

兄弟们,服务器到货了,后续与大家分享内容就用它了。我预装的操作系统是Centos8,首先要解决的是远程访问的问题。

【特别注意】下述的端口,记得在阿里云安全组配置中放开端口入规则!!

15.1 FRP服务器配置

之前我有购买的阿里云服务器[如果没有,可以购买一台最低配的,只要想办法弄到公网IP即可]

下载frp_0.53.0_linux_arm64.tar.gz,然后解压后/home/shenjian目录下

cd frp_0.53.0_linux_amd64/
vim frps.ini

frps.ini配置内容如下:

[common]
bind_port=7000
dashboard_port=7500
# 控制台用户名
dashboard_user=shenjian
# 控制台密码
dashboard_pwd=123456
# auth 认证方式, token
authentication_method=token
# 认证方式, 开启连接时校验
authenticate_new_work_conns=true
# token, 随便填, 客户端配置需要一样
token=1234567890

服务启动

nohup ./frps -c frps.ini &

访问控制面板[http://公网IP:7500],需输入配置的密码

15.2 FRP客户端配置

在家用服务器中,同样下载以上文件,创建frpc.ini文件并配置如下:

[common]
[common]
# frps服务器ip
server_addr=公网IP地址
server_port=7000
# auth 和服务端保持一致
authentication_method=token
authenticate_new_work_conns=true
token=1234567890   
tls_enable=true

[ssh]
type = tcp
local_ip = 127.0.0.1
local_port = 22
remote_port = 6000

[rdp]
type = tcp
local_ip = 127.0.0.1
local_port = 3389
remote_port = 33389

[vnc]
type = tcp
local_ip = 127.0.0.1
local_port = 5901
remote_port = 35901

服务启动

nohup ./frpc -c frpc.ini &

我们此时可以看到映射的信息

此时我们可以通过任意电脑SSH连接公网IP+6000端口进行访问家用服务器了,其他端口映射同理

欢迎关注公众号 算法小生

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

算法小生Đ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值