5.1 处理Http请求
所谓处理Http请求,就是SpringBoot把用户通过URL地址发送的请求交给不同的业务代码进行处理的过程。
5.1.1使用@Controller声明控制器类
被@Controller标注的类称作控制器类,这个注解本身被@Component注解标注,所以控制器也属于组件。这说明他们SpringBoot启动时控制器类就会被自动扫描进容器中。
5.1.2使用@RequestMapping映射URL地址
SpringBoot提供了用于映射URL地址的@RequestMapping注解。
如果@RequestMapping标注在控制器类上,则控制器类内所有的请求都必须要带上控制器类所映射的地址。
如果@RequestMapping标注在控制器类的方法上,则必须方法上的映射地址保证不一样,否则编译不过(创建了相同的Bean)
@Controller
@RequestMapping("say")//控制器的地址,里面所有的方法都要使用这个地址
public class HelloController {
//下面的格式都可以,但只能有一个@RequestMapping标注
// @RequestMapping("/hello1")
// @RequestMapping("hello2")
// @RequestMapping(value = "/hello3")
// @RequestMapping(value = {"hello4","hello5"}) //支持映射多个地址
@RequestMapping("hello") //请求接口为localhost:端口号/say/hello
@ResponseBody //返回的字符串被直接显示在浏览器上
public String sayHello() {
return "hello http" ;
}
}
@RequestMapping注解有value method params headers等属性
- value确定映射地址
- method确定http请求的类型 RequestMethod.GET RequestMethod.POST等
- parames确定http请求所必须携带的参数,类型为字符串数组,所以可以指定多个参数
- headers确定http请求中须包含哪些指定的请求头,请求头是以键值对形式存在,故headers以map形式存数据,形式如:@RequestMapping(headers={ "k1 = v1", "k2 = v2","k3 = v3",...})
- consumes属性能够指定请求的数据类型,常见的是"application/json" "text/html"等。
5.1.3解析@ResponseBody的作用及其用法
@ResponseBody注解的作用是将标注的方法的返回值转为页面数据,如果是字符串,则返回字符串,如果是其他类型的数据,则会被自动封装为JSON格式的字符串。
注意注意:如果控制器类方法没有使用@ResponseBody注解,那么这个方法的返回值是即将跳转的URL地址。现在主流开发都是前后端分离,所以基本都要用@ResponseBody。
5.1.4 新增注解-@RestController
既然主流开发都是前后端分离的方式,每个方法或者控制器类都要加@ResponseBody,那就太重复了,于是有了组合类@RestController。
@Controller+@ResponseBody====>@RestController
这样看起来就简化很多。
5.2 重定向URL地址
重定向URL地址是指用户通过原始的URL发送的请求指向了新的URL地址,并且请求上的数据不会被保留,也就是通过重定向URL地址,服务器可以把用户推送到其他网站。
5.2.1使用"redirect:"前缀
如果需要用到重定向功能,那就不用使用@ResponseBody这个注解了
@Controller
public class HelloController {
@RequestMapping("redirect")
public String redirect(){
return "redirect:http://www.baidu.com";//重定向到百度
}
}
5.2.2使用response对象
presonse对象指的是HttpServletResponse类型的对象,也可用于实现重定向URL的功能。
需要确保此方法没有返回值。
@RequestMapping("response")
public void goBd(HttpServletResponse response){
try {
response.sendRedirect("http://wwww.baidu.com");
}catch (IOException e){
e.printStackTrace();
}
}
5.3 解析URL地址中的参数
5.3.1自动解析URL地址中的参数
SpringBoot能够自动解析URL地址中的参数,并将参数注入到方法的参数中,只需要URL地址中的值,在方法中设置为同类型,同名的参数即可。
//请求地址 localhost:8088/hello?age=18&name=lilei
@RequestMapping("hello")
public String autoParams(String name, int age) {
return "hello ,my name is " + name + " ,now I am " + age;
}
自动识别参数需要注意:
- SpringBoot可以识别各种类型的URL的参数,比如GET/POST/PUT等
- 参数名需要区分大小写
- 参数根据名称来确定,所以不需要顺序一致,参数个数一致,取不到的参数即为空
- 方法参数不应采用基本数据类型
5.3.2使用@RequestParam标注方法参数
如果不想代码中的参数暴露给用户,可以使用@RequestParam注解对方法中的参数进行标注。
//请求地址 localhost:8088/hello?age=18&name=lilei
@RequestMapping("hello")
public String autoParams(@RequestParam("name") String name1,@RequestParam("age") int age1,@RequestParam(value = "address" ,defaultValue = "shenzhen")String address) {
return "hello ,my name is " + name1 + " ,now I am " + age1+" I'm in "+address;
}
@RequestParam的属性:
- value 指定当前方法参数映射的URL的参数名,默认属性,可以隐式调用。
- name 同value
- required 指定此参数是否是必须参数,默认为true,如果true但实际请求url并无此参数,直接报缺少请求参数异常。
- defaultValue 如果请求url并无此参数,理论上会爆异常,但你可以设置默认值,从而规避异常
5.3.3使用@RequestBody封装JSON数据
URL地址中的参数键值对可以看成是JSON格式,@RequestBody就可以把这个JSON格式直接封装成实体类对象。
/**请求地址 localhost:8088/hello
请求参数应使用Body形式添加,如下
{ "name":"lilei",
"age":18,
"address":"shenzhen"
}
**/
@RequestMapping("hello")
public String autoParams(@RequestBody StudentInfo info) {
return "hello ,my name is " + info.getName() + " ,now I am " + info.getAge()+" I'm in "+info.getAddress();
}
注意注意:只有使用POST方式,请求中才包含键值对
5.3.4获取request、response和session对象的方式
在开发项目过程中,经常要用到request/response/session来解决问题。
- request: 用于从请求中接收数据
- response: 对已经接收到的数据做出相应
- session: 保存用户的请求,并跟踪这个请求的操作状态
可以通过2个方法获取这三个对象。
- 注入属性
SpringBoot会自动创建request对象和response对象的Bean,控制器类可以直接注入这两个Bean。
其中request对象的类型为HttpServletRequest
response对象的类型为HttpSerlvetResponse
用注入属性的方式存在问题,当前记录此问题,先不深入排查此问题
@RestController
public class HelloController {
@Autowired
HttpServletRequest request;//这个方法不得行,Could not autowire. No beans of 'HttpServletRequest' type found.
@Autowired
HttpServletResponse response;//这个方法不得行,Could not autowire. No beans of 'HttpServletResponse' type found.
@RequestMapping("hello")
public String hello() {
HttpSession session = request.getSession();
return "hello";
}
}
- 注入参数
注入参数的意思就是直接向控制器类的处理方法中添加HttpServletRequest/HttpServletResponse和HttpSession类型的参数。
@RequestMapping("hello")
public String hello(HttpServletRequest request,HttpServletResponse response,
HttpSession session) {//不影响请求url的其他参数
request.setAttribute("id",1);
response.setHeader("response","success");
session.setAttribute("loginstate",true);
return "hello";
}
5.4 使用RESTful风格映射动态URL地址
5.4.1 什么是RESTful风格
REST是一种软件架构规则,直译为表述性状态传递,可以理解为让HTTP请求用更简洁/最直观的方式来表达。
举个栗子:
传统的方式url传参为: localhost:8080/info?id=10&name=lilei&age=8
而以RESTful的风格,就变成了 localhost:8080/info/10/lilei/8
这就会有2个问题,不知道这个接口要干什么和不知道url上的参数怎么和处理http方法的参数进行对应。
可以根据http请求类型来确定这个接口要干什么
有以下约定的对应关系
|--------|--------|----------------------|----------------|
| 请求类型 | 约定业务类型 | 对应枚举 | 对应注解 |
| GET | 查询信息 | RequestMethod.GET | @GetMapping |
| POST | 创建信息 | RequestMethod.POST | @PostMapping |
| PUT | 更新信息 | RequestMethod.PUT | @PutMapping |
| PATCH | 更新部分信息 | RequestMethod.PATCH | @PatchMapping |
| DELETE | 删除信息 | RequestMethod.DELETE | @DeleteMapping |
对应新增的注解,即为@RequestMapping+确定method属性的简化。
而第2个问题就需要映射动态URL地址来解决。
5.4.2 映射动态URL地址
可以对url中的参数做分割处理,分别用{}作为动态url的占位符
//localhost:8088/info/10/lilei/8
@GetMapping("info/{id}/{name}/{age}")
public String hello(@PathVariable Integer id,@PathVariable String name,@PathVariable Integer age) {
return "hello , My id is "+id+" ,My name is "+name+" ,and now I'm "+age+" years old";
}
显示:hello , My id is 10 ,My name is lilei ,and now I'm 8 years old
这里用到的注解@PathVariable可以将URL地址中参数占位符的值注入到方法参数中,@PathVariable会自动根据方法的名称进行匹配,先后顺序不会影响注入结果。
如果不想URL定位符的标识与方法参数一致,可以用@PathVariable的value属性对URL的参数匹配即可
//localhost:8088/info/10/lilei/8
@GetMapping("info/{id}/{name}/{age}")
public String hello(@PathVariable(value = "id") Integer studentId,@PathVariable String name,@PathVariable Integer age) {
return "hello , My studentId is "+studentId+" ,My name is "+name+" ,and now I'm "+age+" years old";
}
显示:hello , My studentId is 10 ,My name is lilei ,and now I'm 8 years old
打完收工。