Unity之Serialized序列化:从原理到实践

内容将会持续更新,有错误的地方欢迎指正,谢谢!
 

Unity之Serialized序列化:从原理到实践
     
TechX 坚持将创新的科技带给世界!

拥有更好的学习体验 —— 不断努力,不断进步,不断探索
TechX —— 心探索、心进取!

助力快速掌握 Serialized序列化 学习

为初学者节省宝贵的学习时间,避免困惑!


文章目录

  • 一、 引言
  • 二、什么是序列化?
  • 三、Unity游戏对象的序列化
  • 四、脚本变量的序列化
    • 1、 [SerializeField]:私有字段的序列化
    • 2、 [System.Serializable]:自定义类的序列化
  • 五、ScriptableObject序列化
  • 六、常见序列化格式
    • 1、 JSON序列化(Newtonsoft.Json)
    • 2、CSV序列化(CsvHelper库)
    • 3、Excel序列化 (EPPlus库)
    • 4、XML序列化


一、 引言


在Unity开发中,序列化(Serialization) 是贯穿整个开发流程的核心技术。无论是游戏对象的持久化存储、Inspector面板的变量显示,还是跨平台数据交换,都离不开序列化的支持。对于编辑器扩展开发而言,深入理解序列化机制更是实现自定义工具和高效数据管理的关键。

为什么需要关注序列化?

  • 数据持久化:保存玩家存档、配置数据、场景状态。

  • Inspector交互:在编辑器中直观调整脚本参数。

  • 跨平台兼容:通过标准格式(如JSON)实现不同平台间的数据交换。

  • 性能优化:合理的序列化策略可减少内存占用和加载时间。



二、什么是序列化?


序列化是将对象转换为可存储或传输的格式(如二进制、JSON等)的过程,使得数据能在不同系统或平台间共享。反向的反序列化则是将这些格式数据还原为原始对象的过程。

在Unity中,序列化的典型场景包括:

  • 场景文件:将游戏对象层次结构和组件数据保存为.unity文件
  • Prefab:保存预设对象的模板
  • Inspector面板:显示并修改脚本的序列化字段
  • 数据持久化:存档、配置文件或网络通信


三、Unity游戏对象的序列化


游戏对象与组件的自动序列化
Unity的GameObject和Component(如Transform、Renderer等)默认支持序列化。其数据保存在场景或Prefab文件中,包括层级关系、组件属性等。

场景文件示例
打开一个.unity场景文件,可以看到类似以下结构的序列化数据:

--- !u!1 &12345
GameObject:
  m_Name: Player
  m_Component:
  - component: {fileID: 123456}
--- !u!4 &123456
Transform:
  m_LocalPosition: {x: 0, y: 0, z: 0}
  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}

序列化的限制
并非所有类型都能被Unity自动序列化。以下情况会导致字段不被序列化:

  • 静态字段(static)
  • 非继承自UnityEngine.Object的类引用
  • 标记为[NonSerialized]的字段
  • 属性(Properties):仅支持字段序列化。
  • 未标记的私有字段:需使用[SerializeField]。
  • 某些引用类型:如Dictionary(需自定义序列化)。


四、脚本变量的序列化


通过特性标记,开发者可以控制脚本中哪些字段需要序列化并在Inspector中显示。

1、 [SerializeField]:私有字段的序列化


Unity默认只会序列化public字段。若需序列化私有或受保护字段,可使用[SerializeField]。

public class Player : MonoBehaviour {
    [SerializeField]
    private int health = 100;  // Inspector中可见
}

2、 [System.Serializable]:自定义类的序列化


自定义类或结构体需添加[System.Serializable]属性,才能在Inspector中显示或被Unity序列化。

[System.Serializable]
public class Weapon {
    public string name;
    public int damage;
}

public class Inventory : MonoBehaviour {
    public List<Weapon> weapons;  // 列表中每个Weapon属性都可在Inspector编辑
}

最佳实践
避免过度序列化:仅序列化必要数据以减少内存开销
版本兼容性:修改序列化类时注意向后兼容性(如添加新字段不影响旧数据)



五、ScriptableObject序列化


ScriptableObject是Unity提供的一个功能强大的工具,通常用于保存游戏数据、配置数据等。ScriptableObject在Unity中是非常重要的,它不仅能够序列化数据,还能够让你避免创建多个实例化的对象。

