# java
**Repository Path**: tecle/java
## Basic Information
- **Project Name**: java
- **Description**: No description available
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2020-05-11
- **Last Updated**: 2020-12-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 图聚后端知识点总结
## 一、基础
### 1. elasticsearch6.5.3安装
*(注:安装之前请先确认服务器已安装好jdk1.8并配置好环境变量)*
#### 1) tar包下载
Elasticsearch 6.5.3 地址:[下载](https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-6.5.3.tar.gz)
其他版本的直接改为对应版本号下载即可下载
#### 2) 上传并解压
用的filezilla将下载好的elasticsearch-6.5.3.tar.gz上传至服务器指定目录,我上传到自建目录:/www/server
解压:
[root@localhost ~]# cd /www/server
[root@localhost server]# tar -zxvf elasticsearch-6.5.3.tar.gz
#### 3)创建用户(elasticsearch默认是不允许使用root用户启动的,以root身份启动会报错)
[root@localhost server]# adduser hoey
[root@localhost server]# mkdir -p esdata/data
[root@localhost server]# mkdir -p esdata/log
[root@localhost server]# chown -R hoey elasticsearch-6.5.3
[root@localhost server]# chown -R hoey esdata
创建用户是为了防止以root身份启动时报如下错误:
Exception in thread “main” java.lang.RuntimeException: don’t run elasticsearch as root。
#### 4) 修改elasticsearch-6.5.3/config/elasticsearch.yml配置文件
```properties
#
#
cluster.name: my-application
#
#
node.name: node-1
#
#
node.attr.rack: r1
#
#注意这里的路径是第三步创建的目录路径 /www/server/esdata/data
path.data: /www/server/esdata/data
#
#注意这里的路径是第三步创建的目录路径 /www/server/esdata/log
path.logs: /www/server/esdata/log
#
#
bootstrap.memory_lock: false
bootstrap.system_call_filter: false
#
#0.0.0.0代表任何IP都可访问
network.host: 0.0.0.0
#
#开启端口
http.port: 9200
#
#
action.destructive_requires_name: true
```
在上述文件加上
```properties
bootstrap.memory_lock: false
bootstrap.system_call_filter: false
```
是为了解决以下报错:
unable to install syscall filter:
java.lang.UnsupportedOperationException: seccomp unavailable: CONFIG_SECCOMP not compiled into kernel, CONFIG_SECCOMP and CONFIG_SECCOMP_FILTER are needed
#### 5) 修改/etc/security/limits.conf配置文件
在/etc/security/limits.conf配置文件文件中加上:
```properties
* soft nofile 65536
* hard nofile 131072
* soft nproc 4096
* hard nproc 4096
```
修改limits.conf是为了解决以下报错:
ERROR: [3] bootstrap checks failed
[1]: max file descriptors [4096] for elasticsearch process is too low, increase to at least [65536]
#### 6) 修改/etc/sysctl.conf配置文件
在文件最后加上:
```properties
vm.max_map_count = 2621441
```
让配置文件生效:
[root@localhost server]# sudo sysctl -p /etc/sysctl.conf
修改sysctl.conf是为了解决以下报错:
max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
#### 7) 修改/etc/security/limits.d/90-nproc.conf配置文件
将/etc/security/limits.d/90-nproc.conf文件改为:
```properties
* soft nproc 4096
root soft nproc 4096
```
修改上述文件是为了解决以下报错:(注意我这里报的是4096,配置文件中的数据应根据报错的来改,改成大于等于报错数据即可)
[3]: max number of threads [2048] for user [tongtech] is too low, increase to at least [4096]
#### 8) 启动
修改/etc/security/limits.conf文件需要重新登录才生效,所以我退出连接重新登录了一下.
1.启动前先关闭防火墙:(该命令是centos6.x版本永久关闭防火墙命令,centos7防火墙命令对应的是firewalld)
[root@localhost server]# chkconfig iptables off
2.进入elasticsearch的bin目录
[root@localhost server]# cd /www/server/elasticsearch-6.5.3/bin
3.切换为第三步创建的用户hoey
[root@localhost bin]# su hoey
4.启动elasticsearch(确认当前命令目录是在bin目录下)
[hoey@localhost bin]$ ./elasticsearch
#### 9) 浏览器访问
### 2.idea相关插件
#### 1) 热部署工具:jrebel
##### ①下载
1、在IDEA中一次点击 File->Settings->Plugins->Brows Repositories
2、在搜索框中输入JRebel进行搜索
3、找到JRebel for intellij
4、install
5、安装好之后需要restart IDEA
##### ②激活
点击https://active.jrebel.cn/
##### ③使用
#### 2) mybatis log查看
##### ①下载
Idea的plugins里面搜索mybatis log plugin,然后安装
##### ②使用
安装完老套路重启idea,重启之后是不是发现装的插件不见了.别急,在idea的tool里面呢,注意看下图:
这样在执行sql的时候就可以打印出系统生成好的sql,方便排查问题
#### 3) 其他插件:
Free Mybatis plugin(快速从代码跳转到mapper及从mapper返回代码)
.ignore(自动创建.ignore文件)
Alibaba Java Coding Guidelines(阿里巴巴Java开发规约扫描插件)
### 3.问题排查
#### 1) 服务挂掉
1.检查数据库、redis是否正常;
2.检查是否有依赖服务挂掉;
3.是否访问限制,如:端口禁用、域名解析被改、阿里负载均衡;
4.重新启动服务,看控制台日志。
#### 2) 服务报500
1.本地跑一下,还原问题,排查sql编写问题、逻辑处理问题等;
2.如果本地没问题,则尝试改端口上传服务器再运行,使用swagger请求原接口,在开发者工具复制curl语句,然后在服务器上**更改ip+端口**发起请求查看问题;
3.**注意控制台报错**,注意是否有多个服务注册到线上服务器注册中心,如本地服务。
#### 3) 服务器无响应(运行中)
1.检查是否有线程阻塞;
2.检查是否因为请求其他http服务导致线程全部等待中;
3.检查数据库、redis等是否访问时间过长。
#### 4) 终极大法(二分法)
确定前端问题(参数没有按照要求)还是后端问题,确定是数据库等外部链接问题还是内部逻辑问题,每个步骤的断点数据是否是预期数据等。
### 4.算法
每个图聚后端都需要多多少少会算法,周末没事刷刷题:https://leetcode-cn.com/
## 二、第三方
### 1.微信相关
#### 1) 公众号、小程序openId获取流程
所有微信相关的接口基本都需要获取accessToken,每天获取上限2000次,2小时过期,建议获取后保存至数据库或redis:
##### **公众号获取openid:**
①用户通过菜单或者重定向的方式访问微信服务器,地址格式为:
https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appId}&redirect_uri=${redirectUri}&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect
***注意:当scope为snsapi_base是静默登录,scope为snsapi_userinfo需要用户手动同意。***
②请求成功后,微信会回调 redirectUri 地址,并在参数后带上code和state:
${redirectUri}?code=CODE&state=STATE;
③网页请求后端服务器,参数为code、state;
④后端服务器请求微信接口获取用户信息;
⑤微信服务器返回给后端用户信息,若scope为snsapi_userinfo,则有额外的用户信息字段;
⑥服务端生成token,并和open_id关联,之后返回给前端;
⑦用户每次访问接口,带上token;
⑨后端服务通过token鉴权,可知道是谁访问了这个接口。
##### **小程序获取openid:**
①小程序获取open_id少了重定向,直接使用wx.login()方法获取code;
②请求后端服务器,后端直接使用appid + appsecret + code得到用户open_id,后续和公众号处理方式一样。
#### 2) 微信支付
公司用的最多的是小程序支付,这里着重介绍:
需要准备的:
-->1.程序访问商户服务都是通过HTTPS,开发部署的时候需要安装HTTPS服务器;
-->2.小程序appId、appSecret,微信支付商户mchId、apiKey、证书(退款用,不需要可忽略);
-->3.在商户后台绑定小程序,并设置域名白名单。
支付流程:
***注意:微信支付需要终端ip的必填参数,使用nginx或负载时,不能使用request.getRemoteAddr(),应该使用IPUtils获取:***
```java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.http.HttpServletRequest;
/**
* IP地址
*
*/
public class IPUtils {
private static Logger logger = LoggerFactory.getLogger(IPUtils.class);
/**
* 获取IP地址
*
* 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址
* 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址
*/
public static String getIpAddr(HttpServletRequest request) {
String ip = null;
try {
ip = request.getHeader("x-forwarded-for");
if (StringUtil.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (StringUtil.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Real-IP");
}
if (StringUtil.isEmpty(ip) || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (StringUtil.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (StringUtil.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (StringUtil.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
} catch (Exception e) {
logger.error("IPUtils ERROR ", e);
}
//使用代理,则获取第一个IP地址
if(StringUtil.isNotEmpty(ip) && ip.length() > 15) {
if(ip.indexOf(",") > 0) {
ip = ip.substring(0, ip.indexOf(","));
}
}
return ip;
}
}
```
文档地址:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1
***微信回调后,必须进行校验方可入库***
***随机字符串需要后端生成,前端不能改,timestamp不能差别太多,否则校验不通过***
**PS:其他支付和微信支付原理差不多,demo:https://gitee.com/52itstyle/springMvc-dubbo-pay **
#### 2) 微信第三方授权
##### 1.申请微信开放平台帐号并创建第三方平台;
**其中:授权事件接收URL是微信每隔10分钟会请求此地址,带上ticket,后面获取第三方accessToken需要用到**
##### 2.获取第三方平台access_token
通过授权事件接收URL获取到ticket后,请求获取第三方accessToken;
http请求方式: POST(请使用https协议)
https://api.weixin.qq.com/cgi-bin/component/api_component_token
POST数据示例:
```json
{
"component_appid":"appid_value" ,
"component_appsecret": "appsecret_value",
"component_verify_ticket": "ticket_value"
}
```
请求参数说明
|参数名称|参数含义|
|--|:--:|
|component_appid|第三方平台appid|
|component_appsecret|第三方平台appsecret|
|component_verify_ticket|微信后台推送的ticket,此ticket会定时推送|
返回结果示例
```json
{
"component_access_token":"61W3mEpU66027wgNZ_MhGHNQDHnFATkDa9-2llqrMBjUwxRSNPbVsMmyD-yq8wZETSoE5NQgecigDrSHkPtIYA",
"expires_in":7200
}
```
结果参数说明
参数名称|参数含义
--|:--:
component_access_token|第三方平台access_token
expires_in|有效期
##### 3.获取预授权码
每次发起授权,都需要获取预授权码:
http请求方式: POST(请使用https协议)
https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode?component_access_token=xxx
POST数据示例:
```json
{
"component_appid":"appid_value"
}
```
请求参数说明
|参数名称|参数含义|
|--|:--:|
|component_appid|第三方平台appid|
返回结果示例
```json
{
"pre_auth_code": "Cx_Dk6qiBE0Dmx4EmlT3oRfArPvwSQ-oa3NL_fwHM7VI08r52wazoZX2Rhpz1dEw",
"expires_in": 600
}
```
结果参数说明
|参数名称|参数含义|
|--|:--:|
|pre_auth_code|预授权码|
|expires_in|有效期|
##### 4.引导进入授权页面
**这里需要注意,微信第三方授权要求refer页面必须授权可信的白名单地址,所以需要在一个白名单域名下html页面,加一个按钮,按钮的响应地址为:**
https://mp.weixin.qq.com/cgi-bin/componentloginpage?component_appid=xxxx&pre_auth_code=xxxxx&redirect_uri=xxxx
|参数名称|参数含义|
|--|:--:|
|component_appid|第三方平台appid|
|pre_auth_code|第三步获取的预授权码|
|redirect_uri|授权成功后的结果页面,用于给用户用户展示|
该网址中第三方平台方需要提供第三方平台方appid、预授权码和回调URI。
##### 5.授权后回调URI,得到授权码和过期时间
授权流程完成后,会进入回调URI,并在URL参数中返回授权码和过期时间(redirect_url?auth_code=xxx&expires_in=600)
##### 6.使用授权码换取公众号的授权信息
接口调用请求说明
http请求方式: POST(请使用https协议)
https://api.weixin.qq.com/cgi-bin/component/api_query_auth?component_access_token=xxxx
POST数据示例:
```json
{
"component_appid": "appid_value",
"authorization_code": "auth_code_value"
}
```
请求参数说明
|参数名称|参数含义|
|--|:--:|
|component_appid|第三方平台appid|
|authorization_code|授权code,第5步获取到的授权码|
返回结果示例
```json
{
"authorization_info": {
"authorizer_appid": "wxf8b4f85f3a794e77",
"authorizer_access_token": "QXjUqNqfYVH0yBE1iI_7vuN_9gQbpjfK7hYwJ3P7xOa88a89-Aga5x1NMYJyB8G2yKt1KCl0nPC3W9GJzw0Zzq_dBxc8pxIGUNi_bFes0qM",
"expires_in": 7200,
"authorizer_refresh_token": "dTo-YCXPL4llX-u1W1pPpnp8Hgm4wpJtlR6iV0doKdY",
"func_info": [{
"funcscope_category": {
"id": 1
}
},
{
"funcscope_category": {
"id": 2
}
},
{
"funcscope_category": {
"id": 3
}
}
]
}
}
```
结果参数说明
|参数名称|参数含义|
|--|:--:|
|authorization_info|授权信息|
|authorizer_appid|授权方appid|
|authorizer_access_token|授权方令牌(在授权的公众号具备API权限时,才有此返回值)|
|expires_in|有效期(在授权的公众号具备API权限时,才有此返回值)|
|authorizer_refresh_token|刷新令牌(在授权的公众号具备API权限时,才有此返回值),只会在授权时刻提供,请妥善保存。 一旦丢失,只能让用户重新授权|
|func_info|公众号授权给开发者的权限集列表|
#### 3) 公众号模板消息推送流程
1.需要获取公众号的accessToken,具体参考获取openid的accessToken;
2.公众号后台添加消息模板(上限25个,如果添加搜索到的,可以直接添加,如果自建消息模板,则需要最长**15天**的审核期);
3.调用发送模板接口:
http请求方式: POST
地址:https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN
POST数据示例如下:
```json
{
"touser": "OPENID",
"template_id": "ngqIpbwh8bUfcSsECmogfXcV14J0tQlEpBO27izEYtY",
"url": "http://weixin.qq.com/download",
"miniprogram": {
"appid": "xiaochengxuappid12345",
"pagepath": "index?foo=bar"
},
"data": {
"first": {
"value": "XX先生,挂号成功!",
"color": "#173177"
},
"keyword1": {
"value": "骨科",
"color": "#173177"
},
"keyword2": {
"value": "39.8元",
"color": "#173177"
},
"keyword3": {
"value": "2014年9月22日",
"color": "#173177"
},
"remark": {
"value": "点击此处进入导航!",
"color": "#173177"
}
}
}
```
参数说明
|参数名称|是否必填|参数含义|
|--|:----:|:----:|
|touser|是|接收者openid|
|template_id|是|模板ID|
|url|否|模板跳转链接|
|miniprogram|否|跳小程序所需数据,不需跳小程序可不用传该数据|
|appid|是|所需跳转到的小程序appid(该小程序appid必须与发模板消息的公众号是绑定关联关系,暂不支持小游戏)|
|pagepath|否|所需跳转到小程序的具体页面路径,支持带参数,(示例index?foo=bar),暂不支持小游戏|
|data|是|模板数据|
|color|否|模板内容字体颜色,不填默认为黑色|
注:url和miniprogram都是**非必填**字段,若都不传则模板无跳转;若都传,会优先跳转至小程序。开发者可根据实际需要选择其中一种跳转方式即可。当用户的微信客户端版本不支持跳小程序时,将会跳转至url。
返回码说明
在调用模板消息接口后,会返回JSON数据包。正常时的返回JSON数据包示例:
```json
{
"errcode": 0,
"errmsg": "ok",
"msgid": 200228332
}
```
### 2.阿里云相关
#### 1) MQ的使用
阿里云MQ使用需要topic、groupId、accessKey、secretKey、namesrvADDR
##### 客户端:
MQProducer:
```java
import com.aliyun.openservices.ons.api.ONSFactory;
import com.aliyun.openservices.ons.api.Producer;
import com.aliyun.openservices.ons.api.PropertyKeyConst;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.Properties;
@Service
public class MQProducerSingleTon {
@Value("${alimq.topic}")
private String groupId;
@Value("${alimq.accessKey}")
private String accessKey;
@Value("${alimq.secretKey}")
private String secretKey;
@Value("${alimq.namesrvADDR}")
private String namesrvADDR;
private static Producer producer;
private static class SingletonHolder {
private static final MQProducerSingleTon INSTANCE = new MQProducerSingleTon();
}
private MQProducerSingleTon() {
}
static MQProducerSingleTon getInstance() {
return SingletonHolder.INSTANCE;
}
@PostConstruct
public void init() {
// producer 实例配置初始化
Properties properties = new Properties();
// 您在控制台创建的Producer ID
properties.setProperty(PropertyKeyConst.GROUP_ID, groupId);
// AccessKey 阿里云身份验证,在阿里云服务器管理控制台创建
properties.setProperty(PropertyKeyConst.AccessKey, accessKey);
// SecretKey 阿里云身份验证,在阿里云服务器管理控制台创建
properties.setProperty(PropertyKeyConst.SecretKey, secretKey);
//设置发送超时时间,单位毫秒
properties.setProperty(PropertyKeyConst.SendMsgTimeoutMillis, "3000");
// 设置 TCP 接入域名(此处以公共云生产环境为例)
properties.setProperty(PropertyKeyConst.NAMESRV_ADDR, namesrvADDR);
// 和上面的二选一,推荐下面这种方式,暂时链接不对 !!!!!!
producer = ONSFactory.createProducer(properties);
// 在发送消息前,必须调用start方法来启动Producer,只需调用一次即可
producer.start();
}
Producer getProducer() {
return producer;
}
}
```
AsyncMQService:
```java
import com.aliyun.openservices.ons.api.Message;
import com.aliyun.openservices.ons.api.Producer;
import com.aliyun.openservices.ons.api.SendResult;
import com.aliyun.openservices.ons.api.exception.ONSClientException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Slf4j
@Service
public class AsyncMQService {
@Resource
private MQProperties mqProperties;
@Value("${bdid}")
private String tags;
@Value("${sendToMq}")
private int sendToMq;
@Async(value = "MQTaskExecutor")
public void sendToMQTT(String data) {
log.info("发送的原始数据为---{}", data);
if (sendToMq == 1) {
Producer producer = MQProducerSingleTon.getInstance().getProducer();
Message message = new Message(mqProperties.getTopic(), tags, data.getBytes());
try {
SendResult sendResult = producer.send(message);
log.info("发送至阿里云成功--->{}", sendResult.getMessageId());
} catch (ONSClientException e) {
log.error("[ERROR]", e);
}
}
}
}
```
##### 接收端:
```java
import com.aliyun.openservices.ons.api.Action;
import com.aliyun.openservices.ons.api.ConsumeContext;
import com.aliyun.openservices.ons.api.Message;
import com.aliyun.openservices.ons.api.MessageListener;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class PushMessageListener implements MessageListener {
@Value("${bdid}")
private String bdid;
@Override
public Action consume(Message message, ConsumeContext consumeContext) {
try {
if (bdid.equals(message.getTag())) {
String pushMessageStr = new String(message.getBody());
log.debug("从MQ接收到的消息为------->{}", pushMessageStr);
log.info("消费成功");
}
return Action.CommitMessage;
} catch (Exception e) {
// 消费失败,重发
log.error("[ERROR]", e);
return Action.ReconsumeLater;
}
}
}
```
***注意:其中tags是用来分别不同医院,进行数据隔离***
#### 2) 负载均衡
目前,我们大多数项目采用阿里负载均衡,一是方便的管理域名证书,二是图形化界面操作简便,可配置多台阿里服务器负载:
1.创建负载均衡实例(基本上已经创建);
2.域名解析:将指定域名解析至负载均衡服务器ip;
3.点击添加监听:
4.跟着步骤设置
5.关闭健康检查(因为发布会扰乱正常访问)
6.点击提交即可完成负载均衡配置。
#### 3) OSS的使用
OSS的只需要调用接口传文件到阿里云服务器,然后返回给前端链接地址:
```java
public String uploadObject(String filePath,
String fileName,
InputStream fileContent,
String contentType) {
OSSClient ossClient = new OSSClient(endPoint, accessId, accessKey);
ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setContentType(contentType);
try {
ossClient.putObject(bucketName, filePath + fileName, fileContent, objectMetadata);
return "https://" +
bucketName + "." +
endPoint.substring(endPoint.lastIndexOf("/") + 1) +
"/" + filePath + fileName;
} catch (OSSException | ClientException oe) {
log.error("[ERROR]", oe);
} finally {
ossClient.shutdown();
}
return null;
}
```
#### 4) 短信发送
短信发送阿里云官方有代码演示:http://ytx-sdk.oss-cn-shanghai.aliyuncs.com/dysms_java.zip?spm=a2c4g.11186623.2.16.654c157bCQichE&file=dysms_java.zip
***注意:模板需要提前发起审核,签名名称必填审核通过才可用。***
### 3.腾讯云相关
#### 1) 直播
直播主要是推流和拉流,采用rtmp://协议;
git Demo地址https://github.com/tencentyun/MLVBSDK ,里面有直播详细介绍和配置方式。
#### 2) 人脸识别
在线版:参考腾讯云官方文档:https://cloud.tencent.com/document/product/867/32770
离线版(百度):参考宋庆龄幼儿园人脸识别https://code.aliyun.com/DestroyKing/morning-check.git ,授权一台服务器(Windows)需要299元,永久;
#### 3) 语音识别、云点播、事实音视频
语音识别腾讯云提供接口,调用如下:
```java
@Override
public String getVoiceText(Long hospitalId, String voiceUrl) {
HospitalConfigEntity hospitalConfig = (HospitalConfigEntity) redisUtil.get(CommonConst.HOSPITAL_CONFIG_PRE + hospitalId);
Credential cred = new Credential(hospitalConfig.getTencentSecretId(), hospitalConfig.getTencentSecretKey());
HttpProfile httpProfile = new HttpProfile();
httpProfile.setEndpoint("asr.tencentcloudapi.com");
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
AsrClient client = new AsrClient(cred, "", clientProfile);
CreateRecTaskRequest req = CreateRecTaskRequest.fromJsonString(this.getVoiceParams(voiceUrl).toJSONString(), CreateRecTaskRequest.class);
CreateRecTaskResponse resp = null;
try {
resp = client.CreateRecTask(req);
} catch (TencentCloudSDKException e) {
log.error("语音转文字失败:{}", e.getMessage());
return "语音转文字失败" + e.getMessage();
}
Long taskId = resp.getData().getTaskId();
return this.getResult(hospitalConfig, taskId);
}
private JSONObject getVoiceParams(String voiceUrl) {
JSONObject params = new JSONObject();
params.put("EngineModelType", "8k_zh");
params.put("ChannelNum", 1);
params.put("ResTextFormat", 0);
params.put("SourceType", 0);
params.put("Url", voiceUrl);
params.put("FilterModal", 1);
return params;
}
private String getResult(HospitalConfigEntity hospitalConfig, Long taskId) {
Credential cred = new Credential(hospitalConfig.getTencentSecretId(), hospitalConfig.getTencentSecretKey());
HttpProfile httpProfile = new HttpProfile();
httpProfile.setEndpoint("asr.tencentcloudapi.com");
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
AsrClient client = new AsrClient(cred, "", clientProfile);
String params = "{\"TaskId\":" + taskId + "}";
DescribeTaskStatusRequest req = DescribeTaskStatusRequest.fromJsonString(params, DescribeTaskStatusRequest.class);
DescribeTaskStatusResponse resp = null;
int tryCount = 20;
while (tryCount > 0) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
resp = client.DescribeTaskStatus(req);
/**
* "Data": {
* "TaskId": 738145629,
* "Status": 1,
* "StatusStr": "doing",
* "Result": "",
* "ResultDetail": null,
* "ErrorMsg": ""
* }
*/
if (resp.getData().getStatus() == 2) {
break;
}
} catch (TencentCloudSDKException e) {
log.error("语音转文字失败:{}", e.getMessage());
return "语音转文字失败" + e.getMessage();
}
tryCount--;
}
return resp.getData().getResult().replaceAll("\\[0:\\d+.\\d+,0:\\d+.\\d+\\]\\s+", "").replaceAll("\n", ",");
}
```
其他请参考线上问诊项目:https://code.aliyun.com/HospitalBU/online-consultation-inquiry.git
*建议使用本地数据库测试,docker开启*