java对接天猫精灵语音助手实现对公司其下的智能设备进行控制

前言当初刚来广州 公司上一任java已经离职半年 ,项目已经跑不动了,才招人的,所以我获得的是一个连跑都跑不起来的项目源码并且对项目一无所知,一年前网上并没有对接天猫精灵的相关走路只能自己整。下面我把整个controller层代码 从授权到控制的代码给贴了出来希望对大家有帮助。(基本自己改改就能直接用目前代码还在公司服务器上跑并且没任何问题)

下面有几点需要注意。
至于在天猫精灵开发者平台哪些东西就不讲了 说一些别的。
1.SSL证书(免费的 另外我有博客写了如何部署等等)在eclipse的tomcat安装ssl证书
2.域名(几块钱一个)
3.外网IP(可以花生壳什么的或者使用别的工具内网穿透直接在开发工具上调试他不香吗,难不成每次改一点点都要去发布一遍项目??)
4.天猫精灵的token会自动过期 (要操控设备的时候就会直接报已授权过期,授权已过期 ,贼烦 所以我这边授权自动过期了它来重新获取授权的时候我还是会去数据库把以前的旧token给它 ,嘿嘿嘿永不过期 )
5. combine接口有一段逻辑根据token 查询用户信息以后 根据用户名提取文件并解析公司存储在linux服务器上的客户客户设备信息并根据天猫精灵可解析的格式返回给天猫精灵 (注意 天猫精灵发送命令也是往这个接口,获取设备信息也是)
6. 有问题可以跟我留言 (目前还对接过小度小度,若琪)
7.差点忘记说了###号的地方请替换为自己的信息
把整个类拷过去然后改一下对应的域名端口号还有ID就好了

