vue+springboot前后端视频文件等的上传与展示(基于七牛云)

前言:在初步说明完成功能之前,我会把重要的部分说明下。后续我会细化。

vue视频文件上传

其实这里和图片这些文件就是一样的。因为上传只是把我们想在云端展示的文件按等传输到云端的bucket。然后方便网站去请求引用。

在这里插入图片描述

有人问我我就说明下。这种东西无非就是照猫画虎,当然你是需要一些逻辑和一些基础的。

先看一下效果
这是我网站展示的效果。

网站地址兰舟千帆的个人博客
在这里呢可以浏览效果。
在这里插入图片描述

在这里插入图片描述
并且呢,单个视频可以独立放大全屏,可以控制倍数,音量进度。
在这里插入图片描述
在这里插入图片描述
做这个三大关键点,第一完成上传与下载的请求封装
第二:会看懂七牛云sdk
第三:会学习到vueplayer

后台上传显示为
在这里插入图片描述
在这里插入图片描述
里面这些限制性数据都可以进行修改

独立功能拆分前后端为

vue 前端
后端
一些信息需要自己去填写,数据库表存在变更。后端七牛云上传代码其实很固定,可以微调。前端需要用到vue-player和watch数据显示等。可以进行参考。前后端可以独立调试视频文件等上传下载。参考可以去做视听模块。

首先从前端
代码很多我把关键点和思路写一下。(具体可以查看链接地代码)
首先是上传按钮。

proButton是封装的组件,就是button。

   <proButton :info="'上传视频文件'" 
                         @click.native="addVideoResource()"
                         :before="$constant.before_color_1"
                        
                         :after="$constant.after_color_1">
   </proButton>

点击将触发一个方法

 addVideoResource(){
        if (this.addResourcePathDialog === false) {
          return;
        }
        if (this.$common.isEmpty(this.resourcePath.type)) {
          this.$message({
            message: "请选择有效资源类型!",
            type: "error"
          });
          return;
        }
        this.resourceVideoDialog = true;
      },

this.resourceVideoDialog = true;
将会让上传的视频的dialog显示出来

   <el-dialog title="视频"
              :visible.sync="resourceVideoDialog"
               width="35%"
               
               :append-to-body="true"
               destroy-on-close
               center>
      <div>
        <uploadVideo :isAdmin="true" :prefix="resourcePath.type+'LoveVideo'" @addVideo="addVideo" :maxSize="5"
                       :maxNumber="10"></uploadVideo>
      </div>
    </el-dialog>

uploadVideo 是封装的组件,其实主要就是el-upload的东西。
eg

  <el-upload
      class="upload-demo"
      ref="upload"
      multiple
      drag
      :action="$constant.qiniuUrl" 
      :on-change="handleChange"
      :before-upload="beforeUpload" 
      :on-success="handleSuccess"
      :on-error="handleError"
      :on-remove="handleRemove"           
      :http-request="customUpload"
      :list-type="listType"
      :accept="accept"
      :limit="maxNumber"
      :auto-upload="false">
      <div class="el-upload__text">
        <svg viewBox="0 0 1024 1024" width="40" height="40">
          <path
            d="M666.2656 629.4528l-113.7664-112.4864c-20.7872-20.5824-54.3232-20.5312-75.1104 0.1024l-113.3056 112.4864c-20.8896 20.736-21.0432 54.528-0.256 75.4688 20.736 20.8896 54.528 21.0432 75.4688 0.256l22.6304-22.4256v189.5936c0 29.44 23.9104 53.3504 53.3504 53.3504s53.3504-23.9104 53.3504-53.3504v-189.5424l22.6816 22.4256a53.1456 53.1456 0 0 0 37.5296 15.4112c13.7728 0 27.4944-5.2736 37.9392-15.8208 20.6336-20.9408 20.4288-54.7328-0.512-75.4688z"
            fill="#FFE37B"></path>
          <path
            d="M820.992 469.504h-5.376c-3.072-163.328-136.3456-294.8096-300.4416-294.8096S217.856 306.1248 214.784 469.504H209.408c-100.7104 0-182.3744 81.664-182.3744 182.3744s81.664 182.3744 182.3744 182.3744h209.7664V761.856c-30.208 5.5808-62.464-3.3792-85.6576-26.7264-37.3248-37.5808-37.0688-98.5088 0.512-135.7824l113.3056-112.4864c37.2224-36.9664 97.8432-37.0176 135.168-0.1536l113.7664 112.4864c18.2272 18.0224 28.3648 42.0864 28.5184 67.7376 0.1536 25.6512-9.728 49.8176-27.7504 68.0448a95.40096 95.40096 0 0 1-68.3008 28.5184c-5.9392 0-11.776-0.512-17.5104-1.5872v72.3456h209.7664c100.7104 0 182.3744-81.664 182.3744-182.3744S921.7024 469.504 820.992 469.504z"
            fill="#8C7BFD"></path>
        </svg>
        <div>拖拽上传 / 点击上传</div>
      </div>
      <template v-if="listType === 'video'">
        <div slot="tip" class="el-upload__tip">
          一次最多上传{{maxNumber}}个视频,且每个视频片不超过{{maxSize}}M!
        </div>
      </template>
      <template v-else>
        <div slot="tip" class="el-upload__tip">
          一次最多上传{{maxNumber}}个文件,且每个文件不超过{{maxSize}}M!
        </div>
      </template>

    </el-upload>

    <div style="text-align: center;margin-top: 20px">
      <el-button type="success" style="font-size: 12px" @click="submitUpload">
        上传
      </el-button>
    </div>

