質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Spring

Spring Framework は、Javaプラットフォーム向けのオープンソースアプリケーションフレームワークです。 Java Platform上に、 Web ベースのアプリケーションを設計するための拡張機能が数多く用意されています。

Thymeleaf

Thymeleaf(タイムリーフ)とは、Java用のテンプレートエンジンで、特定のフレームワークに依存せず使用することが可能です。

Spring Boot

Spring Bootは、Javaのフレームワークの一つ。Springプロジェクトが提供する様々なフレームワークを統合した、アプリケーションを高速で開発するために設計されたフレームワークです。

Q&A

1回答

3670閲覧

spring boot @CreatedDate 自動設定できない。

oruka1982

総合スコア10

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Spring

Spring Framework は、Javaプラットフォーム向けのオープンソースアプリケーションフレームワークです。 Java Platform上に、 Web ベースのアプリケーションを設計するための拡張機能が数多く用意されています。

Thymeleaf

Thymeleaf(タイムリーフ)とは、Java用のテンプレートエンジンで、特定のフレームワークに依存せず使用することが可能です。

Spring Boot

Spring Bootは、Javaのフレームワークの一つ。Springプロジェクトが提供する様々なフレームワークを統合した、アプリケーションを高速で開発するために設計されたフレームワークです。

1グッド

1クリップ

投稿2020/09/13 08:34

編集2020/09/15 12:46

■環境
Spring Tool Suite 4
Version: 4.6.0.RELEASE
Build Id: 202003181317

mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.21 |
+-----------+

mysql> desc mydata;

+-----------------+--------------+------+-----+-------------------+-----------------------------------------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+--------------+------+-----+-------------------+-----------------------------------------------+
| id | int | NO | PRI | NULL | auto_increment |
| name | varchar(50) | YES | | NULL | |
| mail | varchar(510) | YES | | NULL | |
| age | int | YES | | NULL | |
| memo | text | YES | | NULL | |
| registered_date | datetime | NO | | CURRENT_TIMESTAMP | DEFAULT_GENERATED |
| update_date | datetime | NO | | CURRENT_TIMESTAMP | DEFAULT_GENERATED on update CURRENT_TIMESTAMP |
| remove_date | datetime | YES | | NULL | |
| last_updated_by | varchar(50) | YES | | NULL | |
+-----------------+--------------+------+-----+-------------------+-----------------------------------------------+

[root@71b31029 /]# java -version
openjdk version "11.0.8" 2020-07-14

■実施したいこと。
mydataに登録処理の際に、「registered_date」「update_date 」を自動で登録したい。

■ソース mydataクラス @Entity

JAVA

