반응형

한양대학교는 2023년부터 Hanyang Popularity Exceeding Competition을 열게 되었다. 이 대회는 일정 기간 진행되며, 대회가 끝나는 시점에 인기도가 가장 높은 학생이 우승한다. 철민이는 Hanyang Popularity Exceeding Competition의 참가자이지만, 이제 막 학교에 다니기 시작한 철민이는 인기도가 밖에 되지 않는다.

철민이는 한양대학교 내의 유명인 명과 만난다는 우승 계획을 세웠다. 이를 위해 철민이는 번 유명인부터 번 유명인까지 차례대로 만날 계획을 세웠다.

하지만 현실은 생각보다 복잡해서, 유명인들과 만난다고 항상 인기도가 올라가지는 않는다. 한쪽의 유명도가 다른 한쪽에 비해 너무 높으면 한쪽의 인기에 다른 쪽이 묻혀버리기 때문이다. 엄밀히 말해서, 철민이의 현재 인기도를 라고 하고, 번 유명인의 인기도를 , 친화력을 라고 하자. 이때, 여야 철민이의 인기도가  올라간다. 라면 철민이의 인기도는 변하지 않는다.

그래서 철민이는 모든 유명인을 다 만나는 대신, 일부 유명인만을 골라 만나서 인기도를 최대화하려고 한다. 이때, 철민이가 도달할 수 있는 최대 인기도는 얼마일까?

유명인들은 바쁜 삶을 보내기 때문에, 유명인과 만나는 시간을 변경할 수는 없다. 즉, 번호가 더 높은 유명인을 먼저 만나도록 계획을 변경할 수는 없다.

제약조건

입력형식

첫 번째 줄에 한양대학교의 유명인들의 수 이 주어진다.

다음 개의 줄의 번째 줄에는 번 유명인의 인기도와 친화력을 의미하는 두 정수  가 공백으로 구분되어 주어진다.

출력형식

첫 번째 줄에 철민이가 도달할 수 있는 최대 인기도를 출력한다.

입력예제1
3 1 1 0 0 2 1
출력예제1
2

 

아래 방식으로 만남을 계획하면 인기도를 최대화할 수 있다.

  •  1번 유명인은 만나지 않고 건너뛴다.
  •  2번 유명인을 만난다. |0 − 0| ≤ 0이므로 철민이의 인기도가 1이 된다.
  •  3번 유명인을 만난다. |1 − 2| ≤ 1이므로 철민이의 인기도가 2가 된다.
입력예제2
5 0 0 0 1 0 2 0 3 0 4
출력예제2
5

 

모든 유명인을 만나면 인기도를 최대로 올릴 수 있다.

 

입력예제3
3 4 3 3 2 2 1
출력예제3
0

 

어떤 방식으로 만남을 계획해도 철민이의 인기도가 오를 수 없다.

 

 

[Solution]

import java.io.*;
import java.util.*;

public class Main {

    public static void main(String[] args) throws IOException{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int N = Integer.parseInt(br.readLine());

        int X = 0;
        
        for(int i=0; i<N; i++){
            StringTokenizer st = new StringTokenizer(br.readLine());
            int P = Integer.parseInt(st.nextToken());
            int C = Integer.parseInt(st.nextToken());

            int absoluteValue = 0 ;
            if((P-X) < 0){
                absoluteValue = (P-X)*-1;
            }else{
               absoluteValue = (P-X); 
            } 

            if(absoluteValue <= C){
                X++;
            }
            
        }

        System.out.println(X);
    }
}
반응형
블로그 이미지

Mr.비타민

,
반응형

