스프링 -6

김정현·2024년 7월 10일
0

Spring

목록 보기
6/14
post-thumbnail

스프링 MVC

1. 스프링 MVC를 위한 설정

- 의존성

servlet-api
servlet.jsp-api
jstl-impl
jstl-api
spring-jdbc
spring-data jdbc
mybatis
mybatis-spring
ojdbc11
lombok
spring-test
slf4j-api
logback classic
spring webmvc
tomcat jdbc
jbcrypt

기초 세팅

의존성 추가 -> org/choongang/config 패키지 -> webapp/ WEBINF/ templates, web.xml -> org/choongang/member/controller/MemberController.java -> config/MvcConfig -> resource/logback.xml

-> config/DBConfig 추가 -> MvcConfig 에서 DBConfig임포트

DBConfig
-DataSource: 연결 + 커넥션풀 설정
-JdbcTemplate
-PlatformmTransactionManager
-SqlSessionFactory

//build.gradle

plugins {
    id 'java'
}

group = 'org.choongang'
version = '1.0-SNAPSHOT'

ext {
    springVersion = '6.1.10'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation "org.springframework:spring-webmvc:$springVersion"
    compileOnly 'jakarta.servlet:jakarta.servlet-api:6.0.0'
    compileOnly 'jakarta.servlet.jsp:jakarta.servlet.jsp-api:3.1.1'
    implementation 'jakarta.servlet.jsp.jstl:jakarta.servlet.jsp.jstl-api:3.0.0'
    implementation 'org.springframework.data:spring-data-jdbc:3.3.1'
    implementation 'org.apache.tomcat:tomcat-jdbc:10.1.25'
    implementation 'org.mindrot:jbcrypt:0.4'

    implementation 'org.glassfish.web:jakarta.servlet.jsp.jstl:3.0.1'
    implementation "org.springframework:spring-jdbc:$springVersion"
    runtimeOnly 'com.oracle.database.jdbc:ojdbc11:23.4.0.24.05'
    implementation 'org.mybatis:mybatis:3.5.16'
    implementation 'org.mybatis:mybatis-spring:3.0.3'
    compileOnly 'org.projectlombok:lombok:1.18.34'
    annotationProcessor 'org.projectlombok:lombok:1.18.34'
    implementation 'org.slf4j:slf4j-api:2.0.13'
    implementation 'ch.qos.logback:logback-classic:1.5.6'
    testImplementation "org.springframework:spring-test:$springVersion"


    testImplementation platform('org.junit:junit-bom:5.10.0')
    testImplementation 'org.junit.jupiter:junit-jupiter'
}

test {
    useJUnitPlatform()
}

// web.xml

<?xml version="1.0" encoding="UTF-8" ?>

<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
                      https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
         version="6.0">

    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <init-param>
            <param-name>contextClass</param-name>
            <param-value>
                org.springframework.web.context.support.AnnotationConfigWebApplicationContext
            </param-value>
        </init-param>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
                org.choongang.config.MvcConfig
            </param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>
            org.springframework.web.filter.CharacterEncodingFilter
        </filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

//MvcConfig

@Configuration
@EnableWebMvc
@ComponentScan("org.choongang")
public class MvcConfig implements WebMvcConfigurer {
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.jsp("/WEB-INF/templates/", ".jsp");
    }
}

//logback.xml

<?xml version="1.0" encoding="UTF-8" ?>

<configuration>
    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d %5p %c{2} - %m%n</pattern>
        </encoder>
    </appender>
    <root level="INFO">
        <appender-ref ref="stdout" />
    </root>

    <logger name="org.springframework.jdbc" level="TRACE" />
    <logger name="mappers" level="DEBUG" />
</configuration>

//MemberController

@Controller
public class MemberController {

    @GetMapping("/member/join")
    public String join() {
        return "member/join";
    }
}

//DBConfig
1) 컨트롤러 구현
2) JSP 구현

WebMvcConfigurer 인터페이스 암기

2. 스프링 MVC 프레임워크 동작 방식

요청(/hello) -> DispatcherServlet -> HandlerMapping -> 컨트롤러 빈(스프링 컨테이너) -> HandlerAdapter -> 컨트롤러 빈 -> 실행 -> ModelAndView
HandlerAdapter : 컨트롤러 빈의 종류가 다양하기 때문에 맞춰서 실행하기 위한 목적
@Controller, Controller 인터페이스의 구현체, HttpRequestHandler 인터페이스 구현체

ModelAndView :
1) Model : 데이터 (EL 속성으로 추가된 데이터)
2) View : 출력 템플릿 경로 정보

3. WebMvcConfigurer 인터페이스와 설정

4. 정리

1) DispatcherServlet

: 요청과 응답의 창구 역할을 하는 서블릿 클래스
- 스프링 컨테이너 생성

2) HandlerMapping

: 요청 방식 + 주소 -> 스프링 컨테이너에 있는 컨트롤러 빈을 검색

3) HandlerAdapter

: 형태가 다양한 컨트롤러 빈(@Controller, Controller 인터페이스, HttpRequestHandler 인터페이스) -> 실행 -> ModelAndView로 반환

참고) ModelAndView 
			- addObject(String name, String value) : EL 속성으로 추가되는 속성 
			- setViewName(...) : 뷰 경로 

요청메서드의 반환값이 String 이미지만 -> HandlerAdpter에서 실행시 ModelAndView 객체로 변환 

