java 模板方法 实现二维码生成 并进行二维码白边自定义的裁剪
由于自己最近在学设计模式,就想着如何能运用到自己工作的项目中。找了半天,想起自己之前写的一段关于生成二维码图片的代码。后面由于同事的需求不同,他们在里面添加了一下其它逻辑的代码。现在感觉这段代码已经不太好被扩展维护了。于是就用选择了设计模式中的模板方法重新进行设计。(重构后的代码布局如图:)
下面是代码的实现:
OperateImage 工具类:
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
/**
* 生成二维码的工具类
* @version 1.0
*/
public class OperateImage {
// ===源图片路径名称如:c:\1.jpg
private String srcpath;
// ===剪切图片存放路径名称.如:c:\2.jpg
private String subpath;
// ===剪切点x坐标
private int x;
private int y;
// ===剪切点宽度
private int width;
private int height;
public OperateImage() {
}
public OperateImage(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
/**
* 对图片裁剪,并把裁剪完蛋新图片保存 。
*/
public void cut() throws IOException {
FileInputStream is = null;
ImageInputStream iis = null;
try {
// 读取图片文件
is = new FileInputStream(srcpath);
/*
* 返回包含所有当前已注册 ImageReader 的 Iterator,这些 ImageReader 声称能够解码指定格式。
* 参数:formatName - 包含非正式格式名称 .(例如 "jpeg" 或 "tiff")等 。
*/
Iterator<ImageReader> it = ImageIO.getImageReadersBySuffix("jpg");
ImageReader reader = it.next();
// 获取图片流
iis = ImageIO.createImageInputStream(is);
/*
* <p>iis:读取源.true:只向前搜索 </p>.将它标记为 ‘只向前搜索’。
* 此设置意味着包含在输入源中的图像将只按顺序读取,可能允许 reader 避免缓存包含与以前已经读取的图像关联的数据的那些输入部分。
*/
reader.setInput(iis, true);
/*
* <p>描述如何对流进行解码的类<p>.用于指定如何在输入时从 Java Image I/O
* 框架的上下文中的流转换一幅图像或一组图像。用于特定图像格式的插件 将从其 ImageReader 实现的
* getDefaultReadParam 方法中返回 ImageReadParam 的实例。
*/
ImageReadParam param = reader.getDefaultReadParam();
/*
* 图片裁剪区域。Rectangle 指定了坐标空间中的一个区域,通过 Rectangle 对象
* 的左上顶点的坐标(x,y)、宽度和高度可以定义这个区域。
*/
Rectangle rect = new Rectangle(x, y, width, height);
// 提供一个 BufferedImage,将其用作解码像素数据的目标。
param.setSourceRegion(rect);
/*
* 使用所提供的 ImageReadParam 读取通过索引 imageIndex 指定的对象,并将 它作为一个完整的
* BufferedImage 返回。
*/
BufferedImage bi = reader.read(0, param);
// 保存新图片
ImageIO.write(bi, "jpg", new File(subpath));
} finally {
if (is != null)
is.close();
if (iis != null)
iis.close();
}
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public String getSrcpath() {
return srcpath;
}
public void setSrcpath(String srcpath) {
this.srcpath = srcpath;
}
public String getSubpath() {
return subpath;
}
public void setSubpath(String subpath) {
this.subpath = subpath;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public static void main(String[] args) {
OperateImage operateImage = new OperateImage(20, 20, 260, 260);
operateImage.setSrcpath("C:/Users/74532/Desktop/bbb.JPG");
operateImage.setSubpath("C:/Users/74532/Desktop/bbb.JPG");
try {
operateImage.cut();
} catch (IOException e) {
e.printStackTrace();
}
}
}
QrCodeTemplate 模板类:
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import com.hx.main.QREncoder;
/**
* 抽象基类,为所有子类提供模板框架
* @version 1.0
*/
public abstract class QrCodeTemplate {
//生成图片宽度
private int imgWidth;
//生成图片高度
private int imgHeight;
//剪切点x坐标
private int cutX;
//剪切点y坐标
private int cutY;
//剪切点宽度
private int cutWidth;
//剪切点高度
private int cutHeight;
{
//初始默认参数
imgWidth = 300;
imgHeight = 300;
cutX = 32;
cutY = 32;
cutWidth = 235;
cutHeight = 235;
}
public QrCodeTemplate() {
}
/**
* 该构造器提供修改默认参数入口
* @param imgWidth 生成图片宽度
* @param imgHeight 生成图片高度
* @param cutX 剪切点x坐标
* @param cutY 剪切点y坐标
* @param cutWidth 剪切点宽度
* @param cutHeight 剪切点高度
*/
public QrCodeTemplate(int imgWidth, int imgHeight, int cutX, int cutY,
int cutWidth, int cutHeight) {
super();
this.imgWidth = imgWidth;
this.imgHeight = imgHeight;
this.cutX = cutX;
this.cutY = cutY;
this.cutWidth = cutWidth;
this.cutHeight = cutHeight;
}
public final byte[] runTemplate(){
//①生成二维码图片地址
String imgPath = qrCodePath();
//②创建二维码文件
File file = createFile(imgPath);
//③获取需要生成二维码的url
String targetUrl = qrCodeTargetUrl();
//④生成二维码图片
qrCodeCreate(targetUrl, imgPath, imgWidth, imgHeight);
//⑤将图片转为为JPG格式
change2jpg(file);
//⑥裁剪二维码
qrCodeTrim(imgPath, cutX, cutY, cutWidth, cutHeight);
//⑦获取二维码信息
byte[] buffer = qrCodeBufferInfo(file,isDeleteImg());
return buffer;
}
/**
* 二维码生成的路径
* @return
*/
protected abstract String qrCodePath();
/**
* 二维码目标url
* @return
*/
protected abstract String qrCodeTargetUrl();
/**
* 是否删除生成的二维码图片
* @return
*/
protected Boolean isDeleteImg() {
return true;
}
/**
* 生成二维码
* @param url 二维码目标url
* @param imgPath 生成图片地址
* @param width 图片宽度
* @param height 图片高度
*/
private void qrCodeCreate(String url, String imgPath, int width, int height) {
QREncoder qrEncode = new QREncoder();
qrEncode.encode(url, imgPath, width, height);
}
/**
* 生成文件
* @param directory 目录文件
* @param filepath 文件全路径
* @return 返回二维码文件
*/
private File createFile(String filepath){
int index = filepath.lastIndexOf("\\");
String directory = filepath.substring(0, index);
File file = new File(filepath);
try {
if (!new File(directory).exists()) {
new File(directory).mkdirs();
}
file.createNewFile();
} catch (IOException e2) {
throw new RuntimeException("创建文件失败");
}
return file;
}
/**
* 将图片转为为JPG格式
* @param file
*/
private void change2jpg(File file) {
BufferedImage bufferedImage;
try {
bufferedImage = ImageIO.read(file);
BufferedImage newBufferedImage = new BufferedImage(
bufferedImage.getWidth(), bufferedImage.getHeight(),
BufferedImage.TYPE_INT_RGB);
// TYPE_INT_RGB:创建一个RBG图像,24位深度,成功将32位图转化成24位
newBufferedImage.createGraphics().drawImage(bufferedImage, 0, 0,
Color.WHITE, null);
// write to jpeg file
ImageIO.write(newBufferedImage, "jpg", file);
} catch (IOException e) {
throw new RuntimeException("转为JPG失败");
}
}
/**
* 裁剪图片
* @param imgPath 图片路径
* @param x 剪切点x坐标
* @param y 剪切点y坐标
* @param width 剪切点宽度
* @param height 剪切点高度
*/
private void qrCodeTrim(String imgPath, int c_x, int c_y, int c_width, int c_height){
OperateImage operateImage = new OperateImage(c_x, c_y, c_width, c_height);
operateImage.setSrcpath(imgPath);
operateImage.setSubpath(imgPath);
try {
//进行二维码图片裁剪
operateImage.cut();
} catch (IOException e) {
throw new RuntimeException("二维码图片剪切失败");
}
}
/**
* 删除二维码文件
* @param file
* @return 返回二维码图片byte数组
*/
private byte[] qrCodeBufferInfo(File file,Boolean isDelete) {
InputStream inputStream = null;
byte[] buffer = null;
try {
inputStream = new FileInputStream(file);
int i = inputStream.available(); // 得到文件大小
buffer = new byte[i];
inputStream.read(buffer);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// 删除二维码图片
if(isDelete){
file.delete();
}
}
return buffer;
}
}
BusinessLicenseNewQrCode 子类:
import javax.servlet.http.HttpServletRequest;
/**
* 实现子类
* @version 1.0
*/
public class BusinessLicenseNewQrCode extends QrCodeTemplate{
private String GSURL="你的url";
/**
* 构造方法:缺省二维码大小
* @param uniscid
*/
public BusinessLicenseNewQrCode(String uniscid){
super();
this.GSURL += uniscid;
}
/**
* 构造方法:自定义二维码图片大小
* @param uniscid 统一信用代码
* @param imgWidth 生成图片宽度
* @param imgHeight 生成图片高度
* @param cutX 剪切点x坐标
* @param cutY 剪切点y坐标
* @param cutWidth 剪切点宽度
* @param cutHeight 剪切点高度
*/
public BusinessLicenseNewQrCode(String uniscid, int imgWidth, int imgHeight, int cutX, int cutY, int cutWidth, int cutHeight){
super(imgWidth, imgHeight, cutX, cutY, cutWidth, cutHeight);
this.GSURL += uniscid;
}
/**
* 二维码生成保存路径
*/
@Override
protected String qrCodePath() {
String dirPath = System.getProperty("user.dir") + "/app/font/qrCodeGS";
String imgPath = dirPath+ "\\" + UUIDUtil.getUUID() + ".jpg";
return imgPath;
}
/**
* 二维码目标url
*/
@Override
protected String qrCodeTargetUrl() {
return GSURL;
}
/**
* 钩子方法
* 获取二维码数据后是否删除生成的二维码图片
*/
@Override
protected Boolean isDeleteImg() {
// TODO Auto-generated method stub
return super.isDeleteImg();
}
}
MaterialsReceiptQrCode 子类:
import javax.servlet.http.HttpServletRequest;
/**
* 实现子类:收取材料凭据二维码的实现
* @version 1.0
*/
public class MaterialsReceiptQrCode extends QrCodeTemplate{
//收取材料凭证二维码生成url
private String RCURL="你的url";
/**
* 构造方法:缺省二维码大小
* @param gid 业务id
* @param regorg 登记机关
*/
public MaterialsReceiptQrCode(String gid, String regorg){
super();
this.RCURL += "?gid=" + gid + "®org=" + regorg;
}
/**
* 构造方法:自定义二维码图片大小
* @param gid 业务id
* @param regorg 登记机关
* @param imgWidth 生成图片宽度
* @param imgHeight 生成图片高度
* @param cutX 剪切点x坐标
* @param cutY 剪切点y坐标
* @param cutWidth 剪切点宽度
* @param cutHeight 剪切点高度
*/
public MaterialsReceiptQrCode(String gid, String regorg, int imgWidth, int imgHeight, int cutX, int cutY, int cutWidth, int cutHeight){
super(imgWidth, imgHeight, cutX, cutY, cutWidth, cutHeight);
this.RCURL += "?gid=" + gid + "®org=" + regorg;
}
/**
* 二维码生成保存路径
*/
@Override
protected String qrCodePath() {
String dirPath = System.getProperty("user.dir") + "/app/font/qrCodeGS";
String imgPath = dirPath+ "\\" + UUIDUtil.getUUID() + ".jpg";
return imgPath;
}
/**
* 二维码目标url
*/
@Override
protected String qrCodeTargetUrl() {
return RCURL;
}
/**
* 钩子方法
* 获取二维码数据后是否删除生成的二维码图片
*/
@Override
protected Boolean isDeleteImg() {
// TODO Auto-generated method stub
return super.isDeleteImg();
}
}
调用方式SpringMVC:
SpringMvc后端:
/**
* 二维码生成
*
* @param request
* @param response
*/
@RequestMapping("/createQRCode")
public void createCertQRCode(HttpServletRequest request, HttpServletResponse response) {
//生成二维码模块对象
QrCodeTemplate qrCode = new BusinessLicenseNewQrCode(“param01”);
//执行模板获取二维码二进制数据
byte[] buffer = qrCode.runTemplate();
/*//生成二维码模块对象
QrCodeTemplate qrCode = new MaterialsReceiptQrCode(“param01”, “param02”);
//执行模板获取二维码二进制数据
byte[] buffer = qrCode.runTemplate();*/
//输出数据
returnImg(buffer, response);
}
// 向客户端输出图片
public void returnImg(byte[] buffer,
HttpServletResponse response){
OutputStream toClient = null;
try {
// 设置返回的文件类型
response.setContentType("image/*");
// 得到向客户端输出二进制数据的对象
toClient = response.getOutputStream();
// 输出数据
toClient.write(buffer);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (toClient != null) {
try {
toClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
前端HTML:
<img src="/createQRCode.do"></img>