C#调用Lua

目录

xLua导入

 打包工具导入

 单例基类导入与AB包管理器导入

Lua解析器

文件加载与重定向

Lua解析器管理器

全局变量获取

全局函数获取

对于无参数无返回值

 对于有参数有返回值

 对于多返回值

 对于变长参数

完整代码 

List与Dictionary映射Table

类映射Table

接口映射Table

LuaTable映射Table

xLua导入

在github上搜索xLua,选择第一个下载,进入master的Assets里面导入

 导入后可以在工具栏中看到XLua,这样导入就完成了。

 打包工具导入

这里上篇中有讲,可以看一下 https://blog.csdn.net/sara_shengxin/article/details/144596428?spm=1001.2014.3001.5502

 单例基类导入与AB包管理器导入

 获取链接http://通过网盘分享的文件:Base.rar 链接: https://pan.baidu.com/s/1-WpLVyrRFowVAs1AudrbdQ?pwd=raux 提取码: raux

AB包管理器导入,在上一篇中最终的代码复制过来就可以ABMgr

Lua解析器

 构建一个lua解析器,使得能够在unity中执行lua语言,提供的方法主要有:DoString(),Tick(),Dispose().此时调用lua脚本我们要将他放在Resources文件夹里面,且要修改lua脚本的后缀为.txt

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//引入命名空间
using XLua;
public class Lesson1LuaEnv : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        //lua解析器 能够在Unity中执行lua语言
        LuaEnv env= new LuaEnv();

        //执行Lua语言
        env.DoString("print('nihao')");

        //执行一个lua脚本 ,利用lua中的多脚本执行require
        env.DoString("require('Main')");//默认脚本加载路径在resource中并且后缀为.txt

        //帮助清除Lua中我们没有手动清除的对象,垃圾回收
        //帧更新中定时执行 或者切场景的时候执行
        env.Tick();

        //销毁Lua解析器
        env.Dispose();
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

 在lua的Main脚本中,我们这样写

print("主lua脚本启动")

文件加载与重定向

 上面所说的加载lua脚本的方法虽然可行,但是比较麻烦。我们还可以利用XLua中提供的一个重定向的方法AddLoader(),允许我们自定义加载lua的方法

using System.IO;
using UnityEngine;
using XLua;

public class Lesson2Loader : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        LuaEnv env = new LuaEnv();
        //xlua提供一个路径重定向的方法
        //允许我们自定义加载lua文件的规则
        //当我们执行lua语言 require时,相当于执行一个lua脚本
        //他会执行我们自定义传入的这个函数
        env.AddLoader(MyCustomLoader);

        env.DoString("require('Main')");
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
    //自动执行
    private byte[] MyCustomLoader(ref string filepath)
    {

        //通过函数中的逻辑加载lua文件
        //传入的参数是require执行lua脚本文件名
        //拼接一个lua文件所在的路径
        string path =Application.dataPath+"/LUA/"+filepath+".lua";
        Debug.Log(path);

        //有路径就去加载文件
        //File知识点 C#提供的文件读写的类
        //判断文件是否存在
        if(File.Exists(path))
        {
            return File.ReadAllBytes(path);
        }
        else
        {
            Debug.Log("文件不存在"+filepath);
        }
        
        return null;
    }
}

 使用require("lua脚本")的方法会先去自定义的函数里面找文件,如果找到则返回,找不到会在默认路径里面寻找

Lua解析器管理器

 有了上面的经验,我们可以创建一个lua管理器,为C#解析lua提供一些通用的方法

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Rendering.VirtualTexturing;
using XLua;
/// <summary>
/// lua管理器
/// 提供lua解析器
/// 保证解析器唯一性
/// 提供通用的方法
/// </summary>
public class LuaMgr:BaseManager<LuaMgr>
{
    //执行lua语言的函数
    //释放垃圾
    //重定向
    //销毁
    private LuaEnv luaenv;
    
    /// <summary>
    /// 得到lua中的_G
    /// </summary>
    public LuaTable Global
    {
        get
        {
            return luaenv.Global;
        }
    }


