Halo(二)

欢迎光临我的博客[http://poetize.cn],前端使用Vue2,聊天室使用Vue3,后台使用Spring Boot

@Conditional 满足条件给容器注册Bean(在配置类 @Configuration 的类和方法上配置)

需要实现Condition接口, 实现matches方法

public class LdCondition implements Condition{
	@Override
	public boolean matches(ConditionContext context,AnnotatedTypeMetadata metadata)     {
		Environment environment = context.getEnvironment();
		//从这里获取配置文件中 active 的值,根据当前的 active 值决定是否加载类
		String[] activeProfiles = environment.getActiveProfiles();
		for (String active : activeProfiles) {
			if(active.equals(ActiveEnum.open_active.getActive().toString())){
				return true;
			}
		}
		return false;
	}
}


标注在类上:
	一个类中可以注入很多实例,@Conditional标注在类上就决定了一批bean是否注入。

标记在方法上

@Configuration
public class BeanConfig {
    //只有一个类时,大括号可以省略
    //如果LdCondition的实现方法返回true,则注入这个bean
    @Conditional({LdCondition.class})
    @Bean("person")
    public Person person(){
        return new Person("ld",22);
    }
}


@ConditionalOnMissingBean:
	容器中没有就注入,有就不注入。

@ConditionalOnMissingBean:	
	容器中没有就不注入,有就注入。

FilterRegistrationBean 自定义过滤器(配置类 @Configuration 中)

使用FilterRegistrationBean来注册Filter:

    @Bean
    public FilterRegistrationBean<CorsFilter> corsFilter() {
        FilterRegistrationBean<CorsFilter> corsFilter = new FilterRegistrationBean<>();
        //设置优先级
        corsFilter.setOrder(Ordered.HIGHEST_PRECEDENCE + 10);
        //注册过滤器
        corsFilter.setFilter(new CorsFilter());
        //拦截路径
        corsFilter.addUrlPatterns("/api/*");
        return corsFilter;
    }

SpringBoot 整合 Swagger2(配置类 @Configuration 上)

依赖:
	implementation "io.springfox:springfox-swagger2:$swaggerVersion"
    implementation "io.springfox:springfox-swagger-ui:$swaggerVersion"


一般 swagger 需要的权限(需要在对应的模块进行排除):
	http://localhost:8080/swagger-resources/configuration/ui
	http://localhost:8080/swagger-resources
	http://localhost:8080/api-docs
	http://localhost:8080/swagger-ui.html
	http://localhost:8080/swagger-resources/configuration/security
	registry.addResourceHandler("swagger-ui.html")
		.addResourceLocations("classpath:/META-INF/resources/");
	registry.addResourceHandler("/webjars/**")
		.addResourceLocations("classpath:/META-INF/resources/webjars/");


@Api("评论接口"):
	用在类上,说明该类的作用
 
@ApiOperation(value="获取评论", notes="根据id获取评论"):
	用在方法上,说明方法的作用,标注在具体请求上。
	value和notes的作用差不多,都是对请求进行说明;
	tags则是对请求进行分类的,
	比如你有好几个controller,分别属于不同的功能模块,那这里我们就可以使用tags来区分了。
 
@ApiImplicitParams:
	用在方法上包含一组参数说明。
 
@ApiImplicitParam(name = "id", value = "12", required = true, dataType = "String"):
	用在@ApiImplicitParams注解中,指定一个请求参数的各个方面。
 
@ApiResponses:
	用于表示一组响应
 
@ApiResponse:
	用在@ApiResponses中,一般用于表达一个错误的响应信息。
 
@ApiModel:
	描述一个Model的信息
	这种一般用在post创建的时候,使用@RequestBody这样的场景,请求参数无法使用@ApiImplicitParam注解进行描述时。
	表明这是一个被swagger框架管理的model,用于class上。

@ApiModelProperty: 
	描述一个model的属性,就是标注在被标注了@ApiModel的class的属性上,
	这里的value是对字段的描述,example是取值例子。


Swagger2配置:

@EnableSwagger2
@Configuration
public class SwaggerConfiguration {

    @Bean
    public Docket haloDefaultApi() {

        return buildApiDocket("content",
                "api.content",
                "/api/content/**");
    }

    @Bean
    public Docket haloAdminApi() {

        return buildApiDocket("admin",
                "api.admin",
                "/api/admin/**");
    }

    private Docket buildApiDocket(@NonNull String groupName, @NonNull String basePackage, @NonNull String antPattern) {
        Assert.hasText(groupName, "Group name must not be blank");
        Assert.hasText(basePackage, "Base package must not be blank");
        Assert.hasText(antPattern, "Ant pattern must not be blank");

        return new Docket(DocumentationType.SWAGGER_2)
                .groupName(groupName)
                .select()
                .apis(RequestHandlerSelectors.basePackage(basePackage))
                .paths(PathSelectors.ant(antPattern))
                .build()
                .apiInfo(apiInfo());
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("API Documentation")
                .description("Documentation for API")
                .version("1.0")
                .build();
    }
}


启动后访问:
	http://localhost:8080/swagger-ui.html

@EnableWebMvc 用于导入 Spring Web MVC configuration(配置类 @Configuration 上)

将此注释添加到 @Configuration 类将导入来自 WebMvcConfigurationSupport 的 Spring MVC配置。


@EnableWebMvc == @Import({DelegatingWebMvcConfiguration.class})


@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "controller")
@PropertySource(value = "classpath:application.yaml", ignoreResourceNotFound = true, encoding = "UTF-8")
public class WebMvcAutoConfiguration implements WebMvcConfigurer {

