반응형

Spring MVC Project를 만들어 주겠습니다.

제목은 ex02로 하고 패키지 세팅은 책과 같이 org.zerock.controller 로 하겠습니다.

 

1. pom.xml의 수정

스프링의 버전과 java버전을 수정해주었습니다. 

	<properties>
		<java-version>1.8</java-version>
		<org.springframework-version>5.0.7.RELEASE</org.springframework-version>
		<org.aspectj-version>1.6.10</org.aspectj-version>
		<org.slf4j-version>1.6.6</org.slf4j-version>
	</properties>

 

스프링에 관련해서 추가적인 라이브러리로는 spring-tx, spring-jdbc, spring-test가 필요합니다.

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>    
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>

 

MyBatis를 이용할 것이므로 HikariCP, MyBatis, mybatis-spring, Log4jdbc 라이브러리들도 추가합니다.

		<dependency>
			<groupId>com.zaxxer</groupId>
			<artifactId>HikariCP</artifactId>
			<version>2.7.8</version>
		</dependency>
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>3.4.6</version>
		</dependency>
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis-spring</artifactId>
			<version>1.3.2</version>
		</dependency>
		<dependency>
			<groupId>org.bgee.log4jdbc-log4j2</groupId>
			<artifactId>log4jdbc-log4j2-jdbc4</artifactId>
			<version>1.16</version>
		</dependency>

 

테스트와 Lombok을 위해서 jUnit 버전을 변경하고, Lombok을 추가합니다. jUnit의 경우 4.7로 설정되어 있으므로 반드시 기존 설정을 변경해 주도록합니다.

<!-- Test -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
			<scope>test</scope>
		</dependency> 
		
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.18.0</version>
			<scope>provided</scope>
		</dependency>

 

servlet 3.1(혹은 3.0)을 제대로 사용하기 위해서는 pom.xml에 있던 서블릿 2.5버전이 아닌 3.0이상으로 수정합니다.

<!-- Servlet -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>3.1.0</version>
			<scope>provided</scope>
		</dependency>

 

Servlet 3.1버전을 제대로 활용하고, JDK8의 기능을 활용하기 위해서 Maven 관련 Java 버전을 1.8로 수정합니다.

 	<plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <compilerArgument>-Xlint:all</compilerArgument>
                    <showWarnings>true</showWarnings>
                    <showDeprecation>true</showDeprecation>
                </configuration>
            </plugin>

 

이제 만든 프로젝트를 선택하고 Maven > Update Project를 실행합니다.

 

마지막으로 Oracle JDBC Driver를 프로젝트의 Build Path에 추가하고, Deployment Assembly에도 추가합니다.

 

 

 

출처: 코드로 배우는 스프링 웹 프로젝트

반응형
블로그 이미지

꽃꽂이하는개발자

,
반응형

  요구사항에서 나오는 용어를 기준으로 테이블이나 클래스의 이름들이 정해지듯이, 요구사항은 화면에도 영향을 미치게 됩니다. '고객이 새로운 게시물을 등록할 수 있어야 한다'면 당연히 그에 해당하는 화면을 구성하게 됩니다. 이 구성은 '어떤 내용들을 입력하게 될 것인가'에 세부적인 설계가 되고, 이를 기준으로 테이블이나 클래스의 멤버 변수(인스턴스 변수)들을 설계하게 됩니다. 실제 프로젝트에서는 결과로 아래 그림과 같이 '스토리 보드'를 만들게 됩니다.

 

  이러한 화면을 설계할 때는 주로 Mock-up(목업) 툴을 이용하는 경우가 많습니다. 대표적으로는 PowerPoint나 Balsamiq studio, Pencil Mockup 등의 SW를 이용해서 작성해 보면 좋습니다.

 

  각 화면을 설계하는 단계에서는 사용자가 입력해야 하는 값과 함께 전체 페이지의 흐름이 설계 됩니다. 이 화면의 흐름을 URL로 구성하게 되는데 이 경우 GET/POST 방식에 대해서 같이 언급해두는 것이 좋습니다.

 

 예제로 만들 게시물 관리는 리스트 화면에서 시작해서 아래 그림과 같은 흐름을 가지게 될 것입니다.

 

다음 글에서 예제 프로젝트를 구성해 보도록 하겠습니다.

 

출처: 코드로 배우는 스프링 웹 프로젝트

