前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Java】微信小程序imgSecCheck接口示例-校验一张图片是否含有违法违规内容

【Java】微信小程序imgSecCheck接口示例-校验一张图片是否含有违法违规内容

作者头像
小帅丶
发布2021-12-28 13:02:21
7240
发布2021-12-28 13:02:21
举报
文章被收录于专栏:XAIXAI

更新时间:2021年4月16日

修改了提供的接口地址。不可以直接调用了。总是有人恶意攻击。

https://apis.ydxiaoshuai.cn/xai/rest/check/general_url 传递图片URL地址

https://apis.ydxiaoshuai.cn/xai/rest/check/general_file 传递图片FILE文件

接口文档地址:http://api.ydxiaoshuai.cn/1961525

近期应该部分个人开发者小程序会收到如下通知

为了快速解决问题,就直接使用官方提供的接口

imgSecCheck校验一张图片是否含有违法违规内容

个人小程序只是图片的一些处理识别。固只拿imgSecCheck接口进行代码示例了。 1.在自己的Java后台服务增加接口调用(api.weixin.qq.com不能直接加入小程序安全域名中) 2.在小程序选择图片后优先走违法违规校验。校验通过再走自己的业务代码。

Java实现获取小程序的图片文件并进行违法违规校验

wx.uploadFile 传递图片文件到后台
代码语言:javascript
复制
 wx.uploadFile({
    url: 图片违法违规校验接口地址,
    filePath: res.tempFilePaths[0],
    header: {
        'content-type': 'multipart/form-data'
    },
    name: 'file',
    success: function(checkres) {
        var checkResult = JSON.parse(checkres.data);
        console.info(checkResult);
        if (checkResult.errcode == '0') {
            //校验没有违法违规进行自己业务代码处理
        } else {
            if (checkResult.errcode == '87014') {
                wx.hideLoading();
                wx.showModal({
                    content: '存在敏感内容,请更换图片',
                    showCancel: false,
                    confirmText: '明白了'
                })
            } else {
                wx.hideLoading();
                wx.showModal({
                    content: '其他错误,稍后再试',
                    showCancel: false,
                    confirmText: '明白了'
                })
            }
        }
    }
后台代码

AccessTokenWX .java

代码语言:javascript
复制
import com.fasterxml.jackson.annotation.JsonInclude;
  
/**
 * @Description AccessTokenWX
 * @author 小帅丶
 * @className AccessTokenWX
 * @Date 2019/9/29-10:22
 **/
@JsonInclude(JsonInclude.Include.NON_NULL)
public class AccessTokenWX {
    private String access_token;
    private Integer expires_in;
    private String errcode;
    private String errmsg;
   //set/get省略
}
代码语言:javascript
复制
/**
     * 图片过滤检测
     * @param file 图片文件
     * @return
     */
    @RequestMapping(value = "/imgcheck", method = {RequestMethod.POST})
    @ResponseBody
    public AccessTokenWX checkPic(@RequestParam(value = "file") MultipartFile file, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
        String token = "";
        //自己写一个定时任务或其他方式 获取AccessToken
        AccessTokenWX accessTokenWX = new AccessTokenWX();
        try {
                token = getAccessTokenJob.getAccessToken();
                String url = "https://api.weixin.qq.com/wxa/img_sec_check?access_token=" + token;
                String result = uploadFile(url, file);
                accessTokenWX = JSON.parseObject(result, AccessTokenWX.class);
                System.out.println("图片检测结果 = " + result);
                return accessTokenWX;
        } catch (Exception e) {
            System.out.println("----------------调用腾讯内容过滤系统出错------------------" + e.getMessage());
            accessTokenWX.setErrcode("500");
            accessTokenWX.setErrmsg("system错误");
            return accessTokenWX;
        }
    }
    /**
     * 上传二进制文件
     * @param graphurl 接口地址
     * @param file 图片文件
     * @return
     */
    public static String uploadFile(String graphurl,MultipartFile file) {
        String line = null;//接口返回的结果
        try {
            // 换行符
            final String newLine = "\r\n";
            final String boundaryPrefix = "--";
            // 定义数据分隔线
            String BOUNDARY = "========7d4a6d158c9";
            // 服务器的域名
            URL url = new URL(graphurl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            // 设置为POST情
            conn.setRequestMethod("POST");
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            // 设置请求头参数
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("Charsert", "UTF-8");
            conn.setRequestProperty("Content-Type","multipart/form-data; boundary=" + BOUNDARY);
            conn.setRequestProperty("User-Agent","Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1");
            OutputStream out = new DataOutputStream(conn.getOutputStream());

            // 上传文件
            StringBuilder sb = new StringBuilder();
            sb.append(boundaryPrefix);
            sb.append(BOUNDARY);
            sb.append(newLine);
            // 文件参数,photo参数名可以随意修改
            sb.append("Content-Disposition: form-data;name=\"image\";filename=\""
                    + "https://api.weixin.qq.com" + "\"" + newLine);
            sb.append("Content-Type:application/octet-stream");
            // 参数头设置完以后需要两个换行,然后才是参数内容
            sb.append(newLine);
            sb.append(newLine);

            // 将参数头的数据写入到输出流中
            out.write(sb.toString().getBytes());

            // 读取文件数据
            out.write(file.getBytes());
            // 最后添加换行
            out.write(newLine.getBytes());

            // 定义最后数据分隔线,即--加上BOUNDARY再加上--。
            byte[] end_data = (newLine + boundaryPrefix + BOUNDARY
                    + boundaryPrefix + newLine).getBytes();
            // 写上结尾标识
            out.write(end_data);
            out.flush();
            out.close();
            // 定义BufferedReader输入流来读取URL的响应
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    conn.getInputStream()));
            while ((line = reader.readLine()) != null) {
                return line;
            }
        } catch (Exception e) {
            System.out.println("发送POST请求出现异常!" + e);
        }
        return line;
    }
/**
     * 上传二进制文件
     * @param apiurl 接口地址
     * @param file 图片文件
     * @return
     */
    public static String uploadFile(String apiurl, byte[] file) {
        //接口返回的结果
        String line = null;
        try {
            // 换行符
            final String newLine = "\r\n";
            final String boundaryPrefix = "--";
            // 定义数据分隔线
            String BOUNDARY = "========7d4a6d158c9";
            // 服务器的域名
            URL url = new URL(apiurl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            // 设置为POST情
            conn.setRequestMethod("POST");
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setUseCaches(false);
            // 设置请求头参数
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("Charsert", "UTF-8");
            conn.setRequestProperty("Content-Type","multipart/form-data; boundary=" + BOUNDARY);
            conn.setRequestProperty("User-Agent","Mozilla/5.0 (iPhone; CPU iPhone OS 14_0_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/7.0.15(0x17000f31) NetType/WIFI Language/zh_CN");
            OutputStream out = new DataOutputStream(conn.getOutputStream());

            // 上传文件
            StringBuilder sb = new StringBuilder();
            sb.append(boundaryPrefix);
            sb.append(BOUNDARY);
            sb.append(newLine);
            // 文件参数,photo参数名可以随意修改
            sb.append("Content-Disposition: form-data;name=\"image\";filename=\""
                    + "https://api.weixin.qq.com" + "\"" + newLine);
            sb.append("Content-Type:application/octet-stream");
            // 参数头设置完以后需要两个换行,然后才是参数内容
            sb.append(newLine);
            sb.append(newLine);

            // 将参数头的数据写入到输出流中
            out.write(sb.toString().getBytes());

            // 读取文件数据
            out.write(file);
            // 最后添加换行
            out.write(newLine.getBytes());

            // 定义最后数据分隔线,即--加上BOUNDARY再加上--。
            byte[] end_data = (newLine + boundaryPrefix + BOUNDARY
                    + boundaryPrefix + newLine).getBytes();
            // 写上结尾标识
            out.write(end_data);
            out.flush();
            out.close();
            // 定义BufferedReader输入流来读取URL的响应
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    conn.getInputStream()));
            while ((line = reader.readLine()) != null) {
                return line;
            }
        } catch (Exception e) {
            System.out.println("发送POST请求出现异常!" + e);
        }
        return line;
    }

