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