5
6

More than 5 years have passed since last update.

[自分用]Spring BootでRESTful Web Service立てたやり方まとめ

Last updated at Posted at 2016-08-25

目的

サーバ側でいろいろ処理してクライアントでは結果だけ出したかった。

はじめに

http://spring.io/guides/gs/rest-service/
の公式ガイドに簡単な流れがあるのでまずはこれを実行してみると良い。

SPRING INITIALIZER

https://start.spring.io
でGradleとかMavenのプロジェクトを生成してくれる。
本まとめではGradleを使う

DependenciesでWebとかMongoDBとか必要なのを入れておくと楽

実行

適当にIntelliJかなんかで開いて、既にあるhogehogeApplication.javaのmainを実行すればデバッグ的には楽か?

生成されたプロジェクトのそのままだと実行してもすぐ終了してしまうので、Greeting.javaGreetingController.javaをぶち込めば http://localhost:8080/greeting でHello Worldできるはず。

https

証明書作る

プロジェクトのルートで

keytool -genkey -alias tomcat -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 3650

適当に情報を入れてオレオレ証明書を作る。

httpsを有効にする

src/main/resources/application.properties

server.ssl.key-store: keystore.p12
server.ssl.key-store-password: 証明書のパスワード

を追記するだけ。
そしたら https://localhost:8443

MongoDB

設定

HostとかPortとかを設定しないとけないので、AbstractMongoConfigurationを継承したクラスを作る。

例えばこういう感じで作成する。

SpringMongoConfig.java
@Configuration
@EnableMongoRepositories("jp.ac.ritsumei.cs.ubi")
public class SpringMongoConfig extends AbstractMongoConfiguration {
    @Value("${spring.data.mongodb.host}")
    private String mongoHost;

    @Value("${spring.data.mongodb.port}")
    private String mongoPort;

    @Value("${spring.data.mongodb.database}")
    private String mongoDB;

    @Override
    public MongoMappingContext mongoMappingContext()
            throws ClassNotFoundException {
        // TODO Auto-generated method stub
        return super.mongoMappingContext();
    }

    @Override
    @Bean
    public Mongo mongo() throws Exception {
        System.out.println("mongo host: " + mongoHost);
        System.out.println("mongo db: " + mongoDB);

        MongoCredential credential = MongoCredential.createMongoCRCredential("ユーザ名", mongoDB, "パス".toCharArray());
        ServerAddress serverAddress = new ServerAddress(mongoHost, Integer.parseInt(mongoPort));

        return new MongoClient(serverAddress, new ArrayList<MongoCredential>() {{
            add(credential);
        }});
    }

    @Override
    protected String getDatabaseName() {
        // TODO Auto-generated method stub
        return mongoDB;
    }
}

hostやportはapplication.propertiesに追記する

spring.data.mongodb.host: localhost
spring.data.mongodb.port: 27017
spring.data.mongodb.database: hogehoge

モデル

MongoDBから取ってきた結果をぶち込むクラスを適当に作る。

@Documentをつけることで、どのコレクションを対象とするか指定する
変数名とフィールド名が違うなら@Fieldで指定する

HogeNode.java
@Document(collection = "HogeNode")
public class HogeNode {
    @Field("_id")
    private String objectId;
    //省略

Repository

findとかするクラスを作る。

HogeRepository.java
public interface HogeRepository extends MongoRepository<Hoge, String> {
    public HogeNode findByフィールド名(String id);
}

findByとかすると、By以降のフィールド名で引数の値をfindしてくれる。
Likeを加えたり、AndやOrを足したり、countByにするとそのようにMongoDBを叩いてくれる。

呼ぶ

@Autowired
    private HogeRepository repository;

@Autowiredを付けると勝手にバインド?してくれるので、適当な場所でインスタンス作る。

    HogeNode hogeNode = repository.findById(id);

さっき作ったfindByで呼ぶと結果が得られる。
結果がなかったらnull

Aggregate

Aggregateしたい場合には、

ProductRepositoryCustom.java
interface ProductRepositoryCustom {
    List<HogeNode> aggregate(int sort);
}

このようなinterfaceを作って、

ProductRepositoryImpl.java
@Repository
class ProductRepositoryImpl implements ProductRepositoryCustom {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Override
    public List<HogeNode> aggregate(int sort) {
            Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.sort(sort == 1 ? Sort.Direction.DESC : Sort.Direction.ASC, "nodeId"),
        );
        AggregationResults<HogeNode> results = mongoTemplate.aggregate(aggregation, "CollectionName", HogeNode.class);
        return results.getMappedResults();
    }

implementsしたクラスでMongoTemplete@AutowiredしてAggregationを作る。

呼ぶ

@Autowired
    private ProductRepositoryCustom repositoryCustom;

でインスタンスが得られるので、コントローラあたりから呼ぶ

group

Aggregation.group("param1")
    .first("param1").as("param1")
    .avg("param2").as("param2")

groupした後の結果はHogeNode.classのメンバを全部網羅しておかないとダメっぽい?

複数のDB

先述したSpringMongoConfig.java

@Bean(autowire = Autowire.BY_NAME, name = "hogeTemplate")
public MongoTemplate ritsubiMongoTemplate() throws Exception {
    return new MongoTemplate(mongo(), "hogeDB");
}

任意のMongoTemplateの名前を指定して、任意のDB名を引数としてMongoTemplateを返すメソッドを実装する。
MongoTemplate@Autowireしてるところで指定したインスタンス名にすると、そのDBに繋がったMongoTemplateとなる。

ただし、こうすると先述したHogeRepository.javaSpringMongoConfig.java

@Override
protected String getDatabaseName() {
    return mongoDB;
}

に依存してしまう?

エラーぺージ

Config.java
@Configuration
public class Config {
    @Bean
    public ErrorAttributes errorAttributes() {
        return new DefaultErrorAttributes() {
            @Override
            public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {
                Map<String, Object> errorAttributes = new HashMap<>();
                errorAttributes.put("timestamp", new Date());
                errorAttributes.put("status", 400);
                errorAttributes.put("error", "Bad Request");
                errorAttributes.put("message", "Bad Request");

                return errorAttributes;
            }
        };
    }
}

@Configurationをつけたクラスに@Beanを付けてErrorAttributesを実装。
putしてるvalueは必須。

認証

簡単化のため、インメモリでユーザ認証するので以下を実装

WebSecurityConfig.java
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("name").password("pass").authorities("ADMIN");
    }
}

こんな https://user:pass@localhost:8443/hogehoge 感じに書くだけで認証されてアクセスできる。

ただ、ブラウザからアクセスすると/loginにリダイレクトされる。
(ブラウザが勝手にやってるだけ?)

レスポンスのJSON

レスポンスのJSONはインデントが綺麗になってないので読み辛いが、

@Configuration
public class CustomWebMvcConfiguration extends WebMvcConfigurationSupport {

    @Override
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        for (HttpMessageConverter<?> converter : converters) {
            if (converter instanceof MappingJackson2HttpMessageConverter) {
                MappingJackson2HttpMessageConverter jacksonConverter = (MappingJackson2HttpMessageConverter) converter;
                jacksonConverter.setPrettyPrint(true);
            }
        }
    }
}

を実装すると、prettyになる。

5
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
6