<2. DB 연결 웹 애플리케이션 - Web API>
http://www.edwith.org/boostcourse-web
* Web API 디자인 가이드 원칙
1. 자원에 대한 행위는 HTTP Method(GET, POST, PUT, DELETE)로 표현한다.
2. URI는 정보의 자원을 표현해야 한다.
3. 슬래시 구분자(/)는 계층을 나타낼 때 사용한다.
1. 자원에 대한 행위는 HTTP Method로 표현
1. 자원에 대한 행위는 HTTP Method로 표현
GET /members/1 (o)
GET /members/get/1 (x)
GET /members/add (x)
POST /members (o)
GET /members/update/1 (x)
PUT /members/1 (o)
GET /members/del/1 (x)
DELETE /members/1 (o)
2. URI는 정보의 자원을 표현해야 한다.
GET /members
: 위의 표현은 맴버의 모든 정보를 달라는 요청
GET /members/delete/1 (X)
: GET은 정보를 요청할 때 사용합니다. 위와 같이 동사로 삭제를 표현하면 안된다.DELETE /members/1 (O)
: HTTP Method 중의 하나인 DELETE를 이용하여 삭제를 표현 한다.
3. 슬래시 구분자(/)는 계층을 나타낼 때 사용
http://domain/houses/apartments (O)
http://domain/departments/1/employees (O)
http://domain/houses/apartments/ (X)
http://restapi.example.com/members/soccer/345/photo.jpg (X)
URI 마지막 문자로 슬래시 구분자(/)를 포함하지 않는다.
하이픈(-)은 URI가독성을 높일 때 사용
언더바(_)는 사용하지 않는다.
URI경로는 소문자만 사용
RFC 3986(URI 문법 형식)은 URI스키마와 호스트를 제외하고는 대소문자를 구별한다.
파일 확장자는 URI에 포함하지 않는다.
Accept Header를 사용
상태 코드 (클라이언트로 인한 오류)
클라이언트가 잘못 요청했을 때 받을 수 있는 상태값
상태 코드 (서버로 인한 오류)
* Web API 사용을 위한 준비작업
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | <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 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>kr.or.connect</groupId> <artifactId>webapiexam</artifactId> <packaging>war</packaging> <version>0.0.1-SNAPSHOT</version> <name>webapiexam Maven Webapp</name> <url>http://maven.apache.org</url> <properties> <!-- web.xml 파일을 삭제해도 eclipse에서 오류가 발생하지 않는다. --> <failOnMissingWebXml>false</failOnMissingWebXml> </properties> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.45</version> </dependency> <!-- json 라이브러리 databind jackson-core, jackson-annotaion에 의존성이 있다. --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.4</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> <build> <finalName>webapiexam</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.6.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project> | cs |
1. 위에 코드를 pom.xml에 추가한 뒤 네비게이터(왼쪽 탭) 안에서 .settings안에 org.eclipse.~~~core.xml 파일을 열고 jst.web version을 3.1로 올린다.
2. 이클립스 재시작 (pom을 건드린 후에는 프로젝트에서 오른쪽버튼 클릭 후 maven -> project update 꼭 해주기)
3. 프로젝트에 마우스 오른쪽 버튼 클릭 후 properties로 이동해서 project facets에서 3.1로 바뀌었는지 확인해본다.
4. 다시 프로젝트 익스프로러로 돌아와서 wepapp>WEB-INF>web.xml 파일을 삭제한다. (Annotation을 사용할 것이기 떄문에)
5. pom.xml 열어서 <failOnMissingWebXml>false</failOnMissingWebXml>을 추가해주어야 오류가 뜨지 않는다. (위에 파일을 복붙했다면 이미 추가되어있음)
6. 네비게이터 창에서 src>main에 오른쪽 버튼 클릭 후 New -> java폴더 만들기.
7. project explorer 탭으로 돌어와서 이렇게 만든 java폴더에 package를 만들고 코드(Servlet, Class)를 작성한다.
* 두 개의 파일을 생성하여 테스트 해보기
이 코드는 테이블 안에 있는 모든 해당 값에 대한 정보를 가져온다.
(+) JSON : JavaScript Object Notation의 약어로 아주 가벼운 형태의 메시지 교환 형식이다.
RoleServlet.java
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 31 32 33 34 35 36 37 38 39 40 41 42 43 | package kr.or.connect.webapiexam.api; import java.io.IOException; import java.io.PrintWriter; import java.util.List; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.fasterxml.jackson.databind.ObjectMapper; import kr.or.connect.jdbcexam.dao.RoleDao; import kr.or.connect.jdbcexam.dto.Role; @WebServlet("/roles") public class RolesServlet extends HttpServlet { private static final long serialVersionUID = 1L; public RolesServlet() { super(); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setCharacterEncoding("utf-8"); response.setContentType("application/json"); //JSON 타입으로 응답 RoleDao dao = new RoleDao(); List<Role> list = dao.getRoles(); ObjectMapper objectMapper = new ObjectMapper(); //JSON라이브러리가 제공해주는 객체 이용 String json = objectMapper.writeValueAsString(list); //파라메터로 리스트 넣어주면 JSON으로 바뀌어 리턴 PrintWriter out = response.getWriter(); out.println(json); out.close(); } } | cs |
RoleDao.java
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 | package kr.or.connect.jdbcexam.dao; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import kr.or.connect.jdbcexam.dto.Role; public class RoleDao { private static String dburl = "jdbc:mysql://localhost:3306/connectdb"; //만들어둔 connectdb를 사용하겠다 private static String dbUser = "connectuser"; //id와 password와 각각 설정해주면 됨 private static String dbpasswd = "connect123!@#"; //select public Role getRoles(Integer roleId) { Role role = null; Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; try { Class.forName("com.mysql.jdbc.Driver"); conn = DriverManager.getConnection(dburl, dbUser, dbpasswd); String sql = "SELECT description, role_id FROM role WHERE role_id = ?"; ps = conn.prepareStatement(sql); ps.setInt(1, roleId); rs = ps.executeQuery(); if (rs.next()) { String description = rs.getString(1); int id = rs.getInt("role_id"); role = new Role(id, description); } } catch (Exception e) { e.printStackTrace(); } finally { if (rs != null) { try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } } if (ps != null) { try { ps.close(); } catch (SQLException e) { e.printStackTrace(); } } if (conn != null) { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } return role; } //리스트 사용하기 - select public List<Role> getRoles() { List<Role> list = new ArrayList<>(); try { Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } String sql = "SELECT description, role_id FROM role order by role_id desc"; try (Connection conn = DriverManager.getConnection(dburl, dbUser, dbpasswd); PreparedStatement ps = conn.prepareStatement(sql)) { try (ResultSet rs = ps.executeQuery()) { while (rs.next()) { String description = rs.getString(1); int id = rs.getInt("role_id"); Role role = new Role(id, description); list.add(role); // list에 반복할때마다 Role인스턴스를 생성하여 list에 추가한다. } } catch (Exception e) { e.printStackTrace(); } } catch (Exception ex) { ex.printStackTrace(); } return list; } //insert public int addRole(Role role) { int insertCount = 0; try { Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundException e) { e.printStackTrace(); } String sql = "INSERT INTO role (role_id, description) VALUES ( ?, ? )"; try (Connection conn = DriverManager.getConnection(dburl, dbUser, dbpasswd); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setInt(1, role.getRoleId()); ps.setString(2, role.getDescription()); insertCount = ps.executeUpdate(); } catch (Exception ex) { ex.printStackTrace(); } return insertCount; } //update public int updateRole(Role role) { int updateCount = 0; Connection conn = null; PreparedStatement ps = null; try { Class.forName( "com.mysql.jdbc.Driver" ); conn = DriverManager.getConnection ( dburl, dbUser, dbpasswd ); String sql = "update role set description = ? where role_id = ?"; ps = conn.prepareStatement(sql); ps.setString(1, role.getDescription()); ps.setInt(2, role.getRoleId()); updateCount = ps.executeUpdate(); }catch(Exception ex) { ex.printStackTrace(); }finally { if(ps != null) { try { ps.close(); }catch(Exception ex) {} } // if if(conn != null) { try { conn.close(); }catch(Exception ex) {} } // if } // finally return updateCount; } //delete public int deleteRole(Integer roleId) { int deleteCount = 0; Connection conn = null; PreparedStatement ps = null; try { Class.forName( "com.mysql.jdbc.Driver" ); conn = DriverManager.getConnection ( dburl, dbUser, dbpasswd ); String sql = "DELETE FROM role WHERE role_id = ?"; ps = conn.prepareStatement(sql); ps.setInt(1, roleId); deleteCount = ps.executeUpdate(); }catch(Exception ex) { ex.printStackTrace(); }finally { if(ps != null) { try { ps.close(); }catch(Exception ex) {} } // if if(conn != null) { try { conn.close(); }catch(Exception ex) {} } // if } // finally return deleteCount; } } | cs |
[결과] connectdb에 있는 값이 모두 출력된다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | [ { roleId: 501, description: "CTO" }, { roleId: 102, description: "Project manager" }, { roleId: 101, description: "Researcher" }, { roleId: 100, description: "Developer" } ] | cs |
* id 값으로 한 건의 정보만 가져오기
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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | package kr.or.connect.webapiexam.api; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.fasterxml.jackson.databind.ObjectMapper; import kr.or.connect.jdbcexam.dao.RoleDao; import kr.or.connect.jdbcexam.dto.Role; @WebServlet("/roles/*") //path가 roles로 시작하지만, 어떤 문자든 모든 올 수 있다는 뜻. public class RoleByIdServlet extends HttpServlet { private static final long serialVersionUID = 1L; public RoleByIdServlet() { super(); // TODO Auto-generated constructor stub } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setCharacterEncoding("utf-8"); response.setContentType("application/json"); String pathInfo = request.getPathInfo(); // /roles/{roleId} String[] pathParts = pathInfo.split("/"); String idStr = pathParts[1]; //{roleId} 부분이 들어간다. int id = Integer.parseInt(idStr); //int로 바꿔준다. RoleDao dao = new RoleDao(); Role role = dao.getRole(id); //roleId에 대한 정보 한 건을 읽어온다. ObjectMapper objectMapper = new ObjectMapper(); String json = objectMapper.writeValueAsString(role); PrintWriter out = response.getWriter(); out.println(json); out.close(); } } | cs |
=> 이렇게 Servlet으로 Web API를 만드는 것은 조금 번거로운데 그래서 만들어진 것이 스프링 프레임워크이다.
'BoostCource > Back-end' 카테고리의 다른 글
#03. BE - xml파일을 이용하여 의존성주입 설정하기 (0) | 2018.08.02 |
---|---|
#03. BE - Spring Framework 기초 (0) | 2018.07.20 |
#02. BE - Rest API (0) | 2018.07.18 |
#02. BE - JDBC (0) | 2018.07.17 |
#02. BE - Maven으로 프로젝트 만들기 (0) | 2018.07.15 |