본문 바로가기
주문, 주문 목록 만들기 (@ManyToOne, @OneToMany, N+1 문제) 주문을 하는 기능과 주문 목록을 저장하는 기능을 만들어보자 주문 id, 주문한 상품의 이름, 가격, 갯수와 주문한 사람의 정보를 저장했다정보는 @ManyToOne, @JoinColumn 해서 가져왔다@Entity@Getter@Setter@ToStringpublic class Sales { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column private String itemName; @Column private Integer price; @Column private Integer count; @ManyToOne @JoinColumn(name = "member_.. 2024. 5. 13.
검색 기능 - index 아이템 목록을 가져오는 기능을 만들어보자 폼에 serachText로 찾고 싶은 아이템 이름을 넘겨주고 검색 리포지토리에서는 해당 이름을 포함한 아이템들 리스트를 반환하게 해서List findAllByTitleContains(String title); 컨트롤러에서는 찾은걸 반환하게 했다@GetMapping("/search")String postSearch(@RequestParam String searchText, Model model){ List itemList = itemRepository.findAllByTitleContains(searchText); if (!itemList.isEmpty()){ model.addAttribute("items", itemList); .. 2024. 5. 8.
댓글 기능 만들기 @GetMapping("/detail/{id}") 기존에 위의 api로 상세 페이지에 접속하게 했는데상세페이지에서 댓글이 작성하게 만들어보자 댓글은 로그인한 회원만 달 수 있고, 작성자 id, 작성자 닉네임, 댓글 내용, 본문 글작성자 id 속성을 가지게 만들었다 @Entity@Getter@Setter@ToStringpublic class Comment { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column private String username; @Column private String content; @Column private Long parentId;} .. 2024. 5. 6.
S3 버킷 스프링 어플리케이션에서 사용하기 s3에 이미지 저장해서 이미지 경로를 만들어주는 S3Service를 만들었다@Service@RequiredArgsConstructorpublic class S3Service { @Value("${spring.cloud.aws.s3.bucket}") private String bucket; private final S3Presigner s3Presigner; String createPreSignedUrl(String path) { var putObjectRequest = PutObjectRequest.builder() .bucket(bucket) .key(path) .build(); .. 2024. 5. 5.
aws S3 이미지 업로드 s3 버킷을 만들어서 정책 편집 1번 정책은 누구나 읽기 가능2번 정책은 수정 삭제는 나만 가능하게 했다{ "Version": "2012-10-17", "Statement": [ { "Sid": "1", "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::hoshi03spring1/*" }, { "Sid": "2", "Effect": "Allow", "Principal": { .. 2024. 5. 5.
페이지 나누기 (pagination) 글이 500만개가 있을때 한번에 다 보여줄 수는 없다 Repository에 Pageable을 선언하고Page findPageBy(Pageable page); /list/page/1 형태로 들어오면 페이지를 가져오는 코드를 작성한다items에 담아둔 page는 html에서 반복문을 돌면서 해당하는 페이지의 아이템들을 가져올 수 있다PageRequest는 0부터 시작해서 n개를 가져오니 -1을 해줬다@GetMapping("/list/page/{id}")String getListPage(Model model, @PathVariable Integer id){ //n번째 페이지에서 m개 가져온다 Page page = itemRepository.findPageBy(PageRequest.of(id-1, 5.. 2024. 5. 5.
DTO 만들어서 데이터 보내기 특정 유저의 데이터를 보내고 싶을때 리포지토리에서 가져온 걸 그대로 보내면  비밀번호까지 보내버린다DTO를 만들어서 보내고 싶은 데이터만 보내자 • dto를 사용하면 데이터 타입체크가 쉽고 재사용성이 올라간다보내고 싶은 데이터가 다른 api가 있을때 데이터에 따른 생성자를 만들거나 하는 방식으로 유연하게 보내줄 수 있다   id와 닉네임만 전달할 dto를 만든다class MemberDto { public String username; public String displayname; MemberDto(String username, String displayname){ this.username = username; this.displayname = displaynam.. 2024. 5. 5.
스프링 시큐리티, 회원가입 기능 만들기, 외부 클래스 DI • 스프링 시큐리티 gradle에 시큐리티를 추가해서 설치한다implementation 'org.springframework.boot:spring-boot-starter-security'implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6:3.1.1.RELEASE' 스프링 시큐리티를 관리할 클래스를 생성한다//필터 체인 - 유저의 요청과 서버 응답 사이에 자동실행하고싶은 코드를 담는 것@Beanpublic SecurityFilterChain filterChain(HttpSecurity http) throws Exception { //csrf - 다른 사이트에 폼 만들어서 내 사이트로 요청을 보내는식으로 공격할수 있음 //c.. 2024. 5. 4.
세션 & 토큰 로그인한 사람만 게시물을 볼 수 있게 회원 기능을 만들어보자id/비번을 db에 저장하고 유저가 보낸 것과 일치하는지 확인 세션, 토큰 두가지 방식이 있음 세션은 세션id가 유저별로 만들어지고, 데이터베이스에 세션 id를 저장 쿠키에 저장하는 방식 세션 아이디가 일치하면 되는 방식인데, db에 부하가 심함 토큰 jwt 방식, db에 저장하지 않고 유저에게 암호화한 유저 정보를 보내고 유저가 유저 정보를 제출할때 변환, db 조회를 하지 않아 db에 부담이 적어지지만 유저 정보를 악용하기가 더 쉬움 OAuth - 유저의 정보를 다른 사이트에서 사용 가능하게 구현소셜 로그인같은 기능을 만들때 사용한다 2024. 5. 3.
삭제 기능 (Ajax 쿼리스트링, getmapping?) 삭제 기능을 만들어보기 위해서1. 삭제할 물건 id 가져오기2. 그 물건 id에 해당하는거 삭제하기  getmapping으로 삭제하기id를 PathVariable로 전달해서 해당 id 인스턴스를 db에서 삭제한다삭제페이지@GetMapping("/delete/{id}")String delete(@PathVariable Long id){ itemService.delete(id); return "redirect:/list";} ajax로 삭제하기쿼리스트링으로 id를 전달하고 받아서 해당 id 인스턴스를 삭제한다삭제버튼//Ajax 쿼리 스트링을 이용한 삭제 기능@DeleteMapping("/item")ResponseEntity deleteItem(@RequestParam Long id){ ite.. 2024. 5. 3.
Ajax, 쿼리 스트링 • Ajax Ajax로 btn 클래스를 가진 버튼을 클릭하면 /test1 으로 post 요청을 보낸다, document.querySelectorAll('.btn')[0].addEventListener('click', function (){ fetch('/test1',{ method : 'POST', headers : {'Content-Type' : 'application/json'}, body : JSON.stringify({name : 'kim'}) })}) @RequestBody로 받은 json을 map에 저장해서 키 : 데이터 형태로 저장할 수 있다@PostMapping("/test1")String test(@RequestBody Map body ){.. 2024. 5. 3.
UPDATE 기능 만들기 • UPDATE 기능 list에서 특정 상품을 클릭하면 id를 받아서 그 오브젝트를 찾고찾은 오브젝트를 가지고 edit.html에서 폼 안에 내용을 입력해서 리포지토리에 갱신된 데이터를 저장하게 했다데이터 저장하는것과 새로 만드는 것은 기존 객체와 id가 같으면 내용을 갱신하는 것이 되고, 새로운 id면 새 객체를 만드는 것으로 된다  /edit/2 형태의 경로로 들어오면findById로 Item 오브젝트를 찾고 제목과 값을 폼 태크에 수정해서 /edit로 post 요청을 보낸다@GetMapping("/edit/{id}")String edit(@PathVariable Long id, Model model){ Optional result = itemService.findOne(id); if (r.. 2024. 5. 3.
서비스 컨트롤러 분리 기존엔 컨트롤러 클래스에 다 박아둔걸 비즈니스 로직(DB 입출력, 검사) 등의 기능을 가지는 건 서비스로 가고html을 보내거나 받는 건 컨트롤러로 가게 기능을 분리하자  물건을 추가할때 기존엔 컨트롤러의 addpost에서 물건을 만든다음 데이터베이스에 저장하는 식으로 한 것을 서비스에메서드를 따로 빼서 가져오는 식으로 변경했다 서비스 메서드 saveItempublic void saveItem(String title, Integer price){ Item item = new Item(); item.setTitle(title); item.setPrice(price); itemRepository.save(item);} 컨트롤러에서는 메서드를 호출하면 된다@PostMapping("/add.. 2024. 5. 1.
타임리프, Rest Api 예외처리 타임리프를 쓴 경우엔 error.html 만들어주면 에러 처리 가능 RestApi는 아래처럼 try-catch나 @ExceptionHandler를 이용하면 된다 1.try - catch 구문 사용하거나2. ExceptionHandler를 만들거나 - 컨트롤러마다 박으면 컨트롤러가 많으면 아찔해짐@ExceptionHandler(Exception.class)public ResponseEntity handler(){ return ResponseEntity.status(404).body("asd");} 3. 모든 컨트롤러의 에러를 캐치하는 @ControllerAdvice 어노테이션을 사용한 클래스를 만들기@ControllerAdvicepublic class MyExceptionHandler { @Ex.. 2024. 5. 1.
타임리프 문법 • 반복문 th:each 지금 itemRepository에 있는 item 클래스 객체들을 싹 긁어서 모델에 items 라는 이름으로 전달@GetMapping("/list") String hello(Model model){ List result = itemRepository.findAll(); model.addAttribute("items",result); return "list.html"; } th:each 반복문으로 items를 순회하면서 안에 있는 요소 하나하나 출력  • css 재활용하기 th:fragment, th:replace 네비게이션바를 재활용 할려고 nav.html을 작성하고 th.. 2024. 5. 1.
Mysql Azure 워크벤치 연동하기 Hostname에 서버 이름Username에 서버 관리자 로그인 이름을 넣고 비번은 Azure 에서 mysql로 만들때 쓴 비번을 넣는다 2024. 5. 1.