해당 포스팅의 목차는 아래와 같다.
1. 파일 생성
1) html
2) jsp
3) Controller
2. 데이터 유효성 검증_Validator
1) Validator(공통)
2) ver01_결합도 높음
3) ver02_결합도 감소
1. 파일 생성(복습)
1) html
.html이라는 확장자를 가질 수 있는 파일 형식이 존재하지 않기 때문에, file형식으로 선택한 후 뒤에 확장자를 수기로 작성해주어야한다. 또한 file생성시 내부가 비어있으므로, 양식을 채워줄 필요가 있다.
채워주어야할 양식 코드를 첨부하였다.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
</body>
</html>
처음 프로그램을 실행하면 아래와 같은 에러가 발생하는 것을 확인할 수 있다. 요청 경로가 명확하지 않음으로 인해 발생한 에러이다. 최초 브라우저를 동작시키게 되면 아래와 같이 출력된다. 정상 출력을 위해 요청 경로를 확인할 필요가 있다.
설명을 위해 본인이 생성한 각 html파일의 생성 위치를 공유하자면 아래와 같다.
url을 주의깊게 살필 필요가 있다.
마찬가지로 url을 주의깊게 살필 필요가 있다.
2) jsp
① build.gradle
jsp사용을 위해 미리 DI해야할 자원들이 필요하다. 다음은 build.gradle의 내용이다. 주석을 통해 기존 내용과 추가된 내용을 분리하여 확인할 수 있다.
plugins {
id 'org.springframework.boot' version '2.6.7'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
id 'war'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.apache.tomcat.embed:tomcat-embed-jasper'//JSP를 해석할 수 있는 파서
implementation 'javax.servlet:jstl'//JSTL사용을 위한 자원
}
tasks.named('test') {
useJUnitPlatform()
}
② application.properis
해당 파일에 경로 설정에 대한 내용을 기술한다.
# JSP관련 설정 -> prefix의 경로에 suffix라는 형식의 파일이 생성할 것이라는 명령
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
위에서 지정한대로 main폴더 하위에 추가적으로 폴더들이 필요하므로 생성해준다.
③ jsp파일
마찬가지로 file형식을 생성하고, 확장자를 .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>
</body>
</html>
3) Controller
실습을 복습 개념으로 진행하며 코드에 대한 내용을 주석으로 확인할 수 있도록 하였다.
package com.example.demo;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class MyController {
// 루트 기능을 하는 메서드 : 디폴트 경로를 찍어주는 메서드
@RequestMapping("/")
public @ResponseBody String root() { // 어노테이션으로 인해 "value값이니까 화면에 그냥 보여주기만 해"라는 의미로 해석된다.
return "JSP 실습"; //viewResolver에 의해 /WEB-INF/views/return값.jsp로 될테니 그걸 바꿔주자
}
@RequestMapping("/page03") // localhost:8080/page03이라고 될 예정(이때 suffix를 설정하였으므로 jsp를 생략해도 무관하다)
public String page03(MemberVO memberVO) { // command 객체이다. -> page03.jsp에서 ${vo.멤버변수명}으로 호출이 가능하다.
return "page03"; //viewResolver에 의해 /WEB-INF/views/page03.jsp을 호출할 예정
}
@RequestMapping("/page04") // "/page04/{name}/{phone}"이런 식으로도 많이 사용한다. 경로 자체에 변수를 넣는다.
public String page04(MemberVO vo, Model model) {
model.addAttribute("name", vo.getName());
model.addAttribute("name", vo.getPhone());
return "page04";
}
// 아래의 메서드와 위의 메서드의 기능은 동일하다.
// @RequestMapping("/page04/{name}/{phone}") // 경로 자체에 변수를 넣는다.
// public String page04(@PathVariable String name, @PathVariable String phone, Model model) {
//
// model.addAttribute("name", name);
// model.addAttribute("phone", phone);
//
// return "page04";
// }
}
각 페이지에서 ulr을 활용한 파라미터 값 전달로 출력이 잘 되는 것을 확인할 수 있다.
page03의 경우 처음에 command객체명(MemberVO)을 vo로 설정했었는데, controller에서 값이 잘 넘어오는 것은 확인되나 ${vo.name}등으로 호출했을때 출력이 안되는 상황이 발생했다. 혹시나 하는 마음에 vo를 memberVO로 변경해서 사용하니 출력이 잘 되는 기적..... 이거 왜인지 아시는 분, 댓글로 공유해주시면 감사하겠습니다......
2. 데이터 유효성 검증_Validator
Validator(관리데이터 클래스)를 활용하여 객체가 제대로 요구사항에 맞추어 생성 됐는지 검증할 수 있다.
유효성 검증에 대하여
1) html 페이지, 클라이언트, 브라우저 : JS를 통해서 검증을 진행, 즉 서버의 부하를 줄일 수 있다.(유효한 요청만이 들어온다.)
2) 서버, jsp페이지, servlet : 악의적인 접근(url)에 대해 파라미터로 넘어온 값을 검증한다.
1) Validator(공통)
실습 순서에 따라 단계별로 나누어 정리하였다.
① validator클래스 추가를 위한 자원 생성
build.gradle파일의 dependencies영역 최하단의 아래의 코드를 붙여넣음으로써 자원을 생성해준다.
implementation 'org.springframework.boot:spring-boot-starter-validation'//데이터 유효성 검증을 위한 자원
② 실습을 위한 JSP페이지 생성
val01.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>01</title>
</head>
<body>
<form action="/val">
<input type="text" name="name" value="${memberVO.name}">
<input type="text" name="phone" value="${memberVO.phone}">
<input type="submit" value="검증하기">
</form>
</body>
</html>
val02.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>02</title>
</head>
<body>
완료!
</body>
</html>
val01.jsp에서 input에 유효성 검사에 따른 값이 입력 되었을때 비로소 val02.jsp로 이동될 수 있도록 할 예정이다.
③ 유효성 로직 클래스(Validator클래스)
유효성 검사 진행을 위한 로직 파일을 생성한다. 이때 해당 클래스파일이 Validator클래스의 기능을 수행할 수 있도록 하기 위해 implements를 진행하고, 각 추상메서드들에 알맞은 내용들을 기입한다. 자세한 내용은 주석을 통해 파악이 가능하다.
package com.example.demo;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
public class MemberValidator implements Validator{
@Override
public boolean supports(Class<?> clazz) { //어떤 클래스를 검증할 것인지를 설정
return MemberVO.class.isAssignableFrom(clazz); // 검증할 객체의 클래스 기입
}
@Override
public void validate(Object target, Errors errors) {
// target : 검증대상, errors: 어떤 에러가 발생했는지를 알려줌
// ★return타입이 void인것으로 보아, 에러에 해당하는 객체를 보내줘야 참조가 가능할 것을 예상할 수 있다.
MemberVO vo=(MemberVO)target; //캐스팅
String name=vo.getName();
String phone=vo.getPhone();
// 검증을 위한 로직, 다양한 로직으로 체크할 수 있다.
if(name==null || name.trim().isEmpty()) { //trim()->스페이스바 여러개를 입력한 공백을 잡아줌
System.out.println("로그: name 값이 비어있습니다.");
errors.rejectValue("name", "error");
}
if(phone==null || phone.isEmpty()) {
System.out.println("로그: phone 값이 비어있습니다.");
errors.rejectValue("phone", "error");
}
}
}
2) ver01_결합도 높음
위 객체의 메서드 결과에 따라 페이지를 다르게 반환할 수 있도록 controller로 작업한다.
@RequestMapping("/val")
public String val(@Valid MemberVO vo, BindingResult result) {
// @Valid: 해당 객체를 검증하겠다는 의미의 어노테이션, 유효성 검사를 수행하라는 요청이다.
System.out.println("c: "+vo); // 컨트롤러에 넘어온 결과를 확인할 목적의 로그
MemberValidator validator = new MemberValidator(); //결합도가 높음
validator.validate(vo, result); // ☆result객체를 인자로 전달해줬기 때문에 참조가 가능하다.
String viewName = "val01";
if(!result.hasErrors()) { // 성공했다면, (hasErrors: 에러가 발생했을때 true반환)
viewName="val02";
}
return viewName;
}
result와 vo가 MemberValidator객체의 validator메서드에 전달되어 반환값은 void임에도 result라는 객체를 통해 메서드 수행 결과를 참조할 수 있게 된다.
이때 위의 코드에서 객체가 초기화 되고 있는 모습을 확인할 수 있는데, 이는 /val요청이 있을때마다 객체의 초기화가 진행될 것이기 때문에 비효율적이라고 할 수 있다. 아래의 단계에서 이 코드의 결합도를 낮춤으로써 유지보수를 용이하도록 수정할 수 있다.
3) ver02_결합도 감소
위의 코드에서 수정작업을 진행하여 결합도를 낮추는 코드로 작업할 예정이다. 프로젝트 실행시 최초로 한 번 동작할 수 있도록 코드를 변경한다.
@RequestMapping("/val")
public String val(@Valid MemberVO memberVO, BindingResult result) {
// @Valid: 해당 객체를 검증하겠다는 의미의 어노테이션, 유효성 검사를 수행하라는 요청이다.
System.out.println("c: "+memberVO); // 컨트롤러에 넘어온 결과를 확인할 목적의 로그
// MemberValidator validator = new MemberValidator(); //결합도가 높음
// validator.validate(memberVO, result); // ☆result객체를 인자로 전달해줬기 때문에 참조가 가능하다.
String viewName = "val01";
if(!result.hasErrors()) { // 성공했다면, (hasErrors: 에러가 발생했을때 true반환)
viewName="val02";
}
return viewName;
}
@InitBinder // 프로젝트가 시작할때 먼저 수행할 메서드임을 선언
protected void initBinder(WebDataBinder binder) {
binder.setValidator(new MemberValidator()); // 한 번 new 한 것을 주입받아서 계속 사용할 수 있도록하여 결합도를 낮춤
}
위의 코드를 통해 MemberValidator객체가 요청시마다 계속해서 초기화 되지 않고, 프로젝트 시행시 한 번 초기화 된 후 재사용됨으로써 결합도가 감소한 모습을 확인할 수 있다.
콘솔을 통해 값이 입력되지 않아 에러로 인식한 경우 로그를 통해 어떤 파라미터의 값이 비어있는지를 확인할 수 있다.
정상적으로 입력된 경우 val02.jsp페이지로 이동되는 모습을 확인할 수 있다.
'Spring' 카테고리의 다른 글
[Controller] method간의 data 전송 (0) | 2022.09.29 |
---|---|
[Boot] DAO 버전관리_JdbcTemplate & MyBatis (0) | 2022.04.26 |
[Boot] Spring Boot 설치 (0) | 2022.04.23 |
[JPA] JPA를 활용한 DAO버전관리_4 (0) | 2022.04.21 |
[Mybatis] Mybatis설치 및 개요_DAO3 (0) | 2022.04.18 |