为了方便大家。我这里直接封装了一个接口供大家使用

接口地址: https://apis.ydxiaoshuai.cn/xai/rest/check/general_file
请求方式: POST
Body参数:
代码语言:javascript
复制
access_token 接口调用凭证
file 图片文件
POSTMAN截图示意
接口地址: https://apis.ydxiaoshuai.cn/xai/rest/check/general_url
请求方式: POST
Body参数:
代码语言:javascript
复制
access_token 接口调用凭证
url 图片URL地址  确保是访问直接是图片 而不是需要校验  或其他内容
POSTMAN截图示意
实现Controller代码如下
代码语言:javascript
复制
    /**
     * 图片过滤检测
     *
     * @param file 图片文件
     * @param access_token 微信token
     * @return
     */
    @RequestMapping(value = "/general_file", method = {RequestMethod.POST})
    public ResponseEntity<Object> checkPicGeneral(@RequestParam(value = "file") MultipartFile file,String access_token) {
        log.info("访问的ip:" + ip);
        WXAccessToken bean = new WXAccessToken();
        try {
            startTime = System.currentTimeMillis();
            if (oConvertUtils.isEmpty(access_token)) {
                bean.setErrcode(410101);
                bean.setErrmsg("接口参数缺失,请检查access_token是否填写");
            } else {
                bean = WeiXinSecurityUtil.checkImg(file,access_token);
            }
        } catch (Exception e) {
            errorMsg = e.getMessage();
            log.info(requestURI + e.getMessage());
            bean.setErrcode(500);
            bean.setErrmsg("system错误");
        }
        //耗时
        timeConsuming = String.valueOf(System.currentTimeMillis() - startTime);
        //响应的内容
        beanStr = JSON.toJSONString(bean);
        return new ResponseEntity<Object>(beanStr, httpHeaders, HttpStatus.OK);
    }

    /**
     * 图片过滤检测
     *
     * @param url 图片公网URL
     * @param access_token 微信token
     * @return
     */
    @RequestMapping(value = "/general_url", method = {RequestMethod.POST})
    public ResponseEntity<Object> checkPicGeneral(String url,String access_token) {
        log.info("访问的ip:" + ip);
        WXAccessToken bean = new WXAccessToken();
        try {
            startTime = System.currentTimeMillis();
            if (oConvertUtils.isEmpty(access_token)) {
                bean.setErrcode(410101);
                bean.setErrmsg("接口参数缺失,请检查access_token是否填写");
            }else if(oConvertUtils.isEmpty(url)){
                bean.setErrcode(410101);
                bean.setErrmsg("接口参数缺失,请检查url是否填写");
            } else {
                bean = WeiXinSecurityUtil.checkImg(url,access_token);
            }
        } catch (Exception e) {
            errorMsg = e.getMessage();
            log.info(requestURI + e.getMessage());
            bean.setErrcode(500);
            bean.setErrmsg("system错误");
        }
        //耗时
        timeConsuming = String.valueOf(System.currentTimeMillis() - startTime);
        //响应的内容
        beanStr = JSON.toJSONString(bean);
        return new ResponseEntity<Object>(beanStr, httpHeaders, HttpStatus.OK);
    }

