HTTP 文件的上载和下载


## HTTP 下载

 
http协议下载关键点:
 
1. 设置响应状态码为 200
2. 设置响应头 Content-Type
3. 设置响应头 Content-length
4. 在响应Body中发送下载byte数据,数据内容必须与Content-Type一致,数据长度必须与Content-Length一致。
 
原理:
 

图片222

 
### Spring MVC 下载
 
SpringMVC对资源下载做了封装:
 
1. 利用@RequestMapping(produces="image/png")设置Content-Type
2. 利用@ResponseBody 和 控制器方法 byte[]类型的返回值填充响应Body, 并且自动设置Content-Length
 
生成验证码图片案例:
 
    /**
     * 生成验证码图片控制器
     * 其中 value="code.do"用于映射URL
     * produces="image/png" 用于设置响应头中的
     * Content-Type 属性
     * 返回值  byte[] 会被注解@ResponseBody自动
     * 处理放置到响应消息的Body中发送到客户端
     *  
     * @ResponseBody 还会根据 byte[] 数组长度自动
     * 设置 响应头部的Content-Length属性
     *  
     * @return
     */
    @RequestMapping(value="code.do",
            produces="image/png")
    @ResponseBody
    public byte[] code(HttpSession session)  
            throws IOException{
        String code = genCode(4);
        session.setAttribute("code", code);  
        byte[] png = createPng(code);
        return png;
    }
    private byte[] createPng(String code) throws IOException{
        //1. 利用BufferedImage 创建 img 对象
        BufferedImage img=new BufferedImage
            (100, 40, BufferedImage.TYPE_3BYTE_BGR);
        img.setRGB(50, 20, 0xffffff);
        Graphics2D g=img.createGraphics();
        
        Random random = new Random();
        //生成随机颜色:
        Color c=new Color(random.nextInt(0xffffff));
        //填充图像的背景
        g.setColor(c);  
        g.fillRect(0, 0, 100, 40);
        
        //绘制500个随机点
        for(int i=0; i<500; i++){
            int x=random.nextInt(100);
            int y=random.nextInt(40);  
            int rgb=random.nextInt(0xffffff);  
            img.setRGB(x, y, rgb);
        }
        //设置平滑抗锯齿绘制
        g.setRenderingHint(
            RenderingHints.KEY_ANTIALIASING,  
            RenderingHints.VALUE_ANTIALIAS_ON);
        //设置字体大小
        g.setFont(new Font(Font.SANS_SERIF,  
                Font.PLAIN, 30));
        g.setColor(new Color(
                random.nextInt(0xffffff)));
        g.drawString(code, 10, 30);
        
        //随机绘制10条线段
        for(int i=0; i<10; i++){
            int x1=random.nextInt(100);
            int y1=random.nextInt(40);
            int x2=random.nextInt(100);
            int y2=random.nextInt(40);
            g.drawLine(x1, y1, x2, y2);
        }
        
        //2. 利用ImageIO将 img 编码为png
        ByteArrayOutputStream out=
                new ByteArrayOutputStream();
        ImageIO.write(img, "png", out);
        out.close();
        byte[] bytes=out.toByteArray();
        return bytes;
    }
    
    private static String chs=
        "345678abcdefhjkmnpqrstuvwxyABCDEFGHJL";
    private String genCode(int len){
        char[] code=new char[len];
        Random random = new Random();
        for(int i=0; i<code.length; i++){
            code[i]=chs.charAt(
                    random.nextInt(chs.length()));
        }
        return new String(code);  
    }
 
检验验证码原理:
 

![](imgs/3.png)

    
步骤:
 
1. login.jsp中添加img标签显示图片:
    
        <div class="text">
            <input type="text" id="code" placeholder="请输入验证码" name="code" required minlength="4" maxlength="4">
            <span><img  id="code_image"  style="top:-39px;right:-155px"  
                src="code.do"></span>
        </div>
 
