Index: build.gradle =================================================================== diff -u -r40980 -r41026 --- build.gradle (.../build.gradle) (revision 40980) +++ build.gradle (.../build.gradle) (revision 41026) @@ -423,6 +423,7 @@ compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-hibernate4', version:jacksonVersion compile group: 'com.fasterxml.jackson.jaxrs', name: 'jackson-jaxrs-base', version:jacksonVersion + compile group: 'org.apache.commons', name: 'commons-text', version:'1.10.0' // json-lib 相关的依赖 compile 'oro:oro:2.0.8' compile 'xom:xom:1.2.5' Index: ssts-tousse/src/main/java/com/forgon/disinfectsystem/tousse/videomanager/action/OcrController.java =================================================================== diff -u --- ssts-tousse/src/main/java/com/forgon/disinfectsystem/tousse/videomanager/action/OcrController.java (revision 0) +++ ssts-tousse/src/main/java/com/forgon/disinfectsystem/tousse/videomanager/action/OcrController.java (revision 41026) @@ -0,0 +1,134 @@ +package com.forgon.disinfectsystem.tousse.videomanager.action; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang.StringUtils; +import org.apache.commons.text.similarity.LevenshteinDistance; +import org.apache.log4j.Logger; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.forgon.disinfectsystem.entity.idcarddefinition.IDCardDefinition; +import com.forgon.tools.db.DatabaseUtil; +import com.forgon.tools.hibernate.ObjectDao; +import com.forgon.websocket.WebSocketServer; + +@Controller +@RequestMapping("/ocrController") +public class OcrController { + private static final Logger logger = Logger.getLogger(OcrController.class.getName()); + + private ObjectDao objectDao; + public void setObjectDao(ObjectDao objectDao) { + this.objectDao = objectDao; + } + @RequestMapping(value = "/paddleOCR.mhtml", method = RequestMethod.POST) + @ResponseBody + public ResponseEntity> paddleOCR(@RequestBody OcrDataRequest ocrDataRequest) { + logger.info("接收到SN数据: {} from: {}"+ocrDataRequest.getClientId() + "__"+ocrDataRequest.getConfidence() + "_" + ocrDataRequest.getText()); + // 处理SN数据(保存到数据库等) + String text = fuzzyQueryForThirdPartySignageBarcode(ocrDataRequest.getText()); + // 发送SN码到指定客户端 + String message = String.format("{\"type\":\"ocrData\",\"text\":\"%s\",\"ClientIp\":\"%s\",\"confidence\":\"%s\",\"timestamp\":%d,\"status\":\"success\"}", + text, ocrDataRequest.getClientId(),ocrDataRequest.getConfidence() , System.currentTimeMillis()); + + boolean sent = WebSocketServer.sendTextToClient(ocrDataRequest.getClientId(), message); + + Map response = new HashMap<>(); + if (sent) { + response.put("status", "success"); + response.put("message", "SN数据接收并转发成功"); + response.put("clientId", ocrDataRequest.getClientId()); + response.put("text", ocrDataRequest.getText()); + } else { + response.put("status", "warning"); + response.put("message", "SN数据接收成功,但客户端未连接"); + response.put("clientId", ocrDataRequest.getClientId()); + } + + return ResponseEntity.ok(response); + } + public String fuzzyQueryForThirdPartySignageBarcode(String barcode) { + if(StringUtils.isBlank(barcode)){ + return null; + } + String sbuStr = null; + if(barcode.length() < 5){ + sbuStr = barcode; + }else{//取后半段 + sbuStr = barcode.substring(barcode.length()/2); + } + String sql = "select thirdPartyIdCard from " + + IDCardDefinition.class.getSimpleName() + + " idd where idd.thirdPartyIdCard like '%"+ sbuStr +"'"; + return findBestMatch(barcode, sql); + } + /** + * 获取数据库中最匹配的数据 + * @param barcode + * @param sql + * @return + */ + public String findBestMatch(String barcode, String sql) { + List fuzzyQueryResult = new ArrayList<>(); + ResultSet rs = objectDao.executeSql(sql); + try { + rs = objectDao.executeSql(sql); + while (rs.next()) { + fuzzyQueryResult.add(rs.getString("thirdPartyIdCard")); + } + } catch (SQLException e) { + e.printStackTrace(); + } finally { + DatabaseUtil.closeResultSetAndStatement(rs); + } + + if (fuzzyQueryResult.isEmpty()) { + return barcode; + } else if (fuzzyQueryResult.size() == 1) { + return fuzzyQueryResult.get(0); + } else { + return findMostSimilarWithLibrary(barcode, fuzzyQueryResult); + } + } + /** + * 返回最相似的一个 + * @param target + * @param candidates + * @return + */ + private String findMostSimilarWithLibrary(String target, List candidates) { + LevenshteinDistance levenshtein = new LevenshteinDistance(); + + String bestMatch = candidates.get(0); + int minDistance = levenshtein.apply(target, bestMatch); + + for (int i = 1; i < candidates.size(); i++) { + String candidate = candidates.get(i); + int distance = levenshtein.apply(target, candidate); + + if (distance < minDistance) { + minDistance = distance; + bestMatch = candidate; + } + } + + // 根据距离计算相似度 + double similarity = 1.0 - (double) minDistance / Math.max(target.length(), bestMatch.length()); + + if (similarity >= 0.6) { + return bestMatch; + } else { + return target; + } + } +} \ No newline at end of file Index: ssts-tousse/src/main/java/com/forgon/disinfectsystem/tousse/videomanager/action/OcrDataRequest.java =================================================================== diff -u --- ssts-tousse/src/main/java/com/forgon/disinfectsystem/tousse/videomanager/action/OcrDataRequest.java (revision 0) +++ ssts-tousse/src/main/java/com/forgon/disinfectsystem/tousse/videomanager/action/OcrDataRequest.java (revision 41026) @@ -0,0 +1,40 @@ +package com.forgon.disinfectsystem.tousse.videomanager.action; +/** + * OCR识别结果 + * + */ +public class OcrDataRequest { + /** + * 识别出的文本 + */ + private String text; + /** + * ip + */ + private String clientId; + /** + * 识别的时间 + */ + private Long timestamp; + /** + * 相似度 + */ + private String confidence; + public String getClientId() { return clientId; } + public void setClientId(String clientId) { this.clientId = clientId; } + public Long getTimestamp() { return timestamp; } + public void setTimestamp(Long timestamp) { this.timestamp = timestamp; } + public String getConfidence() { + return confidence; + } + public void setConfidence(String confidence) { + this.confidence = confidence; + } + public String getText() { + return text; + } + public void setText(String text) { + this.text = text; + } + +} Index: forgon-core/src/main/java/com/forgon/websocket/WebSocketServer.java =================================================================== diff -u -r37125 -r41026 --- forgon-core/src/main/java/com/forgon/websocket/WebSocketServer.java (.../WebSocketServer.java) (revision 37125) +++ forgon-core/src/main/java/com/forgon/websocket/WebSocketServer.java (.../WebSocketServer.java) (revision 41026) @@ -189,7 +189,29 @@ logger.debug("发送消息失败:message=" + message); } } - + public static boolean sendTextToClient(String clientId, String message) { + try { + boolean flag = false; + if(MapUtils.isNotEmpty(webSocketClients)){ + for (WebSocketSession session : webSocketClients.values()) { + try{ + session.getSession().getBasicRemote().sendText(message); + logger.info("SN码已发送到客户端: clientId=" + clientId + ", message=" + message); + flag = true; + }catch(Exception e){ + e.printStackTrace(); + logger.debug("发送消息失败:message=" + message); + } + } + } + + return flag; + + } catch (Exception e) { + logger.error("发送SN码到客户端失败: clientId=" + clientId, e); + return false; + } + } public static synchronized int getOnlineCount() { return onlineCount; }