ScriptableObject核心特性:

  • 独立数据容器:不与场景绑定,保存于.asset文件
  • 运行时修改持久化:编辑器模式下修改可保存到项目
  • 高效引用系统:作为资产被多个对象引用
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif

[System.Serializable]
public class SkillEffect {
    public enum EffectType { Damage, Heal, Buff }
    public EffectType type;
    public float value;
    public float duration;
}

[System.Serializable]
public class SkillLevel {
    [Range(1, 100)]
    public int requiredLevel = 1;
    public float manaCost;
    public SkillEffect[] effects;
}

// 主ScriptableObject类
[CreateAssetMenu(fileName = "New Skill", menuName = "RPG/Skill Config")]
public class SkillConfig : ScriptableObject {
    public string skillName;
    public Sprite icon;
    public float baseCooldown;
    
    [TextArea(3, 5)]
    public string description;
    
    [Space]
    public SkillLevel[] levels = new SkillLevel[5]; // 最多5级技能
}

public class SkillSystemTest : MonoBehaviour {
    void Start() {
        // 创建临时技能配置
        SkillConfig tempSkill = CreateSkill("雷电术", 
            new SkillLevel {
                requiredLevel = 5,
                manaCost = 30,
                effects = new[] {
                    new SkillEffect {
                        type = SkillEffect.EffectType.Damage,
                        value = 50,
                        duration = 2
                    }
                }
            }
        );

        // 在编辑器模式下保存资产
        #if UNITY_EDITOR
        AssetDatabase.CreateAsset(tempSkill, "Assets/Skills/Lightning.asset");
        AssetDatabase.SaveAssets();
        #endif
    }

    SkillConfig CreateSkill(string name, params SkillLevel[] levels) {
        SkillConfig config = ScriptableObject.CreateInstance<SkillConfig>();
        config.skillName = name;
        config.levels = levels;
        return config;
    }
}




六、常见序列化格式


1、 JSON序列化(Newtonsoft.Json)


为什么选择Newtonsoft?

  • 原生JsonUtility不足:不支持字典、私有字段嵌套类
  • Newtonsoft特性:高效灵活,支持复杂类型转换
  • 安装方法:通过Unity Package Manager添加com.unity.nuget.newtonsoft-json
using Newtonsoft.Json;
using System.Collections.Generic;
using UnityEngine;

// 复杂数据结构示例(包含嵌套类和字典)
[System.Serializable]
public class Player {
    public string name;
    [SerializeField]
    private int _health; //私有字段支持序列化
    public Dictionary<string, int> skills = new Dictionary<string, int>();
    
    // 自定义Vector3序列化(需转换) 
    [JsonIgnore]
    public Vector3 position;
    
    [JsonProperty("position")]
    private Vector3Serializable PositionSerializable {
        get => new Vector3Serializable(position);
        set => position = value.ToVector3();
    }
}

// Vector3序列化辅助类
[System.Serializable]
public struct Vector3Serializable {
    public float x;
    public float y;
    public float z;

    public Vector3Serializable(Vector3 v) {
        x = v.x;
        y = v.y;
        z = v.z;
    }

    public Vector3 ToVector3() => new Vector3(x, y, z);
}

public class JsonExample : MonoBehaviour {
    void Start() {
        Player player = new Player {
            name = "Arthur",
            _health = 200,
            position = new Vector3(10, 2, 5)
        };
        player.skills.Add("Attack", 85);
        player.skills.Add("Defense", 60);

        // 序列化
        string json = JsonConvert.SerializeObject(player, Formatting.Indented);
        Debug.Log("JSON Output:\n" + json);
        
        // 反序列化
        Player loadedPlayer = JsonConvert.DeserializeObject<Player>(json);
        Debug.Log($"Position: {loadedPlayer.position}");
    }
}

控制台输出:

{
  "name": "Arthur",
  "skills": {
    "Attack": 85,
    "Defense": 60
  },
  "position": {
    "x": 10.0,
    "y": 2.0,
    "z": 5.0
  }
}

关键注释:

  • [JsonIgnore]:标记不参与序列化的字段
  • [JsonProperty]:自定义字段映射名称
  • Vector3Serializable:需要手动处理Unity引擎特有类型

2、CSV序列化(CsvHelper库)


