Spring MVC

김정훈·2024년 7월 9일

Spring

목록 보기
8/24

1. 스프링 MVC 설정

1) 의존성

  • spring webmvc
  • servlet-api
  • servlet.jsp-api
  • jstl-impl
  • jstl 구현체
  • tomcat jdbc
  • spring-jdbc
  • spring-data jdbc
  • spring-test
  • mybatis
  • mybatis-spring
  • ojdbc11
  • slf4j-api
  • logback classic
  • lombok
implementation 'org.springframework:spring-webmvc:6.1.10' //Spring Web MVC » 6.1.10
implementation 'org.springframework:spring-jdbc:6.1.10' //Spring JDBC » 6.1.10
implementation 'org.springframework.data:spring-data-jdbc:3.3.1' //Spring Data JDBC » 3.3.1

runtimeOnly 'com.oracle.database.jdbc:ojdbc11:23.4.0.24.05' //Ojdbc11 » 23.4.0.24.05
implementation 'org.mybatis:mybatis:3.5.16' //MyBatis » 3.5.16
implementation 'org.mybatis:mybatis-spring:3.0.3' //MyBatis Spring » 3.0.3

compileOnly 'jakarta.servlet:jakarta.servlet-api:6.0.0' //Jakarta Servlet API» 6.0.0
compileOnly 'jakarta.servlet.jsp:jakarta.servlet.jsp-api:3.1.1' //Jakarta Server Pages API » 3.1.1
implementation 'org.apache.tomcat:tomcat-jdbc:10.1.25' //Tomcat JDBC » 10.1.25
implementation 'jakarta.servlet.jsp.jstl:jakarta.servlet.jsp.jstl-api:3.0.0' //Jakarta Standard Tag Library API » 3.0.0
implementation 'org.glassfish.web:jakarta.servlet.jsp.jstl:3.0.1' //Jakarta Standard Tag Library Implementation » 3.0.1

compileOnly 'org.projectlombok:lombok:1.18.34' //Project Lombok » 1.18.34
annotationProcessor 'org.projectlombok:lombok:1.18.34' //Project Lombok » 1.18.34

implementation 'org.slf4j:slf4j-api:2.0.13' //SLF4J API Module » 2.0.13
implementation 'ch.qos.logback:logback-classic:1.5.6' //Logback Classic Module » 1.5.6
implementation 'org.mindrot:jbcrypt:0.4' //JBCrypt » 0.4

testImplementation 'org.springframework:spring-test:6.1.10' //Spring TestContext Framework » 6.1.10

2) 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>

3) MvcConfig

@Configuration
@EnableWebMvc
@ComponentScan("org.choongang")
@Import(DBConfig.class)
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");
    }
}

4) DBConfig

  • DataSource : 연결 + 커넥션풀 설정
  • JdbcTemplate
  • PlatformTransactionManager
  • SqlSessionFactory
  • NamedParameterJdbcOperations
@Configuration
@EnableTransactionManagement
@MapperScan("org.choongang")
@EnableJdbcRepositories("org.choongang")
public class DBConfig extends AbstractJdbcConfiguration {

    @Bean(destroyMethod = "close")
    public DataSource dataSource(){
        DataSource ds = new DataSource();

//        연결 설정 S
        ds.setDriverClassName("oracle.jdbc.driver.OracleDriver");
        ds.setUrl("jdbc:oracle:thin:@localhost:1521:XE");
        ds.setUsername("SPRING");
        ds.setPassword("oracle");
//        연결 설정 E

//        커넥션 풀 설정 S
        ds.setInitialSize(2);
        ds.setMaxActive(10);
        ds.setTestWhileIdle(true);
        ds.setMinEvictableIdleTimeMillis(1000 * 60);
        ds.setTimeBetweenEvictionRunsMillis(1000 * 5);
//        커넥션 풀 설정 E
        return ds;
    }

    @Bean
    public JdbcTemplate jdbcTemplate(){
        return new JdbcTemplate(dataSource());
    }

    @Bean
    public PlatformTransactionManager transactionManager(){
        return new DataSourceTransactionManager(dataSource());
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception{
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource());
        return factoryBean.getObject();
    }
    
    @Bean
    public NamedParameterJdbcOperations namedParameterJdbcOperations(DataSource dataSource){
        return new NamedParameterJdbcTemplate(dataSource);
    }
}

5) 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="org.choongang.member.mappers" level="DEBUG"/>
</configuration>

6) 컨트롤러 구현

@Controller
public class MemberController {

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

7) JSP 구현

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

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

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

3. WebMvcConfigurer 인터페이스와 설정

WebMvcConfigurer인터페이스는 설정메서드들이 default형태로 존재한다.
@EnableWebMvc을통해 기본세팅을 하고 필요한 설정만 오버라이딩으로 설정하면된다.

MvcConfig

@Configuration
@EnableWebMvc //기본세팅
@ComponentScan({"member"})
@Import(DBConfig.class)
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"); //출력할 뷰객체를 찾아줌
    }
}

4. 정리

1) DispatcherServlet

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

2) HandlerMapping

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

3) HandlerAdapter

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

참고) ModelAndView

  • Model : View에서 사용할 데이터

  • addObject(String name, String value) : EL 속성으로 추가되는 속성

  • setViewName(...) : 뷰 경로

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

@Controller
public class MemberController {


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

4) ViewResolver

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

정적경로설정

CSS, JS, image등의 정적파일에 대한 경로를 설정

@Configuration
@EnableWebMvc
@ComponentScan("org.choongang")
@Import(DBConfig.class)
public class MvcConfig implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**")
                .addResourceLocations("classpath:/static/");
    }
}

** : /board/** 👉 /board 경로의 모든 파일과 하위 경로를 포함한 모든 파일
* : /board/* 👉 /board 경로의 모든 파일
? : 문자 1개

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

1) 요청 데이터의 이름과 동일한 매개변수를 요청 메서드에 정의하면 자동으로 주입
2) 정의한 변수의 자료형으로 자동 형변환
3) 요청 데이터의 이름과 요청 메서드에 정의한 이름이 다른 경우

@RequestParam("요청 데이터의 이름")

  • required : true(기본값) : 요청 파라미터의 필수

요청 데이터

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

HttpServletRequest
String getParameter(String name)
String[] getParameterValues(String name);

1) 커맨드 객체

요청쪽 데이터를 자동 매핑

	@PostMapping("/mebmer/join")
    public String joinPs(RequestJoin form) {
        
        return "member/join";
    }
profile
안녕하세요!

0개의 댓글