현대자동차그룹은 주요 물류센터에 각종 자동화 기기를 도입하며 ‘스마트 물류’를 실현하고 있다. 최근에는 자동차 반조립 부품(KD, Knock-Down) 물류기지인 KD센터에 포장 관련 자동화 로봇 개발과 구축을 완료했다. 기존 수작업으로 진행하던 일부 작업 라인을 자동화 기기로 전환해 생산성을 높이기 위한 시도다. 기다란 작업 라인에 로봇과 부품이 아래 그림과 같이 단위 간격으로 놓여 있다. 로봇들의 위치에서 거리가 K 이하인 부품만 잡을 수 있다. 왼쪽 오른쪽은 상관 없다.



위 그림에서 K = 1인 경우를 생각해보자. 이 경우 모든 로봇은 그의 위치 바로 옆에 인접한 부품만 집을 수 있다.

* 10번 위치에 있는 로봇은 바로 왼쪽 11번 위치에 있는 부품을 집을 수 있다. 이 경우 다음과 같이 최대 5개의 로봇이 부품을 집을 수 있다.
* 2번 위치에 있는 로봇은 1번 위치에 있는 부품을 집을 수 있다.
* 4번 위치에 있는 로봇은 5번 위치에 있는 부품을 집을 수 있다.
* 6번 위치에 있는 로봇은 7번 위치에 있는 부품을 집을 수 있다.
* 9번 위치에 있는 로봇은 8번 위치에 있는 부품을 집을 수 있다.
* 10번 위치에 있는 로봇은 11번 위치에 있는 부품을 집을 수 있다.
* 12번 위치에 있는 로봇은 집을 수 있는 부품이 없다.

만약 K = 2라고 한다면 다음과 같이 6개 로봇 모두가 부품을 집을 수 있다.

* 2번 위치에 있는 로봇은 1번 위치에 있는 부품을 집을 수 있다.
* 4번 위치에 있는 로봇은 3번 위치에 있는 부품을 집을 수 있다.
* 6번 위치에 있는 로봇은 5번 위치에 있는 부품을 집을 수 있다.
* 9번 위치에 있는 로봇은 7번 위치에 있는 부품을 집을 수 있다.
* 10번 위치에 있는 로봇은 8번 위치에 있는 부품을 집을 수 있다.
* 12번 위치에 있는 로봇은 11번 위치에 있는 부품을 집을 수 있다.

라인의 길이 N, 부품을 집을 수 있는 거리 K, 그리고 로봇과 부품의 위치가 주어졌을 때 부품을 집을 수 있는 로봇의 최대 수를 구하는 프로그램을 작성하라.

 

제약조건

1 ≤ N ≤ 20,000

1 ≤ K ≤ 10

 

입력형식

입력의 첫 줄에는 두 정수 N과 K가 나온다.

다음 줄에는 로봇과 부품의 위치가 문자 P(로봇)와 H(부품)로 이루어지는 길이 N인 문자열로 주어진다.

 

출력형식

입력에 대해서 부품을 집을 수 있는 최대 로봇 수(정수)를 나타낸다.

 

입력예제1

20 1

HHPHPPHHPPHPPPHPHPHP

 

출력예제1

8

 
입력예제2

20 2

HHHHHPPPPPHPHPHPHHHP

 

출력예제2

7

 

 

 

[Solution]

로봇 왼쪽 먼 곳부터 오른쪽으로 순차적으로 차례대로 체크하면서 집는다고 생각하고 구현.

 

import java.io.*;
import java.util.*;

public class Main {

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
		
        int N = Integer.parseInt(st.nextToken());
        int K = Integer.parseInt(st.nextToken());
        int count = 0;
        char[] str = br.readLine().toCharArray();
		
	for (int i = 0; i < N; i++) {
		if (str[i] == 'P') {
			for (int j = i - K; j <= i + K; j++) {
				if (j < 0 || j >= N){
					continue;
				}else if (str[j] == 'H') {
					str[j] = '*';
					count++;
					break;
				}
			}
		}
	}
        System.out.println(count);
    }
}
반응형
블로그 이미지

Mr.비타민

,
반응형

Frontend와 Backend는 port가 다르기때문에 다른 주소로 판단을 하므로,

CORS에 대한 처리를 해줘야한다.

