필기정리 - Springboot

조형찬·2023년 4월 11일
0

필기 정리

목록 보기
11/11

  • java 설정
  1. 시스템 변수 - 시스템변수 - 새로만들기
    JAVA_HOME ,경로 C드라이브 JDK11넣기
  2. PATH - 편집 - 새로만들기 - %JAVA_HOME%\bin
    (jdk경로를 JAVA_HOME으로 만들고 그 경로를 적어준것이다. 그냥 jdk 경로를 적어도 된다.)

  • intelij 다운

https://www.jetbrains.com/ko-kr/idea/download/#section=windows

community 버전 다운로드(d-download)

설치시 - add bin, add open, .java , shortcut 이정도 체크하고 나머진 다 디폴트값으로 진행


  • 스프링 부트

https://start.spring.io/

예)
maven, java, 2.7.10 (snapshot은 되도록 x), Artifact
: spring-demo, Package name:com.example, jar, 11버전,Dependencies :Spring Web
=>generate - d -download - springstartprj폴더 만들어서 저장
압축은 workspace-boorspring폴더에 해제

이를 intelij에서 open으로 경로 눌러서 열기


  • 스프링 부트 폴더 설명

src-main-resources-static에는 html, css등의 파일이 들어간다.
src-main-resources-application.properties에는 설정정보가 있다.
src-main-resources-templates에는 view파일을 저장한다.


  • 이클립스 스프링 부트

워크스페이스를 스프링부트 압축 풀어둔 폴더로 잡고
포트 번호를 바꿔서 실행하면 되는데 포트번호를 바꾸는 방법은
src/main/resource 아래 application properties에서
server.port=80 등으로 포트 번호 바꿔주면 오류없이 된다.


  • intelij 롬복 다운로드

세팅- 플러그인 - 롬복 인스톨(최신버전에는 이미 내장되어 있다.) - pom.xmldependancy 추가 후 재접속 하면 인스톨 된다.


  • mySql 다운

https://dev.mysql.com/downloads/installer/에서 두번째 거 다운
d-download-dbms에 다운 후 설치
next , execute 등 하고 설치 workbench 체크
포트번호 3306


  • mysql

create database shop default character set utf8 collate utf8_general_ci; //shop이라는 database 생성함.
cf. utf8로하면 이모지가 사용 안될수도 있긴함. utf8mb4를 쓰면 해결되지만 버전이 안맞을수도 있긴하다.

show databases; // 데이터베이스 목록 보기
use shop; // 데이터베이스 사용
select database(); // 사용중인 데이터베이스 확인


  • application.properties 설정
#서버 설정
server.port=8081 //포트는 겹치지 않기위해 다른 것으로 바꾸기

#데이터베이스 연결 설정
//mysql일때 연결방법
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver 
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/shop?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=java1234

#jpa setting
spring.jpa.hibernate.ddl-auto= create-drop
/*
보통 개발할 때 create를 사용한다. 이렇게 하면 테스트를 할 때 deleteall안해줘도 된다.
데이터가 있으면 지우고 채워주는 것.
create-drop을 할경우 table을 다 지우면서 마무리한다.
update를 할 경우 data가 있어도 지우는 과정을 먼저 하지 않고 새롭게 data를 추가한다. 
따라서 맨처음 table을 만들 때는 create를 쓰고 그다음에 update를 한다면 data가 계속 쌓이게 된다.
*/
spring.jpa.properties.hibernate.show_sql = true //기타 옵션등
spring.jpa.properties.hibernate.format_sql = true //기타 옵션등
logging.level.org.hibernate.type.descriptor.sql= trace//기타 옵션등
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect //mysql사용시 필수 설정 

  • 스프링 부트를 사용한 쇼핑몰 프로그램 만드는 순서
  1. 스프링 설정정보를 압축해제하여 오픈

  2. src-java-com.shop(예)-이경로에 패키지로 각각
    constant,entity,repository를 만든다.

  3. constant에는 enum으로 상수를 설정한다.

)
public enum ItemSellStatus {
    SELL,SOLD_OUT //static 필드고 파이널이다.
}

entity에는 생성할 테이블이름, 내용등의 설정을 적는다.

) 

@Entity //Item 클래스를 entity로 선언
@Table(name = "item")  //DB에 저장될 테이블명을 item으로한다는 뜻.
@Getter
@Setter
@ToString
public class Item {
    @Id //entity에는 primaryKey가 꼭 필요한데 @Id가 붙으면 pk이다. 아래 Long id가 pk라는 것을 의미하는 것이다.
    @Column(name =  "item_id") //컬럼명이 item_id이다.
    @GeneratedValue(strategy =GenerationType.AUTO)
    private Long id; //상품코드

    @Column(nullable = false,length = 50) 
    /*DB에 not null제약 조건을 걸어주지만 유효성 검사는 해주지 않는다. 
    @NotNull의 경우 제약조건 설정과 유효성 검사를 같이해주기 때문에 좀 더 안전하게 사용가능하긴 하다.*/
    private String ItemNm; //상품명

    @Column(name = "price",nullable = false)
    private int price; //가격

    @Column(nullable = false)
    private int stockNumber; //재고수량

    @Lob //255이상의 문자를 저장하고 싶을 때 주로사용한다.
    @Column(nullable = false)
    private String itemDetail; //상품 상세설명

    @Enumerated(EnumType.STRING) 
    /*type이string인경우 enum의 name값을 db에 저장한다. 
    cf. ordinal의 경우 순서를 나타내는 숫자를 db에 저장한다.*/
    private ItemSellStatus itemSellStatus;
    private LocalDateTime regTime;
    private LocalDateTime updateTime;
}

repository에는 인터페이스를 만든다.

public interface ItemRepository extends JpaRepository<Item,Long> { 

    List<Item> findByPrice(int i); //이는 필수가 아니고 find를 해보기 위해 임의로 만든 부분
}

인터페이스로 repository 만들고 반드시JpaRepository상속받아야 한다.
또한, @Entity 선언한 클래스 이름이랑, @Id 선언한 데이터 타입을 적어야 한다.
(예시의 경우 Long타입이었다)

이후 인터페이스 이름에서 마우스 우클릭-goto-Test를 하면 Testclass가 생성된다.
(src-test-repository-이경로)

@SpringBootTest //Test를 위해 필수로 넣어야 할 @이다.
//@TestPropertySource(locations = "classpath:application-Test.properties") 
//참고할 연결 설정의 경로를 적는다. 보통은 application.properties가 기본값이다.
class ItemRepositoryTest {

    @Autowired
    ItemRepository itemRepository; //인터페이스를 가져온다.
    
    @Test //Test하기위해 적어준다.
    @DisplayName(value = "상품 저장 테스트") //테스트 이름 간결하게 보여줌
    public void createItemTest(){
        Item item = new Item(); 
        item.setItemNm("테스트 상품");
        item.setPrice(10000);
        item.setItemDetail("테스트 상품 상세 설명");
        item.setItemSellStatus(ItemSellStatus.SELL);
        item.setStockNumber(100);
        item.setRegTime(LocalDateTime.now());
        item.setUpdateTime(LocalDateTime.now());
        Item savedItem = itemRepository.save(item);
        System.out.println(savedItem.toString());
        assertEquals(1,itemRepository.count());

//        assertEquals(0,itemRepository.count());
        List<Item> list= itemRepository.findByPrice(10000); //필수는 아닌 부분
        for (Item getitem:list ){
            System.out.println("=============================="+getitem);
         }
    } 

  • page를 만드는데 도와주는 Pageable
ItemRepository.java
    List<Item> findByIdGreaterThanOrderByIdDesc(Long id, Pageable pg);

ItemRepositoryTest.java
    @Test
    @DisplayName(value = "findByIdGreaterThanOrderByIdDesc 테스트")
    public void findByIdGreaterThanOrderByIdDescTest(){
        this.createItemTest(); //data생성하는 테스트
        Pageable paging = PageRequest.of(1,5); 
        // 기본 문법형태, 0page부터 시작인거라서 사실상 2페이지의 5개의 내용을 보겠다는 의미
        List<Item> itemList = itemRepository.findByIdGreaterThanOrderByIdDesc(5L,paging);
        /*select * from item where id>5L 이뜻에서 내림차순으로 보겠다는 뜻이다. 
        즉, 5보다 큰data를 내림차순으로 보는데 2페이지에 해당하는 부분에서 5개만큼을 보겠다는 의미이다.*/
        for (Item item : itemList){
            System.out.println("====2page 자료 ==> " +item.toString());  
            //100개의 data가 있었다고 할 때 95~91번째 자료가 출력된다.
        }
    }
/*cf. findByIdGreaterThanOrderByIdDescPrice를 쓰면
(이 예제의 경우 id의 중복값이 없지만 )
id가 중복될 때는 Price기준으로 정렬한다는 의미이다. 
원래 PriceAsc이지만 Asc는 기본값이라서 생략 가능하다.*/

