Spring Web Example
1. log4j
2. @controller
3. @RequsetMapping
4. InternalResourceView
5. model & modelandView
6. EL(Expression Language)
특정 class가 "controller" 역할을 하는 Bean임을 나타내는 annotation
(핸들러 어댑터에게 주는게 아무것도 없으면) handler에서 리턴이 안 되면, request URL을 이용해서 결과 Veiw Object를 생성하려고 함
controller
package my.spring.springweb.sample01;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
// 컨트롤러 지정
@Controller
public class TestController01 {
//해당 클래스에 대한 정보를 인자로 넣음
private static final Logger logger = LoggerFactory.getLogger(TestController01.class);
// http://loaclhost:8080/springweb/여기부터~~
// http://loaclhost:8080/springweb/testController01
// value = "testController01" or "/testController01" 가능
// 지정이 없으면 기본은 GET
// testController01 얘가 view resolver로 가져감
@RequestMapping(value="/testController01", method=RequestMethod.GET)
String myMethod() {
logger.debug("/springweb/testController01 호출 !!"); // 운영할 때 저 설정파일에 가서 debug가 출력 안 돼서 편함(???)
return "sample01/testController01";
}
}
jsp
<%@ 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>
<h1>소리없는 아우성</h1>
</body>
</html>
testcontroller02
package my.spring.springweb.sample01;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class TestController02 {
private static final Logger logger = LoggerFactory.getLogger(TestController01.class);
@RequestMapping("/testController02/info")
String myMethod01() {
logger.debug("/testController02/info 호출 !!");
return "sample01/testController02";
}
@RequestMapping("/testController02/profile")
String myMethod02() {
logger.debug("/testController02/profile 호출 !!");
return "sample01/testController02";
}
}
=
@RequestMapping을 클래스에 주면
하위 메소드들이 계층구조로!
package my.spring.springweb.sample01;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/testController02")
public class TestController02 {
private static final Logger logger = LoggerFactory.getLogger(TestController01.class);
@RequestMapping("/info")
String myMethod01() {
logger.debug("/testController02/info 호출 !!");
return "sample01/testController02";
}
@RequestMapping("/profile")
String myMethod02() {
logger.debug("/testController02/profile 호출 !!");
return "sample01/testController02";
}
// 여러개의 핸들러를 하나의 URL에서 처리할 수 있음
@RequestMapping(value= {"","/test01", "test02", "test03/*"})
String myMethod03() {
logger.debug("/testController02/멀티 호출 !!");
return "sample01/testController02";
}
}
testcon03
package my.spring.springweb.sample01;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
// client request method에 따른 handler 호출
// method=RequestMethod.GET
@Controller
@RequestMapping(value="/testController03")
public class TestController03 {
private static final Logger logger = LoggerFactory.getLogger(TestController03.class);
@RequestMapping(value="", method=RequestMethod.GET)
String myMethod1() {
return null;
}
@RequestMapping(value="", method=RequestMethod.POST)
String myMethod2() {
return null;
}
}
03은 결과확인 안 했음
04
05
package my.spring.springweb.sample01;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping(value="/testController05")
public class TestController05 {
private static final Logger logger = LoggerFactory.getLogger(TestController05.class);
// GetMapping이 RequestMapping을 상속하고 있음
@GetMapping(params="myName")
String myMethod01() {
logger.debug("testController05 호출 ---- myName");
return "sample01/testController05";
}
// myMethod02가 myMethod01보다 자세해서 myMethod02를 찾아서 호출함
// but 이렇게 쓰면 안 됨 !
@GetMapping(params="myName=신사임당")
String myMethod02() {
logger.debug("testController05 호출 ---- myName=신사임당");
return "sample01/testController05";
}
}
06
package my.spring.springweb.sample01;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.InternalResourceView;
@Controller
@RequestMapping(value="testController06")
public class TestController06 {
private static final Logger logger = LoggerFactory.getLogger(TestController06.class);
// 이거 진자로 Bean이 생성 되는 건가요?
public TestController06() {
logger.debug("TestController06 Bean 생성");
}
@GetMapping
public ModelAndView showStaticView() {
logger.debug("testController06 호출");
// html인 경우 webapp하단부터 절대경로를 이용하면 편함
InternalResourceView view = new InternalResourceView("/resources/sample01/testController06.html");
// model 객체, view객체 두개를 가짐
ModelAndView mav = new ModelAndView(view);
return mav;
}
}
07
: JSP 2.0 spec안에 포함되어 있음
: JSP(expression) <%= %>
대신 EL 사용함
: JSP Scriptlet <% %>
- JSTL
=> 이 둘은 유지보수가 너무 힘들어서 EL과 JSTL을 사용함
EL로 data를 찾아서 찍어야함
${ 변수명(key값) }
변수명 찾는 방법
pageScope > requestScope > sessionScope > applicationScope 순서대로 찾음
- pageScope는 pageContext객체가 포함되어 있음
- requestScope는 request객체, Model객체
- sessionScope는 session객체
- applicationScope는 servletContext객체(공용객체)
-> 같은 이름의 변수가 다른 scope에 있을 수 있음
EL은 찾은 Scope를 명시할 수 있음
${sessionScope.myName}
EL의 표현법, 연산, 내장객체에 대해서 알아보자
① pageScope
② requestScope
③ sessionScope
④ applicationScope
=>1~4번은 해당 scope를 access할 때 사용하는 내장객체
⑤ param
: client request parameter의 이름과 값을 가지고 있는
⑥ header
: client request의 header 정보
08
package my.spring.springweb.sample01;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import my.spring.springweb.sample01.vo.User;
@Controller
@RequestMapping(value="testController08")
public class TestController08 {
private static final Logger logger = LoggerFactory.getLogger(TestController08.class);
@PostMapping("useEL")
public String myMethod(Model model) {
model.addAttribute("myName", "홍길동");
model.addAttribute("myAge", 20);
List<String> list = new ArrayList<String>();
list.add("강감찬");
list.add("신사임당");
model.addAttribute("myList", list);
User user = new User("이순신",40);
model.addAttribute("myUser", user);
return "sample01/testController08";
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>EL에 대해 알아보자</h1>
<!-- requestMapping -->
<form action="/springweb/testController08/useEL" method="post" >
이름: <input type="text" name="userName"><br>
나이: <input type="number" name="userAge">
<br><br>
<input type="submit" value="서버로 전송">
</form>
</body>
</html>
<%@ 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>
<h1>testController08.jsp 호출</h1>
<h3>EL을 이용해서 데이터를 추출하는 다양한 방법</h3>
<ul>
<li>문자열 출력 -1 : ${ "test" }</li>
<li>문자열 출력 -2 : ${ 'test' }</li>
<br>
<li>숫자 출력 : ${ 123123 }</li>
<li>논리값 출력 : ${ true }</li>
<li>null 출력 : ${ null }</li> <!-- null은 아예 출력 안 됨 -->
<li>list 출력(myList[1]) : ${ myList[1] }</li>
<br>
<li>JavaBean(VO) : ${ myUser.userName }</li>
<li>Map : ${ myName }</li>
<br>
<li>param객체를 써보자 : ${ param.userName }</li>
<li>header객체를 써보자 : ${ header.referer }</li> <!-- referer은 뒤로가기 버튼에 쓰면 좋음 -->
<br>
<li>산술연산(+,-,*,/,%) : ${ param.userAge + 20 }</li>
<li>논리연산(&&, ||, !) : ${ !false }</li>
<li>비교연산(==, !=, 비교연산자사용가능) : ${ param.userAge < 20 }</li>
<li>삼항연산( 논리값 ? a : b ) : ${ param.userAge < 20 ? "미성년자" : "성인"}</li>
<br>
<li>empty 연산 : ${empty ""} - ("")true</li>
<li>empty 연산 : ${empty "abc"} - ("abc")false</li>
<li>empty 연산 : ${empty null} - (null)true</li>
<li>empty 연산 : ${empty null} - (null)true</li>
<li>empty 연산 : ${empty myList} - (안에 2개 있음)false</li>
</ul>
<br><br>
<a href="${ header.referer}">뒤로가기</a>
</body>
</html>
client request parameter
request.getParameter("myName");
이 방법 말고 다른 방식에 대해서 알아보자
ModelAndView class
sample02 - calc
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>연산할 두개의 숫자를 입력하고 연산자를 선택하세요!</h1>
<br><br>
<form action="/springweb/calc.do" method="post">
<input type="number" name="firstNum" required="required">
<select name="operator">
<option value="plus"> + </option>
<option value="minus"> - </option>
<option value="mul"> * </option>
<option value="div"> / </option>
</select>
<input type="number" name="secondNum" required="required">
<br><br>
<input type="submit" value="계산하기">
</form>
</body>
</html>
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>연산성공!</h1>
<!-- EL 검색순서
pageScope > requestScope > sessionScope > applicationScope
-->
<%-- <% pageContext.setAttribute("myData", "소리없는 아우성!"); %> --%>
<% pageContext.setAttribute("msg", "소리없는 아우성!"); %>
<br>
<h3>request.getAttribute("msg") - 결과는 : <%= request.getAttribute("msg") %></h3>
<h3>$ { msg } - 결과는 : ${ msg } </h3>
<h3>$ { param.msg } - 결과는 : ${ param.msg } </h3>
<h3>$ { param.firstNum } - 결과는 : ${ param.firstNum } </h3>
<h3>$ { pageScope.msg } - 결과는 : ${ pageScope.msg } </h3>
<%-- <h3>$ { pageScope.myData } - 결과는 : ${ pageScope.myData } </h3> --%>
<a href="${ header.referer }">뒤로가기</a>
</body>
</html>
package my.spring.springweb.sample02;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import my.spring.springweb.sample01.TestController08;
@Controller
@RequestMapping("/calc.do")
public class CalcController {
private static final Logger logger = LoggerFactory.getLogger(TestController08.class);
@PostMapping
public ModelAndView process(@RequestParam("firstNum") int num1, int secondNum, String operator ) {
// 넘어오는 키값이 html의 parameter값과 같으면 이렇게 씀.
// 원래는 @RequestParam("firstNum") int firstNum => int firstNum
// 사용자가 보내준 데이터를 받아야함
// 이전에는, String num1 = request.getParameter("firstNum");
// @RequestParam("")를 이용해서 받음 ! (String포함해서 primitive type인 경우)
ModelAndView mav = new ModelAndView();
String viewName = " ";
if(operator.equals("div")&& secondNum == 0) {
// 나눗셈을 하는데 분모가 0 => 무한대.. 무한대 개녕이 없음.. Exception
viewName = "sample02/errorResult";
mav.addObject("msg", "나눗셈은 0으로 나눌 수 없음!");
} else {
int result =0;
if(operator.equals("plus")) {
result = num1 + secondNum;
} else if(operator.equals("minus")) {
result = num1 - secondNum;
} else if(operator.equals("mul")) {
result = num1 - secondNum;
} else {
result = num1 / secondNum;
}
viewName = "sample02/calcResult";
mav.addObject("msg",result);
}
mav.setViewName(viewName);
return mav;
}
}
https://www.projectlombok.org/
다운로드 후 sts 재실행
pom.xml - project lombok dependency 추가
https://mvnrepository.com/artifact/org.projectlombok/lombok/1.18.26
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
<scope>provided</scope>
</dependency>
package my.spring.springweb.sample02.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@ToString
// @Data : 위의 5개를 모두 포함
@Data
public class User {
private String userName;
private int userAge;
private String userDept;
private String userAddress;
}