SpringMVC学习
1. 简介
spring-webmvc-4.1.6.RELEASE
1.1. 重要组件
DispatcherServlet 前端控制器,接收所有请求,不包含jsp
HandlerMapping 解析请求格式,判断希望执行那个具体方法
HandlerAdapter 负责调用具体方法
ViewResovler 视图解析器,准备跳转到具体的物理视图

1.2. 原理
web.xml中设置DispatcherServlet的url-pattern为/时,当用户发起请求,请求一个控制器,首先执行HandlerMapping,由DispatcherServlet调用HandlerMapping的实现类DefaultAnntationHandlerMapping解析URL,解析后调用HandlerAdapter组件的实现类AnnotationMethodHandlerAdapter调用Controller的HandlerMethod,当HandlerMethod执行完成后会返回View,被ModelAndView进行视图解析,解析后调用jsp对象的class文件并运行,最终将class文件的响应给客户端
2. 环境搭建
2.1. web.xml
配置DispatcherServlet前端控制器
url-pattern – 拦截除jsp以外所有映射
contextConfigLocation 加载 mvc配置文件springmvc.xml
不指定xml 会默认寻找[servlet-name]-serlvet.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <servlet> <servlet-name>dispatcherServlet</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> <load-on-startup>1</load-on-startup> </servlet>
<servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
|
2.2. springmvc.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <bean id="demo1" class="com.runaccpeted.controller.UserController"/>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="urlMap"> <map> <entry key="demo" value-ref="demo1"/> </map> </property> </bean>
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="./"></property> <property name="suffix" value=".jsp"></property> </bean>
|
2.3. UserController
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package com.runaccpeted.controller;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.Controller;
public class UserController implements Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { ModelAndView view = new ModelAndView("main"); return view; } }
|
3. Spring – SpringMVC
3.1. DispatcherServlet
结构

所有组件
1 2 3 4 5 6 7 8 9 10 11
| protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); }
|
doService
1 2 3
| protected void doService(HttpServletRequest request, HttpServletResponse response)throws Exception{ doDispatch(request, response); }
|
doDispatch
1 2 3 4 5 6 7 8 9 10 11 12 13
| protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; ModelAndView mv = null; processedRequest = checkMultipart(request); mappedHandler = getHandler(processedRequest); HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); }
|
3.2. 父类FrameworkServlet

