Spring Boot 9 設定ファイル

設定ファイル読み込み

フォルダ構成

Test
└src
 └main
  └java
   └myPack
    └Test.java
  └resources
   └confing
    └application.properties
    └application-aaa.properties
    └application-bbb.properties
   application.properties (ここでも可)
 pom.xml

設定ファイル

※application.properties
spring.profiles.include=aaa
spring.profiles.include=bbb
test1=test
※application-aaa.properties
test2=aaa
※application-bbb.properties
test3=bbb

読み込み

※Test.java
package myPack;
public class Test implements CommandLineRunner {

 @Value("${test1}")
 private String prm1;

 @Value("${test2}")
 private String prm2;

 @Value("${test3}")
 private String prm3;

 @Value("${test4}")
 private String prm4;

 →エラー(test4という設定項目は無い)

 @Value("${test4:#{null}}")
 private String prm4;
 →OK:(test4という設定項目は無い時はnullが設定される)

 public static void main(String[] args) {
  SpringApplication.run(PostTestApplication.class, args);
 }

 @Override
 public void run(String… arg0) throws Exception {

  System.out.println(prm1);
  prm1:test
  System.out.println(prm2);
  prm2:aaa
  System.out.println(prm3);
  prm3:bbb
 }
}

設定ファイルの配置場所をjar(war)の外に出す

自動で読み込まれるアプリケーション配下、config配下の設定ファイルの他に任意の場所をクラスパスに追加する
Apache Maven 設定方法」参照
なお、この場合アプリケーション配下、config配下の設定ファイルは削除する事

環境毎に設定を変える

フォルダ構成

Test
└src
 └main
  └java
   └myPack
    └Test.java
  └resources
   └confing
    └A
     └application.properties
     └application-aaa.properties
    └B
     └application.properties
     └application-aaa.properties
 pom.xml

※pom.xml
<profiles>
 <profile>
  <id>A</id>
  <activation>
   <activeByDefault>true</activeByDefault>
  </activation>
  <build>
   <resources>
    <resource>
     <directory>src/main/resources/config/A</directory>
    </resource>
   </resources>
  </build>
 </profile>
 <profile>
  <id>B</id>
  <activation>
   <activeByDefault>false</activeByDefault>
  </activation>
  <build>
   <resources>
    <resource>
     <directory>src/main/resources/config/B</directory>
    </resource>
   </resources>
  </build>
 </profile>
</profiles>

設定ファイル

※A/application.properties
spring.profiles.include=aaa
test1=a
※B/application.properties
spring.profiles.include=aaa
test1=b

プロファイルを指定してビルド

> mvn package -P A
> mvn package -P B

Spring Boot 8 テスト

設定

pom.xml
<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-test</artifactId>
 <scope>test</scope>
</dependency>

テスト対象

Bean

※MyBean.java
public class MyBean {
 public String getTest1(){
  return "TEST1";
 }
 public String getTest2(){
  return "TEST2";
 }
}

※MyAppConfig.java
@Configuration
public class MyAppConfig {
 @Bean
 public MyBean getMyBean(){
  return new MyBean();
 }
}

コントローラ

※HelloController.java
@Controller
public class HelloController {
 @Autowired
 MyBean bean;

 @RequestMapping(value = "/")
 public ModelAndView index(ModelAndView model){
  model.setViewName("index");
  model.addObject("test", bean.getTest1() + bean.getTest2());
  return model;
 }
}

RESTコントローラ

※HelloRestController
@RestController
public class HelloRestController {
 @Autowired
 MyBean bean;

 @RequestMapping(value = "/rest/")
 public String index(ModelAndView model){
  return bean.getTest1() + bean.getTest2();
 }
}

テストコード

Bean

※MyBeanTest.java
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class MyBeanTest {
 @Autowired
 MyBean bean;

 @Test
 public void testGet(){
  assertEquals("test", bean.test());
 }
}

コントローラ

※ControllerTest.java
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class ControllerTest {
 @Autowired
 private MockMvc mock;

 @Autowired
 MyBean bean;

 @Test
 public void indexOK() throws Exception{
  mock.perform(get("/"))
   .andExpect(status().isOk())
   .andExpect(view().name("index"))
   .andExpect(model().hasNoErrors());
 }
}

RESTコントローラ

※ControllerTest.java
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class ControllerTest {
 @Autowired
 private MockMvc mock;

 @Autowired
 MyBean bean;

 @Test
 public void restOK() throws Exception{
  mock.perform(get("/rest/"))
   .andExpect(status().isOk());
 }
}

実行

Eclipse
自動テストツール JUnit」参照

Maven
Apache Maven 使用方法/テスト実行」参照

Spring Boot 7 DI処理

DI処理

ソースコードにクラス名を直接記述せずにインスタンス化を行うプログラミング方法
Spring DIコンテナ」参照

@Service

※MyService.java
@Service
public class MyService {
 public String getTest(){
  return "TEST";
 }
}

※MyRestContoller.java
@RestController
public class MyRestContoller {
 @Autowired
 private MyService service;
 MyServiceを探して自動インスタンス化

