Springmvc进阶:
Springmvc的文件上传:
Springmvc作为一个mvc框架,当然少不了的是在页面上进行文件的上传功能,在springmvc中的文件上传,是配置一个文件上传解析器并引入文件上传的common-fileupload相关工具来接收文件。
首先、导入依赖管理
<!-- 文件上传组件 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
然后、编写实现类
@Controller
@RequestMapping("file")
public class UploadController {
/**
* file:上传文件参数名。
* @param multipartFile:上传文件对象
* @return String:返回视图名称,简写方式返回视图名称。
* @throws IllegalStateException
* @throws Exception
*/
@RequestMapping("/upload")
public String upload(@RequestParam("file") MultipartFile multipartFile) throws Exception{
if (multipartFile != null) {
//将上传的文件保存文件到指定路径
multipartFile.transferTo(new File("C:\\tmp\\" + multipartFile.getOriginalFilename()));
}
return "redirect:/success.jsp";
}
}
最后、在springmvc-servlet.xml中配置视图解析器
<!-- 定义文件上传解析器 -->
<bean id="multipartResolver” class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置默认字符编码 -->
<property name="defaultEncoding" value="uft-8"></property>
<!-- 设置最大上传文件大小(单位B)5*1024*1024=5242880B=5MB -->
<property name="maxUploadSize" value="5242880"></property>
</bean>
在页面上也是一样,需要有一个input标签type为file,name为file,注意的是form表单的为multipart/form-data和post方式提交
springmvc下载:
在springmvc中下载文件,需要几步。不仅要定制实现类继承AbstractView,还需要定义具体的视图解析器,在视图中获取模型数据然后在返回响应。
①、实现类
②、定义视图解析器
除了定义普通的下载视图,还能定义excel的下载视图。
首先、导入依赖管理
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.9</version>
</dependency>
然后、定义实现类继承AbstractExcelView
@Controller
@RequestMapping("excel")
public class ExcelController {
@RequestMapping("/export")
public ModelAndView exportExcel(){
ModelAndView mv = new ModelAndView();
//设置视图名称
mv.setViewName("excelView");
//到service查询用户列表数据
List<User> userList = new ArrayList<User>();
for(long i = 1; i <= 10; i ++){
User user = new User();
user.setId(i);
user.setName("黑马程序员" + i);
user.setSex(i%2==0?1:0);
user.setAge(Integer.parseInt(i+""));
user.setBirthday(new Date());
userList.add(user);
}
//添加模型数据
mv.addObject("userList", userList);
return mv;
}
}
public class UserExcelView extends AbstractExcelView {
@Override
protected void buildExcelDocument(Map<String, Object> model, HSSFWorkbook workbook, HttpServletRequest request, HttpServletResponse response) throws Exception {
//创建工作表
HSSFSheet sheet = workbook.createSheet("用户列表");
//设置Excel的头标题行
HSSFRow row1 = sheet.createRow(0);
String[] titles = {"用户名称","年龄","性别","生日"};
for(int i = 0; i < titles.length; i++){
HSSFCell cell = row1.createCell(i);
cell.setCellValue(titles[i]);
}
//获取数据列表并填写数据
List<User> userList = (List<User>)model.get("userList");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
for(int j = 0; j < userList.size(); j++){
HSSFRow row = sheet.createRow(j+1);
row.createCell(0).setCellValue(userList.get(j).getName());
row.createCell(1).setCellValue(userList.get(j).getAge());
row.createCell(2).setCellValue(userList.get(j).getSex()==1?"男":"女");
row.createCell(3).setCellValue(sdf.format(userList.get(j).getBirthday()));
}
//设置响应中 下载文件的名称
response.setHeader("Content-Disposition", "attachment;filename=" + new String("用户列表.xls".getBytes(), "ISO-8859-1"));
}
}
最后,是定义自定义的视图解析器
<!-- 定义视图 -->
<bean name="excelView" class="mjf.haihan.springmvc.view.UserExcelView"></bean>
<!-- 定义视图解析器 -->
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
<!-- 设置视图解析器的顺序;order 越小越先执行 -->
<property name="order" value="1"></property>
</bean>
需要注意的是:在配置视图解析器的时,已经配置了InternalResourceViewResolver,在配置视图解析器时,如果不指定解析器的order属性,那么会按照配置顺序先执行InternalResourceViewResolver而导致后续的视图无执行机会;另外,在多个视图解析器的执行顺序,取决于视图解析器的order属性。而且,在定义自己的视图时,需要连续写下定义类和定义的视图解析器。
Order的值越小越先执行,最小为0。也需要将原配置的视图解析器设置order属性,其值应该比BeanNameViewResolver的值小。
<!-- 定义视图解释器 -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- Example: prefix="/WEB-INF/jsp/", suffix=".jsp", viewname="test" ->
"/WEB-INF/jsp/test.jsp" -->
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
<property name="order" value="2"/>
</bean>
Springmvc拦截器:
Springmvc的处理拦截器有执行具体方法时的前、后、完成时三个点进行拦截处理。
执行链:
HandlerExecutionChain执行链,从HandlerMapping返回给DispatcherServlet,其中包含了Handler对象和Interceptor对象。Handler是实现了Controller接口或者使用了@Controller注解的对象,而Interceptor则是实现了HandlerInterceptor接口的对象。
在springmvc中的拦截器接口定义了三个方法:
PreHandler:调用Handler之前执行。
PostHandler:调用Handler之后执行(如果没有调用执行handler将不执行此方法,如果preHandler方法返回false的话,postHandler方法就不执行)。
AfterCompletion:视图渲染完之后并且preHandler方法返回true执行。
执行流程:
当有多个拦截器的时候,每个拦截器中的三个方法执行的顺序:PreHandler按顺序执行,PostHandler和AfterHandler都是逆序执行的。
定义拦截器:
(一)单个拦截器的设置
首先、实现拦截器类
public class MyHandlerInterceptor1 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("MyHandlerInterceptor1的前置方法(preHandle)执行了");
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("MyHandlerInterceptor1的后置方法(postHandle)执行了");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception ex) throws Exception {
System.out.println("MyHandlerInterceptor1的完成方法(afterCompletion)执行了");
}
}
然后、添加拦截器配置
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 配置进入拦截器的web路径规则 -->
<mvc:mapping path="/**/*.action"/>
<!-- 拦截器 -->
<bean class="mjf.haihan.springmvc.interceptor.MyHandlerInterceptor1"/>
</mvc:interceptor>
</mvc:interceptors>
如果想要比较简洁的写法:
<!-- 配置拦截器 -->
<mvc:interceptors>
<bean class="mjf.haihan.springmvc.interceptor.MyHandlerInterceptor1"/>
</mvc:interceptors>
(二)多个拦截器的设置
只需要在配置里面添加拦截器即可
<!-- 配置拦截器 -->
<mvc:interceptors>
<mvc:interceptor>
<!-- 配置进入拦截器的web路径规则 -->
<mvc:mapping path="/**/*.action"/>
<!-- 拦截器 -->
<bean class="mjf.haihan.springmvc.interceptor.MyHandlerInterceptor1"/>
</mvc:interceptor>
<mvc:interceptor>
<!-- 配置进入拦截器的web路径规则 -->
<mvc:mapping path="/**/*.action"/>
<!-- 拦截器 -->
<bean class="mjf.haihan.springmvc.interceptor.MyHandlerInterceptor2"/>
</mvc:interceptor>
<mvc:interceptor>
<!-- 配置进入拦截器的web路径规则 -->
<mvc:mapping path="/**/*.action"/>
<!-- 拦截器 -->
<bean class="mjf.haihan.springmvc.interceptor.MyHandlerInterceptor3"/>
</mvc:interceptor>
</mvc:interceptors>
拦截器的总结:
①、拦截器的执行过程和Struts2的拦截器执行过程类似
②、拦截器的preHandle方法是顺序执行,如果其中一个返回false则请求返回;拦截器的PostHandle方法是倒序执行,postHandle方法只有在preHandle方法全部执行后并且处理器也执行了才能被执行。
③、拦截器的afterCompletion方法是倒序执行,afterCompletion方法不仅是在最后执行,而且如果有多个拦截器时再前面的拦截器的preHandle返回是true时,后面的拦截器即使返回false,那么前面的拦截器的afterCompletion也会执行。
静态资源404和日期问题:
静态资源404:
当配置的DispatcherServlet的url-pattern为“/”时,意思是匹配所有的资源,那么就包含了系统所有的html、css、images等这些静态的资源文件,而后台的Handler是无法处理静态资源的,导致找不到资源404。
在springmvc中可以在配置文件中添加<mvc:defalut-servlet-handler />解决此问题。意思是将静态资源转交给服务器处理;这样spring会默认用Servlet来响应静态文件,DefaultServletHttpRequestHandler在容器启动时会使用主流web容器默认Servlet的名称列表自动查找容器的默认Servlet。
解决字符转日期问题:
在表单中输入日期后提交到后台,如果接收的对象对应的属性类型为日期的那么会提交失败,原因是转换类型失败。需要在属性上添加@DateTimeFormat注解进行转换即可。
例:
@DateTimeFormat(pattern=“yyyy-MM-dd”)
Private Date birthday;