Spring MVC------->version4.3.6-------->知识点------>实现Controller(编程思路)

          Spring MVC:    Controller

Controller—— annotation-based programming 

基本知识点:

    • @Controller,@RequestMapping,@PathVariable, @RequestParam,@ModelAttribute, and so on.
    • @Controller注解
      • The @Controller annotation indicates that a particular class serves the role of a controller 
      • spring MVC会通过DispatcherServlet来查找@Controller标注的类,并且在这样的类中查找匹配的@RequestMapping注解,之后将请求交给对应的handler处理
      • 但是,要想DispatcherServlet能够识别@Controller这个标注,还需要先添加一些配置才行。需要配置Spring-context对应的配置文件,使得Spring的ApplicationContext自动去扫描明确配置的包,识别@Controller之类的注解,并且将扫描识别到的Controller类实例化所得beans注册到 the dispatcher’s context.(具体配置方法参见本文“”编程思路“”部分的step3) 
    • @RequestMapping注解
      • 该注解可以放在整个类上,也可以放在类的成员方法上
      • the class-level annotation maps a specific request path (or path pattern) onto a form controller
      • additional method-level annotations narrowing the primary mapping for a specific HTTP method request method ("GET", "POST", etc.)or an HTTP request parameter condition.
      • HTTP request有多种提交方式,如GET/POST/PUT/DELETE等等,method-level @RequestMapping可以指定某个成员方法只接收并处理某种提交方式提交的HTPP请求,有两种方法实现这种限制:
        • 方法一,使用@RequestMapping及其参数来实现这种限制,如
          @RequestMapping(method = RequestMethod.GET)
          .....Controller类中的一个成员函数...

          方法二,直接使用@RequestMapping的变种注解Controller类中的某个method,语法如下

        • @GetMapping
          ...controller类中的某个成员函数...

          除了@GetMapping之外,@RequestMapping还有多个类似的变种,具体包括@GetMapping、@PostMapping、@PutMapping、@DeleteMapping、@PatchMapping

      • 关于@RequestMapping的用法示例,参见本文“”例程“”部分实例二,或者直接参见ReferenceDoc
      • @RequestMapping中配置的URL,其实就是一个字符串。URL中有许多需要注意的知识点
        • URL支持多种Pattern,如支持URI Template,还支持Ant-style Pattern URL
        • URI Template Pattern URL:实际上就是包含有{varName}的URL,例如:http://www.example.com/users/{userId}  contains the variable userId
        • Ant-pattern URL:例如/myPath/*.do
        • @RequestMapping中还支持URI Template和Ant-style的混用,如/owners/*/pets/{petId}
        • @RequestMapping的URL中还可以使用正则表达式来限定request URL的格式:
          • 语法:{varName:正则表达式},example1: 
            @RequestMapping("/spring-web/{symbolicName:[a-z-]+}-{version:\d\.\d\.\d}{extension:\.[a-z]+}")上述正则表达式将URL限定为如下格式: "/spring-web/spring-web-3.0.5.jar",并且将最后一部分拆分出三个variable,也就是说使用上述正则表达式实现了一个含有三个variable的URI Template
        • URL中支持占位符${...}
        • URL中支持后缀模式匹配,如/text1.*  匹配/text1.pdf也匹配/text1.doc
      • @MatrixVariable
        • URL中也支持Matrix Variables:可以在URL的任何一个片段中追加一个matrix,这个matrix含有多个var-value对儿
          • 默认情况下spring MVC的URL是不支持matrix variables的,如果想要在URL中使用matrix variables,必须先更改相应的配置:
            <?xml version="1.0" encoding="UTF-8"?>
            <beans xmlns="http://www.springframework.org/schema/beans"
                xmlns:mvc="http://www.springframework.org/schema/mvc"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                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">
            
                <mvc:annotation-driven enable-matrix-variables="true"/>
            
            </beans>
          • example1,        "/cars;color=red;year=2012"    matrix中含有var-value对儿,多个var-value之间用“;”分号分割
          • example2,      "color=red,green,blue"        matrix的一个var有多个value,一个var的多个value之间用“”,“”逗号分隔
                • or the variable name may be repeated "color=red;color=green;color=blue".  
          • // GET /pets/42;q=11;r=22
            
            @GetMapping("/pets/{petId}")
            public void findPet(@PathVariable String petId, @MatrixVariable int q) {
            
                // petId == 42
                // q == 11
            
            }

            Since all path segments may contain matrix variables,这种情况下需要指明你想用的matrix中的var是属于URI Template的哪个segment:

            // GET /owners/42;q=11/pets/21;q=22
            
            @GetMapping("/owners/{ownerId}/pets/{petId}")
            public void findPet(
                    @MatrixVariable(name="q", pathVar="ownerId") int q1,
                    @MatrixVariable(name="q", pathVar="petId") int q2) {
            
                // q1 == 11
                // q2 == 22
            
            }

            还可以定义matrix variable的required和defaultValue属性:

            // GET /pets/42
            
            @GetMapping("/pets/{petId}")
            public void findPet(@MatrixVariable(required=false, defaultValue="1") int q) {
            
                // q == 1
            
            }

             可以使用Map集合来接收URL中所有或者一部分matrix中的var

            // GET /owners/42;q=11;r=12/pets/21;q=22;s=23
            
            @GetMapping("/owners/{ownerId}/pets/{petId}")
            public void findPet(
                    @MatrixVariable MultiValueMap<String, String> matrixVars,
                    @MatrixVariable(pathVar="petId"") MultiValueMap<String, String> petMatrixVars) {
            
                // matrixVars: ["q" : [11,22], "r" : 12, "s" : 23]
                // petMatrixVars: ["q" : 11, "s" : 23]
            
            }
          • 其实关于URL中的matrix variables,还有很多语法知识,详情参见reference doc 的spring MVC模块的

            “22.3.2节中Matrix Variables部分”的内容

                
    • @PathVariable
      • URI Template Patterns
        • 上面已经讲述了@RequestMapping的意义以及用法,知道这个注解就是用于URL请求和handler进行匹配的,这个里面涉及到URL,那么URL中有一些知识点需要注意
        • 除了可以使用常量URL之外,@RequestMapping中还可以使用变量URL(变量URL又称作URI Template Patterns)  
        • URI Template Patterns:  
          •  里面含有使用{}括起来的variable,该variable的值是可变的
          • 例:the URI Template http://www.example.com/users/{userId} contains the variable userId
          • URI Template中的variable可以绑定到controller类的method的函数参数上:springMVC的controller类中可以使用@RequestMapping中URI Template的variable,只需要在Controller类相应method的函数参数上加上@PathVariable注解即可将URL中的variable绑定到controller类中某个method的函数参数上,如下面的例子
            //第一种写法:只有URI Template中variable的名称和函数参数的名称一致时,才可以省略@PathVariable括号中的内容
            @GetMapping("/owners/{ownerId}") public String findOwner(@PathVariable String ownerId, Model model) { Owner owner = ownerService.findOwner(ownerId); model.addAttribute("owner", owner); return "displayOwner"; }

            上面的程序将@GetMapping中URI Template中的变量ownerId绑定到了controller类的findOwner()函数的ownerId:String参数上了,所以controller类的findOwner()函数的函数体中就可以通过其函数参数来使用URI Template中的variable的值.除了上述程序中的写法,下面的写法也能完成上述程序的功能:

            //第二种写法:因为URI Template中variable的名称和函数参数的名称不一致,所以不可以省略@PathVariable括号中的内容
            @GetMapping("/owners/{ownerId}")
            public String findOwner(@PathVariable("ownerId") String theOwner, Model model) {
                // implementation omitted省略
            }

            这两种写法都是将URI Template中的variable绑定到controller中method的函数参数上,但是写法不同,第一种写法更简洁,但是只有controller成员函数参数名称和URI Template中variable的名称一致时,才可以使用第一种写法

          • URI Template中可以有多个variable,如下面的例子:
            @GetMapping("/owners/{ownerId}/pets/{petId}")
            public String findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
                Owner owner = ownerService.findOwner(ownerId);
                Pet pet = owner.getPet(petId);
                model.addAttribute("pet", pet);
                return "displayPet";
            }

            例二:

            @Controller
            @RequestMapping("/owners/{ownerId}")
            public class RelativePathUriTemplateController {
            
                @RequestMapping("/pets/{petId}")
                public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
                    // implementation omitted
                }
            
            }
          • 使用URI Template中的variable绑定到controller函数参数上时应该注意类型转换(URI Template中variable是string类型的,但是它想要绑定的controller的method的函数参数类型可以是int/float/Object/map等类型的,这时要注意类型转换):但是web application中,由URL传递而来的都是字符串,包括form中的参数也是先转变成string再附加至URL中,再传递给相应的controller,上面已经讲过,绑定到controller的某个method的URL是可变的,即可以使用URI Template绑定到controller的某个method上,且URI Template中的variable可以在controller的method中使用,只要将URI Template中的variable绑定到函数参数上即可。但是我们的controller的成员函数的参数类型可能不是string,而是其他基本类型如int、short、long,也可能是类对象类型,也可能是Map集合类型等等,spring framework可以将URL中string类型的variable自动转变成method中函数参数类型或者抛出TypeMismatchException,至于spring framework支持string类型到哪些类型的自动转换,以及如何将URI Template中string类型的variable变成其他method 参数类型,详情参见reference doc的 the section called “Method Parameters And Type Conversion” and the section called “Customizing WebDataBinder initialization”.
          • URI Template中可以加入正则表达式,用于限制request中相应variable的value的格式或者用于将URL中一部分内容拆分成若干个variable:
            • 语法是: {varName:regex}, 也即{变量名:正则表达式}  
            • example1,
              @RequestMapping("/spring-web/{symbolicName:[a-z-]+}-{version:\d\.\d\.\d}{extension:\.[a-z]+}")
              public void handle(@PathVariable String version, @PathVariable String extension) {
                  // ...
              }

              Consider the URL "/spring-web/spring-web-3.0.5.jar",最后一部分内容中包含三个variable,也相当于最后一部分内容通过正则表达式被拆分成三部分了

    •  