WeiXinSecurityUtil代码

代码语言:javascript
复制
    private static Integer IMG_WIDTH = 750;
    private static Integer IMG_HEIGHT = 1334;
    /**
     * 图片检测接口
     */
    private static String IMG_SEC_URL = "https://api.weixin.qq.com/wxa/img_sec_check?access_token=";

    /**
     * @Author 小帅丶
     * @Description 图片安全检查
     * @Date  2020/9/29
     * @param imageUrl 图片公网地址
     * @param access_token 微信的token
     * @return cn.ydxiaoshuai.modules.weixin.po.WXAccessToken
     **/
    public static WXAccessToken checkImg(String imageUrl,String access_token) throws Exception{
        WXAccessToken bean;
        BufferedImage bufferedImage = ImageUtil.imgUrlConvertBufferedImage(imageUrl);
        String url = IMG_SEC_URL + access_token;
        //750px * 1334px
        if (bufferedImage.getWidth() > IMG_WIDTH || bufferedImage.getHeight() > IMG_HEIGHT) {
            //缩放图片
            byte[] newImage = ImageUtil.zoomImageByte(bufferedImage);
            String result = ImgCheckHttpUtil.uploadFile(url,newImage);
            log.info(result);
            bean = JSON.parseObject(result, WXAccessToken.class);
            System.out.println("general缩放图片检测结果 = " + result);
        } else {
            ByteArrayOutputStream outputStreamSource = new ByteArrayOutputStream();
            ImageIO.write(bufferedImage, "jpg", outputStreamSource);
            String result = ImgCheckHttpUtil.uploadFile(url,outputStreamSource.toByteArray());
            log.info(result);
            bean = JSON.parseObject(result, WXAccessToken.class);
            System.out.println("general图片检测结果 = " + result);
        }
        return bean;
    }

