微信开发

package com.ys.zhenlian.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.ys.zhenlian.bean.*;
import com.ys.zhenlian.entity.*;
import com.ys.zhenlian.service.AccessTokenService;
import com.ys.zhenlian.service.TeacherService;
import com.ys.zhenlian.service.UserService;
import com.ys.zhenlian.service.ZhenLianService;
import com.ys.zhenlian.util.*;
import com.ys.zhenlian.util.voiceTools.entity.TranslateResult;
import com.ys.zhenlian.util.voiceTools.entity.XunfeiRequest;
import com.ys.zhenlian.util.voiceTools.tools.Consts;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.security.NoSuchAlgorithmException;
import java.util.*;

/**
 * 微信验证,获取token控制器
 * Created by DELL on 2017/11/30.
 */
@Controller
@RequestMapping("/service/weixin")
public class WeiXinValidateController extends BaseController {

    private final Logger log = LoggerFactory.getLogger(this.getClass());
//    public long timeLose;

    @Value("${accessTokenVersion}")
    private Integer accessTokenVersion;
    @Value("${baseUrl}")
    private String baseUrl;
    @Value("${voicePath}")
    private String voicePath;
    @Value("${picturePath}")
    private String picturePath;
    @Value("${appid}")
    private String appid;
    @Value("${secret}")
    private String secret;
    /*打分接口 header参数*/
    @Value("${authorization}")
    private String token;
    /*打分接口 请求Url*/
    @Value("${reqUrl}")
    private String reqUrl;

    @Resource
    private UserService userService;
    @Resource
    private TeacherService teacherService;
    @Resource
    private ZhenLianService zhenLianService;
    @Resource
    private AccessTokenService accessTokenService;

    private static final Map<String, String> htmlUrl = new HashMap<String, String>();

    /**
     * 微信网页授权验证
     *
     * @param response
     * @throws Exception
     */
    @RequestMapping("/getAuthorize")
    public void getAuthorize(HttpServletRequest request, HttpServletResponse response) throws Exception {

        String rUrl = StringUtils.trim(request.getParameter("url"));
        if(rUrl != null) {
            rUrl = rUrl.replace("?from=singlemessage", "").replace("&isappinstalled=0", "");
        }
//        rUrl = rUrl.replace("?from=singlemessage", "").replace("&isappinstalled=0", "");
        String uid = UUID.randomUUID().toString();

        if (StringUtils.isNotEmpty(rUrl)){
            htmlUrl.put(uid, rUrl);
        }

        //第一步:用户同意授权,获取code
        String cbUrl = URLEncoder.encode(baseUrl + "/service/weixin/" + uid + "/index.do", "utf-8");
        String url = "https://open.weixin.qq.com/connect/oauth2/authorize?" +
                "appid=" + appid + //公众号的唯一标识
                //授权后重定向的回调链接地址,请使用urlEncode对链接进行处理,应当使用https链接来确保授权code的安全性
                "&redirect_uri=" + cbUrl +
                "&response_type=code" +//返回类型,请填写code
                //应用授权作用域:
                // 1.snsapi_base (不弹出授权页面,直接跳转,只能获取用户openid)
                // 2.snsapi_userinfo (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且,即使在未关注的情况下,只要用户授权,也能获取其信息)
                "&scope=snsapi_userinfo" +
                //非必须字段,重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节
                "&state=STATE" +
                //无论直接打开还是做页面302重定向时候,必须带此参数
                "#wechat_redirect";
        //重定向至微信验证地址
        response.sendRedirect(url);
    }


