动力节点王鹤SpringBoot3笔记——第五章 说说Web服务

本文详细介绍了SpringBoot3中构建高效Web服务的各个方面,包括HTML页面视图、JSON视图、添加favicon,深入探讨了Spring MVC的控制器、模型、视图、请求流程、自动配置、Servlets、Filters、Listeners的使用。此外,还讨论了文件上传、全局异常处理,特别是ProblemDetail在SpringBoot3中的应用,以及如何扩展ProblemDetail进行自定义错误响应。
摘要由CSDN通过智能技术生成

 目录

第五章 说说Web服务

5.1 高效构建Web应用

5.1.1  html页面视图

5.1.2 JSON视图 

5.1.3  给项目加favicon

5.2 Spring MVC 

5.2.1 控制器Controller 

5.2.1.1  匹配请求路径到控制器方法

5.2.1.2 @RequestMapping

5.2.1.3 控制器方法参数类型与可用返回值类型 

5.2.1.4 接收请求参数

5.2.1.4.1 接收json 

5.2.1.4.2 Reader-InputStream

5.2.1.4.3 数组参数接收多个值

5.2.1.5 验证参数

5.2.1.5.1 Java Bean Validation 

5.2.1.5.2 JSR-303注解 

5.2.1.5.3 快速上手

5.2.1.5.4 分组校验

5.2.1.5.5 ValidationAutoConfiguration

5.2.2  模型Model

5.2.3 视图View

5.2.3.1 页面视图 

5.2.3.2  JSON视图

5.2.3.3  复杂JSON

5.2.3.4  ResponseEntity

5.2.3.5 Map作为返回值 

5.3  SpringMVC请求流程

5.3.1 DispatcherServlet是一个Servlet 

5.3.2 Spring MVC的完整请求流程 

5.4 SpringMVC自动配置 

5.4.1 DispatcherServletAutoConfiguration.class 

5.4.2  WebMvcConfigurationSupport

5.4.3  ServletWebServerFactoryAutoConfiguration 

5.5  Servlets, Filters, and Listeners 

5.5.1 Servlets 

5.5.1.1 @WebServlet使用Servlet

5.5.1.2 ServletRegistrationBean 

5.5.2  创建Filter

5.5.2.1 @WebFilter注解 

5.5.2.2  FilterRegistrationBean

5.5.2.3 Filter排序

5.5.2.4  使用框架中的Filter

5.5.3  Listener

5.6 WebMvcConfigurer

5.6.1 页面跳转控制器 

5.6.2 数据格式化

5.6.3 拦截器

5.6.3.1  一个拦截器 

5.6.3.2  多个拦截器

5.7  文件上传

5.7.1  MultipartResolver 

5.7.2  Servlet规范

5.7.3 多文件上传 

5.8 全局异常处理

5.8.1  全局异常处理器 

5.8.2  BeanValidator异常处理

5.8.3  ProblemDetail [SpringBoot 3] 

5.8.3.1  RFC 7807 

5.8.3.2  MediaType

5.8.3.3 Spring支持Problem Detail 

5.8.3.4  自定义异常处理器ProblemDetail 

5.8.3.5  扩展ProblemDetail 

5.8.3.6 ErrorResponse 

5.8.3.7  扩展ErrorResponseException


第五章 说说Web服务

基于浏览器的B/S结构应用十分流行。Spring Boot非常适合Web应用开发。可以使用嵌入式Tomcat、Jetty、Undertow或Netty创建一个自包含的HTTP服务器。一个Spring Boot的Web应用能够自己独立运行,不依赖需要安装的Tomcat,Jetty等。

Spring Boot可以创建两种类型的Web应用 

  • 基于Servlet体系的Spring Web MVC应用
  • 使用spring-boot-starter-webflux模块来构建响应式,非阻塞的Web应用程序

Spring WebFlux是单独一个体系的内容,其他课程来说。 当前文档讲解 Spring Web MVC。又被称为“Spring MVC”。Spring MVC是“model view controller”的框架。专注web应用开发。我们快速的创建控制器(Controller),接受来自浏览器或其他客户端的请求。并将业务代码的处理结果返回给请求方。 

