zoukankan      html  css  js  c++  java
  • SpringMVC

    一、SpringMVC的处理流程

    二、配置文件

      1、配置Springmvc.xml

    <?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:p="http://www.springframework.org/schema/p"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:mvc="http://www.springframework.org/schema/mvc"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
            http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    
        <!-- 配置controller扫描包 -->
        <context:component-scan base-package="cn.itcast.springmvc.controller" />
    
    </beans>

      2、配置web.xml

    <!-- 配置SpringMVC前端控制器 -->
        <servlet>
            <servlet-name>springmvc-first</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <!-- 指定SpringMVC配置文件 -->
            <!-- SpringMVC的配置文件的默认路径是/WEB-INF/${servlet-name}-servlet.xml -->
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>classpath:springmvc.xml</param-value>
            </init-param>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>springmvc-first</servlet-name>
            <!-- 设置所有以action结尾的请求进入SpringMVC -->
            <url-pattern>*.action</url-pattern>
        </servlet-mapping>
    </web-app>

     

    三、SpringMVC架构

    1、框架结构

    2、架构流程

    ① 用户发送请求至前端控制器DispatcherServlet

    ② DispatcherServlet收到请求调用HandlerMapping处理器映射器。

    ③ 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。

    ④ DispatcherServlet通过HandlerAdapter处理器适配器调用处理器

    ⑤ 执行处理器(Controller,也叫后端控制器)。

    ⑥ Controller执行完成返回ModelAndView

    ⑦ HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet

    ⑧ DispatcherServlet将ModelAndView传给ViewReslover视图解析器

    ⑨ ViewReslover解析后返回具体View

    ⑩ DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中),DispatcherServlet响应用户。

    3、组件说明

    ① DispatcherServlet:前端控制器

      用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。

    ② HandlerMapping:处理器映射器

      HandlerMapping负责根据用户请求url找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。

    ③ Handler:处理器

      Handler 是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。由于Handler涉及到具体的用户业务请求,所以一般情况需要程序员根据业务需求开发Handler。

    ④ HandlAdapter:处理器适配器

      通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。

    ⑤ ViewResolver:视图解析器

      View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。

    ⑥ View:视图

      springmvc框架提供了很多的View视图类型的支持,包括:jstlView、freemarkerView、pdfView等。我们最常用的视图就是jsp。

     

    说明:在springmvc的各个组件中,处理器映射器、处理器适配器、视图解析器称为springmvc的三大组件。需要用户开发的组件有handler、view

     

    4、组件扫描器

      使用组件扫描器省去在spring容器配置每个Controller类的繁琐。使用<context:component-scan>自动扫描标记@Controller的控制器类,在springmvc.xml配置文件中配置如下:

    <!-- 配置controller扫描包,多个包之间用,分隔 -->
    <context:component-scan base-package="cn.itcast.springmvc.controller" />

    5、注解映射器和适配器

      ① 配置处理器映射器

      注解式处理器映射器,对类中标记了@ResquestMapping的方法进行映射。根据@ResquestMapping定义的url匹配@ResquestMapping标记的方法,匹配成功返回HandlerMethod对象给前端控制器。HandlerMethod对象中封装url对应的方法Method。

      在springmvc.xml配置文件中配置如下:

    <!-- 配置处理器映射器 -->
    <bean  class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" />

      ② 配置处理器适配器

      注解式处理器适配器,对标记@ResquestMapping的方法进行适配。在springmvc.xml配置文件中配置如下:

    <!-- 配置处理器适配器 -->
    <bean  class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" />

      ③ 注解驱动

      直接配置处理器映射器和处理器适配器比较麻烦,可以使用注解驱动来加载。

      SpringMVC使用<mvc:annotation-driven>自动加载RequestMappingHandlerMapping和RequestMappingHandlerAdapter,可以在springmvc.xml配置文件中使用<mvc:annotation-driven>替代注解处理器和适配器的配置。

    <!-- 注解驱动 -->
    <mvc:annotation-driven />

    6、视图解析器

      视图解析器使用SpringMVC框架默认的InternalResourceViewResolver,这个视图解析器支持JSP视图解析。在springmvc.xml配置文件中配置如下:

    <!-- 配置视图解析器 -->
        <bean
            class="org.springframework.web.servlet.view.InternalResourceViewResolver">
            <!-- 配置逻辑视图的前缀 -->
            <property name="prefix" value="/WEB-INF/jsp/" />
            <!-- 配置逻辑视图的后缀 -->
            <property name="suffix" value=".jsp" />
        </bean>
    @Controller
    public class ItemController {
    
        // @RequestMapping:里面放的是请求的url,和用户请求的url进行匹配
        // action可以写也可以不写
        @RequestMapping("/itemList.action")
        public ModelAndView queryItemList() {
            // 创建页面需要显示的商品数据
            List<Item> list = new ArrayList<>();
            list.add(new Item(1, "1华为 荣耀8", 2399, new Date(), "质量好!1"));
            list.add(new Item(2, "2华为 荣耀8", 2399, new Date(), "质量好!2"));
            list.add(new Item(3, "3华为 荣耀8", 2399, new Date(), "质量好!3"));
            list.add(new Item(4, "4华为 荣耀8", 2399, new Date(), "质量好!4"));
            list.add(new Item(5, "5华为 荣耀8", 2399, new Date(), "质量好!5"));
            list.add(new Item(6, "6华为 荣耀8", 2399, new Date(), "质量好!6"));
    
            // 创建ModelAndView,用来存放数据和视图
            ModelAndView modelAndView = new ModelAndView();
            // 设置数据到模型中
            modelAndView.addObject("list", list);
            // 设置视图jsp,需要设置视图的物理地址
            modelAndView.setViewName("itemList");
    
            return modelAndView;
        }
    }

     7、默认支持的参数类型

       HttpServletRequest、HttpServletResponse、HttpSession

    8、Model和ModelMap

      除了ModelAndView以外,还可以使用Model来向页面传递数据,Model是一个接口,在参数里直接声明model即可。如果使用Model则可以不使用ModelAndView对象,Model对象可以向页面传递数据,View对象则可以使用String返回值替代。

      不管是Model还是ModelAndView,其本质都是使用Request对象向jsp传递数据。

      ModelMap是Model接口的实现类,也可以通过ModelMap向页面传递数据,使用Model和ModelMap的效果一样,如果直接使用Model,springmvc会实例化ModelMap。

      代码实现:

    @RequestMapping("/itemEdit")
    public String queryItemById(HttpServletRequest request, Model model) {
        // 从request中获取请求参数
        String strId = request.getParameter("id");
        Integer id = Integer.valueOf(strId);
    
        // 根据id查询商品数据
        Item item = this.itemService.queryItemById(id);
    
        // 把结果传递给页面
        // ModelAndView modelAndView = new ModelAndView();
        // 把商品数据放在模型中
        // modelAndView.addObject("item", item);
        // 设置逻辑视图
        // modelAndView.setViewName("itemEdit");
    
        // 把商品数据放在模型中
        model.addAttribute("item", item);
    
        return "itemEdit";
    }
    @RequestMapping("/itemEdit")
    public String queryItemById(HttpServletRequest request, ModelMap model) {
        // 从request中获取请求参数
        String strId = request.getParameter("id");
        Integer id = Integer.valueOf(strId);
    
        // 根据id查询商品数据
        Item item = this.itemService.queryItemById(id);
    
        // 把结果传递给页面
        // ModelAndView modelAndView = new ModelAndView();
        // 把商品数据放在模型中
        // modelAndView.addObject("item", item);
        // 设置逻辑视图
        // modelAndView.setViewName("itemEdit");
    
        // 把商品数据放在模型中
        model.addAttribute("item", item);
    
        return "itemEdit";
    }

    9、绑定简单类型

      ① 参数类型推荐使用包装数据类型,因为基础数据类型不可以为null

      ② @RequestParam常用于处理简单类型的绑定。value:参数名字,即入参的请求参数名字,如value=“itemId”表示请求的参数区中的名字为itemId的参数的值将传入。required:是否必须,默认是true

    10、绑定pojo类型

      注意:提交的表单中不要有日期类型的数据,否则会报400错误。如果想提交日期类型的数据需要用到后面的自定义参数绑定的内容。

    11、解决乱码问题

      ① post乱码

    <!-- 解决post乱码问题 -->
        <filter>
            <filter-name>encoding</filter-name>
            <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
            <!-- 设置编码参是UTF8 -->
            <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>

       ② get乱码

         方法一:

    //修改tomcat配置文件添加编码与工程编码一致,如下:
    <Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>

       方法二:

    //另外一种方法对参数进行重新编码:
    String userName new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8")
    //ISO8859-1是tomcat默认编码,需要将tomcat编码后的内容按utf-8编码

    12、自定义参数绑定

      由于日期数据有很多种格式,springmvc没办法把字符串转换成日期类型。所以需要自定义参数绑定。

        前端控制器接收到请求后,找到注解形式的处理器适配器,对RequestMapping标记的方法进行适配,并对方法中的形参进行参数绑定。可以在springmvc处理器适配器上自定义转换器Converter进行参数绑定。

        一般使用<mvc:annotation-driven/>注解驱动加载处理器适配器,可以在此标签上进行配置。

      ① 自定义Converter

    //Converter<S, T>
    //S:source,需要转换的源的类型
    //T:target,需要转换的目标类型
    public class DateConverter implements Converter<String, Date> {
    
        @Override
        public Date convert(String source) {
            try {
                // 把字符串转换为日期类型
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyy-MM-dd HH:mm:ss");
                Date date = simpleDateFormat.parse(source);
    
                return date;
            } catch (ParseException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            // 如果转换异常则返回空
            return null;
        }
    }

      ② 配置Converter

    <!-- 配置注解驱动 -->
    <!-- 如果配置此标签,可以不用配置... -->
    <mvc:annotation-driven conversion-service="conversionService" />
    
    <!-- 转换器配置 -->
    <bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="cn.itcast.springmvc.converter.DateConverter" />
            </set>
        </property>
    </bean>

     13、高级参数绑定

      ① 绑定数组:如删除页面选中的多个商品

    /**
     * 包装类型 绑定数组类型,可以使用两种方式,pojo的属性接收,和直接接收
     * 
     * @param queryVo
     * @return
     */
    @RequestMapping("queryItem")
    public String queryItem(QueryVo queryVo, Integer[] ids) {
    
        System.out.println(queryVo.getItem().getId());
        System.out.println(queryVo.getItem().getName());
    
        System.out.println(queryVo.getIds().length);
        System.out.println(ids.length);
    
        return "success";
    }

       ② 将表单的数据绑定到List :如商品数据的批量修改

    14、@RequestMapping

      ① 添加在方法上面:@RequestMapping(value="item")或@RequestMapping("/item"),value的值是数组,可以将多个url映射到同一个方法

    @RequestMapping(value = { "itemList", "itemListAll" })

      ② 添加在类上面:在class上添加@RequestMapping(url)指定通用请求前缀, 限制此类下的所有方法请求url必须以请求前缀开头,可以使用此方法对url进行分类管理

      ③ 请求方法限定:限定GET方法@RequestMapping(method = RequestMethod.GET);限定POST方法@RequestMapping(method = RequestMethod.POST);GET和POST都可以@RequestMapping(method = {RequestMethod.GET,RequestMethod.POST})

    15、Controller方法返回值

      ① 返回ModelAndView

      controller方法中定义ModelAndView对象并返回,对象中可添加model数据、指定view。

      ② 返回void

    request.getRequestDispatcher("/WEB-INF/jsp/success.jsp").forward(request, response);
    response.sendRedirect("/springmvc-web2/itemEdit.action");
    response.getWriter().print("{"abc":123}");

      ③ 返回字符串

    //指定逻辑视图名,经过视图解析器解析为jsp物理路径:/WEB-INF/jsp/itemList.jsp
    return "itemList";
    @RequestMapping("updateItem")
    public String updateItemById(Item item) {
        // 更新商品
        this.itemService.updateItemById(item);
    
        // 修改商品成功后,重定向到商品编辑页面
        // 重定向后浏览器地址栏变更为重定向的地址,
        // 重定向相当于执行了新的request和response,所以之前的请求参数都会丢失
        // 如果要指定请求参数,需要在重定向的url后面添加 ?itemId=1 这样的请求参数
        return "redirect:/itemEdit.action?itemId=" + item.getId();
    }
    @RequestMapping("updateItem")
    public String updateItemById(Item item) {
        // 更新商品
        this.itemService.updateItemById(item);
    
        // 修改商品成功后,继续执行另一个方法
        // 使用转发的方式实现。转发后浏览器地址栏还是原来的请求地址,
        // 转发并没有执行新的request和response,所以之前的请求参数都存在
        return "forward:/itemEdit.action";
    
    }
    //结果转发到editItem.action,request可以带过去
    return "forward: /itemEdit.action";

    16、异常处理器

      springmvc在处理请求过程中出现异常信息交由异常处理器进行处理,自定义异常处理器可以实现一个系统的异常处理逻辑。

      ① 异常处理思路

      系统中异常包括两类:预期异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。

           系统的dao、service、controller出现都通过throws Exception向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理,如下图:

      ② 自定义异常类 :如果controller、service、dao抛出此类异常说明是系统预期处理的异常信息。

    public class MyException extends Exception {
        // 异常信息
        private String message;
    
        public MyException() {
            super();
        }
    
        public MyException(String message) {
            super();
            this.message = message;
        }
    
        public String getMessage() {
            return message;
        }
    
        public void setMessage(String message) {
            this.message = message;
        }
    
    }

      ③ 自定义异常处理器

    public class CustomHandleException implements HandlerExceptionResolver {
    
        @Override
        public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
                Exception exception) {
            // 定义异常信息
            String msg;
    
            // 判断异常类型
            if (exception instanceof MyException) {
                // 如果是自定义异常,读取异常信息
                msg = exception.getMessage();
            } else {
                // 如果是运行时异常,则取错误堆栈,从堆栈中获取异常信息
                Writer out = new StringWriter();
                PrintWriter s = new PrintWriter(out);
                exception.printStackTrace(s);
                msg = out.toString();
    
            }
    
            // 把错误信息发给相关人员,邮件,短信等方式
            // TODO
    
            // 返回错误页面,给用户友好页面显示错误信息
            ModelAndView modelAndView = new ModelAndView();
            modelAndView.addObject("msg", msg);
            modelAndView.setViewName("error");
    
            return modelAndView;
        }
    }

      ④ 异常处理器配置:在springmvc.xml中添加:

    <!-- 配置全局异常处理器 -->
    <bean id="customHandleException"     class="cn.itcast.ssm.exception.CustomHandleException"/>

    17、json数据交互

       @RequestBody

      作用:@RequestBody注解用于读取http请求的内容(字符串),通过springmvc提供的HttpMessageConverter接口将读到的内容(json数据)转换为java对象并绑定到Controller方法的参数上。

      传统的请求参数:itemEdit.action?id=1&name=zhangsan&age=12

      现在的请求参数:使用POST请求,在请求体里面加入json数据

    {
    "id": 1,
    "name": "测试商品",
    "price": 99.9,
    "detail": "测试商品描述",
    "pic": "123456.jpg"
    }

      ② @ResponseBody

      作用:@ResponseBody注解用于将Controller的方法返回的对象,通过springmvc提供的HttpMessageConverter接口转换为指定格式的数据如:json,xml等,通过Response响应给客户端

    /**
     * 测试json的交互
     * @param item
     * @return
     */
    @RequestMapping("testJson")
    // @ResponseBody
    public @ResponseBody Item testJson(@RequestBody Item item) {
        return item;
    }

      ③ 配置json转换器 :如果不使用注解驱动<mvc:annotation-driven />,就需要给处理器适配器配置json转换器

      在springmvc.xml配置文件中,给处理器适配器加入json转换器:

    <!--处理器适配器 -->
        <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
            <property name="messageConverters">
            <list>
              <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
            </list>
            </property>
        </bean>

    18、RESTful支持

      Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。

      从url上获取商品id,步骤如下:

      1. 使用注解@RequestMapping("item/{id}")声明请求的url,{xxx}叫做占位符,请求的URL可以是“item /1”或“item/2”

         2、使用(@PathVariable() Integer id)获取url上的数据

    @RequestMapping("item/{id}")
    @ResponseBody
    public Item queryItemById(@PathVariable() Integer id) {
        Item item = this.itemService.queryItemById(id);
        return item;
    }

      如果@RequestMapping中表示为"item/{id}",id和形参名称一致,@PathVariable不用指定名称。如果不一致,例如"item/{ItemId}"则需要指定名称@PathVariable("itemId")。

      注意两个区别

      1. @PathVariable是获取url上数据的。@RequestParam获取请求参数的(包括post表单提交)

       2. 如果加上@ResponseBody注解,就不会走视图解析器,不会返回页面,目前返回的json数据。如果不加,就走视图解析器,返回页面

    19、拦截器

    public class HandlerInterceptor1 implements HandlerInterceptor {
        // controller执行后且视图返回后调用此方法
        // 这里可得到执行controller时的异常信息
        // 这里可记录操作日志
        @Override
        public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
                throws Exception {
            System.out.println("HandlerInterceptor1....afterCompletion");
        }
    
        // controller执行后但未返回视图前调用此方法
        // 这里可在返回用户前对模型数据进行加工处理,比如这里加入公用信息以便页面显示
        @Override
        public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
                throws Exception {
            System.out.println("HandlerInterceptor1....postHandle");
        }
    
        // Controller执行前调用此方法
        // 返回true表示继续执行,返回false中止执行
        // 这里可以加入登录校验、权限拦截等
        @Override
        public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
            System.out.println("HandlerInterceptor1....preHandle");
            // 设置为true,测试使用
            return true;
        }
    }

    应用:

    1、有一个登录页面,需要写一个Controller访问登录页面

    2、登录页面有一提交表单的动作。需要在Controller中处理。

    a)  判断用户名密码是否正确(在控制台打印)

    b)  如果正确,向session中写入用户信息(写入用户名username)

    c)  跳转到商品列表

    3、拦截器。

    a)  拦截用户请求,判断用户是否登录(登录请求不能拦截)

    b)  如果用户已经登录。放行

    c)  如果用户未登录,跳转到登录页面。

  • 相关阅读:
    C# 从需要登录的网站上抓取数据
    mysql
    Fiddler抓取https设置详解(图文)
    Handlebars块级Helpers
    SQL优化技巧
    MyBatis持久层框架使用总结
    网页刷新页面方法小结
    史上最全的程序猿面试资料
    ActiveMQ开发与简介
    Lex使用指南
  • 原文地址:https://www.cnblogs.com/a591378955/p/8442156.html
Copyright © 2011-2022 走看看