一直都想着做接口自动化测试,乘项目空闲时间研究了下。由于公司使用的是http协议,可使用httpclient做。
总体代码架构如下:
myConfigureFile为配置文件,JDBC为操作数据库部分,buddy.AccountTestCase为项目中一个模块的测试用例。
1、httpclient的使用
共有四种请求方式,分别是:get、post、put、delete
对其进行封装,代码如下:
package com.myConfigureFile;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.junit.Test;
public class httpclienttest2 extends configureFile{
public static String testpost(String url,Map<String,String> params) {
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpPost httppost = new HttpPost(url);
String data = null;
httppost.setHeader("Content-Type", "application/json");
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
Set<String> keySet = params.keySet();
for(String key : keySet) {
formparams.add(new BasicNameValuePair(key, params.get(key)));
}
UrlEncodedFormEntity uefEntity;
try {
uefEntity = new UrlEncodedFormEntity(formparams, "UTF-8"); //Accept-Language: zh-Hans-CN;q=1 Accept-Encoding: gzip, deflate
httppost.setEntity(uefEntity);
System.out.println("executing request " + httppost.getURI());
CloseableHttpResponse response = httpclient.execute(httppost);
try {
HttpEntity entity = response.getEntity();
if (entity != null) {
System.out.println("--------------------------------------");
data=EntityUtils.toString(entity, "UTF-8");
//
//System.out.println("Response content: " + EntityUtils.toString(entity, "UTF-8"));
System.out.println("--------------------------------------");
}
} finally {
response.close();
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
httpclient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return data;
}
public static String testget(String url) {
CloseableHttpClient httpclient = HttpClients.createDefault();
String data = null;
try {
HttpGet httpget = new HttpGet(url);
System.out.println("executing request " + httpget.getURI());
CloseableHttpResponse response = httpclient.execute(httpget);
try {
HttpEntity entity = response.getEntity();
System.out.println("--------------------------------------");
System.out.println(response.getStatusLine());
if (entity != null) {
System.out.print("-----------------get--------------");
System.out.println("Response content length: " + entity.getContentLength());
data = EntityUtils.toString(entity);
System.out.println("Response content: " + data);
}
System.out.println("------------------------------------");
} finally {
response.close();
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
httpclient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return data;
}
public static String testput(String url,Map<String,String> params){
String data = null;
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpPut httpput = new HttpPut(url);
httpput.setHeader("Content-Type", "application/json");
List<NameValuePair> formparams = new ArrayList<NameValuePair>();
Set<String> keySet = params.keySet();
for(String key : keySet) {
formparams.add(new BasicNameValuePair(key, params.get(key)));
}
UrlEncodedFormEntity uefEntity;
try {
uefEntity = new UrlEncodedFormEntity(formparams, "UTF-8"); //Accept-Language: zh-Hans-CN;q=1 Accept-Encoding: gzip, deflate
httpput.setEntity(uefEntity);
System.out.println("executing request " + httpput.getURI());
CloseableHttpResponse response = httpclient.execute(httpput);
try {
HttpEntity entity = response.getEntity();
if (entity != null) {
System.out.println("--------------------------------------");
data=EntityUtils.toString(entity, "UTF-8");
//System.out.println("Response content: " + EntityUtils.toString(entity, "UTF-8"));
System.out.println("--------------------------------------");
}
} finally {
response.close();
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
httpclient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return data;
}
public String httpdelete(String url){
CloseableHttpClient httpclient = HttpClients.createDefault();
String data = null;
try {
HttpDelete httpdelete = new HttpDelete(url);
System.out.println("executing request " + httpdelete.getURI());
CloseableHttpResponse response = httpclient.execute(httpdelete);
try {
HttpEntity entity = response.getEntity();
System.out.println("--------------------------------------");
System.out.println(response.getStatusLine());
if (entity != null) {
System.out.println("Response content length: " + entity.getContentLength());
data = EntityUtils.toString(entity);
System.out.println("Response content: " + data);
}
System.out.println("------------------------------------");
} finally {
response.close();
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
httpclient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return data;
}
public void testcase(){
String url="http://app.personbuddy.com:8080/api/devices/133790246811208/contacts?access_token=7efbe5bd-7add-4c36-bbf8-c467cc1cacf8&userId=efe27a5d24fb4360a7874717030e086a";
Map<String,String> parms =new HashMap<String, String>();
parms.put("name", "妈妈");
parms.put("avatar", "2");
parms.put("relation", "2");
parms.put("isSos", "true");
parms.put("mobile", "15088132089");
testpost(url,parms);
}
}
2、mysql的使用
由于想着低耦合性,特封装为一个模块。
model包下为数据库表结构;Dao包下为中间件,主要作用是加载数据库,并提供对外接口连接数据库;controller包下为提供对外接口操作数据库表。
具体模型结构如下:
1)model下的数据表结构
package com.JDBC.model;
import java.sql.Date;
import org.omg.CORBA.PRIVATE_MEMBER;
public class interfaceTestreport {
private Integer id;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTestmodule() {
return testmodule;
}
public void setTestmodule(String testmodule) {
this.testmodule = testmodule;
}
public String getCases() {
return cases;
}
public void setCases(String cases) {
this.cases = cases;
}
public String getInterfacedesc() {
return interfacedesc;
}
public void setInterfacedesc(String interfacedesc) {
this.interfacedesc = interfacedesc;
}
public String getExpectedresult() {
return expectedresult;
}
public void setExpectedresult(String expectedresult) {
this.expectedresult = expectedresult;
}
public String getFlatexplain() {
return flatexplain;
}
public void setFlatexplain(String flatexplain) {
this.flatexplain = flatexplain;
}
public String getCreatedBy() {
return createdBy;
}
public void setCreatedBy(String createdBy) {
this.createdBy = createdBy;
}
public Date getTesttime() {
return testtime;
}
public void setTesttime(Date testtime) {
this.testtime = testtime;
}
private String testmodule;
private String cases;
private String interfacedesc;
private String expectedresult;
private String flatexplain;
private String createdBy;
private Date testtime;
private String testversion;
private String testresult;
public String getTestresult() {
return testresult;
}
public void setTestresult(String testresult) {
this.testresult = testresult;
}
public String getTestversion() {
return testversion;
}
public void setTestversion(String testversion) {
this.testversion = testversion;
}
}
2)Dao下连接数据库代码:
package com.JDBC.Dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
public class DBUtil {
private static final String URL="jdbc:mysql://127.0.0.1:3306/zentao";
private static final String NAME="root";
private static final String PASSWORD="O0Vkki1Un0W";
private static Connection conn=null;
//静态代码块(将加载驱动、连接数据库放入静态块中)
static{
try {
//1.加载驱动程序
Class.forName("com.mysql.jdbc.Driver");
//2.获得数据库的连接
conn = DriverManager.getConnection(URL, NAME, PASSWORD);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
//对外提供一个方法来获取数据库连接
public static Connection getConnection(){
return conn;
}
}
3)controller下操作数据库表
package com.JDBC.controller;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import com.JDBC.Dao.DBUtil;
import com.JDBC.model.interfaceTestreport;
//import com.JDBC.model.myTestreoprt;
import com.myConfigureFile.configureFile;
import com.mysql.fabric.xmlrpc.base.Data;
public class interfaceTestreportAction {
String testversion=new configureFile().getTestversion();
String version=new configureFile().getTestversion();
// String testresult=mcon.getTestresult();
/**
* 添加数据
* @param myinterfaceTestreport 要添加的数据对象
* @throws Exception
*/
public void addmyTestreport(interfaceTestreport myinterfaceTestreport) throws Exception{
Connection con=DBUtil.getConnection();//首先拿到数据库的连接
String sql="" +
"insert into interfacetestreport"+
"(testmodule,cases,interfacedesc,testversion,interfaceresult,"+
"expectedresult,flatexplain,createdBy,testtime) "+
"values("+
"?,?,?,?,?,?,?,?,current_date())";//参数用?表示,相当于占位符;用mysql的日期函数current_date()来获取当前日期
//预编译sql语句
PreparedStatement psmt = con.prepareStatement(sql);
//先对应SQL语句,给SQL语句传递参数
// psmt.setInt(0, myinterfaceTestreport.getId());
psmt.setString(1, myinterfaceTestreport.getTestmodule());
psmt.setString(2, myinterfaceTestreport.getCases());
psmt.setString(3, myinterfaceTestreport.getInterfacedesc());
psmt.setString(4, myinterfaceTestreport.getTestversion());
psmt.setString(5, myinterfaceTestreport.getTestresult());
psmt.setString(6, myinterfaceTestreport.getExpectedresult());
psmt.setString(7, myinterfaceTestreport.getFlatexplain());
// psmt.setString(8, myinterfaceTestreport.getCreatedBy());
psmt.setDate(8, new Date(myinterfaceTestreport.getTesttime().getTime()));
//执行SQL语句
psmt.execute();
/**
* prepareStatement这个方法会将SQL语句加载到驱动程序conn集成程序中,但是并不直接执行
* 而是当它调用execute()方法的时候才真正执行;
*
* 上面SQL中的参数用?表示,相当于占位符,然后在对参数进行赋值。
* 当真正执行时,这些参数会加载在SQL语句中,把SQL语句拼接完整才去执行。
* 这样就会减少对数据库的操作
*/
}
//更新
public void updateInterfaceTestReport(interfaceTestreport mtest) throws SQLException{
Connection con=DBUtil.getConnection();//首先拿到数据库的连接
String sql="" +
"update interfacetestreport "+
"set testmodule=?,sex=?,age=?,birthday=?,email=?,mobile=?,"+
"update_user=?,update_date=current_date(),isdel=?) "+
"where id=?";//参数用?表示,相当于占位符;用mysql的日期函数current_date()来获取当前日期
//预编译sql语句
PreparedStatement psmt = con.prepareStatement(sql);
//先对应SQL语句,给SQL语句传递参数
psmt.setInt(1, mtest.getId());
/* psmt.setInt(2, g.getSex());
psmt.setInt(3, g.getAge());
//注意:setDate()函数第二个参数需要的是java.sql.Date类型,我们传进来的是java.util.Date,类型不符,需要做一下转换
psmt.setDate(4, new Date(g.getBirthday().getTime()));
psmt.setString(5, g.getEmail());
psmt.setString(6, g.getMobile());
psmt.setString(7, g.getUpdateUser());
psmt.setInt(8, g.getIsDel());
psmt.setInt(9, g.getId());*/
//执行SQL语句
psmt.execute();
}
//删除
public void delmytestreport(Integer id) throws SQLException{
Connection con=DBUtil.getConnection();//首先拿到数据库的连接
String sql="" +
"delete from interfacetestreport "+
"where id=?";//参数用?表示,相当于占位符;用mysql的日期函数current_date()来获取当前日期
//预编译sql语句
PreparedStatement psmt = con.prepareStatement(sql);
//先对应SQL语句,给SQL语句传递参数
psmt.setInt(1, id);
//执行SQL语句
psmt.execute();
}
//查询单个(根据id去查询)
public interfaceTestreport get(Integer id) throws SQLException{
interfaceTestreport mtest=null;
Connection con=DBUtil.getConnection();//首先拿到数据库的连接
String sql="" +
"select * from interfacetestreport "+
"where id=?";//参数用?表示,相当于占位符;用mysql的日期函数current_date()来获取当前日期
//预编译sql语句
PreparedStatement psmt = con.prepareStatement(sql);
//先对应SQL语句,给SQL语句传递参数
psmt.setInt(1, id);
//执行SQL语句
/*psmt.execute();*///execute()方法是执行更改数据库操作(包括新增、修改、删除);executeQuery()是执行查询操作
ResultSet rs = psmt.executeQuery();//返回一个结果集
//遍历结果集
while(rs.next()){
mtest=new interfaceTestreport();
mtest.setId(rs.getInt("id"));
/* g.setUserName(rs.getString("user_name"));
g.setAge(rs.getInt("age"));
g.setSex(rs.getInt("sex"));
//rs.getDate("birthday")获得的是java.sql.Date类型。注意:java.sql.Date类型是java.util.Date类型的子集,所以这里不需要进行转换了。
g.setBirthday(rs.getDate("birthday"));
g.setEmail(rs.getString("email"));
g.setMobile(rs.getString("mobile"));
g.setCreateUser(rs.getString("create_user"));
g.setCreateDate(rs.getDate("create_date"));
g.setUpdateUser(rs.getString("update_user"));
g.setUpdateDate(rs.getDate("update_date"));
g.setIsDel(rs.getInt("isdel"));*/
}
return mtest;
}
//查询单个(根据姓名等信息去查询)----->使用Map存储条件信息;防止条件为空可加一条where 1=1
public List<interfaceTestreport> get(List<Map<String, Object>> params) throws SQLException{
List<interfaceTestreport> result=new ArrayList<interfaceTestreport>();
Connection con=DBUtil.getConnection();//首先拿到数据库的连接
StringBuffer sb=new StringBuffer();
sb.append("select * from imooc_goddess where 1=1 ");//注意where 1=1 的小技巧
if(params !=null && params.size()>0){//先判断集合是否为空
//遍历集合
for(int i=0;i<params.size();i++){
Map<String, Object> map=params.get(i);
sb.append("and "+map.get("name")+" " +map.get("rela")+" "+map.get("value")+" ");//查询什么?关系是什么?以及值是什么,我们都可以通过参数传进来。
}
}
//预编译sql语句
PreparedStatement psmt = con.prepareStatement(sb.toString());
System.out.println(sb.toString());
//执行SQL语句
/*psmt.execute();*///execute()方法是执行更改数据库操作(包括新增、修改、删除);executeQuery()是执行查询操作
ResultSet rs = psmt.executeQuery();//返回一个结果集
interfaceTestreport g=null;
//遍历结果集
while(rs.next()){
g=new interfaceTestreport();
/* g.setId(rs.getInt("id"));
g.setUserName(rs.getString("user_name"));
g.setAge(rs.getInt("age"));
g.setSex(rs.getInt("sex"));
//rs.getDate("birthday")获得的是java.sql.Date类型。注意:java.sql.Date类型是java.util.Date类型的子集,所以这里不需要进行转换了。
g.setBirthday(rs.getDate("birthday"));
g.setEmail(rs.getString("email"));
g.setMobile(rs.getString("mobile"));
g.setCreateUser(rs.getString("create_user"));
g.setCreateDate(rs.getDate("create_date"));
g.setUpdateUser(rs.getString("update_user"));
g.setUpdateDate(rs.getDate("update_date"));
g.setIsDel(rs.getInt("isdel"));*/
result.add(g);//将结果封装到对象中
}
return result;
}
@Test
public void testrep(){
testAddInterfaceTestReport("testmodule", "cases", "interfacedesc", "testresult", "flatexplain");
}
public void testAddInterfaceTestReport(String testmodule,String cases,String interfacedesc,String testresult,String flatexplain){
interfaceTestreportAction mtestreportAct=new interfaceTestreportAction();
interfaceTestreport mtereport=new interfaceTestreport();
//mtereport.setId();
mtereport.setTestmodule(testmodule);
mtereport.setCases(cases);
mtereport.setInterfacedesc(interfacedesc);
mtereport.setTestresult(testresult);
//mtereport.setTesttime(new Date(mtereport.getTesttime().getTime()));
mtereport.setTestversion(testversion);
//System.err.println("-testversion----"+testversion);
mtereport.setTesttime(new Date(System.currentTimeMillis()));
//System.out.println("-------写入成功"+new Date(System.currentTimeMillis()).);
Date date=new Date(System.currentTimeMillis());
DateFormat df1 = DateFormat.getDateInstance();//日期格式,精确到日
System.out.println("----"+df1.format(date));
DateFormat df2 = DateFormat.getDateTimeInstance();//可以精确到时分秒
System.out.println("----"+df2.format(date));
DateFormat df3 = DateFormat.getTimeInstance();//只显示出时分秒
System.out.println("----"+df3.format(date));
try {
mtestreportAct.addmyTestreport(mtereport);
System.out.println("-------写入成功");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.out.println("--------------"+e.toString());
}
}
}
3、写测试用例
这里使用Java自带的junit执行测试用例。
package com.buddy.AccountTestcase;
import java.sql.Date;
import java.text.DateFormat;
import java.util.HashMap;
import java.util.Map;
import org.junit.Test;
import com.JDBC.controller.interfaceTestreportAction;
import com.myConfigureFile.configureFile;
import com.myConfigureFile.httpclienttest2;
public class habitsTestcase {
configureFile mcon=new configureFile();
httpclienttest2 mhttp=new httpclienttest2();
interfaceTestreportAction mrepAct=new interfaceTestreportAction();
String burl=mcon.getdeviceIdbUrl();
String access_token=mcon.getaccess_token();
String userId=mcon.getuserId();
String testparam = null;//接口参数说明
String flatexplain=mcon.getFlatexplain();
/* 此接口用于根据分类获取今天习惯和未订阅习惯列表。
请求方法
GET
请求地址
http://x.x.x.x/api/devices/{deviceId}/habits/today?access_token=xxx&userId=xxx
习惯分类 category
1:好习惯提醒
2:能力提升
此接口根据分类用于获取已订阅和未添加的习惯列表。
请求方法
GET
请求地址
http://x.x.x.x/api/devices/{deviceId}/habits?access_token=xxx&userId=xxx
*/
@Test
public void testhabits(){
String category="1";
String gethabitstoday="/habits/today";
String gethabitsall="/habits";
String urlswitch = null;
String flag="0";
if(flag=="0"){
String testmodule="8.1测试用例:分类获取今天习惯和未订阅习惯列表。";
System.out.print("测试用例:分类获取今天习惯和未订阅习惯列表。");
for(int i=0;i<2;i++){
urlswitch=gethabitstoday;
String url=burl+urlswitch+"?access_token="+access_token+"&"+"userId="+userId+"&category="+category;
String data=mhttp.testget(url);
//System.out.print(data);
mrepAct.testAddInterfaceTestReport(testmodule, url, testparam, data, flatexplain);
//mrepAct.addmyTestreport(myinterfaceTestreport)
if(category=="1"){
category="2";
}
}
flag="1";
}else{
urlswitch=gethabitsall;
System.out.print("测试用例:测试分类获取所有习惯和未订阅习惯列表。");
String testmodule="8.2测试用例:分类获取所有习惯和未订阅习惯列表。";
for(int i=0;i<3;i++){
switch(i){
case 0:
category="0";
break;
case 1:
category="1";
break;
case 2:
category="2";
break;
default:
break;
}
testparam=category;
flatexplain="category=0:所有;category=1:习惯;category=2:能力";
urlswitch=gethabitstoday;
String url=burl+urlswitch+"?access_token="+access_token+"&"+"userId="+userId+"category="+category;
//mhttp.testget(url);
String data=mhttp.testget(url);
mrepAct.testAddInterfaceTestReport(testmodule, url, testparam, data, flatexplain);
}
}
}
/*此接口用于获取习惯详情。
请求方法
GET
请求地址
http://x.x.x.x/api/devices/{deviceId}/habits/info?access_token=xxx&userId=xxx
deviceId String 是 设备ID
userId String 是 用户ID
habitId Long 是 习惯ID
flag Integer 是 标记
0:添加
1:修改
*/
@Test
public void testhabitsinfo(){
Long habitId = null;
String flag="0";
String testmodule="8.3测试用例:测试获取习惯详情";
flatexplain="flag=0:添加习惯;flag=1:修改习惯";
System.out.print("测试用例:测试获取习惯详情。");
for(int i=0;i<2;i++){
String url=burl+"/habits/info?"+"access_token="+access_token+"&"+"userId="+userId+"habitId="+habitId+"flag="+flag;
String data=mhttp.testget(url);
mrepAct.testAddInterfaceTestReport(testmodule, url, testparam, data, flatexplain);
if(flag=="0"){
flag="1";
}else{
flag="0";
}
}
}
/*此接口用于获取习惯内容铃声;如果是添加习惯,第一个铃声为默认播放铃声。
请求方法
GET
请求地址
http://x.x.x.x/api/devices/{deviceId}/habits/voice?access_token=xxx&userId=xxx
deviceId String 是 设备ID
userId String 是 用户ID
contentId Long 是 内容ID
*/
@Test
public void testhabitsvoice(){
Long contentId = null;
String testmodule="8.4测试用例:测试用于获取习惯内容铃声;如果是添加习惯,第一个铃声为默认播放铃声。";
System.out.print("测试用例:测试用于获取习惯内容铃声;如果是添加习惯,第一个铃声为默认播放铃声。");
String url=burl+"/habits/voice?access_token="+access_token+"&"+"userId="+userId+"contentId="+contentId;
String data=mhttp.testget(url);
mrepAct.testAddInterfaceTestReport(testmodule, url, testparam, data, flatexplain);
}
/*此接口根据分类用于获取历史任务列表。
请求方法
GET
请求地址
http://x.x.x.x/api/devices/{deviceId}/habits/history?access_token=xxx&userId=xxx
deviceId String 是 设备ID
userId String 是 用户ID
playDate String 是 播放日期(格式:yyyy-MM-dd)
category Integer 是 习惯分类
1:好习惯提醒
2:能力提升
*/
@Test
public void testhabitshistory(){
Date date=new Date(System.currentTimeMillis());
DateFormat df1 = DateFormat.getDateInstance();//日期格式,精确到日
System.out.println("----"+df1.format(date));
String playDate = df1.format(date);
String category="0";
for(int i=0;i<2;i++){
System.out.print("8.5测试用例:测试用于获取历史任务列表。");
String testmodule="8.5测试用例:测试用于获取历史任务列表。";
String url=burl+"/habits/history?access_token"+access_token+"&"+"userId="+userId+"playDate="+playDate+"category="+category;
String data=mhttp.testget(url);
mrepAct.testAddInterfaceTestReport(testmodule, url, testparam, data, flatexplain);
/* if(category=="1"){
category="2";
}else{
category="1";
}*/
}
}
/* 此接口用于管理员给设备订阅习惯,并且可以定义相关参数。
请求方法
POST
请求地址
http://x.x.x.x/api/devices/{deviceId}/habits/subscribe?access_token=xxx&userId=xxx
{
"habitId":8,
"playFlag":1,
"playTime":"21:30",
"voiceType":1,
"repeatExpression":"0111110"
}
*/