walker-jdbc-support/walker-jdbc-support-oracle/pom.xml
@@ -5,7 +5,7 @@ <parent> <artifactId>walker-jdbc-support</artifactId> <groupId>com.walkersoft</groupId> <version>2.3.0-SNAPSHOT</version> <version>2.7.18</version> </parent> <modelVersion>4.0.0</modelVersion> walker-ml-openocr/src/main/java/com/walker/openocr/AbstractFaceRecognize.java
New file @@ -0,0 +1,9 @@ package com.walker.openocr; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class AbstractFaceRecognize implements FaceRecognize { protected final transient Logger logger = LoggerFactory.getLogger(this.getClass()); } walker-ml-openocr/src/main/java/com/walker/openocr/FaceDetectResult.java
New file @@ -0,0 +1,123 @@ package com.walker.openocr; public class FaceDetectResult { public int getFaceNum() { return faceNum; } public void setFaceNum(int faceNum) { this.faceNum = faceNum; } public String getFaceToken() { return faceToken; } public void setFaceToken(String faceToken) { this.faceToken = faceToken; } public double getLeft() { return left; } public void setLeft(double left) { this.left = left; } public double getTop() { return top; } public void setTop(double top) { this.top = top; } public double getWidth() { return width; } public void setWidth(double width) { this.width = width; } public double getHeight() { return height; } public void setHeight(double height) { this.height = height; } public double getFaceProbability() { return faceProbability; } public void setFaceProbability(double faceProbability) { this.faceProbability = faceProbability; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public boolean isSmile() { return smile; } public void setSmile(boolean smile) { this.smile = smile; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public boolean isGlasses() { return glasses; } public void setGlasses(boolean glasses) { this.glasses = glasses; } public String getFaceType() { return faceType; } public void setFaceType(String faceType) { this.faceType = faceType; } public double getFaceTypeProbability() { return faceTypeProbability; } public void setFaceTypeProbability(double faceTypeProbability) { this.faceTypeProbability = faceTypeProbability; } private int faceNum = 1; private String faceToken; private double left = 0; private double top = 0; private double width = 0; private double height = 0; private double faceProbability = 0; // 人脸置信度,范围【0~1】,代表这是一张人脸的概率,0最小、1最大 private int age = 0; private boolean smile = false; private String gender = null; // 性别,male:男性 female:女性 private boolean glasses = false; // 是否带眼镜,face_field包含glasses时返回 private String faceType = null; // 人脸类型,human: 真实人脸 cartoon: 卡通人脸 private double faceTypeProbability = 0; // 人脸类型判断正确的置信度,范围【0~1】,0代表概率最小、1代表最大 } walker-ml-openocr/src/main/java/com/walker/openocr/FaceMatchResult.java
New file @@ -0,0 +1,53 @@ package com.walker.openocr; public class FaceMatchResult { /** * 对比人脸结果评分,推荐阈值80分 * @return */ public double getScore() { return score; } public void setScore(double score) { this.score = score; } /** * 获得原始人脸图像token * @return */ public String getSrcToken() { return srcToken; } public void setSrcToken(String srcToken) { this.srcToken = srcToken; } /** * 获得目标人脸图像token * @return */ public String getDestToken() { return destToken; } public void setDestToken(String destToken) { this.destToken = destToken; } private double score = 0; private String srcToken; private String destToken; @Override public String toString() { return "FaceMatchResult{" + "score=" + score + ", srcToken='" + srcToken + '\'' + ", destToken='" + destToken + '\'' + '}'; } } walker-ml-openocr/src/main/java/com/walker/openocr/FaceRecognize.java
New file @@ -0,0 +1,53 @@ package com.walker.openocr; import com.walker.openocr.util.FaceItem; /** * 人脸识别规范定义。 * @author 时克英 * @date 2024-01-30 */ public interface FaceRecognize { /** * 人脸检测 * <pre> * 图片类型 * 1) BASE64:图片的base64值,base64编码后的图片数据,编码后的图片大小不超过2M; * 2) URL:图片的 URL地址( 可能由于网络等原因导致下载图片时间过长); * 3) FACE_TOKEN: 人脸图片的唯一标识,调用人脸检测接口时,会为每个人脸图片赋予一个唯一的FACE_TOKEN,同一张图片多次检测得到的FACE_TOKEN是同一个。 * </pre> * @param image 图像内容,根据type定。 * @param imageType 图像类型 * @param option * @return */ FaceDetectResult detect(String image, String imageType, Object option); // /** // * 两个人脸对比。 // * @return // */ // FaceMatchResult match(); double matchTwoFace(FaceItem face1, FaceItem face2); double matchTwoImageFile(String file1, String file2); /** * 对比两张照片,判断是否同一人 * @param photo_live_base64 * @param imageBase64 * @return */ double matchTwoImageBase64(String photo_live_base64, String imageBase64); /** * 对比两张照片,判断是否同一人,增加了一个输入参数(活体级别) * @param photo_live_base64 * @param imageBase64 * @param livenessControl 活体检测选项:LOW/NORMAL/HIGH * @return */ double matchTwoImageBase64(String photo_live_base64, String imageBase64, String livenessControl); } walker-ml-openocr/src/main/java/com/walker/openocr/support/BaiduFaceRecognize.java
New file @@ -0,0 +1,150 @@ package com.walker.openocr.support; import com.baidu.aip.face.AipFace; import com.baidu.aip.face.MatchRequest; import com.walker.infrastructure.utils.StringUtils; import com.walker.openocr.AbstractFaceRecognize; import com.walker.openocr.FaceDetectResult; import com.walker.openocr.util.FaceItem; import com.walker.openocr.util.FaceUtils; import org.json.JSONObject; import java.util.ArrayList; import java.util.List; public class BaiduFaceRecognize extends AbstractFaceRecognize { // private HashMap<String, String> options; @Override public FaceDetectResult detect(String image, String imageType, Object option) { throw new UnsupportedOperationException("未实现人脸检测接口"); } @Override public double matchTwoFace(FaceItem face1, FaceItem face2){ logger.debug(face1.getFaceToken() + ", " + face2.getFaceToken()); MatchRequest req1 = new MatchRequest(face1.getFaceToken(), "FACE_TOKEN"); MatchRequest req2 = new MatchRequest(face2.getFaceToken(), "FACE_TOKEN"); ArrayList<MatchRequest> requests = new ArrayList<MatchRequest>(); requests.add(req1); requests.add(req2); JSONObject res = client.match(requests); logger.info("matchTwoFace(FaceItem) result = {}", res); return 0; } @Override public double matchTwoImageFile(String file1, String file2){ MatchRequest req1 = new MatchRequest(FaceUtils.getImageBase64(file1), "BASE64"); MatchRequest req2 = new MatchRequest(FaceUtils.getImageBase64(file2), "BASE64"); List<MatchRequest> requests = new ArrayList<MatchRequest>(); requests.add(req1); requests.add(req2); try{ return this.doMatchProcess(requests); } catch(RuntimeException ex){ throw ex; } } @Override public double matchTwoImageBase64(String photo_live_base64, String imageBase64){ // 活体检测选项:LOW/NORMAL/HIGH MatchRequest req1 = new MatchRequest(photo_live_base64, "BASE64","LIVE", "NORMAL","LOW"); MatchRequest req2 = new MatchRequest(imageBase64, "BASE64", "CERT", null, null); ArrayList<MatchRequest> requests = new ArrayList<MatchRequest>(); requests.add(req1); requests.add(req2); try{ return this.doMatchProcess(requests); } catch(RuntimeException ex){ throw ex; } } @Override public double matchTwoImageBase64(String photo_live_base64, String imageBase64, String livenessControl){ // 活体检测选项:LOW/NORMAL/HIGH MatchRequest req1 = new MatchRequest(photo_live_base64, "BASE64","LIVE", "NORMAL",livenessControl); MatchRequest req2 = new MatchRequest(imageBase64, "BASE64", "CERT", null, null); ArrayList<MatchRequest> requests = new ArrayList<MatchRequest>(); requests.add(req1); requests.add(req2); try{ return this.doMatchProcess(requests); } catch(RuntimeException ex){ throw ex; } } private double doMatchProcess(List<MatchRequest> requests){ JSONObject res = client.match(requests); if(res == null){ // logger.error("调用matchTwoImage接口,返回空数据"); throw new RuntimeException("调用matchTwoImage接口,返回空数据"); } logger.info("face match result = {}", res); if(res.getInt("error_code") != 0){ logger.error("调用detect接口,返回错误数据:" + res.getString("error_msg")); throw new RuntimeException(res.getString("error_msg")); } JSONObject result = res.getJSONObject("result"); return result.getDouble("score"); } public void checkFaceClient(){ if(this.client == null){ if(StringUtils.isEmpty(this.appId) || StringUtils.isEmpty(this.apiKey) || StringUtils.isEmpty(this.secretKey)){ throw new IllegalArgumentException("appId, apiKey, secretKey为空,无法初始化百度OCR client!"); } client = new AipFace(this.appId, this.apiKey, this.secretKey); // 可选:设置网络连接参数 client.setConnectionTimeoutInMillis(2000); client.setSocketTimeoutInMillis(60000); // 传入可选参数调用接口 // options = new HashMap<String, String>(); // options.put("language_type", "CHN_ENG"); // options.put("detect_direction", "true"); // options.put("detect_language", "true"); // options.put("probability", "true"); logger.info("百度: AipFace初始化成功"); } } public String getAppId() { return appId; } public void setAppId(String appId) { this.appId = appId; } public String getApiKey() { return apiKey; } public void setApiKey(String apiKey) { this.apiKey = apiKey; } public String getSecretKey() { return secretKey; } public void setSecretKey(String secretKey) { this.secretKey = secretKey; } private String appId; private String apiKey; private String secretKey; private AipFace client; } walker-ml-openocr/src/main/java/com/walker/openocr/util/FaceItem.java
New file @@ -0,0 +1,34 @@ package com.walker.openocr.util; /** * 描述: * @author 时克英 * @date 2020年2月18日 下午9:10:09 */ public class FaceItem { private String faceToken; private double liveScore = 0.0; private String summary; public String getFaceToken() { return faceToken; } public void setFaceToken(String faceToken) { this.faceToken = faceToken; } public double getLiveScore() { return liveScore; } public void setLiveScore(double liveScore) { this.liveScore = liveScore; } public String getSummary() { return summary; } public void setSummary(String summary) { this.summary = summary; } } walker-ml-openocr/src/main/java/com/walker/openocr/util/FaceUtils.java
New file @@ -0,0 +1,28 @@ package com.walker.openocr.util; import org.apache.commons.codec.binary.Base64; import org.springframework.util.FileCopyUtils; import java.io.File; import java.io.IOException; /** * 描述: * @author 时克英 * @date 2020年2月18日 下午10:06:57 */ public class FaceUtils { public static final String getImageBase64(String filePath){ byte[] fileBytes; try { fileBytes = FileCopyUtils.copyToByteArray(new File(filePath)); byte[] fileBase64 = Base64.encodeBase64(fileBytes); return new String(fileBase64); } catch (IOException e) { e.printStackTrace(); return null; } } } walker-ml-openocr/src/test/java/com/walker/openocr/BaiduFaceTest.java
New file @@ -0,0 +1,29 @@ package com.walker.openocr; import com.baidu.aip.face.AipFace; import com.walker.openocr.support.BaiduFaceRecognize; import org.junit.Test; public class BaiduFaceTest { public static final String APP_ID = "18547554"; public static final String API_KEY = "epNhm4LRAhSpDTCB6Wfc8VQO"; public static final String SECRET_KEY = "ICwmmmVQB7A89dhtiPfu0q8OiwDh1Qpb"; private AipFace client = null; private BaiduFaceRecognize faceRecognize = null; @Test public void faceMatch(){ this.faceRecognize = new BaiduFaceRecognize(); this.faceRecognize.setAppId(APP_ID); this.faceRecognize.setApiKey(API_KEY); this.faceRecognize.setSecretKey(SECRET_KEY); this.faceRecognize.checkFaceClient(); // 人脸对比(两张图片) // double score = faceRecognize.matchTwoImageFile("F:/图片/sfz01.jpg", "F:/图片/shl01.jpg"); double score = faceRecognize.matchTwoImageFile("F:/图片/mike.jpg", "F:/图片/mike_card.jpg"); System.out.println("score = " + score); } } walker-pay-support-payunk/src/test/java/com/walker/pay/payunk/TestPayUnkEngine.java
@@ -30,7 +30,7 @@ System.out.println(MoneyUtils.scaleYuan2Accuracy(1)); } @Test // @Test public void payAliAnDf(){ RestTemplate restTemplate = this.getRestTemplate(); PayEngineProvider payEngineProvider = new PayUnkEngineProvider(restTemplate); walker-scheduler/src/test/java/com/walker/scheduler/TestScheduler.java
@@ -7,7 +7,7 @@ public class TestScheduler { @Test // @Test public void testEveryDayOnce(){ EveryDayScheduler scheduler = new EveryDayScheduler(1, "机构信息同步"); Option option = new Option(); walker-web-security/src/main/java/com/walker/web/security/DefaultAccessDeniedHandler.java
@@ -1,7 +1,6 @@ package com.walker.web.security; import com.walker.infrastructure.utils.JsonUtils; import com.walker.web.ResponseCode; import com.walker.web.ResponseValue; import com.walker.web.util.ServletUtils; import org.slf4j.Logger; @@ -27,7 +26,8 @@ public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { String msg = "已认证,但未分配系统权限:" + request.getRequestURI(); try { ServletUtils.renderString(response, JsonUtils.objectToJsonString(ResponseValue.error(ResponseCode.NO_PERMISSION.getCode(), msg))); // ServletUtils.renderString(response, JsonUtils.objectToJsonString(ResponseValue.error(ResponseCode.NO_PERMISSION.getCode(), msg))); ServletUtils.renderString(response, JsonUtils.objectToJsonString(ResponseValue.error(msg))); } catch (Exception e) { logger.error("未分配系统权限:" + request.getRequestURI()); } walker-web/src/main/java/com/walker/web/ResponseCode.java
@@ -11,7 +11,7 @@ * 对后台普通异常,前端仅返回一个提示,而且不会弹出到界面,主要用于接口反馈。 * @date 2024-01-05 */ EXCEPTION(-1, "系统错误"), EXCEPTION(-9, "系统错误"), /* 成功 */ SUCCESS(1, "success"), walker-web/src/main/java/com/walker/web/annotation/RepeatSubmit.java
@@ -22,7 +22,7 @@ /** * 间隔时间(ms),小于此时间视为重复提交 */ public int interval() default 5000; public int interval() default 2000; /** * 提示消息