반응형
블로그 이미지

꽃꽂이하는개발자

,
반응형

 프로젝트를 진행하기 전에 고객의 요구사항을 인식하고, 이를 설계하는 과정이 필요합니다. 이를 흔히 요구사항 분석 설계라고 하는데, 고객이 원하는 내용이 무엇이고, 어느 정도까지 구현할 것인가에 대한 프로젝트의 범위를 정하는 것을 목적으로 합니다.

 

  요구사항은 실제로 상당히 방대해질 수 있으므로, 프로젝트에서는 단계를 정확히 구분해 주는 것이 좋습니다. 만일 팀원들이 경험이 풍부하다면 초기 버전을 상당히 많은 기능을 포함시켜 개발을 진행할 수 있지만, 그렇지 못하다면 최대한 단순하고 눈에 보이는 결과를 만들어 내는 형태로 진행하는 것이 좋습니다.

 

  요구사항은 온전한 문장으로 정리하는 것이 좋습니다. 주어는 '고객'이고 목적어는 '대상'이 됩니다. 여기서의 '대상'은 결국 데이터의 베이스 설계와 시스템 설계에서 가장중요한 용어가 됩니다(다른 용어로는 도메인(Domain)이라는 단어를 사용하는 경우도 많습니다.). 예를 들어, 게시판의 경우 다음과 같이 요구사항을 정리할 수 있습니다.

 

  • 고객은 새로운 게시물을 등록할 수 있어야 한다.
  • 고객은 특정한 게시물을 조회할 수 있어야 한다.
  • 고객은 작성한 게시물을 삭제할 수 있어야 한다.
  • 기타 등등

  이 경우 '대상'은 '게시물'이 되므로, 게시물이라는 용어가 필요하게 되고, 게시물의 구조를 판단해서 데이터베이스 테이블을 설계하게 됩니다. 예를 들어, 게시물의 경우 'tbl_board'라는 테이블을 설계하고 되고, 테이블과 관련된 VO클래스 역시 BoardVO와 같은 이름으로 설계 될 수 있습니다. 게시물과 관련된 로직은 org.zerock.service.BoardService가 될 수 있고, org.zerock.controller.BoarController라는 이름의 클래스를 생성하는 연속적인 과정을 거치게 됩니다.

 

출처: 코드로 배우는 스프링 웹 프로젝트

반응형
블로그 이미지

꽃꽂이하는개발자

,
반응형

  패키지의 구성은 프로젝트의 크기나 구성원들의 성향으로 결정합니다. 예를 들어, 규모가 작은 프로젝트는 Controller 영역을 별도의 패키지로 설계하고, Service 영역등을 하나의 패키지로 설계 할 수 있습니다.

  

  반면에 프로젝트의 규모가 커져서 많은 Service 클래스와 Controller들이 혼재할 수 있다면 비지니스를 단위별로 구분하고(비지니스 단위 별로 패키지를 작성하고) 다시 내부에서 Controller 패키지, Service 패키지 등으로 다시 나누는 방식을 이용합니다. 이런 방식은 담당자가 명확해지고, 독립적인 설정을 가지는 형태로 개발하기 때문에 큰 규모의 프로젝트에 적합합니다. 다만 패키지가 많아지고, 구성이 복잡하게 느껴지는 단점이 있습니다.

 

 제가 이 카테고리에서 앞으로 사용할 패키지의 구성은

  • org.zerock.config: 프로젝트와 관련된 설정 클래스들의 보관 패키지
  • org.zerock.controller: 스프링 MVC의 Controller들의 보관 패키지
  • org.zerock.service: 스프링의 Service 인터페이스와 구현 클래스 패키지
  • org.zerock.domain: VO, DTO 클래스들의 패키지
  • org.zerock.persistence: MyBatis Mapper 인터페이스 패키지
  • org.zerock.exception: 웹 관련 예외 처리 패키지
  • org.zerock.app: 스프링의 AOP 관련 패키지
  • org.zerock.security: 스프링 Security 관련 패키지
  • org.zerock.util: 각종 유틸리티 클래스 관련 패키지

 

출처: 코드로 배우는 웹 스프링 프로젝트

반응형
블로그 이미지

꽃꽂이하는개발자