    /**
     * 根据code获取用户登陆accesstoken
     * 获取用户信息
     * 初始化教师信息
     *
     * @param request
     * @return
     * @throws Exception
     */
    @ResponseBody
    @RequestMapping("/{uid}/index")
    public Msg getToken(HttpServletRequest request, HttpServletResponse response, @PathVariable("uid")String uid) {
        try {
            String code = request.getParameter("code");

            if (code == null || code.isEmpty()) {
                log.error("获取code失败");
                return new Msg(400, "获取code失败");
            }
            log.info("获取code成功,code=" + code);

            //第二步:通过code换取网页授权access_token
            String url = "https://api.weixin.qq.com/sns/oauth2/access_token?" +
                    "appid=" + appid +
                    "&secret=" + secret +
                    "&code=" + code +
                    "&grant_type=authorization_code";

            WeiXinTokenResult tokenResult;
            String token_result = HttpUtil.sendGet(url);

            if (token_result.contains("errcode")) {
                log.error("用户token获取失败," + token_result);
                return new Msg(400, "用户token获取失败," + token_result);
            }
            Gson gson = new Gson();
            tokenResult = gson.fromJson(token_result, WeiXinTokenResult.class);
            log.info("token获取成功,token=" + tokenResult.getAccess_token());
            request.getSession().setAttribute("user_token", tokenResult);

            //第三部:获取用户信息
            UserInfo userInfo = getUser(tokenResult);
            if (userInfo == null) {
                log.error("用户信息获取失败");
                return new Msg(400, "用户信息获取失败");
            }
            //根据opeaId查询用户
            List<UserInfo> userList = userService.selectByOpeaId(userInfo.getOpenid());
            if (userList == null || userList.size() <= 0) {
                log.info("用户信息不存在,第一次登陆,开始保存用户信息");
                //保存到数据库
                int result = userService.insertByUserInfo(userInfo);
                if (result != 1) {
                    log.error("用户信息保存失败");
                    return new Msg(400, "用户信息保存失败");
                }
            } else {
                log.info(userInfo.toString());
                //更新数据库
                int result = userService.updateByOpenid(userInfo);
                if (result != 1) {
                    log.error("用户信息更新失败");
                    return new Msg(400, "用户信息更新失败");
                }
            }
            userList = userService.selectByOpeaId(userInfo.getOpenid());
            if (userList.size() != 1) {
                log.error("用户信息保存更新失败");
                return new Msg(400, "用户信息保存更新失败");
            }
            request.getSession().setAttribute("user_info", userList.get(0));

            //初始化教师信息
            List<Teacher> list = teacherService.getTeacherList();
            if (list.size() == 0) {
                log.error("获取老师信息失败");
                return new Msg(400, "获取老师信息失败");
            }
            request.getSession().setAttribute("teacher_List", list);
            log.info("教师信息初始化成功");


            String rUrl = htmlUrl.get(uid);

            if (StringUtils.isEmpty(rUrl)){
                //重定向到前台html
                response.sendRedirect(baseUrl + "/index.html");
            } else {
                htmlUrl.remove(uid);
                response.sendRedirect(rUrl);
            }


            return new Msg(200, "登陆成功");
        } catch (Exception ex) {
            log.info("登陆错误," + ex.getMessage());
            return new Msg(400, "登陆错误," + ex.getMessage());
        }
    }

    /**
     * 刷新网页token
     */
    @ResponseBody
    @RequestMapping("/refreshToken")
    public Msg refreshToken(HttpServletRequest request) {
        try {
            WeiXinTokenResult tokenResult = (WeiXinTokenResult) request.getSession().getAttribute("user_token");
            String url = "https://api.weixin.qq.com/sns/oauth2/refresh_token" +
                    "?appid=" + appid +
                    "&grant_type=refresh_token" +
                    "&refresh_token=" + tokenResult.getRefresh_token();
            String refresh_result = HttpUtil.sendGet(url);
            if (!refresh_result.contains("errcode")) {
                log.error("token刷新失败" + refresh_result);
                return new Msg(400, "token刷新失败" + refresh_result);
            }
            Gson gson = new Gson();
            tokenResult = gson.fromJson(refresh_result, WeiXinTokenResult.class);
            request.getSession().setAttribute("user_token", tokenResult);
            log.info("token刷新成功,token=" + tokenResult.getAccess_token());
            return new Msg(200, "", "token刷新成功");
        } catch (JsonSyntaxException e) {
            e.printStackTrace();
            log.error("token刷新错误," + e.getMessage());
            return new Msg(400, "token刷新错误," + e.getMessage());
        }
    }

    /**
     * 返回用户信息
     */
    @ResponseBody
    @RequestMapping("/getUserInfo")
    public Msg getUserInfo(HttpServletRequest request) {
        try {
            UserInfo userInfo = (UserInfo) request.getSession().getAttribute("user_info");
            if (userInfo == null) {
                log.error("用户信息获取失败");
                return new Msg(400, "用户信息获取失败");
            }
            return new Msg(200, userInfo);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("用户信息获取错误," + e.getMessage());
            return new Msg(400, "用户信息获取错误," + e.getMessage());
        }
    }

    /**
     * 返回用户微信信息
     */
    @ResponseBody
    @RequestMapping("/getWeixinUser")
    public Msg getWeixinUser(HttpServletRequest request) {
        try {
            WeiXinTokenResult tokenResult = (WeiXinTokenResult) request.getSession().getAttribute("user_token");
            if (tokenResult == null) {
                log.error("用户没有授权,无法获取用户微信信息");
                return new Msg(400, "用户没有授权,无法获取用户微信信息");
            }
            UserInfo userInfo = getUser(tokenResult);
            return new Msg(200, userInfo);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("获取错误," + e.getMessage());
            return new Msg(400, "获取错误," + e.getMessage());
        }
    }

    /**
     * 登陆接口(测试使用)
     *
     * @param request
     * @return
     */
    @ResponseBody
    @RequestMapping("/login")
    public Msg loginTest(HttpServletRequest request) {
        //取openid
        List<UserInfo> userInfos = userService.getOpenId();
        WeiXinTokenResult tokenResult = new WeiXinTokenResult();
        tokenResult.setOpenid(userInfos.get(0).getOpenid());
        request.getSession().setAttribute("user_token", tokenResult);
        request.getSession().setAttribute("user_info", userInfos.get(0));
        List<Teacher> list = teacherService.getTeacherList();
        if (list.size() == 0) {
            log.error("获取老师信息失败");
            return new Msg(400, "获取老师信息失败");
        }
        request.getSession().setAttribute("teacher_List", list);
        System.out.println(Charset.defaultCharset());
        log.info("登陆成功");
        return new Msg(200, "登陆成功");
    }