CsvHelper核心功能

  • 自动映射类属性到CSV列
  • 处理标题行复杂数据类型
  • 安装方法:通过NuGet安装CsvHelper
using CsvHelper;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using UnityEngine;

// CSV数据模型类
public class EnemyData {
    public int Id { get; set; }
    public string Name { get; set; }
    public float Speed { get; set; }
    public string PrefabPath { get; set; }
}

public class CsvExample : MonoBehaviour {
    private string csvPath = "Enemies.csv";

    void Start() {
        WriteCSV();
        ReadCSV();
    }
	
	//序列化 将数据写入CSV文件中
    void WriteCSV() {
        List<EnemyData> enemies = new List<EnemyData> {
            new EnemyData { Id = 1, Name = "Goblin", Speed = 3.5f, PrefabPath = "Prefabs/Enemies/Goblin" },
            new EnemyData { Id = 2, Name = "Dragon", Speed = 8.0f, PrefabPath = "Prefabs/Enemies/Dragon" }
        };

        using (var writer = new StreamWriter(csvPath))
        using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture)) {
            csv.WriteRecords(enemies);
        }
        Debug.Log("CSV写入完成!");
    }
	
	//反序列化 将读取到的数据转换成类
    void ReadCSV() {
        using (var reader = new StreamReader(csvPath))
        using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture)) {
            var records = csv.GetRecords<EnemyData>();
            foreach (var enemy in records) {
                Debug.Log($"ID: {enemy.Id}, Name: {enemy.Name}, Speed: {enemy.Speed}");
            }
        }
    }
}

生成CSV内容:

Id,Name,Speed,PrefabPath
1,Goblin,3.5,Prefabs/Enemies/Goblin
2,Dragon,8,Prefabs/Enemies/Dragon

3、Excel序列化 (EPPlus库)


EPPlus库核心能力

  • 创建、修改.xlsx文件
  • 支持公式、样式、图表
  • 安装:从NuGet安装EPPlus(注意Unity需使用兼容版本)
using OfficeOpenXml;
using System;
using System.IO;
using UnityEngine;

public class ExcelExample : MonoBehaviour {
    private string excelPath = "GameData.xlsx";

    void Start() {
        WriteExcel();
        ReadExcel();
    }

    private void WriteExcel() {
        ExcelPackage.LicenseContext = LicenseContext.NonCommercial;

        // 序列化 写入数据 创建新Excel文件
        using (ExcelPackage package = new ExcelPackage()) {
            // 添加工作表
            ExcelWorksheet sheet = package.Workbook.Worksheets.Add("玩家数据");

            // 填充标题行
            sheet.Cells[1, 1].Value = "ID";
            sheet.Cells[1, 2].Value = "Name";
            sheet.Cells[1, 3].Value = "Level";
            sheet.Cells[1, 4].Value = "LastLogin";

            // 填充数据
            sheet.Cells[2, 1].Value = 101;
            sheet.Cells[2, 2].Value = "Player1";
            sheet.Cells[2, 3].Value = 15;
            sheet.Cells[2, 4].Value = DateTime.Now;

            // 保存文件
            FileStream fileStream = new FileStream(excelPath, FileMode.Create);
            package.SaveAs(fileStream);
            fileStream.Close();
        }

        Debug.Log("Excel写入完成!");
    }
	
	//反序列化 读取数据
    private void ReadExcel() {
        using (ExcelPackage package = new ExcelPackage(new FileInfo(excelPath))) {
            ExcelWorksheet sheet = package.Workbook.Worksheets["玩家数据"];
            int rowCount = sheet.Dimension.Rows;

            for (int row = 2; row <= rowCount; row++) { //跳过标题行
                int id = int.Parse(sheet.Cells[row, 1].Text);
                string name = sheet.Cells[row, 2].Text;
                int level = int.Parse(sheet.Cells[row,3].Text);
                DateTime lastLogin = DateTime.Parse(sheet.Cells[row,4].Text);

                Debug.Log($"读取到玩家:{name} (等级{level}), 最后登录时间:{lastLogin}");
            }
        }
    }
}

4、XML序列化


核心优势:

  • 严格的树状数据格式,支持复杂嵌套结构
  • 内置Schema验证(XSD)保证数据完整性
  • 支持注释和CDATA块处理特殊字符
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
using UnityEngine;

