<!DOCTYPE html>

<html xmlns:th="http://www.thymeleaf.org">

<head>

    <title th:text="${title}">Report mail</title>

    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

</head>

<body>

    <h1>Send Test Report Email</h1>

    <table>

        <thead>

        </thead>

        <tbody>

        <colcolgroup>

        <col style="width: 100px;"/>

        <col/>

        </colcolgroup>

            <tr>

                <td th:text="#{mail.th.project.id}">Proejct</td>

                <td th:text="${projectId}">Project</td>

            </tr>

            <tr>

                <td th:text="#{mail.th.sub.project.id}">Sub Project</td>

                <td th:text="${subProjectId}">Sub Project</td>

            </tr>

            <tr>

                <td th:text="#{mail.th.duration}">Duration</td>

                <td th:text="${duration}">Duration</td>

            </tr>

            <tr>

                <td th:text="#{mail.th.format}">Report Format</td>

                <td th:text="${format}">Document</td>

            </tr>

            <tr>

                <td th:text="#{mail.th.start.datetime}">Start Datetime</td>

                <td th:text="${startDateTime}"></td>

            </tr>

            <tr>

                <th th:text="#{mail.th.end.datetime}">End Datetime</th>

                <td th:text="${endDateTime}"></td>

            </tr>

        </tbody>

    </table>

</body>

</html> 

위의 템플릿 코드는 그대로 둔 채,

<!-- Thymeleaf template -->

<dependency>

    <groupId>org.thymeleaf</groupId>

    <artifactId>thymeleaf</artifactId>

    <version>2.0.17</version>

</dependency>

<dependency>

    <groupId>org.thymeleaf</groupId>

    <artifactId>thymeleaf-spring3</artifactId>

    <version>2.0.17</version>

</dependency>

아래의 오류가 발생한다. 

ERROR: org.thymeleaf.TemplateEngine - [THYMELEAF][http-bio-8080-exec-7] Exception processing template "report/testReportMail": Exception evaluating SpringEL expression: "title" (report/testReportMail:4)

thymeleaf 의 version을 2.0.17 에서 2.0.16으로 변경해보자.

정상동작한다. 

현재 사용하고 있는 스프링은 '3.2.0.RELEASE'


이메일 발송용 템플릿 엔진으로 사용하려고 Thymeleaf 를 찾았다.

전 프로젝트에서는 StringTemplate3를 사용했었는데, StringTemplate4로 바뀌면서 그 사용법이 많이 바뀐 탓에 새로 익혀야할 것 같아 찾다보니 몇몇 사람들의 추천하는 글을 보고는 덜컥 시도를 해본다.

ㅡ_-);; 주된 삽질의 끝은 오탈자였다. 하아...

Spring에서 사용하는 예제 : http://www.thymeleaf.org/springmail.html

<!-- THYMELEAF: Template Resolver for email templates --> 

<bean id="emailTemplateResolver" class="org.thymeleaf.templateresolver.ClassLoaderTemplateResolver"> 

  <property name="prefix" value="mail/" /> 

  <property name="templateMode" value="HTML5" /> 

  <property name="characterEncoding" value="UTF-8" /> 

  <property name="order" value="1" /> 

</bean> 


<!-- THYMELEAF: Template Resolver for webapp pages   --> 

<!-- (we would not need this if our app was not web) --> 

<bean id="webTemplateResolver" class="org.thymeleaf.templateresolver.ServletContextTemplateResolver"> 

  <property name="prefix" value="/WEB-INF/templates/" /> 

  <property name="templateMode" value="HTML5" /> 

  <property name="characterEncoding" value="UTF-8" /> 

  <property name="order" value="2" /> 

</bean> 


<!-- THYMELEAF: Template Engine (Spring3-specific version) --> 

<bean id="templateEngine" class="org.thymeleaf.spring3.SpringTemplateEngine"> 

  <property name="templateResolvers"> 

    <set> 

      <ref bean="emailTemplateResolver" /> 

      <ref bean="webTemplateResolver" /> 

    </set> 

  </property> 

</bean> 

