使用Spring Web MVC,开发者可以直接访问官方文档Spring Web MVC文档Version 5.2.1.RELEASE,本文及Spring MVC系列文章都参考于此文档及源码。

这一节来看Spring MVC更多使用方法。

1. CORS

可以看到文档是怎么介绍的:

For security reasons, browsers prohibit AJAX calls to resources outside the current origin. For example, you could have your bank account in one tab and evil.com in another. Scripts from evil.com should not be able to make AJAX requests to your bank API with your credentials — for example withdrawing money from your account!

Cross-Origin Resource Sharing (CORS) is a W3C specification implemented by most browsers that lets you specify what kind of cross-domain requests are authorized, rather than using less secure and less powerful workarounds based on IFRAME or JSONP.

浏览器禁止跨域,可以使用W3C规范的CORS,而不是使用安全性低,功能弱的变通方法IFRAME或者JSONP。

  1. @CrossOrigin
    可以使用@CrossOrigin允许跨域访问,例如:
    @CrossOrigin(maxAge = 3600)
    @RestController
    @RequestMapping("/account")
    public class AccountController {
    
        @CrossOrigin("https://domain2.com")
        @GetMapping("/{id}")
        public Account retrieve(@PathVariable Long id) {
            // ...
        }
    
        @DeleteMapping("/{id}")
        public void remove(@PathVariable Long id) {
            // ...
        }
    }
  2. 全局配置
    可以使用WebMvcConfigurer全局配置如:
    @Configuration
    @EnableWebMvc
    public class WebConfig implements WebMvcConfigurer {
    
        @Override
        public void addCorsMappings(CorsRegistry registry) {
    
            registry.addMapping("/api/**")
                .allowedOrigins("https://domain2.com")
                .allowedMethods("PUT", "DELETE")
                .allowedHeaders("header1", "header2", "header3")
                .exposedHeaders("header1", "header2")
                .allowCredentials(true).maxAge(3600);
    
            // Add more mappings...
        }
    }
    还可以xml进行全局配置
    <mvc:cors>
    
        <mvc:mapping path="/api/**"
            allowed-origins="https://domain1.com, https://domain2.com"
            allowed-methods="GET, PUT"
            allowed-headers="header1, header2, header3"
            exposed-headers="header1, header2" allow-credentials="true"
            max-age="123" />
    
        <mvc:mapping path="/resources/**"
            allowed-origins="https://domain1.com" />
    
    </mvc:cors>
  3. 拦截器实现
    CorsConfiguration config = new CorsConfiguration();
    
    // Possibly...
    // config.applyPermitDefaultValues()
    
    config.setAllowCredentials(true);
    config.addAllowedOrigin("https://domain1.com");
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");
    
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", config);
    
    CorsFilter filter = new CorsFilter(source);

2. URI

  1. 可以是用UriComponentsBuilder创建UriComponents,URI:

    UriComponents uriComponents = UriComponentsBuilder
            .fromUriString("https://example.com/hotels/{hotel}")  
            .queryParam("q", "{q}")  
            .encode() 
            .build(); 
    
    URI uri = uriComponents.expand("Westin", "123").toUri(); 

    也可以使用UriBuilder,UriBuilderFactory,UriComponentsBuilder实现了UriBuilder:

    String baseUrl = "https://example.org";
    DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(baseUrl);
    factory.setEncodingMode(EncodingMode.TEMPLATE_AND_VALUES);
  2. 使用RestTemplate或者WebClient操作URI:

    RestTemplate restTemplate = new RestTemplate();
    restTemplate.setUriTemplateHandler(factory);
    
    WebClient client = WebClient.builder().uriBuilderFactory(factory).build();

3. Asyn

Spring MVC提供了异步接口使用。

  1. DeferredResult

    @GetMapping("/quotes")
    @ResponseBody
    public DeferredResult<String> quotes() {
        DeferredResult<String> deferredResult = new DeferredResult<String>();
        // Save the deferredResult somewhere..
        return deferredResult;
    }
    
    // From some other thread...
    deferredResult.setResult(result);
  2. Callable

    @PostMapping
    public Callable<String> processUpload(final MultipartFile file) {
    
        return new Callable<String>() {
            public String call() throws Exception {
                // ...
                return "someView";
            }
        };
    }

4. 缓存

CacheControl提供对配置与Cache-Control标头相关的设置的支持。

// Cache for an hour - "Cache-Control: max-age=3600"
CacheControl ccCacheOneHour = CacheControl.maxAge(1, TimeUnit.HOURS);

// Prevent caching - "Cache-Control: no-store"
CacheControl ccNoStore = CacheControl.noStore();

// Cache for ten days in public and private caches,
// public caches should not transform the response
// "Cache-Control: max-age=864000, public, no-transform"
CacheControl ccCustom = CacheControl.maxAge(10, TimeUnit.DAYS).noTransform().cachePublic();
@GetMapping("/book/{id}")
public ResponseEntity<Book> showBook(@PathVariable Long id) {

Book book = findBook(id);
String version = book.getVersion();

return ResponseEntity
        .ok()
        .cacheControl(CacheControl.maxAge(30, TimeUnit.DAYS))
        .eTag(version) // lastModified is also available
        .body(book);
}