프로필사진
RESTful(7) - RESTful server구현해보기 (간단예제!)

2019. 11. 26. 11:30🔴 Spring

300x250

RESTful로 구현한다는 것은
: 하나의 RESTful server → 여러개 APP (=client program)가 접속하도록 만든다는 뜻이다


환경설정

<pom.xml>

<!-- Mybatis설정 -->
		<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>3.4.1</version>
		</dependency> 
		<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis-spring</artifactId>
			<version>1.3.0</version>
		</dependency>
<!-- JSON 사용하기 -->
		<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<!-- @Responsebody를 쓰면 객체를 Json으로 반환할 수 있도록 해줌 -->
			<version>2.9.8</version>
		</dependency>

<servlet-context.xml>

<!-- Mybatis설정 : dataSource, mapper경로 -->
	<beans:bean id="sqlSessionFactory"
		class="org.mybatis.spring.SqlSessionFactoryBean">
		<beans:property name="dataSource" ref="dataSource" />
		<beans:property name="mapperLocations"
			value="classpath:com/bitcamp/mm/mapper/mybatis/*.xml">
		</beans:property>
	</beans:bean>

	<beans:bean id="sqlSession"
		class="org.mybatis.spring.SqlSessionTemplate">
		<beans:constructor-arg index="0"
			ref="sqlSessionFactory" />
	</beans:bean>

DAO

DAO interface

package com.bitcamp.mm.member.dao;

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

import com.bitcamp.mm.member.domain.MemberInfo;
import com.bitcamp.mm.member.domain.SearchParam;

public interface MemberSessionDao {
	public MemberInfo selectMemberById(String userId);
	public int insertMember(MemberInfo memberInfo);
	public int selectTotalCount(SearchParam searchParam);
	public List<MemberInfo> selectList(Map<String,Object>params);
	public List<MemberInfo> selectAllList(); // 전체 리스트 받아옴
	public int memberDelete(int id);// 회원 정보 삭제
	
}

Mapper로 처리 <memberMapper.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">

