通用的文件字节渲染器

1、需求背景:

我司内部大大小小的团队非常多,每个团队又有自己专属的开发小队,业务关系,经常需要用到其他团队的接口,例如需要某团队开发的一个接口,这个接口返回一个文件流,我想直接在前端打开或者下载。

2、实现方式:

扩展JFinal的Render类

3、代码:

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;

import com.jfinal.kit.LogKit;
import com.jfinal.kit.StrKit;
import com.jfinal.render.Render;
import com.jfinal.render.RenderException;

public class ByteRender extends Render {

	private String fileName;// 下载名称
	private byte[] fileByte;
	//前端试图展示的文件类型,例如想通过浏览器直接打开为pdf类型
	private FileType fileType = FileType.PDF;
	//浏览器直接试图查看和下载两种方式
	private RenderType renderType = RenderType.VIEW;// 默认类型

	private ServletOutputStream outputStream;

	public ByteRender() {
	}

	public void render() {

		if (validate() == false) {
			throw new RenderException("请检查ByteRender属性值是否为空");
		}

		if (renderType == RenderType.DOWNLOAD) {
			response.setHeader("Content-Disposition", getFilename(request));
		}
		response.setHeader("Pragma", "no-cache");
		response.setHeader("Cache-Control", "no-cache");
		response.setHeader("Accept-Ranges", "bytes");
		response.setDateHeader("Expires", 0);
		response.setContentType(fileType.contentType);

		try {
			this.outputStream = response.getOutputStream();
			switch (fileType) {
			case JPG:
				renderImage();
			case PDF:
				// 暂时只支持pdf
				renderPdf();
			}

		} catch (IOException e) {
			LogKit.error(e.getMessage(), e);
		} catch (Exception e) {
			LogKit.error(e.getMessage(), e);
		} finally {
			if (outputStream != null) {
				try {
					outputStream.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

	void renderPdf() throws IOException {
		outputStream.write(fileByte);
		outputStream.flush();
		outputStream.close();
	}

	void renderImage() {
		//这里自定义扩展
	}

	/**
	 * 文件下载名称
	 */
	private String getFilename(HttpServletRequest request) {
		try {
			String agent = request.getHeader("USER-AGENT");
			if (agent.toLowerCase().indexOf("firefox") > 0) {
				fileName = new String(fileName.getBytes("utf-8"), "ISO8859-1");
			} else {
				fileName = URLEncoder.encode(fileName, "UTF-8");
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return "attachment; filename=" + fileName + "." + fileType.suffix;
	}

	private boolean validate() {
		if (renderType == null || fileType == null) {
			return false;
		}
		// 如果是下载,需要传入下载的名称
		if (renderType == RenderType.DOWNLOAD) {
			if (StrKit.isBlank(fileName)) {
				return false;
			}
		}
		if (fileByte == null || fileByte.length == 0) {
			return false;
		}
		return true;
	}

	public static ByteRender create() {
		return new ByteRender();
	}
	public static ByteRender create(byte[] fileByte) {
		return create().setFileByte(fileByte);
	}

	public ByteRender setFileName(String fileName) {
		this.fileName = fileName;
		return this;
	}

	public ByteRender setFileByte(byte[] fileByte) {
		this.fileByte = fileByte;
		return this;
	}

	public ByteRender setFileType(FileType fileType) {
		this.fileType = fileType;
		return this;
	}

	public void setRenderType(RenderType renderType) {
		this.renderType = renderType;
	}

	public enum FileType {
		PDF("application/pdf", "pdf"),

		JPG("image/jpeg", "jpg");

		public String contentType;
		public String suffix;

		FileType(String contentType, String suffix) {
			this.contentType = contentType;
			this.suffix = suffix;
		}
	}

	public enum RenderType {
		// 下载和视图显示
		DOWNLOAD, VIEW
	}

	@Override
	public String toString() {
		return "ByteRender [fileName=" + fileName + ", fileByte[length]="
				+ (fileByte == null ? "null" : fileByte.length) + ", fileType=" + fileType + ", renderType="
				+ renderType + "]";
	}
}

4、使用方式:

byte[] bytes = data.toString().getBytes(ISO);//来自任何地方
默认方式:
render(ByteRender.create(bytes));
或者自定义:
render(ByteRender.create(bytes).setFileType(ByteRender.FileType.JPG));//还要其他属性


评论区

zzutligang

2019-11-05 10:18

怎么和我的几乎一样呢!^_^

leomj

2019-11-05 14:59

@zzutligang 来来,贴出来看下,向大神学习一下,@JFinal有没更加优雅的做法?

JFinal

2019-11-08 13:44

@leomj 使用 jfinal 的 Render 扩展出各种格式的响应数据极度便利,比扩展 spring 的 ViewResolver 简单 32 倍

享主的分享简单实用,必须赞

JFinal

2019-11-08 13:44

此外,switch 语句貌似差了一句 break;