SpringBoot中的请求处理(超详细)

2,478 阅读7分钟

前言

大家好,一直以来我都本着 用最通俗的话理解核心的知识点, 我认为所有的难点都离不开 基础知识 的铺垫

适合人群

  • 学完Java基础
  • 想通过Java快速构建web应用程序
  • 想学习或了解SpringBoot

大佬可以绕过 ~

背景

本节给大家讲讲 Java的SpringBoot框架, 之前我们学习的都是java的基础知识和底层提供的一些能力,我们日常工作都是在写接口。在我们在产品开发中,一般我们都会选择比较稳定的框架来帮我们加速开发,不会自己去造轮子,而在java众多框架中,spring框架表现的非常好,大部分公司都会首选它作为开发框架,而至今,大部分企业都是以springboot来构建项目了~

情景回顾

上期我们讲解了springboot的基础配置以及常用的几个注解,并且给他们做了一个比较,本期呢,带大家学习一下springboot中的http请求处理, 同样的,本节我们依然学习新的注解。最近github可能会被墙,所以我把源码放到了国内gitee上,本节我们依然使用上期的代码

往期内容

项目源码(持续更新⭐️)

@Controller & @RestController

首先,@RestController,大家都不陌生,因为前几节我们讲过,它主要用于rest api。而这个@Controller从字面意思讲,它也是一个控制器,那它有什么不同呢?我们从代码来看一下:

@Controller
public class WebController {
    
    @RequestMapping
    public String index() {
        return "index";
    }
}

当我们新建完这个类的时候,先不着急运行,我们把鼠标移到"index"上,如果你是idea,它的下标会有波浪线提示无法解析 MVC 视图 'index',我们可以猜测到,它是视图控制器使用的。下面运行一下 GET http://localhost:8080/api/index

Circular view path [index]: would dispatch back to the current handler URL [/api/index] again. Check your ViewResolver setup! (Hint: This may be the result of an unspecified view, due to default view name generation.)

好家伙,直接报错, 说的没有view set,意思是没有设置视图,那怎么解决这个问题呢?很简单,设置一个不就好了,这里给大家推荐使用比较多的模板引擎thymeleaf, 我们在pom.xml加入:

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

添加模板文件:

<!-- src/main/resources/templates/index.html -->
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1 th:text="${data}"></h1>
</body>
</html>

然后,我们把鼠标放到原来的位置,发现没有波浪线提示了,说明问题解决了, 修改一下控制器

@Controller
public class WebController {

    @RequestMapping
    public String index(HashMap<String,Object> map) {
        map.put("data","我是数据data");
        return "index";
    }
}

th:text="${data}"是它的一个模板语法,用来做数据渲染的,这不是本节的重点,所以不多讲,有兴趣的小伙伴可以搜索一下它的使用教程,现在都是前后端分离的开发模式,所以不用过多深入去学习

@RequestMapping

这个注解其实在入门篇的时候,我们就已经使用过了,但是没有细讲,它的主要作用就是将http 请求映射到我们的控制器上,也就是@Controller & @RestController, 配合使用。它可以作用到和方法上。

它可以处理GETPOST请求, 也就是说发送POST和GET都可以被处理。那有什么办法只让它处理GET请求呢?方法很简单,只需要给它加属性就好了, 包括自定义请求头的设置

    @RequestMapping(value = "/hello3", headers = {}, method = RequestMethod.GET)
    public String hello3(){
        HelloService.hello();
        return "Hello World!";
    }

我们最常用的就是这两种请求了,下边就给大家讲讲他们分开的处理方法

@GetMapping

只针对GET的请求处理, 那么get请求下的参数怎么去接收和处理呢?下面主要有两种情况

  • 针对 /path/$var的处理

  • 针对 /path?arg=$val的处理

我们先说第一种,也就是路径上的参数,通常用于详情的接口,比如/detail/id, 我们看下代码:

@GetMapping("/hello4/{id}")
public String hello4(@PathVariable String id){
    return "Hello World!" + id;
}

第二种也很简单, 比如这种/user?name=xiaomimg这种query参数的处理

@GetMapping("/hello5/user")
public String hello5(@RequestParam String name){
    return "Hello World!" + name;
}

