JSP 实用程序之简易图片服务器

最初 node 版本在这里

源码下载,单 jsp 文件 http://pan.baidu.com/s/1gfoDy0r (百度云提供)

App 客户端加载图片的时候,在服务端需要进行相关的优化,否则会给流量和占用内存带来消耗和压力。起初想到了利用 node 搭建一个简易的图片服务器来完成。遗憾的是,因为 Centos 平台上 node-images二进制包的问题,导致不能顺利使用 node 方案。于是迫不得已,改用 Java 来完成。及后,考虑到逻辑不复杂和部署的简易,特意将 Java 改成 JSP 页面调用,而非 Servlet。JSP 大家都比较熟悉,这里再提一提它的优点:1、可以“过程式”编码,不用考虑包等的问题。虽然面向对象 OO 必须强调,但某些时候“过程式”足矣,结构简单明晰;2、无须重启服务器,修改立刻看到效果,减少运维的工作。有同学说过,JSP 问题:一、混搭 HTML 代码不好看,这个确实是如果开发者可以注意下,也是能够规避的;二、写起来太慢。噢~我现在不是第一时间在 JSP 里面写 Java,而是在 Java 类里面写好了、测试好了再 copy 到 JSP(原 Java 文件在这里),稍微改动下,有点像手动打包的过程,呵呵。

值得一提的是,Tomcat 7 下 JSP 默认的 Java 语法仍旧是 1.6 的。在 JSP 里面嵌入 Java 1.7 特性的代码会抛出“Resource specification not allowed here for source level below 1.7”的异常。于是需要修改 Tomcat/conf/web.xml 里面的配置文件,找到 <servlet> 节点,加入下面粗体部分才可以。注意是 jsp 节点,不是 default 节点(很相似)。

 <servlet>
        <servlet-name>jsp</servlet-name>
        <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
        <init-param>
            <param-name>fork</param-name>
            <param-value>false</param-value>
        </init-param>
        <init-param>
            <param-name>xpoweredBy</param-name>
            <param-value>false</param-value>
        </init-param>
        <init-param>
            <param-name>compilerSourceVM</param-name>
            <param-value>1.7</param-value>
        </init-param>
        <init-param>
            <param-name>compilerTargetVM</param-name>
            <param-value>1.7</param-value>
        </init-param>
        <load-on-startup>3</load-on-startup>
    </servlet>

调用例子:

img_resize.jsp?url=http://desk.fd.zol-img.com.cn/t_s1920x1200c5/g5/M00/0F/04/ChMkJ1dGqWOITU3xAA5PBuQ0iRMAAR6mAAAAAAADk8e103.jpg&h=400

先说说图片处理的流程。

  1. 首先从 url 参数获取图片地址,该参数必填
  2. 通过 HTTP HEAD 请求检测是否 404,以及图片文件大小
  3. 如果小于 100kb (1024 * 100)则无须压缩,响应对象发出 302 重定向 url 地址
  4. 如果大于 100kb,则读取文件流,输入到 java.awt.Image 对象
  5. 如果没有指定高、宽,那么直接在浏览器输出图片(原尺寸输出)
  6. 若 w / h 指定其一则按图片比例缩放,w:int = 宽度,可选,h:init = 高度,可选。
  7. 通过图片原尺寸计算出比例,求得 w / h
  8. 通过 setResize(Image img, int height, int width) 方法设置图片大小

可能还有考虑不周的情况,望大家指点提拨。

JSP 页面调用方式就是:

<%@page pageEncoding="utf-8" import="java.io.*, java.net.*, javax.imageio.ImageIO, java.awt.Image, java.awt.image.*"%>
<%
    // JSP 实用程序之简易图片服务器
    // http://blog.csdn.net/zhangxin09/article/details/51523489
    // sp42 2016-5-30
    String url = request.getParameter("url");
    if(url == null){
        out.println("缺少 url 参数!");
        return;
    }
    try{
        getImg(url, request, response);
        //清除输出流,防止释放时被捕获异常
        out.clear();
        out = pageContext.pushBody();
    } catch(Exception e) {
        out.println("Error:" + e);
    }
%>

依赖函数仅仅是以下几个:

