* 2번의 Form 클래스, 5번의 vo는 Form 등록 구현 시에만 해당함
이외의 CRUD 작업에서는 생략 가능
<!-- 첨부파일 있을 땐 꼭 enctype="multipart/form-data" 설정 -->
<form class="border bg-light p-3" method="post" action="create" enctype="multipart/form-data">
<div class="form-group mb-3">
<label class="form-label">상품명</label>
<input type="text" class="form-control" name="name" />
</div>
<div class="form-group mb-3">
<label class="form-label">상품가격</label>
<input type="text" class="form-control" name="price" />
</div>
<div class="form-group mb-3">
<label class="form-label">입고수량</label>
<input type="text" class="form-control" name="stock" />
</div>
<div class="form-group mb-3">
<label class="form-label">상품사진</label>
<input type="file" class="form-control" name="photofile" />
</div>
<div class="form-group mb-3">
<label class="form-label">상품설명</label>
<textarea rows="5" class="form-control" name="description"></textarea>
</div>
<div class="text-end">
<button type="submit" class="btn btn-primary">등록</button>
</div>
</form>
@Getter
@Setter
@ToString
public class ProductCreateForm {
private String name;
private int price;
private int stock;
private MultipartFile photofile; // MultipartFile : 스프링에서 첨부파일 업로드를 지원하는 API
private String description;
}
요청핸들러 메서드명
은@Controller
@RequestMapping("/product")
public class ProductController {
@Autowired // 객체 찾아서 넣어줌 (객체 생성 X)
private ProductService productService;
// Form객체를 매개변수로 사용하는 요청핸들러 메서드
@PostMapping("/create")
public String create(ProductCreateForm productCreateForm) {
productService.createProduct(productCreateForm);
return "redirect:list";
}
}
Builder의 메서드 체이닝
을 이용해 전달받은 값을 vo객체에 옮겨주기@Service
public class ProductService {
@Autowired
private ProductMapper productMapper;
/**
* ProductCreateForm 객체를 전달받아서 신규 상품으로 등록한다.
* @param form 신규 상품정보가 포함된 ProductCreateForm 객체
*/
public void createProduct(ProductCreateForm form) {
// ProductCreateForm 객체에 저장된 값으로 Product 객체를 생성하고, 초기화한다.
Product product = Product.builder()
.name(form.getName())
.description(form.getDescription())
.price(form.getPrice())
.stock(form.getStock())
.build();
productMapper.insertProduct(product);
}
}
@NoArgsConstructor
@Getter
@Setter
@ToString
public class Product {
private int no;
private String name;
private String description;
private int stock;
private String status;
private int price;
private String filename;
private Date updatedDate;
private Date createdDate;
@Builder
public Product(int no, String name, String description, int stock, String status, int price, String filename,
Date updatedDate, Date createdDate) {
super();
this.no = no;
this.name = name;
this.description = description;
this.stock = stock;
this.status = status;
this.price = price;
this.filename = filename;
this.updatedDate = updatedDate;
this.createdDate = createdDate;
}
}
@Mapper
public interface ProductMapper {
void insertProduct(Product product);
}
<mapper namespace="com.sample.mapper.ProductMapper">
<insert id="insertProduct" parameterType="com.sample.vo.Product">
insert into shop_products
(product_no, product_name, product_description, product_stock, product_price)
values
(products_seq.nextval, #{name}, #{description}, #{stock}, #{price})
</insert>
</mapper>
---------> 탐색(호출)
┍ HandlerAdapter ┑ ┍ MapperProxy ┑
DispatcherServlet ---> Controller ---> Service ---> Mapper
└ HandlerMapping ┘
<--------- 값 전달(매개변수를 통해)
DispatcherServlet <--- Controller <--- Service <--- Mapper
└ Model 객체 생성 ┘
└ ViewResolver ┘ └ ModelAndView ┘
위 과정을 거쳐 DispatcherServlet이 View를 실행해
Model에 저장된 정보를 요청객체의 속성으로 저장하고 JSP로 내부이동하게 된다.
최종적으로 JSP에서 EL, JSTL을 통해 값을 획득할 수 있다.
SpringShopApplication.java의 메인 메서드가 실행된다.
SpringShopApplication.run() 메서드가 실행되어 스프링 컨테이너를 생성한다.
SpringShopApplication.java가 위치한 com.sample 패키지 및 그 하위 패키지에서 스캔할 클래스를 찾는다.
MainController.java, ProductController.java, ProductSerivce.java 클래스를 스캔해서 객체를 생성하고 스프링 컨테이너의 빈으로 등록한다.
의존성 자동주입을 위해서 스프링 컨테이너에 등록된 빈들의 어노테이션을 분석한다.
ProductController 객체는
@Autowired
private ProductService productService
로 자동의존성 주입을 요구한다.
스프링 컨테이너는 등록된 빈들 중에서 ProductService 타입의 객체를 찾는다.
4번에서 등록된 빈 중에서 ProductService 객체를 찾아서
ProductController의 멤버변수 productService에 주입한다.