 @RequestMapping(value = "/getTest")
 public String getAll() {
  return service.getTest();
 }
}

@Component

※ComponentTestApplication.java
@SpringBootApplication
public class ComponentTestApplication {
 public static void main(String[] args) {
  SpringApplication.run(ComponentTestApplication.class, "TEST");
 }
}

※MyComponent.java
@Component
public class MyComponent {
 private List<String> list;

 public List<String> getList() {
  return this.list;
 }

 @Autowired
 public MyComponent (ApplicationArguments args) {
  this.list = args.getNonOptionArgs();
  this.list:TEST
 }
}

※MyRestContoller.java
@RestController
public class MyRestContoller {
 @Autowired
 private MyComponent component;
 MyComponentを探して自動インスタンス化
 @Autowiredが付加されたコンストラクタを実行

 @RequestMapping(value = "/rest")
 public String restAll() {
  return component.getList().get(0);
 }
}

@Configuration+@Bean

※MyBean.java
public class MyBean {
 public String getTest1(){
  return "TEST1";
 }
 public String getTest2(){
  return "TEST2";
 }
}

※MyAppConfig.java
@Configuration
public class MyAppConfig {
 @Bean
 public MyBean getMyBean(){
  return new MyBean();
 }
}

※MyRestContoller.java
@RestController
public class MyRestContoller {
 @Autowired
 private MyBean bean;
 MyBeanを探して自動インスタンス化
 @RequestMapping(value = "/getTest")
 public String restAll() {
  return bean.getTest1() + bean.getTest2();
 }
}

@Repository

Spring Boot 6 データベース操作」参照

Spring DIコンテナ

DIコンテナとは

DI

Dependency Injection
依存性注入
依存性を外部ファイルに記述し、ソースコードの変更を少なくする事

依存性

※Car1.java
class Car1{
 ~
}
※Car2.java
class Car1{
 ~
}
※Main.java
Car1 car1 = new Car1();

Car2 car2 = new Car2();
MainクラスはCar1、Car2に依存している
※Car1→Car2へ変更する場合、ソースコードを変更する必要がある

依存性の解決

設定ファイル方式
1) 呼び出し先クラスを記述した設定ファイルを読み込むのみ
設定ファイルの内容を変えるだけで呼び出し対象クラスを変更できる
アノテーション方式
2) アノテーションを付加した呼び出し先クラスを自動読み込み
呼び出し先クラスのアノテーションを変更するだけで呼び出し対象クラスを変更できる
3) インスタンス化はフレームワーク(Spring、Spring-Boot等)が自動実行
呼び出し元ではクラス名を書かないで済む。変更に強い

設定ファイル実装例

Bean定義ファイル

※applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans
 xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="
  http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
 <bean id="carImpl" class="com.office.yone.CarImpl1"></bean>
 <bean id="person" class="com.office.yone.Person">
  <property name="car" ref="carImpl" />
 </bean>
 ↓
 呼び出すクラスをCarImpl1→CarImpl2に変える場合
 設定ファイルのクラス名を変更する
 <bean id="carImpl" class="com.office.yone.CarImpl2"></bean>
 <bean id="person" class="com.office.yone.Person">
  <property name="car" ref="carImpl" />
 </bean>
</beans>

実行されるクラス

※Car.java
public interface Car {
 String Drive();
}

※CarImpl1.java
public class CarImpl1 implements Car {
 @Override
 public String Drive() {
  return "車種1でドライブ";
 }
}

※CarImpl2.java
public class CarImpl2 implements Car {
 @Override
 public String Drive() {
  return "車種2でドライブ";
 }
}

DIコンテナ

※Person.java
public class Person {
 private Car car;
 public void setCar(Car car){
  this.car = car;
 }
 public String getPlan(){
  return car.Drive();
 }
}

実行クラス

※DiTest.java
public class DiTest {
 public static void main(String[] args) {
  ApplicationContext context =
   new ClassPathXmlApplicationContext("applicationContext.xml");
  Person person = (Person) context.getBean("person");
  System.out.println(person.getPlan());
  Bean定義ファイル:class=CarImpl1の場合
  →車種1でドライブ
  Bean定義ファイル:class=CarImpl2の場合
  →車種2でドライブ
  ※Car1→Car2へ変更する場合、ソースコードを変更する必要がない
 }
}

アノテーション実装例

Spring Boot 7 DI処理」参照

Spring Boot 6 データベース操作

JPAとは

Java Persistence API
永続化ライブラリ
マッピングされたデータベースオブジェクトを操作可能

共通

pom.xml

※pom.xml

<project ~>
 ~<br/>
 <dependencies>
  ~
  
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-jpa</artifactId>
  </dependency>
  
  オープンソースDB
  <dependency>
   <groupId>org.hsqldb</groupId>
   <artifactId>hsqldb</artifactId>
   <scope>runtime</scope>
  </dependency>
  
 </dependencies>
</project>

エンティティクラス

※MyData.java

@Entity
@Table(name="myTable")
public class MyData {
 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 @Column
 private long id;

 @Column(length = 50, nullable = false)
 private String name;