    /// <summary>
    /// 初始化
    /// </summary>
    public void Init()
    {
        if (luaenv != null)
            return;
        luaenv = new LuaEnv();

        //重定向
        luaenv.AddLoader(MyCustomLoader);
        luaenv.AddLoader(MyCustomLoaderAB);
    }
    //自动执行
    private byte[] MyCustomLoader(ref string filepath)
    {

        //通过函数中的逻辑加载lua文件
        //传入的参数是require执行lua脚本文件名
        //拼接一个lua文件所在的路径
        string path = Application.dataPath + "/LUA/" + filepath + ".lua";

        //有路径就去加载文件
        //File知识点 C#提供的文件读写的类
        //判断文件是否存在
        if (File.Exists(path))
        {
            return File.ReadAllBytes(path);
        }
        else
        {
            Debug.Log("文件不存在" + filepath);
        }

        return null;
    }

    //Lua脚本会放在AB包中
    //最终我们会通过加载AB包再加载其中的Lua脚本资源来执行
    //AB包中如果要加载文本,后缀还是会有限制 .lua不能被识别
    //打包时还是要把lua文件后缀改为txt
    //重定向加载AB中的lua脚本
    private byte[] MyCustomLoaderAB(ref string filepath)
    {
        Debug.Log("进入AB包加载");
        从AB包中加载Lua文件
        加载AB包
        //string path = Application.streamingAssetsPath + "/LUA";
        //AssetBundle ab=AssetBundle.LoadFromFile(path);

        加载Lua文件,返回
        //TextAsset tx = ab.LoadAsset<TextAsset>(filepath + ".lua");

        加载lua文件里的byte数组
        //return tx.bytes;

        //通过AB包管理器加载的lua脚本
        TextAsset lua =ABgr.GetInstance().LoadRes<TextAsset>("LUA", filepath + ".lua");
        if (lua != null)
        {
            return lua.bytes;
        }
        else
        {
            Debug.Log("重定向失败"+filepath);
        }
        return null;


    }

    /// <summary>
    /// 传入lua文件名,执行lua脚本
    /// </summary>
    /// <param name="filename"></param>
    public void DoLuaFile(string filename)
    {
        string s = string.Format("require('{0}')", filename);
        DoString(s);
    }



    /// <summary>
    /// 执行lua语言
    /// </summary>
    /// <param name="s"></param>
    public void DoString(string s)
    {
        if(luaenv == null)
        {
            Debug.Log("解析器未初始化");
            return;
        }
        luaenv.DoString(s);
    }

    /// <summary>
    /// 释放垃圾
    /// </summary>
    public void Tick()
    {
        if (luaenv == null)
        {
            Debug.Log("解析器未初始化");
            return;
        }
        luaenv.Tick();
    }

    /// <summary>
    /// 销毁
    /// </summary>
    public void Dispose()
    {
        if (luaenv == null)
        {
            Debug.Log("解析器未初始化");
            return;
        }
        luaenv.Dispose();
        luaenv= null;
    }

}

全局变量获取

 我们修改lua中Main脚本的内容

print("主lua脚本启动")
--Unity中写lua执行
--xlua帮我们处理
--只要是执行lua脚本都会自动进入我们的重定向函数中找文件
require("Test")

然后我们在test脚本中声明一些变量,必须是全局变量,因为通过C#不能获取Lua中的本地变量

testnum=1
testbool=true
testfloat=11.8
teststring="xxxx"

 然后我们通过Global属性,利用Get获取,如果我们要修改值的内容,利用Set进行修改。如果直接修改是不能改变lua中的内容的,因为是浅拷贝

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Lesson4CallVarlable : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        LuaMgr.GetInstance().Init();

        LuaMgr.GetInstance().DoLuaFile("Main");

        //使用lua解析器中的luaenv中的Global属性
        //获取
        int i=LuaMgr.GetInstance().Global.Get<int>("testnum");
        Debug.Log(i);
        //该值
        LuaMgr.GetInstance().Global.Set("testnum",100);
        int i2 = LuaMgr.GetInstance().Global.Get<int>("testnum");
        Debug.Log(i2);
        //不能获取lua中的本地局部变量
        //int test=LuaMgr.GetInstance().Global.Get<int>("test");
        //Debug.Log(test);
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

