武林游戏 2017-05-02 11:15

本文介绍在Java语言环境下,使用POI为Excel打水印的解决方案,具体的代码编写以及相关的注意事项。

需求描述:

要求通过系统下载的Excel都带上公司的水印,列宽调整为合适的宽度,并且设置为不可编辑,即只读。

即:

1:加水印;

2:调整列宽将单元格内容显示全;

3:设置只读;

解决方案思路介绍:

三点需求比较来说,以第一点比较复杂,同时网上关于POI为Excel加水印的资料非常少,而这些资料又多数是相互之间Copy得来,干货较少。

一:使用模版Excel的形式设置水印:

目前网上关于POI为Excel打水印,主要是通过模版的形式来实现,即先准备一份打了水印的模版Excel,说白了就是在这个模版Excel中的一个Sheet中添加一些艺术字,调整下透明度还有字体,角度等,模仿水印,然后加载该模版,再将内容输出到该模版中,以达到为Excel添加水印的目的,详细可参考下面这份博客(不追溯该博客是否是原始版本):http://jsonchar.blog.163.com/blog/static/17601614120106135519213/

但这种方式有如下问题:

1:通过手动添加水印,水印数量固定:通过人工在一个Sheet中添加水印,个数必然固定,当实际内容行数不定,列数不定,会导致水印不能覆盖内容;

2:当无法确定下载的Excel会有多少个Sheet的时候,无法保证输出的多个Sheet都有水印:产生这种情况是因为,这种实现方式的根本原理是读取已经存在的模版Excel内的Sheet,并将内容输出到该Sheet中,也就是说如果模版内的Sheet内有水印则输出内容有水印,如果该Sheet没有水印则输出内容没有水印。毕竟通过手工添加水印,准备模版的方式,你不能准备无限多个模版Sheet,准备一个两个也就到头了。

3:你无法通过程序拷贝模版Sheet:你可能会问了,那我准备一个模版Sheet,在其中尽量多的打上水印,麻烦一点横向纵向多大点,然后再通过程序拷贝该模版Sheet,想其中输出内容的形式不行吗?很遗憾,不行,翻查POI的API你就会发现创建Sheet的方式就那么两个,即通过workbook进行创建,虽然sheet(无论类型)的构造函数是public的,但是你无法将你构造好的sheet添加到workbook中。当然,workbook也提供了cloneSheet的api,但是如果你的模版水印是通过艺术字或者图片的形式打上去的,那么也将无法拷贝。

所以这种方案,适合于输出的内容Sheet页个数固定,行数可控的形式,因为只有这些固定下来了,在提供模版Excel的时候才能做出合适的模版,在固定的sheet页,大致的行上打上水印。

二:使用程序将水印图片动态打到Sheet上:

因为上面方案的问题,我选择通过程序将提前准备好的水印图片打印到Sheet上的方案,这种方案的主要步骤为:

1:将需要输出的内容正常输出到Excel中,输出的Excel假定将存在多个Sheet,每个Sheet中内容的行数也不一定;

2:获取workbook对象,提取其中的多个sheet;

3:调用工具类,传入workbook和每一个sheet,根据提供好的水印图片将睡衣图片打到每一个sheet上,水印图片在sheet上的位置,个数等可配置;

要求:

1:水印图片是png格式,无背景,且水印主体颜色要尽可能浅,且细,避免遮挡excel上的信息;

2:使用的POI的版本是3.9,pom文件配置如下:

<!-- poi -->
<dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>3.9</version>
</dependency>
<dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.9</version>
</dependency>

步骤1和步骤2不提供代码,网上有很多,直接贴步骤三的代码,如下:

 1
