vue2中trhee.js加载模型展示天空盒子

news2025/1/29 7:31:09

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/13b9193d6738428791fc1ff112e03627.png
加载模型的时候需要把模型放在public文件下面
创建场景

this.scene = new THREE.Scene()

创建相机

  this.camera = new THREE.PerspectiveCamera(
        45,
        this.viewNode.clientWidth / this.viewNode.clientHeight,
        1,
        9999999
      )

调整相机位置

this.camera.position.set(600, 800, 1000)
      this.camera.lookAt(0, 0, 0)

创建渲染器

this.renderer = new THREE.WebGLRenderer({ 
        antialias: true,
        alpha: true 
      })
      this.renderer.setSize(this.viewNode.clientWidth, this.viewNode.clientHeight)
      this.renderer.setPixelRatio(window.devicePixelRatio)
      this.renderer.shadowMap.enabled = true // 启用阴影
      this.viewNode.appendChild(this.renderer.domElement)

添加轨道控制器

   // 添加轨道控制器
      this.controls = new OrbitControls(this.camera, this.renderer.domElement)
      this.controls.enableDamping = true
      this.controls.dampingFactor = 0.05
      this.controls.maxPolarAngle = Math.PI * 0.45
      this.controls.minPolarAngle = Math.PI * 0.1
      this.controls.minDistance = 5
      this.controls.maxDistance = 30
      this.controls.enableRotate = false // 禁止相机旋转
      this.controls.enableZoom = false // 禁止相机缩放
      this.controls.enablePan = false // 禁止相机平移

      this.initLights()
      this.initWater()
      this.initSky()
      this.loadGLTFModel()
    },

天空盒子

initSky() {
      this.sky = new Sky()
      this.sky.name='sky'
      this.sky.scale.setScalar(999999) // 调整天空盒子的大小
      this.scene.add(this.sky)

      const skyUniforms = this.sky.material.uniforms
      skyUniforms['turbidity'].value = 10
      skyUniforms['rayleigh'].value = 2
      skyUniforms['mieCoefficient'].value = 0.005
      skyUniforms['mieDirectionalG'].value = 0.8

      const parameters = {
        elevation: 2,
        azimuth: 180
      }

      const pmremGenerator = new THREE.PMREMGenerator(this.renderer)
      const phi = THREE.MathUtils.degToRad(90 - parameters.elevation)
      const theta = THREE.MathUtils.degToRad(parameters.azimuth)

      const sun = new THREE.Vector3()
      sun.setFromSphericalCoords(1, phi, theta)
      this.sky.material.uniforms['sunPosition'].value.copy(sun)
    },

添加模型的点击事件

onMouseClick(event) {
      const mouse = new THREE.Vector2()
      mouse.x = (event.clientX / this.viewNode.clientWidth) * 2 - 1
      mouse.y = -(event.clientY / this.viewNode.clientHeight) * 2 + 1

      const raycaster = new THREE.Raycaster()
      raycaster.setFromCamera(mouse, this.camera)
      console.log(';点击了模型上的某一个点点击了模型上的某一个点点击了模型上的某一个点');
   
      const intersects = raycaster.intersectObjects(this.scene.children, true)
      if (intersects.length > 0) {
        console.log(';点击了模型上的某一个点点击了模型上的某一个点点击了模型上的某一个点');
          const baifenDom = document.querySelector('.baifen')
          
          
        const intersect = intersects[0]
        console.log(intersect,'intersect-*-*-*--*');
        // if (intersect.object.type === this.model) {
        if (intersect.object.type === "Mesh" && intersect.object.parent.type === "Group") {

          console.log(this.icondom,'icon-*-*-*--*');
          console.log(this.divdom,'divdivdiv-*-*-*--*');
          
          //  // 清除上一次点击的所有操作
           this.icondom&&this.scene.remove(this.icondom);
           this.divdom&&baifenDom.removeChild(this.divdom)

           // 创建icon图标
           const iconGeometry = new THREE.SphereGeometry(0.5, 60, 60);
          const iconMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 });
           this.icondom = new THREE.Mesh(iconGeometry, iconMaterial);
           this.icondom.position.set(intersect.point.x, intersect.point.y, intersect.point.z);
          this.scene.add(this.icondom);
          console.log( intersect,'baifenDombaifenDom');
          this.divdom = document.createElement('div')
          this.divdom.style.position = 'absolute'
          this.divdom.style.width = '200px'
          this.divdom.style.height = '200px'
          this.divdom.style.backgroundColor = 'rgba(0, 0, 0, 0.5)'
          this.divdom.style.color = 'white'
          this.divdom.style.padding = '10px'
          this.divdom.style.borderRadius = '5px'
          this.divdom.style.zIndex = '1000'
          this.divdom.style.top = `${event.clientY}px`
          this.divdom.style.left = `${event.clientX}px`
          this.divdom.innerHTML = `点击了模型上的某一个点,位置为: (${intersect.point.x}, ${intersect.point.y}, ${intersect.point.z})`
          baifenDom.appendChild(this.divdom)
          // 调整相机位置以拉近模型
          // this.camera.position.set(intersect.point.x, intersect.point.y, intersect.point.z + 10); // 将相机位置设置为点击点的位置,并在z轴上偏移10单位以拉近模型
          // this.camera.lookAt(intersect.point); // 让相机看向点击点
        }
      }
    },

