Spring05_MVC패턴실습
Spring MVC 실습 1
1. Maven Project생성
- File - New - Maven Project
- Create a simple project(skip archetype selection) 체크
- Group Id(kr.ac.kopo) Artifact Id 등 설정 후, Packaging
war
로 설정!!
2. pom.xml 세팅
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>kr.ac.kopo</groupId>
<artifactId>spring-mvc</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp/jsp-api -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.9</version>
</dependency>
</dependencies>
</project>
- spring-web말고 webmvc로 할것! xml에서는 4버전을 쓰지만 지금은 5버전사용가능
3. web.xml, spring-mvc.xml 파일 복붙
- web.xml은
webapp/WEB-INF/
에 복붙
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>spring-mvc</display-name>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:config/spring/spring-mvc.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.do</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>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
- spring-mvc.xml 은
src/main/resources/config/spring/
경로에 둔다.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="kr.co.mlec" />
<mvc:annotation-driven />
<mvc:default-servlet-handler />
<mvc:view-resolvers>
<!-- forward시킬 주소 값을 자동으로 앞에 경로 붙이고 뒤에는 .jsp로 인식하도록 -->
<mvc:jsp prefix="/WEB-INF/jsp/" suffix=".jsp" />
</mvc:view-resolvers>
</beans>
4. 서버세팅
- 다른 프로젝트에서 서버사용중이면 stop후 spring 서버 실행해야함 (충돌주의)
- Servers 에서 서버 tomcat 9버전 추가
- HTTP/1.1 포트번호 9999로 변경
- (선택사항) Use custom location 체크 후, 미리만들어둔 eclipse-webwork 경로로 설정
- 서버 Start
5. 소스파일
- HelloController.java
package kr.co.mlec.hello;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class HelloController {
@RequestMapping("/hello/hello.do")
public ModelAndView hello() {
ModelAndView mav = new ModelAndView("hello/hello"); // forward시킬 jsp의 주소
mav.addObject("msg","hi 스프링 mvc~~"); // request공유영역에 올림.
return mav;
}
}
- hello.jsp :
WEB-INF/jsp/hello
경로- WEB-INF폴더에 jsp 파일을 넣어 보안성 강화함
- 이제는 css, img, js는 WEB-INF에 있으면 안됌!!!!!!!!!
- css, img는 webapp 폴더아래에 서 관리
<%@ 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>
서버에서 받은 메시지 : ${ msg }
</body>
</html>
- index.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>
<a href="<%= request.getContextPath() %>/hello/hello.do">hello</a>
</body>
</html>
Spring MVC 실습 2
1. @RequestMapping
- RequestMapping을 이용하여 method에 따라 다른 행동을 취하도록 할 수 있다.
- 다른 동작을 하는 jsp를 하나의 url을 사용하도록 할 수 있음
- @RequestMapping(value=” “, method= )
- MethodController.java
1-1. @RequestMapping 분리1
package kr.co.mlec.method;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class MethodController {
/* RequestMapping으로
* 같은 url을 method(get/post)에 따라 다른 행동을 취하도록 할 수 있다.
*
*/
@RequestMapping(value="/method/method.do", method=RequestMethod.GET)
public String callGet() {
return "method/methodForm";
}
@RequestMapping(value="/method/method.do", method=RequestMethod.POST)
public String callPost() {
return "method/methodProcess";
}
}
- Dispatcher Servlet이 복잡한구조이므로, 우리가 유연하게 사용할 수 있음
★ Return타입 : ModelAndView, void, String
- String : forward시킬 jsp주소라는 것을 알아서 인식함. ( 매우 유연 )
- ModelAndView : forward, 공유영역 객체가 있다는 것을 인식
@RequestMapping("/join.do")
public ModelAndView join(MemberVO member) {
//ModelAndView로 forward할 주소입력하고, 공유영역에 공유할 수 있음
ModelAndView mav = new ModelAndView();
mav.setViewName("form/memberInfo"); // forward
mav.addObject("member",member); // 공유영역 추가
return mav;
}
1-2. @RequestMapping 분리2
- value와 method를 분리해서 사용가능 (value는 class위에, method는 메소드위에)
package kr.co.mlec.method;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@RequestMapping(value="/method/method.do")
@Controller
public class MethodController {
//@RequestMapping(value="/method/method.do", method=RequestMethod.GET)
@RequestMapping(method=RequestMethod.GET)
public String callGet() {
return "method/methodForm";
}
//@RequestMapping(value="/method/method.do", method=RequestMethod.POST)
@RequestMapping(method=RequestMethod.POST)
public String callPost() {
return "method/methodProcess";
}
}
1-3. @RequestMapping 분리3
- 겹치는 부분(“/form”)은 class위에 다른부분은 메소드 위에 정의해둘 수 있다.
package kr.co.mlec.form;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/form")
public class MemberController {
// "/form/joinForm.do"
@RequestMapping("/joinForm.do")
public String joinForm() {
return "form/joinForm";
}
@RequestMapping("/join.do")
public String join(HttpServletRequest request) {
//원래 인코딩해주어야하지만 web.xml에서 이미 처리되도록 설정해주었음
String id = request.getParameter("id");
String password = request.getParameter("password");
String name = request.getParameter("name");
MemberVO member = new MemberVO();
member.setId(id);
member.setPassword(password);
member.setName(name);
//System.out.println(member.toString());
request.setAttribute("member", member);
return "form/memberInfo";
}
}
Spring MVC 실습 3
1. @RequestParam
- RequestParam으로 HttpServletRequest대신 사용할 수 있다.
- java가 제공하는 것이 아니라 Spring이 제공함.
@RequestMapping("/join.do")
public String join(HttpServletRequest request) {
//원래 인코딩해주어야하지만 web.xml에서 이미 처리되도롱 설정해주었음
String id = request.getParameter("id");
String password = request.getParameter("password");
String name = request.getParameter("name");
MemberVO member = new MemberVO();
member.setId(id);
member.setPassword(password);
member.setName(name);
//System.out.println(member.toString());
request.setAttribute("member", member);
return "form/memberInfo";
}
- 위의 코드는 아래와 같다.
- 물론 HttpServletRequest request도 함께사용가능.
- 공유영역에 올리려면 request필요
@RequestMapping("/join.do")
public String join(@RequestParam("id") String id,
@RequestParam("password") String password,
@RequestParam("name") String name,
HttpServletRequest request) {
MemberVO member = new MemberVO();
member.setId(id);
member.setPassword(password);
member.setName(name);
System.out.println(member.toString());
//request.setAttribute("member", member);
return "form/memberInfo";
}
2. @ModelAttribute
- 모든 변수를 하나하나 받아오는 것은 비효율적이다.
- @ModelAttribute를 써서 VO객체에 바로 set해주고, 공유영역에 올려줄 수 있다.
- 공유영역 객체의 이름을 내가 원하는 것으로 지정해줄 수 있다.
- MemberVO -> member
@RequestMapping("/join.do")
public String join(@ModelAttribute("member") MemberVO member) {
// 모든 변수를 하나하나 다 써주는건 비효율적
/*System.out.println(member.toString());
* @ModerAttribute안쓰면 request.setAttribute("memberVO", member); 로 알아서 등록시킴.
* 쓰면 ("member")로 지정가능
*/
return "form/memberInfo";
}
- 안쓰면 VO객체의 첫글자를 소문자로 자동으로 바꿔서 들어감.
- MemberVO -> memberVO
@RequestMapping("/join.do")
public String join(MemberVO member) {
// 모든 변수를 하나하나 다 써주는건 비효율적
System.out.println(member.toString());
//request.setAttribute("memberVO", member); 로 알아서 등록시킴.
return "form/memberInfo";
}
Request영역에 객체 등록하는 방법
1.내가직접 파라미터 받아서 등록. 2.ModelAndView로 하는 방법(VO로 알아서 받아옴) 3.Model을 메소드 파라미터로 받아와서 등록하는방법.
@RequestMapping("/join.do")
public String join(MemberVO member, Model model) {
// request공유영역에 등록하는 방법은 여러개이다.
// 1.내가직접 setAtt
// 2.ModelAndView
// 3.Model을 파라미터로 받아와서 등록하는방법
model.addAttribute("member",member);
return "form/memberInfo";
}
Spring MVC 실습 4
1. @ResponseBody
- 어떤 Client가 요청시 요청받은 메소드가 jsp를 거치지 않고 바로 데이터를 응답한다.
- 4버전부터 @RestController가 등장.
- 메소드에 붙는 어노테이션
- 사용
- 단순문장, json형태로 리턴할 때 사용.
- ajax쓸때 사용.
- 메시지를 forward시키지않고 바로 응답하게 하고 싶을 때 사용.
- 바로 넘기면 한글안나옴.
message-converters
가 필요하다. - spring-mvc.xml수정
<mvc:annotation-driven>
부분 수정
<mvc:annotation-driven>
<mvc:message-converters>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html; charset=utf-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
string msg보내기
package kr.co.mlec.body;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("/ajax")
public class ResBodyController {
@RequestMapping("/resBody.do")
@ResponseBody
public String resStringBody(HttpServletRequest request) {
// 메시지를 forward시키지않고 바로 응답하게 하고싶다.
return "ok, 성공!";
}
}
json 보내기
- .json uri 처리할 수 있도록 web.xml 수정(아래 추가)
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.json</url-pattern>
</servlet-mapping>
- 406에러의 이유 : .json은 불러왔지만 응답의 해석안되고있음
- message-converter가 또 필요함. 아래의 value추가해준다.
<value>application/json; charset=utf-8</value>
- jackson (Mave Repository에서 검색) 추가.(Databind, Core, Annotations)
- jackson도 컨버터가 빌요하지만 5버전부터는 필요없어짐.
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html; charset=utf-8</value>
<value>application/json; charset=utf-8</value>
</list>
</property>
</bean>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.12.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.12.4</version>
</dependency>
@RequestMapping("/resBody.json")
@ResponseBody
public Map<String, String> resJsonBody(){
Map<String, String> result = new HashMap<String, String>();
result.put("id", "hong");
result.put("name", "홍길동");
result.put("addr", "서울");
return result;
}
VO
@RequestMapping("/resVOBody.json")
@ResponseBody
public MemberVO resJsonVOBody(){
MemberVO vo = new MemberVO();
vo.setId("hong");
vo.setName("홍길동");
vo.setPassword("1234");
return vo;
}
List<String>
@RequestMapping("/resStringListBody.json")
@ResponseBody
public List<String> resJsonStringListBody(){
List<String> list = new ArrayList<String>();
for(int i = 1; i<4 ;i++) {
list.add(String.valueOf(i));
}
return list;
}
List<MemberVO>
@RequestMapping("/resVOListBody.json")
@ResponseBody
public List<MemberVO> resVOListBody(){
List<MemberVO> list = new ArrayList<MemberVO>();
for(int i = 1; i<4 ;i++) {
MemberVO vo = new MemberVO();
vo.setId("hong");
vo.setName("홍길동");
vo.setPassword("1234");
list.add(vo);
}
return list;
}
Tip ( ResponseBody <-> RequestBody )
- ResponseBody: java가 가진 객체를 json형태로 바꿔주는 것
- RequestBody : json형태로 날아오는 것을 java객체로 바꿔줌.
2. @RestController
- ResponseBody대신 class에 @RestController붙이면 같은 기능을 할 수 있음
package kr.co.mlec.body;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import kr.co.mlec.form.MemberVO;
@RestController
@RequestMapping("/ajax")
public class RestBodyController {
// 메세지 기반의 컨트롤러 생성시 RestController
@RequestMapping("/restBody.do")
public String resStringBody(HttpServletRequest request) {
// 메시지를 forward시키지않고 바로 응답하게 하고싶다.
// 바로 넘기면 한글안나옴. message 컨버터가 필요하다.
return "ok, 성공!";
}
@RequestMapping("/restBody.json")
public Map<String, String> resJsonBody(){
Map<String, String> result = new HashMap<String, String>();
result.put("id", "hong");
result.put("name", "홍길동");
result.put("addr", "서울");
return result;
}
@RequestMapping("/restVOBody.json")
public MemberVO resJsonVOBody(){
MemberVO vo = new MemberVO();
vo.setId("hong");
vo.setName("홍길동");
vo.setPassword("1234");
return vo;
}
@RequestMapping("/restStringListBody.json")
public List<String> resJsonStringListBody(){
List<String> list = new ArrayList<String>();
for(int i = 1; i<4 ;i++) {
list.add(String.valueOf(i));
}
return list;
}
@RequestMapping("/restVOListBody.json")
public List<MemberVO> resVOListBody(){
List<MemberVO> list = new ArrayList<MemberVO>();
for(int i = 1; i<4 ;i++) {
MemberVO vo = new MemberVO();
vo.setId("hong");
vo.setName("홍길동");
vo.setPassword("1234");
list.add(vo);
}
return list;
}
}
Spring MVC 실습 5
컨트롤러 없이 페이지 매핑
- uploadForm.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>
<h2>파일업로드 테스트</h2>
<form method="post" enctype="multipart/form-data" action="<%= request.getContextPath() %>/file/upload.do">
<input type="text" name="id" value="test"/><br>
<input type="file" name="attachFile1" /><br>
<input type="file" name="attachFile2" /><br>
<input type="submit" value="업로드" />
</form>
</body>
</html>
- spring-mvc.xml
</mvc:annotation-driven>
아래에 추가
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 최대 업로드 파일사이즈 : 10MB -->
<property name="maxUploadSize" value="10485760"/>
</bean>
<mvc:view-controller path="/file/uploadForm.do" view-name="file/fileUploadForm"/>
- pom.xml
- 아래 내용 추가
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
- UploadController.java
package kr.co.mlec.file;
import java.io.File;
import java.util.Iterator;
import java.util.UUID;
import javax.servlet.ServletContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
@RequestMapping("/file")
@Controller
public class UploadController {
@Autowired
ServletContext servletContext;
@RequestMapping(value="/upload.do", method=RequestMethod.POST)
public ModelAndView fileUpload(MultipartHttpServletRequest mRequest) throws Exception {
// 실행되는 웹어플리케이션의 실제 경로 가져오기
String uploadDir = servletContext.getRealPath("/upload/");
System.out.println(uploadDir);
ModelAndView mav = new ModelAndView("file/uploadResult");
//forward주소
String id = mRequest.getParameter("id"); //
System.out.println("id : " + id);
Iterator<String> iter = mRequest.getFileNames();
while(iter.hasNext()) {
String formFileName = iter.next();
// 폼에서 파일을 선택하지 않아도 객체 생성됨
MultipartFile mFile = mRequest.getFile(formFileName);
// 원본 파일명
String oriFileName = mFile.getOriginalFilename();
System.out.println("원본 파일명 : " + oriFileName);
if(oriFileName != null && !oriFileName.equals("")) {
// 확장자 처리
String ext = "";
// 뒤쪽에 있는 . 의 위치
int index = oriFileName.lastIndexOf(".");
if (index != -1) {
// 파일명에서 확장자명(.포함)을 추출
ext = oriFileName.substring(index);
}
// 파일 사이즈
long fileSize = mFile.getSize();
System.out.println("파일 사이즈 : " + fileSize);
// 고유한 파일명 만들기
String saveFileName = "mlec-" + UUID.randomUUID().toString() + ext; // 확장자 붙이기
System.out.println("저장할 파일명 : " + saveFileName);
// 임시저장된 파일을 원하는 경로에 저장
mFile.transferTo(new File(uploadDir + saveFileName));
}
}
return mav;
}
/*
@RequestMapping("/uploadForm.do")
public String upload() {
return "file/fileUploadForm";
}
*/
}