实现Excel文件和其他文件导出为压缩包,并导入

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 实现Excel文件和其他文件导出为压缩包,并导入

 导出

后端:

@PostMapping("/exportExcelData")
  public void exportExcelData(HttpServletRequest request, HttpServletResponse response, @RequestBody ResData resData) throws IOException {
    List<Long> menuIds = resData.getMenuIds();
    List<Conversion> conversions = new ArrayList<>();
    List<String> ktrFilePaths = new ArrayList<>();
    for (Long menuId : menuIds) {
      Conversion conversion = conversionMapper.selectById(menuId);
      if (conversion != null) {
        conversions.add(conversion);
        String ktrFilePath = fileService.getKtrFilePathById(menuId);
        if (ktrFilePath != null && !ktrFilePaths.contains(ktrFilePath)) {
          ktrFilePaths.add(ktrFilePath);
        }
      }
    }
    // 创建Excel工作簿
    HSSFWorkbook workbook = new HSSFWorkbook();
    // 创建一个工作表
    Sheet sheet = workbook.createSheet("Conversions");
    // 创建单元格样式,并设置为文本格式
    CellStyle textStyle = workbook.createCellStyle();
    DataFormat format = workbook.createDataFormat();
    textStyle.setDataFormat(format.getFormat("@")); // "@" 表示文本格式
    // 创建标题行
    Row titleRow = sheet.createRow(0);
    // 创建单元格样式,并设置为文本格式
    titleRow.createCell(0).setCellValue("主键");
    titleRow.createCell(1).setCellValue("分组id");
    titleRow.createCell(2).setCellValue("名称");
    titleRow.createCell(3).setCellValue("备注");
    titleRow.createCell(4).setCellValue("创建人");
    titleRow.createCell(5).setCellValue("关联状态");
    titleRow.createCell(6).setCellValue("XMl");
    titleRow.createCell(7).setCellValue("创建时间");
    // 应用文本格式到标题行的特定单元格
    titleRow.getCell(0).setCellStyle(textStyle);
    titleRow.getCell(1).setCellStyle(textStyle);
    // 填充数据
    int rowNum = 1;
    for (Conversion conversion : conversions) {
      Row row = sheet.createRow(rowNum++);
      Cell cell = row.createCell(0);
      cell.setCellValue(String.valueOf(conversion.getId()));
      cell.setCellStyle(textStyle);
      cell = row.createCell(1);
      cell.setCellValue(String.valueOf(conversion.getGroupId()));
      cell.setCellStyle(textStyle); // 应用文本格式
      row.createCell(2).setCellValue(conversion.getName());
      row.createCell(3).setCellValue(conversion.getRemark());
      row.createCell(4).setCellValue(conversion.getCreateUserName());
      row.createCell(5).setCellValue(conversion.getState());
      row.createCell(6).setCellValue(conversion.getEditXml());
      row.createCell(7).setCellValue(String.valueOf(conversion.getCreateTime()));
    }
    // 设置响应头
    response.setContentType("application/vnd.ms-excel");
    response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("conversions.xls", "UTF-8"));
    // 设置响应头
    response.setContentType("application/zip");
    response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("conversions.zip", "UTF-8"));
    ZipOutputStream zipOut = new ZipOutputStream(response.getOutputStream());
    // 将Excel文件添加到压缩包
    ZipEntry excelEntry = new ZipEntry("conversions.xls");
    zipOut.putNextEntry(excelEntry);
    workbook.write(zipOut);
    zipOut.closeEntry();
    workbook.close();
    // 添加.ktr文件到ktr目录
    for (String filePath : ktrFilePaths) {
      File ktrFile = new File(filePath);
      if (ktrFile.exists()) {
        FileInputStream fis = new FileInputStream(ktrFile);
        // 创建ZipEntry时,需要包含ktr目录
        ZipEntry ktrEntry = new ZipEntry("ktr/" + ktrFile.getName());
        zipOut.putNextEntry(ktrEntry);
        byte[] bytes = new byte[1024];
        int length;
        while ((length = fis.read(bytes)) >= 0) {
          zipOut.write(bytes, 0, length);
        }
        fis.close();
        zipOut.closeEntry();
      }
    }
    // 完成压缩包
    zipOut.finish();
    zipOut.close();
  }

