unity 之工厂三维应用实践(数据可视化应用/数字孪生)踩过的坑记录!C#脚本与unity开发


一、unity之C#调用Java的webservice接口的坑


初识Unity

虽然前些年我是C#出身的女程序员,后来转成Java方向了,但是我对unity的后台脚本那是一丁点儿不知道啊,但是最近公司在做工厂方面的三维应用,而负责弄三维的UI大佬对开发语言那是一窍不通的小白鼠啊,那怎么办?只有我挺身而出(谁让我是公司唯一的一个会C#的人呢),这里差点被鸭梨山大压得喘不上气啊~~~~~

坑One

以下是Java里的webservice调用方式:
XXX是自己写的jar包

package com.XXX.util;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;

public class WebServiceClient2 {
	public static void main(String[] args) {
		try {
			// 1 指定WebService服务的请求地址:
			String wsUrl = "http://10.192.154.206:9001/XXX/services/WebScadaServiceAPI";

			// 2 创建URL:
			URL url = new URL(wsUrl);
			// 3 建立连接,并将连接强转为Http连接
			URLConnection conn = url.openConnection();
			HttpURLConnection con = (HttpURLConnection) conn;

			// 4,设置请求方式和请求头:
			con.setDoInput(true); // 是否有入参
			con.setDoOutput(true); // 是否有出参
			con.setRequestMethod("POST"); // 设置请求方式
			con.setRequestProperty("content-type", "text/xml;charset=UTF-8");

			// 5,手动构造请求体
			String requestBody = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ser=\"http://service.XXX.com/\">";
			requestBody += "<soapenv:Header/>";
			requestBody += "<soapenv:Body>";
			requestBody += "<ser:getPointsData>";
			requestBody += "<kdName>yd_123456_Ia</kdName>";
			requestBody += "</ser:getPointsData>";
			requestBody += "</soapenv:Body>";
			requestBody += "</soapenv:Envelope>";

			// 6,通过流的方式将请求体发送出去:
			OutputStream out = con.getOutputStream();
			out.write(requestBody.getBytes());
			out.close();
			// 7,服务端返回正常:
			int code = con.getResponseCode();
			if (code == 200) {// 服务端返回正常
				InputStream is = con.getInputStream();
				byte[] b = new byte[1024];
				StringBuffer sb = new StringBuffer();
				int len = 0;
				while ((len = is.read(b)) != -1) {
					String str = new String(b, 0, len, "UTF-8");
					sb.append(str);
				}
				System.out.println(sb.toString());
				is.close();
			}
			con.disconnect();
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}
}

想着java那是通过soapui的方式来请求的,那unity也可以用这样的方式通过C#来实现啊,soeasy啊!码上我的C#代码!

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Text;
using System.Xml;
using UnityEngine.UI;
using System.IO;
using System.Net;
using LitJson;
using System.Linq;
using UnityEngine.Networking;

public class webtest001 : MonoBehaviour
{
    public Text yd_123456_Ia;
    public Text yd_123456_Ib;
    
    void Start()
    {
            
        Dictionary<string, string> dic = new Dictionary<string, string>();
        dic.Add("1", "yd_123456_Ia");
        dic.Add("2", "yd_123456_Ib");
        StartCoroutine(callWebService("getPointsData", dic));
    }

    public  string callWebService(string methodName, Dictionary<string, string> param)
    {
        Dictionary<string, string> dic = new Dictionary<string, string>();
        ///获取请求数据
        byte[] data = getRequestDataALL(methodName, param); 
        String url = "http://10.192.154.206:9001/XXX/services/WebScadaServiceAPI HTTP/1.1";
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
        request.Method = "POST";
        request.ContentType = "text/xml; charset=utf-8";
        string mSoapAction = "";//"http://tempuri.org/" + methodName;
        request.Headers.Add("SOAPAction", mSoapAction);
        request.ContentLength = data.Length;
        Stream rStream = request.GetRequestStream();
        rStream.Write(data, 0, data.Length);
        rStream.Close();

        WebResponse response = request.GetResponse();
        Stream dataStream = response.GetResponseStream();
        StreamReader reader = new StreamReader(dataStream);
        string result = reader.ReadToEnd();

        dataStream.Close();
        response.Close();

        result = result.Replace("&quot;","\"");
        object obj="";
        String str=FormatXML(result);
        if (str.Equals("") == false)
        {
            str = str.Substring(0, str.Length - 1);
            JsonData jsonData = JsonMapper.ToObject(str);
            string res = jsonData["result"].ToJson();
            jsonData = JsonMapper.ToObject(res);
            foreach (JsonData item in jsonData)
            {
                obj+=  item["kdData"].ToString();
                dic.Add(item["kdName"].ToString(), item["kdData"].ToString());
                //print(item["kdData"] + ":" + item["alarmStatue"] + ":" + item["kdName"]);
            }
        }

        string d1=dic.SingleOrDefault(o => o.Key == "yd_123456_Ia").Value;
        string d2 = dic.SingleOrDefault(o => o.Key == "yd_123456_Ib").Value;

        yd_WNSJD150_Ia.GetComponent<Text>().text = String.Format("设备效率:{0}", d1);

        yd_WNSJD150_Ib.GetComponent<Text>().text = String.Format("冷却温度比:{0}", d2);
        return result;
    }


