覚えきれる量を明らかに超えている気がするので,すぐに参照できるように自分で分かりやすい形で備忘録としてまとめます.
Spring用語
IoCコンテナ
IoCはInversion of Controlの略称とのこと.現在では,Dependency Injectionコンテナという名称の方が広く使用されている.要はDIを実施して生成されるインスタンスを管理するコンテナ.
Bean
IoCコンテナによって管理されるオブジェクト
AOP
Aspect Oriented Programming. アスペクト指向プログラミング.ログ等の予備機能やメソッド・クラスの共通処理を別クラスに抽出し,実機能の可読性を挙げるためのプログラミング.
確かにログが入り混じってると見にくいのでこれは導入したいなぁ
Advice
抽出された共通処理.@Aspectでクラスを指定し,下記のAnnotationで実行タイミングを指定する.
- @Before
- @After
- @Around
- @AfterReturning : メソッドが正常に完了した場合
- @AfterThrowing :メソッドが例外をスローした場合
Pointcut
実行場所の指定
- execution : メソッドが一致した場合
- within:クラスが一致した場合
- bean:beanが一致した場合
- @annotation : メソッドのアノテーションが一致した場合
- @within:クラスのアノテーションが一致した場合
なお,メソッド・クラスの指定にはワイルドカードを使用可能
- * :任意の文字列,1階層,1引数
- ..:任意の0文字以上の文字列,0以上階層,0以上引数
- +:クラス,サブクラス,実装クラス
また,論理演算で重ねることも可能
Join Point
実行されているメソッド実行自体.Springではその情報の格納オブジェクト.
@Slf4j @Aspect public class LoggerAspect { @Before("execution(String com.example.demo.MyController.showList(Object))") public void startLog(JoinPoint jp){ log.info("{}: Before Process", jp.getSignature()); } }
上記のexecutionは書くのが手間なので,以下のようにワイルドカードを用いて書くことが可能
@Before("execution(* com.example.demo.MyController.showList(..))") @Before("execution(* ...MyController..*(..))") //ほかにも同名のが引っかかる可能性はある
Spring Boot Web
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
@SpringBootApplication
SpringBootApplicationクラスであることの指定.
@Configuration, @EnableAutoConfiguration, @ComponentScanの3つを付与しているのと同様
@Configuration
Configurationクラスであることの指定
@Bean
@Configurationクラス内でメソッドに付与することで,DIコンテナで管理することが可能.Bean名称は何もしなければメソッド名になる.
@Bean public Object objectName(){ return new Object(); } //@Bean({"name"}) で別名を与えることも可能
@Componentとの使い分けは,@Componentを付与することのできないクラスをDIコンテナの管理下に置きたいときに利用するとのこと.
@EnableAutoConfiguration
自動構成機能のEnable化
@ComponentScan
@Componentをスキャンし,DIを実施します.
@Component
Springで管理されるクラスであることを明示する.すなわち,Spring Containerに登録されるBeanでDIの対象となる.
@Controller, @Service, @Repositoryは@Componentの子
@Autowired
Springがオブジェクトを管理・依存性注入を行ってくれる.なお,Field Injection, Setter Injection, Constructor Injectionが可能だが,現在はConstructor Injectionが推奨されている.その理由としては以下のようなことが考えられるようです。
- 単一責任の原則に反していることが判別しやすくなる
- Spring Containerなしに使用できる(Testabilityの増加)
- publicでないフィールドにInjectionする場合,依存性が外部に公開されない.すなわち,依存性を解決できないので,利用しにくい
- Immutableにできる
また,Constructor Injectionについては,Constructorが一つの場合には@Autowiredのアノテーションは不要.
@Scope
BeanのScopeを定義することができます.指定したScopeごとにインスタンスを生成します.これは一般のServletで用いるJavaBeanと同様ですね.(そりゃそうか)
singleton, prototype, request, session, application, websocket
を選択可能.デフォルトはsingleton. request, session, applicationは@RequestScope, @SessionScope, @ApplicationScopeでも同様.
@Service
ビジネスロジックであるAnnotation.@Componentの一種.
Controlloer
@Controller
Front ControllerパターンにおけるControllerを指定する.返り値のurlにforwardする.
@Controller public class HomeController { }
@RestController
REST用のController.返り値をそのまま返す.APIとしての役割.
Request
@RequestMapping
あらゆるHttpRequestを受け付けます(GET, POST, PUT, DELETE, PATCH).また,クラスに付与することもでき,例えば@Controllerのトップレベルドメインを指定することが可能.
@RequestMapping("/") public String doSomething(){ return "index"; }
@GetMapping
HTTPのGETリクエストに対応します.
Attributeとして登録するためには,Modelを追加の引数として指定する
@RequestMapping("/") public String doSomething(@RequestParam String message, Model model) { model.addAttribute("message", message); return "index"; //return "redirect:/index"; // redirectの場合 }
@RequestParam
@RequestParamでリクエストパラメータの取得が可能.引数名と同一であれば省略可能であり,異なるのであれば,@RequestParam(“name”)としてパラメータ名を指定する.
なお,RequestParamに対応したパラメータがない場合はデフォルトではエラーとなるため,@RequestParam(required=false)を指定するとパラメータがなくとも応答可能となる.
@ModelAttribute
引数パラメータを自動的にAttributeに追加する.下記で自動的に追加される.@RequestParamと異なり,@ModelAttributeはパラメータがなくともよい.
@RequestMapping("/") public String doSomething(@ModelAttribute String message) { return "index"; }
@PostMapping
HTTPのPOSTリクエストに対応します.
@PathVariable
指定したpathの一部分をそのまま取得することが可能.下記の例では,{id}部分が引数idに格納される.
@GetMapping("/edit/{id}") public String doSomething(@PathVariable Long id, Model model){ model.addAttribute("obj", repository.findById(id)); return "index"; }
Format
@NumberFormat(pattern = “#,###”)
指定したパターン文字列を数値に変換します
@DateTimeFormat
文字列をLocalDateオブジェクトに変換します.文字列で指定する方法と規定されたパターンから選択する方法がある
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE) @DateTimeFormat(pattern = "yyyy-MM-dd")
Class, Interface
ApplicationContext
IoCコンテナのinterface.
(Hoge) appContext.getBean("hoge"); //BeanをStringから取得.名前は先頭小文字のクラス名 appContext.getBeanDefinitionNames(); //登録された全てのBean名称を取得
CommandLineRunner
コンポーネントスキャン時にコマンドラインとして実行される.コンポーネントスキャンは@ComponentScanが付与されたクラスが起動されたときに実施される.そのため,基本的には起動時である.
error.html
作製しておけば,エラー時に自動的に呼び出してくれる.statusにはステータスコード,errorにはエラーメッセージが格納されており,そのまま利用することが可能.
“error”というフォルダを作製すれば,その中でステータスコードごとにhtmlファイルを分割することも可能.
schema.sql, data.sql
resources/schema.sql, data.sqlは作成した場合に自動で読み込まれ,テーブルの作成等を起動時に行うことが可能.
なお,この場合はspring.jpa.hibernate.ddl-auto=noneを設定しておかないと競合が発生する
UserDetailsService
ユーザー認証時に使用される.
Spring Validation
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
@Validated
Validationを掛けたいパラメータに指定する.BindingResultがValidation結果を保持しています.
@RequestMapping("/") public String doSomething(@Validated @ModelAttribute DataObject object, BindingResult result) { return "index"; }
@Data class DataObject{ @NotBlank @Size(max = 30) private String name; @NotNull @Pattern(regexp = "[0-9]*?") private String id; }
だいたい確認したいValidationはそろっているので,公式サイトから確認すること
@NotBlank, @NotEmpty, @NotNull
@Min, @Max
@Size, @Pattern
自作Validatorを作製する時
ConstraintValidator
これを継承したクラスを作製する.必須Override項目はisValidのみ.
また,以下のアノテーションを実装した自作アノテーションを作製することで,自作Validatorによるアノテーションチェックを可能とする
@Target
アノテーションの適用箇所を規定する.ElementType.METHOD, ElementType.FIELD等がある
@Retention
アノテーションの保持期間を指定する.RetentionPolicy.RUNTIME, RetentionPolicy.CLASS等がある
@Constraint
アノテーションのチェック実行対象を指定する.自作クラスを指定する.メソッド類はよくわからないが必須らしい.また調べる.
@Target({ElementType.FIELD, ElementType.METHOD}) @Retention(RetentionPolicy.CLASS) @Constraint(validatedBy = MyValidator.class) public @interface MyValidation { String message() default "invalid"; Class<?>[] groups() default{}; Class<? extends Payload>[] payload() default {}; }
application.properties
spring.messages.fallback-to-system-locale
デフォルトはtrueで,サーバー言語を設定します.(通常の設定であれば日本語のはず)
falseにすることで,defaultのmessages.propertiesが読み込まれる.
spring.messages.basename
読み込むファイル名の指定が可能.resourcesをルートとした相対パスで指定する.
spring.datasource.url
jdbcを指定する.なお,jdbcの設定としてmemが存在し,memの場合はApplication終了と同時にデータベースは破棄される.(In memoryなので当然か)
spring.h2.console.enabled
Spring BootでDevToolsをEnableにしていない場合は,こちらで設定することでh2Consoleが起動される.
spring.datasource.url=jdbc:h2:mem:testdb spring.h2.console.enabled=true
spring.jpa.hibernate.ddl-auto=create, create-drop, update,none
- create : @Entityのテーブルがあれば削除し,再生成を行う.
- create-drop : createに加えてSpring Boot終了時にテーブルを削除する.これはmemの場合はcreateと同様.
- update : @Entityのテーブルがない場合に作成する.
- none:何もしない
spring.jpa.show-sql=true
HibernateによるDatabaseのSQL操作がConsoleに出力されるようになります.Intellijの場合,以下のようにconsoleに出力されるようになる
Spring Data JPA
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency>
JPAとは
JPAとはJava Persistence APIの略称で,ORMです.Object Relation Mapping.自分の認識では,JDBCがqueryベースでデータベーステーブルを直接操作するのに対して,JPAはJavaオブジェクトがレコード・テーブルに対応して,Javaオブジェクトベースでデータベース操作ができるという違いがある.
JPAの方がJDBCに対して,クラスがデータベース内の依存関係を表現しやすく,オブジェクト指向に向いているということです.
@Entity
エンティティであるクラス.カラムに対応するということ
@Id
フィールドをエンティティの主キーに設定する
@GeneratedValue
@IDアノテーションとの併用.フィールドとして主キーを自動生成する.
GenerationTypeとして,AUTO, IDENTITY, SEQUENCE, TABLEを利用可能.DefaultはAUTOで使用するRDBMSに応じて最適なものが選択される.
@GeneratedValue(strategy = GenerationType.IDENTITY)
以下が詳しい
@Repository
データベースレポジトリであることを示します.JpaRepositoryを継承する場合にはなくてもよい.
@ManyToOne
多対一のテーブルを指定する.
@ManyToOneのみの短方向でもデータベースとして機能するが,双方向で関連させたほうが良いらしい.検索しやすいため.
@OneToMany
一対多のテーブルを指定する.mappedByで多の方のcolumn名を指定します.
@OneToMany(mappedBy = "column_name")
@Query
SQLやJPQLを直接発行する関数を作製可能. JPQLはEntityに対する操作で,SQLはデータベースに対して直接発行します.
@Query("SELECT o FROM Obj o WHERE o.name LIKE ?1") //JPQL. 引数は ?1 ?2 等でアクセス Collection<Obj> searchByName(String name) @Query("SELECT * FROM obj_table WHERE name LIKE :name, nativeQuery=true) //SQL形式 Collection<Obj> searchByName(String name)
Class, Interface
JpaRepository
@Repositoryとしての最低限の機能が提供されている.
関数を定義するだけで,自動的に対応したクエリを作製してくれる.基本的には,以下のように定義可能.その他にもcount, exists, delete, LessThan, GreaterThanなども作成可能.
repository.findByXxxx //フィールド名検索 repository.findByXxxLike
Spring Security
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-springsecurity5</artifactId> </dependency>
<html xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
@EnableWebSecurity
Spring Securityの機能を有効にするクラスを指定する
Classes and Interface
WebSecurityConfigurerAdapter
@Configuration, @EnableWebSecurityアノテーションを付与して,SecurityのConfigurationを設定する.
設定可能なのは,configure(http) リクエスト用とconfigure(auth)認証用とconfigure(web)のweb全体に関する設定の3つ.
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { //HttpRequestに対するセキュリティ http.authorizeRequests() .antMatchers("/login", "/error").permitAll() //login, errorには認証なしで .anyRequest().authenticated() //その他は認証あり .and() .formLogin() //ログインフォーム .loginPage("/login") //ログインフォームページ指定 .defaultSuccessUrl("/") //ログインが成功した時のリダイレクト先 } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { //認証方法の設定 auth.inMemoryAuthentication() //メモリ内認証 auth.userDetailsService()でDB .withUser("admin") .password("password") .authorities("ROLE_ADMIN") } @Override public void configure(WebSecurity web) throws Exception { //Web全体のセキュリティ web.ignoring().antMatchers("/css/**", "/img/**", "/webjars/**"); //静的リソースをセキュリティから除外します.認証なしでロゴ等が表示されるようにするため. } }
PasswordEncorder
PasswordEncorderの共通Interface.以下のような実態クラスが使用可能.
- BCryptPasswordEncoder
- Argon2PasswordEncoder
- Pbkdf2PasswordEncoder
使用方法はencodeしてmatchesさせるだけ.
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); String result = encoder.encode("myPassword"); encoder.matches("myPassword", result);
勿論だが,Client⇔Server間の通信を暗号化している訳ではない.ここはHTTPSプロトコルの担当であるので,HTTPで通信している人は注意.
認証情報の取得
以下のようにしてControllerから認証情報を取得することが可能
@GetMapping("/") public Object doSomething(Authentication auth, Model model){} public Object doSomething(Principal auth, Model model){} public Object doSomething(Model model){ Authentication auth = SecurityContextHolder.getContext().getAuthentication; }
logout.html
自動で生成されている.ここにアクセスすることでログアウトすることが可能.
application.properties
spring.messages.basename=org/springframework/security/messages
一部のエラーメッセージを日本語化可能.
Thymeleaf 記法
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
springboot thymeleaf
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency>
<html xmlns:th="http://www.thymeleaf.org">
th:object
フォームにバインドするオブジェクトを指定する.該当オブジェクトには上記の選択変数式でアクセス可能となる.
th:field
id, name, valueに同一の値を設定する
th:errorclass=”hoge”
th:fieldがValidationでErrorとなった時にclass名に”hoge”を動的に追加する.すなわち,th:fieldがErrorの時にclass=”original hoge”となる
<input type="text" class="form-control" th:errorclass="is-invalid" th:field="*{name}">
この場合,nameがvalidationの結果Errorになった場合,class=”form-control is-invalid”となる.
th:errors
指定したフィールドのValidation Errorを全て取得する
th:href
外部リソースを参照する場合に使用します.動的にリンクを作製することも可能で,以下のような規則に基づいて作成されます.
//obj.id=5のときth:href="@{/obj/contents(contentsId=${obj.id})}
// ⇒/obj/contents?contentsId=5th:href="@{/obj/contents/{
contentsId}(contentsId=${obj.id})}
// ⇒/obj/contents/5
<link th:href=”@{/hoge.css}” rel=”stylesheet”>
hoge.cssをスタイルシートに設定する
<script th:src=”@{/hoge.js}”></script>
hoge.jsを埋め込む.Bootstrapの場合は,body最下部へ配置すること.
th:each
Collectionの繰り返しを実装できる
<div th:each="object : ${list}"> <div>[[${object.id}]] - [[${object.content}]]</div> </div>
th:if
タグに追加することで,条件式が満たされる場合に該当タグが実行されます.タグはなんでもよい.
<div th:if="${list.size() == 0}"> 該当データがありません </div>
th:replace
特定タグに置き換えます.指定にはフラグメント式を利用します.下記の例では,fragments/header.html内のheaderというfragmentに置換されます.
<div th:replace="~{fragments/header :: header}"></div>
th:include
これは非推奨となりました.th:replaceかth:insertを利用します
th:remove
タグ内から,指定した条件に応じてタグを削除します.replaceやinsertと併用することが多い様子.
指定できるものは,all, body, tag, all-but-first, noneがあります.
th:block
HTMLとして出力しないタグで,Thymeleafの処理に使用可能.
th:for
<label for>の代替だが,#idsと併用することでid指定を楽にすることができる.
<input type="radio" th:field="*{obj}"> <label th:for="${#ids.prev('obj')}">xxxx</label>
thymeleaf layout dialect
レイアウト用のライブラリ
<dependency> <groupId>nz.net.ultraq.thymeleaf</groupId> <artifactId>thymeleaf-layout-dialect</artifactId> </dependency>
<html xmlns:layout="http://www.ultraq.net.nz/web/thymeleaf/layout">
layout:fragment
layoutのfragmentを選択できます.後に別ファイルからth:replace, th:insertで利用することができます.
<div layout:fragment="content"> </div>
layout:decorate
レイアウトを指定できます.下記ではlayout.htmlを指定したことになります.
layout:decorate="~{layout}"
spring-security
<html xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
sec:authorize
th:ifと意味的には同じ.以下のようにして.特定のRoleを持っているときに表示させるなどが可能
<div sec:authorize="hasRole('ROLE_ADMIN')">xxxx</div>
その他表記
#{}
外部ファイル参照.標準のSpringBootファイル構成においては,resources下のpropertiesファイルに記載されたproperty.
${}
変数式.Attribute呼び出し
${@…}
DIコンテナが管理しているBeanを参照
*{}
選択変数式と呼ぶらしい.Attribute呼び出しの短縮記法.formにバインドされたObjectに短縮系でアクセス可能.なお,${object.id}としても同様にアクセスできる.
<form th:action="@{/}" th:object="${object}" method="post"> <label for="id">ID:</label> <input type="text" th:field="*{id}"> </form>
@{}
リンク先を指定する.
[[hogehoge]]
インライン表記
~{}
フラグメント式.フラグメントを指定する際に使用する
${T(package.class).STATICFIELD
Staticフィールドを参照可能
#ids
以下の形式で,idを呼び出すことができ,繰り返し処理等で役に立ちそうなユーティリティメソッド
${#ids.seq('someId')} ${#ids.next('someId')} ${#ids.prev('someId')}
HTML
HTML一般なことはこちらに記載
<div class=”hoge”>
グループIDという認識.CSSで一括して操作を行うことが可能な単位.前後に改行が入る
<span>
グルーピングタグ.<span>はインライン要素として使用可能なグルーピングタグ.divは前後に改行が入る点が異なる
<script>
javascript等のスクリプトを文書内に埋め込む.
<nav>
主要なナビゲーションセクションであることを示す.すなわち,他ページへのリンクを掲載するセクションであることを示す.セクションタグの一種.
<ul>
unordered list.箇条書きで示す場合に利用される
<ol>
ordered list
<li>
<ul>等のlistとセットで使用され,一つ一つの項目を表すタグ.
<i>
イタリック体表記となる.
<hr>
horizontal rule.水平の横線を描画する.
<select>
要素選択の際に使用されるタグ.<option>タグで要素を追加する.Thymeleafと併用すると以下のような形で表記ができる.
<select class="form-control" th:field="*{obj}"> <th:block th:each=" item : ${list}"> <option th:value="${item.id}" th:text="${item.name}"></option> </th:block> </select>
<small>, <big>
テキストを一回り小さく,大きくできる.font size=”-1″, font size=”+1″と同様の効果がある.なお,これらの値はcssで設定でも設定できるので,スタイルシートで設定することが推奨されている様子
<main>
アウトラインには寄与しない.<body>内で主要な内容であることを示す.
<label>
<input>と併用する.<input>のidと<label>のforを同一名称にすることで,関連付けを行うことができ,ブラウザ上での補助機能が使用可能となる.例えば,ラベルをクリックした場合に対応構成部品がアクティブになったりする.
Lombok
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
@Data
getter, setter, equals, toStringなどデータクラスに必要な関数を自動生成
@Data class DataObject{ private String name; private String id; }
これだけで,以下のものを全て自動生成してくれる.便利.
@Getter
getterだけ
@Setter
setterだけ
@EqualsAndHashCode
equalsやhashCodeだけ
@ToString
toStringだけ
@RequiredArgsConstructor
finalなフィールドのConstructorを自動生成します.
@Componentと組み合わせて使用することで,インジェクションを自動化することが可能.
@Slf4j
slf4jの当該クラス用のLoggerを自動生成してくれる.以下と等しい.
private static final Logger log = LoggerFactgory.getLogger(hoge.class)
application.propertiesに以下の設定を入れることで様々な設定が可能
logging.level.{package名}=error/warn/info/debug/trace logging.file.path=./logFiles //フォルダの指定 logging.file.name=./logFiles/application.log //ファイル名の指定
Bootstrap
Bootstrap
<dependency> <groupId>org.webjars</groupId> <artifactId>bootstrap</artifactId> <version>5.0.1</version> </dependency>
bootstrap-icons
Bootstrap公式のアイコンライブラリ.
<dependency> <groupId>org.webjars.npm</groupId> <artifactId>bootstrap-icons</artifactId> <version>1.5.0</version> </dependency>
<div class=”invalid-feedback” th:errors=”*{hoge}”></div>
Validationに引っかかった場合に,規定のerror messageを赤文字で表記してくれます.
BootStrap単体では,下記のようにdivタグの間にError Messageを表記することでError Messageを規定します.
<div class="invalid-feedback" th:errors="*{hoge}">Message Example</div>
SpringBootと併用する場合は,JavaEEのBeanValidationとHTMLのcontraint validation apiの仕様に則り,ValidationMessages.propertiesに規定した値でValidation Messageが表示される.(正直あまり理解できていないが,こういうことらしい)
なお,それらしいDefault値は英語ですでに設定されているため,ValidationMessages_ja.propertiesを作製して,そこに日本語時のValidationを記載するようである.
なお,ValidationMessageはデフォルトでは一つしか表示されないため,優先順位が設定されている.下記のようにPriorityは設定されている.
//Priority high NotBlank.boundHoge.field //Annotation + bind + filed NotBlank.field //Annotation + field NotBlank //Annotation //Priority low
Webjars
クライアントサイドのライブラリをGradle,Maven経由で読み込むことができる便利な依存解決ライブラリ.これは,サードライブラリが循環的に依存している場合でも,そうならないように適切に依存関係を解決してくれるという点でよい.そのため,サードライブラリを読み込む場合はwebjarsを経由して読み込むことが推奨されている?
SpringBootで使用する場合は,webjars-locator-coreを使用すること.以下のようにversionはSpringBootで管理されているため,webjarsの読み込み時には指定する必要がない.
<dependency> <groupId>org.webjars</groupId> <artifactId>webjars-locator-core</artifactId> </dependency>
H2 Database
<dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency>