1 SpringMVC的组件
a.前端控制器(DispatcherServlet)
本质上是一个Servlet,相当于一个中转站,所有的访问都会走到这个Servlet中,再根据配置进行中转到相应的Handler中进行处理,获取到数据和视图后,在使用相应视图做出响应。
b.处理器映射器(HandlerMapping)
本质上就是一段映射关系,将访问路径和对应的Handler存储为映射关系,在需要时供前端控制器查阅。
c.处理器适配器(HandlerAdapter)
本质上是一个适配器,可以根据要求找到对应的Handler来运行。前端控制器通过处理器映射器找到对应的Handler信息之后,将请求响应和对应的Handler信息交由处理器适配器处理,处理器适配器找到真正handler执行后,将结果即model和view返回给前端控制器。
d.视图解析器(ViewResolver)
本质上也是一种映射关系,可以将视图名称映射到真正的视图地址。前端控制器调用处理器适配完成后得到model和view,将view信息传给视图解析器得到真正的view。
e.视图(View)
本质上就是将handler处理器中返回的model数据嵌入到视图解析器解析后得到的jsp页面中,向客户端做出响应。
2 springmvc核心配置文件
SpringMVC默认在和web.xml相同的位置即WEB-INF目录下寻找核心配置文件,文件名默认[前端控制器Servlet-name]-servlet.xml
如果需要,可以通过配置,手动指定核心配置文件的位置和文件的名称:
<!-- 配置前端控制器 -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:/springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
</web-app>
2.1 创建核心配置文件
SpringMVC默认会自动在web应用的WEB-INF目录下去寻找[前端控制器ServletName]-servlet.xml作为当前SpringMVC的核心配置文件。如果自己指定了核心配置文件位置,则需要在指定位置创建。
在配置文件中开启SpringMVC的注解模式
<!-- 开启包扫描 -->
<context:component-scan base-package="com.yyy.springmvc"></context:component-scan>
<!-- 开启SpringMVC的注解控制 -->
<mvc:annotation-driven/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
2.2 SpringMVC注解方式工作原理
a.当服务器启动时,先会加载web.xml,创建前端控制器Servlet,前端控制器加载并解析SpringMVC的配置文件。
b.当解析到包扫描时,扫描指定的包,并将含有@Controller注解的类解析为处理器
c.解析@RequestMapping(value="/hello.html"),将指定的地址和当前方法的映射关系进行保存
d.当用户发出请求访问一个地址时,SpringMVC寻找该地址映射关系,如果存在,则找到响应处理器相应方法执行,如果找不到,则报404。
3 SpringMVC细节
3.1 @RequestMapping注解属性
(1)String [] value() default {};
指定要将当前处理器绑定到哪个访问路径上。
可以配置多个路径。
路径中也可以使用*号作为通配符匹配部分路径。
@RequestMapping({"/test01.html","/test001.html","/test002*.html"})
(2)RequestMethod[] method() default {}
指定当前处理器处理哪种提交方式提交的请求。
不指定则接收任意请求方式的请求
@RequestMapping(value="/test03.action",method= RequestMethod.POST)
(3)String[] params() default {};
用来限定当前请求中必须包含指定名称的请求参数才会被当前处理器处理
通过params属性指定只处理请求参数符合指定要求的请求
格式1:只指定名称,要求必须具有该名称的请求参数
格式2:以"名称=值"或"名称!=值"的方式指定必须具有某个请求参数,且值必须等于或不等于给定值
格式3:以"!名称"的方式指定必须不包含指定名称的请求参数
@RequestMapping(value="/test04.html",params= {"name","gender=male","!age","addr!=bj"})
String[] headers() default {};
用来限定当前请求中必须包含指定名称的请求头才会被当前处理器处理
格式1:只指定名称,要求必须具有该名称的请求头
格式2:以"名称=值"或"名称!=值"的方式指定必须具有某个请求头,且值必须等于或不等于给定值
格式3:以"!名称"的方式指定必须不包含指定名称的请求头
@RequestMapping(value="/test05.html",headers= {"host=localhost"})
3.2 @RequestParam注解属性
@RequestParam(value="age",required=true,defaultValue=25) Integer Age
3.3 处理复杂类型
如果自动封装的bean中存在复杂类型,只要该复杂类型的属性同样具有setXxx方法,则可以在请求参数中包含[bean中复杂类型].[属性]的方式为该复杂类型的参数复制,从而实现自动封装bean的过程中处理其中的复杂类型。
3.4 请求参数中存在多个同名参数
<tr>
<td>爱好</td>
<td>
<input type="checkbox" name="like" value="zq"/>足球
<input type="checkbox" name="like" value="lq"/>篮球
<input type="checkbox" name="like" value="pq"/>排球
<input type="checkbox" name="like" value="qq"/>铅球
</td>
</tr>
此时直接获取,会得到一个用逗号分隔的字符串
@RequestMapping("/hello.html")
public String hello(String like,Model model){
System.out.println(Arrays.toString(like));
model.addAttribute("msg","hello,world");
return "hello";
}
得到
lq,pq,qq
也可以修改Controller方法的形参为数组类型,则直接接收到一个数组
@RequestMapping("/hello.html")
public String hello(String[] like,Model model){
System.out.println(Arrays.toString(like));
model.addAttribute("msg","hello,world");
return "hello";
}
得到
[lq,pq,qq]
3.5 请求参数中的中文乱码
<!-- 配置SpringMVC乱码解决过滤器 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-value>encoding</param-value>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*<url-pattern>
</filter-mapping>
这种方式只能解决POST提交的乱码,对GET方式提交的乱码无效!
GET方式提交的乱码只能进行手动编解码解决
username=new String(username.getByte("ISO8859-1"),"utf-8");
3.6 日期数据的处理
在SpringMVC中解析页面提交的请求参数时,无法自动获取封装日期到Data。
如果想要实现自动封装,必须手动注册适配器自己来指定转换方式。
@InitBinder
public void InitBinder(ServletRequestDataBinder binder){
binder.registerCustomEditor(Date.class,new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));
}
3.7 SpringMVC文件上传
(1)准备文件上传表单
文件上传表单必须满足如下三个条件
a.文件上传项必须有name属性
b.表单必须是Post提交
c.表单必须是enctype=“multipart/form-data”
<form action="${pageContex.request.contextPath}/hello.html" method="POST" enctype="multipart/form-data">
<tr>
<td>文件</td>
<td><input type="file" name="fx"/></td>
</tr>
(2)在配置文件中配置文件上传工具
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultiPartResolver">
<property name="maxUploadSize" value="1024"></property>
</bean>
(3)在Controller中实现文件上传
@RequestMapping("/hello.html")
public String upload(MultipartFile fx,Model model) throws IOException {
System.out.println(fx.getOriginalFilename());
FileUtils.writeByteArrayToFile(new File("d:\\"+fx.getOriginalFilename()),fx.getBytes());
return "hello";
}
3.8 SpringMVC中的资源跳转
//传统方式,请求转发和重定向
request.getRequestDispatcher("/index.jsp").forward(request,response);
response.sendRedirect(request.getContextPath()+"/index.jsp");
//SpringMVC方式,请求转发和重定向
return "forward:/index.jsp";
return "redirect:/index.jsp";
SpringMVC中没有提供实现定时刷新的便捷方式,只能用传统方式实现定时刷新
response.setHeader("refresh","3;url="+request.getContextPath()+"/index.jsp");
3.9 @ModelAttribute
(1)使用在方法上
则被修饰的方法将会在当前类的任意handler方法执行之前执行,该方法返回的返回值会自动存入model供后续使用
@ModelAttribute("uname")
public String method1(){
return "yyy";
}
(2)使用在方法参数之前
则会从model中获取属性值赋值到被修饰的方法参数上
@RequestMapping("test01.html)
public void test01(@ModelAttribute("uname")String uname){
System.out.println(uname);
}