SpringBoot3 Web开发新特性(Problemdetails、函数式Web)
2023-12-18 10:47:56
1. Problemdetails
错误信息返回新格式
package org.springframework.boot.autoconfigure.web.servlet;
......省略部分......
public class WebMvcAutoConfiguration {
......省略部分......
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnProperty(
prefix = "spring.mvc.problemdetails",
name = {"enabled"},
havingValue = "true"
)
static class ProblemDetailsErrorHandlingConfiguration {
ProblemDetailsErrorHandlingConfiguration() {
}
@Bean
@ConditionalOnMissingBean({ResponseEntityExceptionHandler.class})
ProblemDetailsExceptionHandler problemDetailsExceptionHandler() {
return new ProblemDetailsExceptionHandler();
}
}
......省略部分......
}
- 默认是关闭的。需要配置一个属性
spring.mvc.problemdetails.enabled=true
- ProblemDetailsExceptionHandler是一个@ControllerAdvice集中处理系统异常
- 如果系统出现以下异常,会被SpringBoot支持以RFC 7807规范方式返回错误数据
@ExceptionHandler({
HttpRequestMethodNotSupportedException.class, // 请求方式不支持
HttpMediaTypeNotSupportedException.class,
HttpMediaTypeNotAcceptableException.class,
MissingPathVariableException.class,
MissingServletRequestParameterException.class,
MissingServletRequestPartException.class,
ServletRequestBindingException.class,
MethodArgumentNotValidException.class,
NoHandlerFoundException.class,
AsyncRequestTimeoutException.class,
ErrorResponseException.class,
ConversionNotSupportedException.class,
TypeMismatchException.class,
HttpMessageNotReadableException.class,
HttpMessageNotWritableException.class,
BindException.class
})
- 以HttpRequestMethodNotSupportedException来讲解开启的效果。不开启前,以post方式请求一个get url: http://localhost:8080/exception。显示如下。其中headers的Content-Type是application/json
{
"timestamp": "2023-07-22T02:51:16.088+00:00",
"status": 405,
"error": "Method Not Allowed",
"path": "/exception"
}
开启后。显示如下。。其中headers的Content-Type是application/problem+json。其中problem可以通过额外的拓展返回一些业务数据
{
"type": "about:blank",
"title": "Method Not Allowed",
"status": 405,
"detail": "Method 'POST' is not supported.",
"instance": "/exception"
}
2. 函数式Web
使用函数式的方式,定义Web的请求处理流程。使用的java8函数式接口
Web请求处理的方式:
- @Controller + @RequestMapping:耦合式 (路由、业务耦合)
- 函数式Web:分离式(路由、业务分离)
2.1 场景
以Restful方式,对User进行CRUD
- GET /user/1: 获取id=1的用户
- GET /users: 获取所有用户
- POST /user: 请求体携带json,新增一个用户
- PUT /user/1: 请求体携带json,修改id=1的用户
- DELETE /user/1: 删除id=1的用户
2.2 主要逻辑
- 给容器中放一个Bean:类型是RouterFunction,集中所有路由信息
- 每个业务准备一个的Handler
2.3 核心对象
- RouterFunction:定义路由信息。发什么请求,谁来处理
- RequestPredicate:定义请求规则:请求方式(GET、POST)和请求参数
- ServerRequest:封装请求完整数据
- ServerResponse:封装响应完整数据
2.4 示例程序
WebFunctionConfig.java
package com.hh.springboot3test.config;
import com.hh.springboot3test.bean.User;
import com.hh.springboot3test.biz.UserBizHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.function.RequestPredicates;
import org.springframework.web.servlet.function.RouterFunction;
import org.springframework.web.servlet.function.RouterFunctions;
import org.springframework.web.servlet.function.ServerResponse;
@Configuration
public class WebFunctionConfig {
@Bean
public RouterFunction<ServerResponse> userRoute(UserBizHandler userBizHandler/*这个会被自动注入进来*/) {
return RouterFunctions.route() // 开始定义路由信息
.GET("/user/{id}", RequestPredicates.accept(MediaType.ALL).and(RequestPredicates.param("key1", "value1")/* 只有/user/n?key1=value1能查询出来结果 */), request -> {
String id = request.pathVariable("id");
System.out.println("查询的用户的id = " + id);
// 模拟数据库查询出来的用户
User user = new User(1, "jim", 28);
// 构造响应。和@ResponseBody原理一样,利用HttpMessageConverter,可写出为json
return ServerResponse.ok().body(user);
})
.GET("/users", userBizHandler::getUsers)
.POST("/user", RequestPredicates.accept(MediaType.APPLICATION_JSON), userBizHandler::saveUser)
.PUT("/user/{id}", RequestPredicates.accept(MediaType.APPLICATION_JSON), userBizHandler::updateUser)
.DELETE("/user/{id}", userBizHandler::deleteUser)
.build();
}
}
UserBizHandler.java
package com.hh.springboot3test.biz;
import com.hh.springboot3test.bean.User;
import jakarta.servlet.ServletException;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.function.ServerRequest;
import org.springframework.web.servlet.function.ServerResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
@Service
public class UserBizHandler {
/**
* 获取所有用户
*/
public ServerResponse getUsers(ServerRequest request) throws Exception {
// 模拟数据库查询出来的所有用户
List<User> users = Arrays.asList(
new User(1, "jim", 28),
new User(2, "lily", 18)
);
return ServerResponse
.ok()
.body(users);
}
/**
* 保存用户
*/
public ServerResponse saveUser(ServerRequest request) throws ServletException, IOException {
// 提取请求体
User user = request.body(User.class);
// 模拟保存用户
System.out.println("保存的用户是: " + user);
return ServerResponse.ok().build();
}
/**
* 更新用户
*/
public ServerResponse updateUser(ServerRequest request) throws ServletException, IOException {
// 提取请求体
User user = request.body(User.class);
// 模拟更新用户
System.out.println("更新的用户是: " + user);
return ServerResponse.ok().build();
}
/**
* 删除用户
*/
public ServerResponse deleteUser(ServerRequest request) {
String id = request.pathVariable("id");
// 模拟删除用户
System.out.println("删除的用户的id = " + id);
return ServerResponse.ok().build();
}
}
文章来源:https://blog.csdn.net/yy8623977/article/details/131864850
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!