1package com.example.demogradle.domain.entity; 2import java.util.Date; 3import java.util.List; 4import javax.persistence.CascadeType; 5import javax.persistence.Column; 6import javax.persistence.Entity; 7import javax.persistence.EntityListeners; 8import javax.persistence.GeneratedValue; 9import javax.persistence.GenerationType; 10import javax.persistence.Id; 11import javax.persistence.NamedQueries; 12import javax.persistence.NamedQuery; 13import javax.persistence.OneToMany; 14import javax.persistence.Table; 15import javax.persistence.Temporal; 16import javax.persistence.TemporalType; 17import javax.validation.constraints.Email; 18import javax.validation.constraints.Max; 19import javax.validation.constraints.Min; 20import javax.validation.constraints.NotEmpty; 21import javax.validation.constraints.NotNull; 22 23import org.springframework.data.annotation.CreatedDate; 24import org.springframework.data.annotation.LastModifiedDate; 25import org.springframework.data.jpa.domain.support.AuditingEntityListener; 26 27import org.springframework.lang.NonNull; 28 29@Entity 30@Table(name = "mydata") 31@EntityListeners(AuditingEntityListener.class) 32@NamedQueries({ 33 @NamedQuery(name = "findWithIdNameMail", query = "from MyData where id = :fid or name like :fname or mail like :fmail") 34 // 複数やる場合は、下記のように追加。※「,」を忘れずに。 35 //,@NamedQuery(name = "findWithMail", query = "from MyData where mail like :fmail") 36}) 37public class MyData { 38 39 // 6-28 追加 40 @OneToMany(cascade = CascadeType.ALL) 41 @Column(nullable = true) 42 private List<MsgData> msgdatas; 43 44 public List<MsgData> getMsgdatas() { 45 return msgdatas; 46 } 47 //ここまで 48 49 //@OneToMany(cascade = CascadeType.ALL) 50 @Id 51 @GeneratedValue(strategy = GenerationType.AUTO) 52 @Column //(name = "ID") 53 @NonNull 54 private Integer id; 55 56 @Column(length = 50, nullable = false) 57 @NotNull 58 @NotEmpty 59 private String name; 60 61 @Column(length = 510, nullable = false) 62 @Email 63 @NotEmpty 64 private String mail; 65 66 @Column(length = 3, nullable = false) 67 @Min(20) 68 @Max(99) 69 private int age; 70 71 @Column(nullable = true) 72 private String memo; 73 74 @Temporal(TemporalType.DATE) 75 @CreatedDate 76 @Column(name = "registered_date", nullable = false, updatable = false) 77 private Date registered_date; 78 79 @LastModifiedDate 80 @Temporal(TemporalType.DATE) 81 @Column(name = "update_date", nullable = false) 82 private Date update_date; 83 84 @Temporal(TemporalType.DATE) 85 @Column(nullable = true) 86 private Date remove_date; 87 88 @Column(nullable = false) 89 private String last_updated_by; 90 91 92 public Integer getId() { 93 return id; 94 } 95 96 public void setId(Integer id) { 97 this.id = id; 98 } 99 100 public String getName() { 101 return name; 102 } 103 104 public void setName(String name) { 105 this.name = name; 106 } 107 108 public String getMail() { 109 return mail; 110 } 111 112 public void setMail(String mail) { 113 this.mail = mail; 114 } 115 116 public int getAge() { 117 return age; 118 } 119 120 public void setAge(int age) { 121 this.age = age; 122 } 123 124 public String getMemo() { 125 return memo; 126 } 127 128 public void setMemo(String memo) { 129 this.memo = memo; 130 } 131 132 public Date getRegistered_date() { 133 return registered_date; 134 } 135 136 public void setRegistered_date(Date registered_date) { 137 this.registered_date = registered_date; 138 } 139 140 public Date getUpdate_date() { 141 return update_date; 142 } 143 144 public void setUpdate_date(Date update_date) { 145 this.update_date = update_date; 146 } 147 148 public Date getRemove_date() { 149 return remove_date; 150 } 151 152 public void setRemove_date(Date remove_date) { 153 this.remove_date = remove_date; 154 } 155 156 public String getLast_updated_by() { 157 return last_updated_by; 158 } 159 160 public void setLast_updated_by(String last_updated_by) { 161 this.last_updated_by = last_updated_by; 162 } 163 164} 165 166```  167CrudController 168```JAVA 169@Controller 170public class CrudController { 171 172 @Autowired 173 MyDataRepository myDataRepository; 174 175 @RequestMapping(value = "/jpa/crud", method = RequestMethod.GET) 176 public ModelAndView create(@ModelAttribute("formModel") MyData mydata,ModelAndView mav) { 177 178 mav.setViewName("jpa/crud"); 179 mav.addObject("msg", "+his is sample content."); 180 Iterable<MyData> list = myDataRepository.findAll(); 181 mav.addObject("datalist", list); 182 return mav; 183 } 184 185 @RequestMapping(value = "/jpa/crud",method = RequestMethod.POST) 186 @Transactional(readOnly = false) 187 public ModelAndView createForm(@ModelAttribute("formModel") @Validated MyData mydata, 188 BindingResult result, 189 ModelAndView mov) { 190 191 ModelAndView res = null; 192 if (!result.hasErrors()){ 193 myDataRepository.saveAndFlush(mydata); 194 res = new ModelAndView("redirect:/jpa/crud"); 195 } else { 196 mov.setViewName("jpa/crud"); 197 mov.addObject("msg","sorry, error is occured..."); 198 Iterable<MyData> list = myDataRepository.findAll(); 199 mov.addObject("datalist",list); 200 res = mov; 201 } 202 return res; 203 } 204

MyDataRepository

JAVA

1@Repository 2public interface MyDataRepository extends JpaRepository<MyData, Integer> { 3 4 public List<MyData> findAll(); 5 public Optional<MyData> findById(Integer id) ; 6 public List<MyData> findByNameLike(String name); 7 public List<MyData> findByIdNotNullOrderByIdDesc(); 8 public List<MyData> findByAgeGreaterThan(Integer age); 9 public List<MyData> findByAgeBetween(Integer age20, Integer age22); 10 11 // リスト6−16 Repositoryからクエリーを投げる場合 12 @Query("SELECT d FROM MyData d ORDER BY d.name") 13 public List<MyData> findAllOrderByName(); 14}

crud.html (thymeleaf)一部抜粋

html

1 <body> 2 <div th:replace="/common/header :: header"></div> 3 <!-- ここから記載--> 4 <h1 th:text="#{content.title.crud}">データCRUD</h1> 5 6 <table border="1" > 7 <form method="post" action="/jpa/crud" th:each="object:${formModel}" th:object="${formModel}" > 8 <h2 th:text="#{content.title.create}">データ登録</h2> 9 <!-- 10 <ul> 11 <li th:each="error : ${#fields.detailedErrors()}" class="err" th:text="${error.message}"> 12 </li> 13 </ul> 14 --> 15 16 <tr><td><label for="name">名前</label></td> 17 <td><input type="text" name="name" th:value="*{name}" th:errorclass="err" class="sample5"></input> 18 <div th:if="${#fields.detailedErrors('name')}" th:errors="*{name}" th:errorclass="err"></div> 19 </td> 20 </tr> 21 <tr><td><label for="age">年齢</label></td> 22 <td><input type="text" name="age" th:value="*{age}" th:errorclass="err" class="sample5"></input> 23 <div th:if="${#fields.detailedErrors('age')}" th:errors="*{age}" th:errorclass="err"></div> 24 </td> 25 </tr> 26 <tr><td><label for="mail">メール</label></td> 27 <td><input type="text" name="mail" th:value="*{mail}" class="sample5"></input> 28 <div th:if="${#fields.detailedErrors('mail')}" th:errors="*{mail}" th:errorclass="err"></div> 29 </td> 30 </tr> 31 <tr><td><label for="memo">メモ</label></td> 32 <td><textarea name="memo" th:text="*{memo}" cols="20" rows="5" class="sample5"></textarea></td> 33 </tr> 34 <tr><td><label for="last_updated_by">登録者</label></td> 35 <td><input type="text" name="last_updated_by" th:value="*{last_updated_by}" class="sample5"></input></td> 36 </tr> 37 <tr><td></td><td><input type="submit" value="登録" class="sample5"></td> 38 </tr> 39 </form> 40 </table> 41

エラー内容

2020-09-13 16:56:39.444 ERROR 3521 --- [io-18443-exec-7] o.h.engine.jdbc.spi.SqlExceptionHelper : Column 'registered_date' cannot be null

2020-09-13 16:56:39.456 ERROR 3521 --- [io-18443-exec-7] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement] with root cause
java.sql.SQLIntegrityConstraintViolationException: Column 'registered_date' cannot be null

エラー内容から、「registered_date」がnullと言うことでエラーになっていると思いますが、formで入力設定しなくても、値があるようにmysqlでは設定しているのですが、Spring側でエラーになっているかと思うのですが。
いろいろ試しのですが、うまく思うように動作できず。
すいませんが、教授お願いします。

A-pZ👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

JPAの監査情報アノテーションはSpringSecurityで認証済みの情報から取得するものですが、こちらSpringSecurityでログイン済みでしょうか。

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#auditing.interfaces

また、こちらの記事も非常に参考にできるでしょう。
Qiita:JPAで最終更新情報の更新を自動化して画面に表示するまで

簡単ですが、以下の設定をして簡易的にSpringSecurityの認証をかけることで、記載していただいたJPAの監査アノテーションで値が入ることを確認済みです。

リスナー登録だけでなく、Configに@EnableJpaAuditingをつけること、ならびにAuditorAwareの実装クラスで名前を返してあげると良いです。

java

1import java.util.Objects; 2import java.util.Optional; 3 4import org.springframework.context.annotation.Bean; 5import org.springframework.data.domain.AuditorAware; 6import org.springframework.data.jpa.repository.config.EnableJpaAuditing; 7import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 8import org.springframework.security.core.Authentication; 9import org.springframework.security.core.context.SecurityContextHolder; 10import org.springframework.security.core.userdetails.User; 11import org.springframework.security.core.userdetails.UserDetails; 12import org.springframework.security.core.userdetails.UserDetailsService; 13import org.springframework.security.provisioning.InMemoryUserDetailsManager; 14 15@EnableWebSecurity 16@EnableJpaAuditing 17public class SecurityConfig { 18 19 @Bean 20 public UserDetailsService userDetailsService() { 21 UserDetails user = User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build(); 22 return new InMemoryUserDetailsManager(user); 23 } 24 25 @Bean 26 public AuditorAware<String> auditorProvider() { 27 return new SpringSecurityAuditorAware(); 28 } 29 30 public class SpringSecurityAuditorAware implements AuditorAware<String> { 31 32 @Override 33 public Optional<String> getCurrentAuditor() { 34 Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); 35 if (Objects.isNull(authentication) || !authentication.isAuthenticated()) { 36 return Optional.empty(); 37 } 38 39 return Optional.of(authentication.getName()); 40 } 41 42 } 43} 44

投稿2020/09/15 13:51

A-pZ

総合スコア12011

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

oruka1982

2020/09/19 16:55

A-pZ様 ご返信、また実装方法など御教授ありがとうございます。 >>JPAの監査情報アノテーションはSpringSecurityで認証済みの情報から取得するものですが、 >>こちらSpringSecurityでログイン済みでしょうか。 特に、認証などは行わずに本件の処理(自動で登録時刻・アップデート時刻)が入る処理イメージを 想定した実装を行いたいと思い投稿させて頂きました。 Springでmysqlの「DEFAULT_GENERATED」を処理する際は、SpringSecurityで認証済みからでないと 難しいのでしょうか。 すいません、学習不足で。 恐れ入りますが、ご教授お願いいたします。
A-pZ

2020/09/20 00:45

JPAの @PrePersist を使うことで、データ登録時の前処理に、@PreUpdateはデータ更新時の前処理にデータを変更できます。 たとえば、 @Column(name = "last_modified") private Date lastModified; があった場合に、 @PrePersist public void onPrePersist() { setLastModified(new Date()); } とすると登録時に現在時刻が入ります。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問