반응형

Java Persistence API (일명 JPA)는 객체와 관계 데이터베이스 간의 데이터를 관리, 유지 및 액세스하기위한 Java 사양입니다. 최대 절전 모드는 JPA 사양을 구현하는 ORM (Object Relational Mapping) 도구입니다.

이 예에서는 Hibernate를 퍼시스턴스 제공자로 사용하여 Spring을 JPA와 통합하는 방법을 학습합니다.

이 응용 프로그램에 사용되는 도구 및 기술은 다음과 같습니다.

 

  • Spring 4.3.7.RELEASE
  • Hibernate 5.2.9.Final
  • JPA 2.1
  • MySQL Connector 6.0.5
  • MySQL Server 5.7.12
  • Eclipse Neon.3
  • Maven 3.3.9
  • JavaSE 1.8

Spring, Hibernate 및 JPA를 사용하여 간단한 독립형 애플리케이션을 작성해 봅시다.

프로젝트 구조

다음 maven 프로젝트 구조를 검토하십시오.

배우기-  이클립스에서 maven 프로젝트를 만드는 방법 .

Jar dependencies

pom.xml파일을 편집 하고 다음과 같이 Spring, Hibernate 및 MySQL 종속성을 추가 하십시오 .

pom.xml

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
  http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
 
  <groupId>com.boraji.tutorial.hibernate</groupId>
  <artifactId>spring-hibernate-jpa-example</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>
 
  <name>spring-hibernate-jpa-tutorial</name>
  <url>http://maven.apache.org</url>
 
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
 
  <dependencies>
    <!-- Spring Context -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>4.3.7.RELEASE</version>
    </dependency>
    <!-- Spring ORM -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-orm</artifactId>
      <version>4.3.7.RELEASE</version>
    </dependency>
    <!-- Mysql Connector -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>6.0.5</version>
    </dependency>
    <!-- Hibernate 5.2.9 Final -->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-core</artifactId>
      <version>5.2.9.Final</version>
    </dependency>
    <!-- Apache Commons DBCP -->
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-dbcp2</artifactId>
      <version>2.1.1</version>
    </dependency>
  </dependencies>
 
  <build>
    <sourceDirectory>src/main/java</sourceDirectory>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.5.1</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>
cs

JPA Entity class

다음과 같이 패키지 @Entity아래  클래스를  작성하십시오 com.boraji.tutorial.spring.entity.

Person.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.boraji.tutorial.spring.entity;
 
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
 
@Entity
@Table(name = "PERSONS")
public class Person {
 
   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   private Long id;
 
   @Column(name = "FIRST_NAME")
   private String firstName;
 
   @Column(name = "LAST_NAME")
   private String lastName;
 
   @Column(name = "EMAIL")
   private String email;
 
   public Person() {}
   
   public Person(String firstName, String lastName, String email) {
      this.firstName = firstName;
      this.lastName = lastName;
      this.email = email;
   }
 
   // Getter and Setter methods
}
cs

Data Access Object (DAO) class

다음과 같이 패키지 @Repository 아래에 클래스를  작성하십시오  com.boraji.tutorial.spring.dao.

PersonDao.java

 

1
2
3
4
5
6
7
8
9
10
package com.boraji.tutorial.spring.dao;
 
import java.util.List;
 
import com.boraji.tutorial.spring.entity.Person;
 
public interface PersonDao {
   void add(Person person);
   List<Person> listPersons();
}
cs

PersonDaoImp.java

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.boraji.tutorial.spring.dao;
 
import java.util.List;
 
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
 
import org.springframework.stereotype.Repository;
 
import com.boraji.tutorial.spring.entity.Person;
 
/**
 * @author imssbora
 *
 */
@Repository
public class PersonDaoImp implements PersonDao {
 
   @PersistenceContext
   private EntityManager em;
 
   @Override
   public void add(Person person) {
      em.persist(person);
   }
 
   @Override
   public List<Person> listPersons() {
      CriteriaQuery<Person> criteriaQuery = em.getCriteriaBuilder().createQuery(Person.class);
      @SuppressWarnings("unused")
      Root<Person> root = criteriaQuery.from(Person.class);
      return em.createQuery(criteriaQuery).getResultList();
   }
 
}
cs

@PersistenceContext주석은 주입하는 데 사용됩니다 EntityManagerDOA 클래스로 객체를.

 

 

Service class

 다음과 같이 패키지 @Service 아래에 클래스를  작성하십시오  com.boraji.tutorial.spring.service.

PersonService.java

1
2
3
4
5
6
7
8
9
10
package com.boraji.tutorial.spring.service;
 
import java.util.List;
 
import com.boraji.tutorial.spring.entity.Person;
 
public interface PersonService {
    void add(Person person);
    List<Person> listPersons();
}
cs

PersonServiceImp.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.boraji.tutorial.spring.service;
 
import java.util.List;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
import com.boraji.tutorial.spring.dao.PersonDao;
import com.boraji.tutorial.spring.entity.Person;
 
/**
 * @author imssbora
 *
 */
@Service
public class PersonServiceImp implements PersonService {
 
   @Autowired
   private PersonDao userDao;
 
   @Transactional
   @Override
   public void add(Person person) {
      userDao.add(person);
   }
 
   @Transactional(readOnly = true)
   @Override
   public List<Person> listPersons() {
      return userDao.listPersons();
   }
 
}
cs

 

persistence.xml 파일

폴더 persistence.xml아래  파일을 src/main/java/META-INF작성하고 다음 코드를 작성하십시오.

persistence.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
             http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
  version="2.1">
 
  <persistence-unit name="LOCAL_PERSISTENCE">
    <description> Spring Hibernate JPA Configuration Example</description>
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
 
    <properties>
      <property name="javax.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver" />
      <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/BORAJI" />
      <property name="javax.persistence.jdbc.user" value="root" />
      <property name="javax.persistence.jdbc.password" value="admin" />
      <property name="hibernate.show_sql" value="true" />
      <property name="hibernate.hbm2ddl.auto" value="update" />
    </properties>
 
  </persistence-unit>
</persistence>
cs

이것은 persistence.xml를 구성하는 데 사용되는 EntityManager응용 프로그램 서버 또는 독립 실행 형 응용 프로그램 내에서. 데이터베이스 (연결 URL, 사용자 이름, 비밀번호 등) 및 ORM 관련 정보가 들어 있습니다.