    /**
     * 下载用户音频,返回微信下载地址
     *
     * @param request
     * @param media_id
     * @return
     */
    @ResponseBody
    @RequestMapping("/downloadVoice")
    public Msg downloadVoice(HttpServletRequest request, Integer dialog_id, String media_id) {
        if (request.getSession().getAttribute("user_info") == null)
            return new Msg(201, "没有用户信息");
        if (dialog_id == null || dialog_id == 0)
            return new Msg(201, "缺少dialog_id参数");
        if (media_id == null || media_id.isEmpty())
            return new Msg(201, "缺少media_id参数");
            log.info("成功获得media_id,media_id为:" + media_id);
        try {
            //获取accessToken
            //需要配置(1,old;2,new)
            AccessToken accessToken = accessTokenService.getAccessToken(accessTokenVersion);
            String tokenStr =  accessToken.getAccessToken();
            log.info("成功获得tokenStr,tokenStr为:" + tokenStr);
            UserInfo userInfo = (UserInfo) request.getSession().getAttribute("user_info");

            //根据dialog_id,获取保存路径
            String voiceSavePath = zhenLianService.getVoicePath(dialog_id);
            if (voiceSavePath == null || voiceSavePath.isEmpty()) {
                log.error("找不到对话保存路径");
                return new Msg(400, "找不到对话保存路径");
            }
            //得到用户语音保存地址
            StringBuilder sb = new StringBuilder();
            voiceSavePath = sb.append(voiceSavePath).insert("download".length() + 1, "/userVoice/" + userInfo.getId()).toString();
            voiceSavePath = voiceSavePath.substring(0, voiceSavePath.lastIndexOf("/") + 1) + System.currentTimeMillis() + ".speex";
            log.info("得到用户语音保存地址:" + voiceSavePath);

            //微信下载音频url
            String url = "https://api.weixin.qq.com/cgi-bin/media/get/jssdk" +
                    "?access_token=" + tokenStr +
                    "&media_id=" + media_id;
            String path = new File(voicePath).getCanonicalPath() + voiceSavePath;
            File file = FileDownloadUtil.saveUrlAs(url, path);
            if (file == null) {
                log.error("下载失败!");
                return new Msg(400, "下载失败!");
            }
            //speex转wav
            String wavPath = path.replace(".speex", ".wav");
            VoiceUtil.speex2wav(path, wavPath);

            //获取音频时长
            int lengh = VoiceUtil.getVoiceLenWav(wavPath);
//            int lengh = VoiceUtil.getVoiceLenWavNew(wavPath);
            //音频相对路径
            String substring = voicePath.substring(voicePath.lastIndexOf("/") + 1);
            String returnPath = wavPath.substring(wavPath.lastIndexOf(substring) + substring.length());

            //保存用户音频
            log.info("保存音频前dialog_id为:"+dialog_id);
            DialogVoiceUser voiceUser = new DialogVoiceUser(dialog_id, userInfo.getOpenid(), returnPath, lengh);
            zhenLianService.insertDialogVoiceUser(voiceUser);

            //获取语音评分
//            Score score = getSpeechScore(returnPath,dialog_id);
            //获取音频路径
            String voice_path = voicePath+returnPath;
            //根据dialog_id查询语音话题ConEn
            SubjectDialog subjectDialog=zhenLianService.getSubjectDialogById(dialog_id);
            log.info("音频地址为:"+voice_path);
            log.info("文本信息为:"+subjectDialog.getConEn());
//            JSONObject score = this.getSpeechScoreData(reqUrl,voice_path,subjectDialog.getConEn());

            //TODO,获取teacher_en,直接数据库获取
            String teacher_en = "";
            teacher_en = zhenLianService.getTeacherEnByDialog(subjectDialog.getId());
            log.info("获取到老师翻译的音频为:----->"+teacher_en);
//
            //模拟数据
//                        String voice_path = "E:\wavFile\Joey.wav";
            //如果teacher_en是"",则采用con_en请求打分接口,否则用teacher_en
            JSONObject score = new JSONObject();
            if (teacher_en == null || "".equals(teacher_en)){
                score = this.getSpeechScoreData(reqUrl,voice_path,subjectDialog.getConEn());
                log.info("获取con_en值为:----->"+subjectDialog.getConEn());
                log.info("根据con_en获取的打分结果为:----->"+score.toString());
            }else {
                score = this.getSpeechScoreData(reqUrl,voice_path,teacher_en);
            }
            //获取语音评分
            BigDecimal speechScore=BigDecimal.ZERO;//语音评分
            //用于存放语音打分数据
            String speech_score_msg = "";
            log.info("打分详情信息为:"+score);
            log.info("请求之前音频得分为:------"+score.get("score"));
            if(null != score){
//                speechScore=new BigDecimal(score.getFinalScore()*100);
                //如果err_code不等于空,这段音频则为无效数据
                if(score.get("err_code") != null && !"".equals(score.get("err_code").toString())){
                    log.info("无效数据!或者声音太小");
                    log.info("接口数据返回为:----"+score.toString());
                    return new Msg(401, "无效音频文件,请重新录入!");
                }
                //分数由十分制改为百分制。author(袁勋)
                if(score.get("score") != null && !"".equals(score.get("score").toString())){
                    log.info("请求之后音频得分为:------"+score.get("score").toString());
                    speechScore=new BigDecimal(Double.parseDouble(score.get("score").toString())*10);
                    if(speechScore.compareTo(BigDecimal.ZERO) <= 0){//小于等于0,得0随机分
//                        Random random=new Random();
//                        speechScore=new BigDecimal(random.nextInt(10)+30);
                        speechScore = new BigDecimal(0);
                    }
//                    else if(speechScore.compareTo(new BigDecimal(96))>0){//大于96,得96分
//                        speechScore=new BigDecimal(96);
//                    }
                }else{
//                    Random random=new Random();
//                    speechScore=new BigDecimal(random.nextInt(10)+30);
                    speechScore = new BigDecimal(0);
                }
                speechScore=speechScore.setScale(3,BigDecimal.ROUND_UP);//格式化返回0.000

//                JSONObject resultObject=JSON.parseObject(score.toString());
//                resultObject.remove("DetailResponse");//移除DetailResponse 响应详情
//                resultObject.remove("BestMatch");//移除BestMatch 批量处理详情
//                speechScoreMsg=resultObject.toJSONString();//返回评分消息
                //如果该JSON字符串字节长度超过1024,则不存入到数据库。author(袁勋)注:将该字段类型转换为text
//                if (score.toString().getBytes().length>1024){
//                    speechScoreMsg = "";
//                }
                speech_score_msg = score.toString();
            }else {
                log.error("打分接口无数据返回");
                log.info("返回的打分数据为:--->"+score.toString());
                speech_score_msg = "";
                return new Msg(400, "测评失败,请联系服务商!");
            }
            //低于30分再加30分
//            if(speechScore.compareTo(new BigDecimal(30))<0){
//                speechScore=speechScore.add(new BigDecimal(30));
//            }
            System.out.println("计算语音评分--得分:"+speechScore);
            log.info("dialog_id为:"+dialog_id);
            //保存用户对话记录
            int resultNumber = zhenLianService.saveUserDialogRecord(dialog_id, userInfo.getOpenid(), returnPath, lengh,speechScore,speech_score_msg);
            if (resultNumber == 0){
                System.out.println("====>>>>>>>  保存用户对话记录失败 <<<<<<<<====");
            }

            VoiceResult voiceResult = new VoiceResult(returnPath, lengh,speechScore);
            log.info("下载成功!用户音频地址为:" + returnPath);
            return new Msg(200, "", voiceResult);
        } catch (Exception ex) {
            ex.printStackTrace();
            log.error("下载错误!" + ex.getMessage());
            return new Msg(400, "下载错误!" + ex.getMessage());
        }
    }

