springboot 通过url下载文件并上传到OSS

news2024/11/25 18:29:06

DEMO流程

  • 传入一个需要下载并上传的url地址
  • 下载文件
  • 上传文件并返回OSS的url地址

springboot pom文件依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.15</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>springboot-rocketmq</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-demo</name>
    <description>springboot-demo</description>
    <properties>
        <java.version>11</java.version>
        <rocketmq-client-java-version>5.1.3</rocketmq-client-java-version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.13</version>
        </dependency>

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.22</version>
        </dependency>

        <!-- 阿里云oss -->
        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>3.13.2</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

application.yml 文件配置

ali:
  oss:
    #oss end-point
    end-point: 
    #oss access-key-id
    access-key-id: 
    #oss access-key-secret
    access-key-secret: 
    #oss bucket-name
    bucket-name: 
    ali-url: https://${ali.oss.bucket-name}.${ali.oss.end-point}/

FileUtil 工具类


import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.IdUtil;

import java.io.File;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class FileUtil {

    private static final String projectUrl = System.getProperty("user.dir").replaceAll("\\\\", "/");

    public static void deleteFiles(String path) {
        File file = new File(path);
        if (file.exists()) {
            if (file.isDirectory()) {
                File[] temp = file.listFiles(); //获取该文件夹下的所有文件
                for (File value : temp) {
                    deleteFile(value.getAbsolutePath());
                }
            } else {
                file.delete(); //删除子文件
            }
            file.delete(); //删除文件夹
        }
    }

    public static void deleteFile(String path){
        File dest = new File(path);
        if (dest.isFile() && dest.exists()) {
            dest.delete();
        }
    }

    public static String getNewFileRootPath(){
        return projectUrl+File.separator+ IdUtil.simpleUUID();
    }

    public static String getFileNameFromUrl(String url) {
        Pattern pattern = Pattern.compile("[^/]*$");
        Matcher matcher = pattern.matcher(url);
        if (matcher.find()) {
            return matcher.group();
        }
        return "";
    }

    /**
     * 获取扩展名
     * @param urlPath
     * @return {@link String}
     */
    public static String getExtName(String urlPath) {
        String fileName = getFileNameFromUrl(urlPath);
        return FileNameUtil.extName(fileName);
    }
}

请求配置 RestTemplateConfig


import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {
    @Bean
    public RestTemplate restTemplate(ClientHttpRequestFactory requestFactory) {
        return new RestTemplate(requestFactory);
    }

    @Bean
    public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
        factory.setReadTimeout(10000);
        factory.setConnectTimeout(10000);
        factory.setHttpClient(httpClient());
        return factory;
    }

    /**
     * @return
     */
    @Bean
    public HttpClient httpClient() {
        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.getSocketFactory())
                .register("https", SSLConnectionSocketFactory.getSocketFactory())
                .build();

        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);

        //设置整个连接池最大连接数
        connectionManager.setMaxTotal(500);

        //MaxPerRoute路由是对maxTotal的细分,每个主机的并发,这里route指的是域名
        connectionManager.setDefaultMaxPerRoute(200);
        RequestConfig requestConfig = RequestConfig.custom()
                //返回数据的超时时间
                .setSocketTimeout(20000)
                //连接上服务器的超时时间
                .setConnectTimeout(10000)
                //从连接池中获取连接的超时时间
                .setConnectionRequestTimeout(1000)
                .build();

        return HttpClientBuilder.create()
                .setDefaultRequestConfig(requestConfig)
                .setConnectionManager(connectionManager)
                .build();
    }
}

阿里组件配置

读取配置类 AliOssProperties

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "ali.oss")
@Data
public class AliOssProperties {
    /**
     * OSS配置信息
     */
    private String endpoint;

    private String accessKeyId;

    private String accessKeySecret;

    private String bucketName;

    private String aliUrl;
}

OSS组件类 OssComponent


import cn.hutool.core.util.StrUtil;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectResult;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.util.Objects;

@Component
@Slf4j
@Getter
public class OssComponent {

    @Resource
    private AliOssProperties aliOssProperties;

    /* -----------------对外功能---------------- */

