From 8a965e2e55e35d977dfec5aaa8c12597752c1093 Mon Sep 17 00:00:00 2001 From: tanzhisong Date: Wed, 19 Feb 2025 18:11:51 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- jeecg-module-miniapp/pom.xml | 15 ++ .../jeecg/modules/miniapp/utils/BaiduOCRUtil.java | 168 +++++++++++++++++++++ .../modules/miniapp/utils/HttpRequestUtil.java | 109 +++++++++++++ .../jeecg/modules/miniapp/utils/PdfFormUtils.java | 129 ++++++++++++++++ 4 files changed, 421 insertions(+) create mode 100644 jeecg-module-miniapp/src/main/java/org/jeecg/modules/miniapp/utils/BaiduOCRUtil.java create mode 100644 jeecg-module-miniapp/src/main/java/org/jeecg/modules/miniapp/utils/HttpRequestUtil.java create mode 100644 jeecg-module-miniapp/src/main/java/org/jeecg/modules/miniapp/utils/PdfFormUtils.java diff --git a/jeecg-module-miniapp/pom.xml b/jeecg-module-miniapp/pom.xml index fa41950..5dd69eb 100644 --- a/jeecg-module-miniapp/pom.xml +++ b/jeecg-module-miniapp/pom.xml @@ -34,5 +34,20 @@ pdfbox 2.0.27 + + + + com.itextpdf + itext-core + 8.0.3 + pom + + + + com.itextpdf + forms + 8.0.3 + + diff --git a/jeecg-module-miniapp/src/main/java/org/jeecg/modules/miniapp/utils/BaiduOCRUtil.java b/jeecg-module-miniapp/src/main/java/org/jeecg/modules/miniapp/utils/BaiduOCRUtil.java new file mode 100644 index 0000000..c201ae9 --- /dev/null +++ b/jeecg-module-miniapp/src/main/java/org/jeecg/modules/miniapp/utils/BaiduOCRUtil.java @@ -0,0 +1,168 @@ +package org.jeecg.modules.miniapp.utils; + +import cn.hutool.core.codec.Base64; +import cn.hutool.http.HttpRequest; +import cn.hutool.json.JSONUtil; +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; + + +/** + * @author Tanzs + * @date 2025/2/19 下午4:14 + * @description + */ +@Slf4j +public class BaiduOCRUtil { + + private static final String API_KEY = "ILgowCd9vTRSAEPRPhVvn0Oy"; // API Key + private static final String SECRET_KEY = "pqRPRjUaHvpgupAiPw7YtHaoj2GnE74S"; // Secret Key + private static final String ACCESS_TOKEN_URL = "https://aip.baidubce.com/oauth/2.0/token"; + + + /** + * 身份证识别API + * @param image 文件 url/文件 path + * @param base64 是否为base64 + * @return + * @throws IOException + */ + public static String recognizeIdCardWithImage(String image, String type, boolean base64) throws IOException { + String accessToken = getAccessToken(); + String apiUrl = "https://aip.baidubce.com/rest/2.0/ocr/v1/idcard"; + JSONObject params = new JSONObject(); + if (base64){ + String base64Image = encodeImageToBase64(image); + params.put("image", base64Image); // 使用图片的Base64编码 + }else { + params.put("url", image); // 使用图片的URL + } + params.put("id_card_side", type); // 正反面 front/back + return makePostRequest(apiUrl, accessToken, params); + } + + /** + * 营业执照识别API + * @param image 文件 url/文件 path + * @param base64 是否为base64 + * @return + * @throws IOException + */ + public static String recognizeBusinessLicenseWithImage(String image, boolean base64) throws IOException { + String accessToken = getAccessToken(); + String apiUrl = "https://aip.baidubce.com/rest/2.0/ocr/v1/business_license"; + JSONObject params = new JSONObject(); + if (base64){ + String base64Image = encodeImageToBase64(image); + params.put("image", base64Image); // 使用图片的Base64编码 + }else { + params.put("url", image); // 使用图片的URL + } + return makePostRequest(apiUrl, accessToken, params); + } + + /** + * 车辆合格证识别API + * @param image 文件 url/文件 path + * @param base64 是否为base64 + * @throws IOException + */ + public static String recognizeVehicleCertificateWithImage(String image, boolean base64) throws IOException { + String accessToken = getAccessToken(); + String apiUrl = "https://aip.baidubce.com/rest/2.0/ocr/v1/vehicle_certificate"; + JSONObject params = new JSONObject(); + if (base64){ + String base64Image = encodeImageToBase64(image); + params.put("image", base64Image); // 使用图片的Base64编码 + }else { + params.put("image_url", image); // 使用图片的URL + } + return makePostRequest(apiUrl, accessToken, params); + } + + /** + * 获取访问令牌 + * @return + */ + private static String getAccessToken(){ + String url = ACCESS_TOKEN_URL + "?grant_type=client_credentials&client_id=" + API_KEY + "&client_secret=" + SECRET_KEY; + log.info("百度获取 token 的 URL:" + url); + String response = HttpRequest.post(url).execute().body(); + JSONObject jsonObject = JSONObject.parseObject(response); + log.info("百度获取 token 的响应:" + jsonObject.toString()); + return jsonObject.getString("access_token"); + } + + + /** + * 文件转换成 base64 编码 + * @param imagePath 编码 + * @return + * @throws IOException + */ + private static String encodeImageToBase64(String imagePath) throws IOException { + byte[] imageBytes = Files.readAllBytes(new File(imagePath).toPath()); + return Base64.encode(imageBytes); + } + + /** + * 发送 POST 请求 + * @param apiUrl - 接口的URL + * @param accessToken - 访问令牌 + * @param params - 请求参数 + * @return + * @throws IOException + */ + private static String makePostRequest(String apiUrl, String accessToken, JSONObject params) { + String url = apiUrl + "?access_token=" + accessToken; + log.info("百度 POST 请求的 URL:" + url); +// log.info("百度 POST 请求的参数:" + params.toString()); + String response = HttpRequest.post(url) + .body(jsonToQueryString(params),"application/x-www-form-urlencoded") + .header("Content-Type", "application/x-www-form-urlencoded") + .execute() + .body(); + log.info("百度 POST 请求的响应:" + response); + return response; + } + + public static String jsonToQueryString(JSONObject jsonObject) { + StringBuilder queryString = new StringBuilder(); + for (String key : jsonObject.keySet()) { + queryString.append(key).append("=") + .append(jsonObject.getString(key)); + + // 如果不是最后一个参数,添加 "&" + if (!key.equals(jsonObject.keySet().toArray()[jsonObject.size() - 1])) { + queryString.append("&"); + } + } + return queryString.toString(); + } + + + + /** + * 调试 + * @param args + * @throws IOException + */ + public static void main(String[] args) throws IOException { + // 示例:调用身份证识别API(图片URL) + String idCardResultUrl = recognizeIdCardWithImage("/Users/tanzs/Pictures/cert/font.jpg","front",true); +// String idCardResultUrl = recognizeIdCardWithImage("https://jf.sh.189.cn/minio/gov-miniapp/order_pdf/font.jpg","front",false); + System.out.println("身份证识别结果: " + idCardResultUrl); + + // 示例:调用营业执照识别API(图片URL) +// String businessLicenseResultUrl = recognizeBusinessLicenseWithImage("/Users/tanzs/Pictures/cert/license.jpg",true); +// System.out.println("营业执照识别结果: " + businessLicenseResultUrl); + + // 示例:调用车辆合格证识别API(图片URL) +// String vehicleCertificateResultUrl = recognizeVehicleCertificateWithImage("https://example.com/path_to_vehicle_certificate_image.jpg"); +// System.out.println("车辆合格证识别结果(URL): " + vehicleCertificateResultUrl); + } +} diff --git a/jeecg-module-miniapp/src/main/java/org/jeecg/modules/miniapp/utils/HttpRequestUtil.java b/jeecg-module-miniapp/src/main/java/org/jeecg/modules/miniapp/utils/HttpRequestUtil.java new file mode 100644 index 0000000..344be6d --- /dev/null +++ b/jeecg-module-miniapp/src/main/java/org/jeecg/modules/miniapp/utils/HttpRequestUtil.java @@ -0,0 +1,109 @@ +package org.jeecg.modules.miniapp.utils; + + +import cn.hutool.http.HttpException; +import cn.hutool.http.HttpRequest; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import lombok.extern.slf4j.Slf4j; + +import java.util.HashMap; +import java.util.Map; + +@Slf4j +public class HttpRequestUtil { + + public static JSONObject postBody(String url, String body, String contentType, Map headers){ + log.info("[postBody]Post携带请求体请求方法:url:{},body:{},contentType:{},headers:{}",url,body,contentType,headers); + String res = null; + try { + // 配置请求地址 + HttpRequest post = HttpRequest.post(url) + // 配置请求体以及请求体格式 + .body(body, contentType); + // 配置请求头 + if (headers != null && !headers.isEmpty()){ + for (String key : headers.keySet()) { + post.header(key,headers.get(key)); + } + } + // 获取响应 + res = post.execute().body(); + log.info("[postBody]Post携带请求体请求方法,响应结果:res:{}",res); + } catch (HttpException e) { + log.error("接口调用异常URL{},请求报文:{},响应报文:{}", url,body,res); + throw new RuntimeException(e); + } + JSONObject result = null; + try { + result = JSON.parseObject(res); + } catch (Exception e) { + log.error("接口响应处理异常异常URL{},请求报文:{},响应报文:{}", url,body,res); + throw new RuntimeException(e); + } + log.info("[postBody]Post携带请求体请求方法返回:result:{}",JSON.toJSONString(result)); + return result; + } + + public static JSONObject postFrom(String url, Map params, Map headers){ + log.info("[postFrom]Form表单Post请求方法:url:{},params:{}",url,params); + String res = null; + try { + HttpRequest post = HttpRequest.post(url); + // 配置请求头 + if (headers != null && !headers.isEmpty()){ + for (String key : headers.keySet()) { + post.header(key,headers.get(key)); + } + } + res = post.form(params).execute().body(); + log.info("[postFrom]Form表单Post请求,响应结果:res:{}",res); + } catch (HttpException e) { + log.error("接口调用异常URL{},请求报文:{},响应报文:{}", url,params,res); + throw new RuntimeException(e); + } + JSONObject result = null; + try { + result = JSON.parseObject(res); + } catch (Exception e) { + log.error("接口响应处理异常异常URL{},请求报文:{},响应报文:{}", url,params,res); + throw new RuntimeException(e); + } + log.info("[postFrom]Form表单Post请求方法返回:result:{}",JSON.toJSONString(result)); + return result; + } + + public static JSONObject getFrom(String url, Map params, Map headers){ + log.info("[getFrom]Form表单Get请求方法:url:{},params:{}",url,params); + String res = null; + try { + HttpRequest get = HttpRequest.get(url); + // 配置请求头 + if (headers != null && !headers.isEmpty()){ + for (String key : headers.keySet()) { + get.header(key,headers.get(key)); + } + } + res = get.form(params).execute().body(); + log.info("[getFrom]Form表单Get请求方法,响应结果:res:{}",res); + } catch (HttpException e) { + log.error("接口调用异常URL{},请求报文:{},响应报文:{}", url,params,res); + throw new RuntimeException(e); + } + JSONObject result = null; + try { + result = JSON.parseObject(res); + } catch (Exception e) { + log.error("接口响应处理异常异常URL{},请求报文:{},响应报文:{}", url,params,res); + throw new RuntimeException(e); + } + log.info("[getFrom]Form表单Get请求方法返回:result:{}",JSON.toJSONString(result)); + return result; + } + + public static void main(String[] args) { + HashMap map = new HashMap<>(); + JSONObject result = postFrom("http://36.153.19.254:9001/api/auth/login", map,null); + System.out.println(result); + } +} diff --git a/jeecg-module-miniapp/src/main/java/org/jeecg/modules/miniapp/utils/PdfFormUtils.java b/jeecg-module-miniapp/src/main/java/org/jeecg/modules/miniapp/utils/PdfFormUtils.java new file mode 100644 index 0000000..73b2fa9 --- /dev/null +++ b/jeecg-module-miniapp/src/main/java/org/jeecg/modules/miniapp/utils/PdfFormUtils.java @@ -0,0 +1,129 @@ +package org.jeecg.modules.miniapp.utils; + +import com.itextpdf.forms.PdfAcroForm; +import com.itextpdf.forms.fields.PdfFormField; +import com.itextpdf.kernel.pdf.PdfDocument; +import com.itextpdf.kernel.pdf.PdfReader; +import com.itextpdf.kernel.pdf.PdfWriter; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; + +/** + * @author Tanzs + * @date 2025/2/19 下午3:29 + * @description PDF表单填充工具类 + */ +public class PdfFormUtils { + + + /** + * 通过 pdf 文本域拼接 PDF 表单 + * @param templatePath PDF 表单文件路径 + * @param outputPath 填充后的 PDF 文件路径 + * @param formData 填充的数据,键为表单字段名称,值为填充的值 + * @param fontSize 字体大小 + */ + public static void fillPdfForm(String templatePath, String outputPath, Map formData, float fontSize) { + try (PdfReader reader = new PdfReader(templatePath); + PdfWriter writer = new PdfWriter(outputPath); + PdfDocument pdfDoc = new PdfDocument(reader, writer)) { + + // 获取表单 + PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, true); + + // 填写表单字段 + Map fields = form.getAllFormFields(); + for (String fieldName : fields.keySet()) { + System.out.println("Field name: " + fieldName); + } + for (Map.Entry entry : formData.entrySet()) { + String fieldName = entry.getKey(); + String fieldValue = entry.getValue(); + + // 确保字段存在并填写值 + if (fields.containsKey(fieldName)) { + fields.get(fieldName).setValue(fieldValue); + fields.get(fieldName).setFontSize(fontSize); // 设置字体大小 + } + } + + // 可选:扁平化表单(使字段不可编辑) + form.flattenFields(); + + } catch (IOException e) { + e.printStackTrace(); + } + } + + + /** + * 通过 pdf 文本域拼接 PDF 表单 + * @param templateUrl PDF 表单文件 URL,例如 "https://example.com/template.pdf" + * @param outputPath 填充后的 PDF 文件路径 + * @param formData 填充的数据,键为表单字段名称,值为填充的值 + * @param fontSize 字体大小 + */ + public static void fillPdfFormFromUrl(String templateUrl, String outputPath, Map formData, float fontSize) { + try { + // 从 URL 获取输入流 + URL url = new URL(templateUrl); + try (InputStream templateInputStream = url.openStream(); + PdfWriter writer = new PdfWriter(outputPath); + PdfDocument pdfDoc = new PdfDocument(new PdfReader(templateInputStream), writer)) { + + // 获取表单 + PdfAcroForm form = PdfAcroForm.getAcroForm(pdfDoc, true); + + // 填写表单字段 + Map fields = form.getAllFormFields(); + for (String fieldName : fields.keySet()) { + System.out.println("Field name: " + fieldName); + } + for (Map.Entry entry : formData.entrySet()) { + String fieldName = entry.getKey(); + String fieldValue = entry.getValue(); + + // 确保字段存在并填写值 + if (fields.containsKey(fieldName)) { + fields.get(fieldName).setValue(fieldValue); + fields.get(fieldName).setFontSize(fontSize); // 设置字体大小 + } + } + + // 可选:扁平化表单(使字段不可编辑) + form.flattenFields(); + + } catch (IOException e) { + e.printStackTrace(); + } + + } catch (IOException e) { + e.printStackTrace(); + } + } + + + // 示例:调用此工具类 + public static void main(String[] args) { + String templatePath = "/Users/tanzs/Downloads/carT.pdf"; + String templateUrl = "https://jf.sh.189.cn/minio/gov-miniapp/order_pdf/carT.pdf"; + String outputPath = "/Users/tanzs/Downloads/carR.pdf"; + float fontSize = 6.5f; // 设置字体大小 + + // 填写的数据 + Map formData = new HashMap(); + formData.put("name", "张三"); + formData.put("idCard", "123213"); + formData.put("carNo", "京A12345"); + formData.put("phone", "19921199563"); + + // 调用工具类进行表单填写 +// fillPdfForm(templatePath, outputPath, formData, fontSize); + fillPdfFormFromUrl(templateUrl, outputPath, formData, fontSize); + } + +}