黑马商城06
今日任务:
1.商品展示
2.添加商品(上传文件)
1.商品展示
前端:
携带当前页面页码请求后端
后端数据拿来后拼串
后端:
把数据该查的查,该算的算,以Json格式返回
2.文件上传
文件上传?
从客户端的计算机 传输 文件到服务器的计算机
本质流传输的过程
///
满足以下条件(java代码版)
1.页面给一个form表单
2.在表单有一个input type=file
3.表单的提交方式 得是post 不能用get是因为数据拼在请求行里,对数据有大小限制
4.修改表单的一个属性 enctype="application/x-www-form-urlencode" 修改为enctype="multipart/form-data"
5.满足了以上四个条件 提交到后端服务器上 接收的时候 reqeust.getParameter|getParameterValues|getParameterMap 都将失效
发现 虽然不能使用request.getParameter系列方法 但是发现数据是有规律的
可以工具类 也是apache提供
common-fileupload
1.maven 添加依赖
2.使用它的api 让它来帮助解析
使用步骤(不需要记忆)-----框架里封装了 (以后开发 也不会写文件上传的服务器代码 为啥 最后解释)
1.创建 文件磁盘工厂对象
2.创建一个上传解析对象 负责帮助我们解析 request中inputstream
3.它解析完成 返回list集合 放着一个个的表单项
4.使用了 遍历集合 取出一个个项
小问题:
文件名重复 覆盖问题 收到文件 文件名字自己取 保证唯一
某个目录下 小文件太过问题 导致操作系统检索变慢
分散目录
随机分散目录
删除临时文件
item.delete()
代码实现
demo.html
<!--enctype="multipart/form-data"-->
<form action="/upload" method="post" enctype="multipart/form-data" >
用户名:<input type="text" name="username"><br>
备注:<input type="text" name="desc"><br>
头像:<input type="file" name="avatar"><br>
身份证:<input type="file" name="IDCard"><br>
<input type="submit" value="点我提交">
</form>
UploadServlet
@WebServlet("/upload")
public class UploadServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//不考虑文件框
/*String username = request.getParameter("username");
String desc = request.getParameter("desc");
String avatar = request.getParameter("avatar");
System.out.println("名字:"+username+"-描述:"+desc+"-头像:"+avatar);*/
//获取请求 头 自己解析 太麻烦 我们使用 apache提供工具类
/* String contentType = request.getHeader("Content-Type");
String boundary=contentType.split("; ")[1].split("=")[1];
System.out.println("该次请去分隔符是:"+boundary);
ServletInputStream inputStream = request.getInputStream();
//自己取数据
BufferedReader bf = new BufferedReader(new InputStreamReader(inputStream));
String s1 = bf.readLine();
System.out.println(s1);
String s2 = bf.readLine();
System.out.println(s2);*/
//使用工具类
//获取ip
String remoteAddr = request.getRemoteAddr();
System.out.println("欢迎我的朋友:"+remoteAddr+"来访问服务器");
//目录将下面 封装了 放在一个方法里 返回一个返回值 返回map集合
Map<String, String[]> map = parseRequest(request);
Set<Map.Entry<String, String[]>> entries = map.entrySet();
for (Map.Entry<String, String[]> entry : entries) {
System.out.println(entry.getKey()+"::::::::"+ Arrays.toString(entry.getValue()));
}
response.getWriter().print("ok");
}
public Map<String,String[]> parseRequest(HttpServletRequest request){
//返回一个map集合
Map<String,String[]> result = new HashMap<>();
try {
//1.创建 文件磁盘工厂对象
DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
//2.创建一个上传解析对象 负责帮助我们解析 request中inputstream
ServletFileUpload parser = new ServletFileUpload(diskFileItemFactory);
//3.它解析完成 返回list集合 放着一个个的表单项
List<FileItem> items = parser.parseRequest(request);
//4.使用了 遍历集合 取出一个个项
for (FileItem item : items) {
//获取表单项的名字
String parameterName = item.getFieldName();
//判断表单是否是普通文本字段
if(item.isFormField()){
//是普通项 关心她的值
String paramValue = item.getString("utf-8");
/*if(result.containsKey(parameterName)){
}*/
//这里注意有坑,当一个表单项有多个值的时候,这样写不行
result.put(parameterName,new String[]{paramValue});
}else{
//文件项 关心就是 文件对应 的流
//文件的名字
String fileName = item.getName();
//以流的形式返回上传文件的数据内容
InputStream in = item.getInputStream();
//创建 分散二级目录
String secondDir = UploadUtil.randDir();
//电脑文件路径+随机目录
String storePath=UploadUtil.BaseDir()+secondDir;
//检查是否存在 有 直接用 没有创建
UploadUtil.mustExist(storePath);
//获取随机文件名
String uuidName = UploadUtil.getUUIDName(fileName);
//创建输出流
FileOutputStream out = new FileOutputStream(storePath + uuidName);
byte[] bf=new byte[1024];
int len=0;
while((len=in.read(bf))!=-1){
//写到输出流
out.write(bf,0,len);
}
//关流
out.close();
in.close();
System.out.println("该文件被保存了:"+fileName);
//删除temp文件夹里的文件
item.delete();
//表单项名字,和目录+随机名字,放到put里面
result.put(parameterName,new String[]{secondDir+uuidName});
}
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
UploadUtil
/**
* 获取文件真实名称
* 由于浏览器的不同获取的名称可能为:c:/upload/1.jpg或者1.jpg
* 最终获取的为 1.jpg
* @param name 上传上来的文件名称
* @return 真实名称
*/
public static String getRealName(String name){
//获取最后一个"/"
int index = name.lastIndexOf("\\");
return name.substring(index+1);
}
/**
* 获取随机名称
* @param realName 真实名称
* @return uuid 随机名称
*/
public static String getUUIDName(String realName){
//realname 可能是 1.jpg 也可能是 1
//获取后缀名
int index = realName.lastIndexOf(".");
if(index==-1){
return UUID.randomUUID().toString().replace("-", "").toUpperCase();
}else{
return UUID.randomUUID().toString().replace("-", "").toUpperCase()+realName.substring(index);
}
}
public static String BaseDir(){
ResourceBundle upload = ResourceBundle.getBundle("upload");
return upload.getString("base");
}
/**
* 获取文件目录,可以获取256个随机目录
* @return 随机目录 /a/4 /b/c
*/
public static String randDir(){
String s="0123456789ABCDEF";
Random r = new Random();
return "/"+s.charAt(r.nextInt(16))+"/"+s.charAt(r.nextInt(16))+"/";
}
public static void mustExist(String path){
File file = new File(path);
if (!file.exists()){
file.mkdirs();
}
}
upload.properties
base=C:\\Users\\Admin\\Desktop\\upload1
3.Ajax上传文件的封装
代码实现
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="resources/js/jquery-1.11.3.min.js" ></script>
<script type="text/javascript" src="resources/js/jquery-heima-0.0.1.js" ></script>
<script>
$(function(){
$("#upload").click(function(){
/*var params=$("form").serialize();
alert(params)*/
//js 专门提供一个对象 对付 ajax上传文件
//这个对象构建的需要给传入参数
//对应的form表单对象
var fd=new FormData(document.getElementById("f01"));
/*$.ajax({
url:"http://api.itheima349.com/upload",
data:fd,
type:"post",
contentType:false,//不要动手脚 对请求头 不要覆盖
processData:false,
success:function(data){
alert(data);
},
error:function(){
//...
}
})*/
//封装好的方法直接用
HM.ajaxFile("/upload","f01",function(vo){
alert(vo)
})
})
})
</script>
</head>
<body>
<form id="f01" enctype="multipart/form-data" >
用户名:<input type="text" name="username"><br>
备注:<input type="text" name="desc"><br>
头像:<input type="file" name="avatar"><br>
身份证:<input type="file" name="IDCard"><br>
<input type="button" value="点我提交" id="upload">
</form>
</body>
</html>
这两个参数一定要改为false,要不传不了值
4.完成上传文件操作
前端:
携带整个表单提交servlet
成功后跳转
后端:
把照片放到对应的目录,开始封装product数据,插入数据库,返回