完整代码

<template>
  <div class="contente">
    <div class="baifen">
      <div class="app-wrap" ref="view"></div>
    </div>
  </div>
</template>

<script>
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { Water } from 'three/examples/jsm/objects/Water.js'
import { Sky } from 'three/examples/jsm/objects/Sky.js'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
// 导入glb模型
// const gltfModel = './models/dapeng2.glb' // 改为使用公共路径

export default {
  name: 'MineTd',

  data() {
    return {
      viewNode: null,
      animationId: null,
      scene: null,
      camera: null,
      renderer: null,
      controls: null,
      water: null,
      sky: null,
      model: null,
      mixer: null, // 用于动画混合器
      moveForward: false,
      moveBackward: false,
      moveLeft: false,
      moveRight: false,
      moveSpeed: 0.05, // 相机移动速度
      icondom: null,divdom: null,
    }
  },

  mounted() {
    this.$nextTick(() => {
      this.initScene()
      this.animate()
    })
    window.addEventListener('resize', this.onWindowResize)
    document.addEventListener('keydown', this.onKeyDown)
    document.addEventListener('keyup', this.onKeyUp)
    this.$refs.view.addEventListener('click', this.onMouseClick)
  },

  methods: {
    initScene() {
      this.viewNode = this.$refs.view
      // 创建场景
      this.scene = new THREE.Scene()
      // 创建相机
      this.camera = new THREE.PerspectiveCamera(
        45,
        this.viewNode.clientWidth / this.viewNode.clientHeight,
        1,
        9999999
      )
      // // 调整相机位置
      this.camera.position.set(600, 800, 1000)
      this.camera.lookAt(0, 0, 0)

      // 创建渲染器
      this.renderer = new THREE.WebGLRenderer({ 
        antialias: true,
        alpha: true 
      })
      this.renderer.setSize(this.viewNode.clientWidth, this.viewNode.clientHeight)
      this.renderer.setPixelRatio(window.devicePixelRatio)
      this.renderer.shadowMap.enabled = true // 启用阴影
      this.viewNode.appendChild(this.renderer.domElement)

      // 添加轨道控制器
      this.controls = new OrbitControls(this.camera, this.renderer.domElement)
      this.controls.enableDamping = true
      this.controls.dampingFactor = 0.05
      this.controls.maxPolarAngle = Math.PI * 0.45
      this.controls.minPolarAngle = Math.PI * 0.1
      this.controls.minDistance = 5
      this.controls.maxDistance = 30
      this.controls.enableRotate = false // 禁止相机旋转
      this.controls.enableZoom = false // 禁止相机缩放
      this.controls.enablePan = false // 禁止相机平移

      this.initLights()
      this.initWater()
      this.initSky()
      this.loadGLTFModel()
    },

    initLights() {
      // 环境光
      const ambientLight = new THREE.AmbientLight(0xffffff, 0.6)
      this.scene.add(ambientLight)

      // 平行光
      const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8)
      directionalLight.position.set(10, 10, 10)
      directionalLight.castShadow = true // 启用阴影投射
      this.scene.add(directionalLight)
    },

    initWater() {
      const waterGeometry = new THREE.PlaneGeometry(100, 100)
      this.water = new Water(waterGeometry, {
        textureWidth: 512,
        textureHeight: 512,
        waterNormals: new THREE.TextureLoader().load(
          'https://threejs.org/examples/textures/waternormals.jpg',
          texture => {
            texture.wrapS = texture.wrapT = THREE.RepeatWrapping
          }
        ),
        alpha: 1.0,
        waterColor: 0x001e0f,
        distortionScale: 3.7,
        fog: this.scene.fog !== undefined,
        depth: 10,
        flowDirection: new THREE.Vector2(1, 0.1),
        scale: 4.0
      })
      this.water.rotation.x = -Math.PI / 2
      this.water.receiveShadow = true // 接收阴影
      this.water.name = 'water' // 设置name
      this.scene.add(this.water)
    },

    initSky() {
      this.sky = new Sky()
      this.sky.name='sky'
      this.sky.scale.setScalar(999999) // 调整天空盒子的大小
      this.scene.add(this.sky)

      const skyUniforms = this.sky.material.uniforms
      skyUniforms['turbidity'].value = 10
      skyUniforms['rayleigh'].value = 2
      skyUniforms['mieCoefficient'].value = 0.005
      skyUniforms['mieDirectionalG'].value = 0.8

      const parameters = {
        elevation: 2,
        azimuth: 180
      }

      const pmremGenerator = new THREE.PMREMGenerator(this.renderer)
      const phi = THREE.MathUtils.degToRad(90 - parameters.elevation)
      const theta = THREE.MathUtils.degToRad(parameters.azimuth)

      const sun = new THREE.Vector3()
      sun.setFromSphericalCoords(1, phi, theta)
      this.sky.material.uniforms['sunPosition'].value.copy(sun)
    },

    loadGLTFModel() {
      const loader = new GLTFLoader()
      const loadingManager = new THREE.LoadingManager()
      
      // 加载管理器
      loadingManager.onProgress = (url, loaded, total) => {
        const progress = (loaded / total * 100).toFixed(2)
        console.log(`加载进度: ${progress}%`)
      }

      // 加载GLB模型
      loader.load(
        "/models/dapeng2.gltf", // 修改为.glb文件
        (gltf) => {
          this.model = gltf.scene
          this.model.name = 'dapeng'
          // 遍历模型网格启用阴影
          this.model.traverse((node) => {
            if (node.isMesh) {
              node.castShadow = true
              node.receiveShadow = true
            }
          })
          
          // 调整模型位置和大小
          this.model.position.set(0, 1, 0) // 将模型位置调整到相机的正下方
          this.model.scale.set(0.2, 0.2, 0.2)
          // 将模型添加到场景
          this.scene.add(this.model)
          
          // 处理动画
          if (gltf.animations && gltf.animations.length) {
            this.mixer = new THREE.AnimationMixer(this.model)
            gltf.animations.forEach((clip) => {
              const action = this.mixer.clipAction(clip)
              action.play()
            })
          }


          const bbox = new THREE.Box3().setFromObject(this.model);
const center = bbox.getCenter(new THREE.Vector3());
// this.camera.position.set(center.x+1000, center.y+1000, center.z+600);
// this.camera.lookAt(scene.position); // 让相机看向场景中心
        },
        (xhr) => {
          console.log(`模型加载中: ${(xhr.loaded / xhr.total * 100)}%`)
        },
        (error) => {
          console.error('模型加载失败:', error)
          this.$message.error('模型加载失败,请检查模型文件是否存在')
        }
      )
    },

    animate() {
      this.animationId = requestAnimationFrame(this.animate)
      
      // 更新水面动画
      if (this.water) {
        this.water.material.uniforms['time'].value += 1.0 / 60.0
      }
      
      // 更新模型动画
      if (this.mixer) {
        this.mixer.update(0.016) // 假设60fps
      }
      
      this.controls.update()
      this.renderer.render(this.scene, this.camera)

      // 根据键盘输入移动相机
      if (this.moveForward) {
        this.camera.position.z -= this.moveSpeed
      }
      if (this.moveBackward) {
        this.camera.position.z += this.moveSpeed
      }
      if (this.moveLeft) {
        this.camera.position.x -= this.moveSpeed
      }
      if (this.moveRight) {
        this.camera.position.x += this.moveSpeed
      }
    },

    onMouseClick(event) {
      const mouse = new THREE.Vector2()
      mouse.x = (event.clientX / this.viewNode.clientWidth) * 2 - 1
      mouse.y = -(event.clientY / this.viewNode.clientHeight) * 2 + 1

      const raycaster = new THREE.Raycaster()
      raycaster.setFromCamera(mouse, this.camera)
      console.log(';点击了模型上的某一个点点击了模型上的某一个点点击了模型上的某一个点');
   
      const intersects = raycaster.intersectObjects(this.scene.children, true)
      if (intersects.length > 0) {
        console.log(';点击了模型上的某一个点点击了模型上的某一个点点击了模型上的某一个点');
          const baifenDom = document.querySelector('.baifen')
          
          
        const intersect = intersects[0]
        console.log(intersect,'intersect-*-*-*--*');
        // if (intersect.object.type === this.model) {
        if (intersect.object.type === "Mesh" && intersect.object.parent.type === "Group") {

          console.log(this.icondom,'icon-*-*-*--*');
          console.log(this.divdom,'divdivdiv-*-*-*--*');
          
          //  // 清除上一次点击的所有操作
           this.icondom&&this.scene.remove(this.icondom);
           this.divdom&&baifenDom.removeChild(this.divdom)

           // 创建icon图标
           const iconGeometry = new THREE.SphereGeometry(0.5, 60, 60);
          const iconMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 });
           this.icondom = new THREE.Mesh(iconGeometry, iconMaterial);
           this.icondom.position.set(intersect.point.x, intersect.point.y, intersect.point.z);
          this.scene.add(this.icondom);
          console.log( intersect,'baifenDombaifenDom');
          this.divdom = document.createElement('div')
          this.divdom.style.position = 'absolute'
          this.divdom.style.width = '200px'
          this.divdom.style.height = '200px'
          this.divdom.style.backgroundColor = 'rgba(0, 0, 0, 0.5)'
          this.divdom.style.color = 'white'
          this.divdom.style.padding = '10px'
          this.divdom.style.borderRadius = '5px'
          this.divdom.style.zIndex = '1000'
          this.divdom.style.top = `${event.clientY}px`
          this.divdom.style.left = `${event.clientX}px`
          this.divdom.innerHTML = `点击了模型上的某一个点,位置为: (${intersect.point.x}, ${intersect.point.y}, ${intersect.point.z})`
          baifenDom.appendChild(this.divdom)
          // 调整相机位置以拉近模型
          // this.camera.position.set(intersect.point.x, intersect.point.y, intersect.point.z + 10); // 将相机位置设置为点击点的位置,并在z轴上偏移10单位以拉近模型
          // this.camera.lookAt(intersect.point); // 让相机看向点击点
        }
      }
    },

    onKeyDown(event) {
      switch (event.key) {
        case 'w':
          this.moveForward = true
          break
        case 's':
          this.moveBackward = true
          break
        case 'a':
          this.moveLeft = true
          break
        case 'd':
          this.moveRight = true
          break
      }
    },

    onKeyUp(event) {
      switch (event.key) {
        case 'w':
          this.moveForward = false
          break
        case 's':
          this.moveBackward = false
          break
        case 'a':
          this.moveLeft = false
          break
        case 'd':
          this.moveRight = false
          break
      }
    },

    onWindowResize() {
      if (this.viewNode) {
        this.camera.aspect = this.viewNode.clientWidth / this.viewNode.clientHeight
        this.camera.updateProjectionMatrix()
        this.renderer.setSize(this.viewNode.clientWidth, this.viewNode.clientHeight)
      }
    }
  },

  beforeDestroy() {
    window.removeEventListener('resize', this.onWindowResize)
    document.removeEventListener('keydown', this.onKeyDown)
    document.removeEventListener('keyup', this.onKeyUp)
    if (this.animationId) {
      cancelAnimationFrame(this.animationId)
    }
    if (this.scene) {
      this.scene.clear()
    }
    if (this.renderer) {
      this.renderer.dispose()
      this.renderer.forceContextLoss()
      this.renderer.content = null
    }
    if (this.mixer) {
      this.mixer.stopAllAction()
    }
  }
}
</script>

