스프링 구조 및 설정

servlet-context.xml
root-context.xml
ServletConfig.java
RootConfig.java
스프링 관련 설정
web.xml WebConfig.java Tomcat 구동 관련 설정

 

프로젝트 구동 초기

  1. web.xml에서 시작
  2. <listener>에서 ContextLoaderListener 동작 실행
  3. <context-param>에서 root-context.xml의 경로 및 처리 실행
  4. root-context.xml에 정의된 객체(Bean)들이 스프링의 영역(context) 안에 생성, 객체들 간의 의존성 처리
  5. 스프링 MVC에서 사용하는 DispatcherServlet이 서블릿과 관련된 동작 실행
  6. DisPatcherServlet에서 servlet-context.xml을 로딩 및 실행

 

SpringFramework MVC 처리 순서

  1. 클라이언트(client)가 서버로 요청(request)를 보냄
  2. DispatcherServlet에서 요청을 가로챔
  3. DispatcherServlet -> HandlerMapping으로 보냄
  4. HandlerMapping에서 컨트롤러를 찾음
  5. @RequestMapping을 통해 요청을 처리할 메서드에 도달
  6. DispatcherServlet은 HandlerAdapter 빈에게 요청 처리 위임
  7. 해당 요청을 처리할 service를 주입(DI)받아 비즈니스 로직을 service에 위임
  8. DAO는 MyBatis 설정을 이용해 SQL쿼리를 날려 DB에 저장되어 있는 정보를 받아 서비스에서 되돌려 줌
  9. 모든 비즈니스 로직을 끝낸 서비스가 결과물을 컨트롤러에 넘김
  10. 컨트롤러에선 Model 객체에 결과물을 넣거나, 어떤 View(jsp)를 보여줄 것이진 정보를 담아 DispatcherServlet에 넘김
  11. viewResolver는 해당 jsp를 찾아 DispatcherServlet에 알려줌
  12. view에 응답 로직을 처리 시킴
  13. DispatcherServlet이 클라이언트에게 랜더링 된 view를 응답

HikariCP는 커넥션 풀(Java와 DataSource라는 인터페이스를 통해 커넥션 풀 사용)

 

-  Java 설정을 이용해 HikariCP 설정

import javax.sql.DataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;

@Configuration
@ComponentSca(basePackages = {"pakage"})
public class RootConfig {
    @Bean
    public DataSource dataSource() {
        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setDriverClassName("oracle.jdbc.driver.OracleDriver");
        hikariConfig.setJdbcUrl("jdbc:oracle:thin:@localhost:1521:XE");
        hikariConfig.setUsername("dbname");
        hikariConfig.setPassword("dbpassword");

        HikariDataSource dataSource = new HikariDataSource(hikariConfig);

        return dataSource;
    }
}

 

 

-  Test 코드

import static org.junit.Assert.fail;

import java.beans.Transient;
import java.sql.Connection;
import javax.sql.DataSource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfigration;
import org.sprintframework.test.context.junit4.SprintJUnit4ClassRunner;

import lombok.setter;
import lombok.extern.log4j.Log4j;

@Runwith(SpringJUnit4ClassRunner.class)
@ContextConfigration(classes = { RootConfig.class })
@log4j
public class testcode {
    @Setter(onMethod_ = { @Autowired })
    private DataSource dataSource;
    
    @Test
    public void testConnection() {
        try(Connection con = dataSource.getConnection()) {
            log.info(con);
        } catch (Exception e) {
            fail(e.getMessage());
        }
    }
}

JDBC 드라이버가 정상적으로 추가되었고, 데이터베이스의 연결이 가능할 때 이를 눈으로 확인할 수 있는 테스트 코드

import static org.junit.Asset.fail;

import java.sql.Connection;
import java.sql.DriverManager;

import org.junit.Test;

import lombok.extern.log4j.Log4j;