spring 为springmvc的父容器
springmvc能调用spring的内容
HttpServletBean
1 2 3 4
| @Override public final void init() throws ServletException { initServletBean(); }
|
3.3. SimpleControllerHandlerAdapter
1 2 3 4 5
| public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return ((Controller) handler).handleRequest(request, response); }
|
3.4. SimpleUrlHandlerMapping
1 2 3 4 5 6 7 8 9 10 11
| protected void registerHandlers(Map<String, Object> urlMap) throws BeansException { urlMap.forEach((url, handler) -> { if (!url.startsWith("/")) { url = "/" + url; } if (handler instanceof String) { handler = ((String) handler).trim(); } registerHandler(url, handler); }); }
|
4. 注解方式
mvc:annotation-driven 自动配置了HandlerMapping和HandlerAdapter
1 2 3 4 5 6 7 8 9 10 11 12 13
| <beans xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation=" http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <context:component-scan base-package="com.runaccpeted.controller"/> <mvc:annotation-driven/> </beans>
|
4.1. @Controller 单例控制器
4.2. @RequestMapping(“/url”) 映射路径
无论方法返回值是什么,都进行跳转
1 2 3 4 5 6 7 8 9 10 11 12 13
| package com.runaccpeted.controller;
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping;
@Controller public class LoginController { @RequestMapping("/demo") public String demo(){ return "/main.jsp"; } }
|
5. 放行静态资源
1 2 3 4
| <mvc:resources location="/js/" mapping="/js/**"></mvc:resources> <mvc:resources location="/css/" mapping="/css/**"></mvc:resources> <mvc:resources location="/images/" mapping="/images/**"></mvc:resources> <mvc:resources location="/files/" mapping="/files/**"></mvc:resources>
|
http://localhost:8080/Spring9.28/js/jquery.min.js
mapping 虚拟路径 /js/* js下所有资源* js下所有子文件
location 实地址 /js/ 在与WEB-INF同级文件下

6. 字节编码过滤器
1 2 3 4 5 6 7 8 9 10 11 12 13
| <filter> <filter-name>encoding</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>utf-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encoding</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
|
7. 传参
参数放在方法参数中,所有参数都可以被赋值
7.1. 对象
1 2 3 4 5 6
| public class User { private int id; private String username; private String password; }
|
传入的参数name为对象成员变量名,必须有get/set方法
1 2 3 4 5
| <form action="./demo" method="get"> <input type="text" name="username" id="name"/> <input type="password" name="password" id="pwd"/> <input type="submit" value="提交"/> </form>
|
Controller
1 2 3 4 5 6
| @RequestMapping("/demo") public String demo(User user,HttpServletRequest request,HttpServletResponse response){ System.out.println(user); return "/main.jsp"; }
|
7.2. 参数不匹配@RequestParam
value=”” 指定传入的参数
defaultValue=”” 指定默认值
required=true 必须有该参数值 == 表列 not null
1 2 3 4 5 6 7
| import org.springframework.web.bind.annotation.RequestParam;
@RequestMapping("/demo") public String demo(@RequestParam(value="username")String name,@RequestParam(value="password")String pwd,HttpServletRequest request,HttpServletResponse response){ System.out.println(name+" "+pwd); return "/main.jsp"; }
|
7.3. list参数-多选参数
1
| public String demo(@RequestParam("fav") List<String> list){}
|
7.4. 类中对象.属性作为参数
1
| <input type="text" name="peo.name"/>
|
java中.表示调用
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class User{ private People peo; }
public class People{ private String name; }
@RequestMapping("/demo") public String demo(User user){ System.out.println(user); return "/main.jsp"; }
|
7.5. @PathVariable
1 2 3 4 5
| @RequestMapping("/demo/{id}/{name}") public String demo(@PathVariable String id,@PathVariable String name){ System.out.println(id+" "+name); return "/main.jsp"; }
|
7.6. HashMap传值
1 2 3 4 5
| @RequestMapping("demo2") public String test2(HashMap<String,String> map){ map.put("m","map传值"); return "/main.jsp"; }
|
作用域在request
7.7. Model传值
1 2 3 4 5
| @RequestMapping("demo3") public String test3(Model model){ model.addAttribute("model", "model传值"); return "/main.jsp"; }
|
作用域在request
7.8. ModelAndView传值
1 2 3 4 5 6 7
| @RequestMapping("demo4") public ModelAndView test4(){ ModelAndView view = new ModelAndView("/main.jsp"); view.addObject("view", "view"); return view; }
|
作用域在request
8. 跳转方式
默认为请求转发
写在return的string语句中
1 2 3
| return "redirect:/main.jsp";
return "/main.jsp";
|
9. 自定义视图解析器
1 2 3 4
| <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/"></property> <property name="suffix" value=".jsp"></property> </bean>
|
添加跳转方式后自定义视图解析器无效,调用默认解析器
1 2
| return "redirect:main"; return "forward:main";
|
10. @ResponseBody
返回值满足key-value形式 将数据转为json 以流的形式输出
响应标头 Content-Type: application/json;charset=UTF-8
1 2 3 4 5 6 7 8 9
| @RequestMapping("demo1") @ResponseBody public User test(){ User user = new User(); user.setId(1); user.setUsername("abc"); user.setPassword("123"); return user; }
|
转不成json,以文本输出
响应标头 Content-Type: text/html 无法解决中英文乱码
1 2 3 4 5
| @RequestMapping("demo1") @ResponseBody public String test(){ return "Hello"; }
|
设置响应头
1 2
| @RequestMapping(value="demo1",produces="text/html;charset=utf-8") @ResponseBody
|
11. 文件下载
1
| <a href="download?fileName=a.jpg"></a>
|
commons-fileupload-1.3.1
commons-io-2.2
设置响应流文件进行下载
response.setHeader(“Content-Disposition”,”attachment;filename=”+file);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @RequestMapping("/download") public void demo(String file,HttpServletRequest request,HttpServletResponse response){ response.setHeader("Content-Disposition", "attachment;filename="+file); try { ServletOutputStream os = response.getOutputStream(); String path=request.getServletContext().getRealPath("files"); File f = new File(path,file);
byte[] bytes = FileUtils.readFileToByteArray(f); os.write(bytes); os.flush(); os.close(); } catch (IOException e) { e.printStackTrace(); } }
|
12. 文件上传
12.1. 前端
form设置enctype为multipart/form-data,以流形式输出
1 2 3 4
| <form action="./upload" enctype="multipart/form-data" method="post"> <input type="file" name="file"> <input type="submit" value="下载"> </form>
|
12.2. 文件视图解析器
id是必须要的,图片大小小于10kB
1 2 3
| <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <property name="MaxUploadSize" value="10240"></property> </bean>
|
12.3. 控制器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @RequestMapping("upload") public String upload(MultipartFile file,HttpServletRequest request){ String path=request.getServletContext().getRealPath("files"); String fileName = file.getOriginalFilename(); String suffix=fileName.substring(fileName.lastIndexOf(".")); String name=UUID.randomUUID().toString(); System.out.println(path+"/"+name+suffix); try { FileUtils.copyInputStreamToFile(file.getInputStream(), new File(path,name+suffix)); } catch (IOException e) { e.printStackTrace(); } return "/main.jsp"; }
|
12.4. 异常视图
可用于处理服务器异常
1 2 3 4 5 6 7
| <bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="org.springframework.web.multipart.MaxUploadSizeExceededException">error</prop> </props> </property> </bean>
|
error.jsp
1 2 3 4 5 6 7 8 9 10 11 12
| <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Images error</title> </head> <body> Maximum upload size of 10240 bytes exceeded; </body> </html>
|
13. 拦截器-针对控制器
发送请求时被拦截器拦截,在控制器前后添加额外功能
仅针对控制器,只拦截控制器
13.1. implements HandlerInterceptor
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| package com.runaccpeted.interceptor;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView;
import com.sun.istack.internal.logging.Logger;
public class DemoInterceptor implements HandlerInterceptor { public boolean preHandle(HttpServletRequest request , HttpServletResponse response, Object object) throws Exception { return true; }
public void postHandle(HttpServletRequest request, HttpServletResponse response , Object obj, ModelAndView view) throws Exception { String viewName=view.getViewName(); String value=view.getModel().get("key").toString(); value.replace("国家", "**"); view.getModel().put("key", value);
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object, Exception exception) throws Exception { Logger logger = Logger.getLogger(DemoInterceptor.class); logger.info(exception.getMessage());
} }
|
13.2. 注册拦截器
mvc:interceptor 拦截一些控制器
1 2 3 4 5 6
| <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/demo"/> <bean class="com.runaccpeted.interceptor.DemoInterceptor"></bean> </mvc:interceptor> </mvc:interceptors>
|
拦截所有控制器
1 2 3
| <mvc:interceptors> <bean class="com.runaccpeted.interceptor.DemoInterceptor"></bean> </mvc:interceptors>
|
13.3. 拦截器栈
执行顺序和springmvc.xml中配置顺序有关
1 2 3 4
| <mvc:interceptors> <bean class="com.runaccpeted.interceptor.DemoInterceptor1"></bean> <bean class="com.runaccpeted.interceptor.DemoInterceptor2"></bean> </mvc:interceptors>
|
preHandler1 –> preHandler2 -> controller –> postHandler2 –> postHandler1 –> jsp –> afterCompletion2 –> afterCompletion1
14. 登陆验证
DispatcherServlet放行jsp ,为了保证jsp不被放行
jsp放在WEB-INF –> pages下
控制器
1 2 3 4
| @RequestMapping("{page}") public String page(@PathVariable String page){ return "/WEB-INF/pages/"+page+".jsp"; }
|
需要视图解析器配置前后缀
1 2 3 4
| <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/pages/"></property> <property name="suffix" value=".jsp"></property> </bean>
|
优先匹配最适合的
1 2 3 4 5 6 7 8 9 10
| @RequestMapping("login") public String login(@RequestParam("username")String uname,@RequestParam("password")String pwd,HttpServletRequest request){ User user=service.selByNamePwd(uname,pwd); if(user!=null){ request.getSession.setAttribute("user",user); return "main"; }else{ return "redirect:/login.jsp"; } }
|
拦截器拦截所有
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| package com.runaccpeted.interceptor;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView;
import com.sun.istack.internal.logging.Logger;
public class DemoInterceptor implements HandlerInterceptor { public boolean preHandle(HttpServletRequest request , HttpServletResponse response, Object object) throws Exception { if(request.geturi().endWith("login")){ return true; }else{ if(request.getSession().getAttribute("user")!=null){ return true; }else{ response.sendRedirect("./login.jsp"); return false; } } return false; } }
|
拦截器
1 2 3
| <mvc:interceptors> <bean class="com.runaccpeted.interceptor.DemoInterceptor"></bean> </mvc:interceptors>
|