BACKEND/스프링 Spring Boot

SpringBoot REST API 상품 조회 , 삭제 , 수정 , 등록

꾸준히개발하자 2024. 1. 8. 11:44

application.properties : 자신의 aws ec2 db ip 로 변경합니다

REST(REpresentational State Transfer) : 대표 상태 전송

분산 환경에서 시스템 간 통신을 위한 소프트웨어 아키텍쳐

자원에 고유한 식별자(URI) 부여하고 HTTP Method로 제어하는 소프트웨어 아키텍쳐

HTTP GET(조회) , POST(생성) , PUT(수정), DELELTE(삭제) Method를 통해 제어

참고) URI : Uniform Resource Identifier 네트워크 상 자원을 구분하는 식별자

ex) http://daum.net/index?pageNo=2 http://daum.net/product/77

URI 는 URL 을 포함하는 상위 개념이다

URL : Uniform Resource Locator 네트워크 상 자원의 위치 ex) http://daum.net/index.html

특징

1. 자원정보를 고유한 URI(통합자원식별자:Uniform Resource Identifier)를 부여해 활용

HTTP GET(조회) , POST(생성) , PUT(수정), DELELTE(삭제) Method를 통해 제어

ex ) http://news.daum.net/v/1004

2. "다양한 클라이언트"에게 서비스를 제공, 클라이언트와 서버 역할의 명확한 분리가 가능.

-> 모바일 , 태블릿, PC , TV 등과 같은 다양한 디바이스에 대한 서비스 및 다른 시스템과의 통신을 위해 사용된다

- REST API : REST 특징을 기반으로 서비스 API를 구현한 것 ,

어플리케이션 간의 데이터 통신을 위한 어플리케이션 프로그래밍 인터페이스

- Rest API 설계 원칙 : URI는 정보의 자원을 표현하고 자원에 대한 행위는 HTTP Method로 표현한다

"URI는 정보의 자원을 표현한다"

자원(Resource) : URI , 자원의 이름은 동사가 아닌 명사를 사용한다 => 자원 표현에 집중 , 계층은 슬래시 / 로 표현하고 , 필요시 하이픈 - 을 이용한다

 

"자원에 대한 행위는 HTTP Method로 표현한다 "

행위(Action) : Http Method , 자원에 대한 행위는 Http GET,POST,PUT,DELETE Method를 통한다

GET /products/123 123 id 상품 조회

DELETE /products/123 123 id 상품 삭제

PUT /products/123 123 id 상품 수정

POST /products 상품 등록

 

쇼핑몰 상품관리 Rest API Server 의 예

http://127.0.0.1:7777/api/products/1

Resource GET(read) POST(create) PUT(update) DELETE(delete)

/products 상품리스트 상품추가

/products/{id} id 해당하는 상품 해당 id 상품수정 해당 id 상품삭제

 

RESTful : REST API 제공하는 웹서비스 시스템을 지칭 , "A 서비스 시스템은 'RESTful' 하다"

Spring Rest Annotation

@RestController : @Controller + @ResponseBody

@GetMapping @PostMapping @PutMapping @DeleteMapping

 

 

 

Spring Tool Suite3 를 사용하였습니다. 

 

 

 

Pom.xml 에 의존성주입 라이브러리 추가 

<?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.7.0</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>org.kosta</groupId>
	<artifactId>springbootstudy9-REST</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>springbootstudy8-REST</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>11</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</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.2.2</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>com.oracle.database.jdbc</groupId>
			<artifactId>ojdbc8</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<excludes>
						<exclude>
							<groupId>org.projectlombok</groupId>
							<artifactId>lombok</artifactId>
						</exclude>
					</excludes>
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

 

 

application.properties

서버 포트 설정