@Log4j
public class JDBCTests {
	static {
    	try {
        	Class.forName("oracle.jdbc.driver.OracleDriver");
        } catch (Exception e) {
        	e.printStackTrace();
        }
    }
    
    
    @Test
    public void testConnection() {
    	try(Connection con =
        	DriverManager.getConnection(
            	"jdbc:oracle:thin:@localhost:1521:XE",
                "@id",
                "@pw")) {
            log.info(con);
        } catch (Exception e) {
        	fail(e.getMessage());
        }
    }
}

스프링 프레임워크의 차별점

  • 복잡함에 반기를 들어서 만들어진 프레임워크
  • 프로젝트 전체 구조를 설계할 때 유용한 프레임워크
  • 다른 프레임워크들의 포옹
  • 개발 생산성과 개발도구의 지원

 

주요 특징

  • POJO기반의 구성
  • 의존성 주입(DI)을 통한 객체간의 관계 구성
  • AOP(Aspect-Oriented-Programming) 지원
  • 편리한 MVC 구조
  • WAS의 종속적이지 않은 개발 환경

 

커넥션 풀이란?

  • 여러명의 사용자를 동시에 처리해야하는 웹 애플리케이션의 경우 DB연결을 이용할 때 사용
  • JAVA에서는 DataSource라는 인터페이스를 통해 사용
  • 여기서는 HikariCP 사용

 

MyBatis란?

  • SQL 매핑(Mapping) 프레임워크

 

전통적인 JDBC프로그램과 MyBatis의 차이점

전통적인 JDBC 프로그렘 MyBatis
- 직접 Connection을 맺고 마지막에 Close()로 닫아줘야함
- Preparedstatement 직접 생성 및 처리
- SetXXX등을 모두 개발자가 직접 처리
- SELECT의 경우 직접 ResultSet 처리
- 자동으로 Connection 처리
- MyBatis 내부적으로 처리
- #{prop}와 같이 속성을 지정하면 내부적으로 자동 처리
- 리턴 타입 지정 시 자동으로 객체 생성 및 ResultSet 처리

 

MyBatis

  • 가장 핵심적인 객체(SQLSession, SQLSessionFactory)
  • SQLSession : MyBatis에서 SQLSession을 통해서 Connection을 생성하거나 원하는 SQL을 전달하고, 결과를 리턴 받는 구조로 작성
  • SQLSessionFactory : 내부적으로 SQLSession을 만들어 내는 존재

 

Mapper

  • SQL과 그에 대한 처리를 지정하는 역할
  • XML과 인터페이스 + 어노테이션 형태로 작성
  • RootConfig.java 설정에서 @MapperScan 어노테이션을 사용해서 패키지를 인식하는 방식으로 처리

 

POJO(Plain Old Java Object)

  • 다른 프레임워크들과 달리 관계를 구성할 때 별도의 API를 사용하지 않음
  • 생산성에 유리, 코드 테스트를 좀 더 유연하게 가능
  • 개발자가 특정 라이브러리나 컨테이너 기술에 종속적이지 않음
  • 개발자가 특정 라이브러리나 컨테이너 기술에 종속적이지 않음

 

구조와 DI

  • 의존성 주입(DI)
  • 'Application Content'에서 존재가 필요한 객체 생성 후 필요한 객체들을 주입하는 역할을 하는 스프링의 구조
  • Application Content가 관리하는 객체 -> 빈(Bean)
  • 빈과 빈 사이의 의존관계를 처리하는 방식(XML 설정, 어노테이션 설정, Java 설정)

 

LOMBOK

  • 컴파일 시 코드를 작성해 주는 라이브러리
  • @Setter
  • @Data

 

@Setter

  • Setter 메소드를 생성해주는 역할
  • OnMethod 속성 : Setter 메소드를 생성시 추가할 어노테이션 지정

 

@Data

  • Lombok에서 가장 자주 사용되는 어노테이션
  • @ToString, @EqualsAndHashCode, @Getter, @Setter, @RequireArgsConstructor를 모두 결합한 형태
// 생성자 선언 및 주입
public class Sample {
	private Chef chef;
    
    public Sample(Chef chef) {
    	this.chef = chef;
    }
}


// =============================================================================
// 생성자의 자동 주입
import org.springframework.stereotype.Component;

import lombok.Getter;
import lombok.ToString;

@Component
@ToString
@Getter
@AllArgsConstructor
public class Sample {
	private Chef chef;
}

 

Spring 관련 어노테이션

  • @Component
  • @Autowired

 

@Component

  • 해당 클래스가 스프링에서 객체로 만들어서 관리하는 대상임을 명시하는 어노테이션
  • @Component가 존재하는 클래스들을 객체로 생성해서 빈으로 관리하게 됨

 

@Autowired

  • 스프링 내부에서 자신이 특정한 객체에 의존적이므로 자신에게 해당 타입의 빈을 주입해주라는 표시
  • public class Test{
    	@Setter(onMehtod_ = { @Autowired }
        private Sample sample;
    }

 

최대공약수(GCD)

    // 반복문 사용
    public static int gcd(int a, int b) {
        while( b!= 0) {
            int r = a%b;
            a = b;
            b = r;
        }
        return a;
    }

    // 재귀함수 이용
    public static int gcd1(int a, int b) {
        if(b == 0)
            return a;
        else
            return gcd1(b, a%b);
    }

 

최소공배수(LCM)

    public static int lcm(int a, int b) {
        return a * b / gcd(a, b);
    }

'알고리즘 > Java' 카테고리의 다른 글

[Java] Anagram 애너그램  (0) 2021.11.22
[Java] 숫자를 입력받아 숫자의 각 자리수 구하기  (0) 2021.08.31

 

public class fibo {
    
    // 메모이제이션 사용
    static long temp[];
    public static long fiboM(int n) {
        if (n <= 1)
            return n;
        else
            return temp[n] = fiboM(n-2) + fiboM(n-1);
        }
   
   // 재귀함수 사용
   public static int fibo(int n) {
        if(n <= 1)
            return n;
        else
            return fibo(n-2) + fibo(n-1);
    }
    

    public static void main(String args[]) {
        temp = new long[100];
        System.out.println(fiboM(6));
    }
}
import java.util.Arrays;

public class Anagram {    
    public static boolean isAnagram(String str1, String str2) {
        // 문자열 공백제거, 소문자 변환, 배열 변환
        char[] charArray1 = str1.replaceAll(" ", "").toLowerCase().toCharArray();
        char[] charArray2 = str2.replaceAll(" ", "").toLowerCase().toCharArray();

        // 배열 길이(글자수) 비교
        if(charArray1.length != charArray2.length){
            return false;
        }

        // 정렬
        Arrays.sort(charArray1);
        Arrays.sort(charArray2);

		// 비교
        return Arrays.equals(charArray1, charArray2);
    }

}

cmd 관리자 권한으로 실행

1 or 2 이후 정상적으로 이동되면 밑에 프로세스 진행

 

1. cd /d %ProgramFiles%\Microsoft Office\Office16
                                   or
2. cd /d %ProgramFiles(x86)%\Microsoft Office\Office16
for /f %x in ('dir /b ..\root\Licenses16\ProPlus2019VL*.xrm-ms') do cscript ospp.vbs /inslic:"..\root\Licenses16\%x"
cscript ospp.vbs /setprt:1688
cscript ospp.vbs /unpkey:6MWKP >nul
cscript ospp.vbs /inpkey:NMMKJ-6RK4F-KMJVX-8D9MJ-6MWKP
cscript ospp.vbs /sethst:kms8.msguides.com
cscript ospp.vbs /act

'기타' 카테고리의 다른 글

Windows 설치 중 CMD 상태에서 포맷하기  (2) 2019.12.16
eclipse 단축키  (0) 2019.09.16
GitHub 사용법  (0) 2019.09.16
토렌트 속도 저하(1/10) 현상  (0) 2019.05.23
import java.util.Scanner;


public class Main {
    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);

        String A = sc.nextLine();

        String[] b = A.split("");

        
        int len = A.length();

        int a = Integer.parseInt(A);


        System.out.println("입력받은 숫자의 자릿수 : " + len);
        int[] arr = new int[len];
        
        // 문자열로 만들어서 나타낸 것
        for(int i=0;i<len;i++) {
            String digit = "0".repeat(i);
            System.out.println("1"+digit+"의 수 : " +b[len-i-1]+digit);
        }

        // %(mod)를 사용해서 나타낸 것
        if (len < 2) {
            arr[0] = a%10;
        }
        else {
            arr[0] = a%10;
            for(int i=1;i<len;i++) {
                arr[i] = (int)(a%(Math.pow(10,i+1))/(Math.pow(10,i)));
            }
        }

        int i = 0;
        while(i <len) {
            int num = (int)Math.pow(10,i);
            System.out.println(num + "의 수 : " +arr[i]*num);
            i++;
        }

        sc.close();
    }
}

 

 

 