全局函数获取

 在获取全局函数时,我们有四种类型的函数:无参数无返回值,有参数有返回值,多返回值,变长参数。

对于无参数无返回值

我们有四种方式获取:

//声明一个无参数无返回值的委托
public delegate void CallNoReturn();

//start中调用

CallNoReturn callNoReturn = LuaMgr.GetInstance().Global.Get<CallNoReturn>("testFun");
callNoReturn();

//Unity自带的委托(无返回值)
UnityAction ua= LuaMgr.GetInstance().Global.Get<UnityAction>("testFun");
ua();

 //C#的委托(无返回值)
Action action = LuaMgr.GetInstance().Global.Get<Action>("testFun");
action();

 //xLua 提供的一种获取函数的方式(尽量少用,会产生一些垃圾)
LuaFunction lf= LuaMgr.GetInstance().Global.Get<LuaFunction>("testFun");
lf.Call();
--无参无返回
testFun=function (  )
	print("无参数无返回")
end

 对于有参数有返回值

也是类似的:其中要注意的时,由于必须添加[CSharpCallLua],因此要在Xlua中先清除生成代码,再生成代码,然后再运行

/声明一个有参数有返回值的委托
//该特性是在xlua命名空间中的
[CSharpCallLua]
public delegate int CallHaveReturn(int a);


//start中调用
CallHaveReturn callHaveReturn = LuaMgr.GetInstance().Global.Get<CallHaveReturn>("testFunc");
Debug.Log("有参有返回"+callHaveReturn(8));

Func<int,int> func = LuaMgr.GetInstance().Global.Get<Func<int, int>>("testFunc");
Debug.Log(func(5));

LuaFunction lf1 = LuaMgr.GetInstance().Global.Get<LuaFunction>("testFunc");
Debug.Log(lf1.Call(19)[0]);//一个返回值返回数组第0个
--有参有返回
testFunc=function ( a)
	print("有参数有返回值")
	return a+4
	
end

 对于多返回值

我们使用out或者ref来接收,他们两个类似,区别为使用out不需要初始化,使用ref需要为他初始化

同样保存后也需要在XLua中重新生成代码再运行

我们还可以使用LuaFunction,使用数组来存他的多个返回值然后再遍历输出

//声明一个多返回值的委托 用out
[CSharpCallLua]
public delegate int CallMutReturn(int a, out int b, out bool c, out float d);

//声明一个多返回值的委托 用ref
[CSharpCallLua]
public delegate int CallMutReturn1(int a, ref int b, ref bool c, ref float d);


 CallMutReturn callMutReturn = LuaMgr.GetInstance().Global.Get<CallMutReturn>("testFunc3");
int b;
bool c;
float d;
Debug.Log("第一个返回值" + callMutReturn(123,out b,out c,out d));
Debug.Log(b+"_"+c+"_"+d);

CallMutReturn1 callMutReturn1 = LuaMgr.GetInstance().Global.Get<CallMutReturn1>("testFunc3");
int b1=0;
bool c1=false;
float d1=0.0f;
Debug.Log("第一个返回值" + callMutReturn1(100, ref b1, ref c1, ref d1));
Debug.Log(b1 + "_" + c1 + "_" + d1);

//使用luaFunction
LuaFunction lf2 = LuaMgr.GetInstance().Global.Get<LuaFunction>("testFunc3");
object[] obj = lf2.Call(10);
for(int i = 0; i < obj.Length; i++)
   {
        Debug.Log("第"+i+"个返回值是"+obj[i]);
   }

 对于变长参数

我们使用自定义的一个委托,变长参数我们使用params,如果能确定是同一类型,后面可以使用该类型,如果有各种类型就使用object

//声明一个变长参数的委托
[CSharpCallLua]
public delegate void CallChange(int a,params object[] obj);

CallChange callChange = LuaMgr.GetInstance().Global.Get<CallChange>("testFunc4");
callChange(3,false,"jwhdkh",7.666,658);

