배움 __IL/TIL 1기

TIL : 101번째- 230501 [5-1-월]

Mo_bi!e 2023. 5. 1. 20:08

I. 들어가며

이전에 매퍼로 하는게 있긴한데 불편해

package kr.co.rland.rlandapiboot3.controller;

import java.util.HashMap;
import java.util.Map;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("members")
public class MemberController {
    
    @GetMapping("isvalid")
    public ResponseEntity<Map<String, Object>> isValid(String userName, String password){

        Map<String, Object> dto = new HashMap<>();
        dto.put("result", false);

        // if(service.isValid(userName, password))
        //     dto.pust("result, true");

        return new ResponseEntity<Map<String,Object>>(dto, HttpStatus.OK);

    }
    
}

JPA 로 쓸 수있어

 

II. JPA

1. 기본세팅

여기서 repository 부분의 구현부분을 Mapper 대신에 JPA를 해보자

mybatis  보다 JPA가 조금 더 편한데 한번 알아보자

 

2. JPA 란

(1) ORM 과 JPA

1) ORM 이란

기존 mybatisDAO 함수함수가 구현할 sequlmapping

나머지는 알아서 마이바티스가 JDBC 코드를 만듬

 

그런데 JPA는 오브젝트와 테이블을 매핑하는거임 (object relation 서로 mapping 해줌)

그러면 DAO interface 까지 알아서 심지워 쿼리까지 만들어줌

 

그래서 JPA 쓰면 마이바티스 못씀 -> XML 만들기 싫어짐

 

2) JPA의 대두

데이터 가져와서 필터링, 집계 정렬 하는게 필요함 -> 이런것을 자동으로 만들어주는데 쉽지는 않음

SQL 을 만들어 줌! MS에는 있었는데 자바에서는 없어서 만든 것이 JPA임

JAVA 에서는 HIbernate 등 사용됐는데, 최근에는 JPA를 씀

 

JDBC 는 DBMS 가 제공하는 driver, API들이 호환이 안되니까...

스스로 구동하는게 없으니까,, 드라이버라는것으로 벤더들이 만들어주고 맞추어 주는거야

JPA라는게 있는데 자바에서 persistence 관련된 도구들을 통일감있게 해주는거야

 

마찬가지로 하이버레이트 관련 어노테이션 쓸 수있지만,

JPA 통해서 쓸지, 혹은 직접 쓸지가 가능한거야

 

아마 JPA 통해서 쓰는게 이득이 있겠지?

우리가 JPA 쓰겠지만 하이버레이트 기능을 거론할수 밖에 없어

 

 

3) JPA 세팅

의존성에 추가하기

전반적으로 성능이 그렇게 뛰어나지는 않아

 

 

3. JPA 설정하기

(1) 기본설정

1) @Entity 추가하기

@Entity 에서 jarkarta 를 하면 됨 (JPA용 entity 선언)

이거를 하면 이제 레포지토리 관련 인터페이스 등을 만들 필요가 없어진다

객체관계mapping이 되는것이다

 

2) @ID 추가하기

Dao 가 아니라 Entity 를 매핑하면됨

@ID 를 해주면 PK와 자동으로 매핑이 된다

 

DAO인터페이스 정의하고 그 다음 쿼리 만들어주는데, 얘가 어떻게 진짜 알아서 하는거야??

다는 아니고 우리가 뻔히 쓰는건(꼭 하는거) 미리 해주는거야!

여기에서 추가적으로 하는거고 거기까지 만들어놓았다 라는거야

 

3) 구현됐는지 확인하기

extends 를 하면 됨

JPAreposity 에서 구현

인터페이스를 보면 이미 CRUD 부분이 다 구현이 되어있어 

mybatis 가 강한이유가 동적쿼리 만들 때!!!인데 기본적인건 JPA가 좋아

package kr.co.rland.rlandapiboot3.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import kr.co.rland.rlandapiboot3.entity.Member;

//여기서 부터 마바, JPA 선택을 함
public interface MemberRepository extends JpaRepository<Member, Integer>{
    

}

이제 여기에 @repository 할필요도 없어

이미 의존성 주입이 다 되어있어

자동완성으로 확인

service에서 보면 이미 자동으로 다 만들어져 있어!!

(2) 기본쿼리문 출력하기

1) service 세팅

package kr.co.rland.rlandapiboot3.service;

import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import kr.co.rland.rlandapiboot3.entity.Member;
import kr.co.rland.rlandapiboot3.repository.MemberRepository;

@Service
public class DefaultMemberService implements MemberService{

    @Autowired
    private MemberRepository repository;

    @Override
    public boolean isValid(String userName, String password) {
        // TODO Auto-generated method stub
        
        //empty 인경우를 위한 optional 이 가능해
        Optional<Member> member = repository.findById(1);


        if(!member.isEmpty())
            System.out.println(member.toString());
        return false;
    }   
}

service 에서 optional 을 쓰면 돼

이것을 왜 쓰는걸까? 일치하는 레코드를 찾지 못한경우를 위한거야

이 경우 null 대신에 optional 을 받아서 코드 안정성을 높일 수있어

 

그리고 그 결과를 가지기 위해서야

package kr.co.rland.rlandapiboot3.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
public class Member {

    @Id
    private int id;
    private String Username;
    private String pwd;
    private String email;
    
}

이렇게 출력이 되려면 entity 에서 멤버명이 table의 컬럼명과 일치해야

그러면 아래와 같이 출력이 성공적으로 돼

 

(3) 다른 쿼리문

1) findbyUserName

그런데 JPA 에서 기본제공 외 추가로 하고싶어?

package kr.co.rland.rlandapiboot3.service;

import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import kr.co.rland.rlandapiboot3.entity.Member;
import kr.co.rland.rlandapiboot3.repository.MemberRepository;

@Service
public class DefaultMemberService implements MemberService{

    @Autowired
    private MemberRepository repository;

    @Override
    public boolean isValid(String userName, String password) {
        // TODO Auto-generated method stub
        
        //empty 인경우를 위한 optional 이 가능해
        // Optional<Member> member = repository.findById(1);

        // 없는경우는 직접 만들어서 가능해 -> 그런데 도로 마이바티스가 돼!
        Member member = repository.findByUserName("newlec");

        // if(!member.isEmpty())
        //     System.out.println(member.toString());
        return false;
    }
}

가능하긴 해! 그런데,, 이럴빠엔 차라리 다시 mybatis로 가게돼

 

2) repositoy

엔티티에 id 붙고,, 서비스에도 붙고,,, 레포도 붙고 여러곳에 쿼리가붙어

package kr.co.rland.rlandapiboot3.repository;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import kr.co.rland.rlandapiboot3.entity.Member;

//여기서 부터 마바, JPA 선택을 함
public interface MemberRepository extends JpaRepository<Member, Integer>{

    @Query("from member where username = :uesername")
    Member findByUserName(String string);
    

}

@Query() 를 하는등으로  이렇게 돼

그런데 쓸 때 조심해야할게 있어 

from member where 은 쿼리가 아냐 조심하자 JPA 가 만들어준 새로운거야

 

(4) repository에 커스텀 메소드 추가하기

1) 로그인 이름으로 사용자 정보가져오기 

이거만으로는 부족해...

그래서 새로 만들어줄 수있는데, 이거를 위한 쿼리가 저절로 만들어지는게 아냐

 

2) 주의

@Query()가 절대로 DB의 오리지널 쿼리문이 아니여서 주의해야해

매개변수의 값이어야하기 때문에 맞추어 주어야해

3) @Param()으로 쿼리스트링처럼 맞추어주기

변수명을 그래도 바꿔줄 수없어 하면이렇게 바꿔주기도 가능해

4)

테이블명대소문자 다 가려

repository는 오브젝트에 있는 속성명, 오브젝트에 남겨진 인자명에 불과해

그래서 @Query 에 있는 것은 db가 아니라 entity 에 있는것을 맞추어 주어야해

 

(4) repo에 커스텀 메소드 추가하기 : 실습

1) entity 

package kr.co.rland.rlandapiboot3.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
public class Member {

    @Id
    private int id;
    @Column(name = "username") //이거로 사용하겠다 고정!
    private String userName;  //->user_name
    private String pwd;
    private String email;
    
}

@Column 을 추가해주는거야

이렇게 하면 자동으로 컬럼명으로 바꿔주는것을 username 이라고 명시적으로 지정이 가능해

멤버 명 지정을 할 수있어

 

 

2) get 요청

포스트맨에서 get 요청을 하면 성공적으로 받을 수 있어

 

III. security 를 위한 vue

1. 기본세팅하기

(1) 기본세팅

1) 폴더구조 세팅

2) layout 지정

<script setup>
import Header from './components/Header.vue'
import Footer from './components/Footer.vue'

// rlan-vue3/src/components/Header.vue

</script>


<template>
    <Header />

    <router-view></router-view>

    <Footer />
</template>

기본세팅으로 이렇게 해줄 수있음

 

위에서 root 에서 헤더, 푸터 넣으면 어디서나 다 가지고 가겠다는 의미야

 

3) 유의사항

이경우 헤더 푸터는 소문자가 아니라 대문자로 해야지 기존 HTML 과 겹치지 않아

 

4) 전체구조 조망

 

inc 에다가 넣어서 가볍게 할 수있어

 

5) main.js 에다가 layout 설정하기

메인함수(main.js)에서 라우터설정하는방법

import { createApp } from 'vue'
import { createRouter, createWebHashHistory } from 'vue-router'

import App from './App.vue'

// 2. Define some routes
// Each route should map to a component.
// We'll talk about nested routes later.
const routes = [
    
    { path: '/index', component: Index},
    { path: '/', component: Layout, children:[
        { path: 'login', component: Login },
    ] },

    { path: '/admin', component: AdminLayout, children:[
        { path: 'menus', component: MenuLaout, children:[
            {path: 'list' , component: MenuList},
            {path: 'detail' , component: MenuDetail}
        ] },
        
    ] },

  ]
  
  // 3. Create the router instance and pass the `routes` option
  // You can pass in additional options here, but let's
  // keep it simple for now.
  const router = VueRouter.createRouter({
    // 4. Provide the history implementation to use. We are using the hash history for simplicity here.
    history: createWebHashHistory(),
    routes, // short for `routes: routes`
  })

// VueElement.createApp() //글로벌 라이브러리
createApp(App).mount('#app') //->ES6 라이브러리

그런데 한곳에서 지정하면 이름중복도 힘들고 어려운데, 분리시킬 수도 있어


1. 보충

(1)인터페이스 의미?  (나무위키)

 

 

 

 

2. 회고 

1) jpa jpa 듣기만 하다가 오늘하게되었다. 편리한것도 있지만, 조금만 변칙이 발생해도 이러한문제가 발생한다

동적 쿼리가 가능한 마이바티스가 이런점에서 용이하다는것을 알게됨

 

'배움 __IL > TIL 1기' 카테고리의 다른 글

TIL : 103번째- 230504 [5-1-목]  (1) 2023.05.04
TIL : 102번째- 230503 [5-1-수]  (0) 2023.05.03
TIL : 100번째- 230428 [4-4-금]  (0) 2023.04.28
TIL : 99번째- 230427 [4-4-목]  (0) 2023.04.27
TIL : 98번째- 230426 [4-4-수]  (0) 2023.04.26