package com.obj.controller;import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import javax.annotation.Resource;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.oltu.oauth2.as.issuer.MD5Generator;
import org.apache.oltu.oauth2.as.issuer.OAuthIssuer;
import org.apache.oltu.oauth2.as.issuer.OAuthIssuerImpl;
import org.apache.oltu.oauth2.as.request.OAuthAuthzRequest;
import org.apache.oltu.oauth2.as.request.OAuthTokenRequest;
import org.apache.oltu.oauth2.as.response.OAuthASResponse;
import org.apache.oltu.oauth2.common.OAuth;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.OAuthResponse;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.xml.sax.SAXException;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.obj.entity.Device;
import com.obj.entity.user;
import com.obj.entity.Token;
import com.obj.service.ControlService;
import com.obj.service.MqttMessageService;
import com.obj.service.ResponseService;
import com.obj.service.deviceService;
import com.obj.service.userService;import utils.AnalysisXML;@Controller
@RequestMapping("/Test")
public class testController {@Resourcepublic userService userservice;@Resourcepublic deviceService deviceservice;@Resourcepublic MqttMessageService mqttService;@Resourcepublic ResponseService responseService;@Resourcepublic ControlService controlService;String grant_type = "authorization_code";String clientId = "###";// String clientSecret = "###";// String userInfoUrl = null;String response_type = "code";String code = null;String cutURL = "https://####:9443/genie/merchantHTML/login.jsp?";//String OAuthURL = "https://####:9443/genie/Test/responseCode.do?";//int cutlength = cutURL.length();int num=0;String s = new String("");@RequestMapping("/userlogin")public String userlogin(HttpServletRequest request, HttpServletResponse response)throws IOException, OAuthSystemException, ServletException {String url = request.getHeader("referer");String username = request.getParameter("username");String password = request.getParameter("password");ServletContext context = request.getSession().getServletContext();context.setAttribute("username", username);user IdentifyUsername = userservice.IdentifyUsername(username);user IdentifyPassword = userservice.IdentifyPassword(username, password);if (IdentifyUsername != null) {if (IdentifyPassword != null) {String outURL = java.net.URLDecoder.decode(url, "UTF-8");int outlength = outURL.length();String responseURL = outURL.substring(cutlength, outlength);System.out.println("截取到的内容:"+responseURL+ "\n 长度:"+responseURL.length());num=responseURL.length();s=responseURL;OAuthURL = OAuthURL +responseURL;return "redirect:" + OAuthURL;} else {System.out.println("密码错误!");}} else {System.out.println("用户名不存在!");}return "error";}@RequestMapping("/responseCode")public Object toShowUser(Model model, HttpServletRequest request) throws IOException {try {// 构建OAuth 授权请求OAuthAuthzRequest oauthRequest = new OAuthAuthzRequest(request);oauthRequest.getClientId();oauthRequest.getResponseType();oauthRequest.getRedirectURI();String token=null;String state=null;String[] strarray=s.split("&"); token =strarray[1].substring(6,strarray[1].length());state =strarray[4].substring(6,strarray[4].length());if (oauthRequest.getClientId() != null && oauthRequest.getClientId() != "") {// 设置授权码String authorizationCode = UUID.randomUUID().toString().replace("-", "").substring(0,18);System.out.println("授权码UUID=" + authorizationCode);// 利用oauth授权请求设置responseType,目前仅支持CODE,另外还有TOKEN// String responseType = oauthRequest.getParam(OAuth.OAUTH_RESPONSE_TYPE);// 进行OAuth响应构建OAuthASResponse.OAuthAuthorizationResponseBuilder builder = OAuthASResponse.authorizationResponse(request, HttpServletResponse.SC_FOUND);// 设置授权码builder.setParam("token",java.net.URLDecoder.decode(token, "UTF-8"));builder.setParam("state", state);builder.setCode(authorizationCode);// 得到到客户端重定向地址String redirectURI = oauthRequest.getParam(OAuth.OAUTH_REDIRECT_URI);// 构建响应OAuthResponse response = builder.location(redirectURI).buildQueryMessage();System.out.println("服务端/responseCode内,返回的回调路径:" + response.getLocationUri() + "\n");String responceUri = response.getLocationUri();// 根据OAuthResponse返回ResponseEntity响应HttpHeaders headers = new HttpHeaders();try {headers.setLocation(new URI(response.getLocationUri()));} catch (URISyntaxException e) {e.printStackTrace();}String strURL = "https://####/genie/Test/responseAccessToken.do?grant_type=authorization_code&client_id=####&client_secret=####&redirect_uri=https://open.bot.tmall.com/oauth/callback&code="+ authorizationCode;URL url = new URL(strURL);HttpURLConnection connection = (HttpURLConnection) url.openConnection();connection.setDoOutput(true);connection.setDoInput(true);connection.setUseCaches(false);connection.setInstanceFollowRedirects(true);connection.setRequestMethod("POST"); // 设置请求方式connection.setRequestProperty("Accept", "application/json"); // 设置接收数据的格式connection.setRequestProperty("Content-Type", "application/json"); // 设置发送数据的格式connection.connect();System.out.println("redirect:" + responceUri);token=null;state=null;return "redirect:" + responceUri;// https://open.bot.tmall.com/oauth/callback?skillId=18105&code=0b58444322e04d9c8e&state=11&token=MjM0MDgzODYwMEFGRUhJTkZEVlE%3D}} catch (OAuthSystemException e) {e.printStackTrace();} catch (OAuthProblemException e) {e.printStackTrace();}return null;}@RequestMapping(value = "/responseAccessToken", method = RequestMethod.POST)public HttpEntity<String> token(HttpServletRequest request) throws OAuthSystemException {JSONObject jsonObject = new JSONObject();SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm");//设置日期格式System.out.println("--------天猫精灵服务端/responseAccessToken---------------------"+df.format(new Date())+"---------------------");OAuthIssuer oauthIssuerImpl = null;OAuthResponse response = null;// 构建OAuth请求try {OAuthTokenRequest oauthRequest = new OAuthTokenRequest(request);String clientSecret = oauthRequest.getClientSecret();String token = oauthRequest.getRefreshToken();String accessToken=null;String refreshToken=null;int AccessToken=0;/** accessToken存进数据库,过期时间3天 绑定user用户*/ServletContext context = request.getSession().getServletContext();String username = (String) context.getAttribute("username");if (clientSecret != null && clientSecret != "") {if(token==null && username!=null) {//绑定 赋予授权// 生成Access TokenoauthIssuerImpl = new OAuthIssuerImpl(new MD5Generator());accessToken = oauthIssuerImpl.accessToken();refreshToken = oauthIssuerImpl.refreshToken();/* 判断 数据库是否有相同token 有则继续取新的*/boolean l=true;  do {  String name=userservice.SelectByToken(accessToken);  String name2=userservice.SelectRefreshToken(refreshToken);if(name==null&&name2==null) {l=false;}else {accessToken=oauthIssuerImpl.accessToken();refreshToken = oauthIssuerImpl.refreshToken();}} while (l);jsonObject.put("access_token", accessToken);jsonObject.put("refresh_token", refreshToken);jsonObject.put("expires_in", 259200);AccessToken = userservice.update(accessToken, username,refreshToken);if(AccessToken!=0) {System.out.println("授权成功");}else {System.out.println("授权失败");}response = OAuthASResponse.tokenResponse(HttpServletResponse.SC_OK).setAccessToken(accessToken).setRefreshToken(refreshToken).setExpiresIn("259200").setParam("expires_in", "259200").setParam("example_parameter", "example_value").buildJSONMessage();// 根据OAuthResponse生成ResponseEntityreturn new ResponseEntity<String>(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));}else if(token!=null) { //天猫主动刷新授权System.out.println("授权过期 天猫精灵自动获取授权!");Token  userToken=userservice.SelectToken(token); //凭着带过来的tokenif(userToken.getTokenid()!=null&&userToken.getRefresh_tokenTM()!=null&&userToken.getUser()!=null) {//如果本身就拥有token 则取出数据库中的token 再返回给天猫精灵refreshToken=userToken.getRefresh_tokenTM();accessToken=userToken.getTokenid();System.out.println("天猫精灵主动发起授权刷新,数据库存在token 将其返回");// 生成OAuth响应response = OAuthASResponse.tokenResponse(HttpServletResponse.SC_OK).setAccessToken(accessToken).setRefreshToken(refreshToken).setExpiresIn("259200").setParam("expires_in", "259200").setParam("example_parameter", "example_value").buildJSONMessage();// 根据OAuthResponse生成ResponseEntityreturn new ResponseEntity<String>(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));}else {//生成新的token 返回给天猫精灵// 生成Access TokenoauthIssuerImpl = new OAuthIssuerImpl(new MD5Generator());accessToken = oauthIssuerImpl.accessToken();refreshToken = oauthIssuerImpl.refreshToken();/* 判断 数据库是否有相同token 有则继续取新的*/boolean l=true;  do {  String name=userservice.SelectByToken(accessToken);  String name2=userservice.SelectRefreshToken(refreshToken);if(name==null&&name2==null) {l=false;}else {accessToken=oauthIssuerImpl.accessToken();refreshToken = oauthIssuerImpl.refreshToken();}} while (l);jsonObject.put("access_token", accessToken);jsonObject.put("refresh_token", refreshToken);jsonObject.put("expires_in", 259200);AccessToken = userservice.update(accessToken, userToken.getUser(),refreshToken);if(AccessToken!=0) {System.out.println("授权成功");}else {System.out.println("授权失败");}// 生成OAuth响应response = OAuthASResponse.tokenResponse(HttpServletResponse.SC_OK).setAccessToken(accessToken).setRefreshToken(refreshToken).setExpiresIn("259200").setParam("expires_in", "259200").setParam("example_parameter", "example_value").buildJSONMessage();// 根据OAuthResponse生成ResponseEntityreturn new ResponseEntity<String>(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));}}else {System.out.println("user:"+username);System.out.println("token:"+token);System.out.println("天猫精灵授权失败");response = OAuthASResponse.tokenResponse(HttpServletResponse.SC_OK).setParam("error", "101").setParam("error_description", "内部错误").buildJSONMessage();jsonObject.put("error", 101);jsonObject.put("error_dercription", "内部错误");System.out.println(jsonObject.toString());return new ResponseEntity<String>(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));}}// 根据OAuthResponse生成ResponseEntityreturn new ResponseEntity<String>(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));} catch (OAuthSystemException e) {response = OAuthASResponse.tokenResponse(HttpServletResponse.SC_OK).setParam("error", "101").setParam("error_description", "内部错误").buildJSONMessage();jsonObject.put("error", 101);jsonObject.put("error_dercription", "内部错误");System.out.println(jsonObject.toString());return new ResponseEntity<String>(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));} catch (OAuthProblemException e) {response = OAuthASResponse.tokenResponse(HttpServletResponse.SC_OK).setParam("error", "102").setParam("error_description", "参数错误").buildJSONMessage();jsonObject.put("error", 102);jsonObject.put("error_dercription", "参数错误");System.out.println(jsonObject.toString());return new ResponseEntity<String>(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));}}/*** 设备控制与设备状态查询* http://doc-bot.tmall.com/docs/doc.htm?spm=0.7629140.0.0.21551780A5E52S&treeId=393&articleId=108268&docType=1*/@RequestMapping(value = "/combine", method = RequestMethod.POST)@ResponseBodypublic JSONObject combineDevice(HttpServletRequest request, HttpServletResponse response, BufferedReader br)throws SAXException, IOException, MqttException, InterruptedException, UnsupportedEncodingException {ServletContext context = request.getSession().getServletContext();String username = "";// 天猫精灵request的BodyString inputLine;String str = "";try {while ((inputLine = br.readLine()) != null) {str += inputLine;}br.close();} catch (IOException e) {System.out.println("IOException: " + e);}System.out.println("天猫精灵的请求体:" + str + "\n");JSONObject recieveHeader = new JSONObject();recieveHeader = JSON.parseObject(str);String str1 = recieveHeader.getString("header");String str2 = recieveHeader.getString("payload");JSONObject recieveMessageId = new JSONObject();JSONObject recievedeviceId = new JSONObject();recieveMessageId = JSON.parseObject(str1);recievedeviceId = JSON.parseObject(str2);JSONObject MerchineList = new JSONObject();// 如果请求体的accessToken与数据库的不一致,则报token错误if (userservice.SelectByToken(recievedeviceId.getString("accessToken")) == null) {return responseService.ErrorResponce(recieveMessageId, recievedeviceId);} else {System.out.println("使用token查询出来的用户名是;"+userservice.SelectByToken(recievedeviceId.getString("accessToken")));// 如果请求体的accessToken与数据库一致,则返回该token对应的用户名username = userservice.SelectByToken(recievedeviceId.getString("accessToken"));}String fileName = "/var/www/html/store/" + username + "_Devices.xml";//String fileName = "file:///F:/DSKJ_Devices.xml";AnalysisXML test = new AnalysisXML();File file = new File("/var/www/html/store/" + username + "_Devices.xml");//File file = new File("F:/DSKJ_Devices.xml");String name = recieveMessageId.getString("name");if (file.exists()) {test.setCenterID(fileName);}String topic = "MSG/" + test.getCenterID();switch (name) {case "DiscoveryDevices":// 对应:登陆天猫精灵后自动查询出的设备列表if (file.exists()) {            // 如果文件是真实存在的,再进行XML解析List<Device> Devices = deviceservice.AnalysisXML(fileName);MerchineList = responseService.DeviceResponce(recieveMessageId, Devices);} else {// 如果文件是不存在的,提供写死的test数据MerchineList = responseService.WritedeadResponce();}return MerchineList;case "TurnOn":// 对应:天猫精灵,打开某某设备System.out.println("进入了打开");MerchineList = controlService.TurnOnResponce(username, topic, recieveMessageId, recievedeviceId);return MerchineList;case "TurnOff":// 对应:天猫精灵,关闭某某设备MerchineList = controlService.TurnOffResponce(username, topic, recieveMessageId, recievedeviceId);return MerchineList;case "Pause":// 对应:天猫精灵,窗帘暂停MerchineList = controlService.PauseResponce(username, topic, recieveMessageId, recievedeviceId);return MerchineList;case "SetBrightness":// 对应:天猫精灵,调节灯光亮度String value = recievedeviceId.getString("value");String setValue = value;if (!(value.equals("max") || value.equals("min"))) {if (Integer.parseInt(value) > 100 || Integer.parseInt(value) < 0) {MerchineList = responseService.ParamsErrorResponce(recieveMessageId, recievedeviceId);return MerchineList;}}MerchineList = controlService.SetBrightnessResponce(setValue, username, topic, recieveMessageId,recievedeviceId);return MerchineList;case "SetTemperature":// 对应:天猫精灵,调节空调温度String value2 = recievedeviceId.getString("value");String setValue2 = value2;if (!(value2.equals("max") || value2.equals("min"))) {if (Integer.parseInt(value2) > 32 || Integer.parseInt(value2) < 16) {MerchineList = responseService.ParamsErrorResponce(recieveMessageId, recievedeviceId);return MerchineList;}}MerchineList = controlService.SetTemperatureResponce(setValue2, username, topic, recieveMessageId,recievedeviceId);return MerchineList;case "Query":// 对应:天猫精灵,查询空调状态MerchineList = controlService.QueryResponce(topic, recieveMessageId, recievedeviceId);return MerchineList;case "SetMode":// 对应:天猫精灵,将空调调到某某模式MerchineList = controlService.SetModeResponce(username, topic, recieveMessageId, recievedeviceId);return MerchineList;case "SetWindSpeed":// 对应:天猫精灵,空调风速调到某风MerchineList = controlService.SetWindSpeedResponce(username, topic, recieveMessageId, recievedeviceId);return MerchineList;case "AdjustUpTemperature":// 对应:天猫精灵,空调温度调高一点MerchineList = controlService.AdjustUpTemperatureResponce(username, topic, recieveMessageId,recievedeviceId);return MerchineList;case "AdjustDownTemperature":// 对应:天猫精灵,空调温度调低一点MerchineList = controlService.AdjustDownTemperatureResponce(username, topic, recieveMessageId,recievedeviceId);return MerchineList;case "AdjustUpWindSpeed":// 对应:天猫精灵,空调风速调高一点MerchineList = controlService.AdjustUpWindSpeedResponce(username, topic, recieveMessageId, recievedeviceId);return MerchineList;case "AdjustDownWindSpeed":// 对应:天猫精灵,空调风速调低一点MerchineList = controlService.AdjustDownWindSpeedResponce(username, topic, recieveMessageId,recievedeviceId);return MerchineList;default:return MerchineList;}}
}

java对接天猫精灵语音助手实现对公司其下的智能设备进行控制(附上源码)相关推荐

  1. 【TB-02模组专题②】学习如何对接天猫精灵语音控制的过程;

    本<安信可ble mesh蓝牙模组TB-02模组专题>系列博客学习由官方博客 CSDN安信可博客 潜心所力所写.如有不对之处,请留言,我们及时更改. 1.BLE MESH开发环境linux ...

  2. 【esp8266】③esp8266对接天猫精灵实现语音控制

    源码github地址:https://github.com/linzhongpaihuai/smartplug ①烧录方法:https://blog.csdn.net/u010177891/artic ...

  3. 【阿里云生活物联网架构师专题 ①】esp32 sdk 直连接入阿里云物联网平台,实现天猫精灵语音控制;

    本系列博客学习由非官方人员 半颗心脏 潜心所力所写,仅仅做个人技术交流分享,不做任何商业用途.如有不对之处,请留言,本人及时更改. 1.esp32接入阿里云物联网平台,实现天猫精灵语音控制: 2.es ...

  4. Esp8266进阶之路11 企业者的福音之8266接入阿里智能,点亮一盏LED灯,期待天猫精灵语音控制的不约而至!

    本系列博客学习由非官方人员 半颗心脏 潜心所力所写,不做开发板.仅仅做个人技术交流分享,不做任何商业用途.如有不对之处,请留言,本人及时更改. 序号 SDK版本 内容 链接 1 nonos2.0 搭建 ...

  5. Alios-Thins教程连载 ④ 图文并茂教你使用乐鑫esp8266轻松连接阿里飞燕平台,个人设备实现轻松对接天猫精灵 。(下篇)(附带demo)

    本系列博客学习由非官方人员 半颗心脏 潜心所力所写,仅仅做个人技术交流分享,不做任何商业用途.如有不对之处,请留言,本人及时更改. 1. 如何搭建阿里开源系统Alios-Things环境,烧录到乐鑫e ...

  6. ESP8266AT指令接入阿里飞燕 , 轻松天猫精灵语音控制单片机;

    安信可ESP-12S AT指令接入阿里飞燕,轻松天猫精灵语音控制单片机 文章目录 一,前言 二,准备工作 三,后台三元组获取 四,云端设备建立 五,终端节点的配置 一,前言 阿里飞燕的需求越来越多,包 ...

  7. 对接天猫精灵X1 (https 的申请)

    1 起因 公司是做智能家居的,最近公司要求对接天猫精灵的智能家居功能,所以就来对接天猫精灵X1 了. 新产品,大家都懂的,坑是有不少的,正常事. 1 首先,语言是 c#,不要和我讲 php 是世界最好 ...

  8. 【蓝牙Mesh笔记 ①】ESP32-C3 模组上实现天猫精灵蓝牙 BLE Mesh AliGenie 接入,无需WiFi 连接也可以实现天猫精灵语音控制。

    本系列博客学习由非官方人员 半颗心脏 潜心所力所写,仅仅做个人技术交流分享,不做任何商业用途.如有不对之处,请留言,本人及时更改. 系列一:ESP32系列模组基础学习系列笔记 1. 爬坑学习新旅程,虚 ...

  9. 【小白之路-1】详解ESP8266 ESP-01SRealy继电器模块天猫精灵语音控制实现(含微信配网及新手防坑提示)

    ESP8266-ESP-01S 前言 一.预期功能 二.功能逐步实现 1. 端口控制实现 2. WiFi联网 3. 天猫精灵接入(小爱.小度同理) 4. APP界面控件编辑 三.防坑提示 1.管脚编号 ...

