From 51efdf5191bc7ecd4efdd22a46139a45af66b7a5 Mon Sep 17 00:00:00 2001
From: zhongrj <646384940@qq.com>
Date: Wed, 20 Mar 2024 21:40:02 +0800
Subject: [PATCH] 集成微信图片安全检测

---
 src/main/java/org/springblade/common/utils/WeiXinSecurityUtil.java       |  321 ++++++++++++++++
 src/main/java/org/springblade/modules/resource/utils/ImageUtil.java      |  171 ++++++++
 src/main/java/org/springblade/modules/resource/endpoint/OssEndpoint.java |   48 ++
 src/main/java/org/springblade/common/utils/ImageUtils.java               |   39 +
 pom.xml                                                                  |    7 
 src/main/java/org/springblade/common/utils/HttpClientUtils.java          |  596 +++++++++++++++++++++++++++++
 6 files changed, 1,177 insertions(+), 5 deletions(-)

diff --git a/pom.xml b/pom.xml
index b3ea7f4..c81e921 100644
--- a/pom.xml
+++ b/pom.xml
@@ -257,6 +257,13 @@
             <artifactId>tess4j</artifactId>
             <version>4.5.4</version>
         </dependency>
+        <!--压缩图片-->
+        <dependency>
+            <groupId>net.coobird</groupId>
+            <artifactId>thumbnailator</artifactId>
+            <version>0.4.8</version>
+        </dependency>
+
 
     </dependencies>
 
