Spring
-
Spring - 서비스 & 테스트2022.09.14
-
Spring - repository 테스트2022.09.14
-
Spring - 도메인 & 리포지토리 만들기2022.09.14
-
Spring - 응답방법2022.09.14
-
첫 Spring2022.09.14
Spring - 서비스 & 테스트
서비스에서는 핵심 비즈니스 로직들이 구현됩니다.
마찬가지로 service 의 위치에 class 를 만듭니다.
private final MemberRepository memberRepository;
멤버 리퍼지토리를 들고와 새로운 리퍼지토리를 생성합니다.
회원가입
public long join(Member member){
validateDuplicateMember(member); // 중복 회원 검증
memberRepository.save(member);
return member.getId();
}
중복 회원 검증을 하고, 리포지토리에 저장을 합니다.
회원가입을 하고 나서는 Id를 return 하게 됩니다.
private void validateDuplicateMember(Member member) {
memberRepository.findByName(member.getName())
.ifPresent(m -> {
throw new IllegalStateException("이미 존재하는 회원입니다.");
});
}
위에서 사용한 중복 회원 함수입니다. 리포지토리에서 동일한 이름이 있다면 ?
stateException 을 반환합니다.
public List<Member> findMembers(){
return memberRepository.findAll();
}
public Optional<Member> findOne(Long memberId){
return memberRepository.findById(memberId);
}
전체 조회와 개인 조회를 만들어 줍니다.
서비스 테스트
테스트를 쉽게 만드는 방법이 있습니다 .
cmd + shift + T 를 이용해 새 테스트를 만들어 주게 되면 자동으로 틀을 잡아줍니다.
하지만 이 서비스는 테스트를 할때마다 새로운 리포지토리에서 진행해야 합니다.
public MemberService(MemberRepository memberRepository){
this.memberRepository = memberRepository;
}
service에 새로운 함수를 추가합니다. 서비스만의 리포지토리를 새롭게 정의하겠다는 함수입니다.
MemberService memberService ;
MemoryMemberRepository memberRepository;
@BeforeEach
public void beforeEach(){
memberRepository = new MemoryMemberRepository();
memberService = new MemberService(memberRepository);
}
@BeforeEach 를 통해 함수 진행 전에 새로운 리포지토리로 초기화를 해줍니다.
회원가입
void 회원가입() {
//given
Member member = new Member();
member.setName("spring1");
// when
Long saveId = memberService.join(member);
// then
Member findMember = memberService.findOne(saveId).get();
Assertions.assertThat(findMember.getName()).isEqualTo(member.getName());
}
given when then
3단 문법을 이용해 테스트 케이스를 적으면 형식을 맞출 수 있습니다.
어떤 인스턴스를 사용하며, 어떤 행동을 하게되면, 어떤 결과를 보여주는지 순서로 진행됩니다.
@Test
public void 중복_회원_예외(){
// given
Member member1 = new Member();
member1.setName("spring1");
Member member2 = new Member();
member2.setName("spring1");
// when
memberService.join(member1);
// ()-> 이 행동을 할때 , 앞의 예외가 터져야 한다. => 터지면 통과
assertThrows(IllegalStateException.class, () -> memberService.join(member2)))
}
중복 확인을 하는 테스트입니다. 똑같은 이름으로 두명이 회원가입을 하려고 할때,
ExceptionError 가 뜨면 성공인 경우를 구현했습니다.
assertThrows ( 결과, 원인 )이 참인지 확인하는 것으로 , ()->행동 이 원인이 되고 stateException이 결과가 됩니다.
'Spring' 카테고리의 다른 글
Spring - repository 테스트 (0) | 2022.09.14 |
---|---|
Spring - 도메인 & 리포지토리 만들기 (0) | 2022.09.14 |
Spring - 응답방법 (0) | 2022.09.14 |
첫 Spring (0) | 2022.09.14 |
Spring - repository 테스트
리포지토리를 생성을 해봤으니 테스트를 해봐야 합니다.
테스트는 스프링에게 굉장히 중요한 작업이라고 합니다.
TDD 라고 테스트 주도 개발 이라는 말이 있을 정도로 테스트의 중요성이 큽니다.
테스트를 하기 위해서 똑같은 구조로 만드는 것이 좋습니다.
MemoryMemberRepositoryTest Class 를 만들고 리포지토리에서 만들었던 함수들을 하나씩 실행해 봅니다.
MemoryMemberRepository repository = new MemoryMemberRepository();
repository 라는 새로운 객체를 만들어줍니다.
@Test
public void save(){
Member member = new Member();
member.setName("myname");
repository.save(member);
Member result = repository.findById(member.getId()).get();
assertThat(result).isEqualTo(member);
}
@Test 를 이용해서 test를 실행할 수 있습니다.
Assertions.assertThat( A ).isEqualTo(B) 를 이용해 A가 B랑 같은지 확인할 수 있습니다.
틀리게 되면 오류가 납니다.
나머지 함수들도 확인해줍니다.
@Test
public void findByName(){
Member member1 = new Member();
member1.setName("spring1");
repository.save(member1);
Member member2 = new Member();
member2.setName("spring2");
repository.save(member2);
Member result = repository.findByName("spring1").get();
System.out.println(result);
assertThat(result).isEqualTo(member1);
}
@Test
public void findAll(){
Member member1 = new Member();
member1.setName("spring1");
repository.save(member1);
Member member2 = new Member();
member2.setName("spring2");
repository.save(member2);
List<Member> result = repository.findAll();
assertThat(result.size()).isEqualTo(2);
System.out.println(result);
}
Test를 한번에 실행하게 되면 순서가 정해져 있지 않기 때문에 오류가 날 것입니다.
그래서 모든 함수들을 순회할 때 마다 실행해주는 방법이 아래와 같습니다.
@AfterEach
public void afterEach(){
repository.clearStore();
}
@AfterEach 로 함수들을 실행시킬 때마다 초기화할 수 있습니다.
'Spring' 카테고리의 다른 글
Spring - 서비스 & 테스트 (0) | 2022.09.14 |
---|---|
Spring - 도메인 & 리포지토리 만들기 (0) | 2022.09.14 |
Spring - 응답방법 (0) | 2022.09.14 |
첫 Spring (0) | 2022.09.14 |
Spring - 도메인 & 리포지토리 만들기
웹 애플리케이션의 계층 구조를 알아야 프로젝트 구조가 잡힐 수 있습니다.
참조 : https://velog.io/@kureungkureung
웹 애플리케이션 계층 구조
- 컨트롤러 : 웹 MVC의 컨트롤러 역할
- 서비스 : 핵심 비즈니스 로직 구현
- 리포지토리 : 데이터베이스에 접근, 도메인 객체를 DB에 저장하고 관리
- 도메인 : 비즈니스 도메인 객체
클래스 의존관계
서비스 개발에 앞서 아래와 같이 도메인과 리포지토리를 만들어줍니다.
도메인 코드 작성
public class Member { // 모든 계층에서 사용하기 위한 POJO
private Long id;
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;
}
}
id 와 name을 갖는 객체를 만들어 줍니다.
또한 id와 name의 getter setter를 자동으로 생성해줍니다.
리포지토리 작성
public interface MemberRepository {
Member save(Member member);
Optional<Member> findById(Long id);
Optional<Member> findByName(String name);
List<Member> findAll();
}
MemberRepository 라는 인터페이스를 만들어줍니다.
사용할 함수들과 결과를 선언을 해줍니다.
Optional을 이용해서 감싸주게 되면 null이라도 오류없이 반환하게 됩니다.
interface를 만들었으니 함수들을 만들러 가겠습니다.
MemoryMemberRepository 를 만들어 줍니다.
public class MemoryMemberRepository implements MemberRepository{
private static Map<Long,Member> store = new HashMap<>();
private static long sequence = 0L;
@Override
public Member save(Member member) {
member.setId(++sequence);
store.put(member.getId(),member);
return member;
}
@Override
public Optional<Member> findById(Long id) {
return Optional.ofNullable(store.get(id));
}
@Override
public Optional<Member> findByName(String name) {
return store.values().stream()
.filter(member -> member.getName().equals(name))
.findAny();
}
@Override
public List<Member> findAll() {
return new ArrayList<>(store.values());
}
public void clearStore(){
store.clear();
}
}
db 가 없으니 store라는 hashmap을 이용해 진행하겠습니다.
sequence 는 id 값으로 0,1,2 .. 1씩 늘어나서 알아서 저장되게 됩니다.
'Spring' 카테고리의 다른 글
Spring - 서비스 & 테스트 (0) | 2022.09.14 |
---|---|
Spring - repository 테스트 (0) | 2022.09.14 |
Spring - 응답방법 (0) | 2022.09.14 |
첫 Spring (0) | 2022.09.14 |
Spring - 응답방법
스프링은 크게 세가지 방법으로 응답할 수 있습니다.
- 정적 컨텐츠
- MVC 와 템플릿 엔진
- API
정적컨텐츠
html 파일을 return 하는 것입니다.
resources / static / 에서 index.html 과 static.html 을 만들게 되면
8080/ 주소에서 index.html 이 보여지게 되고,
8080/static.html 의 주소는 static.html 이 보여지게 됩니다.
MVC 와 템플릿 엔진
여기부터 spring이 역할을 하게 됩니다.
Controller의 코드를 보겠습니다.
@GetMapping("hello")
public String hello(Model model){
model.addAttribute("data","hello!!!!");
return "hello";
}
8080/hello 라는 get 요청을 받으면 hello.html 을 return 합니다.
hello.html 에서 hello 라는 model의 "data" 에 참조가 가능하기 때문에 아래와 같이 사용이 가능합니다.
<p th:text="'안녕하세요.' + ${data} "/>
Params
Parameter를 받는 방법입니다.
@GetMapping("hello/mvc")
public String helloMvc(@RequestParam("name") String name,Model model){
model.addAttribute("name",name);
return "hello-tem";
}
8080/hello/mvc?name=이름 과 같은 형태로 요청이 가능합니다.
@RequestParams("name") 을 통해서 param을 읽을 수 있고 이 값은 name(String)으로 사용가능합니다.
model에 name에서 설정하면 name 을 View 에서 참조가 가능해지게 됩니다.
<p th:text="'안녕하세요.' + ${name} " />
String 반환
@GetMapping("hello/string")
@ResponseBody
public String helloString(@RequestParam("name") String name, Model model){
model.addAttribute("name",name);
return "반갑습니다....." + name;
}
@ResponseBody 를 사용하게 되면 http 요청의 본문(body) 가 그대로 전달됩니다.
return 으로 .html를 찾는 것이 아닌 return 뒤 내용이 response 되게 됩니다.
API
return으로 html 이 아닌 JSON으로 넘기는 방법으로 가장 많이 사용하는 방식입니다.
@GetMapping("hello/api")
@ResponseBody
public Hello helloApi(@RequestParam("name") String name){
Hello data = new Hello();
data.setName(name);
return data;
}
static class Hello{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
1. Hello 라는 Object 클래스를 만듭니다.
2. Hello 에서 Getter, Setter 를 만들고 name 을 관리할 수 있습니다.
3. Hello 클래스를 상속한 HelloApi를 만들면 , 그 안에서 Hello 클래스를 사용 가능합니다.
4. Hello 클래스를 상속하는 data에 new Hello() 를 이용해 새로운 Object 형식을 만듭니다.
5. setName 으로 { "name": name} 으로 설정해줍니다.
8080/hello/api?name=heyhey 로 요청을 하면 {name:heyhey} 를 응답하게 됩니다.
'Spring' 카테고리의 다른 글
Spring - 서비스 & 테스트 (0) | 2022.09.14 |
---|---|
Spring - repository 테스트 (0) | 2022.09.14 |
Spring - 도메인 & 리포지토리 만들기 (0) | 2022.09.14 |
첫 Spring (0) | 2022.09.14 |
첫 Spring
혹시 이 자료 api 데이터 어떻게 보내드리면 되나요 ?
"~ 프로젝트 열어보셔서 소스 파일안에 ~ 컨트롤러 안에 보시면 됩니다. 스프링 코드 보실 줄 알죠?"
프론트엔드라고 해서 현업에서 리액트만 쓰는게 아니었습니다.
장고를 공부를 했었지만 스프링을 많이 쓰는 현실이기 때문에 백 코드를 위해 스프링 공부의 필요성을 느끼고
스프링 공부를 해야겠다고 생각을 하게 되었습니다.
깊히는 들어가지 않고, 코드를 구성하는 법과 api 로 CRUD가 가능할 정도를 목표로 공부해 보겠습니다.
Spring
스프링은 간단히 백엔드에서 서버를 구성하기 위한 프레임워크 입니다.
스프링 부트
이전에는 세팅을 하나씩 했지만 현재는 스프링 부트를 이용해 시작을 합니다.
https://start.spring.io/ 으로 들어가서
gradle 프로젝트, 언어는 java , springboot는 계속 바뀌어서 안전한 것을 찾고, Name을 설정해줍니다.
마지막에 자바 버전을 주의해야합니다.
우측에 Dependencies 에 필요한 라이브러리를 추가합니다.
web을 만들것이기 때문에 Spring Web 과
Tymeleaf 라는 지정된 템플릿 양식과 데이터가 합쳐져 html 문서를 출력하는 소프트웨어를 추가했습니다.
이후 Generate 버튼으로 프로젝트를 시작할 수 있게 됩니다.
프로젝트 빌드하기
인텔리제이를 열어 구조를 열어보겠습니다.
gradlew를 이용해 gradle wrapper 파일을 생성합니다.
최상위 dir에서 ./gradlew 를 입력하여 warpper 파일을 생성합니다.
빌드 준비가 끝난건데, 그 후 ./gradlew build 로 빌드를 할 수 있습니다.
./gradlew build
./gradlew clean build 빌드한 이미지 삭제하기
java -jar prac-spring-0.0.1-SNAPSHOT.jar = 실행시키기
jar 위치 = build/libs
프로젝트 시작하기
src/ main/ java/ 프로젝트이름 / ~Applicataion (초록색 화살표) 통해 실행할 수 있습니다.
localhost:8080 에서 white 라벨 페이지가 뜨면 성공한 것입니다.
화면 페이지를 구성해보겠습니다.
resources 는 java 파일을 제외한 내용들입니다. spring도 포함됩니다.
static에서 index.html 이라는 정적 파일을 만들어 초기 페이지를 구성해보겠습니다.
<!DOCTYPE HTML>
<html>
<head>
<title>HELLO</title>
<meta http-equiv="Content-Type" content="text/html"; charset="UTF-8" />
</head>
<body>
HELLO
<a href="/hello">HELOOO</a>
</body>
</html>
원하는 결과대로 잘 나오는 것을 볼 수 있습니다.
/hello 페이지를 이동하면 다시 whitelabel 페이지가 나옵니다. 이 페이지도 만들어 보겠습니다.
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p th:text="'안녕하세요.' + ${data} "></p>
</body>
</html>
이번에는 thymeleaf 라는 템플릿 엔진을 이용해 데이터를 불러와보겠습니다.
src/ main / java/ prj / controller 안에 Java 클래스로 Controller 하나를 만들어 줍니다.
@Controller
public class HelloController {
@GetMapping("hello")
public String hello(Model model){
model.addAttribute("data","hello!!!!");
return "hello";
}
}
import 문장들을 빼면 이정도의 코드 입니다.
@Controller = 컨트롤러를 만들기 위한 코드입니다.
@GetMapping = get요청 입니다. localhost:8080/hello 에 대한 결과를 줄 수 있습니다.
hello 라는 모델을 Model에 상속해서 만들고, hello "data"에 "hello"라는 값을 부여합니다.
return "hello" 를 이용해 "hello.html" 를 응답 결과로 줍니다.
결과물
hello.html 의 <p th:text="'안녕하세요.' + ${data} "/> 에서 data 를 hello model에서 참조하여 사용할 수 있게 됩니다.
위의 패턴을 이해하기 위해서는 MVC 패턴에 대해서 알고 있어야 합니다.
MVC 패턴
Model-View-Controller의 약자로 애플리케이션을 세 가지 역할로 구분한 개발 방법론입니다.
1. 사용자가 Controller를 조작하면
2. Controller는 Model을 통해 데이터를 가져오고
3. 그 데이터를 View를 통해 시각적 표현을 제어하여 사용자에게 전달하게 됩니다.
Model
데이터를 가진 객체를 모델이라고 지칭합니다. 데이터는 내부의 상태에 대한 정보를 가질 수도 있고, 모델을 표현하는 이름 속성으로 가질 수 있습니다. 모델의 상태에 변화가 있을 때 컨트롤러와 뷰에 이를 통보합니다.
이와 같은 통보를 통해 뷰는 최신의 결과를 보여줄 수 있고, 컨트롤러는 모델의 변화에 따른 적용 가능한 명령을 추가, 제거, 수정할 수 있습니다.
View
클라이언트 측 기술은 HTML/CSS/Javascript들을 모아둔 컨테이너입니다.
사용자가 볼 결과물을 생성하기 위해 모델로부터 정보를 얻어옵니다.
Controller
사용자가 접근한 URL에 따라 사용자의 요청사항을 파악한 후에 그 요청에 맞는 데이터를 Model을 의뢰하고, 데이터를 View에 반영해서 사용자에게 알려줍니다.
'Spring' 카테고리의 다른 글
Spring - 서비스 & 테스트 (0) | 2022.09.14 |
---|---|
Spring - repository 테스트 (0) | 2022.09.14 |
Spring - 도메인 & 리포지토리 만들기 (0) | 2022.09.14 |
Spring - 응답방법 (0) | 2022.09.14 |