Spring boot之Rest 风格请求处理--接收参数相关注解--复杂参数和自动封装讲解

582 阅读7分钟

Spring boot之Rest 风格请求处理

基本介绍

1. Rest 风格支持(使用HTTP 请求方式动词来表示对资源的操作)

举例说明:

● 请求方式: /monster

● GET-获取怪物

● DELETE-删除怪物

● PUT-修改怪物

● POST-保存妖怪

SpringBoot Rest 风格应用实例

需求: 演示SpringBoot 中如何实现Rest 风格的增删改查

 

应用实例 

创建MonsterController.java

@RestController
public class MonsterController {

    //等价的写法
    //@RequestMapping(value = "/monster",method = RequestMethod.GET)
    @GetMapping("/monster")
    public String getMonster() {
        return "GET-查询妖怪";
    }

    //等价写法
    //@RequestMapping(value = "/monster", method = RequestMethod.POST)
    @PostMapping("/monster")
    public String saveMonster() {
        return "POST-添加妖怪";
    }

    //等价写法
    //@RequestMapping(value = "/monster",method = RequestMethod.PUT)
    @PutMapping("/monster")
    public String putMonster() {
        return "PUT-修改妖怪~~";
    }

    //等价写法
    //@RequestMapping(value = "/monster", method = RequestMethod.DELETE)
    @DeleteMapping("/monster")
    public String delMonster() {
        return "DELETE-删除妖怪";
    }

}

使用Postman 完成测试

请求url: http://localhost:8080/monster

Rest 风格请求-注意事项和细节

1、客户端是PostMan 可以直接发送Put、delete 等方式请求,可不设置Filter

2、如果要SpringBoot 支持页面表单的Rest 功能, 则需要注意如下细节

1) Rest 风格请求核心Filter ; HiddenHttpMethodFilter , 表单请求会被HiddenHttpMethodFilter 拦截, 获取到表单_method 的值, 再判断是PUT/DELETE/PATCH

(注释: PATCH 方法是新引入的,是对PUT 方法的补充,用来对已知资源进行局部更新:
segmentfault.com/q/101000000…)

2) 如果要SpringBoot 支持页面表单的Rest 功能, 需要在application.yml 启用filter 功能,
否则无效

3) 修改application.yml 启用filter 功能

spring:
  mvc:
    #static-path-pattern: /hellores/** #修改静态资源访问的路径/前缀
    hiddenmethod:
      filter:
        enabled: true #启用了HiddenHttpMethodFilter,开启页面表单的Rest功能
    
  web:
    resources:
      #修改/指定 静态资源的访问路径/位置
      #
      static-locations: ["classpath:/ninhaoimg/","classpath:/META-INF/resources/",
                         "classpath:/resources/", "classpath:/static/", "classpath:/public/"]      #String[] staticLocations

4) 修改对应的页面,

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>rest</title>
</head>
<body>
<h1>测试rest风格的url, 来完成请求.</h1>
<form action="/monster" method="post">
    u: <input type="text" name="name"><br/>
    <!--    通过隐藏域传递_method 参数指定值-->
    <input type="hidden" name="_method" value="delete">
    <input type="submit" value="点击提交">
</form>
</body>
</html>

完成测试

注意 url 是localhost:8080/hellores/rest.html, 如果希望url 是