<!-- DAO interface의 full name을 namespace의 속성으로 사용 -->
<mapper namespace="com.bitcamp.mm.member.dao.MemberSessionDao">
	
	<!-- DB와 이름 맞추기 -->
	<resultMap type="com.bitcamp.mm.member.domain.MemberInfo" id="memberResultmap">
		<id property="idx" column="idx"/>
		<result property="uId" column="uid"/>
		<result property="uPw" column="upw"/>
		<result property="uName" column="uname"/>
		<result property="uPhoto" column="uphoto"/>
		<result property="regDate" column="regdate"/>
	</resultMap>
	
	<select id="selectMemberById"
		resultMap="memberResultmap">
		select * from member where uid = #{uId}
	</select>

	<insert id="insertMember"
		parameterType="com.bitcamp.mm.member.domain.MemberInfo">
		insert into member (uid, uname, upw, uphoto) values
		(#{uId}, #{uName},#{uPw}, #{uPhoto})
	</insert>

	<select id="selectList" parameterType="map"
		resultMap="memberResultmap">
		select * FROM member limit #{index}, #{count}
	</select>

	<select id="selectTotalCount"
		parameterType="com.bitcamp.mm.member.domain.SearchParam"
		resultType="int">
		select count(*) from member
		<if test="_parameter != null">
			<where>
				<if test="'both'.equals(type)">
					uid like CONCAT ('%', #{keyword} ,'%') 
					or uname like CONCAT ('%', #{keyword} ,'%')
				</if>
				<if test="'id'.equals(type)">
					uid like CONCAT ('%', #{keyword} ,'%') 
				</if>
				<if test="'name'.equals(type)">
					uname like CONCAT ('%', #{keyword} ,'%')
				</if>
			</where>
		</if>
	</select>
	
	<!-- 전체 회원 리스트 구하기 -->
	<select id="selectAllList"
		resultMap="memberResultmap"
	>
	select * from member order by uname
	
	</select>
	
	<delete id="memberDelete">
	delete from member where idx = #{idx}
	</delete>
</mapper>

CONTROLLER

<MemberRestApiController.java>

package com.bitcamp.mm.member.controller;

import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.bitcamp.mm.member.domain.MemberInfo;
import com.bitcamp.mm.member.domain.MemberRestApiRegRequest;
import com.bitcamp.mm.member.domain.RequestMemberRegist;
import com.bitcamp.mm.member.service.MemberDeleteService;
import com.bitcamp.mm.member.service.MemberListService;
import com.bitcamp.mm.member.service.MemberRegService;

// /rest-api/members      GET ---> 전체 리스트, 페이징 처리된 리스트
// /rest-api/members/{id} GET ---> 회원 한명의 정보를 반환(memberInfo객체)
// /rest-api/members      POST ---> 회원 정보를 저장
// /rest-api/members/{id} PUT ---> 회원 정보를 수정
// /rest-api/members/{id} DELETE ---> 회원 정보를 삭제

@Controller //
@RequestMapping("/rest-api/members")
public class MemberRestApiController {

	@Autowired
	private MemberListService listService;
	
	@Autowired
	private MemberRegService regService;
	
	@Autowired
	private MemberDeleteService deleteService;
 
	// @RequestMapping("/{id}") // = /rest-api/members/{id}

	// @CrossOrigin("https://www.naver.com", ...) // 접속 허용 범위 설정
	@CrossOrigin
	@RequestMapping(method = RequestMethod.GET)
	@ResponseBody
	public List<MemberInfo> getAllList() {
		return listService.getAllList();
	}

	@CrossOrigin
	@ResponseBody
	@RequestMapping(method = RequestMethod.POST)
	public String regMember(@RequestBody RequestMemberRegist regRequest, HttpServletRequest request) {
		System.out.println(regRequest);
		int result = regService.memberInsert(request,regRequest);
		//return "success";
		return result>0?"success":"fail";
	}
	
	@CrossOrigin
	@ResponseBody
	@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
	public String deleteMember(
			@PathVariable("id") int idx
			) {
		
		System.out.println(idx);
		
		int result = deleteService.memberDelete(idx);
		
		return result>0?"success":"fail";
	}
}

SERVICE

  • getAllList

<MemberListService.java>

package com.bitcamp.mm.member.service;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.bitcamp.mm.jdbc.ConnectionProvider;
import com.bitcamp.mm.member.dao.MemberDao;
import com.bitcamp.mm.member.dao.MemberJdbcTemplateDao;
import com.bitcamp.mm.member.dao.MemberSessionDao;
import com.bitcamp.mm.member.domain.ListViewData;
import com.bitcamp.mm.member.domain.MemberInfo;
import com.bitcamp.mm.member.domain.SearchParam;

@Service("listService")
public class MemberListService implements MemberService {

	/*
	 * @Autowired private MemberDao dao;
	 */
	@Autowired
	// private MemberJdbcTemplateDao dao;
	private SqlSessionTemplate template;

	private MemberSessionDao dao;

	final int MEMBER_CNT_LIST = 3;

	public ListViewData getListData(int currentPageNumber, SearchParam searchParam) {

		// dao 생성
		dao = template.getMapper(MemberSessionDao.class);

		ListViewData listData = new ListViewData();

			// 현재 페이지 번호
			listData.setCurrentPageNumber(currentPageNumber);
			// 전체 게시물 개수
			// int totalCnt = dao.selectTotalCount(conn, searchParam);
			int totalCnt = dao.selectTotalCount(searchParam);

			int totalPageCnt = 0;
			// 전페 페이지 개수
			if (totalCnt > 0) {
				totalPageCnt = totalCnt / MEMBER_CNT_LIST;
				if (totalCnt % MEMBER_CNT_LIST > 0) {
					totalPageCnt++;
				}
			}
			listData.setPageTotalCount(totalPageCnt);

			// 구간 검색을 위한 index
			// 1 -> 0, 2->3, 3->6, 4->9
			int index = (currentPageNumber - 1) * MEMBER_CNT_LIST;

			// 회원 정보 리스트
			// listData.setMemberList(dao.selectList(conn, index, MEMBER_CNT_LIST));
			
			// map으로 삽입
			Map<String, Object> params = new HashMap<String, Object>();
			params.put("index",index);
			params.put("count",MEMBER_CNT_LIST);
			listData.setMemberList(dao.selectList(params));

			List<MemberInfo> memberList = null;
			// 1. 검색 조건이 없는 경우 : selectList -> 전체 회원의 리스트
			// 2. id로 검색 : where like uid '%?%'
			// 3. name으로 검색 : where like uname '%?%'
			// 4. id 또는 name : where like uname '%?%' or like uid '%?%'

			// 1-> 9-0 = 9
			// 2 -> 9-3 = 6
			int no = totalCnt - index;
			listData.setNo(no);

			listData.setTotalCount(totalCnt);

		return listData;
	}
	
	public List<MemberInfo> getAllList(){
		
		dao = template.getMapper(MemberSessionDao.class);
		List<MemberInfo> list = dao.selectAllList();
		
		return list;
	}

}

 

  • regMember

<MemberRegService.java>

package com.bitcamp.mm.member.service;

import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;

import javax.servlet.http.HttpServletRequest;

import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestParam;

import com.bitcamp.mm.jdbc.ConnectionProvider;
import com.bitcamp.mm.member.dao.MemberDao;
import com.bitcamp.mm.member.dao.MemberJdbcTemplateDao;
import com.bitcamp.mm.member.dao.MemberSessionDao;
import com.bitcamp.mm.member.domain.MemberInfo;
import com.bitcamp.mm.member.domain.RequestMemberRegist;

@Service("registService")
public class MemberRegService implements MemberService {

	/*
	 * @Autowired private MemberDao dao;
	 */

	@Autowired
	// private MemberJdbcTemplateDao dao;
	private SqlSessionTemplate template;

	private MemberSessionDao dao;

	public int memberInsert(HttpServletRequest request, RequestMemberRegist regist) {

		// dao 생성
		dao = template.getMapper(MemberSessionDao.class);

		// 서버경로
		String path = "/uploadfile/userphoto";
		// 절대경로
		String dir = request.getSession().getServletContext().getRealPath(path);
		MemberInfo memberInfo = regist.toMemberInfo();

		int resultCnt = 0;
		// Connection conn = null;
		String newFileName = "";

		try {
			if (regist.getuPhoto() != null) {
				// 새로운 파일 이름 생성
				newFileName = memberInfo.getuId() + "_" + regist.getuPhoto().getOriginalFilename();
				// conn = ConnectionProvider.getConnection();

				// 파일 서버의 지정 경로에 저장
				regist.getuPhoto().transferTo(new File(dir, newFileName));

				// 데이터베이스 저장을 하기 위한 파일 이름 set
				memberInfo.setuPhoto(newFileName);
			} 

			// DB저장
			// resultCnt = dao.insertMember(conn, memberInfo);
			resultCnt = dao.insertMember(memberInfo);

		} catch (IllegalStateException e) {
			// TODO: handle exception
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		/*
		 * catch (SQLException e) { // TODO Auto-generated catch block
		 * e.printStackTrace(); new File(dir, newFileName).delete(); }
		 */

		return resultCnt;
	}

	public char idCheck(String id) {

		char chk = dao.selectMemberById(id) == null ? 'Y' : 'N';

		return chk;
	}

	public String idCheck1(String id) {

		return dao.selectMemberById(id) == null ? "Y" : "N";
	}

}

 

  • deleteMember

<MemberDeleteService.java>

package com.bitcamp.mm.member.service;

import java.sql.Connection;
import java.sql.SQLException;

import javax.inject.Inject;

import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.bitcamp.mm.jdbc.ConnectionProvider;
import com.bitcamp.mm.member.dao.MemberDao;
import com.bitcamp.mm.member.dao.MemberSessionDao;

@Service("deleteService")
public class MemberDeleteService implements MemberService {
	
	//@Autowired
	//private MemberDao dao;
	private MemberSessionDao dao;
	
	@Inject
	private SqlSessionTemplate template;
	
	public int memberDelete(int id) {

		dao = template.getMapper(MemberSessionDao.class);
		return dao.memberDelete(id);
	}
}

여러개 client APP

<rest-client.html>

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
    <style>
        div.card {
            float: left;
            margin: 2px;
            width: 33%;
            border: 3px solid;
        }

        div#memberlist {
            overflow: hidden;
        }
    </style>
</head>

<body>
    <h1>회원리스트</h1>
    <hr>
    <div id="memberlist">


    </div>

    <script>
        $(document).ready(function() {

            list();

        });

        function del(idx) {

            if (confirm('삭제하시겠습니까?')) {
                $.ajax({
                    url: 'http://localhost:9090/mm/rest-api/members/' + idx,
                    type: 'DELETE',
                    success: function(data) {
                        //alert(JSON.stringify(data));
                        if (data == 'success') {
                            alert('삭제되었습니다');
                            list();
                        }
                    }
                });
            }
        }

        function list() {
            $.ajax({
                url: 'http://localhost:9090/mm/rest-api/members',
                type: 'GET',
                success: function(data) {
                    //alert(JSON.stringify(data));

                    var html = '';
                    for (var i = 0; i < data.length; i++) {
                        html += '<div class="card">\n';
                        html += 'idx : ' + data[i].idx + '<br>\n';
                        html += 'uId : ' + data[i].uId + '<br>\n';
                        html += 'uName : ' + data[i].uName + '<br>\n';
                        html += 'uPhoto : ' + data[i].uPhoto + '\n';
                        html += '<button onclick="del(' + data[i].idx + ')">삭제하기</button><br>\n';
                        html += '</div>\n';
                    }

                    $('#memberlist').html(html);

                }
            });
        }
    </script>
</body></html>

 

<rest-reg.html>

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
    <style>
        div.card {
            float: left;
            margin: 2px;
            width: 33%;
            border: 3px solid;
        }

        div#memberlist {
            overflow: hidden;
        }
    </style>
</head>

<body>
    <h1>회원가입</h1>
    <hr>
    <form id="form">
        아이디 <input type="text" name="uId" id="uId"><br>
        비밀번호 <input type="password" name="uPw" id="uPw"><br>
        이름 <input type="text" name="uName" id="uName"><br>
        <input type="submit" value="가입">
    </form>

    <script>
        $(document).ready(function() {

            /*var list = {
                uId: 'idididid',
                uPw: 'passsssss',
                uName: '홍길동'
            };*/

            $('#form').submit(function() {

                $.ajax({
                    url: 'http://localhost:9090/mm/rest-api/members',
                    type: 'POST',
                    data: JSON.stringify({ //JavaScript 값이나 객체를 JSON 문자열로 변환
                        uId: $('#uId').val(),
                        uPw: $('#uPw').val(),
                        uName: $('#uName').val()
                    }),
                    contentType: 'application/json; charset=utf-8',
                    dataType: 'json',
                    success: function(data) {
                        alert(data);
                    }
                });
                return false;
            });

        });
    </script>
</body></html>
300x250