Spring_boot/Project

[Spring] REST 웹 서비스

달의요정루나 2022. 8. 13. 15:54

https://julian5383.tistory.com/94

 

[Spring] JPA로 블로그하고 데이터를 액세스 하기

https://julian5383.tistory.com/93 [Spring] MVC를 이용해 블로그 만들기 프로젝트를 생성합니다. Spring Boot DevTools, Lombok, Thymeleaf, Spring Web이 선택됩니다. Overview 옆에 있는 Dependencies로 들어..

julian5383.tistory.com

위 게시물 이후로 이어집니다.

2개의 RestController를 작성한다.

package com.aaa.blog.rest;

import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.aaa.blog.model.User;
import com.aaa.blog.service.UserService;

@RestController
@RequestMapping(value="/rest/user")
public class UserRestController {

	@Autowired
	private UserService userService;
	
	@GetMapping(value="/getAll")
	public ResponseEntity<List<User>> getAllPost(){
		List<User> users = this.userService.findAll();
		
		if (users == null || users.isEmpty()) {
			return new ResponseEntity<List<User>>(users, HttpStatus.OK);
		}
		
		return new ResponseEntity<List<User>>(users, HttpStatus.OK);
	}
	
	@PostMapping(value="/login")
	public ResponseEntity<Boolean> authenticate(@RequestBody Map<String, String> params, HttpSession session){
		Boolean blogin = userService.authenticate(params.get("username"), params.get("password"));
		if(!blogin) {
			return new ResponseEntity<Boolean>(blogin, HttpStatus.FORBIDDEN);
		}
		
		session.setAttribute("username", params.get("username"));
		return new ResponseEntity<Boolean>(blogin, HttpStatus.OK);
	}
}

UserRestController.java

package com.aaa.blog.rest;

import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Optional;

import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.aaa.blog.model.Post;
import com.aaa.blog.model.User;
import com.aaa.blog.service.PostService;
import com.aaa.blog.service.TagService;
import com.aaa.blog.service.UserService;

@RestController
@RequestMapping("/rest/post")
public class PostRestController {

	@Autowired
	private PostService postService;
	
	@Autowired
	private UserService userService;
	
	@Autowired
	private TagService tagService;
	
	@GetMapping("getAll")
	public ResponseEntity<List<Post>> getAllPost(){
		List<Post> posts = this.postService.findAllOrderedById();
		if (posts == null || posts.isEmpty()) {
			return new ResponseEntity<List<Post>>(HttpStatus.NOT_FOUND);
		}
		
		return new ResponseEntity<List<Post>>(posts, HttpStatus.OK);
	}
	
	@GetMapping("get/{id}")
	public ResponseEntity<Post> getPostById(@PathVariable("id")long id){
		Optional<Post> optionalPost = this.postService.findById(id);
		if(optionalPost.isPresent()) {
			return new ResponseEntity<Post>(optionalPost.get(), HttpStatus.OK);
		}
		
		return new ResponseEntity<Post>(HttpStatus.NOT_FOUND);
	}
	
	@PostMapping("create")
	public ResponseEntity<Post> create(@RequestBody Post post, HttpSession session){
		post.setId(postService.findAllOrderedById().stream().map(Post::getId).max(Comparator.naturalOrder()).orElse(Long.MIN_VALUE)+1);
		post.setUser(userService.findByUsername((String)session.getAttribute("username")).get());
		Post p = this.postService.create(post);
		
		if(p==null) {
			return new ResponseEntity<Post>(HttpStatus.INTERNAL_SERVER_ERROR);
		}
		
		return new ResponseEntity<Post>(p, HttpStatus.OK);
	}
	
