【Java・SpringBoot】RESTサービス① - GETメソッド

#REST (Representational State Transfer)とは
* URLを叩くと各種Webサービスを実行することができます
    * 例えば、yahoo天気情報などを取得する
    * AIや天気情報、地図検索、経路検索などを実行する、など
* 通常のHTMLリクエストを送ると、HTMLがレスポンスとして返ってきて、ブラウザでは、返ってきたHTMLを画面に表示する
* RESTではHTMLリクエストを送ると、**Webサービスの実行結果が返る**
* →アプリケーションから**外部サービスを利用することができる**！
    * 既にあるサービスを使えば、開発効率UPすることができます💮
* RESTではJSON形式でレスポンスを返すのがメイン

#RESTサービス実装の準備
* ユーザ情報を取得、登録、更新、削除するRESTサービスを実装します

```RestService.java
package com.example.demo.login.domain.service;

import java.util.List;

import com.example.demo.login.domain.model.User;

public interface RestService {

    //１件登録用メソッド
    public boolean insert(User user);

    //１件検索用メソッド
    public User selectOne(String userId);

    //全件検索用メソッド
    public List<User> selectMany();

    //１件更新用メソッド
    public boolean update(User user);

    //１件削除用メソッド
    public boolean delete(String userId);
}
```

#インターフェース実装クラスを作成

```RestServiceJdbcImpl.java
package com.example.demo.login.domain.service.jdbc;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.example.demo.login.domain.model.User;
import com.example.demo.login.domain.repository.UserDao;
import com.example.demo.login.domain.service.RestService;

@Transactional
@Service
public class RestServiceJdbcImpl implements RestService {

    @Autowired
    @Qualifier("UserDaoJdbcImpl")
    UserDao dao;

    //１件登録用メソッド
    @Override
    public boolean insert(User user) {

        int result = dao.insertOne(user);
            return false;
    }

    //１件検索用メソッド
    @Override
    public User selectOne(String userId) {
        return null;
    }

    //全件検索用メソッド
    @Override
    public List<User> selectMany() {
        return null;
    }

    //１件更新用メソッド
    @Override
    public boolean update(User user) {
            return false;
    }

    //１件削除用メソッド
    @Override
    public boolean delete(String userId) {
            return false;
    }
}

```

#コントローラクラス

###@RestController
* REST用のコントローラークラスには、@RestControllerアノテーションを付けます


```UserRestController.java
package com.example.demo.login.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.login.domain.service.RestService;

@RestController
public class UserRestController {

    @Autowired
    RestService service;
}
```

#セキュリティの設定
* RESTサービスを作る前に、セキュリティの設定をします
* RESTサービスのみCSRF対策を無効にし、Springが用意しているRequestMatcherを実装したクラスを作成します。
* このクラスの中では、GETメソッドおよび、指定されたURLの場合、CSRF対策のチェックをしないようにします。
* RestMatcherの設定をSecurityConfig.javaに反映します

```RestMatcher.java
package com.example.demo;

import javax.servlet.http.HttpServletRequest;

import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;

public class RestMatcher implements RequestMatcher {

    //マッチャー
    private AntPathRequestMatcher matcher;

    //コンストラクタ
    public RestMatcher(String url) {
        super();
        matcher = new AntPathRequestMatcher(url);
    }

    //URLのマッチ条件
    @Override
    public boolean matches(HttpServletRequest request) {

        // GETならCSRFのチェックはしない
        if ("GET".equals(request.getMethod())){
            return false;
        }

        // 特定のURLに該当する場合、CSRFチェックしない
        if (matcher.matches(request)){
            return false;
        }

        return true;
    }
}

```


