MVC 활용(3) : HTTP 요청 맵핑하기 2부 - URI 패턴 맵핑
3. HTTP 요청 맵핑하기 2부 - URI 패턴 맵핑
URI, URL, URN 햇갈린다
여러개의 문자열로 매핑할 수도 있다.
@Controller
public class SampleController {
@RequestMapping({"/hello", "/hi"})
@ResponseBody
public String hello(){
return "hello";
}
}
테스트 코드
@RunWith(SpringRunner.class)
@WebMvcTest
public class SampleControllerTest {
@Autowired
MockMvc mockMvc;
@Test
public void helloTest() throws Exception{
mockMvc.perform(get("/hello"))
.andDo(print())
.andExpect(status().isOk());
mockMvc.perform(get("/hi"))
.andDo(print())
.andExpect(status().isOk());
}
}
요청 식별자로 맵핑하기
- @RequestMapping은 다음의 패턴을 지원한다.
- ? : 한 글자 (“/author/???” => “/author/123”)
- * : 여러 글자 (“/author/*” => “/author/keesun”)
- ** : 여러 패스 (“/author/** => “/author/keesun/book”)
한글자만 맵핑
@Controller
public class SampleController {
@GetMapping("/hello?")
@ResponseBody
public String hello(){
return "hello";
}
}
테스트 코드
@RunWith(SpringRunner.class)
@WebMvcTest
public class SampleControllerTest {
@Autowired
MockMvc mockMvc;
@Test
public void helloTest() throws Exception{
mockMvc.perform(get("/hello1"))
.andDo(print())
.andExpect(status().isOk());
}
}
Path가 있고 그 다음에 한 글자가 올 수도 있다.
@Controller
public class SampleController {
@GetMapping("/hello/?")
@ResponseBody
public String hello(){
return "hello";
}
}
테스트 코드
@RunWith(SpringRunner.class)
@WebMvcTest
public class SampleControllerTest {
@Autowired
MockMvc mockMvc;
@Test
public void helloTest() throws Exception{
mockMvc.perform(get("/hello/1"))
.andDo(print())
.andExpect(status().isOk());
}
}
여러 글자가 오는 경우
@Controller
public class SampleController {
@GetMapping("/hello/*")
@ResponseBody
public String hello(){
return "hello";
}
}
테스트 코드
@RunWith(SpringRunner.class)
@WebMvcTest
public class SampleControllerTest {
@Autowired
MockMvc mockMvc;
@Test
public void helloTest() throws Exception{
mockMvc.perform(get("/hello/123"))
.andDo(print())
.andExpect(status().isOk());
}
}
여러 Path가 오는 경우
@Controller
public class SampleController {
@GetMapping("/hello/**")
@ResponseBody
public String hello(){
return "hello";
}
}
테스트 코드
@RunWith(SpringRunner.class)
@WebMvcTest
public class SampleControllerTest {
@Autowired
MockMvc mockMvc;
@Test
public void helloTest() throws Exception{
mockMvc.perform(get("/hello/123/456"))
.andDo(print())
.andExpect(status().isOk());
}
}
클래스에 선언한 @RequestMapping과 조합
- 클래스에 선언한 URI 패턴뒤에 이어 붙여서 맵핑한다.
@Controller
@RequestMapping("/hello")
public class SampleController {
@GetMapping("/**")
@ResponseBody
public String hello(){
return "hello";
}
}
테스트 코드
@RunWith(SpringRunner.class)
@WebMvcTest
public class SampleControllerTest {
@Autowired
MockMvc mockMvc;
@Test
public void helloTest() throws Exception{
mockMvc.perform(get("/hello/123/456"))
.andDo(print())
.andExpect(status().isOk());
}
}
정규 표현식으로 맵핑할 수도 있다.
- /{name:정규식}
@Controller
@RequestMapping("/hello")
public class SampleController {
@RequestMapping("/{name:[a-z]+}")
@ResponseBody
public String hello(@PathVariable String name){
return "hello " + name;
}
}
테스트 코드
@RunWith(SpringRunner.class)
@WebMvcTest
public class SampleControllerTest {
@Autowired
MockMvc mockMvc;
@Test
public void helloTest() throws Exception{
mockMvc.perform(get("/hello/spring"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().string("hello spring"));
}
}
테스트 코드2 : 영문자가 아닌 숫자를 넣으면 테스트가 깨진다.
@RunWith(SpringRunner.class)
@WebMvcTest
public class EventControllerTest {
@Autowired
MockMvc mockMvc;
@Test
public void helloTest() throws Exception{
mockMvc.perform(get("/hello/123"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().string("hello spring"));
}
}
패턴이 중복되는 경우에는?
- 가장 구체적으로 맵핑되는 핸들러를 선택한다.
@Controller
@RequestMapping("/hello")
public class SampleController {
@RequestMapping("/spring")
@ResponseBody
public String hellospring(){
return "hello spring";
}
@RequestMapping("/*")
@ResponseBody
public String hello(){
return "hello";
}
}
테스트 코드
@RunWith(SpringRunner.class)
@WebMvcTest
public class SampleControllerTest {
@Autowired
MockMvc mockMvc;
@Test
public void helloTest() throws Exception{
mockMvc.perform(get("/hello/spring"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().string("hello spring"));
}
}
테스트 코드2 : 어떤 핸들러에 매핑되었는지 알고싶다.
@RunWith(SpringRunner.class)
@WebMvcTest
public class SampleControllerTest {
@Autowired
MockMvc mockMvc;
@Test
public void helloTest() throws Exception{
mockMvc.perform(get("/hello/spring"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().string("hello spring"))
.andExpect(handler().handlerType(SampleController.class))
.andExpect(handler().methodName("hellospring"));
}
}
URI 확장자 맵핑 지원
- 이 기능은 권장하지 않는다. (스프링 부트에서는 기본으로 이 기능을 사용하지 않도록 설정 해 줌)
- 보안 이슈 (RFD Attack)
- URI 변수, Path 매개변수, URI 인코딩을 사용할 때 할 때 불명확 함.
스프링 MVC는 암묵적으로 다음과 같은 매핑을 해준다.
@Controller
@RequestMapping("/hello")
public class SampleController {
@RequestMapping({"/spring", "/spring.*"})
@ResponseBody
public String hellospring(){
return "hello spring";
}
}
스프링 MVC에서는 spring.json, spring.html, spring.xml도 처리할 수 있게끔 해준다.
테스트 코드 : 스프링 부트 X, DispatcherServlet /app으로 매핑
@Controller
public class helloController {
@Autowired
HelloService helloService;
@GetMapping("/hello")
@ResponseBody
public String hello(){
return "Hello, " + helloService.getName();
}
}
@Service
public class HelloService {
public String getname(){
return "spring";
}
}
이를 톰캣에서 실행해보면 http://localhost:8080/app/hello, http://localhost:8080/app/hello.json도 실행된다.
RFD Attack
- https://www.trustwave.com/en-us/resources/blogs/spiderlabs-blog/reflected-file-download-a-new-web-attack-vector/
- https://www.owasp.org/index.php/Reflected_File_Download
- https://pivotal.io/security/cve-2015-5211
테스트 코드 : 스프링 부트
@Controller
@RequestMapping("/hello")
public class SampleController {
@RequestMapping("/spring")
@ResponseBody
public String hellospring(){
return "hello spring";
}
}
@RunWith(SpringRunner.class)
@WebMvcTest
public class SampleControllerTest {
@Autowired
MockMvc mockMvc;
@Test
public void helloTest() throws Exception{
mockMvc.perform(get("/hello/spring.json"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().string("hello spring"))
.andExpect(handler().handlerType(SampleController.class))
.andExpect(handler().methodName("hellospring"));
}
}
@RunWith(SpringRunner.class)
@WebMvcTest
public class SampleControllerTest {
@Autowired
MockMvc mockMvc;
@Test
public void helloTest() throws Exception{
mockMvc.perform(get("/hello/spring.json"))
.andDo(print())
.andExpect(status().isNotFound());
}
}
최근의 추세는 Accept 헤더에 어떤 타입을 원한다고 지정을 해두면 확장자를 보지 않더라도 서버가 헤더에 있는 내용을 보고 판단할 수 있다.
또한 헤더가 불편하면 파라미터로 지정하는 방법도 있다. ?type=
또한 확장자가 없는 요청과 같이 지원할 수도 있다. 그러나 이 방법은 권장하지 않는다.
@Controller
@RequestMapping("/hello")
public class SampleController {
@RequestMapping({"/spring", "/spring.*"})
@ResponseBody
public String hellospring(){
return "hello spring";
}
}
@RunWith(SpringRunner.class)
@WebMvcTest
public class SampleControllerTest {
@Autowired
MockMvc mockMvc;
@Test
public void helloTest() throws Exception{
mockMvc.perform(get("/hello/spring.xml"))
.andDo(print())
.andExpect(status().isOk());
mockMvc.perform(get("/hello/spring"))
.andDo(print())
.andExpect(status().isOk());
}
}
참고
- 인프런 : 스프링 웹 MVC(백기선)
- https://stackoverflow.com/questions/176264/what-is-the-difference-between-a-uri-a-url-and-aurn
- https://www.trustwave.com/en-us/resources/blogs/spiderlabs-blog/reflected-file-download-a-new-web-attack-vector/
- https://www.owasp.org/index.php/Reflected_File_Download
- https://pivotal.io/security/cve-2015-5211
Author And Source
이 문제에 관하여(MVC 활용(3) : HTTP 요청 맵핑하기 2부 - URI 패턴 맵핑), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@jsj3282/스프링-MVC-활용3-HTTP-요청-맵핑하기-2부-URI-패턴-맵핑저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)