    /**
     * 单个文件上传(指定文件名(带后缀))
     *
     * @param inputStream 文件
     * @param fileName    文件名(带后缀)
     * @return 返回完整URL地址
     */
    public String uploadFile(String fileDir, InputStream inputStream, String fileName) {
        try {
            this.uploadFile2Oss(fileDir, inputStream, fileName);
            String url = getFileUrl(fileDir, fileName);
            if (url != null && url.length() > 0) {
                return url;
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("获取路径失败");
        }
        return "";
    }

    /**
     * 通过文件名获取文完整件路径
     *
     * @param fileUrl 文件名
     * @return 完整URL路径
     */
    public String getFileUrl(String fileDir, String fileUrl) {
        if (fileUrl != null && fileUrl.length() > 0) {
            String[] split = fileUrl.replaceAll("\\\\","/").split("/");
            String url = aliOssProperties.getAliUrl() + fileDir + split[split.length - 1];
            return Objects.requireNonNull(url);
        }
        return null;
    }


    public boolean deleteFile(String fileDir, String fileName) {
        OSS ossClient = new OSSClientBuilder().build(aliOssProperties.getEndpoint(), aliOssProperties.getAccessKeyId(), aliOssProperties.getAccessKeySecret());
        // 删除文件
        ossClient.deleteObject(aliOssProperties.getBucketName(), fileDir + fileName);
        // 判断文件是否存在
        boolean found = ossClient.doesObjectExist(aliOssProperties.getBucketName(), fileDir + fileName);
        // 如果文件存在则删除失败

        return !found;
    }





    /* -----------内部辅助功能------------------------ */

    /**
     * 获取去掉参数的完整路径
     *
     * @param url URL
     * @return 去掉参数的URL
     */
    private String getShortUrl(String url) {
        String[] imgUrls = url.split("\\?");
        return imgUrls[0].trim();
    }


    /**
     * 上传文件(指定文件名)
     *
     * @param inputStream 输入流
     * @param fileName    文件名
     */
    private void uploadFile2Oss(String fileDir, InputStream inputStream, String fileName) {
        OSS ossClient = new OSSClientBuilder().build(aliOssProperties.getEndpoint(), aliOssProperties.getAccessKeyId(), aliOssProperties.getAccessKeySecret());
        String ret;
        try {
            //创建上传Object的Metadata
            ObjectMetadata objectMetadata = new ObjectMetadata();
            objectMetadata.setContentLength(inputStream.available());
            objectMetadata.setCacheControl("no-cache");
            objectMetadata.setHeader("Pragma", "no-cache");
            String contentType = getContentType(fileName.substring(fileName.lastIndexOf(".")));
            if(StrUtil.isNotEmpty(contentType)){
                objectMetadata.setContentType(contentType);
            }
            objectMetadata.setContentDisposition("inline;filename=" + fileName);
            //上传文件
            PutObjectResult putResult = ossClient.putObject(aliOssProperties.getBucketName(), fileDir + fileName, inputStream, objectMetadata);
            ret = putResult.getETag();
            if (StrUtil.isEmpty(ret)) {
                log.error("上传失败,文件ETag为空");
            }
            ossClient.shutdown();
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 请求类型
     *
     * @param filenameExtension :
     * @return :
     */
    private static String getContentType(String filenameExtension) {
        if (FileNameSuffixEnum.BMP.getSuffix().equalsIgnoreCase(filenameExtension)) {
            return "image/bmp";
        }
        if (FileNameSuffixEnum.GIF.getSuffix().equalsIgnoreCase(filenameExtension)) {
            return "image/gif";
        }
        if (FileNameSuffixEnum.JPEG.getSuffix().equalsIgnoreCase(filenameExtension) ||
                FileNameSuffixEnum.JPG.getSuffix().equalsIgnoreCase(filenameExtension) ||
                FileNameSuffixEnum.PNG.getSuffix().equalsIgnoreCase(filenameExtension)) {
            return "image/jpeg";
        }
        if (FileNameSuffixEnum.HTML.getSuffix().equalsIgnoreCase(filenameExtension)) {
            return "text/html";
        }
        if (FileNameSuffixEnum.TXT.getSuffix().equalsIgnoreCase(filenameExtension)) {
            return "text/plain";
        }
        if (FileNameSuffixEnum.VSD.getSuffix().equalsIgnoreCase(filenameExtension)) {
            return "application/vnd.visio";
        }
        if (FileNameSuffixEnum.PPTX.getSuffix().equalsIgnoreCase(filenameExtension) ||
                FileNameSuffixEnum.PPT.getSuffix().equalsIgnoreCase(filenameExtension)) {
            return "application/vnd.ms-powerpoint";
        }
        if (FileNameSuffixEnum.DOCX.getSuffix().equalsIgnoreCase(filenameExtension) ||
                FileNameSuffixEnum.DOC.getSuffix().equalsIgnoreCase(filenameExtension)) {
            return "application/msword";
        }
        if (FileNameSuffixEnum.XML.getSuffix().equalsIgnoreCase(filenameExtension)) {
            return "text/xml";
        }
        if (FileNameSuffixEnum.PDF.getSuffix().equalsIgnoreCase(filenameExtension)) {
            return "application/pdf";
        }
        return "";
    }


}

@Getter
enum FileNameSuffixEnum {

    /**
     * 文件后缀名
     */
    BMP(".bmp", "bmp文件"),
    GIF(".gif", "gif文件"),
    JPEG(".jpeg", "jpeg文件"),
    JPG(".jpg", "jpg文件"),
    PNG(".png", "png文件"),
    HTML(".html", "HTML文件"),
    TXT(".txt", "txt文件"),
    VSD(".vsd", "vsd文件"),
    PPTX(".pptx", "PPTX文件"),
    DOCX(".docx", "DOCX文件"),
    PPT(".ppt", "PPT文件"),
    DOC(".doc", "DOC文件"),
    XML(".xml", "XML文件"),
    PDF(".pdf", "PDF文件");

    /**
     * 后缀名
     */
    private final String suffix;

    /**
     * 描述
     */
    private final String description;

    FileNameSuffixEnum(String suffix, String description) {
        this.suffix = suffix;
        this.description = description;
    }
}

文件服务

FileService
public interface FileService {
    String uploadJavaVideo(String url) throws Exception;
}
FileServiceImpl

import cn.hutool.core.util.IdUtil;
import com.example.springbootrocketmq.config.OssComponent;
import com.example.springbootrocketmq.service.FileService;
import com.example.springbootrocketmq.utils.FileUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RequestCallback;
import org.springframework.web.client.RestTemplate;

import java.io.File;
import java.io.FileInputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;

@Slf4j
@Service
public class FileServiceImpl implements FileService {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private OssComponent ossComponent;

    @Override
    public String uploadJavaVideo(String url) throws Exception {
        String extName = FileUtil.getExtName(url);//获取扩展名称
        String fileName = IdUtil.simpleUUID()+"."+extName;
        log.info("fileName:{}",fileName);
        String newFileRootPath = FileUtil.getNewFileRootPath();
        File rootFile = new File(newFileRootPath);
        if(!rootFile.exists()){
            rootFile.mkdirs();
        }
        String toPath = newFileRootPath+ File.separator + fileName;
        try {
            log.info("toPath:{}",toPath);
            uploadBigFile(url,toPath);
            return ossComponent.uploadFile("demo/",new FileInputStream(toPath),fileName);
        } finally {
            FileUtil.deleteFiles(newFileRootPath);
        }
    }

    /**
     * 下载文件
     * @param url
     * @param toPath
     * @throws Exception
     */
    public void uploadBigFile(String url, String toPath) throws Exception {
        //定义请求头的接收类型
        RequestCallback requestCallback = request -> request.getHeaders()
                .setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));
        //对响应进行流式处理而不是将其全部加载到内存中
        restTemplate.execute(url, HttpMethod.GET, requestCallback, clientHttpResponse -> {
            Files.copy(clientHttpResponse.getBody(), Paths.get(toPath));
            return null;
        });
    }
}

测试 TestController 类


import com.example.springbootrocketmq.service.FileService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
@RequestMapping("/")
public class TestController {