PostMapping

上边我们说的get请求都是在对url携带的参数做处理,在post中上述也可以适用,但是我们一般都是把参数放到body里,这样就不会把信息暴露到url上, 那怎么处理呢? 一般这种请求用于数据的上报或者修改,get一般用于数据的获取,比如获取文章列表,获取文章详情等,废话不多说直接上代码:

@PostMapping("/hello6/create")
public String hello6(@RequestBody String name){
    return "Hello World!" + name;
}

上边这是简单的请求, 我们知道一般我们发出的post请求通常都会携带大量的参数,不会这么几个这么简单,那我要一个个这样写吗,显然不友好,后边如果有复用的表单信息,难不成又复制一遍,不利于维护, 我们可以集中定义到一个类身上,就拿修改文章和创建文章这两个接口来讲,其实他们之间的区别就在于是否有id,有id说明文章存在,做修改操作,下边我们就实际操作一下:

首先创建一个接收参数的公共类:

public class Post {
    
    private Integer id;
    
    private String title;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getCover() {
        return cover;
    }

    public void setCover(String cover) {
        this.cover = cover;
    }

    private String content;
    
    private String cover;
}


添加请求方法:

@PostMapping("/post/create")
public String create(@RequestBody Post req){
    return "Hello World!" + req.getTitle();
}

@PostMapping("/post/update")
public String update(@RequestBody Post req){
    return "Hello World!" + req.getContent();
}

这样写是不是简洁很多,后续只要维护Post类就可以了,加字段就在里边加就好了~

参数校验

关于参数校验,当一个请求进来,我们不可能两眼一抹黑啥请求都接着,对于一些缺参少参的请求,我们应当拒之门外,这样一方面可以缓解服务器和数据库的压力,另一方面减少脏数据的产生,我们应该尽可能的让我们的请求产生的数据完整。另外,对于安全性较高的系统我们需要对参数进行签名和加解密的操作,所以校验非常的重要,针对签名方式和加解密后边会有专门一节讲解~ 耐心等待

其实Springboot也提供了一套注解来对参数的类型和值做校验,但是这里并没有给大家介绍,对于校验这一块,我更建议大家自定义去处理,为什么这么说,因为对流程上比较严谨的系统,我们要溯源问题,这个过程会产生日志,甚至有告警等,自定义处理方式我们可以更加的灵活,我们也可以自己封装一套, 我们可以拿枚举去针对每种情况下,返回给前端特定的状态码和错误信息, 对用户反馈的交互也都比较的友好

请求头信息的获取

有时候我们需要获取请求头中的信息,比如cookie信息的获取,怎么做呢? 我们来看下代码

@GetMapping("/hello7")
public String hello7(HttpServletRequest req){
    return "Hello World!" + req.getHeader("Cookie");
}

只需要添加 HttpServletRequest req 参数就好了,可能你会问了,这不是写请求参数的地方吗,那我接收参数,写哪?跟在后边写就好了,前面也可以,位置随便,对@PostMapping、@GetMapping、@RequestMapping 都生效

这里多讲一些,请求头中的信息还是比较重要的,它存放着很多重要的信息,有时候我们需要对请求做处理,光看参数看不出啥来,有时候我们要对设备做处理,不同设备返回不同信息,甚至屏蔽,比如ua判断, 甚至ip封禁,都会用到它, 更多的做跨域处理、请求日志记录

@RestControllerAdvice

这个注解控制器是用来处理全局错误的, 就是说对异常做特殊响应,不至于啥都返回502,我们直接看代码,用户是看不懂啥是502

@RestControllerAdvice
public class ExceptionController {
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public String error(Exception e) {
        return e.getMessage();
    }
}

结束语

本节到此就结束了,我们主要讲了控制器请求处理以及它们的参数是如何接收和处理的,建议大家多自己练习练习,写着写着就熟悉了,不要去背单词,要去理解它,适当的做些总结, 最新的代码已经同步到仓库了

下期预告

下期我会给大家讲讲MyBatis的使用, 没错,下期我们就来和数据库打交道了, 同时会教大家安装Mysql和学习简单的sql语法,我们下期不见不散 ~