## HTTP 下载
http协议下载关键点:
1. 设置响应状态码为 200
2. 设置响应头 Content-Type
3. 设置响应头 Content-length
4. 在响应Body中发送下载byte数据,数据内容必须与Content-Type一致,数据长度必须与Content-Length一致。
原理:
### 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);
}
检验验证码原理:
步骤:
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