流程图
一、前期准备
1.1 打开百度智能云官网找到管理中心创建应用
全选文字识别
1.2 保存好AppId、API Key和Secret Key
1.3 找到通用场景文字识别,立即使用
1.4 根据自己需要,选择要开通的项目
二、代码编写
以通用文字识别(高精度版)为例
2.1 加依赖(pom.xml)
<dependencies>
<!-- 引入Spring Boot的web starter依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入Lombok依赖 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 引入Spring Boot的测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 百度人工智能依赖 -->
<dependency>
<groupId>com.baidu.aip</groupId>
<artifactId>java-sdk</artifactId>
<version>4.11.3</version>
</dependency>
<!-- okhttp -->
<!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>
<!-- 对象转换成json -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
<!-- thymeleaf模板引擎 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
</dependencies>
2.2 编写yml文件
# 这是一个配置块,用于设置百度OCR服务的认证信息。
baidu:
ocr: # OCR服务的配置项
appId: # 百度OCR服务的应用ID
apiKey: # 百度OCR服务的API密钥
secretKey: # 百度OCR服务的密钥
spring:
thymeleaf:
cache: false
2.3 工具类
package com.baiduocr.util;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
/**
* 这个类定义了全局的异常处理器。
*/
public class GlobalExceptionHandler {
/**
* 处理所有类型的异常。
*
* @param e 异常对象,捕获到的异常会作为参数传入。
* @return 返回一个包含异常信息的ResponseEntity对象,状态码为500(内部服务器错误)。
*/
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleException(Exception e) {
// 构造并返回一个包含异常信息的ResponseEntity对象
return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
package com.baiduocr.util;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Map;
/**
* JsonChange 类提供了将 JSON 字符串转换为 Map 对象的静态方法。
*/
public class JsonChange {
/**
* 将JSON字符串解析为Map对象。
* @param jsonString 待转换的JSON字符串。
* @return 返回一个包含JSON数据的Map对象。
* @throws Exception 如果转换过程中发生错误,则抛出异常。
*/
public static Map<Object, Object> json2map(String jsonString) throws Exception {
// 创建 ObjectMapper 实例用于处理 JSON 字符串
ObjectMapper mapper = new ObjectMapper();
// 设置序列化选项,仅包含非空值
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// 将 JSON 字符串解析为 Map 对象并返回
return mapper.readValue(jsonString, Map.class);
}
}
2.4 Service层
package com.baiduocr.service;
import okhttp3.*;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.IOException;
@Service
public class OcrService {
@Value("${baidu.ocr.appId}")
private String appId;
@Value("${baidu.ocr.apiKey}")
private String apiKey;
@Value("${baidu.ocr.secretKey}")
private String secretKey;
// accessToken
private String accessToken;
// HTTP客户端
static final OkHttpClient HTTP_CLIENT = new OkHttpClient().newBuilder().build();
/**
* 调用百度高精度版OCR接口进行文字识别。
*
* @param imageBytes 待识别的图片字节数组
* @return OCR识别结果
* @throws IOException IO异常
*/
public String performOcr(byte[] imageBytes) throws IOException {
// 设置请求体
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
RequestBody body = RequestBody.create(mediaType, "detect_direction=false¶graph=false&probability=true");
// 创建请求
Request request = new Request.Builder()
.url("https://aip.baidubce.com/rest/2.0/ocr/v1/accurate?access_token=" + accessToken)
.method("POST", body)
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.addHeader("Accept", "application/json")
.build();
// 发送请求并获取响应
Response response = HTTP_CLIENT.newCall(request).execute();
// 返回响应内容
return response.body().string();
}
/**
* 获取百度的Access Token。
*
* @return 百度的Access Token
* @throws IOException IO异常
*/
private String getAccessToken() throws IOException {
// 设置请求体
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
RequestBody body = RequestBody.create(mediaType, "grant_type=client_credentials&client_id=" + apiKey
+ "&client_secret=" + secretKey);
// 创建请求
Request request = new Request.Builder()
.url("https://aip.baidubce.com/oauth/2.0/token")
.method("POST", body)
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.build();
// 发送请求并获取响应
Response response = HTTP_CLIENT.newCall(request).execute();
// 解析响应内容获取Access Token
return new JSONObject(response.body().string()).getString("access_token");
}
}
2.5 eneity层
package com.baiduocr.entity;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* BaiduOcrProperties类用于配置百度OCR服务的相关属性。
* 该类通过@ConfigurationProperties注解与配置文件中的baidu.ocr前缀绑定,
* 使得我们可以从配置文件中动态读取appId, apiKey和secretKey等属性值。
*
* @Configuration 表示这是一个配置类,可以被Spring作为配置源。
* @ConfigurationProperties(prefix = "baidu.ocr") 将该类的属性与配置文件中的baidu.ocr前缀绑定。
* @Data 提供了基于Lombok的自动getter/setter等代码生成,方便属性的访问和设置。
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "baidu.ocr")
public class BaiduOcrProperties {
// 百度OCR的App ID
private String appId;
// 百度OCR的API Key
private String apiKey;
// 百度OCR的Secret Key
private String secretKey;
}
2.6 控制器
package com.baiduocr.controller;
import com.baidu.aip.ocr.AipOcr;
import com.baiduocr.entity.BaiduOcrProperties;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import okhttp3.*;
/**
* OcrController类负责处理OCR相关的请求。
* 它利用百度OCR服务对上传的文件或文本进行识别,并返回识别结果。
*/
@Controller
public class OcrController {
// 创建一个日志记录器
private static final Logger logger = LoggerFactory.getLogger(OcrController.class);
// 注入BaiduOcrProperties对象
private final BaiduOcrProperties baiduOcrProperties;
// 创建一个OkHttpClient对象
static final OkHttpClient HTTP_CLIENT = new OkHttpClient().newBuilder().build();
// 构造函数,注入BaiduOcrProperties对象
@Autowired
public OcrController(BaiduOcrProperties baiduOcrProperties) {
this.baiduOcrProperties = baiduOcrProperties;
}
@RequestMapping(value = {"/", "/ocr"})
public String index() {
return "ocr";
}
/**
* 处理OCR识别请求。
*
* @param file 用户上传的文件,将进行OCR识别。
* @param model Spring模型,用于在识别后向视图传递数据。
* @return 视图名称,根据识别结果决定是显示结果还是错误页面。
*/
@RequestMapping(value = "/doOcr")
public String ocr(MultipartFile file, Model model) {
try {
List<String> ocrResult = performOcr(file); // 执行OCR识别
model.addAttribute("ocrResult", ocrResult); // 将识别结果添加到模型中
} catch (Exception e) {
logger.error("OCR识别失败", e);
return "error"; // 识别失败,返回错误页面
}
return "ocr_result"; // 识别成功,返回结果页面
}
/**
* 执行OCR识别操作。
*
* @param file 需要进行OCR识别的文件。
* @return 识别到的文本列表。
* @throws Exception 如果识别过程中出现错误,则抛出异常。
*/
private List<String> performOcr(MultipartFile file) throws Exception {
logger.info("Performing OCR on file: {}", file.getOriginalFilename()); // 记录日志,表示开始进行OCR识别
AipOcr client = new AipOcr(baiduOcrProperties.getAppId(), baiduOcrProperties.getApiKey(), baiduOcrProperties.getSecretKey()); // 创建百度OCR客户端
// 获取Access Token
String accessToken = getAccessToken();
// 在开发环境中记录Access Token(请在生产环境中移除或注释掉此行)
//logger.debug("Access Token: {}", accessToken);
HashMap<String, String> options = new HashMap<>(); // 设置OCR识别的选项
options.put("language_type", "CHN_ENG");
options.put("detect_direction", "true");
options.put("detect_language", "true");
options.put("probability", "true");
byte[] buf = file.getBytes(); // 从文件中读取内容
JSONObject res = client.basicAccurateGeneral(buf, options); // 使用高精度接口进行通用文字识别
List<String> wordsList = new ArrayList<>(); // 存储识别出的文本
for (Object obj : res.getJSONArray("words_result")) { // 遍历识别结果,提取文本
JSONObject jsonObj = (JSONObject) obj;
wordsList.add(jsonObj.getString("words"));
}
return wordsList;
}
/**
* 从百度OCR服务获取Access Token。
*
* @return Access Token,用于身份验证。
* @throws IOException 如果在获取Access Token过程中出现IO错误。
*/
private String getAccessToken() throws IOException {
MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
RequestBody body = RequestBody.create(mediaType, "grant_type=client_credentials&client_id=" + baiduOcrProperties.getApiKey()
+ "&client_secret=" + baiduOcrProperties.getSecretKey());
Request request = new Request.Builder()
.url("https://aip.baidubce.com/oauth/2.0/token")
.method("POST", body)
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.build();
Response response = HTTP_CLIENT.newCall(request).execute(); // 发送请求,获取响应
return new JSONObject(response.body().string()).getString("access_token"); // 从响应中提取Access Token
}
/**
* 捕获并处理所有异常。
*
* @param e 异常对象。
* @return 响应实体,包含异常信息。
*/
@ExceptionHandler(Exception.class)
public ResponseEntity<String> handleException(Exception e) {
return new ResponseEntity<>(e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR); // 返回内部服务器错误信息
}
}
2.6 前端页面(thymeleaf)
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>OCR识别</title>
</head>
<body>
<h1>上传图片进行OCR识别</h1>
<form th:action="@{/doOcr}" method="post" enctype="multipart/form-data">
<input type="file" name="file" accept="image/*">
<button type="submit">上传并识别</button>
</form>
</body>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
background-color: #f8f9fa;
}
h1 {
color: #343a40;
margin-top: 20px;
}
form {
margin: 20px 0;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 5px;
background-color: #fff;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
input[type="file"] {
margin-bottom: 10px;
}
button {
background-color: #007bff;
color: white;
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
}
button:hover {
background-color: #0056b3;
}
</style>
</html>
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>OCR结果</title>
</head>
<body>
<h1>OCR识别结果</h1>
<div th:if="${ocrResult != null}">
<ul>
<li th:each="word : ${ocrResult}" th:text="${word}"></li>
</ul>
</div>
<a href="/">返回首页</a>
</body>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
background-color: #f8f9fa;
}
h1 {
color: #343a40;
margin-top: 20px;
}
div {
margin: 20px 0;
padding: 20px;
border: 1px solid #dee2e6;
border-radius: 5px;
background-color: #fff;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
width: 80%;
max-width: 800px;
}
ul {
list-style-type: none;
padding: 0;
}
li {
padding: 5px 0;
border-bottom: 1px solid #dee2e6;
}
a {
margin-top: 20px;
color: #007bff;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
</style>
</html>