  • pageable의 다양한 사용법

ItemRepository.java
    List<Item> findByIdGreaterThan(Pageable pageable, Long id);

ItemRepositoryTest.java
예1)
    @Test
    @DisplayName(value = "pageable을 이용한 단일컬럼 정렬 테스트")
    public void findByIdGreaterThanTest() {
        this.createItemTest();
        Pageable paging = PageRequest.of(0,5, Sort.Direction.DESC,"id"); 
        //내림차순을 id기준으로 하겠다는 의미이다.
        List<Item> itemList = itemRepository.findByIdGreaterThan(paging,5L);
        for (Item item : itemList){
            System.out.println("====1page 자료 ==> " +item.toString());
        }
    }2)
    @Test
    @DisplayName(value = "pageable을 이용한 다중컬럼 정렬 테스트")
    public void findByIdGreaterThanTest2() {
        this.createItemTest();
        Pageable paging = PageRequest.of(0,5,
                Sort.by(new Sort.Order(Sort.Direction.DESC,"id"),
                        new Sort.Order(Sort.Direction.ASC,"price")) 
                        //여러개의 경우사용하며 id기준으로 내림차순하고 price기준으로 오름차순한다.
            );
        List<Item> itemList = itemRepository.findByIdGreaterThan(paging,5L);
        for (Item item : itemList){
            System.out.println("====1page 자료 ==> " +item.toString());
       }
}

  • JPQL 사용

ItemRepository.java

예1)
    @Query("select i from Item i") //=select * from Item ,별명 i를 주고 *자리에 i를 넣어주었다.
    List<Item> findByItemDetail();2)
    @Query("select i from Item i where i.itemDetail like %:itemDetail% order by i.price desc")
    List<Item> findByItemDetail(@Param("itemDetail") String itemDetail);  
    //where절 아래 i.itemDetail로 넣어야 하며 값을 넣을 때는 :를 사용한다.
    //like %%는 %%안의 내용이 같은 부분을 찾으라는 코드이다.

//sql문법을 기존 방식으로 사용하려면 예3)과 같이 nativeQuery=true를 넣어주면 된다.3)
    @Query(value = "select * from Item",nativeQuery = true) //쿼리문 방식은 동일하고 속성을 추가하였다.
    List<Item> findNativeAll();

cf)
예2)의 경우 @Entity에서 가져오기 때문에 Item(item x)으로 써야한다.
예3)의 경우 Item, item모두 가능하다.

성능면에서는 예3)처럼 하는 것이 더 좋긴 하지만
oracle, mysql등 sql문법이 바뀌는 경우 예3)의 방법은 쿼리문을 다시 바꿔줘야 하는 문제가 생길 수 있다.
예2)의 경우 sql문법이 달라도 문제없이 작동한다.
따라서 유지보수 측면에서 본다면 예2)와 같은 JPQL문법을 사용하는 것이 좋다.

cf)

ItemQueryString.java //쿼리문을 저장할 인터페이스
 
public interface ItemQueryString {
    String findByItemDetail="select i from Item i where i.itemDetail 
    like %:itemDetail% order by i.price desc";
    String findNativeAll="select * from item"; 
    //인터페이스로 쿼리문을 만들어두고
}

ItemRepository.java

    @Query(ItemQueryString.findByItemDetail) //쿼리를 직접 적기 대신 가져오는 방식으로 사용해도 좋다.
    List<Item> findByItemDetail(@Param("itemDetail") String itemDetail);

    @Query(value = ItemQueryString.findNativeAll,nativeQuery = true)
    List<Item> findNativeAll();

  • Querydsl 방법

문자열로 이루어진 쿼리문은 오류가 날경우 바로 해결하기 어렵다.
따라서 그부분의 단점을 보완하기 위한 방법이다.

우선 pom.xml설정 추가가 필요하다.
1. dependency설정

<!-- https://mvnrepository.com/artifact/com.querydsl/querydsl-jpa -->
<dependency>
    <groupId>com.querydsl</groupId>
    <artifactId>querydsl-jpa</artifactId>
  <!--  <version>4.3.1</version>  버전이 추가되면 오류 생김--> 
</dependency>

<!-- https://mvnrepository.com/artifact/com.querydsl/querydsl-apt -->
<dependency>
    <groupId>com.querydsl</groupId>
    <artifactId>querydsl-apt</artifactId>
  <!-- <version>4.3.1</version> 버전이 추가되면 오류 생김--> 
</dependency>

2. plugin설정
	<plugin>
		<groupId>com.mysema.maven</groupId>
			<artifactId>apt-maven-plugin</artifactId>
				<version>1.1.3</version>
					<executions>
						<execution>
							<goals>
								<goal>process</goal>
							</goals>
						<configuration>
							<outputDirectory>target/generated-sources/java</outputDirectory>						
							<processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
						</configuration>
					</execution>
				</executions>
			</plugin>
            

plugins에 추가로 위의 내용을 적는다.
플러그인 설정까지 넣은 후

우측 maven에서 reload를 하여 다운로드 후 compile을 더블클릭 해준다.
만약 문제가 있는경우 file-projectStructure에서
modules에서 target-generated-sources폴더 선택 후 sources누르고
(파란색 폴더로 바뀜) applyok해준다.

