1、第三方类
<!-- 二维码支持包 -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.3.3</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.3.3</version>
</dependency>
<!-- 阿里云oss -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.10.2</version>
</dependency>
2、创建二维码工具类
package com.shouchuang.utils;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.StrUtil;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import java.util.HashMap;
@Slf4j
@Component
public class QrCodeUtil {
/**
* 默认宽度
*/
private static final Integer WIDTH = 140;
/**
* 默认高度
*/
private static final Integer HEIGHT = 140;
/**
* LOGO 默认宽度
*/
private static final Integer LOGO_WIDTH = 22;
/**
* LOGO 默认高度
*/
private static final Integer LOGO_HEIGHT = 22;
/**
* 图片格式
*/
private static final String IMAGE_FORMAT = "png";
private static final String CHARSET = "utf-8";
/**
* 原生转码前面没有 data:image/png;base64 这些字段,返回给前端是无法被解析
*/
private static final String BASE64_IMAGE = "data:image/png;base64,%s";
/**
* 生成二维码,使用默认尺寸
*
* @param content 内容
* @return
*/
public String getBase64QRCode(String content) {
return getBase64Image(content, WIDTH, HEIGHT, null, null, null);
}
/**
* 生成二维码
*
* @param content 内容
* @param width 二维码宽度
* @param height 二维码高度
* @param logoUrl logo 在线地址
* @param logoWidth logo 宽度
* @param logoHeight logo 高度
* @return
*/
public String getBase64QRCode(String content, Integer width, Integer height, String logoUrl, Integer logoWidth, Integer logoHeight) {
return getBase64Image(content, width, height, logoUrl, logoWidth, logoHeight);
}
private String getBase64Image(String content, Integer width, Integer height, String logoUrl, Integer logoWidth, Integer logoHeight) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
BufferedImage bufferedImage = crateQRCode(content, width, height, logoUrl, logoWidth, logoHeight);
try {
ImageIO.write(bufferedImage, IMAGE_FORMAT, os);
} catch (IOException e) {
log.error("[生成二维码,错误{}]", e);
}
// 转出即可直接使用
return String.format(BASE64_IMAGE, Base64.encode(os.toByteArray()));
}
/**
* 生成二维码
*
* @param content 内容
* @param width 二维码宽度
* @param height 二维码高度
* @param logoUrl logo 在线地址
* @param logoWidth logo 宽度
* @param logoHeight logo 高度
* @return
*/
private BufferedImage crateQRCode(String content, Integer width, Integer height, String logoUrl, Integer logoWidth, Integer logoHeight) {
if (StrUtil.isNotBlank(content)) {
ServletOutputStream stream = null;
HashMap<EncodeHintType, Comparable> hints = new HashMap<>(4);
// 指定字符编码为utf-8
hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
// 指定二维码的纠错等级为中级
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
// 设置图片的边距
hints.put(EncodeHintType.MARGIN, 2);
try {
QRCodeWriter writer = new QRCodeWriter();
BitMatrix bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, width, height, hints);
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
bufferedImage.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
}
}
if (StrUtil.isNotBlank(logoUrl)) {
insertLogo(bufferedImage, width, height, logoUrl, logoWidth, logoHeight);
}
return bufferedImage;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (stream != null) {
try {
stream.flush();
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
return null;
}
/**
* 二维码插入logo
*
* @param source 二维码
* @param width 二维码宽度
* @param height 二维码高度
* @param logoUrl logo 在线地址
* @param logoWidth logo 宽度
* @param logoHeight logo 高度
* @throws Exception
*/
private void insertLogo(BufferedImage source, Integer width, Integer height, String logoUrl, Integer logoWidth, Integer logoHeight) throws Exception {
// logo 源可为 File/InputStream/URL
Image src = ImageIO.read(new URL(logoUrl));
// 插入LOGO
Graphics2D graph = source.createGraphics();
int x = (width - logoWidth) / 2;
int y = (height - logoHeight) / 2;
graph.drawImage(src, x, y, logoWidth, logoHeight, null);
Shape shape = new RoundRectangle2D.Float(x, y, logoWidth, logoHeight, 6, 6);
graph.setStroke(new BasicStroke(3f));
graph.draw(shape);
graph.dispose();
}
/**
* 获取二维码
*
* @param content 内容
* @throws IOException
*/
public void getQRCode(String content,OutputStream output) throws IOException {
BufferedImage image = crateQRCode(content, WIDTH, HEIGHT, null, null, null);
ImageIO.write(image, IMAGE_FORMAT, output);
}
/**
* 获取二维码
*
* @param content 内容
* @param logoUrl logo资源
* @param output 输出流
* @throws Exception
*/
public void getQRCode(String content, String logoUrl, OutputStream output) throws Exception {
BufferedImage image = crateQRCode(content, WIDTH, HEIGHT, logoUrl, LOGO_WIDTH, LOGO_HEIGHT);
ImageIO.write(image, IMAGE_FORMAT, output);
}
}
3、在yml文件中增加oss配置项目
oss:
access-key-id: XXXXXX
access-key-secret: XXXXXX
bucket: shouchuangzichan
endpoint: XXXXXXX
dir: file/
oss-url: XXXXX
4、创建config包,增加oss属性类,属性类中引入了yml中的属性,根据你的属性配置名称修改
package com.shouchuang.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "oss")
public class OSSProperties{
private String endpoint;
private String accessKeyId;
private String accessKeySecret;
private String bucket;
private String dir;
//省略getset
public String getEndpoint() {
return endpoint;
}
public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
}
public String getAccessKeyId() {
return accessKeyId;
}
public void setAccessKeyId(String accessKeyId) {
this.accessKeyId = accessKeyId;
}
public String getAccessKeySecret() {
return accessKeySecret;
}
public void setAccessKeySecret(String accessKeySecret) {
this.accessKeySecret = accessKeySecret;
}
public String getBucket() {
return bucket;
}
public void setBucket(String bucket) {
this.bucket = bucket;
}
public String getDir() {
return dir;
}
public void setDir(String dir) {
this.dir = dir;
}
}
5、新增config配置类,主要实例oss对象方便项目使用
package com.shouchuang.config;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSClientBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class OSSConfig {
@Autowired
private OSSProperties ossProperties;
@Bean
public OSSClient ossClient(){
OSS ossClient = new OSSClientBuilder().build(ossProperties.getEndpoint(),
ossProperties.getAccessKeyId(),
ossProperties.getAccessKeySecret());
return (OSSClient) ossClient;
}
}
6、新增oss工具类,方便项目逻辑中调用上传等方法
package com.shouchuang.utils;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectResult;
import com.shouchuang.config.OSSProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
@Component
public class OSSUtil {
@Autowired
private OSSProperties ossProperties;
@Autowired
private OSSClient ossClient;
@Autowired
private Environment env;
/**
* 上传图片
*
* @param file
* @param fileName
* @return
* @throws IOException
*/
public String uploadImg2Oss(MultipartFile file, String fileName) throws IOException {
try {
InputStream inputStream = file.getInputStream();
this.uploadFile2OSS(inputStream, fileName);
String url = "https://" + env.getProperty("oss.bucket") + "." + env.getProperty("oss.endpoint") + "/" + env.getProperty("oss.dir") + fileName;
System.out.println(url);
return url;
} catch (Exception e) {
System.out.println(e.getMessage() +"图片错误");
throw new IOException("图片上传失败");
}
}
/**
* 上传到OSS服务器 如果同名文件会覆盖服务器上的
*
* @param instream 文件流
* @param fileName 文件名称 包括后缀名
* @return 出错返回"" ,唯一MD5数字签名
*/
public String uploadFile2OSS(InputStream instream, String fileName) {
String ret = "";
try {
// 创建上传Object的Metadata
ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setContentLength(instream.available());
objectMetadata.setCacheControl("no-cache");
objectMetadata.setHeader("Pragma", "no-cache");
objectMetadata.setContentType(getcontentType(fileName.substring(fileName.lastIndexOf("."))));
objectMetadata.setContentDisposition("inline;filename=" + fileName);
// System.out.println("oss-cn-beijing.aliyuncs.com");
// 上传文件
// PutObjectResult putResult = ossClient.putObject(ossProperties.getBucket(), ossProperties.getDir() + fileName, instream, objectMetadata);
PutObjectResult putResult = ossClient.putObject(env.getProperty("oss.bucket"), env.getProperty("oss.dir") + fileName, instream, objectMetadata);
System.out.println(123);
System.out.println(putResult);
ret = putResult.getETag();
}
catch (IOException e)
{
System.out.println(e.getMessage()+"123");
}
finally {
try {
if (instream != null) {
instream.close();
}
} catch (IOException e) {
System.out.println(e.getMessage()+"错误信息");
e.printStackTrace();
}
}
return ret;
}
/**
* Description: 判断OSS服务文件上传时文件的contentType
*/
public static String getcontentType(String filenameExtension) {
if (filenameExtension.equalsIgnoreCase("bmp")) {
return "image/bmp";
}
if (filenameExtension.equalsIgnoreCase("gif")) {
return "image/gif";
}
if (filenameExtension.equalsIgnoreCase("jpeg") || filenameExtension.equalsIgnoreCase("jpg")
|| filenameExtension.equalsIgnoreCase("png")) {
return "image/jpeg";
}
if (filenameExtension.equalsIgnoreCase("html")) {
return "text/html";
}
if (filenameExtension.equalsIgnoreCase("txt")) {
return "text/plain";
}
if (filenameExtension.equalsIgnoreCase("vsd")) {
return "application/vnd.visio";
}
if (filenameExtension.equalsIgnoreCase("pptx") || filenameExtension.equalsIgnoreCase("ppt")) {
return "application/vnd.ms-powerpoint";
}
if (filenameExtension.equalsIgnoreCase("docx") || filenameExtension.equalsIgnoreCase("doc")) {
return "application/msword";
}
if (filenameExtension.equalsIgnoreCase("xml")) {
return "text/xml";
}
return "image/jpeg";
}
}
7、控制器方法
package com.shouchuang.controller;
import com.shouchuang.annotation.PassToken;
import com.shouchuang.config.OSSProperties;
import com.shouchuang.dao.Admin;
import com.shouchuang.service.AdminService;
import com.shouchuang.service.QrCodeService;
import com.shouchuang.utils.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
@RestController
public class QrCodeController {
@Autowired
Environment env;
@Autowired
OSSProperties ossProperties;
@Autowired
QrCodeUtil qrCodeUtil;
@Autowired
OSSUtil ossUtil;
@Autowired
QrCodeService qrCodeService;
@Autowired
AdminService adminService;
/***
* @auth lifang
* @info 根据数量项目下新增二维码
* @param number 数量
* @param request 请求
*/
@PassToken
@GetMapping(value = "batch/add/qrcode")
public JSONResult add(@RequestParam Integer number, HttpServletRequest request)
{
try {
//获取用户id
String token = request.getHeader("token");
String userId = JSONWebToken.getAudience(token);
//获取用户信息
Admin admin = adminService.getByUserName(userId);
for (int i=0; i<number ;i++)
{
Integer bRet = qrCodeService.addCode(admin);
if ( bRet != 1 )
{
return JSONResult.errorMsg("添加失败");
}
}
return JSONResult.ok();
}
catch (Exception e)
{
return JSONResult.errorMsg(e.getMessage());
}
}
}
8、service逻辑
package com.shouchuang.service.impl;
import com.shouchuang.dao.Admin;
import com.shouchuang.dao.QrCode;
import com.shouchuang.exception.GraceException;
import com.shouchuang.mapper.QrCodeMapper;
import com.shouchuang.service.QrCodeService;
import com.shouchuang.utils.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
@Service
public class QrCodeServiceImpl implements QrCodeService {
@Autowired
QrCodeUtil qrCodeUtil;
@Autowired
OSSUtil ossUtil;
@Autowired
Environment env;
@Autowired
QrCodeMapper qrCodeMapper;
@Override
public Integer addCode(Admin admin) throws IOException {
Long lid = SnowFlakeUtil.getSnowflakeId();
String id = String.valueOf(lid);
String url = creteCode(id);
System.out.println(url);
//生成当前时间
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String date = simpleDateFormat.format(new Date());
//赋值创建二维码
QrCode qrCode = new QrCode();
qrCode.setId(new BigInteger(id));
qrCode.setImg_url(url);
qrCode.setStatus(2);
qrCode.setLoads(0);
qrCode.setSign_code("");
qrCode.setAdmin_id(admin.getId());
qrCode.setProject_id(admin.getProject());
qrCode.setCreated_at(date);
qrCode.setUpdated_at(date);
return qrCodeMapper.addQrCode(qrCode);
}
/***
* @auth lifang
* @info 创建二维码上传至oss
* @param id
* @return
* @throws IOException
*/
public String creteCode(String id) throws IOException {
//生成base64的二维码
String base64QRCode = qrCodeUtil.getBase64QRCode("http://XXXXXXXXX:8287/code.png?id="+id);
// System.out.println(base64QRCode);
//转换为二维码图片
MultipartFile multipartFile = Base64DecodeMultipartFile.base64ToMultipart(base64QRCode);
//获取stream格式文件
InputStream inputStream = multipartFile.getInputStream();
//上传到oss
String ext = "png";
Date now = new Date();
SimpleDateFormat date = new SimpleDateFormat("yyyyMMdd");
String newfilename = date.format(now) + "/";
SimpleDateFormat time = new SimpleDateFormat("HHmmssSSS");
newfilename += time.format(now);
newfilename += "_" + new Random().nextInt(1000) + "." + ext;
ossUtil.uploadFile2OSS(inputStream, newfilename);
String url = "https://" + env.getProperty("oss.bucket") + "." + env.getProperty("oss.endpoint") + "/" + env.getProperty("oss.dir") + newfilename;
return "/"+env.getProperty("oss.dir") + newfilename;
}
}