의존성이란 어떤 객체가 생성되기 위해 다른 객체가 꼭 필요한 상태를 의미합니다. 의존성은 new 연산자를 통해 발생합니다. 의존성이 높아지면 결합도 또한 높아집니다.
결합도가 높으면 해당 클래스를 수정할 경우 참조하고 있는 다른 클래스도 함께 이해해야합니다. 왜냐하면 무작정 수정했다가는 사이드 이펙트가 발생할 수 있기 때문입니다.
그리고 결합도가 높은 클래스는 재사용하기 힘듭니다.
1) 의존성 예제
public class Windows {
public void booting() {
System.out.println("Windows booting !");
}
}
public class Computer {
private Windows os;
public Computer() {
this.os = new Windows();
}
public void booting() {
os.booting();
}
}
Computer 클래스가 Windows 클래스를 참조하고 있는 상태입니다.
만약 Mac, Linux 등 다양한 OS 객체를 전달 받으려면 소스를 수정해야합니다. 이는 코드의 유연성을 떨어트리고 중복 소스가 생기며 가독성 또한 떨어트리는 원인이 됩니다.
이러한 문제를 해결하기 위한 방법 중 하나는 바로 의존성 역전(Dependency Injection)을 이용하는 방법입니다.
2) 의존성 주입(Dependency Injection) 예제
public interface OS {
public void booting();
}
public class Windows implements OS {
@Override
public void booting() {
System.out.println("Windows booting !");
}
}
public class Linux implements OS {
@Override
public void booting() {
System.out.println("Linux booting !");
}
}
public class Computer {
private OS os;
//외부에서 객체를 주입받는다.
public Computer(OS os) {
this.os = os;
}
public void booting() {
os.booting();
}
}
public class Main {
public static void main(String[] args) {
OS windows = new Windows();
Computer windowsComputer = new Computer(windows);
OS linux = new Linux();
Computer linuxComputer = new Computer(linux);
windowsComputer.booting();
linuxComputer.booting();
}
}
단순히 생성자를 통해 외부에서 객체를 전달받았다고 의존성 주입이라고 하지 않습니다. 만약 Windows 객체를 생성자로 주입받았다면, 외부로 부터 객체를 주입받았지만, 결합도가 낮아졌다고 할 수 없습니다. 이전에 존재했던 문제를 똑같이 안고 가는 것 입니다.
제대로 된 의존성 주입을 하려면 추상화된 객체를 외부에서 주입 받아야 합니다. Computer 클래스의 생성자는 외부에서 생성된 객체(OS 인터페이스를 구현한 객체)를 전달 받습니다. Windows 객체를 전달 받았을 때보다 결합도가 낮아 졌으며, OS가 새로 추가되더라도 Computer 클래스는 수정하지 않아도 됩니다.
2. 의존성 주입이란?
의존성 주입이란 추상화된 객체를 외부에서 주입받는 것을 의미합니다. (ex : OS 인터페이스를 구현한 Windows 또는 Linux)
key=value 형식으로 전달된 파라미터를 매핑하는 어노테이션입니다. 파라미터 전달 시 content-type은 application/x-www-form-urlencoded; charset=UTF-8;으로 해주어야합니다. Get 방식으로 전달 할 경우 url 맨 뒤에 ?key=value 형식으로 전달되고, Post 방식일 경우 Body를 통해 전달됩니다.
@PostMapping("/RequestParam")
@ResponseBody
public String requestParam(
// form의 input 배열을 받을 때도 아래와 같이 사용한다. ex) checkbox, multiselectbox
@RequestParam(required = false, value = "arr") List<Integer> arr
) {
return "success";
}
3. @ModelAttribute
key=value 형식으로 전달된 파라미터를 매핑하는 어노테이션입니다. 파라미터 전달 시 content-type은 application/x-www-form-urlencoded; charset=UTF-8;으로 해주어야합니다. @RequestParam은 변수 한개씩 매핑하는 반면에 @ModelAttribute는 Object를 통해 한번에 받을 수 있습니다. Object의 setter와 getter를 필수로 만들어주어야 합니다.
public class Member {
private Integer id;
private String name;
private String description;
private String address;
private boolean active;
private List<Integer> arr;
//setter,getter 생략
}
$(document).ready(function () {
$("#saveBtn").click(function () {
var formData = new FormData();
//formData란 <form> 태그를 객체화한 것을 의미한다.
//formData.append(key, value)를 이용해 데이터를 삽입할 수 있다.
//form 태그 내에 input 태그를 사용한 것과 동일하다.
var files = $("#files")[0].files; //선택한 파일리스트를 가져온다.
for (var index = 0; index < files.length; index++) {
formData.append(`files[${index}].file`, files[index]);
formData.append(`files[${index}].id`, index + 1);
}
//formData의 file key값을 files[0,1..].file 형식으로 지정한다.
$.ajax({
type: "POST",
data: formData,
dataType: 'json',
processData: false,
contentType: false,
success: function (data) {
alert("completed!");
},
error : function(){
alert("failed! ")
}
});
});
});
processData가 false인 경우 formData를 QueryString으로 변환하지 않는다. contentType이 false인 경우 contentType이 아래와 같이 설정된다. multipart/form-data; boundary=----WebKitFormBoundaryzS65BXVvgmggfL5A
@Controller
class FileUploadController{
@GetMapping(value = "/fileUpload")
public String fileUploadPage() {
return "page/fileUpload";
}
@ResponseBody
@PostMapping(value = "/fileUpload")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void fileUpload(FileFormTO fileFormTO) {
fileFormTO.getFiles().forEach(fileData -> {
logger.info("{} {}", fileData, fileData.getFile().getOriginalFilename());
});
//file save Logic
}
}
3. FileTO
public class FileTO {
private Integer id;
private boolean deleted = false;
private MultipartFile file;
//setter, getter, toString 생략
}
파일 객체를 정의한다.
4. FileFormTO
public class FileFormTO {
private List<FileTO> files;
//setter, getter 생략
}