image.gif

导出后的文件组成:

image.gif 编辑

image.gif 编辑

image.gif 编辑

excel文件:

image.gif 编辑

前端:

<template>
  <div class="app-container" style="width:100%;">
    <el-form label-width="80px" label-position="left">
      <el-form-item label="模型树">
        <el-tree
          ref="tree"
          :data="treeData"
          show-checkbox
          :default-expand-all="false"
          node-key="id"
          highlight-current
          :props="defaultProps"
        />
      </el-form-item>
    </el-form>
    <div style="text-align: center;width:100%;">
      <el-button type="primary" @click="onSave">导出</el-button>
      <el-button type="danger" @click="closePage">取消</el-button>
    </div>
  </div>
</template>
<script>
import { getTreeData } from '@/api/dataSchema'
import { exportData,exportExcelData } from '@/api/conversion'
import { Message } from 'element-ui'
export default {
  name: 'Zzjg',
  inject: ['getList'],
  props: {
    proid: {
      type: String,
      required: true
    }
  },
  data() {
    return {
      defaultProps: {
        children: 'children',
        label: 'name'
      },
      treeData: []
    }
  },
  methods: {
    getDetailed() {
      const loading = this.$loading({
        lock: true,
        text: 'Loading',
        spinner: 'el-icon-loading',
        background: 'rgba(0, 0, 0, 0.7)'
      })
      getTreeData().then(response => {
        this.treeData = response.data
        
        loading.close()
      }).catch(function() {
        loading.close()
      })
    },
    onSave() {
      var menuIds = this.$refs.tree.getCheckedKeys()
      if (menuIds.length === 0) {
        Message({
          message: '请选择要导出的模型',
          type: 'error',
          duration: 5 * 1000
        })
        return
      } else {
        const loading = this.$loading({
          lock: true,
          text: 'Loading',
          spinner: 'el-icon-loading',
          background: 'rgba(0, 0, 0, 0.7)'
        })
        
        exportExcelData({ menuIds: menuIds }).then(response => {
          var fileName = 'download.zip'
          const contentDisposition = response.headers['content-disposition']
          if (contentDisposition) {
            fileName = window.decodeURI(response.headers['content-disposition'].split('=')[1], 'UTF-8')
          }
          const blob = new Blob([response.data], {
            type: `application/zip` // word文档为msword,pdf文档为pdf
          })
          const objectUrl = URL.createObjectURL(blob)
          const link = document.createElement('a')
          link.href = objectUrl
          link.setAttribute('download', fileName)
          document.body.appendChild(link)
          link.click()
          // 释放内存
          window.URL.revokeObjectURL(link.href)
          Message({
            message: '导出成功',
            type: 'success',
            duration: 5 * 1000
          })
          loading.close()
          this.$emit('update:visible', false)
          this.getList()
        }).catch(response => {
          loading.close()
        })
      }
    },
    closePage() {
      this.$emit('update:visible', false)
      this.getList()
    }
  }
}
</script>

image.gif

代码拆解:

通过前端传来的menuIds进行遍历,把每一条数据插到excel里面并且通过menuIds找到文件名与之对应的ktr文件放到文件夹中。

for (Long menuId : menuIds) {
      Conversion conversion = conversionMapper.selectById(menuId);
      if (conversion != null) {
        conversions.add(conversion);
        String ktrFilePath = fileService.getKtrFilePathById(menuId);
        if (ktrFilePath != null && !ktrFilePaths.contains(ktrFilePath)) {
          ktrFilePaths.add(ktrFilePath);
        }
      }
    }

image.gif

创建excel导出模板:

// 创建Excel工作簿
    HSSFWorkbook workbook = new HSSFWorkbook();
    // 创建一个工作表
    Sheet sheet = workbook.createSheet("Conversions");
    // 创建单元格样式,并设置为文本格式
    CellStyle textStyle = workbook.createCellStyle();
    DataFormat format = workbook.createDataFormat();
    textStyle.setDataFormat(format.getFormat("@")); // "@" 表示文本格式
    // 创建标题行
    Row titleRow = sheet.createRow(0);
    // 创建单元格样式,并设置为文本格式
    titleRow.createCell(0).setCellValue("主键");
    titleRow.createCell(1).setCellValue("分组id");
    titleRow.createCell(2).setCellValue("名称");
    titleRow.createCell(3).setCellValue("备注");
    titleRow.createCell(4).setCellValue("创建人");
    titleRow.createCell(5).setCellValue("关联状态");
    titleRow.createCell(6).setCellValue("XMl");
    titleRow.createCell(7).setCellValue("创建时间");
    // 应用文本格式到标题行的特定单元格
    titleRow.getCell(0).setCellStyle(textStyle);
    titleRow.getCell(1).setCellStyle(textStyle);
    // 填充数据
    int rowNum = 1;
    for (Conversion conversion : conversions) {
      Row row = sheet.createRow(rowNum++);
      Cell cell = row.createCell(0);
      cell.setCellValue(String.valueOf(conversion.getId()));
      cell.setCellStyle(textStyle);
      cell = row.createCell(1);
      cell.setCellValue(String.valueOf(conversion.getGroupId()));
      cell.setCellStyle(textStyle); // 应用文本格式
      row.createCell(2).setCellValue(conversion.getName());
      row.createCell(3).setCellValue(conversion.getRemark());
      row.createCell(4).setCellValue(conversion.getCreateUserName());
      row.createCell(5).setCellValue(conversion.getState());
      row.createCell(6).setCellValue(conversion.getEditXml());
      row.createCell(7).setCellValue(String.valueOf(conversion.getCreateTime()));
    }

image.gif

我这里的id和groupId位数特别长,所以对这两列做了默认为文本的处理,否则会变成科学计数法,会丢精。

具体如下:

 

// 创建单元格样式,并设置为文本格式
    CellStyle textStyle = workbook.createCellStyle();
    DataFormat format = workbook.createDataFormat();
    textStyle.setDataFormat(format.getFormat("@")); // "@" 表示文本格式
// 应用文本格式到标题行的特定单元格
    titleRow.getCell(0).setCellStyle(textStyle);
    titleRow.getCell(1).setCellStyle(textStyle);
Row row = sheet.createRow(rowNum++);
      Cell cell = row.createCell(0);
      cell.setCellValue(String.valueOf(conversion.getId()));
      cell.setCellStyle(textStyle);
      cell = row.createCell(1);
      cell.setCellValue(String.valueOf(conversion.getGroupId()));
      cell.setCellStyle(textStyle); // 应用文本格式

image.gif

把excel文件添加到压缩包:

// 将Excel文件添加到压缩包
    ZipEntry excelEntry = new ZipEntry("conversions.xls");
    zipOut.putNextEntry(excelEntry);
    workbook.write(zipOut);
    zipOut.closeEntry();
    workbook.close();

image.gif

把ktr文件放到ktr命名的文件夹中,并关闭压缩文件流

// 添加.ktr文件到ktr目录
    for (String filePath : ktrFilePaths) {
      File ktrFile = new File(filePath);
      if (ktrFile.exists()) {
        FileInputStream fis = new FileInputStream(ktrFile);
        // 创建ZipEntry时,需要包含ktr目录
        ZipEntry ktrEntry = new ZipEntry("ktr/" + ktrFile.getName());
        zipOut.putNextEntry(ktrEntry);
        byte[] bytes = new byte[1024];
        int length;
        while ((length = fis.read(bytes)) >= 0) {
          zipOut.write(bytes, 0, length);
        }
        fis.close();
        zipOut.closeEntry();
      }
    }
    // 完成压缩包
    zipOut.finish();
    zipOut.close();

image.gif

导出就完成了。

导入

后端

导入的时候有一个要求,就是把导出时的id作为老的id存到数据库里,并生成新的id把新的id作为对应ktr的文件名存到对应的路径下面

解析数据:

@PostMapping("/insertData")
  public ResultData insertData(@RequestAttribute Long _userId, HttpServletRequest request) {
    MultipartHttpServletRequest req = (MultipartHttpServletRequest) request;
    MultipartFile uploadFile = req.getFile("uploadfile_ant");
    String originalName = uploadFile.getOriginalFilename();
    String docPath = "";
    List<Long> codes = new ArrayList<>(); // 用于存储所有导入的 ID
    try {
      String classpath = ResourceUtils.getURL("classpath:").getPath();
      String path = classpath + File.separator + "static" + File.separator + "file" + File.separator + "yulan";
      docPath = path + File.separator + originalName;
      File dir = new File(path);
      if (!dir.exists()) {
        dir.mkdirs();
      }
      // 保存压缩文件
      File zipFile = new File(docPath);
      FileCopyUtils.copy(uploadFile.getInputStream(), new FileOutputStream(zipFile));
      // 解压压缩文件
      File unzipDir = new File(zipFile.getPath().substring(0, zipFile.getPath().lastIndexOf(".zip")));
      if (!unzipDir.exists()) {
        unzipDir.mkdirs();
      }
      unzipFile(zipFile, unzipDir);
      // 处理解压后的文件
      processUnzippedFiles(unzipDir);
      return ResultData.success("ok", codes); // 返回所有导入的 ID 列表
    } catch (Exception e) {
      e.printStackTrace();
      return ResultData.error("error");
    }
  }

image.gif

解压代码:

private void unzipFile(File zipFile, File unzipDir) throws IOException {
    try (ZipInputStream zipIn = new ZipInputStream(new FileInputStream(zipFile))) {
      ZipEntry entry = zipIn.getNextEntry();
      while (entry != null) {
        String filePath = unzipDir.getPath() + File.separator + entry.getName();
        if (!entry.isDirectory()) {
          extractFile(zipIn, filePath);
        } else {
          File dir = new File(filePath);
          dir.mkdirs();
        }
        zipIn.closeEntry();
        entry = zipIn.getNextEntry();
      }
    }
  }

image.gif

private void extractFile(ZipInputStream zipIn, String filePath) throws IOException {
    new File(filePath).getParentFile().mkdirs();
    try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath))) {
      byte[] bytesIn = new byte[4096];
      int read = 0;
      while ((read = zipIn.read(bytesIn)) != -1) {
        bos.write(bytesIn, 0, read);
      }
    }
  }

image.gif

根据不同的文件类型去做不同的处理:

private void processUnzippedFiles(File unzipDir) throws Exception {
    // 遍历解压后的目录,处理每个文件
    Files.walk(unzipDir.toPath())
        .forEach(filePath -> {
          try {
            if (Files.isRegularFile(filePath) && filePath.toString().endsWith(".xls")) {
              //如果是excel文件
              processExcelFile(filePath, unzipDir.toPath());
//            } else if (Files.isDirectory(filePath) && "ktr".equals(filePath.getFileName().toString())) {
//              //ktr文件夹
//              processKtrDirectory(filePath);
            }
          } catch (Exception e) {
            e.printStackTrace();
          }
        });
  }

image.gif

处理excel:

@Transactional
  public void processExcelFile(Path filePath, Path zipPath) throws Exception {
    Workbook workbook = null;
    try {
      FileInputStream excelFile = new FileInputStream(filePath.toFile());
      workbook = WorkbookFactory.create(excelFile); // 支持多种格式
      // 假设我们只处理第一个工作表
      Sheet sheet = workbook.getSheetAt(0);
      // 跳过标题行
      int startRowIndex = 1;
      DataFormatter formatter = new DataFormatter();
      for (int i = startRowIndex; i <= sheet.getLastRowNum(); i++) {
        Row row = sheet.getRow(i);
        if (row != null) {
          // 假设Excel文件的列顺序和数据库字段对应
          Cell idCell = row.getCell(0);
          Cell groupIdCell = row.getCell(1);
          Cell NameCell = row.getCell(2);
          Cell remarkCell = row.getCell(3);
          Cell creatorCell = row.getCell(4);
          Cell xmlCell = row.getCell(6);
          // 检查空值和数据转换
          String setOldId = formatter.formatCellValue(row.getCell(0));
          String groupId = formatter.formatCellValue(row.getCell(1));
          String remark = (remarkCell != null) ? remarkCell.getStringCellValue() : null;
          String Name = (NameCell != null) ? NameCell.getStringCellValue() : null;
          String creator = (creatorCell != null) ? creatorCell.getStringCellValue() :null;
          String state = formatter.formatCellValue(row.getCell(5));
          String XML = (xmlCell != null) ? xmlCell.getStringCellValue() : null;
          // 创建一个数据对象,例如DataObject,并填充字段
          Conversion conversion = new Conversion();
          conversion.setId(SnowflakeIdGenerator.getId());
          conversion.setOldId(Long.parseLong(setOldId));
          conversion.setGroupId(Long.parseLong(groupId));
          conversion.setName(Name);
          conversion.setRemark(remark);
          conversion.setCreateUserId(creator);
          conversion.setState(Integer.parseInt(state));
          conversion.setEditXml(XML);
          conversion.setCreateTime(LocalDateTime.now());
          // 保存到数据库
          conversionMapper.insert(conversion);
          //ktr文件夹
          processKtrDirectory(zipPath, conversion.getId(), conversion.getOldId());
        }
      }
    } catch (Exception e) {
      throw new Exception("Error processing Excel file", e);
    } finally {
      if (workbook != null) {
        try {
          workbook.close();
        } catch (IOException e) {
          // Log and handle workbook close exception
        }
      }
    }
  }