Spring configuration

 패키지 @Configuration 아래에 클래스를  만듭니다  com.boraji.tutorial.spring.config.

@EnableTransactionManagement 트랜잭션 관리 기능을 사용하려면 주석으로이 구성 클래스에 주석을 답니다  .

AppConfig.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.boraji.tutorial.spring.config;
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScans;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
 
/**
 * @author imssbora
 *
 */
@Configuration
@EnableTransactionManagement
@ComponentScans(value = { @ComponentScan("com.boraji.tutorial.spring.dao"),
      @ComponentScan("com.boraji.tutorial.spring.service") })
public class AppConfig {
 
   @Bean
   public LocalEntityManagerFactoryBean geEntityManagerFactoryBean() {
      LocalEntityManagerFactoryBean factoryBean = new LocalEntityManagerFactoryBean();
      factoryBean.setPersistenceUnitName("LOCAL_PERSISTENCE");
      return factoryBean;
   }
 
   @Bean
   public JpaTransactionManager geJpaTransactionManager() {
      JpaTransactionManager transactionManager = new JpaTransactionManager();
      transactionManager.setEntityManagerFactory(geEntityManagerFactoryBean().getObject());
      return transactionManager;
   }
}
cs

Run application

위의 spring-hibernate-jpa 구성을 테스트 할 기본 클래스를 작성하십시오.

MainApp.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package com.boraji.tutorial.spring;
 
import java.util.List;
 
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
 
import com.boraji.tutorial.spring.config.AppConfig;
import com.boraji.tutorial.spring.entity.Person;
import com.boraji.tutorial.spring.service.PersonService;
 
/**
 * @author imssbora
 *
 */
public class MainApp {
   public static void main(String[] args) {
      AnnotationConfigApplicationContext context = 
            new AnnotationConfigApplicationContext(AppConfig.class);
 
      PersonService personService = context.getBean(PersonService.class);
 
      // Add Persons
      personService.add(new Person("Sunil""Bora""suni.bora@example.com"));
      personService.add(new Person("David""Miller""david.miller@example.com"));
      personService.add(new Person("Sameer""Singh""sameer.singh@example.com"));
      personService.add(new Person("Paul""Smith""paul.smith@example.com"));
 
      // Get Persons
      List<Person> persons = personService.listPersons();
      for (Person person : persons) {
         System.out.println("Id = "+person.getId());
         System.out.println("First Name = "+person.getFirstName());
         System.out.println("Last Name = "+person.getLastName());
         System.out.println("Email = "+person.getEmail());
         System.out.println();
      }
 
      context.close();
   }
}
cs

Output

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Hibernate: create table PERSONS (id bigint not null auto_increment, EMAIL varchar(255), FIRST_NAME varchar(255), LAST_NAME varchar(255), primary key (id)) engine=MyISAM
Hibernate: insert into PERSONS (EMAIL, FIRST_NAME, LAST_NAME) values (?, ?, ?)
Hibernate: insert into PERSONS (EMAIL, FIRST_NAME, LAST_NAME) values (?, ?, ?)
Hibernate: insert into PERSONS (EMAIL, FIRST_NAME, LAST_NAME) values (?, ?, ?)
Hibernate: insert into PERSONS (EMAIL, FIRST_NAME, LAST_NAME) values (?, ?, ?)
Hibernate: select person0_.id as id1_0_, person0_.EMAIL as EMAIL2_0_, person0_.FIRST_NAME as FIRST_NA3_0_, person0_.LAST_NAME as LAST_NAM4_0_ from PERSONS person0_
Id = 1
First Name = Sunil
Last Name = Bora
Email = suni.bora@example.com
 
Id = 2
First Name = David
Last Name = Miller
Email = david.miller@example.com
 
Id = 3
First Name = Sameer
Last Name = Singh
Email = sameer.singh@example.com
 
Id = 4
First Name = Paul
Last Name = Smith
Email = paul.smith@example.com
cs

 

Download Sources

spring-hibernate-jpa-example.zip18.19 KB

반응형

'JAVA/SPRING > SPRING' 카테고리의 다른 글

Spring Framework: annotation 정리  (0) 2017.12.04
Spring Web MVC, @Controller 어노테이션 정리  (0) 2017.12.04
반응형

https://penthegom.tistory.com/48

 

[Spring Boot]Spring MVC JSP 웹 튜토리얼(인텔리제이용 intelliJ) - 1

이 글에서는 스프링 부트 프레임 워크를 사용하여 스프링 MVC 웹 애플리케이션을 만들고 부트 스트랩하는 방법을 설명하겠다. JSP를 웹 애플리케이션의보기로 사용합니다. 이 응용 프로그램에 사용되는 도구 및 기..

penthegom.tistory.com

앞서 기본 Spring Boot MVC 를 만들어봤다. 이어서 이제 Mybatis와 PostgreSQL을 연결하는 방법을 설명하겠다.

이 응용 프로그램에 사용되는 도구 및 기술은 다음과 같다.

 

  • Spring Boot 2.1.x
  • Tomcat Embedded (Spring Boot 내장)
  • JavaSE 1.8
  • Maven
  • Mybatis
  • PostgreSQL 9.6.15
  • IntelliJ IDEA Ultimate 

 

프로젝트 구조(TREE)

1. DB설치 및 테이블 생성

Oracle, PostgreSQL, MySQL 등등 DB툴을 설치 해야한다. 여기서는 PostgreSQL을 사용하기로 한다.

이번 튜토리얼을 하기 위해 test라는 DB스키마를 생성한다.

 

1
2
3
4
5
6
7
8
CREATE TABLE test (
    id integer NOT NULL,
    name varchar NULL,
    CONSTRAINT test_pkey PRIMARY KEY (id)
);
 
INSERT INTO test (id, "name")
VALUES(1'펜다곰'),(2'홍길동');
cs

 

2. 각종 소스

 

- pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.8.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.penthegom.example</groupId>
    <artifactId>penthegomdemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>penthegomdemo</name>
    <description>Demo project for Spring Boot</description>
 
    <properties>
        <java.version>1.8</java.version>
    </properties>
 
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
 
        <!-- JSP -->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
 
</project>
 
cs

 