    //文件协议
    private static final String FILE_PROTOCOL = "file:///";

    //配置信息实体
    private final HaloProperties haloProperties;

	//自动注入HaloProperties
    public WebMvcAutoConfiguration(HaloProperties haloProperties) {
        this.haloProperties = haloProperties;
    }

    /**
     * Spring Boot底层通过HttpMessageConverters(依靠Jackson库)将Java实体类输出为JSON格式。
     * 
     * MappingJackson2HttpMessageConverter可以将Java对象转换为application/json。
     */
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.stream()
                .filter(c -> c instanceof MappingJackson2HttpMessageConverter)
                // ifPresent():如果存在一个值,则使用该值执行给定的操作,否则什么也做不成
                .findFirst().ifPresent(converter ->
        {
        	// MappingJackson2HttpMessageConverter:读写Json转换器
            MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = (MappingJackson2HttpMessageConverter) converter;
            Jackson2ObjectMapperBuilder builder = Jackson2ObjectMapperBuilder.json();
            // JsonComponentModule 来扫描被 @JsonComponent 注解的类,
            // 并自动注册 JsonSerializer 和 JsonDeserializer。
            JsonComponentModule module = new JsonComponentModule();
            // addSerializer():为序列化模块添加自定义序列化程序来处理特定类型的值。
            // PageJacksonSerializer:Page对象的序列化
            module.addSerializer(PageImpl.class, new PageJacksonSerializer());
            // builder.modules():指定序列化模块
            ObjectMapper objectMapper = builder.modules(module).build();
            // 设置自定义 objectMapper,未设置则使用默认 objectMapper
            mappingJackson2HttpMessageConverter.setObjectMapper(objectMapper);
        });
    }

    /**
     * 自定义参数处理器
     */
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(new AuthenticationArgumentResolver());
    }

    /**
     * 配置静态资源路径
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        String workDir = FILE_PROTOCOL + haloProperties.getWorkDir();
        //映射 /** 的请求到 addResourceLocations() 指定的目录
        registry.addResourceHandler("/**")
                .addResourceLocations(workDir + "templates/themes/")
    }

    /**
     *  添加转换器(Converter)和格式器(Formatters)
     */
    @Override
    public void addFormatters(FormatterRegistry registry) {
    	//ConverterFactory:range范围转换器的工厂(可以将对象从S转换为R的子类型)
        registry.addConverterFactory(new StringToEnumConverterFactory());
    }

    /**
     * 配置 freemarker
     */
    @Bean
    public FreeMarkerConfigurer freemarkerConfig(HaloProperties haloProperties) throws IOException, TemplateException {
        FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
        //设置模板路径与字符集
        configurer.setTemplateLoaderPaths(FILE_PROTOCOL + haloProperties.getWorkDir() + "templates/", "classpath:/templates/");
        configurer.setDefaultEncoding("UTF-8");

        Properties properties = new Properties();
        properties.setProperty("auto_import", "/common/macro/common_macro.ftl as common,/common/macro/global_macro.ftl as global");

        configurer.setFreemarkerSettings(properties);

        return configurer;
    }

    /**
     * 配置视图解析器来转换基于字符串的视图名称
     */
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        FreeMarkerViewResolver resolver = new FreeMarkerViewResolver();
        resolver.setCache(false);
        resolver.setSuffix(HaloConst.SUFFIX_FTL);
        resolver.setContentType("text/html; charset=UTF-8");
        registry.viewResolver(resolver);
    }
}

