【JavaWeb】4、文件上传、下载

八、文件上传、下载

文件上传

  1. form表单,method=post
  2. encType属性值必须为multipart/form-data
  3. 在form标签中使用input type=file添加要上传的文件
  4. 编写服务器代码(Servlet),接收、处理上传的数据

1、演示

<form action="uploadServlet" method="post" enctype="multipart/form-data">
    用户名:<input type="text" name="username"/>
    头像:<input type="file" name="photo"/>
    <input type="submit" value="上传"/>
</form>

multipart/form-data表示提交的数据,以多段(每一个表单项作为一个数据段)的形式进行拼接,然后以二进制流的形式发送给服务器

HTTP请求报文如下

POST /09_EL_JSTL/uploadServlet HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Content-Length: 306
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
Origin: http://localhost:8080
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryYBjPBNY57i0B5j0B

boundary表示每段数据的分隔符

----WebKitFormBoundaryYBjPBNY57i0B5j0B 是每次由浏览器都随机生成,就是多段数据间的分界符

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    ServletInputStream is = req.getInputStream();
    byte[] buffer = new byte[1024];
    int len;
    while((len=is.read(buffer))!=-1){
        System.out.println(new String(buffer,0,len));
    }
}

打印台测试输出如下

------WebKitFormBoundaryIuflEP7Y4UBOf8CD
Content-Disposition: form-data; name="username"

SY2106317
------WebKitFormBoundaryIuflEP7Y4UBOf8CD
Content-Disposition: form-data; name="photo"; filename="1.txt"
Content-Type: text/plain

HelloWorld锛侊紒锛侊紒锛?
------WebKitFormBoundaryIuflEP7Y4UBOf8CD--


2、常用API

由于处理流比较繁琐,所以用外部api来协助处理接受的数据

导入commons-fileupload和commons-io两个jar包

常用类:

  • ServletFileUpload,用于解析上传的数据
  • boolean ServletFileUpload.isMultipartContent(HttpServletRequest request),判断数据是否是多段格式
  • public List< FileItem > parseRequest(HttpServletRequest request),解析上传的各段数据为FileItem对象
  • boolean FileItem.isFormField(),判断当前表单项是否是普通表单项,还是上传的文件类型(false表示是上传的文件)
  • String FileItem.getFieldName(),获取表单项的name属性值
  • String FileItem.getString(),获取表单项的值
  • String FileItem.getName(),获取上传的文件名
  • void FileItem.write(file),将上传的文件写到参数file所指向的硬盘位置

3、练习

Servlet程序:

    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        1. 先判断上传数据是否是多段数据(只有是多段的数据,才是文件上传的)
        if(ServletFileUpload.isMultipartContent(req)){
//            创建FileItemFactory工厂实现类对象
            FileItemFactory fileItemFactory = new DiskFileItemFactory();
//            创建用于解析数据的工具类ServletFileUpload类对象
            ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);

            try {
 //            解析上传的数据,得到每一个表单项FileItem
                List<FileItem> fileItems = servletFileUpload.parseRequest(req);
                for(FileItem fileItem:fileItems){
                    if(fileItem.isFormField()){
//                        普通表单项
                        System.out.print("表单项name:"+fileItem.getFieldName());
                        System.out.println(",表单项value:"+fileItem.getString("UTF-8"));
//                        参数utf-8,解决中文乱码问题
                    }else{
//                        文件
                        System.out.print("表单项name:"+fileItem.getFieldName());
                        String name = fileItem.getName();
                        System.out.println("上传的文件名:"+name);
                        File file = new File(name);
                        fileItem.write(file);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

文件下载

服务器:

  1. 获取要客户端下载的文件名

  2. 读取要下载的文件内容

  3. 在回传前,通过响应头告诉客户端返回的数据类型、以及收到的数据是用于下载

  4. 把文件内容回传给客户端

演示

在web目录下新建file目录,并放入要下载的文件,例如2.png

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        1. 获取要下载的文件名
        String downloadFileName = "2.png";
//        2. 获取要下载的文件内容(通过ServletContext对象可以获取)
        ServletContext servletContext = getServletContext();

//        获取要下载的文件类型
        String mimeType = servletContext.getMimeType("/file/" + downloadFileName);
        System.out.println("下载的文件类型:"+mimeType);
//        3. 告诉客户端回传的数据类型、以及收到的数据是用于下载
        resp.setContentType(mimeType);
        resp.setHeader("Content-Disposition","attachment; filename="+downloadFileName);
//        Content-Disposition响应头,表示收到数据的处理方式
//        attachment 附件,表示下载使用
//        filename= 指定下载的文件名
//		  url编码时把汉字转换成为%xx%xx的格式,让下载的文件名支持中文        

        InputStream is = servletContext.getResourceAsStream("/file/" + downloadFileName);
        System.out.println("inputStream:"+is);
//        /斜杠为服务器解析表示地址为http://ip:port/工程名/  映射到代码的web目录
//        获取响应的输出流
        OutputStream os = resp.getOutputStream();
//        4. 把要下载的文件内容回传给客户端
//        读取输入流中全部数据,复制给输出流,输出给客户端
        IOUtils.copy(is,os);
    }

Base64编码

下载文件名还可以用Base64编码

    public static void main(String[] args) throws Exception {
        String str = "我爱你中国";
        BASE64Encoder base64Encoder = new BASE64Encoder();
        String s = base64Encoder.encodeBuffer(str.getBytes("UTF-8"));
        System.out.println("编码后的结果:"+s);
        BASE64Decoder base64Decoder = new BASE64Decoder();
        byte[] bytes = base64Decoder.decodeBuffer(s);
        String s1 = new String(bytes, "UTF-8");
        System.out.println("解码后的结果是:"+s1);
    }

九、其他

BeanUtils

使用第三方工具类BeanUtils可以直接把HttpServletRequest中的数据封装到Bean对象中,为了降低耦合性,也可以直接把Map的数据封装到Bean对象中

需要导入

commons-beanutils

commons-logging

commons-collections

三个jar包

工具类:

public class WebUtils {
    public static <T> T copyParamToBean(Map map, T bean){
        try {
            BeanUtils.populate(bean, map);
        }catch (Exception e){
            e.printStackTrace();
        }
        return bean;
    }
}

然后在Servlet程序中,直接调用就可以返回封装好属性值的Bean对象

底层调用了Bean对象的 set属性名(属性值)方法

User user = WebUtils.copyParamToBean(req.getParameterMap(), new User());

MVC模型

MVC:Model模型、View视图、Controller控制器

  • View:只负责数据和界面的显示,不接受任何与显示数据无关的代码
  • Controller:只负责接收请求,调用业务层的代码处理请求,然后派发页面(转到或重定向到某个页面),是“调度者”——Servlet
  • Model:将与业务逻辑相关的数据封装为具体的JavaBean类,其中不掺杂任何与数据处理相关的代码——JavaBean/domain/entity/pojo

MVC是一种思想,将软件代码拆分为组件,单独开发,组合使用,可以降低耦合,让代码合理分层

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值