// 装备品类(嵌套定义)
[System.Serializable]
public class EquipmentItem {
    public enum ItemRarity { Common, Rare, Epic }

    [XmlAttribute("id")]  // 设置为XML属性
    public string itemID;
    
    [XmlElement("displayName")] // 设置为XML元素
    public string itemName;
    
    [XmlIgnore]  // 不参与XML序列化
    public ItemRarity rarity;
    
    [XmlElement("durability")]
    public int currentDurability = 100;

    // 自定义字段序列化转换器
    [XmlElement("rarity")]
    public string RarityString {
        get => rarity.ToString();
        set => rarity = (ItemRarity)System.Enum.Parse(typeof(ItemRarity), value);
    }
}

// 角色装备数据容器
[System.Serializable]
public class CharacterEquipment {
    [XmlArray("WeaponSlots")] // 定义数组包裹元素
    [XmlArrayItem("Weapon")]
    public List<EquipmentItem> weapons = new List<EquipmentItem>();

    [XmlArray("ArmorSlots")]
    [XmlArrayItem("Armor")]
    public EquipmentItem[] armors = new EquipmentItem[4]; // 固定长度数组
}

public class XMLSerializeExample : MonoBehaviour {
    private string xmlPath = "CharacterData.xml";

    void Start() {
        // 创建测试数据
        CharacterEquipment equipment = new CharacterEquipment {
            weapons = {
                new EquipmentItem { itemID = "w_001", itemName = "Steel Sword", rarity = EquipmentItem.ItemRarity.Epic },
                new EquipmentItem { itemID = "w_002", itemName = "Wooden Bow", rarity = EquipmentItem.ItemRarity.Common }
            },
            armors = {
                new EquipmentItem { itemID = "a_001", itemName = "Iron Helmet" },
                null, // 演示空元素处理方法
                new EquipmentItem { itemID = "a_003", itemName = "Chainmail" }
            }
        };

        // 序列化到文件
        SerializeToXML(equipment, xmlPath);
        
        // 从文件反序列化
        CharacterEquipment loadedData = DeserializeFromXML<CharacterEquipment>(xmlPath);
        Debug.Log($"加载的武器数量: {loadedData.weapons.Count}");
    }

    void SerializeToXML<T>(T data, string path) {
        XmlSerializer serializer = new XmlSerializer(typeof(T));
        using (StreamWriter stream = new StreamWriter(path)) {
            serializer.Serialize(stream, data);
        }
        Debug.Log($"XML序列化完成,文件尺寸:{new FileInfo(path).Length} bytes");
    }

    T DeserializeFromXML<T>(string path) {
        XmlSerializer serializer = new XmlSerializer(typeof(T));
        using (StreamReader stream = new StreamReader(path)) {
            return (T)serializer.Deserialize(stream);
        }
    }
}

XML输出结构:

<CharacterEquipment>
  <WeaponSlots>
    <Weapon id="w_001">
      <displayName>Steel Sword</displayName>
      <rarity>Epic</rarity>
      <durability>100</durability>
    </Weapon>
    <Weapon id="w_002">
      <displayName>Wooden Bow</displayName>
      <rarity>Common</rarity>
      <durability>100</durability>
    </Weapon>
  </WeaponSlots>
  <ArmorSlots>
    <Armor id="a_001">
      <displayName>Iron Helmet</displayName>
      <rarity>Common</rarity>
      <durability>100</durability>
    </Armor>
    <Armor />
    <Armor id="a_003">
      <displayName>Chainmail</displayName>
      <rarity>Common</rarity>
      <durability>100</durability>
    </Armor>
  </ArmorSlots>
</CharacterEquipment>

关键注解:

  • [XmlAttribute]:将字段序列化为XML属性(紧凑格式)
  • [XmlElement]:自定义元素名称(默认使用字段名)
  • [XmlArray]+[XmlArrayItem]:控制集合的嵌套结构
  • 自定义属性转换器:处理枚举类型与字符串的转换




TechX —— 心探索、心进取!

每一次跌倒都是一次成长

每一次努力都是一次进步


