이번 포스팅에서는 JPA에 대해서 알아보도록 합시다.
제가 예전에 JDBC에서 Mybatis까지 사용했었는데 현재는 JPA를 자주 사용한다고 해서 공부를 해봤습니다.
1. JPA?
JPA란 말 그대로 (Java Persistence API) 자바 퍼시스턴스 API를 줄인 말입니다.
자바 플랫폼 중에 EE와 SE를 사용하는 응용 프로그램에서 관계형 DB 관리를 표현하는 자바 API를 말합니다.
이렇게 말하면 사실 무슨 소리인지 알기 어렵습니다.
그렇다면 퍼시스턴스라는 단어를 분석해서 볼까요?
1-1 퍼시스턴스(Persistence)
퍼시스턴스는 프레임 워크의 종류 중 하나인데
데이터의 저장, 조회, 변경, 삭제를 다루는 클레스 및 설정 파일들의 집합니다.
즉 예전에는 JDBC로 연결해서 DB에서 데이터를 가져오는 방식이였다면 현재는 그런 복잡한 과정을 최소화 할 수 있는
퍼시스턴스 프레임 워크를 이용하는 시대가 되었다고 이해하면 될 것입니다.
JDBC의 복잡성을 최소화 하였기 떄문에 개발속도는 당연하게도 빨라질 것입니다.
그렇다면 JPA라는 건 자바 DB 연동해주는 프레임워크 API 중 하나로 DB연결을 간편하게 해줄 수 있는 프레임 워크라고
요약할 수 있겠습니다.
2. 개발 코드
기존 MVC 로직과 동일하게 만들어봤습니다.
기존에 사용하던 JSP -> Controller -> Vo -> Svc -> Dao 과정과 유사합니다.
제가 JPA를 이용하는 코드는 제 미니 프로젝트 과정을 기반으로 진행해보겠습니다.
Pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
Controller
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import com.heejea.simple.entity.*;
import com.heejea.simple.repository.noticeboardRepository;
import com.heejea.simple.repository.projectRepository;
import com.heejea.simple.svc.profileEntityService;
import lombok.Builder;
import lombok.RequiredArgsConstructor;
@Controller
@RestController
public class mainController {
@Autowired
public profileEntityService profileEntitySvc;
@RequestMapping(value="/index", method=RequestMethod.GET)
public ModelAndView main(ModelAndView M) {
List<noticeboardEntity> result = profileEntitySvc.mainInit();
M.addObject("main", result);
M.setViewName("index");
return M;
}
}
컨트롤러에서는 Service로 데이터를 넘기는 작업만 진행하였습니다.
noticeboardEntity
package com.heejea.simple.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
// table connect
@Entity(name="noticeboard")
public class noticeboardEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int nid;
@Column(nullable = false, unique = true, length = 100)
private String category;
@Column(nullable = false, length = 500)
private String title;
@Column(nullable = false, length = 1000)
private String contents;
// @Builder
public noticeboardEntity(String category, String title, String contents) {
this.category = category;
this.title = title;
this.contents = contents;
}
}
저는 여기서 lombok을 이용했는데 lombok은 getter와 setter를 작성하지 않아도 자동으로 생성해줍니다.
pom.xml에 선언해서 사용하지만 pom.xml에서는 선언해도 안되는 경우가 있습니다.
선언해도 안되는 경우 위에서 다운받으시면 됩니다.
Service / ServiceImpl
/**
* Service
**/
package com.heejea.simple.svc;
import java.util.List;
import com.heejea.simple.entity.noticeboardEntity;
public interface profileEntityService {
public List<noticeboardEntity> mainInit();
}
/**
* ServiceImpl
**/
package com.heejea.simple.svc.impl;
import java.util.List;
import org.springframework.stereotype.Service;
import com.heejea.simple.entity.noticeboardEntity;
import com.heejea.simple.repository.noticeboardRepository;
import com.heejea.simple.repository.projectRepository;
import com.heejea.simple.svc.profileEntityService;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class profileEntityServiceImpl implements profileEntityService {
final private projectRepository pRepository;
final private noticeboardRepository nRepository;
@Override
public List<noticeboardEntity> mainInit() {
List<noticeboardEntity> result = nRepository.findAll();
return result;
}
}
서비스에서는 repository를 호출해서 사용하고 findAll을 이용해서 DB에 있는 모든 값을 가져올 예정입니다.
Repository
package com.heejea.simple.repository;
import com.heejea.simple.entity.noticeboardEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface noticeboardRepository extends JpaRepository<noticeboardEntity, Integer>{
}
Repository는 정말 간단하게 보이지만 JapRepository가 다양한 기능들을 포함하고 있습니다.
한번 내부를 볼까요?
JpaRepository
/*
* Copyright 2008-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.jpa.repository;
import java.util.List;
import javax.persistence.EntityManager;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.QueryByExampleExecutor;
/**
* JPA specific extension of {@link org.springframework.data.repository.Repository}.
*
* @author Oliver Gierke
* @author Christoph Strobl
* @author Mark Paluch
*/
@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#findAll()
*/
@Override
List<T> findAll();
/*
* (non-Javadoc)
* @see org.springframework.data.repository.PagingAndSortingRepository#findAll(org.springframework.data.domain.Sort)
*/
@Override
List<T> findAll(Sort sort);
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#findAll(java.lang.Iterable)
*/
@Override
List<T> findAllById(Iterable<ID> ids);
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#save(java.lang.Iterable)
*/
@Override
<S extends T> List<S> saveAll(Iterable<S> entities);
/**
* Flushes all pending changes to the database.
*/
void flush();
/**
* Saves an entity and flushes changes instantly.
*
* @param entity
* @return the saved entity
*/
<S extends T> S saveAndFlush(S entity);
/**
* Deletes the given entities in a batch which means it will create a single {@link Query}. Assume that we will clear
* the {@link javax.persistence.EntityManager} after the call.
*
* @param entities
*/
void deleteInBatch(Iterable<T> entities);
/**
* Deletes all entities in a batch call.
*/
void deleteAllInBatch();
/**
* Returns a reference to the entity with the given identifier. Depending on how the JPA persistence provider is
* implemented this is very likely to always return an instance and throw an
* {@link javax.persistence.EntityNotFoundException} on first access. Some of them will reject invalid identifiers
* immediately.
*
* @param id must not be {@literal null}.
* @return a reference to the entity with the given identifier.
* @see EntityManager#getReference(Class, Object) for details on when an exception is thrown.
*/
T getOne(ID id);
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.QueryByExampleExecutor#findAll(org.springframework.data.domain.Example)
*/
@Override
<S extends T> List<S> findAll(Example<S> example);
/*
* (non-Javadoc)
* @see org.springframework.data.repository.query.QueryByExampleExecutor#findAll(org.springframework.data.domain.Example, org.springframework.data.domain.Sort)
*/
@Override
<S extends T> List<S> findAll(Example<S> example, Sort sort);
}
내부 코드를 보면 대략 find에 대해서만 보이지만 계속 참조되는 곳들을 따라가다보면 Save부터 Delete까지
확인 가능합니다.
그만큼 JDBC보다 간편하다는 것을 알 수 있었습니다.
profile_tb
로직을 이용해서 프로필 메인 페이지에 DB에 있는 데이터를 불러왔습니다.
JSP랑 나머지 코드들은 계속 수정하면서 완성되면 올리는 것으로 진행하겠습니다.
우선 이번 포스팅에서 알 수 있던 것은 JPA가 JDBC보다 간편하다는 것을 알 수 있었습니다.
GitHub
위의 깃에서 코딩 할 시간 될때마다 수정할 예정입니다.
우선으로는 위에있는 내용을 올린 상태입니다.
오늘은 JPA에 대해서 알아봤습니다.
다음에는 Simple 프로젝트를 좀 더 세분화하여 진행하는 포스팅으로 찾아오겠습니다.
'Programing > Java & Spring' 카테고리의 다른 글
세무민의 코딩일기 : (JPA&Jquery) 포트폴리오 화면에 블로그 기능 추가하기 1탄 [포트폴리오 사이트 제작하기 3탄] (0) | 2022.02.07 |
---|---|
(Java&Spring) JPQL 활용하기[포토폴리오 싸이트 제작하기 2탄 - 세무민의 코딩일기] (0) | 2022.01.04 |
세무민의 코딩일기 : 개발자가 객체 설계시 염두해야 할 사항은? (0) | 2021.06.20 |
Spring MVC를 이용하여 웹 페이지 제작 vo4 : Bootstrap을 이용해서 디자인 및 FileIO [File 입출력, Json, JqGrid 등] (0) | 2021.01.20 |
Spring MVC를 이용하여 웹 페이지 제작 vo3 : Json File을 연결한 후 view(jsp)를 이용하여 확인해보자. (0) | 2021.01.12 |