ImageUtil代码

代码语言:javascript
复制
package cn.ydxiaoshuai.common.util;

import lombok.extern.slf4j.Slf4j;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.net.URL;

/**
 * @author 小帅丶
 * @className ImageUtil
 * @Description 图片缩放
 * @Date 2020/9/29-9:58
 **/
@Slf4j
public class ImageUtil {
    /**
     * 缩放比例系数
     */
    private static double SCALING = 0.56;
    /**
     * 符合base64的宽
     */
    private static int MAX_WIDTH = 560;
    /**
     * 最大高
     */
    private static int MAX_HEIGHT = 1000;

    /**
     * @Author 小帅丶
     * @Description 根据图片公网地址转BufferedImage
     * @Date  2020/9/29 10:52
     * @param url 图片公网地址
     * @return java.awt.image.BufferedImage
     **/
    public static BufferedImage imgUrlConvertBufferedImage(String url) throws Exception {
        URL urls = new URL(url);
        Image image = Toolkit.getDefaultToolkit().getImage(urls);
        BufferedImage bufferedImage = toBufferedImage(image);
        return bufferedImage;
    }
    /**
     * @Author 小帅丶
     * @Description 根据BufferedImage处理图片并返回byte[]
     * @Date  2020/9/29 10:55
     * @param bufferedImage
     * @return byte[]
     **/
    public static byte[] zoomImageByte(BufferedImage bufferedImage) throws Exception {
        ByteArrayOutputStream outputStreamZoom = new ByteArrayOutputStream();
        ByteArrayOutputStream outputStreamSource = new ByteArrayOutputStream();
        ImageIO.write(bufferedImage, "jpg", outputStreamSource);
        BufferedImage bufferedImageZoom = zoomImage(outputStreamSource.toByteArray());
        //写入缩减后的图片
        ImageIO.write(bufferedImageZoom, "jpg", outputStreamZoom);
        return outputStreamZoom.toByteArray();
    }

    /**
     * @Author 小帅丶
     * @Description 根据byte[]处理图片并返回byte[]
     * @Date  2020/9/29 10:55
     * @param src
     * @return byte[]
     **/
    public static byte[] zoomImageByte(byte[] src) throws Exception {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        BufferedImage bufferedImage = zoomImage(src);
        //写入缩减后的图片
        ImageIO.write(bufferedImage, "jpg", outputStream);
        return outputStream.toByteArray();
    }

