1、SFTP文件上次工具类

        <!--sftp  jsch-->
        <dependency>
            <groupId>com.jcraft</groupId>
            <artifactId>jsch</artifactId>
            <version>0.1.54</version>
        </dependency>

import com.jcraft.jsch.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.http.entity.ContentType;
import org.springframework.mock.web.MockMultipartFile;

import java.io.*;
import java.util.ArrayList;
import java.util.Properties;
import java.util.Vector;

public class SFTPUtil {

    private ChannelSftp sftp;

    private Session session;
    /**
     * FTP 登录用户名
     */
    private String username;
    /**
     * FTP 登录密码
     */
    private String password;
    /**
     * 私钥
     */
    private String privateKey;
    /**
     * FTP 服务器地址IP地址
     */
    private String host;
    /**
     * FTP 端口
     */
    private int port;


    /**
     * 构造基于密码认证的sftp对象
     *
     * @param username
     * @param password
     * @param host
     * @param port
     */
    public SFTPUtil(String username, String password, String host, int port) {
        this.username = username;
        this.password = password;
        this.host = host;
        this.port = port;
    }

    /**
     * 构造基于秘钥认证的sftp对象
     *
     * @param username
     * @param host
     * @param port
     * @param privateKey
     */
    public void SFTPUtil(String username, String host, int port, String privateKey) {
        this.username = username;
        this.host = host;
        this.port = port;
        this.privateKey = privateKey;
    }

    public void SFTPUtil() {
    }

    /**
     * 连接sftp服务器
     *
     * @throws Exception
     */
    public void login() {
        try {
            JSch jsch = new JSch();
            if (privateKey != null) {
                jsch.addIdentity(privateKey);// 设置私钥
                log.info("sftp connect,path of private key file:{}", privateKey);
            }
            log.info("sftp connect by host:{} username:{}", host, username);

            session = jsch.getSession(username, host, port);
            log.info("Session is build");
            if (password != null) {
                session.setPassword(password);
            }
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");

            session.setConfig(config);
            session.connect();
            log.info("Session is connected");

            Channel channel = session.openChannel("sftp");
            channel.connect();
            log.info("channel is connected");

            sftp = (ChannelSftp) channel;
            log.info(String.format("sftp server host:[%s] port:[%s] is connect successfull", host, port));
        } catch (JSchException e) {
            log.error("Cannot connect to specified sftp server : {}:{} \n Exception message is: {}", new Object[]{host, port, e.getMessage()});
        }
    }

    /**
     * 关闭连接 server
     */
    public void logout() {
        if (sftp != null) {
            if (sftp.isConnected()) {
                sftp.disconnect();
                log.info("sftp is closed already");
            }
        }
        if (session != null) {
            if (session.isConnected()) {
                session.disconnect();
                log.info("sshSession is closed already");
            }
        }
    }

    /**
     * 将输入流的数据上传到sftp作为文件
     *
     * @param directory    上传到该目录
     * @param sftpFileName sftp端文件名
     * @param input           输入流
     * @throws SftpException
     * @throws Exception
     */
    public void upload(String directory, String sftpFileName, InputStream input) throws SftpException {
        try {
            sftp.cd(directory);
        } catch (SftpException e) {
            log.warn("directory is not exist");
            sftp.mkdir(directory);
            sftp.cd(directory);
        }
        sftp.put(input, sftpFileName);
        log.info("file:{} is upload successful", sftpFileName);
    }

    /**
     * 上传单个文件
     *
     * @param directory  上传到sftp目录
     * @param uploadFile 要上传的文件,包括路径
     * @throws FileNotFoundException
     * @throws SftpException
     * @throws Exception
     */
    public void upload(String directory, String uploadFile) throws FileNotFoundException, SftpException {
        File file = new File(uploadFile);
        upload(directory, file.getName(), new FileInputStream(file));
    }

    /**
     * 将byte[]上传到sftp,作为文件。注意:从String生成byte[]是,要指定字符集。
     *
     * @param directory    上传到sftp目录
     * @param sftpFileName 文件在sftp端的命名
     * @param byteArr      要上传的字节数组
     * @throws SftpException
     * @throws Exception
     */
    public void upload(String directory, String sftpFileName, byte[] byteArr) throws SftpException {
        upload(directory, sftpFileName, new ByteArrayInputStream(byteArr));
    }

    /**
     * 将字符串按照指定的字符编码上传到sftp
     *
     * @param directory    上传到sftp目录
     * @param sftpFileName 文件在sftp端的命名
     * @param dataStr      待上传的数据
     * @param charsetName  sftp上的文件,按该字符编码保存
     * @throws UnsupportedEncodingException
     * @throws SftpException
     * @throws Exception
     */
    public void upload(String directory, String sftpFileName, String dataStr, String charsetName) throws UnsupportedEncodingException, SftpException {
        upload(directory, sftpFileName, new ByteArrayInputStream(dataStr.getBytes(charsetName)));
    }

    /**
     * 下载文件
     *
     * @param directory    下载目录
     * @param downloadFile 下载的文件
     * @param saveFile     存在本地的路径
     * @throws SftpException
     * @throws FileNotFoundException
     * @throws Exception
     */
    public void download(String directory, String downloadFile, String saveFile) throws SftpException, FileNotFoundException {
        if (directory != null && !"".equals(directory)) {
            sftp.cd(directory);
        }
        File file = new File(saveFile);
        sftp.get(downloadFile, new FileOutputStream(file));
        log.info("file:{} is download successful", downloadFile);
    }

    /**
     * 下载文件
     *
     * @param directory    下载目录
     * @param downloadFile 下载的文件名
     * @return 字节数组
     * @throws SftpException
     * @throws IOException
     * @throws Exception
     */
    public byte[] download(String directory, String downloadFile) throws SftpException, IOException {
        if (directory != null && !"".equals(directory)) {
            sftp.cd(directory);
        }
        InputStream is = sftp.get(downloadFile);

        byte[] fileData = IOUtils.toByteArray(is);

        log.info("file:{} is download successful", downloadFile);
        return fileData;
    }

