내일배움캠프 D+58: 0614 🐢

enyo9rt·2022년 6월 14일

TIL-S

목록 보기
39/79

🌌 실시간 강의

네이버 지역 검색 API를 이용하여 맛집을 검색하고 위시 리스트에 추가한다.

ModelAndView 객체를 사용해서 페이지를 로딩하는데, 타임리프를 종속성에서 빼먹어서 404가 떠서 식겁했다ㅎㅎ...
외부 API 사용하는 것도 정말 쉽지가 않다.
map형태로 저장하기, 설정값 변수로 가져오기, db 생성하기 등을 배울 수 있던 시간이었다.


🍃 Spring 심화반

람다를 배울 때 스프링부트로 페이징하면 편하게 할 수 있다고 하셨는데 이번에 페이징을 배우게 됐다.
별 다른 설정을 하지 않고도 Page 클래스가 다 알아서 해준다!
size는 한 페이지에 가져올 상품의 수를 의미한다.

//Controller
    // 로그인한 회원이 등록한 상품들 조회
    @GetMapping("/api/products")
    public Page<Product> getProducts(
            @RequestParam("page") int page,
            @RequestParam("size") int size,
            @RequestParam("sortBy") String sortBy,
            @RequestParam("isAsc") boolean isAsc,
            @AuthenticationPrincipal UserDetailsImpl userDetails
    ) {
        Long userId = userDetails.getUser().getId();
        page = page - 1;
        return productService.getProducts(userId, page , size, sortBy, isAsc);
    }
    // (관리자용) 등록된 모든 상품 목록 조회
    @Secured("ROLE_ADMIN")
    @GetMapping("/api/admin/products")
    public Page<Product> getAllProducts(
        @RequestParam("page") int page,
        @RequestParam("size") int size,
        @RequestParam("sortBy") String sortBy,
        @RequestParam("isAsc") boolean isAsc
    ) {
        return productService.getAllProducts(page , size, sortBy, isAsc);
    }
}

// Service
    public Page<Product> getProducts(Long userId, int page, int size, String sortBy, boolean isAsc) {
        Sort.Direction direction = isAsc ? Sort.Direction.ASC : Sort.Direction.DESC;
        Sort sort = Sort.by(direction, sortBy);
        Pageable pageable = PageRequest.of(page, size, sort);

        return productRepository.findAllByUserId(userId, pageable);
    }
    // 모든 상품 조회 (관리자용)
    public Page<Product> getAllProducts(int page, int size, String sortBy, boolean isAsc) {
        Sort.Direction direction = isAsc ? Sort.Direction.ASC : Sort.Direction.DESC;
        Sort sort = Sort.by(direction, sortBy);
        Pageable pageable = PageRequest.of(page, size, sort);

        return productRepository.findAll(pageable);
    }
}

//Repository
public interface ProductRepository extends JpaRepository<Product, Long> {
    Page<Product> findAllByUserId(Long userId, Pageable pageable);
}

그 때는 프론트 쪽도 신경써서 했는데 이번에는 서버쪽만 만드는 거라 더 이해가 수월했다.
프론트 쪽도 pagenation으로 간단하게 처리하는 듯하다.

    var sorting = $("#sorting option:selected").val();
    var isAsc = $(':radio[name="isAsc"]:checked').val();
    console.log(sorting, isAsc);

    $('#pagination').pagination({
        dataSource: isAdmin ? `/api/admin/products?sortBy=${sorting}&isAsc=${isAsc}` : `/api/products?sortBy=${sorting}&isAsc=${isAsc}`,
        locator: 'content',
        alias: {
            pageNumber: 'page',
            pageSize: 'size'
        },
        totalNumberLocator: (response) => {
            return response.totalElements;
        },
        pageSize: 10,
        showPrevious: true,
        showNext: true,
        ajax: {
            beforeSend: function() {
                $('#product-container').html('상품 불러오는 중...');
            }
        },
        callback: function(data, pagination) {
            $('#product-container').empty();
            for (let i = 0; i < data.length; i++) {
                let product = data[i];
                let tempHtml = addProductItem(product);
                $('#product-container').append(tempHtml);
            }
        }
    });

그리고 테스트를 위해 데이터를 넣어주고 h2 db 데이터를 파일화하는 방식으로 앞으로의 테스트를 더 편리하게 할 수 있을 것 같다!

▶ 영속성 컨텍스트(entity context)
영속성 컨텐스트란 엔티티를 영구 저장하는 환경이라는 뜻이다. 애플리케이션과 데이터베이스 사이에서 객체를 보관하는 가상의 데이터베이스 같은 역할을 한다. 출처

  • JPA: java에서 사용되는 ORM. 객체와 DB 사이의 통역 역할을 한다.
    • 객체 --- ORM --- DB
    • 객체 --- 영속성 컨텍스트 매니저 (Entity Context Manager) --- DB

이 영속성 컨텍스트 매니저가 영속성 컨텍스트를 관리하게 된다.
디버그 모드로 테스트 코드에 브레이킹 포인트를 걸어서 차례차례 실행했더니 find로 찾아오는 객체가 매번 달랐다.

그러나 스프링으로 실행하니 같은 주소를 가져오는 것을 볼 수 있었다.

찾아와서 삭제할 때는 영속성 컨텍스트와 원본 db 모두 삭제되지만 객체 자체에는 남아있다.

이렇게 영속성 컨텍스트에서는 '1차 캐시'를 사용해 객체 1개로 사용되는 것(동일성)을 보장한다.

find로 객체에 넣어준 후 값을 변경한 뒤 DB를 확인해보면 값이 그대로인 것을 볼 수 있다.
@Transactional 어노테이션을 추가(Dirty Check로 알아서 저장)해주거나 save로 영속성 컨텍스트에 저장해 주어야 한다.
Dirty Check: 함수가 끝나는 시점에 변경 부분을 알아서 업데이트하는 것


🐢 스터디

<인터페이스, 추상 클래스>

예제1: 동물

abstract class Animal {
	String name;
	int age;
	String howling;
	
	Animal(String name, int age) {
		this.name = name;
		this.age = age;
	}
	
	void howl() {
		System.out.println(this.howling+" 내 이름은 "+ this.name +", " +
				age+"살 이다옹!");
	}
	abstract void charming();
}

class Cat extends Animal {
	Cat(String name, int age) {
		super(name, age);
		this.howling = "야옹";
	}
	@Override
	void charming() {
		System.out.println("부비부비");
	}
}

class Dog extends Animal {
	Dog(String name, int age) {
		super(name, age);
		this.howling = "멍멍";
	}
	
	@Override
	void charming() {
		System.out.println("발라당");
	}
	
}

public class Prac {
	public static void main(String[] args) {
		Animal cat = new Cat("나비", 3);
		Animal dog = new Dog("바둑이", 5);
		Animal[] animals = {cat, dog};
		for (Animal animal:animals) {
			if(animal instanceof Cat)	((Cat)animal).howl();
			if(animal instanceof Dog)	((Dog)animal).howl();
			animal.charming();
		}
	}
}

ㅋㅋ문제가 귀엽다

예제2: 사각형, 삼각형 넓이

abstract class Figure {
	abstract void area(int a, int b);
}

class Rect extends Figure {
	@Override
	void area(int a, int b) {
		System.out.println("사각형의 넓이는 "+ (a*b)+"입니다.");
	}
}
class Tri extends Figure {
	@Override
	void area(int a, int b) {
		System.out.println("삼각형의 넓이는 "+ (a*b/2)+"입니다.");
	}
}

public class Prac {
	public static void main(String[] args) {
		Figure rect = new Rect();
		Figure tri = new Tri();
		rect.area(2,2);
		tri.area(10,10);
		Figure[] figures = {rect, tri};
		System.out.println("두 수를 입력해 주세요.");
		Scanner sc = new Scanner(System.in);
		int a = sc.nextInt();
		int b = sc.nextInt();
	  for (Figure figure : figures) {
			figure.area(a,b);
	  }
	}
}

예제3: 택시 요금

public interface Meter {
 public abstract void start();
 public abstract int stop(int distance);
}
---------------------------------------------
public class Taxi implements Meter {
 public int Base_Fare = 4000; // 원래는 static 달고 Meter에 선언했는데 메인에서 변경하기 위해 Taxi 클래스 내로 옮김
 
 @Override
 public void start() {
  System.out.println("운행을 시작합니다.");
 }
 
 @Override
 public int stop(int distance) {
  int fare = Base_Fare + distance * 2;
  System.out.println("운행을 종료합니다. 요금은 "+fare+"원입니다.");
  return fare;
 }
}
---------------------------------------------
public class MeterExam {
 
 public static void main(String[] args) {
  Taxi taxi = new Taxi();
  taxi.Base_Fare = 4200;
  taxi.start();
  System.out.println("거리를 입력하세요.");
  Scanner scanner = new Scanner(System.in);
  int distance = scanner.nextInt();
  if(distance <= 0 ) throw new IllegalArgumentException("1보다 작은 값은 입력할 수 없습니다..");
  try {
   taxi.stop(distance);
  } catch (Exception e) {
   e.getMessage();
  }
 }
}

퀴즈: Auto Car

interface Operatorcar {
 void start();
 void stop();
 void setSpeed(int speed);
 void turn(int degree);
}

class AutoCar implements Operatorcar {
 
 @Override
 public void start() {
  System.out.println("자동차가 출발합니다.");
 }
 
 @Override
 public void stop() {
  System.out.println("자동차가 정지합니다.");
  
 }
 
 @Override
 public void setSpeed(int speed) {
  System.out.println("자동차가 속도를 "+speed+"km/h로 바꿉니다.");
  
 }
 
 @Override
 public void turn(int degree) {
  System.out.println("자동차가 방향을 "+degree+"도만큼 바꿉니다.");
  
 }
}

public class Prac {
 public static void main(String[] args) {
  Operatorcar obj = new AutoCar();
  obj.start();
  obj.setSpeed(30);
  obj.turn(30);
  obj.stop();
 }
}

SAVE 💾

스프링 강의에서 일대다, 다대일 관계를 형성하는 부분이 나왔다. 의도치 않은 예습을 했다..
디버그 모드가 낯설었는데 강의에서 써보면서 더욱 친숙해진 느낌이다.
서블릿에 대한 지식의 필요성을 느껴서 공부해야겠다는 생각이 든다.

0개의 댓글