import java.awt.image.BufferedImage;2 import java.io.ByteArrayOutputStream;3 import java.io.IOException;4 import java.io.InputStream;5 6 import javax.imageio.ImageIO;7 8 import org.apache.poi.ss.usermodel.ClientAnchor;9 import org.apache.poi.ss.usermodel.Drawing;
10 import org.apache.poi.ss.usermodel.Picture;
11 import org.apache.poi.ss.usermodel.Sheet;
12 import org.apache.poi.ss.usermodel.Workbook;
13
14 /**
15  * Excel水印工具类
16  * @author gang.wang
17  * 2017年4月23日
18  */
19 public class ExcelWaterRemarkUtils {
20
21     /**
22      * 为Excel打上水印工具函数
23      * 请自行确保参数值,以保证水印图片之间不会覆盖。
24      * 在计算水印的位置的时候,并没有考虑到单元格合并的情况,请注意
25      * @param wb       Excel Workbook
26      * @param sheet    需要打水印的Excel
27      * @param waterRemarkPath  水印地址,classPath,目前只支持png格式的图片,
28      * 因为非png格式的图片打到Excel上后可能会有图片变红的问题,且不容易做出透明效果。
29      * 同时请注意传入的地址格式,应该为类似:"\\excelTemplate\\test.png"
30      * @param startXCol  水印起始列
31      * @param startYRow  水印起始行
32      * @param betweenXCol 水印横向之间间隔多少列
33      * @param betweenYRow 水印纵向之间间隔多少行
34      * @param XCount 横向共有水印多少个
35      * @param YCount 纵向共有水印多少个
36      * @param waterRemarkWidth 水印图片宽度为多少列
37      * @param waterRemarkHeight 水印图片高度为多少行
38      * @throws IOException
39      */
40     public static void putWaterRemarkToExcel(Workbook wb, Sheet
sheet, String waterRemarkPath, int startXCol, int startYRow,
41 int betweenXCol, int betweenYRow, int XCount, int YCount,
42 int waterRemarkWidth, int waterRemarkHeight) throws IOException{
43
44         //校验传入的水印图片格式
45         if(!waterRemarkPath.endsWith("png") &&
!waterRemarkPath.endsWith("PNG")){
46 throw new RuntimeException("向Excel上面打印水印,目前支持png格式的图片。");
47         }
48
49         //加载图片
50         ByteArrayOutputStream byteArrayOut = new
ByteArrayOutputStream;
51         InputStream imageIn =
Thread.currentThread.getContextClassLoader.getResourceAsStream(waterRemarkPath);
52         if(null == imageIn || imageIn.available < 1){
53 throw new RuntimeException("向Excel上面打印水印,读取水印图片失败(1)。");
54         }
55         BufferedImage bufferImg = ImageIO.read(imageIn);
56         if(null == bufferImg) {
57 throw new RuntimeException("向Excel上面打印水印,读取水印图片失败(2)。");
58         }
59         ImageIO.write(bufferImg,"png",byteArrayOut);
60
61         //开始打水印
62         Drawing drawing = sheet.createDrawingPatriarch;
63
64         //按照共需打印多少行水印进行循环
65         for(int yCount=0; yCount<YCount; yCount++){
66 //按照每行需要打印多少个水印进行循环
67 for(int xCount=0; xCount<XCount; xCount++){
68 //创建水印图片位置
69 int xIndexInteger = startXCol + (xCount * waterRemarkWidth) + (xCount* betweenXCol);
70 int yIndexInteger = startYRow + (yCount * waterRemarkHeight) +
(yCount * betweenYRow);
71
72 /*
73  * 参数定义:
74  * 第一个参数是(x轴的开始节点);
75  * 第二个参数是(是y轴的开始节点);
76  * 第三个参数是(是x轴的结束节点);
77  * 第四个参数是(是y轴的结束节点);
78  * 第五个参数是(是从Excel的第几列开始插入图片,从0开始计数);
79  * 第六个参数是(是从excel的第几行开始插入图片,从0开始计数);
80  * 第七个参数是(图片宽度,共多少列);
81  * 第8个参数是(图片高度,共多少行);
82 */
83 ClientAnchor anchor = drawing.createAnchor(0, 0, Short.MAX_VALUE,
Integer.MAX_VALUE, xIndexInteger, yIndexInteger, waterRemarkWidth,
waterRemarkHeight);
84 Picture pic = drawing.createPicture(anchor,
wb.addPicture(byteArrayOut.toByteArray, Workbook.PICTURE_TYPE_PNG));
85  pic.resize;
86  }
87         }
88     }
89 }