#port
server.port=8089
#dbcp
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@54.180.24.239:1521:xe 
spring.datasource.username=scott 
spring.datasource.password=tiger 
#devtools : reloading 
spring.devtools.livereload.enabled=true
#log level setting
logging.level.root=error
logging.level.org.kosta.myproject.test=debug
logging.level.org.kosta.myproject.controller=debug
logging.level.org.kosta.myproject.service=debug
logging.level.org.kosta.myproject.mapper=debug
# mybatis setting
#mybatis.type-aliases-package=org.kosta.myproject.model.vo
mybatis.configuration.map-underscore-to-camel-case=true
server.servlet.session.tracking-modes=cookie

 

8089로 설정 하였습니다

 

 

디렉 터리 구조

 

 

 

상품 조회 , 삭제 , 수정 , 등록 을 Rest API 로 등록해 보겠습니다.

 

상품 관련 SQL

create table rest_product(
	id number primary key,
	name varchar2(100) not null,
	maker varchar2(100) not null,
	price number not null
)
create sequence rest_product_seq;
select * from rest_product;
insert into rest_product values(rest_product_seq.nextval,'갤럭시8','삼성',150);
insert into rest_product values(rest_product_seq.nextval,'아이폰7','애플',170);
commit

 

상품 번호 , 이름 , 메이커 , 가격 테이블 생성

상품 2개를 등록했습니다.

 

 

ProductVO - 상품 정보 VO 

package org.kosta.myproject.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class ProductVO {
	private long id;
	private String name;
	private String maker;
	private int price;
}

 

 

 

ProductRestApiController 

package org.kosta.myproject.controller;

import java.util.List;

import org.kosta.myproject.service.ProductService;
import org.kosta.myproject.vo.ProductVO;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

import lombok.RequiredArgsConstructor;


@RequiredArgsConstructor
public class ProductRestApiController {
	private final ProductService productService;
	
	public List<ProductVO> getAllProductList(){
		return productService.getAllProductList();
	}
	
    // 상품 조회 
	public ResponseEntity<ProductVO> findProductById(String id){
		ProductVO productVO=productService.findProductById(id);
		if(productVO==null) {
		//	return new ResponseEntity<ProductVO>(HttpStatus.NOT_FOUND);//상품정보가 없을 때는 404 Not Found
			return ResponseEntity.notFound().build();
		}
			//return new ResponseEntity<ProductVO>(productVO, HttpStatus.OK);//정상수행일때 상품정보와 200 OK으로 응답 
		  return ResponseEntity.ok().body(productVO);
	}
	
    // 상품 등록
	public ResponseEntity<String> registerProduct(ProductVO productVO){
		productService.registerProduct(productVO);
		return new ResponseEntity<String>(productVO.getId()+" 상품 등록완료",HttpStatus.OK);
	}
	
    // 상품 수정 
	public ResponseEntity<String> updateProduct(ProductVO productVO){
		int result=productService.updateProduct(productVO);
		if(result==0) {
			//return new ResponseEntity<>(HttpStatus.NOT_FOUND);
			return ResponseEntity.notFound().build();
		}
		//return new ResponseEntity<>(productVO.getId()+" 상품 수정완료",HttpStatus.OK);
		return ResponseEntity.ok().body(productVO.getId()+" 상품 수정완료");
	}
	
    // 상품 삭제 
	public ResponseEntity<String> deleteProduct(String id){
		int result=productService.deleteProduct(id);
		if(result==0)
		//	return new ResponseEntity<String>(HttpStatus.NOT_FOUND);
			return ResponseEntity.notFound().build();
		//return new ResponseEntity<String>(id+" 상품 삭제완료",HttpStatus.OK);
		return ResponseEntity.ok().body(id+" 상품 삭제완료");
	}
}

 

  ResponseEntity : rest 응답시 상태코드( http status code : 404 , 405, 500 ,200 ) 와 응답메세지를 전송하기
      위한 클래스 
 @PathVariable : url 정보를 컨트롤러 메서드의 변수로 할당받기 위한 어노테이션 
  ex)  ip:port/product/1004  => 아래의 매개변수 id에 1004가 할당된다 

 

 

Productservice 클래스  