Spring MVC处理请求: 

5.1 高效构建Web应用

创建Web应用,Lession12-quick-web。 依赖选择spring-web 包含了Spring MVC , Restful, Tomcat这些功能。再选择Thymeleaf(视图技术,代替jsp),Lombok依赖。包名 com.bjpowernode.quickweb。 项目结构: 

5.1.1  html页面视图

step1: Maven依赖

spring-web starter 

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- 视图技术 Thymeleaf模板引擎 -->
<dependency>
  
<groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

<!-- Lombok -->
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <optional>true</optional>
</dependency>

step2: 创建Controller

在根包的下面,创建子包controller,并创建QuickController

@Controller
public class QuickController {

  @RequestMapping("/exam/quick")
  public String quick(Model model){
    //业务处理结果数据,放入到Model模型
    model.addAttribute("title", "Web开发");
    model.addAttribute("time", LocalDateTime.now());
    return "quick";
  }
}

step3: 创建视图

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>视图</title>
</head><body>
  <!--格式化,排列数据,视图在浏览器显示给用户-->
  <h3>显示请求处理结果</h3>
  <p th:text="${title}"></p>
  <p th:text="${time}"></p>
</body>
</html>

step4:代码编写完成,现在运行启动类,在浏览器访问exam/quick url地址

编写Spring MVC的应用分成三步:

  1. 编写请求页面(在浏览器直接模拟的请求)
  2. 编写Controller
  3. 编写视图页面

5.1.2 JSON视图 

上面的例子以Html文件作为视图,可以编写复杂的交互的页面,CSS美化数据。除了带有页面的数据,还有一种只需要数据的视图。比如手机应用app,app的数据来自服务器应用处理结果。app内的数据显示和服务器无关,只需要数据就可以了。主流方式是服务器返回json格式数据给手机app应用。我们可以通过原始的HttpServletResponse应该数据给请求方。 借助Spring MVC能够无感知的处理json。 

step1:创建Controller 

@Data
public class User {
  private String name;
  private Integer age;
}


@Controller
public class JSONViewController {

  //HttpServletResponse
  @RequestMapping("/exam/json")
  public void exam1(HttpServletResponse response) throws IOException {
    String data="{\"name\":\"lisi\",\"age\":20}";
    response.getWriter().println(data);
  }

  //@ResponseBody
  @RequestMapping("/exam/json2")
  @ResponseBody public User exam2()  {
    User user = new User();
    user.setName("张三");
    user.setAge(22);
    return  user;
  }
}

注意:从Spring6. Spring Boot3开始 javax包名称,修改为jakarta。

原来:

javax.servlet.http.HttpServletRequest;

修改后:

jakarta.servlet.http.HttpServletRequest;

step2:浏览器测试两个地址 

构建前-后端分离项目经常采用这种方式。 

5.1.3  给项目加favicon

什么是favicon.ico :

favicon.ico是网站的缩略标志,可以显示在浏览器标签、地址栏左边和收藏夹,是展示网站个性的logo标志。 

 我们自己的网站定制logo。首先找一个在线工具创建favicon.ico。比如https://quanxin.org/favicon , 用文字,图片生成我们需要的内容。生成的logo文件名称是favicon.ico

step1:将生成的favicon.ico拷贝项目的resources/ 或 resources/static/ 目录。

step2:在你的视图文件,加入对favicon.ico的引用。 

在视图的<head>部分加入 

<link rel="icon" href="../favicon.ico" type="image/x-icon"/>

代码如下

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>视图</title>
  <link rel="icon" href="../favicon.ico" type="image/x-icon"/>
</head>
<body>

测试:浏览器访问项目地址http://localhost:8080/favicon.ico

注意:

  1. 关闭缓存,浏览器清理缓存
  2. 如果项目有过滤器,拦截器需要放行对favicon.ico的访问 

5.2 Spring MVC 

Spring MVC是非常著名的Web应用框架,现在的大多数Web项目都采用Spring MVC。它与Spring有着紧密的关系。是Spring 框架中的模块,专注Web应用,能够使用Spring提供的强大功能,IoC , Aop等等。

Spring MVC框架是底层是基于Servlet技术。遵循Servlet规范,Web组件Servlet,Filter,Listener在SpringMVC中都能使用。同时 Spring MVC也是基于MVC架构模式的,职责分离,每个组件只负责自己的功能,组件解耦。 学习Spring MVC首先具备Servlet的知识,关注MVC架构的M、V、C在 Spring MVC框架中的实现。掌握了这些就能熟练的开发Web应用。

Spring Boot的自动配置、按约定编程极大简化,提高了Web应用的开发效率 

5.2.1 控制器Controller 

控制器一种有Spring管理的Bean对象,赋予角色是“控制器”。作用是处理请求,接收浏览器发送过来的参数,将数据和视图应答给浏览器或者客户端app等。

控制器是一个普通的Bean,使用@Controller或者@RestController注释。 @Controller被声明为@Component。所以他就是一个Bean对象。源代码如下: 

如何创建控制器对象?

创建普通Java类,其中定义public方法。类上注解@Controller或者@RestController。

控制器类中的方法作用:

Controller类中的方法处理对应uri的请求, 一个(或多个)uri请求交给一个方法处理。就是一个普通的方法。方法有参数,返回值。方法上面加入@RequestMapping,说明这个uri由这个方法处理。

5.2.1.1  匹配请求路径到控制器方法

SpringMVC支持多种策略,匹配请求路径到控制器方法。AntPathMatcher 、 PathPatternParser 

从SpringBoot3推荐使用 PathPatternParser策略。比之前AntPathMatcher提示6-8倍吞吐量。

我们看一下PathPatternParser中有关uri的定义

通配符:

  • ? : 一个字符
  • * : 0或多个字符。在一个路径段中匹配字符
  • **:匹配0个或多个路径段,相当于是所有
  • 正则表达式: 支持正则表达式 

RESTFul的支持路径变量

{变量名}

{myname:[a-z]+}: 正则皮a-z的多个字面,路径变量名称“myname”。@PathVariable(“myname”)

{*myname}: 匹配多个路径一直到uri的结尾 

例子: 