当然el绑定的这些方法我们都会写出来,里面有一些说明

  submitUpload() {
        this.$refs.upload.submit();//调用el组件的上传
      },
      // 点击提交,会将el-upload的内容提交,会转到自定义的customUpload
      customUpload(options) {
        options
        // options 是文件对象
        // 进行文件名分割处理
        let suffix = "";
        if (options.file.name.lastIndexOf('.') !== -1) {
          suffix = options.file.name.substring(options.file.name.lastIndexOf('.'));
        }

        // 给上传的文件起名字(prefix是前缀,最终在存储空间形成文件夹的名字)

        let key = this.prefix + "/" + "daodaozi" + new Date().getTime() + Math.floor(Math.random() * 1000) + suffix;

        const xhr = new XMLHttpRequest();
        // 启动一个请求(还没发送)
        xhr.open('get', this.$constant.baseURL + "/qiniu/getUpToken?key=" + key, false);

   

        // 这是请求到后端要携带的token,这里就不携带了。加入到博客项目或者其他需要视频文件上传的网站中就加上做一些权限校验等

        // if (this.isAdmin) {
        //   xhr.setRequestHeader("Authorization", localStorage.getItem("adminToken"));
        // } else {
        //   xhr.setRequestHeader("Authorization", localStorage.getItem("userToken"));
        // }

        try {
          xhr.send();//发送请求,上传需要获取后端凭证,这个时候上面那个准备的请求就将真正的发送
          const res = JSON.parse(xhr.responseText);

       
          if (res !== null && res.hasOwnProperty.call("code") && res.code === 200) {
            options.data = {
              token: res.data,
              key: key
            };
            return upload(options);
          } else if (res !== null && res.hasOwnProperty.call("code") && res.code !== 200) {
            if(res.code===3000)
            {

    

              // 3000代表token过期了
                //  那就清理掉
               
                localStorage.removeItem("userToken");
              
                localStorage.removeItem("adminToken");
                localStorage.removeItem("currentUser");
                localStorage.removeItem("currentAdmin")
                //将页面刷新下
               window.location.reload()
               window.location.href  =  "/"
               

              // debugger
            }
            return Promise.reject(res.message);
          } else {
            return Promise.reject("服务异常!");
          }
        } catch (e) {
          return Promise.reject(e.message);
        }
      },

      // 文件上传成功时的钩子
      handleSuccess(response, file, fileList) {

        // 返回上传后的url
        let url = this.$constant.qiniuDownload + response.key;
        // 调用common中的方法向后端请求,将文件(图片信息保存)
        this.$common.saveVideoResource(this, this.prefix, url, file.size, file.raw.type, this.isAdmin);

        // 子组件向父组件传值(引用该组件的组件会获取到此处传递的值)
        this.$emit("addVideo", url);
      },
      handleError(err, file, fileList) {
        this.$message({
          message: err,
          type: "error"
        });
      },
      // 上传文件之前的钩子,参数为上传的文件,若返回 false 或者返回 Promise 且被 reject,则停止上传
      beforeUpload(file) {
      },
      // 文件列表移除文件时的钩子
      handleRemove(file, fileList) {
      },
      // 添加文件、上传成功和上传失败时都会被调用
      handleChange(file, fileList) {
        let flag = false;

        
        // if (file.size > this.maxSize * 1024 * 1024) {
        //   this.$message({
        //     message: "视频最大为" + this.maxSize + "M!",
        //     type: "warning"
        //   });
        //   flag = true;
        // }

        if (flag) {
          fileList.splice(fileList.size - 1, 1);
        }
      }
    }
  }
