electron-上传文件,下载csv txt xlsx

2023-11-04

https://github.com/SimulatedGREG/electron-vue
https://simulatedgreg.gitbooks.io/electron-vue/content/cn/
在这里插入图片描述

主进程

  • 可以看做是package.json中main属性对应得文件
  • 一个应用只会有一个进行
  • 只有主进程可以进行GUI的API操作(图例中Native apis)

渲染进程:

  • windows中展示的界面通过渲染进程表现
  • 一个应用可以有多个渲染进程

核心:启动主进程,创建窗口,加载指定界面,之后开启渲染进程,如果说渲染进程需要通信这时候利用ipc完成通信操作,之后通过主进程调用原生api,在进行跟操作系统进行互动从而完成功能的操作。

在这里插入图片描述
ipcRenderer
https://www.electronjs.org/zh/docs/latest/api/ipc-renderer

  • ipcRenderer.on
ipcRenderer.on(channel, listener)
// channel: string
// listener: function(event, ...args)
监听channel,当新消息到达,将通过listener(event, args...)调用listener
  • ipcRenderer.send
ipcRenderer.send(channel, ...args)
// channel: string
// ...args: any
通过channel向主进程发送异步信息,可以发送任意参数。
主进程中,通过ipcMain模块下的channel来处理这些消息

在vue中调用接口 - 相互通信

大概流程就是vue中不能直接向接口发送请求,必须通过ipcRenderer.send()来向主进程发送请求,然后再主进程中发送接口请求,把接口请求的返回参数通过event.sender.send()发送给.vue中,.vue中必须时刻监听‘event.sender.send()请求’,监听的方式是ipcRenderer.on()

在****.vue中

<template>
	<div @click="handleLogin">接口请求</div>
</template>
<script>
import { ipcRenderer } from 'electron'
export default {
  data () {
    return {}
  },
  created () {
    ipcRenderer.send('getaccount-login')  // 加载的时候接口请求
  },
  mounted () {
  	// 监听主进程返回的数据
    ipcRenderer.on('account-login', (event, response) => {
      console.log(response)
    })
  },
  methods: {
    handleLogin () {
      ipcRenderer.send('getaccount-login', this.ruleForm)
    }
  }
}
</script>

在index.js中

import { app, BrowserWindow, ipcMain, Menu, session, dialog } from 'electron'
import elog from 'electron-log'
import {getAccountLogin} from './api'
 // 创建窗口
function createWindow () {
  elog.info('app on ready')
  /**
   * Initial window options
   */
  if (process.platform === 'darwin') {
    const template = [
      {
        label: 'Application',
        submenu: [
          { label: 'Quit',
            accelerator: 'Command+Q',
            click: () => { app.quit() }
          }
        ]
      },
      {
        label: 'Edit',
        submenu: [
          { label: 'Copy', accelerator: 'CmdOrCtrl+C', selector: 'copy:' },
          { label: 'Paste', accelerator: 'CmdOrCtrl+V', selector: 'paste:' }
        ]
      }
    ]
    // mac下 设置快捷按键
    Menu.setApplicationMenu(Menu.buildFromTemplate(template))
  } else {
    Menu.setApplicationMenu(null)
  }
  // 设置窗口的参数
  mainWindow = new BrowserWindow({
    height: 623,
    useContentSize: true,
    width: 1000
  })

  mainWindow.loadURL(winURL)

  mainWindow.on('closed', () => {
    mainWindow = null
  })
}
app.on('ready', createWindow)

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', () => {
  if (mainWindow === null) {
    createWindow()
  }
})

ipcMain.on('getaccount-login', (event, form) => {
  getAccountLogin(form).then(res => {
    event.sender.send('account-login', res)  // 将接口中的参数返沪
  }).catch(e => {
    console.log(e)
  })
})

api.js

import myAxios from 'axios'
import Util from './util.js'
const service = myAxios.create({
  timeout: 10000, // 请求超时时间
  withCredentials: true
})
// // respone拦截器
// service.interceptors.response.use(
//   response => {
//     /**
//     * code为非20000是抛错 可结合自己业务进行修改
//     */
//     const res = response.data
//     if (res.code) {
//       // 401:Token 过期了;
//       const errRes = {code: res.code}
//       return errRes
//     } else {
//       return response.data
//     }
//   },
//   error => {
//     let errorMsg = error.response
//     // console.log('errorMsg', errorMsg)
//     if (!errorMsg) {
//       errorMsg = error.message
//     }
//     return Promise.reject(error)
//   }
// )

export const getAccountLogin = (params) => {
  return service({
    headers: {'Content-Type': 'application/json'},
    method: 'post',
    url: `https://authentication.com/accsounts/accountLogin`,
    data: params
  })
}

filePath = ''
ipcRenderer.send('openFile-dialog', this.filePath)


// 打开文件选择框,oldPath上一次打开的位置
ipcMain.on('openFile-dialog', (event, oldPath) => {
  if (oldPath === '') {
    oldPath = app.getPath('downloads')
  }
  console.log('oldPath==', oldPath)
  let newPath = dialog.showOpenDialog({
    title: '保存的位置',
    properties: ['openDirectory', 'createDirectory'],
    defaultPath: oldPath
  })
  event.sender.send('file-name', newPath)
})

csv、txt

示例:
上传文档csv或者txt,并将文件中得内容解析
在这里插入图片描述

在这里插入图片描述

<template>
	<el-button @click="jieix">解析csv内容</el-button>
	<el-input v-model="form.filePath" :disabled="true" placeholder="请选择上传测试集.csv/.txt">
     	<el-button slot="append" icon="el-icon-document" @click="onOpenFile">	</el-button>
	</el-input>
</template>
import { ipcRenderer } from 'electron'
<script>
	export default {
		data() {
			return {
				form: {
					filePath: ''
				}
			}
		},
		mounted() {
    		ipcRenderer.on('selected-file', (event, path) => {
      			this.form.filePath = path ? path[0] : ''
    		})
		},
		method: {
    		// 上传测试集
    		onOpenFile () {
      			ipcRenderer.send('open-file')
    		},

    		jieix () {
      			ipcRenderer.send('detail-data', this.form)
    		}
		}
	}
</script>

上传csv文件

index.js中

import { ipcMain, dialog } from 'electron'
// 上传csv文件
ipcMain.on('open-file', (event, param) => {
  let filters = [{name: 'CSV', extensions: ['csv', 'txt']}]
  dialog.showOpenDialog({
    properties: ['openFile'],
    filters: filters
  }, (path) => {
    if (path) {
      event.sender.send('selected-file', path)
    }
  })
})

将csv文件读取内容

iconv-lite:解决读取内容乱码

// 将csv文件解析内容
import iconv from 'iconv-lite'
ipcMain.on('detail-data', (event, form) => {
  let detailData = fs.readFileSync(path.resolve(form.filePath)) // 读取文件内容
  detailData = iconv.decode(detailData, 'GBK') // 处理乱码问题
  // detailData = iconv.decode(detailData, 'UTF-8') // 解析txt时,用utf-8
  let lineArr = detailData.split('\r\n') // 分割文件的每一行文本
  console.log('lineArr=====', lineArr) // 解析到的内容
})

xlsx

上传xlsx文件

// 上传xlsx文件
ipcMain.on('open-file', (event, param) => {
  let filters = [{ name: 'XLSX', extensions: ['xlsx'] }]
  dialog.showOpenDialog({
    properties: ['openFile'],
    filters: filters
  }, (path) => {
    if (path) {
      event.sender.send('selected-file', path)
    }
  })
})

xlsx文件内容读取

上传xlsx文件并读取xlsx文件内容
“node-xlsx”: “^0.15.0”,
“xlsx-style”: “^0.8.13”

nodeExcel.js中

const xlsx = require('node-xlsx').default
export const readExcel = (fileName) => {
  return xlsx.parse(fileName)
}