LuaFunction lf3 = LuaMgr.GetInstance().Global.Get<LuaFunction>("testFunc4");
lf3.Call(2, false, "jwhdkh", 7.666, 658);
--变长参数
testFunc4=function ( a,... )
	print("变长参数")
	print(a)
	arg={...}
	for k,v in pairs(arg) do
		print(k,v)
	end
end

完整代码 

using System;
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.Events;
using XLua;

//声明一个无参数无返回值的委托
public delegate void CallNoReturn();

//声明一个有参数有返回值的委托
//该特性是在xlua命名空间中的
[CSharpCallLua]
public delegate int CallHaveReturn(int a);

//声明一个多返回值的委托 用out
[CSharpCallLua]
public delegate int CallMutReturn(int a, out int b, out bool c, out float d);

//声明一个多返回值的委托 用ref
[CSharpCallLua]
public delegate int CallMutReturn1(int a, ref int b, ref bool c, ref float d);

//声明一个变长参数的委托
[CSharpCallLua]
public delegate void CallChange(int a,params object[] obj);//如果lua中后面的变长数组全是int或者是一种类型,那么可以就写params int[] b或者params string[] c
public class Lesson5CallFunction : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        LuaMgr.GetInstance().Init();
        LuaMgr.GetInstance().DoLuaFile("Main");

        无参无返回的获取
        //委托
        CallNoReturn callNoReturn = LuaMgr.GetInstance().Global.Get<CallNoReturn>("testFun");
        callNoReturn();
        //Unity自带的委托(无返回值)
        UnityAction ua= LuaMgr.GetInstance().Global.Get<UnityAction>("testFun");
        ua();

        //C#的委托(无返回值)
        Action action = LuaMgr.GetInstance().Global.Get<Action>("testFun");
        action();

        //xLua 提供的一种获取函数的方式(尽量少用,会产生一些垃圾)
        LuaFunction lf= LuaMgr.GetInstance().Global.Get<LuaFunction>("testFun");
        lf.Call();



        //有参有返回
        CallHaveReturn callHaveReturn = LuaMgr.GetInstance().Global.Get<CallHaveReturn>("testFunc");
        Debug.Log("有参有返回"+callHaveReturn(8));

        Func<int,int> func = LuaMgr.GetInstance().Global.Get<Func<int, int>>("testFunc");
        Debug.Log(func(5));

        LuaFunction lf1 = LuaMgr.GetInstance().Global.Get<LuaFunction>("testFunc");
        Debug.Log(lf1.Call(19)[0]);//一个返回值返回数组第0个



        ///多返回值
        //使用out与ref来接收(out接收外面的值不需要初始化,ref需要初始化)
        CallMutReturn callMutReturn = LuaMgr.GetInstance().Global.Get<CallMutReturn>("testFunc3");
        int b;
        bool c;
        float d;
        Debug.Log("第一个返回值" + callMutReturn(123,out b,out c,out d));
        Debug.Log(b+"_"+c+"_"+d);

        CallMutReturn1 callMutReturn1 = LuaMgr.GetInstance().Global.Get<CallMutReturn1>("testFunc3");
        int b1=0;
        bool c1=false;
        float d1=0.0f;
        Debug.Log("第一个返回值" + callMutReturn1(100, ref b1, ref c1, ref d1));
        Debug.Log(b1 + "_" + c1 + "_" + d1);

        //使用luaFunction
        LuaFunction lf2 = LuaMgr.GetInstance().Global.Get<LuaFunction>("testFunc3");
        object[] obj = lf2.Call(10);
        for(int i = 0; i < obj.Length; i++)
        {
            Debug.Log("第"+i+"个返回值是"+obj[i]);
        }



        变长参数
        CallChange callChange = LuaMgr.GetInstance().Global.Get<CallChange>("testFunc4");
        callChange(3,false,"jwhdkh",7.666,658);

        LuaFunction lf3 = LuaMgr.GetInstance().Global.Get<LuaFunction>("testFunc4");
        lf3.Call(2, false, "jwhdkh", 7.666, 658);
    }

  
}