<%!
	/**
	 * 主要的函数
	 */
	public static void getImg(String url, HttpServletRequest request,  HttpServletResponse response) throws IOException {
		System.out.println("请求地址:" + url);
		URL urlObj = new URL(url);
		HttpURLConnection conn = (HttpURLConnection) urlObj.openConnection();

		int imgSize = getSize(conn, urlObj.getHost());
		if (imgSize < (1024 * 100)) {
			response.sendRedirect(url);// 发送重定向
			return;
		} else {
	//		System.out.println("BigImg");

			String imgType = getImgType(url);

			response.setContentType(getContentType(imgType));
			try (
				InputStream is = new URL(url).openStream();
				ServletOutputStream op = response.getOutputStream();
			){
				String height = request.getParameter("h"), width = request.getParameter("w");

				if (height != null && width != null) {
					BufferedImage bufImg = setResize(ImageIO.read(is), Integer.parseInt(height), Integer.parseInt(width));
					ImageIO.write(bufImg, imgType, op);
				} else if (height != null) {
					Image img = ImageIO.read(is);// 将输入流转换为图片对象
					int[] size = resize(img, Integer.parseInt(height), 0);

					BufferedImage bufImg = setResize(img, size[0], size[1]);
					ImageIO.write(bufImg, imgType, op);
				} else if (width != null) {
					Image img = ImageIO.read(is);// 将输入流转换为图片对象
					int[] size = resize(img, 0, Integer.parseInt(width));

					BufferedImage bufImg = setResize(img, size[0], size[1]);
					ImageIO.write(bufImg, imgType, op);
				} else {
					// 直接写浏览器
					byte[] buf = new byte[1024];
					int len = is.read(buf, 0, 1024);
					while (len != -1) {
						op.write(buf, 0, len);
						len = is.read(buf, 0, 1024);
					}
				}
			}
		}
	}

	/**
	 * 返回 Content type
	 * @param imgType
	 * @return
	 */
	private static String getContentType(String imgType) {
		switch (imgType) {
		case "jpg":
			return "image/jpeg";
		case "gif":
			return "image/gif";
		case "png":
			return "image/png";
		default:
			return null;
		}
	}

	/**
	 * 获取 url 最后的 .jpg/.png/.gif
	 * @param url
	 * @return
	 */
	private static String getImgType(String url) {
		String[] arr = url.split("/");
		arr = arr[arr.length - 1].split("\\.");
		String t = arr[1];

		return t.replace('.', ' ').trim().toLowerCase();
	}

	/**
	 * 缩放比例
	 *
	 * @param img
	 *            图片对象
	 * @param height
	 *            高
	 * @param width
	 *            宽
	 * @return
	 */
	public static int[] resize(Image img, int height, int width) {
		int oHeight = img.getHeight(null), oWidth = img.getWidth(null);
		double ratio = (new Integer(oHeight)).doubleValue() / (new Integer(oWidth)).doubleValue();

		if(width != 0) {
			height =  (int) (ratio * width);
		}else {
			width = (int) ( height / ratio);
		} 

		return new int[]{height, width};
	} 

	/**
	 * 完成设置图片大小
	 *
	 * @param img
	 *            图片对象
	 * @param height
	 *            高
	 * @param width
	 *            宽
	 * @return 缓冲的图片对象
	 */
	public static BufferedImage setResize(Image img, int height, int width) {
		BufferedImage bufImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		bufImg.getGraphics().drawImage(img, 0, 0, width, height, null);

		return bufImg;
	}

	/**
	 *
	 * @param conn
	 * @param referer
	 * @return
	 */
	public static int getSize(HttpURLConnection conn, String referer) {
		try {
			conn.setRequestMethod("HEAD");
			conn.setInstanceFollowRedirects(false); // 必须设置false,否则会自动redirect到Location的地址
			conn.addRequestProperty("Accept-Charset", "UTF-8;");
			conn.addRequestProperty("User-Agent",
					"Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.2.8) Firefox/3.6.8");
			conn.addRequestProperty("Referer", referer);
			conn.setConnectTimeout(5000);// 设置超时
			conn.setReadTimeout(30000);

			InputStream body = null;

			try {
				body = conn.getInputStream();
			} catch (UnknownHostException e) {
				throw new RuntimeException("未知地址!" + conn.getURL().getHost() + conn.getURL().getPath());
			} catch (FileNotFoundException e) {
				throw new RuntimeException("404 地址!" + conn.getURL().getHost() + conn.getURL().getPath());
			} catch (SocketTimeoutException e) {
				throw new RuntimeException("请求地址超时!" + conn.getURL().getHost() + conn.getURL().getPath());
			}

			body.close();
			// if (conn.getResponseCode() > 400) // 如果返回的结果是400以上,那么就说明出问题了
			// LOGGER.warning("Err when got responseCode :" +
			// conn.getResponseCode() + getUrlStr());

			// conn.connect();也就是打开流
		} catch (IOException e) {
			e.printStackTrace();
			return -1;
		}
		String sizeStr = conn.getHeaderField("content-length");

		return Integer.parseInt(sizeStr);
	}
%>

开发过程值得记住的几点:

  • Url 和 Connection 貌似不能重复使用,于是两次请求(同一地址)得有两个 url 对象
  • 调整图片比例函数比较简单,但编码有时得晓得不是写算术。
  • 设定好正确的 图片ContentType
  • 不知道动图 gif 压缩后是否只剩一帧?

不足之处,敬请大家提出。

时间: 2024-09-29 04:47:53