우선 Backend에서 허용하는 URL에 대한 예외처리와 HTTP Method 허용을 해줘야 Backend에서 전달받아서 처리를 할 수 있다.

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("http://localhost:3000","http://example.com:9000")
                .allowedMethods("GET", "POST", "PUT", "DELETE");
    }
}
반응형
블로그 이미지

Mr.비타민

,
반응형

Session을 사용하지않고 Token 방식으로 현 사용자에 대한 인증 및 처리를 하기위해 JWT를 사용한 로그인을 작성한다.

1. build.gradle

implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
implementation 'io.jsonwebtoken:jjwt-impl:0.11.5'
implementation 'io.jsonwebtoken:jjwt-jackson:0.11.5'

Spring Security를 사용하여 JWT를 구현한다.(implementation 추가)

2. JwtToken DTO추가

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;

@Builder
@Data
@AllArgsConstructor
public class JwtToken {
    private String grantType;
    private String accessToken;
    private String refreshToken;
}

Frontend에서 사용 할 Token을 전송하기 위한 DTO를 생성한다.

 

3. 암호키설정

커맨드명령어 : openssl rand -hex 32
생성된 키를 application.properties에 저장하고 사용한다.

jwt.secret=34075631b07f8f57d88b1a63d00148709f3f11cc7227d50e3c8a8db687a772a1

 

4. JwtTokenProvider 생성

import java.security.Key;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import com.expetdia.common.domain.JwtToken;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.UnsupportedJwtException;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class JwtTokenProvider {
    private final Key key;

    // application.yml에서 secret 값 가져와서 key에 저장
    public JwtTokenProvider(@Value("${jwt.secret}") String secretKey) {
        byte[] keyBytes = Decoders.BASE64.decode(secretKey);
        this.key = Keys.hmacShaKeyFor(keyBytes);
    }

    // Member 정보를 가지고 AccessToken, RefreshToken을 생성하는 메서드
    public JwtToken generateToken(Authentication authentication) {
        // 권한 가져오기
        String authorities = authentication.getAuthorities().stream()
                .map(GrantedAuthority::getAuthority)
                .collect(Collectors.joining(","));

        long now = (new Date()).getTime();

        // Access Token 생성
        Date accessTokenExpiresIn = new Date(now + 86400000);
        String accessToken = Jwts.builder()
                .setSubject(authentication.getName())
                .claim("auth", authorities)
                .setExpiration(accessTokenExpiresIn)
                .signWith(key, SignatureAlgorithm.HS256)
                .compact();

        // Refresh Token 생성
        String refreshToken = Jwts.builder()
                .setExpiration(new Date(now + 86400000))
                .signWith(key, SignatureAlgorithm.HS256)
                .compact();

        return JwtToken.builder()
                .grantType("Bearer")
                .accessToken(accessToken)
                .refreshToken(refreshToken)
                .build();
    }

    // Jwt 토큰을 복호화하여 토큰에 들어있는 정보를 꺼내는 메서드
    public Authentication getAuthentication(String accessToken) {
        // Jwt 토큰 복호화
        Claims claims = parseClaims(accessToken);

        if (claims.get("auth") == null) {
            throw new RuntimeException("권한 정보가 없는 토큰입니다.");
        }

        // 클레임에서 권한 정보 가져오기
        Collection<? extends GrantedAuthority> authorities = Arrays.stream(claims.get("auth").toString().split(","))
                .map(SimpleGrantedAuthority::new)
                .collect(Collectors.toList());

        // UserDetails 객체를 만들어서 Authentication return
        // UserDetails: interface, User: UserDetails를 구현한 class
        UserDetails principal = new User(claims.getSubject(), "", authorities);
        return new UsernamePasswordAuthenticationToken(principal, "", authorities);
    }

    // 토큰 정보를 검증하는 메서드
    public boolean validateToken(String token) {
        try {
            Jwts.parserBuilder()
                    .setSigningKey(key)
                    .build()
                    .parseClaimsJws(token);
            return true;
        } catch (SecurityException | MalformedJwtException e) {
            log.info("Invalid JWT Token", e);
        } catch (ExpiredJwtException e) {
            log.info("Expired JWT Token", e);
        } catch (UnsupportedJwtException e) {
            log.info("Unsupported JWT Token", e);
        } catch (IllegalArgumentException e) {
            log.info("JWT claims string is empty.", e);
        }
        return false;
    }


    // accessToken
    private Claims parseClaims(String accessToken) {
        try {
            return Jwts.parserBuilder()
                    .setSigningKey(key)
                    .build()
                    .parseClaimsJws(accessToken)
                    .getBody();
        } catch (ExpiredJwtException e) {
            return e.getClaims();
        }
    }

}

 

