package com.ruoyi.web.controller.smartor;
|
|
import com.google.zxing.BarcodeFormat;
|
import com.google.zxing.EncodeHintType;
|
import com.google.zxing.WriterException;
|
import com.google.zxing.client.j2se.MatrixToImageWriter;
|
import com.google.zxing.common.BitMatrix;
|
import com.google.zxing.qrcode.QRCodeWriter;
|
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
|
import com.mchange.v2.uid.UidUtils;
|
import com.ruoyi.common.core.domain.AjaxResult;
|
import com.ruoyi.framework.config.ServerConfig;
|
import com.smartor.domain.Question;
|
import com.smartor.domain.SvyLibTemplate;
|
import freemarker.template.Configuration;
|
import freemarker.template.Template;
|
import freemarker.template.TemplateException;
|
import io.swagger.annotations.Api;
|
import io.swagger.annotations.ApiOperation;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.http.MediaType;
|
import org.springframework.web.bind.annotation.*;
|
|
import javax.imageio.ImageIO;
|
import javax.servlet.http.HttpServletRequest;
|
import java.awt.Color;
|
import java.awt.Graphics2D;
|
import java.awt.RenderingHints;
|
import java.awt.image.BufferedImage;
|
import java.io.File;
|
import java.io.IOException;
|
import java.io.InputStream;
|
import java.io.StringWriter;
|
import java.net.URI;
|
import java.util.*;
|
|
@Slf4j
|
@Api(description = "问卷二维码")
|
@RestController
|
@RequestMapping("/qrcode")
|
public class QRCodeController {
|
|
private final Configuration configuration;
|
|
public QRCodeController(Configuration configuration) {
|
this.configuration = configuration;
|
}
|
|
@Value("${ruoyi.profile}")
|
private String profile;
|
|
/**
|
* 公司logo在classpath中的路径,打包进jar后任何环境都能读取到
|
*/
|
private static final String LOGO_CLASSPATH = "/images/hrslogo.png";
|
|
@Autowired
|
private ServerConfig serverConfig;
|
|
/**
|
* 问卷题目
|
*
|
* @param reqid 问卷ID
|
* userid 用户ID
|
* @return
|
* @throws IOException
|
* @throws TemplateException
|
*/
|
@ResponseBody
|
@GetMapping(value = "/generateStaticHtml/{reqid}/{userid}", produces = MediaType.TEXT_HTML_VALUE)
|
public String generateStaticHtml(@PathVariable("reqid") String reqid, @PathVariable("userid") String userid) throws IOException, TemplateException {
|
// 创建Freemarker配置
|
Configuration configuration = new Configuration(Configuration.VERSION_2_3_31);
|
configuration.setClassForTemplateLoading(SvyLibTemplateController.class, "/template");
|
configuration.setDefaultEncoding("UTF-8");
|
|
try {
|
// 加载模板
|
Template template = configuration.getTemplate("question.ftl");
|
|
// 准备题目数据
|
List<Question> questions = new ArrayList<>();
|
|
// 单选题
|
List<String> singleChoiceOptions = new ArrayList<>();
|
singleChoiceOptions.add("Option 1");
|
singleChoiceOptions.add("Option 2");
|
singleChoiceOptions.add("Option 3");
|
Question singleChoiceQuestion = new Question("singleChoice", "单选题111", "单选题题目1:", singleChoiceOptions);
|
|
List<String> singleChoiceOptions2 = new ArrayList<>();
|
singleChoiceOptions2.add("Option 4");
|
singleChoiceOptions2.add("Option 5");
|
singleChoiceOptions2.add("Option 6");
|
Question singleChoiceQuestion2 = new Question("singleChoice", "单选题222", "单选题题目2:", singleChoiceOptions2);
|
|
questions.add(singleChoiceQuestion);
|
questions.add(singleChoiceQuestion2);
|
|
// 多选题
|
List<String> multipleChoiceOptions = new ArrayList<>();
|
multipleChoiceOptions.add("Option A");
|
multipleChoiceOptions.add("Option B");
|
multipleChoiceOptions.add("Option C");
|
Question multipleChoiceQuestion = new Question("multipleChoice", "多选题1", "Question 2: Select multiple options", multipleChoiceOptions);
|
questions.add(multipleChoiceQuestion);
|
|
// 问答题
|
Question openEndedQuestion = new Question("openEnded", "问答题题", "问答题题目1", null);
|
questions.add(openEndedQuestion);
|
|
// 准备模板数据
|
Map<String, Object> data = new HashMap<>();
|
data.put("questions", questions);
|
|
// 渲染模板
|
StringWriter writer = new StringWriter();
|
template.process(data, writer);
|
String renderedTemplate = writer.toString();
|
return writer.toString();
|
// 返回模板内容给客户端
|
// System.out.println(renderedTemplate); // 这里只是示例,实际应用中应将内容返回给客户端进行展示
|
} catch (IOException | TemplateException e) {
|
e.printStackTrace();
|
}
|
return null;
|
}
|
|
/**
|
* @param url 问卷ID
|
* @param url 用户ID
|
*/
|
@ApiOperation("获取问卷二维码")
|
@PostMapping(value = "/getQRcode")
|
public AjaxResult getQRcode(@RequestParam("url") String url) {
|
log.info("获取问卷二维码的入参:{}", url);
|
// 尝试从url中提取p参数的值作为图片名称,值为空则用UUID
|
String fileName = UUID.randomUUID().toString().replace("-", "");
|
try {
|
URI uri = new URI(url);
|
String query = uri.getQuery();
|
if (query != null) {
|
for (String param : query.split("&")) {
|
String[] pair = param.split("=", 2);
|
if ("p".equals(pair[0]) && pair.length > 1 && !pair[1].isEmpty()) {
|
fileName = pair[1] + "-" + System.currentTimeMillis();
|
break;
|
}
|
}
|
}
|
} catch (Exception e) {
|
log.warn("解析url中的p参数失败,使用UUID作为文件名");
|
}
|
String filePath = profile + "\\qrpath" + "\\" + fileName + ".png"; // 保存二维码图像的文件路径
|
//判断文件夹是否存在
|
File file = new File(profile + "\\qrpath");
|
if (!file.exists()) {
|
file.mkdirs();
|
}
|
generateQRCode(url, filePath);
|
return AjaxResult.success(serverConfig.getUrl() + "/profile/qrpath/" + fileName + ".png");
|
}
|
|
private void generateQRCode(String url, String filePath) {
|
QRCodeWriter qrCodeWriter = new QRCodeWriter();
|
try {
|
// 使用高容错级别(H级,30%容错),确保二维码中间嵌入logo后仍可正常扫描
|
Map<EncodeHintType, Object> hints = new HashMap<>();
|
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
|
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
|
hints.put(EncodeHintType.MARGIN, 1);
|
|
BitMatrix bitMatrix = qrCodeWriter.encode(url, BarcodeFormat.QR_CODE, 500, 500, hints);
|
|
// 将BitMatrix转为二值BufferedImage(黑白)
|
BufferedImage binaryImage = MatrixToImageWriter.toBufferedImage(bitMatrix);
|
|
// 创建RGB彩色图像,把二维码画上去,否则后续绘制logo会丢失颜色
|
BufferedImage qrImage = new BufferedImage(500, 500, BufferedImage.TYPE_INT_RGB);
|
Graphics2D graphics = qrImage.createGraphics();
|
graphics.setColor(Color.WHITE);
|
graphics.fillRect(0, 0, 500, 500);
|
graphics.drawImage(binaryImage, 0, 0, null);
|
|
// 从classpath读取logo并绘制到二维码中间
|
try (InputStream logoStream = this.getClass().getResourceAsStream(LOGO_CLASSPATH)) {
|
if (logoStream != null) {
|
BufferedImage logoImage = ImageIO.read(logoStream);
|
|
// 计算logo尺寸,设为二维码的1/5
|
int logoWidth = qrImage.getWidth() / 5;
|
int logoHeight = qrImage.getHeight() / 5;
|
|
// 计算logo居中位置
|
int logoX = (qrImage.getWidth() - logoWidth) / 2;
|
int logoY = (qrImage.getHeight() - logoHeight) / 2;
|
|
// 绘制白色圆角背景,让logo更突出
|
int padding = 6;
|
graphics.setColor(Color.WHITE);
|
graphics.fillRoundRect(logoX - padding, logoY - padding, logoWidth + padding * 2, logoHeight + padding * 2, 10, 10);
|
|
// 绘制logo
|
graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
graphics.drawImage(logoImage, logoX, logoY, logoWidth, logoHeight, null);
|
} else {
|
log.warn("classpath中未找到二维码logo: {}", LOGO_CLASSPATH);
|
}
|
}
|
graphics.dispose();
|
|
// 输出最终图片
|
File outputFile = new File(filePath);
|
ImageIO.write(qrImage, "PNG", outputFile);
|
} catch (WriterException | IOException e) {
|
e.printStackTrace();
|
}
|
}
|
|
/**
|
* 问券结果处理
|
*
|
* @param request
|
*/
|
@PostMapping(value = "/getFormDate")
|
public void getFormDate(HttpServletRequest request) {
|
Map<String, String[]> formData = request.getParameterMap();
|
System.out.println(formData.toString());
|
}
|
|
}
|