@@ -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(); | WxMpWifiService getWifiService(); | ||||
/** | |||||
* 返回WIFI接口方法的实现类对象,以方便调用其各个接口. | |||||
* | |||||
* @return WxMpWifiService | |||||
*/ | |||||
WxMpOcrService getOcrService(); | |||||
void setKefuService(WxMpKefuService kefuService); | void setKefuService(WxMpKefuService kefuService); | ||||
void setMaterialService(WxMpMaterialService materialService); | void setMaterialService(WxMpMaterialService materialService); | ||||
@@ -527,6 +534,8 @@ public interface WxMpService { | |||||
void setMarketingService(WxMpMarketingService marketingService); | 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 WxMpWifiService wifiService = new WxMpWifiServiceImpl(this); | ||||
private WxMpMarketingService marketingService = new WxMpMarketingServiceImpl(this); | private WxMpMarketingService marketingService = new WxMpMarketingServiceImpl(this); | ||||
private WxMpCommentService commentService = new WxMpCommentServiceImpl(this); | private WxMpCommentService commentService = new WxMpCommentServiceImpl(this); | ||||
private WxMpOcrService ocrService = new WxMpOcrServiceImpl(this); | |||||
private Map<String, WxMpConfigStorage> configStorageMap; | private Map<String, WxMpConfigStorage> configStorageMap; | ||||
@@ -600,6 +601,11 @@ public abstract class BaseWxMpServiceImpl<H, P> implements WxMpService, RequestH | |||||
return this.wifiService; | return this.wifiService; | ||||
} | } | ||||
@Override | |||||
public WxMpOcrService getOcrService() { | |||||
return this.ocrService; | |||||
} | |||||
@Override | @Override | ||||
public WxMpMarketingService getMarketingService() { | public WxMpMarketingService getMarketingService() { | ||||
return this.marketingService; | return this.marketingService; | ||||
@@ -610,6 +616,11 @@ public abstract class BaseWxMpServiceImpl<H, P> implements WxMpService, RequestH | |||||
this.marketingService = marketingService; | this.marketingService = marketingService; | ||||
} | } | ||||
@Override | |||||
public void setOcrService(WxMpOcrService ocrService) { | |||||
this.ocrService = ocrService; | |||||
} | |||||
@Override | @Override | ||||
public WxMpCommentService getCommentService() { | public WxMpCommentService getCommentService() { | ||||
return this.commentService; | 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 | @AllArgsConstructor | ||||
enum Card implements WxMpApiUrl { | 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); | |||||
} | |||||
} | |||||
} |