webFlux 学习(三)

不忘初心,方得始终

 

正文

入门crud

这次我们来学习webflux入门CRUD

首先我们需要安装一个mondodb 在这里我就不说怎么安装了.

配置文件如下

spring.data.mongodb.uri=mongodb://xxxxx:27017/webflux

领域对象

复制代码
/**
 * @Created by xiaodao
 */
@Document(collection = "user")
@Data
public class User {


    @Id
    private String id;

    @NotBlank
    private String name;
    @Range(min = 10,max = 100)
    private Integer age;
}
复制代码

repository

复制代码
/**
 * @Created by xiaodao
 */
@Repository
public interface UserRepository extends ReactiveMongoRepository<User,String> {

    Flux<User> findByAgeBetween(int start, int end );


    @Query("{'age':{$gte:?0,$lte:?1}}")
    Flux<User> oldUser(int start, int end );
}
复制代码

 Controller

复制代码
package com.xiaodao.webflux.controller;

import com.xiaodao.webflux.pojo.User;
import com.xiaodao.webflux.repository.UserRepository;
import com.xiaodao.webflux.utils.CheckUtil;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import javax.validation.Valid;
import java.awt.*;

/**
 * @Created by xiaodao
 */
@RestController
@RequestMapping("/user")
public class UserController {

    private final UserRepository userRepository;

    public UserController(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    /**
     * 以数组形式一次性返回数据
     * @return
     */
    @GetMapping("/")
    public Flux<User> getAll(){
        return userRepository.findAll();
    }

    /**
     * sse 形式多次返回方式
     * @return
     */
    @GetMapping(value = "/stream/all",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<User> getStreamAll(){
        return userRepository.findAll();
    }

    /**
     * 新增
     * @param user
     * @return
     */
    @PostMapping("/")
    public Mono<User> createUser(@Valid @RequestBody User user){
        CheckUtil.checkName(user.getName());
        return this.userRepository.save(user);

    }

    /**
     * 返回状态码 存在返回200 不存在返回404
     * @param id
     * @return
     */
    @DeleteMapping("/{id}")
    public Mono<ResponseEntity<Void>> delete(@PathVariable String id){

        //没有返回值.不知道数据有没有
//        this.userRepository.deleteById(id);

       return this.userRepository.findById(id)
                //当需要操作数据,并返回一个mono这时候用flatMap
                //当不操作数据,不返回数据,只是转换数据使用map
                .flatMap(user->this.userRepository.delete(user)
                .then(Mono.just(new ResponseEntity<Void>(HttpStatus.OK))))
                .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));

    }

    /**
     * 修改
     * 存在的时候返回200 和修改后的数据,不存在的时候返回404
     * @param id
     * @param user
     * @return
     */
    @PutMapping("/{id}")
    public Mono<ResponseEntity<User>> updateUser( @PathVariable String id ,@RequestBody @Valid User user){
       return this.userRepository.findById(id).flatMap(u->{
            user.setId(id);
          return   this.userRepository.save(user);
        }).map(u->new ResponseEntity<User>(u,HttpStatus.OK))
                .defaultIfEmpty(new ResponseEntity<>(HttpStatus.NOT_FOUND));
    }


    /**
     * 根据id查找一个值
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    public Mono<ResponseEntity<User>> findById(@PathVariable String id ){
        return  this.userRepository.findById(id).map(u->new ResponseEntity<User>(u,HttpStatus.OK))
                .defaultIfEmpty(new ResponseEntity<User>(HttpStatus.NOT_FOUND));
    }


    /**
     * 根据年龄段查找
     * @param start
     * @param end
     * @return
     */
    @GetMapping("/age/{start}/{end}")
    public Flux<User> findByage(@PathVariable int start , @PathVariable int end){
        return this.userRepository.findByAgeBetween( start,end  );
    }

    /**
     * 流式
     * @param start
     * @param end
     * @return
     */
    @GetMapping(value = "/ageStream/{start}/{end}",produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<User> findByageStream(@PathVariable int start , @PathVariable int end){
        return this.userRepository.findByAgeBetween( start,end  );
    }


    @GetMapping("/findoldUser/{start}/{end}")
    public Flux<User> findoldUser(@PathVariable int start , @PathVariable int end){
        return this.userRepository.oldUser( start,end  );
    }
}
复制代码

上面的代码加了一点hibernate的校验和自己的校验

controllerAdvice

复制代码
/**
 * 异常处理
 * @Created by xiaodao
 */
@ControllerAdvice
public class CheckAdvice {



    @ExceptionHandler(WebExchangeBindException.class)
    public ResponseEntity<String> handleBindException(WebExchangeBindException e ){
        return new ResponseEntity<String>(tostr(e), HttpStatus.BAD_REQUEST);
    }