List与Dictionary映射Table

 我们在lua中分别创建一个同类型与不同类型的列表与字典,列表一般用来没有自定义索引的表,如果确定类型就用指定类型,如果不确定就用object。字典一般是用来有自定义索引的表,如果确定类型就用指定类型,如果不确定就用object。

--List
testlist ={1,2,3,4,5,6}
testlist2={"vv",4,34,true,4.68}

--Dictionary
testDic={
	["1"]=1,
	["2"]=2,
	["3"]=3,
	["4"]=4,
	["5"]=5
}
testDic2={
	["1"]=1,
	[true]=2,
	[false]=true,
	["4"]=4.5,
	["5"]=false
}

 注意:遍历列表时用for,遍历字典时我们使用的时foreach。并且无论是字典还是列表,都为浅拷贝。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Lesson6CallListDic : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        LuaMgr.GetInstance().Init();
        LuaMgr.GetInstance().DoLuaFile("Main");

        //同一类型 List
        List<int> list = LuaMgr.GetInstance().Global.Get<List<int>>("testlist");
        Debug.Log("*********************List**********************");
        for(int i = 0; i < list.Count; i++)
        {
            Debug.Log(list[i]);
        }
        //为值拷贝 浅拷贝,不会改变lua中的值
        //list[0] = 100;
        //List<int> list2 = LuaMgr.GetInstance().Global.Get<List<int>>("testlist");
        //for (int i = 0; i < list.Count; i++)
        //{
        //    Debug.Log(list2[i]);
        //}
        //不指定类型 List
        List<object> list3= LuaMgr.GetInstance().Global.Get<List<object>>("testlist2");
        for (int i = 0; i < list3.Count; i++)
        {
            Debug.Log(list3[i]);
        }

        Debug.Log("*********************Dic**********************");
        //同一类型 Dic
        Dictionary<string,int> dic1= LuaMgr.GetInstance().Global.Get<Dictionary<string,int>>("testDic");
        foreach(string item in dic1.Keys)
        {
            Debug.Log(item + "_" + dic1[item]);
        }
        //若直接修改值,也为浅拷贝

        //不同类型 Dic
        Dictionary<object, object> dic2 = LuaMgr.GetInstance().Global.Get<Dictionary<object, object>>("testDic2");
        foreach (object item in dic2.Keys)
        {
            Debug.Log(item + "_" + dic2[item]);
        }
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

类映射Table

 lua中没有类,用表自定义类

testClass={
	testint=5,
	testbool=true,
	testfloat=4.5,
	teststring="xnbsa",
	testFun=function (  )
		print("243566764")
	end
    testInClass={
		testInInt=66,
		testInString=("*****************这是一个嵌套表******************")
	}
}

 在C#中,我们也定义一个类,其中声明的成员变量名字要和lua中一致,数量可以多也可以少。类中的嵌套在C#上的表现也是再声明一个类,其中的成员变量与函数名也要相同。

其中,在类中的拷贝为深拷贝,在C#中修改值会同步修改lua中的值

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

public class CallLuaClass
{
    //在类中声明成员变量 名字要和lua中的一样
    //数量可以比lua中多也可以更少
    public int testint;
    public float testfloat;
    public bool testbool;
    public string teststring;
    public UnityAction testFun;
    public CallLuaInClass testInClass;
}

public class CallLuaInClass
{
    public int testInInt;
    public string testInString;
}
public class Lesson7CallClass : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {

        LuaMgr.GetInstance().Init();
        LuaMgr.GetInstance().DoLuaFile("Main");

        CallLuaClass obj = LuaMgr.GetInstance().Global.Get<CallLuaClass>("testClass");
        Debug.Log(obj.testint);
        Debug.Log(obj.testfloat);
        Debug.Log(obj.testbool);
        //Debug.Log(obj.teststring);
        //obj.testFun();
        Debug.Log(obj.testInClass.testInInt);
        Debug.Log(obj.testInClass.testInString);
        //浅拷贝
        //obj.testint = 999;
        //CallLuaClass obj1 = LuaMgr.GetInstance().Global.Get<CallLuaClass>("testClass");
        //Debug.Log(obj1.testint);
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

接口映射Table

