webmvc和webflux的配置详解

2024-01-29 07:38
文章标签 配置 详解 webflux webmvc

本文主要是介绍webmvc和webflux的配置详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

webmvc和webflux作为spring framework的两个重要模块,代表了两个IO模型,阻塞式和非阻塞式的。

webmvc是基于servlet的阻塞式模型(一般称为oio),一个请求到达服务器后会单独分配一个线程去处理请求,如果请求包含IO操作,线程在IO操作结束之前一直处于阻塞等待状态,这样线程在等待IO操作结束的时间就浪费了。

webflux是基于reactor的非阻塞模型(一般称为nio),同样,请求到达服务器后也会分配一个线程去处理请求,如果请求包含IO操作,线程在IO操作结束之前不再是处于阻塞等待状态,而是去处理其他事情,等到IO操作结束之后,再通知(得益于系统的机制)线程继续处理请求。

这样线程就有效地利用了IO操作所消耗的时间。

本文就webmvc和webflux两个框架做一个对比。有兴趣的可以看看官方文档做原始参考web servlet和web reactive。

服务器配置

webmvc

@Configuration
@EnableWebMvc		//使用注解@EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {		//继承WebMvcConfigurer//配置静态资源@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");registry.addResourceHandler("/file/**").addResourceLocations("file:" + System.getProperty("user.dir") + File.separator + "file" + File.separator);registry.addResourceHandler("/swagger-ui.html**").addResourceLocations("classpath:/META-INF/resources/");registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");}//配置拦截器//配置编解码...
}

webflux

@Configuration
@EnableWebFlux		//使用注解@EnableWebFlux
public class WebFluxConfig implements WebFluxConfigurer {		//继承WebFluxConfigurer //配置静态资源@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");registry.addResourceHandler("/file/**").addResourceLocations("file:" + System.getProperty("user.dir") + File.separator + "file" + File.separator);registry.addResourceHandler("/swagger-ui.html**").addResourceLocations("classpath:/META-INF/resources/");registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");}//配置拦截器//配置编解码...
}

认证配置

webmvc-验证依赖于用户数据服务,需定义实现UserDetailsService的Bean