package org.kosta.myproject.service;

import java.util.List;

import org.kosta.myproject.vo.ProductVO;

public interface ProductService {
	public List<ProductVO> getAllProductList();
	public ProductVO findProductById(String id);
	public void registerProduct(ProductVO productVO);
	public int updateProduct(ProductVO productVO);
	public int deleteProduct(String id);
}

 

ProductserviceImpl

package org.kosta.myproject.service;

import java.util.List;

import org.kosta.myproject.mapper.ProductMapper;
import org.kosta.myproject.vo.ProductVO;
import org.springframework.stereotype.Service;

import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
public class ProductServiceImpl implements ProductService {
	private final ProductMapper productMapper;
	@Override
	public List<ProductVO> getAllProductList() {
		return productMapper.getAllProductList();
	}

	@Override
	public ProductVO findProductById(String id) {
		return productMapper.findProductById(id);
	}

	@Override
	public void registerProduct(ProductVO productVO) {
		productMapper.registerProduct(productVO);
	}

	@Override
	public int updateProduct(ProductVO productVO) {
		return productMapper.updateProduct(productVO);
	}

	@Override
	public int deleteProduct(String id) {
		return productMapper.deleteProduct(id);
	}

}

 

 

 

 

ProductMapper.xml - 마이바티스 

