OOM killer 라는게 있다는건 처음 알았네.
http://sylphong.egloos.com/523835
며칠동안 이유없이 tomcat이 죽더니... dmesg로 확인해 볼 것. 혹은 OOM killer 로 더 알아볼 것.
2012-09-26
2012-09-25
Spring MVC Controller 의 REST scaffold
spring roo 가 제공하는 것을 약간 수정하여 나만의 scaffold로...
* roo는 update 경로가 좀 다르고
* list에서 spring data의 Pageable을 사용함.
http://java.dzone.com/articles/restful-standard-resolved 도 참고하자.
* roo는 update 경로가 좀 다르고
* list에서 spring data의 Pageable을 사용함.
http://java.dzone.com/articles/restful-standard-resolved 도 참고하자.
@RequestMapping public String list(@PageableDefaults(pageNumber = 0, value = Config.PAGE_SIZE) Pageable pageable, Model model) { } @RequestMapping(method = RequestMethod.POST) public String create(@Valid MyObj obj, BindingResult bindingResult, Model model, HttpServletRequest httpServletRequest) { } @RequestMapping(params = "form") public String createForm(Model model) { } @RequestMapping(value = "/{obj}", method = RequestMethod.PUT) public String update(@Valid @ModelAttribute("obj") MyObj obj, BindingResult bindingResult, Model model, HttpServletRequest httpServletRequest) { } @RequestMapping(value = "/{id}", method = RequestMethod.DELETE) public View remove(@PathVariable Long id) { } @RequestMapping(value = "/{id}", method = RequestMethod.GET) public ModelAndView show(@PathVariable Long id, Model model) throws Exception { }
2012-09-22
roo의 service는 aggregate repository 같다. domainTypes에 entity만 지정해주면 그에 해당하는 repository들을 모두 엮어 준다. 그렇다면 하나의 entity가 여러 service에 지정될 수도 있다. 하지만 이건 좋지 않은 것 같다. 서로 역할이 달라야 할 service들이 하나의 entity에 대한 operation들을 중복해서 가지게 되니까. 각 service가 처리하는 entity들은 관련 영역별로 구분하여 모아주는 것이 좋지 않을까. 물론 service라는 것이 지정된 entity만 처리할 수는 없을 것이다. 그럴 때는 domainTypes에 해당 entity를 지정하는 것보다는 그 entity의 repository를 DI 받도록 하자.
2012-09-15
mac에서 iso를 usb로 옮기기. 부팅 가능하게.
우선 아래 명령으로 usb 의 device명을 알아낸다.
$ sudo diskutil list
나의 경우는 /dev/disk4 였다.
usb를 꽂고 diskutil 로 erase 를 해준다. ms-dos (FAT)로.
그런 다음 partition을 unmount하자. 이 때 usb는 diskutil에 여전히 표시되고 있다.
이제 터미널에서 다음을 입력한다.
sudo dd if=myfile.iso of=/dev/disk4 bs=8192
음... 부팅안되는구나. 미안. ㅋ
$ sudo diskutil list
나의 경우는 /dev/disk4 였다.
usb를 꽂고 diskutil 로 erase 를 해준다. ms-dos (FAT)로.
그런 다음 partition을 unmount하자. 이 때 usb는 diskutil에 여전히 표시되고 있다.
이제 터미널에서 다음을 입력한다.
sudo dd if=myfile.iso of=/dev/disk4 bs=8192
음... 부팅안되는구나. 미안. ㅋ
2012-09-12
2012-09-07
jade4j
java에서 jade를 쓰고 싶어서 scalate를 쓰게 되었는데, jade4j로 갈아 타야겠다. 복잡한 페이지는 컴파일하는 시간도 오래 걸리고. 메모리는 왜 일케 많이 잡아 먹는거야. app reload하면 2~400메가씩 점유량이 올라가니 tomcat메모리를 max 2G 줘도 몇번 코드 수정하고 나면 빌빌댄다.
--
ognl을 사용하므로 scala 문법의 if, for 등을 ognl 구문으로 바꾸어야 한다.
.getXXX 메소드 호출을 .xxx 와 같이 property 접근으로 바꾸어야 한다. sublime text에서 작업해야만 했다.
Find: \.get(.)
Replace: .\L\1
jade4j 에서는 BigDecimal 을 표시할 때, scale 대로 표시해준다. db에 설정된 scale대로 값을 가지므로 사실상 정수임에도 불구하고 .0000 과 같이 소수점이하 자리가 표시된다. ognl 은 객체의 메소드 호출을 지원하므로, 이런 류의 포맷팅을 위한 객체 및 메소드를 만든 다음, 이 객체를 페이지의 모델에 포함시켜, 페이지에서는 이 객체의 메소드를 호출함으로서 원하는 조작을 할 수 있다. 이 외에도 그 객체에 유틸리티 메소드를 정의해두면 좋을 것이다.
uri method를 f.uri로 바꾸기.
Find: =\{uri(.+)\}
Replace: =f.uri\1
반면 jade4j는 그냥 text를 parse하여 변환하는 것 같다. pegdown, ognl 같은거 쓰더라. 에러 났을 때 보여주는 ui는 play와 닮았던데 그대로 가져온 모양이다. 멋지다. 페이지 inheritance도 훨씬 잘되어 있고. mixin은 써본 적 없지만 잘만 하면 좋은 용처가 있을 것 같고.
슬슬 옮겨 가자.
--
ognl을 사용하므로 scala 문법의 if, for 등을 ognl 구문으로 바꾸어야 한다.
.getXXX 메소드 호출을 .xxx 와 같이 property 접근으로 바꾸어야 한다. sublime text에서 작업해야만 했다.
Find: \.get(.)
Replace: .\L\1
jade4j 에서는 BigDecimal 을 표시할 때, scale 대로 표시해준다. db에 설정된 scale대로 값을 가지므로 사실상 정수임에도 불구하고 .0000 과 같이 소수점이하 자리가 표시된다. ognl 은 객체의 메소드 호출을 지원하므로, 이런 류의 포맷팅을 위한 객체 및 메소드를 만든 다음, 이 객체를 페이지의 모델에 포함시켜, 페이지에서는 이 객체의 메소드를 호출함으로서 원하는 조작을 할 수 있다. 이 외에도 그 객체에 유틸리티 메소드를 정의해두면 좋을 것이다.
uri method를 f.uri로 바꾸기.
Find: =\{uri(.+)\}
Replace: =f.uri\1
ConversionService와 @ModelAttribute 를 이용한 Entity Update (수정) 처리
스프링 사용자 그룹에 질문을 던졌다.
ConversionService 를 이용한 id -> ModelAttribute 변환
결론은 허탈하게 해결되긴 했지만 그래도 나름 내부 구조를 이해하는데 도움이 되기도 했으니 다행이다.
하지만 나로서는 더 중요한 문제가 해결되었다. 수정폼의 submit을 매우 간단하게 처리할 수 있게 되었다.
예전에는 이렇게 했다. http://blog.jabberstory.net/2012/08/blog-post.html
하지만 이제 매우 간단해졌다. 그냥 uri 와 @ModelAttribute로 받고 저장하면 끝. controller를 분리할 필요도 없다.
여기서 uri에 있는 "user"와 @ModelAttribute에 붙어 있는 "user"가 같아야 한다. 그리고 String -> User 변환을 위한 Converter를 등록해 두어야 한다. 이 converter는 db에서 주어진 user 문자열로 User를 찾는 작업을 한다.
예전에 했던 방식은 UserDto로 @ModelAttribute으로 받은 다음, 별도로 find한 User에 필드 복사를 일일이 해주었다. (bean의 속성을 복사하는 유틸리티 클래스를 이용하기도 했다)
이렇게 하다가 귀찮아서 merge()를 사용했는데, merge()도 위험하다. 수정 폼에 모든 필드가 없다면 @ModelAttribute으로 받은 dto에는 null 필드가 있을 것이고, 이게 db필드로 들어갈 위험성이 있기 때문이다.
이에 대한 해결책으로 토비 책에는 @SessionAttributes을 사용하라는 얘기가 나온다. 하지만 이것도 해결책은 될 수 없는데, 동시에 열려 있는 여러 User에 대한 수정폼을 처리할 수 없다. session에 저장된 user는 하나이기 때문이다. (3.1 이전에 출간되었기 때문에 어쩔 수 없지 않았나 생각한다)
하지만 ConversionService와 @ModelAttribute을 동시에 이용하면 위의 문제를 모두 해결할 수 있다.
success !
ConversionService 를 이용한 id -> ModelAttribute 변환
결론은 허탈하게 해결되긴 했지만 그래도 나름 내부 구조를 이해하는데 도움이 되기도 했으니 다행이다.
하지만 나로서는 더 중요한 문제가 해결되었다. 수정폼의 submit을 매우 간단하게 처리할 수 있게 되었다.
예전에는 이렇게 했다. http://blog.jabberstory.net/2012/08/blog-post.html
하지만 이제 매우 간단해졌다. 그냥 uri 와 @ModelAttribute로 받고 저장하면 끝. controller를 분리할 필요도 없다.
@RequestMapping(value="/user/{user}", method=RequestMethod.PUT) public String update(@ModelAttribute("user") User user) { UserRepository.save(user); }
여기서 uri에 있는 "user"와 @ModelAttribute에 붙어 있는 "user"가 같아야 한다. 그리고 String -> User 변환을 위한 Converter를 등록해 두어야 한다. 이 converter는 db에서 주어진 user 문자열로 User를 찾는 작업을 한다.
예전에 했던 방식은 UserDto로 @ModelAttribute으로 받은 다음, 별도로 find한 User에 필드 복사를 일일이 해주었다. (bean의 속성을 복사하는 유틸리티 클래스를 이용하기도 했다)
이렇게 하다가 귀찮아서 merge()를 사용했는데, merge()도 위험하다. 수정 폼에 모든 필드가 없다면 @ModelAttribute으로 받은 dto에는 null 필드가 있을 것이고, 이게 db필드로 들어갈 위험성이 있기 때문이다.
이에 대한 해결책으로 토비 책에는 @SessionAttributes을 사용하라는 얘기가 나온다. 하지만 이것도 해결책은 될 수 없는데, 동시에 열려 있는 여러 User에 대한 수정폼을 처리할 수 없다. session에 저장된 user는 하나이기 때문이다. (3.1 이전에 출간되었기 때문에 어쩔 수 없지 않았나 생각한다)
하지만 ConversionService와 @ModelAttribute을 동시에 이용하면 위의 문제를 모두 해결할 수 있다.
success !
피드 구독하기:
글 (Atom)