    /**
     * 删除文件
     *
     * @param directory  要删除文件所在目录
     * @param deleteFile 要删除的文件
     * @throws SftpException
     * @throws Exception
     */
    public void delete(String directory, String deleteFile) throws SftpException {
        sftp.cd(directory);
        sftp.rm(deleteFile);
    }

    /**
     * 列出目录下的文件
     *
     * @param directory 要列出的目录
     * @return
     * @throws SftpException
     */
    public Vector<?> listFiles(String directory) throws SftpException {
        return sftp.ls(directory);
    }


    public ArrayList<String> listFile(String dir) throws SftpException{
        ArrayList<String> files = new ArrayList<String>();
        sftp.cd(dir);
        Vector<String> lss = sftp.ls("*");
        for (int i = 0; i < lss.size(); i++)
        {
            Object obj = lss.elementAt(i);
            if (obj instanceof com.jcraft.jsch.ChannelSftp.LsEntry)
            {
                ChannelSftp.LsEntry entry = (ChannelSftp.LsEntry) obj;
                if (true && !entry.getAttrs().isDir())
                {
                    files.add(entry.getFilename());
                }
                if (true && entry.getAttrs().isDir())
                {
                    if (!entry.getFilename().equals(".") && !entry.getFilename().equals(".."))
                    {
                        files.add(entry.getFilename());
                    }
                }
            }
        }
        return files;
    }
    //上传文件测试
    public static void main(String[] args) throws SftpException {
//        SFTPUtil sftp = new SFTPUtil("root", "li983798.", "47.102.142.218", 22);
        SFTPUtil sftp = new SFTPUtil("hzwq", "hzwq2021", "192.168.15.71", 22);
//  		File file = new File("F:\\aeac.tar.gz");
        InputStream is = null;
        System.out.println("file.exists()");
        try {
            sftp.login();
            MockMultipartFile multipartFile = null;

            try (InputStream inputStream = new BufferedInputStream(new FileInputStream("C:\\Users\\lixin\\Desktop\\x1.zip"))) {
                multipartFile = new MockMultipartFile(
                        "test.zip", "test.zip", ContentType.APPLICATION_OCTET_STREAM.toString(), inputStream);
            }
            //上传文件
            sftp.upload("/home/hzwq/C_MODEL/test/20220331","计算模型.zip",multipartFile.getInputStream());
            System.out.println("上传成功");
            //下载文件
            //byte[] download = sftp.download("/usr/local", "xxx.zip");

            //列出当前目录下的所有文件目录或文件
//            ArrayList<String> strings = sftp.listFile("/usr/local/zookeeper");
//            System.out.println(strings);
//            Vector files = sftp.listFiles("/usr/local/zookeeper");
//            Iterator iterator = files.iterator();
//            List<String> fileList = new ArrayList<>();
//            while (iterator.hasNext()) {
//                ChannelSftp.LsEntry file = (ChannelSftp.LsEntry) iterator.next();
//                //文件名称
//                String fileName = file.getFilename();
//                fileList.add(fileName);
//            }
//            System.out.println("--------------------------------------");
//            System.out.println(fileList);


        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            sftp.logout();
        }

    }
}

2、ZIP工具类

        <!--压缩或解压缩zip 防止会出现中文乱码问题-->
        <dependency>
            <groupId>org.apache.ant</groupId>
            <artifactId>ant</artifactId>
            <version>1.9.4</version>
        </dependency>
        
        <!-- 解压缩 https://mvnrepository.com/artifact/org.apache.commons/commons-compress -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-compress</artifactId>
            <version>1.18</version>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.22</version>
        </dependency>

import cn.hutool.core.util.CharsetUtil;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveException;
import org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.archivers.ArchiveStreamFactory;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;
import org.apache.tools.zip.ZipOutputStream;

import java.io.*;
import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.*;
import java.util.*;
import java.util.zip.ZipInputStream;


/**
 * @ClassName ZipUtil
 * @Description 压缩或解压缩zip:由于直接使用java.util.zip工具包下的类,会出现中文乱码问题,所以使用ant.jar中的org.apache.tools.zip下的工具类
 * @Author
 * @Date 2020/3/8 11:30
 * @Version 1.0
 */
public class ZipUtil {

