일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- java 1509
- kotiln const
- 전략 패턴이란
- ipfs bean
- kotiln const val
- spring mongodb switch
- go
- java 파티
- 자바 백준 팩토리얼 개수
- javav 1676
- rabbitmq 싱글톤
- mongodb lookup
- 백준 1504 java
- 백준 2252 줄세우기
- 익명 객체 @transactional
- ipfs singletone
- spring mongoTemplate
- nodejs rabbitmq
- Spring ipfs
- java 팩토리얼 개수
- spring mongodb
- 백준 연결요소 자바
- 안정해시
- java 백준 1509
- java 1238
- spring mongoTemplate switch
- kotiln functional interface
- 자바 1676
- Java Call By Refernce
- 백준 특정한 최단 경로
- Today
- Total
공부 흔적남기기
Spring으로 간단한 게시판 만들기 본문
Spring으로 게시판을 만드는 과정을 빠르게 한번 살펴보면서 내가 접했던 오류들? -> 실수들을 남겨두기 위해 적음
API 설계
이번 게시글을 만들면서 크게 사용한 기술들은 Java Spring MVC, JPA, Ajax, Thymleaf, H2(로컬에서만 사용하고 외부에 올릴때는 Mysql)로올림
프로젝트의 구조는 Controller에서 요청을 받고 Service에서 Repository를 이용하여 데이터를 처리한후 Controller에 return 해주면 Controller가 그 값을 리턴해주는 식으로 하였다. 리턴해줄 때 데이터를 리턴해주는 것과 template의 text/html을 return해주는 2경우로 나뉘니 잘 살펴보는 것이 좋을 것임. @Bean들의 의존관계는 @Autowired를 통해 자동으로 설정해두었음
전체 글 조회
먼저 전체 글을 조회 하는 부분 부터 살펴보도록 하겠음.
//Controller
@ResponseBody
@GetMapping("/posts")
public List<PostResponseDto> getPosts(){
return postService.getPosts();
}
//Service
public List<PostResponseDto> getPosts(){
List<Post> Posts = postRepository.findAllByOrderByModifiedAtDesc();
List<PostResponseDto> postResponseDtos = new ArrayList<>();
for (Post post : Posts) {
PostResponseDto postRequestDto = new PostResponseDto(post);
postResponseDtos.add(postRequestDto);
}
return postResponseDtos;
}
//ajax
function posts() {
$.ajax({
type: "GET",
url : "/posts",
success : function (response){
console.log(response);
for(let i =0; i<response.length; i++) {
let str = response[i].time;
$('.posts').append(`
<div>제목: ${response[i].title} 작성자:${response[i].name} 작성날짜:${str.substring(0,19)} <button onclick='post(${response[i].id})'>글 보러가기</button></div>
<hr>
`);
}
}
})
}
//html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="home.js"></script>
</head>
<body>
<h1>게시판 페이지</h1>
<button onclick=`${window.location.href='/posts/create'}`>글작성하러가기 </button>
<div class="posts"></div>
</body>
</html>
이 부분에서 중요하다고 생각되는 것은 DTO이다 DTO 즉 데이터가 들어가있는 객체를 보내게 되면 ajax에서 받을때 자동으로 JSON 형태가되어 아주 유용하다. DTO를 처음 듣는다면 꼭 공부해야 하는 개념이다!
글 등록
글을 조회하려면 글을 등록해야한다. 위 HTML에 button을 눌러 글을 작성하러 가본 후 작성해서 저장하는 부분까지의 코드를 보면
//Controller
//글 등록 페이지로 이동
@GetMapping("/posts/create")
public String createPostPage(){
return "createPost";
}
//글 등록
@ResponseBody
@PostMapping("/posts")
public Post createPost(@RequestBody PostRequestDto postRequestDto){
return postService.createPost(postRequestDto);
}
//Service
// 글작성
public Post createPost(PostRequestDto postRequestDto){
Post post = new Post(postRequestDto);
return postRepository.save(post);
}
//ajax
function createPost(){
$.ajax({
type : "POST",
url : "/posts",
data: JSON.stringify({name : $('#name').val(), title : $('#title').val(), contents : $('#contents').val()}),
contentType : "application/json",
success : function (response){
alert("저장성공");
window.location.href ="/";
}
})
}
/html
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<!-- > js파일이 적용이 안되서 여기다가 적음 <-->
<script>function createPost(){
$.ajax({
type : "POST",
url : "/posts",
data: JSON.stringify({name : $('#name').val(), title : $('#title').val(), contents : $('#contents').val()}),
contentType : "application/json",
success : function (response){
alert("저장성공");
window.location.href ="/";
}
})
}</script>
</head>
<body>
<h1>글 작성 페이지</h1>
<button onclick=`${window.location.href='/'}`>홈으로</button>
<br>
제목
<input type="text" id="title" name = "title">
<hr>
이름
<input type="text" id="name" name = "name">
<hr>
글 내용
<textarea name="contents" id="contents" cols="30" rows="10"></textarea>
<hr>
<button onclick="createPost()">제출</button>
</body>
</html>
여기서 중요한 부분은 ajax에 데이터를 보낼때 String 형태로 보내야 하기때문에 JSON.stringify를 적어야하고 서버에 이게 JSON형태의 데이터임을 알려주기위해 content-type에 json/application을 적어야 한다.
특정 글 조회
이제 글을 적었으니 그글의 내용을 조회해보는 기능을 하는 코드를 보면
//Controller
@GetMapping("/posts/{id}")
public String getPost(@PathVariable Long id, Model model){
PostResponseDto post = postService.getPost(id);
String time = post.getTime().toString();
model.addAttribute("id",post.getId());
model.addAttribute("title" , post.getTitle());
model.addAttribute("name", post.getName());
model.addAttribute("time", time.substring(0, 19));
model.addAttribute("contents", post.getContents());
return "post";
}
//Service
//글 id로 조회
public PostResponseDto getPost(Long id){
Post post = postRepository.findById(id).orElseThrow(
() -> new IllegalArgumentException("글이 존재하지 않아요!")
);
PostResponseDto postResponseDto = new PostResponseDto(post);
return postResponseDto;
}
//html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>특정 게시글 조회 페이지</h1>
<button onclick=`${window.location.href='/'}`>홈으로</button>
<button th:onclick="|javascript:delete2(${id})|">삭제하기</button>
<button th:onclick="|javascript:update(${id})|">수정하기</button>
<div th:text="|제목: ${title} 작성자 :${name} 날짜:${time}|"></div>
<div th:text="|내용: ${contents}|"></div>
</body>
</html>
알아가는 부분은 원래 ajax를 통해 값을 받아오면서 print를 시켜봤는데 데이터가 계속해서 2번씩 나오길래 하나씩 확인해보았더니 window.location.href =`/posts/${id}`; 이부분으로 들어가면 ajax를 사용할 필요없이 그냥 GET방식으로 들어가진다는 것을 알게 되었다. 그리고 model에 넣을때 멍청이처럼 하나씩 넣었는데 그냥 객체를 넣고 js에서 객체.속성 이렇게 해도 상관없다.밑에서 수정할때에는 그렇게 했으니 확인해보도록 하자
그리고 타임리프의 문법을 몰라 onclick에서 헤맸는데 역시 구글에 치니 안나오는 것이 없는 것 같다.
글 수정
글도 작성했겠다 글을 수정해보도록하자 수정을 하기위해선 원래의 값과함께 수정페이지로 이동한 후 데이터들을 수정하고나서 디비에 값 변화를 저장해야한다.
//Controller
@GetMapping("/posts/update/{id}")
public String updatePostpage(@PathVariable Long id, Model model){
PostResponseDto post = postService.getPost(id);
model.addAttribute("info", post);
return "updatePage";
}
@ResponseBody
@PutMapping("/posts/{id}")
public Post update(@PathVariable Long id,@RequestBody PostRequestDto postRequestDto){
return postService.updatePost(id, postRequestDto);
}
//Service
@Transactional
public Post updatePost(Long id, PostRequestDto postRequestDto) {
Post post = postRepository.findById(id).orElseThrow(
() -> new IllegalArgumentException("글이 존재하지 않아요!")
);
post.update(postRequestDto);
return post;
}
//ajax
function update(id){
$.ajax({
type: "GET",
url: `/posts/update/${id}`,
success : function (response){
window.location.href=`/posts/update/${id}`;
}
})
}
function updatePost(id){
$.ajax({
type : "PUT",
url : `/posts/${id}`,
data: JSON.stringify({name : $('#name').val(), title : $('#title').val(), contents : $('#contents').val()}),
contentType : "application/json",
success : function (response){
alert("수정성공");
window.location.href ="/";
}
})
}
//html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<!-- > js파일이 적용이 안되서 여기다가 적음 <-->
<script>function updatePost(id){
$.ajax({
type : "PUT",
url : `/posts/${id}`,
data: JSON.stringify({name : $('#name').val(), title : $('#title').val(), contents : $('#contents').val()}),
contentType : "application/json",
success : function (response){
alert("수정성공");
window.location.href ="/";
}
})
}</script>
</head>
<body>
<h1>글 수정 페이지</h1>
<button onclick=`${window.location.href='/'}`>홈으로</button>
<br>
제목
<input type="text" id="title" name = "title" th:value="${info.title}">
<hr>
이름
<input type="text" id="name" name = "name" th:value="${info.name}">
<hr>
글 내용
<textarea name="contents" id="contents" cols="30" rows="10" th:text="${info.name}"></textarea>
<hr>
<button th:onclick="|javascript:updatePost(${info.id})|">제출</button>
</body>
</html>
이번에는 Model에 객체를 담아 보낸뒤 html에서 타임리프를 이용하여 객체.속성을 이용하여 표현했다. textarea에서는 input박스와 달리 th:text를 사용해야했다. @Transactional을 이용하면 객체를 새로만들어서 값을 바꿔줘도 db에서 알아서 바뀌는 것 같다.
글 삭제
이제 마지막으로 간단한 삭제를 봐보자~
//Controller
@ResponseBody
@DeleteMapping("/posts/{id}")
public Long deletePost(@PathVariable Long id){
postService.delete(id);
return id;
}
//Service
public void delete(Long id) {
postRepository.deleteById(id);
}
//ajax
function delete2(id) {
$.ajax({
type: "DELETE",
url: `/posts/${id}`,
success: function (response) {
alert("삭제완료");
window.location.href = "/";
}
})
}
전체적인 리뷰
먼저 타임리프를 이용해서 데이터를 보낼때 ajxa에서 window.location.href를 통해 url를 바꿔주었는데 이렇게 하는게 맞는건지 잘 모르겠다. Controller에서는 template에서 html을 복사해와서 response로 보내줘야하는데 이렇게 하는게 맞겠지? Controller에서 html을 보내면서 경로를 바꾸는 법이 있는지 확인해봤는데 잘 못찾았었다.
시간을 제일 많이 날린 곳을 생각해보면 타임리프 문법과 url을 제대로 맞추지 않아서 4XX오류가 계속났었고 ajax에서 url을 적을때 백틱을 사용하지 않아서 시간을 많이 날린 것 같다. 그리고 이번에는 mysql를 RDS를 통해 연결해놓았기 때문에 코드에 노출되서는 안되는 정보가 있어서 처음으로 gitignore을 사용해보는 경험도 해보았다. 이번 게시판 만들기를 통해 Response와 Request를 좀 더 자세히 안 것 같고 RequsetDTO와 Response DTO 사용, 다음에는 DAO도 사용해봐야겠다. @PathVariable, @RequestBody,@ModelAttribute,@RequestParam에 대해 다시한번 공부해보는 시간이 되었던 것 같다.
@RestController를 사용하지 않고 @Controller과 @ResponseBody를 사용하면서 둘의 차이를 좀 더 명확히 알게 된 것 같다.
'web study > Spring' 카테고리의 다른 글
jsp 간단한 사용방법 (ONLY JSP) (0) | 2022.01.26 |
---|---|
Severlet 간단한 사용방법 (0) | 2022.01.26 |
Spring MVC 예제를 통한 이해 (0) | 2022.01.22 |
Spring Dto와 서버와 클라이언트가 통신할 때의 값의 Type (0) | 2022.01.22 |
Spring JPA를 이용한 간단한 CRUD를 하면서 실수한 부분들 (0) | 2022.01.21 |