采用servlet 3.0 , 我是这样来完成图片上传及相关图片操作的;

		<dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
			<version>2.4</version>
		</dependency>

		<dependency>
			<groupId>commons-fileupload</groupId>
			<artifactId>commons-fileupload</artifactId>
			<version>1.3.1</version>
		</dependency>

之前是采用上面两个第三方jar包来完成文件上传工作的,代码相对比较繁琐;无意间看了片文章说servlet 3.0支持文件上传,于是就尝试了下;先来看servlet3.0提供的几种方法,而后进入实操:

1.HttpServletRequest提供的方法

Part getPart(String name):根据名称获取文件上传域
Collection<Part> getParts():获取所有的文件上传域

2.Part中常用的方法

String getContentType():获取上传文件的文件类型
long getSize():上传文件的大小
String getSubmittedFileName():上传文件的原始文件名
String getName():获取<input name="upload" ...>标签中name属性值
String getHeader(String name):获取请求头部
Collection<String> getHeaderNames():获取所有请求头部名称
InputStream getInputStream():获取上传文件的输入流
void write(String path):保存文件至服务器

3.表单enctype属性说明

在使用标签时,需要设置enctype=“multipart/form-data”,指定表单数据的编码方式。enctype属性值说明:

application/x-www-form-urlencoded:默认编码方式,只处理表单中的value属性值,这种编码方式会将表单中的值处理成URL编码方式
multipart/form-data:以二进制流的方式处理表单数据
text/plain:当表单action属性为mailto:URL形式时比较方便,适用于直接通过表单发送邮件方式

4.@MultipartConfig注解属性说明 : 声明后的Servlet,既可以实现单个文件上传,也可以实现多个文件上传,同时还支持获取表单中的其他指字段.

属性 类型 是否必需
maxFileSize long 否
maxRequestSize long 否
fileSizeThreshold int 否
location String 否

========================

下面进入实操

  1. 前端html部分
<form action="../test" method="post" enctype="multipart/form-data">
分类名称:<input type="text" id="categoryName" name="categoryName" class="form-control"/>
分类图片:<input type="file" accept="image/*" id="categoryPic" name="filePath" />
<input type="submit" id="submit" value="上传图片" class="btn btn-success">
</form>
  1. js部分
function uploadClick() {
	$("#submit").click(function() {
				// 分类名称,去除首位空格后的为空判断();
				var categoryName = $("#categoryName").val();
				categoryName = $.trim(categoryName); // 去除首位空格;
				if (1 > categoryName.length) {
					alert("请输入分类名称后再提交!")
					return false;
				}

				// 上传文件未选择判断
				if (1 > $("#categoryPic").val().length) { 
					alert("请选择文件后,再提交!");
					return false;
				}

				// 文件大小限制;
				var categoryPicSize = $("#categoryPic")[0].files[0].size
				if (500 < categoryPicSize) {
					alert("上传文件大小超过500k!");
					return false; 
				}

			})
  1. servlet部分
@MultipartConfig(maxFileSize = 500, fileSizeThreshold = 1024 * 1024)
public class TestUploadServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) {
		String savePath = req.getServletContext().getRealPath("img/category");
		{
			File addDir = new File(savePath); 
			if (!addDir.exists()) {
				addDir.mkdirs();
			}
		}
		String fileName = System.currentTimeMillis() + ".jpg"; 

