Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#30 [FEAT] IoT 기기 제어 명령 API #40

Merged
merged 9 commits into from
Nov 20, 2024
1 change: 1 addition & 0 deletions server/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
runtimeOnly 'mysql:mysql-connector-java:8.0.33'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
Expand Down
22 changes: 22 additions & 0 deletions server/src/main/java/org/cecd/server/common/BaseTimeEntity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.cecd.server.common;

import jakarta.persistence.Column;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.MappedSuperclass;
import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.LocalDateTime;

@Getter
@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
public abstract class BaseTimeEntity {
@CreatedDate
@Column(updatable = false)
private LocalDateTime createdAt;
@LastModifiedDate
private LocalDateTime modifiedAt;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.cecd.server.controller;

import lombok.RequiredArgsConstructor;
import org.cecd.server.dto.CommandRequest;
import org.cecd.server.service.CommandService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping
@RequiredArgsConstructor
public class CommandController {

private final CommandService commandService;

@PostMapping("/control")
public ResponseEntity<String> sendControlCommand(@RequestBody CommandRequest commandRequest) {
String result = commandService.forwardToAgent(commandRequest);
return ResponseEntity.ok(result);
}

@PostMapping("/command")
public ResponseEntity<CommandRequest> echoControlCommand(@RequestBody CommandRequest commandRequest) {
return ResponseEntity.ok(commandRequest);
}
}
26 changes: 26 additions & 0 deletions server/src/main/java/org/cecd/server/domain/Command.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.cecd.server.domain;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.cecd.server.common.BaseTimeEntity;

@Getter
@Setter
@NoArgsConstructor
@Entity
public class Command extends BaseTimeEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "command_id")
private Long commandId;

@Column(nullable = false)
private String sensorId;

@Column(nullable = false)
private boolean command; // true : ON, false : OFF

}
12 changes: 12 additions & 0 deletions server/src/main/java/org/cecd/server/dto/CommandRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.cecd.server.dto;

import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;

@Getter
@Setter
public class CommandRequest {
private String sensorId;
private boolean command;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.cecd.server.repository;

import org.cecd.server.domain.Command;
import org.springframework.data.jpa.repository.JpaRepository;

public interface CommandRepository extends JpaRepository<Command, Long> {
}
20 changes: 20 additions & 0 deletions server/src/main/java/org/cecd/server/service/CommandService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.cecd.server.service;

import lombok.RequiredArgsConstructor;
import org.cecd.server.dto.CommandRequest;
import org.cecd.server.utils.AgentClient;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class CommandService {

private final AgentClient agentClient;

public String forwardToAgent(CommandRequest commandRequest) {
// agent로 POST 요청
return agentClient.sendCommand(commandRequest);
}

}

32 changes: 32 additions & 0 deletions server/src/main/java/org/cecd/server/utils/AgentClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.cecd.server.utils;

import lombok.RequiredArgsConstructor;
import org.cecd.server.dto.CommandRequest;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

@Component
@RequiredArgsConstructor
public class AgentClient {

private final RestTemplate restTemplate = new RestTemplate();
private static final String AGENT_URL = /*agent-server-ip*/ "http://192.168.0.113:3000/control";

public String sendCommand(CommandRequest commandRequest) {

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);

HttpEntity<CommandRequest> request = new HttpEntity<>(commandRequest, headers);

try {
restTemplate.postForEntity(AGENT_URL, request, String.class);
return "Command sent successfully!";
} catch (Exception e) {
return "Failed to send command: " + e.getMessage();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package org.cecd.server.controller;

import org.cecd.server.dto.CommandRequest;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;

import static org.assertj.core.api.Assertions.assertThat;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class CommandControllerTest {

@Autowired
private TestRestTemplate restTemplate;

@Test
void sendControlCommand() {

// 요청 데이터 생성
CommandRequest commandRequest = new CommandRequest();
commandRequest.setSensorId("000100010000000093");
commandRequest.setCommand(true);

HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json");

HttpEntity<CommandRequest> request = new HttpEntity<>(commandRequest, headers);

// 테스트용 엔드포인트로 POST 요청 전송
ResponseEntity<String> response = restTemplate.exchange(
"/command",
HttpMethod.POST,
request,
String.class
);

// 응답 검증
assertThat(response.getStatusCodeValue()).isEqualTo(200); // 상태 코드 검증
assertThat(response.getBody()).contains("Command sent successfully"); // 응답 메시지 검증
}
}
Loading