    private String getTeacherConEn(String voiceSavePath) {
        //定义课程英语翻译
        String con_en= "";
//        String reqPath = voicePath + voiceSavePath;
        String reqPath = voiceSavePath;
        //请求xunfei参数设置
        XunfeiRequest xfReq = new XunfeiRequest();
        xfReq.setLanguage(Consts.Language.ENGLISH);
        xfReq.setPath(reqPath);
        //请求讯飞翻译接口
        TranslateResult translateResult = TranslateUtils.xunfei(xfReq);
        log.info("downloadVoice()---获取讯飞翻译结果translateResult :"+ translateResult.getText());
        if (translateResult.isSuccess()){
            con_en = translateResult.getText().replace("[", "").replace("]", "").replace("", "").replace(""", "");
        }else {
            con_en = "Error,this dialog is not exist !";
        }
        return con_en;
    }

    /**
     * 获取用户的语音平均评分
     *
     * @param request
     * @param lesson_id 主题ID
     * @return
     */
    @ResponseBody
    @RequestMapping("/getSpeechAvgScore")
    public Msg getSpeechAvgScore(HttpServletRequest request, Integer lesson_id) {
        if (request.getSession().getAttribute("user_info") == null)
            return new Msg(201, "没有用户信息");
        if (lesson_id == null || lesson_id == 0)
            return new Msg(201, "缺少lesson_id参数");

        try {
            //获取accessToken
            //需要配置(1,old;2,new)
            AccessToken accessToken = accessTokenService.getAccessToken(accessTokenVersion);
            String tokenStr =  accessToken.getAccessToken();
            log.info("成功获得tokenStr,tokenStr为:" + tokenStr);
            UserInfo userInfo = (UserInfo) request.getSession().getAttribute("user_info");

            //保存用户对话记录
            BigDecimal speechScore = zhenLianService.getSpeechAvgScore(lesson_id, userInfo.getOpenid());

            //百分比(超过百分之几的人)
            BigDecimal percentScore=BigDecimal.ZERO;
            if(speechScore != null){
                BigDecimal seventy=new BigDecimal(70);
                BigDecimal hundred=new BigDecimal(100);
                //scoreNumber=(平均分-70)*100/70
                BigDecimal scoreNumber=speechScore.subtract(seventy).multiply(hundred).divide(seventy,3);
                //scoreNumber=50+scoreNumber
                scoreNumber=new BigDecimal(50).add(scoreNumber);
                //如果百分比小于0,则按照0显示
                if(scoreNumber.compareTo(BigDecimal.ZERO)>0){
                    percentScore=scoreNumber;
                }
            }
            JSONObject result=new JSONObject();
            result.put("speechScore",speechScore);
            result.put("lesson_id",lesson_id);
            result.put("percentScore",percentScore);
            log.info(userInfo.getOpenid()+"用户语音平均评分为:" + speechScore);
            return new Msg(200, "", result);
        } catch (Exception ex) {
            log.error("获取用户语音评分错误:",ex);
            return new Msg(400, "获取用户语音平均评分错误!" + ex.getMessage());
        }
    }

    /**
     * 生成微信前端接口权限
     *
     * @param url
     * @return
     * @throws NoSuchAlgorithmException
     */
    @ResponseBody
    @RequestMapping("/getJsConfig")
    public String getJsConfig(String url) {
        if (url == null || url.isEmpty())
            return "wx.config(缺少url参数);";
        log.info("url获取成功,url:" + url);
        try {
            //第一步获取AccessToken
            String tokenStr;
            //获取accessToken
            AccessToken accessToken = accessTokenService.getAccessToken(accessTokenVersion);

            if (accessToken != null && System.currentTimeMillis() - accessToken.getLastTime().getTime() < 7200000) {
                tokenStr = accessToken.getAccessToken();
            } else {
                log.info("accessToken不存在,或者已过期,开始获取accessToken");
                tokenStr = getAccessToken();
                if (tokenStr.isEmpty() || tokenStr.contains("失败")) {
                    log.error("access_token获取失败," + tokenStr);
                    return "wx.config(获取access_token信息失败);";
                }
                log.info("accessToken获取成功,accessToken:" + tokenStr);
            }

            //第二步,获取jsTicket(相同的accesstoken,得到的ticket是不变的)
            String getUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket" +
                    "?access_token=" + tokenStr +
                    "&type=jsapi";
            String jsTicket_result = HttpUtil.sendGet(getUrl);
            if (!jsTicket_result.contains("ticket")) {
                log.error("获取jsTicket失败," + jsTicket_result);
                return "wx.config(获取jsTicket失败);";
            }
            Gson gson = new Gson();
            JsTicket jsTicket = gson.fromJson(jsTicket_result, JsTicket.class);
            String ticket = jsTicket.getTicket();
            log.info("jsTicket获取成功,jsTicket:" + ticket);

            //第三步,生成JS-SDK权限验证的签名
            String noncestr = WXSignatureUtil.getRandomString(16);
            log.info("noncestr获取成功,noncestr:" + noncestr);
//            String timestamp = String.valueOf(System.currentTimeMillis());
            //当前时间戳(单位秒)(去掉后三位)
            Date date = new Date();
            String timestampTemp = String.valueOf(date.getTime());
            int length = timestampTemp.length();
            String timestamp = timestampTemp.substring(0, length - 3);

            log.info("timestamp获取成功,timestamp:" + timestamp);
            //按照参数名排序,拼接成str
            String str = "jsapi_ticket=" + ticket +
                    "&noncestr=" + noncestr +
                    "&timestamp=" + timestamp +
                    "&url=" + url;
            //生成签名(签名算法)
            String signature = WXSignatureUtil.SHA1(str);
            log.info("签名:" + signature);
            //前端使用接口集合
            List<String> jsApiList = new ArrayList<>();
            jsApiList.add("onMenuShareTimeline");
            jsApiList.add("onMenuShareAppMessage");
            jsApiList.add("onMenuShareQQ");
            jsApiList.add("onMenuShareWeibo");
            jsApiList.add("previewImage");
            jsApiList.add("downloadImage");
            jsApiList.add("chooseImage");
            jsApiList.add("uploadImage");
            jsApiList.add("checkJsApi");
            jsApiList.add("startRecord");
            jsApiList.add("stopRecord");
            jsApiList.add("onVoiceRecordEnd");
            jsApiList.add("playVoice");
            jsApiList.add("pauseVoice");
            jsApiList.add("stopVoice");
            jsApiList.add("onVoicePlayEnd");
            jsApiList.add("uploadVoice");
            jsApiList.add("downloadVoice");
            jsApiList.add("translateVoice");
            jsApiList.add("hideOptionMenu");
            jsApiList.add("showOptionMenu");
            jsApiList.add("hideMenuItems");
            jsApiList.add("showMenuItems");
            jsApiList.add("hideAllNonBaseMenuItem");
            jsApiList.add("showAllNonBaseMenuItem");
            WXsignature wXsignature = new WXsignature(false, appid, timestamp, noncestr, signature, jsApiList);
            log.info("wx.config获取成功,wx.config:" + "wx.config(" + gson.toJson(wXsignature) + ");");
            return "wx.config(" + gson.toJson(wXsignature) + ");";
        } catch (Exception e) {
            log.error("wx.config(获取权限错误," + e.getMessage() + ");");
            return "wx.config(获取权限错误," + e.getMessage() + ");";
        }
    }


    /**
     * 提交用户预约
     *
     * @return
     */
    @ResponseBody
    @RequestMapping("/saveUserReservation")
    public Msg userReservation(@ModelAttribute("json") JSONObject jsonObject) {
        if (jsonObject == null || jsonObject.size() == 0) {
            log.error("缺少UserReservation对象参数");
            return new Msg(201, "缺少UserReservation对象参数");
        }
        UserReservation userReservation = JSON.toJavaObject(jsonObject, UserReservation.class);
        try {
            int result = userService.saveUserReservation(userReservation);
            if (result != 1) {
                log.error("用户预约失败");
                return new Msg(400, "用户预约失败");
            }
            log.info("用户预约成功");
            return new Msg(200, "用户预约成功");
        } catch (Exception ex) {
            log.error("用户预约错误," + ex.getMessage());
            return new Msg(400, "用户预约错误," + ex.getMessage());
        }
    }

    /**
     * 获取、刷新accessToken
     */
//    private String getAccessToken() {
//        try {
//            String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential" +
//                    "&appid=" + appid + //公众号的唯一标识;
//                    "&secret=" + secret;
//            String token_result = HttpUtil.sendGet(url);
//            if (token_result.contains("errcode")) {
//                log.error("获取、刷新accessToken失败,原因:" + token_result);
//                return token_result;
//            }
//            Gson gson = new Gson();
//            AccessTokenResult accessToken = gson.fromJson(token_result, AccessTokenResult.class);
//            String access_token = accessToken.getAccess_token();
//            log.info("获取、刷新accessToken成功,access_token:" + access_token);
//            //封装条件
//            Map<String, Object> condition = new HashMap<>();
//            condition.put("accessTokenVersion", accessTokenVersion);
//            condition.put("access_token", access_token);
//            //保存access_token(存在刷新,不存在添加)
//            accessTokenService.saveAccessToken(condition);
//            return access_token;
//        } catch (JsonSyntaxException e) {
//            e.printStackTrace();
//            log.error("获取、刷新accessToken错误," + e.getMessage());
//            return "获取、刷新accessToken错误," + e.getMessage();
//        }
//    }

    private String getAccessToken() {
        try {
            //返回值初始化
            String access_token = "";
            //根据accessTokenVersion查询access_token
            AccessToken accessToken = accessTokenService.getAccessToken(accessTokenVersion);
            access_token = accessToken.getAccessToken();
            log.info("获取的access_token为:------"+access_token);
            return access_token;
        }catch (Exception e){
            e.printStackTrace();
            log.error("获取、刷新accessToken错误," + e.getMessage());
            return "获取、刷新accessToken错误," + e.getMessage();
        }
    }

    /**
     * 获取用户信息
     *
     * @param tokenResult
     * @return
     */
    private UserInfo getUser(WeiXinTokenResult tokenResult) {
        String url = "https://api.weixin.qq.com/sns/userinfo" +
                "?access_token=" + tokenResult.getAccess_token() +
                "&openid=" + tokenResult.getOpenid() +
                "&lang=zh_CN";
        String info_result = HttpUtil.sendGet(url);
        if (info_result.contains("errcode")) {
            log.error("用户信息获取失败,原因" + info_result);
            return null;
        }
        Gson gson = new Gson();
        UserInfo userInfo = gson.fromJson(info_result, UserInfo.class);
        log.info("用户信息获取成功");
        return userInfo;
    }

    /**
     *根据语音文本进行语音评分
     * @param returnPath 文件路径
     * @param dialog_id 对话ID
     * @return score 评分
     * */
//    private Score getSpeechScore(String returnPath,Integer dialog_id){
//        try {
//            SubjectDialog subjectDialog=zhenLianService.getSubjectDialogById(dialog_id);
//            if(subjectDialog==null){
//                return null;
//            }
//            File file=new File(voicePath+returnPath);
//            InputStream stream = new FileInputStream(file);
//            String fileName = System.nanoTime() + ".wav";
//            //获取打分
////            Score score = SpeechScoreApp.getScore(subjectDialog.getConEn(), stream, fileName);
//            return score;
//        } catch (Exception ex) {
//            log.error("获取用户语音评分错误:",ex);
//            return null;
//        }
//    }


    /**
     * 用户音频打分接口
     *
     * @param request
     * @param dialog_id
     * @return
     */
    @ResponseBody
    @RequestMapping("/getUserSpeechScoreInfo")
    public Msg getUserSpeechScoreInfo(HttpServletRequest request, Integer dialog_id) {
        if (dialog_id == null || dialog_id == 0)
            return new Msg(201, "缺少dialog_id参数");
            log.info("dialog_id,dialog_id为:" + dialog_id);
        if (request.getSession().getAttribute("user_info") == null)
            return new Msg(201, "没有用户信息");
        try {
            //获取accessToken
            //需要配置(1,old;2,new)
            AccessToken accessToken = accessTokenService.getAccessToken(accessTokenVersion);
            String tokenStr =  accessToken.getAccessToken();
            log.info("成功获得tokenStr,tokenStr为:" + tokenStr);
            UserInfo userInfo = (UserInfo) request.getSession().getAttribute("user_info");

            //返回结果初始化
            JSONObject json = new JSONObject();
            //根据user的openId、dialogId查询用户音频数据
            Map<String,Object> userDialogRecord = zhenLianService.getUserDialogRecordById(dialog_id,userInfo.getOpenid());
            //获取用户音频text
            SubjectDialog subjectDialog = zhenLianService.getSubjectDialogById(dialog_id);
            json.put("speech_dialog",subjectDialog.getConEn());
                //获取用户音频的打分数据
                if (userDialogRecord != null && userDialogRecord.size() > 0){
                    //获取音频得分
                    BigDecimal speechScore = new BigDecimal(userDialogRecord.get("speech_score").toString());
                    speechScore=speechScore.setScale(0,BigDecimal.ROUND_UP);//格式化返回0
                    json.put("score",speechScore);
                    //根据得分判断返回话术
                    String speechMsg = "";
                    if (speechScore.compareTo(new BigDecimal(60)) < 0){
                        speechMsg = "学习不易,再接再厉!";
                    }
                    if (speechScore.compareTo(new BigDecimal(60)) >= 0 && speechScore.compareTo(new BigDecimal(90)) < 0){
                        speechMsg = "很不错,继续加油!";
                    }
                    if (speechScore.compareTo(new BigDecimal(90)) >= 0){
                        speechMsg = "非常赞!";
                    }
                    json.put("speech_msg",speechMsg);
                    String wavPath = userDialogRecord.get("voice_url").toString();
                    String returnPath = wavPath;
                    json.put("voice_path",returnPath);

                    JSONObject voiceData = new JSONObject();
                    //标红单词列表初始化
                    JSONArray errArray = new JSONArray();

                    //TODO,获取teacher_en,直接数据库获取
                    String teacher_en = "";
                    teacher_en = zhenLianService.getTeacherEnByDialog(subjectDialog.getId());

                    //如果音频数据不为空,则取数据返回
                    if(userDialogRecord.get("speech_score_msg") != null && !"".equals(userDialogRecord.get("speech_score_msg"))){
                        String speechJson = userDialogRecord.get("speech_score_msg").toString();
                        log.info("获取的userDialogJson数据为:-------"+speechJson);
                        if (teacher_en != null){
                            json.put("teachen_cn",teacher_en);//返回老师的音频翻译
                        }else {
                            json.put("teachen_cn","");
                        }
                        voiceData = JSONObject.parseObject(speechJson);
                        //如果err_code不等于空,这段音频则为无效数据
                        if(voiceData.get("err_code") != null && !"".equals(voiceData.get("err_code").toString())){
                            log.info("无效数据!或者声音太小");
                            log.info("接口数据返回为:----"+voiceData.toString());
                            return new Msg(401, "无效音频文件,请重新录入!");
                        }
                        getErrorWordsJarray(voiceData, errArray);
                    }else {
                        //如果用户的返回数据为空,则请求打分接口获取数据返回
                        //获取音频路径
                        String voice_path = voicePath+wavPath;
                        //根据dialog_id,获取保存路径
                        String teacher_voice = "";
                        if (teacher_en != null){
                            json.put("teachen_cn",teacher_en);//返回老师的音频翻译
                        }else {
                            json.put("teachen_cn","");
                        }
                        //模拟数据
//                        String voice_path = "E:\wavFile\Joey.wav";

                        //请求声讯科技打分接口
//                        JSONObject speech_score_data = this.getSpeechScoreData(reqUrl,voice_path,subjectDialog.getConEn());
                        //如果老师翻译文本不为空则根据老师音频打分
                        JSONObject speech_score_data = new JSONObject();
                        if (teacher_en == null || "".equals(teacher_en)){
                            speech_score_data = this.getSpeechScoreData(reqUrl,voice_path,subjectDialog.getConEn());
                            log.info("获取con_en值为:----->"+subjectDialog.getConEn());
                            log.info("根据con_en获取的打分结果为:----->"+speech_score_data.toString());
                        }else {
                            speech_score_data = this.getSpeechScoreData(reqUrl,voice_path,teacher_en);
                        }
                        if (speech_score_data == null){
                            return new Msg(400,"打分异常,无法解析到打分结果!");
                        }else {
                            //如果err_code不等于空,这段音频则为无效数据
                            if(speech_score_data.get("err_code") != null && !"".equals(speech_score_data.get("err_code").toString())){
                                log.info("无效数据!或者声音太小");
                                log.info("接口数据返回为:----"+speech_score_data.toString());
                                return new Msg(401, "无效音频文件,请重新录入!");
                            }
                        }
                        log.info("获取的userDialogJson数据为:-------"+speech_score_data.toString());
                        getErrorWordsJarray(speech_score_data, errArray);
                    }
                    json.put("err_words",errArray);
                }else{
                    return new Msg(400,"没有用户音频记录");
                }
                log.info("返回的Json数据为:----->"+json.toString());
            return new Msg(200, "", json);
        } catch (Exception ex) {
            log.error("获取用户语音评分错误:",ex);
            return new Msg(400, "获取用户语音评分信息错误!" + ex.getMessage());
        }

    }

    private void getErrorWordsJarray(JSONObject voiceData, JSONArray errArray) throws Exception {
        if (voiceData.get("words") != null && !"".equals(voiceData.get("words").toString())){
            JSONArray wordsArray = JSONArray.parseArray(voiceData.get("words").toString());
            if (wordsArray != null && wordsArray.size() > 0){
                for (int i = 0; i < wordsArray.size();i++){
                    JSONObject wordObject = wordsArray.getJSONObject(i);
                    log.info("获取打分结果的单词信息:----->"+wordObject.toString());
                    if (wordObject != null && !"".equals(wordObject)){
                        //获取读错的单词列表
                        JSONObject word = new JSONObject();
                        BigDecimal wordScore = new BigDecimal(Double.parseDouble(wordObject.get("score").toString())*10);
                        if (wordScore.compareTo(new BigDecimal(60)) < 0){
                            word.put("word_name",wordObject.get("name").toString());
                            JSONArray syllables = JSONArray.parseArray(wordObject.get("syllables").toString());
                            String dict = "";//正确音标
                            String rec = "";//用户发音音标
                            if (syllables != null && syllables.size() >0 ){
                                for(int s = 0;s < syllables.size();s++){
                                    JSONObject syllables_view = syllables.getJSONObject(s);
                                    //获取单词音标组phones
                                    if (syllables_view != null && !"".equals(syllables_view)){
                                        JSONArray phones = JSONObject.parseArray(syllables_view.get("phones").toString());
                                        if(phones !=null && phones.size() > 0){
                                            for(int p = 0;p < phones.size(); p++){
                                                JSONObject phone = phones.getJSONObject(p);
                                                if (phone != null && !"".equals(phone)){
                                                    String dictCode = phone.get("dict").toString();//正确音标组件
                                                    String recCode = phone.get("rec").toString();//用户音标组件
                                                    //音标转换
                                                    dictCode = EnglishToPhoneticUtil.phoneticValue(dictCode);
                                                    recCode = EnglishToPhoneticUtil.phoneticValue(recCode);
                                                    //拼接成音标
                                                    dict += dictCode;
                                                    rec += recCode;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                            //将单词的音标存入words数组里
                            word.put("word_dict",dict.trim());
                            word.put("word_rec",rec.trim());

                            //生成单词的正确读音音频文件
                            String word_name = wordObject.get("name").toString();
                            //用户单词音频的开始时间,
                            word.put("rec_start",wordObject.get("start"));//单位:毫秒
                            word.put("rec_end",wordObject.get("end"));//单位:毫秒
                            word.put("word_score",wordScore);//单词的得分
                            errArray.add(word);
                        }
                        log.info("错词详细信息为:----->"+word.toString());
                    }
                }
            }
        }
    }

    /**
     * 请求打分接口
     * @param
     * @param
     * @param
     */

    public JSONObject getSpeechScoreData(String reqUrl,String filePath,String text)throws IOException{
        File file = new File(filePath);
        MultipartUtility multipartUtility = new MultipartUtility(reqUrl,"UTF-8",token);
        multipartUtility.addFilePart("myWavfile",file);
        multipartUtility.addFormField("word_name",text);
        List<String> pListResponse = multipartUtility.finish();
        String voiceData = pListResponse.get(0);
        JSONObject voiceObt = com.alibaba.fastjson.JSONObject.parseObject(voiceData);
        return voiceObt;
    }

    /**
     * 请求打分接口
     * @param
     * @param
     * @param
     */
    @RequestMapping("/test")
    public JSONObject text()throws IOException{
        File file = new File("F:\workspace\zhenlianService\src\main\resources\1542878441365.wav");
        MultipartUtility multipartUtility = new MultipartUtility(reqUrl,"UTF-8",token);
        multipartUtility.addFilePart("myWavfile",file);
        multipartUtility.addFormField("word_name","111");
        List<String> pListResponse = multipartUtility.finish();
        String voiceData = pListResponse.get(0);
        JSONObject voiceObt = com.alibaba.fastjson.JSONObject.parseObject(voiceData);
        return voiceObt;
    }
}
原文地址:https://www.cnblogs.com/wujf/p/11101255.html