package com.feiyangedu.springcloud.petstore.common.config;

import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.feiyangedu.springcloud.petstore.common.exception.APIException;
import com.feiyangedu.springcloud.petstore.common.filter.UserContextFilter;
import com.feiyangedu.springcloud.petstore.common.rest.RestExceptionHandler;
import com.netflix.hystrix.exception.HystrixBadRequestException;

import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Aspect
@Configuration
@EnableSwagger2
@EnableDiscoveryClient
public class CustomWebConfig {

	final Log log = LogFactory.getLog(getClass());

	@Bean
	public Docket createSwaggerDocket() {
		return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select()
				.paths(PathSelectors.regex("^/api/.*$")).build();
	}

	private ApiInfo apiInfo() {
		return new ApiInfoBuilder().title("Petstore")
				.contact(new Contact("Liao Xuefeng", "http://www.liaoxuefeng.com", "askxuefeng@gmail.com"))
				.license("Apache 2.0").licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html")
				.description("Petstore Sample Application on Spring Cloud").build();
	}

	@Around("execution(* com..*FeignClient.*(..))")
	public Object processFeignClientResult(ProceedingJoinPoint pjp) throws Throwable {
		log.info("Invoke feign client...");
		try {
			return pjp.proceed();
		} catch (HystrixBadRequestException e) {
			Throwable t = e.getCause();
			if (t instanceof APIException) {
				log.warn("Convert HystrixBadRequestException to APIException.");
				throw t;
			}
			log.warn("HystrixBadRequestException", e);
			throw e;
		} catch (Exception e) {
			log.warn(e.getClass(), e);
			throw e;
		}
	}

	@Bean
	public RestExceptionHandler restExceptionHandler() {
		return new RestExceptionHandler();
	}

	@Value("${filter.userContext.urlPattern:/api/*}")
	String userContextFilterPattern;

	@Bean
	public FilterRegistrationBean userContextFilterRegistration() {
		UserContextFilter userContextFilter = new UserContextFilter();
		userContextFilter.setObjectMapper(objectMapper);
		FilterRegistrationBean registration = new FilterRegistrationBean();
		registration.setFilter(userContextFilter);
		registration.addUrlPatterns(userContextFilterPattern);
		registration.setName("userContextFilter");
		registration.setOrder(1);
		return registration;
	}

	/**
	 * Customized JSON ObjectMapper.
	 */
	@Bean
	public ObjectMapper objectMapper() {
		final ObjectMapper mapper = new ObjectMapper();
		mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
		// ignored properties: Page.sort
		mapper.addMixIn(Page.class, PageMixIn.class);
		// disabled features:
		mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
		mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
		mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
		// add java8 time support:
		mapper.registerModule(new JavaTimeModule());
		return mapper;
	}

	@Autowired
	ObjectMapper objectMapper;

	@Bean
	public WebMvcConfigurer webMvcConfigurer() {
		return new WebMvcConfigurerAdapter() {
			/**
			 * Spring默认把静态资源文件/static/abc.js映射到/abc.js，不利于配置反向代理。配置为保留/static/前缀
			 */
			@Override
			public void addResourceHandlers(ResourceHandlerRegistry registry) {
				super.addResourceHandlers(registry);
				registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
			}

			/**
			 * Json默认序列化设置，增加Java8 Time支持
			 */
			@Override
			public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
				final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
				converter.setObjectMapper(objectMapper);
				converters.add(converter);
				super.configureMessageConverters(converters);
			}
		};
	}
}

abstract class PageMixIn {

	@JsonIgnore
	public abstract Sort getSort(); // we don't need it!

}

@@ -2831,16 +2831,96 @@
 ();%0A%09%7D%0A%0A
+%09/**%0A%09 * Convert HystrixBadRequestException to APIException using AspectJ.%0A%09 */%0A
 %09@Around

add comment