1. 데이터 입력

 - keyboard : scan()

n <- scan()

ss <- scan(what ="")  # 문자열 입력

df1 <- data.frame()
df1 <- edit(df1)      # data frame 수정창 출력

 

2 파일 읽기

getwd()      # 작업경로 확인. setwd()
list.dirs()  # 작업경로의 폴더 정보
list.files() # 작업경로의 파일 정보

stud <- read.table(file = "testdata/student1.txt", header = TRUE) #테이블 read. header(defalut : FALSE)

stud1 <- read.table(file = "testdata/student2.txt", header = TRUE, sep =";") #sep : 구분자 

stud2 <- read.table(file = "testdata/student3.txt", header = TRUE, sep =" ", na.strings = "-") # na.strings : 해당 값은 NA로 처리

stud3 <- read.csv(file = "testdata/student4.txt", header = TRUE, na.strings = "-") # read.csv : csv 파일 읽기 (csv 구분자 , 로 된 파일)
class(stud3) # data.frame

datas <- read.csv("https://raw.githubusercontent.com/pykwon/Test-datas-for-R/master/agedata.csv") # 웹 data 가져오기

 

3 출력

 - console

x <- 10; y <- 20; z <- x*y
cat(x,y,z)
cat("결과는", z)
print(x)
print(x,y) # 1개만 출력에 참여

 

4 자료 저장

sink("output/my.txt") # 저장 선언
datas <- read.csv("https://raw.githubusercontent.com/pykwon/Test-datas-for-R/master/agedata.csv")
head(datas,5)
kbs <- 9
kbs
sink() # 저장 작업 종료
#DataFrame 저장
name <- c("관우","장비", "유비")
age <- c(35,33,20)
gender <- c("M","M","F")
myframe <- data.frame(name, age, gender)
myframe
# name age gender
# 1 관우  35      M
# 2 장비  33      M
# 3 유비  20      F

write.table(myframe, "output/my1.txt") #파일저장
write.table(myframe, "output/my2.txt", fileEncoding ="utf-8")
read.table("output/my1.txt") #파일 불러오기

 

'BACK END > R' 카테고리의 다른 글

[R] R 정리 6 - 조건문, 반복문  (0) 2021.01.28
[R] R 정리 5 - 도수 분포표  (0) 2021.01.28
[R] R 정리 3 - 자료구조  (0) 2021.01.27
[R] R 정리2 - 변수  (0) 2021.01.26
[R] R 정리1 - 환경구축  (0) 2021.01.26

3. 자료구조(객체타입)

1. vector : 1차원 배열

2. matrix : 2차원 배열


 

1. vector : 1차원 배열형태의 자료구조. - 동일한 데이터만 저장

1 벡터 생성

year <- 2021
is.vector(year)          # is.vector() : 벡터인지 확인

name <-'tom'
is.vector(name)

year
year[1]                  # index가 1부터 시작

seq(1,5)                 # seq() : 수열 생성
1:5

seq(1,10,2)              # 1~10까지 2 간격으로 생성.
seq(1,10,length.out = 4) # 1~10까지 간격이 같은 4개의 수열.

rep(1:3, 3)              # 1~3까지 3번 반복. 1 2 3 1 2 3 1 2 3
rep(1:3, times=3)        # 동일
rep(1:3, each=3)         # 1~3까지 각각 반복. 1 2 3 1 2 3 1 2 3

aa <- c(10,20,30,-10,-5)

x<- c(1,3,5)
y<- c(1:3,1:3)

 

2 이름 설정

age <- c(10,20,30)
names(age) <- c("홍길동", "김길동", "이길동") # names(x) <- : age에 이름을 설정
age[1]                                        # index로 값 호출
age["홍길동"]                                 # 이름으로 값 호출
age[10] <- 50                                 # 없는 값은 NA 
length(age)                                   # 길이는 10
age <- NULL                                   # NULL값 set

 

3 우선순위

kk <- c(1, 3, FALSE, T, 3.5, 'hi') # 벡터는 값은 데이터 타입을 가지기 때문에 우선순위에 따라 전체 타입이 정해짐
                                   # 우선순위 : 문자열 > 실수 > 정수 > bool

 

4 벡터 요소 조회(index) : 슬라이싱

v1 <-c(13,-5,20:23, 12, -2:3)
v1 <- append(v1, 60, after=5)  # v1벡터의 5번째 인자 이후에 60이 들어간다.
v1[1]                          # 첫번째 값. index 1부터 시작
v1[c(1, 3, 6)]                 # 1, 3, 6 인덱스 값
v1[1:5]                        # 1~5 인덱스 값
v1[c(3, 5, 1, 8, 9)]
v1[-1]                         # 1번째 요소를 제외한 나머지를 반환
v1[-c(1, 3, 5)]                # 1, 3, 5번째 요소를 제외한 나머지

 

5 연산

# 하나의 벡터 연산
a <-1:5
a + 5         # 각 요소에 연산적용
a ^ 2         # 제곱
a ** 2        # 제곱
sqrt(a)       # 제곱근
sqrt(a) ** 2  # a

# 두 개의 벡터 연산
a <- 1:3
b <- 4:6
a + b      # 각 index끼리 연산
a * b
a + 10
a[4] <-2
b[4] <-2

 

6 집합

a               # 1 2 3 2
b               # 4 5 6 2
union(a,b)      # 합집합. 중복값 하나만 포함.   1 2 3 4 5 6
c(a, b)         # 중복 허용.                    1 2 3 2 4 5 6 2
setdiff(a,b)    # 차집합. a-b                   1 3
intersect(a, b) # 교집합                        2

2. matrix : 2차원 배열

 

1

a <- 1:8
dim(a) <- c(2, 4)          # 2행 4열의 2차원 배열을 생성.(a의 원소)
                           #     [,1] [,2] [,3] [,4]
                           #[1,]    1    3    5    7
                           #[2,]    2    4    6    8
class(a)                   # "matrix" "array"
m <- matrix(1:5) # 5행 1열
m
dim(m)           # 5행 1열
m <- matrix(1:9, nrow = 3)            # 3열
#     [,1] [,2] [,3]
#[1,]    1    4    7
#[2,]    2    5    8
#[3,]    3    6    9

m <- matrix(1:9, nrow = 3, byrow = T) # 행 우선
#     [,1] [,2] [,3]
#[1,]    1    2    3
#[2,]    4    5    6
#[3,]    7    8    9

m2 <- matrix(1:10,2)                  # 2행
dim(m2)                               # 2 5
m2 <- matrix(1:9, 3)                  # 3행
class(m2)                             # matrix array 

 

2 인덱싱

m2[1,]    # 1행 전체
m2[,1]    # 1열 전체
m2[2,3]   # 2행 3열
m2[2,2:4] # 2행 2,3,4열

 

3 이름 설정

m2 <- matrix(1:12, 3)
colnames(m2) <- c("a", "b", "c", "d")
rownames(m2) <- c("r1", "r2", "r3")
#    a b c  d
# r1 1 4 7 10
# r2 2 5 8 11
# r3 3 6 9 12

 

4 연산

a <- matrix(c(1,2,3,4),2,2)
b <- matrix(5:8, 2)
a + b
a - b
a * b
a %*% b             # 행렬 곱(내적)

diag(a)             # 행, 열 인덱스가 같은 라인의 요소 
diag(2)
# 1    0
# 0    1

solve(a)            # 역행렬
solve(solve(a))
a %*% solve(a) %*% a

 

5 행 묶음

x1 <- c(5, 40, 50:52)
# 5 40 50 51 52
x2 <- c(30, 5, 6:8)
# 30  5  6  7  8

mr <- rbind(x1, x2) # 행 묶음
#     [,1] [,2] [,3] [,4] [,5]
# x1    5   40   50   51   52
# x2   30    5    6    7    8

mc <- cbind(x1, x2) # 열 묶음
#      x1 x2
# [1,]  5 30
# [2,] 40  5
# [3,] 50  6
# [4,] 51  7
# [5,] 52  8

 

6. apply()

x <- matrix(1:9, 3)
#      [,1] [,2] [,3]
# [1,]    1    4    7
# [2,]    2    5    8
# [3,]    3    6    9

apply(x, 1, max)  # max함수를 실행하는 함수(행방향)
# 7 8 9
apply(x, 1, min)  # min함수를 실행하는 함수(행방향)
apply(x, 1, mean) # 행 방향 평균
# 4 5 6
apply(x, 2, mean) # 열 방향 평균
# 2 5 8

func <- function(x){
  x + c(5, 10, 15)
}
func(x)
#      [,1] [,2] [,3]
# [1,]    6    9   12
# [2,]   12   15   18
# [3,]   18   21   24

apply(x, 1, func) # 행렬 or 배열에 적용
#      [,1] [,2] [,3]
# [1,]    6    7    8
# [2,]   14   15   16
# [3,]   22   23   24

lapply(x, func) # 결과가 list
# [[1]]
# [1]  6 11 16
# [[2]]
# [1]  7 12 17
# [[3]]
# [1]  8 13 18
# [[4]]
# [1]  9 14 19
# [[5]]
# [1] 10 15 20
# [[6]]
# [1] 11 16 21
# [[7]]
# [1] 12 17 22
# [[8]]
# [1] 13 18 23
# [[9]]
# [1] 14 19 24

sapply(x, func) # 결과가 벡터, 행렬 or 배열
#      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
# [1,]    6    7    8    9   10   11   12   13   14
# [2,]   11   12   13   14   15   16   17   18   19
# [3,]   16   17   18   19   20   21   22   23   24

iris # 붓 꽃 데이터 Sepal.Length Sepal.Width Petal.Length Petal.Width Species
dim(iris)  # 150   5
apply(iris[,1:4], 2, mean)
lapply(iris[,1:4], mean)
sapply(iris[,1:4], mean)

 


3. Array : 다차원 배열

d <- c(1:12)
class(d)                              # class 확인- "integer"
is.vector(d)                          # TRUE

arr1 <- array(d)                      # array() : 배열 생성함수
class(arr1)                           # class 확인- "array"
is.vector(arr1)                       # FALSE
is.array(arr1)                        # TRUE

dim(arr1)                             # 12
arr2 <- array(c(1:12), dim=c(6,2))
#      [,1] [,2]
# [1,]    1    7
# [2,]    2    8
# [3,]    3    9
# [4,]    4   10
# [5,]    5   11
# [6,]    6   12
dim(arr2) # 6 2

arr3 <- array(c(1:12), dim=c(3,2,2))
# , , 1
# 
#      [,1] [,2]
# [1,]    1    4
# [2,]    2    5
# [3,]    3    6
# 
# , , 2
# 
#      [,1] [,2]
# [1,]    7   10
# [2,]    8   11
# [3,]    9   12
dim(arr3) # 3 2 2 - 행 열 면

arr3[,,1]
arr3[,1,1]
arr3[1,,1]
arr3[1,1,1]

a1 <- array(1:8, dim = c(2,2,2))
a2 <- array(8:1, dim = c(2,2,2))

a1 + a2
a1 * a2
a1 %*% a2
sum(a1 * a2)

4. List : 서로 다른 타입의 자료를 기억 가능. java의 레코드형 기억장소. c: 구조체.

li <- list('1', '이순신', 70, '2', '한송이', 80)
class(li)          # list
unli <- unlist(li) # list에서 되돌리기

num <- list(1:5, 6:10, c("a", "b", "c")) # 1, 2, 3 key에 값을 넣는다.
num[1]; print(class(num[1]))             # list
num[[1]]; print(class(num[[1]]))         # integer
num[[1]][2]                              # 1번 list의 index 2번의 값

num2 <- list(x=1:5, y=6:10)              # x, y key에 값을 넣는다.
num2$x                                   # num list의 x key의 데이터
num2$y

mem <- list(name='tom', age=22)          # name, age key에 값을 넣는다.

a<-list(c(1:5))                          # 1~5
b <- list(6:10)                          # 6~10
result <- lapply(c(a,b), max)            # 결과 값을 list로 반환
# [[1]]
# [1] 5
# 
# [[2]]
# [1] 10

5. DataFrame : DB의 테이블 구조와 유사.
 - vetor로 DataFrame 생성

no <- c(1,2,3)
name <- c("tom", "james", "jonh")
pay <- c(300, 400, 500)
df <- data.frame(bunho = no, irum = name, imkum = pay)
#bunho  irum imkum
#1     1   tom   300
#2     2 james   400
#3     3  jonh   500
class(df)   # data.frame
df[1:2]
df[c(1,3)]
df[2,2]
df[-1,]
df[,-1]
df <- data.frame(irum = c('aa', 'bb', 'cc'), nai = c(22,25,33), row.names = c("one","two", "three"))
df
nrow(df)      # 행 수
ncol(df)      # 열 수
str(df)       # 구조
names(df)     # 이름 확인
head(df, n=2) # 앞의 2개 데이터 출력
tail(df, n=2) # 뒤의 2개 데이터 출력
names(iris)
head(iris,3)
class(iris)   # data.frame
class(Nile)   # ts
class(ChickWeight)  #"nfnGroupedData" "nfGroupedData"  "groupedData"    "data.frame" 

 

- matrix로 DataFrame 생성

m <- matrix(c(1,'hong',300,2,'lee',350,3,'kim',320), 3, by =T)
# [,1] [,2]   [,3] 
# [1,] "1"  "hong" "300"
# [2,] "2"  "lee"  "350"
# [3,] "3"  "kim"  "320"
mdf <- data.frame(m)
colnames(mdf) <- c("c1", "c2", "c3") # column name설정
#   c1   c2  c3
# 1  1 hong 300
# 2  2  lee 350
# 3  3  kim 320

mdf$c1                 # column data
mdf['c1']              # column data
mdf[1,2]               # 1행 2열

'BACK END > R' 카테고리의 다른 글

[R] R 정리 6 - 조건문, 반복문  (0) 2021.01.28
[R] R 정리 5 - 도수 분포표  (0) 2021.01.28
[R] R 정리 4 - 데이터 입출력  (0) 2021.01.28
[R] R 정리2 - 변수  (0) 2021.01.26
[R] R 정리1 - 환경구축  (0) 2021.01.26

① 실행하기

편집  - 전부 실행하기
ctrl + Enter : 한줄 실행
코드 블록 잡기 + ctrl + Enter : 일부분 실행
ctrl + alt + R : 전체실행

ctrl + l  : console창 비우기

ctrl + shift + c : 블록영역 주석처리

# : 주석

 

 

② 변수 : R에서는 모든 참조형 변수를 사용한다.

 

 - 대입

a <- 1
a=2
3->a
a.kor<-4; # 가능 하나 지양
a_kor<-4

 

 - 출력

cat(a)
cat(a, a.kor)   # cat() : 복수의 데이터
print(a, a.kor) # print() : 하나만 출력 - a만 출력
a
(a)

 

 - 변수유형

k <- 9             # 숫자는 기본 double
object.size(k)     # object.size() : 객체 크기 - 56 bytes
typeof(k)          # typeof() : 타입 - double

k <- as.integer(k) # as.integer() : integer로 type으로 변경
typeof(k)

s <- 5L            # L은 정수형 리터럴
typeof(s)          # integer

ss <- 'tom'        # 문자형
typeof(ss)         # character

bb<-TRUE           # 논리형 - T
typeof(bb)         # logical

 

 - NA, NaN, NULL

aa <- NA        # 결측값 : 값으로 인식은 하나 값 자체는 없음.
typeof(aa)      # logical
is.na(aa)       # is.na() : na 인지 판단.

bb <- NaN       # 값으로 인식은 하나 수학적으로 정의되지 않음.
typeof(bb)      # double

0 * Inf         # NaN
Inf + -Inf      # NaN

cc <- NULL      # 값으로 인식하지 않음.
typeof(cc)      # NULL

sum(2, 3)       # 5
sum(2, 3, NULL) # 5
sum(2, 3, NA)   # NA
sum(2, 3, NaN)  # NaN

 

 - 벡터, factor

ff <-c(2,2,3,2,4) # c() : 벡터 생성.
ff                #                              [1] 2 2 3 2 4
str(ff)           # str() : data 구조 확인 num [1:5] 2 2 3 2 4
ff<-factor(ff)    # factor() : 범주형 데이터 생성 (레벨을 가지는 배열)
str(ff)           # Factor w/ 3 levels "2","3","4": 1 1 2 1 3
                  # 2,3,4의 레벨을 가지며, 각요소의 레벨 index를 인자로 가진다.

 

 - 함수

func <- function(){  # 함수 생성
  return ('good')
}
func()               # 함수 호출
typeof(func)         # "closure"8

 

 - 데이터 정보 확인

k <-9
cat(k, typeof(k), class(k), mode(k))   # 9 double numeric numeric
                                       # mode() : old type 확인.
                                       # class() : class 확인
str(k)                                 # num 9
is(k)                                  # [1] "numeric" "vector" 

 

 - 메모리 clear

ls()          # ls() : 메모리에 있는 객체 리턴
ls.str()
rm(kbs)       # rm() : 메모리 제거
rm(list=ls()) # 모든 변수 메모리 제거
gc()          # 가비지 컬렉터. 점유된 메모리 제거.

 

 - pakage  : data + 기능 + 알고리즘 꾸러미 : 라이브러리

available.packages()         # available.packages() : 사용 가능한 pakage 목록 확인.
dim(available.packages())    # dim() : 객체의 차원수 확인
                             # R에서 제공하는 라이브러리 수 확인 (16969)
length(installed.packages()) # installed.packages() : 설치된 package 리스트 . 
                             # 설치된 라이브러 수 확인 (480)

install.packages("plyr")     # install.packages() : 라이브러리 설치
library(plyr)                # library() : 라이브러리를 load. (import)
                             # plyr : 연습용 데이터 라이브러리
data(package='plyr')         # data(package='') : 라이브러리 데이터 확인.
baseball                     # plyr column
ozone                        # plyr column
remove.packages("plyr")      # remove.packages() : 라이브러리 삭제

 

 - 데이터 확인

data()
Nile          # 나일강의 데이터를 제공하는 라이브러리
head(Nile)    # 첫 데이터
tail(Nile)    # 마지막 데이터
hist(Nile)    # 히스토그램 출력
density(Nile) # 밀도
plot(density(Nile))

 - 기타

help("mean")                # 도움말
x <- c(0:10, 50)
xm <- mean(x)               # 표본평군
c(xm, mean(x, trim = 0.10)) # mean(x, trim = 0.1) : 절사평균. x의 데이터를 크기 순 
                            # 나열 후 0 ~ 0.5의 trim 값에 따라 앞/뒤를 제거 후 평균을 구한다.

 

'BACK END > R' 카테고리의 다른 글

[R] R 정리 6 - 조건문, 반복문  (0) 2021.01.28
[R] R 정리 5 - 도수 분포표  (0) 2021.01.28
[R] R 정리 4 - 데이터 입출력  (0) 2021.01.28
[R] R 정리 3 - 자료구조  (0) 2021.01.27
[R] R 정리1 - 환경구축  (0) 2021.01.26

1) R 설치

www.r-project.org/

 

R: The R Project for Statistical Computing

 

www.r-project.org

② Download - CRAN

 

③ Korea - ftp.harukasan.org/CRAN/

 

④ Download R for Windows

 

⑤ base

 

⑥ Download R 4.0.3 for Windows

 

⑦ R-4.0.3-win.exe 관리자권한으로 실행 

 

 

2) R studio 설치

① rstudio.com/

 

RStudio | Open source & professional software for data science teams

RStudio provides free and open source tools for R and enterprise-ready professional software for data science teams to develop and share their work at scale.

rstudio.com

② product  - r studio

 

③ RStudio Desktop
Donload rstrudio desktop


④ Free - Download


⑤ RStudio-1.4.1103.exe

 

⑥ RStudio-1.4.1103.exe 관리자권한으로 실행

 

⑦ 경로 접속

C:\ProgramData\Microsoft\Windows\Start Menu\Programs\RStudio
Rstudio - 오른쪽 클릭 - 속성 - 호환성 - 관리자 권한으로 이 프로그램 실행

 

⑧ tools - global options
General - defauly working directory - C:/work/rsou
code - savig - default text encoding : UTF-8

'BACK END > R' 카테고리의 다른 글

[R] R 정리 6 - 조건문, 반복문  (0) 2021.01.28
[R] R 정리 5 - 도수 분포표  (0) 2021.01.28
[R] R 정리 4 - 데이터 입출력  (0) 2021.01.28
[R] R 정리 3 - 자료구조  (0) 2021.01.27
[R] R 정리2 - 변수  (0) 2021.01.26

[목차]

① DB 연동

② Controller

③ Aspect


[내용]

= sprweb22_aop_login

① DB 연동

- Configuration(xml)

<configuration>
 <typeAliases>
 	<typeAlias type="pack.model.JikwonDto" alias="dto"/>
 </typeAliases>
 <!--  DB 연결을 root-context.xml에서 하도록 수정.-->
 <mappers>
  <mapper resource="pack/mybatis/DataMapper.xml" />
 </mappers>
</configuration>

 

 

 - DataMapper(xml)

<mapper namespace="dev">

 <select id="selectJikwonAll" resultType="dto">
  select jikwon_no, jikwon_name, jikwon_jik, jikwon_gen, buser_name
  from jikwon left outer join buser
  on jikwon.buser_num = buser.buser_no
 </select>
 
 <select id="selectLoginData" resultType="dto" parameterType="string">
 	select jikwon_no, jikwon_name
 	from jikwon
 	where jikwon_no=#{no}
 </select>
 
</mapper>

 

 

- MyDataSource

public class MyDataSource extends DriverManagerDataSource {
	public MyDataSource() {
		setDriverClassName("org.mariadb.jdbc.Driver");
		setUrl("jdbc:mysql://127.0.0.1:3306/test");
		setUsername("root");
		setPassword("123");
	}
}

 

 

- root-context(xml)

	<bean id="dataSource" class="pack.model.MyDataSource"/>
    
	<bean class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource"/>
		<property name="configLocation" value="classpath:pack/mybatis/Configuration.xml"/>
	</bean>

 

 

② Controller

- main(jsp)

<body>
	<h2>메인</h2>
	<a href="jikwonlist">직원 보기</a>
</body>

 

 

- JikwonController

@Controller
public class JikwonController {
	@Autowired
	//@Qualifier("JikwonImpl")
	private JikwonInter jikwonInter; 
	
	@RequestMapping("jikwonlist")
	public ModelAndView jikwonShow() {
		//모델과 통신
		List<JikwonDto> list = jikwonInter.jikwonList();
		ModelAndView view = new ModelAndView("jikwonlist");
		view.addObject("list", list);
		return view;
	}
}

 

 

- JikwonInter

public interface JikwonInter {
	List<JikwonDto> jikwonList();
	JikwonDto getLoginInfo(String bun);
}

 

 

- JikwonImpl

@Repository
public class JikwonImpl extends SqlSessionDaoSupport implements JikwonInter{

	@Autowired
	public JikwonImpl(SqlSessionFactory factory) {
		setSqlSessionFactory(factory);
	}
	
	@Override
	public List<JikwonDto> jikwonList() {
		return getSqlSession().selectList("selectJikwonAll");
	}

	@Override
	public JikwonDto getLoginInfo(String bun) {
		return getSqlSession().selectOne("selectLoginData",bun);
	}
}

 

 

 - JikwonDto

public class JikwonDto {
	private String jikwon_no, jikwon_name, jikwon_jik, jikwon_gen, buser_name;
	//getter/setter
}

 

 

- jikwonlist(jsp)

<body>
	<h2>직원자료</h2>
	<% 
	if(session.getAttribute("name") != null){
		out.print("<a href='logout'>로그아웃</a>");
	}
	%>
	<table border="1">
		<tr>
			<th>사번</th><th>직원명</th><th>부서명</th><th>직급</th><th>성별</th>
		</tr>
		<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
		<c:forEach var="j" items="${list}">
		<tr>
			<td>${j.jikwon_no}</td>
			<td>${j.jikwon_name}</td>
			<td>${j.buser_name}</td>
			<td>${j.jikwon_jik}</td>
			<td>${j.jikwon_gen}</td>
		</tr>		
		</c:forEach>
	</table>
</body>

 

 

③ Aspect

- LoginClass

public class LoginClass {
	public boolean loginCheck(HttpServletRequest request, HttpServletResponse response)
					throws Exception{
		HttpSession session = request.getSession();
		
		if(session.getAttribute("name") == null) {
			response.sendRedirect("login");
			return true;
		}else {
			return false;
		}
	}
}

 

 

- MyAdvice

@Aspect
@Component
public class MyAdvice {
	@Autowired
	private LoginClass loginClass;
	
	@Around("execution(* jikwonShow*(..))")
	public Object aopProcess(ProceedingJoinPoint joinPoint) throws Throwable{
		HttpServletRequest request = null;
		HttpServletResponse response = null;
		
		for(Object obj:joinPoint.getArgs()) {
			if(obj instanceof HttpServletRequest) {
				request = (HttpServletRequest)obj;
			}
			if(obj instanceof HttpServletResponse) {
				response = (HttpServletResponse)obj;
			}
		}
		
		if(loginClass.loginCheck(request, response)) {
			return null;
		}
		
		Object object = joinPoint.proceed();
		return object;
	}
}

 

 

- login(jsp)

<body>
	<h2>로그인</h2>
	<form action="login" method="post">
	직원번호 : <input type="text" name="no"><br>
	직원이름 : <input type="text" name="name"><br>
	<input type="submit" value="로그인">
	</form>
</body>

[목차]

12. Ajax

① XML 형식 출력

② JSON 형식 출력

③ AJAX 처리

④ AJAX 처리- DB연동


[내용]

① XML 형식 출력

= sprweb17_xml

- index.jsp

<body>
  <h2>스프링으로 xml 형태의 결과 반환연습</h2>
  <a href="member">출발</a><br>
</body>

 => 요청명 member 전달.(GET방식)

 

 

- myform.jsp

<body>
	<h2>자료입력</h2>
	<form action="member" method="post">
	name : <input type="text" name="name" value="tom"><br>
	age : <input type="text" name="age" value="22"><br>
	<input type="submit">
	</form>
	<hr>
	<form action="member_xml" method="post">
	name : <input type="text" name="name" value="tom"><br>
	age : <input type="text" name="age" value="22"><br>
	<input type="submit">
	</form>
</body>

 => 상기 <form>태그 요청명 member 전달.(POST방식)

 => 하기 <form>태그 요청명 member_xml 전달.(POST방식)

 

- MemberController

@Controller
public class MemberController {
	@RequestMapping(value="member", method = RequestMethod.GET)
	public String formBack() {
		return "myform";
	}
	
	@RequestMapping(value="member", method = RequestMethod.POST)
	@ResponseBody // 자바객체를 Http 응답객체로 클라이언트에 전송 가능.
	public String submit(@RequestBody String formData) {
		// @RequestBody는 요청 몸체(body)에 있는 client의 요청 값을 그대로 받아들임.
		System.out.println("formData : "+formData); // name=tom&age=22
		formData+="hello";
		return formData; // @ResponseBody 사용 시 formData가 가진 값을 클라이언트에게 바로 송신.
	}
	...
}

 => @RequestBody : 요청의 Boby 값을 변수에 대입. ex) name=tom&age=22

 => @ResponseBody : 자바객체를 Http 응답객체로 클라이언트에 전송. 리턴 값을 클라이언트에 송신.

 

@Controller
public class MemberController {
	...
	@RequestMapping(value="member_xml", method = RequestMethod.POST)
	@ResponseBody
	public XmlMessageList submit_xml(@RequestParam("name") String name,
					@RequestParam("age") String age) {
		System.out.println(name+" "+age);
		return getXml(name, age);
	}
	
	public XmlMessageList getXml(String name, String age) {
		List<XmlMessage> messages = Arrays.asList(
				new XmlMessage(name, age),
				new XmlMessage("oscar", "25"),
				new XmlMessage("emma", "24")
				);
		return new XmlMessageList(messages);
	}
}

 => 요청명 member_xml(Post방식) 일 경우 실행.

 => @ResponseBody : getXml()의 리턴값을 클라이언트에서 출력한다.

 => 

 

 

- XmlMessage

@XmlAccessorType(XmlAccessType.FIELD)
//@XmlType(name="", propOrder = {"name","age"})
public class XmlMessage {
	private String name;
	private String age;
	
	public XmlMessage() {
	}
	
	public XmlMessage(String name, String age) {
		this.name = name;
		this.age = age;
	}
	
	public String getName() {
		return name;
	}
	
	public String getAge() {
		return age;
	}
	
	public void setAge(String age) {
		this.age = age;
	}
	public void setName(String name) {
		this.name = name;
	}
}

 

- XmlMessageList

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "msg-list") // Root Element 이름 지정
public class XmlMessageList {
	
	@XmlElement(name = "msg")
	private List<XmlMessage> messages;
	
	public XmlMessageList() {
	}
	
	public XmlMessageList(List<XmlMessage> messages) {
		this.messages = messages;
	}
	
	public List<XmlMessage> getMessages(){
		return messages;
	}
}


② JSON 형식 출력

 = sprweb18_json

 - index.jsp

<body>
	<h2>JSON 기초연습</h2>
	<a href="list1?name=james">json 처리1 : 단일자료</a><br>
	<a href="list2">json 처리2 : 복수자료</a><br>
</body>

 - JsonController

@Controller
@RequestMapping("list1")
public class JsonController {
	@Autowired
	private MyModel myModel;
	
	@RequestMapping(method = RequestMethod.GET)
	@ResponseBody // 결과를 JSON형식으로 클라이언트 브라우저에 송신.
	public MyModel getJson(@RequestParam("name") String name) {
		myModel.setName(name);
		myModel.setSkills(new String[] {"자바 전문 개발자", "DB 선수", "web 전문가"});
		return myModel;
	}
}

 

 - JsonController2

@Controller
@RequestMapping("list2")
public class JsonController2 {
	@RequestMapping(method = RequestMethod.GET)
	@ResponseBody
	public Map getJsons() {
		ArrayList<Map<String, String>> dataList = new ArrayList<Map<String, String>>();
		
		Map<String, String> data =new HashMap<String, String>();
		
		data.put("name", "한국인");
		data.put("age", "22");
		dataList.add(data);
		
		data =new HashMap<String, String>();
		data.put("name", "신기해");
		data.put("age", "32");
		dataList.add(data);
		
		data =new HashMap<String, String>();
		data.put("name", "한가해");
		data.put("age", "33");
		dataList.add(data);
		
		//return data; // 마지막 자료만 리턴됨.
		Map<String, Object> data2 = new HashMap<String, Object>();
		data2.put("datas", dataList);
		
		return data2;
	}
}

 

 

 - MyModel

@Component
public class MyModel {
	private String name;
	private String skills[];
	
	public String getName() {
		return name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public String[] getSkills() {
		return skills;
	}
	
	public void setSkills(String[] skills) {
		this.skills = skills;
	}
}

③ AJAX 처리

= sprweb19_ajax

 - json_test.jsp

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){ // : text만 먼저 수행.
// js : window.onload= function(){} : 모든 페이지 로딩 완료 후 수행.
	//alert("수행");
	$("#btnOk1").click(function(){
		//alert("수행2");
		$("#showData").html("");
		$.ajax({ // get()/post()
			type:"get",
			url:"list1",
			data:{"name":"john"}, //name = "john"
			dataType:"Json",
			success:function(data){
				//alert(data);
				var str ="";
				str += data.name +"<br>";
				str += data.skills[0] +" ";
				str += data.skills[1] +" ";
				str += data.skills[2] +" ";
				$("#showData").html(str);
			},
			error:function(data){
				$("#showData").text("에러 발생");
			}
		});
	});
	$("#btnOk2").click(function(){
		//alert("수행3");
		$.ajax({
			type:"get",
			url:"list2",
			dataType:"Json",
			success:function(data){
				var str = "<table>";
				var list = data.datas;
				$(list).each(function(ind, obj){
					str += "<tr>";
					str += "<td>"+obj["name"]+"</td>";
					str += "<td>"+obj["age"]+"</td>";
					str += "</tr>";
				});
				str += "</table>";
				$("#showData").html(str);
			},
			error:function(data){
				$("#showData").html("<b>에러 발생</b>");
			}
			
		});
	});
});
</script>
</head>
<body>
	<h2>* Ajax</h2>
	<input type="button" id="btnOk1" value="한개의 자료 읽기"><br>
	<input type="button" id="btnOk2" value="여러개의 자료 읽기"><br>
	<div id="showData">msg</div>
</body>


④ Ajax처리 - DB연동

 - DB연동

= sprweb20_ajax_db

- servlet-context.xml

<context:component-scan base-package="pack.controller" />
<context:component-scan base-package="pack.model" />

 

 

 - root-context.xml

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
	<property name="locations">
		<value>classpath:pack/mybatis/db.properties</value>
	</property>
</bean>

<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
	<property name="driverClass" value="${driver}"/>
	<property name="url" value="${url}"/>
	<property name="username" value="${username}"/>
	<property name="password" value="${password}"/>
</bean>

<bean class="org.mybatis.spring.SqlSessionFactoryBean">
	<property name="dataSource" ref="dataSource"/>
	<property name="configLocation" value="classpath:pack/mybatis/Configuration.xml"></property>
</bean>

 

 

- db.properties

driver=org.mariadb.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/test
username=root
password=123

 

 

 - Configuration.xml

<configuration>
 <typeAliases>
 	<typeAlias type="pack.model.SangpumDto" alias="dto"/>
 	<typeAlias type="pack.controller.SangpumBean" alias="formBean"/>
 </typeAliases>
 <!--  DB 연결을 root-context.xml에서 하도록 수정.-->
 <mappers>
  <mapper resource="pack/mybatis/DataMapper.xml" />
 </mappers>
</configuration>

 

 

- DataMapper.xml

<mapper namespace="dev">
 <select id="selectAll" resultType="dto">
  select * from sangdata
 </select>
</mapper>

 

 

 - index.jsp

<body>
	<ul>
		<li>메뉴 1</li>
		<li>메뉴 2</li>
		<li><a href="sangpum">상품보기1(json)</a></li>
		<li><a href="sanglist.jsp">상품보기2(ajax)</a></li>
	</ul>
</body>

 

 - SangpumController

@Controller
public class SangpumController {
	@Autowired
	private DataDao dataDao;
	
	@RequestMapping("sangpum")
	@ResponseBody // Body를 통채로 송부한다.
	public Map<String, Object> abc(){ // JSON은 Map을 리턴해야한다.
		List<Map<String, String>> dataList = new ArrayList<Map<String, String>>();
		
		Map<String, String> data = null;
		List<SangpumDto> sangList = dataDao.sangpumList(); // DB에서 데이터를 받아온다.
		
		for(SangpumDto s : sangList) {
			data = new HashMap<String, String>();
			data.put("code", s.getCode()); // key, value 형식으로 DB값을 담는다. 
			data.put("sang", s.getSang());
			data.put("su", s.getSu());
			data.put("dan", s.getDan());
			dataList.add(data); // List에 Record 값을 넣는다.
		}
		
		Map<String, Object> sangpumDatas = new HashMap<String, Object>();
		sangpumDatas.put("datas", dataList); // Map에 List를 담아 전송한다.
		return sangpumDatas; // JSON은 Map을 리턴해야한다.
	}
}

 

- DataDao

@Repository
public class DataDao extends SqlSessionDaoSupport{
	public DataDao(SqlSessionFactory factory) {
		setSqlSessionFactory(factory);
	}
	public List<SangpumDto> sangpumList(){
		List<SangpumDto> list = getSqlSession().selectList("selectAll");
		return list;
	}
}

 

 

 - SangpumDto

public class SangpumDto {
	private String code, sang, su, dan;
    //getter/setter
}

 

 

- sanglist.jsp

<head>
	<meta charset="UTF-8">
	<title>Insert title here</title>
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
	<script type="text/javascript">
	$(document).ready(function(){
		$("#btnShow").click(function(){ // 버튼 클릭시 실행.
			$("#showData").empty(); // div의 내용 비우기.
			$.ajax({
				type:"get",
				url:"sangpum",
				dataType:"json",
				success:function(sangData){
					var str = "<table border='1'>";
					str+="<tr><th>코드</th><th>품명</th><th>수량</th><th>단가</th></tr>";
					let list = sangData.datas;
					$(list).each(function(idx, arr){
						str += "<tr>";
						str += "<td>"+arr["code"]+"</td>";
						str += "<td>"+arr["sang"]+"</td>";
						str += "<td>"+arr.su+"</td>";
						str += "<td>"+arr.dan+"</td>";
						str += "</tr>";
					});
					str+="</table>";
					$("#showData").html(str);
				},
				error:function(){
					$("#showData").text("에러발생");
				}
			});
		});
	});
	</script>
</head>
<body>
	<button id="btnShow">show</button>
	<h2>상품자료(@MVC - Ajax)</h2>
	<div id="showData"></div>
</body>

 

[목차]

11. 게시판 만들기

① DB 연결

② List 출력

③ 게시물 등록

④ 검색

⑤ 상세 페이지 보기

⑥ 게시글 수정

⑦ 게시글 삭제

⑧ 댓글 기능 추가


[내용]

① DB 연결

 = sprweb16_board

 - db.properties

driver=org.mariadb.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/happydb
username=root
password=123

 => 계정 정보 설정파일.

 

 

 - Configuration.xml

<configuration>
<typeAliases>
	<typeAlias type="pack.model.BoardDto" alias="dto"/>
	<typeAlias type="pack.controller.BoardBean" alias="formBean"/>
</typeAliases>
 <mappers>
  <mapper resource="pack/mybatis/DataMapper.xml" />
 </mappers>
</configuration>

 => DataMapper.xml 연결.

 

 

- DataMapper.xml