@GetMapping("/file/t?st.html")
?匹配只有一个字符
( GET http://localhost:8080/file/test.html
( GET http://localhost:8080/file/teest.html

@GetMapping("/file/t?st.html")
public String path1(HttpServletRequest request){
  return "path请求="+request.getRequestURI();
}
@GetMapping ("/images/*.gif")
*:匹配一个路径段中的0或多个字符
( GET http://localhost:8080/images/user.gif
( GET http://localhost:8080/images/cat.gif
( GET http://localhost:8080/images/.gif

( GET http://localhost:8080/images/gif/header.gif
( GET http://localhost:8080/images/dog.jpg

@GetMapping ("/images/*.gif")
public String path2(HttpServletRequest request){
  return "* 请求="+request.getRequestURI();
}
@GetMapping ("/pic/**")
** 匹配0或多段路径, 匹配/pic开始的所有请求
( GET http://localhost:8080/pic/p1.gif
( GET http://localhost:8080/pic/20222/p1.gif
( GET http://localhost:8080/pic/user
( GET http://localhost:8080/pic/

@GetMapping ("/pic/**")
public String path3(HttpServletRequest request){
  return "/pic/**请求="+request.getRequestURI();
}

RESTFul

@GetMapping("/order/{*id}")
{*id} 匹配 /order开始的所有请求, id表示order后面直到路径末尾的所有内容。
      id自定义路径变量名称。与@PathVariable一样使用

( GET http://localhost:8080/order/1001
( GET http://localhost:8080/order/1001/2023-02-16

@GetMapping("/order/{*id}")
public String path4(@PathVariable("id") String orderId, HttpServletRequest request){
  return "/order/{*id}请求="+request.getRequestURI() + ",id="+orderId;
}
注意:@GetMapping("/order/{*id}/{*date}")无效的, {*..}后面不能在有匹配规则了
@GetMapping("/pages/{fname:\\w+}.log")
:\\w+ 正则匹配, xxx.log

( GET http://localhost:8080/pages/req.log
( GET http://localhost:8080/pages/111.log

( GET http://localhost:8080/pages/req.txt
( GET http://localhost:8080/pages/###.log

@GetMapping("/pages/{fname:\\w+}.log")
public String path5(@PathVariable("fname") String filename, HttpServletRequest request){
  return "/pages/{fname:\\w}.log请求="+request.getRequestURI() + ",filename="+filename;
}

5.2.1.2 @RequestMapping

@RequestMapping:用于将web请求映射到控制器类的方法。此方法处理请求。可用在类上或方法上。 在类和方法同时组合使用。

重要的属性

  • value:别名path 表示请求的uri, 在类和方法方法同时使用value,方法上的继承类上的value值。
  • method:请求方式,支持GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE。 

值为:RequestMethod[] method()  , RequestMethod是enum类型。 

快捷注解

  • @GetMapping: 表示get请求方式的@RequestMapping
  • @PostMapping:表示post请求方式的@RequestMapping
  • @PutMapping:表示put请求方式的@RequestMapping
  • @DeleteMapping: 表示delete请求方式的@RequestMapping 

对于请求方式get,post,put,delete等能够HttpMethod表示,Spring Boot3之前他是enum,Spring Boot3他是class 

public enum HttpMethod      Spring Boot3之前他是enum

public final class HttpMethod  Spring Boot3他是class 

5.2.1.3 控制器方法参数类型与可用返回值类型 

参数类型 

类型 作用
WebRequest, NativeWebRequest 访问请求参数,作用同ServletRequest,
jakarta.servlet.ServletRequest, jakarta.servlet.ServletResponse Servlet API中的请求,应答
jakarta.servlet.http.HttpSession Servlet API的会话
jakarta.servlet.http.PushBuilder Servlet 4.0 规范中推送对象
HttpMethod 请求方式
java.io.InputStream, java.io.Reader IO中输入,读取request body
java.io.OutputStream, java.io.Writer IO中输入,访问response body
@PathVariable,@MatrixVariable,@RequestParam,@RequestHeader,@CookieValue,@RequestBody,@RequestPart,@ModelAttribute uri模板中的变量,访问矩阵,访问单个请求参数,访问请求header,访问cookie,读取请求 body, 文件上传, 访问model中属性
Errors, BindingResult 错误和绑定结果
java.util.Map, org.springframework.ui.Model, org.springframework.ui.ModelMap 存储数据Map,Model,ModelMap
其他参数 String name, Integer , 自定义对象
完整https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-arguments

 返回值:

返回值类型 作用
@ResponseBody 将response body属性序列化输出
HttpEntity<B>, ResponseEntity<B> 包含http状态码和数据的实体
String 实体名称或字符串数据
自定义对象 如果有json库,序列化为json字符串
ErrorResponse 错误对象
ProblemDetail RFC7807,规范的错误应答对象
void 无返回值
ModelAndView 数据和视图
java.util.Map, org.springframework.ui.Model 作为模型的数据
...https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-return-types

5.2.1.4 接收请求参数

用户在浏览器中点击按钮时,会发送一个请求给服务器,其中包含让服务器程序需要做什么的参数。 这些参数发送给控制器方法。控制器方法的形参列表接受请求参数。

接受参数方式: 

  • 请求参数与形参一一对应,适用简单类型。形参可以有合适的数据类型,比如String,Integer ,int等。
  • 对象类型,控制器方法形参是对象,请求的多个参数名与属性名相对应。
  • @RequestParam注解,将查询参数,form表单数据解析到方法参数,解析multipart文件上传。
  • @RequestBody,接受前端传递的json格式参数。
  • HttpServletRequest 使用request对象接受参数, request.getParameter(“...”)
  • @RequestHeader ,从请求header中获取某项值 

解析参数需要的值,SpringMVC 中专门有个接口来干这个事情,这个接口就是:HandlerMethodArgumentResolver,中文称呼:处理器方法参数解析器,说白了就是解析请求得到 Controller 方法的参数的值。 

5.2.1.4.1 接收json 

step1:创建控制器类 

@Data
public class User {
  private String name;
  private Integer age;
}

@RestController
public class ParamController {

  @PostMapping("/param/json")
  public String getJsonData(@RequestBody User user){
    System.out.println("接收的json:"+user.toString());
    return "json转为User对象"+user.toString();
  }
}

IDEA Http Client测试:

POST http://localhost:8080/param/json
Content-Type: application/json

{"name":"lisi","age":22}

接收 json array

step1:创建控制器方法 

@PostMapping("/param/jsonarray")
public String getJsonDataArray(@RequestBody List<User> users){
  System.out.println("接收的json array:"+users.toString());
  return "json转为List<User>对象"+users.toString();
}

测试:
POST http://localhost:8080/param/jsonarray
Content-Type: application/json

[
 {"name":"lisi","age":22},
 {"name":"zhangesan","age":26},
 {"name":"zhouli","age":30}
]

5.2.1.4.2 Reader-InputStream

Reader 或 InputStream 读取请求体的数据, 适合post请求体的各种数据。具有广泛性。

step1:创建新的控制器方法 

@PostMapping("/param/json2")
public String getJsonData2(Reader in)  {
  StringBuffer content = new StringBuffer("");
  try(BufferedReader bin = new BufferedReader(in)){
      String line = null;
      while( (line=bin.readLine()) != null){
        content.append(line);
      }
  } catch (IOException e) {
     throw new RuntimeException(e);
  }
  return "读取请求体数据"+ content.toString();
}

IDEA Http Client测试:

POST http://localhost:8080/param/json2
Content-Type: application/json 可无

{"name":"lisi","age":26}

5.2.1.4.3 数组参数接收多个值

 数组参数接收多个值 数组作为形参,接受多个参数值 ,请求格式 参数名=值1&参数名=值2... 

@GetMapping("/param/vals")
public String getMultiVal(Integer [] id){
  List<Integer> idList = Arrays.stream(id).toList();
  return idList.toString();
}

测试请求:
GET http://localhost:8080/param/vals?id=11&id=12&id=13
GET http://localhost:8080/param/vals?id=11,12,13,14,15

都是成功的方式

5.2.1.5 验证参数

服务器端程序,Controller在方法接受了参数,这些参数是由用户提供的,使用之前必须校验参数是我们需要的吗,值是否在允许的范围内,是否符合业务的要求。比如年龄不能是负数,姓名不能是空字符串,email必须有@符号,phone国内的11位才可以。

验证参数 

  • 编写代码,手工验证,主要是if语句,switch等等。
  • Java Bean Validation : JSR-303是JAVA EE 6 中的一项子规范,叫做 Bean Validation, 是一个运行时的数据验证规范,为 JavaBean 验证定义了相应的元数据模型和API。 

5.2.1.5.1 Java Bean Validation 

Spring Boot使用Java Bean Validation验证域模型属性值是否符合预期,如果验证失败,立即返回错误信息。 Java Bean Validation将验证规则从controller,service集中到Bean对象。一个地方控制所有的验证。

Bean的属性上,加入JSR-303的注解,实现验证规则的定义。JSR-3-3是规范,hibernate-validator是实现。 

JSR-303: https://beanvalidation.org/  ,最新3.0版本,2020年10.

hibernate-validator:https://hibernate.org/validator/                 https://docs.jboss.org/hibernate/validator/4.2/reference/en-US/html/ 

5.2.1.5.2 JSR-303注解 

JSR-303定义的常用注解:

注解 作用
@Null 被注释的元素必须为 null
@Null 被注释的元素必须不为 null
@AssertTrue 被注释的元素必须为 true
@AssertFalse 被注释的元素必须为 false
@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max, min) 被注释的元素的大小必须在指定的范围内
@Digits (integer, fraction) 被注释的元素必须是一
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值