애플리케이션이 초기에 가동될 때 필요한 데이터를 입력하는 작업은 필수적인 기초작업이다. ㅡ_-)>
애플리케이션 개발이 완료된 단계에서는 Flyway를 이용해서 DB 마이그레이션을 진행하면 되지만, 한창 개발중인 와중인지라 엔티티가 변경될 가능성도 높고해서 생성에 필요한 부분들을 당장 Flyway로 적재할 필요가 없어서 설정만 해두었다.

SpringBoot(Hibernate + Spring Data JPA)를 활용할 때 데이터베이스를 초기화 하는 방법은

  • JPA를 이용해서 데이터베이스를 초기화
    • spring.jpa.generate-ddl (boolean) switches the feature on and off and is vendor independent.
    • spring.jpa.hibernate.ddl-auto (enum) is a Hibernate feature that controls the behavior in a more fine-grained way. See below for more detail.
  • Hibernate를 이용해서 데이터베이스 초기화
    • import.sql를 루트클래스 경로에 놓아두면 시작시 실행된다.
  • Spring JDBC를 이용해서 데이터베이스 초기화
    • 설정파일에서 spring.datasource.initialize를 추가해두고
    • schema.sql 를 사용하면 JPA에서 설정해두면 JPA에서 테이블 생성할 때 schema.sql에 동일한 테이블이 있으면 문제가 생긴다.
    • ddl-auto=create-drop 으로 설정해두고 새로운 기초데이터를 넣기 위한data.sql을 사용할 수 있다.

      지금 사용하는 프로젝트에서는 spring.datasource.initialize설정을 통해서 data.sql을 이용하는 방법이 편해보여서 그렇게 했다.

  • Spring Batch database를 이용한 초기화
    • 가장 범용적으로 사용되는 SQL 초기화 스크립트를 이용한 방법이다.
  • 혹은 높은 수준의 데이터베이스 마이그레이션 도구를 사용
    • Flyway
    • Liquibase

Spring JDBC를 이용해서 데이터베이스 초기화 설정방법

spring:
  datasource:
    initialize: true
    driverClassName: org.h2.Driver
    url: jdbc:h2:file:./h2database;AUTO_SERVER=TRUE
    username: user
    password:

위와 같이 설정해두고
project/java/main/resource 경로에 data.sql을 넣어두어 프로젝트 초기화 데이터를 넣어두었다. 최초 실행시 initialize true로 두고 구동하면 JPA에 의해 테이블이 생성된 후에 data.sql이 실행되면서 데이터가 입력된다. 이후에는 initialize false로 변경하면 된다.

혹은,

spring:
  datasource:
    initialize: false

로 둔 상태에서 ./gradlew bootRepackage로 실행가능한 아카이브 파일로 만들어두고

$ java -jar archive.war --spring.datasource.initialize=true

로 실행하면 최초에 data.sql이 실행될 것이다(아마도…?).

스프링 부트 참고가이드

작성자

Phillip Webb, Dave Syer, Josh Long, Stéphane Nicoll, Rob Winch, Andy Wilkinson, Marcel Overdijk, Christian Dupuis, Sébastien Deleuze

1.2.0.BUILD-SNAPSHOT

Copyright © 2013-2014

Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically.


  • 목차

I. 스프링부트 문서

1. 문서에 대해

2. 조력 구

3. 첫걸음

4. 스프링부트 작동

5. 스프링부트 기능 학습

6. 출시

7. 고급기능들

II. 시작

8. 스프링부트 시작

9. 시스템 요구사항

9.1. 서블릿 컨테이너

10. 스프링부트 설치

10.1. 자바 개발자를 위한 설치법 소개

10.1.1. 메이븐 기반 설치법

10.1.2. 그레들 기반 설치법

10.2. 스프링부트 CLI를 이용한 설치

10.2.1. 규정 설치법

10.2.2. GVM을 이용한 설치법

10.2.3. OSX Homebrew 설치법

10.2.4. 커맨드라인 완성

10.2.5. 스프링 CLI로 빠르게 시작하는 예제

10.3. 이전버전의 스프링부트로부터 업그레이드

11. 초기 스프링부터 애플리케이션 개발

11.1. POM 파일 생성

11.2. classpath 의존성 추가

11.3. 코드 작성