index.js中

import {readExcel} from './nodeExcel.js'
ipcMain.on('xlsx-data', (event, form) => {
  const xlsxJson = readExcel(form.filePath) // 读取xlsx内容
  for (let i = 0; i < xlsxJson.length; i++) {  // 注意这边将每个工作表中单元格为空的返回'',否则对应不上
    for (let j = 0; j < xlsxJson[i].data.length; j++) {
      for (let x = 0; x < xlsxJson[i].data[0].length; x++) { // 根据标题(第一行)得长度
        if (xlsxJson[i].data[j][x] === undefined) {
          xlsxJson[i].data[j][x] = ''
        }
      }
    }
  }
  event.sender.send('getxslx-data', xlsxJson)
})

上传的xlsx
在这里插入图片描述
xlsxJson数据格式
在这里插入图片描述

下载xslx文件

简单无样式的表格 node-xlsx

import os from 'os'
const xlsx = require('node-xlsx').default
const fs = require('fs')
export const createExcelTest = (options, callback) => {
  const worksheets = [
    {
      name: 'sheet1',
      data: [['表头A', '表头B', '表头C', '表头D'], ['数据A', '数据B', '数据C', '数据D']]
    },
    {
      name: 'sheet2',
      data: [['表头A', '表头B', '表头C', '表头D'], ['数据A', '数据B', '数据C', '数据D']]
    }
  ]
  const buffer = xlsx.build(worksheets)
  console.log('buffer=', buffer)
  const folderExists = fs.existsSync(`${os.homedir()}/assess-tools`)  // os 模块内置的应用编程接口,用于获取当前用户的主目录路径
  console.log('folderExists=', folderExists)
  if (!folderExists) {
    fs.mkdirSync(`${os.homedir()}/assess-tools/`)
  }
  let fileName = `测试结果明细-${new Date().getTime()}.xlsx`
  fs.writeFile(`${os.homedir()}/assess-tools/${fileName}`, buffer, function (err) {
    if (err) { throw err }
    console.log('Write to xlsx has finished')
    const res = {msg: `测试报告已生成`, path: `${os.homedir()}/assess-tools/${fileName}`}
    callback(res)
  })
}

下载xslx文件 带有格式(一个工作表)xlsx-style

在这里插入图片描述

import os from 'os'
const xlsx = require('node-xlsx').default
const styleXlsx = require('xlsx-style')
const fs = require('fs')

export const createExcelTest = (options, callback) => {
  let _headers = ['id', 'name', 'age', 'country', 'remark']
  let _headersName = ['sid', 'sname', 'asge', 'csountry', 'rsemark']
  let _data = [
    {
      id: 1,
      name: 'dsd',
      age: 22,
      country: 'shagng',
      remark: 'hello'
    },
    {
      id: 12,
      name: '232dsd',
      age: 32,
      country: 'shagng2323',
      remark: 'hell2323o'
    }
  ]
  let headersExport = _headersName
    .map((v, i) => Object.assign({}, { v: v, position: String.fromCharCode(65 + i) + 1 }))
    .reduce((prev, next) => Object.assign({}, prev, {
      [next.position]: {
        v: next.v
      }
    }), {})

  let dataExport = _data.map((v, i) => _headers.map((k, j) => Object.assign({}, { v: v[k], position: String.fromCharCode(65 + j) + (i + 2) })))
    .reduce((prev, next) => prev.concat(next))
    .reduce((prev, next) => Object.assign({}, prev, {
      [next.position]: {
        v: next.v,
        s: {
          alignment: {
            horizontal: 'center',
            vertical: 'center',
            wrapText: true // 设置单元格换行
          }
        }
      }
    }), {})
  console.log('dataExport==', dataExport)
  // 合并 headersExport和dataExport
  const output = Object.assign({}, headersExport, dataExport)
  // 获取所有单元格的位置
  const outputPos = Object.keys(output)
  // 计算出范围
  const ref = outputPos[0] + ':' + outputPos[outputPos.length - 1]
  // 构建workbook对象
  const wb = {
    SheetNames: ['Sheet'],
    Sheets: {
      'Sheet': Object.assign({}, output, { '!ref': ref }, {'!cols': [ { wch: 20 }, { wpx: 150 }, { wch: 20 }, { wch: 15 }, { wch: 15 } ]})
    }
  }
  const folderExists = fs.existsSync(`${os.homedir()}/assess-tools`)
  if (!folderExists) {
    fs.mkdirSync(`${os.homedir()}/assess-tools/`)
  }
  let fileName = `测试结果明细-${new Date().getTime()}.xlsx`
  const filePath = `${os.homedir()}/assess-tools/${fileName}`
  styleXlsx.writeFile(wb, filePath)
  console.log('Write to xlsx has finished')
  const res = {msg: `校验报告已生成`, path: filePath}
  callback(res)
}