image.gif

处理ktr:

private void processKtrDirectory(Path ktrDir, Long newId, Long oldId) throws Exception {
    // 处理ktr文件夹,将文件保存到磁盘路径下的逻辑
    // 例如:
    String targetPath = ktrPath + File.separator + Constant.kettleScriptFileName + File.separator + Constant.ktrFileName + File.separator;
    String newPath = ktrDir.toString()+"/ktr";
    try {
      Files.copy(Paths.get(newPath + File.separator + oldId.toString()), Paths.get(targetPath + newId.toString()));
    } catch (IOException e) {
      e.printStackTrace();
    }
  }

image.gif

用copy(source,target)就可以实现把文件保存到指定路径

fileService.getKtrFilePathById:

/**
 * 根据menuId获取对应的.ktr文件路径。
 * @return 文件路径
 */
@Service
@Transactional
public class FileServiceImpl implements FileService {
    @Value("${ktr.path}")
    private String ktrPath;
    public String getKtrFilePathById(Long menuId) {
        // 假设.ktr文件存储在 "/path/to/ktr/files/" 目录下,文件名为 "menuId.ktr"
        String baseDir = ktrPath + File.separator + Constant.kettleScriptFileName + File.separator + Constant.ktrFileName+File.separator;
        File file = new File(baseDir + menuId);
        if (file.exists()) {
            return file.getAbsolutePath();
        } else {
            return null; // 或者抛出一个异常,表示文件不存在
        }
    }
}

image.gif

前端:

<template>
  <div class="app-container" style="margin: 0 auto;width:100%;">
    <el-form ref="form" label-width="80px" label-position="left">
      <!-- <el-form-item>
        <div slot="label">分组<font color="red">*</font></div>
        <el-select v-model="form.groupId" placeholder="请选择分组" style="width: 100%">
          <el-option v-for="item in fzList" :key="item.id" :label="item.name" :value="item.id" />
        </el-select>
      </el-form-item> -->
      <!-- <el-form-item>
        <div slot="label">模型名称<font color="red">*</font></div>
        <el-input v-model="form.name" style="width:100%;" :autosize="{ minRows: 2, maxRows: 2}" />
      </el-form-item> -->
      <el-form-item>
        <div slot="label">导入模型<font color="red">*</font></div>
        <el-upload
          accept=".zip"
          ref="upload"
          name="uploadfile_ant"
          class="upload-demo"
          :limit="1"
          :action="uploadpath"
          :headers="uoloadheaders"
          :before-upload="beforeAvatarUpload"
          :on-success="handleAvatarSuccess"
          :on-change="handleChange"
          :on-remove="handleRemove"
          :on-exceed="handleExceed"
          :file-list="fileList"
        >
          <el-button size="small" icon="el-icon-upload" type="primary">选择模型文件</el-button>
          <span style="color:red;">  上传文件大小不能超过100MB</span>
        </el-upload>
      </el-form-item>
      <!-- <el-form-item label="备注:">
        <el-input v-model="form.remark" type="textarea" maxlength="200" rows="6" placeholder="备注" />
      </el-form-item> -->
    </el-form>
    <!-- <div style="text-align: center;width:100%;">
      <el-button type="primary" @click="onSave">保存</el-button>
      <el-button type="danger" @click="closePage">取消</el-button>
    </div> -->
  </div>