5. JwtAuthenticationFilter 구현

import java.io.IOException;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.GenericFilterBean;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public class JwtAuthenticationFilter extends GenericFilterBean {
    private final JwtTokenProvider jwtTokenProvider;


    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // 1. Request Header에서 JWT 토큰 추출
        String token = resolveToken((HttpServletRequest) request);

        // 2. validateToken으로 토큰 유효성 검사
        if (token != null && jwtTokenProvider.validateToken(token)) {
            // 토큰이 유효할 경우 토큰에서 Authentication 객체를 가지고 와서 SecurityContext에 저장
            Authentication authentication = jwtTokenProvider.getAuthentication(token);
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }
        chain.doFilter(request, response);
    }

    // Request Header에서 토큰 정보 추출
    private String resolveToken(HttpServletRequest request) {
        String bearerToken = request.getHeader("Authorization");
        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer")) {
            return bearerToken.substring(7);
        }
        return null;
    }
}

 

6. SecurityConfig 구현

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import lombok.RequiredArgsConstructor;

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
    private final JwtTokenProvider jwtTokenProvider;
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception {
        return httpSecurity
                // REST API이므로 basic auth 및 csrf 보안을 사용하지 않음
                .httpBasic().disable()
                .csrf().disable()
                // JWT를 사용하기 때문에 세션을 사용하지 않음
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeHttpRequests()
                // 해당 API에 대해서는 모든 요청을 허가
                .requestMatchers("/v1/mem/login").permitAll()
                .requestMatchers("/v1/mem/check-dup-id").permitAll()
                .requestMatchers("/v3/api-docs/**").permitAll()
                .requestMatchers("/swagger-ui/**").permitAll()
                // USER 권한이 있어야 요청할 수 있음
                //.requestMatchers("/v1/com/*").hasRole("USER")
                // 이 밖에 모든 요청에 대해서 인증을 필요로 한다는 설정
                .anyRequest().authenticated()
                .and()
                // JWT 인증을 위하여 직접 구현한 필터를 UsernamePasswordAuthenticationFilter 전에 실행
                .addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider), UsernamePasswordAuthenticationFilter.class)
                .build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        // BCrypt Encoder 사용
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }


}

 

7. UserDetails Interface 구현

import java.util.ArrayList;
import java.util.Collection;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;


@Data
@AllArgsConstructor
@Builder
@SuppressWarnings("serial")
public class CustomUserDetails implements UserDetails {
	
	private String username;
	private String password;
	private String usrNo;
	private String name;
	private String auth;
	private int enabled;
	
	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		ArrayList<GrantedAuthority> authList = new ArrayList<GrantedAuthority>();
		authList.add(new SimpleGrantedAuthority(auth));
		return authList;
	}

	@Override
	public String getPassword() {
		return password;
	}

	@Override
	public String getUsername() {
		return username;
	}

	@Override
	public boolean isAccountNonExpired() {
		return true;
	}

	@Override
	public boolean isAccountNonLocked() {
		return true;
	}

	@Override
	public boolean isCredentialsNonExpired() {
		return true;
	}

	@Override
	public boolean isEnabled() {
		return enabled==1?true:false;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	public String getUsrNo() {
		return usrNo;
	}

	public void setUsrNo(String usrNo) {
		this.usrNo = usrNo;
	}

}

 

