类型转换器
SpringMVC实际上自带了一些简单的类型转换器:
String---->int/float/double
String------>boolean类型
全局类型转换器
全局类型转换器:在springmvc.xml配置一次,在任意controller层都可以使用。
1.在springmvc的配置文件中配置一个FormattingConversionServiceFactoryBean 2.Mvc:annotation-driven标签配置一个converservice-service属性
3.自定义一个类实现converter<S,T>接口
例子1:通过form表单获取数据
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <a href="user/test03?birth=1994-11-29">把字符串转为日期</a> <form action="user/test02" method="post"> 姓名:<input type="text" name="username"><br> 性别:<input type="radio" name="sex" value="1">男 <input type="radio" name="sex" value="0">女 <br> 年龄:<input type="text" name="age"><br> 工资:<input type="text" name="salary"><br> 生日:<input type="text" name="birthday"><br> <input type="submit" value="提交"> </form> </body> </html>
public class User { private String username; private boolean sex; private Integer age; private double salary; private Date birthday; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public boolean isSex() { return sex; } public void setSex(boolean sex) { this.sex = sex; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } @Override public String toString() { return "User [username=" + username + ", sex=" + sex + ", age=" + age + ", salary=" + salary + ", birthday=" + birthday + "]"; } }
public class DateTimeConverter implements Converter<String, Date>{ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); @Override public Date convert(String arg0) { try { return sdf.parse(arg0); } catch (ParseException e) { e.printStackTrace(); } return null; }
public class NumberConverter implements Converter<String, Double>{ DecimalFormat df = new DecimalFormat("###,###.##"); @Override public Double convert(String arg0) { try { Number parse = df.parse(arg0); return parse.doubleValue(); } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; }
@RequestMapping("test02") public String test02(User user) { System.out.println("全局数据转换:"+user); return "success"; }
不使用注解:
使用注解:类上加注解
xml文件:
输出结果:
例子2:通过a标签获取数据
@RequestMapping("test04") public String test04(Date birth) { System.out.println("全局数据类型转换"+birth); return "success"; }
输出结果:
局部类型转换器
局部类型转换器:在controller层的方法上每一次使用都需要配置一次。
@DateTimeFormat:时间类型的类型转换器,指定pattern属性值
@NumberFormat:数值类型的类型转换器
例子1:通过form表单获取数据
@DateTimeFormat注解可以放在方法参数上
也可以放在User类的属性上
例子2:通过a标签
输出结果:
文件上传与下载
1 文件上传
前端页面:
必须发送post请求
Form表单的encytype=“multipart/form-data”
type=file
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <form action="file/upload" method="post" enctype="multipart/form-data"> 姓名:<input type="text" name="username"><br> 头像:<input type="file" name="file"><br> <input type="submit" value="提交"> </form> </body> </html>
后端要求:
导入文件上传所需要的jar包:commons-fileupload.jar 和commons-io.jar
在springmvc.xml配置一个多媒体解析器:CommonsMultiPartResolver
在controller层的方法上使用MultiPartFile类型的参数接收一个文件
@RequestMapping("/upload") public ModelAndView upload(MultipartFile file,HttpServletRequest request,String username) throws IOException { ServletContext context = request.getServletContext(); String realPath = context.getRealPath("/upload"); File directory = new File(realPath); if(!directory.exists()) { directory.mkdirs(); } String fileName = UUID.randomUUID().toString().replaceAll("-", "")+file.getOriginalFilename(); FileOutputStream fos = new FileOutputStream(realPath+"/"+ fileName); InputStream fis = file.getInputStream(); IOUtils.copy(fis, fos); fis.close(); fos.close(); ModelAndView mv = new ModelAndView(); mv.setViewName("success"); mv.addObject("fileName",fileName); return mv; }
2 文件下载
文件下载要求:
返回值类型必须为ResponseEntity类型
设置两个响应头信息
@RequestMapping("/download") public ResponseEntity<byte[]> download(HttpServletRequest request) throws IOException { String fileName = "风吹麦浪.mp3"; String realPath = request.getServletContext().getRealPath("/WEB-INF/"+fileName); FileInputStream fis = new FileInputStream(new File(realPath)); byte[] body = new byte[fis.available()]; fis.read(body);
fileName = new String(fileName.getBytes("gbk"),"iso8859-1");
MultiValueMap<String, String> headers = new HttpHeaders();
headers.add("Content-Disposition", "attachment;filename="+fileName);
HttpStatus statusCode = HttpStatus.OK;
ResponseEntity<byte[]> responseEntity = new ResponseEntity<byte[]>(body, headers, statusCode);
return responseEntity;
}
拦截器[Interceptor]
拦截器简介及实现
拦截器类似于javaweb学过的filter【过滤器】,是在请求到达目标方法之前拦截请求,然后进行过滤、权限验证。类似于现实中安检员。
具体实现:
自定义一个类,实现HandlerInterceptor接口
public class FirstInterceptor implements HandlerInterceptor { /** * preHandle:在目标方法执行之前执行 * 返回值:boolean类型,true表示放行该请求,false表示拦截该请求 * 作用:日志、权限验证、获取连接 */ @Override public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception { System.out.println("FirstInterceptor preHandle"); return true; } /** * postHandle:在目标handler方法执行之后,在视图渲染(render)之前【给页面填充数据】执行 * 作用:修改域中的值,用的不多 */ @Override public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception { // TODO Auto-generated method stub System.out.println("FirstInterceptor postHandle"); } /** * afterCompletion:在目标handler方法执行之后,在视图渲染(render)之后【给页面填充数据】执行 * 作用:释放资源,用的不多。 */ @Override public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception { System.out.println("FirstInterceptor afterCompletion"); } }
在springmvc的配置文件中通过mvc:interceptors标签内部配置该拦截器对象
执行流程图:
多拦截器的执行顺序问题
问题1:拦截器的顺序实际上是由springmvc.xml文件中配置的顺序决定的。
问题2:拦截器也可以只拦截某些指定的请求。具体配置如下
问题3:拦截器中各个方法的执行顺序,是由springmvc框架源码决定的和前面学过的aop有点区别
SpringMVC的运行流程图及源码(***)
核心架构的具体流程步骤如下: 1、 首先用户发送请求——>DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行处理,作为统一访问点,进行全局的流程控制; 2、 DispatcherServlet——>HandlerMapping, HandlerMapping将会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象、多个HandlerInterceptor拦截器)对象,通过这种策略模式,很容易添加新的映射策略; 3、 DispatcherServlet——>HandlerAdapter,HandlerAdapter将会把处理器包装为适配器,从而支持多种类型的处理器,即适配器设计模式的应用,从而很容易支持很多类型的处理器; 4、 HandlerAdapter——>处理器功能处理方法的调用,HandlerAdapter将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理;并返回一个ModelAndView对象(包含模型数据、逻辑视图名); 5、 ModelAndView的逻辑视图名——> ViewResolver, ViewResolver将把逻辑视图名解析为具体的View,通过这种策略模式,很容易更换其他视图技术; 6、 View——>渲染,View会根据传进来的Model模型数据进行渲染,此处的Model实际是一个Map数据结构,因此很容易支持其他视图技术; 7、返回控制权给DispatcherServlet,由DispatcherServlet返回响应给用户,到此一个流程结束。