spring boot学习笔记之CORS支持

相关博文:

SpringBoot学习(3)-SpringBoot添加支持CORS跨域访问:https://blog.csdn.net/yft_android/article/details/80307672

SpringBoot(六):SpringBoot使用CROS解决跨域问题:https://blog.csdn.net/saytime/article/details/74937204

No converter found for return value of type: class java.util.HashMap异常解决方案:https://blog.csdn.net/fxbin123/article/details/83221986

CORS(Cross-Origin Resource Sharing)”跨域资源共享”,是一个W3C标准,它允许浏览器向跨域服务器发送Ajax请求,打破了Ajax只能访问本站内的资源限制。我们在开发中都会遇到前端请求后台服务器出现跨域错误,下面我就讲一下如何让你的SpringBoot项目支持CORS跨域。

核心:配置CorsConfiguration

WebMvcConfigurerAdapter已经过时,新的实现是:

@Configuration
public class WebMvcConfg implements WebMvcConfigurer {
  //省略
}
@Configuration
public class WebMvcConfg extends WebMvcConfigurationSupport {
  //省略
}

网上推荐使用第二种方案,WebMvcConfigurationSupport是WebMvcConfigurerAdapter替代方案;

package com.wisely.config;
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
 
@Configuration
public class CustomCorsConfiguration {
 
	@Bean
	public WebMvcConfigurationSupport corsConfigurer() {
		return new WebMvcConfigurationSupport() {
			@Override
			public void addCorsMappings(CorsRegistry registry) {
				//允许访问的接口
				registry.addMapping("/api/*")
						//允许站外访问的路径
						.allowedOrigins("http://localhost:8888");
						//.allowedMethods("GET", "POST", "DELETE", "PUT", "OPTIONS")
						//.allowCredentials(false).maxAge(3600);
			}
		};
	}
}

但项目运行时出现异常

org.springframework.http.converter.HttpMessageNotWritableException: No converter found for return value of type: class java.util.HashMap

网上给出的异常原因有:

1、缺失Jackson 依赖,如果有 spring-boot-starter-web依赖可排除该问题
2、是否是 POJO (get set 方法是否有)
3、注解是否是 @RestController

若以上可能性完全排除:

具体原因:

extends WebMvcConfigurationSupport,这种方式会屏蔽springboot @EnableAutoConfiguration中的设置

@ConditionalOnMissingBean(WebMvcConfigurationSupport.class),只有当容器中没有WebMvcConfigurationSupport这个类型的组件的时候,才会启动自动配置。

所以当我们继承WebMvcConfigurationSupport之后,除非在继承类中重写了一系列有关WebMVC的配置,否则可能就会遇到静态资源访问不到,返回数据不成功这些一系列问题了。

鉴于SpringBoot2.X 中 WebMvcConfigurerAdapter 已经过时,所以可以实现 WebMvcConfigurer 接口来达到相同的目的:
 

package com.wisely.config;
 
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
@Configuration
public class CustomCorsConfiguration implements WebMvcConfigurer{

	@Override
	public void addCorsMappings(CorsRegistry registry) {
		//允许访问的接口
		registry.addMapping("/api/*")
		//允许站外访问的路径
		.allowedOrigins("http://localhost:8888");
		//.allowedMethods("GET", "POST", "DELETE", "PUT", "OPTIONS")
		//.allowCredentials(false).maxAge(3600);
	}
}

至此,项目中出现的问题得到解决。

别人的总结:
1、@EnableWebMvc=WebMvcConfigurationSupport,使用了@EnableWebMvc注解等于扩展了WebMvcConfigurationSupport但是没有重写任何方法。@EnableWebMvc 和WebMvcConfigurationSupport 二者只能选一个,如果同时实现,则会失效 (感谢一位网友热心帮助,开始忽略了这个问题)
2、继承WebMvcConfigurationSupport, 需要重写一系列有关WebMVC的配置,否则可能就会遇到静态资源访问不到,返回数据不成功这些一系列问题了(我就是掉在此坑),
因为springboot已经实例化了WebMvcConfigurationSupport, 如果使用@EnableWebMvc 注解或者继承WebMvcConfigurationSupport会覆盖默认实现, 一般建议还是不覆盖默认的好
3、实现WebMvcConfigurer 接口
示例:

import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.format.datetime.DateFormatter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

/**
 * 实现WebMvcConfigurer接口的部分示例...
 *
 * @author fxbin
 * @version v1.0
 * @since 2018/11/7 1:21
 */
@Configuration
public class WebConfig implements WebMvcConfigurer {

    /**
     * 添加类型转换器和格式化器
     * @author fxbin
     * @param registry
     */
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addFormatterForFieldType(LocalDate.class, new DateFormatter());
    }

    /**
     * 跨域支持
     * @author fxbin
     * @param registry
     */
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowCredentials(true)
                .allowedMethods("GET", "POST", "DELETE", "PUT")
                .maxAge(3600 * 24);
    }

    /**
     * 添加静态资源--过滤swagger-api (开源的在线API文档)
     * @author fxbin
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        //过滤swagger
        registry.addResourceHandler("swagger-ui.html")
                .addResourceLocations("classpath:/META-INF/resources/");

        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");

        registry.addResourceHandler("/swagger-resources/**")
                .addResourceLocations("classpath:/META-INF/resources/swagger-resources/");

        registry.addResourceHandler("/swagger/**")
                .addResourceLocations("classpath:/META-INF/resources/swagger*");

        registry.addResourceHandler("/v2/api-docs/**")
                .addResourceLocations("classpath:/META-INF/resources/v2/api-docs/");

    }

    /**
     * 配置消息转换器--这里我用的是alibaba 开源的 fastjson
     * @author fxbin
     * @param converters
     */
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        //1.需要定义一个convert转换消息的对象;
        FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
        //2.添加fastJson的配置信息,比如:是否要格式化返回的json数据;
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat,
                SerializerFeature.WriteMapNullValue,
                SerializerFeature.WriteNullStringAsEmpty,
                SerializerFeature.DisableCircularReferenceDetect,
                SerializerFeature.WriteNullListAsEmpty,
                SerializerFeature.WriteDateUseDateFormat);
        //3处理中文乱码问题
        List<MediaType> fastMediaTypes = new ArrayList<>();
        fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
        //4.在convert中添加配置信息.
        fastJsonHttpMessageConverter.setSupportedMediaTypes(fastMediaTypes);
        fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);
        //5.将convert添加到converters当中.
        converters.add(fastJsonHttpMessageConverter);
    }

    /**
     * 添加自定义的拦截器
     * @author fxbin
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");
    }
}


/**
 * 拦截器
 * @author fxbin
 * @version v1.0
 * @since 2018/11/7 1:25
 */
class MyInterceptor extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("Interceptor preHandler method is running !");
        return super.preHandle(request, response, handler);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("Interceptor postHandler method is running !");
        super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("Interceptor afterCompletion method is running !");
        super.afterCompletion(request, response, handler, ex);
    }

    @Override
    public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("Interceptor afterConcurrentHandlingStarted method is running !");
        super.afterConcurrentHandlingStarted(request, response, handler);
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值