<!-- THYMELEAF: View Resolver - implementation of Spring's ViewResolver interface --> 

<!-- (we would not need this if our app was not web)                              --> 

<bean id="viewResolver" class="org.thymeleaf.spring3.view.ThymeleafViewResolver"> 

  <property name="templateEngine" ref="templateEngine" /> 

  <property name="characterEncoding" value="UTF-8" /> 

</bean> 



내가 적용한 코드

<!-- THYMELEAF: Template Resolver for email templates -->

    <bean id="emailTemplateResolver" class="org.thymeleaf.templateresolver.ClassLoaderTemplateResolver">

        <property name="prefix" value="META-INF/template/mail" />

        <property name="suffix" value=".html"/>

        <property name="templateMode" value="HTML5" />

        <property name="characterEncoding" value="UTF-8" />

        <property name="order" value="1" />

        <!-- Template cache is true by default. Set to false if you want -->

        <!-- templates to be automatically updated when modified.        -->

        <property name="cacheable" value="true" />

    </bean>

    

    <!-- THYMELEAF: Template Engine (Spring3-specific version) -->

    <bean id="templateEngine" class="org.thymeleaf.spring3.SpringTemplateEngine">

        <property name="templateResolvers">

          <set>

            <ref bean="emailTemplateResolver" />

          </set>

        </property>

    </bean>

이렇게 설정을 해놓으니 계속 

org.thymeleaf.exceptions.TemplateInputException: Error resolving template "email-test", template might not exist or might not be accessible by any of the configured Template Resolvers

TemplateEngine에서 템플릿 파일을 찾지 못한다는 오류를 뿌린다. ㅡ_-);;

2시간 정도 삽질을 한 결과를 알아냈다.

<bean id="emailTemplateResolver" class="org.thymeleaf.templateresolver.ClassLoaderTemplateResolver">

        <property name="prefix" value="META-INF/template/mail" />

...

</bean>

의 항목을

<bean id="emailTemplateResolver" class="org.thymeleaf.templateresolver.ClassLoaderTemplateResolver">

        <property name="prefix" value="META-INF/template/mail/" />

...

</bean>

으로 바꾸니까 된다.

미묘한 차이인데, 발견했는가? ㅡ_-)?

예제의 '/' 하나를 무시한 결과가 나의 3시간 삽질의 차이를 낳았다. Orz.

ihoneymon@ihoneymon-desktop:/workspace/git-repositories/never-ending-study$ git push origin develop

ssh_exchange_identification: Connection closed by remote host

fatal: Could not read from remote repository.


참고 페이지 : https://github.com/nodester/nodester/issues/346


git pull --rebase

후 git pull origin develop 정상동작

### 개발환경

* Hibernate 4.2.0.Final


### 문제발생 원인

* @Entity 선언 객체를 정렬하려는 영도로 interface Compare<T>를 구현한 후

 int compareTo(Object o) 에서 사용하려는 비교값 필드로 order 을 정의했다.

@Entity

@Table(name="SAMPLE")

public class Sample implements Serialize, Compare<Sample> {

@Id

@GeneratedValue(strategy=GenerationType.AUTO)

private Long id;


     @Getter

private Long order;


@Override

public int compareTo(Sample o) {

return getOrder().compareTo(o.getOrder());

}

}


  이렇게 정의된 엔티티 객체의 테이블이 생성되지 않는 문제가 발생해서, 이를 해결하기 위해서 여러가지를 시도해봤다.  복사해서 새로운 엔티티 객체를 만들어보고, 객체의 참조관계를 변경해보고, 클래스명을 바꿔보고 하이버네이트 버전을 변경해봤지만 증상은 동일했다.

  이를 확인하기 위해서 구현하는 과정을 한단계한단계 되짚어보았다. ㅠㅅ-) 그러다가 발견했다.

  새로 만들어서 id 값을 넣었을 떄까지는 이상없이 생성이 되다가,

private Long order;

이 필드를 넣는 순간부터 구현되지 않는 것을 발견했다.


### 해결방법

* order -> seq 로 변경