END
感谢您阅读本篇博客!希望这篇内容对您有所帮助。如果您有任何问题或意见,或者想要了解更多关于本主题的信息,欢迎在评论区留言与我交流。我会非常乐意与大家讨论和分享更多有趣的内容。
如果您喜欢本博客,请点赞和分享给更多的朋友,让更多人受益。同时,您也可以关注我的博客,以便及时获取最新的更新和文章。
在未来的写作中,我将继续努力,分享更多有趣、实用的内容。再次感谢大家的支持和鼓励,期待与您在下一篇博客再见!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

某手sig3-ios算法 Chomper黑盒调用

Chomper-iOS界的Unidbg 最近在学习中发现一个Chomper框架&#xff0c;Chomper 是一个模拟执行iOS可执行文件的框架&#xff0c;类似于安卓端大名鼎鼎的Unidbg。 这篇文章使用Chomper模拟执行某手的sig3算法&#xff0c;初步熟悉该框架。这里只熟悉模拟执行步骤以及一些常见的…

PyTorch 深度学习框架中 torch.cuda.empty_cache() 的妙用与注意事项

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 在使用 PyTorch 进行深度学习模型训练与调优过程中&#xff0c;torch.cuda.empty_cache() 方法作为一种高效工具被广泛采用&#xff1b;但其正确应用要求充分理解该方法的功能及最佳实践。下文将对该方…

巧用GitHub的CICD功能免费打包部署前端项目

近年来&#xff0c;随着前端技术的发展&#xff0c;前端项目的构建和打包过程变得越来越复杂&#xff0c;占用的资源也越来越多。我有一台云服务器&#xff0c;原本打算使用Docker进行部署&#xff0c;以简化操作流程。然而&#xff0c;只要执行sudo docker-compose -f deploy/…

配置Api自动生成

我的飞书:https://rvg7rs2jk1g.feishu.cn/docx/TVlJdMgYLoDJrsxAwMgcCE14nxt 使用Springfox Swagger生成API&#xff0c;并导入Postman&#xff0c;完成API单元测试 Swagger: 是一套API定义的规范&#xff0c;按照这套规范的要求去定义接口及接口相关信息&#xff0c;再通过可…

【JMeter使用-2】JMeter中Java Request采样器的使用指南

Apache JMeter 是一款功能强大的性能测试工具&#xff0c;支持多种协议和测试场景。除了内置的采样器&#xff08;如HTTP请求、FTP请求等&#xff09;&#xff0c;JMeter还允许通过 Java Request采样器 调用自定义的Java代码&#xff0c;从而实现更复杂的测试逻辑。本文将详细介…

将Google文档导入WordPress:简单实用的几种方法

Google文档是内容创作者非常实用的写作工具。它支持在线编辑、多人协作&#xff0c;并能够自动保存内容。但当我们想把Google文档中的内容导入WordPress网站时&#xff0c;可能会遇到一些小麻烦&#xff0c;比如格式错乱、图片丢失等问题。本文将为大家介绍几种简单实用的方法&…

Android开发-深入解析Android中的AIDL及其应用场景

深入解析 Android 中的 AIDL 及其应用场景 1. 前言2. AIDL 的核心概念3. AIDL 的实现步骤3.1. 定义 AIDL 接口文件3.2. 实现服务端&#xff08;Service&#xff09;3.3. 客户端绑定与调用 4. AIDL 的典型应用场景4.1. 多进程应用4.2. 与系统服务交互4.3. 高性能 IPC4.4. 跨应用…

PWM(脉宽调制)技术详解:从基础到应用实践示例

PWM&#xff08;脉宽调制&#xff09;技术详解&#xff1a;从基础到应用实践示例 目录 PWM&#xff08;脉宽调制&#xff09;技术详解&#xff1a;从基础到应用实践示例学前思考&#xff1a;一、PWM概述二、PWM的基本原理三、PWM的应用场景四、PWM的硬件配置与使用五、PWM的编程…

谷粒商城—分布式高级②.md

认证服务 1. 环境搭建 创建gulimall-auth-server模块,导依赖,引入login.html和reg.html,并把静态资源放到nginx的static目录下 2. 注册功能 (1) 验证码倒计时 //点击发送验证码按钮触发下面函数 $("#sendCode").click(function () {//如果有disabled,说明最近…

Nginx(详解以及如何使用)

目录 1. 什么是Nginx&#xff1f; 2. 为什么使用nginx? 3. 安装nginx 3.1?安装nginx的依赖插件 3.2 下载nginx ?3.3?创建一个目录作为nginx的安装路径 ?3.4?解压 ?3.5?进入解压后的目录 3.6?指定nginx的安装路径 ?3.7?编译和安装nginx 3.8 启动nginx ?…