    /**
     * 直接替换zip中的文件
     */
    public void replace() {
        Path myFilePath = Paths.get("C:\\Users\\lixin\\Desktop\\xxx.docx");
        Path zipFilePath = Paths.get("C:\\Users\\lixin\\Desktop\\test2.zip");

        try (FileSystem fs = FileSystems.newFileSystem(zipFilePath, null)) {
            Path fileInsideZipPath = fs.getPath("new 2.txt");
            System.out.println(fileInsideZipPath.toAbsolutePath());
            Files.copy(myFilePath, fileInsideZipPath, StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static boolean add(String zipUrl, String fromUrl, String toUrl) throws IOException {
        zipUrl = "D:/temp/playbook_1936_拍照商品照片.zip";
        fromUrl = "C:/图片/000.png";
        toUrl = "/33/44/000.png";

        Map<String, String> env = new HashMap<>();
        env.put("create", "true");
        //使用语法定位文件系统
        //在java.net.JarURLConnection中定义
        Path path = Paths.get(zipUrl);
        URI uri = URI.create("jar:" + path.toUri());
        try (FileSystem zipfs = FileSystems.newFileSystem(uri, env)) {
            Path externalTxtFile = Paths.get(fromUrl);
            Path pathInZipfile = zipfs.getPath(toUrl);
            //将文件复制到zip文件中
            Files.copy(externalTxtFile, pathInZipfile, StandardCopyOption.REPLACE_EXISTING);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 输出压缩文件中的名称
     */
    public static void fileExist() {
        ZipInputStream in = null;
        java.util.zip.ZipEntry entry = null;
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream(new File("E:\\gd\\xxx.zip"));
            BufferedInputStream bis = new BufferedInputStream(inputStream);
            //String code = CodeDetector.getEncode(bis, false);
            in = new ZipInputStream(bis, CharsetUtil.CHARSET_GBK);
            while ((entry = in.getNextEntry()) != null) {
                if (entry.isDirectory()) {
                    System.out.println("文件夹" + entry.getName());
                } else {
                    //压缩文件夹中的文件名称
                    System.out.println("文件名 " + entry.getName());
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                in.close();
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    // tar压缩
    public void tar() throws IOException {
        //源文件或目录
        File srcDir = new File("/test");
        //目标文件
        String targetFile = "/test.tar";
        try (TarArchiveOutputStream tos = new TarArchiveOutputStream(
                new FileOutputStream(targetFile))) {
            tarRecursive(tos, srcDir, "");
        }
    }

    /**
     * 递归压缩目录下的文件和目录
     *
     * @param tos
     * @param srcFile
     * @param basePath
     * @throws IOException
     */
    private void tarRecursive(TarArchiveOutputStream tos, File srcFile, String basePath) throws IOException {
        if (srcFile.isDirectory()) {
            File[] files = srcFile.listFiles();
            String nextBasePath = basePath + srcFile.getName() + "/";
            if (ArrayUtils.isEmpty(files)) {
                // 空目录
                TarArchiveEntry entry = new TarArchiveEntry(srcFile, nextBasePath);
                tos.putArchiveEntry(entry);
                tos.closeArchiveEntry();
            } else {
                for (File file : files) {
                    tarRecursive(tos, file, nextBasePath);
                }
            }
        } else {
            TarArchiveEntry entry = new TarArchiveEntry(srcFile, basePath + srcFile.getName());
            tos.putArchiveEntry(entry);
            FileUtils.copyFile(srcFile, tos);
            tos.closeArchiveEntry();
        }
    }

    // tar解压
    public void untar() throws IOException {
        InputStream is = new FileInputStream("/test.tar");
        String outPath = "/test";
        try (TarArchiveInputStream tis = new TarArchiveInputStream(is)) {
            TarArchiveEntry nextEntry;
            while ((nextEntry = tis.getNextTarEntry()) != null) {
                String name = nextEntry.getName();
                File file = new File(outPath, name);
                //如果是目录,创建目录
                if (nextEntry.isDirectory()) {
                    file.mkdir();
                } else {
                    //文件则写入具体的路径中
                    FileUtils.copyToFile(tis, file);
                    file.setLastModified(nextEntry.getLastModifiedDate().getTime());
                }
            }
        }
    }

    /**
     * 解压缩.zip文件
     *
     * @param zipFile   压缩文件路径
     * @param targetDir 要解压存放的目录
     * @throws IOException
     * @throws ArchiveException
     */
    public static void decompressor(String zipFile, String targetDir) throws IOException, ArchiveException {
        File archiveFile = new File(zipFile);
        // 文件不存在,跳过
        if (!archiveFile.exists())
            return;
        ArchiveInputStream input = new ArchiveStreamFactory().createArchiveInputStream(new BufferedInputStream(new FileInputStream(zipFile)));
        ArchiveEntry entry = null;
        while ((entry = input.getNextEntry()) != null) {
            if (!input.canReadEntryData(entry)) {
                // log something?
                continue;
            }
            String name = Paths.get(targetDir, entry.getName()).toString();
            File f = new File(name);
            if (entry.isDirectory()) {
                if (!f.isDirectory() && !f.mkdirs()) {
                    throw new IOException("failed to create directory " + f);
                }
            } else {
                File parent = f.getParentFile();
                if (!parent.isDirectory() && !parent.mkdirs()) {
                    throw new IOException("failed to create directory " + parent);
                }
                try (OutputStream o = Files.newOutputStream(f.toPath())) {
                    IOUtils.copy(input, o);
                }
            }
        }
        input.close();
    }

    /**
     * 解压 zip 文件
     *
     * @param zipFile zip 压缩文件
     * @param destDir zip 压缩文件解压后保存的目录
     * @return 返回 zip 压缩文件里的文件名的 list
     * @throws Exception
     */
    public static List<String> unZip(File zipFile, String destDir) throws Exception {
        // 如果 destDir 为 null, 空字符串, 或者全是空格, 则解压到压缩文件所在目录
        if (StringUtils.isBlank(destDir)) {
            destDir = zipFile.getParent();
        }

        destDir = destDir.endsWith(File.separator) ? destDir : destDir + File.separator;
        ZipArchiveInputStream is = null;
        List<String> fileNames = new ArrayList<String>();

        try {
            is = new ZipArchiveInputStream(new BufferedInputStream(new FileInputStream(zipFile), BUFFER_SIZE));
            ZipArchiveEntry entry = null;

            while ((entry = is.getNextZipEntry()) != null) {
                fileNames.add(entry.getName());

                if (entry.isDirectory()) {
                    File directory = new File(destDir, entry.getName());
                    directory.mkdirs();
                } else {
                    OutputStream os = null;
                    try {
                        os = new BufferedOutputStream(new FileOutputStream(new File(destDir, entry.getName())), BUFFER_SIZE);
                        IOUtils.copy(is, os);
                    } finally {
                        IOUtils.closeQuietly(os);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        } finally {
            IOUtils.closeQuietly(is);
        }

        return fileNames;
    }

    /**
     * @param zip      压缩目的地址
     * @param srcFiles 压缩的源文件
     * @return void
     * @Author AlphaJunS
     * @Date 11:32 2020/3/8
     * @Description
     */
    public static void zipFile(String zip, File[] srcFiles) {
        try {
            if (zip.endsWith(".zip") || zip.endsWith(".ZIP")) {
                FileOutputStream fos = new FileOutputStream(new File(zip));
                ZipOutputStream _zipOut = new ZipOutputStream(fos);
                _zipOut.setEncoding("GBK");
                for (File _f : srcFiles) {
                    handlerFile(zip, _zipOut, _f, "");
                }
                fos.close();
                _zipOut.close();
            } else {
                System.out.println("target file[" + zip + "] is not .zip type file");
            }
        } catch (FileNotFoundException e) {
        } catch (IOException e) {
        }
    }

    /**
     * @param zip     压缩的目的地址
     * @param zipOut
     * @param srcFile 被压缩的文件信息
     * @param path    在zip中的相对路径
     * @return void
     * @Author
     * @Description
     */
    private static void handlerFile(String zip, ZipOutputStream zipOut, File srcFile, String path) throws IOException {
        System.out.println(" begin to compression file[" + srcFile.getName() + "]");
        if (!"".equals(path) && !path.endsWith(File.separator)) {
            path += File.separator;
        }
        if (!srcFile.getPath().equals(zip)) {
            if (srcFile.isDirectory()) {
                File[] _files = srcFile.listFiles();
                if (_files.length == 0) {
                    zipOut.putNextEntry(new ZipEntry(path + srcFile.getName() + File.separator));
                    zipOut.closeEntry();
                } else {
                    for (File _f : _files) {
                        handlerFile(zip, zipOut, _f, path + srcFile.getName());
                    }
                }
            } else {
                InputStream _in = new FileInputStream(srcFile);
                zipOut.putNextEntry(new ZipEntry(path + srcFile.getName()));
                int len = 0;
                byte[] _byte = new byte[1024];
                while ((len = _in.read(_byte)) > 0) {
                    zipOut.write(_byte, 0, len);
                }
                _in.close();
                zipOut.closeEntry();
            }
        }
    }

    /**
     * @param zipPath 待解压缩的ZIP文件名
     * @param descDir 目标目录
     * @return java.util.List<java.io.File>
     * @Author AlphaJunS
     * @Description 解压缩ZIP文件,将ZIP文件里的内容解压到targetDIR目录下
     */
    public static List<File> unzipFile(String zipPath, String descDir) {
        return unzipFile(new File(zipPath), descDir);
    }

    /**
     * @param zipFile 解压缩文件
     * @param descDir 压缩的目标地址,如:D:\\测试 或 /mnt/d/测试
     * @return java.util.List<java.io.File>
     * @Author
     * @Description 对.zip文件进行解压缩 默认只支持GBK格式的文件
     */
    public static List<File> unzipFile(File zipFile, String descDir) {
        List<File> _list = new ArrayList<File>();
        try {
            ZipFile _zipFile = new ZipFile(zipFile, "GBK");
            for (Enumeration entries = _zipFile.getEntries(); entries.hasMoreElements(); ) {
                ZipEntry entry = (ZipEntry) entries.nextElement();
                File _file = new File(descDir + File.separator + entry.getName());
                if (entry.isDirectory()) {
                    _file.mkdirs();
                } else {
                    File _parent = _file.getParentFile();
                    if (!_parent.exists()) {
                        _parent.mkdirs();
                    }
                    InputStream _in = _zipFile.getInputStream(entry);
                    OutputStream _out = new FileOutputStream(_file);
                    int len = 0;
                    byte[] _byte = new byte[1024];
                    while ((len = _in.read(_byte)) > 0) {
                        _out.write(_byte, 0, len);
                    }
                    _in.close();
                    _out.flush();
                    _out.close();
                    _list.add(_file);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return _list;
    }

    /**
     * @param delpath 要删除的文件夹或文件路径
     * @return void
     * @Author AlphaJunS
     * @Description 对临时生成的文件夹和文件夹下的文件进行删除
     */
    public static void deletefile(String delpath) {
        try {
            File file = new File(delpath);
            if (!file.isDirectory()) {
                file.delete();
            } else if (file.isDirectory()) {
                String[] fileList = file.list();
                for (int i = 0; i < fileList.length; i++) {
                    File delfile = new File(delpath + File.separator + fileList[i]);
                    if (!delfile.isDirectory()) {
                        delfile.delete();
                    } else if (delfile.isDirectory()) {
                        deletefile(delpath + File.separator + fileList[i]);
                    }
                }
                file.delete();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //##############################################################原生zip
    private static final int BUFFER_SIZE = 2 * 1024;

    /**
     * 压缩成ZIP 方法1
     *
     * @param srcDir           压缩文件夹路径
     * @param out              压缩文件输出流
     * @param KeepDirStructure 是否保留原来的目录结构,true:保留目录结构;
     *                         false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败)
     * @throws RuntimeException 压缩失败会抛出运行时异常
     */
    public static void toZip(String srcDir, OutputStream out, boolean KeepDirStructure)
            throws RuntimeException {

        long start = System.currentTimeMillis();
        java.util.zip.ZipOutputStream zos = null;
        try {
            zos = new java.util.zip.ZipOutputStream(out);
            File sourceFile = new File(srcDir);
            compress(sourceFile, zos, sourceFile.getName(), KeepDirStructure);
            long end = System.currentTimeMillis();
            //log.info("压缩完成,耗时:{}" + (end - start) +" ms");
        } catch (Exception e) {
            throw new RuntimeException("zip error from ZipUtils", e);
        } finally {
            if (zos != null) {
                try {
                    zos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    /**
     * 压缩成ZIP 方法2
     *
     * @param srcFiles 需要压缩的文件列表
     * @param out      压缩文件输出流
     * @throws RuntimeException 压缩失败会抛出运行时异常
     */
    public static void toZip(List<File> srcFiles, OutputStream out) throws RuntimeException {
        long start = System.currentTimeMillis();
        java.util.zip.ZipOutputStream zos = null;
        try {
            zos = new java.util.zip.ZipOutputStream(out);
            for (File srcFile : srcFiles) {
                byte[] buf = new byte[BUFFER_SIZE];
                zos.putNextEntry(new java.util.zip.ZipEntry(srcFile.getName()));
                int len;
                FileInputStream in = new FileInputStream(srcFile);
                while ((len = in.read(buf)) != -1) {
                    zos.write(buf, 0, len);
                }
                zos.closeEntry();
                in.close();
            }
            long end = System.currentTimeMillis();
            System.out.println("压缩完成,耗时:" + (end - start) + " ms");
        } catch (Exception e) {
            throw new RuntimeException("zip error from ZipUtils", e);
        } finally {
            if (zos != null) {
                try {
                    zos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**
     * 递归压缩方法
     *
     * @param sourceFile       源文件
     * @param zos              zip输出流
     * @param name             压缩后的名称
     * @param KeepDirStructure 是否保留原来的目录结构,true:保留目录结构;
     *                         false:所有文件跑到压缩包根目录下(注意:不保留目录结构可能会出现同名文件,会压缩失败)
     * @throws Exception
     */
    public static void compress(File sourceFile, java.util.zip.ZipOutputStream zos, String name,
                                boolean KeepDirStructure) throws Exception {
        byte[] buf = new byte[BUFFER_SIZE];
        if (sourceFile.isFile()) {
            // 向zip输出流中添加一个zip实体,构造器中name为zip实体的文件的名字
            zos.putNextEntry(new java.util.zip.ZipEntry(name));
            // copy文件到zip输出流中
            int len;
            FileInputStream in = new FileInputStream(sourceFile);
            while ((len = in.read(buf)) != -1) {
                zos.write(buf, 0, len);
            }
            // Complete the entry
            zos.closeEntry();
            in.close();
        } else {
            File[] listFiles = sourceFile.listFiles();
            if (listFiles == null || listFiles.length == 0) {
                // 需要保留原来的文件结构时,需要对空文件夹进行处理
                if (KeepDirStructure) {
                    // 空文件夹的处理
                    zos.putNextEntry(new java.util.zip.ZipEntry(name + "/"));
                    // 没有文件,不需要文件的copy
                    zos.closeEntry();
                }

            } else {
                for (File file : listFiles) {
                    // 判断是否需要保留原来的文件结构
                    if (KeepDirStructure) {
                        // 注意:file.getName()前面需要带上父文件夹的名字加一斜杠,
                        // 不然最后压缩包中就不能保留原来的文件结构,即:所有文件都跑到压缩包根目录下了
                        compress(file, zos, name + "/" + file.getName(), KeepDirStructure);
                    } else {
                        compress(file, zos, file.getName(), KeepDirStructure);
                    }

                }
            }
        }
    }

}

3、list转换

public class ObjectToBeanUtils {

    /*
     *  Object对象转换为List<T>
     */
    public static <t> List<t> objtolist(Object obj, Class<t> cla) throws Exception {
        List<t> list = new ArrayList<t>();
        if (obj instanceof ArrayList<?>) {
            for (Object o : (List<?>) obj) {
                list.add(cla.cast(o));
            }
            return list;
        }
        return null;
    }


    /**
     * 把List<Object[]>转换成List<T>
     */
    public static <T> List<T> objectToBean(List<Object[]> objList, Class<T> clz) throws Exception {
        if (objList == null || objList.size() == 0) {
            return null;
        }

        Class<?>[] cz = null;
        Constructor<?>[] cons = clz.getConstructors();
        for (Constructor<?> ct : cons) {
            Class<?>[] clazz = ct.getParameterTypes();
            if (objList.get(0).length == clazz.length) {
                cz = clazz;
                break;
            }
        }

        List<T> list = new ArrayList<T>();
        for (Object[] obj : objList) {
            Constructor<T> cr = clz.getConstructor(cz);
            list.add(cr.newInstance(obj));
        }
        return list;
    }
}

4、HiveDbUtil 根据类获取其指定的字段信息


import lombok.Data;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.Optional;

/**
 * @author lixing
 * @date 2021/9/3 10:51
 */
@Service
public class HiveDbUtil {
    static final Integer defaultLimitcount = 1000;

    /**
     * 查询表名
     * @param cls
     * @return
     */
    public static String getTableName(Class cls) {
//        boolean annotationPresent = cls.isAnnotationPresent(Table.class);  判断person对象上是否有Table注解
//        Table infoAnno = (Table) cls.getAnnotation(Table.class);//获取该对象上Table类型的注解
//        Annotation[] annotations = cls.getAnnotations();//返回所有的注解

        Annotation annotation = cls.getAnnotation(Table.class);
        Assert.notNull(annotation, cls.toString() + "未设置@Table注释");
        Table table = (Table) annotation;
        return table.name();
    }

    /**
     * 查询表的主键名
     * @param cls
     * @return
     */
    public static String getPrimaryKey(Class cls) {
        Field[] fields = cls.getDeclaredFields();
        String keyName = null;
        for (Field field : fields) {
            if (field.getAnnotation(Id.class) != null && field.getAnnotation(Column.class) != null) {
                keyName = field.getAnnotation(Column.class).name();
                break;
            }
        }
        Assert.notNull(cls.getName(), cls.toString() + "未设置@Id @Column注解");
        return keyName;
    }

    /**
     * 根据实体类的名称查询出真实的字段名
     * @param cls
     * @param name
     * @return
     */
    public static String getColumnName(Class cls, String name) {
        Field[] fields = cls.getDeclaredFields();
        String columnName = null;
        for (Field field : fields) {
            if (name.equals(field.getName()) && field.getAnnotation(Column.class) != null) {
                columnName = field.getAnnotation(Column.class).name();
                break;
            }
        }
        Assert.notNull(columnName, cls.toString() + "未找到" + name + "对应的字段");
        return columnName;
    }

    /**
     * 组合得到通过主键查询数据
     * @param cls
     * @return
     */
    @SuppressWarnings("all")//抑制编译器产生警告信息。
    public static String getFindByIdSql(Class cls) {
        return String.format("select * from %s where %s=?", getTableName(cls), getPrimaryKey(cls));
    }



    /**
     * all to suppress all warnings (抑制所有警告)
     * boxing to suppress warnings relative to boxing/unboxing operations(抑制装箱、拆箱操作时候的警告)
     * cast to suppress warnings relative to cast operations (抑制映射相关的警告)
     * dep-ann to suppress warnings relative to deprecated annotation(抑制启用注释的警告)
     * deprecation to suppress warnings relative to deprecation(抑制过期方法警告)
     * fallthrough to suppress warnings relative to missing breaks in switch statements(抑制确在switch中缺失breaks的警告)
     * finally to suppress warnings relative to finally block that don’t return (抑制finally模块没有返回的警告)
     * hiding to suppress warnings relative to locals that hide variable()
     * incomplete-switch to suppress warnings relative to missing entries in a switch statement (enum case)(忽略没有完整的switch语句)
     * nls to suppress warnings relative to non-nls string literals(忽略非nls格式的字符)
     * null to suppress warnings relative to null analysis(忽略对null的操作)
     * rawtypes to suppress warnings relative to un-specific types when using generics on class params(使用generics时忽略没有指定相应的类型)
     * restriction to suppress warnings relative to usage of discouraged or forbidden references
     * serial to suppress warnings relative to missing serialVersionUID field for a serializable class(忽略在serializable类中没有声明serialVersionUID变量)
     * static-access to suppress warnings relative to incorrect static access(抑制不正确的静态访问方式警告)
     * synthetic-access to suppress warnings relative to unoptimized access from inner classes(抑制子类没有按最优方法访问内部类的警告)
     * unchecked to suppress warnings relative to unchecked operations(抑制没有进行类型检查操作的警告)
     * unqualified-field-access to suppress warnings relative to field access unqualified (抑制没有权限访问的域的警告)
     * unused to suppress warnings relative to unused code  (抑制没被使用过的代码的警告)
     */
}

5、HttpUtil请求


import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;

/**
 * java原生HttpURLConnection
 * @author lixing
 * @date 2021/9/17 9:38
 */
@Slf4j
public class HttpUtil {

    /**
     * 向指定URL发送GET方法的请求
     *
     * @param httpurl 请求参数用?拼接在url后边,请求参数应该是 name1=value1&name2=value2 的形式。
     * @return result 所代表远程资源的响应结果
     */
    public static String doGet(String httpurl) {
        HttpURLConnection connection = null;
        InputStream is = null;
        BufferedReader br = null;
        String result = null;// 返回结果字符串
        try {
            // 创建远程url连接对象
            URL url = new URL(httpurl);
            // 通过远程url连接对象打开一个连接,强转成httpURLConnection类
            connection = (HttpURLConnection) url.openConnection();
            // 设置连接方式:get
            connection.setRequestMethod("GET");
            // 设置连接主机服务器的超时时间:15000毫秒
            connection.setConnectTimeout(15000);
            // 设置读取远程返回的数据时间:60000毫秒
            connection.setReadTimeout(60000);
            // 发送请求
            connection.connect();
            // 通过connection连接,获取输入流
            if (connection.getResponseCode() == 200) {
                is = connection.getInputStream();
                // 封装输入流is,并指定字符集
                br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
                // 存放数据
                StringBuffer sbf = new StringBuffer();
                String temp = null;
                while ((temp = br.readLine()) != null) {
                    sbf.append(temp);
                    sbf.append("\r\n");
                }
                result = sbf.toString();
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            if (null != br) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            connection.disconnect();// 关闭远程连接
        }

        return result;
    }

    /**
     * 向指定 URL 发送POST方法的请求
     *
     * @param httpUrl 发送请求的 URL
     * @param param   请求参数应该是{"key":"==g43sEvsUcbcunFv3mHkIzlHO4iiUIT R7WwXuSVKTK0yugJnZSlr6qNbxsL8OqCUAFyCDCoRKQ882m6cTTi0q9uCJsq JJvxS+8mZVRP/7lWfEVt8/N9mKplUA68SWJEPSXyz4MDeFam766KEyvqZ99d"}的形式。
     * @return 所代表远程资源的响应结果
     */
    public static String doPost(String httpUrl, String param) {

        HttpURLConnection connection = null;
        InputStream is = null;
        OutputStream os = null;
        BufferedReader br = null;
        String result = null;
        try {
            URL url = new URL(httpUrl);
            // 通过远程url连接对象打开连接
            connection = (HttpURLConnection) url.openConnection();
            // 设置连接请求方式
            connection.setRequestMethod("POST");
            // 设置连接主机服务器超时时间:15000毫秒
            connection.setConnectTimeout(15000);
            // 设置读取主机服务器返回数据超时时间:60000毫秒
            connection.setReadTimeout(60000);

            // 默认值为:false,当向远程服务器传送数据/写数据时,需要设置为true
            connection.setDoOutput(true);
            // 默认值为:true,当前向远程服务读取数据时,设置为true,该参数可有可无
            connection.setDoInput(true);
            // 设置传入参数的格式:请求参数应该是 name1=value1&name2=value2 的形式。
            connection.setRequestProperty("Content-Type", "application/json");
            // 设置鉴权信息:Authorization: Bearer da3efcbf-0845-4fe3-8aba-ee040be542c0
            //connection.setRequestProperty("Authorization", "Bearer da3efcbf-0845-4fe3-8aba-ee040be542c0");
            // 通过连接对象获取一个输出流
            os = connection.getOutputStream();
            // 通过输出流对象将参数写出去/传输出去,它是通过字节数组写出的
            os.write(param.getBytes());
            // 通过连接对象获取一个输入流,向远程读取
            if (connection.getResponseCode() == 200) {

                is = connection.getInputStream();
                // 对输入流对象进行包装:charset根据工作项目组的要求来设置
                br = new BufferedReader(new InputStreamReader(is, "UTF-8"));

                StringBuffer sbf = new StringBuffer();
                String temp = null;
                // 循环遍历一行一行读取数据
                while ((temp = br.readLine()) != null) {
                    sbf.append(temp);
                    sbf.append("\r\n");
                }
                result = sbf.toString();
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            if (null != br) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != os) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            // 断开与远程地址url的连接
            connection.disconnect();
        }
        return result;
    }

    /**
     * @param httpUrl 请求的url
     * @param param   form表单的参数(key,value形式)
     * @return
     */
    public static String doPostForm(String httpUrl, Map param) {

        HttpURLConnection connection = null;
        InputStream is = null;
        OutputStream os = null;
        BufferedReader br = null;
        String result = null;
        try {
            URL url = new URL(httpUrl);
            // 通过远程url连接对象打开连接
            connection = (HttpURLConnection) url.openConnection();
            // 设置连接请求方式
            connection.setRequestMethod("POST");
            // 设置连接主机服务器超时时间:15000毫秒
            connection.setConnectTimeout(15000);
            // 设置读取主机服务器返回数据超时时间:60000毫秒
            connection.setReadTimeout(60000);

            // 默认值为:false,当向远程服务器传送数据/写数据时,需要设置为true
            connection.setDoOutput(true);
            // 默认值为:true,当前向远程服务读取数据时,设置为true,该参数可有可无
            connection.setDoInput(true);
            // 设置传入参数的格式:请求参数应该是 name1=value1&name2=value2 的形式。
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            // 设置鉴权信息:Authorization: Bearer da3efcbf-0845-4fe3-8aba-ee040be542c0
            //connection.setRequestProperty("Authorization", "Bearer da3efcbf-0845-4fe3-8aba-ee040be542c0");
            // 通过连接对象获取一个输出流
            os = connection.getOutputStream();
            // 通过输出流对象将参数写出去/传输出去,它是通过字节数组写出的(form表单形式的参数实质也是key,value值的拼接,类似于get请求参数的拼接)
            os.write(createLinkString(param).getBytes());
            // 通过连接对象获取一个输入流,向远程读取
            if (connection.getResponseCode() == 200) {

                is = connection.getInputStream();
                // 对输入流对象进行包装:charset根据工作项目组的要求来设置
                br = new BufferedReader(new InputStreamReader(is, "UTF-8"));

                StringBuffer sbf = new StringBuffer();
                String temp = null;
                // 循环遍历一行一行读取数据
                while ((temp = br.readLine()) != null) {
                    sbf.append(temp);
                    sbf.append("\r\n");
                }
                result = sbf.toString();
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            if (null != br) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != os) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            // 断开与远程地址url的连接
            connection.disconnect();
        }
        return result;
    }

    /**
     * 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
     *
     * @param params 需要排序并参与字符拼接的参数组
     * @return 拼接后字符串
     */
    public static String createLinkString(Map<String, String> params) {

        List<String> keys = new ArrayList<String>(params.keySet());
        Collections.sort(keys);

        StringBuilder prestr = new StringBuilder();
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = params.get(key);
            if (i == keys.size() - 1) {// 拼接时,不包括最后一个&字符
                prestr.append(key).append("=").append(value);
            } else {
                prestr.append(key).append("=").append(value).append("&");
            }
        }

        return prestr.toString();
    }


    public static void main(String[] args) {
        String url = "http://localhost:8082/api/conf/findConfList?type=1";
        String getResult = HttpUtil.doGet(url);
        System.out.println(getResult);

        url = "http://localhost:8082/api/core/login";
        JSONObject json = new JSONObject();
        json.put("key", "==g43sEvsUcbcunFv3mHkIzlHO4iiUIT R7WwXuSVKTK0yugJnZSlr6qNbxsL8OqCUAFyCDCoRKQ882m6cTTi0q9uCJsq JJvxS+8mZVRP/7lWfEVt8/N9mKplUA68SWJEPSXyz4MDeFam766KEyvqZ99d");
        String postResult = HttpUtil.doPost(url, json.toJSONString());
        System.out.println(postResult);

        url = "http://localhost:8082/api/test/testSendForm";
        Map<String, String> map = new HashMap<>();
        map.put("name", "测试表单请求");
        String formResult = HttpUtil.doPostForm(url, map);
        System.out.println(formResult);

    }

}

6、自定义注解

import java.lang.annotation.*;


//@Documented:注解信息会被添加到Java文档中
//@Retention:注解的生命周期,表示注解会被保留到什么阶段,可以选择编译阶段、类加载阶段,或运行阶段
//@Target:注解作用的位置,ElementType.METHOD表示该注解仅能作用于方法上

/**
 * Redis分布式锁注解,用于注释方法,表示该方法需要持有锁的人才能调用
 * @author lixing
 * @date 2021/9/15 9:19
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface RedisLock {

    /**
     * redis的key,留空的话为类名加方法名
     * @return
     */
    String key() default "";

    /**
     * 锁持有时间
     * @return
     */
    long timeout() default 300;

    /**
     * 是否在操作后立即释放锁
     * @return
     */
    boolean releaseOnSuccess() default false;

    /**
     * 如果未获得锁,则执行该方法回调
     * @return
     */
    Class<? extends RedisLockCallback> callback() default RedisLockCallback.class;
}
public interface RedisLockCallback {
    default Object failback(Object ... obj){
        return "cannot get the lock";
    }
}

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * Redis Lock的AOP实现类
 *
 * @author lixing
 * @date 2021/9/15 9:36
 */
@Aspect
@Component
public class RedisLockAspect {
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private ApplicationContext applicationContext;

    /**
     * 切点,拦截带有@RedisLock的注解方法
     */
    @Pointcut("@annotation(com.Utils.redisUtil.RedisLock)")
    void cutPoint() {
    }

    ;

    /*@Before("cutPoint() && @annotation(RedisLock)")
    public void advice(RedisLock lock) {
        System.out.println("--- lock的内容为[" + lock.key() +lock.timeout() + "] ---");
    }*/

    /*@Before("cutPoint() && @annotation(RedisLock)")
    public void advice(JoinPoint joinPoint, RedisLock logger) {
        System.out.println("注解作用的方法名: " + joinPoint.getSignature().getName());

        System.out.println("所在类的简单类名: " + joinPoint.getSignature().getDeclaringType().getSimpleName());

        System.out.println("所在类的完整类名: " + joinPoint.getSignature().getDeclaringType());

        System.out.println("目标方法的声明类型: " + Modifier.toString(joinPoint.getSignature().getModifiers()));
    }*/

    @Around("cutPoint()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        //获取当前请求对象
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String urlStr = request.getRequestURL().toString();
        String remoteUser = request.getRemoteUser();
//        # 可以发挥反射的功能获取关于类的任何信息,例如获取类名如下
//        String className = joinPoint.getTarget().getClass().getName();
//        getSignature());是获取到这样的信息 :修饰符+ 包名+组件名(类名) +方法名
//        获取切入点方法的名字
//        String methodName = joinPoint.getSignature().getName()
//        获取切入点方法的参数列表
//        Object[] args = joinPoint.getArgs();
        //返回结果
//        Object result = point.proceed();
        //获取类的字节码对象,通过字节码对象获取方法信息
        Class<?> targetCls = point.getTarget().getClass();

        Signature signature = point.getSignature();
        //获取方法签名(通过此签名获取目标方法信息)
        MethodSignature methodSignature = (MethodSignature) signature;
        /*Method declaredMethod = targetCls.getDeclaredMethod(methodSignature.getName(), methodSignature.getParameterTypes());
        RedisLock annotation = declaredMethod.getAnnotation(RedisLock.class);*/
        Method method = methodSignature.getMethod();
        //获取方法上的注解
        RedisLock redisLock = method.getAnnotation(RedisLock.class);
        String key = redisLock.key();
        if (StringUtils.isEmpty(key)) {
            String userId = "";
            String paatId = "";
            //获取方法的参数
            for (Object arg : point.getArgs()) {
                //User 可以自行替换
                if (arg instanceof User) {
                    User user = (User) arg;
                    userId = String.valueOf(user.getId());
                    paatId = user.getName();
                }
            }
            key = targetCls.getName() + "-" + method.getName() + "-" + paatId + userId;
        }
        //通过setnx设置值,如果值不存在,则获得锁
        Boolean aBoolean = redisTemplate.opsForValue().setIfAbsent(key, point.getThis().toString(), redisLock.timeout(), TimeUnit.MINUTES);
        if (aBoolean) {
            try {
                //环绕通知=前置+目标方法执行+后置通知,proceed方法就是用于启动目标方法执行的
                Object result = point.proceed();
                return result;
            } finally {
                //如果设置删除操作完成后删除token,则删除key释放锁
                if (redisLock.releaseOnSuccess()) {
                    redisTemplate.delete(key);
                }
            }
        } else {
            //查找错误处理器
            RedisLockCallback redisLockCallback = applicationContext.getBean(redisLock.callback());
            return redisLockCallback.failback(point.getArgs());
        }
    }





/*
public interface JoinPoint {
    String toString();         //连接点所在位置的相关信息
    String toShortString();     //连接点所在位置的简短相关信息
    String toLongString();     //连接点所在位置的全部相关信息
    Object getThis();         //返回AOP代理对象,也就是com.sun.proxy.$Proxy18
    Object getTarget();       //返回目标对象,一般我们都需要它或者(也就是定义方法的接口或类,为什么会是接口呢?这主要是在目标对象本身是动态代理的情况下,例如Mapper。所以返回的是定义方法的对象如aoptest.daoimpl.GoodDaoImpl或com.b.base.BaseMapper<T, E, PK>)
    Object[] getArgs();       //返回被通知方法参数列表
    Signature getSignature();  //返回当前连接点签名  其getName()方法返回方法的FQN,如void aoptest.dao.GoodDao.delete()或com.b.base.BaseMapper.insert(T)(需要注意的是,很多时候我们定义了子类继承父类的时候,我们希望拿到基于子类的FQN,这直接可拿不到,要依赖于AopUtils.getTargetClass(point.getTarget())获取原始代理对象,下面会详细讲解)
    SourceLocation getSourceLocation();//返回连接点方法所在类文件中的位置
    String getKind();        //连接点类型
    StaticPart getStaticPart(); //返回连接点静态部分
}

public interface ProceedingJoinPoint extends JoinPoint {
    public Object proceed() throws Throwable;
    public Object proceed(Object[] args) throws Throwable;
}

JoinPoint.StaticPart:提供访问连接点的静态部分,如被通知方法签名、连接点类型等:
public interface StaticPart {
    Signature getSignature();    //返回当前连接点签名
    String getKind();          //连接点类型
    int getId();               //唯一标识
    String toString();         //连接点所在位置的相关信息
    String toShortString();     //连接点所在位置的简短相关信息
    String toLongString();     //连接点所在位置的全部相关信息
}*/


    /**
     * 根据方法和传入的参数获取请求参数
     */
    private Object getParameter(Method method, Object[] args) {
        List<Object> argList = new ArrayList<>();
        Parameter[] parameters = method.getParameters();
        for (int i = 0; i < parameters.length; i++) {
            //将RequestBody注解修饰的参数作为请求参数
            RequestBody requestBody = parameters[i].getAnnotation(RequestBody.class);
            if (requestBody != null) {
                argList.add(args[i]);
            }
            //将RequestParam注解修饰的参数作为请求参数
            RequestParam requestParam = parameters[i].getAnnotation(RequestParam.class);
            if (requestParam != null) {
                Map<String, Object> map = new HashMap<>();
                String key = parameters[i].getName();
                if (!StringUtils.isEmpty(requestParam.value())) {
                    key = requestParam.value();
                }
                map.put(key, args[i]);
                argList.add(map);
            }
        }
        if (argList.size() == 0) {
            return null;
        } else if (argList.size() == 1) {
            return argList.get(0);
        } else {
            return argList;
        }
    }
}

import java.lang.annotation.*;

/**
 * 接口签名验证
 * @author lixing
 * @date 2021/9/15 10:30
 */
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SecuritySign {

    /**
     * 入参是否验证
     * @return
     */
    boolean isCheck() default true;
}

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.HashMap;

/**
 * @author lixing
 * @date 2021/9/15 10:32
 */
@Aspect
@Component
@Slf4j
public class SecuritySignAspect {

    @Pointcut("@annotation(com.Utils.redisUtil.SecuritySign)")
    void securitySignPointcut() {
    }

    @Around("securitySignPointcut()")
    public Object doAround(ProceedingJoinPoint point) throws Throwable {

        //接收到请求,记录请求内容
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();

        //记录请求内容
        log.info("request url : ", request.getRequestURL().toString());
        log.info("request method : ", request.getMethod());
        log.info("request ip : ", request.getRemoteAddr());

        //获取注解的属性值
        SecuritySign securitySign = ((MethodSignature) point.getSignature()).getMethod().getAnnotation(SecuritySign.class);
        if (securitySign.isCheck()) {
            CommonResponse response = new CommonResponse();
            HashMap<String, Object> requestParam = new HashMap<>();
            Enumeration<String> enums = request.getParameterNames();
            while (enums.hasMoreElements()) {
                String paranName = enums.nextElement();
                //通过参数名获取参数值
                String parameterValue = request.getParameter(paranName);
                requestParam.put(paranName, parameterValue);
            }

            //验证参数是否正确
            if (requestParam == null || StringUtils.isEmpty(requestParam.get("appId"))) {
                response = CommonResponse.fail();
                return response;
            }
            //验证签名是否为空
            if (requestParam == null || StringUtils.isEmpty(requestParam.get("sign"))) {
                response = CommonResponse.fail();
                return response;
            }

        }
        Object object = point.proceed();
        return object;
    }
}

Q.E.D.