2. 更新 login.css 显示位置
 
        #cover .txt{
            float: left;
            overflow: hidden;
            width: 253px;
            /* height: 277px;  避免遮挡验证码 */  
            padding: 10px;
        }
 
3. 发起ajax请求验证
 
        $("#code").blur(function(){
            var data = $("#code").val();
            console.log(data);
            if (data == null || data == "") {
                $("#showResult").text("验证码不能为空!");
                $("#showResult").css("color","red");
                return false;
            }
            $.ajax({
                "type":"POST",
                "url":"checkCode.do",
                "data":"code="+data,
                "beforeSend":function(XMLHttpRequest){
                    $("#showResult").text("正在查询...");
                    $("#showResult").css("color", "green");
                },
                "success":function(obj) {
                    var color = obj.state == 1
                        ? "green" : "red";
                    $("#showResult").css("color", color);
                    $("#showResult").text(obj.message);
                },
                "error":function() {
                    //错误处理
                }
            });
            
        });
 
4. 添加更新点击更新图片的方法
 
    //点击验证码图片时候更新图片
    $("#code_image").click(function(){
        var img=this;
        console.log(img);
        //添加请求参数的目的避免浏览器的缓存
        img.src="code.do?"+new Date().getTime();
    });
 
5. 添加检验验证码 控制器 方法
 
        /**
         * 检查验证码
         */
        @RequestMapping("checkCode.do")
        @ResponseBody
        public ResponseResult<Void> checkCode(
                String code,  
                HttpSession session){
            ResponseResult<Void> rr=
                    new ResponseResult<Void>();
            String c = (String)session.getAttribute("code");
            if(c !=null && c.equalsIgnoreCase(code)){
                rr.setState(ResponseResult.STATE_OK);
                rr.setMessage("验证码检查通过");
            }else{
                rr.setState(ResponseResult.STATE_ERROR);
                rr.setMessage("验证码错误");  
            }
            return rr;
        }
 
6. 放过 验证请求 spring-mvc.xml:
 
        <mvc:exclude-mapping path="/user/code.do"/>
        <mvc:exclude-mapping path="/user/checkCode.do"/>
 
7. 测试....
 
## 自动下载图片功能
 
Http协议中如果了下载属性头Content-Disposition,设置这个响应头,就可以实现下载保存到文件中:
 
步骤:
 
1. 编写控制器方法
 
        /**
         * 下载图片
         * Content-Disposition:  
         *     attachment; filename="fname.ext"
         *  
         * 参考:RFC2616 19.5.1 Content-Disposition
         */
        @RequestMapping(value="downloadImage.do",
                produces="image/png")
        @ResponseBody
        public byte[] downloadImage(
                HttpServletResponse response)
            throws Exception{
            //手工设置 下载头 Content-Disposition
            response.setHeader(
                "Content-Disposition",  
                "attachment; filename=\"ok.png\"");
            byte[] bytes=createPng("OK");
            return bytes;
        }
 
2. 客户端下载连接:
 
        <a href="downloadImage.do">下载</a>  
 
 
3. 测试。。。
 
## 下载Excel
 
与下载PNG图片的原理一样,只是ContentType的值不同:
 
1. 导入 POI API
 
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.16</version>
        </dependency>
 