</template>
<script>
import { getWorkList } from '@/api/dataSchema'
import { updateData } from '@/api/conversion'
import { Message, MessageBox } from 'element-ui'
import tool from '@/utils/tool'
export default {
  name: 'Zzjg',
  inject: ['getList'],
  props: {
    proid: {
      type: String,
      required: true
    }
  },
  data() {
    return {
      uploadpath: '',
      uoloadheaders: {},
      fileData: '', // 文件上传数据(多文件合一)
      fileList: [], // upload多文件数组
      fzList: [],
      form: {},
      code: ''
    }
  },
  methods: {
    getDetailed() {
      getWorkList().then(response => {        
        this.fzList = response.data
        let address = process.env.NODE_ENV == 'development' ? process.env.VUE_APP_URL_RECON : process.env.VUE_APP_BASE_API;
        var path = '/ltcloud/conversion/insertData'
        this.uploadpath = address + path
        
        this.uoloadheaders = {
          'X-TOKEN' : tool.getCookie('X-Token'),
          'client-url':location.href,
          'applicationId':this.applicationId
        }
      })
    },
    handleAvatarSuccess(res, file) {
      if (res.code === 20000) {
        this.code = res.data
        Message({
          message: '上传成功',
          type: 'success',
          duration: 5 * 1000
        })
      } else {
        Message({
          message: res.msg,
          type: 'error',
          duration: 5 * 1000
        })
      }
    },
    // 移除
    handleRemove(file, fileList) {
      this.fileList = fileList
    },
    beforeAvatarUpload(file) {
      const isLt2M = file.size / 1024 / 1024 < 100
      if (!isLt2M) {
        this.$message.error('上传文件大小不能超过100MB!')
      }
      return isLt2M
    },
    // 选取文件超过数量提示
    handleExceed(files, fileList) {
      this.$message.warning(`当前限制选择 1 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`)
    },
    // 监控上传文件列表
    handleChange(file, fileList) {
      const existFile = fileList.slice(0, fileList.length - 1).find(f => f.name === file.name)
      if (existFile) {
        this.$message.error('当前文件已经存在!')
        fileList.pop()
      }
      this.fileList = fileList
    },
    onSave() {
      console.log('分组不能为空')
      if (!this.form.groupId) {
        this.$message.error('分组不能为空')
        return
      } else if (!this.form.name) {
        this.$message.error('模型名称不能为空')
        return
      } else if (this.fileList.length === 0) {
        this.$message.error('导入模型不能为空')
        return
      } else {
        const loading = this.$loading({
          lock: true,
          text: 'Loading',
          spinner: 'el-icon-loading',
          background: 'rgba(0, 0, 0, 0.7)'
        })
        
        this.form.idList = this.code
        updateData(this.form).then(response => {
          Message({
            message: '编辑成功',
            type: 'success',
            duration: 5 * 1000
          })
          loading.close()
          this.$emit('update:visible', false)
          this.getList()
        }).catch(response => {
          loading.close()
          this.getList()
        })
      }
    },
    closePage() {
      this.$emit('update:visible', false)
      this.getList()
    }
  }
}
</script>
<style lang="less">
  /deep/ .el-dialog {
    width: 550px;
    height: 650px;
  }
  .displayCol {
    display: flex;
  }
  .newNum {
    height: 20px;
    width: 20px;
    border: 1px solid #333;
    border-radius: 50%;
    text-align: center;
    margin-top: 3px;
    line-height: 20px;
  }
  /deep/.el-form-item__label {
    text-align: left !important;
    padding: 0 10px;
  }
  .disabled-text {
    pointer-events: none; /* 阻止鼠标事件 */
    cursor: default; /* 将鼠标光标设置为默认样式,表明文本不可点击 */
    opacity: 0.5; /* 降低文本的不透明度以显示出它是不可交互的 */
    user-select: none; /* 禁止文本被选中 */
  }
  .el-upload-list {
    float: left;
    margin: 0;
    padding: 0;
    list-style: none;
  }
  .el-upload {
    margin-left: 0px;
    display: inline-block;
    text-align: center;
    cursor: pointer;
    outline: 0;
  }
  .el-upload__tip {
    font-size: 12px;
    color: #606266;
    margin-top: 7px;
    width: 300px;
    line-height: 45px;
    height: 10px;
  }
