アノテーションとサンプルコードまとめ

# はじめに

こんにちは。takunと申します。

私はSpringBoot3の勉強中で、アノテーションを使った実装を学んでおります。
正直多くて覚えられないと思ったので、一旦ざっとまとめてみようと思った次第です。

当方は初心者エンジニアです。間違ったことや不適切な内容となってしまう可能性もあることをご承知ください。また、助言など頂けると嬉しいです。

# アノテーションの共通機能(Bean関連)
インスタンスをBean(オブジェクト)としてDIコンテナに登録する。

# 複数のクラスで扱うアノテーション

### @Autowired
DIに登録してるクラスのインスタンスを取得する。
インターフェースを指定しても、必要な処理が組み込まれた無名クラスのインスタンスが作成・設定される。
今後廃止になりそうな記述もあることに注意。
~~~java
@Autowired
PersonRepository repository;  //フィールドインジェクションは非推奨。
~~~
~~~java
private final PersonRepository repository;

@Autowired
public HogeClass(PersonRepository repository;){
    this.repository = repository;        //コンストラクタインジェクション。推奨。
}
~~~
### @RequiredArgsConstructor
クラス内でprivate finalで宣言した変数のコンストラクタを自動生成してくれる。
上記のAutowiredのコンストラクタ部分を省略できる！
~~~java
@RequiredArgsConstructor  
public class SignupService {
	private final UserInfoRepository repository;
	private final Mapper mapper;
	private final PasswordEncoder passwordEncoder;
~~~
### @Bean
Beanとして登録。インスタンスを返すメソッドにつける。
他クラスでフィールドに注入できる。
~~~java
@Bean
public Person person() {
	return new Person("takun",27,"man");
}
~~~
@Componentはクラス単位で再利用可能にできる。
### @Value
アプリケーションプロパティを利用して初期値を設定する
~~~application.properties
error.message=エラーだよ！
~~~
~~~java
@Value("${error.message}")  
private String errMsg;
~~~

# コントローラークラス
### @Controller
クラス内にURLマッピングするメソッドを利用する際に必要。クラス名の上に付与。
### @RestController
使い方はControllerと同じ。大きく異なるのは、RESTfulなAPIとして扱われること。
ビュー(HTML)をレスポンスするのではなく、データ(JSON,XML)を返す。
### @RequestMapping
~~~java
@RequestMapping(value = "/find", method = RequestMethod.GET)
public ModelAndView index(ModelAndView mav) {/*処理*/}
	
@RequestMapping(value = "/find", method = RequestMethod.POST)
public ModelAndView search(HttpServletRequest request,ModelAndView mav) {/*処理*/}
~~~
### @GetMapping,@PostMappging
クラス自体に@RequestMapping("/hoge")のように付与する場合は、このアノテーション付与でメソッド振り分けができる。
> 1画面1コントローラーの設計ならこれがいいのかも
### @PreAuthorize
SecurityConfigクラスで@EnableMethodSecurityを記述しておけば利用できる。
下記のようにリクエスト(メソッド)ごとに細かなアクセス制限ができる。
~~~java
@RequestMapping("/")
@PreAuthorize("permitAll")
public ModelAndView index(ModelAndView mav) {/*処理*/}
~~~ 
- hasRole('ロール') - 指定したロールを許可する
- hasAnyRole([ロール配列]) - 指定したロール全てを許可する
- permitAll - 全て許可
- denyAll - 全て拒否
- isAnonymous() - 匿名ユーザー(未認証)のみ許可
- isAuthenticated() - 認証ユーザーのみ許可
### @Transactional
コミット処理がかかるリクエストハンドラに付与する。
~~~java
@RequestMapping(value = "/delete", method = RequestMethod.POST)
@Transactional
public ModelAndView remove(@RequestParam long id, ModelAndView mav) {
	repository.deleteById(id);
	return new ModelAndView("redirect:/");
}
~~~
### @RequestParam
リクエストパラメータを取得する。
~~~java
public String processMenuForm(Model model, 
			@RequestParam(value = "全検索", required = false) String all,
			@RequestParam(value = "詳細検索", required = false) String detail,
			@RequestParam(value = "genre", required = false) String[] genres,
			@RequestParam(value = "category", required = false) String[] categories,
			@RequestParam(value = "count", required = false) Integer count) {/*処理*/}
~~~
### @PathVariable
パスパラメータを取得する。
~~~java
@RequestMapping(value = "/edit/{id}", method = RequestMethod.GET)
	public ModelAndView edit(@ModelAttribute Person Person, 
                             @PathVariable int id, ModelAndView mav){/*処理*/}
~~~
### @ModelAttribute
引数にはインスタンス名を指定。GETでは、自動でnewされたインスタンスが作成されて割り当てられる。POSTでは、送信されたフォームの値が渡される。
~~~java
@RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView index(@ModelAttribute("formModel") Person person, ModelAndView mav) {/*処理*/}
~~~
~~~index.html
<form method="post" action="/" th:object="${formModel}">
<input type="text" class="form-control"
	    	name="name" th:value="*{name}"/> <!--Personクラスのフィールドを用意-->
~~~
### @Validated
渡されたエンティティの値をバリデーションチェックしてくれる。BindingResultにバインドした結果が格納される。
エンティティのフィールドに付与したバリデーション用のアノテーションを参照する。
~~~java
public ModelAndView form(@ModelAttribute("formModel") @Validated Person person, 
                         BindingResult result,ModelAndView mav) {
		ModelAndView res = null;
		if (!result.hasErrors()) {
			repository.saveAndFlush(person);
			res = new ModelAndView("redirect:/");
		} else {
			mav.setViewName("index");
			mav.addObject("title", "登録ページ");
			mav.addObject("msg", "エラーが起きました");
			res = mav;
		}
		return res;
}
~~~
# エンティティクラス
### 基本的なアノテーション
~~~java
@Entity  //クラスに付与。エンティティクラスであることを示すアノテーション。
@Table(name="people")  //name指定しなければクラス名が適用される
@Data  //getter,setter用意してくれる。
public class Person {
	@Id //プライマリキー
	@GeneratedValue(strategy = GenerationType.AUTO)  //キーの生成方法＝列挙型で自動的に割り振る。
	@Column
	@NotNull  
	private long id;
	