<style lang="scss" scoped>
.contente {
  width: 100%;
  height: 100%;
  position: relative;
  .baifen {
    background: #fff;
    height: 100%;
    position: relative;
    .app-wrap {
      width: 100%;
      height: 100%;
      position: relative;
      overflow: hidden;
    }
  }
}
</style>

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

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

相关文章

安装Office自定义项,安装期间出错

个人博客地址&#xff1a;安装Office自定义项&#xff0c;安装期间出错 | 一张假钞的真实世界 卸载PowerDesigner后&#xff0c;打开“WPS文字”时出现下图错误&#xff1a; 解决方法&#xff1a; 按“WinR”快捷键&#xff0c;打开【运行】框&#xff0c;在对话框中输入“re…

代码审查中的自动化与AI应用

代码审查&#xff08;Code Review&#xff09;作为软件开发中的一项重要实践&#xff0c;通常被认为是提高代码质量、减少bug和提升团队协作的重要手段。随着开发规模的不断扩大&#xff0c;手动代码审查在效率、准确性、以及可扩展性上都存在明显的局限性。尤其是在敏捷开发和…

蓝桥杯模拟算法:蛇形方阵

P5731 【深基5.习6】蛇形方阵 - 洛谷 | 计算机科学教育新生态 我们只要定义两个方向向量数组&#xff0c;这种问题就可以迎刃而解了 比如我们是4的话&#xff0c;我们从左向右开始存&#xff0c;1&#xff0c;2&#xff0c;3&#xff0c;4 到5的时候y就大于4了就是越界了&…

PostGIS笔记:PostgreSQL 数据库与用户 基础操作

数据库基础操作包括数据模型的实现、添加数据、查询数据、视图应用、创建日志规则等。我这里是在Ubuntu系统学习的数据库管理。Windows平台与Linux平台在命令上几乎无差异&#xff0c;只是说在 Windows 上虽然也能运行良好&#xff0c;但在性能、稳定性、功能扩展等方面&#x…

Nginx中部署多个前端项目

1&#xff0c;准备前端项目 tlias系统的前端资源 外卖项目的前端资源 2&#xff0c;nginx里面的html文件夹中新建&#xff0c;tlias和sky两个文件夹。 切记这是在nginx/html下创建的 mkdir sky mkdir tlias 把tlias和sky的资源都放到对应的文件夹中 3&#xff0c;编辑配置ngi…

人力资源管理HR系统的需求设计和实现

该作者的原创文章目录&#xff1a; 生产制造执行MES系统的需求设计和实现 企业后勤管理系统的需求设计和实现 行政办公管理系统的需求设计和实现 人力资源管理HR系统的需求设计和实现 企业财务管理系统的需求设计和实现 董事会办公管理系统的需求设计和实现 公司组织架构…

2025年美赛B题-结合Logistic阻滞增长模型和SIR传染病模型研究旅游可持续性-成品论文

模型设计思路与创新点&#xff1a; 建模的时候应该先确定我们需要建立什么类的模型&#xff1f;优化类还是统计类&#xff1f;这个题需要大量的数据分析&#xff0c;因此我们可以建立一个统计学模型。 统计学建模思路&#xff1a;观察规律&#xff0c;建立模型&#xff0c;参…

【太阳——几何计算】

题目 代码 #include <bits/stdc.h> using namespace std; using PII pair<int, int>; using ll long long; const int N 1e5 10; set<PII> s; bool st[N]; struct node {int x, y, id; } arr[2 * N]; int main() {int n, X, Y;cin >> n >> …

嵌入式MCU面试笔记2

目录 串口通信 概论 原理 配置 HAL库代码 1. 初始化函数 2. 数据发送和接收函数 3. 中断和DMA函数 4. 中断服务函数 串口通信 概论 我们知道&#xff0c;通信桥接了两个设备之间的交流。一个经典的例子就是使用串口通信交换上位机和单片机之间的数据。 比较常见的串…

云原生时代,如何构建高效分布式监控系统

文章目录 一.监控现状二.Thanos原理分析SidecarQuerierStoreCompactor 三.Sidecar or ReceiverThanos Receiver工作原理 四.分布式运维架构 一.监控现状 Prometheus是CNCF基金会管理的一个开源监控项目&#xff0c;由于其良好的架构设计和完善的生态&#xff0c;迅速成为了监控…

