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