	@Column(length = 50,nullable = false)  //最大50文字でnullは認めない。
	@NotBlank //未入力チェック
	private String name;
	
	@Column(length = 200,nullable = true)  //@Tableと同様name指定もできる。
	@Email  //メール形式なのかチェック
	private String mail;
	
	@Column(nullable = true)
	@Min(0)  //数値の最小、最大チェック
	@Max(150)
	private Integer age;
}

~~~
### @NamedQuery
クラスに付与する。DAOクラスなどで扱うクエリ文を用意できる。クエリ文はコードから切り離して管理できるのがメリット。
実装クラスでQueryインスタンスを取得する際に呼び出される。
~~~java
@NamedQuery(
			name = "findByAge",
			query = "from Person where age >= :min and age < :max"
	)
~~~
### @OneToMany,@ManyToOne
エンティティ同士を関連づけるアノテーション。情報抽出に関してクエリだけでなく、プロパティで参照できて便利そう。
~~~Person.java
@OneToMany(mappedBy="Person")  //連携するエンティティ(Message.java)のどのプロパティに紐づくか
@Column(nullable=true)
private List<Message> messages;  
~~~
~~~Message.java
@ManyToOne	//1人のメンバー：複数のメッセージエンティティ
private Person Person;
~~~

# (Security)Configクラス
構成クラスとも言う。アプリケーションで利用される各種のBean類をまとめて管理するクラス。
必要に応じてコメントアウトをすれば、複数の構成クラスを切り替えて開発できる。
### @Configuration
クラスに付与して使う。
アプリケーション実行時に構成クラスと認識され、クラス内のBeanも全て実行。DIコンテナに格納される。
### @EnableWebSecurity
クラスに付与、Webセキュリティを動作するために使う。
### @EnableMethodSecurity
@EnableWebSecurityとの違いは、パスごとのアクセス制限をコントローラークラスでのメソッドごとに設定できる。(@PreAuthorize参照)
こっちの方が管理しやすそう。
# リポジトリ(JPA) / DAOクラス
データベースアクセスをするクラス。基本的なアクセスはJPAが基本。
- SprindDataJPA
正確にはクラスではなくインターフェース。JpaRepositoryインターフェースを継承する。
リポジトリは、汎用的なDBアクセス処理を自動生成し実装する。
- DAO
クエリの自動実装はないが、より複雑なデータアクセスのロジックを実装できる。
リポジトリと比べて、コントローラークラスからデータロジックを分離しやすいのがメリット。
### @Repository
クラスに付与し、データアクセスクラスであることを示す。
アプリケーション起動時にこのインターフェースの実装クラスが作成、Beanに登録される。
### @PersistenceContext
DAOで利用する。EntityManagerのBean(インスタンス)を取得するアノテーション。
これはSpringBootアプリケーションの場合、起動時に自動的にBeanとして登録されている。
~~~java
@PersistenceContext
EntityManager entityManager;
//具体的なメソッド内でのコード
//entityManager.createQuery("クエリ文")
//             .setParameter("バインド変数",値)
//             .getResult〜
~~~
.createNamedQuery("@NamedQueryで作った名前")も扱える。
### @Query
@NamedQueryでエンティティクラスに作成できる一方で、検索機能の拡張のために書き換える必要もある。
@Queryでは、JPAを継承したインターフェースにも定義できる。
~~~java
@Repository
public interface PersonRepository extends JpaRepository<Person, Long> {
	@Query("from Person where age >= :min and age < :max")
	public List<Person> findByAge(@Param("min") int min,@Param("max") int max);
 ~~~
@Paramは引数名とバインド変数名が一致しない場合に使用する必要がある。

# サービスクラス
### @Service
クラスに付与。
サービスレイヤーの機能を提供するクラスを指す。つまり、ロジック担当。
様々なコントローラーやBeanから利用する必要のある機能はここにまとめる。
リポジトリ(JPA)もこれを利用すれば、ロジックを分離して管理できる。


# おわりに
完全に主観ですが、この辺が重要そうなアノテーションなのかなと感じました。
もちろん異論は認めます（笑）。コメントやアドバイスなど頂けたら嬉しいです！

こんな新米エンジニアの記事をここまで見て頂けて嬉しいです。拙い文章で恐縮ですが、見ていただいてる方に分かりやすい内容となるよう努めていきます！