8. UserDetailsService Interface 구현

import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import com.expetdia.member.application.port.out.LoginOutPort;
import com.expetdia.member.domain.CustomUserDetails;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class CustomUserDetailsService implements UserDetailsService {

    private final LoginOutPort loginOutPort;

    private final PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    	
    	CustomUserDetails user = loginOutPort.findByUsername(username);
    	
    	if(user == null) {
    		throw new UsernameNotFoundException("username " + username + " not found");
    	}
    	
        return User.builder()
                .username(user.getUsername())
                .password(user.getPassword())
                .roles(user.getAuth())
                .build();
    }

}

 

9. 최종적으로 인증을 사용할 Service 구현

    @Override
    public JwtToken userLogin(String username, String password) {
    	// 1. ID / PASSWORD 확인
    	UserVO vo = loginOutPort.checkUserInfo(CustomUserDetails.builder().username(username).build());
    	    	
    	if(vo == null || !passwordEncoder.matches(password, vo.getLgnPwd())) {
    		throw new LoginAuthenticationException("");
    	}
    	
    	UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
        // 2. 실제 검증. authenticate() 메서드를 통해 요청된 Member 에 대한 검증 진행
        // authenticate 메서드가 실행될 때 CustomUserDetailsService 에서 만든 loadUserByUsername 메서드 실행
        Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);
        // 3. 인증 정보를 기반으로 JWT 토큰 생성
        JwtToken jwtToken = jwtTokenProvider.generateToken(authentication);
		return jwtToken;
	}
반응형
블로그 이미지

Mr.비타민

,
반응형

이번에는 Statement가 아닌 PreparedStatement를 활용하여 

데이터를 핸들링하는 예제를 작성해보자.


JdbcConnector.java

package com.util;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

import com.bean.UserBean;


public class JdbcConnector {
	
	public static Connection getConnection() throws ClassNotFoundException, SQLException{
		
		//DB 종료에 따른 JDBC DRIVER 클래스
		Class.forName("com.mysql.jdbc.Driver");
		
		//DB접속 url
		String url = "jdbc:mysql://localhost/test";
		//DB접속 ID
		String id = "root";
		//DB접속 패스워드
		String pw = "1234";
		
		//접속정보로 JDBC 연결 커넥션 생성
		Connection conn = DriverManager.getConnection(url,id,pw);
		
		return conn;
	}
	public static void main(String args[]) throws ClassNotFoundException, SQLException {
		//커넥션생성
		Connection conn = getConnection();
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		UserBean user = new UserBean();
		user.setId("pby0716");
		user.setName("박병영");
		user.setEmail("pby0716@naver.com");
		
		String sql1 = "INSERT INTO MEMBER(ID,NAME,EMAIL) VALUES (?,?,?)";
		
		//PreaparedStatement 생성 후 실행할 쿼리정보 등록
		pstmt = conn.prepareStatement(sql1);
		
		//?에 대한 하는 가변부분 셋팅
		pstmt.setString(1, user.getId());
		pstmt.setString(2, user.getName());
		pstmt.setString(3, user.getEmail());
		
		int count = pstmt.executeUpdate();
		if(count > 0) {
			System.out.println("Insert 성공");
		}else {
			System.out.println("Insert 실패");
		}
		
		/*Insert 한 데이터를 조회하는 예제*/
		
		//받아올 id를 담으면 된다. 지금은 예제로써 임의로 담아두었다.
		String id = "pby0716";
		
		//실행 쿼리
		String sql2 = "SELECT ID, NAME, EMAIL FROM MEMBER WHERE ID = ?";
		//PreaparedStatement 생성 후 실행할 쿼리정보 등록
		pstmt = conn.prepareStatement(sql2);
		//위 sql에 담겨있는 쿼리에 가변하는 변수(id)를 세팅하는 부분
		pstmt.setString(1, id);
		
		//결과를 담을 ResultSet 생성 후 결과 담기
		rs = pstmt.executeQuery();
		
		//결과를 담을 ArrayList생성
		ArrayList<UserBean> list = new ArrayList<UserBean>();
		
		//ResultSet에 담긴 결과를 ArrayList에 담기
		while(rs.next()) {
			UserBean bean = new UserBean();
			bean.setId(rs.getString("ID"));
			bean.setName(rs.getString("NAME"));
			bean.setEmail(rs.getString("EMAIL"));
			list.add(bean);
		}
		//결과물 출력
		for(int i=0; i<list.size(); i++) {
			System.out.println("회원아이디:"+list.get(i).getId());
			System.out.println("회원이름:"+list.get(i).getName());
			System.out.println("회원이메일:"+list.get(i).getEmail());
		}
	}
}

