today_is
[ spring ] 스프링과의 첫만남 본문
오늘의 목표
스프링 legacy maven 프로젝트를 실행시켜보자
기본 설정파일
root-context.xml
: 스캔 / bean 등록 ..
<?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:context="http://www.springframework.org/schema/context"
xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- Root Context: defines shared resources visible to all other web components -->
<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="jdbcUrl" value="jdbc:oracle:thin:@192.168.1.100:1521:xe" />
<property name="username" value="c##itbank" />
<property name="password" value="it" />
</bean>
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<constructor-arg ref="hikariConfig" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- classpath : src/main/java .java 형식의 자바 소스코드를 배치하는 위치
src/main/resources .java 가 아닌 기타 형식의 파일 (xml, properties 등)을 배치하는 위치
-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mapperLocations">
<list>
<value>classpath:mybatis/test2-mapper.xml</value>
<value>classpath:mybatis/test3-mapper.xml</value>
</list>
</property>
</bean>
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg ref="sqlSessionFactory" />
</bean>
<context:component-scan base-package="com.itbank.service" />
<context:component-scan base-package="com.itbank.repository" />
<!-- 지정한 패키지에서 인터페이스 형태의 DAO 를 스캔함
: 스캔후에는 xml 과 연결 가능
-->
<mybatis-spring:scan base-package="com.itbank.repository" />
</beans>
pom.xml
: 의존성 추가
<?xml version="1.0" encoding="UTF-8"?>
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itbank</groupId>
<artifactId>day01</artifactId>
<name>day01</name>
<packaging>war</packaging>
<version>1.0.0-BUILD-SNAPSHOT</version>
<properties>
<java-version>11</java-version>
<org.springframework-version>5.3.30</org.springframework-version>
<org.aspectj-version>1.6.10</org.aspectj-version>
<org.slf4j-version>1.6.6</org.slf4j-version>
</properties>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework-version}</version>
<exclusions>
<!-- Exclude Commons Logging in favor of SLF4j -->
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<!-- AspectJ -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j-version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.15</version>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
<exclusion>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jmx</groupId>
<artifactId>jmxri</artifactId>
</exclusion>
</exclusions>
<scope>runtime</scope>
</dependency>
<!-- @Inject -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<!-- Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/xerces/xercesImpl -->
<dependency>
<groupId>xerces</groupId>
<artifactId>xercesImpl</artifactId>
<version>2.12.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.oracle.database.jdbc/ojdbc10 -->
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc10</artifactId>
<version>19.21.0.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.30</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.zaxxer/HikariCP -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>4.0.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.15</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.1.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
<configuration>
<additionalProjectnatures>
<projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
</additionalProjectnatures>
<additionalBuildcommands>
<buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
</additionalBuildcommands>
<downloadSources>true</downloadSources>
<downloadJavadocs>true</downloadJavadocs>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<source>11</source>
<target>11</target>
<compilerArgument>-Xlint:all</compilerArgument>
<showWarnings>true</showWarnings>
<showDeprecation>true</showDeprecation>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<configuration>
<mainClass>org.test.int1.Main</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="4.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_4_0.xsd">
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<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>
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
HomeController
: 최상위경로(/)로 GET 요청을 받았을때 처리하는 controller
@Autowired private TestService testService
-> com.itbank.service 에 TestService 클래스가 만들어져 있어야한다.
내가 만든 클래스를 스프링 빈으로 만드는 방법 : 1) 스캔 2) 어노테이션
MVC 패턴에서는 JSP를 향한 forward를 기본으로 사용하기 때문에
요청 주소와 JSP의 이름은 분리해서 생각해야한다
home() 함수의 반환형은 ModelAndView
: 어트리뷰트, 리다이렉트 등등 그대로 넣을 수 있기 때문
package com.itbank.controller;
import java.sql.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;
import com.itbank.service.TestService;
@Controller
public class HomeController {
@Autowired private TestService testService;
@GetMapping("/") // 만약 최상위 경로로 GET 요청을 받으면 home() 함수를 실행하고 viewName을 "home"으로 설정
public ModelAndView home() {
ModelAndView mav = new ModelAndView("home");
String version = testService.getDBVersion(); // getDBVersion() : 함수명은 마음대로 설정
Date sysdate = testService.getSysDate();
mav.addObject("version", version);
mav.addObject("sysdate", sysdate);
return mav;
}
}
home.jsp
: 최상위경로를 실행하면 사용자에게 접속된 DB버전과 현재 시간이 출력된다
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<html>
<head>
<title>Home</title>
</head>
<body>
<h1>
Hello world!
</h1>
<h3>접속된 DB 버전 : ${version }</h3>
<h3>${sysdate }</h3>
<a href="member"><button>member</button></a>
</body>
</html>
MemberController
: Controller 어노테이션을 이용해서, 해당 클래스가 Controller 역할을 수행함을 명시하자
PathVariable
: 경로변수
요청 주소 상의 특정 경로의 값을 정수 및 문자열 형태로 전달받아서 파라미터와 유사하게 사용 가능
쿼리스트링을 안써도 된다
GetMapping
: 일반적으로, 데이터 처리 없이 페이지를 실행할때
PostMapping
: form 등의 submit 을 통한 데이터 처리가 일어난 상황일때
package com.itbank.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import com.itbank.service.MemberService;
import java.util.HashMap;
import java.util.List;
import com.itbank.member.MemberDTO;
@Controller
public class MemberController {
@Autowired private MemberService ms;
@GetMapping("/member")
public ModelAndView memberList() {
ModelAndView mav = new ModelAndView("member-list");
List<MemberDTO> list = ms.getMemberList();
mav.addObject("list", list);
return mav;
}
@PostMapping("/member")
public ModelAndView memberSearchList(@RequestParam HashMap<String, String> paramMap) {
// DTO 에 정의 되어 있지 않은 값을 여러개 받을 때는
// HashMap 을 사용할 수 있다 !!
// 단, HashMap은 파라미터 처리외에도 다양한 기능들이 있기 때문에
// 어노테이션 RequestParam 으로 파라미터 처리를 하라는 명시를 해주자
ModelAndView mav = new ModelAndView("member-list");
List<MemberDTO> list = ms.getMemberSearchList(paramMap);
mav.addObject("list", list);
return mav;
}
// a 태그를 이용한 이동에는 @GetMapping 으로 처리
@GetMapping("/member/add")
public ModelAndView memberAdd() {
ModelAndView mav = new ModelAndView("member-add");
return mav;
}
@PostMapping("/member/add")
public ModelAndView memberAdd(MemberDTO dto) {
// form 의 input name과 dto의 필드이름이 일치하다면
// 자동으로 파라미터가 입력된다
ModelAndView mav = new ModelAndView("redirect:/member");
int row = ms.add(dto);
System.out.println(row != 0 ? "추가 성공" : "추가 실패");
return mav;
}
@GetMapping("/member/delete/{idx}")
public ModelAndView delete(@PathVariable("idx")int idx) {
ModelAndView mav = new ModelAndView("alert");
int row = ms.delete(idx);
String message = row != 0 ? "삭제 성공" : "삭제 실패";
String url = "/member";
mav.addObject("message", message);
mav.addObject("url", url);
return mav;
}
}
MemberService
package com.itbank.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import com.itbank.member.MemberDTO;
import com.itbank.repository.MemberDAO;
@Service
public class MemberService {
@Autowired private MemberDAO dao;
public List<MemberDTO> getMemberList() {
List<MemberDTO> list = dao.selectList();
list.forEach(dto -> dto.setUserpw("******"));
return list;
}
public List<MemberDTO> getMemberSearchList(HashMap<String, String> paramMap) {
// mybatis 함수는 인자를 하나만 전달하거나, 아예 전달하지 않는다
// (= 인자를 2개이상 전달하지 않음. 즉, 파라미터는 묶어서 전달해야함)
List<MemberDTO> list = dao.selectSearchList(paramMap);
list.forEach(dto -> dto.setUserpw("******"));
return list;
}
public int add(MemberDTO dto) {
int row = dao.insert(dto);
return row;
}
public int delete(int idx) {
int row = dao.delete(idx);
return row;
}
}
MemberDTO
: 필드와 getter & setter 생성
IDX | NOT NULL | NUMBER |
USERID | NOT NULL | VARCHAR2(100) |
USERPW | NOT NULL | VARCHAR2(100) |
USERNAME | NOT NULL | VARCHAR2(100) |
NOT NULL | VARCHAR2(500) |
MemberDAO
: spring 에서는 일반적으로 DAO 를 interface로 생성한다
인터페이스는 어노테이션이 필요없지만, 가독성때문에 쓰기도 한다
package com.itbank.repository;
import java.util.HashMap;
import java.util.List;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;
import com.itbank.member.MemberDTO;
@Repository
public interface MemberDAO {
@Select("select * from member order by idx")
List<MemberDTO> selectList();
// pstmt 에는 ?에 대응하는 표현식이 2개 있다
// ${} 안에는 따옴표를 넣지 않음
// #{} 안에는 자료형에 따라서 따옴표를 적절히 넣어줌
@Select("select * from member where ${searchType} like '%' || #{searchKeyword} || '%' order by idx")
List<MemberDTO> selectSearchList(HashMap<String, String> paramMap);
@Insert("insert into member (userid, userpw, username, email)"
+ " values ( #{userid}, #{userpw} , #{username}, #{email} )")
int insert(MemberDTO dto);
@Delete("delete from member where idx = #{idx}")
int delete(int idx);
}
코드 해석 및 용어정리
context 파일
: 스프링빈을 만들때 사용하기 위한 설정파일
Dispather servlet
직접적으로 응답과 요청에 연관있는 애들 작성 (= 인터셉트 같은 애들)
root context 는 직접적으로 관련은 없는데 다 쓰는 것
servlet-context
<resources mapping="/resources/**" location="/resources/" />
-> 요청이 들어오면 이 경로에서 처리해라 (css나 이미지 폴더 등은 여기에 넣어두기)
[ 사용자 요청 처리 과정 ]
과정 1 | 과정 2 | 과정 3 | 과정 4 |
Controller | JDBC Template | DB | DAO |
사용자의 요청을 받는다 | Spring 과 DB 를 연결 | DB service 참조 | DAO 참조 |
[ DB 와 연결해서 결과를 처리하는 방법 ]
1) JdbcTemplate 2) SqlSessionTemplate 3) mapper auto injection
= myBatis-spring
Study_review
오늘은 spring legacy maven 프로젝트를 이용한 실습을 해보았다
spring 프로젝트는 처음에 설정파일만 잘 준비시켜놓는다면,
jsp로만 구성된 dynamic 프로젝트를 할때보다 훨씬 수월하게 실행할 수 있을 것 같다
사실 다이나믹 프로젝트할때 라이브러리를 일일이 넣어주는게 너무 너무 귀찮았었다..
또한 미리 이론을 학습해서인지, controller와 service, DAO 간의 데이터 움직이는 순서는 얼추 이해가 되었다 !!
새롭게 프레임워크를 배우게 되었으니, 앞으로도 열심히 해야겠다
'spring' 카테고리의 다른 글
[ spring ] 어노테이션 문법정리 (0) | 2024.01.02 |
---|---|
[ spring ] Interceptor (0) | 2024.01.01 |
[ spring ] mybatis mapper 이용 (0) | 2023.12.28 |
[ spring ] HashComponent 이용하기 (0) | 2023.12.28 |
[ spring ] 스프링 구조파악 (0) | 2023.12.26 |