</style>

image.gif


目录
相关文章
|
15天前
|
存储 人工智能 弹性计算
阿里云弹性计算_加速计算专场精华概览 | 2024云栖大会回顾
2024年9月19-21日,2024云栖大会在杭州云栖小镇举行,阿里云智能集团资深技术专家、异构计算产品技术负责人王超等多位产品、技术专家,共同带来了题为《AI Infra的前沿技术与应用实践》的专场session。本次专场重点介绍了阿里云AI Infra 产品架构与技术能力,及用户如何使用阿里云灵骏产品进行AI大模型开发、训练和应用。围绕当下大模型训练和推理的技术难点,专家们分享了如何在阿里云上实现稳定、高效、经济的大模型训练,并通过多个客户案例展示了云上大模型训练的显著优势。
|
19天前
|
存储 人工智能 调度
阿里云吴结生:高性能计算持续创新,响应数据+AI时代的多元化负载需求
在数字化转型的大潮中,每家公司都在积极探索如何利用数据驱动业务增长,而AI技术的快速发展更是加速了这一进程。
|
10天前
|
并行计算 前端开发 物联网
全网首发!真·从0到1!万字长文带你入门Qwen2.5-Coder——介绍、体验、本地部署及简单微调
2024年11月12日,阿里云通义大模型团队正式开源通义千问代码模型全系列,包括6款Qwen2.5-Coder模型,每个规模包含Base和Instruct两个版本。其中32B尺寸的旗舰代码模型在多项基准评测中取得开源最佳成绩,成为全球最强开源代码模型,多项关键能力超越GPT-4o。Qwen2.5-Coder具备强大、多样和实用等优点,通过持续训练,结合源代码、文本代码混合数据及合成数据,显著提升了代码生成、推理和修复等核心任务的性能。此外,该模型还支持多种编程语言,并在人类偏好对齐方面表现出色。本文为周周的奇妙编程原创,阿里云社区首发,未经同意不得转载。
|
23天前
|
缓存 监控 Linux
Python 实时获取Linux服务器信息
Python 实时获取Linux服务器信息
|
8天前
|
人工智能 自然语言处理 前端开发
什么?!通义千问也可以在线开发应用了?!
阿里巴巴推出的通义千问,是一个超大规模语言模型,旨在高效处理信息和生成创意内容。它不仅能在创意文案、办公助理、学习助手等领域提供丰富交互体验,还支持定制化解决方案。近日,通义千问推出代码模式,基于Qwen2.5-Coder模型,用户即使不懂编程也能用自然语言生成应用,如个人简历、2048小游戏等。该模式通过预置模板和灵活的自定义选项,极大简化了应用开发过程,助力用户快速实现创意。
|
5天前
|
云安全 存储 弹性计算
|
7天前
|
云安全 人工智能 自然语言处理
|
5天前
|
人工智能 C++ iOS开发
ollama + qwen2.5-coder + VS Code + Continue 实现本地AI 辅助写代码
本文介绍在Apple M4 MacOS环境下搭建Ollama和qwen2.5-coder模型的过程。首先通过官网或Brew安装Ollama,然后下载qwen2.5-coder模型,可通过终端命令`ollama run qwen2.5-coder`启动模型进行测试。最后,在VS Code中安装Continue插件,并配置qwen2.5-coder模型用于代码开发辅助。
369 4
|
5天前
|
缓存 Linux Docker
【最新版正确姿势】Docker安装教程(简单几步即可完成)
之前的老版本Docker安装教程已经发生了变化,本文分享了Docker最新版安装教程,其他操作系统版本也可以参考官 方的其他安装版本文档。
【最新版正确姿势】Docker安装教程(简单几步即可完成)
|
11天前
|
人工智能 自然语言处理 前端开发
用通义灵码,从 0 开始打造一个完整APP,无需编程经验就可以完成
通义灵码携手科技博主@玺哥超carry 打造全网第一个完整的、面向普通人的自然语言编程教程。完全使用 AI,再配合简单易懂的方法,只要你会打字,就能真正做出一个完整的应用。本教程完全免费,而且为大家准备了 100 个降噪蓝牙耳机,送给前 100 个完成的粉丝。获奖的方式非常简单,只要你跟着教程完成第一课的内容就能获得。