Spring Web在Controller使用@RequestMapping
設定API路徑時可選擇是否填入路徑參數(path variable)的作法如下。
範例環境:
- Spring Boot 2.3.2
- Spring Web
Spring Web @RequestMapping
若設定了路徑參數@PathVariable
,則一定要填入參數才能正確呼叫API。例如下面DemoController.api()
必須/api/
後接任意字才能正確呼叫,例如/api/helloworld
;而/api
則返回404找不到結果。
DemoController
package com.abc.demo.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.RestController;
@RestController
public class DemoController {
@RequestMapping(value = "/api/{text}", method = RequestMethod.GET)
public void api(@PathVariable("text") String text) {
System.out.println(text);
}
}
若希望/api
也能正確呼叫DemoController.api()
則改為設定如下。@RequestMapping.value
多設一條無路徑參數的API路徑並將@PathVariable.required
設為false。
DemoController
package com.abc.demo.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.RestController;
@RestController
public class DemoController {
@RequestMapping(value = {"/api", "/api/{text}"}, method = RequestMethod.GET)
public void api(@PathVariable(value = "text", required = false) String text) {
System.out.println(text);
}
}
但如果有兩個連續的路徑參數,且兩個都設為非必填時,則只能全不填或全填。
例如下面路徑參數arg1
和arg1
的@PathVariable.required
接設為false。
DemoController
package com.abc.demo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DemoController {
@GetMapping(value = {"/api", "/api/{arg1}/{arg2}"})
public String api(
@PathVariable(value = "arg1", required = false) String arg1,
@PathVariable(value = "arg2", required = false) String arg2
) {
if (arg1 == null) {
arg1 = "";
}
if (arg2 == null) {
arg2 = "";
}
return arg1 + arg2;
}
}
則/api
或/api/a/b
才能正確呼叫,/api/a
或/api//b
則會404 Not Found找不到資源。
測試如下。
DemoControllerTests
package com.abc.demo.controller;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@AutoConfigureMockMvc
@SpringBootTest
public class DemoControllerTests {
@Autowired
private MockMvc mockMvc;
@Test
public void api_arg1AndArg2_ok() throws Exception {
mockMvc.perform(get("/api/a/b"))
.andExpect(status().isOk())
.andExpect(content().string("ab"));
}
@Test
public void api_noArgs_ok() throws Exception {
mockMvc.perform(get("/api"))
.andExpect(status().isOk())
.andExpect(content().string(""));
}
@Test
public void api_arg1_notFound() throws Exception {
mockMvc.perform(get("/api/a"))
.andExpect(status().isNotFound());
}
@Test
public void api_arg2_notFound() throws Exception {
mockMvc.perform(get("/api//b"))
.andExpect(status().isNotFound());
}
}
若改用Map<String, String>
來接連續的路徑參數,一樣只能全不填或全填。否則會404 Not Found。
DemoController
package com.abc.demo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
@RestController
public class DemoController {
@GetMapping(value = {"/api", "/api/{arg1}/{arg2}"})
public String api(@PathVariable Map<String, String> args) {
String arg1 = args.get("arg1");
String arg2 = args.get("arg2");
if (arg1 == null) {
arg1 = "";
}
if (arg2 == null) {
arg2 = "";
}
return arg1 + arg2;
}
}
/api
或/api/a/b
才能正確呼叫,/api/a
或/api/a/
或/api//b
會404 Not Found。
測試如下。
DemoControllerTests
package com.abc.demo.controller;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@AutoConfigureMockMvc
@SpringBootTest
public class DemoControllerTests {
@Autowired
private MockMvc mockMvc;
@Test
public void api_arg1AndArg2_ok() throws Exception {
mockMvc.perform(get("/api/a/b"))
.andExpect(status().isOk())
.andExpect(content().string("ab"));
}
@Test
public void api_noArgs_ok() throws Exception {
mockMvc.perform(get("/api"))
.andExpect(status().isOk())
.andExpect(content().string(""));
}
@Test
public void api_arg1_notFound() throws Exception {
mockMvc.perform(get("/api/a"))
.andExpect(status().isNotFound());
}
@Test
public void api_arg2_notFound() throws Exception {
mockMvc.perform(get("/api//b"))
.andExpect(status().isNotFound());
}
}
沒有留言:
張貼留言