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 {
@Resource
public userService userservice;
@Resource
public deviceService deviceservice;
@Resource
public MqttMessageService mqttService;
@Resource
public ResponseService responseService;
@Resource
public 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 Token
oauthIssuerImpl = 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生成ResponseEntity
return new ResponseEntity<String>(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));
}else if(token!=null) { //天猫主动刷新授权
System.out.println("授权过期 天猫精灵自动获取授权!");
Token userToken=userservice.SelectToken(token); //凭着带过来的token
if(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生成ResponseEntity
return new ResponseEntity<String>(response.getBody(), HttpStatus.valueOf(response.getResponseStatus()));
}else {//生成新的token 返回给天猫精灵
// 生成Access Token
oauthIssuerImpl = 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生成ResponseEntity
return 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生成ResponseEntity
return 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)
@ResponseBody
public JSONObject combineDevice(HttpServletRequest request, HttpServletResponse response, BufferedReader br)
throws SAXException, IOException, MqttException, InterruptedException, UnsupportedEncodingException {
ServletContext context = request.getSession().getServletContext();
String username = "";
// 天猫精灵request的Body
String 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;
}
}
}