localhost:8080/rest.html, 将application.yml static-path-pattern: /hellores/** 注销即可

问题

为什么这里return "GET-查询妖怪", 返回的是字符串, 而不是转发到对应的资源文件?-SpringMVC 

 解读:

因为@ResController 是一个复合注解, 含有@ResponseBody, 所以springboot 底层(springmvc), 在处理

return "xxx" 时, 会以@ResponseBody 注解进行解析处理, 即返回字符串"xxx", 而不会使用视图解析器来处理.

如果我们把@RestController 改成@Controller ,

当你访问getMonster() 时, 如果你有xxx.html就会转发到xxx.html , 如果没有xxx.html , 就会报404

提示: 在测试时, 讲xxx.html 放在main\resources\public\xxx.html 进行测试, 并在application.yml 配置视图解析器

---在application.yml 配置解析器-----
spring:
  mvc:
    #static-path-pattern: /hellores/** #修改静态资源访问的路径/前缀
    hiddenmethod:
      filter:
        enabled: true #启用了HiddenHttpMethodFilter,开启页面表单的Rest功能
    view:       #配置视图解析器
      suffix: .html
      prefix: /        #这里是需要注意 prefix需要和当前的static-path-pattern一致

 创建MonsterController2 测试

注意这个是@Controller 不要用@RestController原因已经上面说了

@Controller
public class MonsterController2 {
    @RequestMapping("/go")
    public String go() {
        return "hello"; // 注意 1 看controller有没有 /hello[没有配置视图解析器]
                        // 2. 如果配置了视图解析器, 就按照视图解析器来定位页面
    }

没有配置视图解析器 就去看controller有没有 没有就报错

@RestController
public class HiController {
    @RequestMapping("/hello")
    public String hi() {
        return "hi:):)";
    }
}

配了的话又是@Controller直接去找页面有没有hello页面没有的话直接404

提示: 测试完后, 把代码恢复原状-----

接收参数相关注解

基本介绍

1. SpringBoot 接收客户端提交数据/参数会使用到相关注解

2. 详解@PathVariable 、@RequestHeader 、@ModelAttribute 、@RequestParam 、@MatrixVariable、@CookieValue、@RequestBody

接收参数相关注解应用实例

需求: 演示各种方式提交数据/参数给服务器,服务器如何使用注解接收

1.创建index.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>

<body>
    <h1>hello,</h1>
    基本注解:
    <hr />
    <a href="monster/100/king">@PathVariable-路径变量monster/100/king</a><br /><br />
</body>

</html>

2.演示@PathVariable 使用,创建ParameterController.java 完成测试

@RestController
public class ParameterController {
    /**
     * /monster/{id}/{name} 解读
     * 1. /monster/{id}/{name} 构成完整请求路径
     * 2. {id} {name} 就是占位变量
     * 3. @PathVariable("name"): 这里name 和{name} 命名保持一致
     * 4. String name_ 这里自定义,故意这样写下
     * 5. @PathVariable Map<String, String> map 把所有传递的值传入map
     * 6. 可以看下@PathVariable源码
     */
    @GetMapping("/monster/{id}/{name}")
    public String pathVariable(@PathVariable("id") Integer id,
                               @PathVariable("name") String name,
                               @PathVariable Map<String, String> map) {
        System.out.println("id-" + id);
        System.out.println("name-" + name);
        System.out.println("map-" + map);
        return "success";
    }
}

3. 演示@RequestHeader 使用,修改ParameterController.java , 完成测试

修改index.html

<a href="requestHeader">@RequestHeader-获取Http 请求头</a><br/><br/>

修改ParameterController.java

 /**
     * @RequestHeader("Host") 获取http请求头的 host信息
     * @RequestHeader Map<String, String> header: 获取到http请求的所有信息
     */
    @GetMapping("/requestHeader")
    public String requestHeader(@RequestHeader("host") String host,
                                @RequestHeader Map<String, String> header,
                                @RequestHeader("accept") String accept) {
        System.out.println("host-" + host);
        System.out.println("header-" + header);
        System.out.println("accept-" + accept);
        return "success";
    }

4. 演示@RequestParam 使用,修改ParameterController.java , 完成测试

修改index.html

<a href="hi?name= nihao&fruit=apple&fruit=pear">@RequestParam- 获取请求参数
</a><br/><br/>

修改ParameterController.java

    /**
     * 解读
     * 如果我们希望将所有的请求参数的值都获取到,可以通过
     * @RequestParam Map<String, String> paras 获取
     */
    @GetMapping("/hi")
    public String hi(@RequestParam(value = "name") String username,
                     @RequestParam("fruit") List<String> fruits,
                     @RequestParam Map<String, String> paras) {

        System.out.println("username-" + username);
        System.out.println("fruit-" + fruits);
        System.out.println("paras-" + paras);
        return "success";
    }

5. 演示@CookieValue 使用,修改ParameterController.java , 完成测试

修改index.html

<a href="cookie">@CookieValue-获取cookie 值</a><br/><br/>

修改ParameterController.java

因为我的浏览器目前没有cookie,我们可以自己设置cookie[技巧还是非常有用]
如果要测试,可以先写一个方法,在浏览器创建对应的cookie

说明

1. value = "cookie_key" 表示接收名字为 cookie_key的cookie

2. 如果浏览器携带来对应的cookie , 那么 后面的参数是String ,则接收到的是对应对value

3. 后面的参数是Cookie ,则接收到的是封装好的对应的cookie 

   /**
     * 因为我的浏览器目前没有cookie,我们可以自己设置cookie[技巧还是非常有用]
     * 如果要测试,可以先写一个方法,在浏览器创建对应的cookie
     * 说明 1. value = "cookie_key" 表示接收名字为 cookie_key的cookie
     * 2. 如果浏览器携带来对应的cookie , 那么 后面的参数是String ,则接收到的是对应对value
     * 3. 后面的参数是Cookie ,则接收到的是封装好的对应的cookie
     */
    @GetMapping("/cookie")
    public String cookie(@CookieValue(value = "cookie_key", required = false) String cookie_value,
                         HttpServletRequest request,
                         @CookieValue(value = "username", required = false) Cookie cookie) {
        System.out.println("cookie_value-" + cookie_value);
        if (cookie != null) {
            System.out.println("username-" + cookie.getName() + "-" + cookie.getValue());
        }
        System.out.println("-------------------------");
        Cookie[] cookies = request.getCookies();
        for (Cookie cookie1 : cookies) {
            System.out.println(cookie1.getName() + "=>" + cookie1.getValue());
        }
        return "success";
    }