```SecurityConfig.java
package com.example.demo;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;

@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    // データソース
    @Autowired
    private DataSource dataSource;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    // ユーザーIDとパスワードを取得するSQL文
    private static final String USER_SQL = "SELECT"
            + "    user_id,"
            + "    password,"
            + "    true"
            + " FROM"
            + "    m_user"
            + " WHERE"
            + "    user_id = ?";

    // ユーザーのロールを取得するSQL文
    private static final String ROLE_SQL = "SELECT"
            + "    user_id,"
            + "    role"
            + " FROM"
            + "    m_user"
            + " WHERE"
            + "    user_id = ?";

    @Override
    public void configure(WebSecurity web) throws Exception {

        //静的リソースへのアクセスには、セキュリティを適用しない
        web.ignoring().antMatchers("/webjars/∗∗", "/css/∗∗");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        // ログイン不要ページの設定
        http
            .authorizeRequests()
                .antMatchers("/webjars/**").permitAll() //webjarsへアクセス許可
                .antMatchers("/css/**").permitAll() //cssへアクセス許可
                .antMatchers("/login").permitAll() //ログインページは直リンクOK
                .antMatchers("/signup").permitAll() //ユーザー登録画面は直リンクOK
                .antMatchers("/rest/**").permitAll() //RESTは直リンクOK
                .antMatchers("/admin").hasAuthority("ROLE_ADMIN") //アドミンユーザーに許可
                .anyRequest().authenticated(); //それ以外は直リンク禁止

        //ログイン処理
        http
            .formLogin()
                .loginProcessingUrl("/login") //ログイン処理のパス
                .loginPage("/login") //ログインページの指定
                .failureUrl("/login") //ログイン失敗時の遷移先
                .usernameParameter("userId") //ログインページのユーザーID
                .passwordParameter("password") //ログインページのパスワード
                .defaultSuccessUrl("/home", true); //ログイン成功後の遷移先

        //ログアウト処理
        http
                .logout()
                .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) //
                .logoutUrl("/logout") //ログアウトのURL
                .logoutSuccessUrl("/login"); //ログアウト成功後のURL

        //CSRFを無効にするURLを設定
        RequestMatcher csrfMatcher = new RestMatcher("/rest/**");

        //RESTのみCSRF対策を無効に設定
        http.csrf().requireCsrfProtectionMatcher(csrfMatcher);
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        // ログイン処理時のユーザー情報を、DBから取得する
        auth.jdbcAuthentication()
                .dataSource(dataSource)
                .usersByUsernameQuery(USER_SQL)
                .authoritiesByUsernameQuery(ROLE_SQL)
                .passwordEncoder(passwordEncoder());
    }
}

```

#GETメソッドの実装
* 先ほどのインターフェース実装クラス、Controllerクラスを編集します
* RESTコントローラクラスでメソッドに@GetMappingアノテーションをつけるだけ
* @RestControllerアノテーションを付けたクラスの各メソッドの戻り値に、htmlファイル以外を指定できます

```RestServiceJdbcImpl.java
//中略
    //１件検索用メソッド
    @Override
    public User selectOne(String userId) {
        return dao.selectOne(userId);

    }

    //全件検索用メソッド
    @Override
    public List<User> selectMany() {
        return dao.selectMany();
    }

//中略

```

```UserRestController.java
package com.example.demo.login.controller;

import java.util.List;

import com.example.demo.login.domain.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.login.domain.service.RestService;

@RestController
public class UserRestController {

    @Autowired
    RestService service;

    /**
     * ユーザー全件取得
     */
    @GetMapping("/rest/get")
    public List<User> getUserMany() {

        // ユーザー全件取得
        return service.selectMany();
    }

    /**
     * ユーザー１件取得
     */
    @GetMapping("/rest/get/{id:.+}")
    public User getUserOne(@PathVariable("id") String userId) {

        // ユーザー１件取得
        return service.selectOne(userId);
    }
}
```

#起動してGETメソッド実行！
* ユーザ一覧を取得
* http://localhost:8080/rest/get


![全部GET.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282755/d9930a9a-cae6-298b-eeb9-04aca28f8cf7.png)

* ユーザIDを指定して取得
* http://localhost:8080/rest/get/yamada@xxx.co.jp
* →yamadaのデータのみ帰ってきました〜^^
![RestUserGet.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282755/0a552d07-0514-6670-c4f9-0e463d9041a2.png)