STM32 HAL库标准库+ESP8266+机智云

前言 最近在项目中需要云平台对接&#xff0c;前面使用的是阿里云物理平台&#xff0c;具体开发可以看看我的这个文章&#xff1a;手把手教会使用阿里云平台&#xff0c;不过好像没有可以在手机很方便打开连接的&#xff0c;所以我在网上找到一些资料&#xff0c;发现机智云是…

【前端框架】Vue3 面试题深度解析

本文详细讲解了VUE3相关的面试题&#xff0c;从基础到进阶到高级&#xff0c;分别都有涉及&#xff0c;希望对你有所帮助&#xff01; 基础题目 1. 简述 Vue3 与 Vue2 相比有哪些主要变化&#xff1f; 答案&#xff1a; 响应式系统&#xff1a;Vue2 使用 Object.definePrope…

DarkLabel 2.4使用指南:高效标注视频数据目标检测标签

工具概述 DarkLabel 2.4 是一款强大的多功能标注工具&#xff0c;专为计算机视觉开发者设计&#xff0c;旨在提升标注工作的效率和精确度。其智能标注引擎支持两项核心功能&#xff1a;线性插值标注与多目标跟踪&#xff0c;极大地优化了视频标注过程。 &#xff08;1&#x…

js解析后端传来的如图示的list集合,怎么获取每个map的key和value

如图示&#xff0c;后端传到前端的questTypeList是一个HashMap的list集合 使用c标签将传来的集合放到下拉单选框中&#xff0c; <% taglib prefix"c" uri"http://java.sun.com/jsp/jstl/core" %><html> <body><form action"yo…

SpringSecurity请求流转的本质

1. SpringSecurity核心源码分析 分析SpringSecurity的核心原理,那么我们从哪开始分析?以及我们要分析哪些内容? 系统启动的时候SpringSecurity做了哪些事情?第一次请求执行的流程是什么?SpringSecurity中的认证流程是怎么样的?1.1 系统启动 当我们的Web服务启动的时候,…

[论文阅读] SeeSR: Towards Semantics-Aware Real-World Image Super-Resolution

文章目录 一、前言二、主要贡献三、Introduction四、Methodology4.1 Motivation &#xff1a;4.2Framework Overview.** 一、前言 通信作者是香港理工大学 & OPPO研究所的张磊教授&#xff0c;也是图像超分ISR的一个大牛了。 论文如下 SeeSR: Towards Semantics-Aware Rea…

在VS中通过vcpkg包管理器来安装使用qt5

常用指令 .\vcpkg install 库名 .\vcpkg install 库名版本号.\vcpkg install 库名 --trip x86-windows.\vcpkg list.\vcpkg search 库名 .\vcpkg x-all-installed --7zip PS G:\vcpkg> .\vcpkg help usage: vcpkg <command> [--switches] [--optionsvalues] [argume…

ESXI 8.0 linux vSphere Client service has stopped working.手动启动服务

1、首先在你的esxi中进入到你的VC系统中&#xff0c;我这个是linux部署 #查看每个服务及状态 service-control --status2、你会发现有停止的服务和正在启动的&#xff0c;在不知道具体哪些服务具体负责的功能&#xff0c;那你就一个一个起&#xff0c;边起边试----重要服务我后…

基于SpringBoot+Vue的装修装潢管理系统的设计与实现

获取源码&#xff1a;SpringBootVue的装修装潢公司管理系统: 用户&#xff1a;登录、注册、忘记密码、首页、产品展示、装修案例、装修套餐、装修预约、新闻动态、合作伙伴、在线留言、我的装修、个人中心、我的留言、我的预约、关于我们等功能管理员&#xff1a;登录、首页、户…

DeepSeek部署到本地(解决ollama模型下载失败问题)

一、下载ollama软件安装 1、下载ollama软件 Ollama 下载完成后可以直接进行安装&#xff08;外网&#xff0c;速度可能会有点慢&#xff09; 2、修改安装目录 进去下载的目录&#xff0c;使用cmd打开终端输入OllamaSetup.exe /DIRE:\MySoftware\Ollama 输入完成后会自动打开…