 public long getId() {
  return id;
 }
 public void setId(long id) {
  this.id = id;
 }

 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
}

テンプレート

※index.html

<!DOCTYPE html>
<html xmsns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<title>DBTest</title>
</head>
<body>
 <form method="post" action="/" th:object="${formModel}">
  <input type="text" name="name" th:value="*{name}" /><br/>
  <input type="submit" name="登録" />
 </form>
 <table>
  <tr><td>ID</td><td>名前</td></tr>
  <tr th:each="obj : ${datalist}">
   <td th:text="${obj.id}"></td>
   <td th:text="${obj.name}"></td>
  </tr>
 </table>
</body>
</html>

リポジトリ方式

流れ

リポジトリクラス

JpaRepositoryクラス
 saveAndFlush();
 findAll();

※MyRepository.java

@Repository
public interface MyRepository extends JpaRepository<MyData, Long> {
 独自検索機能の(自動)実装
 MyRepositoryインターフェースを実装したクラスでのメソッド記述は不要
 Idという名前からエンティティクラスのカラムをfindする処理を自動生成する

 public MyRepository findById(Long id)
}

コントローラー

※HelloController.java
@Controller
public class HelloController {
 @Autowired
 MyRepository repository;

 @RequestMapping(value = "/", method = RequestMethod.GET)
 public ModelAndView index(ModelAndView model){

  リポジトリの検索メソッドを利用
  Iterable<MyData> list = this.repository.findAll();

  model.setViewName("index");
  model.addObject("datalist", list);
  return model;
 }

 @RequestMapping(value = "/", method = RequestMethod.POST)
 @Transactional(readOnly=false)
 public ModelAndView form(
   MyDataのインスタンスを自動作成。POST元のth:objectで指定

   @ModelAttribute("formModel") MyData mydata,
   ModelAndView model){

  mydata.name = "C#";
  repository.saveAndFlush(mydata);

  return new ModelAndView("redirect:/");
 }
 
 @RequestMapping(value = "/", method = RequestMethod.POST)
 @Transactional(readOnly=false)
 public ModelAndView form(
  エンティティを用いない場合
  String name
  ModelAndView model){

  return new ModelAndView("redirect:/");
 }
}

EntityManager

DAOインターフェイス

※MyDataDao.java
public interface MyDataDao<T> extends Serializable {
 public List<T> getAll();
}

DAOクラス

※MyDataDaoImpl.java
public class MyDataDaoImpl implements MyDataDao<MyData> {
 private EntityManager entityManager;

 public MyDataDaoImpl() {
  super();
 }

 public MyDataDaoImpl(EntityManager manager) {
  this.entityManager = manager;
 }

 @Override
 public List<MyData> getAll() {
  Query query = this.entityManager.createQuery("from MyData");
  List<MyData> list = query.getResultList();
  this.entityManager.close();
  return list;
 }
}

コントローラー

※HelloController.java
@Controller
public class HelloController {
 EntityManagerの自動インスタンス化
 @PersistenceContext
 EntityManager entityManager;

 MyDataDaoImpl dao;

 コンテナの初期化時に自動実行
 @PostConstruct
 public void init(){
  this.dao = new MyDataDaoImpl(this.entityManager);
 }

 @RequestMapping(value = "/", method = RequestMethod.GET)
 public ModelAndView index(ModelAndView model){

  DAOの検索メソッドを利用
  Iterable<MyData> list = this.dao.getAll();

  model.setViewName("index");
  model.addObject("datalist", list);
  return model;
 }

 @RequestMapping(value = "/", method = RequestMethod.POST)
 @Transactional(readOnly=false)
 public ModelAndView form(
   MyDataのインスタンスを自動作成。POST元のth:objectで指定

   @ModelAttribute("formModel") MyData mydata,
   ModelAndView model){

  mydata.name = "C#";
  repository.saveAndFlush(mydata);

  return new ModelAndView("redirect:/");
 }
}

サービス層

リポジトリクラス

※MyRepository.java
@Repository
public interface MyRepository extends JpaRepository<MyData, Long> {}

サービスコンポーネント

※MyDataService.java
@Service
public class MyDataService {
 @PersistenceContext
 private EntityManager entityManager;
 public List<MyData> getAll(){
  return (List<MyData>)this.entityManager
   .createQuery("from MyData").getResultList();
 }
}

コントローラー

※HelloController.java
@Controller
public class HelloController {
 @Autowired
 private MyRepository repository;

 @Autowired
 private MyDataService service;

 @PostConstruct
 public void init(){
  MyData data1 = new MyData(); data1.setName("Java");
  this.repository.save(data1);

  MyData data2 = new MyData(); data2.setName("C#");
  this.repository.save(data2);

  MyData data3 = new MyData(); data3.setName("PHP");
  this.repository.save(data3);
 }

 @RequestMapping(value = "/", method = RequestMethod.GET)
 public ModelAndView index(
   @ModelAttribute("formModel") MyData mydata,
   ModelAndView model){

  Iterable<MyData> list = service.getAll();

  model.setViewName("index");
  model.addObject("datalist", list);

  return model;
 }
}