,
반응형

  프로젝트를 위와 같이 3-tier로 구성하는 가장 일반적인 설명은 '유지보수'에 대한 필요성 때문입니다. 각 영역은 독립적으로 설계되어 나중에 특정한 기술이 변하더라도 필요한 부분을 전자제품의 부품처럼 쉽게 교환할 수 있게 하자는 방식입니다. 따라서 각 영역은 설계 당시부터 영역을 구분하고, 해당 연결 부위는 인터페이스를 이용해서 설계하는 것이 일반적인 구성방식입니다.

  프로젝트를 진행할 때에는 다음과 같은 네이밍 규칙을 가지고 작성합니다.

  • xxxController: 스프링 MVC에서 동작하는 Controller 클래스를 설계할 때 사용합니다.
  • xxxService, xxxServiceimpl: 비지니스 영역을 담당하는 인터페이스는 'xxxService'라는 방식을 사용하고, 인터페이스를 구현한 클래스는 'xxxServiceImpl'이라는 이름을 사용합니다.
  • xxxDAO, xxxRepository: DAO(Data-Acess-Object)나 Repository(저장소)라는 이름으로 영역을 따로 구성하는 것이 보편적입니다. 다만 여기서는 별도의 DAO를 구성하는 대신에 MyBatis의 Mapper 인터페이스를 활용합니다.
  • VO, DTO: VO와 DTO는 일반적으로 유사한 의미로 사용하는 용어로, 데이터를 담고 있는 객체를 의미한다는 공통점이 있습니다. 다만. VO의 경우는 주로 Read Only의 목적이 강하고, 데이터 자체도 Immutable(불변)하게 설계하는 것이 정석입니다. DTO는 주로 데이터 수집의 용도가 좀 더 강하게 나타납니다. 예를 들어 웹 화면에서 로그인하는 정보를 DTO로 처리하는 방식을 사용합니다.

출처: 코드로 배우는 웹 프로젝트

 

반응형
블로그 이미지

꽃꽂이하는개발자

,
반응형

  스프링 MVC를 이용하는 프로젝트의 구성을 이해하는 일은 전체 데이터의 흐름을 보기 위해서입니다. 브라우저에서 전송한 데이터를 스프링 MVC의 어떤 단계를 거쳐서 실행되는지를 이해한다면 문제가 발생했을 때 빠른 대처와 대안을 찾을 수 있기 때문입니다.

 

Presentation Tier(화면 계층)는 화면에 보여주는 기술을 사용하는 영역입니다. 책의 예제에서는 Servlet/JSP나 스프링 MVC가 담당하는 영역이 됩니다. Presentation Tier는 프로젝트의 성격에 맞춰 앱으로 제작하거나, CS(Client-Server)로 구성되는 경우도 있습니다. 이전 파트에서 학습한 스프링 MVC와 JSP을 이용한 화면 구성이 이에 속합니다.

 

 Business Tier(비지니스 계층)는 순수한 비지니스 로직을 담고 있는 영역입니다. 이 영역이 중요한 이유는 고객이 원하는 요구 사항을 반영하는 계층이기 대문입니다. 이 영역의 설계는 고객의 요구 사항과 정확히 일치해야 합니다. 이 영역은 주로 'xxxService'와 같은 이름으로 구성하고, 메서드의 이름 역시 고객들이 사용하는 용어를그대로 사용하는 것이 좋습니다.

 

  Persistence Tier(영속 계층 혹은 데이터 계층)는 데이터를 어떤 방식으로 보관하고, 사용하는가에 대한 설계가 들어가는 계층입니다. 일반적인 경우에는 데이터베이스를 많이 이용하지만, 경우에 따라서 네트워크 호출이나 원격 호출 등의 기술이 접목될 수 있습니다. 이 영역은 MyBatis와 mybatis-spring을 이용해서 구성했던 파트 1을 이용합니다.

 

계층에 대한 설명을 스프링 MVC와 맞춰서 설명해 보면 다음과 같은 구조가 됩니다.

 

 

  스프링 MVC영역은 Presentation Tier를 구성하게 되는데, 각 영역은 사실 별도의 설정을 가지는 단위로 볼 수 있습니다. 이전 예제에서는 root-context.xml, servlet-context.xml 등의 설정 파일이 해당 영역의 설정을 담당하였습니다.

  스프링 Core영역은 흔히 POJO(Plain-Old-Java-Object)의 영역입니다. 스프링의 의존성 주입을 이용해서 객체 간의 연관구조를 완성해서 사용합니다.

  MyBatis 영역은 현실적으로는 mybatis-spring을 이용해서 구성하는 영역입니다. SQL에 대한 처리를 담당하는 구조입니다.

 