 lua中的脚本我们继续使用类的代码

testClass={
	testint=5,
	testbool=true,
	testfloat=4.5,
	teststring="xnbsa",
	testFun=function (  )
		print("243566764")
	end
}

 但是在C#中,接口是不允许有成员变量的,我们要使用属性来接收lua中的变量。

由于我们要使用[CSharpCallLua],在每一次对接口进行修改后我们都需要在XLua中进行清空然后生成代码再运行。

接口也可以有嵌套,嵌套方式与类中相似

注意的是接口中的拷贝也为深拷贝

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using XLua;

[CSharpCallLua]
//接口中是不允许有成员变量,因此我们用属性来接收
//与类相似,内容属性可多可少,但是每一次修改interface结构后都需要先清空xLua再生成运行
//嵌套几乎和类一样,无非就是要遵循接口的规则
public interface ICCallLua
{
    int testint
    {
        get; set;
    }
    bool testbool
    {
        get; set;
    }

    float testfloat
    {
        get; set;
    }

    string teststring
    {
        get; set;
    }

    UnityAction testFun
    {
        get; set;
    }
}

public class Lesson8CallInterface : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        LuaMgr.GetInstance().Init();
        LuaMgr.GetInstance().DoLuaFile("Main");

        ICCallLua obj = LuaMgr.GetInstance().Global.Get<ICCallLua>("testClass");
        Debug.Log(obj.testint);
        Debug.Log(obj.testbool);
        Debug.Log(obj.teststring);
        Debug.Log(obj.testfloat);
        obj.testFun();

        //接口为引用拷贝,改了值lua中的值也会变化
        obj.testint = 18888;
        ICCallLua obj1 = LuaMgr.GetInstance().Global.Get<ICCallLua>("testClass");
        Debug.Log(obj1.testint);
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

LuaTable映射Table

 同样使用lua之前的代码

testClass={
	testint=5,
	testbool=true,
	testfloat=4.5,
	teststring="xnbsa",
	testFun=function (  )
		print("243566764")
	end
}

 在之前的使用中,我们多次用到LuaTable,在LuaMgr的定义中我们知道,他将其定义为Global,来得到Get里面的变量与函数

但是我们不建议使用LuaTable与LuaFunction,因为他们效率低且会产生垃圾,在不需要使用后要记得销毁

并且他也为深拷贝

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;

public class Lesson9CallLuaTable : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        LuaMgr.GetInstance().Init();
        LuaMgr.GetInstance().DoLuaFile("Main");

        //不建议用LuaTable与LauFunction,因为效率低且容易产生垃圾
        //是一种引用对象
        LuaTable table=LuaMgr.GetInstance().Global.Get<LuaTable>("testClass");
        Debug.Log(table.Get<int>("testint"));
        Debug.Log(table.Get<bool>("testbool"));
        Debug.Log(table.Get<float>("testfloat"));
        Debug.Log(table.Get<string>("teststring"));
        table.Get<LuaFunction>("testFun").Call();
        //是引用拷贝
        table.Set("testint", 1949);
        Debug.Log(table.Get<int>("testint"));

        LuaTable table1 = LuaMgr.GetInstance().Global.Get<LuaTable>("testClass");
        Debug.Log(table1.Get<int>("testint"));