이후 정상적으로 complie된 경우 target-java-Qitem.java 파일이 생긴다.
cf) @Entity가 붙은 클래스가 있는 만큼 생긴다.

이 파일이 있는 경우
인터페이스에서 설정할 필요없이 테스트 파일에서도 바로 사용가능하다.

)
    @Autowired
    EntityManager em; // 이것도 추가로 가져와야 한다

  @Test
    @DisplayName("Querydsl을 이용한 조회테스트1")
    public void querydslTest(){
        this.createItemTest();
        JPAQueryFactory queryFactory =new JPAQueryFactory(em);
        QItem qItem=QItem.item;
        JPAQuery<Item> query = queryFactory.selectFrom(qItem) //여기까지는 거의 고정
                .where(qItem.itemSellStatus.eq(ItemSellStatus.SELL))
                .where(qItem.itemDetail.like("%"+"상품 상세"+"%")) //조건추가 가능
                .orderBy(qItem.price.desc());//정렬도 가능
        List<Item> itemList=query.fetch();
        for (Item item : itemList){
            System.out.println("====1page 자료 ==> " +item.toString());
        }
    }2)
    @Test
    @DisplayName("Querydsl을 이용한 id값을 이용해서 조회테스트2")
    public void querydslSelectOneTest(){
        this.createItemTest();
        JPAQueryFactory queryFactory =new JPAQueryFactory(em);
        QItem qItem=QItem.item;
        JPAQuery<Item> query = queryFactory.selectFrom(qItem) //여기까지 고정
                .where(qItem.id.eq(3L));
        Item itemOne=query.fetchOne(); //하나의 자료라 fetchOne
            System.out.println("====1page 자료 ==> " +itemOne.toString());
        }

  • Thymeleaf

확장자명은 .html을 사용한다. 단, 사용시 namespace를 달아줘야 한다. 예) <html xmlns:th="http://www.thymeleaf.org">
이후 일반적인 태그처럼 사용한다. th:
.jsp의 경우 서버 사이드 렌더링을 하지않으면 정상적인 화면 출력이 어렵지만 Tymeleaf.html기반이라서 서버 사이드 렌더링을 하지 않아도 정상적인 화면 출력이 가능하다

src/resources/templates 위치에 thymeleaf를 사용한 html파일을 넣는다. (cf. 타임리프는 동적인 파일)
templatesspring 기준 views와 같다고 보면 된다.
static에는 css,js 등 고정적인 파일이 들어간다.

+spring boot devtools(서버 다시 안켜도 반영됨), live reload(새로고침 안해도 리로드 됨,로그인 필요) 적용해주기

타임리프 예제
itemDto안에 데이터가 저장된 형태로 보내진 상태일 때
<span th:text="${itemDto.itemNm}"></span>
태그안에 속성 th:text="${}" 를 사용하면 태그안의 내용 대신에 ${}안에 해당하는 데이터 값이 출력된다.


  • spring security

dependency를 추가한다. (spring-boot-starter-security)

<dependency>			
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-security</artifactId>		
</dependency>

추가 후 maven reload

모든 요청에 대하여 로그인이 필요하도록 한다.
id는 user로 정해져 있으며 pw는 console창에 나온다.
한번 로그인 되면 또 할필요는 없으며, localhost/logout으로 갈경우 로그아웃이 가능하다.


  • @Configuration

설정정보가 들어있음을 나타내는 어노테이션이다.
cf) extends WebSecurityConfigurerAdapter의 상속을 받아야 한다. (이전 버전)

@EnableWebSecurity을 추가하면 상속받지 않아도 사용가능하다.
이후 db에 등록되는 pw를 암호화하여 저장하도록, Bean에 등록한다. (본인이 만들어도 되긴하다.)

@Bean
    protected PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    

  • 생성자를 통한 주입 방법
@RequiredArgsConstructor //이 어노테이션을 붙이고
public class MemberService {

    private final MemberRepository memberRepository;

}

final 혹은 @nonnull을 넣어주면 생성자를 통한 주입이 가능하다.
기본생성자가 없다는 단점이있다. 왜냐면 final을 넣으면 생성과 동시에 값이 입력되어야 하기 때문.
그러나 요즘 추세는 생성자를 통한 주입이다.
@Autowired 와 같은 역할을 한다.


  • @Transactional

@Transactional은 로직을 처리하다가 오류가 발생할 경우 데이터를 로직이 수행되기 전으로 롤백시켜준다.
또한, 테스트에서 사용될 경우 테스트 종료 후 롤백시켜준다.


MockMvc (목업) 가짜 Mvc

profile
서버개발 공부중

0개의 댓글