회원 목록 조회
package jpabook.jpashop.Controller;
import jpabook.jpashop.domain.Address;
import jpabook.jpashop.domain.Member;
import jpabook.jpashop.service.MemberService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import javax.validation.Valid;
import java.util.List;
@Controller
@RequiredArgsConstructor
public class MemberController {
private final MemberService memberService;
@GetMapping("/members/new")
public String createForm(Model model) {
model.addAttribute("memberForm", new MemberForm());
return "members/crateMemberForm";
} // 화면 이동 시 MemberForm 빈 껍데기 객체를 가져온다.
@PostMapping("/members/new") // @Valid를 통해 javax의 validation기능을 사용할 수 있다.
public String create(@Valid MemberForm form, BindingResult result) {
if (result.hasErrors()) {
return "members/createMemberForm";
}
Address address = new Address(form.getCity(), form.getStreet(),form.getZipcode());
Member member = new Member();
member.setName(form.getName());
member.setAddress(member.getAddress());
memberService.join(member);
return "redirect:/";
}
@GetMapping("/members")
public String list(Model model) {
List<Member> members = memberService.findMembers();
model.addAttribute("members", members);
return "members/memberList";
}
}
name, userpassword등의 멤버 변수를 객체가 가지고 있는데, 이것을 그대로 갖다 쓰면 내부에 있는 변수가 노출이 되어 API를 유지보수하기 힘들어지는 문제가 있다.
<상품 등록>
items/new
<상품 수정>
<변경 감지와 병합>
준영속 엔티티 : JPA 영속성 엔티티가 더 이상 관리하지 않는 엔티티를 의미한다.
- JPA가 아니기 때문에, 변경 감지가 불가능하다.
- 그렇다면 준영속 엔티티는 어떻게 데이터를 변경할 수 있는 것인가?
변경 감지 기능 사용
영속성 컨텍스트에서 엔티티를 다시 조회한 후에 데이터를 수정하는 방법
: 트랜잭션 안에서 엔티티를 다시 조회, 변경할 값을 선택하고 Commit 시점에 변경을 감지(Dirty Checking) 이후 데이터베이스에서 Update 쿼리를 실행한다.
병합 사용
준영속 상태의 엔티티를 영속 상태의 엔티티로 만드는 것
- 엔티티 변경 시 항상 변경 감지를 사용하는 것이 옳다.
<주문 목록과 취소 기능>
package jpabook.jpashop.Controller;
import jpabook.jpashop.domain.Member;
import jpabook.jpashop.domain.Order;
import jpabook.jpashop.domain.item.Item;
import jpabook.jpashop.service.ItemService;
import jpabook.jpashop.service.MemberService;
import jpabook.jpashop.service.OrderService;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
@Controller
@RequiredArgsConstructor
public class OrderController {
private final OrderService orderService;
private final MemberService memberService;
private final ItemService itemService;
@GetMapping("/order")
public String createForm(Model model) {
List<Member> members = memberService.findMembers();
List<Item> items = itemService.findItems();
model.addAttribute("members", members);
model.addAttribute("items", items);
return "order/orderForm";
}
@PostMapping("/order")
public String order(@RequestParam("memberId") Long memberId,
@RequestParam("itemId") Long itemId,
@RequestParam("count") int count) {
orderService.order(memberId, itemId, count);
return "redirect:/orders";
}
@GetMapping("/orders")
public String orderList(@ModelAttribute("orderSearch") OrderSearch orderSearch, Model model) {
List<Order> orders = orderService.findOrders(orderSearch);
model.addAttribute("orders", orders);
return "order/orderList";
}
}
어노테이션 정리
@ResponseBody : ViewResolver가 아닌 HttpMessageConverter가 동작하여 JSON 방식으로 데이터를 전송
@Controller : 스프링 빈이 자동 등록되는 어노테이션
+ @Component를 포함하고, 스프링 빈으로 자동 등록되는 어노테이션
: @Controller, @Service, @Repository
@RestController : MVC @Controller에 @ResponseBody가 추가된 것이다. 컨트롤러 클래스의 하위 메소드에 @ResponseBody를 붙이지 않아도 문자열과 JSON을 반환할 수 있다. (메서드마다 ResponseBody를 추가하지 않아도 된다.)
@RequestMapping 어노테이션 : URL을 매핑해준다. 즉 클래스가 동작하는 URL을 지정해준다. 클래스 뿐만 아니라 메소드 레벨에서도 사용할 수 있으나, 메소드 레벨에서 사용하는 annotation은 다음과 같다.
- @GetMapping 어노테이션 : Get방식으로 RequestMapping을 한다. 메소드에만 적용됨. 주소에 파라미터가 노출
- @PostMapping 어노테이션 : Post방식으로 RequestMapping을 한다. 주소창에 파라미터가 노출되지 않는다.
이 두 어노테이션은 RequestMapping의 축약형이라 할 수 있다. 그이유는,
@RequestMapping(value = "/getList", method = {RequestMethod.POST})
@PostMapping("/getList")
다음과 같이 코드 길이를 줄일 수 있기 때문이다.
@Autowired : 생성자에 주입하여, 컴포넌트 스캔을 이용하지 않고 스프링 빈을 주입
스프링 테스트 시 사용되는 어노테이션
@SpringBootTest : 스프링 컨테이너와 테스트를 함께 시작한다.
@Transactional : Test 시작 전에 이를 실행시키고, 테스트 완료 후에 항상 롤백 시킴 -> 디비에 데이터가 남지 않아 다음 테스트에 영향을 주지 않는다.
@Entity : 클래스를 테이블과 매핑한다고 JPA에게 알려준다. 이 어노테이션이 사용되는 클래스를 엔티티 클래스라고 한다.
@Table : 엔티티 클래스에 매핑될 테이블 정보를 알려준다. (name 속성으로 테이블을 설정) 이를 생략하면 클래스이름으로 매핑됨.
@Id : 엔티티 클래스의 PK에 매핑한다. 즉, 이 어노테이션이 사용된 필드를 식별자 필드라고 한다.
@Column : 필드를 컬럼에 매핑한다. (name 속성을 사용)
@Generated Value : 주키의 자동 생성 전력, 즉 인덱스 자동증가 역할을 한다. @Id @GeneratedValue(strategy=GenerationType.AUTO)로 작성하는 경우에!
@Repository : 해당 클래스가 Repository역할을 하는 것을 명시
@Service : 해당 클래스가 Service역할을 하는 것을 명시
'Framework > Spring' 카테고리의 다른 글
Data JPA를 이용한 상품 구매 사이트 Item 엔티티 개발 예제 (0) | 2021.09.13 |
---|---|
스프링 부트 Application 실행 시 MySQL root@localhost Access Denied 오류 해결 (0) | 2021.09.13 |
스프링 부트 JPA 활용 1 - 회원 도메인 개발 (0) | 2021.06.23 |
스프링 부트 JPA 활용 1 - 도메인 분석 설계 / 엔티티 클래스 개발 (0) | 2021.06.02 |
[스프링 입문] 스프링 빈과 의존 관계 (0) | 2021.05.25 |