		try {
			Part part = req.getPart("filePath"); // // 获取part对象;
			part.write(savePath + File.separator + fileName);

			// 文件格式转换
			String fileType = part.getSubmittedFileName(); 
			if (!fileType.endsWith(".jpg")) { 
				File file = new File(savePath, fileName);
				BufferedImage img = ImageUtil.change2jpg(file);
				ImageIO.write(img, "jpg", file);
			// 文件尺寸调整
				ImageUtil.resizeImage(file, 50, 50, file); 
			}
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ServletException e) {
			e.printStackTrace();
		}
  1. Util图片工具类
package util;

import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferInt;
import java.awt.image.DirectColorModel;
import java.awt.image.PixelGrabber;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

public class ImageUtil {
    public static BufferedImage change2jpg(File f) {
        try {
            Image i = Toolkit.getDefaultToolkit().createImage(f.getAbsolutePath());
            PixelGrabber pg = new PixelGrabber(i, 0, 0, -1, -1, true);
            pg.grabPixels();
            int width = pg.getWidth(), height = pg.getHeight();
            final int[] RGB_MASKS = {0xFF0000, 0xFF00, 0xFF};
            final ColorModel RGB_OPAQUE = new DirectColorModel(32, RGB_MASKS[0], RGB_MASKS[1], RGB_MASKS[2]);
            DataBuffer buffer = new DataBufferInt((int[]) pg.getPixels(), pg.getWidth() * pg.getHeight());
            WritableRaster raster = Raster.createPackedRaster(buffer, width, height, width, RGB_MASKS, null);
            BufferedImage img = new BufferedImage(RGB_OPAQUE, raster, false, null);
            return img;
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
    }

    public static void resizeImage(File srcFile, int width, int height, File destFile) {
        try {
            Image i = ImageIO.read(srcFile);
            i = resizeImage(i, width, height);
            ImageIO.write((RenderedImage) i, "jpg", destFile);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public static Image resizeImage(Image srcImage, int width, int height) {
        try {

            BufferedImage buffImg = null;
            buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            buffImg.getGraphics().drawImage(srcImage.getScaledInstance(width, height, Image.SCALE_SMOOTH), 0, 0, null);

            return buffImg;
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }
}

新手上路 , 如果有更好或不妥的地方,请多多指教 !

应用总结 ;

  1. 父类是servlet,重写service方法(内含文件上传功能实现代码);在req子类时,完成了"文件上传功能";

  2. 当把父类改为abstract抽象类,功能一样实现;注:同上,父类可以不注解@MultipartConfig;子类必须注解@MultipartConfig;

  3. 当前端输入流是:enctype=“multipart/form-data”,采用req.getParameter()和req.getPart()方法,能正常使用;

  4. 前端不是带上传功能(multipart/form-data)的混合流时,会抛异常;

  5. 父类通过反射,调用子类方法(获取req的getParameter和getPart),运行正常;

=======================

其他,碰到个问题,get不到相应数据,情况是:

  1. 如果不经过filter映射到相应servlet的method;使用是正常的;
  2. 否则,get不到相应数据,为null;(在filter中getParameter()就已经是null);

待解决:
J2EE下做的,filter映射到相应servlet的method;搞不定,最后还是选择采用文章开头提到的第三方类,来完成的;

注: 这个问题可能是出在:一个servlet只能转发或者重定向一次上,回头继续排查问题,同时尝试用添加接口来解决问题;待续…/ 另外,为什么filter里读取是null,也有待排查原因(我在其他类似结构的测试类中,filter中是能获取到值的,这个项目中为什么会是null???)

问题已找到: 前端发起的请求servlet名字,如admin_category_add(由于进行了servlet的映射,所以admin_category_add这个servlet实际是不存在的).所以在filter监听时,采用servlet3.0上传文件的方法,get相应值均为null;

解决方法:

1. 采用之前的第三方类,来完成相应操作;
2. 如果做个upload类,请求指向这个servlet,而后进行转发,应该也能实现类似功能;

总结:get相应值出现null的可能情况:

  1. 没有注解;
  2. 前端请求的servlet不存在;
  3. 超出注解配置的文件大小等限制;

其他 : 重新部署后,上传的文件会丢失;因为:重新部署项目的时候,tomcat下的webapps文件夹下的项目会被重新部署,覆盖掉了之前的项目文件,所以文件就消失了。[对策]将上传文件夹,设置在webapps文件夹外面;

========================
寻找问题时,看到其它一些较好的知识点:

无论是RequestDispatcher.forward方法,还是HttpServletResponse.sendRedirect方法,在调用它们之前,都不能有内容已经被实际输出到了客户端。如果缓冲区中已经有了一些内容,这些内容将被从缓冲区中清除。

代码的执行:

无论是 request.getRequestDispatcher(path).forward(request, response)还是response.sendRedirect,程序都会在执行完该句的情况下继续向下执行,因此在必要的时候应该使用return终止该方法.

对于 request.getRequestDispatcher(path).forward(request, response),在执行完该方法的时候再进行对request的操作已经没有任何意义,如果在该方法之后再进行request.setAttribute(),该值将不会被放进当前请求的request中.

response.setRedirect:该方法执行之后,接下来的方法也会被执行.但是使用该方法的时候,会发送一个全新的request,将不再使用原先的request,因此不论在该方法执行之前,还是在该方法执行之后,对request操作,都是无效的.

参考资料:
java web中的servlet3 upload上传文件实践

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值