BoostCource/Back-end

#02. BE - Web API

칸타탓 2018. 7. 18. 01:20

<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