前言
大家好,一直以来我都本着 用最通俗的话理解核心的知识点, 我认为所有的难点都离不开 基础知识 的铺垫
适合人群
- 学完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, 配合使用。它可以作用到类和方法上。
它可以处理GET和POST请求, 也就是说发送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语法,我们下期不见不散 ~