Spring makes it easy to create Java enterprise applications
(spring document) : https://docs.spring.io/spring-framework/docs/current/reference/html/overview.html#overview
스프링을 통해서 자바 엔터프라이즈 애플리케이션을 쉽게 만들수 있다.
👆 IOC와 DI를 통해 재사용 및 유지보수가 용이하고 높은 확장성을 가짐
✌ 개발자는 비즈니스 로직에만 집중하여 생산성 향상시킴
📌IOC(Inversion of control) : 제어의 역전
말 그대로 메소드나 객체의 호출이 개발자가 아닌 외부에서 결정된다.
✔ 즉 개발자는 프레임워크에 필요한 부품을 개발하고 조립하면 프레임워크가 최종 호출을 하게 되는 것이다.
📌DI(Dependency Injection) : 의존성 주입
IOC가 일어날 때 객체간의 관계를 관리하는 것으로
✔ 의존적인 객체를 직접 생성하거나 제어하는 것이 아닌 특정객체에 필요한 객체를 외부에서 결정해 연결 시켜주는 것이다.
dependency 같은 경우 groupID, artifactId, version까지 일일이 다 걸어주어야 함
또한 thymeleaf 같은 템플릿 엔진을 사용에도 bean 설정 등 많은 세팅이 요구됨.
외부에서 서버를 띄우기 위한 tomcat등을 설치하는데도 시간이 소요됨.
👉 즉 기본 프로젝트 세팅에 많은 시간이 허비된는 것
Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can "just run".
(spring boot document) : https://spring.io/projects/spring-boot
쉽게, 단독적으로, 상용화수준의 스프링 기반 애플리케이션을 만들수 있다.
"just run"
👆 Auto Configuration을 통한 간편한 설정
✌ 쉬운 의존성 관리 & 자동 권장 버전 관리
🤟 내장 서버로 인한 간단한 서버 배포 구축
🖖 Spring Security, JPA 등 다른 프레임워크 요소를 쉽게 사용 가능
JSP 같은 경우 서블릿 형태로 변환되는데 서블릿도 자바 코드다 보니 JSP안에 자바코드가 포함되는 일종의 짬뽕(?)이 되기 쉽다.
👉 thymeleaf 같은 경우 필요한 정보를 태그의 속성값으로 넣고 뺄수 있고,
웹 서버를 띄우지 않고도 페이지의 생성 및 수정등이 가능하다는 장점이 있다.
또한 스프링과의 통합이 쉽다는 장점이 있다.
📌 JDBC는 자바 진영의 DB표준 인터페이스로써
우리가 사용하는 API를 변경하지 않고도 DriverManager을 통해 MySQL이든 ORCLE이든 갈아끼우면 작동 됨.
👉 SQL Query 하나당 많은 객체들의 중복 코드가 발생함.
👉 종료 될 때마다 연결을 끊어주는 등의 커넥션 관리를 해줘야 함.
MyBatis is a first class persistence framework with support for custom SQL
(MyBtis documnet : https://mybatis.org/mybatis-3/)
📌 자바의 관계형 데이터베이스 프로그래밍을 좀 더 쉽게 할 수 있게 도와 주는 프레임 워크
Configuration된 SessionFactory에서 SQLSession을 통해 데이터를 주고 받는다.
👆 복잡한 JDBC 코드를 없앰.
✌ Query를 Java XML파일로 SQL을 분리함.
🤟 ResultSet과 같은 결과값을 매핑하는 객체가 없음.
🎯 MVC 패턴 사용시에 일부 컨트롤러 부분에서 비즈니스로직을 처리한 점
@PostMapping("/product/{productId}/edit")
public String editProduct(@PathVariable int productId, @RequestParam String selected, @ModelAttribute("product") ProductSaveForm form,
BindingResult bindingResult) throws IOException {
if (bindingResult.hasErrors()) return "products/editProduct";
//~~생략~~//
// 변동된 이미지가 없었을 경우 -> 기존의 이미지를 가져옴
if (imageFile == null){
UploadFile image = productService.findImage(productId);
updateProduct.setProductImage(image);
}else {
updateProduct.setProductImage(imageFile);
}
productService.updateProduct(updateProduct);
return "redirect:/product/{productId}";
}
📃 상품 수정 부분에서 수정된 값들을 서비스로 넘겨주기 전에 변동된 이미지가 없을경우 현재 이미지를 가져오는 등의 분리 미흡
🎯 중복된 로직에 대해 일부 리팩토링 하였지만 부족한 점 ->
@GetMapping("/products/{category}")
public String productsByCategory(@SessionAttribute(name = SessionConst.LOGIN_MEMBER, required = false) Member loginMember,
Model model, @ModelAttribute("cri") Criteria cri, @PathVariable String category){
//~~생략~~//
}
@GetMapping("/products/{category}/{page}")
public String paging(@SessionAttribute(name = SessionConst.LOGIN_MEMBER, required = false) Member loginMember,
Model model, @PathVariable String category, @PathVariable int page){
Criteria cri = new Criteria();
cri.setPageNum(page);
//~~생략~~//
}
📃 전체 상품 목록을 보여주는 부분에서 카테고리 분리 및 페이징 처리를 한번에 할 수 있었지만 분리하여 사용함으로써 중복 코드 발생
🎯 타임리프 문법 이해 부족 ->
<div th:each="num,index : ${#numbers.sequence(pageMake.getStartPage(),pageMake.getEndPage())}">
<button class="btn" style="border: 0; outline: 0;">
<span class="badge bg-white text-black ms-1 rounded-pill">
<a th:href="@{/products/{category}/{page}(category=${products[0].category}, page=${index.current})}" th:text="${num}" style="text-decoration: none; color: black;">1</a>
</span>
</button>
</div>
📃 페이징 처리시에 thymeleaf에서 #numbers.sequence로 시작, 끝 페이지를 가져오는 것과 index.current로 현재 값을 가져올수 있다는 점