Java Spring Boot controller的使用之参数解析

发布时间 2023-12-06 16:14:13作者: 进击的davis

Spring Boot 作为 Java 中广受欢迎的框架,其 controller 的使用必须掌握了解,本篇的学习将从以下几个方面展开:

  • 动态URL
  • 组路由
  • 参数解析
  • Restful controller

本篇假设你已经了解 Spring Boot 开发的基本流程,以下示例主要从 controller 角度学习。

1.动态URL

说到此,做过 web开发 的各位码农应该都见过类似:/user/id1, /user/id2这种,也就是 /user/{id} 这种,好在 Spring Boot 中,我们可以通过功能强大的注解解决这种问题,包括解析到具体 路由。

以下是编码示例:

package com.example.springbootdemo2.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.Map;

@Controller
public class DynamicURLParamController {

    @RequestMapping(value = "/dynamic/normal", method = RequestMethod.GET)
    public @ResponseBody Object normal() {
        Map<String, String> map = new HashMap<>();
        map.put("handler", "normal");
        return map;
    }

    @RequestMapping(value = "/dynamic/{id}/{action}", method = {RequestMethod.GET})
    public @ResponseBody Object returnIdAndAction(@PathVariable(value = "id") Integer id, @PathVariable(value = "action") String action) {
        Map<String, Object> map = new HashMap<>();
        map.put("id", id);
        map.put("action", action);
        return map;
    }
}

上面的示例中,我们先实现了一个静态路径访问的 URL: /dynamic/normal,只要输入 http://ip:port/dynamic/normal, 就会返回一个 Map 结构的响应体。

接着我们在注解 @RequestMapping 中的 value 设置为 /dynamic/{id}/{action},访问 method 设置为 GET ,在具体的处理方法中我们通过注解 @PathVariable 解析赋值给对应的动态参数 idaction,在具体的处理方法中就可以直接使用这里的动态字段了,比如有这样的应用场景,我们通过 id 获取到用户的信息,根据 action 做相应的动作。

2.组路由

组路由,显然我们对开放的 API接口 根据业务功能做一定分类分组,比如我们可以有这样几个组:

  • /auth,认证用
  • /register,注册用
  • /article,文章的增删改查
  • /userInfo,用户信息的增删改查

上面枚举的只是几个常有的业务分组,实际的运用中根据具体的业务场景就是其他的功能分组了。

下面是编码示例:

package com.example.springbootdemo2.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
@RequestMapping("/group")
public class GroupRouterController {

    @GetMapping("/subGroup")
    public @ResponseBody String subGroup() {
        return "This is the subGroup under the group.";
    }
}

从代码中也可以看到,这里的分组其实简单,我们只需要在控制器类上加个注解 @RequestMapping 就可以区分不同的组,接着在具体的处理方法中继续写响应的路径,我们就可以通过 /group/subGroup 访问到 subGroup 这个方法并完成一定功能。

3.参数解析

在我们日常访问浏览器时,是不是会有这种访问路径:https://ip:port/aaa/bbb?username=xxx&query=yyy ,相信细心的你肯定遇到过,又或者是通过表单提交的,又或者是现如今更为普遍的通过 json 传递请求参数的。

所以我们这里的参数解析主要通过以下三个方面来解析相关参数:

  • GET请求中,参数在URL上,有长度限制
  • POST请求中,参数通过表单传递
  • POST请求中,参数通过json传递

话不多说,上实现编码:

package com.example.springbootdemo2.controller;

import com.example.springbootdemo2.param.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;

@Controller
@RequestMapping(value = "/parse")
public class ParseParamsController {
    // 1.解析多个query参数到指定字段
    @GetMapping(value = "/query/simple") // /parse/query/simple?name=xxx&age=xx
    public @ResponseBody Object parseGetQueryParams(@RequestParam("name") String name, @RequestParam("age") Integer age) {
        Map<String, Object> map = new HashMap<>();
        map.put("name", name);
        map.put("age", age);
        return map;
    }

    // 2.解析多个query参数到Map结构
    @GetMapping(value = "/query/map")
    public @ResponseBody Object parseGetQueryMap(@RequestParam Map<String, Object> map) {
        return map;
    }

    // 3.解析多个query参数到List,前提是同字段
    @GetMapping(value = "/query/list")
    public @ResponseBody Object parseGetQueryList(@RequestParam("name") String[] names) {
        return names;
    }

    @PostMapping(value = "/form")
    public @ResponseBody Object parsePostFormParams(@RequestParam(value = "username") String username, @RequestParam(value = "age") Integer age) {
        Map<String, Object> map = new HashMap<>();
        map.put("username", username);
        map.put("age", age);
        return map;
    }

    @PostMapping("/json/map")
    public @ResponseBody Object parsePostJsonParamsWithMap(@RequestBody Map data) {
        return data;
    }

    @PostMapping("/json/object")
    public @ResponseBody Object parsePostJsonParamsWithObject(@RequestBody User user) {
        return user;
    }
}

相关的 User 类 就是一个简单的 Bean:

package com.example.springbootdemo2.param;

public class User {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

GET-query参数

我们在上面的代码中,我们首先是解析多个query参数到指定的字段,形如访问 /parse/query/simple?name=xxx&age=yy,这里我们通过注解 @RequestParam 获取到指定字段。

接着我们也可以将query参数全部倒进一个 Map 结构中,同样用到 @RequestParam 注解,只是这里直接指明是 Map 结构,如果需要用到参数,就可以通过 map.get(xxx) 获取指定字段的值。

最后我们将query参数中的同字段解析到一个数组中,前提是query参数的字段是同一字段,好比是 /parse/query/list?name=aaa&name=bbb&name=ccc ,最后我们在 names 中的就是 String[] names = {"aaa", "bbb", "ccc"}

POST-Form表单

表单参数传递也是常见的方式之一,这里我们也是用 @RequestParam 注解获取到对应的参数,看看代码就知道了。

POST-Json

在如今的 web开发中,Rest风格的API 比较常见,这里尤以 Json 居多。注意,我们这里是通过注解 @RequestBody 来解析请求体的,这里分两种情况:

  • 解析到 Map 结构,比较通用,但字段需要通过 get 方法获取
  • 解析到我们预先写好的 Bean 中,这里是个简单的 User 类,只有两个私有字段,name和age

4.Restful controller

发现没有,我们在上面的编码中,其实用到很多注解,如果换个注解:@Controller -> @RestController 的话,会响应的减少一些注解,因为 @RestCOntroller 做了更多的包装处理,依然还是编码实现:

package com.example.springbootdemo2.controller;

import com.example.springbootdemo2.param.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
public class RestfulStyleController {

    @GetMapping(value = "/rest/user/{id}")
    public Object getUserInfoById(@PathVariable("id") String id) {
        System.out.println("正在查找 id = " + id + "的用户");
        Map<String, Object> info = new HashMap<>();
        info.put("id", id);
        info.put("name", "alice");
        info.put("age", 25);
        return info;
    }

    @PostMapping(value = "/rest/userAction/register")
    public Object postUserInfoToRegister(User user) {
        return "ok";
    }
}

在上面的代码中,我们首先实现一个 GET 方法访问的路径,接着实现了一个 POST 方法访问的路径,在 Rest风格 中不同的是,我们可以减少一些如 @ResponseBody/@RequestBody等注解,是不是又减少了一些工作量。

参考: