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방식과 동일

 

 


 

+ Recent posts

1···4567891011