[회사일] CRUD 구현
먼저 앞에서 만든 뷰를 가지고 컨트롤러 코드를 만드는데 이때 URL을 어떻게 가져갈지 구상해야합니다.
/base/code/list GET
/base/code/add GET
/base/code/add POST
/base/code/update?id=23 GET
/base/code/update?id=23 POST
/base/code/delete?id=23 GET
이전에는 이런식으로 썼었습니다. 그런데 이번에는 URL을 REST 스타일로 만들어 보고자 스프링 Roo 레퍼런스에 있는 그림을 참조했습니다.
그래서 이번에는
/base/code/ GET
/base/code/form GET
/base/code POST
/base/code/{id}/form GET
/base/code/{id} PUT
/base/code/{id} DELETE
이런식으로 구성했습니다. 아직 하나 안만든건 view인데 그건 /base/code/{id} GET이 될겁니다.
아직 익숙하지 않아서 잘 적응되고 있진 않은데 이렇게 만들어 두면 나중에 웹 서비스 별도로 만들 필요없이 저 런 RESTful URL과 스프링 3.0의 컨텐츠 네고 기능을 이용해서 모바일 용 앱을 만들때 한결 편할 것 같습니다.
암튼 이 다음은 스프링 3.0의 @Validation 기능을 적용하는 것인데 이때 하이버 벨리데이터를 의존성에 추가해 줬습니다.
<!-- Validation -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>com.springsource.org.hibernate.validator</artifactId>
<version>4.0.0.GA</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>com.springsource.javax.xml.bind</artifactId>
<version>2.1.7</version>
</dependency>
스프링 웹 설정은 변경한것이 없습니다.
<mvc:annotation-driven />
이게 전부이고 나머진 예외-뷰 설정과 컨텐츠 네고 설정 뿐입니다.
@Controller
@RequestMapping("/base/code/*")
@SessionAttributes("code")
public class CodeController {
@Autowired CodeService codeService;
@RequestMapping(value="mgt")
public void mgt(Model model){
model.addAttribute("searchParam", new CodeSearchParam());
}
@RequestMapping(method = RequestMethod.GET)
public void list(Model model, CodeSearchParam searchParam, PageParam pageParam) {
model.addAttribute("codeList", codeService.list(pageParam, searchParam));
}
@RequestMapping(value = "form", method = RequestMethod.GET)
public String addForm(Model model){
model.addAttribute("code", new Code());
return "/base/code/new";
}
@RequestMapping(method = RequestMethod.POST)
public String addFormSubmit(Model model, @Valid Code code, BindingResult result, SessionStatus status){
if(result.hasErrors())
return "base/code/new";
status.setComplete();
codeService.add(code);
return "redirect:/base/code/mgt";
}
@RequestMapping(value = "{id}/form", method = RequestMethod.GET)
public String editForm(@PathVariable int id, Model model){
model.addAttribute("code", codeService.getById(id));
return "/base/code/edit";
}
@RequestMapping(value = "{id}", method = RequestMethod.PUT)
public String editFormSubmit(Model model, @Valid Code code, BindingResult result, SessionStatus status){
if(result.hasErrors())
return "base/code/edit";
status.setComplete();
codeService.update(code);
return "redirect:/base/code/mgt";
}
@RequestMapping(value = "{id}", method = RequestMethod.DELETE)
public String delete(@PathVariable int id){
codeService.deleteBy(id);
return "redirect:/base/code/mgt";
}
}
컨트롤러는 이렇게 구현했는데 URL을 클래스 선언부와 메서드 선언부에 분할해서 설정했습니다. 그래야 나중에 상위클래스로 빼서 프레임워크화 할 때 용이하기 때문입니다. 서비스와 DAO 코드는 간단하기 때문에 생략입니다.
참 컨트롤러에서 PUT, DELETE 같은 method를 사용하고 있는데 사실은 화면에서 넘어올땐 걍 POST일 뿐이고 _method라는 히든 파람을 스프링이 읽어서 적절한 애노테이션 핸들러를 찾아주게 되어 있습니다. 히든 파람으로 RESTfult 한 API를 만들기 위해서는 web.xml에 필터를 하나 등록해줘야 합니다.
<filter>
<filter-name>httpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>httpMethodFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
자 그럼 오늘은 이만하고 내일은 Code에 새로운 속성들을 추가해 봐야겠습니다. 시간이 남으면 User 도메인 CRUD까지 구현해야겠네요. 그 다음부터는 드뎌 OSAF 3.0 코드가 조금씩 간추려 지겠군요.