还是移除Word水印的问题,这次需要在应用系统上实现用户请求Word文件时,自动把Word的水印移除。这次的重点不是如何移除Word水印的问题,而是如何实现在response发送给客户端之前对数据流进行修改。实现的方式是实现自己的HttpServletResponseWrapper类并进行相应的修改操作。
直接上代码:
/**
* @CopyRright (c)2011: BrokenStone
* @Project: WordWatermark
* @File: RemoveWordWatermarkFilter.java
* @JDK version used: JDK1.6
* @<br/>
* @Author: BrokenStone
* @Blog: http://sheng.javaeye.com)
* @Email: wdmsyf@yahoo.com
* @since: 2012-1-13
* @Ver: 1.0
*/
package com.iteye.sheng.utils.office.tools;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
/**
* @author ShengYoufu
*
*/
public class RemoveWordWatermarkFilter implements Filter {
private static final Logger log = Logger.getLogger(RemoveWordWatermarkFilter.class);
//需要过过滤的请求服务器IP,因为mastudio没有较好的办法让应用系统知道是mastudio发起的请求,所以就先按IP来区分
//如果有更好的办法,建议改成更好的办法来处理
private static String[] filterSourceIPs = {"145.24.16.134"};
/* (non-Javadoc)
* @see javax.servlet.Filter#destroy()
*/
public void destroy() {
//
}
/* (non-Javadoc)
* @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
log.debug("Enter into doFilter...");
if(resp instanceof HttpServletResponse){
String requestIP = getRealRemoteAddress((HttpServletRequest)req, (HttpServletResponse)resp);
log.debug("Remote address(IP):" + requestIP);
if(needProcess(requestIP)){
log.debug("Begin process...");
RemoveWordWatermarkResponse response = new RemoveWordWatermarkResponse((HttpServletResponse)resp);
chain.doFilter(req, response);
log.debug("End process.");
return;
}
}
chain.doFilter(req, resp);
}
/* (non-Javadoc)
* @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
*/
public void init(FilterConfig config) throws ServletException {
String sourceIP = config.getInitParameter("filterSourceIP");
String[] temp = sourceIP.split(";");
if(temp!=null && temp.length>0)
filterSourceIPs = temp;
}
protected boolean needProcess(String requestIP){
for(int ii=0; ii<filterSourceIPs.length; ii++){
if(filterSourceIPs[ii].equals(requestIP)) return true;
}
return false;
}
protected String getRealRemoteAddress(HttpServletRequest req, HttpServletResponse resp){
if(req == null){
return null;
}
// 如果有apache
String ip = req.getHeader("X-Forwarded-For");
if (ip == null || ip.length() == 0) {
// 如果有weblogic配置
ip = req.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0) {
ip = req.getRemoteAddr();
}
return ip;
}
}
/**
* @CopyRright (c)2011: BrokenStone
* @Project: WordWatermark
* @File: RemoveWordWatermarkResponse.java
* @JDK version used: JDK1.6 @<br/>
* @Author: BrokenStone
* @Blog: http://sheng.javaeye.com)
* @Email: wdmsyf@yahoo.com
* @since: 2012-1-13
* @Ver: 1.0
*/
package com.iteye.sheng.utils.office.tools;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import org.apache.log4j.Logger;
/**
* @author ShengYoufu
*
*/
public class RemoveWordWatermarkResponse extends HttpServletResponseWrapper {
private static final Logger log = Logger.getLogger(RemoveWordWatermarkResponse.class);
protected ServletOutputStream stream = null;
protected PrintWriter writer = null;
public HttpServletResponse origResponse = null;
protected static Pattern pattern = Pattern.compile("attachment;filename=(.*)(\\.doc)$"); //判断是否word文件正则表达式
protected Map headerMap = new HashMap();
protected int contentLength = 0;
/**
*
* @param response
*/
public RemoveWordWatermarkResponse(HttpServletResponse response) {
super(response);
origResponse = response;
}
public void addHeader(String name, String value){
super.addHeader(name, value);
this.headerMap.put(name, value);
}
public Map getAllHeaders(){
return this.headerMap;
}
public String getHeader(String name){
return (String)this.headerMap.get(name);
}
/**
* 重载setContentLength是为了能取得原来写入response的数据长度
*/
public void setContentLength(int contentLength){
super.setContentLength(contentLength);
this.contentLength = contentLength;
}
public int getContentLength(){
return this.contentLength;
}
/**
* 判断是否是Word文档
* @return
*/
public boolean isWordDocument(){
Iterator it = this.headerMap.keySet().iterator();
while(it.hasNext()){
String name = (String)it.next();
if("Content-Disposition".equals(name)){
String val = (String)this.headerMap.get(name);
Matcher matcher = pattern.matcher(val);
if(matcher.find()) return true;
}
}
return false;
}
/**
* 创建自定义OutputStream
* @return
* @throws IOException
*/
public ServletOutputStream createOutputStream() throws IOException {
//只处理Word文件
if(isWordDocument()){
log.debug("Create RemoveWordWatermarkFilterServletOutputStream...");
return (new RemoveWordWatermarkFilterServletOutputStream(this));
} else
return origResponse.getOutputStream();
}
/**
* 返回自定义的OutputStream(自动把Word文件的水印删除)
*/
public ServletOutputStream getOutputStream() throws IOException {
if (writer != null) {
throw new IllegalStateException("getWriter() has already been " + "called for this response");
}
if (stream == null) {
stream = createOutputStream();
}
return stream;
}
/**
* 返回包装自定义OutputStream的Writer(自动把水印删除)
*/
public PrintWriter getWriter() throws IOException {
if (writer != null) {
return writer;
}
if (stream != null) {
throw new IllegalStateException("getOutputStream() has already " + "been called for this response");
}
stream = createOutputStream();
writer = new PrintWriter(stream);
return writer;
}
}
/**
* @CopyRright (c)2011: BrokenStone
* @Project: WordWatermark
* @File: RemoveWordWatermarkFilterServletOutputStream.java
* @JDK version used: JDK1.6 @<br/>
* @Author: BrokenStone
* @Blog: http://sheng.javaeye.com)
* @Email: wdmsyf@yahoo.com
* @since: 2012-1-13
* @Ver: 1.0
*/
package com.iteye.sheng.utils.office.tools;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.servlet.ServletOutputStream;
import org.apache.log4j.Logger;
import com.aspose.words.Document;
/**
* @author ShengYoufu
*
*/
public class RemoveWordWatermarkFilterServletOutputStream extends ServletOutputStream {
private static final Logger log = Logger.getLogger(RemoveWordWatermarkFilterServletOutputStream.class);
private OutputStream _out;
private RemoveWordWatermarkResponse _response = null;
private ByteArrayOutputStream _buffer;
private boolean closed = false;
private int ContentLength = 0;
private int _bufferSize = 0;
public RemoveWordWatermarkFilterServletOutputStream( RemoveWordWatermarkResponse resp ) throws IOException{
_buffer = new ByteArrayOutputStream();
// _out = resp.getOutputStream();
_out = resp.getResponse().getOutputStream();
_response = resp;
}
protected RemoveWordWatermarkFilterServletOutputStream( OutputStream realStream ) throws IOException{
_buffer = new ByteArrayOutputStream();
_out = realStream;
}
public void close() throws IOException {
if (closed) {
throw new IOException("This output stream has already been closed");
}
//移除水印
try{
removeWatermark();
}catch(Exception ex){
throw new IOException("移除Word水印失败: "+ ex.getMessage());
}
_out.flush();
_out.close();
closed = true;
}
public void flush() throws IOException {
if (closed) {
throw new IOException("Cannot flush a closed output stream");
}
//移除水印
try{
removeWatermark();
}catch(Exception ex){
throw new IOException("移除Word水印失败: "+ ex.getMessage());
}
_out.flush();
}
public void write(int b) throws IOException {
if (closed) {
throw new IOException("Cannot write to a closed output stream");
}
//对于单个字节,不需要执行移除水印操作
// _buffer.write((byte) b);
_out.write(b);
}
public void write(byte b[]) throws IOException {
write(b, 0, b.length);
}
public void write(byte b[], int off, int len) throws IOException {
if (closed) {
throw new IOException("Cannot write to a closed output stream");
}
// log.debug("Enter into write...");
_buffer.write(b, off, len);
_bufferSize += len;
//当写入的数据小于1024(缓冲区大小)时,则认为写入数据已经结束,可以进行移除水印操作了。
//当总的数据长度已经达到原Response中设定值,则认为写入数据已经结束,可以进行移除水印操作了。
if(len<1024 || _bufferSize >= _response.getContentLength()){
try {
removeWatermark();
} catch (Exception ex) {
log.error("移除水印失败。",ex);
throw new IOException("移除水印失败。");
}
}
}
/**
* 移除水印操作
* @throws Exception
*/
public void removeWatermark() throws Exception {
log.debug("Enter into removeWatermark...");
//载入Aspose.Words组件的许可证
WordWatermarkUtil.loadLicense();
ByteArrayInputStream bais = null;
byte[] buff = null;
byte[] buf = new byte[1024];
int len = 0;
long beginTime = System.currentTimeMillis();
//记下新的ContentLength
this.setContentLength(_buffer.size());
if(_response!=null){
_response.setContentLength(_buffer.size());
}
try{
try{
_buffer.flush();
buff = _buffer.toByteArray();
bais = new ByteArrayInputStream(_buffer.toByteArray());
_buffer.close();
}catch(IOException ex){
throw new Exception("缓冲字节流flush失败。", ex);
}
try{
Document doc = new Document(bais);
bais.close();
WordWatermarkUtil.removeWatermark(doc);
_buffer = new ByteArrayOutputStream();
doc.save(_buffer, null);
if(_response!=null){
_response.setContentLength(_buffer.size());
}
bais = new ByteArrayInputStream(_buffer.toByteArray());
while( (len = bais.read(buf))>0){
_out.write(buf, 0, len);
}
log.debug("Remove watermark from doc succeed.");
}catch(Exception ex){
log.error("从Word文件中移除水印失败,直接用原文件返回.", ex);
bais = new ByteArrayInputStream(buff);
while( (len = bais.read(buf)) > 0){
_out.write(buf, 0, len);
}
}
}finally{
try {
_buffer.close();
} catch (IOException ex) {
log.warn("关闭临时缓冲字节流失败.", ex);
}
if(bais!=null){
bais.close();
}
bais = null;
long endTime = System.currentTimeMillis();
log.debug("移除Word文档水印耗时:"+String.valueOf( endTime - beginTime) + " ms");
}
}
/**
*
* @param args
*/
public static void main(String[] args){
FileInputStream fis = null;
FileOutputStream fos = null;
//载入Aspose.Words的许可证
WordWatermarkUtil.loadLicense();
try {
fis = new FileInputStream("C:\\with_watermark.doc");
fos = new FileOutputStream("C:\\test1.doc");
RemoveWordWatermarkFilterServletOutputStream os = new RemoveWordWatermarkFilterServletOutputStream(fos);
byte[] buf = new byte[1024];
int len = 0;
while( (len = fis.read(buf))>0){
os.write(buf, 0, len);
}
os.flush();
os.close();
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
if(fis!=null){
try {
fis.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
fis = null;
if(fos!=null){
try {
fos.flush();
} catch (IOException ex){
ex.printStackTrace();
}
try {
fos.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
fos = null;
}
}
public int getContentLength() {
return ContentLength;
}
public void setContentLength(int contentLength) {
ContentLength = contentLength;
}
}
/**
* @CopyRright (c)2011: BrokenStone
* @Project: WordWatermark
* @File: WordWatermarkUtil.java
* @JDK version used: JDK1.6
* @<br/>
* @Author: BrokenStone
* @Blog: http://sheng.javaeye.com)
* @Email: wdmsyf@yahoo.com
* @since: 2012-1-13
* @Ver: 1.0
*/
package com.iteye.sheng.utils.office.tools;
import java.awt.Color;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import com.aspose.words.Document;
import com.aspose.words.HeaderFooter;
import com.aspose.words.HeaderFooterType;
import com.aspose.words.HorizontalAlignment;
import com.aspose.words.License;
import com.aspose.words.Paragraph;
import com.aspose.words.RelativeHorizontalPosition;
import com.aspose.words.RelativeVerticalPosition;
import com.aspose.words.Section;
import com.aspose.words.SectionCollection;
import com.aspose.words.Shape;
import com.aspose.words.ShapeType;
import com.aspose.words.VerticalAlignment;
import com.aspose.words.WrapType;
/**
* @author ShengYoufu
*
*/
public class WordWatermarkUtil {
/**
*
* Inserts a watermark into a document.
*
* @param doc The input document.
* @param watermarkText Text of the watermark.
*
*/
public static void insertWatermarkText(Document doc, String watermarkText) throws Exception {
// Create a watermark shape. This will be a WordArt shape.
// You are free to try other shape types as watermarks.
Shape watermark = new Shape(doc, ShapeType.TEXT_PLAIN_TEXT);
// Set up the text of the watermark.
watermark.getTextPath().setText(watermarkText);
watermark.getTextPath().setFontFamily("Arial");
watermark.setWidth(500);
watermark.setHeight(100);
// Text will be directed from the bottom-left to the top-right corner.
watermark.setRotation(-40);
// Remove the following two lines if you need a solid black text.
watermark.getFill().setColor(Color.GRAY); // Try LightGray to get more Word-style watermark
watermark.setStrokeColor(Color.GRAY); // Try LightGray to get more Word-style watermark
// Place the watermark in the page center.
watermark.setRelativeHorizontalPosition(RelativeHorizontalPosition.PAGE);
watermark.setRelativeVerticalPosition(RelativeVerticalPosition.PAGE);
watermark.setWrapType(WrapType.NONE);
watermark.setVerticalAlignment(VerticalAlignment.CENTER);
watermark.setHorizontalAlignment(HorizontalAlignment.CENTER);
// Create a new paragraph and append the watermark to this paragraph.
Paragraph watermarkPara = new Paragraph(doc);
watermarkPara.appendChild(watermark);
// Insert the watermark into all headers of each document section.
SectionCollection sects = doc.getSections();
Iterator it = sects.iterator();
while(it.hasNext()){
Section sect = (Section)it.next();
// There could be up to three different headers in each section, since we want
// the watermark to appear on all pages, insert into all headers.
insertWatermarkIntoHeader(watermarkPara, sect, HeaderFooterType.HEADER_PRIMARY);
insertWatermarkIntoHeader(watermarkPara, sect, HeaderFooterType.HEADER_FIRST);
insertWatermarkIntoHeader(watermarkPara, sect, HeaderFooterType.HEADER_EVEN);
}
}
/**
* 插入水印
* @param watermarkPara
* @param sect
* @param headerType
* @throws Exception
*/
public static void insertWatermarkIntoHeader(Paragraph watermarkPara, Section sect, int headerType) throws Exception {
HeaderFooter header = sect.getHeadersFooters().getByHeaderFooterType(headerType);
if (header == null) {
// There is no header of the specified type in the current section, create it.
header = new HeaderFooter(sect.getDocument(), headerType);
sect.getHeadersFooters().add(header);
}
// Insert a clone of the watermark into the header.
header.appendChild(watermarkPara.deepClone(true));
}
/**
* 移除全部水印
* @param inStream
* @throws Exception
*/
public static void removeWatermark(InputStream inStream) throws Exception {
Document doc = new Document(inStream);
removeWatermark(doc);
}
/**
* 移除全部水印
* @param doc
* @throws Exception
*/
public static void removeWatermark(Document doc) throws Exception {
SectionCollection sects = doc.getSections();
Iterator it = sects.iterator();
while(it.hasNext()){
Section sect = (Section)it.next();
// There could be up to three different headers in each section, since we want
// the watermark to appear on all pages, insert into all headers.
removeWatermarkFromHeader(sect, HeaderFooterType.HEADER_PRIMARY);
removeWatermarkFromHeader(sect, HeaderFooterType.HEADER_FIRST);
removeWatermarkFromHeader(sect, HeaderFooterType.HEADER_EVEN);
}
}
/**
* 移除指定Section的水印
* @param sect
* @param headerType
* @throws Exception
*/
public static void removeWatermarkFromHeader(Section sect, int headerType) throws Exception {
HeaderFooter header = sect.getHeadersFooters().getByHeaderFooterType(headerType);
if (header != null) {
header.removeAllChildren();
}
}
/**
* 从Classpath(jar文件中)中读取License
*/
public static void loadLicense() {
//返回读取指定资源的输入流
License license = new License();
InputStream is = null;
try {
is = WordWatermarkUtil.class.getResourceAsStream("/resources/aspose.word.license.xml");
if(is==null)
throw new RuntimeException("Cannot find licenses file. Please contact wdmsyf@yahoo.com or visit http://sheng.javaeye.com for get more information.");
license.setLicense(is);
} catch (Exception ex) {
ex.printStackTrace();
}finally{
if(is!=null){
try{ is.close(); }catch(IOException ex){ };
is = null;
}
}
}
/**
* @param args
*/
public static void main(String[] args) throws Exception {
loadLicense();
Document doc = new Document("c:/with_watermark.doc");
removeWatermark(doc);
doc.save("c:/without_watermark.doc");
}
}