1. 所需依赖
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
2. 配置文件
# 微信小程序配置
wxApp:
appId: xxx
appSecret: xxx
envVersion: trial
uploadPagePath: bundle/pages/picture-upload/picture-upload
3. 创建二维码生成工具类
package org.jeecg.modules.system.util;
import com.alibaba.fastjson.JSONObject;
import okhttp3.*;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.util.RedisUtil;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
/**
* 微信小程序码生成工具
*/
@Component
public class WxAppQRCodeUtils {
private static final OkHttpClient HTTP_CLIENT = new OkHttpClient().newBuilder().build();
//获取token地址
private static final String API_GET_TOKEN = "https://api.weixin.qq.com/cgi-bin/token";
//获取小程序码接口
private static final String API_POST_QR_CODE = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=";
//redisKey微信小程序token前缀
private static final String WX_TOKEN_PREFIX = "WxAppToken_";
@Resource
private RedisUtil redisUtil;
/**
* 生成并返回小程序码
* @param appId 小程序id
* @param appSecret secret
* @param page 页面路径(根路径前不要填加 /,不能携带参数)
* @param scene 携带参数
* @param envVersion 要打开的小程序版本。正式版为 "release",体验版为 "trial",开发版为 "develop"。默认是正式版
* @param checkPath 默认是true,检查page 是否存在,为 true 时 page 必须是已经发布的小程序存在的页面(否则报错);为 false 时允许小程序未发布或者 page 不存在
*/
public byte[] getQRCodeByte(String appId, String appSecret, String page, String scene, String envVersion, Boolean checkPath) {
byte[] qrCodeBytes = null;
try {
HttpURLConnection conn = (HttpURLConnection) new URL(API_POST_QR_CODE + getToken(appId, appSecret)).openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setDoOutput(true);
if (StringUtils.isBlank(envVersion)) {
envVersion = "release";
}
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("scene", scene);
paramMap.put("page", page);
paramMap.put("check_path", checkPath);
paramMap.put("env_version", envVersion);
String param = GsonUtils.toJson(paramMap);
conn.getOutputStream().write(param.getBytes("UTF-8"));
InputStream is = conn.getInputStream();
qrCodeBytes = IOUtils.toByteArray(is);
is.close();
conn.disconnect();
}catch (Exception e) {
e.printStackTrace();
}
return qrCodeBytes;
}
/**
* 根据appid及secret获取token
* @param appId 小程序id
* @param appSecret secret
* @return token
*/
private String getToken(String appId, String appSecret) {
String token = null;
String redisKey = WX_TOKEN_PREFIX + appId;
if (redisUtil.hasKey(redisKey)) {
return redisUtil.get(redisKey).toString();
}
try {
Request request = new Request.Builder()
.url(API_GET_TOKEN + "?grant_type=client_credential&appid=" + appId + "&secret=" + appSecret)
.build();
Response response = HTTP_CLIENT.newCall(request).execute();
assert response.body() != null;
JSONObject result = JSONObject.parseObject(response.body().string());
token = result.getString("access_token");
redisUtil.set(redisKey, token, Long.parseLong(result.getString("expires_in")));
}catch (Exception e) {
e.printStackTrace();
}
return token;
}
}
4. 文件处理工具类
package org.jeecg.modules.system.util;
import org.jeecg.common.util.CommonUtils;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Base64;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 文件处理工具类
*/
public class ImageFileUtils {
/**
* 图片base64转MultipartFile
* @param base64Str
* @return
* @throws IOException
*/
public static MultipartFile convertByBase64(String base64Str) throws IOException {
// 解码base64字符串
byte[] data = Base64.getDecoder().decode(base64Str);
// 创建临时文件
Path tempFilePath = Files.createTempFile("tempfile", ".tmp");
Files.write(tempFilePath, data);
String uuid = UUID.randomUUID().toString();
// 创建MultipartFile实例
MultipartFile multipartFile = new MockMultipartFile(uuid, uuid + ".png", "image/png", Files.newInputStream(tempFilePath));
// 删除临时文件
Files.delete(tempFilePath);
return multipartFile;
}
/**
* 根据图片url地址转换base64
* @param imageUrl
* @return
*/
public static String convertByImgUrl(String imageUrl) {
try (InputStream inputStream = new URL(imageUrl).openStream(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
byte[] imageBytes = outputStream.toByteArray();
return Base64.getEncoder().encodeToString(imageBytes);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 图片url转File
* @param imageUrl
* @return
*/
public static File getFile(String imageUrl) {
//对本地文件命名
String fileName = UUID.randomUUID() + ".png";
File file = null;
URL urlfile;
InputStream inStream = null;
OutputStream os = null;
try {
file = File.createTempFile("net_url", fileName);
//下载
urlfile = new URL(imageUrl);
inStream = urlfile.openStream();
os = new FileOutputStream(file);
int bytesRead = 0;
byte[] buffer = new byte[8192];
while ((bytesRead = inStream.read(buffer, 0, 8192)) != -1) {
os.write(buffer, 0, bytesRead);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (null != os) {
os.close();
}
if (null != inStream) {
inStream.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return file;
}
/**
* 解析出图片 url
*
* @param content md文本(源 md 文本使用 html 的 <img> 标签 src 属性引用图片)
* @return 提取 src 属性值
*/
public static ArrayList<String> extractUrls(String content) {
ArrayList<String> imgUrls = new ArrayList<>();
Pattern compile = Pattern.compile("!\\[.*?\\]\\((.*?)\\)");
Matcher matcher = compile.matcher(content);
while (matcher.find()) {
String group = matcher.group(1);
String replace = group.replace("src=", "").replace("\"", "");
imgUrls.add(replace);
}
return imgUrls;
}
/**
* 解析markdown中图片url,下载上传文件并替换url
* @param source 源文件
* @return
*/
public static String getMarkDownImageContent(String source) {
String content = source;
try {
ArrayList<String> imgUrls = extractUrls(source);
for (String img : imgUrls) {
String imgUrl = CommonUtils.upload(convertByImageUrl(img), "upload/aiChat", "alioss");
content = content.replace(img, imgUrl);
}
}catch (Exception e) {
e.printStackTrace();
}
return content;
}
/**
* 图片url转MultipartFile
* @param imageUrl
* @return
* @throws IOException
*/
public static MultipartFile convertByImageUrl(String imageUrl) throws IOException {
URL url = new URL(imageUrl);
InputStream inputStream = url.openStream();
// 获取图片文件名
String fileName = UUID.randomUUID().toString();
// 使用Spring的MockMultipartFile类来创建MultipartFile
return new MockMultipartFile(fileName, fileName + ".png", "text/plain", inputStream);
}
/**
* byte[] 转 MultipartFile
* @param imageBytes
* @return
* @throws IOException
*/
public static MultipartFile toMultipartFile(byte[] imageBytes) throws IOException {
String filename = UUID.randomUUID().toString();
return new MultipartFile() {
@Override
public String getName() {
return filename;
}
@Override
public String getOriginalFilename() {
return filename + ".png";
}
@Override
public String getContentType() {
// 根据实际情况设置内容类型,例如图片可以设置为"image/jpeg"
return "image/jpeg";
}
@Override
public boolean isEmpty() {
return imageBytes == null || imageBytes.length == 0;
}
@Override
public long getSize() {
return imageBytes.length;
}
@Override
public byte[] getBytes() throws IOException {
return imageBytes;
}
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(imageBytes);
}
@Override
public void transferTo(java.io.File dest) throws IOException, IllegalStateException {
new java.io.FileOutputStream(dest).write(imageBytes);
}
};
}
}
5. 编写接口测试
@Value("${wxApp.appId}")
private String appId;
@Value("${wxApp.appSecret}")
private String appSecret;
@Value("${wxApp.envVersion}")
private String envVersion;
@Value("${wxApp.uploadPagePath}")
private String uploadPagePath;
/**
* 获取微信小程序码
* @param aiChatQrCodeReq
* @return
* @throws IOException
*/
@ApiOperation(value="获取微信小程序码")
@PostMapping("/getWxAppQRCode")
public Result<String> getWxAppQRCode(String text, HttpServletRequest request) throws IOException {
byte[] imgBytes = wxAppQRCodeUtils.getQRCodeByte(appId, appSecret, uploadPagePath, text, envVersion, false);
MultipartFile file = ImageFileUtils.toMultipartFile(imgBytes);
String imgUrl = CommonUtils.upload(file, "upload/aiChat/wxAppQrCode", "alioss");
return Result.ok(imgUrl);
}