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); + } + } +}