当前位置:网站首页>百度图片识别自定义实现(替代AipOcr)
百度图片识别自定义实现(替代AipOcr)
2022-04-23 14:03:00 【洒了脱】
package com.visy.service;
import com.baidu.aip.util.Base64Util;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.visy.exception.ErrorEnum;
import com.visy.exception.BusinessException;
import com.visy.config.BaiduConfig;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* 百度图片识别自定义实现(替代AipOcr)
* @author visy.wang
* @date 2022/1/19 9:24
*/
@Slf4j
@Service
public class AipOcrClient {
private static long expireTime = 0L; //token过期时间戳
private static String accessToken = null; //token值
@Autowired
private BaiduConfig baiduConfig; //百度认证信息,配置自己的apiKey和secretKey
@Autowired
private RestTemplate restTemplate;
//Url管理枚举
@Getter
@AllArgsConstructor
enum UrlKey {
ACCESS_TOKEN("https://aip.baidubce.com/oauth/2.0/token", "认证地址"),
DRIVING_LICENSE("https://aip.baidubce.com/rest/2.0/ocr/v1/driving_license", "驾驶证识别地址"),
VEHICLE_LICENSE("https://aip.baidubce.com/rest/2.0/ocr/v1/vehicle_license", "行驶证识别地址");
private final String url;
private final String desc;
}
/**
* 驾驶证识别
* @param image 图片(二进制)
* @param options 其他参数
* @return 识别结果
*/
public JSONObject drivingLicense(byte[] image, HashMap<String,String> options){
options.put("image", Base64Util.encode(image));
return request(UrlKey.DRIVING_LICENSE, options);
}
/**
* 驾驶证识别
* @param imageUrl 图片地址
* @param options 其他参数
* @return 识别结果
*/
public JSONObject drivingLicense(String imageUrl, HashMap<String,String> options){
options.put("url", imageUrl);
return request(UrlKey.DRIVING_LICENSE, options);
}
/**
* 行驶证识别
* @param image 图片(二进制)
* @param options 其他参数
* @return 识别结果
*/
public JSONObject vehicleLicense(byte[] image, HashMap<String,String> options){
options.put("image", Base64Util.encode(image));
return request(UrlKey.VEHICLE_LICENSE, options);
}
/**
* 行驶证识别
* @param imageUrl 图片地址
* @param options 其他参数
* @return 识别结果
*/
public JSONObject vehicleLicense(String imageUrl, HashMap<String,String> options){
options.put("url", imageUrl);
return request(UrlKey.VEHICLE_LICENSE, options);
}
//带Token过期检查的request,暂不需要,现已计算过期时间并在失效前重新获取
private JSONObject requestWithTokenCheck(UrlKey urlKey, Map<String,String> options){
JSONObject res = request(urlKey, options);
if(res.has("error_code")){
int errCode = res.getInt("error_code");
if(errCode==110 || errCode==111){
accessToken = null; //Token失效,清除并重新获取
return request(urlKey, options);
}
}
return res;
}
/**
* 请求
* @param urlKey url地址枚举
* @param options 其他参数
* @return 识别结果
*/
private JSONObject request(UrlKey urlKey, Map<String,String> options){
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
String url = urlKey.getUrl();
MultiValueMap<String, String> queryStr = getQueryStr(urlKey);
UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(url).queryParams(queryStr);
MultiValueMap<String, Object> formData = new LinkedMultiValueMap<>();
if(Objects.nonNull(options) && !options.isEmpty()){
options.forEach(formData::add);
}
HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(formData, headers);
ResponseEntity<String> res = restTemplate.postForEntity(uriBuilder.toUriString(), request, String.class);
if(!HttpStatus.OK.equals(res.getStatusCode())){
throw buzError("请求失败:httpStatus=" + res.getStatusCode());
}
String resBody = res.getBody();
if(StringUtils.isBlank(resBody)){
throw buzError("响应体为空");
}
return new JSONObject(resBody);
}
private MultiValueMap<String, String> getQueryStr(UrlKey urlKey){
MultiValueMap<String, String> queryStr = new LinkedMultiValueMap<>();
if(UrlKey.ACCESS_TOKEN.equals(urlKey)){
queryStr.add("grant_type", "client_credentials");
queryStr.add("client_id", baiduConfig.getApiKey());
queryStr.add("client_secret", baiduConfig.getSecretKey());
}else{
queryStr.add("access_token", getAccessToken()); //添加认证信息
}
return queryStr;
}
/**
* 获取AccessToken
* @return AccessToken
*/
private String getAccessToken(){
long now = System.currentTimeMillis();
if(StringUtils.isNotBlank(accessToken) && now<expireTime){
//有缓存并在有效期内,直接使用
return accessToken;
}
try{
return getAccessToken(now);
}catch (Exception e){
throw buzError("AccessToken获取失败:" + e.getMessage());
}
}
private String getAccessToken(long now){
log.info("正在重新获取AccessToken...");
JSONObject body = request(UrlKey.ACCESS_TOKEN, null);
if(body.has("error")){
throw buzError(body.getString("error_description"));
}
int tokenExpires = body.getInt("expires_in"); //有效期,单位秒,默认30天
expireTime = now + (tokenExpires-86400L)*1000L; //提前1天失效
accessToken = body.getString("access_token"); //缓存token
log.info("认证成功,有效期至:{}", new Date(expireTime));
return accessToken;
}
/**
* 抛出业务异常
* @param errMsg 错误信息
* @return 业务异常
*/
private BusinessException buzError(String errMsg){
//BusinessException: 自定义业务异常
return new BusinessException(ErrorEnum.BUSINESS_ERR.getCode(), errMsg);
}
}
package com.visy.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* @author visy.wang
* @date 2022/1/19 9:28
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "baidu")
public class BaiduConfig {
private String appId;
private String apiKey;
private String secretKey;
}
版权声明
本文为[洒了脱]所创,转载请带上原文链接,感谢
https://blog.csdn.net/xhom_w/article/details/122583189
边栏推荐
- Quartus prime hardware experimental development (de2-115 board) experiment 1 CPU instruction calculator design
- FBS(fman build system)打包
- 基于ibeacons三点定位(微信小程序)
- RobotFramework 之 公共变量
- Node接入支付宝开放平台的沙箱实现支付功能
- The latest development of fed digital currency
- Basic knowledge learning record
- Chapter I review of e-commerce spike products
- 程序编译调试学习记录
- Crontab timing task output generates a large number of mail and runs out of file system inode problem processing
猜你喜欢
Quartus prime hardware experimental development (de2-115 board) experiment II function adjustable comprehensive timer design
联想产品经理林林:天津当地网络运营商网络故障 ZUI系统后台服务器暂时无法正常工作
CDH cluster integration Phoenix based on CM management
Intégration de Clusters CDH Phoenix basée sur la gestion cm
CentOS mysql多实例部署
There is a mining virus in the server
1256: bouquet for algenon
Elmo (bilstm-crf + Elmo) (conll-2003 named entity recognition NER)
分库分表 & ShardingSphere
Business case | how to promote the activity of sports and health app users? It is enough to do these points well
随机推荐
JS 烧脑面试题大赏
Oracle告警日志alert.log和跟踪trace文件中文乱码显示
SPC简介
leetcode--977. Squares of a Sorted Array
Universal template for scikit learn model construction
Introduction to spark basic operation
读了一篇博客,重新理解闭包整理一下
Neuron and neural network
STM32学习记录0007——新建工程(基于寄存器版)
基於CM管理的CDH集群集成Phoenix
Logging模块
Haruki Murakami -- Excerpt from "what do I talk about when I talk about running"
Un modèle universel pour la construction d'un modèle d'apprentissage scikit
封装logging模块
RobotFramework 之 文件上传和下载
程序编译调试学习记录
网站_收藏
记录一个奇怪的bug:缓存组件跳转之后出现组件复制
nodejs通过require读取本地json文件出现Unexpected token / in JSON at position
Go语言 RPC通讯