반응형
블로그 이미지

꽃꽂이하는개발자

,
반응형

WAS의 구동 중 가장 흔한 에러와 관련된 HTTP 상태 코드는 '404'와 '500' 에러코드입니다. 500 메시지는 'Internal Server Error'이므로 @ExceptionHandler를 이용해서 처리되지만, 잘못된 URL을 호출할 때 보이는 404 에러 메시지의 경우 조금 다르게 처리하는 것이 좋습니다.

 

  서블릿이나 JSP를 이용했던 개발 시에는 web.xml을 이용해서 별도의 에러 페이지를 지정할 수 있습니다. 에러 발생 시 추가적인 작업을 하기는 어렵기 때문에 스프링을 이용해서 404와 같이 WAS 내부에서 발생하는 에러를 처리하는 방식을 알아두는 것이 좋습니다.

 

  스프링 MVC의 모든 요청은 DispatcherServlet을 이용해서 처리되므로 404에러도 같이 처리할 수 있도록 web.xml을 수정합니다.

 

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

	<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/root-context.xml</param-value>
	</context-param>
	
	<!-- Creates the Spring Container shared by all Servlets and Filters -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<!-- Processes application requests -->
	<servlet>
		<servlet-name>appServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
		</init-param>
		<!-- 404 error page -->
		<init-param>
			<param-name>throwExceptionIfNoHandlerFound</param-name>
			<param-value>true</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
		
	<servlet-mapping>
		<servlet-name>appServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

</web-app>

web.xml의 일부를 수정해주었습니다.

 

org.zerock.exception.CommonExceptionAdvice에는 다음과 같이 메서드를 추가합니다.

package org.zerock.exception;

import org.springframework.http.HttpStatus;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.NoHandlerFoundException;

import lombok.extern.log4j.Log4j;

@ControllerAdvice
@Log4j
public class CommonExceptionAdvice {
	
	@ExceptionHandler(Exception.class)
	public String except(Exception ex, Model model) {
		log.error("Exception.........." + ex.getMessage());
		model.addAttribute("exception", ex);
		log.error(model);
		return "error_page";
	}
	
	@ExceptionHandler(NoHandlerFoundException.class)
	@ResponseStatus(HttpStatus.NOT_FOUND)
	public String handle404(NoHandlerFoundException ex) {
		return "custom404";
	}
}

 

  에러 메시지는 custom404.jsp를 작성해서 처리합니다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>해당 URL은 존재하지 않습니다.</h1>
