1 / 35

Spring 4 기반의 RESTful Web Service 구현

Spring 4 기반의 RESTful Web Service 구현. Oct. 2015 Youn-Hee Han LINK@KOREATECH http://link.koreatech.ac.kr. RESTful Server. Spring 프로젝트 내 pom.xml 수정. REST Web Service 구현을 위한 pom.xml 수정 객체를 XML/JSON 로 변환하거나 그 역변환을 위한 라이브러리 ( 의존성 ) 추가. … <!-- XML and JSON -->

balkire
Download Presentation

Spring 4 기반의 RESTful Web Service 구현

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Spring 4 기반의 RESTful Web Service 구현 Oct. 2015 Youn-Hee Han LINK@KOREATECH http://link.koreatech.ac.kr

  2. RESTful Server LINK@KOREATECH

  3. Spring 프로젝트 내 pom.xml 수정 • REST Web Service 구현을 위한 pom.xml 수정 • 객체를 XML/JSON로 변환하거나 그 역변환을 위한 라이브러리(의존성) 추가 … <!-- XML and JSON --> <dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> <version>2.6.2</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.6.2</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.6.2</version> </dependency> </dependencies> LINK@KOREATECH

  4. Resource 정보구축 • 온도 센서 정보를 Resource로 활용 • MySQL 활용 • Temperature 테이블 내 다음과 같은 정보 저장 온도 센서 HTTP Reqeuest HTTP Response 온도 자원을 구축하고 있는 자원 서버 + 웹 서비스 Server 구축 (Spring 기반) 온도 자원을 활용하는웹 서비스 Client LINK@KOREATECH

  5. Resource 정보구축 • 온도 센서 정보를 Resource로 활용 • 현재 사용중인 DB 스키마 (예: wsc)에 Temperature 테이블 생성및 가상 온도 정보 입력 • 프로젝트 소스 내 다음 파일 참고 • src/main/resources/common/rest.sql DROP TABLE IF EXISTS `temperature`; CREATE TABLE `temperature` ( `ID` int(32) unsigned NOT NULL AUTO_INCREMENT, `sensor_id` varchar(45) NOT NULL, `temperature` float NOT NULL, `datetime` datetime NOT NULL, `location` varchar(500) NOT NULL, PRIMARY KEY (`ID`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; INSERT INTO `temperature` VALUES (1, 'temp1', 32.4, '2015-05-15 08:18:24', '1st Floor, 4th Engineering Building, KoreaTech'), (2, 'temp2', 34.9, '2015-05-16 08:10:54', '3st Floor, 2th Engineering Building, KoreaTech'); LINK@KOREATECH

  6. Domain 객체 클래스 구성 • Temperature 클래스 구성 • 온도 정보를 담아서 전달시킬 수 있는 기본 클래스 • 웹서비스 Server가 Client로 전달할 때 Json 포맷으로 변환됨 • 프로젝트 소스 내 다음 파일 참고 • src/main/java/koreatech/cse/domain/rest/Temperature.java package koreatech.cse.domain.rest; import java.sql.Date; public class Temperature { private int id; private String sensorId; private float temperature; private Date datetime; private String location; public int getId() { return id; } … } LINK@KOREATECH

  7. Repository 객체 클래스 구성 • MyBatis기반 TemperatureMapper 인터페이스 구성 • src/main/java/koreatech/cse/repository/rest/TemperatureMapper.java package koreatech.cse.repository.rest; … @Repository public interface TemperatureMapper { @Insert("INSERT INTO TEMPERATURE (SENSOR_ID, TEMPERATURE, DATETIME, LOCATION) VALUES (#{sensorId}, #{temperature}, #{datetime}, #{location})") @SelectKey(statement = "SELECT LAST_INSERT_ID()", keyProperty = "id", before = false, resultType = int.class) void insert(Temperature temperature); @Update("UPDATE TEMPERATURE SET TEMPERATURE = #{temperature}, DATETIME = #{datetime}, LOCATION = #{location} WHERE ID = #{id}") void update(Temperature temperature); @Select("SELECT * FROM TEMPERATURE WHERE ID = #{id}") Temperature findOne(@Param("id") int id); @Delete("DELETE FROM TEMPERATURE WHERE ID = #{id}") void delete(@Param("id") int id); @Select("SELECT * FROM TEMPERATURE WHERE SENSOR_ID = #{sensorId}") Temperature findOneBySensorId(@Param("sensorId") String sensorId); @Select("SELECT * FROM TEMPERATURE WHERE LOCATION LIKE CONCAT('%', #{location}, '%')") List<Temperature> findByLocation(@Param("location") String location); } LINK@KOREATECH

  8. RestController 구성 • Spring 4 기반의 RestController 구성 • 클래스 정의 위에 @RestController 어노테이션 지정 • 컨트롤러이므로 @RequestMapping 을 활용하여 접근 패스 지정 • {Context Root}/thermometer • 이전에 생성한 Repository 객체를 @Inject 로 주입받음 • 프로젝트 소스 내 다음 파일 참조 • src/main/java/koreatech/cse/controller/rest/ TemperatureRestController.java package koreatech.cse.controller.rest; …@RestController@RequestMapping("/thermometer")public class TemperatureRestController {@Inject private TemperatureMapper temperatureMapper; … } LINK@KOREATECH

  9. RestController 구성 • GET 서비스 – 1 • Path: {Context Root}/thermometer/temperature/{sensorId} • 센서 아이디를 받아서 해당 센서의 센싱 정보를 JSON 포맷으로 전달 • 서비스 요청 예 • http://localhost:8080/thermometer/temperature/temp1 • 센서 ID에 해당하는 ‘temp1’은 PathVariable 형태로 활용됨 @Transactional @RequestMapping(value="/temperature/{sensorId}", method=RequestMethod.GET, produces = "application/json") public ResponseEntity<Temperature> temperature(@PathVariable("sensorId") String sensorId) { Temperature temperature = temperatureMapper.findOneBySensorId(sensorId); if (temperature == null) { System.out.println("Temperature sensor with id (" + sensorId + “) is not found"); return new ResponseEntity<Temperature>(HttpStatus.NOT_FOUND); } return new ResponseEntity<Temperature>(temperature, HttpStatus.OK); } LINK@KOREATECH

  10. RestController 구성 • GET 서비스 – 2 • Path: {Context Root}/thermometer/xml/temperature/{sensorId} • 센서 아이디를 받아서 해당 센서의 센싱 정보를 XML 포맷으로 전달 • 서비스 요청 예 • http://localhost:8080/thermometer/xml/temperature/temp1 @Transactional@RequestMapping(value="/xml/temperature/{sensorId}", method=RequestMethod.GET, produces="application/xml")public ResponseEntity<Temperature> temperatureXml(@PathVariable("sensorId") String sensorId) { Temperature temperature = temperatureMapper.findOneBySensorId(sensorId); if (temperature == null) { System.out.println("Temperature sensor with id " + sensorId + " is not found"); return new ResponseEntity<Temperature>(HttpStatus.NOT_FOUND); } return new ResponseEntity<Temperature>(temperature, HttpStatus.OK);} LINK@KOREATECH

  11. RestController 구성 • GET 서비스 – 3 • Path: {Context Root}/thermometer/temperature/location/{location} • 센서 위치정보를 받아서 해당 위치정보를 지니고 있는 센서들의 센싱 정보를 JSON 포맷으로 전달 • 서비스 요청 예 • http://localhost:8080/thermometer/temperature/location/KoreaTech • 위치정보에 해당하는 ‘KoreaTech’는 PathVariable 형태로 활용됨 @Transactional @RequestMapping(value="/temperature/location/{location}", method=RequestMethod.GET, produces="application/json") public ResponseEntity<List<Temperature>> temperatureByLocation(@PathVariable("location") String location) { List<Temperature> temperatureList = temperatureMapper.findByLocation(location); if (temperatureList.size() == 0) { System.out.println("Temperature sensors with location of " + location + " are not found"); return new ResponseEntity<List<Temperature>>(HttpStatus.NOT_FOUND); } return new ResponseEntity<List<Temperature>>(temperatureList, HttpStatus.OK); } LINK@KOREATECH

  12. RestController 구성 • GET 서비스 – 4 • Path: {Context Root}/thermometer/xml/temperature/location/{location} • 센서 위치정보를 받아서 해당 위치정보를 지니고 있는 센서들의 센싱 정보를 XML 포맷으로 전달 • 서비스 요청 예 • http://localhost:8080/thermometer/xml/temperature/location/KoreaTech @Transactional@RequestMapping(value="/xml/temperature/location/{location}", method=RequestMethod.GET, produces="application/xml")public ResponseEntity<List<Temperature>> temperatureByLocationXml(@PathVariable("location") String location) { List<Temperature> temperatureList = temperatureMapper.findByLocation(location); if (temperatureList.size() == 0) { System.out.println("Temperature sensors with location of " + location + " are not found"); return new ResponseEntity<List<Temperature>>(HttpStatus.NOT_FOUND); } return new ResponseEntity<List<Temperature>>(temperatureList, HttpStatus.OK);} LINK@KOREATECH

  13. RestController 구성 • POST 서비스 (Create a Temperature Resource) • Path: {Context Root}/temperature • 새로운센서 정보를 서버의 자원으로 생성 @Transactional @RequestMapping(value = "/temperature/", method = RequestMethod.POST) public ResponseEntity<Void> createTemperature(@RequestBody Temperature temperature, UriComponentsBuilder ucBuilder) { if (temperatureMapper.findOneBySensorId(temperature.getSensorId()) != null) { System.out.println("A temperature sensor with id (" + temperature.getSensorId() + ") already exists"); return new ResponseEntity<Void>(HttpStatus.CONFLICT); } temperatureMapper.insert(temperature); HttpHeaders headers = new HttpHeaders(); headers.setLocation( ucBuilder.path("/temperature/{sensorId}").buildAndExpand(temperature.getSensorId()).toUri()); return new ResponseEntity<Void>(headers, HttpStatus.CREATED); } LINK@KOREATECH

  14. RestController 구성 • PUT 서비스 (Update a Temperature Resource) • Path: {Context Root}/temperature/{sensorId} • 기존센서 정보를 업데이트 @Transactional @RequestMapping(value = "/temperature/{sensorId}", method = RequestMethod.PUT) public ResponseEntity<Void> updateTemperature(@PathVariable("sensorId") String sensorId, @RequestBody Temperature temperature) { Temperature storedTemperature = temperatureMapper.findOneBySensorId(sensorId); if (storedTemperature == null) { System.out.println("No temperature sensor with id (" + sensorId + " not found"); return new ResponseEntity<Void>(HttpStatus.NOT_FOUND); } storedTemperature.setTemperature(temperature.getTemperature()); storedTemperature.setLocation(temperature.getLocation()); storedTemperature.setDatetime(temperature.getDatetime()); temperatureMapper.update(storedTemperature); return new ResponseEntity<Void>(HttpStatus.OK); } LINK@KOREATECH

  15. RestController 구성 • DELETE 서비스 (Delete a Temperature Resource) • Path: {Context Root}/temperature/{sensorId} • 기존센서 정보를 삭제 @Transactional @RequestMapping(value = "/temperature/{sensorId}", method = RequestMethod.DELETE) public ResponseEntity<Temperature> deleteTemperature(@PathVariable("sensorId") String sensorId) { Temperature storedTemperature = temperatureMapper.findOneBySensorId(sensorId); if (storedTemperature == null) { System.out.println("No temperature sensor with id (" + sensorId + " not found"); return new ResponseEntity<Temperature>(HttpStatus.NOT_FOUND); } temperatureMapper.delete(storedTemperature.getId()); return new ResponseEntity<Temperature>(HttpStatus.NO_CONTENT); } LINK@KOREATECH

  16. RESTful Client LINK@KOREATECH

  17. RestClient 생성 • Spring4에서 지원하는 RestTemplate 클래스 활용 • org.springframework.web.client.RestTemplate • 서버와 별개의 프로젝트로서 구성 • 콘솔창에서 임의의 폴더로 이동하여 아래 명령어 수행 • 새로운 프로젝트 폴더 (restful_client)를 IntelliJ 프로젝트로서 등록 mvn archetype:generate -DgroupId=koreatech.link -DartifactId=restful_client -Dpackage=koreatech.cse.rest.client -Dversion=1.0

  18. Spring 프로젝트 내 pom.xml 수정 • RestTemplate 활용을 위한 라이브러리(의존성) 추가 … <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>4.2.1.RELEASE</version> </dependency> </dependencies> LINK@KOREATECH

  19. Spring 프로젝트 내 pom.xml 수정 • 객체를 XML/JSON로 변환하거나 그 역변환을 위한 라이브러리(의존성) 추가 … <!-- XML and JSON --> <dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> <version>2.6.2</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.6.2</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.6.2</version> </dependency> </dependencies> LINK@KOREATECH

  20. Domain 객체 클래스 구성 • Temperature 클래스 구성 • 온도 정보를 담아서 전달시킬 수 있는 기본 클래스 • 클라이언트 프로젝트 소스 내 다음 파일 참고 • src/main/java/koreatech/cse/rest/client/domain/Temperature.java package koreatech.cse.rest.client.domain; import java.sql.Date; public class Temperature { private int id; private String sensorId; private float temperature; private Date datetime; private String location; public int getId() { return id; } … } LINK@KOREATECH

  21. Domain 객체 클래스 구성 • Temperature 클래스내에 toString() 구성 • IntelliJ의 코드 자동 생성 기능 사용 • 서버로 부터 받은 온도 정보 객체를 클라이언트에서 출력하기 위한 목적 @Override public String toString() { return "Temperature{" + "id=" + id + ", sensorId='" + sensorId + '\'' + ", temperature=" + temperature + ", datetime=" + datetime + ", location='" + location + '\'' + '}'; } } LINK@KOREATECH

  22. Domain 객체 클래스 구성 • Temperature 클래스내에 toString() 구성 • IntelliJ의 코드 자동 생성 기능 사용 • 서버로 부터 받은 온도 정보 객체를 클라이언트에서 출력하기 위한 목적 @Override public String toString() { return "Temperature{" + "id=" + id + ", sensorId='" + sensorId + '\'' + ", temperature=" + temperature + ", datetime=" + datetime + ", location='" + location + '\'' + '}'; } } LINK@KOREATECH

  23. RESTful Client – CRUD 요청 코드 • Spring 4 기반의 RestTemplate 활용 • 서버의 기본 URI 지정 package koreatech.cse.rest.client; import koreatech.cse.rest.client.domain.Temperature; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestTemplate; import java.net.URI; import java.util.Date; import java.util.List; public class App { public static final String REST_SERVICE_URI = "http://localhost:8080/thermometer"; … … } LINK@KOREATECH

  24. RESTful Client – CRUD 요청 코드 • GET 서비스 요청 – 1 private static void getTemperature() { System.out.println("Testing GET METHOD (1)----------"); RestTemplate restTemplate = new RestTemplate(); try { ResponseEntity<Temperature> temperatureResponseEntity = restTemplate.getForEntity(REST_SERVICE_URI + "/temperature/temp1", Temperature.class); Temperature temperature = temperatureResponseEntity.getBody(); System.out.println(temperature); } catch (HttpClientErrorException e) { System.out.println(e.getStatusCode() + ": " + e.getStatusText()); } } LINK@KOREATECH

  25. RESTful Client – CRUD 요청 코드 • GET 서비스 요청 – 2 private static void getTemperatureXml() { System.out.println("Testing GET METHOD (2)----------");RestTemplate restTemplate = new RestTemplate(); try { ResponseEntity<Temperature> temperatureResponseEntity = restTemplate.getForEntity(REST_SERVICE_URI + "/xml/temperature/temp1", Temperature.class); Temperature temperature = temperatureResponseEntity.getBody(); System.out.println(temperature); } catch (HttpClientErrorException e) { System.out.println(e.getStatusCode() + ": " + e.getStatusText()); } } LINK@KOREATECH

  26. RESTful Client – CRUD 요청 코드 • GET 서비스 요청 – 3 private static void getTemperatureByLocation() { System.out.println("Testing GET METHOD (3)----------"); RestTemplate restTemplate = new RestTemplate(); try { ResponseEntity<List> listResponseEntity = restTemplate.getForEntity(REST_SERVICE_URI + "/temperature/location/KoreaTech", List.class); List<Temperature> temperatureList = listResponseEntity.getBody(); for (int i = 0; i < temperatureList.size(); i++) { System.out.println(temperatureList.get(i)); } } catch (HttpClientErrorException e) { System.out.println(e.getStatusCode() + ": " + e.getStatusText()); } } LINK@KOREATECH

  27. RESTful Client – CRUD 요청 코드 • GET 서비스 요청 – 4 private static void getTemperatureByLocationXml() { System.out.println("Testing GET METHOD (4)----------"); RestTemplate restTemplate = new RestTemplate(); try { ResponseEntity<List> listResponseEntity = restTemplate.getForEntity(REST_SERVICE_URI + "/xml/temperature/location/KoreaTech", List.class); List<Temperature> temperatureList = listResponseEntity.getBody(); for (int i = 0; i < temperatureList.size(); i++) { System.out.println(temperatureList.get(i)); } } catch (HttpClientErrorException e) { System.out.println(e.getStatusCode() + ": " + e.getStatusText()); } } LINK@KOREATECH

  28. RESTful Client – CRUD 요청 코드 • POST 서비스 요청 private static void createTemperature() { System.out.println("Testing POST METHOD----------"); RestTemplate restTemplate = new RestTemplate(); Temperature temperature = new Temperature(); temperature.setSensorId("temp3"); temperature.setTemperature((float)37.0); temperature.setDatetime(new Date()); temperature.setLocation("2nd Floor, 4th Engineering Building, KoreaTech"); try { URI uri = restTemplate.postForLocation( REST_SERVICE_URI + "/temperature/", temperature, Temperature.class); System.out.println("Location : " + uri.toString()); } catch (HttpClientErrorException e) { System.out.println(e.getStatusCode() + ": " + e.getStatusText()); } } LINK@KOREATECH

  29. RESTful Client – CRUD 요청 코드 • PUT 서비스 요청 private static void updateTemperature() { System.out.println("Testing PUT METHOD----------"); RestTemplate restTemplate = new RestTemplate(); Temperature temperature = new Temperature(); temperature.setSensorId("temp1"); temperature.setTemperature((float)31.1); temperature.setDatetime(new Date()); temperature.setLocation("1st Floor, 4th Engineering Building, KoreaTech"); try { restTemplate.put(REST_SERVICE_URI + "/temperature/temp1", temperature); System.out.println("PUT METHOD - SUCCESS!"); } catch (HttpClientErrorException e) { System.out.println(e.getStatusCode() + ": " + e.getStatusText()); } } LINK@KOREATECH

  30. RESTful Client – CRUD 요청 코드 • DELETE 서비스 요청 private static void deleteTemperature() { System.out.println("Testing DELETE METHOD----------"); RestTemplate restTemplate = new RestTemplate(); try { restTemplate.delete(REST_SERVICE_URI + "/temperature/temp2"); System.out.println("DELETE METHOD - SUCCESS!"); } catch (HttpClientErrorException e) { System.out.println(e.getStatusCode() + ": " + e.getStatusText()); } } LINK@KOREATECH

  31. 크롬 앱을 활용한 Rest Client 테스트 • Advanced Rest Client 크롬 앱 활용 LINK@KOREATECH

  32. 크롬 앱을 활용한 Rest Client 테스트 • GET 요청 테스트 LINK@KOREATECH

  33. 크롬 앱을 활용한 Rest Client 테스트 • POST 요청 테스트 LINK@KOREATECH

  34. 크롬 앱을 활용한 Rest Client 테스트 • PUT 요청 테스트 LINK@KOREATECH

  35. 크롬 앱을 활용한 Rest Client 테스트 • DELETE 요청 테스트 LINK@KOREATECH

More Related