    public string FormatXML(string str)
    {
        String val = "";
        XmlDocument doc = new XmlDocument();
        doc.LoadXml(str);
        XmlNodeList nodeList = doc.GetElementsByTagName("soap:Body");
        StringBuilder nameList = new StringBuilder();
        //循环xml数据
        foreach (XmlNode xmlNode in nodeList)
        {
            XmlNodeList childList = xmlNode.ChildNodes; //取得row下的子节点集合
           foreach (XmlNode item in childList)
           {
                String name = item.InnerXml;
                if (name.Contains("return"))
                {
                    val+=item.InnerText+",";
                }
           }
        }

        return val;
    }

    
    public  byte[] getRequestDataALL(string methodName, Dictionary<string, string> param)
    {
        string str = "";
        StringBuilder requestBuider = new StringBuilder();
        requestBuider.Append("<soapenv:Envelope xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/' xmlns:ser='http://service.XXX.XXX.com/'>");
        requestBuider.Append("<soapenv:Header/>");
        requestBuider.Append("<soapenv:Body>");

        requestBuider.Append("<ser:").Append(methodName).Append(">");
        requestBuider.Append("<kdName>");
        foreach (KeyValuePair<string, string> item in param)
        {

            str+=item.Value+",";
        }
        str = str.Substring(0,str.Length-1);
        requestBuider.Append(str);
        requestBuider.Append("</kdName>");
        requestBuider.Append("</ser:").Append(methodName).Append(">");
        requestBuider.Append("</soapenv:Body>");
        requestBuider.Append("</soapenv:Envelope>");
        string val = requestBuider.ToString();
       byte[] data = Encoding.UTF8.GetBytes(val);
       return data;
    }
    
}

然后在unity中进行运行的时候,数据请求过来了,暗自窃喜成功了,然而UI大佬那里发布出来生成Webgl的时候却是个空白,画面啥数据都没有!
后来UI大佬自己百度了下原因,说与以下网页遇到的问题是一样的,得用unity自己的请求方式才行!

https://www.codercto.com/a/72962.html

分析了下:首先是Http请求的问题,我最开始想的是,直接用C#里的写法,编辑器里测试毫无问题,但是一打包出来就不行,会报出 SystemException: Thread creation failed. 的错误,无奈只能用Unity自己的 请求方式,例如UnityWebRequestWWW 等。

我参考了下面的网址:https://www.cnblogs.com/fyluyg/p/6047819.html
后来发现www已经过时,后来就用了UnityWebRequest方式

using LitJson;
using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;

public class WebGLTest : MonoBehaviour
{
    enum Request_Type
    {
        POST,
        SOAP,
    }

    public Text myText;
    public Text txtNum;
    public Text txtNum02;

    public float timer = 10.0f;
    public string mu_url = "http://10.192.154.206:9001/XXX/unty3DServiceAPI";

    //声明的协程对象
    IEnumerator ie;

    // Start is called before the first frame update
    void Start()
    {
        Dictionary<string, string> dic = new Dictionary<string, string>();
        dic.Add("1", "yd_123456_Ia");
        dic.Add("2", "yd_123456_Ib");

        JsonData data = new JsonData();
        data["kdName"] = "yd_123456_Ia,yd_123456_Ib";//传JSON格式参数定义,具体根据提供的JOSN数据为准
        ie = IPostData(mu_url, data);
        StartCoroutine(ie);
    }

