SpringMVC

作者: 抬头挺胸才算活着 | 来源:发表于2021-11-19 17:31 被阅读0次
    • Controller
      @RequestMapping定义了请求路径和方法之间的关联,方法可以非常灵活,没有特殊限制。MyController需要使用使用@Bean创建出来或者@ConponentScan出来。
    @Controller
    public class MyController {
        @RequestMapping(value = "/my-handler-path", method = RequestMethod.GET)
        public String myHandlerMethod(...) {
           .....
        }
    }
    
    • Model
      model由Spring传入
    @Controller
    public class MyMvcController {
        @RequestMapping(value = "/my-uri-path")
        public String prepareView(Model model) {
           model.addAttribute("msg", "msg-value");
            .....
        }
    }
    
    • View
      Generally speaking it's anything which implements org.springframework.web.servlet.View.

    • ViewResolver
      查找视图
      下面的配置会返回/WEB-INF/views/路径下,以jsp结尾的视图。

    @Configuration
    public class MyWebConfig {
    
        @Bean
        public ViewResolver viewResolver() {
            InternalResourceViewResolver viewResolver =
                          new InternalResourceViewResolver();
    
            viewResolver.setPrefix("/WEB-INF/views/");
            viewResolver.setSuffix(".jsp");
            return viewResolver;
        }
    }
    
    • DispatcherServlet
      DispatcherServlet负责将对应的请求转发给对应的Controller,然后根据用户返回的view的名字和model,用ViewResolver找到对应的view,然后视图将model的属性赋值到view中,返回给客户端。


      image
    • WebApplicationInitializer
      WebApplicationInitializer一般初始化DispatcherServlet和AnnotationConfigWebApplicationContext

    • AnnotationConfigWebApplicationContext
      AnnotationConfigWebApplicationContext除了有Spring的容器管理外,还有javax.servlet.ServletContext的实例

    • @EnableWebMvc
      记得我们之前学Spring的时候有学到@Import可以引入其他的配置,@EnableWebMvc也是引入了WebMvcConfigurationSupport,该类提供了MVC的配置,该配置需要加载@Configuration注解的类上。
      @EnableWebMvc对应的XML配置为<mvc:annotation-driven/>

    @EnableWebMvc
    @Configuration
    public class MyWebConfig {
     .....
    }
    

    @EnableWebMvc的类引入了DelegatingWebMvcConfiguration,是WebMvcConfigurationSupport的子类。

    package org.springframework.web.servlet.config.annotation;
     ...
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    @Documented
    @Import(DelegatingWebMvcConfiguration.class)
    public @interface EnableWebMvc {
    }
    

    DelegatingWebMvcConfiguration在setConfigurers方法中注入了WebMvcConfigurer,因此我们如果有在配置类中定义这类实例,也会注入到在里面

    @Configuration
    public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
       .....
      @Autowired(required = false)
      public void setConfigurers(List<WebMvcConfigurer> configurers) {
        if (!CollectionUtils.isEmpty(configurers)) {
            this.configurers.addWebMvcConfigurers(configurers);
        }
      }
    }
    
    • 自定义MVC配置
      可以实现WebMcvConfigurer(5.0之后)/WebMvcConfigurerAdapter(5.0之前)的方法,WebMvcConfigurationSupport会在配置阶段回调这些方法。
      更高级的自定义配置需要重写WebMvcConfigurationSupport或者其子类的方法

    • WebMvcConfigurerAdapter如何引入新配置的?
      我们的配置类继承了WebMvcConfigurerAdapter,重写了addViewControllers方法。

    @EnableWebMvc
    @Configuration
    public class MyWebConfig extends WebMvcConfigurerAdapter {
      .....
       @Override
        public void addViewControllers (ViewControllerRegistry registry) {
            //our customization
        }
      ...
     }
    

    上面的配置类会被注入到DelegatingWebMvcConfiguration的configurers。

    @Configuration
    public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
       .....
      @Autowired(required = false)
      public void setConfigurers(List<WebMvcConfigurer> configurers) {
        if (!CollectionUtils.isEmpty(configurers)) {
            this.configurers.addWebMvcConfigurers(configurers);
        }
      }
    }
    

    在配置阶段DelegatingWebMvcConfiguration会调用addViewControllers进行配置类配置。

     @Configuration
    public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
        ...
        @Override
        protected void addViewControllers(ViewControllerRegistry registry) {
           this.configurers.addViewControllers(registry);
        }
        ...
    }
    
    • SpringServletContainerInitializer
      SpringServletContainerInitializer实现了ServletContainerInitializer,这意味着SpringServletContainerInitializer的onStartup会在servlet容器启动的时候执行。

    • WebApplicationInitializer
      SpringServletContainerInitializer上有注解@HandlesTypes(WebApplicationInitializer.class),这意味着SpringServletContainerInitializer的onStartup方法会执行WebApplicationInitializer类的所有onStartup方法。

    • DispatcherServlet.properties
      定义了DispatcherServlet默认使用的对象或者句柄,如果没有对应的对象或者句柄,会使用这里面的。

    • @RequestMapping
      @RequestMapping注解上标注了@Target(value={METHOD,TYPE}),因此可以用在方法或者类上。
      元素value可以是单个字符串或者多个字符串或者类似下面的路径参数,可以匹配/users/{userId}路径

     @RequestMapping("/users")
     @Controller
     public class UserController{
       @RequestMapping("/{userId}")
        public String handle(....){
         ....
        }
     }
    

    路径参数可以被捕获到方法的输入参数

        @RequestMapping("/{userId}")
        public void handle(@PathVariable("userId") String userId) {
                // ...
        }
    

    下面的用法中方法也要加上RequestMapping,不然会报404,@RequestMapping("")和@RequestMapping都会映射“/”路径。

     @Controller
     @RequestMapping("/users")
     public class UserController {
    
      @RequestMapping
      public String handleAllUsersRequest(){
            .....
      }
     }
    

    元素method可以是RequestMethod.GET、RequestMethod.DELETE
    元素params是链接问号后面的内容是否包含该元素
    元素headers是HTTP协议的头元素
    元素consumes是多媒体类型

    • URI Patterns模式匹配
      ? matches one character
    • matches zero or more characters
      ** matches zero or more directories in a path
    • @RequestParam
      问号之后的请求参数
      如果是map,则会包含全部的参数
      @RequestParam Map<String, String> queryMap

    • @RequestHeader
      用法类似于@PathVariable和@RequestParam,都可以在方法中获取参数,只不过这个参数是Header里面的。而且具有以下几种通用用法:
      1、参数名字相同的时候可以@RequestHeader可以省略参数
      2、使用Map提取所有的Header参数
      3、也可以使用@RequestHeader HttpHeaders httpHeaders提取所有的Header参数
      4、自动类型转换
      5、默认的元素required=true,也就是没有的时候会报400的错误
      6、不同的RequestHeader并不能作为多个路径对待,但在@RequestMapping中使用header可以

    • @RequestBody

    • 将参数(包括路径变量和请求参数)映射到变量的属性
      将请求参数映射到Trade trade变量
      /trades?buySell=buy&buyCurrency=EUR&sellCurrency=USD

     public class Trade {
    
        private String buySell;
        private String buyCurrency;
        private String sellCurrency;
    
        public String getBuySell () {
            return buySell;
        }
    
        public void setBuySell (String buySell) {
            this.buySell = buySell;
        }
    
       .................
    }
    
    @Controller
    @RequestMapping("trades")
    public class TradeController {
        @RequestMapping
        public String handleTradeRequest (Trade trade,
                                          Model map) {
            String msg = String.format(
                              "trade request. buySell: %s, buyCurrency: %s, sellCurrency: %s",
                               trade.getBuySell(), trade.getBuyCurrency(),
                               trade.getSellCurrency());
            map.addAttribute("msg", msg);
            return "my-page";
        }
    

    将路径变量/trades/buy/EUR/USD映射到Trade trade变量

    @Controller
    @RequestMapping("trades")
    public class TradeController {
    
        @RequestMapping("{buySell}/{buyCurrency}/{sellCurrency}")
        public String handleTradeRequest (Trade trade, Model map) {
            String msg = String.format(
                               "trade request. buySell: %s, buyCurrency: %s, sellCurrency: %s",
                               trade.getBuySell(), trade.getBuyCurrency(),
                               trade.getSellCurrency());
    
            map.addAttribute("msg", msg);
            return "my-page";
        }
    }
    
    • 使用Converter将路径变量或者请求参数转化为其他对象
      使用了下面的Converter我们请求路径中的数字会转化为Trade trade变量。
    public class TradeIdToTradeConverter implements Converter<String, Trade> {
    
        private TradeService tradeService;
    
        public TradeIdToTradeConverter (TradeService tradeService) {
            this.tradeService = tradeService;
        }
    
        @Override
        public Trade convert (String id) {
            try {
                Long tradeId = Long.valueOf(id);
                return tradeService.getTradeById(tradeId);
            } catch (NumberFormatException e) {
                return null;
            }
        }
    }
    
    @Controller
    public class EmployeeController {
        .............
      @RequestMapping("/employee3")
      @ResponseBody
      public String getEmployeeByDept3 (@RequestParam("dept") Optional<String> deptName) {
          return "test response for dept: " + (deptName.isPresent() ? deptName.get() :
                    "using default dept");
      }
    }
    
      @Scope(WebApplicationContext.SCOPE_SESSION)
      public Visitor visitor(HttpServletRequest request){
           return new Visitor(request.getRemoteAddr());
      }
    

    Controller中获取

    @Controller
    @RequestMapping("/trades")
    public class TradeController {
    
      @Autowired
      private Provider<Visitor> visitorProvider;
    
      @RequestMapping("/**")
      public String handleRequestById (Model model, HttpServletRequest request) {
          model.addAttribute("msg", "trades request, serving page " + request.getRequestURI());
          visitorProvider.get()
                         .addPageVisited(request.getRequestURI());
          return "traders-page";
      }
    }
    

    2、在Controller方法中写HttpSession httpSession
    3、通过@Autowired

    @Component
    @Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
    public class VisitorInfo implements Serializable {
      private String name;
      private int visitCounter;
      private LocalDateTime firstVisitTime;
      //getters/setters
        .............
    }
    
    • @ModelAttribute
      Controller每个请求都会调用所有的@ModelAttribute方法,会在handler之前给model赋值,key是time,value是返回值。
        @ModelAttribute("time")
        public LocalDateTime getRequestTime () {
            return LocalDateTime.now();
        }
    
    • @RequestAttribute
      和@RequestParam的区别:
      @RequestAttribute是在一个请求中,拦截器,Handler等共享的元素
      @RequestParam是请求链接中的参数

    相关文章

      网友评论

          本文标题:SpringMVC

          本文链接:https://www.haomeiwen.com/subject/mtgstrtx.html