前几天做了个为图片添加水印 ,实现自动盖章的功能,在正常试运行几天后,用户突然反馈有些文件下载不下来。通过查看系统日志发现,在盖章的代码里,出现了文件丢失的错误。经过各种模拟排查与bug重现,发现是在自动生成签字章图片的时候用了System.currentTimeMillis()来命名。一般来说,这样的命名方式不会产生冲突。但在超高并发的情况下,会出现在极短的时间内同时生成一份文件,并同时进行相关操作的情况。而且由于缓存的图片文件也以该方式命名,导致在执行完某段程序后,删除缓存文件可能存在误删同名文件的错误,进而导致文件寻找失败。之后改用System.nanoTime()来命名文件后便不再出现该错误。
附上盖章代码
导入工具类:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Transparency;
import java.awt.font.TextAttribute;
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.AttributedString;
import javax.imageio.ImageIO;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfGState;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
/**
*盖章,
* @param inputfile
* @param outputfile
* @param username
* @throws DocumentException
* @throws IOException
*/
public static void setWatermarkForBill(String inputfile,String outputfile,String username)
throws DocumentException, IOException {
PdfReader reader = new PdfReader(inputfile);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(outputfile)));
PdfStamper stamper = new PdfStamper(reader, bos);
String zhang1=null;
String zhang2=null;
try
{
int total = reader.getNumberOfPages() + 1;
PdfContentByte content;
PdfGState gs = new PdfGState();
//第一章盖章图片
zhang1=generateStyle2Sign(username);
//第二张盖章图片
zhang2=generateStyle3Sign();
for (int i = 1; i < total; i++) {
content = stamper.getOverContent(i);// 在内容上方加水印
gs.setFillOpacity(0.7f);
content.beginText();
Image image = Image.getInstance(zhang1);
image.setAbsolutePosition(415, 6);
image.scaleToFit(130,70);
content.addImage(image);
image = Image.getInstance(zhang2);
image.setAbsolutePosition(250,50);
image.scaleToFit(130,70);
content.addImage(image);
content.endText();
}
}finally
{
try {
stamper.close();
reader.close();
bos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(zhang1!=null)
{
File file=new File(zhang1);
if(file.exists())
{
file.delete();
}
}
if(zhang2!=null)
{
File file=new File(zhang2);
if(file.exists())
{
file.delete();
}
}
}
}
/**
* 生成签章
* @param username
* @return
* @throws IOException
*/
public static String generateStyle2Sign(String username) throws IOException {
int imageWidth = 400;
int imageHeight = 215;
BufferedImage image = new BufferedImage(imageWidth, imageHeight,BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D) image.getGraphics();
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, imageWidth, imageHeight);
// ---------- 增加下面的代码使得背景透明 -----------------
image =
g2d.getDeviceConfiguration().createCompatibleImage(imageWidth,
imageHeight, Transparency.TRANSLUCENT);
g2d.dispose();
g2d = image.createGraphics();
// ---------- 背景透明代码结束 -----------------
g2d.setColor(new Color(220, 240, 240));
g2d.setStroke(new BasicStroke(10.0f));
// 画横线
g2d.setColor(Color.red);
g2d.drawLine(1, 1, imageWidth - 1, 1);
g2d.drawLine(1, imageHeight - 1, imageWidth - 1, imageHeight - 1);
// 画竖线
g2d.setColor(Color.red);
g2d.drawLine(1, 1, 1, imageHeight - 1);
g2d.drawLine(imageWidth - 1, 1, imageWidth - 1, imageHeight - 1);
// 设置字体
Font font = new Font("宋体", Font.BOLD, 60);
g2d.setFont(font);
// 写入内容
g2d.setColor(Color.red);
g2d.drawString("xx 文 件", 20, 80);
font = new Font("宋体", Font.BOLD, 40);
String line="批准人: ";
AttributedString as = new AttributedString(line);
as.addAttribute(TextAttribute.FONT, font);
as.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON, 3,line.length());
g2d.drawString(as.getIterator(), 20, 190);
font = new Font("宋体", Font.BOLD, 48);
g2d.setFont(font);
g2d.setColor(Color.blue);
g2d.drawString(username, 160, 188);
// String path = imagePath+File.separator+System.currentTimeMillis()+".png";
String path = imagePath+File.separator+System.nanoTime()+".png";//修改命名方式,防止同一时间操作导致图纸重名bug
ImageIO.write(image, "png", new File(path));
return path;
}