이전에 사용했던 Statement와 PreparedStatement의 차이가 무엇일까?


Statement의 경우에는 완성형 쿼리를 담아서 실행을 하게되지만,

PreparedStatement의 경우에는 가변처리되어야하는 부분에 대해서 ?로 처리하여 쿼리를 바인딩한 후에도 핸들링하여 사용할 수 있다.


완전한 쿼리가 실행될때는 Statement객체를 사용하는 것이 속도측면에서 빠르며,

불완전한 쿼리를 가변처리를 하며 반복적으로 사용할 경우에는 PreparedStatement객체를

사용하는 것이 빠르다.


예제소스에서도 보듯이 Statement의 경우에는 실행하기직전에 쿼리를 담아서 컴파일처리를 하며, PreparedStatement의 경우에는 객체 생성시에 쿼리를 미리 담아서 ?에 대한부분을 미리 처리한 후 컴파일해놓고 처리를 한다.


때에 따라서 해당 두가지를 적절히 사용하면, DB속도 및 소프트웨어 속도 면에서 향상된 프로그램을 개발할 수 있다.!


반응형
블로그 이미지

Mr.비타민

,
반응형

JAVA에서 프래그램을 작성하다보면 DB에 연결하여 데이터를 가져와야하는 경우가 많다.


해당 방법을 위하여 Connection 부터 데이터 처리까지의 방법을 확인해보자.



JdbcConnector.java

package com.util;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;

import com.bean.UserBean;


public class JdbcConnector {
	
	public static Connection getConnection() throws ClassNotFoundException, SQLException{
		
		//DB 종료에 따른 JDBC DRIVER 클래스
		Class.forName("com.mysql.jdbc.Driver");
		
		//DB접속 url
		String url = "jdbc:mysql://localhost/test";
		//DB접속 ID
		String id = "root";
		//DB접속 패스워드
		String pw = "1234";
		
		//접속정보로 JDBC 연결 커넥션 생성
		Connection conn = DriverManager.getConnection(url,id,pw);
		
		return conn;
	}
	public static void main(String args[]) throws ClassNotFoundException, SQLException {
		//커넥션생성
		Connection conn = getConnection();
		//실행 쿼리
		String sql = "SELECT ID, NAME, EMAIL FROM MEMBER";
		//Statement 생성 후 실행할 쿼리정보 등록
		Statement stmt = conn.createStatement();
		//결과를 담을 ResultSet 생성 후 결과 담기
		ResultSet rs = stmt.executeQuery(sql);
		
		//결과를 담을 ArrayList생성
		ArrayList<UserBean> list = new ArrayList<UserBean>();
		
		//ResultSet에 담긴 결과를 ArrayList에 담기
		while(rs.next()) {
			UserBean bean = new UserBean();
			bean.setId(rs.getString("ID"));
			bean.setName(rs.getString("NAME"));
			bean.setEmail(rs.getString("EMAIL"));
			list.add(bean);
		}
		//결과물 출력
		for(int i=0; i<list.size(); i++) {
			System.out.println("회원아이디:"+list.get(i).getId());
			System.out.println("회원이름:"+list.get(i).getName());
			System.out.println("회원이메일:"+list.get(i).getEmail());
		}
	}
}