diff --git a/src/main/java/org/springblade/common/utils/HttpClientUtils.java b/src/main/java/org/springblade/common/utils/HttpClientUtils.java
new file mode 100644
index 0000000..e75f430
--- /dev/null
+++ b/src/main/java/org/springblade/common/utils/HttpClientUtils.java
@@ -0,0 +1,596 @@
+package org.springblade.common.utils;
+
+import com.alibaba.fastjson.JSON;
+import org.apache.http.HttpEntity;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.config.Registry;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.conn.socket.PlainConnectionSocketFactory;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.conn.ssl.TrustStrategy;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.*;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.ssl.SSLContextBuilder;
+import org.apache.http.util.EntityUtils;
+import sun.misc.BASE64Encoder;
+
+import javax.net.ssl.SSLContext;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.*;
+
+
+public class HttpClientUtils {
+	/**
+	 * 执行有参GET请求
+	 *
+	 * @param url
+	 * @param params
+	 * @return
+	 */
+	public static String doGet(String url, Map<String, String> params) {
+
+//获取httpclient客户端
+		CloseableHttpClient httpclient = HttpClients.createDefault();
+
+		String resultString = "";
+
+		CloseableHttpResponse response = null;
+
+		try {
+			URIBuilder builder = new URIBuilder(url);
+
+			if (null != params) {
+				for (String key : params.keySet()) {
+					builder.setParameter(key, params.get(key));
+				}
+			}
+
+			HttpGet get = new HttpGet(builder.build());
+
+			response = httpclient.execute(get);
+
+			System.out.println(response.getStatusLine());
+
+			if (200 == response.getStatusLine().getStatusCode()) {
+				HttpEntity entity = response.getEntity();
+				resultString = EntityUtils.toString(entity, "utf-8");
+			}
+
+		} catch (Exception e) {
+
+			e.printStackTrace();
+		} finally {
+			if (null != response) {
+				try {
+					response.close();
+				} catch (IOException e) {
+					e.printStackTrace();
+				}
+			}
+			if (null != httpclient) {
+				try {
+					httpclient.close();
+				} catch (IOException e) {
+					e.printStackTrace();
+				}
+			}
+		}
+
+		return resultString;
+	}
+
+	/**
+	 * 执行有参GET请求,带请求头
+	 *
+	 * @param url 请求url
+	 * @param params 参数
+	 * @param key 请求头Key
+	 * @param secretKey 秘钥
+	 * @return
+	 */
+	public static String doGetHeader(String url, String key, String secretKey,Map<String, String> params) {
+
+//获取httpclient客户端
+		CloseableHttpClient httpclient = HttpClients.createDefault();
+
+		String resultString = "";
+
+		CloseableHttpResponse response = null;
+
+		try {
+			URIBuilder builder = new URIBuilder(url);
+
+			if (null != params) {
+				for (String keys : params.keySet()) {
+					builder.addParameter(keys,params.get(keys));
+//builder.setParameter(keys, params.get(keys));
+				}
+			}
+
+			HttpGet httpGet = new HttpGet(builder.build());
+
+//设置请求头
+			httpGet.addHeader(key,secretKey);
+// 传输的类型
+			httpGet.addHeader("Content-Type", "application/x-www-form-urlencoded");
+//执行Http请求调用
+			response = httpclient.execute(httpGet);
+//判断是否请求成功返回
+			if (200 == response.getStatusLine().getStatusCode()) {
+				HttpEntity entity = response.getEntity();
+				resultString = EntityUtils.toString(entity, "utf-8");
+			}
+
+		} catch (Exception e) {
+			e.printStackTrace();
+		} finally {
+			if (null != response) {
+				try {
+					response.close();
+				} catch (IOException e) {
+					e.printStackTrace();
+				}
+			}
+			if (null != httpclient) {
+				try {
+					httpclient.close();
+				} catch (IOException e) {
+					e.printStackTrace();
+				}
+			}
+		}
+
+		return resultString;
+	}
+
+	/**
+	 * 执行有参GET请求,带请求头,接收图片流
+	 *
+	 * @param url 请求url
+	 * @param params 参数
+	 * @param key 请求头Key
+	 * @param secretKey 秘钥
+	 * @return
+	 */
+	public static String doGetHeaderPictureBase64(String url, String key, String secretKey,Map<String, String> params) {
+
+//获取httpclient客户端
+		CloseableHttpClient httpclient = HttpClients.createDefault();
+		String resultString = "";
+		CloseableHttpResponse response = null;
+		try {
+			URIBuilder builder = new URIBuilder(url);
+			if (null != params) {
+				for (String keys : params.keySet()) {
+					builder.addParameter(keys,params.get(keys));
+				}
+			}
+			HttpGet httpGet = new HttpGet(builder.build());
+//设置请求头
+			httpGet.addHeader(key,secretKey);
+// 传输的类型
+			httpGet.addHeader("Content-Type", "application/x-www-form-urlencoded");
+//执行Http请求调用
+			response = httpclient.execute(httpGet);
+// 将返回的图片或者文件转化成字节数组的形式
+			byte[] data = EntityUtils.toByteArray(response.getEntity());
+			BASE64Encoder encoder = new BASE64Encoder();
+//String imageBase64 = "data:image/png;base64," + encoder.encodeBuffer(data).trim();
+			return encoder.encodeBuffer(data).trim().replaceAll("\n", "").replaceAll("\r", "").replaceAll(" ", "");//删除 \r\n
+		} catch (Exception e) {
+			e.printStackTrace();
+		} finally {
+			if (null != response) {
+				try {
+					response.close();
+				} catch (IOException e) {
+					e.printStackTrace();
+				}
+			}
+			if (null != httpclient) {
+				try {
+					httpclient.close();
+				} catch (IOException e) {
+					e.printStackTrace();
+				}
+			}
+		}
+		return resultString;
+	}
+
+	/**
+	 * 执行无参GET请求
+	 *
+	 * @param url
+	 * @return
+	 */
+	public static String doGet(String url) {
+		return doGet(url, null);
+	}
+
+	/**
+	 * 执行有参POST请求
+	 *
+	 * @param url
+	 * @param params
+	 * @return
+	 */
+	public static String doPost(String url, Map<String, String> params) {
+/**
+ * 在4.0及以上httpclient版本中,post需要指定重定向的策略,如果不指定则按默认的重定向策略。
+ *
+ * 获取httpclient客户端
+ */
+		CloseableHttpClient httpclient = HttpClientBuilder.create().setRedirectStrategy(new LaxRedirectStrategy()).build();
+
+		String resultString = "";
+
+		CloseableHttpResponse response = null;
+
+		try {
+
+
+			HttpPost post = new HttpPost(url);
+
+			List<NameValuePair> paramaters = new ArrayList<>();
+
+			if (null != params) {
+				for (String key : params.keySet()) {
+					paramaters.add(new BasicNameValuePair(key, params.get(key)));
+				}
+// 构造一个form表单式的实体
+				UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(paramaters);
+// 将请求实体设置到httpPost对象中
+				post.setEntity(formEntity);
+			}
+
+
+/**
+ * HTTP/1.1 403 Forbidden
+ *   原因:
+ *      有些网站,设置了反爬虫机制
+ *   解决的办法:
+ *      设置请求头,伪装浏览器
+ */
+			post.addHeader("user-agent", "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36");
+
+			response = httpclient.execute(post);
+
+			System.out.println(response.getStatusLine());
+
+			if (200 == response.getStatusLine().getStatusCode()) {
+				HttpEntity entity = response.getEntity();
+				resultString = EntityUtils.toString(entity, "utf-8");
+			}
+
+		} catch (Exception e) {
+
+			e.printStackTrace();
+		} finally {
+			if (null != response) {
+				try {
+					response.close();
+				} catch (IOException e) {
+					e.printStackTrace();
+				}
+			}
+			if (null != httpclient) {
+				try {
+					httpclient.close();
+				} catch (IOException e) {
+					e.printStackTrace();
+				}
+			}
+		}
+		return resultString;
+	}
+
+	public static String doPost(String url) {
+		return doPost(url, null);
+	}
+
+
+	public static void main(String[] args) {
+
+		Map<String, String> params = new HashMap<>();
+		params.put("scope", "project");
+		params.put("q", "数据库");
+//
+//    System.out.println(doGet("http://www.baidu.com/s",params));
+
+		/**
+		 * 有一部分网站,禁止爬虫技术访问网站。
+		 *
+		 * 解决方案:
+		 *    伪装浏览器
+		 *    post.addHeader("user-agent", "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36");
+		 */
+		System.out.println(doPost("http://www.oschina.net/search", params));
+	}
+
+	/**
+	 * post 请求 header 带 秘钥
+	 * @param url
+	 * @param appKey
+	 * @param appKeyValue
+	 * @param map
+	 * @return
+	 */
+	public static String httpPost(String url, String appKey, String appKeyValue, Map<String, String> map) {
+// 返回body
+		String body = null;
+// 获取连接客户端工具
+		CloseableHttpClient httpClient = HttpClients.createDefault();
+		CloseableHttpResponse httpResponse = null;
+// 2、创建一个HttpPost请求
+		HttpPost post = new HttpPost(url);
+// 5、设置header信息
+		/**header中通用属性*/
+//        post.setHeader("Accept", "*/*");
+//        post.setHeader("Accept-Encoding", "gzip, deflate");
+//        post.setHeader("Cache-Control", "no-cache");
+//        post.setHeader("Connection", "keep-alive");
+		post.setHeader("Content-Type", "application/json;charset=UTF-8");
+/**业务参数*/
+		post.setHeader(appKey, appKeyValue);
+// 设置参数
+		if (map != null) {
+			try {
+				StringEntity entity1 = new StringEntity(JSON.toJSONString(map), "UTF-8");
+				entity1.setContentEncoding("UTF-8");
+				entity1.setContentType("json/form-data");
+				post.setEntity(entity1);
+
+// 7、执行post请求操作,并拿到结果
+				httpResponse = httpClient.execute(post);
+// 获取结果实体
+				HttpEntity entity = httpResponse.getEntity();
+				if (entity != null) {
+// 按指定编码转换结果实体为String类型
+					body = EntityUtils.toString(entity, "UTF-8");
+				}
+				try {
+					httpResponse.close();
+					httpClient.close();
+				} catch (IOException e) {
+					e.printStackTrace();
+				}
+			} catch (Exception e) {
+				e.printStackTrace();
+			}
+		}
+		return body;
+	}
+
+	public static SSLContext createIgnoreVerifySSL() throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {
+
+		SSLContext sc = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
+
+			public boolean isTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
+				return true;
+			}
+
+		}).build();
+
+		return sc;
+	}
+
+	//适用于post请求并传送form-data数据(同样适用于post的Raw类型的application-json格式)
+	public static String postParams(String url, String appKey, Map<String, String> map) {
+		SSLContext sslcontext = null;
+		try {
+			sslcontext = createIgnoreVerifySSL();
+		} catch (KeyManagementException e) {
+			e.printStackTrace();
+		} catch (NoSuchAlgorithmException e) {
+			e.printStackTrace();
+		} catch (KeyStoreException e) {
+			e.printStackTrace();
+		}
+// 设置协议http和https对应的处理socket链接工厂的对象
+		Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
+			.register("http", PlainConnectionSocketFactory.INSTANCE)
+			.register("https", new SSLConnectionSocketFactory(sslcontext))
+			.build();
+		PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
+
+//创建自定义的httpclient对象
+		CloseableHttpClient client = HttpClients.custom().setConnectionManager(connManager).build();
+		HttpPost post = new HttpPost(url);
+		post.setHeader("appKey", appKey);
+		CloseableHttpResponse res = null;
+		try {
+			List<NameValuePair> nvps = new ArrayList<NameValuePair>();
+			Set<String> keySet = map.keySet();
+			for (String key : keySet) {
+				nvps.add(new BasicNameValuePair(key, map.get(key)));
+			}
+			post.setEntity(new UrlEncodedFormEntity(nvps, "utf-8"));
+			res = client.execute(post);
+			HttpEntity entity = res.getEntity();
+			return EntityUtils.toString(entity, "utf-8");
+		} catch (Exception e) {
+			e.printStackTrace();
+		} finally {
+			try {
+				res.close();
+				client.close();
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+		}
+		return "";
+	}
+
+
+
+	//适用于post请求并传送form-data数据(同样适用于post的Raw类型的application-json格式)
+	public static String postParams(String url, Map<String, Object> map) {
+		SSLContext sslcontext = null;
+		try {
+			sslcontext = createIgnoreVerifySSL();
+		} catch (KeyManagementException e) {
+			e.printStackTrace();
+		} catch (NoSuchAlgorithmException e) {
+			e.printStackTrace();
+		} catch (KeyStoreException e) {
+			e.printStackTrace();
+		}
+// 设置协议http和https对应的处理socket链接工厂的对象
+		Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
+			.register("http", PlainConnectionSocketFactory.INSTANCE)
+			.register("https", new SSLConnectionSocketFactory(sslcontext))
+			.build();
+		PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
+
+//创建自定义的httpclient对象
+		CloseableHttpClient client = HttpClients.custom().setConnectionManager(connManager).build();
+		HttpPost post = new HttpPost(url);
+//		post.setHeader(appKey, appKeyValue);
+		CloseableHttpResponse res = null;
+		try {
+			List<NameValuePair> nvps = new ArrayList<NameValuePair>();
+			Set<String> keySet = map.keySet();
+			for (String key : keySet) {
+				nvps.add(new BasicNameValuePair(key, map.get(key).toString()));
+			}
+			post.setEntity(new UrlEncodedFormEntity(nvps, "utf-8"));
+			res = client.execute(post);
+			HttpEntity entity = res.getEntity();
+			return EntityUtils.toString(entity, "utf-8");
+		} catch (Exception e) {
+			e.printStackTrace();
+		} finally {
+			try {
+				res.close();
+				client.close();
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+		}
+		return "";
+	}
+
+	/**
+	 * 向指定 URL 发送POST方法的请求
+	 *
+	 * @param url    发送请求的 URL
+	 * @param params 请求的参数集合
+	 * @return 远程资源的响应结果
+	 */
+	@SuppressWarnings("unused")
+	public static String sendPost(String url, Map<String, String> params) {
+		OutputStreamWriter out = null;
+		BufferedReader in = null;
+		StringBuilder result = new StringBuilder();
+		try {
+			URL realUrl = new URL(url);
+			HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
+// 发送POST请求必须设置如下两行
+			conn.setDoOutput(true);
+			conn.setDoInput(true);
+// POST方法
+			conn.setRequestMethod("POST");
+// 设置通用的请求属性
+			conn.setRequestProperty("accept", "*/*");
+			conn.setRequestProperty("connection", "Keep-Alive");
+			conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
+			conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
+			conn.connect();
+// 获取URLConnection对象对应的输出流
+			out = new OutputStreamWriter(conn.getOutputStream(), "UTF-8");
+// 发送请求参数
+			if (params != null) {
+				StringBuilder param = new StringBuilder();
+				for (Map.Entry<String, String> entry : params.entrySet()) {
+					if (param.length() > 0) {
+						param.append("&");
+					}
+					param.append(entry.getKey());
+					param.append("=");
+					param.append(entry.getValue());
+// System.out.println(entry.getKey()+":"+entry.getValue());
+				}
+// System.out.println("param:"+param.toString());
+				out.write(param.toString());
+			}
+// flush输出流的缓冲
+			out.flush();
+// 定义BufferedReader输入流来读取URL的响应
+			in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
+			String line;
+			while ((line = in.readLine()) != null) {
+				result.append(line);
+			}
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+// 使用finally块来关闭输出流、输入流
+		finally {
+			try {
+				if (out != null) {
+					out.close();
+				}
+				if (in != null) {
+					in.close();
+				}
+			} catch (IOException ex) {
+				ex.printStackTrace();
+			}
+		}
+		return result.toString();
+	}
+
+
+	/**
+	 * json  body
+	 * @param url
+	 * @param json
+	 * @return
+	 * @throws IOException
+	 */
+	public static String httpPostWithjson(String url, String json) throws IOException {
+		String result = "";
+		HttpPost httpPost = new HttpPost(url);
+		CloseableHttpClient httpClient = HttpClients.createDefault();
+		try {
+			BasicResponseHandler handler = new BasicResponseHandler();
+			//解决中文乱码问题
+			StringEntity entity = new StringEntity(json, "utf-8");
+			entity.setContentEncoding("UTF-8");
+			entity.setContentType("application/json");
+			httpPost.setEntity(entity);
+			result = httpClient.execute(httpPost, handler);
+			return result;
+		} catch (Exception e) {
+			e.printStackTrace();
+		} finally {
+			try {
+				httpClient.close();
+			} catch (Exception e) {
+				e.printStackTrace();
+			}
+		}
+		return result;
+	}
+}
+
+
diff --git a/src/main/java/org/springblade/common/utils/ImageUtils.java b/src/main/java/org/springblade/common/utils/ImageUtils.java
index 0fcf2c4..a0af0b6 100644
--- a/src/main/java/org/springblade/common/utils/ImageUtils.java
+++ b/src/main/java/org/springblade/common/utils/ImageUtils.java
@@ -8,6 +8,7 @@
 import java.awt.*;
 import java.awt.image.BufferedImage;
 import java.io.ByteArrayOutputStream;
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.HttpURLConnection;
@@ -16,6 +17,44 @@
 
 public class ImageUtils {
 
+	/**
+	 * 几种常见的图片格式
+	 */
+	public static String IMAGE_TYPE_GIF = "gif";// 图形交换格式
+	public static String IMAGE_TYPE_JPG = "jpg";// 联合照片专家组
+	public static String IMAGE_TYPE_JPEG = "jpeg";// 联合照片专家组
+	public static String IMAGE_TYPE_BMP = "bmp";// 英文Bitmap(位图)的简写,它是Windows操作系统中的标准图像文件格式
+	public static String IMAGE_TYPE_PNG = "png";// 可移植网络图形
+	public static String IMAGE_TYPE_PSD = "psd";// Photoshop的专用格式Photoshop
+
+
+	/**
+	 * 程序入口:用于测试
+	 * @param args
+	 */
+	public static void main(String[] args) {
+		// -图像类型转换:
+		ImageUtils.convert("D:/IMG_20180811_222034.png", "jpg", "D:/test.jpg");//测试OK
+	}
+
+	/**
+	 * 图像类型转换:GIF->JPG、GIF->PNG、PNG->JPG、PNG->GIF(X)、BMP->PNG
+	 * @param srcImageFile 源图像地址
+	 * @param formatName 包含格式非正式名称的 String:如JPG、JPEG、GIF等
+	 * @param destImageFile 目标图像地址
+	 */
+	public static void convert(String srcImageFile, String formatName, String destImageFile) {
+		try {
+			File f = new File(srcImageFile);
+			f.canRead();
+			f.canWrite();
+			BufferedImage src = ImageIO.read(f);
+			ImageIO.write(src, formatName, new File(destImageFile));
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
 
 
 	public static String getBase64ByImgUrl(String url){
diff --git a/src/main/java/org/springblade/common/utils/WeiXinSecurityUtil.java b/src/main/java/org/springblade/common/utils/WeiXinSecurityUtil.java
new file mode 100644
index 0000000..675d02a
--- /dev/null
+++ b/src/main/java/org/springblade/common/utils/WeiXinSecurityUtil.java
@@ -0,0 +1,321 @@
+package org.springblade.common.utils;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ByteArrayEntity;
+import org.apache.http.entity.ContentType;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.commons.io.FileUtils;
+import java.awt.image.BufferedImage;
+import javax.imageio.ImageIO;
+import net.coobird.thumbnailator.Thumbnails;
+
+/**
+ * 微信安全检验工具类
+ */
+public class WeiXinSecurityUtil {
+	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=";
+
+	//获取wxAccessToken
+	private static String WX_GET_ACCESS_TOKEN = "https://api.weixin.qq.com/cgi-bin/token";
+
+	private static String WX_APP_ID = "wx41aa8a5d2e565a05";
+	private static String WX_SECRET = "e0e9218ac368cd4ca620ff4c7030f468";
+
+	/**
+	 * 恶意图片过滤-校验图片是否含有违法违规内容
+	 * MultipartFile multipartFile, String accessToken
+	 * @param multipartFile
+	 * @return
+	 */
+	public static String checkImg(MultipartFile multipartFile){
+		String result = "";
+		//压缩图片
+		InputStream inputStream = compressImage(multipartFile);
+		// 校验api url
+		String url = IMG_SEC_URL + getWxAccessToken();
+		// 获得Http客户端(可以理解为:你得先有一个浏览器;注意:实际上HttpClient与浏览器是不一样的
+		HttpClient httpclient = HttpClients.createDefault();
+		//创建一个post请求
+		HttpPost request = new HttpPost(url);
+		//设置响应头   ( application/octet-stream:二进制流,不知道下载文件类型)
+		request.addHeader("Content-Type", "application/octet-stream");
+		try {
+			//创建一个byte数组,和输入的文件的大小一样
+			byte[] byt = new byte[inputStream.available()];
+			//从输入流中读取全部,并将其存储在缓冲区数组byt 中。
+			inputStream.read(byt);
+			//定制提交内容
+			request.setEntity(new ByteArrayEntity(byt, ContentType.create("image/jpg")));
+			//由客户端执行(发送)请求,执行校验
+			HttpResponse response = httpclient.execute(request);
+			// 从响应模型中获取响应实体
+			HttpEntity entity = response.getEntity();
+			result = EntityUtils.toString(entity, "UTF-8");// 转成string
+			//打印校验结果
+			System.out.println("result:" + result);
+		} catch (IOException e) {
+			e.printStackTrace();
+		} finally {
+			if(inputStream != null){
+				try {
+					inputStream.close();
+				} catch (IOException e) {
+					e.printStackTrace();
+				}
+			}
+		}
+		// 响应返回结果
+		return result;
+	}
+
+
+
+	/**
+	 * 图片过滤检测
+	 * @param file 图片文件
+	 * @return
+	 */
+	public String checkPic(MultipartFile file) {
+		String access_token = "";
+		String result = "";
+		//自己写一个定时任务或其他方式 获取AccessToken
+		try {
+			access_token = getWxAccessToken();
+			String url = "https://api.weixin.qq.com/wxa/img_sec_check?access_token=" + access_token;
+			result = uploadFile(url, file);
+			System.out.println("图片检测结果 = " + result);
+		} catch (Exception e) {
+			System.out.println("----------------调用腾讯内容过滤系统出错------------------" + e.getMessage());
+		}
+		// 返回
+		return result;
+	}
+
+	/**
+	 * 上传二进制文件
+	 * @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;
+	}
+
+	/**
+	 * 获取 WxAccessToken
+	 * @return
+	 */
+	public static String getWxAccessToken() {
+		//参数
+		Map<String, String> params = new HashMap<>();
+		params.put("grant_type", "client_credential");
+		params.put("appid", WX_APP_ID);
+		params.put("secret", WX_SECRET);
+		String result = HttpClientUtils.doGet(WX_GET_ACCESS_TOKEN, params);
+		JSONObject jsonObject = JSON.parseObject(result);
+		String accessToken = jsonObject.getString("access_token");
+		return accessToken;
+	}
+
+
+
+	/**
+	 * 压缩图片
+	 * @param multipartFile
+	 */
+	public static InputStream compressImage(MultipartFile multipartFile){
+		//*************对不是jpg格式的图片转换成jpg格式***************
+		//获取文件名后缀,判断其格式
+		int begin = multipartFile.getOriginalFilename().lastIndexOf(".");
+		int last = multipartFile.getOriginalFilename().length();
+		//获得文件后缀名
+		String houzuiFileName = multipartFile.getOriginalFilename().substring(begin, last);
+		//创建临时文件
+		File tempFile = new File(multipartFile.getOriginalFilename());
+		//写入临时File文件 tempFile,将multipartFile转换成File
+		try {
+			//import org.apache.commons.io.FileUtils;
+			FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), tempFile);
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+		//如果文件不是jpg格式,转换其格式
+		if (!"jpg".equalsIgnoreCase(houzuiFileName)){
+			//ImageUtils是一个工具类,下面给出
+			//将png格式转换成jpg,输出到tempFile
+			//测试OK
+			ImageUtils.convert(multipartFile.getOriginalFilename(), "jpg", tempFile.getAbsolutePath());
+			//*************对不是jpg格式的图片转换成jpg格式***************
+		}
+		try {
+			//压缩图片
+			BufferedImage bufferedImage = Thumbnails.of(tempFile)
+				.size(740, 1330)//指定压缩之后的图片尺寸
+				.outputQuality(0.8f)//图片压缩质量
+				.asBufferedImage();
+			ByteArrayOutputStream os = new ByteArrayOutputStream();
+			ImageIO.write(bufferedImage, "jpg", os);
+			InputStream inputStream = new ByteArrayInputStream(os.toByteArray());
+//            System.out.println(inputStream);
+			return inputStream;
+		} catch (IOException e) {
+			e.printStackTrace();
+		}finally {
+//             会在本地产生临时文件,用完后需要删除
+			if (tempFile.exists()) {
+				tempFile.delete();
+			}
+		}
+		return null;
+	}
+
+}
diff --git a/src/main/java/org/springblade/modules/resource/endpoint/OssEndpoint.java b/src/main/java/org/springblade/modules/resource/endpoint/OssEndpoint.java
index 413f2f0..c40fa1e 100644
--- a/src/main/java/org/springblade/modules/resource/endpoint/OssEndpoint.java
+++ b/src/main/java/org/springblade/modules/resource/endpoint/OssEndpoint.java
@@ -16,10 +16,14 @@
  */
 package org.springblade.modules.resource.endpoint;
 
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.JSONPObject;
 import io.swagger.annotations.Api;
 import lombok.AllArgsConstructor;
 import lombok.SneakyThrows;
 import org.springblade.common.utils.ImageUtils;
+import org.springblade.common.utils.WeiXinSecurityUtil;
 import org.springblade.core.launch.constant.AppConstant;
 import org.springblade.core.oss.model.BladeFile;
 import org.springblade.core.oss.model.OssFile;
@@ -37,6 +41,15 @@
 import org.springblade.modules.resource.service.IAttachService;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.BufferedReader;
+import java.io.DataOutputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
 
 /**
  * 对象存储端点
@@ -158,7 +171,7 @@
 		// 修改link
 		changeLink(bladeFile);
 		// 返回
-		return R.data(bladeFile);
+		return R.data(200,bladeFile,"");
 	}
 
 	/**
@@ -227,15 +240,27 @@
 	 *
 	 * @param file 文件
 	 * @param prefixPath 文件
+	 * @param isCheck 是否校验
 	 * @return ObjectStat
 	 */
 	@SneakyThrows
 	@PostMapping("/put-file-by-prefix-path")
-	public R<BladeFile> putFileByPrefixPath(@RequestParam MultipartFile file,@RequestParam(required = false) String prefixPath) {
+	public R<BladeFile> putFileByPrefixPath(@RequestParam MultipartFile file,
+											@RequestParam(required = false) String prefixPath,
+											@RequestParam(required = false) Integer isCheck) {
+		// 不传默认不检验
+		if(null!=isCheck){
+			String checkResult = WeiXinSecurityUtil.checkImg(file);
+			JSONObject jsonObject = JSONObject.parseObject(checkResult);
+			Integer errorCode = Integer.parseInt(jsonObject.getString("errcode"));
+			if (errorCode!=0){
+				return R.data(201,null,"图片存在敏感内容,请更换其他图片!");
+			}
+		}
 		BladeFile bladeFile = ossBuilder.templateByPrefixPath(prefixPath).putFile(file.getOriginalFilename(), file.getInputStream());
 		// 修改link
 		changeLink(bladeFile);
-		return R.data(bladeFile);
+		return R.data(200,bladeFile,"");
 	}
 
 	/**
@@ -243,11 +268,23 @@
 	 *
 	 * @param file 文件
 	 * @param prefixPath 文件
+	 * @param isCheck 是否校验
 	 * @return ObjectStat
 	 */
 	@SneakyThrows
 	@PostMapping("/put-file-attach-by-prefix-path")
-	public R<BladeFile> putFileAttachByPrefixPath(@RequestParam MultipartFile file,@RequestParam(required = false) String prefixPath) {
+	public R<BladeFile> putFileAttachByPrefixPath(@RequestParam MultipartFile file,
+												  @RequestParam(required = false) String prefixPath,
+												  @RequestParam(required = false) Integer isCheck) {
+		// 不传默认不检验
+		if(null!=isCheck){
+			String checkResult = WeiXinSecurityUtil.checkImg(file);
+			JSONObject jsonObject = JSONObject.parseObject(checkResult);
+			Integer errorCode = Integer.parseInt(jsonObject.getString("errcode"));
+			if (errorCode!=0){
+				return R.data(201,null,"图片存在敏感内容,请更换其他图片!");
+			}
+		}
 		String fileName = file.getOriginalFilename();
 		BladeFile bladeFile = ossBuilder.templateByPrefixPath(prefixPath).putFile(file.getOriginalFilename(), file.getInputStream());
 		Long attachId = buildAttach(fileName, file.getSize(), bladeFile);
@@ -255,7 +292,7 @@
 		bladeFile.setAttachId(attachId);
 		// 修改link
 		changeLink(bladeFile);
-		return R.data(bladeFile);
+		return R.data(200,bladeFile,"");
 	}
 
 	/**
@@ -329,4 +366,5 @@
 		return R.success("操作成功");
 	}
 
+
 }
diff --git a/src/main/java/org/springblade/modules/resource/utils/ImageUtil.java b/src/main/java/org/springblade/modules/resource/utils/ImageUtil.java
new file mode 100644
index 0000000..797cb32
--- /dev/null
+++ b/src/main/java/org/springblade/modules/resource/utils/ImageUtil.java
@@ -0,0 +1,171 @@
+package org.springblade.modules.resource.utils;
+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 arsn
+ * @className ImageUtil
+ * @Description 图片缩放
+ **/
+@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;
+	}
+
+	/**
+	 * @Description Image转BufferedImage
+	 * @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;
+	}
+}

--
Gitblit v1.9.3