1.引入依赖
<!--内容审核增强版-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>green20220302</artifactId>
<version>2.20.0</version>
</dependency>
2.配置类
@Component
@Data
@ConfigurationProperties(prefix = "aliyun.green")
public class AliyunGreenProperties {
private String accessKeyId;
private String accessKeySecret;
private String endpoint;
private String service;
}
aliyun:
green:
access-key-id: xxxxxxxxxx
access-key-secret: xxxxxxxxxxx
endpoint: green-cip.cn-shanghai.aliyuncs.com
service: baselineCheck # 多个服务用,分割 eg: baselineCheck,baselineCheck_pro
3.工具类
审核工具类
package com.coame.bff.integration.aliyun.green;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
@Data
public class ImageModerationResult {
private String dataId;
private String riskLevel;
private final List<LabelResult> results = new ArrayList<>();
private final List<ServiceResult> serviceResults = new ArrayList<>();
public void addResult(String label, Float confidence) {
results.add(new LabelResult(label, confidence));
}
public void addServiceResult(ServiceResult serviceResult) {
serviceResults.add(serviceResult);
}
public boolean isRiskByConfidence(float threshold) {
return results.stream().anyMatch(r -> r.confidence != null && r.confidence >= threshold)
|| serviceResults.stream()
.flatMap(sr -> sr.getResultList().stream())
.anyMatch(r -> r.confidence != null && r.confidence >= threshold);
}
public boolean isHighRisk() {
return "high".equalsIgnoreCase(riskLevel)
|| serviceResults.stream().anyMatch(sr -> "high".equalsIgnoreCase(sr.getRiskLevel()));
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("审核结果:\n");
sb.append("dataId: ").append(dataId).append("\n");
sb.append("== 通用结果 ==\n");
for (LabelResult r : results) {
sb.append("label: ").append(r.label).append(", confidence: ").append(r.confidence).append("\n");
}
sb.append("== 各服务细分结果 ==\n");
for (ServiceResult sr : serviceResults) {
sb.append("Service: ").append(sr.service).append(", RiskLevel: ").append(sr.riskLevel).append("\n");
for (LabelResult lr : sr.resultList) {
sb.append(" label: ").append(lr.label).append(", confidence: ").append(lr.confidence).append("\n");
}
}
return sb.toString();
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class LabelResult {
private String label;
private Float confidence;
}
@Data
@NoArgsConstructor
public static class ServiceResult {
private String service;
private String riskLevel;
private List<LabelResult> resultList = new ArrayList<>();
public ServiceResult(String service, String riskLevel) {
this.service = service;
this.riskLevel = riskLevel;
}
public void addLabelResult(String label, Float confidence) {
resultList.add(new LabelResult(label, confidence));
}
}
}
package com.coame.bff.integration.aliyun.green;
import com.alibaba.fastjson.JSON;
import com.aliyun.green20220302.Client;
import com.aliyun.green20220302.models.ImageBatchModerationRequest;
import com.aliyun.green20220302.models.ImageBatchModerationResponse;
import com.aliyun.green20220302.models.ImageBatchModerationResponseBody;
import com.aliyun.green20220302.models.ImageBatchModerationResponseBody.ImageBatchModerationResponseBodyData;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@Component
public class ImageModerationUtil {
@Resource
private AliyunGreenProperties properties;
private static String accessKeyId;
private static String accessKeySecret;
private static String endpoint;
private static String service;
@PostConstruct
public void init() {
accessKeyId = properties.getAccessKeyId();
accessKeySecret = properties.getAccessKeySecret();
endpoint = properties.getEndpoint();
service = properties.getService();
}
/**
* 创建阿里云内容安全客户端
*/
private static Client createClient() throws Exception {
Config config = new Config();
config.setAccessKeyId(accessKeyId);
config.setAccessKeySecret(accessKeySecret);
config.setEndpoint(endpoint);
return new Client(config);
}
/**
* 审核图片
*
* @param imageUrl 图片地址
* @return 审核结果(完整结构)
*/
public static ImageModerationResult moderateImage(String imageUrl) {
try {
Client client = createClient();
RuntimeOptions runtime = new RuntimeOptions();
Map<String, String> serviceParameters = new HashMap<>();
serviceParameters.put("imageUrl", imageUrl);
serviceParameters.put("dataId", UUID.randomUUID().toString());
ImageBatchModerationRequest request = new ImageBatchModerationRequest();
request.setService(service);
request.setServiceParameters(JSON.toJSONString(serviceParameters));
ImageBatchModerationResponse response = client.imageBatchModerationWithOptions(request, runtime);
if (response.getStatusCode() == 200) {
ImageBatchModerationResponseBody body = response.getBody();
if (body.getCode() == 200) {
ImageBatchModerationResponseBodyData data = body.getData();
ImageModerationResult result = new ImageModerationResult();
result.setDataId(data.getDataId());
result.setRiskLevel(data.getRiskLevel());
// 通用结果 Data.Result
List<ImageBatchModerationResponseBody.ImageBatchModerationResponseBodyDataResult> generalResults = data.getResult();
if (generalResults != null) {
for (ImageBatchModerationResponseBody.ImageBatchModerationResponseBodyDataResult item : generalResults) {
result.addResult(item.getLabel(), item.getConfidence());
}
}
// 分服务结果 Data.Results
List<ImageBatchModerationResponseBody.ImageBatchModerationResponseBodyDataResults> detailedResults = data.getResults();
if (detailedResults != null) {
for (ImageBatchModerationResponseBody.ImageBatchModerationResponseBodyDataResults serviceResult : detailedResults) {
String service = serviceResult.getService();
String riskLevel = serviceResult.getRiskLevel();
ImageModerationResult.ServiceResult sr = new ImageModerationResult.ServiceResult(service, riskLevel);
List<ImageBatchModerationResponseBody.ImageBatchModerationResponseBodyDataResultsResult> labels = serviceResult.getResult();
if (labels != null) {
for (ImageBatchModerationResponseBody.ImageBatchModerationResponseBodyDataResultsResult label : labels) {
sr.addLabelResult(label.getLabel(), label.getConfidence());
}
}
result.addServiceResult(sr);
}
}
return result;
} else {
System.err.println("审核失败,返回code: " + body.getCode() + ",message: " + body.getMsg());
}
} else {
System.err.println("请求失败,HTTP状态码: " + response.getStatusCode());
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
违规图片覆盖方法
public static Boolean overrideWithViolationImage(String fileKey, String url) throws IOException {
String bucketName;
if (url.contains(OssConstants.OSS_PUBLIC_RESOURCE_CDN_URL_PREFIX)) {
bucketName = OssConstants.OSS_PUBLIC_RESOURCE_BUCKET_NAME;
} else if (url.contains(AliYunClientFactory.ossProperties().getCdn())) {
bucketName = OssUtil.getBucketName();
} else {
log.error("未知域名,无法覆盖");
return false;
}
try (InputStream splitImageStream = new URL(OssConstants.SPLIT_IMAGE_URL).openStream()) {
OSS ossClient = new OSSClientBuilder().build(
OssConstants.OSS_PUBLIC_RESOURCE_ENDPOINT,
OssConstants.OSS_PUBLIC_RESOURCE_ACCESS_KEY_ID,
OssConstants.OSS_PUBLIC_RESOURCE_ACCESS_KEY_SECRET
);
try {
PutObjectRequest putObjectRequest = new PutObjectRequest(
// OssConstants.OSS_PUBLIC_RESOURCE_BUCKET_NAME,
bucketName,
fileKey,
splitImageStream
);
PutObjectResult putObjectResult = ossClient.putObject(putObjectRequest);
log.info("图片违规,已覆盖原路径:{} 为分裂图", fileKey);
return true;
} catch (Exception e) {
log.error("覆盖违规图片为分裂图失败,原路径:{}", fileKey, e);
return false;
} finally {
if (ossClient != null) {
ossClient.shutdown(); // 手动关闭 OSSClient
}
}
}
}
public static String extractFileKey(String url) {
if (StringUtils.isBlank(url)) {
return null;
}
try {
// 去除参数部分
int queryIndex = url.indexOf("?");
String baseUrl = queryIndex >= 0 ? url.substring(0, queryIndex) : url;
// 提取路径部分
URL u = new URL(baseUrl);
String path = u.getPath(); // e.g. /dev/tenant/account/file.png or /tenant/account/file.png
// 去除前导斜杠
if (path.startsWith("/")) {
path = path.substring(1);
}
return path;
} catch (MalformedURLException e) {
log.warn("URL解析失败: {}", url, e);
return null;
}
}
5.Controller
package com.coame.bff.integration.controller;
import com.coame.bff.integration.aliyun.green.ImageModerationResult;
import com.coame.bff.integration.aliyun.green.ImageModerationUtil;
import com.coame.bff.integration.aliyun.oss.OssHelper;
import com.malgo.common.ErrMsgEnum;
import com.malgo.share.RpcResult;
import io.swagger.v3.oas.annotations.Operation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Slf4j
@RestController
@RequestMapping("/v1/green")
public class GreenController {
@Operation(summary = "图片审核")
@PostMapping("/image/review.json")
public RpcResult<Boolean> reviewImage(@RequestBody Map<String, Object> request) {
String url = (String) request.get("url");
if (url == null || url.isEmpty()) {
return RpcResult.failure(ErrMsgEnum.ParamError);
}
ImageModerationResult result = ImageModerationUtil.moderateImage(url);
if (result == null) {
return RpcResult.failure(ErrMsgEnum.SysError);
}
boolean isSafe = !result.isHighRisk();
return RpcResult.success(isSafe);
}
@Operation(summary = "批量图片审核并处理违规图片")
@PostMapping("/oss/batch/replaceViolationImages")
public RpcResult<List<String>> replaceViolationImages(@RequestBody List<String> urls) {
if (CollectionUtils.isEmpty(urls)) {
return RpcResult.failure(ErrMsgEnum.ParamError);
}
List<String> violationImageUrl = new ArrayList<>(); // 违规图片的OSS路径
for (String url : urls) {
// 审核图片
ImageModerationResult moderationResult = ImageModerationUtil.moderateImage(url);
if (moderationResult == null) {
continue;
}
// 判断是否违规
boolean isHighRisk = moderationResult.isHighRisk();
// 收集违规图片的url
if (isHighRisk) {
violationImageUrl.add(url);
}
}
for (String url : violationImageUrl) {
try {
String fileKey = OssHelper.extractFileKey(url);
if (fileKey != null) {
OssHelper.overrideWithViolationImage(fileKey, url);
} else {
log.warn("未能提取fileKey: {}", url);
}
} catch (Exception e) {
log.error("替换违规图片失败: {}", url, e);
}
}
return RpcResult.success(violationImageUrl);
}
}
1973

被折叠的 条评论
为什么被折叠?