下载xslx文件 多张工作表表,位置数据

在这里插入图片描述

import os from 'os'
const xlsx = require('node-xlsx').default
const styleXlsx = require('xlsx-style')
const fs = require('fs')
export const createExcelTest = (options, callback) => {
options.dataInfo = [
    {
      name: '单轮测试集',
      data: [
        ['测试用例', '技能', '任务', '意图', '语义', 'command', 'nlg', '错误提示', '实际结果'],
        ['打开主驾车窗', '1', '', '', '', '', '', '技能错误,预期返回结果:无语义错误,预期返回结果:无,实际返回结果:有', '{"contextId":"24ca0af766a931","d…"skillId":"2022101700000012","topic":"dm.output"}'],
        ['打开主驾车窗', '', '2', '3', '', '', '', '技能错误,预期返回结果:预期返回结果:无,实际返回结果:有', '{"contextId":"2022112","topic":"dm.output"}'],
        ['打开主驾车窗', '', '', 'd', 'd', '', '', '技能错误,预期返回结果:…,预期返回结果:无,实际返回结果:有', '12","topic":"dm.output"}'],
        ['打开主驾车窗', '', '', '', '', '', '', '技能错误,预期返回结果有', '{"contextId":"24ca0af760b']
      ]
    },
    {
      name: '单轮车控测试集ssdsd',
      data: [
        ['测试用sds例', '技能', '任务', '意图', '语义', 'command', 'nlg', '错误提示', '实际结果'],
        ['sd', '1', '', '', '', '', '', '技能错误,预期返回结果:无,实际返回结果义错误,预期返回结果:无,实际返回结果:有', '{"contextId":"24c8931","d…"skillId":"2022112","topic":"dm.output"}']
      ]
    }
  ]

  const wb = {
    SheetNames: [],
    Sheets: {}
  }
  let _header = [] // 每个sheet表中表格标题,第一行(二维数组)
  let _data = [] // 每个sheet表中表格内容,第二行开始的内容(三维数组)
  options.dataInfo.forEach((item, index) => {
    wb.SheetNames.push(item.name)
    _header.push(item.data[0])
    let data = item.data.slice(1, item.data.length)
    _data.push(data)
  })
  let headersExport = _header.map((item, index) => {
    let obj = item.map((v, i) => Object.assign({}, { v: v, position: String.fromCharCode(65 + i) + 1 }))
      .reduce((prev, next) => Object.assign({}, prev, {
        [next.position]: {
          v: next.v
        }
      }), {})
    return obj
  })
  let dataExport = []
  _data.forEach(sitem => {
    let dataExportArr = sitem.map((item, index) => {
      let obj = item.map((v, i) => Object.assign({}, {v: v, position: String.fromCharCode(65 + i) + (index + 2)}))
        .reduce((prev, next) => Object.assign({}, prev, {
          [next.position]: {
            v: next.v,
            s: {
              alignment: {
                horizontal: 'center',
                vertical: 'center',
                wrapText: true // 设置单元格换行
              }
            }
          }
        }), {})
      return obj
    })
    dataExport.push(dataExportArr)
  })
  let output = []
  for (let i = 0; i < headersExport.length; i++) {
    let obj = {}
    dataExport[i].forEach(item => {
      obj = {...obj, ...item}
    })
    let outputInfo = {
      ...headersExport[i],
      ...obj
    }
    output.push(outputInfo)
  }

  let outputPos = output.map(item => {
    return Object.keys(item)
  })

  let ref = []
  outputPos.forEach(item => {
    console.log(item)
    let refText = item[0] + ':' + item[item.length - 1]
    ref.push(refText)
  })
  wb.SheetNames.forEach((item, index) => {
    // wb.Sheets[item] = Object.assign({}, output[index], { '!ref': ref[index] }, {'!cols': [ { wch: 20 }, { wpx: 150 }, { wch: 20 }, { wch: 15 }, { wch: 15 } ]})
    wb.Sheets[item] = Object.assign({}, output[index], { '!ref': ref[index] })
  })
  console.log('wb=====', wb)
  console.log(wb.Sheets['单轮测试集'])
  console.log(wb.Sheets['单轮测试集'])

  const folderExists = fs.existsSync(`${os.homedir()}/assess-tools`)
  if (!folderExists) {
    fs.mkdirSync(`${os.homedir()}/assess-tools/`)
  }
  let fileName = `测试结果-${new Date().getTime()}.xlsx`
  const filePath = `${os.homedir()}/assess-tools/${fileName}`
  styleXlsx.writeFile(wb, filePath)
  console.log('Write to xlsx has finished')
  const res = {msg: `校验报告已生成`, path: filePath}
  callback(res)
}