- application.yml(application.properties 를 application.yml로 변경후 적읍시다! 한글주석과 트리형태로 관리가 됩니다.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
spring:
  mvc:
    view:
      prefix: /WEB-INF/views/
      suffix: .jsp
    static-path-pattern: /resources/**
  #DB 설정
  datasource:
    url: jdbc:postgresql://127.0.0.1:5432/tutorial
    driver-class-name: org.postgresql.Driver
   username: penthegom
   password: penthegom
  #JSP 바로적용 설정
  devtools:
    livereload:
      enabled: true
#로그 레벨
logging:
  level:
    # 쿼리 보기
    com.penthegom.example.penthegomdemo: DEBUG
 
cs

 

 

- DatabaseConfig.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.penthegom.example.penthegomdemo.config;
 
import javax.sql.DataSource;
 
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.transaction.annotation.EnableTransactionManagement;
 
@Configuration
@MapperScan(basePackages="com.penthegom.example.penthegomdemo.mapper")
@EnableTransactionManagement
public class DatabaseConfig {
 
    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        sessionFactory.setMapperLocations(resolver.getResources("classpath:mapper/postgresql/*.xml"));
        return sessionFactory.getObject();
    }
    
    @Bean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) throws Exception {
      final SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(sqlSessionFactory);
      return sqlSessionTemplate;
    }
}
cs

 

- HelloController.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.penthegom.example.penthegomdemo.controller;
 
import com.penthegom.example.penthegomdemo.dto.Test;
import com.penthegom.example.penthegomdemo.service.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
 
import java.util.List;
 
@Controller
public class HelloController {
 
    @Autowired
    TestService testService;
 
    @RequestMapping("/")
    public String index() {
 
        return "index";
    }
 
    @RequestMapping("/query")
    public @ResponseBody
    List<Test> query() throws Exception{
        return testService.getAll();
    }
}
 
cs

 

- Test.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.penthegom.example.penthegomdemo.dto;
 
public class Test {
    private String id;
    private String name;
 
    public String getId() {
        return id;
    }
 
    public void setId(String id) {
        this.id = id;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
}
cs

 

- TestMapper.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.penthegom.example.penthegomdemo.mapper;
 
import java.util.List;
 
import com.penthegom.example.penthegomdemo.dto.Test;
import org.springframework.stereotype.Repository;
 
@Repository
public interface TestMapper {
 
    public List<Test> getAll() throws Exception;
    
}
 
cs

 

- TestService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.penthegom.example.penthegomdemo.service;
 
import java.util.List;
 
import com.penthegom.example.penthegomdemo.dto.Test;
import com.penthegom.example.penthegomdemo.mapper.TestMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
 
@Service
public class TestService {
 
    @Autowired
    TestMapper testMapper;
    
    public List<Test> getAll() throws Exception{
        return testMapper.getAll();
    }
}
 
cs

 

- test.xml

1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.penthegom.example.penthegomdemo.mapper.TestMapper">
    <select id="getAll" resultType="com.penthegom.example.penthegomdemo.dto.Test">
        SELECT * FROM test
    </select>
</mapper>
cs

 

3. 실행 결과

 

반응형
반응형

spring boot 1.x 버전대

- application.properties

server.jsp-servlet.init-parameters.development=true

 

spring boot 2.x 버전대

dependency 추가

1
2
3
4
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>
cs

application.properties 추가

JSP 바로적용 설정

devtools.livereload.enabled=true

반응형
반응형

이 글에서는 스프링 부트 프레임 워크를 사용하여 스프링 MVC 웹 애플리케이션을 만들고 부트 스트랩하는 방법을 설명하겠다. JSP를 웹 애플리케이션의보기로 사용합니다.

이 응용 프로그램에 사용되는 도구 및 기술은 다음과 같습니다.

 

 

  • Spring Boot 2.1.x
  • Tomcat Embedded (Spring Boot 내장)
  • JavaSE 1.8
  • Maven
  • IntelliJ IDEA Ultimate 

 

프로젝트 구조(TREE)

 

1. 프로젝트 추가

 

2. 실행해보기(오류 발생)

 

우측 상단에 빨간펜으로 칠한 실행버튼을 누르면 프로젝트를 받자마자 에러가 납니다.

properties 에 db관련정보가 없어서 에러가 납니다. 

방법은 db접속정보를 넣어주거나 일단 tutorial이니 어노테이션 하나로 처리합시다.

 

@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})

 

 

실행이 잘 성공한다면 아래와같이 나온다.

 

 

 

3. 각종 소스

 

- pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.8.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.penthegom.example</groupId>
    <artifactId>penthegomdemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>penthegomdemo</name>
    <description>Demo project for Spring Boot</description>
 
    <properties>
        <java.version>1.8</java.version>
    </properties>
 
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.0</version>
        </dependency>
 
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
 
        <!-- JSP -->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
 
</project>
 
cs

- application.yml(application.properties 를 application.yml로 변경후 적읍시다! 한글주석과 트리형태로 관리가 됩니다.)

1
2
3
4
5
6
spring:
  mvc:
    view:
      prefix: /WEB-INF/views/
      suffix: .jsp
    static-path-pattern: /resources/**
cs

- index.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>JSP - Hello World Tutorial - penthegom</title>
</head>
<body>
<%= "Hello World!" %>
Hi penthegom !!
</body>
</html>
cs

 

- test.html

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
resources test
</body>
</html>
cs

 

- HelloController.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.penthegom.example.penthegomdemo.controller;
 
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
 
@Controller
public class HelloController {
 
    @RequestMapping("/")
    public String index() {
        return "index";
    }
}
 
cs

 

4. 실행 결과 화면

 

################## 필자가 하면서 에러 났던 부분 혹은 참고사항 ##################

 

문제 -> No mapping for GET /WEB-INF/views 어쩌구 저쩌구... 와 함께 404에러

해결 -> pom.xml에 jsp읽을 수 있는 디펜던시 추가(위 pom.xml 47라인 참고)

 

문제 -> jsp나 html수정시 재기동 해야만 적용되는거 바로바로 적용되게 하려면?

해결 -> https://penthegom.tistory.com/50 글 참고

 

문제 -> 이클립스에서 maven 관련 꼬임현상(?)이 빈번하게 일어나 항상 project-clean, maven clean 등 인텔리제이에서도 무언가가 적용이 되지 않을때.. 예) 디펜던시 추가 후 라이브러리가 제대로 추가가 되지 않는다면?

 

해결 -> 빨간 새로고침 버튼 클릭(Reimport All Maven Projects)

 

반응형
반응형

1. JUnit이란?

JUnit은 단위 테스트 도구입니다. 외부 테스트 프로그램(케이스)을 작성하여 System.out으로 번거롭게 디버깅하지 않아도 됩니다. 프로그램 테스트 시 걸릴 시간도 관리할 수 있게 해주며 오픈 소스이며, 플러그인 형태로 Eclipse에 포함되어 있습니다. 하나의 jar 파일이 전부이며 사용법도 간단합니다. 어느 정도 개발이 진행되면 프로그램에 대한 단위 테스트는 반드시 수행해야 합니다. JUnit은 보이지 않고 숨겨진 단위 테스트를 끌어내어 정형화시켜 단위 테스트를 쉽게 해주는 테스트용 Framework 입니다. JDK 1.4에서 추가된 assertXXX를 사용하여 Test를 진행합니다. JUnit은 테스트 결과를 확인하는 것 이외 최적화된 코드를 유추해내는 기능도 제공합니다. 또한, 테스트 결과를 단순한 텍스트로 남기는 것이 아니라 Test클래스로 남깁니다. 그래서 개발자에게 테스트 방법 및 클래스의 History를 넘겨줄 수도 있습니다.



2. 특징

  • 단위 테스트 Framework 중 하나
  • 문자 혹은 GUI 기반으로 실행됨
  • 단정문으로 테스트 케이스의 수행 결과를 판별함(assertEquals(예상 값, 실제 값))
  • 어노테이션으로 간결하게 지원함
  • 결과는 성공(녹색), 실패(붉은색) 중 하나로 표시


3. Eclipse에 JUnit 설정하기

  • Java Project를 생성
  • Project 이름에서 오른쪽 마우스를 클릭하고 Properties를 선택
  • Java BuildPath를 선택
  • Libraries 탭을 선택하고, Add Library를 선택
  • < 그림 1 >

    JUnit을 선택하고, Next 버튼 선택

    < 그림 2 >

    버전을 선택하고, Finish 버튼 선택

    < 그림 3 >

    JUnit이 추가 된 사항을 확인 할 수 있습니다.

    < 그림 4 >

    그림 4까지 하셨으면 Eclipse에 JUnit이 설정되었습니다. 지금부터는 간단한 Calculator 클래스를 통해 Eclipse에서 어떻게 JUnit을 사용하는지 알아봅니다.


4. JUnit 사용하기

먼저 com.calculator 패키지를 만들고 Calculator 클래스를 만듭니다. 메소드는 int형 두 개의 파라미터를 받아 두 개의 합을 리턴 하는 간단한 sum 메소드 입니다. 소스는 다음과 같습니다.

package com.calculator;

public class Calculator {  
    public int sum(int num1, int num2){
        return num1 + num2;
    }
}

Calculator 클래스를 테스트하기 위한 테스트 클래스를 만들겠습니다. 먼저 com. Calculator.test 패키지를 만듭니다. 그리고 com. Calculator.test 패키지에서 마우스 오른쪽 버튼 -> New -> JUnit Test Case 선택

< 그림 5 >

아래 그림에서

①은 테스트 클래스 이름 입력 부분이고, 테스트 클래스 이름은 테스트할 클래스 이름에 Test를 추가해서 입력합니다.

②는 테스트 클래스가 테스트하게 될 클래스를 지정하는 부분입니다.

Next 버튼 선택,

< 그림 6 >

Calculator 클래스에서 테스트할 메소드를 선택하고 Finish 버튼을 선택,

< 그림 7 >

다음과 같은 테스트 코드가 생성됩니다.

package com.calculator.test;  
import static org.junit.Assert.*;  
import org.junit.Test;  
public class CalculatorTest {  
    @Test
    public void testSum() {
        fail("Not yet implemented");
    }
}

위 testSum 메소드를 보면 어노테이션으로 @Test가 선언된 것을 볼 수 있습니다. 이 의미는 testSum 메소드가 단위 테스트 메소드임을 지정한다는 것입니다. 그리고 이 testSum 메소드 안에서 Calculator 클래스의 Sum메소드를 테스트합니다.

testSum 메소드를 다음과 같이 수정하였습니다.

    @Test
    public void testSum() {
        Calculator calculator = new Calculator();
        assertEquals(30, calculator.sum(10, 20));
    }

위 소스를 보시면 Calculator 클래스 객체를 생성한 후 assertEquals 메소드를 사용하여 sum 메소드의 리턴 값이 제대로 반환되는지 확인합니다. 반환 값이 지정한 결과와 같으면 테스트는 성공입니다. 하지만 반환 값이 생각한 결과와 같지 않으면 실패입니다.

테스트 클래스를 실행하는 방법은 테스트 클래스에서 마우스 오른쪽 버튼 -> RunAs -> JUnit Test를 선택

< 그림 8 >

테스트 메소드가 아무런 문제 없이 성공되면 그림 9와 같습니다.

< 그림 9 >

테스트 메소드에 문제가 있어 실패하면 그림 10과 같습니다.

< 그림 10 >

지금까지 간단한 Calculator 클래스를 통해 JUnit에 대해 알아보았습니다. 예제 소스에서 assertEquals 메소드를 보셨을 겁니다. 이 메소드는 JUnit에서 가장 많이 사용되는 메소드입니다. 이외에도 유용한 메소드가 있으며 이러한 메소드를 단정문 이라고도 합니다. 단정문에 해당하는 메소드는 많이 있으며 대표적인 것에 대해 알아보겠습니다.

5. 대표적인 단정문

assertArrayEquals(a,b) : 배열 a와b가 일치함을 확인 
assertEquals(a,b) : 객체 a와b의 값이 같은지 확인 
assertSame(a,b) : 객체 a와b가 같은 객체임을 확인 
assertTrue(a) : a가 참인지 확인 
assertNotNull(a) : a객체가 null이 아님을 확인 
이외에도 다양한 단정문이 존재합니다. 자세한 내용은 아래 링크를 가시면 확인하실 수 있습니다.http://junit.sourceforge.net/javadoc/org/junit/Assert.html

6. 어노테이션 활용하기

Java 언어 자체가 좀 더 넓게 확장하고 다양하게 발전할 수 있도록 도와준 어노테이션을 JUnit에서 활용할 수 있습니다.

(1) 테스트 메소드 지정하기

@Test가 메소드 위에 선언되면 이 메소드는 테스트 대상 메소드임을 의미합니다.

    @Test
    public void testSum() { 

    }

(2) 테스트 메소드 수행시간 제한하기

@Test(timeout=5000)를 메소드 위에 선언합니다. 시간단위는 밀리 초 입니다. 이 테스트 메소드가 결과를 반환하는데 5,000밀리 초를 넘긴다면 이 테스트는 실패입니다.

    @Test(timeout=5000)
    public void testSum() { 

    }

(3) 테스트 메소드 Exception 지정하기

@Test(expected=RuntimeException.class)가 메소드 위에 선언되면 이 테스트 메소드는 RuntimeException이 발생해야 테스트가 성공, 그렇지 않으면 실패입니다.

    @Test(expected=RuntimeException.class)
    public void testSum() { 

    }

(4) 초기화 및 해제

@BeforeClass, @AfterClass가 메소드 위에 선언되면 해당 테스트 클래스에서 딱 한 번씩만 수행되도록 지정하는 어노테이션 입니다.

    @BeforeClass
    public static void setUpBeforeClass() throws Exception {

    }

    @AfterClass
    public static void tearDownAfterClass() throws Exception {

    }

@Before, @After가 메소드 위에 선언되면 해당 테스트 클래스 안에 메소드들이 테스트 되기 전과 후에 각각 실행되게 지정하는 어노테이션 입니다.

    @Before
    public void setUp() throws Exception {

    }

    @After
    public void tearDown() throws Exception {

    }

아래 그림과 같이 표현할 수 있습니다.

< 그림 11 >

@BeforeClass 어노테이션은 테스트 클래스 수행 시 단위 테스트 메소드 보다 먼저 딱 한 번 수행되어야 할 경우 지정합니다. 예를 들어 DB 연결 시 드라이버 로딩 부분을 @BeforeClass로 지정한 메소드에 작성합니다. 반대로 @AfterClass 어노테이션은 단위 테스트 함수들이 다 수행되고 맨 마지막에 수행되어야 할 경우 지정합니다. 예를 들어 DB 연결 후 마지막에 드라이버를 반납하는 부분을 @AfterClass로 지정한 메소드에 작성합니다.

@Before와@After는 @Test로 지정된 단위 테스트 메소드가 실행되기 전 한 번씩 수행하거나 실행되고 난 후 수행되어야 하는 부분을 작성합니다. 예를 들어 공통으로 객체를 생성하는 코드를 @Test로 지정된 단위 테스트 메소드 안에 있다면 그 부분을 @Before에 지정된 메소드에 작성합니다.

7. 마치며...

지금까지 단위 테스트 Framework인 JUnit에 대해 알아보았습니다. JUnit을 사용하여 테스트 클래스를 작성하는 데 있어 깊은 내용은 아니지만, Eclipse에서 설치 방법과 어떻게 사용하는지를 살펴 보았습니다. JUnit을 처음 접하시는 분들께 작은 도움이나마 되었으면 하는 바램입니다.

감사합니다.

참고 도서 및 사이트



반응형
반응형

 요즘 Spring Boot를 이용해서 Non-web application을 만드는 작업에 빠져서 Spring에 대해 많은 걸 배우고 공부하는 중이다. 그래서 이번에는 Spring Boot application을 위한 설정파일로 가장 간단하게 이용할 수 있는 방법인 application.properties를 이용하는 방법을 간단히 설명해 보려고 한다.


 Spring Boot를 이용할 때 대부분의 경우 설정 파일로 application.properties를 이용한다. application.properties는 기본적으로 Spring Boot가 읽어들이도록 되어있기 때문에 사실 파일만 만들어서 'src/main/resources' 폴더에 넣어주면 바로 설정파일로 이용이 가능하다. 이렇게 편한 방법이 있는데 따로 만들어서 사용할 이유가 없다.

 간단한 사용법을 보자.

# application.properties
name=Michael
import org.springframework.stereotype.*
import org.springframework.beans.factory.annotation.*

@Component
public class MyBean {

    @Value("${name}")
    private String name;

    // ...

}
 위의 MyBean 클래스의 name 멤버변수는 @Value 어노테이션을 지정한 것만으로 application.properties에 있는 name속성 값 "Michael"로 초기화가 된다. 

 만약에 application.properties 파일에 name 속성이 정의되어있지 않았을 때 default값을 지정하는 방법도 있다. 아래와 같이 @Value 어노테이션에서 속성 이름 옆에 콜론(:)을 찍고 직접 지정해 주면 된다.

    @Value("${name:Michael}")
    private String name;

    @Value("${age:20}")
    private int age;
 위 예에서 지정된 default 값들은 application.properties에 값이 정의되어있지 않으면 각 변수의 타입에 맞게 변환되어 대입된다. 

 사실 Spring Boot의 문서를 보면 property source를 설정하는 다양한 방법이 제공된다.

  1. Devtools global settings properties on your home directory (~/.spring-boot-devtools.properties when devtools is active).
  2. @TestPropertySource annotations on your tests.
  3. @SpringBootTest#properties annotation attribute on your tests.
  4. Command line arguments.
  5. Properties from SPRING_APPLICATION_JSON (inline JSON embedded in an environment variable or system property)
  6. ServletConfig init parameters.
  7. ServletContext init parameters.
  8. JNDI attributes from java:comp/env.
  9. Java System properties (System.getProperties()).
  10. OS environment variables.
  11. A RandomValuePropertySource that only has properties in random.*.
  12. Profile-specific application properties outside of your packaged jar (application-{profile}.properties and YAML variants)
  13. Profile-specific application properties packaged inside your jar (application-{profile}.properties and YAML variants)
  14. Application properties outside of your packaged jar (application.properties and YAML variants).
  15. Application properties packaged inside your jar (application.properties and YAML variants).
  16. @PropertySource annotations on your @Configuration classes.
  17. Default properties (specified using SpringApplication.setDefaultProperties).

 위의 목록은 더 높은 우선순위를 갖는 property source부터 차례대로 나열한 것이다. 여기서 소개하는 application.properties 파일을 'src/main/resources' 폴더에 넣는 방법은 위의 목록 중 15번에 나오는 방법으로 우선순위로 보면 상당히 아래쪽에 나온다. 즉 상당히 우선순위가 낮다는 말이다. 'src/main/resources' 폴더에 application.properties 파일을 넣어 놓는다는 것은 배포 시에 jar 파일에 함께 묶여서 배포가 된다는 것이고 따라서 배포 후에 설정 값을 변경하려는 의도로 사용하기에는 적합하지 않다. 그러한 용도로 사용하려면 14번에서 말하는 jar 외부의 application.properties를 사용하면 된다. 그냥 application.properties 파일을 따로 만들어서 jar를 실행하는 directory에 두면 된다. jar 안에 있는 application.properties 파일보다 우선순위가 높기 때문에 둘 다 있는 경우 jar 외부의 application.properties 파일의 값이 더 높은 우선순위를 갖는다.

 여기서 많은 사람들이 우선순위에 대해서 오해하는 점 하나를 짚고 가야겠다. 예를 들어 jar안에 같이 포함된 application.properties파일과 jar 외부의 application.properties 파일이 둘 다 존재할 때 외부의 application.properties 파일이 더 우선순위가 높기 때문에 내부의 application.properties 파일이 완전히 무시된다고 생각하기 쉽다. 하지만 그렇지 않다. 우선순위가 높은 property source의 값들은 더 낮은 property source의 값들을 덮어쓰는 것이지 낮은 우선순위의 property source를 읽어들이지 않는 다는 뜻이 아니다. 즉 둘 다 name 속성이 정의되어있다면 더 높은 우선순위의 property source에 선언된 name 속성 값이 사용된다. 하지만 age라는 속성이 더 낮은 우선순위의 property source에만 선언되어있다면 낮은 우선순위의 property에 선언되었지만 그 값이 사용된다. (더 높은 우선순위에 값이 정의되지 않았으므로)

 즉 위 목록의 모든 property source들을 아래쪽부터 윗쪽으로 차례대로 다 찾아서 읽어들이면서 이미 정의된 property들은 덮어 쓰는 개념이다. 목록을 보면 테스트 환경을 제외하고 command line argument가 가장 우선순위가 높으므로 임시로 특정 값을 override하고 싶다면 command line을 이용해서 property를 전달하면 무조건 전달된 값이 이용될 것이다.

 command line을 이용하는 방법은 아래와 같은 방법으로 전달하면 된다. ('server.port' 속성값 지정)

$ java -jar myapp.jar --server.port=9000

 위 목록에 나열된 방법은 많지만 흔히 사용하는 방법으로 이 정도만 알고 있으면 대부분의 경우 문제없이 개발을 진행할 수 있다. 개념적으로 잘 이해하고 있다면 다른 나머지 방법을 이용하는 것도 사실 시간문제일 뿐 크게 어려운 부분은 없을 것이다.



출처 : http://progtrend.blogspot.kr/2017/07/spring-boot-applicationproperties.html

반응형
반응형

https://mvnrepository.com/artifact/org.openpnp/opencv


OpenPnP OpenCV

OpenCV packaged with native libraries and loader for multiple platforms.


LicenseBSD
Used By5 artifacts


VersionRepositoryUsagesDate
3.2.x3.2.0-1Central4(Dec, 2016)
3.2.0-0Central0(Dec, 2016)
2.4.x2.4.13-0Central2(Aug, 2016)
2.4.11-2Central0(Nov, 2015)
2.4.11-1Central0(Oct, 2015)
2.4.9-8Central0(Oct, 2015)


<dependency>

<groupId>org.openpnp</groupId>

<artifactId>opencv</artifactId>

<version>3.2.0-1</version>

</dependency>



pom.xml에 디펜던시에 추가하면 된다.


필자는 spring-boot 사용하고 있고, 아래 config 클래스를 추가하였다.


@Configuration

public class LibLoadingConfig {

    static {

    nu.pattern.OpenCV.loadShared();

        System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME);

    }

}


*** 위 버전중 2.x 버전중에 몇가지가 nu.pattern.OpenCV.loadShared(); 가 먹히질 않음.. ***





반응형
반응형

예제에 앞서 REST 에 대한 정의는 Representational state transfer 이다. RESTFul을 이용하는 이유에 대해서는 굳이 설명을 하지 않아도 될 듯 하다. 간단히 내 생각을 이야기 하자면, 우선 cloud 가 아닌 단일 Web Application만 생각해 볼때 현재 개발 추세가 Back-end 의 중요성 보다는 Front-end 의 UI/UX 디자인의 비중이 좀더 커가고 있다. 예전에 그저 model을 던저 주고 JSP 에서 그 모델을 JSP 페이지 쪽에 던져 주어 content를 만드는 방법에서 이제는 Front-end 가 로딩 되어진 상태에서 asynchronous 방식으로 content를 서버쪽에서 받아와 보여주는 방식을 선호 하게 되었다. 이렇게 하여 우선 Front-end의 로딩 속도를 빨리 가져 갈수 있다. 머 사실 어찌 되었던 간에 Back-end 데이타 가져 오는 데 걸리는 시간은 같지만…. 그래도 페이지 전체가 먼저 보여 졌을 때랑, 그렇지 않고 back-end 데이타를 기다리는 동안 페이지르 볼 수 없는 것이랑은 느낌이 틀리니. 이런 이유로 RESTFul Web Service 의 비중도 커졌고 이에 대한 개발도 좀더 구체화 되었다.

먼저 내가 사용한 개발 환경은:

  • Spring Boot 1.4.3.RELEASE (Spring Framework 4.3.5.RELEASE 가 사용 되어 진다.)
  • Java 1.7 version으로 세팅 (1.8로 해도 무난)
  • Postman – RESTFul 개발시 test 를 위해 사용 되어 지는 GUI 이다. Mac OS, Windows, Chrome browser 용으로 설치 하면 된다.
  • Eclipse

자 그럼 시작에 앞서 아래 5가지의 HTTP request method type 들에 대해서 알아 보자.

  • GET – 데이타를 검색하여 해당 값을 받아 올때 사용한다. (CRUD 에서 Retrieve 할 때 사용)
  • POST – 새롭게 데이타를 생성 할 때 사용 한다. (CRUD 에서  Create 할 때 사용)
  • PUT – 데이타를 업데이트 할 때 사용 한다. (CRUD 에서  Update 할 때 사용)
  • PATCH – PUT 과 마찬가지로 데이타를 업데이트 할 때 사용하지만 PUT 과 달리 전체 Entity 데이타의 업데이트가 아닌 부분의 값을 업데이트 할 때 사용한다.
  • DELETE – 데이타를 삭제 할 때 사용한다. (CRUD 에서  Delete 할 떄 사용)

이렇게 HTTP request method type 에 대해 Front-end 개발자와 Back-end 개발자 사이에 확실한 이해를 하고 넘어 가야 한다. 물론 Back-end 개발자의 경우 Front-end 개발자가 사용 할 수 있도록 정확한 문서를 제공해야 한다.

먼저 아래와 같이 Eclipse 를 이용하여 sbrest 라고 하는 프로젝트를 만들고 pom.xml 을 설정하자.

그러면 이제 Customer Entity 를 이용한 CRUD 를 하는 간단한 RESTFul 을 만들어 보자. 우선 아래와 같이 Customer entity를 만든다.

Spring framework 4.0 이후 버전에서는 Entity class 에서 @Table annotation 을 사용 하지 않으면 기본적으로 class 이름과 같은 table 을 맵핑한다. 따라서 class 이름과 다른 table 이름을 사용 한다면 @Table(name = “tbl_customer”) 처럼 명시 하여 주어야 한다. 또 한 가지는 class의 property 들도 @Column annotation을 사용 하지 않는 다면 기본적으로 property 이름을 이용하여 table column 이름과 맵핑을 하게 된다. 위에서는 firstname과 lastname이 이 경우에 해당한다.

다음으로 Spring Data JPA 를 이용하여 아래와 같이 간단하게 Repository 인터페이스와 Service 를 만들자.

 

 

여기 까지 간단하게 Customer entity 에 대한 CRUD 오퍼레이션을 하는 Repository와 Service 를 만들어 보았다. 이제 RESTFul 을 만들어 보자. 개인적으로 @RestController 들을 따로 package를 만들어 관리를 하는 것을 선호 한다. 따라서 아래와 같이 rest package를  만들어 그곳에 Rest Controller 들을 정의 한다.

위와 같이 RestCustomerConstroller.java 를 만들고 @RestController annotation을 설정 하여 Rest Controller를 만들었다. 먼저 GET/POST/PUT/PATCH/DELETE 를 이용한 Rest 코드 부터 하나 하나 알아 보겠다.

 

GET – To retrieve data

GET 을 이용 하는 경우는 Data를 검색할 때 사용 한다.

위에서 보면 전체 customer list를 가져오거나 @PathVariable을 이용하여 customer ID 를 보내 특정 customer 를 검색하여 데이타를 받는 경우이다. method = RequestMethod.GET 을 @RequestMapping 에 정의 하면 된다. 리턴은 ReponseEntity<T> 클래스를 이용하여 검색이 되지 않았을 경우에는 HttpStatus.NOT_FOUND 를 넘겨 주고, 검색이 되었을 경우에는 검색한 결과 object을 HttpStatus.OK 와 함께 넘겨 준다. 이때 Spring 에서는 자동으로 jackson-databind 를 이용하여 JSON 포맷으 데이타를 넘겨 준다.

 

POST – To create data

POST 를 이용 하는 경우는 Data를 새롭게 만들 때 사용 한다.

POST 는 새로운 Data를 생성 할 때 사용 하는 방법으로 method = RequestMethod.POST 로 설정을 해 준다. argument 들로 Customer 객체를 @RequestBody 를 이용하여 받아 왔다. Front-end 쪽에서 JSON 포맷으로 Customer 데이타를 보내 주면 된다. 이 떄 Front-end 개발자는 POST 이기 때문에 새로운 객체를 생성해야 하는 것으로 알고 데이타를 보내 주어야 한다. 두번 째 argument 로 UriComponentBuilder 를 설정 했다. 이유는 Customer를 생성하고 HttpHeaders 객체의 location 정보를 넣어 주기 위함이다. 이렇게 해 주면 Front-end 쪽 개발자는 새로운 데이타가 성공적으로 생성 (HttpStatus.CREATED) 되었을 경우 header 정보에서 location 값을 찾아 redirect 해 줄 수 있게 된다.

위에서 보면 만약 새롭게 생성하려고 하는 데이타가 이미 존재 하는 경우라면 HttpStatus.CONFLICT를 ResponseEntity<Void> 를 통해 리턴해 준다.

 

PUT –  To update data

PUT 을 이용 하는 경우는 존재 하는 Data를 업데이트 할 때 사용 한다.

 

PATCH – To update partial data

PATCH 는 부분적이 Data를 업데이트 할 때 사용 한다. 즉 Front-end 쪽에서 객체 전체 업데이트가 아닌 부분만 업데이트 할 때 업데이트 하는 부분만 RESTFul 에 보내 준다. PUT 과 PATCH 는 공통적으로 update 할 때 사용 하지만 PATCH 가 부분 데이타를 업데이트 한다는 점에서 PUT 과 차이가 있다.

위에서 method = RequestMethod.PATCH 를 설정해 주었고 업데이트 하려는 Customer의 ID와 Customer 객체를 받았다. 받은 Customer 객체의 경우 실제 업데이트 하려는 property 에만 값이 들어 있고 나머지는 null 이 들어 있게 된다. PATCH 가 성공적으로 되었으면 업데이트된 Customer 와 HttpStatus.OK 를 ResponseEntity<Customer> 에 넣어 보내 주고, 그렇지 않을 경우에는 HttpStatus.NOT_FOUND 를 넘겨준다. CustomerServiceImpl.java 의 patchCustomer 메소드를 참고 하기 바란다.

 

DELETE – To delete data

DELETE 를 이용 하는 경우는  Data를 삭제 할 때 사용 한다.

method = RequestMethod.DELETE 를 이용 하고 성공했을 경우 ResponseEntity<Void> 에 HttpStatus.OK 를 넣어 주고 그렇지 않을 경우 HttpStatus.NOT_FOUND 를 넣어 넘겨주었다.

 

지금 까지 RESTFul controller 를 개발 하는 방법을 설명 하였다. 아래는 최종 파일 이다.

이렇게 하여 간단하게 Spring Boot 을 이용한 REST web application을 만들어 보았다.

 

최종 프로젝트는 위와 같을 것이다. 자 그러면 이제 Postman 을 이용하여 위에서 만든 RESTFul web application을 테스트 해 보자. 아직 Postman을 설치 하지 않았다면 아래 사이트에 가서 각자의 환경에 맞게 다운 받아 설치를 하자.

Postman

 

TEST

자 그러면 먼저 Spring Boot application을 실행 하자.

그리고 이제 Postman을 실행 하자. 원하면 Sign up을 해서 자신이 test 한 것을 저장할 수 있다.

먼저 Data 가 아무 것도 없으니 CREATE method 를 이용하여 생성 해 보자.

위와 같이 POST 로 http://localhost:8080/customer 를 호출 하였다. 이때 Body 에는 javascript의 AJAX 를 이용하여 업데이트 한다는 가정으로 raw 와 JSON (application/json) 을 설정하고 JSON 데이타를 타입한 후에 Send 버튼을 눌러 호출 하면 된다. 이렇게 하면 아래 보는 것과 같이 Status: 201 Created 가 넘어 오는 것을 확인 할 수 있다. 다른 이름을 이용하여 하나 더 만들어 보자.

그 다음으로 위에서 생성한 데이타를 검색해 보자.

위에서는 http://localhost:8080/customer 를 GET 방식을 이용하여 Send 를 눌렀다. 그리고 나면 아래와 같이 Status: 200 OK 와 생성한 Customer 리스트를 볼 수 있다.

위에서는 http://localhost:8080/customer/2 를 GET 방식을 이용하여 Send 를 눌렀다. 그리고 나면 아래와 같이 Status: 200 OK 와 id 값이 2 인 Customer 검색 결과가 리턴 된다.

이번엔 PUT을 이용한 Update 이다.

보는 것과 같이 Front-end 쪽에서는 객체 전체 데이타를 update 하기 위해 보내 주었다. 위와 같이 PUT으로 설정해서 Send 를 누르면 업데이트 된 결과 값이 Status: 200 OK 와 함께 넘어 온다.

이제 PATCH 를 보자.

위에서 보면 front-end 에서는 lastname 만 넣어 PATCH 를 이용하여 request를 보냈다. 이렇게 하면 back-end 쪽에서는 부분 업데이트로 알고 lastname 만 업데이트 해 주었다. 리턴된 결과를 보면 Status: 200 OK 와 lastname 이 업데이트된 JSON 데이타 결과 같이 넘어 왔다.

마지막으로 아래 DELETE 를 해 보자.

DELETE 를 이용 http://localhost:8080/customer/2 를 호출 하여보면 ID 가 2 인 Customer 가 삭제 되고 Status: 200 OK 가 넘어 왔다.

 

이상 Spring Boot 을 이용한 RESTFul web service 를 만들어 보았다.

 

** DOWNLOAD this project

 

** Reference


반응형
반응형

깃 주소


https://github.com/shuhei/Rectify



반응형

'JAVA/SPRING > JAVA' 카테고리의 다른 글

[JUnit] 단위 테스트 도구 시작하기 1  (0) 2018.07.20
[펌]Java로 OTP 구현하기  (0) 2018.01.16
Maven으로 javadoc API 문서 만들기  (0) 2017.12.04
Eclipse 한글화  (0) 2017.12.01
[SFTP] jsch Pipe closed 익셉션 관련  (0) 2017.12.01
반응형

단 50줄이면 Java에서 OTP를 구현할 수 있습니다.


제가 OTP를 구현해야겠다고 생각한 계기는,
'클라이언트와 서버 간 REST 통신시, 해커로부터 데이터 변조 공격을 막기 위해서 일회용 비밀번호(OTP)를 사용하면 어떨까?' 라는 생각에서 출발했습니다.
(적용은 안했지만, 누군가에게 도움이 되길 바라며...)

OTP (One Time Password)
고정된 패스워드 대신 무작위로 생성되는 일회용 패스워드를 이용하는 사용자 인증 방식.


은행에서 OTP 단말기나, OTP 카드를 사용해보신 분이라면 한 번쯤 생각해보셨을 겁니다.

'서버랑 통신하는건가..?'

사실, OTP는 단말기와 서버가 통신하는게 아닙니다.

미리 정의된 비밀키와 시간 정보를 토대로 Hash 처리하여 비밀번호를 만들어냅니다.

핵심은 시간입니다. 시간은 변하므로, 일정 시간(정하기 나름) 마다 비밀번호가 바뀌죠.

그리고, 똑같은 알고리즘으로 단말기에서 비밀번호를 생성하고, 서버에서 검증합니다.

같은 시간대에 만들어졌으므로 단말기와 서버에서 만든 패스워드는 동일합니다.


그럼 이제 OTP를 만들고 검증하는 클래스를 생성하고, 아래와 같이 상수를 정의합니다.

 private static final long DISTANCE = 30000; // 30 sec
 private static final String ALGORITHM = "HmacSHA1";
 private static final byte[] SECRET_KEY = "define your secret key here".getBytes();


그리고 비밀키와 시간에 따라 Hash 처리하여 패스워드를 생성하는 메소드를 아래와 같이 정의합니다.

 private static long create(long time) throws Exception {
  byte[] data = new byte[8];
  
  long value = time;
  for (int i=8; i-- > 0; value >>>= 8) {
   data[i] = (byte) value;
  }
  
  Mac mac = Mac.getInstance(ALGORITHM);
  mac.init(new SecretKeySpec(SECRET_KEY, ALGORITHM));
  
  byte[] hash = mac.doFinal(data);
  int offset = hash[20-1] & 0xF;
  
  long truncatedHash = 0;
  for (int i=0; i<4; ++i) {
   truncatedHash <<= 8;
   truncatedHash |= hash[offset+i] & 0xFF;
  }
  
  truncatedHash &= 0x7FFFFFFF;
  truncatedHash %= 1000000;
  
  return truncatedHash;
 }


마지막으로, OTP 클래스를 외부에서 사용할 수 있도록 public으로 create(), vertify() 메소드를 아래와 같이 정의합니다.

 public static String create() throws Exception {
  return String.format("%06d", create(new Date().getTime() / DISTANCE));
 }
 
 public static boolean vertify(String code) throws Exception {
  return create().equals(code);
 }

 

테스트 코드는 다음과 같습니다.

  String code = OTP.create();
  
  System.out.println("Created OTP : " + code);
  
  System.out.println("Vertify OTP : " + OTP.vertify(code));


30초(DISTANCE)마다 비밀번호가 변경되는 것을 확인할 수 있습니다.

 

참조 글

http://terms.naver.com/entry.nhn?docId=1380773&cid=40942&categoryId=32854

http://zero-gravity.tistory.com/m/post/221

http://www.javacodegeeks.com/2011/12/google-authenticator-using-it-with-your.html/comment-page-1/#comment-14663



출처: http://silentsoft.tistory.com/9

반응형

+ Recent posts