        //不用了要记得销毁,会有垃圾
        table.Dispose();
        table1.Dispose();
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

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

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

相关文章

麒麟操作系统服务架构保姆级教程(七)Nginx+PHP+Mysql部署服务

上边几篇文章已经交过大家二进制部署nginx和php&#xff0c;现在咱们打通nginx和php&#xff0c;mysql和php&#xff0c;开始部署服务&#xff0c;学会部署服务之后就可以开始学习负载均衡啦&#xff0c;话不多说&#xff0c;咱们直接开始~~~ 目录 一、.nginx部署 二、安装PH…

开源模型迎来颠覆性突破:DeepSeek-V3与Qwen2.5如何重塑AI格局?

不用再纠结选择哪个AI模型了&#xff01;chatTools 一站式提供o1推理模型、GPT4o、Claude和Gemini等多种选择&#xff0c;快来体验吧&#xff01; 在全球人工智能模型快速发展的浪潮中&#xff0c;开源模型正逐渐成为一股不可忽视的力量。近日&#xff0c;DeepSeek-V3和Qwen 2.…

【Java项目】基于SpringBoot的【新生宿舍管理系统】

【Java项目】基于SpringBoot的【新生宿舍管理系统】 技术简介&#xff1a;本系统使用采用B/S架构、Spring Boot框架、MYSQL数据库进行开发设计。 系统简介&#xff1a;管理员登录进入新生宿舍管理系统可以查看首页、个人中心、公告信息管理、院系管理、班级管理、学生管理、宿舍…

《learn_the_architecture_-_trustzone_for_aarch64_102418_0101_03_en》学习笔记

1.TrustZone是Arm A-profile架构中安全架构的名称。TrustZone首次在Armv6K中引入&#xff0c;Armv7-A和Armv8-A也支持。TrustZone提供两个执行环境&#xff0c;它们之间具有系统范围的硬件强制隔离。在Arm架构中&#xff0c;有两种安全状态&#xff1a;安全和非安全。在EL0、EL…

Excel | 空格分隔的行怎么导入excel?

准备工作&#xff1a;windows&#xff0c;一个记事本程序和微软的Excel软件。 打开记事本&#xff0c;选中所有内容&#xff0c;按CtrlA全选&#xff0c;然后复制(CtrlC)。 在Excel中&#xff0c;定位到你想粘贴的单元格&#xff0c;按CtrlV进行粘贴。粘贴后&#xff0c;你会在…

南京观海微电子----GH7009国宇测试盒使用

1. SPI接线 针对7009&#xff1a; 2. 国宇上位机代码准备 在主函数首尾两端加入IO2时序控制的代码、以及国语SPI有效位控制的代码&#xff08;请注意7009和其他700x使用的有效位控制不一致&#xff0c;需要用哪一款加入哪一行即可&#xff09;&#xff1a; 三、国宇SPI读的使…

Arduino Uno简介与使用方法

目录 一、Arduino Uno概述 1. 硬件特性 2. 开发环境 二、Arduino Uno的基本使用方法 1. 硬件连接 2. 软件编程 三、Arduino Uno编程基础 1. 基本语法 2. 常用函数 四、Arduino Uno应用举例 1. LED闪烁 2. 温度检测 3. 超声波测距 五、Arduino Uno的扩展与应用 1…

使用命令行管理git项目

# 初始化一个新的Git仓库 git init # 添加文件到暂存区 git add <file> # 提交暂存区的更改到仓库 git commit -m "commit message" # 查看当前仓库的状态 git status # 查看提交历史 git log # 查看文件的改动 git diff <file> # 创建一个新…

网络安全的学习与实践经验(附资料合集)

学习资源 在线学习平台&#xff1a; Hack This Site&#xff1a;提供从初学者到高级难度的挑战任务&#xff0c;适合练习各种网络安全技术。XCTF_OJ&#xff1a;由XCTF组委会开发的免费在线网络安全网站&#xff0c;提供丰富的培训材料和资源。SecurityTube&#xff1a;提供丰…

基于STM32的热带鱼缸控制系统的设计

文章目录 一、热带鱼缸控制系统1.题目要求2.思路3.电路仿真3.1 未仿真3.2 开始仿真&#xff0c;显示屏显示水温、浑浊度、光照强度等值3.3 当水温低于阈值&#xff0c;开启加热并声光报警3.4 当浑浊度高于阈值&#xff0c;开启自动换水并声光报警3.5 当光照低于阈值&#xff0c…

【DevOps】Jenkins项目发布

Jenkins项目发布 文章目录 Jenkins项目发布前言资源列表基础环境一、Jenkins发布静态网站1.1、项目介绍1.2、部署Web1.3、准备gitlab1.4、配置gitlab1.5、创建项目1.6、推送代码 二、Jenkins中创建gitlab凭据2.1、创建凭据2.2、在Jenkins中添加远程主机2.3、获取gitlab项目的UR…

SSM-SpringMVC

目录 “为什么要学 SpringMVC&#xff1f;它和 Servlet 是什么关系&#xff1f;” “什么是异步&#xff1f;为什么异步交互中常用 JSON 格式&#xff1f;异步请求和 JSON 如何配合&#xff1f;” 一、概述 SpringMVC主要负责 1 SpringMVC的常用组件 2 SpringMVC的工作流程…

基层医联体医院患者历史检验检查数据的快速Python编程分析

​​​​​​​ 一、引言 1.1 研究背景与意义 在当今数字化医疗时代,医疗数据呈爆炸式增长,涵盖患者的基本信息、病史、检验检查结果、治疗方案等各个维度。这些海量且复杂的数据蕴含着巨大价值,为精准医疗决策提供了关键依据。通过对患者历史检验检查数据的深入对比分析…

计算机网络基础(7)中科大郑铨老师笔记

应用层 目标&#xff1a;  网络应用的 原理&#xff1a;网络应用协议的概念和实现方面 传输层的服务模型 客户-服务器模式 对等模式(peerto-peer) 内容分发网络  网络应用的 实例&#xff1a;互联网流行的应用层协 议  HTTP  FTP  SMTP / POP3 / IMAP  DNS…

Fabric环境部署-Git和Node安装

一.安装Git&#xff08;v2.43.0&#xff09; Git 是一个开源的分布式版本管理系统&#xff08;也是全球最大的开源软件存储服务器&#xff09;&#xff0c;用于敏捷高效地处理任何或小或大的项目。搭建区块链需要使用Git&#xff0c;因为区块链的开发和部署需要使用版本控制工…

SAP MM物料管理模块常见BAPI函数清单

【SAP系统研究】 #SAP #MM #物料管理 #函数 #BAPI 1、物料主数据 BAPI_MATERIAL_SAVEDATA 创建/更改物料主数据 BAPI_MATERIAL_SAVEREPLICA 物料主数据视图扩充 BAPI_MATERIAL_EXISTENCECHECK 检查物料主数据是否存在 BAPI_MATERIAL_GETLIST 显示物料主数据明细 BAPI_MATERIALG…

Windows11安装Oracle11g以及plsqldev工具连接配置

文章目录 一、安装Oracle数据库软件二、配置数据库三、配置监听&#xff08;listener.ora&#xff09;四、本地网络服务名配置&#xff08;tnsnames.ora&#xff09;五、网络服务名配置以及监听文件路径六、plsqldev工具连接Oracle配置 一、安装Oracle数据库软件 点击“setup.…

unity学习6:unity的3D项目的基本界面和菜单

目录 1 unity界面的基本认识 1.1 file 文件 1.2 edit 编辑/操作 1.3 Assets 1.4 gameobject 游戏对象 1.5 组件 1.6 windows 2 这些部分之间的关系 2.1 关联1&#xff1a; Assets & Project 2.2 关联2&#xff1a;gameobject & component 2.3 关联3&#xf…

HTML5新特性|06 文本效果text-shadowword-wrap自定义字体

文本效果 1、CSS3包含多个新的文本特性 属性: text-shadow:水平阴影 垂直阴影 模糊距离 阴影颜色 word-wrap&#xff1a;用于指定当文本溢出其容器的边界时如何处理换行的问题 浏览器支持: Internet Explorer 10、Firefox、 Chrome、 Safari 以及Opera支持text-shadow属性…

【踩坑指南2.0 2025最新】Scala中如何在命令行传入参数以运行主函数

这个地方基本没有任何文档记录&#xff0c;在学习的过程中屡屡碰壁&#xff0c;因此记录一下这部分的内容&#xff0c;懒得看可以直接跳到总结看结论。 踩坑步骤 首先来看看书上让我们怎么写&#xff1a; //main.scala object Start {def main(args:Array[String]) {try {v…