最新文章

  1. oracle分组聚合查询,Oracle中分组查询group by用法规则解析
  2. SAP UI5 应用开发教程之五十六 - SAP UI5 树控件(tree)的开发
  3. Oracle命令--alter 操作
  4. HDU - 7054 Yiwen with Formula 分治拆位FFT + dp + 费马小定理降幂
  5. [HAOI2016]字符合并(ing)
  6. java创建一个成员方法吗,java构造方法和成员方法的区别
  7. 算法不会,尚能饭否之对分查找二叉树(又为快速排序之二叉树实现)
  8. Apache查看并发及TIME_WAIT过多的解决
  9. 上海戏剧学院开学计算机考试,2021年上海戏剧学院大一新生转专业及入学考试相关规定...
  10. Linux文件系统的创建与管理(上)
  11. 在惠普BL460C G1上安装System Management Homepage(CentO...
  12. html vba 单元格 格式,VBA设置单元格格式之——边框
  13. 【modelarts】华为人工智能平台_modelarts平台系列教程1
  14. 有线网络、无线网络、蜂窝网络、移动网络到底是啥?
  15. 农历和阳历日期互转,Python实现
  16. [STM32]记录一个低功耗的怪异现象
  17. L1-054 福到了(15 分)
  18. LogMeIn软件介绍
  19. 001-TensorFlow 2.0 教程-Transformer
  20. python写的程序怎么打包手机app_Python Kivy(App开发) Windows安装打包步骤

热门文章

  1. 漫谈CRM体系化建设2 – 如何开发客户?
  2. 一分钟解决你的公有云私有云选择困难症
  3. OL3-Cesium 二三维鼠标事件统一处理
  4. Android 圆形头像实现
  5. Android 蓝色光滤波器(护眼神器) 反编译
  6. 计算机地图制图pdf,《计算机地图制图》课件简介.pdf
  7. 【转】胡侃学习(理论)计算机
  8. 海思3559AV100 HiSysLink 之 IPCMSG
  9. OpenCV入门到进阶:实战三大典型项目(更新至12) IT自学视频教程
  10. 00后php团队,00后学霸团队自制视频脱口秀走红:不想做网红