@PropertySource 加载指定的配置文件到 Spring 的 Environment 中(配置类 @Configuration 上)

@PropertySource(value = "classpath:application.yaml", 
		ignoreResourceNotFound = true, encoding = "UTF-8")    //true表示属性源是可选的

用于 PropertySource 在 Spring 的上 添加 Environment。与 @Configuration 类一起使用。


获取配置文件中的值通过 Environment 具体使用方法:
	@Autowired
	private Environment env;

或者

使用 @value 注解,从配置文件读取值:
    @Value("${test.value}")

HandlerMethodArgumentResolver 自定义参数解析

自定义解析器需要实现 HandlerMethodArgumentResolver 接口。

实现自定义参数解析器步骤:1、自定义注解   2、自定义参数解析器   3、注册   4、在需要注入属性的 controller 添加注解


自定义注解:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface UserToken {String value() default "user";}


自定义参数解析器:
@Component
public class AuthenticationArgumentResolver implements HandlerMethodArgumentResolver {
   /**
    * 解析器是否支持当前参数
    */
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        // 指定参数如果被应用 UserToken 注解,则使用该解析器。
        // 如果直接返回true,则代表将此解析器用于所有参数
        return parameter.hasParameterAnnotation(UserToken.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, 
    			ModelAndViewContainer mavContainer, 
    			NativeWebRequest webRequest, 
    			WebDataBinderFactory binderFactory) {}
}


注册:
public class WebMvcAutoConfiguration implements WebMvcConfigurer {
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(new AuthenticationArgumentResolver());
    }
}

序列化和反序列化

层次低的一种是 Byte <---> Message,二进制与程序内部消息对象之间的转换,就是常见的序列化/反序列化。

另外一种是 Message <---> Message,程序内部对象之间的转换,比较高层次的序列化/反序列化。


Http序列化和反序列化(高层次)的核心是HttpMessageConverter。

@JsonSerialize @JsonDeserialize @JsonComponent

如果使用 Jackson 序列化和反序列化 JSON 数据,
您可能需要编写自己的 JsonSerializer 和 JsonDeserializer 类。
自定义序列化程序通常通过模块向 Jackson 注册,
但 Spring Boot 提供了另一种 @JsonComponent 注释,可以更容易地直接注册 Spring Beans。

您可以直接在 JsonSerializer 或 JsonDeserializer 实现上使用 @JsonComponent 注释。
您还可以在包含 JsonSerializer 或 JsonDeserializer 作为内部类的类上使用它。


@JsonSerialize:
	可以实现数据转换功能,此注解用于属性或者 getter() 方法上。

@JsonDeserialize:
	此注解用于属性或者 setter() 方法上,用于在反序列化时可以嵌入我们自定义的代码。

@JsonComponent:
	注释允许我们将带注释的类公开为Jackson序列化器和/或反序列化器,而无需手动将其添加到ObjectMapper。


@JsonSerialize(using = JsonDateSerialize.class)
@JsonDeserialize(using = JsonDateDeserialize.class)
private Date birthday;
posted @ 2019-11-17 09:29  LittleDonkey  阅读(405)  评论(0编辑  收藏  举报