    // Update is called once per frame
    void Update()
    {
        JsonData data = new JsonData();
        data["kdName"] = "yd_123456_Ia,yd_123456_Ib";

        timer -= Time.deltaTime;
        if (timer <= 0)
        {
            Debug.Log(string.Format("Timer1 is up !!! time=${0}", Time.time));
            timer = 10.0f;
            StartCoroutine(IPostData(mu_url, data));
        }
    }


    IEnumerator IPostData(string m_url, JsonData data)
    {

        using (UnityWebRequest webRequest = new UnityWebRequest(m_url, UnityWebRequest.kHttpVerbPOST))
        {
            byte[] postBytes = System.Text.Encoding.UTF8.GetBytes(data.ToJson());

            webRequest.uploadHandler = (UploadHandler)new UploadHandlerRaw(postBytes);
            webRequest.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
            webRequest.SetRequestHeader("Content-Type", "application/json");

            webRequest.SendWebRequest();
            
            if (webRequest.isNetworkError || webRequest.isHttpError)
            {
                Debug.LogError(webRequest.error + webRequest.isHttpError);
            }

            while (webRequest.responseCode != 200)
            {
                yield return null;//这里一定要写到调用接口不通的情况下才迭代返回,不然update那里实时刷新调取进来这个方法只会调取一次
            }
            if(webRequest.responseCode == 200)
            {
                string st = webRequest.downloadHandler.text.Replace("\\", "");
                print(st.Substring(1, st.Length - 1));

                Dictionary<string, string> dic = parseJson(st.Substring(1, st.Length - 1));

                string d1 = dic.SingleOrDefault(o => o.Key == "yd_123456_Ia").Value;
                string d2 = dic.SingleOrDefault(o => o.Key == "yd_123456_Ib").Value;
                //unity控件绑定值方式1
                //GameObject t = GameObject.Find("myText");
                //t.GetComponent<Text>().text = d1;//有效
                //GameObject txtNum = GameObject.Find("txtNum");
                //txtNum.GetComponent<Text>().text = d2;//有效
                
				//unity控件绑定值方式2(需要在unity的inspector中绑定,后面会说到)
                myText.text = d1;
                txtNum.text = d2;
            }
        }

    }


    private Dictionary<string, string> parseJson(string data)
    {
        Dictionary<string, string> dic = new Dictionary<string, string>();
        JsonData jsonData = JsonMapper.ToObject(data);
        string errorCode = jsonData["errorCode"].ToString();
        if (errorCode.Equals("0"))
        {
            string res = jsonData["result"].ToJson();
            jsonData = JsonMapper.ToObject(res);
            foreach (JsonData item in jsonData)
            {
                Debug.Log(item["kdData"].ToString());
                dic.Add(item["kdName"].ToString(), item["kdData"].ToString());
            }
        }

        return dic;
    }


}

坑Two

在这里插入图片描述

码完上面的代码,发现接口调取是通的(返回状态是200),但是为何没有数据呢?postman测试接口工具也是可以正常有返回数据的,为何这里C#就返回没有数据?头疼了一天多后来通过debug模式才发现是java那里post方式获取参数没有通过流模式读取,而是request方式来获取。
改成第一个红框中请求方式,发现返回过来值就有了,于是就在unity运行没有问题。开始发布webgl看看有没有问题,然而天有不测风云,又出现:**CORS 头缺少 ‘Access-Control-Allow-Origin’**问题

坑Three

我各种百度,google,基本上都说是加上上图中的**Access-Control-Allow-Origin:***参数设置或者通过Firefox浏览器将 security.fileuri.strict_origin_policy 修改,但是在新的Firefox浏览器不支持,于是其转换方向,向浏览器跨域问题方向百度,居然真的被我找到答案。

https://blog.csdn.net/nju_zjy/article/details/108870385

使用firefox浏览器插件来实现跨域,例如CORS-EVERYWHERE

https://addons.mozilla.org/en-US/firefox/addon/cors-everywhere/

它是可用的。它的github地址是https://github.com/spenibus/cors-everywhere-firefox-addon。

装完插件,在运行webgl下面的index.html记得点击下firefox浏览器右上角的CORS-EVERYWHERE插件

在这里插入图片描述
绿色代表插件启用,或者自行前往设置插件默认启用

好了,关于unity中数据请求并实时刷新的实现方式及webgl中跨域问题的坑完美解决~~(现在百度上很多关于webgl的浏览器跨域问题求助帖都没办法解决,希望他们可以看到我的记录吧)

后续再更新如何在unity中使用XCharts及实时更新数锯,记得关注我哦~~~

  • 6
    点赞
  • 68
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值