package com.zy.asrs.service.impl;
|
|
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONObject;
|
import com.baomidou.mybatisplus.mapper.EntityWrapper;
|
import com.core.common.Cools;
|
import com.zy.asrs.entity.LocDetl;
|
import com.zy.asrs.service.InboundCameraCaptureService;
|
import com.zy.asrs.service.LocDetlService;
|
import com.zy.system.entity.Config;
|
import com.zy.system.service.ConfigService;
|
import lombok.extern.slf4j.Slf4j;
|
import okhttp3.MediaType;
|
import okhttp3.OkHttpClient;
|
import okhttp3.Request;
|
import okhttp3.RequestBody;
|
import okhttp3.Response;
|
import okhttp3.ResponseBody;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Service;
|
|
import java.text.SimpleDateFormat;
|
import java.util.ArrayList;
|
import java.util.Date;
|
import java.util.LinkedHashSet;
|
import java.util.List;
|
import java.util.Set;
|
import java.util.concurrent.TimeUnit;
|
|
@Slf4j
|
@Service
|
public class InboundCameraCaptureServiceImpl implements InboundCameraCaptureService {
|
|
private static final String CONFIG_CODE = "InboundCameraCapture";
|
private static final MediaType JSON_MEDIA_TYPE = MediaType.parse("application/json;charset=utf-8");
|
private static final OkHttpClient HTTP_CLIENT = new OkHttpClient.Builder()
|
.connectTimeout(5, TimeUnit.SECONDS)
|
.readTimeout(10, TimeUnit.SECONDS)
|
.build();
|
|
@Autowired
|
private ConfigService configService;
|
|
@Autowired
|
private LocDetlService locDetlService;
|
|
@Override
|
public String capture(Integer sourceStaNo, String locNo, String barcode) {
|
CaptureConfig config = loadConfig();
|
if (config == null || !config.enabled) {
|
return null;
|
}
|
if (sourceStaNo == null) {
|
log.warn("入库抓拍配置跳过:sourceStaNo为空");
|
return null;
|
}
|
JSONArray cameras = config.stations.getJSONArray(String.valueOf(sourceStaNo));
|
if (Cools.isEmpty(cameras)) {
|
log.warn("入库抓拍配置缺失:sourceStaNo={}", sourceStaNo);
|
return null;
|
}
|
if (cameras.size() != 2) {
|
log.warn("入库抓拍摄像头数量不是2:sourceStaNo={}, count={}", sourceStaNo, cameras.size());
|
}
|
|
String baseName = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())
|
+ "_" + sanitize(String.valueOf(sourceStaNo))
|
+ "_" + sanitize(locNo)
|
+ "_" + sanitize(barcode);
|
List<String> successPics = new ArrayList<>();
|
for (int i = 0; i < cameras.size(); i++) {
|
JSONObject camera = cameras.getJSONObject(i);
|
if (camera == null) {
|
continue;
|
}
|
String picName = baseName + "-" + (i + 1) + ".jpg";
|
if (captureOne(config.captureUrl, sourceStaNo, i + 1, camera, picName)) {
|
successPics.add(picName);
|
}
|
}
|
return successPics.isEmpty() ? null : JSON.toJSONString(successPics);
|
}
|
|
@Override
|
public List<String> resolvePicUrls(String pic) {
|
CaptureConfig config = loadConfig();
|
String prefix = config == null ? "" : config.imageUrlPrefix;
|
Set<String> urls = new LinkedHashSet<>();
|
for (String picName : parsePicNames(pic)) {
|
if (Cools.isEmpty(picName)) {
|
continue;
|
}
|
if (picName.startsWith("http://") || picName.startsWith("https://")) {
|
urls.add(picName);
|
} else if (!Cools.isEmpty(prefix)) {
|
urls.add(prefix + picName);
|
}
|
}
|
return new ArrayList<>(urls);
|
}
|
|
@Override
|
public List<String> resolveLocPicUrls(String locNo) {
|
if (Cools.isEmpty(locNo)) {
|
return new ArrayList<>();
|
}
|
List<LocDetl> locDetls = locDetlService.selectList(new EntityWrapper<LocDetl>().eq("loc_no", locNo));
|
Set<String> urls = new LinkedHashSet<>();
|
for (LocDetl locDetl : locDetls) {
|
urls.addAll(resolvePicUrls(locDetl.getPic()));
|
}
|
return new ArrayList<>(urls);
|
}
|
|
private boolean captureOne(String captureUrl, Integer sourceStaNo, int index, JSONObject camera, String picName) {
|
String ip = camera.getString("ip");
|
if (Cools.isEmpty(ip)) {
|
log.warn("入库抓拍摄像头IP为空:sourceStaNo={}, cameraIndex={}", sourceStaNo, index);
|
return false;
|
}
|
JSONObject requestJson = new JSONObject();
|
requestJson.put("ip", ip);
|
requestJson.put("port", defaultInt(camera.getInteger("port"), 554));
|
requestJson.put("user", defaultString(camera.getString("user"), "admin"));
|
requestJson.put("password", defaultString(camera.getString("password"), "a327482030"));
|
requestJson.put("picName", picName);
|
|
try {
|
RequestBody body = RequestBody.create(JSON_MEDIA_TYPE, requestJson.toJSONString());
|
Request request = new Request.Builder()
|
.url(captureUrl)
|
.post(body)
|
.build();
|
try (Response response = HTTP_CLIENT.newCall(request).execute()) {
|
ResponseBody responseBody = response.body();
|
String bodyText = responseBody == null ? "" : responseBody.string();
|
if (!response.isSuccessful()) {
|
log.warn("入库抓拍HTTP失败:sourceStaNo={}, cameraIndex={}, ip={}, httpCode={}, picName={}",
|
sourceStaNo, index, ip, response.code(), picName);
|
return false;
|
}
|
JSONObject result = JSON.parseObject(bodyText);
|
Integer code = result == null ? null : result.getInteger("code");
|
if (code != null && code == 200) {
|
return true;
|
}
|
String msg = result == null ? bodyText : result.getString("msg");
|
log.warn("入库抓拍返回失败:sourceStaNo={}, cameraIndex={}, ip={}, code={}, msg={}, picName={}",
|
sourceStaNo, index, ip, code, msg, picName);
|
return false;
|
}
|
} catch (Exception e) {
|
log.warn("入库抓拍异常:sourceStaNo={}, cameraIndex={}, ip={}, picName={}",
|
sourceStaNo, index, ip, picName, e);
|
return false;
|
}
|
}
|
|
private CaptureConfig loadConfig() {
|
Config config = configService.selectConfigByCode(CONFIG_CODE);
|
if (config == null || Cools.isEmpty(config.getValue())) {
|
return null;
|
}
|
if (config.getStatus() != null && config.getStatus() == 0) {
|
return null;
|
}
|
try {
|
JSONObject json = JSON.parseObject(config.getValue());
|
CaptureConfig captureConfig = new CaptureConfig();
|
Boolean enabled = json.getBoolean("enabled");
|
captureConfig.enabled = enabled == null || enabled;
|
captureConfig.captureUrl = json.getString("captureUrl");
|
captureConfig.imageUrlPrefix = normalizePrefix(json.getString("imageUrlPrefix"), captureConfig.captureUrl);
|
captureConfig.stations = json.getJSONObject("stations");
|
if (Cools.isEmpty(captureConfig.captureUrl) || captureConfig.stations == null) {
|
log.warn("入库抓拍配置不完整:code={}", CONFIG_CODE);
|
return null;
|
}
|
return captureConfig;
|
} catch (Exception e) {
|
log.warn("入库抓拍配置解析失败:code={}", CONFIG_CODE, e);
|
return null;
|
}
|
}
|
|
private List<String> parsePicNames(String pic) {
|
List<String> names = new ArrayList<>();
|
if (Cools.isEmpty(pic)) {
|
return names;
|
}
|
try {
|
Object parsed = JSON.parse(pic);
|
if (parsed instanceof JSONArray) {
|
JSONArray array = (JSONArray) parsed;
|
for (int i = 0; i < array.size(); i++) {
|
names.add(array.getString(i));
|
}
|
return names;
|
}
|
if (parsed instanceof String) {
|
names.add((String) parsed);
|
return names;
|
}
|
} catch (Exception ignored) {
|
// 兼容旧数据中直接存单个文件名或逗号分隔文件名的情况。
|
}
|
String[] split = pic.split(",");
|
for (String item : split) {
|
if (!Cools.isEmpty(item)) {
|
names.add(item.trim());
|
}
|
}
|
return names;
|
}
|
|
private String normalizePrefix(String imageUrlPrefix, String captureUrl) {
|
String prefix = imageUrlPrefix;
|
if (Cools.isEmpty(prefix) && !Cools.isEmpty(captureUrl)) {
|
int idx = captureUrl.lastIndexOf("/");
|
prefix = idx > "http://".length() ? captureUrl.substring(0, idx) + "/image/" : "";
|
}
|
if (!Cools.isEmpty(prefix) && !prefix.endsWith("/")) {
|
prefix = prefix + "/";
|
}
|
return prefix;
|
}
|
|
private String sanitize(String value) {
|
if (value == null) {
|
return "null";
|
}
|
return value.replaceAll("[\\\\/:*?\"<>|\\s]+", "_");
|
}
|
|
private int defaultInt(Integer value, int defaultValue) {
|
return value == null ? defaultValue : value;
|
}
|
|
private String defaultString(String value, String defaultValue) {
|
return Cools.isEmpty(value) ? defaultValue : value;
|
}
|
|
private static class CaptureConfig {
|
private boolean enabled;
|
private String captureUrl;
|
private String imageUrlPrefix;
|
private JSONObject stations;
|
}
|
}
|