• Gin + Element + 云IDE 挑战一小时打造春联生成平台


    一、云空间创建

    1、点击官方链接即可开始创建工作空间

    2、查看已创建好的工作空间

    二、云IDE使用

    1、在 git 地址钱加入 ide 回车即可访问云IDE

    2、可以看到 云IDE 的界面跟本地的 VSCODE IDE 界面是相同的

    图-云IDE

    图-本地 IDE 

    3、云IDE 优点

    云端预制了常见的开发环境,无需下载安装,一键创建项目,灵活配置代码仓和云主机。同时支持在线安装 VSCode 插件来增强使用体验,支持从基础组件快速构建高阶组件,无需重新编写组件,提高研发效率。随时随地开发编码,拥有媲美本地IDE 的流畅编码体验。

    三、封装工具 

    1、该工具用于生成指定春联,指定:words  内容,horV 方向,font 字体

    2、原理是在图片上渲染字体像素

    Golang 使用 image 库将图片转字符_余衫马的博客-CSDN博客Golang 使用 image 库将图片转字符https://blog.csdn.net/weixin_47560078/article/details/127480457?spm=1001.2014.3001.55013、实现代码

    1. package util
    2. import (
    3. "flag"
    4. "github.com/golang/freetype"
    5. "image"
    6. "image/color"
    7. "image/png"
    8. "io/ioutil"
    9. "log"
    10. . "mock/lib/font/config"
    11. "os"
    12. )
    13. // charset 中文文字
    14. // horV - H-横排,V-竖排
    15. // out 输出文件名
    16. // font 字体
    17. func Generator(charset []string, outPath string, horV string, textFont TextFont) {
    18. // 打开背景图
    19. bgFile, err := os.OpenFile("../img/bg.png", os.O_RDONLY, 6)
    20. if err != nil {
    21. log.Fatal(err)
    22. }
    23. defer bgFile.Close()
    24. // 解码
    25. i, err := png.Decode(bgFile)
    26. if err != nil {
    27. log.Fatal(err)
    28. }
    29. // 图片的宽度
    30. srcWidth := 640
    31. // 图片的高度
    32. srcHeight := 640
    33. if horV == "H" {
    34. srcWidth = 640 * len(charset)
    35. }
    36. if horV == "V" {
    37. srcHeight = 640 * len(charset)
    38. }
    39. imgFile, _ := os.Create(outPath)
    40. defer imgFile.Close()
    41. img := image.NewRGBA(image.Rect(0, 0, srcWidth, srcHeight))
    42. if horV == "H" {
    43. log.Println("横向生成,渲染背景...")
    44. // 根据字符长度创建背景
    45. for index := 0; index < len(charset); index++ {
    46. // 复制背景图
    47. for y := 0; y < srcHeight; y++ {
    48. for x := index * 640; x < srcWidth; x++ {
    49. if x < 640 {
    50. img.Set(x, y, i.At(x, y))
    51. } else {
    52. img.Set(x, y, i.At(x-index*640, y))
    53. }
    54. }
    55. }
    56. }
    57. }
    58. if horV == "V" {
    59. log.Println("竖向生成,渲染背景...")
    60. // 根据字符长度创建背景
    61. for index := 0; index < len(charset); index++ {
    62. // 复制背景图
    63. for y := index * 640; y < srcHeight; y++ {
    64. for x := 0; x < srcWidth; x++ {
    65. if y < 640 {
    66. img.Set(x, y, i.At(x, y))
    67. } else {
    68. img.Set(x, y, i.At(x, y-index*640))
    69. }
    70. }
    71. }
    72. }
    73. }
    74. // 读取字体数据
    75. fontFileName := "../lib/font/" + textFont.FontName
    76. fontBytes, err := ioutil.ReadFile(fontFileName)
    77. log.Printf("加载字体:%s...", textFont.FontName)
    78. if err != nil {
    79. log.Fatal(err)
    80. }
    81. // 载入字体数据
    82. font, err := freetype.ParseFont(fontBytes)
    83. if err != nil {
    84. log.Println("载入字体失败!", err)
    85. }
    86. f := freetype.NewContext()
    87. // 设置分辨率
    88. f.SetDPI(100)
    89. // 设置字体
    90. f.SetFont(font)
    91. // 设置尺寸
    92. f.SetFontSize(textFont.FontSize)
    93. f.SetClip(img.Bounds())
    94. // 设置输出的图片
    95. f.SetDst(img)
    96. // 设置字体颜色(黑色)
    97. f.SetSrc(image.NewUniform(color.Black))
    98. if horV == "H" {
    99. log.Println("开始绘制对联...")
    100. // 绘制字符
    101. for index := 0; index < len(charset); index++ {
    102. // 设置字体的位置
    103. pt := freetype.Pt(textFont.X+index*640, textFont.Y)
    104. _, err = f.DrawString(charset[index], pt)
    105. if err != nil {
    106. log.Fatal(err)
    107. }
    108. }
    109. }
    110. if horV == "V" {
    111. // 绘制字符
    112. for index := 0; index < len(charset); index++ {
    113. // 设置字体的位置
    114. pt := freetype.Pt(textFont.X, textFont.Y+index*640)
    115. _, err = f.DrawString(charset[index], pt)
    116. if err != nil {
    117. log.Fatal(err)
    118. }
    119. }
    120. }
    121. // 以png 格式写入文件作为输出
    122. err = png.Encode(imgFile, img)
    123. if err != nil {
    124. log.Fatal(err)
    125. }
    126. log.Println("Done.")
    127. }

    四、Template 引用 Element UI

    1、参考 Element 官方文档

    2、页面功能:用户在输入框填写文本,选择效果(方向,字体)后,点击 Run 按钮,返回用户预期效果图片

    1. html>
    2. <html>
    3. <head>
    4. <meta charset="UTF-8">
    5. <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js">script>
    6. <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
    7. head>
    8. <body>
    9. <div id="app">
    10. <div class="demo-image__lazy" style="margin-top:30px;">
    11. <el-image src="../res/3f8b879b-fa29-4dda-8e08-1f82cbd2d895.png">el-image>
    12. div>
    13. <el-input placeholder="请输入内容" v-model="input" clearable>
    14. el-input>
    15. <el-radio v-model="horV" label="H">水平方向el-radio>
    16. <el-radio v-model="horV" label="V">垂直方向el-radio>
    17. <el-radio v-model="font" label="font1">字体1el-radio>
    18. <el-radio v-model="font" label="font2">字体2el-radio>
    19. <el-button style="margin-left: 10px;margin-top:30px;" size="small" type="success" @click="submitUpload"
    20. v-loading.fullscreen.lock="fullscreenLoading" element-loading-text="拼命加载中">Run
    21. el-button>
    22. <div class="demo-image__lazy" style="margin-top:30px;">
    23. <el-image v-for="url in urls" :key="url" :src="url" lazy>el-image>
    24. div>
    25. div>
    26. body>
    27. <script src="https://unpkg.com/vue@2/dist/vue.js">script>
    28. <script src="https://unpkg.com/element-ui/lib/index.js">script>
    29. <script>
    30. new Vue({
    31. el: '#app',
    32. data() {
    33. return {
    34. horV: 'H',
    35. font: 'font1',
    36. input: '',
    37. urls: [],
    38. fullscreenLoading: false
    39. };
    40. },
    41. methods: {
    42. // 提交表单
    43. submitUpload() {
    44. if (this.input.length > 0) {
    45. console.log(this.input, this.horV, this.font);
    46. let formdata = {
    47. words: this.input,
    48. horV: this.horV,
    49. font: this.font,
    50. };
    51. this.fullscreenLoading = true;
    52. var that = this;
    53. axios({
    54. url: '/api/GetImg',
    55. method: 'post',
    56. data: formdata,
    57. headers: {
    58. 'Content-Type': 'application/x-www-form-urlencoded'
    59. }
    60. })
    61. .then(function (response) {
    62. console.log('success');
    63. console.log(response);
    64. that.urls = response.data.urls;
    65. that.fullscreenLoading = false;
    66. })
    67. .catch(function (error) {
    68. console.log('error');
    69. console.log(error);
    70. });
    71. }
    72. }
    73. }
    74. })
    75. script>
    76. html>

    五、定义控制器

    1、Index 用于返回定义好的 Index.tmpl 模板

    2、GetImg 用于响应页面请求

    1. package controller
    2. import (
    3. "net/http"
    4. "github.com/gin-gonic/gin"
    5. "mock/lib/font/config"
    6. . "mock/util"
    7. uuid "github.com/satori/go.uuid"
    8. )
    9. // 首页
    10. func Index(c *gin.Context) {
    11. c.HTML(http.StatusOK, "index.tmpl", nil)
    12. }
    13. // 参数 worlds,horV,font => 春联内容,方向,字体
    14. func GetImg(c *gin.Context) {
    15. // ================== 参数处理
    16. words := c.PostForm("words")
    17. // 处理字符
    18. var charset []string
    19. if len(words) > 0 {
    20. for _, v := range words {
    21. charset = append(charset, string(v))
    22. }
    23. } else {
    24. charset = []string{"你", "好", "世", "界"}
    25. }
    26. // 处理方向
    27. horV := c.PostForm("horV")
    28. if len(horV) > 0 {
    29. if horV != "H" && horV != "V" {
    30. horV = "H"
    31. }
    32. } else {
    33. horV = "H"
    34. }
    35. // 输出路径
    36. outPath := "../res/" + uuid.NewV4().String() + ".png"
    37. // 处理字体
    38. font := config.Font_1
    39. ft := c.PostForm("font")
    40. if len(ft) > 0 {
    41. if ft != "font1" && ft != "font2" {
    42. font = config.Font_1
    43. }
    44. } else {
    45. font = config.Font_1
    46. }
    47. // 生成对联
    48. Generator(charset, outPath, horV, font)
    49. // 返回数组
    50. urls := []string{outPath}
    51. c.JSON(http.StatusOK, gin.H{
    52. "status": "success",
    53. "urls": urls,
    54. })
    55. }

    六、跨域中间件

    1、如果不做跨域配置,axios 请求可能会被拦截

    1. package middleware
    2. import (
    3. "github.com/gin-contrib/cors"
    4. "github.com/gin-gonic/gin"
    5. "time"
    6. )
    7. // 跨域请求
    8. func Cors() gin.HandlerFunc {
    9. handlerFunc := cors.New(cors.Config{
    10. AllowMethods: []string{"*"},
    11. AllowHeaders: []string{"content-type", "token", "fileType", "size", "digest"}, //此处设置非默认之外的请求头(自定义请求头),否则会出现跨域问题
    12. AllowAllOrigins: true,
    13. AllowCredentials: true,
    14. MaxAge: 24 * time.Hour,
    15. ExposeHeaders: []string{"*"},
    16. })
    17. return handlerFunc
    18. }
    19. // gin 上下文配置 cors
    20. func CORSMiddleware() gin.HandlerFunc {
    21. return func(c *gin.Context) {
    22. c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
    23. c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
    24. c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
    25. c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, GET, PUT, HEAD, OPTIONS")
    26. if c.Request.Method == "OPTIONS" {
    27. c.AbortWithStatus(204)
    28. return
    29. }
    30. c.Next()
    31. }
    32. }
    33. //nginx 跨域
    34. //server {
    35. //#以上省略
    36. //add_header 'Access-Control-Allow-Origin' '*';
    37. //add_header 'Access-Control-Allow-Headers' 'X-Pagination-Current-Page,Content-Type';
    38. //add_header 'Access-Control-Allow-Methods' 'PUT,GET,POST,HEAD,DELETE';
    39. //add_header 'Access-Control-Expose-Headers' 'X-Pagination-Current-Page,Content-Type';
    40. //#以下省略
    41. //}
    42. //Allow-Headers "Accept","Accept-Encoding","Host","Origin","Referer","User-Agent",

    七、定义路由

    1、放行静态路径和页面模板

    2、放行业务接口

    1. package router
    2. import (
    3. . "mock/controller"
    4. "mock/middleware"
    5. "net/http"
    6. "github.com/gin-gonic/gin"
    7. )
    8. /*
    9. InitRouter 路由初始化
    10. */
    11. func InitRouter() *gin.Engine {
    12. router := gin.Default()
    13. // 加载 templates 文件夹下所有的 tmpl
    14. router.LoadHTMLGlob("../templates/*")
    15. router.StaticFS("/res", http.Dir("../res"))
    16. router.GET("/", Index)
    17. v1 := router.Group("/api")
    18. v1.Use(middleware.CORSMiddleware())
    19. {
    20. v1.Any("/GetImg", GetImg)
    21. }
    22. return router
    23. }

    八、main入口

    1、以 8080 端口启动服务,默认为 localhost

    1. package main
    2. import (
    3. "mock/router"
    4. )
    5. func main() {
    6. r := router.InitRouter()
    7. r.Run(":8080")
    8. }

    九、自动化脚本

    1、先执行 go build 生成可执行文件 cmd 后,编写自动执行脚本

    1. autoOpen: true
    2. apps:
    3. - port: 8080
    4. command: go env -w GOPROXY=https://goproxy.cn,direct & cd cmd && ./cmd
    5. root: ./
    6. name: demo
    7. description: demo
    8. autoOpen: true

    十、运行效果

    1、重新打开页面时,脚本自动执行,自动开启前后端

    十一、云IDE测评总结 

    1、编码流畅度:目前使用来说很流畅,偶尔会有字符输入延时,也有出现整个IDE卡死、没有提示语法的情况

    2、开发环境:云端自带的开发环境能满足大部分的需求,也可以自行安装插件,我使用的是Go环境也能自动识别,这点可以节省一大部分搭建环境的时间(下载-安装-配置),提高开发效率。

    3、灵活度:不局限与本地机器,只要有网络,随时随地都可以使用云IDE。

  • 相关阅读:
    软件定义汽车的关键—车载操作系统
    【算法题】2525. 根据规则将箱子分类
    eeglab加载显示脑电数据,eeglab简单操作
    Leetcode刷题详解——不同路径
    CSP漫画工作室clipstudiopaint最新版本2022功能介绍
    【Python】Flask上下文管理
    STC15W单片机防丢语音报警GPS北斗定位测距双机LORA无线手持可充电
    Dubbo(二)Dubbo和ZooKeeper的协同工作原理
    【模板语法+数据绑定+el与data的两种写法+MVVM模型】
    C#基础--对象和类型
  • 原文地址:https://blog.csdn.net/weixin_47560078/article/details/127712877