在这里插入图片描述

在这里插入图片描述

创建csv文件,并异步一条条写入数据

方法一 fs.createReadStream readline.createInterface

注:csv可以创建文件后,一条条写入数据,xlsx不支持此功能

fs :
1、返回一个readStream(文件读取流,输入流)对象。(可读流)
fs.createReadStream(path, [options])
由于该方法属于fs模块,使用前需要引入fs模块(var fs= require(“fs”) )
2、fs.existsSync以同步的方法检测目录是否存在。如果目录存在 返回 true ,如果目录不存在 返回false

readline :
通过这个模块我们可以以逐行的方式读取数据流
readline.createInterface({input: fRead}) 创建readline接口实例

import fs from 'fs'
import readline from 'readline'
format () {
  const fRead = fs.createReadStream(form.filePath) // 创建可读流,并读取,注意这边form.filePath不为空如果为空则会报错
  const objReadline = readline.createInterface({input: fRead})
  objReadline.on('close', function () {
	const filePath = `${os.homedir()}/assess-tools`
	const folderExists = fs.existsSync(`${filePath}`)
	if (!folderExists) {
      fs.mkdirSync(`${filePath}/`)
    }
    let fileName = `assess-${new Date().getTime()}.csv` // 注:最好加上日期不然第二次下载的时候,会报错(第一个文件跟第二个文件同名)
    let createFileName = `${os.homedir()}/as/${fileName}`
    let data = ['name', 'age', 'sex']
    fs.appendFileSync(createFileName, `\uFEFF${data .join(',')}\n`, {
        encoding: 'utf8',
        mode: 0o666,
        flag: 'a'
    }) // 有多少数据写多少数据,可以将此段提取出来,跟接口返回操作,通过websocket连接,得到一条数据,写入csv文件中一条
    getTestDm(createFileName, res => {
    	// 判断是否是最后一条数据
    	console.log(res)
	})
  }
}
function getTestDm (createFileName, callback) {
  let datas = ['lily', '22', 'girl']
  fs.appendFileSync(createFilePath[count], `\uFEFF${datas.join(',')}\n`)
  // 当一切操作完可以返回一些内容
  let res = 'done'
  callback(res)
}

对于上述fs.createReadStream(form.filePath)使用局限性问题,这边示例则采用之间创建csv文件并异步存入数据

方法二 fs.writeFile

import os from 'os'
import fs from 'fs'
function createCsvFile () {
  const filePath = `${os.homedir()}/assess-tools`
  const folderExists = fs.existsSync(`${filePath}`)
    if (!folderExists) {
    fs.mkdirSync(`${filePath}/`)
  }
  let fileName = `测试-${new Date().getTime()}.csv`
  let createFilePath = `${os.homedir()}/assess-tools/${fileName}`
  let title = ['姓名', '年龄']
  fs.writeFile(createFilePath, `\uFEFF${title.join(',')}\n`, function (err) {
	if (!err) {
	 // 可以写个函数放上数据然后
	 // let data = ['哈哈哈', '20']
	 // fs.appendFileSync(createFilePath[count], `\uFEFF${datas.join(',')}\n`)
	}
  })
}

`姓名,年龄\n哈哈哈,20\n嘻嘻嘻,89’
生成csv为
姓名 年龄
哈哈哈 20
嘻嘻嘻 89

csv 格式编辑

单元格支持英文逗号

注:
1、英文状态下逗号,csv中会当成另外一列
2、\n在csv中规则换行
3、csv中单元格换个加双引号并且换行的内容处加\n 如dataArr[7] = ""操作=调节\n对象=车窗 \n对象_raw=车窗
3、如果let val = {“a”: “bb”, “c”: “dd”} let strs = JSON.stringify(val).replace(/“/g, "") strs = "${strs}"将原本的"替换为”",然后进行’“a,b”'类似这种写法

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

electron-上传文件,下载csv txt xlsx 的相关文章

随机推荐

  • mysqld: File ‘./binlog.index‘ not found (OS errno 13 - Permission denied)

    背景 CentOS Stream 9安装Mysql8 0社区版时 为了修改端口 增加了my cnf文件 发现重启后报错 binlog index找不到 解决方法 1 关掉SELINUX root 192 mysql vi etc selin
  • JAVA异常实验:车站检查危险品的设备,如果发现危险品会发出警告。编程模拟设备发现危险品

    车站检查危险品的设备 如果发现危险品会发出警告 编程模拟设备发现危险品 编写能够满足如下条件的程序 编写一个Exception的子类DangerException 该子类可以创建异常对象 该异常对象调用showMessage 方法输出 属于
  • Spring MVC 源码分析之 加载及查找 Controller

    目录 一 前言 二 查找Handler 2 1 回顾 doDispatch 2 2 查看 getHandler方法 2 3 handlerMappings的前世今生 三 补充说明 1 通过 方式 2 SpringBoot方式 四 总结 一
  • python中request、lxml、xpath使用

    request lxml xpath request 环境搭建 pip install requests 使用方法 下载完包之后 在项目中引入包 import requests 发送请求 get请求 import requests 通过re
  • 再谈type ahead 问题

    问题 给定一个词典 包括一些词和其出现的频率 实现type ahead功能 要求用户每键入一个字符 下拉框显示以当前输入为前缀的前10个最热门的词 解法1 用不带data的Trie data仅仅是词频 实时查询法 需要实时的去build h
  • redis cluster 实践总结

    最近项目接触到了redis cluster 现在趁着使用做一下总结 记录一下遇到过的问题 简单的概述一下常用到的命令和功能 本篇文章主要是以运维的角度去讲述如何去更好的规划redis cluster和跳坑 redis cluster 官方文
  • 解决springboot 启动类 &controller 不在一个module 显示404的问题

    1 启动类中添加扫描 SpringBootApplication scanBasePackages com zqm 2 启动类的pom依赖必须有controller中的pom依赖 3 如果有控制类多个module 都需要添加依赖 扫描 4
  • 代理IP基础、实际运用,以及如何获取

    代理IP是指通过一个中间服务器来转发用户的网络请求 从而在网络上隐藏用户的真实IP地址 或者绕过网络限制以达到访问特定内容的目的 下面是代理IP的一些基础知识 1 代理IP的分类 代理IP可以分为普匿代理IP 透明代理IP和高匿代理IP三种
  • 实现JS异步加载的三种方法

    一 为什么要写异步加载 js加载本身是属于同步加载的 加载js文件会阻塞文档 一旦网速不好 那么整个网站将等待js加载而不进行后续渲染等工作 但是有些工具方法需要按需加载 有一些工具js文件它是不会改变页面的 用到再加载 不用不加载 但是实
  • leetcode905–按奇偶排序数组(经典/原地排序)

    经典题目 给定一个非负整数数组 A 返回一个数组 在该数组中 A 的所有偶数元素之后跟着所有奇数元素 你可以返回满足此条件的任何数组作为答案 主要要掌握最优解 这道题很简单 类快排 你不是真正的快排 Note The returned ar
  • 如何为你的文本标签添加圆点、三角等不规则图形-保姆级教程

    1 通过无序列表 有序列表可以简单的生成带符号的文本 带符号的文本 https img blog csdnimg cn 9005611a7fa74d188ee071cd63fae0cf png 具体代码如下 h4 Disc 项目符号列表 h
  • Java实现内网穿透

    使用场景 1 当公司的一些系统功能使用了第三方服务时 通常第三方会回调我们的接口 在对接阶段 为了方便debug 我们肯定希望能回调到我们本地电脑上来 2 当你在公司想访问部署在家里电脑的服务或者文件时 3 当你的外地同事想访问你本地的服务
  • spring-boot-starter-data-mongodb 配置副本集读写分离、故障转移等

    一 为什么需要 MongoDB 副本集配置 副本集配置为数据库提供了高可用的保证 mongodb 副本集能够支持在主节点宕机的情况进行自动选主 同时利用多个从节点进行数据冗余 达到数据热备份的作用 同时由于数据同步 可支持读写分离 二 如何
  • es中must和should的组合查询

    使用must和should混用的时候 should不生效 列如 需要同时满足productRecomentd和location shold中满足一个条件就返回 经过多次测试 发现should不起效果 from 0 size 2 query
  • Java学习—字面常量值,变量,最终变量

    一 什么是字面常量值 他们是在程序中固定写死的的值 二 各种数据类型的表示 所有字符串类型的字面常量值必须加 所有char类型的字面常量值必须加 boolean类型的常量值只有两个 true false 浮点类型的常量值 没有加F或f的都是
  • unity 模型销毁_Unity3D常用 API 之实例化与销毁

    1 实例化游戏物体 1 1 游戏中的案例介绍 在很多 MMORPG 类的游戏中都有类似于 金钱副本 的副本关卡 在这类副 本中通常都是限定一个时间 在这个时间内玩家可以尽情的破坏 然后收集金钱 分析游戏截图讲解场景元素 见图 场景中所有的坛
  • latex 如何添加圆圈数字?

    众所周知 LATEX 提供了 textcircled 命令用以给字符加圈 但效果却不怎么好 实际上 加圈并不是一个平凡的变换 它会涉及到圈内字符形状的微调 而这是几乎无法在 TEX 宏层面解决的 因此 要得到比较好的效果 最好能使用预先设计
  • iwebsec靶场 文件包含漏洞通关笔记9-file://伪协议利用

    目录 前言 1 file协议 2 利用条件 1 file 用于访问本地文件系统 2 file 必须是绝对路径 第09关 file 伪协议利用 1 打开靶场 2 源码分析 3 获取 etc passwd渗透 前言 1 file协议 file协
  • QCQI学习笔记(1)

    Chapter I II overview of the quantum information probabilistic model qubit tensor product dirac notation Chapter III Sup
  • electron-上传文件,下载csv txt xlsx

    electron 主进程 渲染进程 在vue中调用接口 相互通信 csv txt 上传csv文件 将csv文件读取内容 iconv lite 解决读取内容乱码 xlsx 上传xlsx文件 xlsx文件内容读取 下载xslx文件 简单无样式的