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 상품삭제
'BACKEND > 스프링 Spring Boot' 카테고리의 다른 글
프로젝트 주제와 DB 구상 (0) | 2024.01.08 |
---|---|
[INTRO] 쇼핑몰 만들기 프로젝트 (1) | 2024.01.08 |
Spring Boot 로 만드는 Restful Api 간단한 예제 (0) | 2024.01.04 |
[SpringBoot] 스프링 부트 시작하기 (0) | 2022.03.30 |
타임리프 입출력 (1) | 2022.03.30 |