一.文件下载
访问资源时相应头如果没有设置 Content-Disposition,浏览器默认按照inline值进行处理,inline 能显示就显示,不能显示就下载。
只需要修改相应头中Context-Disposition="attachment;filename=文件名",attachment 下载是以附件形式下载,filename=值就是下载时显示的下载文件名。
实现步骤
第一步,导入apatch 的两个 jar。
第二步,在 jsp 中添加超链接,设置要下载文件,在 springmvc 中放行静态资源 files 文件夹,编写控制器方法。
<a href="download?fileName=abc.rar">下载</a>
@RequestMapping("download")
public void download(String fileName,HttpServletResponse res,HttpServletRequest req) throws IOException{
//设置响应流中文件进行下载
res.setHeader("Content-Disposition", "attachment;filename="+fileName);
//把二进制流放入到响应体中.
ServletOutputStream os = res.getOutputStream();
String path = req.getServletContext().getRealPath("files");
System.out.println(path);
File file = new File(path, fileName);
byte[] bytes = FileUtils.readFileToByteArray(file);
os.write(bytes);
os.flush();
os.close();
}
二.文件上传
基于 apache 的 commons-fileupload.jar 完成文件上传。
MultipartResovler 作用:把客户端上传的文件流转换成 MutipartFile 封装类,通过 MutipartFile 封装类获取到文件流。
表单数据类型分类:在<form>的 enctype 属性控制表单类型;默认值 application/x-www-form-urlencoded,普通表单数据,(少量文字信息);text/plain大文字量时使用的类型,邮件论文;multipart/form-data 表单中包含二进制文件内容。
实现步骤
第一步,导入 springmvc 包和 apache 文件上传 commons-fileupload 和 commons-io 两个 jar。
第二步,编写JSP页面。
<form action="upload" enctype="multipart/form-data" method="post">
姓名:<input type="text" name="name"/><br/>
文件:<input type="file" name="file"/><br/>
<input type="submit" value="提交"/>
</form>
第三步,配置springmvc.xml。
<!-- MultipartResovler 解析器 -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="50"></property>
</bean>
<!-- 异常解析器 -->
<bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="org.springframework.web.multipart.MaxUploadSizeExceededException">/error.jsp</prop>
</props>
</property>
</bean>
第四步,编写控制器类。
MultipartFile 对象名必须和<input type=”file”/>的 name 属性值相同。
@RequestMapping("upload")
public String upload(MultipartFile file,String name) throws IOException{
String fileName = file.getOriginalFilename(); String suffix = fileName.substring(fileName.lastIndexOf("."));
//判断上传文件类型
if(suffix.equalsIgnoreCase(".png")){
String uuid = UUID.randomUUID().toString();
FileUtils.copyInputStreamToFile(file.getInputStream (), new File("E:/"+uuid+suffix));
return "/index.jsp";
}else{
return "error.jsp";
}
}
三.自定义拦截器
是跟过滤器比较像的技术。
发送请求时被拦截器拦截,在控制器的前后添加额外功能,跟AOP区分开,AOP在特定方法前后扩充(对ServiceImpl),拦截器是请求的拦截,针对点是控制器方法(对Controller)。
SpringMVC拦截器和Filter的区别,拦截器只能拦截Controller,Filter可以拦截任何请求。
自定义拦截器实现步骤
第一步,新建类实现HandlerInterceptor接口。
public class DemoInterceptor implements HandlerInterceptor {
//在进入控制器之前执行
//如果返回值为 false,阻止进入控制器
//控制代码
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
System.out.println("arg2:"+arg2);
System.out.println("preHandle");
return true;
}
//控制器执行完成,进入到 jsp 之前执行.
//日志记录.
//敏感词语过滤
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception {
System.out.println("往"+arg3.getViewName()+"跳转");
System.out.println("model 的值"+arg3.getModel().get("model"));
String word = arg3.getModel().get("model").toString();
String newWord = word.replace("祖国", "**");
arg3.getModel().put("model", newWord);
//arg3.getModel().put("model", "修改后的内容");
System.out.println("postHandle");
}
//jsp 执行完成后执行
//记录执行过程中出现的异常.
//可以把异常记录到日志中
@Override
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception {
System.out.println("afterCompletion"+arg3.getMessage());
}
}
第二步,在springmvc.xml配置拦截器需要拦截哪些控制器。下面分别是拦截所有控制器和拦截特定的url。
<mvc:interceptors>
<bean class="com.lidong.interceptor.DemoInterceptor"></bean>
</mvc:interceptors>
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/demo"/>
<mvc:mapping path="/demo1"/>
<mvc:mapping path="/demo2"/>
<bean class="com.lidong.interceptor.DemoInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
四.拦截器栈
多个拦截器同时生效时,组成了拦截器栈。拦截器栈的顺序是先进后出。执行顺序和springmvc.xml中配置顺序有关。设置先配置拦截器A再配置拦截器B执行顺序为preHandle(A) --> preHandle(B) --> 控制器方法 --> postHandle(B) --> postHanle(A) --> JSP --> afterCompletion(B) --> afterCompletion(A)。
五.SpringMVC运行原理
文字解释
如果在 web.xml 中设置 DispatcherServlet 的<url-pattern>为/时,当用户发起请求,请求一个控制器 ,首先会执行 DispatcherServlet,由DispatcherServlet 调 用 HandlerMapping 的 DefaultAnnotationHandlerMapping 解 析 URL,解 析 后 调 用 HandlerAdatper 组 件 的 AnnotationMethodHandlerAdapter 调 用Controller 中的 HandlerMethod。当 HandlerMethod 执行完成后会返回View,会被 ViewResovler 进行视图解析,解析后调用 jsp 对应的.class 文件并运行,最终把运行.class 文件的结果响应给客户端。以上就是 springmvc 运行原理。
六.SpringMVC对Date类型转换
在 springmvc.xml 中配置,代码中不需要做任何修改。
必须额外导入 joda-time.jar,时间类型 java.sql.Date。
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
<bean id="conversionService" class="org.springframework.format.support.Formattin gConversionServiceFactoryBean">
<property name="registerDefaultFormatters" value="false" />
<property name="formatters">
<set>
<bean class="org.springframework.format.number.NumberForm atAnnotationFormatterFactory" />
</set>
</property>
<property name="formatterRegistrars">
<set>
<bean class="org.springframework.format.datetime.joda.Jod aTimeFormatterRegistrar">
<property name="dateFormatter">
<bean class="org.springframework.format.datetime.joda.Dat eTimeFormatterFactoryBean">
<property name="pattern" value="yyyy-MM-dd" />
</bean>
</property>
</bean>
</set>
</property>
</bean>