728x90
나는 원래 spring을 spring boot 로 처음 접했었어서 그런지 spring 의 설정이 복잡하다는 것을 잘 몰랐었다. 다만 spring boot 가 spring 의 설정을 복잡함을 해결하고자 나왔다 라는 걸 알았기에 어느정도 복잡하구나...정도로 생각할 뿐이었다. 그런데 이번에 spring boot 가 아닌, 본래 spring 을 배우게 되었는데 세상에...엄청 복잡하다. 다만 복잡함에도 중요한 것들이 있었고, 이에 따라서 정리해보려고 한다.
1. 스프링 동작 원리
spring 실행순서
- web.xml을 로딩
- web.xml에 등록된 ContextLoaderListner 가 생성된다
- ContextLoaderListner가 root-context.xml을 로딩시작!
- root-context.xml에서 web 제외한 component를 스캔 및 생성
- 클라이언트 요청에 의해 DispatcherServlet 가 생성된다
- DispatcherServlet이 servlet-context.xml을 로딩!
- servlet-context.xml에서 web 관련 component를 스캔 및 생성
spring 구동 순서
- 클라이언트가 URL로 접근하여 정보를 요청
- DispatcherServlet이 클라이언트의 요청을 가로챈다.
- 가로챈 요청을 HandlerMapping으로 보내 해당 요청을 처리할 Controller 검색
- Controller에서 DB를 통해 정보를 가져온다.
- (Controller - Service - DAO - DB - DAO - Service - Controller)
- Controller에서 View를 리턴하면 ViewResolver를 통해 해당 View가 존재하는지 검색
- DispatcherServlet은 ViewResolver를 통해 접두사(prefix)와 접미사(suffix)가 붙은 JSP파일의 이름과 경로를 리턴받아 JSP를 실행, View에 결과를 보낸 후 DispatcherServlet은 최종결과를 클라이언트로 전송
※ Dispatcher Servlet 란?
- DIspatcher Servlet 은 스프링에서 아주아주 중요한 역할을 담당한다.
- 얘는 요청이 들어왔을 때 ‘자동으로’ 지정된 view 를 찾아서 model 에 담은 내용을 view 로 연결해주는 역할을 한다.
- 참고로 view 를 찾아가는 역할을 하도록 도와주는건 viewResolver
spring Web 설정하기 : 아주 복잡하다
참고로 모든 xml 파일은 /spring_web01/src/main/webapp/WEB-INF 에 위치해야 한다
web.xml
servlet name 과 class mapping 을 적어준다.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" version="4.0">
<display-name>spring_web02</display-name>
<!-- 모든 요청은 servlet-name 에 선언된 dispatcher servlet 를 따라서 이동-->
<!-- dispatcher servlet 를 이용한 이동을 좀 더 설정하기 위해
/webapp/WEB-INF/dispatcher-servlet.xml 을 만들어주어야함
-->
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<!-- dispatcher 는 *.do 에 해당하는 모든 요청을 처리함 -->
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.jsp</welcome-file>
<welcome-file>default.htm</welcome-file>
</welcome-file-list>
</web-app>
disaptcher-servlet.xml
web.xml 에서 설정한 servlet-name 과 일치하도록하는게 중요하다.
즉 (servlet-name)-servlet.xml 로 파일명을 만들어야한다.
- prefix : viewResolver 을 통해 찾아가는 view 의 위치
- suffix : viewResolver 를 통해 찾아가는 view 파일의 확장자명
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- Handler Mapping 객체 설정 -->
<bean id="beanNameUrlHandlerMapping"
class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<!-- viewResolver 객체 설정 -->
<bean id="internalResourceViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- prefix 는 접두사, suffix 는 접미사 -->
<property name="prefix" value="/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 여기서 id 에 해당하는 .do 의 위치는 결국 jsp 의 실제 위치를 적어주어야한다 -->
<!-- 만약 /views/hello.jsp 라면 id 에 /views/hello.do 가 되어야한다-->
<!-- .do 인 이유는 요청 request 가 ~~.do 로 들어오기 때문!!-->
<bean id="/hello.do"
class="kr.kro.hjproject.control.HelloController"></bean>
<bean id="/greeting.do"
class="kr.kro.hjproject.control.HelloImpleController" p:name="pray"></bean>
</beans>
Controller & ModelAndView
- 컨트롤러에 해당하는 클래스는 반드시!! Controller 를 구현하는 구현 클래스가 되어야함
- 컨트롤러에서는 Model 과 View 를 합친 modelandView 객체를 사용함
- addObject 를 통해서 key 와 value 를 담을 수 있고, setviewName 을 통해서 찾아가야하는 view 의 이름을 설정할 수 있음
- 앞서 dispatcher-servlet 에서 설정한 prefix 가 / 였음으로 viewName 에 따로 /hello 로 작성할 필요는 없고 webapp 디렉토리에서의 위치와 파일명을 작성하면 됨
- 이때 webapp/views 위치에 jsp 파일이 있는 경우 vewName 에는 /views/파일명 이 들어가야한다
package kr.kro.hjproject.control;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
public class HelloController implements Controller{
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
// TODO Auto-generated method stub
ModelAndView mav = new ModelAndView();
mav.addObject("hello" , "fire"); // view 에 전달된 model 내용
mav.setViewName("hello"); // 찾아가야하는 view 이름
return mav;
}
}
JSP
- jsp 코드에서는 하이퍼링크 영역을 실제 페이지가 있는 영역으로 잡아야한다
- .do 로 요청을 하면 dispatcher servlet.xml 이 해당 요청에 맞는 controller 에 맞춰서 알아서 찾아가준다
<%@ 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>
<ul>
<li><a href="./views/showdata.do">showdata</a></li>
</ul>
</body>
</html>
활용 : Spring 에 DB 연결 후 내용 불러오기
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<display-name>spring_web05</display-name>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 초기화 할때 dispatcher 의 설정파일명을 변경한다는 의미
/web-inf/webapp.xml 에 있는 파일이 설정파일이 됨
-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/webapp.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-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>
webapp.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="beanNameUrlHandlerMapping"
class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<bean id=""
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- 시작 지점은 / , 웹 확장자명은 .jsp -->
<property name="prefix" value="/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!-- hjprojectDAO 를 Bean으로 생성 -->
<bean id="hjproject" class="kr.kro.hjproject.dao.HjprojectDAO"></bean>
<!-- showdata.do 에 대한 Controller 매핑 과 동시에 DI -->
<bean id="/views/showdata.do"
class="kr.kro.hjproject.control.ShowData"
c:hjproject-ref="hjproject">
</bean>
</beans>
MakeConnection : 싱글톤 패턴으로 생성한 DB 연결을 위한 Connection 객체
package makeConnction;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class MakeConnection implements ConnInfo{
private static MakeConnection mc;
private Connection conn = null;
private MakeConnection() {}
// 외부에서 getInstance 했을 때 mc 가 null 이면 mc 를 생성 후 return
// null 이 아니면 그대로 이미 만들어졌던 mc return
public static MakeConnection getInstance() {
if(mc != null) {
return mc;
}else {
mc = new MakeConnection();
return mc;
}
}
// 외부에서 getConnection 했을 때 내부에 Connection 이 없다면
// Connection 을 만들고 return
public Connection getConnection() {
if(conn==null) {
try {
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(url, user, passwd);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return conn;
}
}
DAO
package kr.kro.hjproject.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import kr.kro.hjproject.dto.HjprojectDTO;
import makeConnction.MakeConnection;
public class HjprojectDAO {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
StringBuffer sb = new StringBuffer();
public HjprojectDAO() {
// MakeConnection 은 싱글톤 패턴으로 생성
try {
Class.forName("com.mysql.jdbc.Driver");
conn = MakeConnection.getInstance().getConnection();
System.out.println("conn : " + conn);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public List<HjprojectDTO> selectAll() {
List<HjprojectDTO> list = new ArrayList<HjprojectDTO>();
sb.setLength(0);
sb.append("SELECT * FROM MEMBER");
try {
pstmt = conn.prepareStatement(sb.toString());
rs = pstmt.executeQuery();
while (rs.next()) {
int code = rs.getInt("member_code");
String id = rs.getString("mid");
String email = rs.getString("memail");
list.add(new HjprojectDTO(code, id, email));
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return list;
}
}
DTO
package kr.kro.hjproject.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class HjprojectDTO {
int code;
String id;
String email;
}
showDataController
package kr.kro.hjproject.control;
import java.sql.Connection;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
import kr.kro.hjproject.dao.HjprojectDAO;
import kr.kro.hjproject.dto.HjprojectDTO;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
// 컨트롤러는 컨트롤러 인터페이스를 구현!!
public class ShowData implements Controller{
// 생성자로 DI
private HjprojectDAO hjproject;
@Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
// TODO Auto-generated method stub
// hjproject 에서 DB 의 전체 내역을 뽑아옴
List<HjprojectDTO> list = hjproject.selectAll();
// modelandView 에 도착할 페이지 위치, 데이터명, 테이터를 담기
ModelAndView mav =
new ModelAndView("/views/showdata", "data", list);
return mav;
}
}
showdata.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor"
crossorigin="anonymous">
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2"
crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
crossorigin="anonymous"></script>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>showdata</h1>
<!-- EL 형식으로 해봤습니다 근데 EL 은 반복문없는건가 못하겠네요ㅠㅠ -->
<div class="container">
<table class="table table-bordered table-primary">
<tr>
<th>code</th>
<th>아이디</th>
<th>이메일</th>
</tr>
<tr>
<th>${requestScope.data[0].code }</th>
<th>${requestScope.data[0].id }</th>
<th>${requestScope.data[0].email }</th>
</tr>
<tr>
<th>${requestScope.data[1].code }</th>
<th>${requestScope.data[1].id }</th>
<th>${requestScope.data[1].email }</th>
</tr>
<tr>
<th>${requestScope.data[2].code }</th>
<th>${requestScope.data[2].id }</th>
<th>${requestScope.data[2].email }</th>
</tr>
</table>
</div>
</body>
</html>
'Java - Spring &&n SpringBoot' 카테고리의 다른 글
Spring MVC 패턴 && dispatcher (0) | 2022.07.18 |
---|---|
Spring Boot && MyBatis without xml : 스프링 부트와 마이 바티스 연동(xml 설정 빼고!) (0) | 2022.07.12 |
spring - 로그인 기능 구현하기 (3) HTTP서블릿 세션 활용하기 (0) | 2022.01.29 |
spring - 로그인 기능 구현하기 (2) 세션으로 로그인 하기 (0) | 2022.01.18 |
spring - 로그인 기능 구현하기 (1) 쿠키 활용, 쿠키의 취약점 (0) | 2022.01.16 |
댓글