    @Autowired
    private FileService fileService;

    @GetMapping("/uploadFileToOss")
    public Object uploadJavaVideo(String url) {
        try {
            return fileService.uploadJavaVideo(url);
        }catch (Exception e){
            log.error("上传转码异常,异常原因e:{}",e);
        }
        return null;
    }
}

启动服务 用 postman 请求

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1090488.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【【萌新的SOC学习之基于BRAM的PS和PL数据交互实验】】

萌新的SOC学习之基于BRAM的PS和PL数据交互实验 基于BRAM的PS和PL的数据交互实验 先介绍 AXI BRAM IP核控制器的简介 AXI BRAM ip核 是xilinx提供的一个软核 这个ip核被设计成 AXI的一个从机接口 用于AXI互联的集成 系统的主设备和本地的RAM进行通信 &#xff08;我们可以通过这…

大数据分析/开发项目实战班

大数据分析/开发项目实战班采用新型教学模式&#xff0c;让学生“学有所用&#xff0c;学能所用”&#xff0c;角色演练开展项目式教学&#xff0c;将产业项目与教学知识结合&#xff0c;突出学生的主体性&#xff0c;打破传统教学壁垒。 大数据分析/开发项目实战班介绍&#x…

ubuntu下yolov6 tensorrt模型部署

文章目录 ubuntu下yolov6 tensorrt模型部署一、Ubuntu18.04环境配置1.1 安装工具链和opencv1.2 安装Nvidia相关库1.2.1 安装Nvidia显卡驱动1.2.2 安装 cuda11.31.2.3 安装 cudnn8.21.2.4 下载 tensorrt8.4.2.41.2.5 下载仓库TensorRT-Alpha并设置 二、从yolov6源码中导出onnx文…

Linux高性能服务器编程 学习笔记 第十三章 多线程编程

早期Linux不支持线程&#xff0c;直到1996年&#xff0c;Xavier Leroy等人开发出第一个基本符合POSIX标准的线程库LinuxThreads&#xff0c;但LinuxThreads效率低且问题多&#xff0c;自内核2.6开始&#xff0c;Linux才开始提供内核级的线程支持&#xff0c;并有两个组织致力于…

【灵动 Mini-G0001开发板】+Keil5开发环境搭建+ST-Link/V2程序下载和仿真+4颗LED100ms闪烁。

我们拿到手里的是【灵动 Mini-G0001开发板】 如下图 我们去官网下载开发板对应资料MM32G0001官网 我们需要下载Mini—G0001开发板的库函数与例程&#xff08;第一手学习资料&#xff09;Keil支持包&#xff0c; PCB文件有需要的&#xff0c;可以自行下载。用户指南需要下载&a…

在Mission Planner上校准外置GPS罗盘

环境 windows 11 pixhawk 2.4.8 GPS M8N Mission Planner 1.3.80 前提 已经校准pixhawl自带的加速度计 根据提示&#xff0c;转动pixhawk&#xff0c;按空格键进行下一个步骤&#xff0c;成功后提示success 校准GPS罗盘 pixhawk飞控支持使用双罗盘&#xff08;也就是内置…

【LeetCode热题100】--394.字符串解码

394.字符串解码 思路&#xff1a; 定义两个栈&#xff0c;用于存放数字和字符如果是遇到’[&#xff0c;则数字和字母进栈如果遇到’]&#xff0c;则出栈&#xff0c;并拼接成一个字符串注意考虑多个数字在一起的情况 class Solution {public String decodeString(String s) …

MySQL的index merge(索引合并)导致数据库死锁分析与解决方案 | 京东云技术团队

背景 在DBS-集群列表-更多-连接查询-死锁中&#xff0c;看到9月22日有数据库死锁日志&#xff0c;后排查发现是因为mysql的优化-index merge&#xff08;索引合并&#xff09;导致数据库死锁。 定义 index merge(索引合并)&#xff1a;该数据库查询优化的一种技术&#xff0…

每日leetcode_775全局倒置与局部倒置

每日leetcode_755全局倒置与局部倒置 记录自己的成长&#xff0c;加油。 题目出处&#xff1a;775. 全局倒置与局部倒置 - 力扣&#xff08;LeetCode&#xff09; 题目 题目简要&#xff1a; 全局倒置&#xff1a;左边的大于右边的&#xff08;不需要紧挨着&#xff09; 局部…

Chrome插件精选 — 网页截图插件

Chrome实现同一功能的插件往往有多款产品&#xff0c;逐一去安装试用耗时又费力&#xff0c;在此为某一类型插件记录下比较好用的一款或几款&#xff0c;便于节省尝试的时间和精力。 捕捉网页截图 - FireShot 下载地址 (访问密码: 8276) Fireshot是一款浏览器插件&#xff0c…

2023.09全国青少年软件编程(scratch图形化)等级考试试卷(一级)

2023年9月全国青少年软件编程 scratch图形化 等级考试试卷&#xff08;一级&#xff09; 第 1 题 下列哪项内容是不可以修改的&#xff1f;&#xff08; &#xff09; A&#xff1a;角色名称 B&#xff1a;造型名称 C&#xff1a;舞台名称 D&#xff1a;背景名称 第 2 题…

11款新编程工具!

导读作为一名开发人员&#xff0c;对于工具的需求是一直都有的。工具使得开发人员只需要关注那些重要的事情就可以了&#xff0c;因此工作也更有效率&#xff0c;生活也更轻松了。对于开发人员来说&#xff0c;由于很难找到更好的替代方案&#xff0c;因此只能一直使用那些熟悉…

Oracle update 关联更新优化方法

关联更新顾名思义就是指&#xff0c;更新的数据从关联的表中获取并update到目标表。并且该SQL将会是一个天然的嵌套循环。有两种优化思路解决&#xff1a; 1、PLSQL 根据rowid更新 是否需要加order by rowid的考量&#xff1a; 如果buffer cache足够大&#xff0c;能够放得下要…

PyTorch 深度学习之卷积神经网络(基础篇)Basic CNN(九)

0. Revision: Fully connected Neural Network 全连接 1. Convolution Neural Network 保留空间信息 1.1 Convolution Convolution-Single Input Channel 单通道 数乘 3 input Channels 3通道 N input Channels N input Channels and M output channel M 个卷积核 1.2 conv…

jmeter性能测试过程中遇到的问题及解决方法

问题1 如何在大并发测试下&#xff0c;让登录或者后续接口只执行一次&#xff1f; 分析 这个问题网上的答案其实很多&#xff0c;但是大多不靠谱。 比如推荐使用仅一次控制器&#xff0c;但是仅一次控制器对线程组无效&#xff1b;比如推荐跨线程组调用&#xff0c;但是这样…

让ChatGPT等模型学会自主思考!开创性技术“自主认知”框架

ChatGPT、百度文心一言、Bard等大语言模型展现出了超强的创造能力&#xff0c;加速了生成式AI的应用进程。但AI模型只能基于训练数据执行各种任务&#xff0c;无法像人类一样利用生活知识、过往经验用于复杂的推理和决策。 例如&#xff0c;在玩游戏时&#xff0c;人类可以利用…

mysql中的几种排名函数

mysql中的排名函数 mysql里面的排名函数&#xff0c;涉及有以下几个&#xff1a; rank()、dense_rank()、row_number() 1、rank() 函数 RANK() OVER (PARTITION BY <expression>[{,<expression>...}]ORDER BY <expression> [ASC|DESC], [{,<expression…

如何用 ChatGPT 的 Advanced Data Analysis 帮你采集数据?

&#xff08;注&#xff1a;本文为小报童精选文章&#xff0c;已订阅小报童或加入知识星球「玉树芝兰」用户请勿重复付费&#xff09; 想采集网页数据却不会写 Python 爬虫&#xff1f;不会就不会吧&#xff0c;ChatGPT 会就可以了 &#x1f602; 问题描述 朋友最近遇到了一点儿…

thinkphp6 获取url路径中的应用名、控制器名、操作名

如果使用了多应用模式&#xff0c;可以通过下面的方法来获取当前应用 app(http)->getName(); 获取当前控制器 Request::controller(); 获取当前操作 Request::action(); 请求信息 ThinkPHP6.0完全开发手册 看云 ThinkPHP6.0基于精简核心和统一用法两大原则在5.1的基础上…

Ansible基础及模块

Ansible是一个基于Python开发的配置管理和应用部署工具&#xff0c;能批量配置、部署、管理上千台主机。比如以前需要切换到每个主机上执行的一或多个操作&#xff0c;使用Ansible只需在固定的一台Ansible控制节点上去完成所有主机的操作 Ansible是基于模块工作的&#xff0c;它…