使用Golang编写Windows小工具

2023-05-10

这段代码是一个用于将派工明细文件同步到MES系统的程序插件。它包含了一些结构体和方法,用于处理文件上传和解析HTTP响应。在main函数中,程序首先获取当前目录并读取配置文件。然后,它遍历指定目录下的文件,找到当天发生变动的派工明细文件。接下来,程序使用多线程并发地读取文件,并将文件内容上传到MES系统。最后,程序解析MES系统的响应,并打印出相应的信息。

简介

派工明细文件同步是将派工明细文件上传到MES系统的过程。派工明细文件包含了产品的详细信息,如产品型号、数量和生产日期等。将这些信息同步到MES系统中可以实现生产数据的实时更新和管理。 派工明细文件同步的重要性在于:

  1. 数据准确性:通过将派工明细文件同步到MES系统,可以确保生产数据的准确性。这有助于避免人工输入错误和数据不一致的问题。
  2. 实时更新:派工明细文件同步可以实现生产数据的实时更新。这意味着生产部门和其他相关部门可以及时获取最新的生产数据,以便做出准确的决策。
  3. 数据分析:将派工明细文件同步到MES系统后,可以对生产数据进行更深入的分析。通过对数据的统计和分析,可以发现生产过程中的潜在问题,并采取相应的措施进行改进。
  4. 效率提升:派工明细文件同步可以提高生产过程的效率。通过自动化的文件上传和数据更新,可以减少人工操作的时间和错误,提高生产效率。 综上所述,派工明细文件同步对于实现生产数据的准确性、实时更新和数据分析具有重要意义。它可以提高生产过程的效率,并为企业的决策提供准确的数据支持。

代码编写

结构体和方法:

  • Config:用于存储配置信息的结构体,包括MES站点地址、扫描文件路径、派工上传人和是否覆盖数据。
  • Multipart:用于处理文件上传的结构体。
  • CreateFormFile方法:用于创建表单文件并将文件内容复制到表单中。
  • CreateFormField方法:用于创建表单字段并将字段值写入表单中。
  • ParseResponse函数:用于解析HTTP响应并返回结果。

主函数步骤:

  • 获取当前目录和配置文件。
  • 读取配置文件,并解析为Config结构体。
  • 遍历指定目录下的文件,找到当天发生变动的派工明细文件。
  • 并发地读取文件并将文件内容上传到MES系统。
  • 解析MES系统的响应并打印相应的信息。

结果解析步骤:

  • 读取响应体的内容。
  • 使用json.Unmarshal函数将响应体解析为map[string]interface{}类型的结果。
  • 返回解析结果和可能的错误。

交叉编译

编译成windows环境exe可执行文件过程,打开文件所在目录,使用以下命令进行交叉编译并生成 Windows 可执行文件。其中,GOOS 环境变量设置为 windows 表示目标操作系统为 Windows,GOARCH 环境变量设置为 amd64 表示目标处理器架构为 64 位。GOOS=windows GOARCH=amd64 go build -o MesUploader.exe 这将会在当前目录下生成一个名为 MesUploader.exe 的 Windows 可执行文件。 现在你可以将生成的 MesUploader.exe 文件拷贝到 Windows 系统上运行。

请注意,在进行交叉编译时,需要使用目标操作系统和处理器架构相关的环境变量来告诉 Go 编译器生成相应的可执行文件。以上示例中使用了 GOOS=windows 和 GOARCH=amd64 来生成适用于 Windows 的 64 位可执行文件。可以根据需要调整这些环境变量以满足你的要求。

总结

通过本文,学习了如何使用Go语言编写一个派工明细文件同步程序插件。了解了如何读取配置文件、遍历文件、并发上传文件,并解析MES系统的响应。这个插件可以帮助实现派工明细文件的同步,提高工作效率。

完整代码

package main
import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/gookit/color"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"os"
	"path/filepath"
	"sync"
	"time"
)

type Config struct {
	ApiUrl        string `json:"MES站点地址"`
	FileDir       string `json:"扫描文件路径"`
	CreateUser    string `json:"派工上传人"`
	UpdateSupport string `json:"是否覆盖数据"`
}
type Multipart struct {
	FilePath string
}

func (m *Multipart) CreateFormFile(writer *multipart.Writer) error {
	file, err := os.Open(m.FilePath)
	if err != nil {
		color.Redp("读取文件失败:", err)
		return err
	}
	defer file.Close()

	part, err := writer.CreateFormFile("file", filepath.Base(m.FilePath))
	if err != nil {
		color.Redp("创建表单文件失败:", err)
		return err
	}
	if err != nil {
		color.Redp("写入表单数据失败:", err)
		return err
	}
	_, err = io.Copy(part, file)
	if err != nil {
		color.Redp("复制文件失败:", err)
		return err
	}
	return nil
}

