BaiduSpeechDemo【百度语音SDK集成】(基于v3.0.7.3)
版权声明:本文为HaiyuKing原创文章,转载请注明出处!
前言
本Demo将百度语音SDK(其中一部分功能)和自定义的UI对话框封装到一个module中,便于后续的SDK版本更新以及调用。
本Demo使用的百度语音SDK版本是audiobd_speech_sdk_asr_v3.0.7.3_bdasr_20180313_726f26e。
本Demo中使用的appkey已失效,请自行创建应用,使用新的appkey。
效果图
前提
(1)新建项目(获取包名)
(2)在百度AI开发平台上创建应用,获取API Key及Secret Key
官网地址:http://ai.baidu.com/tech/speech
1、成为开发者
参考《接入指南》
2、创建应用
2.1、点击百度AI开放平台导航右侧的控制台,选择需要使用的AI服务项【这里选择语音技术】。
2.2、创建应用
2.3、填写应用信息
2.4、创建成功
2.5、应用列表
(3)下载SDK
3.1、管理应用
3.2、下载SDK
下载地址:https://ai.baidu.com/sdk#asr
代码分析
普通话 search搜索模型:参考SpeechBottomSheetDialog.java类
普通话 input输入法模型,适用于长句及长语音,有逗号分割,无语义:参考SpeechLongBottomSheetDialog.java类
注意:关于语音识别状态维护,API调用的代码,是自己根据官网demo的理解进行整理的,可能有所偏颇,仅供参考。【希望官网demo可以添加百度APP的语音对话框效果就好了】
使用步骤
一、项目组织结构图
注意事项:
1、 导入类文件后需要change包名以及重新import R文件路径
2、 Values目录下的文件(strings.xml、dimens.xml、colors.xml等),如果项目中存在,则复制里面的内容,不要整个覆盖
二、导入步骤
(1)新建module,命名为BaiduSpeech
(2)在baiduspeech的AndroidManifest.xml中添加以下代码
从官方demo的AndroidManifest.xml中找到如下信息,然后复制到您自己的同名文件中。此处需要您复制1、权限2、官网申请的应用信息3、SDK的Service。
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.why.project.baiduspeech">
- <!-- ======================百度语音====================== -->
- <!-- begin: baidu speech sdk 权限 -->
- <uses-permission android:name="android.permission.RECORD_AUDIO" />
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.READ_PHONE_STATE" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <!-- end: baidu speech sdk 权限 -->
- <application>
- <!-- ======================百度语音========================== -->
- <!-- 正式发布时,请替换成您自己的appId 本demo的appId会不定时下线 -->
- <meta-data
- android:name="com.baidu.speech.APP_ID"
- android:value="11588936" />
- <meta-data
- android:name="com.baidu.speech.API_KEY"
- android:value="XRF3IOf2tNGePzlv47cBnvF3" />
- <meta-data
- android:name="com.baidu.speech.SECRET_KEY"
- android:value="diC8lQ7XDcGBKQ6FzCpvnan54F5CnMZI" />
- <service
- android:name="com.baidu.speech.VoiceRecognitionService"
- android:exported="false" />
- </application>
- </manifest>
注意:此时<service>标签那里是红色错误的标记,暂时不用管,导入jar、so文件后编译下就正常了。
(3)复制jar 文件
将官方demo中的app\libs\bdasr_V3_20180320_9066860.jar复制进您项目的同名目录。
在build.gradle中确认是否含有以下红色标记的代码
(4)复制jni库的so文件
复制官方demo中 app\src\main\jniLibs 至项目的同名目录。
这个时候编译下,就会发现AndroidManifest.xml文件的<service>标签那里正常了。
(5)在官方demo中找到下面的文件复制到项目中(按照下面的包名进行查找)【注意,复制过来后,需要重新import 相关类】
(6)修改MessageStatusRecogListener.java文件【根据实际情况进行修改】
- package com.why.project.baiduspeech.recognization;
- import android.os.Handler;
- import android.os.Message;
- import android.util.Log;
- /**
- * Created by fujiayi on 2017/6/16.
- */
- public class MessageStatusRecogListener extends StatusRecogListener {
- private Handler handler;
- private long speechEndTime;
- private boolean needTime = true;
- private static final String TAG = "MesStatusRecogListener";
- public MessageStatusRecogListener(Handler handler) {
- this.handler = handler;
- }
- @Override
- public void onAsrReady() {
- super.onAsrReady();
- sendStatusMessage("引擎就绪,可以开始说话。");
- }
- @Override
- public void onAsrBegin() {
- super.onAsrBegin();
- sendStatusMessage("检测到用户说话");
- }
- @Override
- public void onAsrEnd() {
- super.onAsrEnd();
- speechEndTime = System.currentTimeMillis();
- sendMessage("检测到用户说话结束");
- }
- @Override
- public void onAsrPartialResult(String[] results, RecogResult recogResult) {
- sendStatusMessage("临时识别结果,结果是“" + results[0] + "”;原始json:" + recogResult.getOrigalJson());
- super.onAsrPartialResult(results, recogResult);
- }
- @Override
- public void onAsrFinalResult(String[] results, RecogResult recogResult) {
- super.onAsrFinalResult(results, recogResult);
- //String message = "识别结束,结果是”" + results[0] + "”";//why 实际中可以去掉,不需要
- String message = recogResult.getOrigalJson();//{"results_recognition":["什么什么"],"origin_result":{"corpus_no":6522034498058113957,"err_no":0,"result":{"word":["什么什么"]},"sn":"bfa8b286-ab0e-4f86-9209-1d36d38b1224","voice_energy":16191.7705078125},"error":0,"best_result":"什么什么","result_type":"final_result"}
- sendStatusMessage(message + "“;原始json:" + recogResult.getOrigalJson());
- if (speechEndTime > 0) {
- long diffTime = System.currentTimeMillis() - speechEndTime;
- //message += ";说话结束到识别结束耗时【" + diffTime + "ms】";// why 实际中可以去掉,不需要
- }
- speechEndTime = 0;
- sendMessage(message, status, true);
- }
- @Override
- public void onAsrFinishError(int errorCode, int subErrorCode, String errorMessage, String descMessage,
- RecogResult recogResult) {
- super.onAsrFinishError(errorCode, subErrorCode, errorMessage, descMessage, recogResult);
- //String message = "识别错误, 错误码:" + errorCode + " ," + subErrorCode + " ; " + descMessage;// why 实际中可以去掉,不需要
- String message = recogResult.getOrigalJson();//{"origin_result":{"sn":"","error":7,"desc":"No recognition result match","sub_error":7001},"error":7,"desc":"No recognition result match","sub_error":7001}
- sendStatusMessage(message + ";错误消息:" + errorMessage + ";描述信息:" + descMessage);
- if (speechEndTime > 0) {
- long diffTime = System.currentTimeMillis() - speechEndTime;
- //message += "。说话结束到识别结束耗时【" + diffTime + "ms】";// why实际中可以去掉,不需要
- }
- speechEndTime = 0;
- sendMessage(message, status, true);
- speechEndTime = 0;
- }
- @Override
- public void onAsrOnlineNluResult(String nluResult) {
- super.onAsrOnlineNluResult(nluResult);
- if (!nluResult.isEmpty()) {
- sendStatusMessage("原始语义识别结果json:" + nluResult);
- }
- }
- @Override
- public void onAsrFinish(RecogResult recogResult) {
- super.onAsrFinish(recogResult);
- sendStatusMessage("识别一段话结束。如果是长语音的情况会继续识别下段话。");
- }
- /**
- * 长语音识别结束
- */
- @Override
- public void onAsrLongFinish() {
- super.onAsrLongFinish();
- sendStatusMessage("长语音识别结束。");
- }
- /**
- * 使用离线命令词时,有该回调说明离线语法资源加载成功
- */
- @Override
- public void onOfflineLoaded() {
- sendStatusMessage("【重要】asr.loaded:离线资源加载成功。没有此回调可能离线语法功能不能使用。");
- }
- /**
- * 使用离线命令词时,有该回调说明离线语法资源加载成功
- */
- @Override
- public void onOfflineUnLoaded() {
- sendStatusMessage(" 离线资源卸载成功。");
- }
- @Override
- public void onAsrExit() {
- super.onAsrExit();
- sendStatusMessage("识别引擎结束并空闲中");
- }
- private void sendStatusMessage(String message) {
- sendMessage(message, status);
- }
- private void sendMessage(String message) {
- sendMessage(message, WHAT_MESSAGE_STATUS);
- }
- private void sendMessage(String message, int what) {
- sendMessage(message, what, false);
- }
- private void sendMessage(String message, int what, boolean highlight) {
- if (needTime && what != STATUS_FINISHED) {
- message += " ;time=" + System.currentTimeMillis();
- }
- if (handler == null){
- Log.i(TAG, message );
- return;
- }
- Message msg = Message.obtain();
- msg.what = what;
- msg.arg1 = status;
- if (highlight) {
- msg.arg2 = 1;
- }
- msg.obj = message + "\n";
- handler.sendMessage(msg);
- }
- }
至此,百度语音SDK集成到baiduspeech中了,下一步就是在baiduspeech中创建UI对话框。
(7)创建底部对话框SpeechBottomSheetDialog【根据实际情况自行修改UI布局】
1、在baiduspeech的build.gradle中引用recyclerview【版本号和项目的appcompat保持一致】【因为demo中用到了】
- apply plugin: 'com.android.library'
- android {
- compileSdkVersion 27
- defaultConfig {
- minSdkVersion 16
- targetSdkVersion 27
- versionCode 1
- versionName "1.0"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
- }
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- }
- }
- }
- dependencies {
- implementation fileTree(dir: 'libs', include: ['*.jar'])
- implementation 'com.android.support:appcompat-v7:27.1.1'
- testImplementation 'junit:junit:4.12'
- androidTestImplementation 'com.android.support.test:runner:1.0.2'
- androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
- //RecyclerView
- compile "com.android.support:recyclerview-v7:27.1.1"
- }
2、对话框类、列表适配器类、布局文件xml文件、图片资源、动画style样式等复制到baiduspeech中
3、这里主要标注下SpeechBottomSheetDialog.java中百度语音的相关代码
- package com.why.project.baiduspeech.dialog;
- import android.content.Context;
- import android.content.DialogInterface;
- import android.graphics.drawable.ColorDrawable;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Message;
- import android.support.v4.app.DialogFragment;
- import android.support.v7.widget.LinearLayoutManager;
- import android.support.v7.widget.RecyclerView;
- import android.util.DisplayMetrics;
- import android.util.Log;
- import android.view.Gravity;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import android.view.Window;
- import android.widget.Button;
- import android.widget.ImageView;
- import android.widget.ProgressBar;
- import android.widget.TextView;
- import android.widget.Toast;
- import com.baidu.speech.asr.SpeechConstant;
- import com.baidu.speech.utils.LogUtil;
- import com.why.project.baiduspeech.R;
- import com.why.project.baiduspeech.control.MyRecognizer;
- import com.why.project.baiduspeech.recognization.IStatus;
- import com.why.project.baiduspeech.recognization.MessageStatusRecogListener;
- import com.why.project.baiduspeech.recognization.StatusRecogListener;
- import com.why.project.baiduspeech.util.Logger;
- import org.json.JSONArray;
- import org.json.JSONException;
- import org.json.JSONObject;
- import java.util.ArrayList;
- import java.util.LinkedHashMap;
- import java.util.Map;
- /**
- * Created by HaiyuKing
- * Used 语音识别底部对话框
- */
- public class SpeechBottomSheetDialog extends DialogFragment {
- private static final String TAG = SpeechBottomSheetDialog.class.getSimpleName();
- private Context mContext;
- /**View实例*/
- private View myView;
- private ImageView img_close;
- private ProgressBar loadProgressBar;
- private TextView tv_tishi;
- private RecyclerView result_list;
- private Button btn_start;
- private ArrayList<String> resultWordList;
- private SpeechResultAdapter speechResultAdapter;
- private String BtnStartText = "按一下开始听音";
- private String BtnStopText = "按一下结束听音";
- private String BtnSearchingText = "正在识别";
- private String TishiNoText = "没听清,请重说一遍";
- /**识别控制器,使用MyRecognizer控制识别的流程*/
- protected MyRecognizer myRecognizer;
- /**控制UI按钮的状态*/
- protected int status;
- protected Handler handler;
- public static SpeechBottomSheetDialog getInstance(Context mContext)
- {
- SpeechBottomSheetDialog speechBottomSheetDialog = new SpeechBottomSheetDialog();
- speechBottomSheetDialog.mContext = mContext;
- return speechBottomSheetDialog;
- }
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(0));//设置背景为透明,并且没有标题
- myView = inflater.inflate(R.layout.dialog_bottomsheet_speech, container, false);
- return myView;
- }
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- // TODO Auto-generated method stub
- super.onActivityCreated(savedInstanceState);
- initHandler();//初始化handler
- initRecog();//初始化语音
- initViews();
- initDatas();
- initEvents();
- }
- /**
- * 设置宽度和高度值,以及打开的动画效果
- */
- @Override
- public void onStart() {
- super.onStart();
- //设置对话框的宽高,必须在onStart中
- DisplayMetrics metrics = new DisplayMetrics();
- this.getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics);
- Window window = this.getDialog().getWindow();
- window.setLayout(metrics.widthPixels, this.getDialog().getWindow().getAttributes().height);
- window.setGravity(Gravity.BOTTOM);//设置在底部
- //打开的动画效果
- //设置dialog的 进出 动画
- getDialog().getWindow().setWindowAnimations(R.style.speechbottomsheetdialog_animation);
- }
- @Override
- public void onDismiss(DialogInterface dialog) {
- super.onDismiss(dialog);
- LogUtil.w(TAG,"{onDismiss}");
- //当对话框消失的时候统一执行销毁语音功能
- destroyRecog();//销毁语音
- }
- private void initViews() {
- img_close = (ImageView) myView.findViewById(R.id.img_close);
- loadProgressBar = (ProgressBar) myView.findViewById(R.id.loadProgressBar);
- tv_tishi = (TextView) myView.findViewById(R.id.tv_tishi);
- result_list = (RecyclerView) myView.findViewById(R.id.result_list);
- btn_start = (Button) myView.findViewById(R.id.btn_start);
- }
- /**初始化数据*/
- private void initDatas() {
- resultWordList = new ArrayList<String>();
- speechResultAdapter = null;
- //设置布局管理器
- LinearLayoutManager linerLayoutManager = new LinearLayoutManager(getActivity());
- result_list.setLayoutManager(linerLayoutManager);
- //可以设置为打开后自动识别语音
- startRecog();
- showProgress();
- }
- private void initEvents() {
- //关闭图标的点击事件
- img_close.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- dismiss();
- }
- });
- //按钮的点击事件
- btn_start.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- switch (status) {
- case IStatus.STATUS_NONE: // 初始状态
- startRecog();
- status = IStatus.STATUS_WAITING_READY;
- updateBtnTextByStatus();//更改按钮的文本
- //显示加载区域
- showProgress();
- break;
- case IStatus.STATUS_WAITING_READY: // 调用本类的start方法后,即输入START事件后,等待引擎准备完毕。
- case IStatus.STATUS_READY: // 引擎准备完毕。
- case IStatus.STATUS_SPEAKING:
- case IStatus.STATUS_FINISHED: // 长语音情况
- case IStatus.STATUS_RECOGNITION:
- stopRecog();
- status = IStatus.STATUS_STOPPED; // 引擎识别中
- updateBtnTextByStatus();//更改按钮的文本
- break;
- case IStatus.STATUS_STOPPED: // 引擎识别中
- cancelRecog();
- status = IStatus.STATUS_NONE; // 识别结束,回到初始状态
- updateBtnTextByStatus();//更改按钮的文本
- break;
- default:
- break;
- }
- }
- });
- }
- /**
- * 显示加载进度区域,隐藏其他区域*/
- private void showProgress(){
- loadProgressBar.setVisibility(View.VISIBLE);
- tv_tishi.setVisibility(View.GONE);
- result_list.setVisibility(View.GONE);
- }
- /**
- * 显示文本提示区域,隐藏其他区域*/
- private void showTishi(){
- tv_tishi.setVisibility(View.VISIBLE);
- loadProgressBar.setVisibility(View.GONE);
- result_list.setVisibility(View.GONE);
- }
- /**
- * 显示语音结果区域,隐藏其他区域*/
- private void showListView(){
- result_list.setVisibility(View.VISIBLE);
- loadProgressBar.setVisibility(View.GONE);
- tv_tishi.setVisibility(View.GONE);
- }
- //======================================语音相关代码==========================================
- /**
- * 初始化handler*/
- private void initHandler(){
- handler = new Handler() {
- /*@param msg*/
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- handleMsg(msg);
- }
- };
- Logger.setHandler(handler);
- }
- /**
- * 在onCreate中调用。初始化识别控制类MyRecognizer
- */
- protected void initRecog() {
- StatusRecogListener listener = new MessageStatusRecogListener(handler);
- myRecognizer = new MyRecognizer(mContext,listener);
- status = IStatus.STATUS_NONE;//默认什么也没有做
- }
- /**
- * 销毁时需要释放识别资源。
- */
- protected void destroyRecog() {
- myRecognizer.release();
- Log.i(TAG, "destroyRecog");
- }
- /**
- * 开始录音,点击“开始”按钮后调用。
- */
- protected void startRecog() {
- Map<String, Object> params = new LinkedHashMap<String, Object>();
- params.put(SpeechConstant.ACCEPT_AUDIO_DATA, false);//是否保存音频
- params.put(SpeechConstant.DISABLE_PUNCTUATION, false);//是否禁用标点符号,在选择输入法模型的前提下生效【不禁用的话,说完一段话,就自带标点符号】
- params.put(SpeechConstant.ACCEPT_AUDIO_VOLUME, false);//暂时不知道什么意思
- params.put(SpeechConstant.PID, 1536); // 普通话 search搜索模型,默认,适用于短句,无逗号,可以有语义
- //params.put(SpeechConstant.VAD_ENDPOINT_TIMEOUT, 0); // 长语音,建议搭配input输入法模型
- myRecognizer.start(params);
- }
- /**
- * 开始录音后,手动停止录音。SDK会识别在此过程中的录音。点击“停止”按钮后调用。
- */
- private void stopRecog() {
- myRecognizer.stop();
- }
- /**
- * 开始录音后,取消这次录音。SDK会取消本次识别,回到原始状态。点击“取消”按钮后调用。
- */
- private void cancelRecog() {
- myRecognizer.cancel();
- }
- protected void handleMsg(Message msg) {
- Log.e(TAG,"msg.what="+msg.what);
- Log.e(TAG,"msg.obj.toString()="+msg.obj.toString());
- Log.e(TAG,"msg.arg2="+msg.arg2);
- switch (msg.what) { // 处理MessageStatusRecogListener中的状态回调
- case IStatus.STATUS_FINISHED:
- //识别结束时候的调用【判断显示结果列表区域还是提示区域】
- if (msg.arg2 == 1) {
- //解析json字符串
- try {
- JSONObject msgObj = new JSONObject(msg.obj.toString());
- String error = msgObj.getString("error");
- if(error.equals("0")){
- //解析结果集合,展现列表
- JSONObject origin_resultObj = msgObj.getJSONObject("origin_result");
- JSONObject resultObj = origin_resultObj.getJSONObject("result");
- JSONArray wordList = resultObj.getJSONArray("word");
- initList(wordList);//初始化集合数据
- showListView();
- }else if(error.equals("7")){
- tv_tishi.setText(TishiNoText);
- showTishi();
- }else{//应该根据不同的状态值,显示不同的提示
- tv_tishi.setText(TishiNoText);
- showTishi();
- }
- } catch (JSONException e) {
- e.printStackTrace();
- tv_tishi.setText(TishiNoText);
- showTishi();
- }
- }else if(msg.arg2 == 0){//无网络的情况
- //解析json字符串{"origin_result":{"sn":"","error":2,"desc":"Network is not available","sub_error":2100},"error":2,"desc":"Network is not available","sub_error":2100}
- try {
- JSONObject msgObj = new JSONObject(msg.obj.toString());
- JSONObject origin_resultObj = msgObj.getJSONObject("origin_result");
- String error = origin_resultObj.getString("error");
- if(error.equals("2")){
- //解析结果集合,展现列表
- String desc = origin_resultObj.getString("desc");
- Toast.makeText(mContext,desc,Toast.LENGTH_SHORT).show();
- }
- } catch (JSONException e) {
- e.printStackTrace();
- }
- }
- status = msg.what;
- updateBtnTextByStatus();
- break;
- case IStatus.STATUS_NONE:
- case IStatus.STATUS_READY:
- case IStatus.STATUS_SPEAKING:
- case IStatus.STATUS_RECOGNITION:
- status = msg.what;
- updateBtnTextByStatus();
- break;
- default:
- break;
- }
- }
- /**更改按钮的文本*/
- private void updateBtnTextByStatus() {
- switch (status) {
- case IStatus.STATUS_NONE:
- btn_start.setText(BtnStartText);
- btn_start.setEnabled(true);
- break;
- case IStatus.STATUS_WAITING_READY:
- case IStatus.STATUS_READY:
- case IStatus.STATUS_SPEAKING:
- case IStatus.STATUS_RECOGNITION:
- btn_start.setText(BtnStopText);
- btn_start.setEnabled(true);
- break;
- case IStatus.STATUS_STOPPED:
- btn_start.setText(BtnSearchingText);
- btn_start.setEnabled(true);
- break;
- default:
- break;
- }
- }
- //========================================更改列表==========================
- /**获取集合数据,并显示*/
- private void initList(JSONArray wordList){
- //先清空
- if(resultWordList.size() > 0){
- resultWordList.clear();
- }
- //再赋值
- for(int i=0;i<wordList.length();i++){
- String wordItem = "";
- try {
- wordItem = wordList.getString(i);
- } catch (JSONException e) {
- e.printStackTrace();
- }
- resultWordList.add(wordItem);
- }
- if(speechResultAdapter == null){
- //设置适配器
- speechResultAdapter = new SpeechResultAdapter(getActivity(), resultWordList);
- result_list.setAdapter(speechResultAdapter);
- //添加分割线
- //设置添加删除动画
- //调用ListView的setSelected(!ListView.isSelected())方法,这样就能及时刷新布局
- result_list.setSelected(true);
- }else{
- speechResultAdapter.notifyDataSetChanged();
- }
- speechResultAdapter.setOnItemClickLitener(new SpeechResultAdapter.OnItemClickLitener() {
- @Override
- public void onItemClick(int position) {
- dismiss();
- if(mOnResultListItemClickListener != null){
- mOnResultListItemClickListener.onItemClick(resultWordList.get(position));
- }
- }
- });
- }
- //=========================语音列表项的点击事件监听==============================
- public static abstract interface OnResultListItemClickListener
- {
- //语音结果列表项的点击事件接口
- public abstract void onItemClick(String title);
- }
- private OnResultListItemClickListener mOnResultListItemClickListener;
- public void seOnResultListItemClickListener(OnResultListItemClickListener mOnResultListItemClickListener)
- {
- this.mOnResultListItemClickListener = mOnResultListItemClickListener;
- }
- }
4、如果想要使用长语音功能,请参考SpeechLongBottomSheetDialog.java文件
- package com.why.project.baiduspeech.dialog;
- import android.content.Context;
- import android.content.DialogInterface;
- import android.graphics.drawable.ColorDrawable;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Message;
- import android.support.v4.app.DialogFragment;
- import android.support.v7.widget.LinearLayoutManager;
- import android.support.v7.widget.RecyclerView;
- import android.util.DisplayMetrics;
- import android.util.Log;
- import android.view.Gravity;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import android.view.Window;
- import android.widget.Button;
- import android.widget.ImageView;
- import android.widget.ProgressBar;
- import android.widget.TextView;
- import android.widget.Toast;
- import com.baidu.speech.asr.SpeechConstant;
- import com.baidu.speech.utils.LogUtil;
- import com.why.project.baiduspeech.R;
- import com.why.project.baiduspeech.control.MyRecognizer;
- import com.why.project.baiduspeech.recognization.IStatus;
- import com.why.project.baiduspeech.recognization.MessageStatusRecogListener;
- import com.why.project.baiduspeech.recognization.StatusRecogListener;
- import com.why.project.baiduspeech.util.Logger;
- import org.json.JSONArray;
- import org.json.JSONException;
- import org.json.JSONObject;
- import java.util.ArrayList;
- import java.util.LinkedHashMap;
- import java.util.Map;
- /**
- * Created by HaiyuKing
- * Used 普通话 input输入法模型,适用于长句及长语音,有逗号分割,无语义【基本上和SpeechBottomSheetDialog代码相同】
- */
- public class SpeechLongBottomSheetDialog extends DialogFragment {
- private static final String TAG = SpeechBottomSheetDialog.class.getSimpleName();
- private Context mContext;
- /**View实例*/
- private View myView;
- private ImageView img_close;
- private ProgressBar loadProgressBar;
- private TextView tv_tishi;
- private RecyclerView result_list;
- private Button btn_start;
- private ArrayList<String> resultWordList;
- private SpeechResultAdapter speechResultAdapter;
- private String BtnStartText = "按一下开始听音";
- private String BtnStopText = "按一下结束听音";
- private String BtnSearchingText = "正在识别";
- private String TishiNoText = "没听清,请重说一遍";
- /**识别控制器,使用MyRecognizer控制识别的流程*/
- protected MyRecognizer myRecognizer;
- /**控制UI按钮的状态*/
- protected int status;
- protected Handler handler;
- public static SpeechLongBottomSheetDialog getInstance(Context mContext)
- {
- SpeechLongBottomSheetDialog speechLongBottomSheetDialog = new SpeechLongBottomSheetDialog();
- speechLongBottomSheetDialog.mContext = mContext;
- return speechLongBottomSheetDialog;
- }
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(0));//设置背景为透明,并且没有标题
- myView = inflater.inflate(R.layout.dialog_bottomsheet_speech, container, false);
- return myView;
- }
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- // TODO Auto-generated method stub
- super.onActivityCreated(savedInstanceState);
- initHandler();//初始化handler
- initRecog();//初始化语音
- initViews();
- initDatas();
- initEvents();
- }
- /**
- * 设置宽度和高度值,以及打开的动画效果
- */
- @Override
- public void onStart() {
- super.onStart();
- //设置对话框的宽高,必须在onStart中
- DisplayMetrics metrics = new DisplayMetrics();
- this.getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics);
- Window window = this.getDialog().getWindow();
- window.setLayout(metrics.widthPixels, this.getDialog().getWindow().getAttributes().height);
- window.setGravity(Gravity.BOTTOM);//设置在底部
- //打开的动画效果
- //设置dialog的 进出 动画
- getDialog().getWindow().setWindowAnimations(R.style.speechbottomsheetdialog_animation);
- }
- @Override
- public void onDismiss(DialogInterface dialog) {
- super.onDismiss(dialog);
- LogUtil.w(TAG,"{onDismiss}");
- //当对话框消失的时候统一执行销毁语音功能
- destroyRecog();//销毁语音
- }
- private void initViews() {
- img_close = (ImageView) myView.findViewById(R.id.img_close);
- loadProgressBar = (ProgressBar) myView.findViewById(R.id.loadProgressBar);
- tv_tishi = (TextView) myView.findViewById(R.id.tv_tishi);
- result_list = (RecyclerView) myView.findViewById(R.id.result_list);
- btn_start = (Button) myView.findViewById(R.id.btn_start);
- }
- /**初始化数据*/
- private void initDatas() {
- resultWordList = new ArrayList<String>();
- speechResultAdapter = null;
- //设置布局管理器
- LinearLayoutManager linerLayoutManager = new LinearLayoutManager(getActivity());
- result_list.setLayoutManager(linerLayoutManager);
- btn_start.setText(BtnStartText);//显示文字,和下面的二选一即可 why
- //可以设置为打开后自动识别语音
- /*startRecog();
- showProgress();*/
- }
- private void initEvents() {
- //关闭图标的点击事件
- img_close.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- dismiss();
- }
- });
- //按钮的点击事件
- btn_start.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- switch (status) {
- case IStatus.STATUS_NONE: // 初始状态
- startRecog();
- status = IStatus.STATUS_WAITING_READY;
- updateBtnTextByStatus();//更改按钮的文本
- //显示加载区域
- showProgress();
- break;
- case IStatus.STATUS_WAITING_READY: // 调用本类的start方法后,即输入START事件后,等待引擎准备完毕。
- case IStatus.STATUS_READY: // 引擎准备完毕。
- case IStatus.STATUS_SPEAKING:
- case IStatus.STATUS_FINISHED: // 长语音情况
- case IStatus.STATUS_RECOGNITION:
- stopRecog();
- status = IStatus.STATUS_STOPPED; // 引擎识别中
- updateBtnTextByStatus();//更改按钮的文本
- //对于长语音来讲,需要手动执行代码,否则还得点击一次才能取消why
- btn_start.callOnClick();
- break;
- case IStatus.STATUS_STOPPED: // 引擎识别中
- cancelRecog();
- hiddenAll();//隐藏加载区域why
- status = IStatus.STATUS_NONE; // 识别结束,回到初始状态
- updateBtnTextByStatus();//更改按钮的文本
- break;
- default:
- break;
- }
- }
- });
- }
- /**
- * 显示加载进度区域,隐藏其他区域*/
- private void showProgress(){
- loadProgressBar.setVisibility(View.VISIBLE);
- tv_tishi.setVisibility(View.GONE);
- result_list.setVisibility(View.GONE);
- }
- /**
- * 显示文本提示区域,隐藏其他区域*/
- private void showTishi(){
- tv_tishi.setVisibility(View.VISIBLE);
- loadProgressBar.setVisibility(View.GONE);
- result_list.setVisibility(View.GONE);
- }
- /**
- * 显示语音结果区域,隐藏其他区域*/
- private void showListView(){
- result_list.setVisibility(View.VISIBLE);
- loadProgressBar.setVisibility(View.GONE);
- tv_tishi.setVisibility(View.GONE);
- }
- /**隐藏所有的区域【主要用于长语音】why*/
- private void hiddenAll(){
- result_list.setVisibility(View.GONE);
- loadProgressBar.setVisibility(View.GONE);
- tv_tishi.setVisibility(View.GONE);
- }
- //======================================语音相关代码==========================================
- /**
- * 初始化handler*/
- private void initHandler(){
- handler = new Handler() {
- /*@param msg*/
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- handleMsg(msg);
- }
- };
- Logger.setHandler(handler);
- }
- /**
- * 在onCreate中调用。初始化识别控制类MyRecognizer
- */
- protected void initRecog() {
- StatusRecogListener listener = new MessageStatusRecogListener(handler);
- myRecognizer = new MyRecognizer(mContext,listener);
- status = IStatus.STATUS_NONE;//默认什么也没有做
- }
- /**
- * 销毁时需要释放识别资源。
- */
- protected void destroyRecog() {
- myRecognizer.release();
- Log.i(TAG, "destroyRecog");
- }
- /**
- * 开始录音,点击“开始”按钮后调用。
- */
- protected void startRecog() {
- Map<String, Object> params = new LinkedHashMap<String, Object>();
- params.put(SpeechConstant.ACCEPT_AUDIO_DATA, false);//是否保存音频
- params.put(SpeechConstant.DISABLE_PUNCTUATION, false);//是否禁用标点符号,在选择输入法模型的前提下生效【不禁用的话,说完一段话,就自带标点符号】
- params.put(SpeechConstant.ACCEPT_AUDIO_VOLUME, false);//暂时不知道什么意思
- //下面的1936和1537选择其中一个 why
- //params.put(SpeechConstant.PID, 1936); // 普通话 far,远场模型,高级,适用于音源离麦克风较远(>1m)的录音,有逗号分隔,可以有语义
- params.put(SpeechConstant.PID, 1537); // 普通话 input输入法模型,适用于长句及长语音,有逗号分割,无语义
- params.put(SpeechConstant.VAD_ENDPOINT_TIMEOUT, 0); // 长语音,建议搭配input输入法模型
- myRecognizer.start(params);
- }
- /**
- * 开始录音后,手动停止录音。SDK会识别在此过程中的录音。点击“停止”按钮后调用。
- */
- private void stopRecog() {
- myRecognizer.stop();
- }
- /**
- * 开始录音后,取消这次录音。SDK会取消本次识别,回到原始状态。点击“取消”按钮后调用。
- */
- private void cancelRecog() {
- myRecognizer.cancel();
- }
- protected void handleMsg(Message msg) {
- switch (msg.what) { // 处理MessageStatusRecogListener中的状态回调
- case IStatus.STATUS_FINISHED:
- //识别结束时候的调用【判断显示结果列表区域还是提示区域】
- if (msg.arg2 == 1) {
- //解析json字符串
- try {
- JSONObject msgObj = new JSONObject(msg.obj.toString());
- String error = msgObj.getString("error");
- if(error.equals("0")){
- //直接输入到文本框中 why
- JSONArray recognitionObj = msgObj.getJSONArray("results_recognition");
- String result = recognitionObj.getString(0);
- if(mOnResultListItemClickListener != null){
- mOnResultListItemClickListener.onItemClick(result);
- }
- }else if(error.equals("7")){
- tv_tishi.setText(TishiNoText);
- showTishi();
- }else{//应该根据不同的状态值,显示不同的提示
- tv_tishi.setText(TishiNoText);
- showTishi();
- }
- } catch (JSONException e) {
- e.printStackTrace();
- tv_tishi.setText(TishiNoText);
- showTishi();
- }
- }else if(msg.arg2 == 0){//无网络的情况
- //解析json字符串{"origin_result":{"sn":"","error":2,"desc":"Network is not available","sub_error":2100},"error":2,"desc":"Network is not available","sub_error":2100}
- try {
- JSONObject msgObj = new JSONObject(msg.obj.toString());
- JSONObject origin_resultObj = msgObj.getJSONObject("origin_result");
- String error = origin_resultObj.getString("error");
- if(error.equals("2")){
- //解析结果集合,展现列表
- String desc = origin_resultObj.getString("desc");
- Toast.makeText(mContext,desc,Toast.LENGTH_SHORT).show();
- }
- } catch (JSONException e) {
- e.printStackTrace();
- }
- }
- status = msg.what;
- updateBtnTextByStatus();
- break;
- case IStatus.STATUS_NONE:
- case IStatus.STATUS_READY:
- case IStatus.STATUS_SPEAKING:
- case IStatus.STATUS_RECOGNITION:
- status = msg.what;
- updateBtnTextByStatus();
- break;
- default:
- break;
- }
- }
- /**更改按钮的文本*/
- private void updateBtnTextByStatus() {
- switch (status) {
- case IStatus.STATUS_NONE:
- btn_start.setText(BtnStartText);
- btn_start.setEnabled(true);
- break;
- case IStatus.STATUS_WAITING_READY:
- case IStatus.STATUS_READY:
- case IStatus.STATUS_SPEAKING:
- case IStatus.STATUS_RECOGNITION:
- btn_start.setText(BtnStopText);
- btn_start.setEnabled(true);
- break;
- case IStatus.STATUS_STOPPED:
- btn_start.setText(BtnSearchingText);
- btn_start.setEnabled(true);
- break;
- default:
- break;
- }
- }
- //========================================更改列表==========================
- /**获取集合数据,并显示*/
- private void initList(JSONArray wordList){
- //先清空
- if(resultWordList.size() > 0){
- resultWordList.clear();
- }
- //再赋值
- for(int i=0;i<wordList.length();i++){
- String wordItem = "";
- try {
- wordItem = wordList.getString(i);
- } catch (JSONException e) {
- e.printStackTrace();
- }
- resultWordList.add(wordItem);
- }
- if(speechResultAdapter == null){
- //设置适配器
- speechResultAdapter = new SpeechResultAdapter(getActivity(), resultWordList);
- result_list.setAdapter(speechResultAdapter);
- //添加分割线
- //设置添加删除动画
- //调用ListView的setSelected(!ListView.isSelected())方法,这样就能及时刷新布局
- result_list.setSelected(true);
- }else{
- speechResultAdapter.notifyDataSetChanged();
- }
- speechResultAdapter.setOnItemClickLitener(new SpeechResultAdapter.OnItemClickLitener() {
- @Override
- public void onItemClick(int position) {
- dismiss();
- if(mOnResultListItemClickListener != null){
- mOnResultListItemClickListener.onItemClick(resultWordList.get(position));
- }
- }
- });
- }
- //=========================语音列表项的点击事件监听==============================
- public static abstract interface OnResultListItemClickListener
- {
- //语音结果列表项的点击事件接口
- public abstract void onItemClick(String title);
- }
- private OnResultListItemClickListener mOnResultListItemClickListener;
- public void seOnResultListItemClickListener(OnResultListItemClickListener mOnResultListItemClickListener)
- {
- this.mOnResultListItemClickListener = mOnResultListItemClickListener;
- }
- }
三、使用方法
(1)因为需要使用到运行时权限,所以参考《Android6.0运行时权限(基于RxPermission开源库)》在APP的build.gradle中引入第三方库
(2)在APP的build.gradle中引入baiduspeech
(3)在Activity中调用
- <?xml version="1.0" encoding="utf-8"?>
- <android.support.constraint.ConstraintLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context="com.why.project.baiduspeechdemo.MainActivity">
- <TextView
- android:id="@+id/tv_result"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Hello World!"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintHorizontal_bias="0.448"
- app:layout_constraintLeft_toLeftOf="parent"
- app:layout_constraintRight_toRightOf="parent"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintVertical_bias="0.325"/>
- <Button
- android:id="@+id/btn_openSpeechDialog"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginEnd="8dp"
- android:layout_marginStart="8dp"
- android:layout_marginTop="32dp"
- android:text="打开搜索模型语音识别对话框"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintHorizontal_bias="0.419"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"/>
- <Button
- android:id="@+id/btn_openSpeechLongDialog"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginEnd="8dp"
- android:layout_marginStart="8dp"
- android:layout_marginTop="16dp"
- android:text="打开input输入模型语音识别对话框"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintHorizontal_bias="0.4"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/btn_openSpeechDialog"/>
- </android.support.constraint.ConstraintLayout>
activity_main.xml
- package com.why.project.baiduspeechdemo;
- import android.Manifest;
- import android.os.Bundle;
- import android.support.v7.app.AppCompatActivity;
- import android.util.Log;
- import android.view.View;
- import android.widget.Button;
- import android.widget.TextView;
- import android.widget.Toast;
- import com.tbruyelle.rxpermissions2.RxPermissions;
- import com.why.project.baiduspeech.dialog.SpeechBottomSheetDialog;
- import com.why.project.baiduspeech.dialog.SpeechLongBottomSheetDialog;
- import io.reactivex.functions.Action;
- import io.reactivex.functions.Consumer;
- public class MainActivity extends AppCompatActivity {
- private static final String TAG = MainActivity.class.getSimpleName();
- private Button mOpenSpeechDialogBtn;
- private Button mOpenSpeechLongDialogBtn;
- private TextView mResultTv;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- onePermission();
- initViews();
- initEvents();
- }
- private void initViews() {
- mOpenSpeechDialogBtn = findViewById(R.id.btn_openSpeechDialog);
- mOpenSpeechLongDialogBtn = findViewById(R.id.btn_openSpeechLongDialog);
- mResultTv = findViewById(R.id.tv_result);
- }
- private void initEvents() {
- mOpenSpeechDialogBtn.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- //打开百度语音对话框
- SpeechBottomSheetDialog speechBottomSheetDialog = SpeechBottomSheetDialog.getInstance(MainActivity.this);
- speechBottomSheetDialog.seOnResultListItemClickListener(new SpeechBottomSheetDialog.OnResultListItemClickListener() {
- @Override
- public void onItemClick(String title) {
- //填充到输入框中
- mResultTv.setText(title);
- }
- });
- speechBottomSheetDialog.show(getSupportFragmentManager(), TAG);
- }
- });
- mOpenSpeechLongDialogBtn.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- //打开百度语音对话框
- SpeechLongBottomSheetDialog speechLongBottomSheetDialog = SpeechLongBottomSheetDialog.getInstance(MainActivity.this);
- speechLongBottomSheetDialog.seOnResultListItemClickListener(new SpeechLongBottomSheetDialog.OnResultListItemClickListener() {
- @Override
- public void onItemClick(String title) {
- //填充到输入框中
- mResultTv.setText(mResultTv.getText()+title);
- }
- });
- speechLongBottomSheetDialog.show(getSupportFragmentManager(), TAG);
- }
- });
- }
- /**只有一个运行时权限申请的情况*/
- private void onePermission(){
- RxPermissions rxPermissions = new RxPermissions(MainActivity.this); // where this is an Activity instance
- rxPermissions.request(Manifest.permission.RECORD_AUDIO,
- Manifest.permission.READ_PHONE_STATE,
- Manifest.permission.WRITE_EXTERNAL_STORAGE) //权限名称,多个权限之间逗号分隔开
- .subscribe(new Consumer<Boolean>() {
- @Override
- public void accept(Boolean granted) throws Exception {
- Log.e(TAG, "{accept}granted=" + granted);//执行顺序——1【多个权限的情况,只有所有的权限均允许的情况下granted==true】
- if (granted) { // 在android 6.0之前会默认返回true
- // 已经获取权限
- } else {
- // 未获取权限
- Toast.makeText(MainActivity.this, "您没有授权该权限,请在设置中打开授权", Toast.LENGTH_SHORT).show();
- }
- }
- }, new Consumer<Throwable>() {
- @Override
- public void accept(Throwable throwable) throws Exception {
- Log.e(TAG,"{accept}");//可能是授权异常的情况下的处理
- }
- }, new Action() {
- @Override
- public void run() throws Exception {
- Log.e(TAG,"{run}");//执行顺序——2
- }
- });
- }
- }
混淆配置
- #=====================百度语音混淆=====================
- -keep class com.baidu.speech.**{*;}
参考资料
http://ai.baidu.com/tech/speech
项目demo下载地址
https://github.com/haiyuKing/BaiduSpeechDemo
BaiduSpeechDemo【百度语音SDK集成】(基于v3.0.7.3)的更多相关文章
- BaiduSpeechDemo【百度语音SDK集成】(基于v3.0.8.1)
版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 上一篇集成的是V3.0.7.3版本的SDK<BaiduSpeechDemo[百度语音SDK集成](基于v3.0.7.3)> ...
- iOS百度地图SDK集成详细步骤
1.iOS百度地图下载地址 http://developer.baidu.com/map/index.php?title=iossdk/sdkiosdev-download 根据需要选择不同的版本 ...
- 接入百度语音SDK的步骤
1.导入依赖库 SystemConfiguration.framework AudioToolbox.framework UIkit.framework AVFoundation.framework ...
- AEAI BPM流程集成平台V3.0.2版本开源发布
本次开源发布的是AEAI BPMV3.0.2版流程平台,该版本是数通畅联首次正式对外发布的版本,产品现已开源并上传至开源社区http://www.oschina.net/p/aeai-bpm. 产品说 ...
- iOS开发——百度地图SDK集成
(正在形成文档,待更新……)
- Android Studio集成百度地图SDK
1.建议先阅读百度地图官方的继承指南,针对了Eclipse和Android Studio. 百度官方集成指南 2.下载百度地图SDK Android SDK v4.1.1 下载有两种: 1.一键下载( ...
- Xamarin.Android 集成百度地图SDK
前言:趁着周六闲得没事干,赶紧搞一搞Xamarin,最近也是怪无聊的,枯燥的生活不如打几行代码带劲:好了我们进入正题 我这篇文章时参考一位大佬的博客进行改变的,当然他写的需要一定的经验才可以看得懂,我 ...
- 全志tina v3.0系统编译时的时间错误的解决(全志SDK的维护BUG)
全志tina v3.0系统编译时的时间错误的解决(全志SDK的维护BUG) 2018/6/13 15:52 版本:V1.0 开发板:SC3817R SDK:tina v3.0 1.01原始编译全志r1 ...
- 百度地图SDK for Android【检索服务】
1搜索服务 百度地图SDK集成搜索服务包括:位置检索.周边检索.范围检索.公交检索.驾乘检索.步行检索,通过初始化MKSearch类,注册搜索结果的监听对象MKSearchListener,实现异步搜 ...
随机推荐
- Java 保留两位小数填坑
下面直接上代码: DecimalFormat df1 = new DecimalFormat("#.00");DecimalFormat df2 = new DecimalForm ...
- testng生成自定义html报告
转自:https://blog.csdn.net/kdslkd/article/details/51198433 testng原生的或reportng的报告总有些不符合需要,尝试生成自定义测试报告,用 ...
- 在docker上运行.net core程序
一.安装docker及镜像 1.在centos上安装docker,命令如下: # yum install docker 2.让docker随机启动: # service docker start# c ...
- bzoj 3551 kruskal重构树dfs序上的主席树
强制在线 kruskal重构树,每两点间的最大边权即为其lca的点权. 倍增找,dfs序对应区间搞主席树 #include<cstdio> #include<cstring> ...
- bzoj 3759 Hungergame 博弈论+线性基
和nim游戏类似 易证必败状态为:当前打开的箱子中石子异或和为0,没打开的箱子中不存在一个子集满足异或和为0 因为先手无论是取石子还是开箱子,后手都可以通过取石子来使状态变回原状态 所以只需判定是否有 ...
- jackson xml转对象 对象转xml
public static void main(String[] args) throws Exception { XnServiceGetUserRequest xnServiceGetUserRe ...
- java 关闭钩子函数的应用
Runtime.getRuntime().addShutdownHook(shutdownHook); 说明:这个方法的意思就是在jvm中增加一个关闭的钩子,当jvm关闭的时候,会执行系统中已经设置的 ...
- React Native开发 - 搭建React Native开发环境
移动开发以前一般都是原生的语言来开发,Android开发是用Java语言,IOS的开发是Object-C或者Swift.那么对于开发一个App,至少需要两套代码.两个团队.对于公司来说,成本还是有的. ...
- 干货,一文带你超详细了解 Filter 的原理及应用
提出问题 1.我们在访问后台很多页面时都需要登录,只有登录的用户才能查看这些页面,我们需要 在每次请求的时候都检查用户是否登陆,这样做很麻烦,有没有一种方法可以在我们请求之 前就帮我们做这些事 ...
- SpringCloud分布式微服务搭建(一)
本例子主要使用了eureka集群作为注册中心来保证高可用,客户端来做ribbon服务提供者的负载均衡. 负载均衡有两种,第一种是nginx,F5这种集中式的LB,对所有的访问按照某种策略分发. 第二种 ...