| @@ -22,6 +22,11 @@ | |||||
| <artifactId>spring-boot-starter-test</artifactId> | <artifactId>spring-boot-starter-test</artifactId> | ||||
| <scope>test</scope> | <scope>test</scope> | ||||
| </dependency> | </dependency> | ||||
| <dependency> | |||||
| <groupId>com.google.zxing</groupId> | |||||
| <artifactId>core</artifactId> | |||||
| <version>3.3.0</version> | |||||
| </dependency> | |||||
| </dependencies> | </dependencies> | ||||
| <build> | <build> | ||||
| <plugins> | <plugins> | ||||
| @@ -9,8 +9,8 @@ import org.springframework.context.annotation.Bean; | |||||
| import tk.mybatis.spring.annotation.MapperScan; | import tk.mybatis.spring.annotation.MapperScan; | ||||
| /** | /** | ||||
| * @author chenkx | |||||
| * @date 2017-12-26 | |||||
| * @author Stormeye | |||||
| * @date 2019-08-08 | |||||
| */ | */ | ||||
| @SpringBootApplication | @SpringBootApplication | ||||
| @MapperScan(basePackages = {"com.iformall.mapper"}) | @MapperScan(basePackages = {"com.iformall.mapper"}) | ||||
| @@ -27,6 +27,9 @@ public class PosApplication { | |||||
| @Value("${fm.open}") | @Value("${fm.open}") | ||||
| private boolean fmOpen; | private boolean fmOpen; | ||||
| @Value("${fm.upload_dir}") | |||||
| private String uploadDir; | |||||
| @Bean | @Bean | ||||
| public boolean isFmException() { | public boolean isFmException() { | ||||
| return fmException; | return fmException; | ||||
| @@ -42,6 +45,11 @@ public class PosApplication { | |||||
| return fmOpen; | return fmOpen; | ||||
| } | } | ||||
| @Bean | |||||
| public String fmUploadDir() { | |||||
| return uploadDir; | |||||
| } | |||||
| public static void main(String[] args) { | public static void main(String[] args) { | ||||
| SpringApplication.run(PosApplication.class, args); | SpringApplication.run(PosApplication.class, args); | ||||
| @@ -1,7 +1,5 @@ | |||||
| package com.iformall.service; | package com.iformall.service; | ||||
| import com.iformall.domain.po.WxCoupon; | |||||
| import com.iformall.domain.vo.WxCouponOrderCVo; | |||||
| import com.iformall.enums.EnumVerifyActionType; | import com.iformall.enums.EnumVerifyActionType; | ||||
| import com.iformall.exception.MallinkException; | import com.iformall.exception.MallinkException; | ||||
| import org.springframework.web.bind.annotation.RequestBody; | import org.springframework.web.bind.annotation.RequestBody; | ||||
| @@ -0,0 +1,94 @@ | |||||
| package com.iformall.utils; | |||||
| import java.awt.Graphics2D; | |||||
| import java.awt.geom.AffineTransform; | |||||
| import java.awt.image.BufferedImage; | |||||
| import com.google.zxing.LuminanceSource; | |||||
| /** | |||||
| * @author Stormeye | |||||
| */ | |||||
| public class BufferedImageLuminanceSource extends LuminanceSource { | |||||
| private final BufferedImage image; | |||||
| private final int left; | |||||
| private final int top; | |||||
| BufferedImageLuminanceSource(BufferedImage image) { | |||||
| this(image, 0, 0, image.getWidth(), image.getHeight()); | |||||
| } | |||||
| BufferedImageLuminanceSource(BufferedImage image, int left, int top, int width, int height) { | |||||
| super(width, height); | |||||
| int sourceWidth = image.getWidth(); | |||||
| int sourceHeight = image.getHeight(); | |||||
| if (left + width > sourceWidth || top + height > sourceHeight) { | |||||
| throw new IllegalArgumentException("Crop rectangle does not fit within image data."); | |||||
| } | |||||
| for (int y = top; y < top + height; y++) { | |||||
| for (int x = left; x < left + width; x++) { | |||||
| if ((image.getRGB(x, y) & 0xFF000000) == 0) { | |||||
| // = white | |||||
| image.setRGB(x, y, 0xFFFFFFFF); | |||||
| } | |||||
| } | |||||
| } | |||||
| this.image = new BufferedImage(sourceWidth, sourceHeight, BufferedImage.TYPE_BYTE_GRAY); | |||||
| this.image.getGraphics().drawImage(image, 0, 0, null); | |||||
| this.left = left; | |||||
| this.top = top; | |||||
| } | |||||
| @Override | |||||
| public byte[] getRow(int y, byte[] row) { | |||||
| if (y < 0 || y >= getHeight()) { | |||||
| throw new IllegalArgumentException("Requested row is outside the image: " + y); | |||||
| } | |||||
| int width = getWidth(); | |||||
| if (row == null || row.length < width) { | |||||
| row = new byte[width]; | |||||
| } | |||||
| image.getRaster().getDataElements(left, top + y, width, 1, row); | |||||
| return row; | |||||
| } | |||||
| @Override | |||||
| public byte[] getMatrix() { | |||||
| int width = getWidth(); | |||||
| int height = getHeight(); | |||||
| int area = width * height; | |||||
| byte[] matrix = new byte[area]; | |||||
| image.getRaster().getDataElements(left, top, width, height, matrix); | |||||
| return matrix; | |||||
| } | |||||
| @Override | |||||
| public boolean isCropSupported() { | |||||
| return true; | |||||
| } | |||||
| @Override | |||||
| public LuminanceSource crop(int left, int top, int width, int height) { | |||||
| return new BufferedImageLuminanceSource(image, this.left + left, this.top + top, width, height); | |||||
| } | |||||
| @Override | |||||
| public boolean isRotateSupported() { | |||||
| return true; | |||||
| } | |||||
| @Override | |||||
| public LuminanceSource rotateCounterClockwise() { | |||||
| int sourceWidth = image.getWidth(); | |||||
| int sourceHeight = image.getHeight(); | |||||
| AffineTransform transform = new AffineTransform(0.0, -1.0, 1.0, 0.0, 0.0, sourceWidth); | |||||
| BufferedImage rotatedImage = new BufferedImage(sourceHeight, sourceWidth, BufferedImage.TYPE_BYTE_GRAY); | |||||
| Graphics2D g = rotatedImage.createGraphics(); | |||||
| g.drawImage(image, transform, null); | |||||
| g.dispose(); | |||||
| int width = getWidth(); | |||||
| return new BufferedImageLuminanceSource(rotatedImage, top, sourceWidth - (left + width), getHeight(), width); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,164 @@ | |||||
| package com.iformall.utils; | |||||
| import java.awt.BasicStroke; | |||||
| import java.awt.Graphics; | |||||
| import java.awt.Graphics2D; | |||||
| import java.awt.Image; | |||||
| import java.awt.Shape; | |||||
| import java.awt.geom.RoundRectangle2D; | |||||
| import java.awt.image.BufferedImage; | |||||
| import java.io.File; | |||||
| import java.io.OutputStream; | |||||
| import java.util.Hashtable; | |||||
| import javax.imageio.ImageIO; | |||||
| import com.google.zxing.BarcodeFormat; | |||||
| import com.google.zxing.BinaryBitmap; | |||||
| import com.google.zxing.DecodeHintType; | |||||
| import com.google.zxing.EncodeHintType; | |||||
| import com.google.zxing.MultiFormatReader; | |||||
| import com.google.zxing.MultiFormatWriter; | |||||
| import com.google.zxing.Result; | |||||
| import com.google.zxing.common.BitMatrix; | |||||
| import com.google.zxing.common.HybridBinarizer; | |||||
| import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; | |||||
| public class QRCodeUtil { | |||||
| private static final String CHARSET = "utf-8"; | |||||
| private static final String FORMAT_NAME = "JPG"; | |||||
| /** | |||||
| * 二维码尺寸 | |||||
| */ | |||||
| private static final int QRCODE_SIZE = 300; | |||||
| /** | |||||
| * LOGO宽度 | |||||
| */ | |||||
| private static final int WIDTH = 60; | |||||
| /** | |||||
| * LOGO高度 | |||||
| */ | |||||
| private static final int HEIGHT = 60; | |||||
| private static BufferedImage createImage(String content, String imgPath, boolean needCompress) throws Exception { | |||||
| Hashtable hints = new Hashtable(); | |||||
| hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); | |||||
| hints.put(EncodeHintType.CHARACTER_SET, CHARSET); | |||||
| hints.put(EncodeHintType.MARGIN, 1); | |||||
| BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE, | |||||
| hints); | |||||
| int width = bitMatrix.getWidth(); | |||||
| int height = bitMatrix.getHeight(); | |||||
| BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); | |||||
| for (int x = 0; x < width; x++) { | |||||
| for (int y = 0; y < height; y++) { | |||||
| image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF); | |||||
| } | |||||
| } | |||||
| if (imgPath == null || "".equals(imgPath)) { | |||||
| return image; | |||||
| } | |||||
| // 插入图片 | |||||
| QRCodeUtil.insertImage(image, imgPath, needCompress); | |||||
| return image; | |||||
| } | |||||
| private static void insertImage(BufferedImage source, String imgPath, boolean needCompress) throws Exception { | |||||
| File file = new File(imgPath); | |||||
| if (!file.exists()) { | |||||
| System.err.println("" + imgPath + " 该文件不存在!"); | |||||
| return; | |||||
| } | |||||
| Image src = ImageIO.read(new File(imgPath)); | |||||
| int width = src.getWidth(null); | |||||
| int height = src.getHeight(null); | |||||
| // 压缩LOGO | |||||
| if (needCompress) { | |||||
| if (width > WIDTH) { | |||||
| width = WIDTH; | |||||
| } | |||||
| if (height > HEIGHT) { | |||||
| height = HEIGHT; | |||||
| } | |||||
| Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH); | |||||
| BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); | |||||
| Graphics g = tag.getGraphics(); | |||||
| // 绘制缩小后的图 | |||||
| g.drawImage(image, 0, 0, null); | |||||
| g.dispose(); | |||||
| src = image; | |||||
| } | |||||
| // 插入LOGO | |||||
| Graphics2D graph = source.createGraphics(); | |||||
| int x = (QRCODE_SIZE - width) / 2; | |||||
| int y = (QRCODE_SIZE - height) / 2; | |||||
| graph.drawImage(src, x, y, width, height, null); | |||||
| Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6); | |||||
| graph.setStroke(new BasicStroke(3f)); | |||||
| graph.draw(shape); | |||||
| graph.dispose(); | |||||
| } | |||||
| public static void encode(String content, String imgPath, String destPath, boolean needCompress) throws Exception { | |||||
| BufferedImage image = QRCodeUtil.createImage(content, imgPath, needCompress); | |||||
| mkdirs(destPath); | |||||
| // String file = new Random().nextInt(99999999)+".jpg"; | |||||
| // ImageIO.write(image, FORMAT_NAME, new File(destPath+"/"+file)); | |||||
| ImageIO.write(image, FORMAT_NAME, new File(destPath)); | |||||
| } | |||||
| public static BufferedImage encode(String content, String imgPath, boolean needCompress) throws Exception { | |||||
| BufferedImage image = QRCodeUtil.createImage(content, imgPath, needCompress); | |||||
| return image; | |||||
| } | |||||
| public static void mkdirs(String destPath) { | |||||
| File file = new File(destPath); | |||||
| // 当文件夹不存在时,mkdirs会自动创建多层目录,区别于mkdir.(mkdir如果父目录不存在则会抛出异常) | |||||
| if (!file.exists() && !file.isDirectory()) { | |||||
| file.mkdirs(); | |||||
| } | |||||
| } | |||||
| public static void encode(String content, String imgPath, String destPath) throws Exception { | |||||
| QRCodeUtil.encode(content, imgPath, destPath, false); | |||||
| } | |||||
| // 被注释的方法 | |||||
| /* | |||||
| * public static void encode(String content, String destPath, boolean | |||||
| * needCompress) throws Exception { QRCodeUtil.encode(content, null, destPath, | |||||
| * needCompress); } | |||||
| */ | |||||
| public static void encode(String content, String destPath) throws Exception { | |||||
| QRCodeUtil.encode(content, null, destPath, false); | |||||
| } | |||||
| public static void encode(String content, String imgPath, OutputStream output, boolean needCompress) | |||||
| throws Exception { | |||||
| BufferedImage image = QRCodeUtil.createImage(content, imgPath, needCompress); | |||||
| ImageIO.write(image, FORMAT_NAME, output); | |||||
| } | |||||
| public static void encode(String content, OutputStream output) throws Exception { | |||||
| QRCodeUtil.encode(content, null, output, false); | |||||
| } | |||||
| public static String decode(File file) throws Exception { | |||||
| BufferedImage image; | |||||
| image = ImageIO.read(file); | |||||
| if (image == null) { | |||||
| return null; | |||||
| } | |||||
| BufferedImageLuminanceSource source = new BufferedImageLuminanceSource(image); | |||||
| BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source)); | |||||
| Result result; | |||||
| Hashtable hints = new Hashtable(); | |||||
| hints.put(DecodeHintType.CHARACTER_SET, CHARSET); | |||||
| result = new MultiFormatReader().decode(bitmap, hints); | |||||
| String resultStr = result.getText(); | |||||
| return resultStr; | |||||
| } | |||||
| public static String decode(String path) throws Exception { | |||||
| return QRCodeUtil.decode(new File(path)); | |||||
| } | |||||
| } | |||||
| @@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; | |||||
| import com.iformall.PosApplication; | import com.iformall.PosApplication; | ||||
| import com.iformall.pay.WxPayConstant; | import com.iformall.pay.WxPayConstant; | ||||
| import com.iformall.pay.WxPayment; | import com.iformall.pay.WxPayment; | ||||
| import com.iformall.utils.QRCodeUtil; | |||||
| import org.junit.Assert; | import org.junit.Assert; | ||||
| import org.junit.FixMethodOrder; | import org.junit.FixMethodOrder; | ||||
| import org.junit.Test; | import org.junit.Test; | ||||
| @@ -100,6 +101,33 @@ public class PosAppTest { | |||||
| Assert.assertEquals(resSigned, true); | Assert.assertEquals(resSigned, true); | ||||
| } | } | ||||
| @Test | |||||
| public void pQrCodeTest() { | |||||
| // 存放在二维码中的内容 | |||||
| String text = "https://ctest.malls.iformall.com/order/1"; | |||||
| // 嵌入二维码的图片路径 | |||||
| String imgPath = ""; | |||||
| // 生成的二维码的路径及名称 | |||||
| String destPath = "/Users/stormeye/Downloads/MyWork/bk/qr.jpg"; | |||||
| try { | |||||
| //生成二维码 | |||||
| QRCodeUtil.encode(text, imgPath, destPath, true); | |||||
| } catch (Exception e) { | |||||
| System.out.println("生成二维码异常"); | |||||
| e.printStackTrace(); | |||||
| } | |||||
| // 解析二维码,这里只是将上面的text解析出来了,所以扫描结果就是一串字符串 | |||||
| String str = null; | |||||
| try { | |||||
| str = QRCodeUtil.decode(destPath); | |||||
| } catch (Exception e) { | |||||
| System.out.println("解析二维码异常"); | |||||
| e.printStackTrace(); | |||||
| } | |||||
| // 打印出解析出的内容 | |||||
| System.out.println(str); | |||||
| } | |||||
| @Test | @Test | ||||
| public void getMemTest() throws Exception { | public void getMemTest() throws Exception { | ||||
| Map<String, String> reqObj = new HashMap<>(); | Map<String, String> reqObj = new HashMap<>(); | ||||