UserBean.java

package com.bean;

public class UserBean {
	String id;
	String name;
	String email;
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
}

출력물 : 
회원아이디:pby0716
회원이름:박병영
회원이메일:pby0716@naver.com
회원아이디:qudduddl
회원이름:박병영
회원이메일:young3629@gamil.com


2가지의 데이터가 출력이 된다.

다음장에는 PreparedStatement를 사용하여 Insert, Select를 핸들링하는 방법을 확인해보자.


반응형
블로그 이미지

Mr.비타민

,
반응형

어플리케이션 개발을 하기위해서는 DB연동은 필수 이기때문에,


오늘은 MYSQL을 설치하는 것으로 포스팅합니다!


https://dev.mysql.com/downloads/windows/installer


해당 URL로 접속하여 MYSQL 설치파일을 다운로드 받습니다.




우선 다운로드 버튼을 눌러서 아래 다운로드 페이지로 이동.



우리는 로그인없이 다운로드를 받을것이기 때문에, 아래 부분을 클릭합니다.


다운로드가 완료 되고나면, 파일을 실행하여 설치 스텝을 진행!!



licences 승인 클릭 후 Next~



우리는 개발용으로 쓸것이기때문에 Developer Default 선택후 Next~



본인이 해당하는 사항이 있다면 추가적으로 Execute로 설치를 진행하고,

없다면 과감하게 Next~



본격적으로 MYSQL 설치에 필요한 요소들을 설치를 진행합니다. Execute~



설치가 완료되고나면 Next~



이제 서버로써 필요한 설정정보들을 진행할 단계입니다.

Next~



우리는 별도의 InnoDB Cluster를 사용하지않고 기본형으로 설치를 할것이기에 

Standalone MySQL Server / Classic MySQL Replication을 선택후 Next~



개발용 타입 선택과 연결할 PORT 설정을 본인에 맞게끔 설정 후 Next



root 계정의 비밀번호 설정을 한 후 Next



윈도우상에서 서버스명으로 MySQL57(변경가능) Next



별도의 문서 저장소를 사용하지않을것이기에 체크하지않고 Next



설정에 관한 내용을 실행을 한 후 서버관련 설정을 완료.



남은 두가지 사항에 대해서는 거의 Skip이라고 보면됨. Next



Finish~



Next~



서버연결이 정상적으로 되는지 root 계정에 대한 접속을 확인 후 Next



최종적으로 Execute



Next~



설치완료를 알리는 Finish




위와 같은 Workbench 창이 뜬다면 정상적으로 설치가 완료 된 상태.


이제 본격적으로 MySQL을 사용하여 개발을 진행해 봅시다!



반응형
블로그 이미지

Mr.비타민

,
반응형

우선 Spring Framework 개발툴로써, 

Eclipse도 사용하지만 Eclipse의 경우는 필요한 플러그인 설치를 다시 해줘야하기때문에 

Spring 개발에 맞춰져있는 STS(Spring Tool Suite)를 설치하도록 한다.


