本文只讲实现代码,不讲所使用的框架
用到的部分包
图片处理
imgSecCheck 接口限制图片的尺寸不能超过 750px * 1334px
且图片大小不能超过 1M
,上传的图片不可能全部都在这个范围内,因此需要对图片的尺寸和大小做一些调整。
上传文件的步骤就不说了,Java中一般都会用 MultipartFile
类型来接收图片,使用 getInputStream
方法即可获取到输入流,直接处理这个流即可,处理完之后返回的也是 InputStream
,后面上传的时候可以直接使用。
/**
*
* 图片工具类
*
* @author: Stephen
*/
public final class ImageUtil {
/**
*
* 改变图片尺寸
*
* @param imageStream
* @return
* @throws Exception
*/
public static InputStream changeSize(InputStream imageStream) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
BufferedImage target = null;
int maxWidth = 1334;
int maxHeight = 750;
try {
BufferedImage bufferedImage = ImageIO.read(imageStream);
int width = bufferedImage.getWidth();
int height = bufferedImage.getHeight();
// 如果图片的尺寸没有超过规定的尺寸,直接进入图片大小的处理
if (width <= maxWidth && height <= maxHeight) {
ImageIO.write(bufferedImage, "png", byteArrayOutputStream);
return compressSize(byteArrayOutputStream.toByteArray());
}
double widthScale = maxWidth * 1.0 / width;
double heightScale = maxHeight * 1.0 / height;
if (widthScale > heightScale) {
widthScale = heightScale;
maxWidth = (int) (widthScale * width);
} else {
heightScale = widthScale;
maxHeight = (int) (heightScale * height);
}
int type = bufferedImage.getType();
if (type == BufferedImage.TYPE_CUSTOM) {
ColorModel colorModel = bufferedImage.getColorModel();
WritableRaster writableRaster = colorModel.createCompatibleWritableRaster(maxWidth, maxHeight);
boolean alphaPremultiplied = colorModel.isAlphaPremultiplied();
target = new BufferedImage(colorModel, writableRaster, alphaPremultiplied, null);
} else {
target = new BufferedImage(maxWidth, maxHeight, type);
}
Graphics2D graphics2D = target.createGraphics();
graphics2D.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
graphics2D.drawRenderedImage(bufferedImage, AffineTransform.getScaleInstance(widthScale, heightScale));
graphics2D.dispose();
ImageIO.write(target, "png", byteArrayOutputStream);
} catch (Exception e) {
e.printStackTrace();
return null;
}
return compressSize(byteArrayOutputStream.toByteArray());
}
/**
*
* 改变图片大小
*
* @param imageBytes
* @return
*/
public static InputStream compressSize(byte[] imageBytes) {
long maxSize = 1024 * 1024;
// 如果图片的大小没有超过规定的大小,则不做处理
if (imageBytes.length <= 0 || imageBytes.length <= maxSize) {
return new ByteArrayInputStream(imageBytes);
}
double accuracy = getAccuracy(imageBytes.length / 1024);
ByteArrayOutputStream byteArrayOutputStream = null;
try {
byteArrayOutputStream = new ByteArrayOutputStream(imageBytes.length);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(imageBytes);
Thumbnails.of(byteArrayInputStream)
.scale(accuracy)
.outputQuality(accuracy)
.toOutputStream(byteArrayOutputStream);
} catch (Exception e) {
e.printStackTrace();
return null;
}
return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
}
/**
*
* 自动调节精度(经验数值)
*
* @param size
* @return
*/
private static double getAccuracy(long size) {
double accuracy;
if (size < 900) {
accuracy = 0.85;
} else if (size < 2047) {
accuracy = 0.6;
} else if (size < 3275) {
accuracy = 0.44;
} else {
accuracy = 0.4;
}
return accuracy;
}
}
调用接口
调用 https
接口使用的是 jsoup
,通过 jackson-databind
包直接映射成 Java
实体,方便调用。
/**
*
* JSoup 工具类
*
* @author: Stephen
*/
public final class JSoupUtil {
/**
*
* 获取Connection
*
* @param url
* @return
*/
private static Connection connection(String url) {
return Jsoup.connect(url).ignoreContentType(true).timeout(86400000);
}
/**
*
* POST请求
*
* @param url
* @param params
* @param className
* @param <T>
* @return
*/
public static<T> T upload(String url, Map<String, Object> params, Class<T> className) {
try {
Connection connection = JSoupUtil.connection(url);
for (String key : params.keySet()) {
Object data = params.get(key);
if (data instanceof String) {
connection.data(key, String.valueOf(data));
} else {
connection.data(key, "image.png", (InputStream) data);
}
}
String response = connection.post().text();
return new ObjectMapper().readValue(response, className);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
使用处理好的图片调用该方法即可完成接口请求,使用方法如下:
String url = "https://api.weixin.qq.com/wxa/img_sec_check?access_token=" + accessToken;
InputStream imageData = ImageUtil.changeSize(imageStream);
Map<String, Object> params = new HashMap<String, Object>(){{
put("media", imageData);
}};
SecurityCheckResult securityCheckResult = JSoupUtil.upload(url, params, SecurityCheckResult.class);
SecurityCheckResult
/**
*
* 安全检查结果
*
* @author: Stephen
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class SecurityCheckResult implements Serializable {
// 错误码
@JsonProperty(value = "errcode")
private Integer errCode;
// 错误信息
@JsonProperty(value = "errmsg")
private String errMsg;
public Integer getErrCode() {
return errCode;
}
public void setErrCode(Integer errCode) {
this.errCode = errCode;
}
public String getErrMsg() {
return errMsg;
}
public void setErrMsg(String errMsg) {
this.errMsg = errMsg;
}
}
瞎歪歪一下
这个接口的调用频率限制为单个 appId
调用上限为 2000
次/分钟,200,000
次/天,注意这里的单个 appId
,也就是说一个 appId
一天可以调用 200,000
次,那么有10个小程序,只有一个小程序需要内容安全检查,其他九个不需要内容安全检查,不使用感觉很浪费啊。
在做 UGC
时不能完全依赖这个接口的检测结果,我这边粗略的测了下准确率大概在 80%
以上吧(仅供参考),建议大家还是要配合 mediaCheckAsync 异步接口进行二次检查,就算这两步全做完了,还是需要人工审核的。