11.3.1. @RestController와 @RequestMapping 에노테이션

11.3.2. @EnableAutoConfiguration 애노테이션

11.3.3. “main” 메서드

11.4. 예제 실행

11.5. 실행가능한 jar 생성

12. 다음 읽을거리

III. 스프링부트 사용

13. 시스템 빌드

13.1. 메이븐

13.1.1. 스프링부트 스타터 부모 상속

13.1.2. 부모 POM 없이 스프링부트 사용

13.1.3. 자바 버전 변경

13.1.4. 스프링부트 메이븐 플러그인 사용

13.2. 그레들

13.3. 앤트

13.4. 스프링부트 스타터 POM 목록

14. 코드 구성

14.1. ‘default’ 패키지 이용

14.2. 메인 애플리케이션 클래스 위치

15. 설정 클래스들

15.1. 추가된 설정 클래스들 불러오기

15.2. XML 설정 불러오기

16. 자동설정(Auto-configuration)

16.1. 점진적으로 자동설정을 대체

16.2. 특정한 자동설정을 비활성화

17. 스프링 빈과 의존성 주입

18. @SpringBootApplication애노테이션 사용

19. 애플리케이션 실행

19.1. IDE에서 실행

19.2. 패키징된 애플리케이션 실행

19.3. 메이븐 플러그인을 이용

19.4. 그레들 플러그인을 이용

19.5. 핫스와핑

20. 출시를 위해서 애플리케이션 패키징

21. 다음 읽을거리

IV. 스프링부트 기능

22. 스프링애플리케이션

22.1. 배너 수정

22.2. 스프링애플리케이션 수정

22.3. 플루언트 빌더 API

22.4. 애플리케이션 이벤트와 리스너

22.5. 웹 환경

22.6. 커맨드라인러너 사용

22.7. 애플리케이션 종료

23. 외부설정

23.1. 커맨드라인 속성 접근

23.2. 애플리케이션 속성 파일들

23.3. 프로파일 지정 속성들

23.4. 속성 플레이스홀더(placeholder)

23.5. Properties 대신 YAML 사용

23.5.1. YAML 읽어오기

23.5.2. 스프링 환경에서 속성들을 YAML로 노출

23.5.3. 다중 프로파일 YAML 문서

23.5.4. YAML 의 단점

23.6. 타입세이프 설정 속성들

23.6.1. 느슨한 연결

23.6.2. @ConfigurationProperties 검증

24. 프로파일

24.1. 활성프로파일 추가

24.2. 프로파일 작성방법

24.3. 프로파일 상세 설정파일

25. 로깅

25.1. 로그 형식

25.2. 콘솔 출력

25.3. 파일 출력

25.4. 로그 레벨

25.5. 로그 설정 변경

26. 웹 애플리케이션 개발

26.1. ‘Spring Web MVC framework’

26.1.1. Spring MVC 자동설정

26.1.2. HttpMessageConverter

26.1.3. MessageCodesResolver