필드명을 seq로 변경하고 나니... 정상적으로 테이블이 생성되는 것을 확인했다.

### 보충 설명

다른 분이 알려주신 것을 보고 생각했다.

'아, order가 hibernate와 관련된 예약어가 아니라 database와 관련된 예약어...였어.'

Entity 객체의 필드명을 지정할 때 Database의 예약어를 사용하지 않도록 하자. 반드시 도메인의 필드명으로 사용해야 한다면, @Column(name="")을 이용하여 테이블의 컬럼명을 다른 것으로 변경하자.



Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException

개발환경

  • hibernate : 4.2.0.Final
    • hibernate dialect : org.hibernate.dialect.MySQLDialect
  • MariaDB : 5.5.29-MariaDB

문제 로그

java.lang.reflect.InvocationTargetException

    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

    at java.lang.reflect.Method.invoke(Method.java:601)

    at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:297)

    at java.lang.Thread.run(Thread.java:722)

Caused by: org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [insert into department(id, name, description, parent_id, createdDate) values(?, ?, ?, ?, ?)]; nested exception is java.sql.BatchUpdateException: Table 'database.department' doesn't exist

    at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:237)

    at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:72)

    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:605)

    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:617)

    at org.springframework.jdbc.core.JdbcTemplate.batchUpdate(JdbcTemplate.java:890)

    at org.springframework.jdbc.core.namedparam.NamedParameterBatchUpdateUtils.executeBatchUpdateWithNamedParameters(NamedParameterBatchUpdateUtils.java:40)

    at org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate.batchUpdate(NamedParameterJdbcTemplate.java:324)

    ... 6 more

Caused by: java.sql.BatchUpdateException: Table 'database.department' doesn't exist

    at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:2054)

    at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1467)

    at com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.executeBatch(NewProxyPreparedStatement.java:1723)

    at org.springframework.jdbc.core.JdbcTemplate$4.doInPreparedStatement(JdbcTemplate.java:905)

    at org.springframework.jdbc.core.JdbcTemplate$4.doInPreparedStatement(JdbcTemplate.java:890)

    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:589)

    ... 12 more

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'database.department' doesn't exist

    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)

    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)

    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)

    at java.lang.reflect.Constructor.newInstance(Constructor.java:525)

    at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)

    at com.mysql.jdbc.Util.getInstance(Util.java:386)

    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1054)

    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4120)

    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:4052)

    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2503)

    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2664)

    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2815)

    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2155)

    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2458)

    at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:2006)

    ... 17 more

[INFO] ------------------------------------------------------------------------

[INFO] BUILD FAILURE

[INFO] ------------------------------------------------------------------------

[INFO] Total time: 10.762s

[INFO] Finished at: Wed Apr 24 22:06:17 KST 2013

[INFO] Final Memory: 43M/365M

[INFO] ------------------------------------------------------------------------

[ERROR] Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.2.1:java (default-cli) on project docs-flow-data-manager: An exception occured while executing the Java class. null: InvocationTargetException: PreparedStatementCallback; bad SQL grammar [insert into department(id, name, description, parent_id, createdDate) values(?, ?, ?, ?, ?)]; nested exception is java.sql.BatchUpdateException: Table 'database.department' doesn't exist -> [Help 1]

[ERROR]

[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.

[ERROR] Re-run Maven using the -X switch to enable full debug logging.

[ERROR]

[ERROR] For more information about the errors and possible solutions, please read the following articles:

[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException

해결책

  • 하이버네이트가 자동으로 @Entity를 이용하여 테이블을 생성할 때 기본은 클래스명을 따른다.
    • 대소문자를 구분하는 Database 에서는 이 부분이 문제를 일으키는 요인으로 추측된다.
  • @Entity 아래에 @Table(name=“TABLE_NAME”) 으로 테이블명을 대문자로 하여 강제적으로 선언했다.
  • 참조관계가 생성되는 부분들에 대해서도 @JoinTable(name=“JOIN_TABLE”)으로 지정해주는 것이 적절해보인다.

+ Recent posts