一、SpringMVC简介
springmvc是spring框架的一个模块,springmvc和spring无需通过中间整合层进行整合。
1. 重要组件:
1.1 DispatcherServlet(不需要程序员开发):前端控制器,接收所有的请求,响应结果,相当于转发器,中央处理器。
1.2 HandlerMapping(不需要程序员开发):处理器映射器,解析请求的url,并查找对应的Handler
1.3 HandlerAdapter:处理器适配器,按照特定规则去执行Handler
1.4 Handler(需要程序员开发):处理器。在编写Handler时,按照HandlerAdapter的要求去做,这样适配器才可以去正确执行Handler
1.5 ViewResovler(不需要程序员开发):视图解析器.解析结果,准备跳转到具体的物理视图
1.6 View(需要程序员开发jsp):视图。View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf...)
2. Spring 容器和 SpringMVC 容器的关系
2.1 Spring 容器和 SpringMVC 容器是父子容器
2.2 SpringMVC 容器中能够调用 Spring 容器的所有内容
二、SpringMVC环境搭建
1. 导入jar包:spring-webmvc
2. 在web.xml中配置前端控制器DispatcherServlet
<servlet> <servlet-name>springmvc</servlet-name> <!-- 在spring-webmvc的jar包下 --> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 修改配置文件路径和名称,在没有指定这一项时,默认会去WEB-INF文件夹下面寻找 --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <!-- 自启动,没配置的时候,servlet只有第一次访问的时候才会被加载 --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <!-- 拦截除了jsp文件外的所有请求 --> <url-pattern>/</url-pattern> </servlet-mapping> |
3. 在src下新建springmvc.xml
3.1 注意导入新的命名空间
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 扫描注解 --> <context:component-scan base-package="com.sen.controller"></context:component-scan>
<!-- 注解驱动 --> <!-- 相当于配置了org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping --> <!-- 相当于配置了org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter --> <mvc:annotation-driven></mvc:annotation-driven>
<!-- 告诉springmvc谁是静态资源,否则它会被拦截 --> <mvc:resources location="/js/" mapping="/js/**"></mvc:resources> <mvc:resources location="/css/" mapping="/css/**"></mvc:resources> <mvc:resources location="/img/" mapping="/img/**"></mvc:resources> <!-- mapping属性:匹配请求时的url /img/*:在img文件夹下的所有的子文件 /img/**:该文件夹下所有的子文件及子文件夹下的所有子文件,一般情况下配2个* location属性:静态资源的位置 --> </beans> |
3.2 编写controller
@Controller public class DemoController{ //由于该类为spring创建,为单例,因此尽量不要在该类使用类变量、成员变量等,否则会造成线程不安全问题 //service除外 @RequestMapping("demo") //由index.jsp的form表单提交来的参数(需要和属性名同名),springmvc自动转型 public String demo(@RequestParam(value="name1")String name,@RequestParam(value="age1")int age) { System.out.println("执行demo"+name+" "+age); return "/main.jsp"; } @RequestMapping("demo2") //如果类型不匹配,则网页错误码为400 public String demo2(People peo,String name,int age,HttpServletRequest req,HttpSession session) { System.out.println("demo2对象"+peo); //相同名称的参数也会被赋值 System.out.println("demo2参数"+name+":"+age); req.setAttribute("demo234","测试HttpServletRequest"); //由此可知,原生servlet中的对象都是可用的 return "/main1.jsp"; }
@RequestMapping("page") public String page(@RequestParam(defaultValue = "2")int pageSize,@RequestParam(defaultValue = "1")int pageNumber) { return "/main.jsp"; }
@RequestMapping("demo3") public String demo3(@RequestParam(required = true)String name) { System.out.println("name是SQL的查询条件,必须要传递name参数"+name); return "/main.jsp"; }
@RequestMapping("demo4") public String demo4(String name,int age,@RequestParam("hover")List<String> hover) { System.out.println(name+":"+age+":"+hover); return "/main.jsp"; }
@RequestMapping("demo5") public String demo5(Demo demo) { System.out.println(demo); return "/main.jsp"; }
@RequestMapping("demo6") public String demo6(String name,int age) { System.out.println(name+":"+age); return "/main.jsp"; }
@RequestMapping("demo7/{id1}/{name1}") public String demo7(@PathVariable(value="name1")String name,@PathVariable("id1")int age) { System.out.println(name+":"+age); return "/main.jsp"; } @RequestMapping("demo8") public String demo8() { System.out.println("默认情况下,返回的字符串是请求转发"); // return "/main.jsp"; //请求转发 // return "forward:/main.jsp"; //重定向 return "redirect:/main.jsp"; }
@RequestMapping("demo9") public String demo9() { System.out.println("默认情况下,返回的字符串是请求转发"); //不加forward:会走自定义视图解析器,加了后会不走自定义视图解析器 return "forward:main.jsp"; }
@RequestMapping(value="demo10",produces ="text/html;charset=utf-8") //把返回值转换成JSON字符串,同时设置响应头为application/JSON //不加的话,返回值都是跳转 @ResponseBody public People demo10(HttpServletResponse resp) { People p = new People(); p.setAge(12); p.setName("小明"); return p; } /** * 传参: * 1.把内容写到方法(HandlerMethod)参数中,SpringMVC只要有这个内容,就会注入 * 2.基本数据类型,默认只要保证参数名和请求中传递的参数名相同 * 3.当请求参数名和方法参数名不对应时,使用 * @RequestParam("") * value:匹配页面传递过来的参数名 * defaultValue:如果页面没有传值,则给默认值 * required:若为true,则必须要传参数,没有参数就报异常 * 注意:required和defaultValue不要一起用。 * 4.HandlerMethod中参数是对象类型,则只需要请求参数名和对象属性名对应(get/set方法) * 如果对象内属性名和请求参数名不同,没有注解可用 * 5.如果请求参数包含多个同名参数的方式,例如复选框。用@RequestParam("") * 6.如果请求参数为peo.name这种格式的,需要新建一个类,内有一属性名为peo(与请求参数名对应) * 7.如果请求参数为peo2[0].name(集合对象类型)这种格式,新建类,含有一属性为peo2集合 * 8.restful传值方式: * @RequestMapping("demo7/{id1}/{name1}") * 在jsp中设定特定的格式,在控制器中编写代码 * @PathVariable(value="name1") * 获取@RequestMapping中的内容,默认按照参数名去寻找 */ } |
4. 注解@ResponseBody
4.1 若方法只有@RequestMapping,则无论返回值是什么,都进行跳转
4.2 添加该注解后不会再进行跳转
4.3 如果返回值满足key-value形式(对象或map)
4.3.1 把响应头设置为 application/json;charset=utf-8
4.3.2 把转换后的内容输出流的形式响应给客户端
4.4 如果返回值不满足 key-value,例如返回值为 String
4.4.1把相应头设置为 text/html,将返回值以流的形式直接输出
4.4.2 如果返回值包含中文,出现中文乱码,则需要添加produces(表示响应头中的Content-Type值)
@RequestMapping(value="demo10",produces ="text/html;charset=utf-8") |
三、字符编码过滤器
1. 作用:将所有的请求和响应加上字符编码格式
2. web.xml下配置
<!-- 字符编码过滤器 --> <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> |
四、视图解析器
1. springMVC有默认的视图解析器
2. 程序员自定义的视图解析器
注意:如果不希望执行自定义视图解析器,可以在controller中的方法返回值前面添加forward:或redirect:
<!-- 自定义视图解析器 --> <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 前缀 --> <property name="prefix" value="/"></property> <!-- 后缀 --> <property name="suffix" value="jsp"></property> </bean> |
五、SpringMVC的作用域传值
1. 使用原生的servlet进行传值,在Hanlder的方法的参数中直接添加作用域对象
@RequestMapping("demo1") public String demo1(HttpServletRequest req,HttpSession sessionParam) { //request的作用域 req.setAttribute("req","req的值"); //session HttpSession session = req.getSession(); session.setAttribute("session", "session的值"); sessionParam.setAttribute("sessionParam","sessionParam的值"); //application ServletContext application = req.getServletContext(); application.setAttribute("application", "application的值"); return "/index.jsp"; } |
2. 使用Map集合
把map中的内容放入request作用域中,spring会对 map 集合通过BindingAwareModelMap进行实例化
@RequestMapping("demo3") public String demo3(Map<String,Object> map) { map.put("map","map的值"); return "/index.jsp"; } |
3. 使用SpringMVC的model接口
//使用SpringMVC中的Model接口 //最终还是把内容放入request中 @RequestMapping("demo4") public String demo4(Model model) { model.addAttribute("model", "就是model"); return "/index.jsp"; } |
4. 使用SpringMVC的ModelAndView类
//使用ModelAndView类 @RequestMapping("demo5") public ModelAndView demo5() { ModelAndView mav = new ModelAndView("/index.jsp"); mav.addObject("mav", "mav的值"); return mav; } |
六、SpringMVC的自定义拦截器Interceptor
1. 概念:Interceptor和过滤器Filter相似,但是有区别。Interceptor只能拦截控制器Controller,而Filter可以拦截任何请求
2. 作用:发送请求的时被拦截器拦截,在控制器的前后添加额外功能。
2.1 注意和AOP区分开来,AOP是对特定方法的前后进行扩充(即对ServiceImpl),而拦截器是针对控制器进行扩充(Controller)
3. 实现自定义拦截器Interceptor
3.1 新建一个类,实现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 { //传值和视图功能ModelAndView System.out.println("view:"+arg3.getView()); System.out.println("model的值"+arg3.getModel().get("model")); //能修改model的值 arg3.getModel().put("model", "修改后的值"); System.out.println("postHandle"); } //jsp执行完成之后执行,无论是否出现异常,该方法会执行 //记录在执行过程中出现的异常,可以存在日志中 @Override public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception { //通过arg3是否为null来判断是否出现异常 if(arg3!=null) { System.out.println("出现异常"); } System.out.println("afterCompletion"); } } |
3.2 在springmvc.xml配置拦截器
<!-- 第一种配置办法,直接配置bean标签.表示所有控制器全部拦截 --> <mvc:interceptors> <bean class="com.sen.interceptor.DemoInterceptor"></bean> </mvc:interceptors> <!-- 第二种配置方法,拦截demo1、demo2 --> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/demo1"/> <mvc:mapping path="/demo2"/> <bean class="com.sen.interceptor.DemoInterceptor"></bean> </mvc:interceptor> </mvc:interceptors> </beans> |