BACKEND/스프링 Spring

[spring2.5] 스프링 간단한 예제

꾸준히개발하자 2022. 3. 23. 02:19

HandlerMapping

클라이언트의 요청을 어떤 Commender가 수행할지의 여부를 결정해주는 역할을 수행한다.

 

구현체 설명
BeanNameUrlHandlerMapping 요청 URI와 동일한 이름을 가진 Controller 빈을 매핑한다.
SimpleUrlHandlerMapping 패턴과 컨트롤러의 이름을 비교 URI가 패턴에 매칭 될때 지정한 컨트롤러를 사용한다.
ControllerClassNameHandlerMapping URI와 매칭되는 클래스 이름을 갖는 빈을 컨트롤러로 사용
DefaultAnnotationHandlerMapping @RequestMapping 어노테이션을 이용하여 요청을 처리할 컨트롤러를 구한다.

DefaultAnnotationHandlerMapping를 많이 사용한다.

 

 

1. applicationContext.xml

 

2. 어노테이션

@Component : 자동으로 빈을 등록한다.  2.5에서는 Controller 를 사용한다.

 

 

@Scope 

자동으로 등록되는 빈의 범위 지정

singleton, prototype , session

 

 

@Required 

Setter 메서드에 지정해서 (반드시 설정)해야 하는 필수 프로퍼티 정의

 

 

@Autowired 

Setter 메서드 , 생성자 메서드 또는 필드(프로퍼티)에 직접 설정 해서 자동으로 의존성 주입이 수행 되도록 구성

 

 

@Autowired with(required = false) Option

컨테이너가 자동으로 의존성 주입을 수행할때 대상 Bean을 발견하지 못해도 오류를 발생시키지 않도록 설정

 

 

@Qualifler 

@Autowired와 함께 사용되어서 자동 의존성 주입이 수행될 대상 Bean을 구체적으로 설정

-자신이 직접 Bean의 이름을 지정 (Spring 2.0기준 @Service("fileManager"))

같은 타입의 Bean이 두 개 이상 등록된 경우 @Autowired에 발생될 수 있는 모호성을 제거한다. 

 

 

@Resource

- 객체를 자동으로 생성 및 이름 지정 , 기본클래스를 객체로 만듬 

- Spring 2.0 기준으로 @Repository("dao") 이건 db객체를 만듬

 

 

@Controller("mainasdas")   - 객체를 대신 생성해주며 적당한 컨트롤러를 상속받는다.

- 적당한 컨트롤러를 알아서 상속받아서 기능을 쓸 수 있다.

- <bean name="mainController" class="com.text.mainController"> 처럼 객체를 알아서 생성해준다. 

즉 MainController main.mainController = new MainController();

나중에 프로젝트가 많으면 충돌이 발생될수가 있는데 그래서 ("이름")을 주게 된다.

이름은 사용자가 주고싶은 이름으로 준다.

 

 

@RequestMapping(value="/main.action")

- 사용자가 /main.action를 쓰면 무조건 메소드 mainController 이 실행된다.

 

컨트롤러

 

예제1 : A에서 B로 데이터를 전송하는 방법

- 어떻게 데이터를 넘기는지가 중요하다.

- 2.5까지는 패키지 이름이 2개까지 괜찮았지만 3.0부터는 최소 3개 작성해야 한다.

 

1. TestController.java

 

ModelAndView

- 스프링에만 있는 반환값

- model : 데이터 + view.jsp

- 데이터와 jsp를 한번에 묶어서 반환한다.

 

return new ModelAndView("test/view")";

- 스프링에는 맵이 없어 데이터와 보여주는 부분을 한번에 돌려준다.

- test폴더의 view.jsp파일로 바로 보낸다.

- 원래는 /test/view.jsp 로 적어야 하나 앞에 / (슬래쉬) 와 .jsp는 항상 동일하다

-> dispatcher-servlet.xml 의 "viewRosolver" 에서 기본셋팅값으로 넣어준다.

-> / 와 jsp 생략하여 작성

-> 포워딩 진짜주소로 보냄 .jsp 

 

package com.test;

import java.util.Calendar;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;

public class TestController2 extends AbstractController {

	
	@Override
	protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {

		int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
		String msg = "";
		
		if(hour>=6&&hour<=8) {
			msg = "아침입니다.";
		} else if(hour>=8&&hour<=13) {
			msg = "지각입니다.";
		} else if(hour>=13&&hour<=14) {
			msg = "점심시간입니다.";
		} else if(hour>=14&&hour<=18) {
			msg = "오후입니다.";
		} else {
			msg = "저녁 입니다.";
		}
		request.setAttribute("msg", msg);

	
		return new ModelAndView("test/view"); 
	
	}
	
}

 

 

2. dispatcher-servlet.xml 

역할 : 요청이 오면 누구한테 보내야 돼? 라고 핸들러 매핑에게 보낸다. 이 핸들러 매핑에는 종류가 4가지가 있다.

 

방법1. BeanNameUrlHandlerMapping

 

<bean id="beanNameUrlMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean name="/test/msg.action" class="test.TestController"/>

 

url에 /test/msg.action 이 오게되면 com.test.TestController 로 간다.

TestController 에서 retrun new ModelAndView("test/view"); 

데이터를 보내야하므로 ModelAndView를 객체생성하면서 test폴더의 view.jsp파일을 실행한다.

 

예제 2 : 스프링 DTO

 

스프링에서는 command 라고 한다.

 

1. ListCommand.java

- DTO

 

public class ListCommand {
	
    private String userId;
    private String userName;
    
    public String getUserId() {
		return userId;
	}
	public void setUserId(String userId) {
		this.userId = userId;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}

}

 

2. ListFormController 

-데이터를 처리해주는 컨트롤러

- DTO를 가져오는데 DTO를 담을 그릇이 필요 그게 바로 ListFormController 이다.

- 그리고 자동으로 매개변수에 있는 command 로 들어간다.

 

public class ListFormController impelemtns Controller {
	
    @Override
    public ModelAndView handleRequest(HttpServletRequest request,HttpServletResponse response)
    thrwos Exception {
    	
        return new ModelAndView("test/write");  // test폴더에 wrtie.jsp 로 이동시킨다.   
    }
}

 

3. ListController

AbstractCommandController 

- DTO를 받아내는 컨트롤러

- Coomand = DTO 이다.

DTO(Command) 객체 생성한다.

생성자에서 실행

setCommandCLass(Command파일이름.java) -> 객체 생성

setCommandName(DTO객체 이름) -> 이름 설정

 

ListCommand listComand = new ListCommand() 와 같이 객체를 생성한 것이다.

-> 스프링에서는 이렇게 객체 생성을 하지 않는다.

 

스프링은 알아서 객체를 넘겨준다.

 

ListController 

package com.test;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractCommandController;


public class ListController extends AbstractCommandController {

	// 생성자 생성
	public ListController2() {
		
		setCommandClass(ListCommand.class);
		setCommandName("listCommand");
		// ListCommand listCommand = new ListCommand();
	}
	
	@Override
	protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object command, BindException arg3)
			throws Exception {

		// 스프링이 알아서 객체를 넘겨준다.
		ListCommand dto= (ListCommand)command;
		
		String message = "이름" + dto.getUserName();
		message += "<br/>아이디 : " + dto.getUserId();
		request.setAttribute("message", message);
		
		return new ModelAndView("test/wrtie_ok");
	}
}

4. test > write.jsp

 

 

body부분

넘겨줄 데이터 폼을 작성한다.

 

<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 
<%
	request.setCharacterEncoding("UTF-8");
	String cp = request.getContextPath();
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

<form action="<%=cp %>/test/write_ok.action" method="post">
	
	아이디 : <input type="text" name="userId"/><br/>
	이름 : <input type="text" name="userName"/><br/>
	<input type="submit" value="전송하기"/><br/>
</form>
</body>
</html>

5. test > write_ok.jsp

 

받은 데이터 출력한다.

 

<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 
<%
	request.setCharacterEncoding("UTF-8");
	String cp = request.getContextPath();
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	
	<h1>Command를 이용하여 데이터 전송 </h1>
	<hr/><br/>
${message }	
</body>
</html>

6. dispatcher-servlet.xml

 

방법2. SimpleUrlHandlerMapping

 

order : 순서

스프링에서 어노테이션을 사용하면 어노테이션의 우선순위는 항상 1순위이다.

항상 어노테이션을 먼저 찾아서 실행한다.

order의 value값을 1로 주면 이 부분을 먼저 실행(1순위) 후 여기에 없는 방법은 어노테이션에서 찾아서 처리한다.

 

alwaysUseFullPath

- 원래 주소 : http://locahost/spring/board/list.action  (가상주소)

- value = "true" : /spring/board/list.action -> 폴더 이름(board)작성 가능

- value = "false" : /spring/list.action -> 폴더를 사용할 수 없어 action 이름을 다르게 작성한다. 

 

<!--방법2 : SimpleHandlerMapping -->
<bean id="SimpleUrlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">

	<property name="order" value="2"/>
    <property name="alwaysUserFullPath" value="true"/>
    <property name="mappings">
    	<props>
       	<!-- prop에 적는건 사용자 정의(listFormController)
        <!-- key의 주소는 변경 가능 : 이 주소는 가상의 주소이다.
        	<prop key="/test/wrtie.action">listFormController</prop>
        	<prop key="/test/write_ok.action">listController</prop>
       </props>
    </property>   
 </bean>
 
 
 <!-- ListFormController & ListController 객체 생성 -->
 <!-- 위의 생성한 prop의 사용자 정의 이름과 동일하다 -->
 <bean name="listFormController" class="com.test.ListFromController"></bean>
 <bean name="listController" class="com.test.ListController"></bean>

 

예제 3 : 예외처리

 

1. LoginCommand.java ( DTO 역할을 함 ) 

 

package com.test1;

public class LoginCommand { // command 는 String에서의 dto
	
	private String userId;
	private String userPwd;
	private String loginType;
	
	public String getUserId() {
		return userId;
	}
	
	public void setUserId(String userId) {
		this.userId = userId;
	}
	public String getUserPwd() {
		return userPwd;
	}
	public void setUserPwd(String userPwd) {
		this.userPwd = userPwd;
	}
	public String getLoginType() {
		return loginType;
	}
	public void setLoginType(String loginType) {
		this.loginType = loginType;
	}
	
}

 

2. 예외 처리

= 예외처리할때 필요한 파일이다.

 

-UserException java  ,  Authenticator.java , LoginAuthenticator.java

 

1.  UserException java 

 

package com.test1;
public class UserException extends Exception {
	
    private static final long serialVersionUID = 1L;
    
    public UserException(String str) {
    	super(str);
    }
}

 

2. Authenticator.java  // 어샌틱케이터 

package com.test1;

public interface Authenticator {
	
	public void authen(String userid, String userPwd) throws UserException; 
    
    // 예외 처리를 떠넘긴다. UserException한테 
    // UserException은 부모 Exception를 상속받고있어서 super(str) 오류메시지 출력  
    
    
    
    
}

 

3. LoginAuthenticator.java

- 로그인성공

-아이디 : kim

-비밀번호 : 123

 

package com.test1

public class LoginAuthenticatorImpl implements Authenticator {
	
    @Override 
    public void authen(String userId,String userPwd) throws UserException {
    
        // 예외를 발생시킴 
        if(!userId.equals("suzi") || !userPwd.equals("123")) {
        	throw new UserException("invalid id : " + userId); 
        }
    }
	
}

 

3. LoginController.java

 

onSubmit 메소드

= submit 버튼을 클릭하면 자동으로 실행된다.

=command : dto가 자동으로 들어온다.

넘어온 dto를 받는다.

LoginCommand login = (LoginCommand)command;

지금은 login으로 받았지만 나중에는 dto로 작성한다.

 

showForm

- 스프링의 객체

- 로그인 실패 시 입력창(login.jsp)를 다시 띄어준다.

 

  • referenceData 메소드

- 특정 데이터를 입력창에 보낼 때 사용한다.

- 예 ) 수정창을 띄울때 수정창에서 보여줄 데이터를 생성하는 작업을 기술한다. 

 

 

referenceData를 알아서 읽어가 login.jsp 화면을 띄울때 데이터가 넘어가 사용이 가능하다.

 

package com.test1;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;

public class LoginController2 extends SimpleFormController {
		
	private Authenticator authenticator;

	
	// 의존성 주입(DI) : setter 만 만든다
	// 클래스 생성 시 자동으로 실행된다.
	public void setAuthenticator(Authenticator authenticator) {
		this.authenticator = authenticator;
	}

	
	// submit버튼을 눌렀을때 실행 
	@Override
	protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object command,
			BindException errors) throws Exception {
			
			// command 로 객체가 넘어옴 
			LoginCommand login = (LoginCommand)command; // 데이터가 넘어온다.
		
			try {
					authenticator.authen(login.getUserId(), login.getUserPwd());			
					String message = "id: " + login.getUserId();
					message += ", pwd:" + login.getUserPwd();
					message += ", type:" + login.getLoginType();
					
					request.setAttribute("message", message);
					return new ModelAndView("test1/login_ok");
				
			} catch (Exception e) {
				return showForm(request,response,errors);
			}
	}

	// submit보다 먼저 실행되어야 함 
	@Override
	protected Map<String, List<String>> referenceData(HttpServletRequest request) throws Exception {
		// map 에 담아내야 하니까 map.put(String,list<String>)
			
		List<String> loginTypes = new ArrayList<>(); // 담을 곳
		loginTypes.add("일반회원");
		loginTypes.add("기업회원");
		loginTypes.add("특별회원");
		
		// 추가된 리스트는 map에 추가
		Map<String , List<String>> map = new HashMap<String,List<String>>();
		
		map.put("loginType", loginTypes);
		
		return map;
	}
}

 

 

4. login.jsp

 

- 로그인 시 필요한 데이터 입력 

<body>

<form action="<%=cp%>/test1/login.action" method="post">
아이디:<input type="text" name="userId"><br/>
패스워드 : <input type="text" name="userPwd"><br/>
로그인 타입:

<!--LoginController.java의 referenceData 데이터를 가져온다.-->
<select name="loginType">
	<c:forEach var="type" items="${loginType}">
    	<option value="${type}">${type}</option>
    </c:forEach>
</select>

<-- LoginController.java에서 onSubmit를 사용하기 때문
<input type="submit" value="로그인">
</form>

</body>

 

5. login_ok.jsp

 

로그인 성공 시 생성한 message 출력 

 

<body>

<h2> 에러처리를 이용하 ㄴ로그인</h2>
<hr/><br/>
${message}

</body>

 

6. dispatcher-servlet.xml

prop의 key가 실제 물리적인 주소가 같으면 formView는 생략이 가능하다.

다만 key의 주소는 사용자 정의로 , key의 값이 실제 물리적인 주소와 다르면 formView를 다시 작성해야 한다.

<bean id="SimpleUrlMapping" class="org.springframework.web.servlet.handelr.SimpleUrlHandlerMapping">
	<property name="order" value="1"></property>
    <property name="alwaysUseFullPath" value="true"></property>
    <property name="mappings">
    	<props>
        	<prop key="/test1/login.action">loginController</prop>
        <props>
     </property>
</bean>

 

 

2. <bean name="authenticator-ref" class="com.test1.LoginAuthenticatorImpl"/>

 

- authenticator 의존성 주입에 값을 넘겨주기 위해 객체 생성 

- 여기서 authenticator 값을 넘겨주기 시작

 

3. 객체 생성

<property name="commandName" value="loginCommand"/>

<property name="commandClass" value="com.test1.LoginCommand"/>

- LoginCommand.java를 loginCommand라는 이름으로 객체 생성

- commandClass의 value값에 있는 클래스를 commandName의 value값으로 객체 생성

LoginCommand loginCommand = new LoginCommand(); 같은 것

- 항상 2개가 짝으로 다닌다 

 

4. formView

명시적으로 다음 화면을 띄우라고 지정해주는 것

 

<bean name="authenticator-ref" class="com.test1.LoginAuthenticatorImpl"/>
<bean name="loginController" class="com.test1.LoginController">

<!-- authenticator 의존성 주입에서 값을 넘겨주는 부분 -->
<!-- 제어의 역전 -->
    <property name="authenticator" ref="authenticator-ref"/>
    <property name="commandName" value="loginCommand"/>
    <property name="coomandClass" value="com.test1.LoginCommand"/>
    <propery name="formView" value="test1/lgoin"/>
</bean>