필요 설치 내역 : Java8 (https://java.com/ko/download) 설치


STS를 설치하기위하여 해당 사이트로 이동하여 후 파일을 받아보자.


https://spring.io/tools



STS 압축파일을 받은 후 설치경로에 압축을 풀어서 진행하자.


압축해제 후 아래경로에 있는 STS.exe 파일을 실행.



정상적으로 실행되었다면, 최초에 workspace 경로 관련 팝업창이 뜬다.



workspace 설정을 완료한 후, Launch를 클릭하면 본격적으로 STS 개발툴이 실행된다.




이제 본격적으로 Spring Framework에 맞춰서 개발을 시작해보자!

반응형
블로그 이미지

Mr.비타민

,
반응형

SELECT문으로 검색을 하다보면 특정 문자가 포함된 조건으로 검색을 할때가 있다.


예를들어 학번이 07학번인 학생들을 검색하고 싶다. 그렇다면 형식이 2007xxxx인 사람들을 검색해야 할것이다. 앞자리에 2007은 무조건 포함되고 뒷숫자자리는 어떻게 되도 상관없다. 그럴때 사용하는 것이 like함수이다.


select * from student where stu_num like '2007%';


이라고 쿼리를 실행하게되면 20070001, 20070002, .... ~20079999 사이 모두 검색이가능하다.

반응형
블로그 이미지

Mr.비타민

,
반응형
웹프로그래밍을 하다보면 회원가입이나 프로필 등등에서 사진을 등록하고 바로보고싶을경우가 있다. 기본적으로 IE와 크롬에서 현재는 fakepath로 막아놓아서 파일경로를 읽어들일수없는데, 아래와 같은 방법을 사용하면 사진을 등록후 바로 미리보기 이미지화시킬수있다. 아래는 javascript코드이다.
function previewImage(targetObj, View_area) {
	var preview = document.getElementById(View_area); //div id
	var ua = window.navigator.userAgent;

	//ie일때(IE8 이하에서만 작동)
	if (ua.indexOf("MSIE") > -1) {
		targetObj.select();
		try {
			var src = document.selection.createRange().text; // get file full path(IE9, IE10에서 사용 불가)
			var ie_preview_error = document
					.getElementById("ie_preview_error_" + View_area);

			if (ie_preview_error) {
				preview.removeChild(ie_preview_error); //error가 있으면 delete
			}

			var img = document.getElementById(View_area); //이미지가 뿌려질 곳

			//이미지 로딩, sizingMethod는 div에 맞춰서 사이즈를 자동조절 하는 역할
			img.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"
					+ src + "', sizingMethod='scale')";
		} catch (e) {
			if (!document.getElementById("ie_preview_error_" + View_area)) {
				var info = document.createElement("

"); info.id = "ie_preview_error_" + View_area; info.innerHTML = e.name; preview.insertBefore(info, null); } } //ie가 아닐때(크롬, 사파리, FF) } else { var files = targetObj.files; for (var i = 0; i < files.length; i++) { var file = files[i]; var imageType = /image.*/; //이미지 파일일경우만.. 뿌려준다. if (!file.type.match(imageType)) continue; var prevImg = document.getElementById("prev_" + View_area); //이전에 미리보기가 있다면 삭제 if (prevImg) { preview.removeChild(prevImg); } var img = document.createElement("img"); img.id = "prev_" + View_area; img.classList.add("obj"); img.file = file; img.style.width = '150px'; img.style.height = '200px'; preview.appendChild(img); if (window.FileReader) { // FireFox, Chrome, Opera 확인. var reader = new FileReader(); reader.onloadend = (function(aImg) { return function(e) { aImg.src = e.target.result; }; })(img); reader.readAsDataURL(file); } else { // safari is not supported FileReader //alert('not supported FileReader'); if (!document.getElementById("sfr_preview_error_" + View_area)) { var info = document.createElement("p"); info.id = "sfr_preview_error_" + View_area; info.innerHTML = "not supported FileReader"; preview.insertBefore(info, null); } } } } }

HTML BODY영역에서 file에 등록하면 지정한 영역에 뿌려줄수있다.
onchange속성을 사용하여 파일이 등록되거나 변경될 시에 바로바로 적용가능하다.
onchange="previewImage(this,'영역아이디')


반응형

'IT관련 > JavaScript' 카테고리의 다른 글

Servlet alert 사용  (0) 2014.06.21
PrintWriter 사용시 인코딩 (한글깨짐)  (0) 2014.06.21
SELECTBOX OPTION SCRIPT  (0) 2014.06.13
블로그 이미지

Mr.비타민

,