编程思路:

    • 概述:编写Controller类的时候,可以基于注解进行编程( 即 annotation-based programming)  
      • 基于@RequestMapping@RequestParam,@ModelAttribute, and so on.等注解进行编写Controller类
      • 使用基于注解的方式来编写Controller类有许多好处,具体包括:
        • annotion-based programming不需要继承特殊的类,也不需要实现特殊的接口,可以直接编写Controller类
        • 基于注解的方式下编写Controller类的时候,也不需要依赖 Servlet or Portlet APIs。
        • 综上所述:基于注解的方式下编写Controller类的时候,可以不用了解任何的API,只需要了解@RequestMapping@RequestParam,@ModelAttribute等注解的意思,就可以编写出一个有效的Controller供DispactherServletd调用
    • step1,决定以 annotation-based programming来编写Controller类
    • step2,了解并熟记基于注解方式编写Controller类所涉及的所有注解的意义及用法,包括@Controller、@RequestMapping等
    • step3,配置Spring配置文件,使得Spring-context的ApplicationContext能够识别@Controller之类的注解,并且扫描相应的程序包,将Controller实例化所得Beans注册到SpringMVC的DispatcherServlet的context中,从而处理相应请求
      • 在spring-context   的配置文件中添加如下配置
        <?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"
            xsi:schemaLocation="
                http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans.xsd
                http://www.springframework.org/schema/context
                http://www.springframework.org/schema/context/spring-context.xsd">
        
            <context:component-scan base-package="org.springframework.samples.petclinic.web"/>
            <!--上述配置,使得Spring的ApplicationContext能够扫描你的project中的org.springframework.samples.petclinic.web包中的所有java程序,并且识别@Controller之类的注解,并且将识别的Controller注册到DispatcherServlet的beans.xml中,使得DispatcherServlet能够识别这些Controller-->
        
         </beans>
    • step4,编写Controller类并且使用@Controller注释
    • step5,编写Controller类中的成员函数,并且在类以及method上添加@RequestMapping注解(或者@GetMapping、@PostMapping、@PutMapping、@DeleteMapping、@PatchMapping注解),同时,根据实际需要选择是否添加@PathVariable以及@MatrixVariable注解
    • step6,编写Controller类的成员函数:
        • 第一步,首先明确method所支持的函数参数类型、函数返回值类型等等     
            