``

upload也是封装的,封装进行上传功能的代码
作用就是类似于底层的组件一个表单上传

function getError(action, option, xhr) {
  let msg;
  if (xhr.response) {
    msg = `${xhr.response.error || xhr.response}`;
  } else if (xhr.responseText) {
    msg = `${xhr.responseText}`;
  } else {
    msg = `fail to ${action} ${xhr.status}`;
  }

  return new Error(msg);
}

function getBody(xhr) {
  const text = xhr.responseText || xhr.response;
  if (!text) {
    return text;
  }

  try {
    return JSON.parse(text);
  } catch (e) {
    return text;
  }
}

export default function upload(option) {
  const xhr = new XMLHttpRequest();
  const action = option.action;

  if (xhr.upload) {
    xhr.upload.onprogress = function progress(e) {
      if (e.total > 0) {
        e.percent = e.loaded / e.total * 100;
      }
      option.onProgress(e);
    };
  }
// 组建上传表单
  const formData = new FormData();

  if (option.data) {
    Object.keys(option.data).forEach(key => {
      formData.append(key, option.data[key]);
    });
  }

  formData.append(option.filename, option.file, option.file.name);

  xhr.onerror = function error(e) {
    option.onError(e);
  };

  xhr.onload = function onload() {
    if (xhr.status < 200 || xhr.status >= 300) {
      return option.onError(getError(action, option, xhr));
    }

    option.onSuccess(getBody(xhr));
  };

  xhr.open('post', action, true);

  if (option.withCredentials && 'withCredentials' in xhr) {
    xhr.withCredentials = true;
  }

  const headers = option.headers || {};

  for (let item in headers) {
    if (headers.prototype.hasOwnProperty.call(item) && headers[item] !== null) {
      xhr.setRequestHeader(item, headers[item]);
    }
  }
  xhr.send(formData);
  return xhr;
}

前端上传的主要就是这些。逻辑就是你首先上传呢,需要先去后端请求到一个七牛云的上传认证token,然后后端给到这个token,然后你带着这个东西去上传。

下面这里是后端的部分代码展示,其实还是有很多的封装。这些代码不需要去记忆,可以运用起来就可以。上传这里呢,主要就是获取到后端的上传token。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
然后就是展示呢。我们的vue主要是这样用了一个组件 vue
-player去做播放器了

<template>
  <div class="card-container" v-if="!$common.isEmpty(videoList)">
  
    <div  v-for="(resourcePath, index) in videoList"
         :key="index"
         class="card-item wow shadow-box-mini">
       
      <div class="card-image">
       
        <!-- <video  autoplay="autoplay" muted loop="loop"
               :src="resourcePath.url">
        </video> -->
        <!-- <el-image class="my-el-image"
                  v-once
                  lazy
                  :preview-src-list="[resourcePath.url]"
                  :src="resourcePath.cover"
                  fit="cover">
          <div slot="error" class="image-slot"></div>
        </el-image> -->
        <el-tooltip placement="top" effect="light">
          <div slot="content">{{resourcePath.title}}</div>
          <div class="card-desc">
            {{resourcePath.title}}
          </div>
        </el-tooltip>
        <div class="player">
          <video-Player
            ref="videoPlayer"
            class="player-video"
            :playsinline="true"
            
            :options="playerOptions[index]"
            @ready="onPlayerReady"
            @play="onPlayerPlay($event,index)"
            @pause="onPlayerPause($event)"
            @ended="onPlayerEnd($event)"
            @waiting="onPlayerWaiting($event)"
            @playing="onPlayerPlaying($event)"
            @loadeddata="onPlayerLoadeddata($event)"
            @timeupdate="onPlayerTimeupdate($event)"
            @statechanged="playerStateChanged($event)"
          ></video-Player></div>






      </div>
      <div class="card-body">
       
        <div class="card-time">
          Date: {{$common.getDateDiff(resourcePath.createTime)}}
        </div>
       
      </div>
    </div>
  </div>