JSP 实用程序之简易图片服务器的相关文章

JSP 实用程序之简易图片验证码

完整代码下载 :http://pan.baidu.com/s/1o7Bj4ls (百度云提供) 本文尝试通过一个简单的 JSP 小程序来实现验证码功能. 前台代码如下: <form action="action.jsp" method="POST"> <label> 用户名: <input type="text" name="name" data-singleTips="请输入用户名&q

用 node-images 打造简易图片服务器(更新)

Edit:2016-5-11 修正了代码里面一些明显的错误,并发布在 ajaxjs 库之中,源码在这里. Edit:2016-5-24 加入 HEAD 请求,检测图片大小.如果小于 80kb 则无须压缩,返回 302 重定向. node HEAD 请求 var http = require('http'); var url = require('url'); var siteUrl = url.parse('http://img1.gtimg.com/view/pics/hv1/42/80/20

JSP 实用程序之简易页面编辑器

完整源码下载:http://pan.baidu.com/s/1bpkHNnp(百度云提供) 需求:提供一页面,放置"帮助"."版权"文字内容,特点:静态页面,无须读数据库,只是应付字眼上频繁的修改:没有复杂的交互,无须 JavaScript:没有图片,不需要文件上传. 给出的方案:提供一页面和简易的后台管理,功能单一,只是编辑页面(只是修改字体.大小.粗体.斜体等的功能). 实现思路:纯 JSP 展示,管理界面用 HTTP Basic 登入,通过一个 JS 写成 H

Linux环境下nginx搭建简易图片服务器_nginx

主要使用Nginx和vsftpd. 安装方面可以直接从nginx官网上下载,或者... 复制代码 代码如下: yum install nginx  如果没有yum源则需要自行添加再进行install. 复制代码 代码如下: yum install wget wget http://www.atomicorp.com/installers/atomic  sh ./atomic  yum check update  如果是从官网上下载的则进行如下操作: 复制代码 代码如下: [root@admin

服务器-php做一个简易图片上传系统

问题描述 php做一个简易图片上传系统 大神们,在下遇见问题了,求帮助,后天要上交. 前台是一个表单,有ID,name,pictureID,picturename,picturefile,savetime,class. 要求,图片存到服务器的文件夹,路径存在数据库,然后在另外一个页面显示图片信息,有图片链接的方式,点击链接即可查看图片 跪求啊 解决方案 http://www.jb51.net/article/13976.htm 解决方案二: http://blog.163.com/ylx2820

关于applet嵌入jsp页面后applet图片显示的问题

问题描述 今天写了一个applet画图工具(当用户访问该页面的时候,applet会首先显示一张服务器端的图片),嵌入到jsp页面后部署到服务器,但是当自己通过浏览器访问该页面的时候发现该applet不能显示预期的图片,请问是什么原因? 解决方案 解决方案二:各位大侠帮帮忙啊急用毕设thanks解决方案三:该回复于2011-03-11 16:21:58被版主删除

nginx 一二事(1) - 简单图片服务器解决方案

最近经常有人问图片上传怎么做,有哪些方案做比较好,也看到过有关于上传图片的做法,但是都不是最好的 今天再这里简单讲一下上传图片以及图片服务器的大致理念 如果是个人项目或者企业小项目,仅仅只有十来号人使用的小项目,可以使用如下方案: 用户访问系统,使用上传图片功能,那么图片就上传到你的当前项目所在的tomcat服务器上,在/image下,上传成功后用户可以直接访问 http://ip:port/project/images/xxx.jpg 这样做在用户少的时候是没有问题的   当你的企业发展起来了

在JSP编译的时候,服务器内部做了什么?

js|编译|服务器 作者/出处:Blueski编译 在JSP第一次获得请求时,不管请求来自于客户端浏览器还是服务器上的servlet, JSP文件将被JSP引擎(JSP engine)转换成为一个servlet.而这个引擎本身也是一个servlet,在JSWDK,它就是 JspServlet. 在编译时候如果发现jsp文件有任何语法错误,转换过程将中断,并向客户端发出出错信息:而如果编译成功了,则所转换产生的servlet代码被编译,然后该servlet被JSP引擎加载到内存中.此时JSP引擎还

Windows平台网站图片服务器架构的演进

构建在Windows平台之上的网站,往往会被业内众多架构师认为很"保守".很大部分原因,是由于微软技术体系的封闭和部分技术人员的短视造成的.由于长期缺乏开源支持,所以只能"闭门造车",这样很容易形成思维局限性和短板.就拿图片服务器为例子,如果前期没有容量规划和可扩展的设计,那么随着图片文件的不断增多和访问量的上升,由于在性能.容错/容灾.扩展性等方面的设计不足,后续将会给开发.运维工作带来很多问题,严重时甚至会影响到网站业务正常运作和互联网公司的发展(这绝不是在危言