<?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="org.kosta.myproject.mapper.ProductMapper">
	<sql id="selectProduct">
		select id,name,maker,price from rest_product
	</sql>
	<select id="getAllProductList"  resultType="org.kosta.myproject.vo.ProductVO">
 		<include refid="selectProduct"></include>
 		order by id desc
 	</select>
 	<select id="findProductById"  resultType="org.kosta.myproject.vo.ProductVO" >
 		<include refid="selectProduct"></include>
 		where id=#{value}
 	</select>
 	<insert id="registerProduct" parameterType="org.kosta.myproject.vo.ProductVO">
 		<selectKey keyProperty="id" resultType="long" order="BEFORE">
 			select rest_product_seq.nextval from dual
 		</selectKey>
 		insert into rest_product(id,name,maker,price)
		values(#{id},#{name},#{maker},#{price})
 	</insert>
 	<delete id="deleteProduct" parameterType="string">
 		delete from rest_product where id=#{value}
 	</delete>
 	<update id="updateProduct" parameterType="org.kosta.myproject.vo.ProductVO">
 		update rest_product set name=#{name},maker=#{maker},price=#{price} 
 		where id=#{id}
 	</update>
</mapper>

 

 

 

index-rest.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
  <script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.slim.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<title>REST</title>
<style type="text/css">
	.restImg{
		width: 600px;
		height: 400px		
	}
</style>
</head>
<body>
<div class="container">
<h3>REST  적용 웹어플리케이션 구현 예제 </h3>
<h5><a href="simple-rest" th:href="@{/simple-rest}">simple rest test</a></h5>	
   <ul> 
   	<li>
   	HTTP Request Method <br><br>
   	GET : 리스트 조회 <input type="button" value="testGetListBtn" id="testGetListBtn"><br>
   	<div id="listView"></div> 	<br> <br>
   	GET : 조회 <input type="button" value="testGetBtn" id="testGetBtn"><input type="number" id="pid"><br><br> 
	POST :생성 <input type="button" value="testCreateBtn" id="testCreateBtn"><br>
	<form id="createProductForm">
		상품명 <input type="text" id="pname" name="name" size="5"> 제조사 <input type="text" name="maker" size="5"> 가격 <input type="number" name="price">
	</form>
	<br><br>	
	PUT : 수정 <input type="button" value="testPutBtn" id="testPutBtn"><br>
		<form id="updateProductForm">
		상품번호 <input type="number"    name="id" size="3" id="updateId"> 
		상품명 <input type="text" name="name" size="5"> 제조사 <input type="text" name="maker" size="5"> 가격 <input type="number" name="price">
	</form>
	<br>
	DELETE : 삭제 <input type="button" value="testDeleteBtn" id="testDeleteBtn">
	<input type="number" id="deleteId">
   	</li>  
   </ul>   
   <img class="restImg" src="images/rest-api.png">
   <script type="text/javascript">
   // API Server로 요청하기 전 javascript 공란체크는 다해야 함 
	 $(function(){
		 // 공통적으로 사용될 Ajax 통신에 대한 기본속성을 정의해 사용할 수 있다 
		 $.ajaxSetup({
			 success:function(data){
				 alert(data);
			 },
			 error:function(xhr,status,error){
				// console.log(xhr);
				 if(xhr.status==404)
					 alert("정보가 존재하지 않아 서비스 불가");
			 }
		 });//ajaxSetup
		 $("#testGetListBtn").click(function() {
			 $("#listView").empty();
			 $.ajax({
					type:"get",
					url:"products",
					success:function(productList){ // success를 정의하지 않으면 ajaxSetup의 success가 실행되고 정의하면 자신의 success가 실행된다 
						//javascript for loop 를 jquery each 로 처리할 수 있다 
						$.each(productList,function(i,product){// i 는 0부터 시작하는 인덱스 
							$("#listView")
							.append(product.id+" "+product.name+" "+product.maker+" "+product.price+"<br>")
							.css("color","blue");							
						});//each
					}
				});//ajax
		 });//testGetListBtn
		 $("#testGetBtn").click(function() {
		 	let pid=$("#pid").val();
		 	if(pid==""){
		 		alert("상품번호를 입력하세요!");
		 		return;
		 	}
		 	$.ajax({
		 		type:"get",
		 		url:"products/"+pid,
		 		success:function(data){
		 			alert(data.id+" "+data.name+" "+data.maker+" "+data.price);
		 		}
		 	});
		 });//testGetBtn
		 $("#testCreateBtn").click(function() {	
			 if($("#pname").val()==""){
			 		alert("상품명을 입력하세요!");
			 		return;
			 	}
			 	$.ajax({
			 		type:"post",
			 		url:"products",
			 		data:$("#createProductForm").serialize()
			 	}).always(function() { // always : ajax 통신 후 수행될 작업을 명시 ( java finally와 유사 )
			 		$("#createProductForm")[0].reset();
			 	});
			});//testCreateBtn
			$("#testPutBtn").click(function() {		
				if($("#updateId").val()==""){
			 		alert("상품번호를 입력하세요!");
			 		return;
			 	}
			 	$.ajax({
			 		type:"put",
			 		url:"products",
			 		data:$("#updateProductForm").serialize()
			 	}).always(function() { // always : ajax 통신 후 수행될 작업을 명시 ( java finally와 유사 )
			 		$("#updateProductForm")[0].reset();
			 	});
			});//testPutBtn
			$("#testDeleteBtn").click(function() {	
				if($("#deleteId").val()==""){
			 		alert("상품번호를 입력하세요!");
			 		return;
			 	}
			 	$.ajax({
			 		type:"delete",
			 		url:"products",
			 		data:"id="+$("#deleteId").val(),
			 		success:function(result){
			 			alert(result);
			 			// 삭제 성공시 후속 작업으로 리스트를 갱신하게 한다 ( jquery trigger를 이용 )
			 			$("#testGetListBtn").trigger("click");// 리스트 버튼 클릭 이벤트를 발생시킨다 
			 		}
			 	}).always(function() { // always : ajax 통신 후 수행될 작업을 명시 ( java finally와 유사 )
			 		$("#deleteId").val("");
			 	});
			});//testDeleteBtn
	 });//ready
    </script>
</div>
</body>
</html>

 

 

쇼핑몰 상품관리 Rest API Server 의 예

http://127.0.0.1:7777/api/products/1

Resource GET(read) POST(create) PUT(update) DELETE(delete)

/products 상품리스트 상품추가

/products/{id} id 해당하는 상품 해당 id 상품수정 해당 id 상품삭제