</template>

<script>
import constant from '../../utils/constant';

import { videoPlayer } from 'vue-video-player';
require("video.js/dist/video-js.css");
require("vue-video-player/src/custom-theme.css");
  export default {
    
    components:{
      videoPlayer

    },
    props: {
      type: String,
     

      resourcePathList: {
        type: Array
      },
      lastTime: {  // 传入的上次播放位置
      type: Number,
      default: 0,
    },
    
     
    },

   


    data() {
      return {
      
      srcVideo:"",
      videoList:[],
      playedTime: this.lastTime,
      currentTime: 0,
      maxTime: 0,
      playsinline: true,
      playerOptions: [],
      options: "",

 
      playOptions: {
        height: "200px",
        width: "100%",
      //   playbackRates: [1,0.5,2,2.5], // 可选的播放速度
      //   autoplay: true, // 如果为true,浏览器准备好时开始回放
      //   muted: false, // 默认情况下静音播放
      //   loop: false, // 是否视频一结束就重新开始
      //   preload: "auto", // 建议浏览器在<video>加载元素后是否应该开始下载视频数据,auto浏览器选择最佳行为,立即开始加载视频(如果浏览器支持)
      //   language: "zh-CN",
      //   aspectRatio: "16:9", // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值,值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3")
      //   fluid: true, // 当true时,Video.js player将拥有流体大小,换句话说,它将按比例缩放以适应其容器
      //   sources: [
      //     {
           
      //       type: "video/mp4", // 类型
      //       src: this.resourcePathList[0].url
      //       // src: require('../common/5.mp4')// url地址,在使用本地的资源时,需要用require()引入,否则控制台会报错
      //     },
      //   ],
      //   poster: "", // 设置封面地址
      //   notSupportedMessage: "此视频暂无法播放,请稍后再试", // 允许覆盖Video.js无法播放媒体源时显示的默认信息
      //   controlBar: {
      //     currentTimeDisplay: true,
      //     progressControl: true,  // 是否显示进度条
      //     playbackRateMenuButton: true, // 是否显示调整播放倍速按钮
      //     timeDivider: true, // 当前时间和持续时间的分隔符
      //     durationDisplay: true, // 显示持续时间
      //     remainingTimeDisplay: true, // 是否显示剩余时间功能
      //     fullscreenToggle: true, // 是否显示全屏按钮
      //   },
      // },

      }
    }

      // }
    },

    computed: {
     
     
    },

    watch: {
      
      resourcePathList(newnew,oldold){
        
        this.videoList = newnew
        this.getMovieList()
      },
      immediate: true,
      deep:true,
      
    },

    created() {
      
      
		// 方法区

     

    },

    mounted() {
     

   

    },

    methods: {

      getMovieList() {
    // 这里正常来说应该是从后台获取的数据,以下操作都是在成功的回调函数里
      for (var i = 0; i < this.videoList.length; i++) {
          let arrs = {
            playbackRates: [0.5,1.0,1.5, 2.0,2.5 ,3.0], //播放速度
           

            autoplay: false, //如果true,浏览器准备好时开始回放。
            muted: false, // 默认情况下将会消除任何音频。
            loop: false, // 导致视频一结束就重新开始。
            preload: "auto", // 建议浏览器在<video>加载元素后是否应该开始下载视频数据。auto浏览器选择最佳行为,立即开始加载视频(如果浏览器支持)
            language: "zh-CN",
            aspectRatio: "16:9", // 将播放器置于流畅模式,并在计算播放器的动态大小时使用该值。值应该代表一个比例 - 用冒号分隔的两个数字(例如"16:9"或"4:3")
            fluid: true, // 当true时,Video.js player将拥有流体大小。换句话说,它将按比例缩放以适应其容器。
            sources: [
              {
                type: "video/mp4",
                // type: "video/ogg",
                src: this.videoList[i].url //url地址
              }
            ],
            poster: this.videoList[i].cover,
            notSupportedMessage: "此视频暂无法播放,请稍后再试", //允许覆盖Video.js无法播放媒体源时显示的默认信息。
            controlBar: {
              timeDivider: true,
              durationDisplay: true,
              remainingTimeDisplay: false,
              fullscreenToggle: true //全屏按钮
            }
          };
          this.playerOptions.push(arrs);
        }
    },
    onPlayerPlay(player, index) {
 
      
       var that = this.$refs.videoPlayer;
       for (let i = 0; i < that.length; i++) {
          if(i != index)
          that[i].player.pause()
       }
    },
    onPlayerPause(player) {

      
},

      clickDemo(){
        this.items  =  this.resourcePathList
        alert(this.items[0].url)
      },
        // 准备好了
    onPlayerReady() {
      console.log("准备好了");
    },
    // 视频播放
    // onPlayerPlay(player) {
    //   console.log('播放了');
    //   console.log(player);
    //   let playTime = 0;
    //     if (
    //       Number(Math.floor(this.playedTime)) ===
    //       Number(Math.floor(player.duration()))
    //     ) {
    //       this.playedTime = 0;
    //       playTime = 0;
    //     } else if (
    //       Number(Math.floor(player.currentTime())) !==
    //       Number(Math.floor(this.playedTime))
    //     ) {
    //       playTime = this.playedTime;
    //       player.currentTime(playTime)
    //     }
    // },
    // // 视频暂停的
    // onPlayerPause(player) {
    //   console.log('暂停中');
    //   console.log(player);
    //   this.playedTime = player.currentTime();
    // },
    // 视频播放完
    onPlayerEnd(player) {
      console.log('播放结束了');
      console.log(player);
    },
    // DOM元素上的readyState更改导致播放停止
    onPlayerWaiting(player) {
      console.log("播放停止中");
      console.log(player);
    },
    // 视频已开始播放
    onPlayerPlaying(player) {
      console.log("开始播放了");
      console.log(player);
    },
    // 当播放器在当前播放位置下载数据时触发
    onPlayerLoadeddata(player) {
      console.log("开始下载数据");
      console.log(player);
    },
    // 当前播放位置发生变化时触发
    onPlayerTimeupdate(player) {
      console.log("播放位置变化了");
      console.log(player);
      let timeDisplay = player.currentTime();
        if (timeDisplay - this.currentTime > 1) {
            player.currentTime(this.currentTime > this.maxTime ? this.currentTime : this.maxTime);
        }
        this.currentTime = player.currentTime();
        this.maxTime = this.currentTime > this.maxTime ? this.currentTime : this.maxTime;
    },
    //播放状态改变
    playerStateChanged(playerCurrentState) {
      console.log("播放状态变化了");
      console.log(playerCurrentState);
    },
    // 手动暂停视频的播放
    pause() {
      // 视频播放器的方法调用,要使用this.$refs.videoPlayer.player这个对象去调用
      this.$refs.videoPlayer.player.pause()
    }
  },



    }