	@PutMapping("put/{id}")
	public ResponseEntity<Post> update(@PathVariable("id") long id, @RequestBody Post post){
		Optional<Post> optionalPost = postService.findById(id);
		
		if(optionalPost.isPresent()) {
			Optional<User> optionalUser = userService.findById(optionalPost.get().getUser().getId());
			
			if(optionalUser.isPresent()) {
				Post updatePost = optionalPost.get();
				updatePost.setId(id);
				updatePost.setTitle(post.getTitle());
				updatePost.setBody(post.getBody());
				updatePost.setCreatedDate(new Date());
				updatePost.setUser(optionalUser.get());
				updatePost.setTags(tagService.getTags());
				
				Post p = postService.edit(post);
				
				if(p==null) {
					return new ResponseEntity<Post>(post, HttpStatus.INTERNAL_SERVER_ERROR);
				}	
				return new ResponseEntity<Post>(post, HttpStatus.OK);
			}
			return new ResponseEntity<Post>(post, HttpStatus.NOT_FOUND);
		}
		return new ResponseEntity<Post>(post, HttpStatus.NOT_FOUND);
	}
	
	@GetMapping("delete/{id}")
	public ResponseEntity<Void> delete(@PathVariable("id") long id){
		Optional<Post> optionalPost = postService.findById(id);
		
		if (optionalPost.isPresent()) {
			postService.deleteById(id);
		}
		return new ResponseEntity<Void>(HttpStatus.OK);
	}
}

PostRestController.java

 

User.java와 Post.java에 @Entity을 부여한 Model 클래스에서 관계형 데이터베이스에 매칭된 POJO객체를 Json 형태로 바인딩해 호출할 수 있도록 새로운 annotation을 추가한다.

package com.aaa.blog.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;

import org.hibernate.validator.constraints.Length;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name="BlogUser")
@JsonPropertyOrder({"id","username","email","fullname","role"})
// 전송될 Json 타입 data의 스키마를 지정
public class User {
	
	@Id
	@Column(name="USER_ID", nullable = false, unique = true)
	@JsonProperty("User_ID") //Json으로 바인딩될 멤버변수를 설정
	private Long id;
	
	@Column(unique = true, nullable = false)
	@Length(min=2, max=30, message="**아이디는 2자 이상 30자 이하입니다.")
	@NotEmpty(message="**계정명을 입력해주세요")
	private String username;
	
	@Column(nullable = false)
	@Length(min=5, message = "**암호를 5글자 이상으로 입력하세요")
	@NotEmpty(message="**암호를 입력하세요")
	@JsonIgnore //Json으로 바인딩될 때 해당 멤버변수를 제외
	private String password;
	
	@Column
	@Email(message = "**유효한 이메일 계정을 입력해주세요")
	@NotEmpty(message="**이메일 계정을 입력하세요")
	private String email;
	
	@Column
	@NotEmpty(message = "**이름을 입력하세요")
	private String fullname;
	
	@Column
	private UserRole role;
}

User.java

package com.aaa.blog.model;

import java.util.Collection;
import java.util.Date;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.validation.constraints.NotEmpty;

import org.hibernate.validator.constraints.Length;
import org.springframework.format.annotation.DateTimeFormat;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table
public class Post {

	@Id
	@Column(name="POST_ID")
	private Long id;
	
	@Column(nullable = false)
	@Length(min=5, max=30, message="**최소 5글자 이상 30글자 이하로 입력해주세요")
	@NotEmpty(message="**제목을 입력하세요")
	private String title;
	
	@Lob
	private String body;
	
	@Temporal(TemporalType.TIMESTAMP)
	@Column(nullable = false, updatable = false)
	@DateTimeFormat(pattern = "yyyy-MM-dd hh:mm:ss")
	private Date createdDate;
	
	@ManyToOne
	@JoinColumn(name="USER_ID", referencedColumnName = "USER_ID", nullable = false)
	private User user;
	
	@OneToMany(mappedBy = "post", cascade = CascadeType.REMOVE)
	@JsonIgnoreProperties("post")
    //Post 객체는 Tag객체를 포함하고 Tag객체 내에는 Post객체를 서로 포함하고 있어서
    //RESTful 웹서비스에서 함수를 호출할때 무한루프에 빠짐, 이를 방지하기 위해 설정
	private Collection<Tag> tags;
}

Post.java

 

Spring-Blog-Jpa 실행 후 웹 브라우저에 아래의 URL 입력하면 Json타입의 값을 반환한다.

http://localhost:8080/rest/user/getAll

http://localhost:8080/rest/post/get/3

 

혹은 http://localhost:8080/rest/post/delete/5로 Post를 삭제할 수 있습니다.

 

pom.xml으로 들어가서  jackson-dataformat-xml 의존체를 검색해 추가하고 저장한다.

 

UserRestController와 PostRestController에 몇 줄을 더 추가한다.

package com.aaa.blog.rest;

import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.aaa.blog.model.User;
import com.aaa.blog.service.UserService;

@RestController
@RequestMapping(value="/rest/user")
public class UserRestController {

	@Autowired
	private UserService userService;
	
    //@GetMapping(value="/getAll")
	@GetMapping(value="/getAll", produces = {"application/xml","text/xml"}, consumes = MediaType.ALL_VALUE)
	public ResponseEntity<List<User>> getAllPost(){
		List<User> users = this.userService.findAll();
		
		if (users == null || users.isEmpty()) {
			return new ResponseEntity<List<User>>(users, HttpStatus.OK);
		}
		
		return new ResponseEntity<List<User>>(users, HttpStatus.OK);
	}
	
	@PostMapping(value="/login")
	public ResponseEntity<Boolean> authenticate(@RequestBody Map<String, String> params, HttpSession session){
		Boolean blogin = userService.authenticate(params.get("username"), params.get("password"));
		if(!blogin) {
			return new ResponseEntity<Boolean>(blogin, HttpStatus.FORBIDDEN);
		}
		
		session.setAttribute("username", params.get("username"));
		return new ResponseEntity<Boolean>(blogin, HttpStatus.OK);
	}
}

UserRestController.java

package com.aaa.blog.rest;

import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Optional;

import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.aaa.blog.model.Post;
import com.aaa.blog.model.User;
import com.aaa.blog.service.PostService;
import com.aaa.blog.service.TagService;
import com.aaa.blog.service.UserService;

@RestController
@RequestMapping("/rest/post")
public class PostRestController {

	@Autowired
	private PostService postService;
	
	@Autowired
	private UserService userService;
	
	@Autowired
	private TagService tagService;
	
    //@GetMapping("getAll")
	@GetMapping(value = "getAll", produces = {"application/xml", "text/xml"}, consumes = MediaType.ALL_VALUE)
	public ResponseEntity<List<Post>> getAllPost(){
		List<Post> posts = this.postService.findAllOrderedById();
		if (posts == null || posts.isEmpty()) {
			return new ResponseEntity<List<Post>>(HttpStatus.NOT_FOUND);
		}
		
		return new ResponseEntity<List<Post>>(posts, HttpStatus.OK);
	}
	
    //@GetMapping("get/{id}")
	@GetMapping(value="get/{id}", produces = {"application/xml","text/xml"}, consumes = MediaType.ALL_VALUE)
	public ResponseEntity<Post> getPostById(@PathVariable("id")long id){
		Optional<Post> optionalPost = this.postService.findById(id);
		if(optionalPost.isPresent()) {
			return new ResponseEntity<Post>(optionalPost.get(), HttpStatus.OK);
		}
		
		return new ResponseEntity<Post>(HttpStatus.NOT_FOUND);
	}
	
	@PostMapping("create")
	public ResponseEntity<Post> create(@RequestBody Post post, HttpSession session){
		post.setId(postService.findAllOrderedById().stream().map(Post::getId).max(Comparator.naturalOrder()).orElse(Long.MIN_VALUE)+1);
		post.setUser(userService.findByUsername((String)session.getAttribute("username")).get());
		Post p = this.postService.create(post);
		
		if(p==null) {
			return new ResponseEntity<Post>(HttpStatus.INTERNAL_SERVER_ERROR);
		}
		
		return new ResponseEntity<Post>(p, HttpStatus.OK);
	}
	