4) ViewResolver

: ModelAndView 정보 -> 출력을 위한 View 객체 검색

5. 요청 처리에 대한 편의 기능 제공

1) 요청 데이터의 이름과 동일한 매개변수를 요청 메서드에 정의하면 자동으로 주입
2) 정의한 변수의 자료형으로 자동 형변환
3) 요청 데이터의 이름과 요청 메서드에 정의한 이름이 다른 경우
@RequestParam("요청 데이터의 이름")
- required : true(기본값) : 요청 파라미터의 필수

요청 데이터
GET : ?이름=값&이름=값
POST : 요청 바디 이름=값&이름=값

	HttpServletRequest 
		String getParameter(String name)
		String[] getParameterValues(String name);
        
  • 커맨드 객체 : 요청쪽 데이터를 자동으로 매핑

Spring Data JDBC

CrudRepository 인터페이스

//Member

@Data
@Builder
@NoArgsConstructor @AllArgsConstructor
public class Member {
    @Id
    private Long seq;
    private String email;
    private String password;
    private String userName;
    private LocalDateTime regDt;
}

//CrudRepository 상속

package org.choongang.member.repositories;

import org.choongang.member.entities.Member;
import org.springframework.data.repository.CrudRepository;

public interface MemberRepository extends CrudRepository<Member, Long> { }

//test에서

   @Autowired
    private MemberRepository repository;

	// 멤버 조회
    @Test
    void test1() {
        List<Member> members = (List<Member>) repository.findAll();
        members.forEach(System.out::println);
    }
    
    
    // 멤버 추가(오류 발생함) (기본키가 있다면 업데이트 쿼리)
    @Test
    void test2() {
        Member member = Member.builder()
                .seq(24L)
                .email("user06@test.org")
                .password("123456789")
                .userName("사용자06")
                .build();
        
        repository.save(member);
    }
    
    // 한 개 조회 및 삭제
    @Test
    void test3() {
        Member member = repository.findById(1L).orElse(null);
        System.out.println(member);
        
        repository.delete(member);
    }

쿼리메서드

: 기본키 말고 다른 정보로 가져옴

public interface MemberRepository extends CrudRepository<Member, Long> {
    Member findByEmail(String email);
 	List<Member> findByUserNameContaining(String keyword);

}
@Test
    void test4() {
        Member member = repository.findByEmail("user02@test.org");
        System.out.println(member);
    }

너무 길경우 가독성이 떨어짐

Query 애노테이션

// MemberRepository 에서

// 복잡한 쿼리는 직접 명시
 @Query("SELECT * FROM MEMBER WHERE USER_NAME LIKE :param1 AND EMAIL LIKE :param2 ORDER BY REG_DT DESC")
    List<Member> getMembers(@Param("param1") String key1, @Param("param2") String key2);

// 테스트에서

 @Test
    void test7() {
        List<Member> members = repository.getMembers("%용자%", "%user%");
        members.forEach(System.out::println);
    }

페이징

Pageable 인터페이스

PageRequest 구현 클래스

Page 자료형

public interface MemberRepository extends CrudRepository<Member, Long> {

    Page<Member> findByUserNameContaining(String keyword, Pageable pageable);
@Test
    void test8() {
        Pageable pageable = PageRequest.of(0, 3, Sort.by(desc("regDt"), asc("email")));
        Page<Member> data = repository.findByUserNameContaining("용자", pageable);

        List<Member> members = data.getContent();

        long total = data.getTotalElements();   // 조회된 전체 레코드 갯수
        int pages = data. getTotalPages();

        members.forEach(System.out::println);

        System.out.printf("총 갯수 : %d, 총 페이지 수 : %d%n", total, pages);
    }
  • 총 레코드 갯수 / 페이지 크기 = 총 페이지수

// entities


@Data
@Builder
@NoArgsConstructor @AllArgsConstructor
//@Table("MEMBER")    //테이블 명과 매핑
public class Member {
    @Id // 기본 키를 알려줌
    @Column("ID") // 해당 명으로 맵핑 시켜줌
    private Long seq;
    private String email;
    private String password;
    private String userName;
    private LocalDateTime regDt;
}

Model

addAttribute(키, 값)
addAllAttribute(Map ...)

Attribute속성

public class MemberController {

    @GetMapping("/member/join")
    public String join(Model model) {
        model.addAttribute("message", "안녕하세요.");
        return "member/join";
    }
    
    /*
    @GetMapping("/member/join")
    public ModelAndView join() {

        ModelAndView mv = new ModelAndView();
        mv.addObject("message", "안녕하세요");
        mv.setViewName("member/join");

        return mv;
    }
    */
}

EL식으로 jsp 에서 받을 수 있음.

정적 경로

  • **

예) /board/** -> /board 경로의 모든 파일과 하위 경로를 포함한 모든 파일
/board/list.jsp
/board/sub/list.jsp

  • *
    /board/* -> /board 경로의 모든파일
    /board/list.jsp (O)
    /board/sub/list.jsp (X)

  • ?
    : 문자 1개

/m?01 -> /ma01, /mb01, /m101

1. 요청 매핑 애노테이션을 이용한 경로 매핑

@RequestMapping
@GetMapping
@PostMapping
@PatchMapping
@DeleteMapping
@DeleteMapping

0개의 댓글