</script>

<style scoped>

  .card-container {
    display: flex;
    flex-wrap: wrap;
  }

  .card-item {
    position: relative;
    overflow: hidden;
    margin: 15px;
    height: 300px;
    flex-shrink: 0;
    width: calc(100% / 3 - 30px);
    cursor: pointer;
    animation: zoomIn 0.8s ease-in-out;
    padding: 1.3rem 1.3rem 1.5rem;
    background: var(--background);
    border-radius: 1.5rem;
    transition: all 0.2s;
  }

  .card-image {
    width: 100%;
    height: 400px;
    border-radius: 1rem;
    overflow: hidden;
    box-shadow: 0 2px 10px rgba(147, 147, 147, 0.61);
    margin-bottom: 1rem;
  }

  .card-image >>> .el-image__inner {
    transition: all 1s;
  }

  .card-image >>> .el-image__inner:hover {
    transform: scale(1.2);
  }

  .card-body {
    padding: 10px 5px;
  }

  .card-desc {
    font-weight: 600;
    text-align: center;
    font-size: 1.05rem;
    color: var(--fontColor);
    letter-spacing: 1px;
    line-height: 1.5;
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
  }

  .card-time {
    position: absolute;
    bottom: 15px;
    color: #999999;
    font-weight: 500;
  }

  @media screen and (max-width: 1300px) {
    .card-item {
      width: calc(100% / 2 - 30px);
    }
  }

  @media screen and (max-width: 1000px) {
    .card-item {
      height: 450px;
    }

    .card-image {
      height: 300px;
    }
  }

  @media screen and (max-width: 750px) {
    .card-item {
      width: 100%;
      margin: 15px 0;
    }
  }

  @media screen and (max-width: 450px) {
    .card-item {
      height: 400px;
    }

    .card-image {
      height: 250px;
    }
  }