<mapper namespace="dev">
 <!-- 전체 검색 -->
 <select id="selectList" resultType="dto">
  	select * from board order by gnum desc, onum asc
 </select>
 
 <!-- 카워드 검색 -->
 <select id="searchList" parameterType="formBean" resultType="dto">
  	select * from board 
  	where ${searchName} like concat('%',#{searchValue},'%') 
  	order by gnum desc, onum asc
 </select>
 
 <!-- 번호로 검색 -->
 <select id="selectOne" parameterType="string" resultType="dto">
  	select * from board where num=#{num}
 </select>
 
 <!-- 추가 -->
 <insert id="insertData" parameterType="formBean">
 	insert into board 
 	values(#{num},#{name},#{pass},#{mail},#{title},#{cont},
 	#{bip},#{bdate},0,#{gnum},0,0)
 </insert>
 
 <update id="updateData" parameterType="formBean">
 	update board 
 	set name=#{name},mail=#{mail},title=#{title},cont=#{cont}
 	where num=#{num}
 </update>
 
 <delete id="deleteData" parameterType="string">
 	delete from board where num=#{num}
 </delete>
 
 <!--  maxnum -->
 <select id="currentNum" resultType="integer">
 	select max(num) from board
 </select>
 
 <select id="totalCnt" resultType="integer">
 	select count(*) from board
 </select>
 
 <!-- readcnt -->
 <update id="updateReadcnt" parameterType="string">
 	update board set readcnt=readcnt + 1 
 	where num=#{num}
 </update>
 
 <!-- password -->
 <select id="selectPass" parameterType="string" resultType="string">
 	select pass from shopboard 
 	where num=#{num}
 </select>

 <!-- reply -->
 <update id="updateOnum" parameterType="formBean">
 	update board set onum=onum + 1
 	where onum >= #{onum} and gnum=#{gnum}
 </update>

 <insert id="insertReData" parameterType="formBean">
 	insert into board
 	values(#{num},#{name},#{pass},#{mail},#{title},#{cont},
 	#{bip},#{bdate},0,#{gnum},#{onum},#{nested})
 </insert>
</mapper>

 => SQL문 작성.

 

 

 - servlet-context.xml

<context:component-scan base-package="pack.controller" />
<context:component-scan base-package="pack.model" />

 => 어노테이션 사용을 위한 패키지 스캔.

 

 

 - root-context.xml

<!-- PropertyPlaceholderConfigurer 사용 : 외부 프로퍼티의 정보를 설정파일에서 사용가능.-->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
	<!-- locations 속성으로 db.properties를 read하도록 설정 -->
	<!-- db.properties의 프로퍼티를 ${프로퍼티값}으로 사용할 수 있다. -->
	<property name="locations">
		<value>classpath:pack/mybatis/db.properties</value>
	</property>
</bean>
<!-- SimpleDriverDataSource 사용 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
	<!--  -->
	<property name="driverClass" value="${driver}"/>
	<property name="url" value="${url}"/>
	<property name="username" value="${username}"/>
	<property name="password" value="${password}"/>
</bean>
<!-- SqlSessionFactoryBean 사용 -->
<!-- 복수개일 경우 id를 셋팅 -->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
	<!-- SqlMapConfig의 SqlSession에  Configuration.xml 연결-->
	<property name="dataSource" ref="dataSource"/>
	<property name="configLocation" value="classpath:pack/mybatis/Configuration.xml"></property>
</bean>

 => DB 연동을 위한 SqlSessionFactory 객체 생성.

 

 


② List 출력

 - index.jsp

<body>
	<h2>메인</h2>
	<ul>
		<li>쇼핑하기</li>
		<li>회원관리</li>
		<li>물류관리</li>
		<li><a href="list?page=1">게시판</a></li>
	</ul>
</body>

 => url (list), key=value(page=1) 전달(GET 방식).

 

 

- ListController

@Controller
public class ListController {
	@Autowired
	private BoardDaoInter boardInter;
	
	private int tot; // 전체 레코드 수
	private int plist=5; // 한 페이지 당 행의 수
	private int pageCount; // 전체 페이지 수
	
	public ArrayList<BoardDto> getListData(ArrayList<BoardDto> list, int page){
		ArrayList<BoardDto> result = new ArrayList<BoardDto>();
		int start = (page - 1)*plist; // 해당 페이지의 첫 게시물의 index
		int size = plist <= list.size() - start ? plist : list.size() - start;
		// 한 페이지에 표시할 데이터가 5개 이하일 경우엔 size가 그 수에 따르도록 조건처리.
        
		for(int i=0; i<size;i++) { // list에 한 페이지당 표시할 데이터만 담아 리턴한다.
			result.add(i, list.get(start + i));
		}
		
		return result;
	}
	
	public int getPageCount() { // get 페이지 수
		pageCount = tot/plist;
		if(tot%plist > 0 ) pageCount+=1; 
		
		return pageCount;
	}
	
	@RequestMapping("list")
	public Model process(Model model, @RequestParam("page") int page) {
		tot = boardInter.totalCnt();
		ArrayList<BoardDto> list = boardInter.getList();
		ArrayList<BoardDto> result = getListData(list, page);
		model.addAttribute("data",result);
		model.addAttribute("pageCount",getPageCount());
		model.addAttribute("page",page);
		//model.addAttribute("data",list); // 페이징 없이 작업할 경우
		return model;
	}
}

 => totalCnt() : 

 => getList() : 전체 List 검색하여 list 리턴.

 => getListData() : 전체 리스트에서 한 페이지 당 표시할 데이터만 리턴값으로 가진다.

 => plist : 한 페이지 당  표시할 레코드 수를 설정.

 => getPageCount() : 페이지의 개수를 리턴.

 

 

- BoardBean

public class BoardBean {
	private String name,pass,mail,title,cont,bip,bdate;
	private int num,readcnt,gnum,onum,nested;
	private String searchName, searchValue;
	
	//getter/setter
}

 => FormBean 작성.

 

 

- BoardDto

public class BoardDto {
	private String name,pass,mail,title,cont,bip,bdate;
	private int num,readcnt,gnum,onum,nested;
	
	//getter/setter
}

=> DTO 작성.

 

 

- BoardDaoInter

public interface BoardDaoInter {
	ArrayList<BoardDto> getList();
	ArrayList<BoardDto> getSearch(BoardBean bean);
	boolean insert(BoardBean bean);
	BoardDto getDetail(String num);
	boolean update(BoardBean bean);
	boolean delete(String num);
	
	int currentNum();
	int totalCnt();
	boolean updateReadcnt(String num);
	String selectPass(String num);
	
	boolean updateOnum(BoardBean bean);
	boolean insertReply(BoardBean bean);
}

=> interface 작성.

 

 

- BoardDaoImpl

@Repository
public class BoardDaoImpl extends SqlSessionDaoSupport implements BoardDaoInter {
	
	@Autowired
	public BoardDaoImpl(SqlSessionFactory factory) {
		setSqlSessionFactory(factory);
	}
	
	@Override
	public ArrayList<BoardDto> getList() {
		return (ArrayList)getSqlSession().selectList("selectList");
	}
    
	@Override
	public int totalCnt() {
		return getSqlSession().selectOne("totalCnt");
	}
	...
	
}

 => getList() : board 테이블의 모든 정보 list 리턴.

 => totalCnt() : 레코드 수를 리턴.

 <!-- 전체 검색 -->
 <select id="selectList" resultType="dto">
  	select * from board order by gnum desc, onum asc
 </select>

<select id="totalCnt" resultType="integer">
 	select count(*) from board
 </select>

 

 

 - list.jsp

<body>
<jsp:include page="./top.jsp"></jsp:include>
<table  class="table">
  <tr>
  	<td>
  		[<a href="list?page=1">최근목록</a>]&nbsp;
  		[<a href="insert">새글작성</a>]
  	</td>
  </tr>
</table>
<table class="table table-striped">
  <thead>
  <tr style="">
  	<th>번호</th><th>제  목</th><th>작성자</th><th>작성일</th><th>조회</th>
  </tr>
  </thead>
  <c:forEach var="b" items="${data}">
  	<!-- 댓글 들여쓰기 준비-->
  	<c:set var="tab" value=""/>
  	<c:forEach var="n" begin="1" end="${b.nested}">
  		<c:set var="tab" value="${tab}&nbsp;&nbsp;"/>
  	</c:forEach>
  <tr>
  	<td>${b.num}</td>
  	<td>
  		${tab}<a href="detail?num=${b.num}&page=${page}">${b.title}</a>
  	</td>
  	<td>${b.name}</td>
  	<td>${b.bdate}</td>
  	<td>${b.readcnt}</td>
  </tr>	
  </c:forEach>
  <!-- paging -->
  <tr style="text-align: center;">
  	<td colspan="5">
  	<c:forEach var="psu" begin="1" end="${pageCount}">
  		<c:if test="${psu==page}">
  			<b>${psu}</b>
  		</c:if>
  		<c:if test="${psu!=page}">
  			<a href="list?page=${psu}">${psu}</a>
  		</c:if>
  	</c:forEach>
  	</td>
  	
  </tr>
  <!-- search -->
  <tr style="text-align: center;">
  	<td colspan="5">
  	<br><br>
  	<form action="search" method="post">
  		<select name="searchName">
  			<option value="title" selected="selected">글제목</option>
  			<option value="name">작성자</option> 
  		</select>
  		<input type="text" name="searchValue">
  		<input type="submit" value="검색">
  	</form>
  	</td>
  </tr>
</table>
</body>

 => 페이지 처리된 list를 출력한다.

 => 제목을 누를 경우 요청명 detail로 num과 page 값을 전달한다.

 => 검색 버튼을 누를 경우 searchName(key)에 title or name(value), searchValue(key)에 값이 요청명 search로 전달.

      (post방식) 

 

 => 게시물 등록 하이퍼링크 클릭시 insert 요청명 전달.(GET방식)

 

 


③ 게시물 등록

- InsertController

@Controller
public class InsertController {
	
	@Autowired
	private BoardDaoInter boardInter;
	
	@RequestMapping(value="insert", method = RequestMethod.GET)
	public String insert() {
		return "insform";
	}
	...
}

 => GET방식 요청명 insert 받을 경우 inform.jsp 실행.

 

 

 - insform.jsp

<head>
	<script type="text/javascript">
		window.onload=function(){
			let btnIns = document.getElementById("btnIns");
			btnIns.addEventListener("click",checkData, false);
		}
		function checkData(){
			if(frm.name.value === ""){
				alert("작성자를 입력하세요");
				frm.name.focus();
				return;
			}else if(frm.pass.value === ""){
				alert("비밀번호를 입력하세요");
				frm.name.focus();
				return;
			}
			frm.submit();
		}
	</script>
</head>
<body>
<jsp:include page="./top.jsp"></jsp:include>
<h4 style="text-align: center;">* 게시물 등록</h4>
<form action="insert" method="post" name="frm">
<table  class="table" style="width: 80%">
  <tr>
  	<td>이름</td>
  	<td><input type="text" name="name"></td>
  </tr>
  <tr>
  	<td>암호</td>
  	<td><input type="text" name="pass"></td>
  </tr>
  <tr>
  	<td>메일</td>
  	<td><input type="text" name="mail"></td>
  </tr>
  <tr>
  	<td>제목</td>
  	<td><input type="text" name="title"></td>
  </tr>
  <tr>
  	<td>내용</td>
  	<td>
  		<textarea rows="5" cols="50" name="cont"></textarea>
  	</td>
  </tr>
  <tr>
  	<td colspan="2" style="text-align: center;">
  		<input type="hidden" name="bip" value="<%=request.getRemoteAddr()%>">
  		<input type="button" value="등록" id="btnIns">
  		<!-- <input type="button" value="등록" onclick="checkData()"> -->
  		<input type="button" value="목록" onclick="location.href='list?page=1'">
  	</td>
  </tr>
</table>
</form>
</body>

 => 등록 버튼 누를 경우 name/pass칸이 비어있을 경우 pop-up 발생.

     요청명 insert 전달.(post 방식)

 => location.href  : 목록버튼 누를 경우 list 출력 창 1 page로 이동.

      focus() : 커서가 해당 창으로 이동.

      submit() : submit 동작 진행.

 

 

- InsertController

@Controller
public class InsertController {
	
	@Autowired
	private BoardDaoInter boardInter;
	...
	@RequestMapping(value="insert", method = RequestMethod.POST)
	public String submit(BoardBean bean) {
		bean.setBdate();
		int newNum = boardInter.currentNum() + 1; // 새로 작성된 글의 번호
		bean.setNum(newNum);
		bean.setGnum(newNum);
		
		boolean b= boardInter.insert(bean);
		if(b) {
			return "redirect:/list?page=1";
		}else {
			return "redirect:/error";
		}
	}
}

 => POST방식 요청명 insert 받을 경우 실행.

 => <form>태그 데이터 FormBean에 set.

 => setBdate() : Calendar객체를 이용하여 오늘 날짜를 set한다.

 => currentNum() : 현재 테이블의 num값중 가장 큰 값을 받아와 +1하여 현재 num가 group num 값을 set한다.

 => insert() : data 추가.

 => insert 성공 시 전체 list 페이지로 이동, 실패 error 페이지로 이동.

public void setBdate() {
	Calendar cal = Calendar.getInstance();
	int year = cal.get(Calendar.YEAR);
	int month = cal.get(Calendar.MONTH) + 1;
	int day = cal.get(Calendar.DATE);
	this.bdate = year + "-" + month + "-" + day;
}

 

 

- BoardDaoImpl

@Repository
public class BoardDaoImpl extends SqlSessionDaoSupport implements BoardDaoInter {
	
	@Autowired
	public BoardDaoImpl(SqlSessionFactory factory) {
		setSqlSessionFactory(factory);
	}
	...	
	@Override
	public boolean insert(BoardBean bean) {
		int result = getSqlSession().insert("insertData",bean);
		if(result>0) {
			return true;
		}else {
			return false;
		}
	}
	...
	@Override
	public int currentNum() {
		//insert시 번호 자동 증가를 위해 현재 레코드 중 가장 큰 번호 얻기.
		if(getSqlSession().selectOne("currentNum") == null) {
			return 0;
		}else {
			return getSqlSession().selectOne("currentNum");
		}
	}
	...
}

 => insert() : insert에 성공 시 true, 실패 시 false 리턴.

 => currentNum() : 레코드가 없을 경우 현재 가장 큰 num값을 0으로 리턴.

...
<!-- 추가 -->
<insert id="insertData" parameterType="formBean">
	insert into board 
	values(#{num},#{name},#{pass},#{mail},#{title},#{cont},
	#{bip},#{bdate},0,#{gnum},0,0)
</insert>
...
<!--  maxnum -->
<select id="currentNum" resultType="integer">
	select max(num) from board
</select>
...

 => Data insert

 => board테이블의 num중 가장 큰 값 리턴.

 

 

 - ErrorController

@Controller
public class ErrorController {
	
	@RequestMapping("error")
	public String err() {
		return "error";
	}
}

 => error.jsp 실행

 

 

 - error.jsp

<body>
	<h2>에러 발생</h2>
	<a href="list?page=1">목록보기</a>
</body>

 => error 페이지 출력.

 

 


④ 검색

- SearchController

@Controller
public class SearchController {
	
	@Autowired
	private BoardDaoInter inter;
	
	@RequestMapping("search")
	public ModelAndView searchProcess(BoardBean bean) {
		ArrayList<BoardDto> list = inter.getSearch(bean); 
		ModelAndView view = new ModelAndView("list", "data", list);
		view.addObject("page","1");
		return view;
	}
}

=> list.jsp에서 검색 버튼을 누를 경우 searchName(key), searchValue(key)가 전달된다.

=> getSearch() : searchName(key), searchValue(key)에 맞는 값을 검색하여 리스트로 출력한다.

=> 리턴 값을 list.jsp에 출력.

 

 

- BoardDaoImpl

@Repository
public class BoardDaoImpl extends SqlSessionDaoSupport implements BoardDaoInter {
	
	@Autowired
	public BoardDaoImpl(SqlSessionFactory factory) {
		setSqlSessionFactory(factory);
	}
	...	
	@Override
	public ArrayList<BoardDto> getSearch(BoardBean bean) {
		return (ArrayList)getSqlSession().selectList("searchList", bean);
	}
	...
}

 => getSearch() : 검색 후 ArrayList 리턴.

 

 

- DataMapper.xml

 ...
 <!-- 카워드 검색 -->
 <select id="searchList" parameterType="formBean" resultType="dto">
  	select * from board 
  	where ${searchName} like concat('%',#{searchValue},'%') 
  	order by gnum desc, onum asc
 </select>
 ...

 => searchName의 Column에서 searchValue의 키워드가 있을 경우 리스트를 리턴한다.

 

 


⑤ 상세 페이지 보기

- DetailController

@Controller
public class DetailController {
	@Autowired
	private BoardDaoInter inter;
	
	@RequestMapping("detail")
	public ModelAndView detailProcess(@RequestParam("num") String num,
			@RequestParam("page") String page) {
		
		// 조회수 증가 작업 선행
		boolean b = inter.updateReadcnt(num);
		
		// 상세보기 진행 후 jsp로 출력
		ModelAndView view = new ModelAndView("detail");
		view.addObject("data", inter.getDetail(num));
		view.addObject("page", page);
		return view;
		
	}
}

 => list.jsp에서 제목을 누를 경우 요청명 detail로 num과 page 값을 전달받는다.

 => @RequestParam : request.getParameter()와 동일.

 => updateReadcnt() : 조회수를 +1한다.

 => getDetail() : 해당 num의 한 레코드 값을 리턴하여 detail.jsp 실행.

 

 

- BoardDaoImpl

@Repository
public class BoardDaoImpl extends SqlSessionDaoSupport implements BoardDaoInter {
	
	@Autowired
	public BoardDaoImpl(SqlSessionFactory factory) {
		setSqlSessionFactory(factory);
	}
	...
	@Override
	public BoardDto getDetail(String num) {
		// 글 내용보기, 글 수정 시 데이터 받아오기
		return getSqlSession().selectOne("selectOne",num);
	}
	...
	@Override
	public boolean updateReadcnt(String num) {
		//상세보기 전 조회수 증가
		int result = getSqlSession().update("updateReadcnt",num);
		if(result>0) {
			return true;
		}else {
			return false;
		}
	}
	...
}

 => getDetail() : 게시글의 내용을 받아온다.

 => updateReadcnt() : 업데이트 성공시 true, 실패 시 false 리턴

 

 

- DataMapper.xml

 ...
 <!-- 번호로 검색 -->
 <select id="selectOne" parameterType="string" resultType="dto">
  	select * from board where num=#{num}
 </select>
 ...
 <!-- readcnt -->
 <update id="updateReadcnt" parameterType="string">
 	update board set readcnt=readcnt + 1 
 	where num=#{num}
 </update>
 ...

 => num값과 동일한 레코드 리턴.

 => num과 동일한 레코드의 조회수 +1.

 

 

- detail.jsp

<script type="text/javascript">
	window.onload=function(){
	document.getElementById("btnDel").onclick = chkDeleData;
	}
	function chkDeleData(){
		
		let pass = prompt("비밀번호를 입력하세요");
		location.href="delete?num=${data.num}&page=${page}&pass="+pass;
	}
</script>
</head>
<body>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:if test="${msg != null}">
	<script type="text/javascript">
		(function msg(){
			alert("${msg}");
		})();
	</script>
</c:if>
<jsp:include page="./top.jsp"></jsp:include>
<div class="container">
<h4 style="text-align: center;">* 상세보기</h4>
<table class="table" style="width: 80%">
  <tr>
  	<td>비밀번호 : ${data.pass}</td>
  	<td style="text-align: right;">
  		<a href="reply?num=${data.num}&page=${page}">
  			<img src="./resources/images/reply.gif" />
  		</a>
  		<a href="update?num=${data.num}&page=${page}">
  			<img src="./resources/images/edit.gif" />
  		</a>
  		<button id="btnDel"><img src="./resources/images/del.gif" /></button>
  		<!-- 
  		<a href="delete?num=${data.num}&page=${page}">
  			<img src="./resources/images/del.gif" />
  		</a>
  		 -->
  		<a href="list?page=${page}">
  			<img src="./resources/images/list.gif" />
  		</a>
  	</td>
  </tr>
</table>

<table border="1" style="width: 80%">
  <tr>
  	<td>
  		작성자 : <a href="mailto:${data.mail}">${data.name}</a>
  		(ip : ${data.bip})
  	</td>
  	<td>작성일 : ${data.bdate}</td>
  	<td>조회수 : ${data.readcnt}</td>
  </tr>
  <tr>
  	<td colspan="3">제목 : ${data.title}</td>
  </tr>
  <tr>
  	<td colspan="3">
  		<textarea rows="5" readonly="readonly" style="width:99%">${data.cont}</textarea>
  	</td>
  </tr>
</table>
</div>
</body>

 => 댓글 기능 : 요청명 reply로 num과 page 값 전달.

 => 수정 기능 : 요청명 update로 num과 page 값 전달.(GET방식)

 => 삭제 기능 : 비밀번호 입력 prompt 출력 후 입력시 요청명 delete로 num, page, password 값 전달.

 => 목록 보기 기능 : 전체 list 출력 페이지로 이동.

 => msg가 있을 경우 pop-up창으로 발생.

 

 


⑥ 게시글 수정

- UpdateController

@Controller
public class UpdateController {
	
	@Autowired
	private BoardDaoInter inter;
	
	@RequestMapping(value="update", method=RequestMethod.GET)
	public ModelAndView edit(@RequestParam("num") String num,
			@RequestParam("page") String page) {
		
		// 모델에서 수정할 자료 읽기
		BoardDto dto = inter.getDetail(num);
		
		ModelAndView view = new ModelAndView("update");
		view.addObject("data", dto);
		view.addObject("page", page);
		return view;
	}
	...
}

=> 상세 페이지에서 수정 버튼 클릭시 실행.

=> getDetail() : 해당 데이터값 리턴.

=> update.jsp 실행.

 

 

- update.jsp

<script type="text/javascript">
	window.onload=function(){
	document.getElementById("btnUp").onclick = chkUpData;
	}
	function chkUpData(){
		if(upFrm.pass.value === ""){
			upFrm.pass.focus();
			alert("비밀번호를 입력하세요");
			return;
		}
		if(confirm("정말 수정할까요?")){
			upFrm.submit();
		}
	}
</script>
</head>
<body>
<jsp:include page="./top.jsp"></jsp:include>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:if test="${msg != null}">
	<script type="text/javascript">
		(function msg(){
			alert("${msg}");
		})();
		location.href="list?page=${page}";
	</script>
</c:if>
<div class="container">
<h4 style="text-align: center;">- 수정 -</h4>
<form action="update" method="post" name="upFrm">
<input type="hidden" name="num" value="${data.num}">
<input type="hidden" name="page" value="${page}">
<table class="table" style="width: 80%">
  <tr>
  	<td>이름</td>
  	<td><input type="text" name="name" value="${data.name}"></td>
  </tr>
  <tr>
  	<td>암호</td>	
  	<td><input type="text" name="pass"></td>
  </tr>
  <tr>
  	<td>메일</td>
  	<td><input type="text" name="mail" value="${data.mail}"></td>
  </tr>
  <tr>
  	<td>제목</td>
  	<td><input type="text" name="title" value="${data.title}"></td>
  </tr>
  <tr>
  	<td>내용</td>
  	<td>
  		<textarea rows="5" cols="50" name="cont">${data.cont}</textarea>
  	</td>
  </tr>
  <tr>
  	<td colspan="2" style="text-align: center;">
  		<input type="button" value="수정" id="btnUp">
  		<input type="button" value="목록" onclick="location.href='list?page=${page}'">
  	</td>
  </tr>
</table>
</form>
</div>
</body>

 => 수정버튼을 누를 경우 비밀번호가 빈칸일 경우 팝업 발생. 있을 경우 요청명 update 전달.(post방식)

 => msg가 있을 경우 pop-up내용 출력 후 list 페이지로 이동.

 

 

 

- UpdateController

@Controller
public class UpdateController {
	
	@Autowired
	private BoardDaoInter inter;
	...
	@RequestMapping(value="update", method=RequestMethod.POST)
	public ModelAndView editSubmit(BoardBean bean,
			@RequestParam("page") String page) {
		// 비밀번호 체크
		String pass = inter.selectPass(Integer.toString(bean.getNum()));
		
		ModelAndView view = new ModelAndView();
		if(bean.getPass().equalsIgnoreCase(pass)) { // 사용자 비밀번호와 db의 비밀번호 비교
			boolean b = inter.update(bean);
			if(b) {
				//view.setViewName("redirect:/list?page="+page);
				view.setViewName("redirect:/detail?num="+bean.getNum()+"&page="+page);
			}else {
				view.setViewName("redirect:/error");
			}
		}else {
			view.setViewName("update");
			view.addObject("msg", "비밀번호 불일치");
			view.addObject("page", page);
		}
		return view;
	}
}

=> 수정 페이지에서 수정 버튼 누를 경우 실행.

=> selectPass() : 해당 num의 password 리턴.

=> 입력 패스트워드와 DB의 저장된 비밀 번호가 일치 할 경우 update()메소드 실행.

                                                               불일치 시 error msg를 전달하여 update 페이지 실행.

=> update 성공 시 수정 진행한 detail 페이지로 이동. 실패 시 error.jsp 실행.

 

 

 - BoardDaoImpl

@Repository
public class BoardDaoImpl extends SqlSessionDaoSupport implements BoardDaoInter {
	
	@Autowired
	public BoardDaoImpl(SqlSessionFactory factory) {
		setSqlSessionFactory(factory);
	}
	...
	@Override
	public boolean update(BoardBean bean) {
		try {
			int result = getSqlSession().update("updateData", bean);
			if(result > 0) {
				return true;
			}else {
				return false;
			}
		} catch (Exception e) {
			System.out.println("update err"+e);
			return false;
		}
	}
	...
	@Override
	public String selectPass(String num) { // 수정용 : 비밀 번호 비교
		return getSqlSession().selectOne("selectPass", num);
	}
	...
}

=> update() : 업데이트 성공 시 true, 실패시 false 리턴.

=> selectPass() : 해당 num의 password 리턴.

 

 

-DataMapper.xml

 ...
 <update id="updateData" parameterType="formBean">
 	update board 
 	set name=#{name},mail=#{mail},title=#{title},cont=#{cont}
 	where num=#{num}
 </update>
 ...
 <!-- password -->
 <select id="selectPass" parameterType="string" resultType="string">
 	select pass from board 
 	where num=#{num}
 </select>
 ...

=> update() : 해당 데이터로 수정.

=> selectPass() : 해당 num의 password 리턴.

 

 


⑦ 게시글 삭제

- DeleteController

@Controller
public class DeleteController {
	@Autowired
	private BoardDaoInter inter;
	
	@RequestMapping("delete")
	public ModelAndView del(@RequestParam("num") String num,
			@RequestParam("page") String page,
			@RequestParam("pass") String pass) {
		BoardDto dto = inter.getDetail(num);
		ModelAndView view = new ModelAndView();
		System.out.println(pass);
		if(dto.getPass().equalsIgnoreCase(pass)) { // 사용자 비밀번호와 db의 비밀번호 비교
			boolean b = inter.delete(num);
			if(b) {
				view.setViewName("redirect:/list?page="+page);
			}else {
				view.setViewName("redirect:/error");
			}
		}else {
			view.setViewName("detail");
			view.addObject("data", dto);
			view.addObject("msg", "비밀번호 불일치");
			view.addObject("page", page);
		}
		return view;
	}
}

 => 상세 페이지에서 delete 버튼 클릭시 실행.

 => 해당 패스워드와 일치 시 delete()메소드 실행.

                            불일치 시 detail 페이지로 이동하여 error msg 팝업 발생.

 => 데이터 삭제 성공 시 전체 페이지 보기로 이동. 실패 시 error.jsp로 이동.

 

 

- BoardDaoImpl

@Repository
public class BoardDaoImpl extends SqlSessionDaoSupport implements BoardDaoInter {
	
	@Autowired
	public BoardDaoImpl(SqlSessionFactory factory) {
		setSqlSessionFactory(factory);
	}
	...
	@Override
	public BoardDto getDetail(String num) {
		// 글 내용보기, 글 수정 시 데이터 받아오기
		return getSqlSession().selectOne("selectOne",num);
	}
	...
	@Override
	public boolean delete(String num) {
		try {
			int result = getSqlSession().delete("deleteData", num);
			if(result > 0) {
				return true;
			}else {
				return false;
			}
		} catch (Exception e) {
			System.out.println("delete err"+e);
			return false;
		}
	}
	...
}

 => delete() : 삭제 성공시 true, 실패시 false 리턴.

 

 

 - DataMapper.xml

 <delete id="deleteData" parameterType="string">
 	delete from board where num=#{num}
 </delete>

 => 데이터 삭제.

 


⑧ 댓글 기능 추가

 - ReplyController

@Controller
public class ReplyController {
	
	@Autowired
	private BoardDaoInter inter;
	
	@RequestMapping(value="reply", method=RequestMethod.GET)
	public ModelAndView reply(@RequestParam("num") String num,
			@RequestParam("page") String page) {
		ModelAndView view = new ModelAndView("reply");
		view.addObject("data", inter.getDetail(num)); // 원글의 데이터
		return view;
	}
	...
}

 => 상세 페이지의 댓글 버튼 클릭시 실행.

 => 원본 글의 데이터를 저장 후 reply.jsp 실행.

 

 

 - reply.jsp

<head>
	<script type="text/javascript">
	window.onload=function(){
		document.getElementById("btnReply").onclick = chk;
	}
	function chk(){
		if(reFrm.name.value === ""){
			alert("작성자 이름을 입력하세요");
			reFrm.name.focus();
		}
		// 입력자료 오류 검사
		reFrm.submit();
	}
	</script>
</head>
<body>
<jsp:include page="./top.jsp"></jsp:include>
<h4 style="text-align: center;">* 댓글 쓰기</h4>
<form action="reply" method="post" name="reFrm">
<input type="hidden" name="num" value="${data.num}">
<input type="hidden" name="page" value="${page}">
<input type="hidden" name="gnum" value="${data.gnum}">
<input type="hidden" name="onum" value="${data.onum}">
<input type="hidden" name="nested" value="${data.nested}">
<input type="hidden" name="bip" value="<%=request.getRemoteAddr()%>">

<table class="table" style="width: 80%">
  <tr>
  	<td>이름</td>
  	<td><input type="text" name="name"></td>
  </tr>
  <tr>
  	<td>암호</td>
  	<td><input type="text" name="pass"></td>
  </tr>
  <tr>
  	<td>메일</td>
  	<td><input type="text" name="mail"></td>
  </tr>
  <tr>
  	<td>제목</td>
  	<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
  	<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
  	<c:set var="title" value="${data.title}"/>
  	<td><input type="text" name="title" value="[Re]:${fn:substring(title,0,8)}"></td>
  </tr>
  <tr>
  	<td>내용</td>
  	<td>
  		<textarea rows="5" style="width:99%" name="cont"></textarea>
  	</td>
  </tr>
  <tr>
  	<td colspan="2" style="text-align: center;">
  		<input type="button" value="작성" id="btnReply">
  		<input type="button" value="목록" onclick="location.href='list?page=${page}'">
  	</td>
  </tr>
</table>
</form>
</body>

 => 댓글 제목이 8보다 클 경우 substring하여 출력.

 => 작성 버튼 클릭 시 작성자이 비어 있을 경우 팝업 발생. 성공 시 reply 요청명 전달(post방식)

 

 

- ReplyController

@Controller
public class ReplyController {
	
	@Autowired
	private BoardDaoInter inter;
	...
	@RequestMapping(value="reply", method=RequestMethod.POST)
	public String replySubmit(BoardBean bean,
			@RequestParam("page") String page) {
		// onum 갱신
		bean.setOnum(bean.getOnum() + 1);
		inter.updateOnum(bean); // 반환값 처리 필요.
		
		// 댓글 저장
		bean.setBdate(); // 작성일 set
		bean.setNum(inter.currentNum() + 1); // 새로운 글의 번호
		bean.setNested(bean.getNested() + 1); // 들여쓰기
		
		if(inter.insertReply(bean)) {
			return "redirect:list?page="+page; // 추가 후 글 목록 보기			
		}else {
			return "redirect:error";
		}
		
	}
}

 => updateOnum() : 원글 내 댓글 번호를 업데이트 한다.

 => insertReply() : 작성일, num+1, 들여쓰기+1하여 댓글을 추가 한다.

 

 

- BoardDaoImpl

@Repository
public class BoardDaoImpl extends SqlSessionDaoSupport implements BoardDaoInter {
	
	@Autowired
	public BoardDaoImpl(SqlSessionFactory factory) {
		setSqlSessionFactory(factory);
	}
	...
	@Override
	public boolean updateOnum(BoardBean bean) {
		//댓글에서 onum 갱신
		int result = getSqlSession().update("updateOnum", bean);
		if(result>0) {
			return true;
		}else {
			return false;
		}
	}

	@Override
	public boolean insertReply(BoardBean bean) {
		try {
			int result = getSqlSession().insert("insertReData", bean);
			if(result > 0) {
				return true;
			}else {
				return false;
			}
		} catch (Exception e) {
			System.out.println("insertReply err"+e);
			return false;
		}
	}
}

 => updateOnum() : 업데이트 성공 시 true, 실패 시 false 리턴.

 => insertReply() : 추가 성공 시 true, 실패 시 false 리턴.

 

 

 ...
 <!-- reply -->
 <update id="updateOnum" parameterType="formBean">
 	update board set onum=onum + 1
 	where onum >= #{onum} and gnum=#{gnum}
 </update>

 <insert id="insertReData" parameterType="formBean">
 	insert into board
 	values(#{num},#{name},#{pass},#{mail},#{title},#{cont},
 	#{bip},#{bdate},0,#{gnum},#{onum},#{nested})
 </insert>
</mapper>

 => 모든 데이터 중 onum이 group num이 같고 onum이 클 경우 onum을 +1한다.

 => 댓글 정보를 추가한다.

[목차]

10. CRUD(Create, Read, Update, Delete)

 : 스프링 사용.

 : xml 의존방식 db 연결(root-context사용).

① DB 연동

② 모든 list 출력

③ 데이터 추가(Insert)

④ Data 수정(Update)

⑤ 데이터 삭제(Delete)


[내용]

 = sprweb15_crud

① DB 연동

 - Configuration.xml

<configuration>
 <typeAliases>
 	<typeAlias type="pack.model.MemDto" alias="dto"/>
 	<typeAlias type="pack.controller.MemBean" alias="formBean"/>
 </typeAliases>
 <!--  DB 연결을 root-context.xml에서 하도록 수정.
 <properties resource="pack/mybatis/db.properties" />
 <environments default="dev">
  <environment id="dev">
   <transactionManager type="JDBC" />
   <dataSource type="POOLED">
    <property name="driver" value="${driver}" />
    <property name="url" value="${url}" />
    <property name="username" value="${username}" />
    <property name="password" value="${password}" />
   </dataSource>
  </environment>
 </environments>
 -->
 <mappers>
  <mapper resource="pack/mybatis/DataMapper.xml" />
 </mappers>
</configuration>

 => DataMapper.xml 연결.

 

 

 - DataMapper.xml

<mapper namespace="dev">
 <select id="selectAll" resultType="dto">
  select num, name, addr from mem
 </select>
 
 <select id="selectPart" parameterType="String" resultType="dto">
 select num, name, addr  from mem
 where num=#{num}
 </select>
 
 <insert id="insertData" parameterType="formBean">
 	insert into mem values(#{num}, #{name}, #{addr})
 </insert>
 
 <update id="updateData" parameterType="formBean">
 	update mem set name=#{name}, addr=#{addr}
 	where num=#{num}
 </update>
 
 <delete id="deleteData" parameterType="String">
 	delete from mem where num=#{num}
 </delete>
 
</mapper>

 => sql문 mapping.

 

 

- db.properties

driver=org.mariadb.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/happydb
username=root
password=123

 => 계정 정보 파일.

 

 

 - root-context.xml

<!-- PropertyPlaceholderConfigurer 사용 : 외부 프로퍼티의 정보를 설정파일에서 사용가능.-->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
	<!-- locations 속성으로 db.properties를 read하도록 설정 -->
	<!-- db.properties의 프로퍼티를 ${프로퍼티값}으로 사용할 수 있다. -->
	<property name="locations">
		<value>classpath:pack/mybatis/db.properties</value>
	</property>
</bean>

<!-- SimpleDriverDataSource 사용 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
	<!--  -->
	<property name="driverClass" value="${driver}"/>
	<property name="url" value="${url}"/>
	<property name="username" value="${username}"/>
	<property name="password" value="${password}"/>
</bean>
<!-- SqlSessionFactoryBean 사용 -->
<!-- 복수개일 경우 id를 셋팅 -->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
	<!-- SqlMapConfig의 SqlSession에  Configuration.xml 연결-->
	<property name="dataSource" ref="dataSource"/>
	<property name="configLocation" value="classpath:pack/mybatis/Configuration.xml"></property>
</bean>

 => DB 연동. SqlFactory 객체 생성.

 

 

 - servlet-context.xml

<context:component-scan base-package="pack.controller" />
<context:component-scan base-package="pack.model" />

 => 어노테이션 스캔

 

 


② 모든 list 출력

 - index.jsp

<body>
	<h2>메인</h2>
	<ul>
		<li>인사관리</li>
		<li>영업관리</li>
	 	<li>물류관리</li>
	 	<li><a href="list">회원관리</a></li>
	 	<li>문의사항</li>
	</ul>
</body>

 => url "list" (Get 방식으로 송부)

 

 

- ListController

@Controller
public class ListController {
	@Autowired
	private MemDaoInter daoInter;
	
	@RequestMapping("list")
	public ModelAndView list() {
		/*
		List<MemDto> list = daoInter.getDataAll();
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("list");
		modelAndView.addObject("list", list);
		return modelAndView;
		*/
		return new ModelAndView("list","list",daoInter.getDataAll());
	}
}

 => @Controller : sevlet controller 동작.

 => url "list" 받을 경우 실행. list.jsp에 key("list")로 value(getDataAll() 리턴 값) 전달.

 

 

- MemBean

public class MemBean {
	private String num;
	private String name;
	private String addr;
	
	//getter/setter
}

 => FormBean작성. (insert/delete/update에 사용)

 

 

- MemDto

public class MemDto {
	private String num;
	private String name;
	private String addr;
	
	//getter/setter
}

 => DTO 작성(select에 사용)

 

 

- MemDaoInter

public interface MemDaoInter {
	List<MemDto> getDataAll();
	MemDto selectPart(String num);
	boolean insertData(MemBean bean);
	boolean updateData(MemBean bean);
	boolean deleteData(String num);
}

 => 다형성 프로그래밍을 위한 interface 사용.

 

 

- MemDaoImpl

@Repository
public class MemDaoImpl extends SqlSessionDaoSupport implements MemDaoInter{
	
	@Autowired
	public MemDaoImpl(SqlSessionFactory factory) {
		setSqlSessionFactory(factory);
	}

	@Override
	public List<MemDto> getDataAll() {
		return getSqlSession().selectList("selectAll");
	}
    ...
}

 => extends SqlSessionDaoSupport : sqlSession사용을 위해 상속진행.

 => 생성자 주입을 통한. sqlSessionFactory 객체 주입.

 => DataMapper.xml의 <select>태그의 id "selectAll" sql문 실행 결과 리턴

<select id="selectAll" resultType="dto">
 select num, name, addr from mem
</select>
...

 

 

 - list.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<body>
	<h2>*회원정보(@MVC - MyBatis : CRUD)</h2>
	<a href="insert">회원추가</a><br>
	
	<table border="1">
		<tr>
			<th>번호</th><th>이름</th><th>주소</th><th>변경</th>
		</tr>
		
		<c:forEach var="m" items="${list}">
			<tr>
				<td>${m.num}</td>
				<td>${m.name}</td>
				<td>${m.addr}</td>
				<td>
					<a href="update?num=${m.num}">수정</a>
					<a href="delete?num=${m.num}">삭제</a>
				</td>
			</tr>
		</c:forEach>
	</table>
</body>

 => 모든 list 출력 결과 실행.

 => 회원추가 하이퍼링크 클릭시 url "insert" 송부.(get방식)

 => 수정 하이퍼링크 클릭시 url "update" 송부.(get방식)(num 값 전달)

 => 삭제 하이퍼링크 클릭시 url "delete" 송부.(get방식)(num 값 전달)

 


③ 데이터 추가(Insert)

- InsertController

@Controller
public class InsertController {
	
	@Autowired
	private MemDaoInter daoInter;
	
	@RequestMapping(value = "insert", method = RequestMethod.GET)
	public String insert() {
		return "insform";
	}
	
	...
}

 => GET방식 url "insert" 받을 경우 insert() 메소드 실행.

 => insform.jsp 실행.

 

 

 - insform.jsp

<body>
	<h2>*회원입력</h2>
	<form action="insert" method="post">
		번호 : <input type="number" name="num"><br>
		이름 : <input type="text" name="name"><br>
		주소 : <input type="text" name="addr"><br>
		<input type="submit" value="추가">
	</form>
</body>

 => 회원정보 입력 <form> 생성.

 => submit시 url "insert" 송부(post방식).

 

 

- InsertController

@Controller
public class InsertController {
	
	@Autowired
	private MemDaoInter daoInter;
	...
	@RequestMapping(value="insert", method=RequestMethod.POST)
	public String submit(MemBean bean) {
		
		boolean b = daoInter.insertData(bean);
		if(b) {
			return "redirect:/list"; // list controller를 실행해야함으로 redirect로 보낸다. 
		}else {
			return "error";
		} 
	}
}

=> POST방식 url "insert" 받을 경우 submit() 메소드 실행.

=> <form>태그 value가 MemBean에 set된다.

=> bean값을 매개변수로 insertData()메소드 실행하여 insert 성공시 모든 list를 다시 출력하고,

     실패할 경우 error.jsp 실행.

 

 

 

- MemDaoImpl

@Repository
public class MemDaoImpl extends SqlSessionDaoSupport implements MemDaoInter{
	
	@Autowired
	public MemDaoImpl(SqlSessionFactory factory) {
		setSqlSessionFactory(factory);
	}

	...
	
	@Override
	public boolean insertData(MemBean bean) {
		try {
			getSqlSession().insert("insertData", bean);
			return true;
		} catch (Exception e) {
			System.out.println("insertData err"+e);
			return false;
		}
	}
	
	...
}

 => DataMapper.xml의 <insert>태그의 id "insertData" sql문 실행 결과 리턴

 

<insert id="insertData" parameterType="formBean">
 insert into mem values(#{num}, #{name}, #{addr})
</insert>

 

 

 - error.jsp

<body>
	<h2>에러가 발생하였습니다.</h2>
	<a href="list">회원자료</a> 보기
</body>

 => 에러 처리 jsp.

 


④ Data 수정(update)

- UpdateController

@Controller
public class UpdateController {
	@Autowired
	private MemDaoInter daoInter;
	
	@RequestMapping(value="update", method = RequestMethod.GET)
	public ModelAndView update(@RequestParam("num") String num) {
		MemDto dto = daoInter.selectPart(num);
		return new ModelAndView("upform","dto",dto);
	}
	...
}

=> GET방식 url "update" 받을 경우 update() 메소드 실행.

=> ?key=value값을 @RequestParam사용하여 num에 set.

=> selectPart()메소드 실행하여 검색 값 리턴하여 upform.jsp에 "dto"key로 값 전달.

 

 

 

- MemDaoImpl

@Repository
public class MemDaoImpl extends SqlSessionDaoSupport implements MemDaoInter{
	
	@Autowired
	public MemDaoImpl(SqlSessionFactory factory) {
		setSqlSessionFactory(factory);
	}
	...
	@Override
	public MemDto selectPart(String num) {
		return getSqlSession().selectOne("selectPart",num);
	}
	...
}

 => DataMapper.xml의 <select>태그의 id "selectPart" sql문 실행 결과 리턴

<select id="selectPart" parameterType="String" resultType="dto">
 select num, name, addr  from mem
 where num=#{num}
</select>

 

 

- upform.jsp

<body>
	<h2>* 회원 정보 수정</h2>
	<form action="update" method="post">
	번호 : ${dto.num}<br>
	<input type="hidden" name="num" value="${dto.num}">
	이름 : <input type="text" name="name" value="${dto.name}"><br>
	주소 : <input type="text" name="addr" value="${dto.addr}"><br>
	<input type="submit" value="수정">
	</form>
</body>

 => 검색한 Data를 초기값으로 set.

 => <form>태그 값 수정 후 submit시 url "update" post방식으로 전달.

 

 

- UpdateController

@Controller
public class UpdateController {
	@Autowired
	private MemDaoInter daoInter;
	...
	@RequestMapping(value="update", method = RequestMethod.POST)
	public String submit(MemBean bean) {
		boolean b = daoInter.updateData(bean);
		if(b) {
			return "redirect:/list";
		}else {
			return "error";
		}
	}
}

=> POST방식 url "update" 받을 경우 submit() 메소드 실행.

=> <form>태그 값 MemBean에 set.

=> bean을 매개변수로 updateData()메소드 실행하여 업데이트 성공시 list.jsp 출력. 실패 시 error.jsp실행.

 

 

 

- MemDaoImpl

@Repository
public class MemDaoImpl extends SqlSessionDaoSupport implements MemDaoInter{
	
	@Autowired
	public MemDaoImpl(SqlSessionFactory factory) {
		setSqlSessionFactory(factory);
	}
	...
	@Override
	public boolean updateData(MemBean bean) {
		try {
			getSqlSession().update("updateData", bean);
			return true;
		}catch (Exception e) {
			System.out.println("updateData err"+e);
			return false;
		}
	}
	...
}

 => DataMapper.xml의 <update>태그의 id "updateData" sql문 실행 결과 리턴

...
 <update id="updateData" parameterType="formBean">
 	update mem set name=#{name}, addr=#{addr}
 	where num=#{num}
 </update>
...

 

 


⑤ 데이터 삭제(Delete)

- DeleteController

@Controller
public class DeleteController {
	@Autowired
	MemDaoInter daoInter;
	
	@RequestMapping("delete")
	public String delete(@RequestParam("num") String num) {
		boolean b = daoInter.deleteData(num);
		if(b) {
			return "redirect:/list";
		}else {
			return "error";
		}
	}
}

=> GET방식 url "delete" 받을 경우 delete() 메소드 실행.

=> @RequestParam사용하여 num값 set.

=> num을 매개변수로 deleteData()메소드 실행하여 삭제 성공시 list.jsp 출력. 실패 시 error.jsp실행.

 

 

- MemDaoImpl

@Repository
public class MemDaoImpl extends SqlSessionDaoSupport implements MemDaoInter{
	
	@Autowired
	public MemDaoImpl(SqlSessionFactory factory) {
		setSqlSessionFactory(factory);
	}
	...
	@Override
	public boolean deleteData(String num) {
		try {
			int result = getSqlSession().delete("deleteData", num);
			return true;
		}catch (Exception e) {
			System.out.println("deleteData err"+e);
			return false;
		}
	}
}

 => DataMapper.xml의 <delete>태그의 id "deleteData" sql문 실행 결과 리턴

<delete id="deleteData" parameterType="String">
	delete from mem where num=#{num}
</delete>

 

 

1. 로컬 저장소를 git에 연동하기

m.blog.naver.com/rlqud1125/221658862879

 

[git/이클립스] github 저장소에 프로젝트 올리기

Git을 사용하는 이유를 간단하게 설명하자면 실무에서 협업의 이유도 있고 갑작스러운 컴퓨터 오류로 프로...

blog.naver.com

 

2. 공동 작업자 초대

blog.pocu.academy/ko/2019/01/06/how-to-invite-user-to-git-repo.html

 

가이드: 내 Git 저장소에 다른 유저를 초대하기 | POCU 블로그

같은 페이지 아래 Existing members and groups 부분에서 추가된 멤버를 확인할 수 있습니다.

blog.pocu.academy

3. 이클립스 연동

jwgye.tistory.com/38

 

[Github 연동] Github(깃허브) 와 이클립스 연동하기

이클립스에 SVN을 연동해서 사용하는 것처럼 깃을 연결해서 사용 할 수 있습니다. https://github.com/jwgye/project.git 이러한 주소와 같이 개인 깃허브 주소가 있으면 가능합니다. 깃허브 주소가 없을 경

jwgye.tistory.com

4. rejected-non-fast-forward 오류 해결

winterandsnow.tistory.com/3

 

[GitHub] rejected-non-fast-forward 오류 해결

이클립스에서 GitHub으로 Commit할때 rejected-non-fast-forward 오류가 뜰 경우 먼저 사진상에 빨간색표시 된 부분을 클릭 클릭하면 이런 화면이 뜨는데 여기서 Git을 클릭 후 Open Open하면 이런 화면이..

winterandsnow.tistory.com

 

[목차]

9. Controller 처리, DB연동

① 요청 파라미터

② get/post 방식이 다른 동일 요청 처리

③ DB 연동 - DataSource

④ DB연동 - JdbcDaoSuport

⑤ DB연동 - Mybatis(xml), (root-servlet.xml사용)

⑥ DB연동 - mybatis(annotation), (root-servlet.xml사용)


[내용]

① 요청 파라미터

 = sprweb10_para_url
 - index.jsp

<body>
	<h2>* 요청 파라미터 연습</h2>
	<h3>get</h3>
	<a href="kbs/login?type=admin">관리자</a><br>
	<a href="kbs/login?type=user">일반 사용자</a><br>
	<a href="kbs/login">파라미터 없음</a><br>
	<h3>post</h3>
	<form action="kbs/login? method="post">
		data : <input type="text" name="type" value="user">
		<input type="submit" value="전송">
	</form>
	<hr>
	<h2>* 요청 URL로 정보전달</h2>
	<form action="mbc/korea" method="get">
		data : <input type="text" name="name" value="tom">
		<input type="submit" value="전송">
	</form>
	<br>
	<form action="mbc/usa" method="get">
		data : <input type="text" name="name" value="james">
		<input type="submit" value="전송">
	</form>
	<h2>* 요청 URL로 정보전달2</h2>
	<form action="ent/bighit/singer/bts" method="get">
		신곡 : <input type="text" name="title" value="다이너마이트">
		<input type="submit" value="전송">
	</form>
	<form action="ent/yg/singer/blackpink" method="get">
		신곡 : <input type="text" name="title" value="아이스크림">
		<input type="submit" value="전송">
	</form>
</body>

 => 요청 url ? 뒤의 key = value 값을 이용하여 정보 전달. (get/post)

 => 요청 url 중 mbc/ 뒤의 값으로 정보 전달.

 => 요청 url 중 ent/ ? /singer/? 각 ent/ singer 뒤의 값으로 정보 전달.

 

 

 - servlet-context.xml

<context:component-scan base-package="aa.bb.controller" />

 => <context:componet-scan> : controller pakage의 어노테이션 스캔.

 

 

 - LoginController

@Controller // controller 동작
public class LoginController {
	
	@RequestMapping(value="kbs/login", params = "type=admin")
	public ModelAndView aa() {
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("show");
		modelAndView.addObject("msg","관리자");
		return modelAndView;
	}
	
	@RequestMapping(value="kbs/login", params = "type=user")
	public ModelAndView bb() {
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("show");
		modelAndView.addObject("msg","일반고객");
		return modelAndView;
	}
	
	@RequestMapping(value="kbs/login", params = "!type") // parameter가 없는경우
	public ModelAndView cc() {
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("show");
		modelAndView.addObject("msg","인자가 없음.");
		return modelAndView;
	}

 => @RequestMapping(value="url", params = "key=name") : value는 요청 url에, params는 key, name값에 매핑되는

      요청이 들어올 경우 해당 메소드가 실행되도록 한다.

 => params 값에 따라 각각 다른 메소드가 실행되어 setViewName()의 show.jsp 파일에 addObject()로 [msg] key에

      value를 전달한다.

 

 

	// 요청 url의 일부를 변수로 받아 처리
	@RequestMapping(value="mbc/{url}")// url변수에 요청 mbc/의 값을 대입한다.
	public ModelAndView dd(
			@PathVariable String url,
			@RequestParam("name") String name) {
		System.out.println("url : "+url+" name : "+name);
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("show");
		
		if(url.equals("korea")) {
			modelAndView.addObject("msg", url+" "+name+"님 만세");
		}else if(url.equals("usa")) {
			modelAndView.addObject("msg", url+" "+name+"님 ㅇㅇ ");
		}else {
			modelAndView.addObject("msg","기타");
		}
		return modelAndView;
	}
	
	@RequestMapping(value="ent/{co}/singer/{singer}")
	public ModelAndView ee(
			@PathVariable String co,
			@PathVariable String singer,
			@RequestParam("title") String title) {
		
		String datas = "소속사 : "+co+", 가수 : "+singer+", 타이틀 곡 : "+title; 
		
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("show");
		modelAndView.addObject("msg", datas);
		
		return modelAndView;
	}
}

=> @RequestMapping(value="url/{변수명}") : mbc/korea로 요청url이 들어올 경우 변수에 korea가 들어간다.

     @PathVariable 타입 변수명 : 요청 url을 변수로 받도록 하는 어노테이션.

     @RequestParam("<form>의 name 속성") 타입 변수 : 변수 String name에 <form>의 value값이 전달된다.

 

 

 - show.jsp

<body>
	결과는 ${msg}
</body>

 => EL 사용 결과값 출력.

 

 


② get/post 방식이 다른 동일 요청 처리

 = sprweb11_getpost
 - index.jsp

<body>
	<h2>메인</h2>
	회원처리 게시판 <a href="login">로그인(get)</a> 
	<pre>본문
	</pre>	
</body>

 => url요청을 login 전달. (Get방식)

 

 

 - LoginController

@Controller
public class LoginController {
	private String formName = "loginform";
	
	@Autowired
	private LoginForm loginForm;
			
	@RequestMapping(value="login", method=RequestMethod.GET)
	public String form() {
		return formName;
	}
	
	@RequestMapping(value="login", method=RequestMethod.POST)
	public String submit(LoginForm loginForm) {
		
		if(loginForm.getUserid().equalsIgnoreCase("aa")&
				loginForm.getPasswd().equalsIgnoreCase("11")) {
			
			return "redirect:/list";//로그인 성공하면 목록보기
		}else {
			return formName; // 로그인 실패하면 로그인 화면으로 이동
		}
	}
}

 => index.jsp에서 전달한 url "login"(get 방식)으로 form()메소드가 실행된다.

 => @RequestMapping(value="url명", method=RequestMethod.GET) : 해당 url중 GET방식으로 전달할 경우만 해당

       메소드가 실행된다.

=> @Controller의 클래스에 String을 리턴값으로 가지는 form() 메소드가 실행될 경우 리턴값과 동일한 jsp파일을 실행

     한다. (loginform.jsp 실행)

 

 

 - loginform.jsp

<body>
	<h2>자료입력</h2>
	<form action="login" method="post"/>
		id : <input type="text" name="userid" id="userid"/><br>
		pwd: <input type="text" name="passwd" id="passwd"/><br>
		<input type="submit" value="전송(전통적)"/><br>
	</form>
</body>

 => LoginController class의 form() 메소드 실행으로 실행된다.

 => index.jsp의 동일한 url 요청명인 "login"으로 Post방식으로 값을 전달한다. 

 

 

 - LoginController

@Controller
public class LoginController {
	private String formName = "loginform";
	
	@Autowired
	private LoginForm loginForm;
			
	@RequestMapping(value="login", method=RequestMethod.GET)
	public String form() {
		return formName;
	}
	
	@RequestMapping(value="login", method=RequestMethod.POST)
	public String submit(LoginForm loginForm) {
		
		if(loginForm.getUserid().equalsIgnoreCase("aa")&
				loginForm.getPasswd().equalsIgnoreCase("11")) {
			
			return "redirect:/list";//로그인 성공하면 목록보기
		}else {
			return formName; // 로그인 실패하면 로그인 화면으로 이동
		}
	}
}

 => @RequestMapping(value="url명", method=RequestMethod.POST) : url중 Post방식으로 송부시에 실행된다.

 => String 메소드명(FormBean 변수명) : <form>태그의 name 속성값과 동일한 변수를 가지는 FormBean을 매개변수로

      가질 경우 FormBean객체에 각 값들이 대입된다.

      str1.equalsIngnorseCase(str2) : str1과 str2를 대소문자 구분하지않고 비교한다.

 => Login에 성공할 경우 redirect로 클라이언트에서 요청을 실행한 것과 같이 실행하여야한다. (forward를 사용하지

      않음). Redirect로 list.jsp를 실행한다.

 

 

-  LoginForm

@Component
public class LoginForm {
	private String userid; // <form>태그의 name속성값과 동일하게 변수를 가진다.
	private String passwd;
	
	public String getUserid() {
		return userid;
	}
	public void setUserid(String userid) {
		this.userid = userid;
	}
	public String getPasswd() {
		return passwd;
	}
	public void setPasswd(String passwd) {
		this.passwd = passwd;
	}
}

 => <form>태그의 name속성값과 동일하게 변수를 가지도록 작성한다. FormBean은 client의 요청을 처리할 때 사용

      한다. DTO는 DB 자료를 처리할 때 사용. (용도에 따라 관례적으로 FormBean과 DTO를 사용한다)

 

 

 - ListController

@Controller
public class ListController {
	@RequestMapping("list")
	public ModelAndView aaa() {
		ModelAndView view = new ModelAndView("list");
		view.addObject("msg", "로그인 성공으로 하고 뭔가를 출력함");
		
		return view;
	}
}

 => 성공시 실행할 내용을 구현한다. "msg" key에 값 전달.

 

 

 - list.jsp

<body>
	결과 : ${msg}
</body>

 => EL사용하여 msg값 출력

 


③ DB 연동 - DataSource

 = sprweb12_db_legacy
 - main.jsp

<body>
	<h2>메인</h2>
	<a href="testdb">상품보기</a>
</body>

 => "testdb" url 전달.(get 방식)

     <%response.sendRedirect("testdb"); %>로 동일한 기능 수행하도록 구현가능.

 

 

 - servlet-context.xml

<context:component-scan base-package="aa.bb.controller" />
<context:component-scan base-package="aa.bb.model" />

 => 어노테이션 scan.

 

 

- ListController

@Controller // 클라이언트로 부터  요청 받을 경우 동작
public class ListController {
	
	@Autowired
	private DataDao dataDao;
	
	@RequestMapping("testdb") // url mapping
	public ModelAndView listProcess() {
		ArrayList<SangpumDto> list = dataDao.getDataAll();
		
		return new ModelAndView("list", "datas", list); // list.jsp에 연결.
	}
}

 => @Controller : 클라이언트로 부터  요청 받을 경우 동작.

      @Autowired : setter injection 기능 수행.

      @RequestMapping("url명") : url명과 동일한 url을 받을 경우 실행.

      dataDao의 getDataAll()를 실행한 list값을 "datas" key에 넣어 실행한다.

 

 

- SangpumDto

public class SangpumDto {
	private String code, sang, su, dan;
	//getter/setter
}

 => DB 데이터를 담는 DTO 정의.

 

 

- DataDao

@Repository // DB 연결.
public class DataDao {
	private Connection conn;
	private PreparedStatement ptmt;
	private ResultSet rs;
	
	public DataDao() {
	}
	
	@Autowired
	private DataSourceMaria dataSourceMaria; 
	
	public ArrayList<SangpumDto> getDataAll(){
		ArrayList<SangpumDto> list = new ArrayList<SangpumDto>();
		
		try {
			String sql = "select * from sangdata";
			conn = dataSourceMaria.getConnection();
			ptmt=conn.prepareStatement(sql);
			rs = ptmt.executeQuery();
			while(rs.next()) {
				SangpumDto dto = new SangpumDto();
				dto.setCode(rs.getString("code"));
				dto.setSang(rs.getString("sang"));
				dto.setSu(rs.getString("su"));
				dto.setDan(rs.getString("dan"));
				list.add(dto);
			}
		} catch (Exception e) {
			System.out.println("getDataAll err"+e);
		}finally {
			try {
				if(conn != null) conn.close();
				if(ptmt != null) ptmt.close();
				if(rs != null) rs.close();
			} catch (Exception e2) {
				System.out.println(e2);
			}
		}
		return list;
	}
}

 => @Repository : 객체 생성. DB 연결하는 클래스에 사용. 기능은 @Component와 동일.

      @Autowired : DriverManagerDataSource를 상속받은 클래스 객체를 setter injection한다.

      getConnection() : jdbc와 연결.

      prepareStatement(sql) : sql문을 get한다.

      executeQuery() : sql문을 실행한 결과를 리턴한다.

      rs.next() : sql 실행 결과를 한 행 단위로 읽는다.

      rs.getString("record명") : 읽고 있는 sql 실행결과 라인의 Record 값을 리턴한다.

 => sql문의 실행 결과를 dto에 담고 실행결과의 한 줄씩 list에 담는다.(list.add(dto))

 => sql문의 실행결과를 ArrayList로 반환한다.

 

 

- DataSourceMaria

@Repository() // DB연동
//@Repository("dataSource") 
public class DataSourceMaria extends DriverManagerDataSource{
	public DataSourceMaria() {
		setDriverClassName("org.mariadb.jdbc.Driver");
		setUrl("jdbc:mysql://127.0.0.1:3306/test");
		setUsername("root");
		setPassword("123");
	}
}

 => extends DriverManagerDataSource : 상속하여 DB와 연결하는 객체를 생성한다.

 => setDriverClassName() / setUrl() / setUsername() / setPassword() : JDBC연결을 위한 정보를 set한다.

 

 

- list.jsp

<%@ taglib prefix="c"  uri="http://java.sun.com/jsp/jstl/core"%>
<body>
	<h2>*상품자료(전통적)</h2>
	<table border="1">
		<tr>
			<th>코드</th><th>품명</th><th>수량</th><th>단가</th>
		</tr>
		
		<c:forEach var="s" items="${datas}">
			<tr>
				<td>${s.code}</td>
				<td>${s.sang}</td>
				<td>${s.su}</td>
				<td>${s.dan}</td>
			</tr>
		</c:forEach>
	</table>
</body>

 => <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> : EL 액션태그로 core 메소드를 액션태그를 사용

      할 수 있게 library를 연결한다.

 => <c:forEach var="변수명" items="${리스트명}"> : var에 items의 list 값을 index 0 부터 null까지 반복 실행한다.

       (for-each문)

 => EL사용하여 결과값 출력.

 

 


④ DB연동 - JdbcDaoSuport

= sprweb13_db_jdbc_dao_support
-  index.jsp

<body>
	<a href="testdb">상품보기(JbdcDaoSupport)</a>
</body>

 => DataSource와 동일

 

 

- servlet-context.xml

<context:component-scan base-package="aa.bb.controller" />
<context:component-scan base-package="aa.bb.model" />

 => DataSource와 동일

 

 

- ListController

@Controller // 클라이언트로 부터  요청 받을 경우 동작
public class ListController {
	
	@Autowired
	private DataDao dataDao;
	
	@RequestMapping("testdb") // url mapping
	public ModelAndView listProcess() {
		ArrayList<SangpumDto> list = dataDao.getDataAll();
		
		return new ModelAndView("list", "datas", list); // list.jsp에 연결.
	}
}

 => DataSource와 동일

 

 

- SangpumDto

public class SangpumDto {
	private String code, sang, su, dan;
	//getter/setter
}

 => DataSource와 동일

 

 

- DataSourceMaria

@Repository() // DB연동
//@Repository("dataSource") 
public class DataSourceMaria extends DriverManagerDataSource{
	public DataSourceMaria() {
		setDriverClassName("org.mariadb.jdbc.Driver");
		setUrl("jdbc:mysql://127.0.0.1:3306/test");
		setUsername("root");
		setPassword("123");
	}
}

 => DataSource와 동일

 

 

- DataDao

@Repository // DB 연결.
public class DataDao extends JdbcDaoSupport{
	//@Autowired
	//private DataSourceMaria dataSourceMaria; // DataDao에 주입됨.
	//DataSource를 JdbcDaoSupport가 가지고 있으로 생성자를 이용한다.
	
	public DataDao(DriverManagerDataSource dataSource) {
		setDataSource(dataSource);
	}
	
	public List<SangpumDto> getDataAll(){
		String sql="select * from sangdata";
		return getJdbcTemplate().query(sql, new ItemRowMapper());
	}
	
	class ItemRowMapper implements RowMapper{
		@Override
		public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
			SangpumDto dto = new SangpumDto();
			dto.setCode(rs.getString("code"));
			dto.setSang(rs.getString("sang"));
			dto.setSu(rs.getString("su"));
			dto.setDan(rs.getString("dan"));
			return dto;
		}
	}
}

 => extends JdbcDaoSupport : JdbcDaoSupport 상속 받아 기능을 수행한다.

 => @Autowird를 사용하면 DataDao객체에 dataSource가 setter injection됨으로 해당 기능이 정상동작하지않는다.

       정상동작을 위해선 상속을 받고있는 JdbcDaoSupport객체에 setter injection을 하여야한다. 생성자를 이용하여

       DataDao객체가 생성되면 setDataSource()가 실행되도록 하여 JdbcDaoSupport객체에 dataSource를 setter

       injection한다.

 => getJdbcTemplate().query(sql, new ItemRowMapper()) : sql문이 ItemRowMapper클래스가 실행하여 한줄 씩 실행된

      결과를  List 리턴.

 => implemets RowMapper : RowMapper를 상속하여 mapRow() 메소드를 오버라이딩하여 sql문을 실행한다.

 

 

 

- list.jsp

<%@ taglib prefix="c"  uri="http://java.sun.com/jsp/jstl/core"%>
<body>
	<h2>*상품자료(전통적)</h2>
	<table border="1">
		<tr>
			<th>코드</th><th>품명</th><th>수량</th><th>단가</th>
		</tr>
		
		<c:forEach var="s" items="${datas}">
			<tr>
				<td>${s.code}</td>
				<td>${s.sang}</td>
				<td>${s.su}</td>
				<td>${s.dan}</td>
			</tr>
		</c:forEach>
	</table>
</body>

 => DataSource와 동일

 


⑤ DB연동 - Mybatis(xml) (root-servlet.xml사용)

 = sprweb14_db_mybatis

 - pom.xml

<!-- MariaDB driver -->
<dependency>
	<groupId>org.mariadb.jdbc</groupId>
	<artifactId>mariadb-java-client</artifactId>
	<version>2.6.2</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.0</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.3.0</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>${org.springframework-version}</version>
</dependency>

 => MariaDB, Mybatis lib 추가한다.

 

 

- main.jsp

<body>
	<a href="list">상품보기(@MVC-MyBatis)</a>
</body>

=> url 요청명 list 전달.(get방식)

 

 

 - servlet-context.xml

<context:component-scan base-package="pack.controller" />
<context:component-scan base-package="pack.model" />

=> 어노테이션 사용을 위한 패키지 스캔.

 

 

- db.properties

driver=org.mariadb.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/test
username=root
password=123

 => 계정정보를 가진 자바 속성 파일. key=name 형식. (암호화 파일로 구현하는 것을 지향)

 

 

 - Configuration.xml

<configuration>
 <typeAliases>
 	<typeAlias type="pack.model.SangpumDto" alias="dto"/>
 	<typeAlias type="pack.controller.SangpumBean" alias="formBean"/>
 </typeAliases>
 <!--  DB 연결을 root-context.xml에서 하도록 수정.
 <properties resource="pack/mybatis/db.properties" />
 <environments default="dev">
  <environment id="dev">
   <transactionManager type="JDBC" />
   <dataSource type="POOLED">
    <property name="driver" value="${driver}" />
    <property name="url" value="${url}" />
    <property name="username" value="${username}" />
    <property name="password" value="${password}" />
   </dataSource>
  </environment>
 </environments>
 -->
 <mappers>
  <mapper resource="pack/mybatis/DataMapper.xml" />
 </mappers>
</configuration>

 => 공유자원을 관리하는 root-context.xml에서 DB연결을 하도록, Sql문 mapping하는 DataMapper.xml관련 설정을

      제외하고 삭제.

 => DataMapper파일과 alias를 정의한다.

 

 

 - DataMapper.xml

<mapper namespace="dev">
	<select id="selectAll" resultType="dto">
		select * from sangdata
	</select>
	<select id="selectSearch" parameterType="formBean" resultType="dto">
		select code, sang, su, dan from sangdata
		where sang like concat('%',#{searchValue},'%')
	</select>
</mapper>

 => sql문과 연결되는 Mapper 파일을 작성한다.(<mapper>태그 내부에 sql문을 형식에 맞춰 작성)

 => <select> : select문 작성 시 사용되는 태그. (id속성 - 외부에서 호출할 이름 / resultType - sql문을 실행한 결과

                    Type / parameterType속성 - 외부로 부터 받을 매개변수의 타입, #{변수명}에 매개변수가 대입된다.)

=> like concat('%', 검색어, '%') : 검색어가 포함된 결과 반환. ( like %검색어%)

 

 

- SqlMapConfig : 미사용 (root-context.xml에서 DB연결)

 

 

 - root-context.xml

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
	<property name="locations">
		<value>classpath:pack/mybatis/db.properties</value>
	</property>
</bean>

 => <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> : 외부 파일의 프로퍼티

       정보를 해당 설정파일에서 사용가능하도록 기능 제공.

 => locations 속성으로 db.properties를 read하도록 설정.
      db.properties의 프로퍼티를 ${프로퍼티값}으로 사용할 수 있다.

<bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
	<property name="driverClass" value="${driver}"/>
	<property name="url" value="${url}"/>
	<property name="username" value="${username}"/>
	<property name="password" value="${password}"/>
</bean>

<bean class="org.mybatis.spring.SqlSessionFactoryBean">
	<property name="dataSource" ref="dataSource"/>
	<property name="configLocation" value="classpath:pack/mybatis/Configuration.xml"></property>
</bean>

 => <bean class="org.springframework.jdbc.datasource.SimpleDriverDataSource"> : db를 사용할 수 있도록 기능제공.

               drivaerClass, url, usernam, password를 setter 주입하여 db연결 객체 생성.

 => <bean class=org.mybatis.spring.SqlSessionFactoryBean"> : SqlSessionFatory 객체를 생성.

               Configuration.xml, dataSource를 setter 주입하여 factory 객체 생성.

               factory객체를 여러개 사용시에는 id속성을 사용한다.

 

 

- ListController

@Controller
//@ComponentScan("pack.model")
public class ListController {
	
	@Autowired // setter injection
	private SangpumInter sangpumInter; // 다형성 사용
	
	@RequestMapping("list")
	public Model process(Model model){
		model.addAttribute("data", sangpumInter.list());
		// Model객체는 addAttribe(key, value) 메소드를 사용하여 값을 전달.
		return model; // 받은 요청명 그대로 송부한다.
	}
}

 => @Controller : Controller 기능 수행 (servlet 동작)

 => "list" url 받을 경우 동작한다. list()메소드를 실행한 결과를 "data" key에 넣어 list.jsp에 리턴한다.

 

 

- SangpumDto

public class SangpumDto {
	private String code,sang, su, dan;
	//setter, getter
}

 => DB연동에 사용되는 데이터는 Dto로 작성.(select)

 

 

- SangpumBean

public class SangpumBean {
	// formBean : 수정, 삭제 등의 작업이 있다면 code, sang, su, dan도 처리
	// 검색용
	private String searchValue;

	public String getSearchValue() {
		return searchValue;
	}

	public void setSearchValue(String searchValue) {
		this.searchValue = searchValue;
	}
}

=> insert, delete의 작업을 진행할 경우 FormBean으로 작성.

=> select문에 매개변수로 들어가 조건을 추가할 searchValue 변수 정의.

 

 

- SangpumInter

public interface SangpumInter {
	List<SangpumDto> list() throws DataAccessException;
	List<SangpumDto> seach(SangpumBean bean) throws DataAccessException;
	//insert, update, delete ...
}

 => 테이블별로 interface로 관리한다.

 => db에서 select 전체 테이블 조회 기능을 갖출 list()메소드 선언.

 => db에서 select 특정 검색어가 들어간 데이터를 조회 기능을 갖출 search()메소드 선언.

 

 

- SangpumImpl

@Repository // DB연동
public class SangpumImpl extends SqlSessionDaoSupport implements SangpumInter{
	
	@Autowired // 타입에 의한 매핑
	// 복수개일 경우 @Quiyfied사용
	public SangpumImpl(SqlSessionFactory factory) {
		// root-context.xml에서 factory 객체 생성함.
		setSqlSessionFactory(factory); // SqlSessionDaoSupport에 factory 주입.
	}
	
	@Override
	public List<SangpumDto> list() throws DataAccessException {
		return getSqlSession().selectList("selectAll");
	}

	@Override
	public List<SangpumDto> seach(SangpumBean bean) throws DataAccessException {
		return getSqlSession().selectList("selectSearch", bean);
	}
}

 => @Repository : 객체생성(DB연동 기능을 갖출경우 관례적으로 @Repository사용)

 => extends SqlSessionDaoSupport : SqlSession을 제공하는 추상 클래스.(getSqlSession()메소드)

 => implements SangpumInter : 다형성을 통한 테이블별 관리를 하기 위해 interface사용

 => 생성자 setter 주입을 통해 SqlSessionFactory 객체를 sqlSessionDaoSupport에 set한다.(setSqlSessionFactory() 사용)

 => getSqlSession() : sqlSession객체의 메소드를 사용하여 sql문을 실행한 결과를 리턴한다.

=> selectList("매핑 id") : select문을 실행하여 복수의 data를 list로 리턴한다. DataMapper.xml의 id를 매개변수로

     가진다.

 

 

- SearchController

@Controller
public class SearchController {
	@Autowired
	private SangpumInter sangpumInter;
	
	@RequestMapping(value="search", method = RequestMethod.POST)
	public ModelAndView searchProcess(SangpumBean bean) {
		List<SangpumDto> list = sangpumInter.seach(bean);
		return new ModelAndView("list","data", list);
	}
}

 => "search" url 받을 경우 <form>태그의 name 속성들의 값을 formBean객체로 대입하여 받는다.

       formBean객체를 매개변수로 search()메소드를 실행하여 list결과를 "data" key에 리턴한다.

 

 

 - list.jsp

<body>
	<h2>* 상품정보(@MVC - MyBatis)</h2>
	<table border="1">
		<tr>
			<th>코드</th><th>품명</th><th>수량</th><th>단가</th>
		</tr>	
		<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
		<c:forEach var="s" items="${data}">
		<tr>
			<td>${s.code}</td>
			<td>${s.sang}</td>
			<td>${s.su}</td>
			<td>${s.dan}</td>
		</tr>
		</c:forEach>
		<tr>
			<td colspan="4">
				<form action="search" method="post">
					이름 : <input type="text" name="searchValue">
					<input type="submit" value="검색">
				</form>
			</td>
		</tr>
	</table>
</body>

 => sql 결과를 테이블 형태로 출력.

 

 


⑥ DB연동 - mybatis(annotation), (root-servlet.xml사용)

 = sprweb14_db_mybatis_annotation

- main.jsp

<body>
	<a href="list">상품보기(@MVC-MyBatis)</a>
</body>

=> xml방식과 동일

 

 

 - servlet-context.xml

<context:component-scan base-package="pack.controller" />
<context:component-scan base-package="pack.model" />

=> xml방식과 동일

 

 

 

- db.properties

driver=org.mariadb.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/test
username=root
password=123

=> xml방식과 동일

 

 

 

 - Configuration.xml : 미사용(어노테이션 사용)

 

 

 - DataMapper.xml : 미사용(어노테이션 사용)

 

- SqlMapConfig : 미사용 (root-context.xml에서 DB연결)

 

 

 - root-context.xml

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
	<property name="locations">
		<value>classpath:pack/mybatis/db.properties</value>
	</property>
</bean>

=> xml방식과 동일

 

 

- ListController

@Controller
//@ComponentScan("pack.model")
public class ListController {
	
	@Autowired // setter injection
	private SangpumInter sangpumInter; // 다형성 사용
	
	@RequestMapping("list")
	public Model process(Model model){
		model.addAttribute("data", sangpumInter.list());
		// Model객체는 addAttribe(key, value) 메소드를 사용하여 값을 전달.
		return model; // 받은 요청명 그대로 송부한다.
	}
}

=> xml방식과 동일

 

 

- SangpumDto

public class SangpumDto {
	private String code,sang, su, dan;
	//setter, getter
}

=> xml방식과 동일

 

 

 

- SangpumBean

public class SangpumBean {
	// formBean : 수정, 삭제 등의 작업이 있다면 code, sang, su, dan도 처리
	// 검색용
	private String searchValue;

	public String getSearchValue() {
		return searchValue;
	}

	public void setSearchValue(String searchValue) {
		this.searchValue = searchValue;
	}
}

=> xml방식과 동일

 

 

- SangpumInter

public interface SangpumInter {
	List<SangpumDto> list() throws DataAccessException;
	List<SangpumDto> seach(SangpumBean bean) throws DataAccessException;
	//insert, update, delete ...
}

=> xml방식과 동일

 

 

- SangpumAnnoInter

// MyBatis SQL mapping interface file
public interface SangpumAnnoInter {
	@Select("select * from sangdata")
	public List<SangpumDto> selectAllData();
	
	@Select(" select code, sang, su, dan from sangdata where sang like concat('%',#{searchValue},'%')")
	public List<SangpumDto> selectSearch(SangpumBean bean);
}

 => MyBatis SQL mapping interface파일 작성.

 => @Select("select sql문") : db에서 sql문 실행한 결과값을 리턴한다.

 

 

- SangpumImpl

@Repository // DB연동
public class SangpumImpl implements SangpumInter{
	
	@Autowired
	private SangpumAnnoInter sangpumAnnoInter;
	
	@Override
	public List<SangpumDto> list() throws DataAccessException {
		return sangpumAnnoInter.selectAllData();
	}

	@Override
	public List<SangpumDto> seach(SangpumBean bean) throws DataAccessException {
		return sangpumAnnoInter.selectSearch(bean);
	}
}

 => extends SqlSessionDaoSupport은 하지않는다.

 => @Autowired : sql mapping interface객체를 setter injection한다.

=> sql mapping interface객체의 메소드의 결과를 리턴받는다.

 

 

- SearchController

@Controller
public class SearchController {
	@Autowired
	private SangpumInter sangpumInter;
	
	@RequestMapping(value="search", method = RequestMethod.POST)
	public ModelAndView searchProcess(SangpumBean bean) {
		List<SangpumDto> list = sangpumInter.seach(bean);
		return new ModelAndView("list","data", list);
	}
}

=> xml방식과 동일

 

 

 - list.jsp

<body>
	<h2>* 상품정보(@MVC - MyBatis)</h2>
	<table border="1">
		<tr>
			<th>코드</th><th>품명</th><th>수량</th><th>단가</th>
		</tr>	
		<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
		<c:forEach var="s" items="${data}">
		<tr>
			<td>${s.code}</td>
			<td>${s.sang}</td>
			<td>${s.su}</td>
			<td>${s.dan}</td>
		</tr>
		</c:forEach>
		<tr>
			<td colspan="4">
				<form action="search" method="post">
					이름 : <input type="text" name="searchValue">
					<input type="submit" value="검색">
				</form>
			</td>
		</tr>
	</table>
</body>

=> xml방식과 동일

 

 


 

[목차]

8. Controller 처리

    ① Client요청을 Controller로 연결하기
    공유 객체 사용
    패턴을 사용한 경로 매핑
    @annotation을 이용한 Controller호출
    Spring MVC Project를 사용
    @RequestParam 사용(get)
        * Controller 값 처리(기존) : getParameter()
        * Controller 값 처리(어노테이션 사용)
        * get 방식은 한글이 안깨지나 post 방식사용시 한글이 깨진다. Encording을 하여 한글 깨짐을 방지한다.
    FormBean, @ModelAttribute 사용(post)
        * Controller 값 처리(기존) : getParameter()
        * Controller 값 처리(FormBean 사용)
        * Controller 값 처리(@ModelAttribute 사용)

 


[내용]

1) Client요청을 Controller로 연결하기

 

    : implements Controller와 @Controller 사용

 

=sprweb3

 - start.html

<body>
	<a href="hello.do">클릭 1-1(get)</a>
	<form action="hello.do" method="post">
		<input type="submit" value="클릭 1-2(post)"/>
	</form>
	<hr>
	<a href="world.do">클릭 2-1</a>
	<a href="good.do">클릭 2-2</a>
	<a href="hi/nice.do">클릭 2-3</a>
	<form action="korea.do" method="get">
		<input type="submit" value="클릭 2-4(get)"/>
	</form>
	<form action="usa.do" method="post">
		<input type="submit" value="클릭 2-4(post)"/>
	</form>
</body>

 => 클릭 1-1 (요청 : hello.do / get)

      클릭 1-2 (요청 : hello.do / post)

      클릭 2-1 (요청 : world.do / get)

      클릭 2-2 (요청 : good.do / get)

      클릭 2-3 (요청 : hi/nice.do / get)

      클릭 2-4 (요청 : korea.do / get)

      클릭 2-4 (요청 : usa.do / post)

 

 

 - web.xml

<!-- DispatcherServlet는 test-servlet.xml의 설정을 불러온다. -->
<servlet>
	<servlet-name>test</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<!-- servlet-name이 아닌 다른  path로 연결할 경우 사용-->
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			<!-- 공백 구분 -->
			/WEB-INF/abc/hello-servlet.xml
			/WEB-INF/def/world-servlet.xml
		</param-value>
	</init-param>
</servlet>
<servlet-mapping>
	<servlet-name>test</servlet-name>
	<url-pattern>*.do</url-pattern>
</servlet-mapping>

=> test-servlet.xml이 아닌 다른 patch로 연결할 경우, <init-param> 태그를 사용한다.

     hello-servlet, world-servlet으로 연결된다.

 

 

- hello-servlet.xml/ world-servlet.xml

 * Controller implemets(상속)을 사용할 경우

<!-- 2. Handler Mapping -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>

<!-- 3. Controller -->
<bean name="/hello.do" class="pack.HelloController"></bean>

<!-- 5. ViewResover -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<property name="prefix" value="/views/"/>
	<property name="suffix" value=".jsp"/>
</bean>

 => hello.do 요청이 올 경우 HelloController가 실행된다.

 

  * @Controller(어노테이션)을 사용할 경우

<!-- 어노테이션 사용시 삭제 -->
<!-- 2. Handler Mapping -->
<!-- 
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
 -->
<!-- 3. Controller -->
<!--  
<bean name="/hello.do" class="pack.HelloController"></bean>
-->
<!-- 어노테이션 사용시 추가 -->
<context:component-scan base-package="pack"/>

<!-- 5. ViewResover -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<property name="prefix" value="/views/"/>
	<property name="suffix" value=".jsp"/>
</bean>

 => 어노테이션 사용시 <context:component-scan>를 사용한다. pack package의 어노테이션이 동작하도록 한다.

 

 

 - HelloController
 * Controller implemets(상속)을 사용할 경우

public class HelloController implements Controller{
	
	@Override
	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
									throws Exception {
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("veiw1"); // veiw1.jsp에 연결 
		modelAndView.addObject("message", "hello"); // 모델에 다녀왔다 가정. // key-value 전달.
		
		return modelAndView;
	}
}

=> hello-servlet.xml/ world-servlet.xml에서 연결한 hello.do 요청 발생 시 실행된다.

=> handlerRequest() 메소드를 오버라이딩하여 request를 처리한다.

=> setVieName("파일명")으로 view1에 연결된다. .hello-servlet.xml 파일의 ViewResover 처리로 /views/view1.jsp파일이

     연결된다.

 => addObject(key, value)를 이용하여 값을 전달한다.

 

  * @Controller(어노테이션)을 사용할 경우

 

@Controller
@RequestMapping("hello.do") // 모든 메소드가 수행된다.
public class HelloController{
	@RequestMapping(method=RequestMethod.GET)
	//@RequestMapping("hello.do") // 해당 메소드만 실행된다.
	public ModelAndView aaa() {
		ModelAndView modelAndView =  new ModelAndView();
		modelAndView.setViewName("view1");
		modelAndView.addObject("message", "hello aaa");
		return modelAndView;
	}
	
	@RequestMapping(method=RequestMethod.POST)
	//@RequestMapping("hello.do")
	public ModelAndView bbb() {
		ModelAndView modelAndView =  new ModelAndView();
		modelAndView.setViewName("view1");
		modelAndView.addObject("message", "hello bbb");
		return modelAndView;
	}
}

 => hello-servlet.xml의 <context:component-scan>태그로 인해 @Controller가 동작한다.

      @Controller : 클라이언트 요청에 따라 해당 클래스가 Controller동작을 하게된다.

      @RequestMapping("요청명") : 요청명에 해당하는 요청이 들어올 경우 클래스가 실행된다.

      @RequestMapping(method=RequestMethod.GET) : Get방식의 요청이 들어올때만 실행하게 한다.

      @RequestMapping(method=RequestMethod.POST) : Post방식의 요청이 들어올때만 실행하게 한다.

 => ModelAndView객체를 리턴하도록 하여 값을 전달한다. 메소드명을 임의 지정 가능하다.

 

 

 -  WorldController
 * Controller implemets(상속)을 사용할 경우

public class WorldController implements Controller{
	
	@Override
	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
								throws Exception {
		
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("view2"); // veiw1.jsp에 연결 
		modelAndView.addObject("message", "hi world"); // 모델에 다녀왔다 가정. // key-value 전달.
		
		return modelAndView;
	}
}

 => HelloController와 동일

 

  * @Controller(어노테이션)을 사용할 경우

 

@Controller
public class WorldController{
	@RequestMapping({"/world.do","/good*.*","/hi/nice.do"}) // 여러개의 요청을 받을 수 있음.
	//@RequestMapping("world.do")
	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
					throws Exception {
		
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("view2"); // veiw1.jsp에 연결 
		modelAndView.addObject("message", "hi world"); // 모델에 다녀왔다 가정. key-value 전달.
		
		return modelAndView;
	}
	
	@RequestMapping(value="/korea.do", method=RequestMethod.GET) // GET만 받을 수 있다.
	//@RequestMapping({"/korea.do"})// Get과 Post를 모두 받을 수 있다.
	public ModelAndView handleRequest2(HttpServletRequest request, HttpServletResponse response)
					throws Exception {
		
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("view2"); // veiw1.jsp에 연결 
		modelAndView.addObject("message", "hi world korea"); // 모델에 다녀왔다 가정. key-value 전달.
		
		return modelAndView;
	}
    
	@RequestMapping(value="/usa.*", method=RequestMethod.POST) // POST만 받을 수 있다.
	//@RequestMapping(value="/usa.*", method=RequestMethod.GET) // GET만 받을 수 있다.
	//@RequestMapping({"/usa.*"})
	public ModelAndView handleRequest3(HttpServletRequest request, HttpServletResponse response)
					throws Exception {
		
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("view2"); // veiw1.jsp에 연결 
		modelAndView.addObject("message", "hi world usa"); // 모델에 다녀왔다 가정. key-value 전달.
		
		return modelAndView;
	}
}

 => @RequestMapping({요청명1, 요청명2,..}) : 배열을 사용하여 여러개의 요청명을 받을 수 있다.

      @RequestMapping(value="요청명", method=RequestMethod.GET) : 요청과 method 방식을 설정할 수 있다.

      요청명에 * 를 사용하여 복수의 요청을 받을 수 있다.

 

 

 - view1.jsp / view2.jsp

<body>
	hello 결과 : ${requestScope.message}
</body>

 => Controller에서 addObject()메소드로 전달한 value를 key를 사용하여 받을 수 있다. (EL 사용 - ${key})

 

 


2) 공유 객체 사용

 = spr4_share

 - index.html

<body>
	클래스 간 자원 공유<br>
	<a href="hello.do">요청 1</a><br>
	<a href="world.kor">요청2</a><br>
</body>

 

 

 - web.xml

<!-- WebApplicationContext보다 먼저 수행 : 공유 자원 설정시 필요 -->
<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>

<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

 => applicationContext.xml에 공유자원을 설정한다.

<!-- WebApplicationContext에 의해 자동 수행 -->
<servlet>
	<servlet-name>hello</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<!-- <load-on-startup> init() 메소드 호출 순서 -->
	<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
	<servlet-name>hello</servlet-name>
	<url-pattern>*.do</url-pattern>
</servlet-mapping>

<servlet>
	<servlet-name>world</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
	<servlet-name>world</servlet-name>
	<url-pattern>*.kor</url-pattern>
	<!-- <url-pattern>/</url-pattern> 모든 요청사항 -->
</servlet-mapping>

 => *.do 요청과 hello-servlet.xml 연결

 => *.kor요청과 world-servlet.xml 연결

 

 

- applicationContext.xml

<!-- 공유 자원 객체 생성 -->
<bean id="sharedData" class="pack.SharedData">
	<property name = "shared" value="스프링 프로젝트 공유자원입니다."/>
</bean>

 => setter injection을 이용하여 공유자원 객체 shard에 value를 설정한다.

 

 

 - hello-servlet.xml, world-servlet.xml

<!-- 2. Handler Mapping -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>

<!-- 3. Controller -->  
<bean name="/hello.do" class="pack.HelloController">
	<property name="data" ref="sharedData"/>
</bean>

<!-- 5. ViewResover -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<property name="prefix" value="/views/"/>
	<property name="suffix" value=".jsp"/>
</bean>

 => hello.do과 HelloController 연결. HelloController에 공유객체를 setter injection한다.

 

 

 - SharedData

public class SharedData {
	private String shared;
	public void setShared(String shared) {
		this.shared = shared;
	}
	public String getShared() {
		return shared;
	}
}

 => getter, setter를 이용하여 공유객체를 사용한다.

 

 

 - HelloController

public class HelloController implements Controller{
	private SharedData data; // 공유객체 선언.
	// setter injection에 사용
	public void setData(SharedData data) {
		this.data = data;
	}
	
	@Override
	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
					throws Exception {
		// 현재 클래스가 공유자원을 사용
		ModelAndView modelAndView = new ModelAndView("helloworld"); // ViewFile명
		modelAndView.addObject("msg", data.getShared() + "hello");
	
		return modelAndView;
	}
}

 => ModelAndView("ViewFile명") : ModelAndView 생성자에 매개변수로 ViewFile명을 전달하여 ViewFile에 연결.  (setViewName("ViewFile명")과 동일)
 => addObject()메소드 사용하여 공유 객체의 내용 전달.

 

 

 - helloworld.jsp

<body>
	결과 : ${msg}
</body>

 


3) 패턴을 사용한 경로 매핑

 

 =spr5_arrange

 - index.html

<body>
	@MVC 기본정리<p/>
	<a href="hello.do">인사하기 1</a>
</body>

 => hello.do 요청. (get)

 

 

 - web.xml

<!-- WebApplicationContext에 의해 자동 수행 -->
<servlet>
	<servlet-name>test</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<!-- <load-on-startup> init() 메소드 호출 순서 -->
	<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
	<servlet-name>test</servlet-name>
	<url-pattern>*.do</url-pattern>
</servlet-mapping>

 => test-servlet.xml과 *.do를 url mapping한다.

 => <servlet-mapping>이 여러개 일 경우 <load-on-startup>로 init() 메소드 호출 순서를 지정할 수 있다.

 

 

 - test-servlet.xml

 * mapping 방법1 : 요청 url과 동일한 이름을 bean과 매핑(basic)

<!-- 2. Handler Mapping -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>

<!-- 3. Controller -->
<bean name="/hello.do" class="pack.controller.HelloController">
	<property name="helloModel" ref="helloModel"></property>
</bean>

<bean id="helloModel" class="pack.model.HelloModel"></bean>

<!-- 5. ViewResover -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<property name="prefix" value="/views/"/>
	<property name="suffix" value=".jsp"/>
</bean>

=> HelloController에 helloModel를 setter injection하여 객체 생성.

=>  hello.do 요청과 HelloController을 mapping

 

* mapping 방법2 : 경로 매핑(패턴 : *, ?)

<!-- 2. Handler Mapping-->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
	<property name="alwaysUseFullPath" value="true"/>
	<property name="mappings">
		<props>
			<!-- <prop key="*.do">hi</prop> -->
			<!-- <prop key="h*.do">hi</prop> -->
			<!--<prop key="/**/*.do">hi</prop> -->
			<prop key="/**/?????.do">hi</prop>
		</props>
	</property>
</bean>

<!-- 3. Controller -->
<bean name="hi" class="pack.controller.HelloController">
	<property name="helloModel" ref="helloModel"></property>
</bean>

<bean id="helloModel" class="pack.model.HelloModel"></bean>

<!-- 5. ViewResover -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<property name="prefix" value="/views/"/>
	<property name="suffix" value=".jsp"/>
</bean>

 =>SimSimpleUrlHandlerMapping사용하여 <prop>에 경로 매핑 가능하다.

 => ?는 글자 갯수. * 복수개의 문자를 나타냄.

 => HelloController mapping의 name을 <prop>의 값으로 받아 패턴을 연결한다.

 

 

 - HelloController

public class HelloController implements Controller{
	
	private HelloModel helloModel;
	
	//setter injection
	public void setHelloModel(HelloModel helloModel) {
		this.helloModel = helloModel;
	}
	
	@Override
	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
				throws Exception {
		// 모델 만들고 모델과 통신하기
		String result = helloModel.getGreeting();
        
		ModelAndView modelAndView = new ModelAndView();
		//ModelAndView modelAndView = new ModelAndView("hello"); // ViewFile명
		
		modelAndView.setViewName("hello");
		modelAndView.addObject("result",result); // forword 방식(default)
		
		//modelAndView.setViewName("redirect:/views/hello.jsp?result='d'"); // reditect 방식
	
		return modelAndView;
	}
}

 => Controller를 상속받고 handleRequest 오버라이딩하여 요청사항을 처리한다.
 => 기본 방식을 forward로 하여 /views/hello.jsp에 addObject(key, value)로 값을 전달한다.
 => setViewName("redirect:/views/hello.jsp")으로 redirect 가능하다.

 

 - HelloModel

public class HelloModel {
	public String getGreeting() {
		int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
		if(hour >= 6 & hour <= 10) {
			return "좋은 아침입니다.";
		}else if(hour >= 12 & hour <= 15) {
			return "점심은 맛있게 드셨나요";
		}else if(hour >= 18 & hour <= 22) {
			return "좋은 저녁되세요";
		}else {
			return "안녕하세요";
		}
	}
}

 => 기능을 담당하는 model 클래스

 

 

 - hello.jsp

<body>
 인사말 : ${result}
</body>

 


4) @annotation을 이용한 Controller호출

 

 = sprwrb6_annotation

 - index.html

<body>
	@MVC 기본정리<p/>
	<a href="hello.do">인사하기 1 - annotation</a><br>
	<a href="abc/world.do">인사하기 2 - annotation</a><br>
	<a href="kbs.do">인사하기 3 - annotation</a><br>
	<a href="hello">인사하기 4 - annotation</a><br>
	<br>
	<a href="kakao.do">인사하기 5 - annotation</a><br>
	<a href="mbc">인사하기 6 - annotation</a><br>
	<a href="sbs">인사하기 7 - annotation</a><br>
</body>

 => 요청 url 설정.

 

 - web.xml

<servlet>
	<servlet-name>test</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
	<servlet-name>test</servlet-name>
    <!--  <url-pattern>*.do</url-pattern>  확장자가 do인 요청 -->
  	<!-- <url-pattern>/aa.jsp</url-pattern> 단일 파일일 경우 /를 붙인다.-->
	<url-pattern>/</url-pattern><!-- 모든요청 -->
</servlet-mapping>

 => <url-pattern>/</url-pattern> 모든요청.
 => test-servlet 실행.

 

 

 - test-servlet.xml

* web.xml의 <url-pattern>/</url-pattern>를 적용하려면 다음 코드를 test-servlet.xml에 추가한다.

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
	<property name="alwaysMustRevalidate" value="true"/>
</bean>

<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
	<property name="alwaysUseFullPath" value="true"/>
</bean>

<mvc:annotation-driven/>
<mvc:default-servlet-handler/>

 => 모든 요청 경로가 연결된다.

 => <mvc:annotation-driven/> : @annotation기반의 Controller호출

 => <mvc:default-servlet-handler/> : 처리하지 못한 요청을 DefaultSerlvet에게 넘겨준다.

<!-- annotation인 경우 -->
<context:component-scan base-package="pack.controller"/>
<context:component-scan base-package="pack.model"/>

<!-- 5. ViewResover -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<property name="prefix" value="/views/"/>
	<property name="suffix" value=".jsp"/>
</bean>

 => <context:component-scan> : 어노테이션 사용시 사용.

 


- HelloController

@Controller // controller implements
@RequestMapping({ "hello.do", "abc/world.do", "k*", "mbc", "sbs", "h*" }) // url mapping
public class HelloController {
	
	@Autowired // setter injection
	private HelloModel helloModel;
	
	@RequestMapping(method=RequestMethod.GET) // GET방식과 mapping 
	public ModelAndView abc() { // 모델 만들고 모델과 통신하기
		String result = helloModel.getGreeting();
		ModelAndView modelAndView = new ModelAndView();
		 
		modelAndView.setViewName("hello");
		modelAndView.addObject("result",result); // forword 방식(default)
		  
		//modelAndView.setViewName("redirect:/views/hello.jsp?result='d'"); // reditect 방식
		 
		return modelAndView; 
	}
}

 => @Controller : 어노테이션을 사용하여 Controller를 호출한다.

 => ModelAndView객체를 리턴값으로 값을 전달한다. result key에 result value를 전달한다.

 

@Controller // controller implements
@RequestMapping({ "hello.do", "abc/world.do", "k*", "mbc", "sbs", "h*" }) // url mapping
public class HelloController {
	
	@Autowired // setter injection
	private HelloModel helloModel;
    
	// Map을 이용할 경우 출력할 View의 ViewName을 명시하지않는다.
	// 요청명을 그대로 ViewName으로 가져간다.
	// 요청명 hello, view명 hello.jsp
	@RequestMapping(method = RequestMethod.GET) // GET방식과 mapping
	public Map<String, Object> abc() {
		String result = helloModel.getGreeting();
		
		HashMap<String, Object> map = new HashMap<String, Object>();
		
		map.put("result", result); // 요청명이 view 파일명이 된다.
		
		return map;
	}
}

 => Map을 이용할 경우 출력할 View의 ViewName을 명시하지않는다.
      요청명을 그대로 ViewName으로 가져간다. (spec에 약속된 사항)
      요청명 hello, view명 hello

=> HashMap를 이용하여 key, value를 전달.

@Controller // controller implements
@RequestMapping({ "hello.do", "abc/world.do", "k*", "mbc", "sbs", "h*" }) // url mapping
public class HelloController {
	
	@Autowired // setter injection
	private HelloModel helloModel;
    
	@RequestMapping(method = RequestMethod.GET) // GET방식과 mapping
	public Model abc(Model model) {
		String result = helloModel.getGreeting();
		
		model.addAttribute("result",result); // 요청명이 view 파일명이 된다.
		
		return model;
	}
}

 => Model 객체를 이용하여 addAttribute()메소드를 이용하여 값을 전달한다.

      요청명을 그대로 ViewName으로 가져간다. (spec에 약속된 사항)

@Controller // controller implements
@RequestMapping({ "hello.do", "abc/world.do", "k*", "mbc", "sbs", "h*" }) // url mapping
public class HelloController {
	@Autowired // setter injection
	private HelloModel helloModel;
	@RequestMapping(method = RequestMethod.GET) // GET방식과 mapping
	public String abc() {
		String result = helloModel.getGreeting();
		
		return "hello";
	}
}

 => String 리턴값을 가져간다.

      요청명을 그대로 ViewName으로 가져간다. (spec에 약속된 사항)

 

 

 - HelloModel

@Component
public class HelloModel {
	public String getGreeting() {
		int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
		if(hour >= 6 & hour <= 10) {
			return "좋은 아침입니다.";
		}else if(hour >= 12 & hour <= 15) {
			return "점심은 맛있게 드셨나요";
		}else if(hour >= 18 & hour <= 22) {
			return "좋은 저녁되세요";
		}else {
			return "안녕하세요";
		}
	}
}

 

 - hello.jsp

<body>
 - annotation<br>
 인사말 : ${result}
</body>

 

 


5) Spring MVC Project를 사용

 

[New] - [Spring Legacy Project] - project명 입력 - [Spring MVC Project] 선택 - [Next] - aa.bb.cc입력 - [finish]

 

 - pom.xml

<properties>
	<java-version>1.8</java-version>
	<org.springframework-version>5.0.0.RELEASE</org.springframework-version>
	<org.aspectj-version>1.6.10</org.aspectj-version>
	<org.slf4j-version>1.6.6</org.slf4j-version>
</properties>

 => 변경

 

 


6) @RequestParam 사용(get)

 = sprweb8_parameter

 - login.jsp

<form action="login" method="get">
	id : <input type="text" name="id"/><br>
	password : <input type="text" name="pwd"/><br>
	<input type="submit" value="전송(get)">
</form>

 => login url로 name이 id, pwd인 값 전달.(get)

 

 

 - LoginController

* Controller 값 처리(기존) : getParameter()

@Controller
public class LoginController {
	//@RequestMapping("login")
	@RequestMapping(value="login", method=RequestMethod.GET)
	public ModelAndView submit(HttpServletRequest request) {
		String id = request.getParameter("id");
		String pwd = request.getParameter("pwd");
		
		System.out.println("id:"+id);
		System.out.println("pwd:"+pwd);
		
		String data = "";
		if(id.equals("aa") && pwd.equals("11")) {
			data = "로그인 성공";
		}else {
			data = "로그인 실패";
		}
			
		ModelAndView view = new ModelAndView();
		view.setViewName("result");
		view.addObject("data", data);
		
		return view;
	}
}

 => getParameter() 메소드를 사용하여 값을 가져온다.

 => 로직 동작 후 seyViewName()로 result.jsp에 addObject()메소드로 data값을 전달한다.

 

* Controller 값 처리(어노테이션 사용)

@Controller
@RequestMapping("login") // type level mapping
public class LoginController {
	
	@RequestMapping(method=RequestMethod.GET) // method level mapping
	public ModelAndView submit(
			@RequestParam("id") String id,
			@RequestParam("pwd") String pwd) {
		
		String data = "";
		if(id.equals("aa") && pwd.equals("11")) {
			data = "로그인 성공";
		}else {
			data = "로그인 실패";
		}
			
		ModelAndView view = new ModelAndView();
		view.setViewName("result");
		view.addObject("data", data);
		
		return view;
	}
}

 => @RequestParam("name")을 사용하여 getParameter()의 기능을 수행한다.

 

 

 - result.jsp

<body>
	결과 : ${data}
</body>

 


* get 방식은 한글이 안깨지나 post 방식사용시 한글이 깨진다. Encording을 하여 한글 깨짐을 방지한다.

 

 - web.xml

<!-- 한글 깨짐 방지(post) -->
<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>

 => web.xml에 위의 코드를 copy&paste한다.

 


7) FormBean, @ModelAttribute 사용(post)

 

 

 - input.jsp

<h2>* 자료입력</h2>
<form action="sangpum" method="post">
	품명 : <input type="text" name="sang"><br>
	수량 : <input type="text" name="su"><br>
	단가 : <input type="text" name="dan"><br>
	<input type="submit" valus="전송(post)"/>
</form>

 

 - SangpumController

* Controller 값 처리(기존) : getParameter()

@Controller
public class SangpumController {
	@RequestMapping(value="sangpum", method=RequestMethod.POST)
	public ModelAndView submit(HttpServletRequest request) {
		String sang = request.getParameter("sang");
		String su = request.getParameter("su");
		String dan = request.getParameter("dan");
		System.out.println(sang+" "+" "+su+" "+dan);
		
		ModelAndView view = new ModelAndView();
		view.setViewName("result");
		view.addObject("data","good");
		
		return view;
	}
}

* Controller 값 처리(FormBean 사용)

@Controller
public class SangpumController {
	@RequestMapping(value="sangpum", method=RequestMethod.POST)
	public ModelAndView submit(SangpumBean bean) { // 지역 변수
		//클라이언트로 부터 들어오는 데이터 양이 많을 경우 사용(form bean)
		
		System.out.println(bean.getSang()+" "+" "+bean.getSu()+" "+bean.getDan());
		
		ModelAndView view = new ModelAndView();
		view.setViewName("result");
		view.addObject("data","good");
		
		return view;
	}
}

 => 매개변수로 FormBean을 사용하여 값을 전달한다. bean의 범위는 {}안으로 지역변수로 사용된다.

 

* Controller 값 처리(@ModelAttribute 사용)

@Controller
public class SangpumController {
	@Autowired // setter injection
	private SangpumModel sanpumModel;
	
	@RequestMapping(value="sangpum", method=RequestMethod.POST)
	//public ModelAndView submit(SangpumBean bean) { // 지역 변수
	public ModelAndView submit(@ModelAttribute("bean") SangpumBean bean) { // 전역변수
		//클라이언트로 부터 들어오는 데이터 양이 많을 경우 사용(form bean)
		
		System.out.println(bean.getSang()+" "+" "+bean.getSu()+" "+bean.getDan());
		
		ModelAndView view = new ModelAndView();
		view.setViewName("result");
		view.addObject("data",sanpumModel.computeSangpum(bean));
		
		return view;
	}
}

 => 매개변수로 @ModelAttribute을 사용시 bean의 범위는 전역변수로 사용되어 addObject() 메소드를 사용하지않아도

      다른 파일에서 접근이 가능하다.

 

 

 - SangpumBean

@Component
public class SangpumBean { // form bean
	private String sang; // 클라이언트로 부터 전달되어 오는 요청 Parameter값과 변수명을 동일하게 가져간다.
	private int su, dan;
	
	public String getSang() {
		return sang;
	}
	public void setSang(String sang) {
		this.sang = sang;
	}
	public int getSu() {
		return su;
	}
	public void setSu(int su) {
		this.su = su;
	}
	public int getDan() {
		return dan;
	}
	public void setDan(int dan) {
		this.dan = dan;
	}
}

 => Form Bean 정의. Form Bean의 멤버변수는 <form>태그 하위 태그 name의 값과 동일하게 가져간다.

 

 - SangpumModel

@Component // 객체생성
public class SangpumModel { // 비지니스 로직 처리를 하는 모델 영역의 클래스
	public String computeSangpum(SangpumBean bean) {
		int price = bean.getSu() * bean.getDan();
		String data = "품명" + bean.getSang() + " , 금액은 "+price;
		
		return data;
	}
}

 

 

- result.jsp

<body>
post 결과 : ${data}
<br>
${bean.sang}
</body>

 

[목차]

7. Spring MVC Pattern 
1) DispatcherServlet 
2) Servlet을 통한 forward(default) 
3) Annotation 사용

 


[내용]

7. Spring MVC Pattern

1) DispatcherServlet

①Dynamic Web Project 생성 - project 오른쪽 클릭 - Configure - Convert Maven Project - finish

 

② pom.xml에서 </build>아래 추가

<properties>
	<!-- Generic properties -->
	<java.version>14.0.2</java.version>
	<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
	<!-- Spring -->
	<spring-framework.version>5.0.0.RELEASE</spring-framework.version>
</properties>
<dependencies>
	<!-- Spring MVC -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-webmvc</artifactId>
		<version>${spring-framework.version}</version>
	</dependency>
	<!-- Other Web dependencies -->
	<dependency>
		<groupId>javax.servlet.jsp</groupId>
		<artifactId>javax.servlet.jsp-api</artifactId>
		<version>2.2.1</version>
	</dependency>
	<dependency>
		<groupId>javax.servlet</groupId>
		<artifactId>jstl</artifactId>
		<version>1.2</version>
	</dependency>
	<dependency>
		<groupId>javax.servlet</groupId>
		<artifactId>javax.servlet-api</artifactId>
		<version>3.1.0</version>
	</dependency>
	<!-- mariadb driver -->
	<dependency>
		<groupId>org.mariadb.jdbc</groupId>
		<artifactId>mariadb-java-client</artifactId>
		<version>2.6.2</version>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-jdbc</artifactId>
		<version>2.3.4.RELEASE</version>
	</dependency>
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-jdbc</artifactId>
		<version>5.0.0.RELEASE</version>
	</dependency>
	<dependency>
		<groupId>commons-dbcp</groupId>
		<artifactId>commons-dbcp</artifactId>
		<version>1.4</version>
	</dependency>
	<!-- mybatis -->
	<dependency>
		<groupId>org.mybatis</groupId>
		<artifactId>mybatis</artifactId>
		<version>3.5.5</version>
	</dependency>
	<dependency>
		<groupId>org.mybatis</groupId>
		<artifactId>mybatis-spring</artifactId>
		<version>2.0.5</version>
	</dependency>
</dependencies>

 

③ index.html

<a href="index.do">start</a>
<a href="good/nice.do">start2</a>

 => client request시 web.xml 실행

 

④ web.xml

<!-- DispatcherServlet : Spring의 중심이 되는 Servlet -->
<!-- DispatcherServlet는 test-servlet.xml의 설정을 불러온다. -->
<servlet>
	<servlet-name>test</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
	<servlet-name>test</servlet-name>
	<url-pattern>*.do</url-pattern>
</servlet-mapping>

 => DispatcherServlet가 test-servlet.xml 실행.

 

⑤ test-servlet.xml

Context - WEB_INF에 <servlet-name>의 네임-servlet의 Spring Bean Configuration을 생성.

<!-- 2. Handler Mapping -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>

<!-- 3. Controller -->
<!-- BeanNameUrlHandlerMapping -->
<bean name="/index.do" class="org.springframework.web.servlet.mvc.ParameterizableViewController">
	<property name="viewName" value="list1"/>
	<!-- list1.jsp 실행 -->
</bean>

<bean name="/good/nice.do" class="org.springframework.web.servlet.mvc.ParameterizableViewController">
	<property name="viewName" value="list2"/>
	<!-- list1.jsp 실행 -->
</bean>

<!-- 5. ViewResover -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<property name="prefix" value="/views/"/>
	<property name="suffix" value=".jsp"/>
</bean>

 => context/views/list1.jsp, context/views/list2.jsp 연결

 


2) Servlet을 통한 forward(default)

 - test-servlet.xml

<!-- 2. Handler Mapping -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>

<!-- 3. Controller -->
<bean name="/start.do" class="pack.StartController"></bean>

<!-- 5. ViewResover -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<property name="prefix" value="/views/"/>
	<property name="suffix" value=".jsp"/>
</bean>

 

 - StartController : Controller 상속

public class StartController implements Controller{

	@Override
	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
		// ModelAndView : DB 처리 결과를 기억, 출력을 위한 view 파일명 기억
		System.out.println("StartController handleRequest()수행");
		
		//return new ModelAndView("list"); // 생성자
		
		//모델과 통신하기 생략
		
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("list"); // setter. forward 방식으로 파일 요청 처리 (default)
		//request.setAttribute("key", value); // servlet에서 사용하는 방법.
		modelAndView.addObject("say", "messages");//모델과 통신 후 얻어진 결과를 기억했다 가정.(request)
		
		return modelAndView;
	}
}

 

 - list.jsp

기존
<% 
	String str = (String)request.getAttribute("say"); 
	out.println(str);%>

EL
${say} ${requestScope.say}

 


3) Annotation 사용

 - test-servlet.xml

<!-- 2. Handler Mapping -->
<!-- annotation 사용시 삭제 -->
<!-- <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> -->


<!-- 3. Controller -->
<!-- annotation 사용시 삭제 -->
<!-- <bean name="/start.do" class="pack.StartController"></bean> -->
<!-- annotation 사용시 추가 -->
<context:component-scan base-package="pack"/>

<!-- 5. ViewResover -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<property name="prefix" value="/views/"/>
	<property name="suffix" value=".jsp"/>
</bean>

 

 - StartController

@Controller // Conponent와 동일. Cotroller에 사용.
public class StartController{
	@RequestMapping("start.do")
	public ModelAndView handleStart(HttpServletRequest request, HttpServletResponse response) throws Exception {
		// ModelAndView : DB 처리 결과를 기억, 출력을 위한 view 파일명 기억
		System.out.println("StartController handleStart()수행 - annotaion");
		
		//return new ModelAndView("list"); // 생성자
		
		//모델과 통신하기 생략
		
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.setViewName("list"); // setter. forward 방식으로 파일 요청 처리 (default)
		//request.setAttribute("key", value); // servlet에서 사용하는 방법.
		modelAndView.addObject("say", "messages - annotaion");//모델과 통신 후 얻어진 결과를 기억했다 가정.(request)
		
		return modelAndView;
	}
}

 

 

 

[목차]

6. Spring에서 DB 연동 

* Maria DB lib 등록 

① JAVA의 JDBC를 사용  

② DaoSupport 클래스 사용  - spring이 지원 

③ MyBatis 사용

 


 

[내용]

 - Spring api 문서

docs.spring.io/spring/docs/5.0.x/javadoc-api/

* Maria DB lib 등록

① search.maven.org/접속

② Search창에 mariadb-java-client 검색 
③ 버전선택 (2.6.2) 
④ Apache Maven 내용 pom.xml에 copy & paste

<!-- MariaDB driver -->
<dependency>
  <groupId>org.mariadb.jdbc</groupId>
  <artifactId>mariadb-java-client</artifactId>
  <version>2.6.2</version>
</dependency>

⑤ Search창에 spring-boot-starter-jdbc 검색 
⑥ 버전선택 (2.3.6.RELEASE) 
⑦ Apache Maven 내용 pom.xml에 copy & paste

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-jdbc</artifactId>
  <version>2.3.6.RELEASE</version>
</dependency>

 


① JAVA의 JDBC를 사용 

 

 - SangpumDto

public class SangpumDto {
	
	private String code, sang, su, dan;
	//getter 추가
	//setter 추가
}


 - SangpumInter

public interface SangpumInter {
	ArrayList<SangpumDto> selectList();
}

 

 - SangpumImpl : DB 처리

@Repository // @Componet와 동일. db와 연동할 코드
public class SangpumImpl implements SangpumInter{
	
	private Connection conn;
	private PreparedStatement ptmt;
	private ResultSet rs;
	
	public SangpumImpl() {
		try {
			Class.forName("org.mariadb.jdbc.Driver");
		} catch (Exception e) {
			System.out.println("SangpumImpl err"+e);
		}
	}
	
	public ArrayList<SangpumDto> selectList() {
		ArrayList<SangpumDto> list = new ArrayList<SangpumDto>();
		String sql="select * from sangdata";
		try {
			conn =DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","123");
			ptmt = conn.prepareStatement(sql);
			rs = ptmt.executeQuery();
			while(rs.next()) {
				SangpumDto dto = new SangpumDto();
				dto.setCode(rs.getString("code"));
				dto.setSang(rs.getString("sang"));
				dto.setSu(rs.getString("su"));
				dto.setDan(rs.getString("dan"));
				list.add(dto);
			}
		} catch (Exception e) {
			System.out.println("selectList err"+e);
		}finally {
			try {
				if(conn != null) conn.close();
				if(ptmt != null) ptmt.close();
				if(rs != null) rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return list;
	}

}

    @Repository : @Componet와 동일. db와 연동할 코드

 

 - BusinessInter

public interface BusinessInter {
	public void dataList();
}

 

 - BusinessImpl

@Service // business logic에 사용
public class BusinessImpl implements BusinessInter{
	@Autowired // setter 주입 사용
	private SangpumInter sangpumInter;
	
	/* 생성자 주입 사용가능
	 * @Autowired public BusinessImpl(SangpumInter sangpumInter) {
	 * this.sangpumInter=sangpumInter; }
	 */
	
	public void dataList() {
		ArrayList<SangpumDto> list = sangpumInter.selectList();
		for(SangpumDto s:list) {
			System.out.println(s.getCode()+" "+
		s.getSang()+" "+
		s.getSu()+" "+
		s.getDan());
		}
	}
}

 

 - main

public static void main(String[] args) {
	ApplicationContext context = new ClassPathXmlApplicationContext("dbinit.xml");
	BusinessInter businessInter = (BusinessInter)context.getBean("businessImpl");
	businessInter.dataList();
}

 

 - dbinit.xml

<!-- 어노테이션 사용하도록 설정 -->
<context:component-scan base-package="pack.business"/>
<context:component-scan base-package="pack.model"/>

 

 


② DaoSupport 클래스 사용

 - SangpumDto 
 - BusinessImpl 
 - main 
 동일

 

 - SangpumInter

public interface SangpumInter {
	List<SangpumDto> selectList() throws DataAccessException;
}

 

 - SangpumImpl

// Spring이 제공하는 DB 연결처리. JdbcDaoSupport 상속.
public class SangpumImpl extends JdbcDaoSupport implements SangpumInter {

//	생성자 주입으로 처리 가능.
//	public SangpumImpl(DataSource dataSource) {
//		super.setDataSource(dataSource);
//	}

	public List<SangpumDto> selectList(/* String code */) throws DataAccessException {
		// member : Datasource, JdbcTemplate
		RowMapper rowMapper = new SangRowMapper();
		
		return getJdbcTemplate().query("select * from sangdata", rowMapper);
		// record수 만큼 mapRow() 호출.
		//return getJdbcTemplate().query("select * from sangdata where code=code", rowMapper); 
		// 매개변수 사용시
	}
	
	// 내부 클래스
	class SangRowMapper implements RowMapper{ // RowMapper 상속
		public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
			// mapRow는 레코드 수 만큼 호출. rs.next()가 내부적으로 처리됨.
			System.out.println("rowNum" + rowNum);
			SangpumDto dto = new SangpumDto();
			dto.setCode(rs.getString("code"));
			dto.setSang(rs.getString("sang"));
			dto.setSu(rs.getString("su"));
			dto.setDan(rs.getString("dan"));
			return dto;
		}
	}
}

 

 - BusinessInter

public class BusinessImpl implements BusinessInter{
	private SangpumInter sangpumInter;
	
	public void setSangpumInter(SangpumInter sangpumInter) {
		this.sangpumInter = sangpumInter;
	}
	
	public void dataList() {
		ArrayList<SangpumDto> list = (ArrayList<SangpumDto>)sangpumInter.selectList();
		for(SangpumDto s:list) {
			System.out.println(s.getCode()+" "+
		s.getSang()+" "+
		s.getSu()+" "+
		s.getDan());
		}
	}
}

 

 - dbinit.xml

<!-- db연결 -->
<!-- xml파일이 아니 별도 class로 작성 가능. -->
<bean id="dataSorce" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
	<property name="driverClassName">
		<value>org.mariadb.jdbc.Driver</value>
	</property>
	<property name="url">
		<value>jdbc:mysql://localhost:3306/test</value>
	</property>
	<property name="username">
		<value>root</value>
	</property>
	<property name="password">
		<value>123</value>
	</property>
</bean>
<!-- db연결 클래스 객체 생성 -->
<bean id="sangpumImpl" class="pack.model.SangpumImpl">
<!--JdbcDaoSupport을 상속받았기 때문에 별도로 dataSource setter를 정의하지않아도 setter주입을 할 수 있다.-->
	<property name="dataSource" ref="dataSorce"/>
</bean>
<!-- 객체생성 -->
<bean id="businessImpl" class="pack.business.BusinessImpl">
	<property name="sangpumInter" ref="sangpumImpl"/>
</bean>

 

 - dbinit.xml

<!-- DriverManagerDataSource를 상속받은 db 연결 class 객체 생성. -->
<bean id="dataSource" class="pack.model.DataSourceMaria"></bean>

<!-- db연결 클래스 객체 생성 -->
<bean id="sangpumImpl" class="pack.model.SangpumImpl">
<!-- JdbcDaoSupport을 상속받았기 때문에 별도로 dataSource setter를 정의하지않아도 setter주입을 할 수 있다. -->
	<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 객체생성 -->
<bean id="businessImpl" class="pack.business.BusinessImpl">
	<property name="sangpumInter" ref="sangpumImpl"/>
</bean>

 


③ MyBatis 사용

 

 - db.properties

 

 - DataMapper.xml

<mapper namespace="dev">
 <select id="selectAll" resultType="dto">
  select * from sangdata
 </select>
</mapper>

 

 - Configuration.xml

<configuration>
 <properties resource="pack/mybatis/db.properties" />
 <typeAliases>
 	<typeAlias type="pack.model.SangpumDto" alias="dto"/>
 </typeAliases>
 <environments default="dev">
  <environment id="dev">
   <transactionManager type="JDBC" />
   <dataSource type="POOLED">
    <property name="driver" value="${driver}" />
    <property name="url" value="${url}" />
    <property name="username" value="${username}" />
    <property name="password" value="${password}" />
   </dataSource>
  </environment>
 </environments>
 <mappers>
  <mapper resource="pack/mybatis/DataMapper.xml" />
 </mappers>
</configuration>

 

 - SqlMapConfig

public class SqlMapConfig { // 메뉴얼 확인하여 작성.
	public static SqlSessionFactory sqlSession; // DB의 SQL 명령 실행을 위한 메소드를 가진 객체.
	
	static {
		String resource = "pack/mybatis/Configuration.xml";
		try {
			Reader reader = Resources.getResourceAsReader(resource);
			// Configuration.xml을 읽는다.
			sqlSession = new SqlSessionFactoryBuilder().build(reader);
			// sqlSession 객체를 생성한다.
			reader.close();
		} catch (Exception e) {
			System.out.println("SqlMapConfig err"+e);
		}
	}
	public static SqlSessionFactory getSqlSession() {
		return sqlSession;
	}
}

 

 - SangpumInter

public interface SangpumInter {
	List<SangpumDto> selectDataAll();
}

 

 - SangpumImpl

@Repository
public class SangpumImpl implements SangpumInter{
	
	private SqlSessionFactory factory = SqlMapConfig.getSqlSession();
	
	public List<SangpumDto> selectDataAll() {
		SqlSession sqlSession = factory.openSession();
		List<SangpumDto> list = null;
		
		try {
			list=sqlSession.selectList("selectAll");
		} catch (Exception e) {
			System.out.println("selectDataAll err"+e);
		}finally {
			if(sqlSession!=null) sqlSession.close();
		}
		return list;
	}
}

 

 - BusinessInter

public interface BusinessInter {
	void dataList();
}

 

 - BusinessImpl

@Service
public class BusinessImpl implements BusinessInter{
	
	@Autowired
	private SangpumInter inter;
	
	public void dataList() {
		List<SangpumDto> list =inter.selectDataAll();
		
		for(SangpumDto s: list) {
			System.out.println(s.getCode()+" "+s.getSang()+" "+s.getSu()+" "+s.getDan());
		}
	}
}

 

 - main

public static void main(String[] args) {
	ApplicationContext context = new ClassPathXmlApplicationContext("dbinit.xml");
	BusinessInter businessInter = (BusinessInter)context.getBean("businessImpl");
	businessInter.dataList();
}

 

 - dbinit

<context:component-scan base-package="pack.business"/>
<context:component-scan base-package="pack.model"/>

 

 

 

[목차]

5. AOP (Aspect Oriented Program)

* 스프링 AOP에서 용어
① AOP 구현

 


 

[내용]

5. AOP (Aspect Oriented Program)

 

: 핵심 로직에서 임의의 동작을 진행할 경우 사용. 
: 별도의 클래스로 정의하여 메소드를 탈부착식으로 사용한다.

: ex) 시큐리티, 로그인, 트랜잭션

 

 1) 설정

 ⓛ 사이트 접속 - search.maven.org/

 ② search창에 aspectjweaver 검색

 ③ version 선택

 ④ Apache Maven 내용 copy & paste

 ⑤ search창에 cglib 검색

 ⑥ version 선택

 ⑦ Apache Maven 내용 copy & paste

 ⑧ pom.xml에 Code 추가

<!-- aop -->
<dependencies>
	<dependency>
		<groupId>aspectj</groupId>
		<artifactId>aspectjweaver</artifactId>
		<version>1.5.4</version>
	</dependency>
	<dependency>
		<groupId>cglib</groupId>
		<artifactId>cglib</artifactId>
		<version>3.3.0</version>
	</dependency>
</dependencies>

 ⑨ 경로에 생성됨. C:\Users\wonh\.m2\repository\

 

2) code

- HelloInter

public interface HelloInter {
	void hello();
	void hi();	
}

 - HelloInterImpl

public class HelloInterImpl implements HelloInter{
	
	public HelloInterImpl() {
		System.out.println("HelloInterImpl 생성자");
	}
	
	public void hello() {
		System.out.println("hello 처리");
	}

	public void hi() {
		System.out.println("hi 처리");
	}
}

 - WriteInter

public interface WriteInter {
	void write();
}

 - WriteInterImpl

public class WriteInterImpl implements WriteInter{ // 핵심 로직을 가진 클래스
	
	public WriteInterImpl() {
		System.out.println("WriteInterImpl 생성자");
	}

	public void write() {
		System.out.println("write 수행");
	}
}

 - MyAspect

public class MyAspect { // 관심사항을 가진 클래스
	public void myLogOn() {
		System.out.println("핵심 메소드 수행전 로그온 작업");
	}
	
	public void myLogOut() {
		System.out.println("핵심 메소드 수행후 로그아웃 작업");
	}
	
	public void mySecurity() {
		System.out.println("핵심 메소드 수행전 보안설정");
	}
}

 - AspectProcess

public class AspectProcess { // 여러개의 관심사항들을 모아 처리하는 클래스
	private MyAspect myAspect; // 관심사항 클래스. 여러개 가능
	
	public void setMyAspect(MyAspect myAspect) {
		this.myAspect = myAspect;
	}
	
	public Object logging(ProceedingJoinPoint joinPoint) throws Throwable{
		Object object = null;
		
		myAspect.myLogOn();
		object = joinPoint.proceed(); // 메타파일에서 설정한 핵심 메소드 수행.
		myAspect.myLogOut();
		
		return object;
	}
	
	public Object logging2(ProceedingJoinPoint joinPoint) throws Throwable{
		Object object = null;
		
		myAspect.mySecurity();
		object = joinPoint.proceed(); // 메타파일에서 설정한 핵심 메소드 수행.
		return object;
	}
}

 => logging() 메소드는 myLogOn() -> 핵심로직 -> myLogOut() 순 호출

 => logging2() 메소드는 mySecurity() -> 핵심로직 순 호출

 - main

public static void main(String[] args) {
	//String[] configs = new String[] {"aop1core.xml"}; // 핵심만 수행
	String[] configs = new String[] {"aop1core.xml", "aop1.xml"}; // 핵심 + Aop 수행.
	
	ApplicationContext context = new ClassPathXmlApplicationContext(configs);
	
	WriteInter writeInter = (WriteInter)context.getBean("writeInterImpl");
	writeInter.write();
	System.out.println();
	
	HelloInterImpl helloInter = (HelloInterImpl)context.getBean("helloInterImpl"); // 방법 1
	HelloInter helloInter = context.getBean("helloInterImpl", HelloInter.class); // 방법 2
	helloInter.hi();
	helloInter.hello();
}

 - aop1core.xml

<bean id="writeInterImpl" class="aop1.WriteInterImpl"/>
<bean id="helloInterImpl" class="aop1.HelloInterImpl"/>

 - aop1.xml

<!-- Aspect(Advice) -->
<bean id="aspectProcess" class="aop1.AspectProcess">
	<property name="myAspect" ref="myAspect"/>
</bean>
<bean id="myAspect" class="aop1.MyAspect"/>

<!-- Aop 설정 -->
<aop:config>
	<aop:pointcut expression="execution(public void wri*(..))" id="poi1"/>
	// wri로 시작하고 매개변수가 0개 이상인 메소드
	// <aop:pointcut expression="execution(public void write())" id="poi1"/>
	<aop:aspect ref="aspectProcess">
		<aop:around method="logging" pointcut-ref="poi1"/>
	</aop:aspect>
</aop:config>
<aop:config>
	<aop:pointcut expression="execution(public void hel*(..)) or execution(public void hi*(..))" id="poi2"/>
	// or || and &&
	<aop:aspect ref="aspectProcess">
		<aop:around method="logging2" pointcut-ref="poi2"/>
	</aop:aspect>
</aop:config>

 => 핵심 로직의 wri로 시작하고 메개변수가 0개 이상인 메소드가 호출될때 AspectProcess(Aspect를 처리하는) 클래스의 logging() 메소드가 실행된다.

 => 핵심 로직의 hel로 시작하고 메개변수가 0개 이상인 메소드 또는 hi로 시작하는 메소드가 호출될때 AspectProcess클래스의 logging2() 메소드가 실행된다.

 


 - ArticleInter

public interface ArticleInter {
	void select();
}

 

- ArticleDao

//@Component
//@Repository
@Repository("articleDao")

public class ArticleDao implements ArticleInter{

	public void select() {
		System.out.println("db의 상품 자료를 read");
	}
}

 - LogicInter

public interface LogicInter {
	void selectData_process();
}

 - LogicImpl

public class LogicImpl implements LogicInter{
	private ArticleInter articleInter; 
    
	public LogicImpl() {
	}
	
	public LogicImpl(ArticleInter articleInter) {
		this.articleInter = articleInter; 
	}
	
	public void selectData_process() {
		System.out.println("selectData_proces 수행");
		articleInter.select();
	}
}
@Service
public class LogicImpl implements LogicInter{

	@Autowired
	//@Qualifier("aticleDao")
	private ArticleInter articleInter; 
	
	public void selectData_process() {
		System.out.println("selectData_proces 수행");
		articleInter.select();
	}
}

 

 - ProfileAdvice

public class ProfileAdvice { // Advice, Aspect
	public Object abc(ProceedingJoinPoint joinPoint) throws Throwable{
		//핵심 메소드 이름 얻기
		String methodName = joinPoint.getSignature().toString();
		
		System.out.println(methodName+" 시작 전 작업");
		Object object = joinPoint.proceed(); // 핵심 메소드
		System.out.println(methodName+" 처리 후 작업");
		
		return object;
	}
}
@Aspect
@Component
public class ProfileAdvice { // Advice, Aspect
	@Around("execution(public void selectData_process())")
	public Object abc(ProceedingJoinPoint joinPoint) throws Throwable{
		//핵심 메소드 이름 얻기
		String methodName = joinPoint.getSignature().toString();
		
		System.out.println(methodName+" 시작 전 작업");
		Object object = joinPoint.proceed(); // 핵심 메소드
		System.out.println(methodName+" 처리 후 작업");
		
		return object;
	}
}

 

 - main

public static void main(String[] args) {
	ApplicationContext context = new ClassPathXmlApplicationContext("aop2.xml");
	LogicInter inter = (LogicInter)context.getBean("logicImpl");
	inter.selectData_process();
}

 - aop2.xml

<!-- 핵심 로직 처리용 클래스 -->
<bean id="logicImpl" class="aop2.LogicImpl">
	<constructor-arg>
		<ref bean="articleDao"/>
	</constructor-arg>
</bean>
<bean id="articleDao" class="aop2.ArticleDao"></bean>

<!-- Aop 설정 -->
<bean id="profileAdvice" class="aop2.ProfileAdvice"/>
<aop:config>
	<aop:aspect ref="profileAdvice">
		<aop:pointcut expression="execution(public void selectData_process())" id="poi"/>
		<aop:around method="abc" pointcut-ref="poi"/>
	</aop:aspect>
</aop:config>	

 => 핵심로직의 selectData_process()메소드 호출 시 profileAdvice클래스의 abc()메소드가 호출.

<!-- 객체 생성 : 어노테이션 -->
<context:component-scan base-package="aop3"/>
<!-- Aop 설정 -->
<aop:aspectj-autoproxy/>

 

 

 

* 스프링 AOP에서 용어


 - Joinpoint : ‘클래스의 인스턴스 생성 시점’, ‘메소드 호출 시점’ 및 ‘예외 발생 시점’ 과 같이 어플리케이션을 실행할 때 특정 작업이 시작되는 시점을 의미.

 - Advice : 조인포인트에 삽입되어 동작할 수 있는 코드를 말함.

 - Pointcut : 여러 개의 조인포인트를 하나로 결합한(묶은) 것을 말함.

 - Advisor : 어드바이스와 포인트컷을 하나로 묶어 취급한 것을 말함.

 - Weaving : 어드바이스를 핵심 로직 코드에 삽입하는 것을 말함.

 - Target : 핵심 로직을 구현하는 클레스.

 - Aspect : 여러 객체에 공통으로 적용되는 공통 관점 사항을 말함.

 

 

1) AOP 구현

 - LogicInter

public interface LogicInter {
	void startProcess();
}

 

 - LogicImpl

@Service // @Component와 동일하지만 가독성을 위해 Service기능을 사용하면 @Service를 사용.
public class LogicImpl implements LogicInter{
	
	public LogicImpl() {
	}
	
	public void startProcess() {
		System.out.println("핵심 로직 수행");
	}
}

 

 - aop4.xml

<!-- 어노테이션을 사용하여 객체 생성 -->
<context:component-scan base-package="aop4"/>
<!-- aop를 사용하도록 설정 -->
<aop:aspectj-autoproxy/>

    <context:component-scan base-package="패키지명"/>
    <aop:aspectj-autoproxy/>

 

 - main

public static void main(String[] args) {
	ApplicationContext context = new ClassPathXmlApplicationContext("aop4.xml");
	LogicInter inter = (LogicInter)context.getBean("logicImpl");
	// getBean의 매개변수 : @객체 생성할 클래스명을 첫글자 소문자로 변경하여 생성. 
	inter.startProcess();
}

 

 - RunAspect

// 아이디가 같으면 핵심로직 수행, 다르면 수행하지않도록 구현.
@Component
@Aspect // 독립적으로 동작할 관심 로직 클래스에 사용
public class RunAspect {
	
	@Around("execution(public void startProcess())")
	// 핵심로직의 메소드를 선택. 해당메소드 호출시 관심 메소드 호출.
	//@Around는 핵심로직 실행 전/후 모두 기능을 추가할 수 있다.
	public Object trace(ProceedingJoinPoint joinPoint) throws Throwable{
		
		System.out.println("AOP 시작 : 핵심 로직 처리전 id 검증");
		System.out.print("input id : ");
		Scanner scanner = new Scanner(System.in);
		String id = scanner.nextLine();
		if(! id.equalsIgnoreCase("aa")) { //equalsIgnoreCase() 대소문자 구분하지않고 비교.
			System.out.println("id 불일치하여 작업을 종료합니다.");
			return null;
		}
		
		Object obj = joinPoint.proceed(); // 핵심 로직 수행.
		
		return obj;
	}
}

    @Component

    @Aspect

    @Around("excution(핵심 로직의 메소드)")

    public Object 관심메소드명(ProceedingJoinPoint joinPoint) throws Throwable{ .. }

    Object obj = joinPoint.proceed();

    str1.equalsIgnoreCase(str2)

 

 

 

 

[목차]

2. 생성자 주입(Constructor Injection)

① meta.xml

② 생성자 호출 
③ MVC 패턴 및 다형성 활용한 프로그래밍

④ 생성자 주입(construnctor injection)
⑤생성자 주입방법 2

3. setter 주입(setter injection) 
4. new를 이용한 객체생성과 Spring 객체 생성의 차이 

 


[내용]

2. 생성자 주입(Constructor Injection)

public static void main(String[] args) {
	// new로 객체 생성시 매번 생성된다.
	
	MessageImpl m1 = new MessageImpl("김이상");
	m1.sayHi();
	
	MessageImpl m2 = new MessageImpl("김이상");
	m2.sayHi();
	
	System.out.println("주소 : "+m1);
	System.out.println("주소 : "+m2);
}

 => new를 이용한 객체 생성

 

① meta.xml

<beans>
	<bean id="moneyCalc" name="aa,bb,cc" class="pack.model.MoneyCalc"/>	
	<bean id="myProcess" class="pack.controller.MyProcess">
		<constructor-arg>
			<ref bean="moneyCalc"/>
		</constructor-arg>
	</bean>
</beans>

 => 매개변수가 있는 생성자일 경우 <contructor-arg>와 <ref> 태그를 사용하여 매개변수를 입력한다.

 => 매개변수도 생성자를 생성한다.

<beans>
	<bean id="moneyCalc" name="aa,bb,cc" class="pack.model.MoneyCalc"/>	
	<bean id="myProcess" class="pack.controller.MyProcess">
		<constructor-arg>
			<ref bean="aa"/>
		</constructor-arg>
	</bean>
</beans>

 => id나 name 둘중 무엇을 사용해도 상관없으며, <ref bean="name">에서 name을 호출가능.

 

 

② 생성자 호출

public class Main {
	public static void main(String[] args) {
		ApplicationContext context = new ClassPathXmlApplicationContext("money_init.xml");
		MyInter inter = (MyInter)context.getBean("myProcess");
		inter.inputMoney();
		inter.showResult();
	}
}

 => ApplicationContext 객체 생성시 xml에 연결된 모든 생성자가 호출되며, 각 객체가 생성된다.

 => context의 getBean()메소드로 객체를 get하여 메소드를 사용한다.

 => getBean() 메소드의 리턴값은 Object로 다형성을 사용하여 캐스팅하여 객체를 대입한다.

 => getBean() 리턴 객체도 다형성을 사용하여 interface 객체에 대입하여 사용하는 것을 지향한다.

 

 

③ MVC 패턴 및 다형성 활용한 프로그래밍

 

pakage Controller(Servlet) Model(Dto, Dao-sql)
Interface BusinessInterface ModelInterface
 
Class BusinessClass ModelClass

 => 다형성을 갖춘 MVC Pattern 작성을 지향하여 프로그래밍한다.

 => Controller의 Business Class에서 Model Interface를 호출하여 사용한다.

 => 각 모델은 다형성을 활용하여 테이블에 따른 Sql문을 호출하여 DB와 연결된다.

 => [src.main/java]에 작성한다.

 

- Business Interface

public interface MyInter {
	void inputMoney();
	void showResult();
}

 - Business Class

public class MyProcess implements MyInter{
	private MoneyInter inter;
	private int result[];
	
	public MyProcess(MoneyInter inter) {
		this.inter = inter;
	}
	
	public void inputMoney() {
		//키보드로 금액입력
		try {
			InputStreamReader reader = new InputStreamReader(System.in);
			BufferedReader br = new BufferedReader(reader);
			int myMoney=0;
			System.out.println("금액입력");
			String data = br.readLine();
			myMoney = Integer.parseInt(data);
			result = inter.calcMoney(myMoney);
		} catch (Exception e) {
			System.out.println("inputMoney err "+e);
		}
	}

	public void showResult() {
		//계산이 끝난 배열 자료 출력.
		System.out.println("만원 : "+result[0]+"개");
		System.out.println("천원 : "+result[1]+"개");
		System.out.println("백원 : "+result[2]+"개");
		System.out.println("십원 : "+result[3]+"개");
		System.out.println("일원 : "+result[4]+"개");
	}

}

 => 생성자에 모델의 interface 객체를 매개변수로 받아 사용.

 

- Model Interface

public interface MoneyInter {
	int[] calcMoney(int money);
}

 

- Model Class

public class MoneyCalc implements MoneyInter{
	public MoneyCalc() {
	}
	public int[] calcMoney(int money) {
		//단위별 금액 건수 계산용
		int result[] = new int[5];
		int temp=0;
		int len = result.length;
		for(int i=0; i<len;i++) {
			if(i == 0) {
				result[i] = money/(int)Math.pow(10, (len-1-i));
				temp=money%(int)Math.pow(10, (len-1-i));
				continue;
			}
			result[i] = temp/(int)Math.pow(10, (len-1-i));
			temp=temp%(int)Math.pow(10, (len-1-i));
		}
		return result;
	}
}

 

③ 생성자 주입(construnctor injection)

 

 - ShowData(Dao)

public class ShowData {
	public String toAlias() {
		return "홍길동";
	}
	
	public String toHobby() {
		return "운동";
	}
}

 - MyProcess(Controller)

public class MyProcess { // 포함으로 약결합 진행
	private int age;
	private String name;
	private ShowData showData; // Class Type
	
	public MyProcess(int age, String name, ShowData showData) {
		this.age = age;
		this.name = name;
		this.showData = showData;
	}
	
	public void printData() {
		System.out.println(name+age+showData.toAlias()+showData.toHobby());
	}
}

 - xml

<beans>
	<bean id="showData" class="pack.model.ShowData"/>	
	<bean id="myProcess" class="pack.controller.MyProcess">
		<constructor-arg>
			<value>13</value>
		</constructor-arg>
		<constructor-arg>
			<value>홍길동</value>
		</constructor-arg>
		<constructor-arg>
			<ref bean="showData"/>
		</constructor-arg>
	</bean>
</beans>

- main

public static void main(String[] args) {
	ApplicationContext context = new ClassPathXmlApplicationContext("init.xml");
	MyProcess myProcess = (MyProcess)context.getBean("myProcess");
	myProcess.printData();
}

④ 생성자 주입방법 2

 - MessageInter

public interface MessageInter {
	void sayHi();
}

 - MessageImpl

public class MessageImpl implements MessageInter{
	private String name1;
	private String name2;
	private int year;
	private MyClass myclass;
	private String spec;
	
	// 생성자 주입
	public MessageImpl(String name1, String name2, int year, MyClass myclass) {
		this.name1=name1;
		this.name2=name2;
		this.year=year;
		this.myclass = myclass;
	}
	
	//setter 주입
	public void setSpec(String spec) {
		this.spec = spec;
	}
	
	// 출력담당 메소드
	public void sayHi() {
		String msg="이름 : "+name1+" / "+name2+"\n";
		msg+="직업 : "+(year+21)+"년 " + myclass.myData();
		msg+="\n보유기술 : "+spec;
		System.out.println(msg);
	}
}

 - arrange.xml

 ① 생성자 주입방법 1

<bean id="mbean" class="pack.MessageImpl" scope="singleton"> 
	<constructor-arg value="홍길동">
		<ref bean="name1"/>
	</constructor-arg>
</bean>
<bean id="mbean" class="pack.MessageImpl" scope="singleton"> 
// <bean> scope의 default는 singleton.
// scope를  prototype 설정 시 getBean()호출시 매번 객체를 생성한다.
// request, session은 web에서 사용.

	<constructor-arg index="1">
		<value>홍길동</value>
	</constructor-arg>
	
	<constructor-arg index="0">
		<value>도둑놈</value>
	</constructor-arg>
	
	<constructor-arg index="2" value="2000"/> // String -> int로 자동 변경된다.
	<constructor-arg index="2" type="int" value="2000"/> // 매개변수가 int일 경우 
	<constructor-arg index="2" type="int" value="이천"/> // error
	<constructor-arg index="3" type="pack2.MyClass" ref="myClass"/>
</bean>
<bean id="myClass" class="pack2.MyClass">
	<property name="data" value="자바"/> // setter injection
</bean>

② 생성자 주입방법 2

 : arrange.xml의 Namespace Tab에서 c, p check

<bean id="mbean" class="pack.MessageImpl"
			c:name1="고길동"
			c:name2="깡패"
			c:year="2000"
			c:myclass-ref="myClass"
			p:spec="sqld">
</bean>

<bean id="myClass" class="pack2.MyClass">
	<property name="data" value="자바"/><!-- setter injection -->
</bean>

 => contruct, setter injection 혼용가능

 

- main

public static void main(String[] args) {
	ApplicationContext context = new ClassPathXmlApplicationContext("arrange.xml");
	ApplicationContext context = new ClassPathXmlApplicationContext("classpath:pack/arrange.xml");
	// src/main/java/pack에 있을경우 
	
	//다형성
	MessageInter inter = (MessageInter)context.getBean("mbean"); // 캐스팅을 interface로 한다.
	// MessageInter inter = (MessageImpl)context.getBean("mbean"); // 지양
	inter.sayHi();
	System.out.println("주소 : "+inter);
}

 


3. setter 주입(setter injection)

 

 - MyProcess

public class MyProcess {
	private int age;
	private String name;
	private ShowData showData;

	// setter를 이용해서 private 멤버에 값을 입력
	public void setAge(int age) {
		this.age = age;
	}
	public void setName(String name) {
		this.name = name;
	}
	public void setShowData(ShowData showData) {
		this.showData = showData;
	}
	
	public void printData() {
		System.out.println(name+age+showData.toAlias()+showData.toHobby());
	}
}

 - init.xml

① 방법 1

<bean id="myProcess" class="pack.MyProcess">
	<property name="age" value="22"/> //MyProcess의 setAge()를 호출한다. 
	<property name="name" value="김이상"/> // setName() 호출
	<property name="showData" ref="showData"/> //객체의 setter 호출시 ref를 사용한다.  
</bean>
 
<bean id="showData" class="pack.ShowData"/> // 다른 <bean>태그에서도 호출 가능

② 방법 2 : 하위 element로 사용

<bean id="myProcess" class="pack.MyProcess">
	<property name="age">
		<value>23</value>
	</property>
	<property name="name">
		<value>김이상</value>
	</property>
	<property name="showData">
		<bean class="pack.ShowData"/> // 해당 <bean>태그에서만 사용가능
	</property>
</bean>

 - main

public static void main(String[] args) {
	ApplicationContext context = new ClassPathXmlApplicationContext("init.xml");
	MyProcess myProcess = (MyProcess)context.getBean("myProcess");
	myProcess.printData();
}

 


 

4. new를 이용한 객체생성과 Spring 객체 생성의 차이

 

 - new

public static void main(String[] args) {
	// new로 객체 생성시 매번 생성된다.
	MessageImpl m1 = new MessageImpl("김이상");
	m1.sayHi();

	MessageImpl m2 = new MessageImpl("김이상");
	m2.sayHi();

	System.out.println("주소 : "+m1); // 주소 : pack.MessageImpl@74e28667
	System.out.println("주소 : "+m2); // 주소 : pack.MessageImpl@1cf6d1be
}

 - xml

public static void main(String[] args) {
	ApplicationContext context = new ClassPathXmlApplicationContext("arrange.xml");
	
	// getBean사용시 singletone으로 객체 생성
	MessageImpl impl1 = (MessageImpl)context.getBean("mbean");
	impl1.sayHi();
	
	MessageImpl impl2 = (MessageImpl)context.getBean("mbean");
	impl2.sayHi();
	
	System.out.println("주소 : "+impl1);
	System.out.println("주소 : "+impl2);
}

 

. 어노테이션 : 객체생성시 xml에 의존적 -> @annotation으로 대체.

① @Require 어노테이션 : setter를 사용하도록 제약을 건다.

 - Abc

 public class Abc {
	private int number;
	
	@Required // setter를 사용하도록 제약을 건다.
	public void setNumber(int number) {
		this.number = number;
	}
	
	public void printData() {
		System.out.println("number : "+number);
	}
}

 - anno1.xml

<beans>
	<context:annotation-config/>
	<bean id="abc" class="anno1.Abc">
		<property name="number" value="100"></property>
	</bean>
</beans>

 - main

public static void main(String[] args) {
	ApplicationContext context = new ClassPathXmlApplicationContext("anno1.xml");
	Abc abc = (Abc)context.getBean("abc");
	abc.printData();
}

② @Component : 객체 생성 

 - SenderInter

public interface SenderInter{
	void show();
}

 - Sender

@Component // 객체 생성 
public class Sender implements SenderInter{
	public void show() {
		System.out.println("show메소드 수행");
	}
}

- Sender2

//@Component = @Component("Sender2")// 객체 생성
@Component("별명")
public class Sender2 implements SenderInter{
	public void show() {
		System.out.println("Sender2의 show메소드 수행");
	}
}

③ @Service : @Component와 동일하나 Business 로직에서 사용한다.

④ @Autowired : setter가 내부적으로 정의되며, type에 의한 mapping 진행.

⑤ @Qualifier("아이디") : type에 대하여 mapping시 동일한 타입(같은 부모를 상속받는 자식) 객체가 복수인 경우 

     Qualifier의 아이디에 명시한 아이디로 mapping한다.

 - SenderProcess

//@Component
//@Service
@Service("SenderProcess") //Component와 동일
public class SenderProcess { // 서비스를 하는 비지니스 로직
	private String name = "tom";
    
	@Autowired  // xml의 type에 대한 mapping.
	//@Qualifier("sender2") // 동일한 타입의 객체(상속받는 자식 객체)가 복수인 경우 id로 mapping
	@Qualifier("별명")
	private SenderInter senderInter;
	
	//public void setSender(Sender sender) { // @Autowired사용시 삭제가능
	//	this.sender = sender;
	//}
    
	public void displayData() {
		System.out.println("displayData의 name : " + name);
		senderInter.show();
	}
}

 - xml

<context:annotation-config/> // @어노테이션을 사용가능하게 한다.
<bean id="senderProcess" class="anno2.SenderProcess"/>
<bean id="sender" class="anno2.Sender"/>
<bean id="sender2" class="anno2.Sender2"/>
 // SenderInter를 상속하는 class가 복수가 되면 type으로 mapping하기 때문에 식별자가 필요하다.
<bean class="anno2.Sender"/>
// type에 대한 mapping으로 id가 없어도 mapping된다.
<context:annotation-config/> // 생략 가능
<context:component-scan base-package="anno2"/> // pakage의 @Component, @Service가 작성된 class의 Bean을 생성.

 - main

public static void main(String[] args) {
	ApplicationContext context = new ClassPathXmlApplicationContext("anno2.xml");
	SenderProcess senderProcess = (SenderProcess)context.getBean("senderProcess");
	senderProcess.displayData();
}

 

[목차]

1. Spring 환경구축
* 이클립스에 연동
* 라이브러리 로딩방법
① maven을 사용하지 않고 spring lib 파일을 직접 다운로드
② Maven, Gradle


 

[내용]

1. Spring 환경구축

* 이클립스에 연동

 

[eclipse] - [help] - [eclipse marketplace] - [find : spring] - [Spring Tools 3 Add-On for Spring Tools 4 3.9.15 RELEASE] download


* 라이브러리 로딩방법

 

① maven을 사용하지 않고 spring lib 파일을 직접 다운로드

 framwork download

maven.springframework.org/release/org/springframework/spring/5.0.5.RELEASE/

 

Index of release/org/springframework/spring/5.0.5.RELEASE

 

maven.springframework.org

 => [spring-framework-5.0.5.RELEASE-dist.zip] Download

 

 라이브러리 등록

[File] - [New] - [New Spring Legacy Project] - [Simple java] check - [next] - [Library] tab - [Add jar] - [spring-framework-5.0.5.RELEASE\libs] 선택

 

③ bean xml 파일에 bean 등록

프로젝트의 [src] 오른쪽 클릭 - [New] - [Spring Bean Configuration file] - xml파일명 입력 - [finish]

<beans>
	<bean id="mes" class="pack.Message1" />
</beans>

④ getBean

ApplicationContext context = new ClassPathXmlApplicationContext("init.xml");
MessageInter inter2 = (MessageInter)context.getBean("mes");
inter2.sayHello("양길동");
// Spring이 객체를 Singletone으로 생성하여 줌.

 

② Maven, Gradle - 주로 사용

 - 외부에서 로딩
 - 프로젝트, 라이브러리 관리

 

① maven 프로젝트 생성

[New] - [Maven Project] - [create a simple project] check - [Group id], [Atifact id] 입력 - [finish]

 

pom.xml파일 수정

<project>
	<properties>
		<!-- Generic properties -->
		<java.version>1.8</java.version>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<!-- Spring -->
		<spring-framework.version>5.0.0.RELEASE</spring-framework.version>
		<!-- => 원하는 버전정보 입력 -->
		<!-- Mybatis -->
		<mybatis.version>3.2.3</mybatis.version>
	</properties>
	<dependencies>
		<!-- Spring and Transactions -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>
		<dependency>
			<groupId>javax.annotation</groupId>
			<artifactId>javax.annotation-api</artifactId>
			<version>1.3.2</version>
		</dependency>
		<!-- Spring jdbc -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>
		<!-- oracle jdbc driver -->
		<dependency>
			<groupId>com.oracle</groupId>
			<artifactId>ojdbc6</artifactId>
			<version>11.1.0.7.0</version>
		</dependency>
		<!-- mybatis -->
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>${mybatis.version}</version>
		</dependency>
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis-spring</artifactId>
			<version>1.0.2</version>
		</dependency>
		<dependency>
			<groupId>commons-dbcp</groupId>
			<artifactId>commons-dbcp</artifactId>
			<version>1.2.2</version>
		</dependency>
	</dependencies>
</project>

 => 다음 경로에 라이브러리가 사이트에서 받아지고 이후 로컬의 라이브러리를 사용한다.

C:\Users\wonh\.m2\repository\org\springframework\spring-core\5.0.0.RELEASE\

 

③ meta.xml 파일 생성

프로젝트의 [src/main/resource] 오른쪽 클릭 - [New] - [Spring Bean Configuration file] - xml파일명 입력 [next] - [beans],[http://www.springframwork.org/schema/beans/spring-beans.xsd] check - [finish] 

<beans>
	<bean id="mes" class="pack.Message1" />
</beans>

12. MVC pattern

Client
(html)
----> Controller
(servlet,
interface, class)
----> Model
(DTO, DAO-sql)
----> DB
----> View
(FormBean, jsp)
   

 

1) Client : html의 <form>,<a>태그로 값을 전달한다.

<form action="path" method="get">
	<input type="text" name="name1" value="value1">
	<input type="submit">
</form>


<a href="sang.do?command=sang">상품</a><br> // Parameter로 값 전달
<a href="sang.do">상품</a> // 요청명으로 값 전달
<a href="buser.do">부서</a>

 

2) Controller

① servlet

@WebServlet("/hobby.do") : 단일
@WebServlet({"/hobby.do","/nicd.do"}) : 배열(복수)
@WebServlet({"*.do","*.kor"}) : 확장자(복수)

 => ( )안 설정한 url pattern을 사용하여 servlet 호출할 수 있다.

 

private HobbyModel model;
public void init() throws ServletException {
	model = new HobbyModel();
}

 => servlet의 service에 구현시 요청마다 new 객체 생성시 메모리를 많이 소모 함으로 init()에 작성한다.

 

protected void service(HttpServletRequest request, HttpServletResponse response)
						throws ServletException, IOException {

 => get/post방식에 상관없이 동작하도록 구현.

 

	try {
		name=request.getParameter("name");
	} catch (Exception e) {
		name=null;
	}  

 => 요청처리 방법 1 : parameter사용. request.getParameter()로 html의 value를 전달받는다.

 

	String str1 = request.getRequestURI();
	// 요청명 : /mvc_ex3_db/sang.do
	int idx = str1.lastIndexOf('/');
	// 11
	String str2 = str1.substring(idx+1); // idx+!부터 끝까지 자름
	// sang.do
	StringTokenizer str3 = new StringTokenizer(str2,"."); // str2를 .을 기준으로 토큰화
	// sang ,  do
	str4 = str3.nextToken();
	// sang
	String command = str4;

 => 요청처리 방법 2 : 요청명을 사용

      "/프로젝트명/uripattern.확장자"로 전달받는다.

 

	CommandInter inter = null;
	String viewName = "views/";
	try {
		if(command.equals("sang")) {
			inter = SangpumImpl.instance();
		}else if(command.equals("buser")) {
			inter = BuserImpl.instance();
		}else if(command.equals("jikwon")) {
			inter = JikwonImpl.instance();			
		}else {
			viewName += "error.html";
			response.sendRedirect(viewName);
            return;
		}
		viewName += inter.showData(request, response);
	} catch (Exception e) {
		System.out.println("service : "+e);
	}

 => interface를 상속받은 클래스의 singletone 객체를 받아온다.

 => 명령에 따른 다른 table의 객체를 받아오도록 오버라이딩을 진행한 메소드를 실행한다.

 

	//HobbyModel model = new HobbyModel();
	ArrayList<String> list = model.getHobby(hobby);
	request.setAttribute("datas", list);

 => 다음의 모델은 interface를 상속받은 클래스에 구현한다.(다형성을 사용)

 

	//response.sendRedirect(viewName+"?result="+result); // 컬렉션 류의 객체는 전달X
		
	request.setAttribute("result", result); // 객체 전달 가능.
	RequestDispatcher rd = request.getRequestDispatcher(viewName);
	rd.forward(request, response);
}

 => request setAttribute(), getAttribute()으로 값 전달.

 => sendRedirect의 경우 객체를 전달할 수 없어 forward로 요청 재지정하여 값 전달.

 

 

 * web.xml를 이용한 url pattern 등록 (경로 : Context/WEB_INF/web.xml)

<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>

 => <welcom-file>내 파일명을 입력하면, 도메인만 입력시에 해당 파일이 실행된다.

 => 위쪽 부터 우선순위를 가진다.

 

<servlet>
	<servlet-name>hobby</servlet-name>
	<servlet-class>pack.controller.HobbyController</servlet-class>
</servlet>
<servlet-mapping>
	<servlet-name>hobby</servlet-name>
	<url-pattern>*.do</url-pattern>
</servlet-mapping>

=> url pattern 등록

 

 

② Interface

public interface CommandInter {
	String showData(HttpServletRequest request, HttpServletResponse response);
}

 

 

③ class

public class SangpumImpl implements CommandInter{
	//Singleton
	static SangpumImpl impl = new SangpumImpl();
	public static SangpumImpl instance() {
		return impl;
	}

	@Override
	public String showData(HttpServletRequest request, HttpServletResponse response) {
		SangpumModel model = new SangpumModel();//원래는 싱글으로 작성된 클래스를 읽어야함.
		ArrayList<SangpumDto> list = model.getDataAll();
		request.setAttribute("datas", list);
		return "sangpum.jsp";
	}

}

 => 모델에 있는 클래스와 통신을 하는 컨트롤러 영역내의 클래스를 선언한다.

 

* Singletone : 한클래스당 하나의 객체만 사용하도록 하는 인스턴스.

class 클래스명{
	private static 클래스명 singleton명 = new 클래스명();
	static 클래스명 getInstance(){
		return singleton;
	}
}

 

 

3) Model

① DTO

public class SangpumDto {
	private String code;
	private String sang;
	private String su;
	private int dan;
	public String getCode() {
		return code;
	}
	public void setCode(String code) {
		this.code = code;
	}
    ...
}

 => 필드, getter, setter 선언

 

 

② DAO (or Model)

 * JDBC Connection pooling

public class SangpumModel {
	private Connection conn;
	private PreparedStatement ptmt;
	private ResultSet rs;
	private DataSource ds;
	
	
	public SangpumModel() {
		try {
			Context context = new InitialContext();
			ds= (DataSource)context.lookup("java:comp/env/jdbc_maria");
		} catch (Exception e) {
			System.out.println("SangpumModel err"+e);
		}
	}
	
	public ArrayList<SangpumDto> getDataAll(){
		ArrayList<SangpumDto> list = new ArrayList<>();
		try {
			conn=ds.getConnection();
			String sql = "select * from sangdata";
			ptmt = conn.prepareStatement(sql);
			rs= ptmt.executeQuery();
			while(rs.next()) {
				SangpumDto dto = new SangpumDto();
				dto.setCode(rs.getString("code"));
				dto.setSang(rs.getString("sang"));
				dto.setSu(rs.getString("su"));
				dto.setDan(rs.getInt("dan"));
				list.add(dto);
			}
		} catch (Exception e) {
			System.out.println("getDataAll err"+e);
		}finally {
			try {
				if(conn!=null) conn.close();
				if(ptmt!=null) ptmt.close();
				if(rs!=null) rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return list;
	}
}

 

 * Mybatis (xml)

  - db.properties : 계정정보

  - Configuration.xml : <alias>, <mapper> 수정

  - DataMapper.xm : xml 형식 sql문 작성

  - SqlMapConfig : SqlSessionFactory 객체 생성

  - DAO(or model)

public class SangpumModel {
	private SqlSessionFactory factory = SqlMapConfig.getSqlSession();
	
	public ArrayList<SangpumDto> getDataAll(){
		ArrayList<SangpumDto> list = null;
		SqlSession sqlSession = factory.openSession();
		list = (ArrayList)sqlSession.selectList("selectDataAll");
		sqlSession.close();
		return list;
	}
}

 

* Mybatis (@어노테이션)

  - db.properties : 계정정보

  - Configuration.xml : <alias>, <mapper> 삭제

  - DataMapper.xm : 삭제

  - SqlMapperInter : 테이블수에 맞게 작성. sql문 작성

public interface SqlMapperInter_Jikwon {
	@Select("select jikwon_no, jikwon_name, buser_num, jikwon_jik from jikwon where buser_num = #{buser_no}")
	public List<JikwonDto> selectPartJikwon(String buser_no);
}

 

  - SqlMapConfig : SqlMapperInter의 class 배열에 연결.

Class[] mappers = {SqlMapperInter_Buser.class, SqlMapperInter_Jikwon.class, SqlMapperInter_Gogek.class};
for(int i=0; i<mappers.length;i++) {
	sqlSession.getConfiguration().addMapper(mappers[i]);
}

 

  - DAO(or model) : SqlSessionFactory객체사용하여 sql 메소드 호출.

public class JikwonDao {
	private SqlSessionFactory factory = SqlMapConfig.getSqlSession();
	
	public ArrayList<JikwonDto> selectPartJikwon(String buser_no){
		ArrayList<JikwonDto> list = new ArrayList<>(); 
		SqlSession sqlSession = factory.openSession();
		
		try {
			SqlMapperInter_Jikwon inter = sqlSession.getMapper(SqlMapperInter_Jikwon.class);
			list = (ArrayList)inter.selectPartJikwon(buser_no);
		} catch (Exception e) {
			System.out.println("selectPartJikwon err"+e);
		}finally {
			if(sqlSession != null) sqlSession.close();
		}
		return list;
	}
	
}

 

 

4) View

① jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>Insert title here</title>
</head>
<body>
	*상품자료(MVC pattern)
	<table border="1">
		<tr>
			<td>코드</td><td>품명</td><td>수량</td><td>단가</td>
		</tr>
		<c:forEach var = "s" items="${datas}">
			<tr>
				<td>${s.code}</td>
				<td>${s.sang}</td>
				<td>${s.su}</td>
				<td>${s.dan}</td>
			</tr>
		</c:forEach>
	</table>
	
</body>
</html>

 

'BACK END > Servlet' 카테고리의 다른 글

[Servlet] Servlet 정리9 - Mybatis2  (0) 2021.01.06
[Servlet] Servlet 정리8 - Mybatis  (0) 2021.01.06
[Servlet] Servlet 정리7 - JDBC  (0) 2021.01.06
[Servlet] Servlet 정리6 - EL, JSTL  (0) 2021.01.04
[Servlet] Servlet 정리5 - Ajax  (0) 2021.01.03

2) @어노테이션을 이용한 Mybatis 사용 : sql문장을 interface의 추상메소드와 연결.

① SqlMapperInter Interface작성 (DataMapper.xml를 대신함 - 삭제)

public interface SqlMapperInter {
	@Select("select * from membertab")
	public List<DataDto> selectDataAllMember();
	
	@Select("select id, name, passwd, reg_date from membertab where id = #{id}")
	public DataDto selectDataPart(String id);
	
	@Insert("insert into membertab values(#{id},#{name},#{passwd},now())")
	public int insertData(DataFormBean bean);
	
	@Update("update membertab set name=#{name} where id=#{id}")
	public int updateData(DataFormBean bean);
	
	@Delete("delete from membertab where id = #{id}")
	public int deleteData(String id);
}

 

② Configuration.xml 내 DataMapper와 연결된 <mapper>태그 및 alias태그 삭제

 

③ SqlMapConfig에서 

public class SqlMapConfig { // 메뉴얼 확인하여 작성.
	public static SqlSessionFactory sqlSession; // DB의 SQL 명령 실행을 위한 메소드를 가진 객체.
	
	static {
		String resource = "pack/mybatis/Configuration.xml";
		try {
			Reader reader = Resources.getResourceAsReader(resource);
			// Configuration.xml을 읽는다.
			sqlSession = new SqlSessionFactoryBuilder().build(reader);
			// sqlSession 객체를 생성한다.
			reader.close();

 - 하기 code 추가 : sqlSession에 @를 연결.

			//Mybatis Annotation을 사용할 경우 추가해야할 코드
			Class[] mappers = {SqlMapperInter.class/*,SqlMapperInter2.class ..*/};
			for(Class m:mappers) {
				//Mapper 등록
				sqlSession.getConfiguration().addMapper(m);
			}
		} catch (Exception e) {
			System.out.println("SqlMapConfig err"+e);
		}
	}
	public static SqlSessionFactory getSqlSession() {
		return sqlSession;
	}
}

④ ProcessDao 수정 : interface의 sql문을 get하도록 수정.

SqlMapperInter inter = sqlSession.getMapper(SqlMapperInter.class); // sql문을 가져온다.
list = inter.selectDataAllMember();

 

public class ProcessDao {
	private SqlSessionFactory factory = SqlMapConfig.getSqlSession();
	
	public List<DataDto> selectDataAllMember(){
		SqlSession sqlSession = factory.openSession();
		List<DataDto> list =null;
		
		try {
			SqlMapperInter inter = sqlSession.getMapper(SqlMapperInter.class); // sql문을 가져온다.
			list = inter.selectDataAllMember();
			//list = sqlSession.selectList("selectDataAll");
		} catch (Exception e) {
			System.out.println("selectDataAllMember err"+e);
		}finally {
			if(sqlSession!=null)sqlSession.close();
		}
		return list;
	}
	public DataDto selectDataPart(String id) {
		SqlSession sqlSession = factory.openSession();
		DataDto dto = null;
		try {
			SqlMapperInter inter = sqlSession.getMapper(SqlMapperInter.class); // sql문을 가져온다.
			dto = inter.selectDataPart(id);
			//dto = sqlSession.selectOne("selectDataPart", id);
		} catch (Exception e) {
			System.out.println("selectDataPart err"+e);
		}finally {
			if(sqlSession!=null)sqlSession.close();
		}
		return dto;
	}
	public boolean insertData(DataFormBean bean) {
		boolean b = false;
		SqlSession sqlSession = factory.openSession();
		try {
			SqlMapperInter inter = sqlSession.getMapper(SqlMapperInter.class); // sql문을 가져온다.
			if(inter.insertData(bean)>0) {
			//if(sqlSession.insert("insertData", bean)>0) {
				b=true;
				sqlSession.commit();
			}
		} catch (Exception e) {
			System.out.println("insertData err"+e);
			sqlSession.rollback();
		}finally {
			if(sqlSession != null) sqlSession.close();
		}
		return b;
	}
	public boolean updateData(DataFormBean bean) {
		boolean b = false;
		SqlSession sqlSession = factory.openSession();
		try {
			SqlMapperInter inter = sqlSession.getMapper(SqlMapperInter.class); // sql문을 가져온다.
			// 비밀번호 비교 후 수정여부 판단.
			DataDto dto = inter.selectDataPart(bean.getId());
			//DataDto dto = selectDataPart(bean.getId());
			if(dto.getPasswd().equals(bean.getPasswd())) {
				if(inter.updateData(bean) >0) {
				//if(sqlSession.update("updateData", bean)>0) {
					b=true;
					sqlSession.commit();
				}
			}
		} catch (Exception e) {
			System.out.println("updateData err"+e);
			sqlSession.rollback();
		}finally {
			if(sqlSession != null) sqlSession.close();
		}
		return b;
	}
	public boolean deleteData(String id) {
		boolean b = false;
		SqlSession sqlSession = factory.openSession();
		try {
			SqlMapperInter inter = sqlSession.getMapper(SqlMapperInter.class); // sql문을 가져온다.
			int cou = inter.deleteData(id);
			//int cou = sqlSession.delete("deleteData", id);
			if(cou>0) {
				b=true;
				sqlSession.commit();
			}
		} catch (Exception e) {
			System.out.println("deleteData err"+e);
			sqlSession.rollback();
		}finally {
			if(sqlSession != null) sqlSession.close();
		}
		return b;
	}

 

'BACK END > Servlet' 카테고리의 다른 글

[Servlet] Servlet 정리 10 - MCV pattern  (0) 2021.01.07
[Servlet] Servlet 정리8 - Mybatis  (0) 2021.01.06
[Servlet] Servlet 정리7 - JDBC  (0) 2021.01.06
[Servlet] Servlet 정리6 - EL, JSTL  (0) 2021.01.04
[Servlet] Servlet 정리5 - Ajax  (0) 2021.01.03

11. Mybatis : ORM 라이브러리

    * ORM(Object-relational mapping) : SQL문을 객체로 만들어 제공.

    * jar의 모임 -> 라이브러리의 모임 -> 프레임워크

     - MyBatis-3-User-Guide_ko 문서 확인.

 

 

    [xml 이용 mybatis 설정하기]

    ① mybatis-3.5.6.jar 추가(하기 사이트에서 다운로드)

     blog.mybatis.org/p/products.html

 

 

    * 보통 Mybatis 파일끼리 package로 묶어서 사용

      - SqlMapConfig.java

      - Configuration.xm

      - DataMapper.xml

      - db.properties

 

    Configuration.xml : 설정파일 작성

    Mapper 파일 추가 <mapper resource="mapper 경로">태그 추가.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
 <properties resource="pack/db.properties" />
 <environments default="dev">
  <environment id="dev">
   <transactionManager type="JDBC" />
   <dataSource type="POOLED">
    <property name="driver" value="${driver}" />
    <property name="url" value="${url}" />
    <property name="username" value="${username}" />
    <property name="password" value="${password}" />
   </dataSource>
  </environment>
 </environments>
 <mappers>
  <mapper resource="pack/DataMapper.xml" />
 </mappers>
</configuration>

    * Configuration.xml에 별칭 추가(<configuration>내부)

 <typeAliases>
 	<typeAlias type="pack.business.DataDto" alias="dto"/>
 	<typeAlias type="pack.business.DataFormBean" alias="formBean"/>
 </typeAliases>

 

 

    ③ db.properties : 계정정보 파일

driver=org.mariadb.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/test
username=root
password=123

 

    DataMapper.xml 추가

    - SQL문을 작성.

    - value값을 매개변수로 가질 경우 #{code}사용.

    - 칼럼값을 매개변수로 가질 경우${code} 사용.

                                 select : List 리턴.

                                 insert : 0, 1 리턴 - 1개씩만 update 가능.
                                 update : 0, n 리턴.
                                 delete : 0, n 리턴.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="dev">
 <select id="selectDataAll" resultType="pack.DataDto">
  select * from sangdata order by code asc
 </select>
 
 <select id="selectDataById" parameterType="string" resultType="pack.DataDto">
  select code,sang,su,dan from sangdata where code = #{code}
 </select>
 
 <insert id="insertData" parameterType="pack.DataDto">
  insert into sangdata(code,sang,su,dan) values(#{code},#{sang},#{su},#{dan})
 </insert>
 
 <update id="updateData" parameterType="pack.DataDto">
  update sangdata set sang=#{sang} where code=#{code}
 </update>
 
 <delete id="deleteData" parameterType="int">
  delete from sangdata where code=#{code}
 </delete>
</mapper>

 => Configuration.xml의 별칭을 resultType에 사용가능.

 

    * DataMapper.xml에  재사용 구문 별도 작성하여 재사용성을 높인다.

 <sql id="my1">id, name, passwd, reg_date</sql>
 <sql id="my2">from membertab where id = #{id}</sql>
 
 <select id="selectDataPart" parameterType="string" resultType="dto" statementType="PREPARED">
  select
  <include refid="my1"/>
  <include refid="my2"/>
 </select>

 

    ⑤ SqlMapConfig : 메뉴얼 확인하여 작성.

public class SqlMapConfig {
	public static SqlSessionFactory sqlSession;
	// DB의 SQL 명령 실행 메소드를 가진 객체.
	static {
		String resource = "pack/Configuration.xml";
		try {
			Reader reader = Resources.getResourceAsReader(resource);
			// Configuration.xml을 읽는다.
			sqlSession = new SqlSessionFactoryBuilder().build(reader);
			// sqlSession 객체를 생성한다.
			reader.close();
		} catch (Exception e) {
			System.out.println("SqlMapConfig err"+e);
		}
	}
	public static SqlSessionFactory getSqlSession() {
		return sqlSession;
	}
}

 * 보통 business 파일끼리 package로 묶어서 사용

  - DataDto.java

  - FormBean.java

  - ProcessDao.java

 

* 용도에 따라 FormBean과 Dto 파일로 데이터를 관리한다.

  - FormBean 용도 : 클라이언트의 정보를 레코드 단위로 받아 처리 (update, delete)
  - DataDTO 용도 : DB에서 넘어오는 정보를 레코드 단위로 받아 처리 (select)

 

     DTO작성 - DataDto.java

 

     FormBean작성


    ⑧ ProcessDao : MyBatis와 연결해서 SQL을 실행하고 그 결과를 얻는 역할

public class ProcessDao {
	private SqlSessionFactory factory = SqlMapConfig.getSqlSession();
	
	public List<DataDto> selectDataAll() throws Exception{
		SqlSession sqlSession = factory.openSession(); // 세션 열기(DB처리를 위한 작업단위)
		List<DataDto> list = sqlSession.selectList("selectDataAll"); // DataMapper의 id를 가져온다.
		// selectList() : 여러개 리턴 
		// selectOne() : 1개 리턴
		sqlSession.close();
		return list; // sql의 결과를 가진다.
	}
	
	public DataDto selectDataPart(String code) throws Exception {
		SqlSession sqlSession = factory.openSession();
		DataDto dto = sqlSession.selectOne("selectDataById", code);
		sqlSession.close();
		return dto;
	}
	
	public int insertData(DataDto dto) throws Exception{
		//SqlSession sqlSession = factory.openSession(); // 수동 commit.
		SqlSession sqlSession = factory.openSession(true); // 자동 commit.
		int result = sqlSession.insert("insertData",dto);
		if(result == 0) {
			sqlSession.rollback();
		}else {
			//sqlSession.commit();
		}
		sqlSession.close();
		return result;
	}
	public int upData(DataDto dto) throws Exception{
		SqlSession sqlSession = factory.openSession();
		int result = sqlSession.update("updateData", dto);
		sqlSession.commit();
		sqlSession.close();
		return result;
	}
	public boolean delData(int code){
		boolean result = false; 
		SqlSession sqlSession = factory.openSession();
		try {
			int cou = sqlSession.delete("deleteData", code);
			if(cou>0) {
				result=true;
			}
			sqlSession.commit();
		} catch (Exception e) {
			System.out.println("dlData err"+e);
			sqlSession.rollback();
		}finally {
			if(sqlSession != null) sqlSession.close();
		}		
		return result;
	}
}

 

 * 보통 jsp파일에 작성.

    ⑨-1) java main

ProcessDao dao = new ProcessDao();
try {
	System.out.println("자료 추가");
	DataDto dataDto = new DataDto();
	dataDto.setCode("11");
	dataDto.setSang("초록양말");
	dataDto.setSu("7");
	dataDto.setDan("4000");
	//DataDto dataDto = new DataDto("11","초록양말","7","4000");
	int result = dao.insertData(dataDto);
	System.out.println(result+"개 자료 추가");
	
	System.out.println("자료 수정");
	DataDto dataDto = new DataDto();
	dataDto.setCode("11");
	dataDto.setSang("빨간양말");
	int result = dao.upData(dataDto);
	System.out.println(result+"개 자료 업데이트");
	
	System.out.println("자료삭제");
	boolean result = dao.delData(5);
	if(result) {
		System.out.println("삭제 성공");
	}else {
		System.out.println("삭제 실패");
	}
	
	System.out.println("\n전체자료 출력");
	List<DataDto> list = dao.selectDataAll();
	//ArrayList<DataDto> list = (ArrayList)dao.selectDataAll();
	for(DataDto s:list) {
		 System.out.println(s.getCode() +"\t"+
							s.getSang() +"\t"+
							s.getSu() +"\t"+
							s.getDan());
	}
	System.out.println("전체 건수:" + list.size());
	
	System.out.println("\n부분자료 출력");
	DataDto dto = dao.selectDataPart("3");
	System.out.println(dto.getCode() +"\t"+
						dto.getSang() +"\t"+
						dto.getSu() +"\t"+
						dto.getDan());
} catch (Exception e) {
	System.out.println("Main err "+e);
}

⑨-2) jsp

- main html

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>Insert title here</title>
</head>
<body>
	* 홈페이지<br>
	인사관리 자재관리 영업관리 <a href="list.jsp">회원관리</a>
	<hr>
	<pre>입력값 출력
	</pre>
	<footer>
	꼬리말
	</footer>
</body>
</html>

 - 모든 list 출력 jsp (select all)

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<jsp:useBean id="processDao" class="pack.business.ProcessDao"/>
<%
	ArrayList<DataDto> slist = (ArrayList)processDao.selectDataAll();
%>
<a href="ins.html">상품추가</a><br>
<span style="color:red">코드를 클릭하면 삭제 품명을 클릭하면 수정처리</span>
<table border="1">
	<tr>
		<th>상품명</th><th>품명</th><th>수량</th><th>단가</th>
	</tr>
	
	<c:forEach var ="s" items="<%=slist%>">
	<tr>
		<td><a href="delete.jsp?code=${s.code }">${s.code}</a></td>
		<td><a href="update.jsp?code=${s.code }">${s.sang}</a></td>
		<td>${s.su}</td>
		<td>${s.dan}</td>
	</tr>
	</c:forEach>		
</table>

 

<%@page import="pack.business.DataDto"%>
<%@page import="java.util.ArrayList"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="func" uri="http://java.sun.com/jsp/jstl/functions" %>
<jsp:useBean id ="processDao" class="pack.business.ProcessDao"/>
<!DOCTYPE html>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>Insert title here</title>
</head>
<body>
	<h2>* 회원정보(Mybatis)</h2>
	<a href="ins.jsp">회원추가</a>
	<table border="1">
		<tr>
			<th>id</th><th>name</th><th>pwd</th><th>date</th>
		</tr>
		<% ArrayList<DataDto> list = (ArrayList)processDao.selectDataAllMember(); %>
		<c:set var="list" value="<%=list %>"/>
		<c:if test="${empty list}">
			<tr>
				<td colspan="4">자료없음</td>
			</tr>
		</c:if>
		<c:forEach var="m" items="<%=list%>">
			<tr>
				<td><a href="del.jsp?id=${m.id}">${m.id}</a></td>
				<td><a href="up.jsp?id=${m.id}">${m.name}</a></td>
				<td>${m.passwd}</td>
				<td>${func:substring(m.reg_date,0,10)}</td>
			</tr>
		</c:forEach>
		<tr>
			<td colspan="4">id클릭은 삭제 name클릭은 수정</td>
		</tr>
	</table>
</body>
</html>

* function 액션태그

<%@ taglib prefix="func" uri="http://java.sun.com/jsp/jstl/functions" %>
${func:substring(m.reg_date,0,10)}

 

 - insert html

<form action="ins.jsp" method="post">
	코드 : <input type="text" name="code"><br>
	품명 : <input type="text" name="sang"><br>
	수량 : <input type="number" name="su"><br>
	단가 : <input type="number" name="dan"><br>
	<input type="submit" value="등록">
</form>

 - insert jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<% request.setCharacterEncoding("utf-8"); %>

<jsp:useBean id="bean" class="pack.business.FormBean"></jsp:useBean>
// java bean객체 생성 액션태그
<jsp:setProperty property="*" name="bean"/>
// 생성 객체에 프로퍼티 값 설정

<jsp:useBean id="processDao" class="pack.business.ProcessDao" />
<%
	processDao.insertData(bean);// Mybatis 호출
	response.sendRedirect("list.jsp");
%>
자바빈 property는 하기와 동일
<%= bean.getCode() %>
<%= bean.getSang() %>

* 수정/ 삭제 후 Redirect 진행해야함(client) forward 진행 시 새로고침시 해당 동작이 중복 수행된다.(수정/삭제에서 실행)

<jsp:forward page="list.jsp" /> insert에선 사용하지않음

* servlet에 하기와 같이 구현가능

// 내부적인 처리만 구현. 비지니스 로직. servlet으로 구현 가능
request.setCharacterEncoding("utf-8");
String code = request.getParameter("code");
String sang = request.getParameter("sang");
...
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>Insert title here</title>
</head>
<body>
	<h2>회원가입</h2>
	<form action="insok.jsp" method="post">
	id : <input type="text" name="id"><br>
	name : <input type="text" name="name"><br>
	passwd : <input type="text" name="passwd"><br>
	<br>
	<input type="submit" value="등록">
	</form>
</body>
</html>

 - insert ok jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<% request.setCharacterEncoding("utf-8"); %>
<jsp:useBean id="fbean" class="pack.business.DataFormBean"/>
<jsp:setProperty property="*" name="fbean"/>
<jsp:useBean id="processDao" class="pack.business.ProcessDao"/>
<%
	boolean b = processDao.insertData(fbean);
	if(b){
		response.sendRedirect("list.jsp");
	}else{
		response.sendRedirect("fail.jsp");
	}
%>

 - update jsp

<%@page import="pack.business.DataDto"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
<jsp:useBean id="processDao" class="pack.business.ProcessDao"></jsp:useBean>
<%
	String code = request.getParameter("code");
	DataDto dto = processDao.selectDataPart(code);
%>

<!DOCTYPE html>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>Insert title here</title>
	<script type="text/javascript">
	</script>
</head>
<body>

	<form action="updateOk.jsp" method="post">
		코드 : <%= dto.getCode() %><br>
		<input type="hidden" name="code" value="<%=dto.getCode()%>">
		//값은 전달이 필요하지만 변경이 필요하지않는다면 input태그의 hidden type으로 구현한다.
		품명 : <input type="text" name="sang" value="<%= dto.getSang()%>"><br>
		수량 : <input type="number" name="su" value="<%= dto.getSu()%>"><br>
		단가 : <input type="number" name="dan" value="<%= dto.getDan()%>"><br>
		<input type="submit" value="수정">
		<input type="button" onclick="history.back()" value="이전">
	</form>
    
</body>
</html>
<%@page import="pack.business.DataDto"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<jsp:useBean id="processDao" class="pack.business.ProcessDao"></jsp:useBean>
<% request.setCharacterEncoding("utf-8");
String id = request.getParameter("id");
DataDto dto = processDao.selectDataPart(id);
%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h2>*회원정보 수정</h2>
	<form action="upok.jsp" method="post">
	id : <%=dto.getId()%><br>
	<input type="hidden" name="id" value="<%=dto.getId()%>"/>
	name : <input type="text" name="name" value="<%=dto.getName()%>"/><br>
	pwd : <input type="text" name="passwd"/><br>
	<input type="submit" value="수정"/>
	</form>
</body>
</html>

 - update ok jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
<% request.setCharacterEncoding("utf-8"); %>

<jsp:useBean id="bean" class="pack.business.FormBean"/>
<jsp:setProperty property="*" name="bean"/>
// formbean 값을 가져온다.
<jsp:useBean id="processDao" class="pack.business.ProcessDao"/>
// sql문 사용 객체 선언
<%
	processDao.upData(bean);
	response.sendRedirect("list.jsp");
%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<% request.setCharacterEncoding("utf-8");%>
<jsp:useBean id="fbean" class="pack.business.DataFormBean"></jsp:useBean>
<jsp:setProperty property="*" name="fbean"/>
<jsp:useBean id="processDao" class="pack.business.ProcessDao"></jsp:useBean>
<%
	boolean b = processDao.updateData(fbean);

	if(b){
		response.sendRedirect("list.jsp");
	}else{
		response.sendRedirect("fail.jsp");
	}
%>

 

 - delete jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<jsp:useBean id="processDao" class="pack.business.ProcessDao"></jsp:useBean>
<%
	int code = Integer.parseInt(request.getParameter("code"));
	boolean b = processDao.delData(code);
	
	
	if(b){
		response.sendRedirect("list.jsp");
	}else{%>
		<script >
			alert("삭제를 실패하였습니다.");
			location.href="list.jsp";
			//response.sendRedirect("list.jsp");
		</script>
	<%}%>
<%@page import="pack.business.DataDto"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<% request.setCharacterEncoding("utf-8");
%>
<jsp:useBean id="processDao" class="pack.business.ProcessDao"></jsp:useBean>
<%
	String id = request.getParameter("id");
	boolean b = processDao.deleteData(id);
	
	if(b){
		response.sendRedirect("list.jsp");
	}else{
		response.sendRedirect("fail.jsp");
	}
%>

 - fail jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>Insert title here</title>
</head>
<body>
	<h2>작업실패</h2>
	<a href="list.jsp">회원정보 보기</a>
</body>
</html>

 


* log4j를 이용해 java + MyBatis log 작성
    ① Root에 log4j.properties 생성

log4j.rootLogger=DEBUG, console
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.Encoding=UTF-8
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%d{ISO8601}] [%-12t] %-5p %m%n

 

    ② Context/WEB_INF/lib에 log4j-1.2.17.jar 추가

 

<tip>

* WEB_INF는 외부에서 접근 불가하다.(보안)

* ctrl + 함수명 : 선언부로 이동.

'BACK END > Servlet' 카테고리의 다른 글

[Servlet] Servlet 정리 10 - MCV pattern  (0) 2021.01.07
[Servlet] Servlet 정리9 - Mybatis2  (0) 2021.01.06
[Servlet] Servlet 정리7 - JDBC  (0) 2021.01.06
[Servlet] Servlet 정리6 - EL, JSTL  (0) 2021.01.04
[Servlet] Servlet 정리5 - Ajax  (0) 2021.01.03

* maria JDBC 사용

public class ConnBean {
	private Connection conn;
	private PreparedStatement ptmt;
	private ResultSet rs;
	
	public ConnBean() {
		try {
			Class.forName("org.mariadb.jdbc.Driver");
		} catch (Exception e) {
			System.out.println("ConnBean err : "+e);
		}finally{
			
		}
	}
	public ArrayList<ProductDto> getData(){
		ArrayList<ProductDto> list = new ArrayList<ProductDto>();
		try {
			conn = DriverManager.getConnection("jdbc:mysql//localhost:3306/test","root","123");
			String sql = "select * from product";
			ptmt = conn.prepareStatement(sql);
			rs = ptmt.executeQuery();
			while(rs.next()) {
				ProductDto dto = new ProductDto();
				dto.setCode(rs.getString("code"));
				dto.setSang(rs.getString("sang"));
				dto.setSu(rs.getInt(3));
				dto.setDan(rs.getInt(4));
				list.add(dto);
			}
		} catch (Exception e) {
			System.out.println("getData err : "+e);
		}finally{			
			try {
				if(conn!=null) conn.close();
				if(ptmt!=null) ptmt.close();
				if(rs!=null) rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return list;
	}
}

 

 

* JDBC Connection pooling을 위한 방법

    ① context.xml 추가

     - 경로

context/META-INF/context.xml

     - 내용

<Context>
	<Resource name="jdbc_maria" auth="Container" type="javax.sql.DataSource"
		driverClassName="org.mariadb.jdbc.Driver" loginTimeout="10" maxWait="5000"
		username="root" password="123" testOnBorrow="true"
		maxActive="500" maxIdle="100"
		url="jdbc:mysql://localhost:3306/test" />
</Context>

* dbcp 사용 : 아파치에서 지원하는 기능. 자동적으로 객체 제어.

JNDI(Java Naming and Directory Interface)

public class ConnBean {
	private Connection conn;
	private PreparedStatement ptmt;
	private ResultSet rs;
	private DataSource ds;
	public ConnBean() {
		try {
			Context context = new InitialContext(); // ds사용
			ds = (DataSource)context.lookup("java:comp/env/jdbc_maria"); // ds사용
		} catch (Exception e) {
			System.out.println("ConnBean err : "+e);
		}finally{
			
		}
	}
    public ArrayList<SangpumDto> getData(){
		ArrayList<SangpumDto> list = new ArrayList<SangpumDto>();
		try {
			conn = ds.getConnection();  // ds사용
			String sql = "select * from sangdata";
			ptmt = conn.prepareStatement(sql);
			rs = ptmt.executeQuery();
			while(rs.next()) {
				SangpumDto dto = new SangpumDto();
				dto.setCode(rs.getString("code"));
				dto.setSang(rs.getString("sang"));
				dto.setSu(rs.getInt(3));
				dto.setDan(rs.getInt(4));
				list.add(dto);
			}
		} catch (Exception e) {
			System.out.println("getData err : "+e);
		}finally{			
			try {
				if(conn!=null) conn.close();
				if(ptmt!=null) ptmt.close();
				if(rs!=null) rs.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		return list;
	}
}

 

[servlet]

protected void service(HttpServletRequest request, HttpServletResponse response) 
					throws ServletException, IOException {
		//jstl은 service메소드를 오버라이딩해야한다.
		//get/post에 따라 나뉘지않는다.
}


* redirect방식

response.sendRedirect("jstlex2.jsp?aa=value");
// 클라이언트를 통해서 서버파일을 호출
// get방식으로 문자열만 전달가능.

* forward방식 

request.getRequestDispatcher("jstlex2.jsp").forward(request, response);
// server에서 server파일을 직접호출.

* String

 -servlet

String irum = "마당쇠";
request.setAttribute("man", irum);


-jsp

<% 
	String str = (String)request.getAttribute("man");
	out.print(str); 
%>

-EL

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
${man}
${requestScope.man}

* 인스턴스

-servlet

Person person = new Person(); // init()에 구현.
person.setName("한국인");
request.setAttribute("person", person);

-jsp

<% 
	Person p = (Person)request.getAttribute("person");
	out.print(p.getName());
%>

-EL

${person.name}

 

* import

- servlet

String[] ani = {"말","고양이","개"};
request.setAttribute("animal", ani);

-EL

<%@page import="pack.Person"%>
${animal[0]}
${animal[1]}
${animal["2"]}

* List

-sevlet

String[] food = {"당근", "고양이밥","개밥"};
List<Object> list = new ArrayList<>();
list.add(ani);
list.add(food);
request.setAttribute("list", list);

- EL

<c:if test="${list != null }">
	<c:forEach var="a" items="${list}">
		${a[0]}, ${a[1]}, ${a[2]}
	</c:forEach>
</c:if>
<c:if test="${list != null }">
	<c:forEach var="a" items="${list}">
		<c:forEach var="b" items="${a}">
			${b}
		</c:forEach>
	</c:forEach>
</c:if>
<c:choose>
	<c:when test="${list eq null}">자료없음</c:when>
	<c:otherwise>자료있음</c:otherwise>
</c:choose>

 

* catch~except처리(예외처리)

<c:catch var ="myErr">
	<%
		int a = 10/0;
		out.print(a);
	%>
</c:catch>
<c:if test="${myErr != null}">
	에러 발생: ${myErr.message}
</c:if>

* 다른 문서 포함

 - include 지시어

<%@ include file="include.jsp"%>

 - jsp action tag

<jsp:include page="include.jsp"/>

 - jstl(문서)

<c:import url="include.jsp"/>

 - jstl(사이트)

<c:import url="https://www.daum.net"/>

 - 내용

<c:set var="url" value="https://www.naver.com"/>
<c:out value="${url}"/>

 - source

<c:import url="${url}" var="u"></c:import>
<c:out value="${u}"/><br> 

 

[목차]

9. EL

 

 

[내용]

9. EL (Expression Language) : jsp는 문서내 <tag>와 java code를 혼용되게 사용하여 유지보수에 어려움이 있어

                                      java code의 사용을 줄이기 위해 개발된 언어.(code를 더 단순화 시킴)

    1) 연산자

     - 산술

${3+4}
${5/4}, ${5 div 4}
${5%4}, ${5 mod 4}

     - 관계

${3>4}, ${3 gt 4}
${3<=4}, ${3 le 4}

     - 논리

${5>4 and 3<2}

     - 3항

${5>4 ? 10:20}

 

    2) life cycle이 다른 내장객체에 따른 데이터 공유

<%
	request.setAttribute("a","air"); // 현재 페이지에서 유효
	session.setAttribute("b","book"); // 설정시간 동안 유효
	application.setAttribute("c","cat"); // 서비스가 유지되는 동안 사용. (지양)
%>
<%= request.getAttribute("a") %>
${requestScope.a}
${a} // requestScope는 생략가능

<%= session.getAttribute("b") %>
${sessionScope.b}

<%= application.getAttribute("c") %>
${applicationScope.c}

 

    3) 지시자

<%@ page isELIgnored="true" %> // EL를 파싱하지않도록 설정. default는 false.

 

    4) Parameter

    - jsp

<%= request.getParameter("userName") %>
<%
	String ir = request.getParameter("irum");
	String[] su = request.getParameterValues("sung");
%>
<%= request.getHeader("host") %>

    - EL

${param.userName}
${param.irum}
${param["irum"]}
${paramValues.sung[0] }
${paramValues.sung["1"] }
${header.host}
${header["host"]}

 

    5) collection

<%
	ArrayList list = new ArrayList();
	list.add("kor");
	list.add("eng");
	request.setAttribute("list", list);
%>

    - jsp

<%
	ArrayList list2 = (ArrayList)request.getAttribute("list");

	out.println(list.get(0));
	out.println(list.get(1));
%>

    - EL

${list[0]}
${list["1"]}

 

10. JSTL(Jsp Standard Tag Library) : jsp에 기능을 더 한 tag 라이브러리(메소드)

 

    1) driver 추가

/context/WEB_INF/lib경로에 jstl-1.2.jar 추가

    2) 지시자 추가

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>

    3) 변수
     - 문자열

<c:set var="변수" value="값" scope="page"/> // scope에 request, session, application, page 사용 가능
<c:out value="${변수}"></c:out>

<c:set var="변수" scope="session">값</c:set>
<c:out value="${변수}"></c:out>

     - 배열

<c:set var="aa" value="${header['User-Agent']}" scope="page"/>
<c:out value="${aa}"></c:out>
<c:remove var="aa" scope="page"/>
<c:out value="${aa}"></c:out>

 

     - 숫자

<c:set var="num1" value="10"></c:set>
<c:set var="num2">20.5</c:set>
${num1+num2}

 

    4) 조건문 if

<c:set var="bb" value="${'star' }"/>
<c:out value="${bb }"></c:out>

<c:if test="${bb == 'star' }">
	// 실행문
</c:if>
<c:set var="cc" value=""/>
<c:out value="${cc }"></c:out>

<c:if test="${cc != '' && cc ne null}">
	// 실행문
</c:if>

 

    5) 조건문 choose

<c:choose>
	<c:when test="${bb eq 'moon' }">
		실행값1
	</c:when>
	<c:when test="${bb eq 'star' }">
		실행값2
	</c:when>
	<c:otherwise>나머지경우</c:otherwise>
</c:choose>
<c:choose>
	<c:when test="${empty param.name }">
		<form>
			<input type="text" name="name">
			<input type="submit" value="확인">
		</form>
	</c:when>
	<c:when test="${param.name == 'admin' }">
		관리자
	</c:when>
	<c:otherwise>
		<c:out value="${param.name }"/>
	</c:otherwise>
</c:choose>

 

    6) 반복문 for each

<c:forEach var="cc" begin="1" end="10" step="1">
	<c:out value="${cc }"/>
	${cc }
</c:forEach>
<c:forEach var="i" begin="1" end="9">
3 * ${i } = ${3*i }<br>
</c:forEach>

 

    7) 이중 for

<c:forEach var="h" items="${headerValues}">
	<c:out value="${h.key}"></c:out>
	<c:forEach var="i" items="${h.value}">
		<c:out value="${i}">&nbsp;</c:out>
	</c:forEach>
</c:forEach>

 

    8) collection

<% 
	HashMap map = new HashMap();
	map.put("name","홍길동");
	map.put("today",new Date());
%>

     - map

<c:set var ="m" value="<%=map%>"/>

<c:forEach var = "mbc" items="${m}">
	${mbc.key} : ${mbc.value}
</c:forEach>

     - 배열

<c:set var ="arr" value="<%=new int[]{1,2,3,4,5}%>"/>

<c:forEach var = "i" items="${arr}" begin="2" end="4" step="1">
	${i}
</c:forEach>

 

    6) 문자열 분할

<c:forTokens var="animal" items="horse,tiger,lion,pig,cat" delims=",">
	동물:${animal }
</c:forTokens>

<c:forTokens var="animal" items="horse,tiger*lion,pig*cat" delims=",*" varStatus="num">
	${num.count}) ${animal}
</c:forTokens><br>

 

    7)  숫자 및 날짜 출력 서식

    - 지시자

<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
숫자
<fmt:formatNumber value="12345.678" type="number"/>
통화
<fmt:formatNumber value="12345.678" type="currency" currencySymbol="W"/>
백분율
<fmt:formatNumber value="12345.678" type="percent"/><br>
소수 이하
<fmt:formatNumber value="12345.678" pattern="#,##0.00"/>
 // 000.0은 무효라도 표시.(001.1)
 // ###.#은 0 값이 자리숫 첫번째에 존재하면 표시하지않는다. (1.1)

<c:set var="now" value="<%= new Date() %>"></c:set>
<c:out value="${now}"></c:out>

날짜
<fmt:formatDate value="${now}" type="date"/>
<fmt:formatDate value="${now}" type="both" dateStyle="full" pattern="yyyy년MM월dd일"/>
<fmt:formatDate value="${now}" type="both" dateStyle="full" pattern="yyyy-MM-dd"/>
시간
<fmt:formatDate value="${now}" type="time"/>

[목차]

8. Ajax

 

 

 

8. Ajax(Asynchronous Javascript And XML)

client request
--------->


response
<---------
server
1) 클라이언트의 뷰페이지에서 요청을
   보낸다.
2) XMLHttpRequest객체가 생성.
3) 요청처리.
6) 응답받은 메시지를 자바스크립트에서
   처리.(응답되는 데이터를 가지고 부분
   화면을 변경하기 위해서 javascript와
   DOM(JQuey) 사용)
7) 페이지를 업데이트.
4) 서버에서 request를 받는다.
5) request에 대한 처리(DBMS액세스)
    후 클라이언트에 응답을 보낸다.
    (데이터, 문자열, xml, json)

 

    [jsp]

    1) 버튼을 누르면 ajax요청을 하기 위해서 runAjax함수 호출.

<body>
	<form name = "myform">
		<input type="text" name="id">
		<button type="button" onclick="runAjax()">Ajax테스트</button>
	</form>
	<div id="result"></div>
</body>

 

    2) 비동기통신 처리를 할 수 있는 자바스크립트 객체를 생성 - XMLHttpRequest

<script type="text/javascript">
	function runAjax(){
		var xhr = new XMLHttpRequest();


    3-1) 요청설정

		open("request타입",url,true-async, false-sync)

     -GET

		xhr.open("GET","servlet 경로?id="+myform.id.value, true);

    - POST

		xhr.open("POST","/serverweb/ajaxtest_post.do", true);

    3-2) 요청보내기 - 비동기 통신으로 요청을 보낸다.

     -GET

		send(); // get방식
		xhr.send();

    - POST

		send("문자열"); // post방식
		xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
		xhr.send("id="+myform.id.value);

    => 요청헤더에 content-type을 변경.
    => form태그를 이용해서 요청하고 있지 않지만 form태그를 이용해서 요청하는 것처럼  key=value의 형식으로

        인코딩을 적용 .
    => ajax요청을 submit버튼을 눌러 요청할때 처럼 key를 이용해서 value를 추출해야 하므로 반드시 설정해야

        하는 정보.

 

    [servlet]

    4) 서버에서 request를 수신 - 처리

String id = request.getParameter("id");
String msg="";
if(id.equals("이미 존재하는 ID")) { // DBMS에서 처리
	msg="사용불가능 id";
}else {
	msg="사용가능 id";
}

 

    5) 클라이언트에 응답하기 위한 메시지를 만들어서 응답

        (문자열이 하나인 경우 변수처리해서 보낸다. json라이브러리를 이용해서 json객체를 만들어서 응답)

    - GET

response.setContentType("text/html;charset=UTF-8");
PrintWriter pw= response.getWriter();
pw.print(msg);

    - POST

response.setContentType("text/html;charset=UTF-8");
response.setHeader("cache-control", "no-cache, no-store");
PrintWriter pw= response.getWriter();
pw.print(msg);


    => response의 헤더 값을 변경.
    => html을 요청하는 것이 정적 리소스를 요청하는 작업이고 요청이 될때마다 서버에서 작업을 수행하고 실행해서

         결과를 가져오는데 이를 비효율적이라 판단해서 기본설정이 동일한 요청이 들어왔을떄 캐쉬에서 저장하고

         있는 파일을 보여준다.
         결과를 캐쉬에 저장하면 다음 요청에 대한 결과가 제대로 나오지 않을 수 있다. 그래서 응답결과를 캐쉬에 저장

         하지 말고 서버에서 바로바로 요청해서 보여줄 수 있도록 헤더값에 설정.

    [jsp]

    6) 서버와 비동기 통신을 하면서 XMLHttpRequest가 갖고 있는 readyState값이 지속으로 변경
       변경될때 마다 onreadystatechange이벤트가 발생하며 이 이벤트를 처리하기 위해서 익명함수를 콜백으로 정의

		xhr.onreadystatechange = function(){ // 함수 자동호출
			if(xhr.readyState == 4 && xhr.status==200){
			// 비동기 통신이 정상처리, http응답도 정상처리
				document.getElementById("result").innerHTML = xhr.responseText;
			}
		}
	}
</script>
		xhr.onreadystatechange = readyCallback;
	}
	function readyCallback(){
		if(xhr.readyState == 4 && xhr.status==200){
			document.getElementById("result").innerHTML = xhr.responseText;
		}
	}
</script>

    * readyState

    0: request가 초기화되지 않은 상태

    1: 서버와 연결이 된 상태

    2: 요청을 받은 상태

    3: 요청을 처리하고 있는 상태

    4: 요청처리가 끝나고 응답 대기 상태

 

    * status

    200 : 정상완료

    404 : 페이지가 존재하지 않는 경우

 

    * 서버응답 처리 객체

    responseText : String데이터를 get으로 응답받은 경우 사용

    response​XML : XML데이터를 get으로 응답받은 경우 사용

[목차]

6. 쿠키

7. 세션

 

* http : 요청을 하고 응답이 클라이언트에게 전송이 되면 서버에서 발생한 모든 정보가 지워진다.(stateless)

 

 * 상태유지 기술
 - 세션
 - 쿠키

 

 

[내용]

7. 쿠키(Cookie) : 클라이언트에 저장되는 텍스트 조각  

client(브라우저) request
------------>
getCookie
server(sevlet) setAttrubute()
------------>
request객체 getAttribute()
------------>
jsp
setCookie
<------------

response
   

 

    1) setCookie

//Servlet
Cookie cookie1 = new Cookie("name","value"); // Cookie객체 생성 및 데이터 저장

cookie1.setMaxAge(60*60*24); // 쿠키에 유효시간 설정(단위 : 초)
// setMaxAge(-1) : 브라우저 종료시 까지 유지
// setMaxAge(0) : 제거

response.addCookie(cookie1); // response에 쿠키 저장

RequestDispatcher rd = request.getRequestDispatcher("context제외된 경로"); // 요청재지정
rd.forward(request, response);

 

    2) getCookie

//Servlet
Cookie[] cookies = request.getCookies(); //request에서 쿠키정보 꺼내기(배열로 리턴됨)

// 쿠키의 name정보를 이용해서 작업하기
String name = "";
for(int i=0;i<cookies.length;i++) {
	if(cookies[i].getName().equals("name")) { // 쿠키의 배열에서 key값인 "name"의 value값 get
		name = cookies[i].getValue();
	}
}

request.setAttribute("name", name); // 쿠키에서 뺀 데이터를 request에 공유

RequestDispatcher rd = request.getRequestDispatcher("context가 제외된 경로"); // 요청 재지정 - forward
rd.forward(request, response);
// jsp
<% 
	String name = (String)request.getAttribute("name");
%>
<%= name %>

7. 세션(Session)
 - 사용자가 브라우저를 키고 사용하는 동안 정보가 유지된다.
 - 서버메모리에 저장된다.
 - 내부적으로 쿠키처럼 처리.


    1) 세션 사용
        ① request에서 세션정보 추출
        ② 세션이 없는 경우
            -> 세션 만들기
           세션이 있는 경우
           -> 세션id와 일치하는 세션에 저장된 정보를 확인.
        ③ 세션 id를 response에 보낸다.

    2) 세션객체 만들기
     - 세션 id를 request에서 꺼내서 작업하는 것이므로 request객체에서 기존의 세션 정보를 가져오거나 새로

        만들어주는 메소드를 제공.
   
    ① getSession()
      - 새로운 세션은 만들때 사용하는 메소드
      - request객체에서 세션 id를 추출하는 데 만약 세션이 만들어져 있지않은 상태면 세션을 새로 생성해서 리턴
         ex) 로그인하기 위해서 로그인 버튼을 클릭하고 요청되는 로그인 서블릿에서 로그인이 성공하면 세션을 새로

              만든다.

    ② getSession(boolean)
      - 기존에 작업하는 세션이 있는 지 확인하기 위해서 사용
      - getSession(true) - getSession()과 동일하게 동작
      - getSession(false) - 기존에 사용하던 세션이 있으면 섹션객체를 리턴하고 없으면 새로만들지 않고 null을 리턴.

 

//servlet
String id = request.getParameter("id");      
HttpSession ses = request.getSession(); //데이터 공유 - 세션
ses.setAttribute("id", id);

RequestDispatcher rd = request.getRequestDispatcher("context가 제외된 경로"); //요청 재지정  - forward
rd.forward(request, response);
//jsp
<%
	String id = (String)session.getAttribute("id");
%>
<%= id %>

 

<tip>

   * Chrome 개발자도구 F12 - Application - Cookies : 쿠키 데이터 확인 가능.

[목차]

5. JSP

    1) MVC 패턴

    2) 요청재지정

    3) 데이터 공유 

    4) JSP

    5) 스크립트 요소 

 

[내용]

5. JSP

    [서블릿 & DAO 연동 코드작성]
    1) 서블릿을 작성.
    2) 서블릿을 작성시 등록한 urlpattern에 매핑된 path를 요청 View(서블릿을 요청하는 최초 실행되는 클라이언트

        화면)의 <form>태그 action속성이나 <a>태그 href속성에 연결.
    3) 서블릿에서 요청정보 추출 후 sysout 테스트 진행.
    4) DTO 클래스 작성.
    5) DAO 클래스 작성.(서블릿에서 호출하는 비지니스 메소드를 가진)
       - 메소드내 sysout으로 출력하여 sysout 테스트.
    6) 서블릿에서 DAO메소드 호출
    7) DAO 코드 작성.
        ① insert, delete, update는 실행결과 행 출력
        ② select
        while문을 작성하고 while문 안에서 sysout출력.
       출력되면 칼럼을 가져와서 출력.
    8) 서블릿에서 dao호출한 리턴결과를 출력.

 

//servlet
MyEmpDAO dao = new MyEmpDAO();
ArrayList<MyEmpDTO> list = dao.getMemberList();
out.println("list.get(i).getDeptno()");
//dao
public ArrayList<MyEmpDTO> getMemberList(){
	ArrayList<MyEmpDTO> list = new ArrayList<MyEmpDTO>(); 
	System.out.println("dao요청");
	String sql = "select * from myemp";
	Connection con = null;
	PreparedStatement ptmt = null;
	ResultSet rs = null;
	try {
		con = DBUtil.getConnect();
		ptmt = con.prepareStatement(sql);
		rs = ptmt.executeQuery();
		while(rs.next()) {
			MyEmpDTO emp = new MyEmpDTO(rs.getString(1), rs.getString(2), rs.getString(3), 
            rs.getString(4), rs.getString(5), rs.getInt(6), rs.getString(7)); 
			list.add(emp);
		}
		System.out.print(list.size());
	} catch (SQLException e) {
		e.printStackTrace();
	}finally {
		DBUtil.close(rs, ptmt, con);
	}
	return list;
}

 

 

    1) MVC 패턴 : Model View Controller로 각 역할을 구분하고 분리해서 작업할 수 있도록 개발하는 패턴
                      : 서블릿, jsp를 이용해서 웹을 개발할때 각 역할별로 분리해서 작업.

Model View Controller
DAO Html Servlet

 


    2) 요청재지정 : MVC패턴 적용을 위한 설정.
                       : 최초로 요청된 web appliction파일(서블릿)이 실행된 후 요청받은 서블릿이 응답되지 않고

                         view파일(jsp)이 응답되도록 설정하는 것
                       : 서블릿에서 뷰를 분리.
        ① forward : servlet에서 사용
            1) 문법

RequestDisptcher rd =  request.getRequestDisptcher("요청 재지정할 application의 context명을 뺀 나머지 path");
rd.forward(request객체, response객체);
RequestDisptcher rd =  request.getRequestDisptcher("/basic/result.jsp");
rd.forward(request, response);

            2) 실행흐름
            - 클라이언트가 서블릿을 요청하는 경우 서블릿이 실행되고 forward로 지정한 web application이

            재요청되어 실행.
            - 이때 재지정되는 요청은 새로운 요청이 만들어지면서 요청되는 것이 아니라 서블릿 요청의 연장.
            - 한번의 요청으로 두개의 web application이 실행된다. (서블릿, jsp파일이 실행)

 

        ② include : jsp에서 사용

//servlet
out.print("머리말");
System.out.println("include연습  - include 서블릿 실행");
//1. 데이터 공유
MyEmpDTO user = new MyEmpDTO("003", "이이", null, "", "", 0, "");
request.setAttribute("myuser", user);
//2. 요청 재지정 - include
RequestDispatcher rd = request.getRequestDispatcher("/jspbasic/page.jsp");
rd.include(request, response);
out.print("꼬리말");

        => 머리말 + jsp 실행내용 + 꼬리말로 실행된다.

 

         - jsp

<jsp:include page="../top.jsp"></jsp:include>

 


    3) 데이터 공유
     - 한번의 요청으로 서블릿과 jsp가 실행되어 같은 request객체를 사용하기 때문에 데이터를 공유할 수 있다.
     - 같은 request를 사용

     - 서블릿에서 Request객체에 저장
     - jsp에서 Request객체에서 값을 가져옴
     - 공유되는 데이터를 attribute라한다.
     - 자바에서 사용할 수 있는 모든 객체를 공유할 수 있다.

     - http 프로토콜 특성으로 한번의 요청을 서버에서 처리하면서 저장한 값은 클라이언트에게 응답하는 순간

       메모리에서 없어진다. 즉 상태정보가 유지 되지않는다.

        ① 데이터 저장 : 서블릿에서 처리

request객체.setAttribute("저장할 attribute의 이름", 저장할 객체);
out.print("servlet 출력"); // forward 사용 시 실행은 되나 출력되지않음.
//1. 데이터 공유
MyEmpDTO user = new MyEmpDTO("003", "이이", null, "", "", 0, ""); // 공유할 객체
request.setAttribute("myuser", user); // 데이터 공유
//2. 요청 재지정 - forward
RequestDispatcher rd = request.getRequestDispatcher("/jspbasic/page.jsp");
rd.forward(request, response);

 

        ② 데이터 가져오기 : jsp에서 처리

Object객체 = (공유객체 타입)request객체.getAttribute("서블릿에서 저장한 attribute의 이름");
//공유 객체로 casting
<%
	MyEmpDTO user = (MyEmpDTO)request.getAttribute("myuser");
%>
<%= user.getName() %>

 

        ③ 데이터 지우기

removeAttribute("name");

 

 

 

    4) JSP : html에서 java code를 사용하기 위한 언어.
             : 이클립스 내부에서 java의 코드를 html문자열로 변환.

 

    * 서버로 인식하는 위치 (context)

    C:\Java\work\webwork\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\serverweb

 

    * jsp 경로

C:\Java\work\webwork\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\work\Catalina\localhost\serverweb\org\apache\jsp\jsp

    

    * jsp파일은 자동으로 하기와 같이 변환된다.

public void _jspInit() { ... }
public void _jspDestroy() { ... }
public void _jspService(final javax.servlet.http.HttpServletRequest request,
final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException { ... }

 

    [Servlet 동작] 
        1) 요청정보 추출 
        2) 비지니스 메소드 호출 
        3) 데이터를 공유 
        4) 요청재지정 
        5) 서블릿에서 공유한 데이터를 꺼내서 출력하기 [jsp] 

* html 파일 
모든 클라이언트에게 항상 고정된 동일한 화면만 서비스(정적 html문서) 

* jsp파일 
모든 클라이언트의 상황에 따라 다른 화면을 서비스할 수 있다.(동적 html)

 

 

    5) 스크립트 요소
        ① 스크립트릿 ( <% %>)

         - 자바코드를 사용할 수 있는 스크립트 요소.
         - 자바명령문을 정의할 수 있는 곳
         - ; 을 문자의 끝에 추가해야한다.
         - 자바와 동일하게 java.lang패키지는 자동으로 인식하지만 다른 패키지를 사용하는 경우 import한다. 

         - .jsp문서 내에서 선언되는 모든 지역변수를 사용할 수 있다.
         - jsp문서내 자바코드는 지양해야한다.
         - 자바코드는 서블릿이 공유하는 데이터를 꺼내서 출력하기 위한 코드만 정의해야한다.
         - jsp목적이 로직과 뷰를 위한 코드가 혼재되어 있는 부분을 없애기 위해서 만들어진 기술
         - 자바코드를 쓰지 않기 위해서 EL & JSTL(표준태그)

<% 
	// jsp문서에 작성하는 모든 태그나 코드의 작성은_jspService메소드 내부에 만들어진다. 
	out.println("<h2>hello</h2>"); // out 객체는 자동생성된 객체이므로 사용가능하다. 
%> 

        - 자동완성하여 객체 타입 설정시 자동 import된다.

<%@page import="basic.MyEmpDTO"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" import="java.util.Random, java.util.ArrayList"%>

        ② 표현식(<%= %>)

         - 기본형변수, 문자열을 반환하거나 해당 타입으로 선언된 변수를 출력.
          변수의 값을 출력하기 위해서 사용. out.print()메소드의 매개변수로 전달되므로 ;을 쓰지않는다.
           <%= 값 or 값을 리턴하는 메소드 호출문 or 연산식%>
          - 표현식은 jsp가 서블릿으로 변환될때 out.print() 메소드의 매개변수로 전달되는 코드
          - 표현식을 정의할때는 ;을 추가하지않는다. ;을 추가하면 out.print(값;);

          - 표현식은 서블릿에서 발생한 값을 웹페이지에 출력할 목적으로 사용하는 jsp스크립트 요소
          - 사용가능한 타입이 제한
          - 서블릿으로 변환될때 print메소드의 매개변수로 전달되기 때문에
          - 기본형, 스트링으로 변환될 수 있는 변수의 값, 메소드의 호출결과, 연산식등을 사용할 수 있다.

<%
	String str = "hello";
%>
<%= str %>
// out.print(str);로 자동변환된다.
<%= str; %>
// ;사용 시 out.print(str;);로 자동변환된다.

        ③ 선언문

         - 멤버를 선언하기 위해 사용.
         - jps문서의 멤버변수, 메소드를 정의하기 위해서 사용(jsp파일에서 java code를 최소화해야함으로 거의

         사용하지않는다)

<%! int num=100000; %>
<%! public void test(){
		System.out.println("test");
	}
%>


        ④ 지시자 - 컨테이너에게 넘겨줄 정보를 선언.


        ⑤ 주석문

<!-- HTML주석문(클라이언트에 전송) -->
<%-- jps주석문(jsp문법에 해당하는 코드를 주석으로 처리하는  용도 : 클라이언트에 전송 되지않는다. --%>
<%
	//	자바주석문
	/* 
		자바 여러줄 주석문 : 클라이언트에 전송 되지않는다.
	*/
%>

 

'BACK END > Servlet' 카테고리의 다른 글

[Servlet] Servlet 정리6 - EL, JSTL  (0) 2021.01.04
[Servlet] Servlet 정리5 - Ajax  (0) 2021.01.03
[Servlet] Servlet 정리4 - Cookie, Session  (0) 2021.01.02
[Servlet] Servlet 정리2 - JDBC  (0) 2020.12.28
[Servlet] Servlet 정리1  (0) 2020.12.28

[목차]

4. JDBC

    1) 오라클 드라이버 로딩 

    2) DB서버에 연결하기(Connection 설정)

    3) SQL문 실행을 담당하는 객체를 생성 

    4) SQL문 실행 

    5) 자원반납 

* DAO(Data Access Object)

* DBUtil

* DTO(Date To Object)

 

[내용]

[오라클에 접속해서 JBC를 사용하기 전에 해야할 일]

    1) 오라클 드라이버를 다운로드 받는다. 
    - 제조사 홈페이지를에서 다운로드 받는다 
    - 오라클 JDBC 위치 : 오라클 설치시 해당경로에 설치된다.(11g XE)

C:\oraclexe\app\oracle\product\11.2.0\server\jdbc\lib\ojdbc6.jar

    2) 이클립스 설정 
    ① [Package Explorer]창에서 [Project] 오른쪽 클릭 
    ② 오른쪽 클릭창 - [Build path] - [Configure Build patch] 
    ③ 대화상자에서 세번째 탭인 [Libaries] Tab 선택 
    ④ [Add External JARs] 선택 후 상기의 오라클 JDBC 위치의 [ojdbc6.jar ] 선택 -> [Apply]

 

 

4. JDBC  : 자바에서 DBMS 연동을 위한 표준 API(java에서 SQL을 실행하기 위해서 제공되는 표준 API) 
 - driver : 오라클회사에서 자바로 오라클을 접속하기 위해 내부에서 처리해야하는 기능을 구현해 놓은 클래스들을 라이브러리로 만들어 놓은것(ojdbc~.jar)

oracle.jdbc.driver OracleDriver.class

 - API를 이용해서 작업 
 - 자바 프로그램으로 insert, delete, update, select를 실행. 

 


    1) 오라클 드라이버 로딩 
    [오라클 드라이버명]

    oracle.jdc.driver.OracleDriver

 

    java.lang패키지에 Class라는 클래스를 이용해서 오라클 드라이버의 핵심 클래스를 메모리에 로딩 
    핵심클래스를 드라이버클래스라 하며 드라이버 클래스는 어떤 DBMS를 쓰느냐에 따라서 달라진다.

public static Class<?> forName(String className) throws ClassNotFoundException
Class.forName("패키지를 포함한 오라클 드라이버 클래스명");
Class.forName("oracle.jdc.driver.OracleDriver");

 

 

    2) DB서버에 연결하기(Connection 설정) 
    => java.sql패키지의 API를 이용 
    DriverManager의 getConnection메소드를 이용해서 DB서버에 연결.

public static Connection getConnection(String url, String user, String password) throws SQLException

    ① static메소드이므로 클래스이름으로 액세스 
    ② throws하고 있는 SQLException에 대한 처리 
    ③ 매개변수 
    url : 연결문자열(접속하기 위한 정보를 하나의 문자열로 만들어 놓은 것, 어떤 DBMS를 쓰느냐에 따라서 다른 

          현상의 문자열을 작성 - 제조사 홈페이지 참고)

    user : 사용자계정 (기본값 : scott) 
    password : 계정 패스워드

 

    [오라클 url]

jdbc:oracle:thin: @ip:port: 데이터베이스서비스명
프로토콜 DBMS가 설치되어있는 PC의 ip와 port 오라클 설치 시 셋팅하는 값으로 달라질 수 있다.(express버전은 xe)
jdbc:oracle:thin: @192.168.0.19:1521: xe

 

    ④ 리턴타입 
    java.sql.Connection이 리턴 
    DriverManager클래스의 getConnection메소드는 DB서버에 연결하고 연결정보를 객체로 만들어서 리턴한다. 
    매개변수에 어떤 DBMS를 사용하냐에 따라 다른 Connection객체의 오버라이딩 메소드가 실행됨.(다형성 적용)

 

    ⑤ 사용방법

Connection con = DriverManager.getConnection(url, user, password);
// oracle.jdbc.driver.T4CConnection 리턴

 

 

    3) SQL문 실행을 담당하는 객체를 생성 
    [상속구조]

Statement  : 정적SQL을 실행할 때 사용(보안취약 - SQL Injection공격 취약)
 
PrspareStatement  : 동적 SQL을 실행할 때 사용(secure coding에 적합 - 정부권고사항)
 
CallableStatement  : 각 DBMS에 특화된 SQL로 작성된 명령문을 실행 : 오라클 (PL-SQL)

    Statement객체 이용 
    Connection객체가 갖고 있는 createStatement메소드를 이용

    [형식]

Statement stmt = con.createStatement();
//stmt객체는 오라클 드라이버에 포함되어 있는 클래스 객체가 리턴
String sql = "select * from mydept where deptno='"+deptno+"' and deptname ='"+deptname+"'";

 

 * sql insaction

select * from mydept where deptno=002 -- and deptname='인사'; 
select * from mydept where deptno='' or '1'='1'-- 

   -- 주석문 뒤의 조건문이 다 맞지않아도 검색된다. 
    => Statement는 보안취약

 

    ② PreparedStatement객체 이용

    - Connection객체의 prepareStatement메소드를 이용해서 생성 
    - PreparedStatement객체를 만들때 미리 sql문을 파싱 후 외부에서 값만 입력받아서 매핑. 
    - Statement의 단점 보완(보안) 
    - 컬럼명은 입력값으로 처리하지 못한다. 
    - 외부에서 입력받아 처리해야하는값은 ?로 대신해서 sql문을 만든다. 
  
        1) sql문을 전달하여 PreparedStatement객체를 생성

String sql = "select * from mydept where deptno = ? and deptname = ?"; 
PrepaeredStatement ptmt = con.prepareStatement(sql); 


        2) ?에 값을 셋팅 
        외부에서 전달받은 값을 ?에 설정해야 sql문이 완성 
        PrepaeredStatement객체에 있는 set~~~메소드를 이용해서 ?에 값을 셋팅 
        set~~~메소드는 타입과 연결이 되는 메소드로 ResultSet의 get~~~메소드와 동일한 방법으로 해석

ptmt.setString(A,"B") // A : ?의 순서, B : ?에 셋팅할 값 
ptmt.setString(1,"002") // 첫번째 물음표에 문자열 "002"를 셋팅 한다.  
                        // (오라클 타입 : varchar2, char) 

 

 

    4) SQL문 실행 
    ① Statement를 사용 
        1) executeUpdate(sql) : insert, delete, update 명령문을 실행. 
        매개변수로 sql을 전달하면 실행결과로 몇개의 row가 반영되었는 지 리턴.

int result = stmt.executeUpdate(sql명령문);
// 몇개의 행이 삽입, 삭제, 수정되었는 지 리턴.

 

        2) executeQuery(sql) : select 명령문을 실행 
        실행한 후 조회된 테이블을 리턴, DBMS에서 조회된 테이블을 사용하기 위해 모델링된 자바의 객체가 ResultSet.

        실제로는 어떤 DBMS가 사용되었는지에 따라 다른 ResultSet객체가 리턴.

        - sql-plus프로그램을 이용해서 select문을 실행할때 결과로 보여지는 2차원 표의 데이터를 자바에서 이용할 수

        있도록 모델링한 클래스가 ResultSet.

        2-1) select문을 실행하면 ResultSet을 리턴하기 때문에 ResultSet타입의 변수를 선언해서 결과를 참조

ResultSet rs = stmt.executeQuery(sql명령문);

        2-2) ResultSet에 있는 테이블의 데이터를 읽기 위해서 ResultSet에서 제공하는 메소드를 이용해서 작업 
        Cursor를 다음 레코드로 이동하면서 레코드 개수만큼 반복작업을 실행. 
        ResultSet에 있는 next()를 호출하면 다음 레코드를 커서를 이동할 수 있다. next()는 커서를 이동했을 때 레코드가

        존재하면 true를 리턴하고 없으면 false를 리턴.

 

while(rs.next()){ // 레코드 개수만큼 실행
	// 레코드의 각 컬럼을 읽는다.
}

        2-3) 한 번에 하나의 칼럼만 읽을 수 있다. ResultSet의 get~~~메소드를 이용해서 칼럼값을 가져온다. 
        타입에 따라서 구분 
        - 오라클의 타입이 varchar2나 char인 경우 : java의 String

        getString(칼럼명) or getString(칼럼의 순서 index)

        칼럼의 순서 index : 원본 테이블에 정의된 칼럼의 순서가 아니라 조회된 테이블의 칼럼순서로 1부터 시작.

 

        - 오라클 타입이 number(정수) : java의 int 
        getInt(칼럼명) or getInt(칼럼index)

 

        - 오라클 타입이 date : java.sql.Date클래스

while(rs.next()){
// 레코드 개수만큼 실행.
// 커서를 하나씩 다음으로 이동.
// 다음 레코드가 있는 경우 true, 없으면 false리턴
	rs.getString("name"); => name컬럼으로 정의되어 있는 칼럼의 입력된 값을 읽어서 출력
	rs.getString(2); => 조회된 테이블의 2번째 칼럼의 입력된 데이터를 읽어서 출력
}
String url = "jdbc:oracle:thin:@127.0.0.1:1521:xe";
String user = "scott";
String password = "tiger";
String sql = "select * from mydept where deptno='"+deptno+"' and deptname ='"+deptname+"'";

try {
	//1. 드라이버 로딩
	Class.forName("oracle.jdbc.driver.OracleDriver");
	//2. DB연결
	Connection con = DriverManager.getConnection(url, user, password);
	//3. sql문법 객체생성
	Statement stmt = con.createStatement();
	//4. sql문 실행
	ResultSet rs = stmt.executeQuery(sql);
	ResultSetMetaData md= rs.getMetaData();
	int columCount = md.getColumnCount();
	System.out.println("칼럼 수 : "+columCount);
	while(rs.next()) {
		for(int i=1;i<=columCount;i++) {
			System.out.print(rs.getString(i)+"\t");
		}
		System.out.println();
	}
} catch (ClassNotFoundException e) {
	e.printStackTrace();
} catch (SQLException e) {
	e.printStackTrace();
}

 

    ② PrepaeredStatement

        1) excuteUpdate() : insert, delete, update 
        2) excuteQuery() : select 
         => 리턴유형, 실행, 처리 모두 Statement메소드와 동일하지만 sql을 매개변수로 전달하지않는다.

String url = "jdbc:oracle:thin:@127.0.0.1:1521:xe";
String user = "scott";
String password = "tiger";
String sql = "select * from mydept where deptno=? and deptname =?";
System.out.println(sql);
try {
	//1. 드라이버 로딩
	Class.forName("oracle.jdbc.driver.OracleDriver");
	//2. DB 연결
	Connection con = DriverManager.getConnection(url, user, password);
	//3. sql문법 객체생성
	PreparedStatement ptmt = con.prepareStatement(sql);
	//4. 외부에서 전달받을 값 설정
	ptmt.setString(1, deptno);
	ptmt.setString(2, deptname);
	//5. sql문 실행
	ResultSet rs = ptmt.executeQuery();
	
	ResultSetMetaData md= rs.getMetaData();
	int columCount = md.getColumnCount();
	
	while(rs.next()) {
		for(int i=1;i<=columCount;i++) {
			System.out.print(rs.getString(i)+"\t");
		}
		System.out.println();
	}
} catch (ClassNotFoundException e) {
	e.printStackTrace();
} catch (SQLException e) {
	e.printStackTrace();
}

 

* like 사용

String sql = "select * from mydept where loc like ?"; 
ptmt.setString(1, "%"+loc+"%");

 

    5) 자원반납 
    - 클라이언트가 점유해서 사용하던 자원을 반납해야한다.(메모리 해제) 
    - Connection, Statement, ResultSet 메모리해제. close메소드를 이용. 
    - 가장 마지막에 생성된 객체부터 메모리 해제한다.

String url = "jdbc:oracle:thin:@127.0.0.1:1521:xe";
String user = "scott";
String password = "tiger";
String sql = "select * from mydept where deptno=? and deptname =?";
Connection con = null;
PreparedStatement ptmt = null;
ResultSet rs = null;
System.out.println(sql);
try {
	Class.forName("oracle.jdbc.driver.OracleDriver");
	con = DriverManager.getConnection(url, user, password);
	ptmt = con.prepareStatement(sql);
	ptmt.setString(1, deptno);
	ptmt.setString(2, deptname);
	rs = ptmt.executeQuery();
	while (rs.next()) {
		System.out.print(rs.getString(1) + "\t");
		System.out.print(rs.getString(2) + "\t");
		System.out.print(rs.getString(3) + "\t");
		System.out.print(rs.getString(4) + "\t");
		System.out.print(rs.getString(5) + "\t");
	}
} catch (ClassNotFoundException e) {
	e.printStackTrace();
} catch (SQLException e) {
	e.printStackTrace();
} finally {
	try {
		if (con != null) con.close();
		if (ptmt != null) ptmt.close();
		if (rs != null) rs.close();
	} catch (SQLException e) {
		e.printStackTrace();
	}
}

 

* DAO(Data Access Object) : 동일한 테이블을 액세스하는 기능은 하나의 객체로 정의하고 사용

class 테이블명DAO{
	public void insert(){
	}
	public void update(){
	}
	public void delete(){
	}
	public void select(){
	}
}
public class MyDeptDAO {
	//insert
	public void insert(String deptno, String deptname, String loc, String tel, String mgr) {
		String sql = "insert into mydept values(?, ?, ?, ?, ?)";
		Connection con = null;
		PreparedStatement ptmt = null;
		try {
			con = DBUtil.getConnect();
			ptmt = con.prepareStatement(sql);
			ptmt.setString(1, deptno);
			ptmt.setString(2, deptname);
			ptmt.setString(3, loc);
			ptmt.setString(4, tel);
			ptmt.setString(5, mgr);
			int result =ptmt.executeUpdate();
			System.out.println(result+"개 행 삽입 성공");
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			DBUtil.close(null, ptmt, con);
		}
	}
	public void delete(String deptno) {
		String sql="delete from mydept where deptno=?";
		Connection con = null;
		PreparedStatement ptmt = null;
		try {
			con = DBUtil.getConnect();
			ptmt = con.prepareStatement(sql);
			ptmt.setString(1, deptno);
			int result = ptmt.executeUpdate();
			System.out.println(result+"개의 데이터가 삭제되었습니다.");
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			DBUtil.close(null, ptmt, con);
		}
	}
	public void select(String deptno, String deptname) {
		String sql = "select * from mydept where deptno=? and deptname =?";
		Connection con = null;
		PreparedStatement ptmt = null;
		ResultSet rs = null;
		try {
			con = DBUtil.getConnect();
			ptmt = con.prepareStatement(sql);
			
			ptmt.setString(1, deptno);
			ptmt.setString(2, deptname);
			
			rs = ptmt.executeQuery();
			
			ResultSetMetaData md= rs.getMetaData();
			int columCount = md.getColumnCount();
			
			while(rs.next()) {
				for(int i=1;i<=columCount;i++) {
					System.out.print(rs.getString(i)+"\t");
				}
				System.out.println();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			DBUtil.close(rs, ptmt, con);
		}
	}
	public void update(String deptno, String deptname) {
		StringBuffer sql=new StringBuffer();
		Connection con = null;
		PreparedStatement ptmt = null;
		sql.append("update mydept ");
		sql.append("set deptname=?");
		sql.append("where deptno=?");
		try {
			con = DBUtil.getConnect();
			ptmt = con.prepareStatement(sql.toString());
			ptmt.setString(1, deptname);
			ptmt.setString(2, deptno);
			int result = ptmt.executeUpdate();
			System.out.println(result+"개 행이 업데이트 되었습니다.");
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			DBUtil.close(null, ptmt, con);
		}
	}
}

 

* DBUtil : DB연동과 관련된 기능을 유틸리티처럼 제공하는 클래스 
    1) Driver Loading 
    2) DB서버 연결 
    3) 자원반납 
    => Utility처럼 사용할 것으로 static으로 구현

public class DBUtil {
		// 1. 드라이버 로딩
		// => 메소드마다 드라이버를 로딩하는 작업을 구현하지않고 클래스 로더가 클래스를
		// 로딩할때 한번만 실행되도록 하기 위해서
		// static 블럭안에 드라이버 로딩 코드를 작성한다.
		static {
			try {
				Class.forName("oracle.jdbc.driver.OracleDriver");
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
		}
		// 2. DB서버 연결
		// SQL문을 실행할때마다 연결을 해야한다.
		public static Connection getConnect(){
			Connection con = null;
			String url = "jdbc:oracle:thin:@127.0.0.1:1521:xe";
			String user = "scott";
			String password = "tiger";
			try {
				con = DriverManager.getConnection(url, user, password);
			} catch (SQLException e) {
				e.printStackTrace();
			}
			return con;
		}
		// 3. 자원반납
		public static void close(ResultSet rs, Statement stmt, Connection con) {
			try {
				if(rs != null) rs.close();
				if(stmt != null) stmt.close();
				if(con != null) con.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}
		// 4. Connection, Statement, ResultSet을 반납하는 메소드 각각 작성가능.
	}

 

* DTO(Date To Object) : Data를 객체로 변환. 테이블의 row로 객체를 생성 (테이블명+VO  or 테이블명+DTO)

class 테이블명DTO{
	변수
	
	생성자()
	
	toString()
	
	getter/setter()
}
public class MyDeptDTO {
	private String deptno;
	private String deptname;
	private String loc;
	private String tel;
	private String mgr;
	public MyDeptDTO() {
		
	}
	public MyDeptDTO(String deptno, String deptname, String loc, String tel, String mgr) {
		super();
		this.deptno = deptno;
		this.deptname = deptname;
		this.loc = loc;
		this.tel = tel;
		this.mgr = mgr;
	}
	@Override
	public String toString() {
		return "MyDeptDTO [deptno=" + deptno + ", deptname=" + deptname
		+ ", loc=" + loc + ", tel=" + tel + ", mgr="+ mgr + "]";
	}
	public String getDeptno() {
		return deptno;
	}
	public void setDeptno(String deptno) {
		this.deptno = deptno;
	}
	public String getDeptname() {
		return deptname;
	}
	public void setDeptname(String deptname) {
		this.deptname = deptname;
	}
	public String getLoc() {
		return loc;
	}
	public void setLoc(String loc) {
		this.loc = loc;
	}
	public String getTel() {
		return tel;
	}
	public void setTel(String tel) {
		this.tel = tel;
	}
	public String getMgr() {
		return mgr;
	}
	public void setMgr(String mgr) {
		this.mgr = mgr;
	}
}
@WebServlet(name = "deptInsert", urlPatterns = { "/dept/Insert.do" })
public class DeptInsertServlet extends HttpServlet {
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
							throws ServletException, IOException {
		System.out.println("서블릿 요청");
		request.setCharacterEncoding("UTF-8");
		response.setContentType("text/html;charset=UTF-8");
		
		//1. 사용자가 입력한 값을 추출
		PrintWriter out = response.getWriter();
		String deptno = request.getParameter("deptno");
		String deptname = request.getParameter("deptname");
		String loc = request.getParameter("loc");
		String tel = request.getParameter("tel");
		String mgr = request.getParameter("mgr");
		
		//2. 비지니스 메소드 호출
		MyDeptDAO dao = new MyDeptDAO();
		MyDeptDTO dept = new MyDeptDTO(deptno, deptname, loc, tel, mgr);
		System.out.println("servelt => "+dept);
		int result = dao.insert(dept);
		//int result = dao.insert(deptno, deptname, loc, tel, mgr);
		
		//3. 결과값 출력
		String msg = "";
		if(result>0) {
			msg = result+"개 행 삽입 성공";
		}else {
			msg = "삽입 실패("+result+")";
		}
		out.println("<h1>"+msg+"</h1>");
	}
}
[html] request
--------->
<--------
response
[Servlet]
요청정보추출
비지니스 메소드 call
결과처리
[DAO]
sql처리
insert(),
update(),
delete(), select()
[DBUtil]
드라이버로딩
Connection생성
자원반납

[DBMS]
  [DTO]
변수
생성자
getter/setter
toString()
 

 

[목차]

1. 서블릿 작성 규칙 

2. 서블릿 요청방법(서블릿 실행방법) 

3. 서블릿 요청정보 추출

4. JDBC

 

[내용]

서블릿
 - 클라이언트의 요청을 처리하기 위한 기술
 - 클라이언트가 요청하면 서버에서 실행되며 DB에 대한 처리, 서버의 리소스를 이용해서 만들어진 결과를 클라이언트에 응답한다.
 - 서버에 의해서 호출되기 때문에 서버가 인식하는 위치에 있어야 하며 서버가 찾아서 실행할 수 있도록 정해진 규칙에 따라 작성되어야한다.
(Context/WEB_INF/classes폴더)

 

 

1. 서블릿 작성 규칙
    1) 표준화된 폴더 구조 안에 서블릿 클래스가 위치해야한다.
    서블릿이 저장될 폴더 - classes폴더(서블릿 디렉토리)

    [표준화된 폴더 구조]

Context WEB_INF web.xml
    lib
    classes
  html, image, css, jsp  

   => classes 폴더에 서블릿이 없으면 서버가 찾을 수 없다.  (매핑 시엔 가능)

    2) 서버에 의해서 호출될 것이므로 반드시 public으로 작성해야한다.


    3) 서블릿 클래스가 되기 위해서 무조건 서블릿 클래스를 상속받아야한다.

Servlet(interface)   
 
Generic Servlet(abstact class) 서블릿의 일반적인 내용이 정의된 서블릿 클래스. 
destory(), init(), service() 
HttpServlet(abstact class) http프로토콜에 특화된 내용이 정의된 서블릿 클래스.
service(), do~~() 
사용자 정의 Servlet  

 

    4) 서버가 내부에서 호출할 메소드를 오버라이딩
    - 서버가 자동으로 호출하는 메소드를 call back메소드
    - 클라이언트가 요청을 하면 서버가 요청을 분석해서 서블릿 디렉토리에 존재하는 (미리 만들어서 저장해놓은)
    서블릿 클래스를 찾아서 적절한 상황에 해당 메소드를 자동으로 호출할 것이므로 그 상황에 맞게처리하고 
     싶은 내용을 각 메소드를 오버라이딩해서 구현한다.
    - 서버가 서블릿의 life cycle을 관리(객체가 생성돠고 객체를 메모리에서 해제하는 모든 작업)
    - 오버라이딩할 메소드는 life cycle과 연관되어 있는 메소드

 

    [오버라이딩할 메소드]
     - init() : 서블릿 객체가 초기화될때 호출되는 메소드.
     - service() : 클라이언트가 요청할때마다 호출되는 메소드
      => 클라이언트의 요청을 처리하는 메소드로 요청을 받고 처리할 내용을 구현.
      ex) 로그인, 게시판 목록보기, 메일읽기, 장바구니 조회, 구매, 예약, 예약정보 확인...

    doGet() : 클라이언트가 get방식으로 요청할때 호출되는 메소드.
    doPost() : 클라이언트가 post방식으로 요청할때 호출되는 메소드.
    destory() : 서블릿 객체가 소멸될때 호출되는 메소드.


    [객체 소멸 case]
    - 서블릿 클래스가 컴파일될 경우
    - WAS가 재부팅될 경우
    - context가 reload될 경우

 

* WAS 처리 동작

실행하려는 서블릿 객체가 메모리에 Loading되어 있는지 확인
(클라이언트 개수와 상관없이 한 서블릿당 1 객체로 운영)
---------------------------------------->
No : 서블릿 객체생성 ->init() -> 
쓰레드 생성 -> 응답, 요청객체 생성
service() -> doGet() or doPost() ->
비지니스 로직
----------------------------------------->
Yes

 

    5) 서블릿을 등록
     - 서버가 요청을 분석해서 서블릿 디렉토리에서 서블릿을 찾아서 실행할 수 있도록 등록.
     - 설정파일에 등록(web.xml)

     - 실제 작업은 anotation으로 설정.(servlet 3.0이상)

     - web.xml파일은 xml형식의 파일이며, 태그로 작성하며, 작성규칙(DTD - xml안에서 정의할 엘리먼트(태그)의 순서

     정의해야하는 필수 엘리먼트, 속성 등이 명시되어 있는 파일)에 따라 정확하게 등록해야한다.

        서블릿 클래스 등록
         => 무엇을