    /**
     * 图片缩放 仅适用于微信内容图片安全检测使用
     *
     * @param src 为源文件byte
     */
    public static BufferedImage zoomImage(byte[] src) throws Exception {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ByteArrayInputStream in = new ByteArrayInputStream(src);
        double wr = 0, hr = 0;
        BufferedImage bufferedImage = null;
        //读取图片
        BufferedImage bufImg = ImageIO.read(in);
        int height = bufImg.getHeight();
        int width = bufImg.getWidth();
        int cHeight = height;
        int cWidth = width;
        double Scaling = width / height;
        if (Scaling < SCALING) {
            if (height > MAX_HEIGHT) {
                cHeight = MAX_HEIGHT;
                cWidth = (width * MAX_HEIGHT) / height;
            }
            //以宽为缩放比例
        } else {
            if (width > MAX_WIDTH) {
                cWidth = MAX_WIDTH;
                cHeight = (height * MAX_WIDTH) / width;
            }
        }
        //获取缩放后的宽高
        log.info("宽{},高{}", cWidth, cHeight);
        //设置缩放目标图片模板
        Image Itemp = bufImg.getScaledInstance(width, cHeight, BufferedImage.SCALE_SMOOTH);
        //获取缩放比例
        wr = cWidth * 1.0 / width;
        hr = cHeight * 1.0 / height;
        log.info("宽比例{},高比例{}", wr, hr);
        AffineTransformOp ato = new AffineTransformOp(AffineTransform.getScaleInstance(wr, hr), null);
        Itemp = ato.filter(bufImg, null);
        try {
            //写入缩减后的图片
            ImageIO.write((BufferedImage) Itemp, "jpg", outputStream);
            ByteArrayInputStream inNew = new ByteArrayInputStream(outputStream.toByteArray());
            bufferedImage = ImageIO.read(inNew);
        } catch (Exception ex) {
            log.info("缩放图片异常{}", ex.getMessage());
        } finally {
            if (null != outputStream) {
                outputStream.close();
            }
            if (null != in) {
                in.close();
            }
        }
        return bufferedImage;
    }

    /**
     * @Author 小帅丶
     * @Description Image转BufferedImage
     * @Date  2020/9/29 10:47
     * @param image 通过url获取的image对象
     * @return java.awt.image.BufferedImage
     **/
    public static BufferedImage toBufferedImage(Image image) {
        if (image instanceof BufferedImage) {
            return (BufferedImage) image;
        }
        // This code ensures that all the pixels in the image are loaded
        image = new ImageIcon(image).getImage();
        BufferedImage bimage = null;
        GraphicsEnvironment ge = GraphicsEnvironment
                .getLocalGraphicsEnvironment();
        try {
            int transparency = Transparency.OPAQUE;
            GraphicsDevice gs = ge.getDefaultScreenDevice();
            GraphicsConfiguration gc = gs.getDefaultConfiguration();
            bimage = gc.createCompatibleImage(image.getWidth(null),
                    image.getHeight(null), transparency);
        } catch (HeadlessException e) {
            // The system does not have a screen
        }
        if (bimage == null) {
            // Create a buffered image using the default color model
            int type = BufferedImage.TYPE_INT_RGB;
            bimage = new BufferedImage(image.getWidth(null),
                    image.getHeight(null), type);
        }
        // Copy image to buffered image
        Graphics g = bimage.createGraphics();
        // Paint the image onto the buffered image
        g.drawImage(image, 0, 0, null);
        g.dispose();
        return bimage;
    }
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 近期应该部分个人开发者小程序会收到如下通知
  • 为了快速解决问题,就直接使用官方提供的接口
  • Java实现获取小程序的图片文件并进行违法违规校验
    • wx.uploadFile 传递图片文件到后台
      • 后台代码
      • 为了方便大家。我这里直接封装了一个接口供大家使用
        • 接口地址: https://apis.ydxiaoshuai.cn/xai/rest/check/general_file
          • 请求方式: POST
            • Body参数:
              • POSTMAN截图示意
                • 接口地址: https://apis.ydxiaoshuai.cn/xai/rest/check/general_url
                  • 请求方式: POST
                    • Body参数:
                      • POSTMAN截图示意
                        • 实现Controller代码如下
                        相关产品与服务
                        云开发 CloudBase
                        云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
                        领券
                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档