当表单中的type为text等普通类型时:
- 可以使用get或post方式提交数据
- enctype 默认值为”application/x-www-form-urlencoded”,
- servlet可以使用request.getParameter(字段名); 来获取值
当表单类型为file 文件上传类型时:
1.只能使用post提交
2.enctype 使用multipart/form-data 在使用包含文件上传控件的表单时,必须使用该值。
3.request.getParameter(字段名); 无法取值, 只能通过 request.getInputStream();
4.必要的两个jar包
jsp文件
设置一个文本输入框 和文件上传框, 可以servlet中将他们获取出来
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
</head>
<body>
<form enctype="multipart/form-data" action="/file/servlet" method="post">
<input type="text" name="text">
<input type="file" name="file"><br>
<input type="submit" >
</form>
</body>
</html>
通过导入jar包的ServletFileUpload, DiskFileItemfactory进行对磁盘的操作
通过表单解析器 得到 form表单中的 类型集合,分别对上传类型 和 非上传类型操作
//判断上传类型是否正确
if (!ServletFileUpload.isMultipartContent(request)){
throw new RuntimeException("not multipart/form-data");
}
//创建DiskFileItemfactory工厂类
DiskFileItemFactory factory = new DiskFileItemFactory();
//创建一个ServletFileUpload核心对象,(表单解析器)
ServletFileUpload sfu = new ServletFileUpload(factory);
//解析request对象, 得到一个list表单项集合
try {
List<FileItem> fileItem = sfu.parseRequest(request);
//遍历
for (FileItem f : fileItem){
if (f.isFormField()){ //普通的表单项
processFormField(f);
}else{
processUploadFile(f);//需要上传的表单项
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
非上传类型 获取 数据
//普通类型的
private void processFormField(FileItem f) {
//这里输出的是字段 和 字段的内容
String fieldname = f.getFieldName(); // 字段名
String fieldvalue = f.getString(); //内容
System.out.println(fieldname+" "+fieldvalue );
}
上传类型 获取 数据 传输到webapp中
对文件上传类型的处理,需要注意的 问题
1.对文件路径只要得到文件名和扩展名(jar包方式, 或手动字符处理方式)
2.对同名文件使用UUID.randomUUID() 方法, 进行随机名字(几乎没有重复的概率)
3.安全问题 ,文件应该放在WEB-INF中
4. 上传的文件过于集中,需要进行打散(日期打散, 16进制打散)
//上传类型的
private void processUploadFile(FileItem f) {
//获取文件名字
String filename = f.getName();
//防止浏览器对文件的不处理, 手动处理文件路径,只需要得到文件名和扩展名
//1.使用jar包提供的方法
if (filename!=null){
filename = FilenameUtils.getName(filename);
}
//2.手动处理
//filename = filename.substring(filename.lastIndexOf(File.separator)+1);
//解决文件同名覆盖问题
filename = UUID.randomUUID()+"_"+filename;
//将文件保存到磁盘
try {
//得到文件流
InputStream in = f.getInputStream();
//创建文件存盘的目录
String path = this.getServletContext().getRealPath("/WEB-INF/upload"); //安全起见, 放在web-inf中
File directory = new File(path);
//若没有此目录 则 new一个
if (!directory .exists()){
directory .mkdirs(); //创建文件目录
}
//解决一个文件夹文件过多问题 -- 文件打散
String childDirectory = makeChildDirectory(directory, filename);//获得一个日期
//在定义dir中构建由表单传来的文件
File file = new File(directory, childDirectory+File.separator+filename); //处理后上传的abc.txt文件所在的目录为/WEB-INF/upload/日期/abc.txt
//通过文件输出流, 将上传的文件保存到磁盘
FileOutputStream fos = new FileOutputStream(file);
int len = -1;
byte[] b = new byte[1024];
while ((len=in.read(b)) != -1){
fos.write(b, 0, len);
}
fos.close();
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
使用日期进行打散 (感觉这总不错,有条理)
//通过日期进行打散
private String makeChildDirectory(File directory) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String dateDirectory = sdf.format(new Date()); //得到日期
//在该目录下查找是否由今天的目录, 没有则创建一个
File file = new File(directory, dateDirectory);
if (!file.exists()){
file.mkdirs();
}
return dateDirectory;
}
//16进制进行打散
//16进制进行打散
private String makeChildDirectory(File directory, String filename){
int hashcode = filename.hashCode();
System.out.println(hashcode);
String code = Integer.toHexString(hashcode);
System.out.println(code);
String childDirectory = code.charAt(0)+File.separator+code.charAt(1); //拼接的越多, 目录打散的越细
//创建指定的目录
File file = new File(directory , childDirectory);
if (!file.exists()){
file.mkdirs();
}
return childDirectory;
}
servlet所有代码
package com.cyh.cc;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import javax.management.RuntimeErrorException;
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.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FilenameUtils;
public class Servlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
//判断上传类型是否正确
if (!ServletFileUpload.isMultipartContent(request)){
throw new RuntimeException("not multipart/form-data");
}
//创建DiskFileItemfactory工厂类
DiskFileItemFactory factory = new DiskFileItemFactory();
//创建一个ServletFileUpload核心对象,(表单解析器)
ServletFileUpload sfu = new ServletFileUpload(factory);
//解析request对象, 得到一个list表单项集合
try {
List<FileItem> fileItem = sfu.parseRequest(request);
//遍历
for (FileItem f : fileItem){
if (f.isFormField()){ //普通的表单项
processFormField(f);
}else{
processUploadFile(f);//需要上传的表单项
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
//上传类型的
private void processUploadFile(FileItem f) {
//获取文件名字
String filename = f.getName();
//防止浏览器对文件的不处理, 手动处理文件路径,只需要得到文件名和扩展名
//1.使用jar包提供的方法
if (filename!=null){
filename = FilenameUtils.getName(filename);
}
//2.手动处理
//filename = filename.substring(filename.lastIndexOf(File.separator)+1);
//解决文件同名覆盖问题
filename = UUID.randomUUID()+"_"+filename;
//将文件保存到磁盘
try {
//得到文件流
InputStream in = f.getInputStream();
//创建文件存盘的目录
String path = this.getServletContext().getRealPath("/WEB-INF/upload"); //安全起见, 放在web-inf中
File directory = new File(path);
//若没有此目录 则 new一个
if (!directory .exists()){
directory .mkdirs(); //创建文件目录
}
//解决一个文件夹文件过多问题 -- 文件打散
String childDirectory = makeChildDirectory(directory, filename);//获得一个日期
//在定义dir中构建由表单传来的文件
File file = new File(directory, childDirectory+File.separator+filename); //处理后上传的abc.txt文件所在的目录为/WEB-INF/upload/日期/abc.txt
//通过文件输出流, 将上传的文件保存到磁盘
FileOutputStream fos = new FileOutputStream(file);
int len = -1;
byte[] b = new byte[1024];
while ((len=in.read(b)) != -1){
fos.write(b, 0, len);
}
fos.close();
in.close();
} catch (Exception e) {
e.printStackTrace();
}
}
//16进制进行打散
private String makeChildDirectory(File directory, String filename){
int hashcode = filename.hashCode();
System.out.println(hashcode);
String code = Integer.toHexString(hashcode);
System.out.println(code);
String childDirectory = code.charAt(0)+File.separator+code.charAt(1); //拼接的越多, 目录打散的越细
//创建指定的目录
File file = new File(directory , childDirectory);
if (!file.exists()){
file.mkdirs();
}
return childDirectory;
}
//通过日期进行打散
private String makeChildDirectory(File directory) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String dateDirectory = sdf.format(new Date()); //得到日期
//在该目录下查找是否由今天的目录, 没有则创建一个
File file = new File(directory, dateDirectory);
if (!file.exists()){
file.mkdirs();
}
return dateDirectory;
}
//普通类型的
private void processFormField(FileItem f) {
//这里输出的是字段 和 字段的内容
String fieldname = f.getFieldName(); // 字段名
String fieldvalue = f.getString(); //内容
System.out.println(fieldname+" "+fieldvalue );
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
补充:
FileItem类自带向磁盘写入文件的方法, 所以不用自己创建输出流
FileItem对象.write(new File(directory, childDirectory+File.separator+filename));
上传文件后,会出现一个临时文件, 但磁盘上只需要一个文件,可以使用
Fileltem.delete(); 进行删除
解决表单乱码问题
ServletFileUpload对象 . setHeaderEncoding(“utf-8”);