例程:

    • GitHub上有一些web applications实例,including MvcShowcaseMvcAjaxMvcBasicPetClinicPetCare, and others. 
      • 上述实例的地址:  Available in the spring-projects Org on Github
      • 这些实例的Controller都是基于MVC注解方式编写的(即annotion-based programming)
    • 基于注解的Controller类,实例一  

    • @Controller
      public class HelloWorldController {
      
          @RequestMapping("/helloWorld")
          public String helloWorld(Model model) {
              model.addAttribute("message", "Hello World!");
              return "helloWorld";
          }
      }
    • 基于注解的Controller类,实例二:用于举例讲述@RequestMapping的用法
      @Controller
      @RequestMapping("/appointments")
      public class AppointmentsController {
      
          private final AppointmentBook appointmentBook;
      
          @Autowired
          public AppointmentsController(AppointmentBook appointmentBook) {
              this.appointmentBook = appointmentBook;
          }
      
          @RequestMapping(method = RequestMethod.GET)
          public Map<String, Appointment> get() {
              return appointmentBook.getAppointmentsForToday();
          }
      
          @RequestMapping(path = "/{day}", method = RequestMethod.GET)
          public Map<String, Appointment> getForDay(@PathVariable @DateTimeFormat(iso=ISO.DATE) Date day, Model model) {
              return appointmentBook.getAppointmentsForDay(day);
          }
      
          @RequestMapping(path = "/new", method = RequestMethod.GET)
          public AppointmentForm getNewForm() {
              return new AppointmentForm();
          }
      
          @RequestMapping(method = RequestMethod.POST)
          public String add(@Valid AppointmentForm appointment, BindingResult result) {
              if (result.hasErrors()) {
                  return "appointments/new";
              }
              appointmentBook.addAppointment(appointment);
              return "redirect:/appointments";
          }
      }

      In the above example, @RequestMapping is used in a number of places. The first usage is on the type (class) level, which indicates that all handler methods in this controller are relative to the /appointments path. The get() method has a further @RequestMapping refinement【细化】: it only accepts GET requests, meaning that an HTTP GET for /appointments invokes【调用】 this method. The add() has a similar refinement, and the getNewForm() combines the definition of HTTP method and path into one, so that GET requests for appointments/new are handled by that method.

      The getForDay() method shows another usage of @RequestMapping: URI templates. (See the section called “URI Template Patterns”).

    • 上述代码和下面的代码等价(下面的代码使用@RequestMapping的变种@GetMapping、@PostMapping、@PutMapping、@DeleteMapping、@PatchMapping等简化@RequestMapping注解
      @Controller
      @RequestMapping("/appointments")
      public class AppointmentsController {
      
          private final AppointmentBook appointmentBook;
      
          @Autowired
          public AppointmentsController(AppointmentBook appointmentBook) {
              this.appointmentBook = appointmentBook;
          }
      
          @GetMapping
          public Map<String, Appointment> get() {
              return appointmentBook.getAppointmentsForToday();
          }
      
          @GetMapping("/{day}")
          public Map<String, Appointment> getForDay(@PathVariable @DateTimeFormat(iso=ISO.DATE) Date day, Model model) {
              return appointmentBook.getAppointmentsForDay(day);
          }
      
          @GetMapping("/new")
          public AppointmentForm getNewForm() {
              return new AppointmentForm();
          }
      
          @PostMapping
          public String add(@Valid AppointmentForm appointment, BindingResult result) {
              if (result.hasErrors()) {
                  return "appointments/new";
              }
              appointmentBook.addAppointment(appointment);
              return "redirect:/appointments";
          }
      }
    • @RequestMapping on the class level is not required. Without it, all paths are simply absolute, and not relative. The following example from the PetClinic sample application shows a multi-action controller using @RequestMapping:

      @Controller
      public class ClinicController {
      
          private final Clinic clinic;
      
          @Autowired
          public ClinicController(Clinic clinic) {
              this.clinic = clinic;
          }
      
          @RequestMapping("/")
          public void welcomeHandler() {
          }
      
          @RequestMapping("/vets")
          public ModelMap vetsHandler() {
              return new ModelMap(this.clinic.getVets());
          }
      
      }

      The above example does not specify GET vs. PUTPOST, and so forth, because @RequestMapping maps all HTTP methods by default. Use@RequestMapping(method=GET) or @GetMapping to narrow the mapping.

        
学习的过程中总会得到一些心得体会,认真地将它们记录下来并分享给每一个愿意花费时间去阅读它们的人,然后意外地收获某个读者的评论,从而激发出新的感想,是一件十分令人欢快的事。如果你也在研习这方面的知识,欢迎加入到我们的队伍中来,和我们一起进步吧(^_^)
原文地址:https://www.cnblogs.com/lxrm/p/6491895.html