话说
各位读者盆友,下午好!有几天都没见面了,甚是想念大家。这几天笔者没有发表博客,主要还是没有进入状态,一旦进入状态,就好了。
今天的博客也比较简短,分享下SpringMVC的文件上传(单文件、多文件)及返回JSON数据,与页面交互。
目录
1、项目整体架构
2、文件上传
3、返回JSON数据
4、总结
开发环境:IntelliJ IDEA(2017.2.5)
Maven Web项目
1、项目整体架构
2、文件上传
文件上传流程都是差不多:导包==》增加文件域==》配置文件上传处理器==》调用FileUtils来写方法
1)单文件上传
1、导包
导入fileUpload这个包
<!--支持文件上传-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
2、修改表单。
增加文件域、增加enctype属性。
我们之前写了springMVC的增删改查,在增的基础上,增加以下图片。
在add.jsp中增加:
<td>
<input type="file" name="bookCover">
</td>
同时,修改表单:
<form action="add.htm" method="post" enctype="multipart/form-data">
这里就是增加一个enctype属性,表明告诉表单,表单你好,我要上传文件啦,你要能够自动处理这种格式奥!
3、配置文件上传处理器
<!--配置文件上传处理器-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>
<!--上面的id必须要叫这个名字:multipartResolver-->
4、对应的Controller层对应的方法中添加MultipartFile参数
/**
* 执行新增图书
*/
@RequestMapping(value = "add.htm",method = RequestMethod.POST)
public String add(Book book, @RequestParam("bookCover") MultipartFile bookCover) throws IOException {
/*System.out.println("getName== "+bookCover.getName());
System.out.println("getContextType=== "+bookCover.getContentType());
System.out.println("getOriginalFilename== "+bookCover.getOriginalFilename());
System.out.println("getInputStream === "+bookCover.getInputStream());*/
FileOutputStream fos = new FileOutputStream("F:\\"+bookCover.getOriginalFilename());
FileCopyUtils.copy(bookCover.getInputStream(),fos);
book.setCover(bookCover.getOriginalFilename());//这里需要手动赋值
// FileUtils.copyFile(cover,fos); //用不了 没法给一个file
books.put(book.getId(),book);
return "redirect:list.htm";
}
这里其他注释代码都是为了了解MultipartFile的其他属性,真正核心代码就2行:
FileOutputStream fos = new FileOutputStream("F:\\"+bookCover.getOriginalFilename());
FileCopyUtils.copy(bookCover.getInputStream(),fos);
文件上传本质就是复制粘贴,复制粘贴本质就是流。搞定输入输出流,就搞定了文件上传。不过人家内部怎么实现的,还是蛮神奇的。
这里我们用的是: FileCopyUtils.copy(inputStream in,outputStream out)而没有用:FileUtils.copyFile(File input ,OutputStream out),是因为没法传入File这个参数呢。所以用FileCopyUtiles.copy()简单些,2种流可以直接获取。这就是变通喽。
2)多文件上传
多文件上传就是转换成数组,遍历一下即可。
页面上增加多个文本域。
<tr>
<td>
<input type="file" name="bookCover"/>
</td>
<td>
<input type="file" name="bookCover">
</td>
<td>
<input type="file" name="bookCover">
</td>
</tr>
修改代码如下:
/**
* 执行新增图书
*/
@RequestMapping(value = "add.htm",method = RequestMethod.POST)
public String add(Book book, @RequestParam("bookCover") MultipartFile bookCover[]) throws IOException {
/*System.out.println("getName== "+bookCover.getName());
System.out.println("getContextType=== "+bookCover.getContentType());
System.out.println("getOriginalFilename== "+bookCover.getOriginalFilename());
System.out.println("getInputStream === "+bookCover.getInputStream());*/
for(int i=0;i<bookCover.length;i++) {
FileOutputStream fos = new FileOutputStream("F:\\"+bookCover[i].getOriginalFilename());
FileCopyUtils.copy(bookCover[i].getInputStream(),fos);
}
// book.setCover(bookCover.getOriginalFilename());//这里需要手动赋值
// FileUtils.copyFile(cover,fos); //用不了 没法给一个file
books.put(book.getId(),book);
return "redirect:list.htm";
}
这里变化点就是把MultipartFile bookCover变成了数组而已,然后遍历取值。
特别注意!
因为springMVC特殊的传参方式,所以实体类的属性名和表单中的name默认一致,文本域的name属性不要和实体类的属性一致,假如实体类有个属性叫String cover,你的文本域的name也叫cover,那么当你提交表单时候,框架就会默认给实体类的cover属性赋值,但是因为你的cover是MultipartFile类型,就会报错:400或者500!那时候,就比较悲剧,你左看右看,上看下看,怎么看代码都没问题!
所以,框架中,起名字是有讲究的,不要任性,也不要偷懒。取不一样的名字就好。这里用的就是bookCover。
3、返回JSON数据
SpringMVC中提供了与前端的交互方式——返回JSON数据。前端可以直接用Ajax获取值,灰常方便奥。
怎么做列?还是老套路:导包==》写方法加注解。核心就是ResponseBody这个注解。
我们要实现什么效果呢?就是类似的这样一个效果,页面访问的时候,直接返回JSON格式的数据。
1)导包
2)写方法
1)导包
非常简单,只用导入databind这个包,其他2个包都会自动导入。
<!--Spring mvc 支持返回json数据-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.2</version>
</dependency>
最终应该有3个包:jackson-databind、jackson-annotations、jackson-core
2)写方法
/**
* 返回JSON数据
*/
@RequestMapping("jsonList.htm")
@ResponseBody
public Map<String,Object> list() {
Map<String,Object> datas = new HashMap<String,Object>();
datas.put("total",28);
List<Book> books = new ArrayList<Book>();
Book book1 = new Book(1,"《神雕侠侣》");
Book book2 = new Book(2,"《封神演义》");
Book book3 = new Book(3,"《八仙过海》");
books.add(book1);
books.add(book2);
books.add(book3);
datas.put("rows",books);
return datas;
}
/**
* 以上方法会报错:
* HTTP Status 500 - No converter found for return value of type: class java.util.HashMap
* 暂且搁置:换一种方法,直接用类来
*/
要实现的效果是:页面访问jsonList.htm的时候,直接出现我们示例那张图的样式。
然鹅,实际效果确实这样:
网上查了资料,说是需要在springmvc-servlet.xml中加这样的配置:
<!-- rest json related... start -->
<bean id="mappingJacksonHttpMessageConverter"
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="mappingJacksonHttpMessageConverter"/>
</list>
</property>
</bean>-->
在下加了,找不到这个包,暂且搁置。换一种方法,我们写一个类,然后重新输出一下:
Pager类如下:
package com.hmc.springmvc.model;
import java.util.List;
/**
* User:Meice
* 2017/11/18
*/
public class Pager {
private int total;
private List<Book> rows;
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
public List<Book> getRows() {
return rows;
}
public void setRows(List<Book> rows) {
this.rows = rows;
}
}
方法如下:
@RequestMapping("jsonlist.htm")
@ResponseBody
public Pager list2() {
Pager pager = new Pager();
pager.setTotal(28);
List<Book> books = new ArrayList<Book>();
Book book1 = new Book(1,"《神雕侠侣》");
Book book2 = new Book(2,"《封神演义》");
Book book3 = new Book(3,"《八仙过海》");
books.add(book1);
books.add(book2);
books.add(book3);
pager.setRows(books);
return pager;
}
这样还是没搞定,暂且搁置。整体思路就是这样的,是以记之,后续有更好方式在做修改。
4、总结
1、文件上传:导入fileUpload这个包,表单增加属性enctype=“multipart/form-data”,在springmvc-servlet.xml中配置文件上传处理器:CommonsMultipartResolver,采用FileUtils或者FileCopyUtils的copyFile方法即可。本质就是输入流、输出流;
2、返回JSON数据是为了更好的和前端进行交互。核心就是注解@ResponseBody。这个案例中有Bug,后续再深度清理。
好了,下期再会!下期,我们将回顾MyBatis啦。
386

被折叠的 条评论
为什么被折叠?



