servlet文件上传与下载

文件上传:
    RFC1867协议的请求与响应的特点:

                   通过浏览器上传文件给服务器,与正常的访问不同,用户通过浏览器给服务器发送的比较复杂,而向浏览器返回的信息

            可能是简单的信息,为了规范通过浏览器上传文件到服务器的行为,就设计了一个RFC1867协议,约定上传文件所需要尊守

            的规则。

   文件上传的本质:

           从客户端复制文件到服务端指定目录下面的过程

   文件上传表单三要素:

           1,使用post方式提交表单

           2,为上传表单的每个表单项添加name属性,便于服务器收集

           3,在form标签中,加上enctype="multipart/form-data" 只有在上传文件时使用


   


为了便于上传,需在项目中引入:commons-fileupload-1.2.1.jar和commons-io-1.4.jar两个包


下面演示FileUpload包API的使用:


upload.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c"  uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>My JSP upload page</title>
	<meta http-equiv="pragma" content="no-cache">
	<meta http-equiv="cache-control" content="no-cache">
	<meta http-equiv="expires" content="0">    
	<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
	<meta http-equiv="description" content="This is my page">
	<style type="text/css">
		.container{
			width:400px;
			margin:100px auto;
		}
		ul li{
			width:350px;
			height:50px;
			list-style:none;
		}
		ul li span{
			color:red;
			font-size:30px;
		}
	</style>
  </head>
 
  
  
  <body>
		<div class="container">
			<form action="${pageContext.request.contextPath}/FileUploadServlet" method="POST" enctype="multipart/form-data">
				<ul>
					<li><span>上传文件</span></li>					
					<li><input id="addLineID" type="button" value="添加上传文件"/></li>
					<li><input id="uploadID" type="submit" value="上传"/></li>
				</ul>
			</form>
		</div>
		<script type="text/javascript">
			var count = 0 ; 
			document.getElementById("addLineID").onclick = function(){
				if(count<5){
				var li = document.createElement("li");
				//创建input节点
				var input = document.createElement("input");
				
				input.type = "file";
				input.name = "image";
				var button = document.createElement("input");
				button.value = "删除";
				button.type = "button";
				button.onclick = function(){
					i--;
					li.parentNode.removeChild(li);
				}
				li.appendChild(input);
				li.appendChild(button);
			
				var ul = document.getElementsByTagName("ul")[0];
				ul.insertBefore(li,this.parentNode);
				count++;
				}else{
					alert("大哥,不能再添加了!");
				}
			}
		</script>
  </body>
</html>


FileUploadServlet

import itcast.util.WebUtil;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