func (m *Multipart) CreateFormField(writer *multipart.Writer, user string, updateSupport string) error {
	fileWriter2, err := writer.CreateFormField("userName")
	if err != nil {
		return err
	}
	_, errs2 := fileWriter2.Write([]byte(user))
	if errs2 != nil {
		return errs2
	}
	fileWriter3, err := writer.CreateFormField("updateSupport")
	if err != nil {
		return err
	}
	_, errs3 := fileWriter3.Write([]byte(updateSupport))
	if errs3 != nil {
		return errs2
	}

	return nil
}


func ParseResponse(response *http.Response) (map[string]interface{}, error) {
	var result map[string]interface{}
	body, err := ioutil.ReadAll(response.Body)
	if err == nil {
		err = json.Unmarshal(body, &result)
	}
	return result, err
}



func main() {

	// 获取当前目录
	dir, err := os.Getwd()
	if err != nil {
		color.Redp("获取当前目录失败:", err)
		fmt.Scanf("h")
		return
	}

	// 读取配置文件
	configFile, err := os.Open(filepath.Join(dir, "config.json"))
	if err != nil {
		color.Error.Println("读取config.json配置文件失败:", err)
		fmt.Scanf("h")
		return
	}
	defer configFile.Close()

	// 解析配置文件
	var config Config
	err = json.NewDecoder(configFile).Decode(&config)
	if err != nil {
		color.Error.Println("解析配置文件config.json失败:", err)
    fmt.Scanf("h")
		return
	}
	fmt.Println("")
	fmt.Println("===========MES-派工明细-同步程序插件================")
	fmt.Printf("当前MES站点地址:%s \t文件扫描路径:%s \t上传人配置:%s \n", config.ApiUrl, config.FileDir, config.CreateUser)
	fmt.Println("===========================================")
	color.Info.Prompt("注意:只会读取" + config.FileDir + "目录下当天发生文件变动的文件\n")
	fmt.Println("===========================================")
	// 遍历目录下的所有文件
	files, err := ioutil.ReadDir(config.FileDir)
	if err != nil {
		color.Error.Println("读取"+config.FileDir+"目录失败:", err)
		fmt.Scanf("h")
		return
	}

	// 先打印出当前目录最后改动日期为当天的文件列表,之后进行列表批量上传
	todayFiles := make([]string, 0)
	for _, file := range files {
		if !file.IsDir() && file.ModTime().Day() == time.Now().Day() {
			switch filepath.Ext(file.Name()) {
			case ".xlsx", ".xls":
				filePath := filepath.Join(config.FileDir, file.Name())
				color.Greenp("找到当天变动文件:" + filePath + "\n")
				todayFiles = append(todayFiles, filePath)
			}
		}
	}
	fmt.Println("===========================================")

	if len(todayFiles) == 0 {
		color.Danger.Prompt("没有找到当天文件改动的派工明细文件,支持的导入EXCEL格式为:xlsx,xls\n")
		fmt.Scanf("h")
		return
	}

	var wg sync.WaitGroup
	for _, filePath := range todayFiles {
		wg.Add(1)
		go func(filePath string) {
			defer wg.Done()
			fmt.Println("正在读取文件:", filePath)
			file, err := os.Open(filePath)
			if err != nil {
				fmt.Println("读取文件失败:", err)
        fmt.Scanf("h")
				return
			}
			defer file.Close()
			var resp *http.Response
			body := &bytes.Buffer{}
			writer := multipart.NewWriter(body)
			m := &Multipart{FilePath: filePath}
			errCreateFormFile := m.CreateFormFile(writer)
			if errCreateFormFile != nil {
				return
			}
			isUpdate := '0'
			if config.UpdateSupport == "是" {
				isUpdate = '1'
			}
			errCreateFormFile = m.CreateFormField(writer, config.CreateUser, string(isUpdate))
			if errCreateFormFile != nil {
				return
			}
			err = writer.Close()
			if err != nil {
				fmt.Println("关闭表单文件失败:", err)
        fmt.Scanf("h")
				return
			}
			resp, err = http.Post(config.ApiUrl+"/pms/productDispatchDetails/golangApi", writer.FormDataContentType(), body)

			if err != nil {
				fmt.Println("上传文件失败:", err)
				fmt.Println("-----------------------")
        fmt.Scanf("h")
				return
			}
			ResponseBackMap, _ := ParseResponse(resp)
			if ResponseBackMap["code"] == float64(200) {
				color.Greenln(ResponseBackMap["msg"])
			} else {
				color.Danger.Println(ResponseBackMap["msg"])
			}
			defer resp.Body.Close()
			fmt.Println("-----------------------")
		}(filePath)
	}
	wg.Wait()
	color.Success.Prompt("所有文件同步MES系统完成~,请注意提示信息,正确则可以关闭程序窗口\n")
	fmt.Scanf("h")
}