diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpOcrService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpOcrService.java
new file mode 100644
index 00000000..1748b553
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpOcrService.java
@@ -0,0 +1,50 @@
+package me.chanjar.weixin.mp.api;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.mp.bean.ocr.WxMpOcrIdCardResult;
+
+import java.io.File;
+
+/**
+ * 基于小程序或 H5 的身份证、银行卡、行驶证 OCR 识别.
+ * https://mp.weixin.qq.com/wiki?t=resource/res_main&id=21516712284rHWMX
+ *
+ * @author Binary Wang
+ * @date 2019-06-22
+ */
+public interface WxMpOcrService {
+ @AllArgsConstructor
+ @Getter
+ enum ImageType {
+ /**
+ * 拍照模型,带背景的图片.
+ */
+ PHOTO("photo"),
+ /**
+ * 扫描模式,不带背景的图片.
+ */
+ SCAN("scan");
+
+ private String type;
+ }
+
+ /**
+ * 身份证OCR识别接口.
+ *
+ * @param imgType 图片类型
+ * @param imgUrl 图片url地址
+ * @throws WxErrorException .
+ */
+ WxMpOcrIdCardResult idCard(ImageType imgType, String imgUrl) throws WxErrorException;
+
+ /**
+ * 身份证OCR识别接口.
+ *
+ * @param imgType 图片类型
+ * @param imgFile 图片文件对象
+ * @throws WxErrorException .
+ */
+ WxMpOcrIdCardResult idCard(ImageType imgType, File imgFile) throws WxErrorException;
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java
index 35debff5..f9d4399a 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/WxMpService.java
@@ -493,6 +493,13 @@ public interface WxMpService {
*/
WxMpWifiService getWifiService();
+ /**
+ * 返回WIFI接口方法的实现类对象,以方便调用其各个接口.
+ *
+ * @return WxMpWifiService
+ */
+ WxMpOcrService getOcrService();
+
void setKefuService(WxMpKefuService kefuService);
void setMaterialService(WxMpMaterialService materialService);
@@ -527,6 +534,8 @@ public interface WxMpService {
void setMarketingService(WxMpMarketingService marketingService);
+ void setOcrService(WxMpOcrService ocrService);
+
/**
* 返回评论数据管理接口方法的实现类对象,以方便调用其各个接口.
*
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java
index 98220cd9..0c7a70cd 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/BaseWxMpServiceImpl.java
@@ -63,6 +63,7 @@ public abstract class BaseWxMpServiceImpl implements WxMpService, RequestH
private WxMpWifiService wifiService = new WxMpWifiServiceImpl(this);
private WxMpMarketingService marketingService = new WxMpMarketingServiceImpl(this);
private WxMpCommentService commentService = new WxMpCommentServiceImpl(this);
+ private WxMpOcrService ocrService = new WxMpOcrServiceImpl(this);
private Map configStorageMap;
@@ -600,6 +601,11 @@ public abstract class BaseWxMpServiceImpl implements WxMpService, RequestH
return this.wifiService;
}
+ @Override
+ public WxMpOcrService getOcrService() {
+ return this.ocrService;
+ }
+
@Override
public WxMpMarketingService getMarketingService() {
return this.marketingService;
@@ -610,6 +616,11 @@ public abstract class BaseWxMpServiceImpl implements WxMpService, RequestH
this.marketingService = marketingService;
}
+ @Override
+ public void setOcrService(WxMpOcrService ocrService) {
+ this.ocrService = ocrService;
+ }
+
@Override
public WxMpCommentService getCommentService() {
return this.commentService;
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpOcrServiceImpl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpOcrServiceImpl.java
new file mode 100644
index 00000000..4d3c434e
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/api/impl/WxMpOcrServiceImpl.java
@@ -0,0 +1,43 @@
+package me.chanjar.weixin.mp.api.impl;
+
+import lombok.RequiredArgsConstructor;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.mp.api.WxMpOcrService;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.bean.ocr.WxMpOcrIdCardResult;
+
+import java.io.File;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+
+import static me.chanjar.weixin.mp.enums.WxMpApiUrl.Ocr.IDCARD;
+
+/**
+ * ocr 接口实现.
+ *
+ * @author Binary Wang
+ * @date 2019-06-22
+ */
+@RequiredArgsConstructor
+public class WxMpOcrServiceImpl implements WxMpOcrService {
+ private final WxMpService wxMpService;
+
+ @Override
+ public WxMpOcrIdCardResult idCard(ImageType imgType, String imgUrl) throws WxErrorException {
+ try {
+ imgUrl = URLEncoder.encode(imgUrl, StandardCharsets.UTF_8.name());
+ } catch (UnsupportedEncodingException e) {
+ // ignore cannot happen
+ }
+
+ final String result = this.wxMpService.get(String.format(IDCARD.getUrl(this.wxMpService.getWxMpConfigStorage()),
+ imgType.getType(), imgUrl), null);
+ return WxMpOcrIdCardResult.fromJson(result);
+ }
+
+ @Override
+ public WxMpOcrIdCardResult idCard(ImageType imgType, File imgFile) {
+ return null;
+ }
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/ocr/WxMpOcrIdCardResult.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/ocr/WxMpOcrIdCardResult.java
new file mode 100644
index 00000000..fb174968
--- /dev/null
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/bean/ocr/WxMpOcrIdCardResult.java
@@ -0,0 +1,33 @@
+package me.chanjar.weixin.mp.bean.ocr;
+
+import com.google.gson.annotations.SerializedName;
+import lombok.Data;
+import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket;
+import me.chanjar.weixin.mp.util.json.WxMpGsonBuilder;
+
+import java.io.Serializable;
+
+/**
+ * OCR身份证识别结果.
+ *
+ * @author Binary Wang
+ * @date 2019-06-23
+ */
+@Data
+public class WxMpOcrIdCardResult implements Serializable {
+ private static final long serialVersionUID = 8184352486986729980L;
+
+ @SerializedName("type")
+ private String type;
+ @SerializedName("name")
+ private String name;
+ @SerializedName("id")
+ private String id;
+ @SerializedName("valid_date")
+ private String validDate;
+
+ public static WxMpOcrIdCardResult fromJson(String json) {
+ return WxMpGsonBuilder.create().fromJson(json, WxMpOcrIdCardResult.class);
+ }
+
+}
diff --git a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java
index 276c1c9e..e6f529d2 100644
--- a/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java
+++ b/weixin-java-mp/src/main/java/me/chanjar/weixin/mp/enums/WxMpApiUrl.java
@@ -426,6 +426,26 @@ public interface WxMpApiUrl {
}
}
+ @AllArgsConstructor
+ enum Ocr implements WxMpApiUrl {
+ /**
+ * 身份证识别.
+ */
+ IDCARD(API_DEFAULT_HOST_URL, "/cv/ocr/idcard?type=%s&img_url=%s");
+
+ private String prefix;
+ private String path;
+
+ @Override
+ public String getUrl(WxMpConfigStorage config) {
+ if (config == null) {
+ return buildUrl(null, prefix, path);
+ }
+
+ return buildUrl(config.getHostConfig(), prefix, path);
+ }
+ }
+
@AllArgsConstructor
enum Card implements WxMpApiUrl {
/**
diff --git a/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpOcrServiceImplTest.java b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpOcrServiceImplTest.java
new file mode 100644
index 00000000..01706065
--- /dev/null
+++ b/weixin-java-mp/src/test/java/me/chanjar/weixin/mp/api/impl/WxMpOcrServiceImplTest.java
@@ -0,0 +1,54 @@
+package me.chanjar.weixin.mp.api.impl;
+
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.mp.api.WxMpOcrService;
+import me.chanjar.weixin.mp.api.WxMpService;
+import me.chanjar.weixin.mp.api.test.ApiTestModule;
+import me.chanjar.weixin.mp.bean.ocr.WxMpOcrIdCardResult;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
+
+import javax.inject.Inject;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * 测试类.
+ *
+ * @author Binary Wang
+ * @date 2019-06-22
+ */
+@Test
+@Guice(modules = ApiTestModule.class)
+public class WxMpOcrServiceImplTest {
+ @Inject
+ private WxMpService mpService;
+
+ @Test
+ public void testIdCard() throws WxErrorException {
+ final WxMpOcrIdCardResult result = this.mpService.getOcrService().idCard(WxMpOcrService.ImageType.PHOTO,
+ "http://www.baidu.com");
+ assertThat(result).isNotNull();
+ System.out.println(result);
+ }
+
+ public static class MockTest {
+ private WxMpService wxService = mock(WxMpService.class);
+
+ @Test
+ public void testIdCard() throws Exception {
+ String returnJson = "{\"type\":\"Back\",\"name\":\"张三\",\"id\":\"110101199909090099\",\"valid_date\":\"20110101-20210201\"}";
+
+ when(wxService.get(anyString(), anyString())).thenReturn(returnJson);
+ final WxMpOcrServiceImpl wxMpOcrService = new WxMpOcrServiceImpl(wxService);
+
+ final WxMpOcrIdCardResult result = wxMpOcrService.idCard(WxMpOcrService.ImageType.PHOTO, "abc");
+ assertThat(result).isNotNull();
+ System.out.println(result);
+ }
+ }
+}