26.1.4. ```Static Content````

26.1.5. Template engines

26.1.6. 오류 제어, 웹스피어

애플리케이션 서버에서 오류 제어

26.2. JAX-RS 그리고 Jersey

26.3. 내장형 서블릿 컨테이너 지원

26.3.1. 서블릿 그리고 필터

26.3.2. EmbeddedWebApplicationContext

26.3.3. 내장형 서블릿 컨테이너 변경

변경 작성방법

ConfigurableEmbeddedServletContainer 직접 변경

26.3.4. JSP 제약사항

27. 보안

28. SQL 데이터베이스 작업

28.1. 데이터베이스 설정

28.1.1. 내장형 데이터베이스 지원

28.1.2. 외부 데이터베이스 연결

28.1.3. JNDI 데이터베이스 연결

28.2. JdbcTemplate 사용

28.3. JPA 그리고 ‘Spring Data’

28.3.1. 엔티티 클래스

28.3.2. Spring Data JPA 레파지토리

28.3.3. JPA 데이터베이스 생성 및 삭제

29. NoSQL 기술 작업

29.1. 레디스Redis

29.1.1. 레디스 연결

29.2. 몽고DBMongoDB

29.2.1. 몽고DB 연결

29.2.2. MongoTemplate

29.2.3. Spring Data 몽고DB 레파지토리

29.3. Gemfire

29.4. Solr

29.4.1. Solr 연결

29.4.2. Spring Data Elasticsearch 레파지토리

30. 메시징

30.1. JMS

30.1.1. HornetQ 지원

30.1.2. ActiveMQ 지원

30.1.3. JNDI ConnectionFactory 사용

30.1.4. 메시지 전송

30.1.5. 메시지 수신

31. 이메일 전송

32. JTA를 이용한 트랜잭션 분산

32.1. Atomikos 트랜잭션 매니저 사용

32.2. Bitronix 트랜잭션 매니저 사용

32.3. Java EE 에서 관리하는 트랜잭션 매니저 사용

32.4. XA 그리고 non-XA JMS 연결 혼합

32.5. 대안적인 내장형 트른잭션 매니저 지원

33. 스프링 통합

34. JMX를 통해서 모니터링과 관리

35. 테스팅

35.1. 테스트 스코프 의존성

35.2. 스프링 애플리케이션 테스트

35.3. 스프링부트 애플리케이션 테스트

35.3.1. 스팍Spock을 사용하여 스프링 부트 애플리케이션 테스트

35.4. 테스트 유틸리티

35.4.1. ConfigFileApplicationContextInitializer

35.4.2. EnvironmentTestUtils

35.4.3. OutputCapture

35.4.4. TestRestTemplate

36. 자동설정으로 개발와 상황에 맞춰 사용

36.1. 자동설정 빈 이해

36.2. 자동설정 위치 후보지

36.3. 상황 애노테이션

36.3.1. 클래스 상황

36.3.2. 빈Bean 상황

36.3.3. 리소스 상황

36.3.4. 웹 애플리케이션 상황

36.3.5. SpEL 표현식 상황

37. 웹소켓

38. 다음 읽을거리

V. 스프링부트 액츄에에터: 출시준비 기능들

39. 사용가능한 출시준비 기능들

40. 엔드포인트

40.1. 엔드포인트 변경

40.2. 상태 정보 변경

40.3. 애플리케이션 정보 안내 변경

40.3.1. 빌드 시간에 관한 속성 확장 자동화

메이븐을 이용하여 속성 확장 자동화

그레들을 이용하여 속성 확장 자동화

40.3.2. 깃 커밋 정보

41. HTTP를 통해서 모니터링 및 관리

41.1. 세밀한 엔드포인트 노출

41.2. 관리 서버컨텍스트패스 변경

41.3. 관리 서버포트 변경

41.4. 관리 서버주소 변경

41.5. HTTP 엔드포인트 비활성화

41.6. 상태 엔드포인트에 대한 무기명 접근 제한

42. JMX를 통한 모니터링 및 관리

42.1. MBean 이름 변경

42.2. JMX 엔드포인트 비활성화

42.3. JMX용 Jolokia를 HTTP를 통해서 사용

42.3.1. Jolokia 변경

42.3.1. Jolokia 비활성화

43. 리모트쉘을 사용하여 모니터링 및 관리

43.1. 리모트쉘 연결

43.1.1. 리모트쉘 자격credentials

43.2. 리모트쉘 확장

43.2.1. 리모트쉘 명령어

43.2.2. 리모트쉘 플러그인

44. 측정

44.1. 데이터소스 측정

44.2. 측정 기록

44.3. 공개 측정 추가

44.4. 측정 레파지토리

44.5. Coda Hale 측정

44.6. 메시지 채널 통합

45. 오디팅auditing

46. 추적Tracing

46.1. 추적 변경

47. 프로세스 모니터링

47.1. 설정 확장

47.2. 작성

48. 다음 읽을거리

VI. 클라우드 배포

49. Cloud Foundry

49.1. 서비스 연결

50. Heroku

51. CloudBees

52. Openshift

53. Google App Engine

54. 다음 읽을거리

VII. 스프링부트 CLI

55. CLI 설치

56. CLI 사용

56.1. CLI를 이용해서 애플리케이션 실행

56.2. CLI에 의존성 추가

56.2.1. “grab” 의존성 추정

56.2.2. “grab” 협력 추정

“grab” 메타데이터 변경

56.2.3. 기본 불러오기 문장

56.2.4. 자동 main 메서드

56.3. 코드 테스트

56.4. 다양한 소스파일을 가진 애플리케이션

56.5. 애플리케이션 패키징

56.6. 새로운 프로젝트 준비

56.7. 내장형 쉘 사용

57. 그루비 빈즈 DSL을 통해서 애플리케이션 개발

58. 다음 읽을거리

VIII. 빌드툴 플러그인

59. 스프링부트 메이븐 플러그인

59.1. 플러그인 추가

59.2. 실행가능한 jar 와 war 파일 패키징

60. 스프링부트 그레들 플러그인

60.1. 플러그인 추가

60.2. 버전 없이 의존성 정의

60.2.1. 버전 관리 변경

60.3. 기본적인 배제 원칙

60.4. 실행가능한 jar 와 war 파일 패키징

60.5. 프로젝트 바로 실행

60.6. 스프링부트 플러그인 설정

60.7. 리패키징 설정

60.8. 변경된 그레들 설정으로 리패키징

60.8.1. 설정 사항

60.9. 그레들 플러그인의 동작방식 이해

60.10. 그레들을 이용해서 메이븐 레파지토리에 아티팩트 배포

60.10.1. 그레들 설정을 이용한 상속적 의존성 관리 POM 제작

60.10.2. 그레들 설정을 이용한 imports 의존성 관리 POM 제작

61. 다른 빌드 지원 시스템 지원

61.1. 리패키징 아카이브

61.2. 내포된 라이브러리

61.3. 메인 클래스 탐색

61.4. repackage 구현 예제

62. 다음 읽을 거리

IX. ‘어떻게How-to’ 가이드

63. 스프링부트 애플리케이션

63.1. 자동설정 문제해결

63.2. 시작 전 Environment 혹은 ApplicationContext 변경

63.3. ApplicationContext 계층 빌드(부모 혹은 루트 컨텍스트 추가)

63.4. non-web 애플리케이션 생성

64. 속성 및 설정

64.1. 스프링애플리케이션의 설정 확장

64.2. 애플리케이션의 외부 속성 위치 변경

64.3. ‘간략한’ 커맨드라인 인자 사용

64.4. 외부 속성을 YAML로 정의

64.5. 활성 스프링 프로파일 설정

64.6. 환경 의존적 설정 변경

64.7. 외부 속성들의 빌트인 항목 살펴보기

65. 내장형 서블릿 컨테이너

65.1. Servlet, Filter 혹은 ServletContextListener 를 애플리케이션에 추가

65.2. HTTP 포트 변경

65.3. HTTP 포트를 지정하지 않고 무작위로 사용

65.4. 실행시 HTTP Port 살펴보기

65.5. SSL 설정

65.6. 톰캣 설정

65.7. 톰캣의 다중커넥터 활성화

65.8. 톰캣을 프론트엔드 프록시 서버로 사용

65.9. 톰캣 대신 제티 사용

65.10. 제티 설정

65.11. 톰캣 대신 언더토우Undertow 사용

65.12. 언더토우 설정

65.13. 톰캣 7 사용

65.14. 제티 8 사용

65.15. @ServerEndpoint를 사용해서 웹소켓 엔드포인트 생성

66. 스프링 MVC

66.1. JSON REST 서비스 작성

66.2. XML REST 서비스 작성

66.3. Jackson ObjectMapper 변경

66.4. @ResponseBody 렌더링 변경

66.5. Multipart 파일 업로드 제어

66.6. Spring MVC DispatcherServlet 끄기

66.7. 기본 MVC 설정 끄기

66.8. ViewResolver 변경

67. 로깅

67.1. 로깅을 위한 Logback 설정

67.2. 로깅을 위한 Log4j 설정

68. 데이터 접근

68.1. 데이터소스 설정

68.2. 복수 데이터소스 설정

68.3. 스프링 데이터 레파지토리 사용

68.4. 스프링 설정으로 부터 @Entity 정의 분리

68.5. JPA 속성 설정

68.6. EntityManagerFactory 변경

68.7. 복수 엔티티매니저 사용

68.8. 전통적인 persistence.xml 사용

68.9. 스프링데이터 JPA와 몽고 레파지토리 사용

69. 데이터베이스 초기화

69.1. JPA 사용하여 데이터베이스 초기화

69.2. Hibernate를 사용하여 데이터베이스 초기화

69.3. Spring JDBC를 사용하여 데이터베이스 초기화

69.4. 스프링 배치 데이터베이스 초기화

69.5. 고차원 데이터베이스 마이그레이션 도구 사용

69.5.1. 시작시 Flyway 실행하여 데이터베이스 마이그레이션

69.5.2. 시작시 Liquibase를 실행하여 데이터베이스 마이그레이션

70. 배치 애플리케이션

70.1. 시작시 스프링 배치 작업 실행

71. 액츄에이터Actuator

71.1. 액츄에이터 엔드포인트의 주소 혹은 HTTP 포트 변경

71.2. ‘whitelabel’ 오류 페이지 변경

72. 시큐리티

72.1. 스프링부트 시큐리티 설정 끄기

72.2. AuthenticationManager를 변경하고 사용자 계정 추가

73. 핫스와핑

73.1. 정적컨텐츠 다시 읽기

73.2. 컨테이너 재시작없이 타임리프Thymeleaf 템플렛 다시 읽기

73.3. 컨테이너 재시작없이 프리마크FreeMarker 템플렛 다시 읽기

73.4. 컨테이너 재시작없이 그루비Groovy 템플렛 다시 읽기

73.5. 컨테이너 재시작없이 벨로시티Velocity 템플렛 다시 읽기

73.6. 컨테이너 재시작없이 자바 클래스 다시 읽기

73.6.1. 메이븐을 이용한 Spring Loaded 설정

73.6.2. 그레들과 IntelliJ를 이용한 Spring Loaded 설정

74. 빌드

74.1. 메이븐으로 의존성 버전 변경

74.2. 메이븐으로 실행가능한 JAR 생성

74.3. 추가적인 실행가능한 JAR 생성

74.4. 실행가능한 jar 동작에 필요한 지정된 라이브러리 추출

74.5. 배제를 통한 실행할 수 없는 JAR 생성

74.6. 메이븐을 이용해서 스프링부트 애플리케이션 원격 디버그 시작

74.7. 그레들을 이용해서 스프링부트 애플리케이션 원격 디버그 시작

74.8. 앤트를 이용해서 실행가능한 아카이브 빌드

75. 전통적 배포

75.1. 배포가능한 war 파일 생성

75.2. 오래된 서블릿 컨테이너에 배포가능한 war 파일 생성

75.3. 기존의 애플리케이션을 스프링부트로 변환

75.4. 웹로직을 위한 war 배포

75.5. 오래된(Servlet 2.5) 컨테이너에 war 배포

X. 부록

A. 일반적인 애플리케이션 속성

B. 메타데이터 설정

B.1. 메타데이터 형식

B.1.1. 그룹 어트리뷰트

B.1.2. 속성 어트리뷰트

B.1.3. 반복적인 메타데이터 아이템

B.2. 애노테이션 프로레서를 사용하여 메타데이터 생성

B.2.1. 내부 속성

B.2.2. 추가적인 메타데이터 추가

C. 자동설정 클래스

C.1. “spring-boot-autoconfigure” 모듈

C.2. “spring-boot-actuator” 모듈

D. 실행가능한 jar 형식

D.1. 내부 JARs

D.1.1. 실행가능한 jar 파일 구조

D.1.2. 실행가능한 war 파일 구조

D.2. 스프링부트의 “JarFile” 클래스

D.2.1. 표준 자바 “JarFile” 의 호환성

D.3. 실행가능한 jars 실행

D.3.1. 매니페스트 실행

D.3.2. 아카이브 확장

D.4. PropertiesLauncher 기능들

D.5. 실행가능한 jar 제약사항

D.5.1. Zip 엔트리 압축

D.5.2. System ClassLoader

D.6. 단독 jar 솔루션 대안


파일을 저장할 때, 파일이 저장될 경로는 부분은 상당한 주의를 요한다. 경로에 따라서는 전혀 다른 위치가 저장될 수 있으니…
우리가 접하게 되는 운영체제에 따라서 다른 파일구분자(‘\’, ‘/‘, ‘:’)를 사용하고 있는데, 이를 문자열로 처리하기는 힘이 들다.

전에는 File.separtor’를 문자열 중간중간에 넣으면서 필요한 경로를 만들었다면,
이제는 java.nio.file 패키지에 있는 ‘Path’, ‘Paths’를 이용하여 간결하게 코드를 작성해보자.

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;

import org.junit.Test;

public class PathTest {

    @Test
    public void testAddFileSeperator() {
        String path = "honeymon" + File.separator + "test";
        assertThat(path.toString(), is("honeymon/test"));

        path = "honeymon" + File.separator + "test" + File.separator + "file-separator";
        assertThat(path.toString(), is("honeymon/test/file-separator"));
    }

    @Test
    public void testPathsGet() {
        Path path = Paths.get("honeymon", "test");
        assertThat(path.toString(), is("honeymon/test"));

        path = Paths.get("honeymon", "test", "path");
        assertThat(path.toString(), is("honeymon/test/path"));
    }
}

파일 경로를 저렇게 만드는 이유 중 하는, 특정 위치에 파일을 생성하거나 조작하기 위해서인데 기존의 방식과 비교하면 다음처럼 파일을 다룰 수 있게 된다.

@Test
public void testMakeDir() {
    File file = new File("honeymon" + File.separator + "test" + File.separator + "file-separator");
    if(!file.exists()) {
        file.mkdir();
    }
}

@Test
public void testMakeDirByPath() {
    File file = Paths.get("honeymon", "test", "path").toFile();
    if(!file.exists()) {
        file.mkdir();
    }
}

위와 같은 형태로 차이가 생겨난다. 이 코드는 경로에 대한 변수가 증가할수록 더욱 확연한 차이를 보일 것이다. 오래전 코드를 사용하려고 하다가, 다르게 적용할 방법이 있을까하고 찾아보다가 걸린 이야기였다.

Sent from My Haroopad
The Next Document processor based on Markdown - Download

Spring Boot: Velocity 한글깨짐(Encoding) 문제

스프링부터SpringBoot를 이용한 프로젝트에서 TemplateViewEngine으로 Velocity를 선택했다.

@Bean
public ViewResolver viewResolver() {
    VelocityViewResolver viewResolver = new VelocityViewResolver();
    viewResolver.setPrefix("classpath:/templates");
    viewResolver.setSuffix(".vm");
    viewResolver.setOrder(Ordered.LOWEST_PRECEDENCE - 20);
    return viewResolver;
}

이 설정만 해서는 Velocity가 인코딩 설정을 제대로 하지 못한다.

스프링부트 설정에 application.yml을 이용했다. YAML을 설정DSL로 채택했는데, 설정이 무척 간결해진다.
Velocity와 관련된 설정은

spring:
  velocity:
    properties:
      input.encoding: UTF-8
      output.encoding: UTF-8

다음과 같이 해주면, Velocity 스프링 설정은 끝.

혹은 별도로 Velocity에 관한 설정을 하는 방법은 다음과 같다.

1. velocity.properties 를 이용하거나

<bean id="velocityConfig" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
  <property name="configLocation" value="classpath:/velocity.properties"/>
</bean>
resource.loader = file

file.resource.loader.description = Velocity File Resource Loader
file.resource.loader.class = org.apache.velocity.runtime.resource.loader.FileResourceLoader
file.resource.loader.path = .
file.resource.loader.cache = false
file.resource.loader.modificationCheckInterval = 2

input.encoding=UTF-8
output.encoding=UTF-8

2. 스프링 빈 설정을 하면 된다.

스프링 빈으로 설정하는 방법은

1. JavaConfig 빈 설정

@Bean
public VelocityConfigurer velocityConfigurer() {
    VelocityConfigurer configurer = new VelocityConfigurer();
    configurer.setResourceLoaderPath("classpath:/templates");
    Properties properties = new Properties();
    properties.setProperty("input.encoding", "UTF-8");
    properties.setProperty("output.encoding", "UTF-8");
    configurer.setVelocityProperties(properties);
    return configurer;
}

2. XML 빈 설정

<bean id="velocityConfigurer" class="import org.springframework.web.servlet.view.velocity.VelocityConfigurer">
    <property name="resourceLoaderPath" value="classpath:/~~"/>
    <property name="velocityProperties">
        <props>
            <prop key="input.encoding">UTF-8</prop>
            <prop key="output.encoding">UTF-8</prop>
        </props>
    </property>
</bean>

두 가지 방법이 있다.



그냥 벨로시티를 사용하기 싫었는데...

실로 오랜만에 적는 독후감(?)이다. 그 동안 이런저런 책을 읽었지만, 독후감을 써야겠다는 생각을 가지게 되는 책이 오랜만에 나타났다.

Deview 2014에 참관하러 갔다가 부스에 계신 인사이트 대표님께 인사드리면서 이야기를 하다가 가판대에 놓여있는 이 책을 발견했다. 이미 대웅에서 나온 책을 가지고 있던 상태여서 잠시 망설였지만, SNS으로 알고 계신 이병준님이 번역(http://www.buggymind.com/559)하시기도 했고 Java 7, 8 주석도 수록했다는 문구에 혹해서 그 자리에서 바로 구매했다. 결코 강요에 의해 구매한 것은 아니다.

프로그래밍을 하게 되면, 자신이 사용하고 있는 프로그래밍 언어와 관련해서 기본을 되짚어 보는 의미로 일년에 한두번 정도 읽어줘야하는 책들이 있다.



자바 쪽에서는 ‘클린코드‘, ‘Effective Java‘, ‘토비의 스프링‘ 등이 있다. Effective Java는 OO출판사에서 나온 것이 있고, 인사이트에서 이번에 출간했다. 00출판사의 서적경우에는 번역이 워낙 거시기해서 원서를 보는 것이 낫다는 평이 많은 편이다. 나 역시 읽어도 내가 읽고 있는 것이 글인지 싶을 만큼 몇줄 읽어내려가다보면 어디를 읽었는지 되짚어야할 만큼 집중도가 뚜욱 떨어진다.

인사이트에서 나온 ‘Effective Java 2nd’는 읽으면서 여러모로 흡족했다. 책크기나 종이재질도 그렇고 폰트도 그렇고.
나는 책에 줄을 치면서 책을 보는데, 책의 본문에 중요하다고 생각되는 문장마다 굵은 글씨 처리가 되어 있어서 줄을 치는 횟수가 많이 줄었다.



어쩌면 내가 허투로 보면서 넘어갈만한 요소들에도 굵은 글씨 처리가 되어 집중하게 된다. 사실 이렇게 책의 중요부분마다 굵은 글씨처리 해주는 것이 사소한듯 하지만 손이 많이 가고 번거로운 작업을 요구한다. 번역자가 그 책을 읽는 분들에게 중요하다고 알려주고 있는 것이다. 내 스타일에는 잘 어울린다.



자바 코딩과 관련된 규칙의 끝날 즈음에는 ‘요약하자면’ 으로 규칙의 내용을 간결하게 한단락으로 정리해주는 부분이 있다. 규칙을 읽어가다보면 이해가 어려웠던 부분도 ‘요약하자면’ 단락을 읽으면서 정리할 수가 있다. 쪽집게 과외 선생님이 콕하고 찝어주는 느낌이랄까?

프로그래밍을 처음 시작하면 예제를 따라서, 다른 사람의 코드를 따라서 혹은 자신만의 방법으로 코딩을 익히고 배우면서 프로그래밍을 익혀나가게 된다. 이러다보면 우리는 종종 그 프로그래밍 언어가 가지고 있는 장점과 단점, 권고사항 등을 제대로 따르지 않게되는 나쁜 습관을 가지게 되는 경우가 있다. 프로그래밍 언어에서 별다른 오류없이 컴파일되고 실행되니까 자기만의 방법으로 코딩하게 된다. 그러다보면 나쁜 냄새를 뿜어내는 프로그램이 만들어지게 될 것이다.

자바 프로그래밍을 하면서 빠지기 쉬운 착오나 자주하게 되는 실수를 짚어준다. hashCode() 메서드를 오버라이딩하면 equals() 메서드도 함께 오버라이딩 해야한다는 규칙(IDE를 사용하면 동시에 생성하도록 강제되어 있다)이라던지 등의 자바 프로그래밍과 관련된 다양한 이야기와 지식이 담겨 있다.

요약하자면, 자바 프로그래밍을 하는 이라면 책장에 꽂아두고 일년에 두번씩은 읽어줘야할 그런 책이다. 책 여기저기에 스며있는 역자의 풍부한 프로그래밍 지식이 잘 스며든 명작이 탄생했다.

꼭 사라~ 반드시 사라~


+ Recent posts