<servlet>
	<servlet-name>서블릿명(alias)</servlet-name>
	<servlet-class>서블릿클래스의 실제 경로(패키지를 포함한 서블릿클래스)</servlet-class>
</servlet>

 

ex) basic패키지에 작성한 FisrtServlet을 first라는 서블릿명으로 등록.

<servlet>
	<servlet-name>first</servlet-name>
	<servlet-class>basic.FisrtServlet</servlet-class>
</servlet>

 

        ② 서블릿 매핑
         => 어떻게
         => 등록된 서블릿을 어떻게 요청할 것인지 등록(어떤 url로 요청할 것인지)
         => 반드시<servlet>엘리먼트 다음에 위치해야한다. 즉 <servlet>엘리먼트와 함께 한 쌍으로 정의해야한다.
         => 위에서 등록한 서블릿을 어떻게 요청할 것인지 등록하는 엘리먼트

<servlet-mapping>
	<servlet-name>위에서 정의한 서블릿의 이름</servlet-name>
	<url-patten>요청할 서블릿의 path</url-patten>
           (반드시 /나 .으로 시작해야한다)
</servlet-mapping>

ex) 위에서 fisrt라는 이름으로 등록한 서블릿을 first.do

<servlet-mapping>
	<servlet-name>first</servlet-name>
	<url-pattern>/first.do</url-pattern>
</servlet-mapping>

 

        ③ @어노테이션 이용 서블릿 매핑하기

 Project Explorer창에서 Project 오른쪽 클릭 -> New -> Servlet -> Class name입력 -> Name(alias) 입력 ->
 URL mapping 입력 -> 오버라이딩할 메소드 or 생성자 선택

@WebServlet(name = "alias", urlPatterns = { "/URL" })
public class PostFormServlet2 extends HttpServlet {
	protected void doPost(HttpServletRequest request, HttpServletResponse response) 
                                             throws ServletException, IOException {
	}
}

 

2. 서블릿 요청방법(서블릿 실행방법)
    [일반 html문서]
    => http://서버ip:port/context명/정적파일명
       (프로토콜)

 

    [서블릿]
    => http://서버ip:port/context명/서블릿매핑명(web.xml <url-patten>에 등록한 path)

        

    1) get방식으로 요청
    => 클라이언트가 입력한 내용을 요청헤더에 저장하여 서버로 전송하는 방식 (255Byte미만)

    => 외부에 노출되어도 상관없는 데이터 송부시 사용.

    => 인코딩/디코딩 작업이 필요없어 처리속도가 빠름.

    => name1=value1&name2=value2,   공백은 +, %16진수로 전달.(영문, 숫자, 일부 특수문자 제외), ?뒤에 Query 

         String입력하여 전달가능.


        ① 주소표시줄에 입력해서 요청하는 방식
         => 테스트용으로 사용되거나 첫 번째 페이지에서 요청하는 경우


        ② 하이퍼링크로 요청  => 텍스트나 이미지를 클릭해서 서블릿을 요청

<a href="http://서버ip:port/context명/서블릿매핑명">서블릿 요청</a> 
<a href="/context명/서블릿 요청url">서블릿 요청</a> 
<a href="/serverweb/서블릿 매핑명">서블릿 요청</a>


        ③ <form>태그의 method속성을 get으로 정의하고 submit버튼을 눌러서 요청하는 경우
         => method속성을 생략하면 get방식(default)

<form action="요청할 web application파일의 path" method="get">
	<input type="text" name="id" />
	<input type="password" name="pass">
	<input type="submit" value="서블릿요청">
</form>

        => submit버튼을 누르면 <form></form>태그 사이에 정의된 모든 양식 태그의 namevalueaction속성

            정의된 서블릿에 요청(실행)하며 등록된 서블릿에게 method속성 요청방식(get)으로 전송한다.

 

    2) post방식으로 요청
        ① <form>태그의 method속성을 post로 정의하고 submit버튼을 눌러서 요청하는 경우

<form action="요청할 web application파일의 path" method="post">
	<input type="text" name="id" />
	<input type="password" name="pass">
	<input type="submit" value="서블릿요청">
</form>

        => submit버튼을 누르면 <form></form>태그 사이에 정의된 모든 양식 태그의 name과 value가 action속성에

             정의된 서블릿으로 요청(실행)하며 등록된 서블릿에게 method속성 요청방식(post) 방식으로 전송한다.

 

 

3. 서블릿 요청정보 추출

public class 서블릿 클래스명 extends HttpServlet{
	public 서블릿 클래스명() { // 생성자
	}
    
	public void init() { // 생성자 호출 후 한번만 호출
	}
	
	public void service(HttpServletRequest req, HttpServletResponse res) 
	throws ServletException, IOException{ 
	// 상위클래스의 service 메소드에서 메소드 요청방식에 따라 doGet,doPost를 자동으로 호출함으로
	// 오버라이딩할 경우 사용자에 맞게 doGet(), doPost()를 연결하여야 한다.
		if(req.getMethod().equals("GET")) {
			doGet(req,res);
		}else {
			doPost(req,res);
		}
	}
	
	public void doGet(HttpServletRequest req, HttpServletResponse res)
	throws ServletException, IOException{
	}
	
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
	throws ServletException, IOException {	
		req.setCharacterEncoding("UTF-8"); //요청정보에 문자셋을 적용하여 한글을 셋팅
		resp.setContentType("text/html;charset=UTF-8");
		//text/html; : MIME타입(응답형식), charset=UTF-8 : 응답데이터에 적용할 문자셋
		
		//응답정보를 클라이언트로 전송하기 위한 스트림객체를 response에서 구하기
		PrintWriter out = resp.getWriter();
		//요청정보를 추출
		String id = req.getParameter("id"); // name(key)으로 값(value) 추출
		String pass = req.getParameter("pass");
		String[] item = req.getParameterValues("item"); // value가 여러개일 경우 배열로 받는다.
	}
    
	public void destroy() {//객체 소멸시 호출.
	}
}

    1) setCharacterEncoding("UTF-8") : 요청정보에 문자셋을 적용하여 한글을 셋팅
    2) setContentType("text/html;charset=UTF-8") :
         text/html; : MIME타입(응답형식)

         charset=UTF-8 : 응답데이터에 적용할 문자셋


    3) PrintWriter out = resp.getWriter() : 응답정보를 클라이언트로 전송하기 위한 스트림객체를 response에서 구하기 
    4) 요청정보를 추출
      String id = req.getParameter("name") : name(key)으로 값(value) 추출
      String[] item = req.getParameterValues("name") : value가 여러개일 경우 배열로 받는다.

 

    5) String str = req.getQueryString() : get방식에서만 사용가능하며, 요청정보의 ? 다음 문자열 전체를 받아온다.

    6) ServletInputstream in= req.getInputStream() : post방식에서 사용. 요청정보의 몸체와 연결된 입력스트림을

        받아온다.

ServletInputstream in= req.getInputStream();
int len = req.getContextLength();
byte[] buffer = new byte[len];
in.readLine(buffer,0,len);
String str = new String(buffer);

 

 

 

<tip>

* 웹구조

Web browser
(client)
request
(header+body)
--------------->

<---------------
response
WAS
(Web Server 
+ Contationer)
--------------->
<---------------
Servlet 서버의 자원
--------------->
<---------------

DBMS

 

 

* 비지니스 로직 분리

                   Servlet
1. 클라이언트의 요청정보를 추출
2. 비지니스 메소드 호출
3. 클라이언트에 응답할 메시지를 생성
매개변수
--------------->

<---------------
리턴값
비지니스 로직

 

* import가 되지않을때

 

Project Explorer창 - Dynamic 파일 오른쪽 클릭 - Build Patch - Configure Build Patch  -Libraries - Add library - Server Run time - Next - finish - Apply 



* 이클립스 창 확대 단축키 : ctrl + M

* error
404 - 파일을 찾을 수 없다.
405 - 요청한 방식의 메소드가 없을 경우

 

[목차]

10. DDL

11. DML

12. 제약조건

13. Sequence

 

[내용]

10. DDL(Date Definition Language) : 테이블 생성, 수정, 삭제, 자동 commit

    1) 테이블 생성 

create table 테이블명(
     칼럼명 데이터 타입(크기)
      ....            );
create table board( 
no number, 
id varchar2(20), 
title varchar2(20), 
content varchar2(2), 
hit number, 
regdate date);
create table myemp(
empno char(5), ename varchar2(10), hiredate date, sal number(10), memo varchar2(10));

 

    2) 테이블 변경 - 추가

alter table 테이블명
add (칼럼명 데이터타입(크기));
alter table board
add (email varchar2(20));

 

 

    3) 테이블 변경 - 수정

alter table 테이블명
modify (칼럼명 데이터타입(크기));

 

alter table board
modify (content varchar2(20));

 

    4) 테이블 삭제

drop table 테이블명;
drop table emp2;


  
11. DML(Data Manipulation Language) : 데이터 조작어

    1) insert into : data 추가

insert into 테이블명
values(값,...);
insert into board values(1,'jang','test','test1',0,sysdate,null);

insert into board values(2,'kim','title','ccocnocnco',0,sysdate,'kwdd@naver.com');

insert into board values(6,'choi','oracle','안녕하세요?????',0,sysdate, null);
insert into myemp values('00001', 'scott', sysdate, 3000,'신입');

     - 선택 칼럼의 데이터만 입력하기

insert into emp (empno, ename, hiredate) values(1111,'이이이',sysdate);
insert into emp (empno, ename, hiredate, deptno) values(7777,'율곡', sysdate, 100);


    2) update

update 테이블
set
where
update board
set title ='oracle'
where no=1;
update board
set title='oracle', hit=hit+1
where no=4;

 

    - set절 서브쿼리 이용하여 조건에 맞는 값 update

update myemp
set sal=(select sal
         from emp
         where empno=7934)
where empno=7369;

 

update myemp
set sal=(select avg(sal)
		from emp
		where mgr=7698)
where ename is null;
update myemp
set sal =sal+300
where sal<(select avg(sal)
           from emp
           where mgr=7698);
-> where절 서브쿼리 이용 조건에 맞는 값 update

 


    3) delete

delete (into) from 테이블명
where
delete from board
where no=5;
delete board
where id is null;

    - where절 서브쿼리 이용 조건에 맞는 값 delete

delete from myemp
where sal>(select avg(sal)
           from myemp);

 

    4) 삽입된 데이터 저장하기

commit;

 


12. 제약조건

    - 테이블 생성시 제약조건 추가

create table 테이블명(
칼럼명 데이터타입(크기) 제약조건,
  ....                 );
create table emp2(id varchar2(10) primary key,
                  name varchar2(10) not null,
                  pass varchar2(10));
create table emp2(
    empno number(5),
    ename varchar2(10) not null,
    deptno varchar2(10),
    sal number,
    tel varchar2(10),
    job varchar2(10),
    constraints emp2_empno_pk primary key(empno));


    - 테이블에 적용된 제약 조건 확인

desc user_contraints
select OWNER,CONSTRAINT_NAME, CONSTRAINT_TYPE, TABLE_NAME
from user_constraints;
OWNER
---------------------------------------------------------------------------------------------------------------------
CONSTRAINT_NAME                                              CO TABLE_NAME
------------------------------------------------------------ -- -----------------------------------------------------
SCOTT
SYS_C006997                                                  P  EMP

SCOTT
SYS_C007004                                                  C  EMP2

SCOTT
BOARD_ID_PK                                                  P  BOARD

SCOTT
EMP2_ID_FK                                                   R  EMP2

SCOTT
EMP2_SAL_CK                                                  C  EMP2

SCOTT
SYS_C007013                                                  P  DEPT2

SCOTT
EMP2_JOB_CK                                                  C  EMP2

     - 제약 조건 변경 (primary key)

alter table board
add constraint board_no_pk primary key(no);

 

     - 제약 조건 변경 (unique key)

alter table emp2
add constraint emp2_tel_uk unique(tel);

 

     - 제약 조건 변경 (check)

alter table 테이블
add constraint 제약조건명 check(조건);
alter table emp2
add constraint emp2_sal_ck check(sal between 5000 and 7000);

alter table emp2
add constraint emp2_job_ck check(job in('developer', 'siger', 'teacher'));

 

     - 제약 조건 변경 (foreign key)

alter table 테이블명
add constraiont 제약조건명 foreign key(칼럼) references 테이블명2(칼럼2);
                        primary key(칼럼);
alter table emp2
add constraint emp2_deptno_fk foreign key(deptno) references dept2(decode);
alter table emp2
add constraint emp2_id_fk foreign key(id) references board(id);

 

    - 제약조건 삭제

alter table emp2
drop constraint emp2_empno_pk;

 

 

13. Sequence
    - 시퀀스 생성

create sequence 시퀀스명;
create sequence board_seq;

 

    - 시퀀스 시작값 설정

create sequence tb_order_seq
start with 2020111100;

    - 현재 시퀀스 확인.

select 시퀀스명.currval form dual;
select tb_order_seq.currval from dual;
->현재 sequence 확인.

    - 다음 시퀀스

select board_seq.nextval from dual;
insert into board(no, title,regdate,hit)
            values(board_seq.nextval, 'text', sysdate,0);

 

14. on delete cascade :  미사용 권장

   - on delete cascade추가하여 foreign 제약조건 추가.

alter table tb_order
add constraint order_fk foreign key(id) references tb_customer(id) on delete cascade;

 

- on delete cascade foreign키 삭제 시 error 발생

drop table tb_customer;

- on delete cascade constraint 삭제

drop table tb_customer cascade constraints;
alter table tb_order
add constraint id_notnull not null(id);
-> error

alter table tb_order
modify id varchar2(10) not null;
-> not null 조건 추가
create table myemp
as
select empno, ename,sal, mgr, hiredate
from emp
where 1=1;
-> 테이블 생성
-> 데이터 들어감

create table myemp2
as
select empno, ename,sal, mgr, hiredate
from emp
where 1=2;
-> 테이블 생성
-> 데이터 안들어감
insert all
     into myemp values(7777,'aaaaa',1000,7475,sysdate)
     into myemp2 values(7777,'aaaaa',1000,7475,sysdate)
select * from dual;
-> myemp, myemp2에 date insert
insert all
     into myemp2 values(1111,'bbbb',1000,7475,sysdate)
     into myemp2 values(2222,'ccccc',1000,7475,sysdate)
select * from dual;
-> myemp2에 2개 date insert

   - Data Dictionary : 읽기전용
   - rollback;

   - 모든 테이블 삭제

SELECT 'DROP TABLE "' || TABLE_NAME || '" CASCADE CONSTRAINTS;' FROM user_tables;

9. 서브쿼리(subquery) : 여러개의 select 문장을 하나로 합쳐있는것
 1) 서브쿼리
  - select문에 삽입된 select문, sql문에 삽입된 다른 sql문
  - select문에만 사용되지않고 insert, update, delete, select문 모두 사용가능
  - 바깥쪽의 쿼리를 메인쿼리 or 기본쿼리라 한다.
  - sql문에 삽입된 쿼리를 서브쿼리라 하며 반드시 괄호로 묶어 주어야한다.
  - 서브쿼리가 메인쿼리 실행전에 한번 싱행된다.
  - 서브쿼리의 결과가 메인쿼리에서 실행된다.
  - select문에서는 select, from, where, having절 모두에서 삽입가능.
  
 2) 서브쿼리의 종류
     ① 단일행 서브쿼리 : 서브쿼리의 실행결과가 행하나, 열 하나로 리턴되는 것, 메인쿼리에서 비교할 때 = 연산자를

      이용하는 것이 가능

select ename, sal, hiredate, deptno
from emp
where sal>=(select max(sal)
            from emp
            where deptno=20);
select *
from emp
where job=(select job
           from emp
           where ename='SMITH');
select ename, deptno, sal
from emp
where sal>(select max(sal)
           from emp
           where deptno=20);
select employee_id, first_name||' '||last_name name, hire_date
from employees
where hire_date like '05%'
       and hire_date < (select hire_date
       			from employees
       			where first_name = 'Lisa');

	   
or
where to(hire_date,'YYYY')='2005'
select e.first_name, e.salary, d.department_name
from employees e, departments d
where e.department_id = d.department_id
      and d.department_name = 'Sales'
	  and salary < (select avg(salary)
	                 from employees
	                 where department_id=100
	                 group by department_id);
select m.employee_id, m.last_name, m.hire_date, m.salary
from employees e, employees m
where e.last_name = 'De Haan'
      and e.manager_id = m.employee_id;
	  
	  
select employee_id, last_name, hire_date, salary
from employees
where e.last_name = (select manager_id
                     from employees
                     where last_name = 'De Haan');
select d.department_name, avg(e.salary)
from employees e, departments d
where e.department_id = d.department_id
group by d.department_name
having avg(e.salary) <= (select avg(salary)
	                     from employees
	                     where department_id = 30
	                     group by department_id);

 

     ② 다중행 서브쿼리 : 서브쿼리의 실행결과가 열은 하나지만 행이 여러개 반환되는 것. = 연산자를 이용할 수 없다.
         1) in 연산자

select ename, sal, deptno
from emp
where sal in(select sal
             from emp
             where job='MANAGER');
select *
from emp
where deptno in (select deptno
              from emp
              where job='MANAGER');
select ename, empno
from emp
where deptno in (select deptno
                from emp
                where ename like '%T%');
select *
from emp
where sal in (select min(sal)
             from emp
              group by deptno);

         2) all 연산자 : 모두 만족해야한다.
         >all(서브쿼리) : 서브쿼리의 모든 값보다 커야함. 서브쿼리의 최대값보다 큰값.

select ename, sal, deptno
from emp
where sal >all(select sal
             from emp
             where job='MANAGER')
order by sal;

         <all(서브쿼리) : 서브쿼리의 최소값보다 작은 값.

select ename, sal, deptno
from emp
where sal <all(select sal
             from emp
             where job='MANAGER')
order by sal;


   
         3) any : 결과 값 중 한개만 만족하면 됨.
         >any(서브쿼리) : 서브쿼리의 어느값중 하나만 만족하면 됨. 서브쿼리의 최소값보다 큰 값.

select ename, sal, deptno
from emp
where sal >any (select sal
             from emp
             where job='MANAGER')
order by sal;


         <any(서브쿼리) : 서브쿼리의 최대값보다 작은 값.

select ename, sal, deptno
from emp
where sal <any (select sal
             from emp
             where job='MANAGER')
order by sal;


     ③ 다중 열(컬럼) 서브쿼리 : 서브쿼리의 칼럼을 다수로 가져가 비교

select *
from emp
where (deptno, sal) in (select deptno, min(sal)
             from emp
              group by deptno);
select employee_id, last_name, salary, department_id
from employees
where (department_id, salary) in (select department_id, max(salary)
                 from employees
                 group by department_id)
order by salary desc

     => deptno도 같아야 할 경우

     => 칼럼 수가 하나면 deptno가 달라도 조회된다.


     ④ 상호연관 서브쿼리
     - 메인쿼리의 칼럼을 서브쿼리에서 사용해야하는 경우.
     - 메인쿼리의 row가 어떤 칼럼값을 가지고 있느냐에 따라서 서브쿼리의 결과가 달라진다.
     [실행순서]
     1) 메인쿼리에서 현재 작업중인 row의 칼럼값을 가져온다.
     2) 메인쿼리에서 가져온 값을 이용해서 서브쿼리를 진행.
     3) 서브쿼리에서 실행한 결과를 다시 메인쿼리로 전달 후 메인쿼리를 실행.
     4) 메인쿼리에서 사용하는 테이블의 전체 row에 대해서 1~3번까지의 작업을 반복수행.

select ename, sal, deptno
from emp main
where sal > (select avg(sal)
from emp e
where e.deptno = main.deptno);

    ⑤ View

    - view생성 권한부여

conn system/manager
grant create view to scott;

    - view생성

create view myempview
as
select d.dname, e.ename, e.sal, e.hiredate
from emp e, dept d
where e.deptno= d.deptno;

 

    - view생성시에는 컬럼에 alias가 꼭 필요.

create view maxsaldata
as
select deptno, max(sal) maxsal
from emp
group by deptno;
create view avgsal
as
select deptno, avg(sal) 평균급여
from emp
group by deptno;

 

    - view 사용

select e.deptno, e.empno, e.ename, e.sal, s.평균급여
from emp e, avgsal s
where e.deptno=s.deptno(+);


    ⑥ inline view
     - from절에 정의하고 사용하는 서브쿼리.
     - 서브쿼리를 이용해서 from절에서 사용할 가상의 테이블을 정의할 수 있는 데, 이를 inline view라 한다.
     - 하나의 테이블에 데이터가 많이 있는 경우 from정에 정의하면 비효율적일 수 있으므로 필요한 행과 열만

        from절에서 사용할 수 있도록 한다.
     [정의방법]

select
from (select
      from
      where
      group by
      having      )alias
select e.deptno, e.empno, e.ename, e.sal, avgt.avgsal
from emp e, (select deptno, avg(sal) avgsal
             from emp
             group by deptno) avgt
where e.deptno = avgt.deptno and
      e.sal>avgt.avgsal;

     => from절에 삽입되는 서브쿼리를 사용하는 경우 반드시 서브쿼리 뒤에 alias를 정의해야한다.(테이블명으로 사용)

          서브쿼리안에서도 계산의 결과로 만들어지는 칼럼은 반드시 alias를 정의해야한다.(칼럼명으로 사용)
 

    ⑦ ton-n 서브쿼리
    - row num을 활용해서 순위와 연관있는 서브쿼리.
  

    - rownum사용

select rownum, ename, sal
from emp;
select 월, 입사자수
from (select substr(hire_date,4,2) 월, count(*) 입사자수
      from employees
      group by substr(hire_date,4,2)
      order by 입사자수 desc)
where rownum<4
order by 월;


select to_char(hire_date,'MM') 월, count(employee_id) 입사자수
from employees
group by to_char(hire_date,'MM')
order by 입사자수 desc
select first_name, salary, department_name
from (select e.first_name, e.salary, d.department_name
from employees e, departments d
where department_name = 'IT'
       and e.department_id = d.department_id
order by salary desc)
where rownum<4;
select rownum, ename, sal
from emp
where rownum<4
order by sal desc;

    ->원하는 결과 X

 

select rownum, ename, sal
from (select *
      from emp
      order by sal desc)
where rownum <4;

    ->원하는 결과 O

 

    1) row_number() over (order by '순위 기준 칼럼' desc) 
     -> 동률자 순차적 순번

select row_number() over (order by sal desc) 순위, ename, sal, deptno
from emp;
      순위 ENAME                       SAL     DEPTNO
---------- -------------------- ---------- ----------
         1 KING                       5000         10
         2 FORD                       3000         20
         3 SCOTT                      3000         20
         4 JONES                      2975         20
         5 BLAKE                      2850         30
         6 CLARK                      2450         10
         7 ALLEN                      1600         30
         8 TURNER                     1500         30
         9 MILLER                     1300         10
        10 ADAMS                      1300         20
        11 WARD                       1250         30
        12 MARTIN                     1250         30
        13 JAMES                       950         30
        14 SMITH                       800         20
        15 율곡                        500         90
        16 이이이                      500

 

    2) rank() over (order by '순위 기준 칼럼' desc)

    -> 동률자 같은 순번 + 다음 순서 동률자 계산O

select rank() over (order by sal desc) 순위, ename, sal, deptno
from emp; 
     순위 ENAME                       SAL     DEPTNO
--------- -------------------- ---------- ----------
        1 KING                       5000         10
        2 FORD                       3000         20
        2 SCOTT                      3000         20
        4 JONES                      2975         20
        5 BLAKE                      2850         30
        6 CLARK                      2450         10
        7 ALLEN                      1600         30
        8 TURNER                     1500         30
        9 MILLER                     1300         10
        9 ADAMS                      1300         20
       11 WARD                       1250         30
       11 MARTIN                     1250         30
       13 JAMES                       950         30
       14 SMITH                       800         20
       15 율곡                        500         90
       15 이이이                      500

    

    3) dense_rank() over (order by '순위 기준 칼럼' desc) 
    -> 동률자 같은 순번 + 다음 순서 동률자 계산

select dense_rank() over (order by sal desc) 순위, ename, sal, deptno
from emp; 
      순위 ENAME                       SAL     DEPTNO
---------- -------------------- ---------- ----------
         1 KING                       5000         10
         2 FORD                       3000         20
         2 SCOTT                      3000         20
         3 JONES                      2975         20
         4 BLAKE                      2850         30
         5 CLARK                      2450         10
         6 ALLEN                      1600         30
         7 TURNER                     1500         30
         8 MILLER                     1300         10
         8 ADAMS                      1300         20
         9 WARD                       1250         30
         9 MARTIN                     1250         30
        10 JAMES                       950         30
        11 SMITH                       800         20
        12 율곡                        500         90
        12 이이이                      500

 

    4) ntile('그룹 갯수') over (order by '순위 기준 칼럼' desc) 
     -> 그룹갯수의 수로 균등한 숫자로 순위 줌. 전체 레코드/그룹개수 
     -> 나머지는 위에 부터 순차적으로 들어감.

select ntile(3) over (order by sal desc) 순위, ename, sal, deptno
from emp; 
      순위 ENAME                       SAL     DEPTNO
---------- -------------------- ---------- ----------
         1 KING                       5000         10
         1 FORD                       3000         20
         1 SCOTT                      3000         20
         1 JONES                      2975         20
         1 BLAKE                      2850         30
         1 CLARK                      2450         10
         2 ALLEN                      1600         30
         2 TURNER                     1500         30
         2 MILLER                     1300         10
         2 ADAMS                      1300         20
         2 WARD                       1250         30
         3 MARTIN                     1250         30
         3 JAMES                       950         30
         3 SMITH                       800         20
         3 율곡                        500         90
         3 이이이                      500

 

    5) 위에 합수 over 구문에 partition by '그룹핑' 하여 그 그룹안에서 각각 순위를 정한다.

select rank() over( partition by deptno order by sal desc) 순위, ename, sal, deptno
from emp;
      순위 ENAME                       SAL     DEPTNO
---------- -------------------- ---------- ----------
         1 KING                       5000         10
         2 CLARK                      2450         10
         3 MILLER                     1300         10
         1 SCOTT                      3000         20
         1 FORD                       3000         20
         3 JONES                      2975         20
         4 ADAMS                      1300         20
         5 SMITH                       800         20
         1 BLAKE                      2850         30
         2 ALLEN                      1600         30
         3 TURNER                     1500         30
         4 MARTIN                     1250         30
         4 WARD                       1250         30
         6 JAMES                       950         30
         1 율곡                        500         90
         1 이이이                      500



8. 조인(join) : 여러 테이블을 연결해서 필요한 데이터를 조회하는 방법
    - 오라클 조인 : 여러테이블 연결조건을 where절에 정의
    - ANSI 조인(표준)

    1) 개요 : 정규화된 여러 테이블의 데이터를 이용해서 데이터를 조회해야하는 경우 테이블 조인을 한다.
    - 조인은 관계형 데이터 베이스에서의 중요기능.
    - 기본키와 외래키 관계를 이용해서 테이블을 조인해야한다.
    - 조인을 하는 경우 반드시 조인 조건 정의.
  
    2) 조인 사용방법
    - from절에 테이블을 정의할 때 alias를 이용해서 정의.

select d.dname, e.ename, e.sal
from emp e, dept d
where e.deptno=d.deptno and sal>2000;
select e.empno, e.ename, e.job, e.deptno, d.deptno, d.dname
from emp e, dept d
where e.deptno=d.deptno;
select d.deptno, d.dname, l.city
from dept d, locations l
where d.loc_code=l.loc_code;

     -> deptno : 기본키


  - select절에서 두 개 이상의 테이블에 있는 칼럼을 추가하는 경우 from절에서 정의한 alias를 이용해서 칼럼의 모호성 제거.
  - where절에서는 반드시 조인조건을 정의해야한다. 조인을하면 외래키 테이블의 외래키와 기본키 테이블의 기본키를 비교하고 일치하는 레코드의 원하는 값을 가져오므로 조건을 정의하지않으면 데이터를 조회할 수 없다.
  - 사용되는 모든 테이블의 조인조건을 정의해야한다. (테이블이 세개면 조인 조건은 두개 정의)

select e.ename, d.dname, e.sal, l.city
from emp e, dept d, locations l
where e.deptno=d.deptno and d.loc_code=l.loc_code;

    - 검색 조건 추가
      where 조인조건
      and 조건추가

select e.empno, e.ename, e.sal, d.dname, d.loc_code
from emp e, dept d
where job='SALESMAN'
and e.deptno=d.deptno;
select ename, sal, hiredate
from emp e, dept d, locations l
where l.city = 'SEOUL'
        and e.deptno=d.deptno and d.loc_code=l.loc_code;
select e.ename, e.sal, e.job, e.hiredate, e.comm
from emp e, dept d, locations l
where e.deptno=d.deptno and d.loc_code=l.loc_code
and l.city='DALLAS' and e.sal>=1500;
select d.department_name, count(e.employee_id)
from employees e, departments d
where e.department_id = d.department_id
group by department_name;
select e.first_name || e.last_name || '의 연봉은 ' || e.salary
|| ' 입니다.' as 결과
from employees e,departments d
where e.department_id = d.department_id
and d.department_name = 'IT'
order by salary asc;
select e.employee_id, e.first_name, j.job_title, d.department_name
from employees e, departments d, locations l, jobs j
where e.department_id=d.department_id
and d.location_id = l.location_id
and e.job_id=j.job_id
and l.city ='Seattle';
select j.job_title job, sum(e.salary) 급여
from employees e, jobs j
where j.job_title not like '%Representative%'
      and j.job_id=e.job_id
group by j.job_title
having sum(e.salary)>30000
order by sum(e.salary);
select d.department_name 부서명, count(e.department_id) 인원수
from employees e, departments d
where e.department_id = d.department_id
      and hire_date <'2005-1-1'
group by d.department_name;
select d.department_id 부서번호, d.department_name 부서명, count(e.employee_id) 인원수,
 max(e.salary) 최고급여, min(e.salary) 최저급여, floor(avg(e.salary)) 평균급여, sum(e.salary) 급여총액
from employees e, departments d
where e.department_id = d.department_id
group by d.department_id, d.department_name
having count(e.department_id)>=3
order by 인원수 desc;
select j.job_title job, sum(e.salary) 급여
from employees e, jobs j
where j.job_title not like '%Representative%'
      and j.job_id=e.job_id
group by j.job_title
having sum(e.salary)>30000
order by sum(e.salary);
select d.department_name, floor(avg(salary)) 평균연봉
from employees e, departments d
where e.department_id=d.department_id
group by d.department_name
having avg(salary)>= 5000
order by 평균연봉 desc; 


  3) 조인의 종류(oracle 조인)
   ① Equip 조인 : 두개 이상의 테이블에서 칼럼 값이 정확하게 일치하는 경우 조회.
    조인조건 : where 기본테이블.기본키 = 외래키테이블.외래키
        (테이블은 alias 사용가능)

select e.ename d.dname
from emp e, dept d
where e.deptno = d.deptno


   ② outer 조인
   - 조인 적용했을 때 조인 조건을 만족하지않는 데이터를 조회하고 싶을때 사용.
   - (+) 연산자를 한쪽 칼럼에 초가해서  사용.
   - 만족하지 않아도 한쪽테이블의 모든 데이터를 조회해서 볼 수 있도록 자원.
   - (+)가 추가되면 만족되지 않는 조건을 임의로 추가해서 비교하므로 (+)가 투가되지않은 테입르의 레코드가 

     출력된다.
   [구문]

select 테이블명1(alias1명).칼럼며으 테이블2 alias2
from 테이블명1 alias1, 테이블명2 alias2
where 테이블명1(alias1).칼럼명(+) = 테이블명2(alias).칼럼명(+)

    - dept table에 null을 추가하여 emp table과 비교하여 emp table의 null data를 조회한다.

    - Equip 조인은 조인문에 detno가 일치하지않거나 null인 경우 조회되지않는다.

select e.empno, d.dname, e.ename, e.sal
from emp e, dept d
where e.deptno = d.deptno(+);
select nvl(m.ename,'관리자없음') 관리자명, count(e.empno) 인원수
from emp e, emp m
where e.mgr=m.empno(+)
group by m.ename;
select j.job_title, count(e.employee_id)
from employees e, jobs j
where e.job_id=j.job_id(+)
group by j.job_title;

    - emp table에 null을 추가하여 dept table과 비교하여 dept table의 null data를 조회한다.

select e.empno, d.dname, e.ename, e.sal
from emp e, dept d
where e.deptno(+) = d.deptno;
select d.department_name, count(e.employee_id)
from employees e, departments d
where e.department_id(+)=d.department_id
group by d.department_name
order by d.department_name;


   ③ non-Equip 조인(등급표 조인)
    - 두테이블에서 비교해야하는 칼럼 값이 정확하게 일치하지않고 사이 값인 경우 조인하는 방법. =연산자를 

      사용하지않은 조인.

select e.empno, e.sal, g.grade
from emp e, salgrade g
where e.sal between g.losal and g.hisal;


   ④ self 조인
    - 같은 테이블에서 조인하는 경우.
    - 하나의 테이블의 다른 칼럼을 가지고 조인하며 서로 다른 테이블인 것처럼 작업할 수 있다.
    - 조인조건은 equip조인과 동일하게 정의

select e.empno 사원번호, e.ename 사원명, e.mgr 관리자코드, m.ename 관리자명
from emp e, emp m
where e.mgr=m.empno;
select e.employee_id, e.first_name, nvl(m.first_name,'관리자 없음') 관리자명
from employees e, employees m
where e.manager_id = m.employee_id(+)
      and e.first_name like '_t%';
select e.first_name, e.salary
from employees e, employees m
where e.manager_id = m.employee_id
      and e.salary>m.salary;

 

 

[목차]

7. 함수

    1) 문자처리 함수 
        ① length() 
        ② sum(), max(), min(), count(), avg(), count(*) 
        ③ lower(), initcap(),upper() 
        ④ dual 
        ⑤ concat(A,B)
        ⑥ instr('문자열', '찾을 문자',m번째 부터 검색, 찾은 문자의 n번째 위치)  
        ⑦ substr('문자열', m번쨰 부터 짜름, n개 글자) 
        ⑧ replace('문자열', 바꿀문자, 바뀔문자) 
        ⑨ lpad('문자열', 전체 자리수, 공백문자)  
            rpad
        ⑩ ltrim('문자열', '지울문자') 
            rtrim
            trim
    2) 숫자자리 함수  
        ① round() 
        ② ceil() 
        ③ floor() 
    3) 날짜 함수  
        ① sysdate 
        ② months_between(A,B)  
        ③ add_month(A,B)  
        ④ next_day(A,B) 
        ⑤ last_day() 
    4) 변환함수  
        ① to_char(A,'9.99')  
        ② to_char(A,'YYYY-MM-DD')  
    5) 조건함수  
        ① decode(칼럼, 값1, 동일하면 출력할 값1 
                             값2, 동일하면 출력할 값2 
                       나머지 경우 출력할 값  )  
        ② case when 조건식1 then  출력할 값1 
            when 조건식2 then 출력할 값2 
            else 나머지 경우 출력할 값 
            end 별칭 
    6) null처리 함수  
        ① nvl(A,B)  
        ② nvl2(A,B)  

 

[내용]

7. 함수 
    1) 문자처리 함수

        ① length()

select ename, length(ename)
where length(ename)>=6;

        ② sum(sal), max(), min(), count(), avg(), count(*)

select ename, sal, max(sal)
from emp
group by ename;
select deptno, count(empno)
from emp
group by deptno;


        ③ lower(), initcap(첫글자만 대문자),upper()

select empno, ename, lower(job), deptno
from emp
where ename = 'SCOTT'


        ④ dual : test 1행짜리 테이블.

select *
from dual; 


        ⑤ concat(A,B) : || 문자열 연결. 
            concat(A, concat(B,C))

select concat(ename,concat('의 급여',concat(sal,'만원')))
from emp
where sal<1000;


        ⑥ instr('문자열', '찾을 문자',m번째 부터 검색, 찾은 문자의 n번째 위치) 
           -> 위치반환


         substr('문자열', m번쨰 부터 짜름, n개 글자) 
           -> 글자 추출 -1은 맨뒤.

select ename, hiredate
from emp
where substr(hiredate,1,2)=81;
select empno, ename, job, sal, deptno
from emp
where substr(ename,1,1) > 'K' and substr(ename,1,1) < 'Y';


        ⑧ replace('문자열', 바꿀문자, 바뀔문자)


        ⑨ lpad('문자열', 전체 자리수, 공백문자) 
           -> 왼쪽에 공백문자를 가짐, 전체 자리수에서 부족한 공백은 설정한 공백문자로 채운다.

            rpad : 오른쪽에 공백문자를 가짐.

select ename, job, lpad(sal,5,'*') as sal
from emp
where sal<=2000;

 

          ⑩ ltrim('문자열', '지울문자') : 왼쪽 문자를 지움

              rtrim('문자열', '지울문자') : 오른쪽 문자를 지움 
              trim(''from'문자열') : 양쪽 문자를 지움 

select ename, job, ltrim(lpad(sal,5,'*'),'*') as sal
from emp
where sal<=2000;
select ltrim(job,'A'), ltrim(sal,1)
from emp
where deptno=10;


    2) 숫자자리 함수 
         round() : 반올림

select deptno, round(avg(sal)) avg
from emp
where job<>'PRESIDENT'
group by deptno
having avg(sal)>1800
order by deptno;


         ceil()  : 올림 
         floor   : 버림 

    3) 날짜 함수 
        ① sysdate : 오늘날짜. 연산가능 
         months_between(최신날짜, 먼날짜) 
         add_month(,더할달수) 
        ④ next_day(지정일,'금') 요일 
        ⑤ last_day(지정일) : 마지막날

select e.first_name, e.salary, e.hire_date, d.department_name
from employees e, departments d
where e.department_id=d.department_id
      and months_between(sysdate,hire_date) >12*18;


    4) 변환함수 
         to_char(   ,'9.99') 
         to_char(   ,'YYYY-MM-DD')

select to_char(hiredate,'MM')월, count(*)입사자수
from emp
group by to_char(hiredate,'MM')
order by to_char(hiredate,'MM');


    5) 조건함수 
         decode(칼럼, 값1, 동일하면 출력할 값1

                             값2, 동일하면 출력할 값2

                       나머지 경우 출력할 값  )

select ename, deptno, decode(deptno, 10, '전산실',
                              20, '총무과',
                              30, '기획실',
                              '신입')
from emp;


         case when 조건식1 then  출력할 값1
            when 조건식2 then 출력할 값2
            else 나머지 경우 출력할 값
            end 별칭

select ename, sal, case when sal>=5000 then '1등급'
                 when sal>=2000 and sal<5000 then '2등급'
                 when sal>=1000 and sal<2000 then '3등급'
                 else '신입'
                 end  등급표
from emp;


    6) null처리 함수 
        ① nvl(칼럼or표현식, null인 경우 적용할 값 or 표현식(연산,함수호출))

select nvl(to_char(department_id),'No Department')부서번호, round(avg(salary),0)평균급여
from employees
group by department_id
having avg(salary) >6000;


        ② nvl2(칼럼 or 표현식, null이 아닌 경우 적용할 값, null인 경우 적용할 값)

select ename, mgr, nvl2(mgr,'담당','상위자') 관리자
from emp
order by 관리자;

+ Recent posts

1234