Spring Request and Response

📢 This article was translated by gemini-2.5-flash

When a browser sends a request, it first goes through the DispatcherServlet, which forwards it to the various *Controller programs for processing. After processing, the result is returned to the DispatcherServlet, and then sent back to the browser.

The DispatcherServlet is known as the core controller or front controller.

Browser request data is encapsulated into an HttpServletRequest object, and response data into an HttpServletResponse object.

*Controllers receive requests and set responses.

Request

Simple Parameters

First, the traditional way: get request parameters manually via the HttpServletRequest object.

1
2
3
4
5
6
7
8
9
@RequestMapping("/simpleParam")
public String simpleParam(HttpServletRequest request){
    String name = request.getParameter("name");
    String ageStr = request.getParameter("age");

    int age = Integer.parseInt(ageStr);
    System.out.println(name + ";" + age);
    return "OK";
}

When you visit http://localhost:8080/simpleParam?name=tom&age=18 in your browser, the page returns “OK”, and the program outputs “Tom;18”.


Clearly, this method is too cumbersome. In Spring Boot, you can simply define method parameters with the same names as the request parameters to receive them.

1
2
3
4
5
@RequestMapping("/simpleParam")
public String simpleParam(String name, Integer age){
    System.out.println(name + ";" + age);
    return "OK";
}

Same effect as above.


However, the above method will still run even if the request parameter names differ; missing parameters will be null.

You can use @RequestParam to map request parameter names to different method parameter names.

1
2
3
4
5
6
7
@RequestMapping("/simpleParam")
public  String simpleParam(@RequestParam(name = "name") String username, Integer age){
    // When @RequestParam is declared, it means the parameter *must* be passed, otherwise an error occurs.
    // If changed to @RequestParam(name = "name", required = false), the parameter is optional.
    System.out.println(username + ";" + age);
    return "OK";
}

Object Parameters

For a few parameters, the above methods work. But for more data, you can use a simple object (POJO). If request parameter names match the POJO’s property names, just define a POJO to receive them.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@RequestMapping("/simplePojo")
public String simplePojo(User user){
    System.out.println(user);
    return "OK";
}

// User class
public class User{
    private String name;
    private Integer age;
    // getters, setters, toString method
}

Visiting http://localhost:8080/simplePojo?name=tom&age=18 returns “OK”, and the program outputs “User{name=‘tom’, age=18}”.


Complex object parameters: If request parameter names match the method parameter’s object property names, nested POJO properties can be received by following the object hierarchy.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
@RequestMapping("/complexPojo")
public String complexPojo(UserComplex user){
    System.out.println(user);
    return "OK";
}

// User class
public class UserComplex{
    private String name;
    private Integer age;
    private Address address;
    // getters, setters, toString
}

// Address class
public class Address{
    private String province;
    private String city;
    // getters, setters, toString
}

Visiting http://localhost:8080/complexPojo?name=tom&age=18&address.province=beijing&address.city=beijing returns “OK”, and the program outputs “UserComplex{name=‘tom’, age=1000, address=Address{province=‘ads,beijing’, city=‘asda,beijing’}}”.

Array Parameters

If the request parameter name matches the method’s array parameter name, and there are multiple values, you can define an array-type method parameter to accept them. For example, for checkboxes.

1
2
3
4
5
@RequestMapping("/arrayParam")
public String arrayParam(String[] hobby){
    System.out.println(Arrays.toString(hobby));
    return "OK";
}

Visiting http://localhost:8080/arrayParam?hobby=ads&hobby=58s returns “OK”, and the program outputs “[ads, 58s]”.

Collection Parameters

If the request parameter name matches the method’s collection parameter name, and there are multiple values, use @RequestParam to bind the parameters.

1
2
3
4
5
@RequestMapping("/listParam")
public String listParam(@RequestParam List<String> hobby){
    System.out.println(hobby);
    return "OK";
}

Visiting http://localhost:8080/listParam?hobby=ads&hobby=58s returns “OK”, and the program outputs “[ads, 58s]”.

Date Parameters

Use the @DateTimeFormat annotation to convert date parameter formats.

It’s worth noting there are three common parameter formats:

  • yyyy-MM-dd HH:mm:ss
  • yyyy/MM/dd HH:mm:ss
  • yyyy年MM月dd日 HH时mm分ss秒 (yyyy年MM月dd日 HH时mm分ss秒)

Frontend and backend need to agree on the format.

1
2
3
4
5
@RequestMapping("/dateParam")
public String dateParam(@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime localDateTime){
    System.out.println(localDateTime);
    return "OK";
}

Visiting http://localhost:8080/dateParam?localDateTime=2024-01-01%2001:01:01 returns “OK”, and the program outputs “2024-01-01T01:01:01”.

JSON Parameters

If JSON data keys match the method parameter’s object property names, you can define a POJO-type method parameter to receive them. You’ll need to use @RequestBody.

To send JSON data, you must use a POST request.

1
2
3
4
5
@RequestMapping("/jsonParam")
public String jsonParam(@RequestBody UserComplex userComplex){
    System.out.println(userComplex);
    return "OK";
}

Request data:

1
2
3
4
5
6
7
8
{
    "name": "jane",
    "age": "18",
    "address": {
        "province": "上海",
        "city": "上海"
    }
}

Using POST to request http://localhost:8080/jsonParam with the data above, the page returns “OK”, and the program outputs “UserComplex{name=‘jane’, age=18, address=Address{province=‘上海’, city=‘上海’}}”.

Path Parameters

Pass parameters directly in the request URL. Use {...} to mark path parameters, and @PathVariable to retrieve them.

1
2
3
4
5
@RequestMapping("/path/{id}")
public String pathParam(@PathVariable Integer id){
    System.out.println(id);
    return "OK";
}

Visiting http://localhost:8080/path/52 returns “OK”, and the program outputs “52”.

Visiting http://localhost:8080/path/255 returns “OK”, and the program outputs “255”.


For multiple path parameters:

1
2
3
4
5
@RequestMapping("/path/{id}/{name}")
public String pathParam(@PathVariable Integer id, @PathVariable String name){
    System.out.println(id + ";" + name);
    return "OK";
}

Visiting http://localhost:8080/path/255/Tom returns “OK”, and the program outputs “255;Tom”.

Summary

  1. Simple Parameters
    • Define method parameters; request parameter names should match variable names.
    • If they don’t match, map them manually with @RequestParam.
  2. Object Parameters
    • Request parameter names should match object property names for automatic encapsulation.
  3. Array & Collection Parameters
    • Arrays: Request parameter name matches array name for direct encapsulation.
    • Collections: Request parameter name matches collection name; bind with @RequestParam.
  4. Date Parameters
    • @DateTimeFormat
  5. JSON Parameters
    • @RequestBody
  6. Path Parameters
    • @PathVariable

Response

Use @ResponseBody to handle responses.

The above request methods could send responses because the @RestController annotation includes both @Controller and @ResponseBody.

@ResponseBody

Type: Method annotation, Class annotation

Location: On a Controller method or class

Purpose: Returns the method’s return value directly as the response. If the return type is an object or collection, it will be converted to JSON format.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@RestController
public class ResponseController {
    @RequestMapping("/hello")
    public String hello(){
        System.out.println("Hello SpringBoot");
        return "Hello SpringBoot";
    }

    @RequestMapping("/getAddr")
    public Address getAddr(){
        Address address = new Address();
        address.setProvince("上海");
        address.setCity("上海");
        return address;
    }

    @RequestMapping("/listAddr")
    public List<Address> listAddr(){
        List<Address> list = new ArrayList<>();
        Address address1 = new Address();
        address1.setProvince("北京");
        address1.setCity("北京");
        Address address2 = new Address();
        address2.setProvince("上海");
        address2.setCity("上海");

        list.add(address1);
        list.add(address2);
        return list;
    }
}

Visit the respective URLs to test.


Unified Response Result

The return types of the three methods above are all different, which makes frontend development harder. To address this, you can unify the response results into a single class.

1
2
3
4
5
6
7
8
9
public class Result{
    // Response code: 1 for success, 0 for failure.
    private Integer code;
    // Message
    private String msg;
    // Returned data
    private Object data;
    // ...
}

Making all response methods return a Result object makes project management and maintenance easier.

For example, this class:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class Result {
    private Integer code ;// 1 for success, 0 for failure
    private String msg; // Message
    private Object data; // Data payload

    public Result() {
    }
    public Result(Integer code, String msg, Object data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }
    public Integer getCode() {
        return code;
    }
    public void setCode(Integer code) {
        this.code = code;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
    public Object getData() {
        return data;
    }
    public void setData(Object data) {
        this.data = data;
    }

    public static Result success(Object data){
        return new Result(1, "success", data);
    }
    public static Result success(){
        return new Result(1, "success", null);
    }
    public static Result error(String msg){
        return new Result(0, msg, null);
    }

    @Override
    public String toString() {
        return "Result{" +
                "code=" + code +
                ", msg='" + msg + '\'' +
                ", data=" + data +
                '}';
    }
}

Then the above code can be changed to:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@RequestMapping("/hello")
public Result hello(){
    System.out.println("Hello SpringBoot");
    return Result.success("Hello SpringBoot");
}

@RequestMapping("/getAddr")
public Result getAddr(){
    Address address = new Address();
    address.setProvince("上海");
    address.setCity("上海");
    return Result.success(address);
}

@RequestMapping("/listAddr")
public Result listAddr(){
    List<Address> list = new ArrayList<>();
    Address address1 = new Address();
    address1.setProvince("北京");
    address1.setCity("北京");
    Address address2 = new Address();
    address2.setProvince("上海");
    address2.setCity("上海");

    list.add(address1);
    list.add(address2);
    return Result.success(list);
}

Visit the respective URLs to test.