函数参数的定义介绍的很详细了,不再过多介绍,说说需要注意的地方:

1:一定要先向Excel中写内容,然后再打日志,要不然图片有可能会拉伸导致失真;

2:最好使用Png格式的图片,避免造成打上的图片背景变红的问题,网上有这种问题的解决方案,这里不再赘述;

3:该函数默认是将图片放在了项目的classpath目录下;

至此,使用poi向Excel上面打水印的功能就完成了!!!可能会有写遮挡,但也实在无法避免了,目前还没有发现类似于设置图片透明度,文字环绕效果,图片置底的api~~

接下来再说两个小点:

1:怎样实现调整列宽:

Sheet提供了默认的自动设置列宽的api,即根据cell中内容的宽度,自动调整列宽(sheet.autoSizeColumnt),但是经过测试,在SXSSFWorkbook和SXSSFSheet中,会遇到个别列特别窄的问题,就是计算的行宽不太准,而且遇到了公式,数字也有可能计算的不太准,因此我是自己计算的列宽,并设置的。

首先在程序循环向Excel中写内容的时候,自行设置一个Map存储每一列的最大列宽,具体的函数很简单,就是一个比较大小的函数,举例如下:

 1     private void getMaxColLength(Map<Integer,Integer> colMaxLength, Integer colIndex, Integer length){2         Integer oriLength = 0;3         if(colMaxLength.containsKey(colIndex)){4 oriLength = colMaxLength.get(colIndex);5         }6         7         if(length > oriLength){8  colMaxLength.put(colIndex, length);9         } else {
10  colMaxLength.put(colIndex, oriLength);
11         }
12     }

得到的每一列的最大宽度(调用字符串的length()函数),需要和Excel中的宽度进行换算,换算的公式是宽度*256,即程序求得的每一列的宽度乘以256,在实际使用中,大多数情况需要多乘以一些,因为实测中,如果只乘以256,会使得列正正好好的匹配内容宽度,遇到汉字还有可能遮挡一部分,因此最好将这个基数扩大些:

sheet.setColumnWidth(colIndex, length * 480);

2:如何设置Excel只读,或者说是不可编辑:

当Excel中的数据敏感,希望客户不能修改内容时,除了使用水印的形式,还需要配合不可修改功能,我的实现是为Excel设置一个密码,保证该Excel不可修改,试图修改将会被要求输入密码,只要密码够复杂应该没有破解的可能,比如你设置一个随机的UUID,并且不记录该UUID,这样就没有人知道该密码了,保证安全性。在设置了密码之后用户依然可以通过拷贝的方法,将Excel中的内容拷贝到其他sheet或者Excel中去,这点需要注意,具体的代码很简单,如下:

sheet.protectSheet(UUID.randomUUID.toString);

到这,本文要介绍的主体内容就介绍完了,实现了一个通过POI,向Excel中打水印图片的主体功能。希望对大家有所帮助。

Java使用POI为Excel打水印,调整列宽并设置Excel只读相关推荐

  1. Excel快捷的把列宽调整到合适的宽度

    Excel快捷的把列宽调整到合适的宽度 第一种方式 选中需要调整列宽的那些列 把光标放到任意选中的两列之间 等光标变成左右箭头的时候,双击鼠标左键 第二种方式 1.选中需要调整列宽的那些列 2.点击[ ...

  2. excel表格怎么调整行高和列宽_在Excel中批量插入图片?这要如何操作呢

    酌酒与君君自宽,人情翻覆似波澜.白首相知犹按剑,朱门先达笑弹冠.草色全经细雨湿,花枝欲动春风寒.世事浮云何足问,不如高卧且加餐. --[唐]王维<酌酒与裴迪> 不知道大家有没有遇到过这种情 ...

  3. Excel行高、列宽怎么调整?

    在日常工作中,经常会需要用到Excel表格,如果打开的Excel表格行高列宽不是我们想要的,要怎么调节到合适的大小呢? 方法一 打开Excel表格,按[Ctrl+A]快捷键,选中全部表格(或者点击表格 ...

  4. excel设置行高等于列宽_如何在Excel中设置行高和列宽

    excel设置行高等于列宽 By default, when you create a new workbook in Excel, the row height and column width i ...

  5. excel表格行宽列高怎么设置_excel的行高列宽怎么设置_excel的行高和列宽在哪设置...

    在使用excel时,行高和列宽一定程度上影响着整个表格的美观程度,下面为你分享了几个关于行高列宽的超实用的小技巧,感兴趣的小伙伴快来看看吧! 1.行高的单位像素怎么更改为厘米? 在设置表格时,要求设置 ...

  6. python保存dataframe数据到excel中,处理列宽数据格式等

    python保存dataframe数据到excel中,处理列宽数据格式等 前言 1,比较简单的datafame 生成excel代码 2,采用excelwriter 包进行数据列的改造 3,根据具体数据 ...

  7. excel根据内容自动调整列宽,行宽

    在excel的一个单元格中,如果内容过多,会有部分的文字看不到 比如: 这时候,我们想要单元格根据内容的多少,自动调整行宽或列宽 有两种方法. 方法一: 选择:"开始"==> ...

  8. 【Qt开发】QTableWidget设置根据内容调整列宽和行高

    QTableWidget要调整表格行宽主要涉及以下一个函数 1.resizeColumnsToContents();                      根据内容调整列宽            ...

  9. excel设置行高和列宽

    excel设置行高和列宽 1.Ctrl+A:全选 2.

最新文章

  1. kubernetes认证,对接第三方认证系统,对接github认证
  2. 运行 vue 报node错
  3. mysql 从服务器同步设置_mysql主从同步配置
  4. javascript 之作用域-06
  5. Idea / Eclipse中使用Lombok
  6. php获取文件目录文件名,php获取路径中的文件名的方法有哪些
  7. 波斯语网站步百度后尘糟伊朗网军出击
  8. 华为发布AI时代数据中心交换机:让网络瓶颈不再是束缚,AI算力提升一倍
  9. python自动化办公都能做什么-用 Python 自动化办公,我与大神之间的差距一下就...
  10. Check Point截获JavaScript文件隐形攻击
  11. Linux 如何配置 SFTP 来代替单一ftp应用
  12. codeblocks编译器报错Id returned 1 exit status
  13. BUUCTF 小易的U盘
  14. 位置不可用无法访问 chkdsk无法修复的文件恢复方法
  15. dell台式机安装centos7网卡设置
  16. 浏览器英文快捷翻译工具~~有道词典
  17. ZUCC_计算机网络实验_实验09 网络基本命令
  18. 互联网因特网计算机网络的区别,因特网和互联网的区别?
  19. 量子计算机新宇宙,脑洞大开!未来的量子计算机将运行在平行宇宙里
  20. QQ登录错误码:100044的解决办法

热门文章

  1. uni-app实战--音频小说app小程序
  2. TP4333移动电源芯片
  3. geoserver+nginx
  4. 大一学生《Web前端网课作业》基于HTML+CSS自我介绍网页设计与制作
  5. 元胞自动机模拟病毒传染(SEIR模型)(Python代码实现)
  6. 【IPD】集成产品开发培训课程「3月4-5日」
  7. Excel 表单控件在工作表大小和位置固定方法
  8. APP性能测试的6项关键指标及测试获取手段
  9. 自动咖啡机项目-软件规格说明书
  10. python小工具-使用百度语音接口进行划字朗读