</style>

怎么说呢,去看我给出的源码地址吧,那里面是比较完整的功能拆分。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux 36.2@Jetson Orin Nano之Hello AI World!

Linux 36.2Jetson Orin Nano之Hello AI World&#xff01; 1. 源由2. Hello AI World&#xff01;3. 步骤3.1 准备阶段3.2 获取代码3.3 Python环境3.4 重点环节3.5 软件配置3.6 PyTorch安装3.7 编译链接3.8 安装更新 4. 测试4.1 video-viewer4.2 detectnet4.3 演示命令 5. 参考…

问题:2、计算机网络的目标是实现________。 #媒体#知识分享

问题&#xff1a;2、计算机网络的目标是实现________。 A&#xff0e;数据处理 B&#xff0e;信息传输与数据处理 C&#xff0e;资源共享与信息传输 D&#xff0e;文献查询 参考答案如图所示

开发者实战 | 如何在 Windows 上调用 NPU 部署深度学习模型

点击蓝字 关注我们,让开发变得更有趣 作者 | 杨亦诚 排版 | 李擎 OpenVINO™..♩~ ♫. ♪.. 相信很多小伙伴都已经知道&#xff0c;在最新一代的 Intel Core Ultra 移动端平台中已经集成了被称为 NPU 的神经网络加速处理器&#xff0c;以提供低功耗的AI算力&#xff0c;特别适合…

代码随想录算法训练营day15||二叉树part02、102.二叉树的层序遍历、 226.翻转二叉树(优先掌握递归)、101. 对称二叉树 (优先掌握递归)

102.二叉树的层序遍历 题目&#xff1a;给你一个二叉树&#xff0c;请你返回其按 层序遍历 得到的节点值。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 接下来我们再来介绍二叉树的另一种遍历方式&#xff1a;层序遍历。 层序遍历一个二叉树。就是…

分布式搜索引擎 elasticsearch

分布式搜索引擎 elasticsearch 第一部分 1.初识elasticsearch 1.1.了解ES 1.1.1.elasticsearch的作用 elasticsearch是一款非常强大的开源搜索引擎&#xff0c;具备非常多强大功能&#xff0c;可以帮助我们从海量数据中快速找到需要的内容 例如&#xff1a; 在GitHub搜索…

酷开科技荣获消费者服务平台黑猫投诉“消费者服务之星”称号

什么是优质服务&#xff1f;既是以客户为中心的庄严承诺&#xff0c;又是对服务能力提升的深耕细作&#xff1b;既是对服务标准的敬畏&#xff0c;也是对服务创新的不断探索……服务是多维的&#xff0c;每个企业都有自己独到的诠释&#xff0c;或事无巨细环环严控&#xff0c;…

Mybatis开发辅助神器p6spy

Mybatis什么都好&#xff0c;就是不能打印完整的SQL语句&#xff0c;虽然可以根据数据来判断一二&#xff0c;但始终不能直观的看到实际语句。这对我们想用完整语句去数据库里执行&#xff0c;带来了不便。 怎么说呢不管用其他什么方式来实现完整语句&#xff0c;都始终不是Myb…

ongoDB从入门到实战之.NET Core使用MongoDB开发ToDoList系统(2)-Swagger框架集成

Swagger是什么&#xff1f; Swagger是一个规范且完整API文档管理框架&#xff0c;可以用于生成、描述和调用可视化的RESTful风格的 Web 服务。Swagger 的目标是对 REST API 定义一个标准且和语言无关的接口&#xff0c;可以让人和计算机拥有无须访问源码、文档或网络流量监测就…

vivado不使用的引脚约束方法

不需要分配的引脚约束方法:收藏备用 方法一&#xff1a; 方法一&#xff1a; set_property SEVERITY {Warning} [get_drc_checks NSTD-1] set_property SEVERITY {Warning} [get_drc_checks RTSTAT-1] set_property SEVERITY {Warning} [get_drc_checks UCIO-1]#方法二 set_p…

Days 27 ElfBoard 板 AltiumDesigner 相同电路快速布局布线