@Configuration
@EnableWebSecurity
public class WebMvcSecurityConfig extends WebSecurityConfigurerAdapter implements 
AuthenticationEntryPoint,		//未验证回调
AuthenticationSuccessHandler,		//验证成功回调
AuthenticationFailureHandler,		//验证失败回调
LogoutSuccessHandler {		//登出成功回调@Overridepublic void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {sendJson(response, new Response<>(HttpStatus.UNAUTHORIZED.value(), "Unauthorized"));}@Overridepublic void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {sendJson(response, new Response<>(1, "Incorrect"));}@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {sendJson(response, new Response<>(0, authentication.getClass().getSimpleName()));}@Overridepublic void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {sendJson(response, new Response<>(0, "Success"));}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests().antMatchers("/swagger*/**", "/webjars/**", "/v2/api-docs").permitAll().and().authorizeRequests().antMatchers("/static/**", "/file/**").permitAll().and().authorizeRequests().anyRequest().authenticated().and().logout().logoutUrl("/user/logout")		//虚拟路径,不是控制器定义的路径.logoutSuccessHandler(this).permitAll().and().exceptionHandling().authenticationEntryPoint(this).and().formLogin().usernameParameter("username").passwordParameter("password").loginProcessingUrl("/user/login")		//虚拟路径,不是控制器定义的路径.successForwardUrl("/user/login")		//是控制器定义的路径.failureHandler(this).and().httpBasic().authenticationEntryPoint(this);}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailService);}

webflux-验证依赖于用户数据服务,需定义实现ReactiveUserDetailsService的Bean

@Configuration
@EnableWebFluxSecurity		//使用注解@EnableWebFluxSecurity
public class WebFluxSecurityConfig implements 
WebFilter,		//拦截器
ServerLogoutSuccessHandler,		//登出成功回调
ServerAuthenticationEntryPoint,		//验证入口
ServerAuthenticationFailureHandler,		//验证成功回调 
ServerAuthenticationSuccessHandler {		//验证失败回调//实现接口的方法@Overridepublic Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {//配置webflux的context-pathServerHttpRequest request = exchange.getRequest();if (request.getURI().getPath().startsWith(contextPath)) {exchange = exchange.mutate().request(request.mutate().contextPath(contextPath).build()).build();}//把查询参数转移到FormData中,不然验证过滤器(ServerFormLoginAuthenticationConverter)接受不到参数if (exchange.getRequest().getMethod() == HttpMethod.POST && exchange.getRequest().getQueryParams().size() > 0) {ServerWebExchange finalExchange = exchange;ServerWebExchange realExchange = new Decorator(exchange) {@Overridepublic Mono<MultiValueMap<String, String>> getFormData() {return super.getFormData().map(new Function<MultiValueMap<String, String>, MultiValueMap<String, String>>() {@Overridepublic MultiValueMap<String, String> apply(MultiValueMap<String, String> stringStringMultiValueMap) {if (stringStringMultiValueMap.size() == 0) {return finalExchange.getRequest().getQueryParams();} else {return stringStringMultiValueMap;}}});}};return chain.filter(realExchange);}return chain.filter(exchange);}@Overridepublic Mono<Void> onLogoutSuccess(WebFilterExchange webFilterExchange, Authentication authentication) {return sendJson(webFilterExchange.getExchange(), new Response<>("登出成功"));}@Overridepublic Mono<Void> commence(ServerWebExchange exchange, AuthenticationException e) {return sendJson(exchange, new Response<>(HttpStatus.UNAUTHORIZED.value(), "未验证"));}@Overridepublic Mono<Void> onAuthenticationFailure(WebFilterExchange webFilterExchange, AuthenticationException exception) {return sendJson(webFilterExchange.getExchange(), new Response<>(1, "验证失败"));}@Overridepublic Mono<Void> onAuthenticationSuccess(WebFilterExchange webFilterExchange, Authentication authentication) {return webFilterExchange.getChain().filter(webFilterExchange.getExchange().mutate().request(t -> t.method(HttpMethod.POST).path("/user/login"))		//转发到自定义控制器.build());}@Beanpublic SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {http.addFilterAfter(this, SecurityWebFiltersOrder.FIRST).csrf().disable().authorizeExchange().pathMatchers("/swagger*/**", "/webjars/**", "/v2/api-docs")		//swagger.permitAll().and().authorizeExchange().pathMatchers("/static/**", "/file/**")		//静态资源.permitAll().and().authorizeExchange().anyExchange().authenticated().and().logout()		//登出.logoutUrl("/user/logout").logoutSuccessHandler(this).and().exceptionHandling()		//未验证回调.authenticationEntryPoint(this).and().formLogin().loginPage("/user/login").authenticationFailureHandler(this)		//验证失败回调.authenticationSuccessHandler(this)		//验证成功回调.and().httpBasic().authenticationEntryPoint(this);		//basic验证,一般用于移动端return http.build();}
}

Session配置

webmvc

@Configuration
@EnableRedisHttpSession	//使用注解@EnableRedisHttpSession	
public class RedisHttpSessionConfig { //考虑到分布式系统,一般使用redis存储session@Beanpublic LettuceConnectionFactory redisConnectionFactory() {return new LettuceConnectionFactory();}}
//单点登录使用FindByIndexNameSessionRepository根据用户名查询session,删除其他session即可
Map<String, Session> map = findByIndexNameSessionRepository.findByPrincipalName(name);

webflux

@Configuration
@EnableRedisWebSession(maxInactiveIntervalInSeconds = 60) //使用注解@EnableRedisWebSession ,maxInactiveIntervalInSeconds设置数据过期时间,spring.session.timeout不管用
public class RedisWebSessionConfig { //考虑到分布式系统,一般使用redis存储session@Beanpublic LettuceConnectionFactory lettuceConnectionFactory() {return new LettuceConnectionFactory();}}
//单点登录使用ReactiveRedisSessionRepository.getSessionRedisOperations().scan方法查询相同用户名的session,删除其他session即可
public Mono<Map<String, String>> findByPrincipalName(String name) {return reactiveSessionRepository.getSessionRedisOperations().scan(ScanOptions.scanOptions().match(ReactiveRedisSessionRepository.DEFAULT_NAMESPACE + ":sessions:*").build()).flatMap(new Function<String, Publisher<Tuple2<String, Map.Entry<Object, Object>>>>() {@Overridepublic Publisher<Tuple2<String, Map.Entry<Object, Object>>> apply(String s) {return reactiveSessionRepository.getSessionRedisOperations().opsForHash().entries(s).map(new Function<Map.Entry<Object, Object>, Tuple2<String, Map.Entry<Object, Object>>>() {@Overridepublic Tuple2<String, Map.Entry<Object, Object>> apply(Map.Entry<Object, Object> objectObjectEntry) {return Tuples.of(s, objectObjectEntry);}});}}).filter(new Predicate<Tuple2<String, Map.Entry<Object, Object>>>() {@Overridepublic boolean test(Tuple2<String, Map.Entry<Object, Object>> rule) {Map.Entry<Object, Object> t = rule.getT2();String key = "sessionAttr:" + HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY;if (key.equals(t.getKey())) {User sci = (User) ((SecurityContextImpl) t.getValue()).getAuthentication().getPrincipal();return sci.getUsername().equals(name);}return false;}}).collectMap(new Function<Tuple2<String, Map.Entry<Object, Object>>, String>() {@Overridepublic String apply(Tuple2<String, Map.Entry<Object, Object>> rule) {return name;}}, new Function<Tuple2<String, Map.Entry<Object, Object>>, String>() {@Overridepublic String apply(Tuple2<String, Map.Entry<Object, Object>> rule) {return rule.getT1().replace(ReactiveRedisSessionRepository.DEFAULT_NAMESPACE + ":sessions:", "");}});}

swagger配置(参考文章)

webmvc

//依赖包
implementation 'io.springfox:springfox-swagger2:2.9.2'
implementation 'io.springfox:springfox-swagger-ui:2.9.2'
//配置
@Configuration
@EnableSwagger2		//使用注解
public class SwaggerConfig {@Beanpublic Docket  docket () {return new Docket(DocumentationType.SWAGGER_2).apiInfo(new ApiInfoBuilder().title("*****").description("******").version("0.0.1").build()).select().apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)).paths(PathSelectors.any()).build();}
}
//参数上传
//定义参数bean
@Setter
@Getter
@ToString
@ApiModel
public class QueryBean{@ApiModelProperty(value = "普通参数", required = false, example = "")private String query;@ApiModelProperty(value = "文件参数", required = false, example = "")private MultipartFile image;		//webmvc中使用MultipartFile作为接收文件的类型
}
//定义接口
@ApiOperation("一个接口")
@PostMapping("/path")
//这里需要使用@ApiImplicitParam显示配置【文件参数】才能使swagger界面显示上传文件按钮
@ApiImplicitParams({@ApiImplicitParam(paramType = "form", //表单参数dataType = "__file", //最新版本使用__file表示文件,以前用的是filename = "image", //和QueryBean里面的【文件参数image】同名value = "文件")	//注释
})
public Mono<Response> bannerAddOrUpdate(QueryBean q) {}

webflux-要稍微麻烦些,多个依赖

//依赖
implementation 'io.springfox:springfox-swagger2:2.10.5'
implementation 'io.springfox:springfox-swagger-ui:2.10.5'
implementation 'io.springfox:springfox-spring-webflux:2.10.5'
//配置
@Configuration
@EnableSwagger2WebFlux		//使用注解
public class SwaggerConfig {@Beanpublic Docket docket() {Set<String> consumes = new HashSet<>();consumes.add(MediaType.APPLICATION_FORM_URLENCODED_VALUE);Set<String> produces = new HashSet<>();produces.add(MediaType.APPLICATION_JSON_VALUE);return new Docket(DocumentationType.SWAGGER_2).apiInfo(new ApiInfoBuilder().title("*****").description("*****").version("0.0.1").build()).pathMapping("/context-path")  //注意webflux没有context-path配置,如果不加这句话的话,接口测试时路径没有前缀.consumes(consumes).produces(produces).select().apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)).paths(PathSelectors.any()).build();}
}
//参数上传
//定义参数bean
@Setter
@Getter
@ToString
@ApiModel
public class QueryBean{@ApiModelProperty(value = "普通参数", required = false, example = "")private String query;@ApiModelProperty(value = "文件参数", required = false, example = "")private FilePart image;		//强调,webflux中使用FilePart作为接收文件的类型
}
//定义接口
@ApiOperation("一个接口")
@PostMapping("/path")
//这里需要使用@ApiImplicitParam显示配置【文件参数】才能使swagger界面显示上传文件按钮
@ApiImplicitParams({@ApiImplicitParam(paramType = "form", //表单参数dataType = "__file", //最新版本使用__file表示文件,以前用的是filename = "image", //和QueryBean里面的【文件参数image】同名value = "文件")	//注释
})
public Mono<Response> bannerAddOrUpdate(QueryBean q) {}

以上就是webmvc和webflux的对比,谢谢大家。

这篇关于webmvc和webflux的配置详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/656206

相关文章

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Zookeeper安装和配置说明

一、Zookeeper的搭建方式 Zookeeper安装方式有三种,单机模式和集群模式以及伪集群模式。 ■ 单机模式:Zookeeper只运行在一台服务器上,适合测试环境; ■ 伪集群模式:就是在一台物理机上运行多个Zookeeper 实例; ■ 集群模式:Zookeeper运行于一个集群上,适合生产环境,这个计算机集群被称为一个“集合体”(ensemble) Zookeeper通过复制来实现

CentOS7安装配置mysql5.7 tar免安装版

一、CentOS7.4系统自带mariadb # 查看系统自带的Mariadb[root@localhost~]# rpm -qa|grep mariadbmariadb-libs-5.5.44-2.el7.centos.x86_64# 卸载系统自带的Mariadb[root@localhost ~]# rpm -e --nodeps mariadb-libs-5.5.44-2.el7

hadoop开启回收站配置

开启回收站功能,可以将删除的文件在不超时的情况下,恢复原数据,起到防止误删除、备份等作用。 开启回收站功能参数说明 (1)默认值fs.trash.interval = 0,0表示禁用回收站;其他值表示设置文件的存活时间。 (2)默认值fs.trash.checkpoint.interval = 0,检查回收站的间隔时间。如果该值为0,则该值设置和fs.trash.interval的参数值相等。

NameNode内存生产配置

Hadoop2.x 系列,配置 NameNode 内存 NameNode 内存默认 2000m ,如果服务器内存 4G , NameNode 内存可以配置 3g 。在 hadoop-env.sh 文件中配置如下。 HADOOP_NAMENODE_OPTS=-Xmx3072m Hadoop3.x 系列,配置 Nam

wolfSSL参数设置或配置项解释

1. wolfCrypt Only 解释:wolfCrypt是一个开源的、轻量级的、可移植的加密库,支持多种加密算法和协议。选择“wolfCrypt Only”意味着系统或应用将仅使用wolfCrypt库进行加密操作,而不依赖其他加密库。 2. DTLS Support 解释:DTLS(Datagram Transport Layer Security)是一种基于UDP的安全协议,提供类似于

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

K8S(Kubernetes)开源的容器编排平台安装步骤详解

K8S(Kubernetes)是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。以下是K8S容器编排平台的安装步骤、使用方式及特点的概述: 安装步骤: 安装Docker:K8S需要基于Docker来运行容器化应用程序。首先要在所有节点上安装Docker引擎。 安装Kubernetes Master:在集群中选择一台主机作为Master节点,安装K8S的控制平面组件,如AP