火语言RPA--配置文件读取

&#x1f6a9;【组件功能】&#xff1a;读取配置文件信息以字典类型输出。 配置预览 配置说明 要读取的文件 支持T或# 读取配置文件的路径及名称&#xff0c;绝对路径。 配置文件类型 INI或XML两种选项供选择。 编码 写入配置文件的编码&#xff0c;以列表方式供选择&am…

电子应用设计方案104:智能家庭AI弹簧床系统设计

智能家庭 AI 弹簧床系统设计 一、引言 智能家庭 AI 弹簧床系统旨在为用户提供更加舒适、个性化的睡眠体验&#xff0c;通过结合人工智能技术和先进的床垫设计&#xff0c;实时监测和调整睡眠环境&#xff0c;以满足不同用户的需求。 二、系统概述 1. 系统目标 - 自动适应用户…

基于paddleocr的表单关键信息抽取

全流程如下&#xff1a; 数据集 XFUND数据集是微软提出的一个用于KIE任务的多语言数据集&#xff0c;共包含七个数据集&#xff0c;每个数据集包含149张训练集和50张验证集分别为&#xff1a; ZH(中文)、JA(日语)、ES(西班牙)、FR(法语)、IT(意大利)、DE(德语)、PT(葡萄牙)&a…

爬虫基础之爬取某基金网站+数据分析

声明: 本案例仅供学习参考使用&#xff0c;任何不法的活动均与本作者无关 网站:天天基金网(1234567.com.cn) --首批独立基金销售机构-- 东方财富网旗下基金平台! 本案例所需要的模块: 1.requests 2.re(内置) 3.pandas 4.pyecharts 其他均需要 pip install 模块名 爬取步骤: …

深入理解动态规划(dp)--(提前要对dfs有了解)

前言&#xff1a;对于动态规划&#xff1a;该算法思维是在dfs基础上演化发展来的&#xff0c;所以我不想讲的是看到一个题怎样直接用动态规划来解决&#xff0c;而是说先用dfs搜索&#xff0c;一步步优化&#xff0c;这个过程叫做动态规划。&#xff08;该文章教你怎样一步步的…

(1)STM32 USB设备开发-基础知识

开篇感谢&#xff1a; 【经验分享】STM32 USB相关知识扫盲 - STM32团队 ST意法半导体中文论坛 单片机学习记录_桃成蹊2.0的博客-CSDN博客 USB_不吃鱼的猫丿的博客-CSDN博客 1、USB鼠标_哔哩哔哩_bilibili usb_冰糖葫的博客-CSDN博客 USB_lqonlylove的博客-CSDN博客 USB …

基于STM32单片机设计的宠物喂食监控系统

1. 项目开发背景 随着宠物数量的增加&#xff0c;尤其是人们对宠物的养护需求日益增多&#xff0c;传统的人工喂养和管理方式难以满足现代养宠生活的需求。人们越来越希望通过智能化手段提高宠物养护的质量和效率&#xff0c;特别是对于宠物喂食、饮水、温湿度控制等方面的智能…

MATLAB绘图:随机彩色圆点图

这段代码在MATLAB中生成并绘制了500个随机位置和颜色的散点图。通过随机生成的x和y坐标以及颜色&#xff0c;用户可以直观地观察到随机点的分布。这种可视化方式在数据分析、统计学和随机过程的演示中具有广泛的应用。 文章目录 运行结果代码代码讲解 运行结果 代码 clc; clea…

重定向与缓冲区

4种重定向 我们有如下的代码&#xff1a; #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h>#define FILE_NAME "log.txt"int main() {close(1)…

Golang Gin系列-8:单元测试与调试技术

在本章中&#xff0c;我们将探讨如何为Gin应用程序编写单元测试&#xff0c;使用有效的调试技术&#xff0c;以及优化性能。这包括设置测试环境、为处理程序和中间件编写测试、使用日志记录、使用调试工具以及分析应用程序以提高性能。 为Gin应用程序编写单元测试 设置测试环境…