</body>
</html>

  브라우저에서 존재하지 않는 URL을 호출하면 custom404.jsp 페이지가 보이는 거슬 확인할 수 있습니다.

  (책에 나와 있는 예제는 'sample/.. 로 시작하는 URL의 경우에는 SampleController가 무조건 동작하므로 이를 제외한 경로 테스트합니다.)

 

출처: 코드로 배우는 스프링 웹 프로젝트.

반응형
블로그 이미지

꽃꽂이하는개발자

,
반응형

Controller를 작성할 때 예외 상황을 고려하면 처리해야 하는 작업이 엄청나게 늘어날 수 밖에 없습니다. 스프링 MVC에서는 이러한 작업을 다음과 같은 방식으로 처리할 수 있습니다.

 

- @ExceptionHandler와 @ControllerAdvice를 이용한 처리

- @ResponseEntity를 이용하는 예외 메시지 구성

 

@ControllerAdvice

@ControllerAdvice는 나중에 알게되는 AOP(Aspect-Oriented-Programming)를 이용하는 방식입니다. AOP에 대해서는 별도의 파트에서 설명하겠지만, 간단히 언급하자면 핵심적인 로직은 아니지만 프로그램에서 필요한 '공통적인 관심사(cross-concern)는 분리'하자는 개념입니다. Controller를 작성할 때는 메서드의 모든 예외사항을 전부 핸들링 해야 한다면 중복적이고 많은 양의 코드를 작성해야 하지만, AOP방식을 이용하면 공통적인 예외사항에 대해서는 별도로 @ControllerAdvice를 이용해서 분리하는 방식입니다.

 

예제를 위해 프로젝트에 패키지를 생성하고, CommonExceptionAdvice 클래스를 생성하겠습니다.

CommonExceptionAdvice는 @ControllerAdvice 어노테이션을 적용하지만 예외 처리를 목적으로 생성하는 클래스이므로 별도의 로직을 처리하지는 않습니다.

package org.zerock.exception;

import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import lombok.extern.log4j.Log4j;

@ControllerAdvice
@Log4j
public class CommonExceptionAdvice {
	
	@ExceptionHandler(Exception.class)
	public String except(Exception ex, Model model) {
		log.error("Exception.........." + ex.getMessage());
		model.addAttribute("exception", ex);
		log.error(model);
		return "error_page";
	}
}

   CommonExceptionAdvice 클래스에는 @ControllerAdvice라는 어노테이션과 @ExceptionHandler라는 어노테이션을 사용하고 있습니다. @ControllerAdvice는 해당 객체가 스프링의 컨트롤러에서 발생하는 예외를 처리하는 존재임을 명시하는 용도로 사용하고, @ExceptionHandler는 해당 메서드가 () 들어가는 예외 타입을 처리한다는 것을 의미합니다. @ExceptionHandler 어노테이션의 속성으로는 Exception 클래스 타입을 지정할 수 있습니다. 위와 같은 경우 Exception.class를 지정하였으므로 모든 예외에 대한 처리가 except()만을 이용해서 처리할 수 있습니다.

 

  만일 특정한 타입의 예외를 다루고 싶다면 Exception.class 대신에 구체적인 예외의 클래스를 지정해야 합니다. JSP화면에서도 구체적인 메시지를 보고 싶다면 Model을 이용해서 전달하는 것이 좋습니다. org.zerock.exception 패키지는 servlet-context.xml에 인식하지 않기 때문에 <component-scan>을 이용해서 해당패키지의 내용을 조사하도록 해야 합니다.

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
		http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

	<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
	
	<!-- Enables the Spring MVC @Controller programming model -->
	<annotation-driven />

	<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
	<resources mapping="/resources/**" location="/resources/" />

	<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
	<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/views/" />
		<beans:property name="suffix" value=".jsp" />
	</beans:bean>
	
	<beans:bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
		<beans:property name="defaultEncoding" value="utf-8"></beans:property>
		
		<!--  1024 * 1024 * 10 bytes 10MB -->
		<beans:property name="maxUploadSize" value="104857560"></beans:property>
		<!--  1024 * 1024 * 2 bytes 2MB -->
		<beans:property name="maxUploadSizePerFile" value="2097152"></beans:property>
		
		<beans:property name="uploadTempDir" value="file:/C:/upload/tmp"></beans:property>
		<beans:property name="maxInMemorySize" value="10485756"></beans:property>
	</beans:bean>
	
	<context:component-scan base-package="org.zerock.controller" />
	<context:component-scan base-package="org.zerock.exception" />
	
	
	
	
</beans:beans>

CommonExceptionAdvice의 except()의 리턴값은 문자열이므로 JSP파일의 경로가 됩니다. JSP는 error_page.jsp이므로 /WEB-INF/views 폴더 내에 작성해야 합니다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

	<h4>
		<c:out value="${exception.getMessage()}"></c:out>
	</h4>

	<ul>
		<c:forEach items="${exception.getStackTrace()}" var="stack">
			<li><c:out value="${stack}"></c:out></li>
		</c:forEach>
	</ul>
</body>
</html>

예외의 메시지가 정상적으로 출력되는지 확인해 보려면 고의로 숫자나 날짜 등의 파라미터 값을 변환에 문제 있게 만들어서 호출해 볼 수 있습니다. 예를 들어, '/sample/ex-94?name=aaa&age=11&page=9'와 호출해야 하는 URL에서 고의로 age 값을 숫자로 변환할 수 없게 다른 값을 전달해 보거나 page와 같은 파라미터를 생략하는 등의 작업을 통해서 확인할 수 있습니다. 

 

 

반응형

'2020 > 주저리 주저리 타이핑.. 낙서장.' 카테고리의 다른 글

스프링 MVC 프로젝트의 기본 구성  (0) 2020.05.11
404 에러 페이지  (0) 2020.05.11
파일 업로드 처리  (0) 2020.05.08
Controller의 리턴 타입  (0) 2020.05.06
RedirectAttributes  (0) 2020.05.06
블로그 이미지

꽃꽂이하는개발자

,