	@PutMapping("put/{id}")
	public ResponseEntity<Post> update(@PathVariable("id") long id, @RequestBody Post post){
		Optional<Post> optionalPost = postService.findById(id);
		
		if(optionalPost.isPresent()) {
			Optional<User> optionalUser = userService.findById(optionalPost.get().getUser().getId());
			
			if(optionalUser.isPresent()) {
				Post updatePost = optionalPost.get();
				updatePost.setId(id);
				updatePost.setTitle(post.getTitle());
				updatePost.setBody(post.getBody());
				updatePost.setCreatedDate(new Date());
				updatePost.setUser(optionalUser.get());
				updatePost.setTags(tagService.getTags());
				
				Post p = postService.edit(post);
				
				if(p==null) {
					return new ResponseEntity<Post>(post, HttpStatus.INTERNAL_SERVER_ERROR);
				}	
				return new ResponseEntity<Post>(post, HttpStatus.OK);
			}
			return new ResponseEntity<Post>(post, HttpStatus.NOT_FOUND);
		}
		return new ResponseEntity<Post>(post, HttpStatus.NOT_FOUND);
	}
	
	@GetMapping("delete/{id}")
	public ResponseEntity<Void> delete(@PathVariable("id") long id){
		Optional<Post> optionalPost = postService.findById(id);
		
		if (optionalPost.isPresent()) {
			postService.deleteById(id);
		}
		return new ResponseEntity<Void>(HttpStatus.OK);
	}
}

PostRestController.java

 

다음 해당 링크를 통해서 Json 타입이 아닌 XML 형식으로 데이터를 반납한다.

http://localhost:8080/rest/user/getAll

http://localhost:8080/rest/post/get/3

 

static에 js파일과 html 파일을 넣는다.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>로그인 화면</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="/js/ajaxlogin.js"></script>
</head>
<body>
	<h1>로그인 화면입니다.</h1>
	<form method="post" id="loginForm" th:object="${loginForm}">
		<div><label for="username">아이디</label></div>
		<input id="username" type="text" name="username" th:value="*{username}"/>
		
		<div><label for="password" th:value="*{username}">비밀번호</label></div>
		<input id="password" type="password" name="password" th:value="*{password}" />
		
		<div>
			<input type="submit" value="로그인" />
			<a href="index.html" th:href="@{/posts}">취소</a>
		</div>
	</form>
	<div id=helloUserDiv></div>
</body>
</html>

ajaxlogin.html

$(document).ready(function () {
	$("#loginForm").submit(function (event) {
		event.preventDefault();
		ajax_login_submit();
	});
});

function ajax_login_submit() {
		var user = {};
		user["username"] = $("#username").val();
		user["password"] = $("#password").val();
		
		console.log(JSON.stringify(user));
		
		$.ajax({
			type: "POST",
			contentType: "application/json; charset=utf-8",
			url: "rest/user/login",
			data: JSON.stringify(user),
			dataType: 'json',
			cache : false,
			success: function (data) {
				$('#helloUserDiv').html('로그인 성공');
				console.log("SUCCESS : ", data);
				alert('로그인이 성공했습니다.');
			},
			error: function (e) {
				var resultJson = e.responseText;
				$('#helloUserDiv').html('로그인 실패');
				console.log("ERROR : ", resultJson);
			}
		});
}

ajaxlogin.js

Spring-Blog-Jpa 프로젝트의 로그인 화면에서 환영 메시지를 표시하는 기능을 Ajax로 구현하였다.

https://github.com/Julian-Hwang/spring_boot_project/tree/main/Spring-Blog-Jpa

 

GitHub - Julian-Hwang/spring_boot_project

Contribute to Julian-Hwang/spring_boot_project development by creating an account on GitHub.

github.com