    /**
     * 校验异常转换为字符串
     * @param e
     * @return
     */
    private String tostr(WebExchangeBindException e) {

     return    e.getFieldErrors().stream()
                .map(a->a.getField()+" : "+ a.getDefaultMessage())
                .reduce("",(s1,s2)-> s1+ "\n"+s2);

    }

    @ExceptionHandler(CheckException.class)
    public ResponseEntity<String> handleCheckException(
            CheckException e) {
        return new ResponseEntity<String>(toStr(e), HttpStatus.BAD_REQUEST);
    }

    private String toStr(CheckException e) {
        return e.getFieldName() + ": 错误的值 " + e.getFieldValue();
    }

}
复制代码

这里注意的一点就是@valid需要加载具体的类上,不然不会生效

这里还有我们的自己定义的校验名字的方法,我也贴到这里

复制代码
/**
 * @Created by xiaodao
 */
public class CheckUtil {

    private static final String[] INVALID_NAMES={"admin","role"};


    public static void checkName(String value){

        Stream.of(INVALID_NAMES).filter(name -> name.equalsIgnoreCase(value))
                .findAny().ifPresent(name->{throw new CheckException("name",value);});
    }


}
复制代码

 RouterFucntion

routerFunction 是webflux的另一种开始模式

webflux 可以运行在servlet3.1 和netty上 需要把

httpServletRequest - >serverRequest

httpServletResponse - >serverResponse 

使用routerFunction开发过程需要  

1.HandlerFunction  就是输入servletRequest 返回的是 serverResponse

2.routerFunction (将请求url和HandleFunction对应起来)

3.然后才是你自己定义的userhandle处理

4.server 处理

代码如下

复制代码
package com.xiaodao.webflux.handle;

import com.xiaodao.webflux.pojo.User;
import com.xiaodao.webflux.repository.UserRepository;
import com.xiaodao.webflux.utils.CheckUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;

/**
 * @Created by xiaodao
 */

@Component
public class UserHandle {

    @Autowired
    private UserRepository userRepository;

    /***
     * 获取所有用户
     * @param request
     * @return
     */
    public Mono<ServerResponse> getAllUser(ServerRequest request){
        return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON_UTF8)
                .body(userRepository.findAll(), User.class);
    }


    /**
     * 创建用户
     * @param request
     * @return
     */
    public Mono<ServerResponse> createUser(ServerRequest request) {
        Mono<User> userMono = request.bodyToMono(User.class);

        return userMono.flatMap(u -> {
                    CheckUtil.checkName(u.getName());
                    return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON_UTF8)
                            .body(userRepository.save(u), User.class);
                }

        );
    }
    /**
     * 删除
     * @param request
     * @return
     */
    public Mono<ServerResponse> deleteUser(ServerRequest request){
        String id = request.pathVariable("id");
        return userRepository.findById(id).flatMap(user->userRepository.delete(user))
                .then(ServerResponse.ok().build())
                .switchIfEmpty(ServerResponse.notFound().build());
    }

}
复制代码

routerFunction 

复制代码
/**
 * @Created by xiaodao
 */
@Configuration
public class AllRouter {

    @Bean
    RouterFunction<ServerResponse> userRouter(UserHandle userHandle){

        return RouterFunctions.nest(
                RequestPredicates.path("/user"),
                //查找所有用户
                RouterFunctions.route(RequestPredicates.GET("/"),userHandle::getAllUser)
                        //创建用户
                .andRoute(RequestPredicates.POST("/")
                        .and(RequestPredicates.accept(MediaType.APPLICATION_JSON_UTF8)
               ) ,userHandle::createUser)
                        //删除用户
                .andRoute(RequestPredicates.DELETE("/{id}"),userHandle::deleteUser)
        );
    }
}
复制代码
复制代码
/**
 * @Created by xiaodao
 */
@Component
@Order(-2)
public class ExceptionHandle implements WebExceptionHandler {
    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable throwable) {
        ServerHttpResponse response = exchange.getResponse();
        //设置响应头400
        response.setStatusCode(HttpStatus.BAD_REQUEST);
        //设置返回类型
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON_UTF8);

        //异常信息
        String errorMsg = tostr(throwable);


        DataBuffer wrap = response.bufferFactory().wrap(errorMsg.getBytes());
        return response.writeWith(Mono.just(wrap));
    }

    private String tostr(Throwable ex) {
        //已知异常
        if(ex instanceof CheckException){

            CheckException check = (CheckException)ex;
            return check.getFieldName() +"  invalid value  "+ check.getFieldValue();

            //未知异常需要打印堆栈方便定位
        }else{
            ex.printStackTrace();
            return ex.toString();
        }
    }
}
复制代码

 

这个时候我来就可以去访问.

localhost:8080/user

 

posted @   北京de小刀  阅读(1045)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
点击右上角即可分享
微信分享提示