在进行设计开发的时候&#xff0c;总会遇到相同的电路&#xff0c;或者模块&#xff0c;这些电路可以使用相同的布局和走线&#xff0c;例如 DC-DC 电源、网口 PHY 电路部分。这类型的电路&#xff0c;我们可以采用AltiumDesigner 中的 Room 进行布局和布线的快速复制&#xff…

参观宋代建筑,感受传统魅力

为了更好地了解和传承中华文化&#xff0c;同时深入挖掘其在现代社会的传承与发展&#xff0c;2024年2月8日&#xff0c;曲阜师范大学计算机学院“古韵新声&#xff0c;格物致‘知’”社会实践队队员饶子恒深入考察中国传统建筑和文化&#xff0c;前往山东省菏泽市郓城县的水浒…

数据库管理-第14期 Oracle Vector DB AI-01(20240210)

数据库管理149期 2024-02-10 数据库管理-第149期 Oracle Vector DB & AI-01&#xff08;20240210&#xff09;1 机器学习2 向量3 向量嵌入4 向量检索5 向量数据库5 专用向量数据库的问题总结 数据库管理-第149期 Oracle Vector DB & AI-01&#xff08;20240210&#xf…

Python中HTTP隧道的基本原理与实现

HTTP隧道是一种允许客户端和服务器之间通过中间代理进行通信的技术。这种隧道技术允许代理服务器转发客户端和服务器之间的所有HTTP请求和响应&#xff0c;而不需要对请求或响应内容进行任何处理或解析。Python提供了强大的网络编程能力&#xff0c;可以使用标准库中的socket和…

波奇学Linux:文件重定向和虚拟文件系统

重定向 文件描述符所对应的分配规则&#xff0c;从0开始&#xff0c;寻找最小没有使用的数组位置。 如图所示&#xff0c;关闭文件描述符的0&#xff0c;新打开的文件描述符为0&#xff0c;而关闭2&#xff0c;文件描述符为2。 重定向&#xff1a;文件输出的对象发生改变 例…

【 buuctf snake 】

需要用到 Serpent 加密&#xff0c;蛇也不一定是 snake&#xff0c;serpent 也是蛇的意思。 binwalk -e /Users/xxx/Downloads/snake/snake.jpgbinwalk 提取 key 中有 base64 编码&#xff0c;解密 图源自BUUCTF:snake_buuctf snake-CSDN博客 结果是 anaconda&#xff0c;还有…

Docker 容器网络:C++ 客户端 — 服务器应用程序。

一、说明 在下面的文章中&#xff0c; 将向您概述 docker 容器之间的通信。docker 通信的验证将通过运行 C 客户端-服务器应用程序和标准“ping”命令来执行。将构建并运行两个单独的 Docker 映像。 由于我会关注 docker 网络方面&#xff0c;因此不会提供 C 详细信息。…

30s学会RecyclerView创建动态列表

详细学习请参考官网 使用 RecyclerView 创建动态列表 | Android 开发者 | Android Developers (google.cn) 1.RecyclerView定义及其构造 少废话&#xff0c;就是一个视图控件&#xff0c;就像你刷小红书&#xff0c;东一块西一块很丝滑地滑动 就是 RecyclerView 如下图&a…

【北邮鲁鹏老师计算机视觉课程笔记】01 introduction

1 生活中的计算机视觉 生活中的各种计算机视觉识别系统已经广泛地应用起来了。 2 计算机视觉与其他学科的关系 认知科学和神经科学是研究人类视觉系统的&#xff0c;如果能把人类视觉系统学习得更好&#xff0c;可以迁移到计算机视觉。是计算机视觉的理论基础。 算法、系统、框…

图形界面基础

X Window System 什么是 X Window System&#xff1f; 最初是1984年麻省理工学院的研究&#xff0c;之后变成UNIX、类UNIX、以及OpenVMS等操作系统所一致适用的标准化软体工具套件及显示架构的运作协定。X Window系统透过软体工具及架构协定来建立操作系统所用的图形用户界面&a…

“智能检测,精准把控。温湿度检测系统,为您的生活带来全方位的健康保障。”#非标协议项目【下】(分文件编程)

“智能检测&#xff0c;精准把控。温湿度检测系统&#xff0c;为您的生活带来全方位的健康保障。”#非标协议项目【下】&#xff08;分文件编程&#xff09; 前言预备知识1温湿度检测系统需求2.分文件编程核心思路3.分文件编程操作4利用分文件操作建立uart.c、lcd1602.c、dht11…