6. 演示@RequestBody 使用,修改ParameterController.java , 完成测试

​修改index.html

<h1>测试@RequestBody获取数据: 获取POST请求体</h1>
<form action="/save" method="post">
    姓名: <input name="name"/> <br>
    年龄: <input name="age"/> <br/>
    <input type="submit" value="提交"/>
</form>

修改ParameterController.java

    /**
     * @RequestBody 是整体取出Post请求内容
     */
    @PostMapping("/save")
    public String postMethod(@RequestBody String content) {
        System.out.println("content-" + content);
        return "success";
    }

7. 演示@RequestAttribute 使用,创建RequestController.java ,完成测试 

修改index.html

<a href="login">@RequestAttribute-获取request 域属性-</a>

创建RequestController.java

解读一下 这里请求转发是

重新发送http://localhost:8080/ok 然后/ok会被控制器 /ok捕获

注意@ResponseBody是发送json数据success

@Controller
public class RequestController {

    @GetMapping("/login")
    public String login(HttpServletRequest request) {
        request.setAttribute("user", "132~");//向request域中添加的数据
        request.getSession().setAttribute("website", "http://www.baidu.com"); //向session中添加数据
        return "forward:/ok";  //请求转发到  /ok
    }

    @GetMapping("/ok")
    @ResponseBody//注意
    public String ok(
            HttpServletRequest request,
            @SessionAttribute(value = "website", required = false) String website,
            @RequestAttribute(value = "user", required = false) String username
    ) {
        //获取到request域中的数据
        System.out.println("username-" + username);
        System.out.println("通过servlet api 获取 username-" + request.getAttribute("user"));
        System.out.println("website-" + website);
        System.out.println("通过servlet api 获取 website-" + request.getSession().getAttribute("website"));
        return "success";
    }

复杂参数

基本介绍

1. 在开发中,SpringBoot 在响应客户端请求时,也支持复杂参数

2.Map、Model、Errors/BindingResult、RedirectAttributes、ServletResponse、SessionStatus、UriComponentsBuilder、ServletUriComponentsBuilder、HttpSession

3. Map、Model 数据会被放在request 域, 底层request.setAttribute()

4. RedirectAttributes 重定向携带数据

复杂参数应用实例

说明: 演示复杂参数的使用,重点: Map、Model、ServletResponse

修改RequestController.java

@Controller
public class RequestController {
 @GetMapping("/register")
    public String register(Map<String,Object> map,
                           Model model,
                           HttpServletResponse response) {
        //如果一个注册请求,会将注册数据封装到map或者model
        //map中的数据和model的数据,会被放入到request域中
        map.put("user","hspedu");
        map.put("job","java架构师");
        model.addAttribute("sal", 80000);
        //一会我们再测试response使用
        //我们演示创建cookie,并通过response 添加到浏览器/客户端
        Cookie cookie = new Cookie("email", "nihao@sohu.com");
        response.addCookie(cookie);

        //请求转发
        return "forward:/registerOk";

    }

    @ResponseBody
    @GetMapping("/registerOk")
    public String registerOk(HttpServletRequest request) {

        System.out.println("user-" + request.getAttribute("user"));
        System.out.println("job-" + request.getAttribute("job"));
        System.out.println("sal-" + request.getAttribute("sal"));

        return "success";
    }

}

自定义对象参数-自动封装

基本介绍

1. 在开发中,SpringBoot 在响应客户端请求时,也支持自定义对象参数

2. 完成自动类型转换与格式化

3. 支持级联封装

自定义对象参数-应用实例

需求说明: 演示自定义对象参数使用,完成自动封装,类型转换

创建public/save.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>添加妖怪</title>
</head>
<body>
<h1>添加妖怪-坐骑[测试封装POJO;]</h1>
<form action="/savemonster" method="post">
    编号: <input name="id" value="100"><br/>
    姓名: <input name="name" value="牛魔王"/> <br/>
    年龄: <input name="age" value="500"/> <br/>
    婚否: <input name="isMarried" value="true"/> <br/>
    生日: <input name="birth" value="2000/11/11"/> <br/>
    坐骑名称:<input name="car.name" value="法拉利"/><br/>
    坐骑价格:<input name="car.price" value="9999.9"/>
    <input type="submit" value="保存"/>
</form>
</body>
</html>

创建bean\Monster.java

@Data
public class Monster {
    private Integer id;
    private String name;
    private Integer age;
    private Boolean isMarried;
    private Date birth;
    private Car car;
}

创建bean\Car.java

@Data
public class Car {
    private String name;
    private Double price;
    //xxxx对象属性
}

修改ParameterController.java 增加处理添加请求

    //处理添加monster的方法

    @PostMapping("/savemonster")
    public String saveMonster(Monster monster) {
        System.out.println("monster-" + monster);
        return "success";
    }

完成测试, 浏览器http://localhost:8080/save.html