| @@ -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 <a href="https://github.com/binarywang">Binary Wang</a> | |||
| * @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; | |||
| } | |||
| @@ -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); | |||
| /** | |||
| * 返回评论数据管理接口方法的实现类对象,以方便调用其各个接口. | |||
| * | |||
| @@ -63,6 +63,7 @@ public abstract class BaseWxMpServiceImpl<H, P> 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<String, WxMpConfigStorage> configStorageMap; | |||
| @@ -600,6 +601,11 @@ public abstract class BaseWxMpServiceImpl<H, P> 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<H, P> implements WxMpService, RequestH | |||
| this.marketingService = marketingService; | |||
| } | |||
| @Override | |||
| public void setOcrService(WxMpOcrService ocrService) { | |||
| this.ocrService = ocrService; | |||
| } | |||
| @Override | |||
| public WxMpCommentService getCommentService() { | |||
| return this.commentService; | |||
| @@ -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 <a href="https://github.com/binarywang">Binary Wang</a> | |||
| * @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; | |||
| } | |||
| } | |||
| @@ -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 <a href="https://github.com/binarywang">Binary Wang</a> | |||
| * @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); | |||
| } | |||
| } | |||
| @@ -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 { | |||
| /** | |||
| @@ -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 <a href="https://github.com/binarywang">Binary Wang</a> | |||
| * @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); | |||
| } | |||
| } | |||
| } | |||