'알고리즘 > Java' 카테고리의 다른 글

[Java] 최대공약수(GCD), 최소공배수(LCM)  (0) 2021.11.24
[Java] Anagram 애너그램  (0) 2021.11.22

Java Stream

자바 공부를 하면서 Stream이 무엇인지, 어떻게 사용되고 있는지 인지는 하고 있었으나 실제 코드로 타이핑해보지 않았다.

그러던 중 이번에 가볍게 API 훑어보는 식으로 공부를 하면서 코드를 쳐보면서 조금 더 익히게 되었다.


Stream은 자바 8부터 추가된 기능으로 "컬렉션, 배열등의 저장 요소를 하나씩 참조하며 함수형 인터페이스(람다식)를 적용하며 반복적으로 처리할 수 있도록 해주는 기능"이다. 

(InputStream, OutputStream같은 I/O Stream이 아니다.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
List<String> names = Arrays.asList("jeong""pro""jdk""java");
// 기존의 코딩 방식
long count = 0;
for (String name : names) {
    if (name.contains("o")) {
        count++;
    }
}
System.out.println("Count : " + count); // 2


// 스트림 이용한 방식
count = 0;
count = names.stream().filter(x -> x.contains("o")).count();
System.out.println("Count : " + count); // 2

다짜고짜 코드를 가지고 설명하면 위와 같다.

어떠한 컬렉션(names)이 존재하고 그 컬렉션의 요소를 순회하면서 "o"가 포함된 요소의 개수를 구한다고 가정했을 때, 기존의 코드 방식은 반복 순회를 위한 for문, 필터링을 위한 분기 if문이 사용되야 비로소 구할 수 있었던 반면,

스트림을 이용하면 한 줄의 코딩만으로 count값을 구할 수 있다. (count 선언, 출력을 제외하면.)

즉, 불필요한 코딩(for, if 문법)을 걷어낼 수 있고 직관적이기 때문에 가독성이 좋아진다.

이 점이 Stream의 장점이자 목적이다.

Stream은 어떤 것들에 적용할 수 있을까?

Stream은 주로 Collection, Arrays에서 쓰인다.

물론 두 개 뿐만 아니라 I/O resources(ex. File), Generators, Stream ranges, Pattern 등에서도 사용할 수 있다.

해당 객체들로 부터 Stream을 생성하는 법은 스스로 찾아보도록 하고 기본적으로 자주 쓰이는 것들만 간단히 소개한다.

1
2
3
4
5
6
7
List<String> names = Arrays.asList("jeong""pro""jdk""java");
names.stream(); //Collection에서 스트림 생성


Double[] dArray = {3.13.23.3};
Arrays.stream(dArray);//배열로 스트림 생성


Stream<Integer> str = Stream.of(1,2); // 스트림 직접 생성

스트림 사용법과 주의사항 

스트림의 구조는 크게 3가지로 나뉜다.

1. 스트림생성

2. 중개 연산

3. 최종 연산

-> 실제 사용법으로 표기하면 "Collections같은 객체 집합.스트림생성().중개연산().최종연산();" 이런식이다.

* 계속해서 . 으로 연계할 수 있게 하는 방법을 파이프라인이라고도 한다.

위에서 어떻게 스트림을 생성하는지는 알았으니 이제부터는 중개 연산에 쓰이는 함수는 어떤 것들이 있고 어떻게 사용하는지를 알아보고, 최종 연산에 쓰이는 함수는 어떤 것들이 있고 어떻게 사용하는지 API를 훑어보는 느낌으로 알아보면 될 것이다.

- 중개 연산

Filter

1

2

List<String> names = Arrays.asList("jeong""pro""jdk""java");

Stream<String> a = names.stream().filter(x -> x.contains("o"));

cs

filter는 말 그대로 필터링, 즉 조건에 맞는 것만 거른다는 것이다.

위의 코드에서는 람다식을 이용해서 x 로 스트림의 요소를 받고 각 요소에 "o"라는 알파벳이 있는 것들만 거른다.

즉, "jeong" 과 "pro" 만 가지고 있는 스트림을 반환한다.

Map

1
2
3
4
5
6
List<String> names = Arrays.asList("jeong""pro""jdk""java");
names.parallelStream()
     .map(x -> x.concat("s"))
     .forEach(x -> System.out.println(x));
//jeongs, pros, jdks, javas


Colored by Color Scripter
cs

앞서 filter나 map은 자바스크립트에서도 다뤄서 어떤 기능을 하는지는 알 수 있다.

map은 스트림의 각 요소를 연산하는데 쓰인다. 위와 같은 경우에는 각 문자열(요소)마다 뒤에 "s"를 붙였다.

숫자일 경우 * 2 로 두 배를 만든다든지 등의 다양한 조작이 가능하다.

Peek

peek()도 Map과 유사하게 각 요소에 어떤 연산을 적용할 때 사용한다.

Sorted

말 그대로 스트림의 요소들을 정렬해준다.

Limit

1

2

3

4

5

List<Integer> ages = Arrays.asList(1,2,3,4,5,6,7,8,9);

ages.stream()

    .filter(x -> x > 3)

    .limit(3);

//4,5,6

Colored by Color Scripter

cs

스트림의 개수를 .limit(3) 으로 지정하면 3개로 제한한다. (물론 중개연산이라 스트림 반환)

Distinct

스트림의 요소가 예를 들어 1,2,1,2,1,2,1,2 일 때 .distinct()를 적용하면 1,2로 중복을 제거한다.

Skip

.skip(3) 이라고하면 처음 3개의 요소는 제외하고 나머지 요소들로 새로운 stream을 만든다.

mapToInt, mapToLong, mapToDouble

mapXXX 함수들은 해당 타입의 스트림으로 바꿔준다. 예를들어 "1","2","3" 을 가진 스트림이 있었으면 mapToInt를 적용하면 1,2,3 을 가진 스트림으로 변환 해준다.

- 최종 연산

count(), min(), max(), sum(), average()

최종 연산이기 때문에 앞서 함수를 적용했던 스트림에 있는 요소들에 대해 count를 세거나 최소값, 최대값, 합계, 평균 값을 얻을 수 있는 함수다.

* 참고로 average()는 연산에 안보인다... 사라진 건 아닐텐데 확인이 필요하다.

reduce

1
2
3
List<Integer> ages = new ArrayList<Integer>();
ages.add(1);ages.add(2);ages.add(3);//1,2,3
System.out.println(ages.stream().reduce((b,c) -> b+c).get());//1+2+3=6
cs

reduce는 누적된 값을 계산하는 함수다.

여기서 b, c로 지정한 파라미터를 가지고 리턴한 결과(b+c)가 다시 b가 되고 다음 스트림의 요소가 c가 되어 계속 누적된다. 따라서 1+2+3인 6이 결과로 찍힌다.

forEach

1
2
3
4
List<Integer> ages = new ArrayList<Integer>();
ages.add(1);ages.add(2);ages.add(3);//1,2,3
Set<Integer> set = ages.stream().collect(Collectors.toSet());
set.forEach(x-> System.out.println(x));//1,2,3
cs

forEach는 map이나 peek의 최종연산 버전이다. 각 요소를 돌면서 처리할 수 있도록 되어있다.

collect

collect는 스트림의 값들을 모아주는 기능을 한다. toMap, toSet, toList로 해당 스트림을 다시 컬렉션으로 바꿔준다.

iterator

1
2
3
4
5
List<String> names = Arrays.asList("jeong""pro""jdk""java");
Iterator<String> iter = names.stream().iterator();
while(iter.hasNext()) {
    System.out.println(iter.next());//jeong, pro, jdk, java
}
Colored by Color Scripter
cs

iterator는 Iterator<T>를 반환한다.

noneMatch, anyMatch, allMatch

1
2
3
List<Integer> ages = new ArrayList<Integer>();
ages.add(1);ages.add(2);ages.add(3);//1,2,3
System.out.println(ages.stream().filter(x -> x>1).noneMatch(x->x>2));//false
cs

noneMatch는 최종적으로 얻은 스트림의 "모든" 요소들이 조건을 만족하지 "않는"지를 판단해서 boolean값을 리턴한다.

anyMatch는 스트림의 요소들 중에 하나라도 조건을 만족하는지 판단해서 boolean값을 리턴하고,

allMatch는 스트림의 "모든" 요소들이 조건을 만족하는지를 판단해서 boolean값을 리턴한다.

 

기타로 그룹핑하고 통계를 얻는 것도 있는데 생략한다.

* 알아 둘 것

- Stream은 재사용이 불가능하다.

1
2
3
4
5
// Stream 재사용 불가 stream has already been operated upon or closed.
Stream<String> a = names.stream().filter(x -> x.contains("o"));
count = a.count();
        
List<String> lists = a.collect(Collectors.toList());

위 코드에서 보듯 한 번 사용한 스트림 a에 대해서 다시 사용하려고 하면 에러가 난다.

 

- 병렬 스트림은 여러 쓰레드가 작업한다.

1 names.parallelStream().filter(x -> x.contains("o")).count();

stream()으로 스트림을 생성하지 않고 위 처럼 parallelStream()으로 병렬 스트림을 만들 수 있다.

이렇게하면 여러 쓰레드가 스트림에서 요소를 필터링하고 나온 요소 수를 계산하고 쓰레드끼리 다시 한 번 각자 계산한 count 값들을 더해서 리턴해준다.

단순하게 생각하면 여러쓰레드가 처리해주니 병렬스트림이 항상 성능면에서 유리해보일 수 있지만 애플리케이션에서 사용하는 쓰레드가 많거나 스트림의 요소 수가 많지 않다면 오히려 쓰레드를 사용하는데 드는 오버헤드가 더 클 수도 있다.

 - 중개 연산은 미리하지 않는다 지연 연산을 한다.

1
2
Stream<String> a = names.stream().filter(x -> x.contains("o")).map(x-> x.concat("s"));
a.forEach(x -> System.out.println(x));
Colored by Color Scripter
cs

위와 같은 코드가 있으면 위에 filter와 map 함수는 미리 계산하고 있지 않고 있다가 forEach와 같은 최종연산이 적용될 때 중개 연산도 실행된다.

이로써 얻는 장점은 미리 계산하면서 두 번 순회하는 짓을 안할 수 있게 된다는 점이다.

 

참고사이트

https://www.slideshare.net/madvirus/8-api

http://iloveulhj.github.io/posts/java/java-stream-api.html

http://jlblog.me/92

https://www.slideshare.net/madvirus/8-api



출처: https://jeong-pro.tistory.com/165 [기본기를 쌓는 정아마추어 코딩블로그]

+ Recent posts