2. 编写控制器方法
    
        /**
         * 下载Excel
         * application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
         */
        @RequestMapping(value="downloadExcel.do",
                produces="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
        @ResponseBody
        public byte[] downloadExcel(
                HttpServletResponse response)
            throws Exception{
            //手工设置 下载头 Content-Disposition
            response.setHeader(
                "Content-Disposition",  
                "attachment; filename=\"ok.xlsx\"");
            byte[] bytes=createExcel();
            return bytes;
        }
    
        /**
         * 利用Excel API POI 创建Excel对象
         */
        private byte[] createExcel() throws IOException{
            //创建工作簿
            XSSFWorkbook workbook=new XSSFWorkbook();
            //在工作簿中添加工作表
            XSSFSheet sheet1=
                workbook.createSheet("花名册");
            //在工作表中添加两行
            XSSFRow head=sheet1.createRow(0);
            XSSFRow row=sheet1.createRow(1);
            //第一行做为表头
            XSSFCell c0= head.createCell(0);
            //表头第一个格子添加 “编号”
            c0.setCellValue("编号");  
            head.createCell(1).setCellValue("姓名");
            head.createCell(2).setCellValue("年龄");
            
            row.createCell(0).setCellValue(1);
            row.createCell(1).setCellValue("范传奇");
            row.createCell(2).setCellValue(12);
            
            //将Excel对象保存为bytes  
            ByteArrayOutputStream out=
                    new ByteArrayOutputStream();
            workbook.write(out);  
            out.close();
            byte[] bytes=out.toByteArray();
            return bytes;
        }
 
 
3. 添加客户端链接
 
        <a href="downloadExcel.do">Excel</a>
 
4. 测试
 
## 上载文件
 
HTTP上载是基于 RFC 1867 标准,Spring MVC 利用Apache commons fileupload 组件支持了这个标准,这样利用Spring MVC提供的API可以轻松的获得上载文件:
 
)
 
参考Spring 3.2 手册: 17.10 Spring's multipart (file upload) support
 
### 表单上载
 
实现上载步骤:
 
1. 导入 commons fileupload 上载组件
 
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.3</version>
        </dependency>
 
2. 配置Spring 上载解析器:
 
     
        <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
            <property name="maxUploadSize"  
                value="5000000"/>
            <property name="defaultEncoding"
                value="utf-8"></property>
        </bean>
         
 
3. 编写表单 web/upload.jsp
 
        <%@ page language="java"  
            contentType="text/html; charset=UTF-8"
            pageEncoding="UTF-8"%>
        <!DOCTYPE html>
        <html>
        <head>
        <meta charset="UTF-8">
        <title>文件上载</title>
        </head>
        <body>
            <h1>文件上载</h1>
            <form enctype="multipart/form-data"  
                action="upload.do" method="post">
                姓名:<input type="text" name="username"><br>  
                照片:<input name="userfile1" type="file"><br>
               <input type="submit" value="上载">
            </form>
        </body>
        </html>
 
4. 编写控制器方法显示表单
 
        /**
         * 显示上载表单
         */
        @RequestMapping("uploadForm.do")
        public String uploadForm(){
            return "upload";
        }
 
5. 编写控制器处理上载请求
    
        /**
         * 处理上载请求
         */
        @RequestMapping(value="upload.do",  
                method=RequestMethod.POST)
        @ResponseBody
        public ResponseResult<Void> upload(
            @RequestParam("userfile1") MultipartFile image,
            @RequestParam("username") String username,
            HttpServletRequest request)  
            throws IOException {
            //打桩输出上载结果
            System.out.println(username);
            System.out.println(image);
            //获取上载文件信息
            System.out.println(image.getContentType());
            System.out.println(image.getName());
            System.out.println(image.getOriginalFilename());
            System.out.println(image.getSize());
            //保存到文件系统
            String path="/images/upload";//WEB路径
            path = request.getServletContext()
                    .getRealPath(path);
            System.out.println(path);  
            //创建upload文件夹
            File dir = new File(path);
            dir.mkdir();
            File file=new File(dir,  
                    image.getOriginalFilename());
            //将上载文件保存到文件中
            image.transferTo(file);
            
            ResponseResult<Void> rr=new ResponseResult<Void>();
            rr.setState(ResponseResult.STATE_OK);
            rr.setMessage("上载成功");
            return rr;
        }
 
6. 测试: 先显示上载表单,然后选择文件上载到服务器
 
        上载后可以使用URL显示上载的文件,如:
        http://localhost:8080/TeduStore/images/upload/Chrysanthemum.jpg

猜你喜欢

转载自blog.csdn.net/weixin_41664173/article/details/79145066