public class FileUploadServlet extends HttpServlet {
	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		try{
			//设置上传参数编码为UTF-8
			request.setCharacterEncoding("UTF-8");
			//创建文件上传工厂
			DiskFileItemFactory factory = new DiskFileItemFactory();
			//设置临时缓存区为100k
			factory.setSizeThreshold(100*1024);
			//设置超过100k时,缓存文件的存放路径
			factory.setRepository(new File(this.getServletContext().getRealPath("/WEB-INF/temp")));
			//创建文件上传对象
			ServletFileUpload fileUpload = new ServletFileUpload(factory);
			//判断是否以RFC协议方式上传文件
			if(fileUpload.isMultipartContent(request)){
				//解析request中的所有表单字段
				List<FileItem> fileItemList = fileUpload.parseRequest(request);
				for(FileItem fileItem : fileItemList){
					//如果是普通字段
					if(fileItem.isFormField()){
						/*
						 * 做获取字段操作
						 * String name = fileItem.getFieldName();
						 *  String value = fileItem.getString("UTF-8");
						 */
			
					}else if(!fileItem.isFormField()){
						long size = fileItem.getSize();
						if(size > 200*1024){
							request.setAttribute("message","<font style='font-size:111px;color:red'>上传文件大
                                                        小必须小于或等于200k</font><a href='"+request.getContextPath()+"/upload.jsp'>
                                                        继续上传</a><a href='"+request.getContextPath()+"/ListFileServlet'>浏览列表</a>");
							request.getRequestDispatcher("/WEB-INF/message.jsp").forward(request,response);
							continue ; 
						}
						String contentType = fileItem.getContentType();
						String agent = request.getHeader("USER-AGENT");  //获取agent参数,IE有MSIE参数,FF没有该参数
						System.out.println(contentType);
					
					   if(!"image/pjpeg".equals(contentType) && !"image/jpeg".equals(contentType) &&
                                                      !"application/octet-stream".equals(contentType)){
							request.setAttribute("message","<font style='font-size:111px;color:red'>上传文件类型
                                                        必须是jpg</font><a href='"+request.getContextPath()+"/upload.jsp'>继续上传</a>
                                                        <a href='"+request.getContextPath()+"/ListFileServlet'>浏览列表</a>");
							request.getRequestDispatcher("/WEB-INF/message.jsp").forward(request,response);
							continue ; 
						}
						String filename = fileItem.getName();
						filename = WebUtil.makeUuidFileName(filename);
						//创建目录把文件分散在2级子目录下
						String uploadPath = WebUtil.makeSubUploadPath(this.getServletContext().getRealPath("/WEB-INF/upload"),
                                                     filename);
						//把文件写到服务器自定服务器下面
						InputStream is = fileItem.getInputStream();
						OutputStream os = new FileOutputStream(new File(uploadPath+"/"+filename));
						WebUtil.writeToFile(is, os);
						fileItem.delete();//删除缓存的临时文件
					}
				}
			}
		}catch(Exception e){
			
		}
		request.setAttribute("message","<font style='font-size:111px;color:green'>上传文件成功</font>
                 <a href='"+request.getContextPath()+"/upload.jsp'>继续上传</a><a href='"+request.getContextPath()+"/ListFileServlet'>浏览列表</a>");
		request.getRequestDispatcher("/WEB-INF/message.jsp").forward(request,response);
	}
}


WebUtil中部分代码:

public static String makeUuidFileName(String filename){
		return UUID.randomUUID().toString()+"_"+filename;
	}
	/*
	 * 该方法是把上传的文件打散在不同的子目录里面
	 */
	public static String makeSubUploadPath(String path,String name){
		int code = name.hashCode();
		int dir1 = Math.abs(code % 16);             //第一级目录
		int dir2 = Math.abs((code >> 1) % 16);     //第二级目录
		File file = new File(path+"/"+dir1+"/"+dir2);
		if(!file.exists()){       //如果目录不存在就创建该目录
 			file.mkdirs();
		}
		return file.getPath();
	}
	/**
	 * 把输入流写到输出流里面
	 * @param is
	 * @param os
	 */
	public static void writeToFile(InputStream is,OutputStream os){
		try{
			int len = 0;
			byte[] buf = new byte[2048];
			while((len = is.read(buf)) > 0){
				os.write(buf, 0, len);
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
				try {
					if(is != null){
					is.close();
					}
					if(os != null){
						os.close();
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
		}
	public static String getFileName(String filename){
		return filename.substring(filename.indexOf("_")+1);
	}
}


               上面例子中,在WEB-INF中创建了一个upload文件夹,同时在为了解决不同用户上传相同文件名的问题,使用UUID分别

       为每个文件区分,同时为了在upload中的文件夹打散在子文件夹,利用了添加UUID后的UUID文件名的哈希码,得到一个子目

       录路径,这样做的好处是:在下载的时候可以通过UUID文件名调用相同的方法获取子目录路径,从而获取输入流


ListFileServlet

import itcast.util.WebUtil;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ListFileServlet extends HttpServlet {

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
			//获取上传文件存放路径
			String uploadPath = this.getServletContext().getRealPath("/WEB-INF/upload");
			//定义一个集合将文件名存放好
			Map<String,String> map = new LinkedHashMap<String, String>();
			//递归遍历所有文件
			getAllFile(uploadPath,map);
			//将map保存到request中
			request.setAttribute("MAP", map);
			//转发到list.jsp 页面
			request.getRequestDispatcher("/WEB-INF/list.jsp").forward(request, response);
			
	}

	public void getAllFile(String uploadPath, Map<String, String> map) {
		File file = new File(uploadPath);
		if(file.isFile()){
			String uuidFileName = file.getName();
			//从uuidName 中截取出filename
			String filename = WebUtil.getFileName(uuidFileName);
			map.put(uuidFileName, filename);           
		}else if(file.isDirectory()){  //如果是目录的话
			File[] files = file.listFiles();
			for(File f : files){
				getAllFile(f.getPath(), map);
			}
		}
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
			doGet(request, response);
	}

}

list.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c"  uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>My JSP 'list.jsp' starting page</title>
	<meta http-equiv="pragma" content="no-cache">
	<meta http-equiv="cache-control" content="no-cache">
	<meta http-equiv="expires" content="0">    
	<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
	<meta http-equiv="description" content="This is my page">
 	<style type="text/css">
 		.container{
 			width:500px;
 			margin:0px auto;
 		}
 		.container ul li{
 			margin:0px auto;
 			width:400px;
 			list-style:none;
 			height:50px;
 		}
 		.container ul li span{
 			width:200px;
 			height:50px;
 			text-align: center;
 			display:inline-block;
 			line-height:50px;
 			
 		}
 	</style>
  </head>
  
  <body>
	<div class="container">
		<ul>
			<li><span>文件名</span><span>下载</span></li>
			<c:forEach var="item" items="${requestScope.MAP}">
			<c:url var="url" value="/FileDownloadServlet">
				<c:param name="name" value="${item.key}"></c:param>
			</c:url>
			<li><span>${item.value}</span><span><a href="${url}">下载</a></span></li>
			</c:forEach>
		</ul>
	</div>
  </body>
</html>


FileDownloadServlet



import itcast.util.WebUtil;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URLEncoder;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class FileDownloadServlet extends HttpServlet {
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//解决中文乱码问题
		//获取参数中的文件名称
		String uuidFileName  = request.getParameter("name");
		uuidFileName = new String(uuidFileName.getBytes("ISO8859-1"),"UTF-8");
		//从uuid文件名中获取文件名
		String filename = WebUtil.getFileName(uuidFileName);
		System.out.println(filename);
		//因为是中文,要进行URL编码,该方法在Firefox Netscape 5.0 (Windows) 失效
		filename = URLEncoder.encode(filename,"UTF-8");
		
		System.out.println(filename);
		//获取上传文件的根目录
		String uploadPath = this.getServletContext().getRealPath("/WEB-INF/upload");
		//内部是通过uuidFileName的hasCode编码的,所以相同的文件名,可以获取相同的子路径
		String path = WebUtil.makeSubUploadPath(uploadPath, uuidFileName);  
		//通知浏览器以下载的方式打开
		response.setHeader("content-disposition","attachment;filename="+filename);
		//从实际文件中读取流
		InputStream is = new FileInputStream(path+"/"+uuidFileName);
		OutputStream os = response.getOutputStream();
		//把内容写到浏览器
		WebUtil.writeToFile(is, os);
	}
	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doGet(request, response);
	}
}

JAVA中的注解

                   注解是JDK5,新增的语法功能,就是用@来标识该类,方法,属性的相关信息

                  注解的作用:通知编译器如何处理被注解修饰过的内容,在某种情况下,可以替代原来的XML或properties等文本文件,

                  例如hibernate,spring,android 中会证明。

    1,@Override

               复写父类方法

    2,@Deprecated

               废弃方法,已经过时。

    3,@SuppressWarnings (value="unchecked")

              表示通知编译器不要警告


JDK5中的内置注解,不能瞒住企业方方面面的业务续修,所以的按规则,开发注解


自定义注解的生命周期

              SOURCE:有且只有在源码级别可见,(不推荐使用)

              CLASS:  有且只有在源码和字节码级别可见,(默认),但在运行时,不可见

              RUNTIME:在整个类的运行期周,都可见。(即源码,字节码,运行时)

元注解的作用

                 修饰其它注解的注解,注意:元注解也可以被其它注解修饰

                 @Retention(RetentionPolicy.RUNTIME):表示该注解可以在运行时,可见

                 @Target(ElementType.METHOD):表示该注解可以用在哪些地方,默认情况下,该注解可以出现在任何地方



自定义注解应用示例:


DB.java

@Target({METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DB {
    String driver() default "com.mysql.jdbc.Driver";
    String url() default "jdbc:mysql://127.0.0.1:3306/jdbc";
    String user() default "root";
    String password() default "root";
}


Demo03.java
    public class Demo03 {
    @DB
    public Connection getConnection() throws Exception {
        Class clazz = this.getClass();
        Method getConnectionMethod = clazz.getMethod("getConnection",null);
        DB dbAnnotation = getConnectionMethod.getAnnotation(DB.class);
        String driver = dbAnnotation.driver();
        String url = dbAnnotation.url();
        String user = dbAnnotation.user();
        String password = dbAnnotation.password();
        Class.forName(driver);
        return DriverManager.getConnection(url,user,password);
    }
    public static void main(String[] args) throws Exception {
        Demo03 test = new Demo03();
        Connection conn = test.getConnection();
        System.out.println(conn!=null?"连接成功":"连接失败");
        conn.close();
    }
}














评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值