728x90

프로젝트를 진행 중에 한 리스트에서 연속된 두 VO를 사용해야 하는데

어떻게 할 수 있을까 고민하다가 생각난 것을 적용해보니 잘 되길래 공유해봅니다.

 

JSTL core의 foreach 태그에는 여러 속성이 있지만 주로 사용하는 방법은 아래와 같습니다.

<c:foreach var="vo" items="${List}">
	<div> ${vo.title} </div>
</c:foreach>

 이렇게 되면 items에 있는 변수가 인덱스 순으로 vo에 담겨서 진행하게 되는데 여기에 속성 몇 개를 추가하면 됩니다.

 

<c:foreach var="vo" items="${List}" varStatus="status" step="2">
	<div> ${vo.title} </div>
    <div> ${List[status.index + 1].title} </div>
</c:foreach>

varStatus 속성으로 설정한 status로 현재 반복문의 인덱스를 받아올 수 있습니다.

step 속성으로는 반복문을 첫 번째 항목부터 시작하여 스텝마다 진행한다는 뜻입니다.

이를 활용하면 세 개씩도 한 반목문 안에 사용할 수 있습니다.

 

예를 들어 아래와 같이 10까지의 숫자가 들어있는 리스트가 있다고 했을 때

String[] list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

아래의 코드를 사용하면 1, 3, 5 ,7, 9만 출력합니다.

<c:foreach var="num" items="${list}" varStatus="status" step="2">
	<div> ${num} </div>
</c:foreach>

여기서 step 속성만 3으로 바꾸면 1, 4, 7, 10이 출력됩니다.

728x90
728x90

https://developers.naver.com/main/

 

NAVER Developers

네이버 오픈 API들을 활용해 개발자들이 다양한 애플리케이션을 개발할 수 있도록 API 가이드와 SDK를 제공합니다. 제공중인 오픈 API에는 네이버 로그인, 검색, 단축URL, 캡차를 비롯 기계번역, 음

developers.naver.com

위 사이트에서 기본적인 서비스 URL과 Callback URL 같은 설정은 맞췄다고 가정하겠습니다.

네이버 로그인 API를 통해서 회원가입까지 구현하기 위해서 기본적인 로직은 크게 5단계로 이루어져 있다고 봅니다.

api 이용 로직


1. 로그인 버튼

API를 사용하려면 우선 로그인 버튼에 내 어플리케이션의 이용 동의를 받는 링크를 설정하는 것입니다.

1. naverlogin.jsp
<%@ page="" import="java.net.URLEncoder" %="">
<%@ page="" import="java.security.SecureRandom" %="">
<%@ page="" import="java.math.BigInteger" %="">
<%@ page="" contentType="text/html;charset=UTF-8" language="java" %="">
<html>
  <head>
    <title>네이버로그인</title>
  </head>
  <body>
  <% String="" clientId="YOUR_CLIENT_ID" ;="" 애플리케이션="" 클라이언트="" 아이디값";="" 
  redirectURI="URLEncoder.encode("YOUR_CALLBACK_URL"," "UTF-8");="" 
  SecureRandom="" random="new" SecureRandom();="" 
  state="new" BigInteger(130,="" random).toString();="" 
  apiURL="https://nid.naver.com/oauth2.0/authorize?response_type=code" 
        +="&client_id=" clientId;="" redirectURI;="" 
        state;="" session.setAttribute("state",="" state);="" %="">
  <a href="<%=apiURL%>"><img height="50" src="http://static.nid.naver.com/oauth/small_g_in.PNG"/></a>
  </body>
</html>

naver developers의 튜토리얼에는 이런식으로 쓰여있습니다.

하지만 저는 클라이언트 아이디나 콜백 주소 그리고 state는 페이지에서 보여주기 싫어서 

로그인 버튼이 보여주는 페이지로 넘어갈 때 컨트롤러에서 객체로 담아 페이지로 값을 넘겨주었습니다.

그러기 위해선 api 관련한 정보를 담을 클래스가 필요해서 그걸 먼저 만드시는 게 좋습니다.

public class SnsVO {
	// naver developers 내 어플리케이션에서 확인
    private String naver_client_id = "본인의 클라이언트 아이디"; 
    // naver developers 내 어플리케이션에서 확인
    private String naver_client_secret = "본인의 클라이언트 비밀번호";
    // 여러개 있을 수 있으니 비워두고 필요할 상황에 set해서 사용가능
    private String naver_redirect_uri = "설정한 리다이렉트 주소";

    private String grant_type;
    private String code;
    private String state;
    private String refresh_token;
    private String access_token;
    private String token_type;
    private String expires_in;
    private String apiURL;
 }

getter/setter를 만드시고 그 후에는 네이버 로그인 관련 메서드를 관리하는 클래스를 만들었습니다.

거기서 a 태그에 설정할 링크를 받아오는 메서드를 우선 만들어 보도록 하겠습니다.

//로그인 관련 vo 객체 profile 객체는 좀더 아래에 나올 예정
SnsVO vo = new SnsProfileVO();

public SnsVO loginApiURL() throws UnsupportedEncodingException {

    vo.setNaver_redirect_uri(URLEncoder.encode(vo.getNaver_redirect_uri(), "UTF-8"));
    SecureRandom random = new SecureRandom();
    vo.setState(new BigInteger(130, random).toString());
    String apiURL = "https://nid.naver.com/oauth2.0/authorize?response_type=code";
    apiURL += "&client_id=" + vo.getNaver_client_id();
    apiURL += "&redirect_uri=" + vo.getNaver_redirect_uri();
    apiURL += "&state=" + vo.getState();

    vo.setApiURL(apiURL);

    return vo;
}

위 코드를 보시면 vo객체에 apiURL을 저장합니다. 

네이버 측에서 리다이렉트 주소를 인코딩해서 보내달라고 요청했으니 잊지 마세요.

loginApiURL 메서드를 통해서 받은 vo 객체를 컨트롤러에서 페이지로 보내는 일만 남았습니다.

spring의 home에 버튼이 있다고 가정하겠습니다.

//컨트롤러
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Model model, HttpServletRequest request, HttpSession session) throws UnsupportedEncodingException {

	// 네이버 apiurl을 받아온다.
    SnsVO navervo = naverservice.loginApiURL(); 
    session.setAttribute("state",navervo.getState()); 
    model.addAttribute("navervo", navervo);

    return "home";
}
//HOME.jsp
<a href="${navervo.apiURL}">
	<img height="50" src="http://static.nid.naver.com/oauth/small_g_in.PNG"/>
</a>

튜토리얼과 다르게 뷰페이지에서 간단하게 버튼을 생성했습니다.

 


2. Callback

다음으로 로그인 버튼의 링크 주소와 callback주소에 별다른 이상이 없다면

리다이렉트 주소로 code값과 state값이 반환됩니다.

 

여기서는 리다이렉트 주소를 http://localhost:8090/controller/callback.do으로 가정하겠습니다.

우리는 위에서 sns vo를 만들어 뒀기 때문에 리다이렉트를 받는 해당 컨트롤러 매개변수에 snsvo를

넣어두면 값을 무리 없이 받을 수 있습니다.  

@RequestMapping(value="/callback.do")
public String naverLogin(SnsVO snsvo) throws IOException {
	System.out.println(snsvo.getCode());
    
    return "common/naverCallback";
}

리턴 값은 페이지로 보낼지 다른 서비스 로직을 구현할지에 따라 다르지만

컨트롤러 매개변수에 snsvo만 설정해두면 값을 받을 수 있다는 것을 인지하는 게 중요합니다.

sysout으로 제대로 값을 받아왔는지 확인해도 좋습니다.


3. Access_Token 발급

이제 accseeToken 까지만 발급받으면 로그인 부분은 끝이라고 할 수 있습니다.

새로 페이지나 버튼, 컨트롤러를 만들어서 토큰을 받아올 수도 있으나

여기서는 리다이렉트 컨트롤러에 추가로 구현해보겠습니다.

그러기 위해서는 먼저 메서드를 만들어야 합니다.

네이버 로그인 개발 가이드를 보면 get/post 두 방식으로 요청을 할 수 있고 json으로 응답합니다.

public SnsVO getAccessToken(SnsVO snsVO) {
    String apiURL;
    apiURL = "https://nid.naver.com/oauth2.0/token?grant_type=authorization_code&";
    apiURL += "client_id=" + snsVO.getNaver_client_id();
    apiURL += "&client_secret=" + snsVO.getNaver_client_secret();
    apiURL += "&redirect_uri=" + snsVO.getNaver_redirect_uri();
    apiURL += "&code=" + snsVO.getCode();
    apiURL += "&state=" + snsVO.getState();

    try {
          URL url = new URL(apiURL);
          HttpURLConnection con = (HttpURLConnection)url.openConnection();
          con.setRequestMethod("GET");

          int responseCode = con.getResponseCode();
          BufferedReader br;

          if(responseCode==200) {
            br = new BufferedReader(new InputStreamReader(con.getInputStream()));
          } else {
            br = new BufferedReader(new InputStreamReader(con.getErrorStream()));
          }
          String inputLine;
          while ((inputLine = br.readLine()) != null) {
            ObjectMapper mapper = new ObjectMapper();
            snsVO = mapper.readValue(inputLine, SnsVO.class);
          }
          br.close();
        } catch (Exception e) {
          System.out.println(e);
        }
    return snsVO;			
}

 

getAccessToken(SnsVO snsVO) 메서드의 snsVO는 리다이렉트 주소로 반환된 code값을 사용하기 위해 설정했습니다.

HttpURLConnection 클래스를 통해서 설정한 apiURL 주소에 get방식으로 요청을 보냅니다.

만약 api주소가 정확하여 응답 코드가 200이면 응답 데이터를 버퍼에 담습니다.

하지만 응답 데이터는 json 형식이라 우리가 사용하기 쉽게 맞춰줄 필요가 있습니다.

버퍼에 담긴 값을 ObjectMapper의 readValue 메서드를 이용하면 snsVO 객체에 해당하는 멤버 변수에 

자동으로 맞춰 값을 담아줍니다. 

 

혹시 받아온 json 데이터에서 객체에 없는 값을 무시하고 싶으시면 아래 코드 한 줄 추가하면 됩니다.

mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);

 

그러면 이제 컨트롤러의 코드는 이렇습니다.

@RequestMapping(value="/callback.do")
public String naverLogin(SnsVO snsvo) throws IOException {
	System.out.println(snsvo.getCode());
    
    snsvo = naverService.getAccessToken(snsvo);
    return "common/naverCallback";
}

naverService는 해당 메서드가 있는 클래스입니다.

그리고 그 값을 받는 snsvo는 새로운 객체를 생성해서 받아도 상관없습니다.

 


4. Access_Token으로 유저 프로필 정보 받기

유저 프로필을 받는 이유는 여러 가지가 있을 수 있지만 저는 api를 통해 회원가입 기능도 구현하려고

유저 프로필 정보를 받았습니다.

또한 프로필 정보도 json 형식으로 응답하기 때문에 ObjectMapper로 객체에 저장하는 과정까지 해보겠습니다.

그 이후로 데이터 베이스와 비교해 회원인지 아닌지 확인하는 과정이나 추가 데이터를 받는 것까지는 하지 않겠습니다.

이 과정은 좀 길어서 세 개의 메서드로 나눴습니다.

 

그전에 프로필 정보를 저장할 vo 클래스를 만들어주세요.

public class SnsProfileVO extends SnsVO {

    private String resultcode;
    private String message;
    @JsonProperty
    private JsonNode response; 
    private String age;
    private String mobile;
    private String id;
    private String name;
    private String nickname;
    private String email;
    private String gender;
    private String birthyear;
    private String birthday;
    private String age_range;
}

getter/setter를 생성해주세요.

response는 데이터 타입이 JsonNode인데 응답 데이터의 형식이 아래와 같아서 한 번에 객체에 저장하려고 그렇습니다.

{
    "resultcode": "00",
    "message": "success",
    "response": {
        "email": "openapi@naver.com",
        "nickname": "OpenAPI",
        "profile_image": "https://ssl.pstatic.net/static/pwe/address/nodata_33x33.gif",
        "age": "40-49",
        "gender": "F",
        "id": "32742776",
        "name": "오픈 API",
        "birthday": "10-01"
    }
}

만약 sns 로그인 API를 네이버 하나만 사용하던지 각각 따로 나눠 사용할 거면

데이터 타입을 JsonNode로 하는 게 아니라 내부 클래스를 이용하는 게 훨씬 편합니다.

다음으로는 프로필 정보를 받아오는 메서드입니다.

public SnsProfileVO getUserProfile(SnsVO snsVO) throws IOException {
    SnsProfileVO snsProfile = new SnsProfileVO();

    String token = snsVO.getAccess_token();
    String header = "Bearer " + token;
    String apiURL = "https://openapi.naver.com/v1/nid/me";

    Map<String, String> requestHeaders = new HashMap<String, String>();
    requestHeaders.put("Authorization", header);
	
    // get은 만든 메서드
    snsProfile = get(apiURL, requestHeaders);
    return snsProfile;
}

private static SnsProfileVO get(String apiURL, Map<String,String> requestHeaders) throws IOException {
    URL url = new URL(apiURL);
    HttpURLConnection con = (HttpURLConnection) url.openConnection();

    try {
        con.setRequestMethod("GET");
        for(Map.Entry<String, String> header : requestHeaders.entrySet()) {
        	con.setRequestProperty(header.getKey(), header.getValue());
   		}
    	int responseCode = con.getResponseCode();
        if(responseCode == HttpURLConnection.HTTP_OK) {
        	// readyBody는 아래에 만든 메서드
            return readyBody(con.getInputStream());
        }else {
        	return readyBody(con.getErrorStream());
        }
    }catch(IOException e){
    	throw new RuntimeException("API Error", e);
    }finally {
    	con.disconnect();
    }
}

private static SnsProfileVO readyBody(InputStream body) {
    InputStreamReader streamReader = new InputStreamReader(body);
    SnsProfileVO snsProfile = new SnsProfileVO();

    try(BufferedReader lineReader = new BufferedReader(streamReader)){
        String line;
        while((line = lineReader.readLine()) != null) {
            ObjectMapper mapper = new ObjectMapper();
            mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            snsProfile = mapper.readValue(line, SnsProfileVO.class);
            snsProfile = mapper.readValue(snsProfile.getResponse().toString(), SnsProfileVO.class);

        }
    	return snsProfile;
    }catch(IOException e) {
    	throw new RuntimeException("API bufferedReader error", e);
    }
}
for(Map.Entry<String, String> header : requestHeaders.entrySet()) {
        	con.setRequestProperty(header.getKey(), header.getValue());
    }

for문으로 헤더에 토큰 값을 저장합니다. 그리고 요청을 보내 응답을 받습니다.

snsProfile = mapper.readValue(line, SnsProfileVO.class);
snsProfile = mapper.readValue(snsProfile.getResponse().toString(), SnsProfileVO.class);

두 번의 readValue로 프로필 값을 객체에 저장합니다. 

그런데 이렇게 할 경우 객체가 두 개 생성되는 문제를 발견했습니다.

프로필 객체의 response 변수에 담겼던 값만 사용한다면 문제가 없지만

accessToken이나 code를 사용하려면 다른 식으로 저장해야 합니다.

이 문제 때문에 로그인 API를 하나만 사용할 거라면 앞서 이야기한 내부 클래스를 이용하는 게 좋습니다.

여기까지 하면 리다이렉트 주소로 한 번에 프로필 정보까지 받을 수 있습니다.

 

@RequestMapping(value="/callback.do")
public String naverLogin(SnsVO snsvo) throws IOException {
    System.out.println(snsvo.getCode());

    snsvo = naverService.getAccessToken(snsvo);
    SnsProfileVO snsProfile = naverService.getUserProfile(snsvo);
    return "common/naverCallback";
}

이제 프로필 정보까지 받아왔으니 구현하려는 기능에 맞춰 Callback 주소를 설정하면 됩니다.

  • 로그인 
  • 회원가입
  • 토큰 갱신
  • 네이버 이용동의 연결해제 등

원하는 기능에 맞춰 메서드를 사용해 구현할 수 있습니다.

이번에 팀 프로젝트를 하면서 구현해본 API입니다.

부족한 점이 있을 수 있으니 너그러이 봐주시고 고칠 점을 알려주시면 고맙습니다.

카카오나 구글도 비슷하기 때문에 기회가 된다면 다음에 작성해보겠습니다.

728x90
728x90

spring에서 네이버 로그인 API를 사용하려고 시도하면서 회원정보를 VO객체에 담으려고 할 때 오류가 났다.

ObjectMapper를 사용해 readValue() 메서드를 사용했는데 response의 값이 string이 아니고 json형식이라 그렇듯 하다.

아래는 네이버 로그인 API에서 응답으로 주는 사용자 정보로 key값 안에 배열이 하나 더 있다.

{
"resultcode":"00",
"message":"success",
"response":
    {
        "id":value,
        "nickname": value,
        "age": value,
        "gender": value,
        "email": value,
        "mobile": value,
        "mobile_e164": value,
        "name": value,
        "birthday": value,
        "birthyear": value
        }
}

해결책은 두가지가 있다.

  1. response 안의 키값들을 멤버 변수로 하는 클래스를 생성하기
  2. response의 데이터 타입을 JsonNode로 바꾸기

첫 번째 방법은 클래스 안에 클래스를 생성하면 된다.

// VO class
public class NaverProfileVO {
	private String resultcode;
	private String message;
	private InnerNaverProfileVO response;
	
	public class InnerNaverProfileVO{
		private String email;
		private String nickname;
		private String profile_image;
		private String age;
		private String gender;
		private String id;
		private String name;
		private String birthday;
		private String birthyear;
		private String mobile;
    }
}
getter/setter
// vo 객체 안에 value 값을 담는 메서드
NaverProfileVO vo = new NaverProfileVO();

ObjectMapper mapper = new ObjectMapper();
vo = mapper.readValue(jason문자열, NaverProfileVO.class);

이렇게 하면 NaverProfileVO 객체 안에 값이 다 담긴다.

그러나 네이버 뿐만 아니라 카카오와 구글 로그인 api도 구현하려고 하다 보니

세 가지를 통합해서 vo를 생성하기 때문에 중복된 변수들이 있어 첫 번째 방법은 사용하기 힘들다.

그래서 두 번째 방법을 사용했다.

 

public class SnsProfileVO extends SnsVO {
	//kakao
	private String properties;
	private String kakao_account;
	private Long kakaoid;
	
	//naver
	private String resultcode;
	private String message;
	@JsonProperty
	private JsonNode response; 
	private String age;
	private String birthyear;
	private String mobile;
	private String id;
	
	//google
	private String aud;
	private String sub;
	
	//common
	private String name;
	private String nickname;
	private String email;
	private String gender;
	private String birthday;
	private String age_range;
}

response의 데이터 타입을 JsonNode로 바꾸고 @JsonProperty 어노테이션을 작성했다.

이상태로 매핑을 하면 response에 json 데이터를 담을 수 있다.

담은 데이터를 다시한번 매퍼로 읽으면 객체에 값을 담을 수 있다.

다른 방법들이 있긴 하지만 다른 방법들은 하나하나 값을 저장하는 방식이라

가장 코드를 적게 사용하는 방법을 찾다 보니 이 방법을 찾게 되었다.

 

SnsProfileVO snsProfile = new SnsProfileVO();
ObjectMapper mapper = new ObjectMapper();
snsProfile = mapper.readValue(json문자열, SnsProfileVO.class);
snsProfile = mapper.readValue(snsProfile.getResponse().toString(), SnsProfileVO.class);

 

 

728x90
728x90

MyBatis Mapper XML파일

태그

  • 구문 태그 INSERT, UPDATE, DELETE, SELECT
  • sql - 다른 구문에서 재사용하기 위한 조각
  • cache - 해당 네임스페이스를 위한 캐시 설정
  • cache-ref - 다른 네임스페이스의 캐시 설정에 대한 참조
  • resultMap - 데이터베이스 결과 데이터를 객체에 로드하는 방법을 정의하는 엘리먼트
  • selectKey - 구문 태그의 실행 전이나 후에 실행할 구문을 지정한다.
  • => keyProperty 구문의 결과가 세팅될 프로퍼티
  • => order (BEFORE, AFTER)를 세팅할 수 있다. 말 그대로 sql 구문의 이전과 이후

태그의 속성

  • parameterType - SQL 구문에 사용할 파라미터 타입을 지정한다. 
  • => MyBatis의 경우 파라미터를 하나만 받아올 수 있기 때문에 객체로 받아오던지 hashmap을 사용한다.
  • => 객체를 넘길 경우 패키지 경로를 포함한 전체 클래스명이나 별칭을 넘겨야 한다. 
  • => 파라미터 표기법 #{} ex) int midx를 받아 온 경우 #{midx}
  • resultType - SQL 구문 작동 후 DB에서 받아오는 결과 타입
  • => 객체를 넘길 경우 패키지 경로를 포함한 전체 클래스명이나 별칭을 넘겨야 한다.

MyBatis CDATA

sql 구문에서 조건문과 같은 비교 연산자를 사용할지 mybatis에서

이를 문자열로 인식하지 않아 오류가 발생할 수 있다.

때문에 비교 연산자와 같이 문자가 아닌 특수문자를 사용할 때에는

오류를 피하고 정확한 구문을 사용하기 위해 CDATA 안에 쿼리를 작성한다.

 

jQuery serialize 메서드

form 태그에서 name 속성을 가진 태그들의 데이터를 문자열로 반환해준다.

<script>
	function Log(){
    	console.log($("#fm").serialize())
    }
</script<
<form id="fm">
	<input type="text" name="id">
    <input type="text" name="pwd">
    <input type="text" name="name">
    <input type="button" onclick="Log()" value="등록">
</form>

<!-- 출력되는 값 -->
<!-- id=input id에 입력한 값&pwd=input pwd에 입력한 값&name= input name에 입력한 값 -->
728x90
728x90

만들려는 사이트가 주식 커뮤니티인 만큼 자신의 자산 추이를 한눈에 볼 수 있는 그래프를 추가하고 싶었는데

그 방법으로 구글차트를 이용해 보겠습니다.

 

 

그래프 하단에 날짜를 지정하고 자산을 입력한 다음 추가 버튼을 누르면 그 정보가 데이터베이스 입력되고 동시에 

그래프와 하단의 목록에 뜨게됩니다.

우선 구글 차트에 들어가서 원하는 차트 타입을 누릅니다.

https://developers.google.com/chart/interactive/docs

저는 선 그래프를 이용했기 때문에 line chart로 설명을 하겠습니다.

왼쪽에 line charts를 눌러주시고 Code it yourself on JSPFiddle을 누르면

예제 코드를 볼 수 있고 데이터도 바꾸면서 확인할 수 있습니다. 

 

html의 script를 본인 html head태그 안에 넣어주시고 

div 태그는 그래프가 그려질 장소이니 그래프를 보여줄 곳에 넣어주면 됩니다.

 

google.charts.load('current', {packages: ['corechart', 'line']});
google.charts.setOnLoadCallback(drawchart);
function drawchart() {
      var data = new google.visualization.DataTable();
      data.addColumn('number', 'X');
      data.addColumn('number', 'Dogs');

      data.addRows([ ]);

      var options = { };

      var chart = new google.visualization.LineChart(document.getElementById('chart_div'));

      chart.draw(data, options);
    }

구글 차트의 기본적인 구조입니다. 

차트를 로드하고 .setOnLoadCallback(); 함수로 html이 전부 로드된 후 매개변수에 들어간 함수를 호출합니다.

data 변수에 데이터 테이블을 생성하고 .addColumn으로 열을 추가합니다

열의 데이터 타입은 많이 있으니 직접 검색해보시면 됩니다.  

.addRows는 만들어진 열에 데이터를 추가하는 것으로 배열 형식으로 추가할 수 있습니다.

options는 그래프의 옵션을 정하는 변수로 x축, y축, 그래프 사이즈 등 여러 옵션을 설정할 수 있습니다.

chart에 그래프가 그려질 곳을 설정하고 .draw로 데이터와 옵션을 추가해 그립니다.

 

저는 oracle db에 있는 데이터를 받아와 출력할 생각이기 때문에 .addRow만 좀 다르게 해 주면 됩니다.한 번에 그리는 방법도 있을 수 있는데 저는 제 실력이 부족해서 한번에 데이터를 받아와 그리는 것을 못했습니다.그래서 html이 전부 그려지고  빈 차트를 그린 후에 거기에 데이터를 추가하는 방법을 선택했습니다.

google.charts.load('current', {packages: ['corechart', 'line'], callback: drawBasic});	
google.charts.setOnLoadCallback(addData);
var data;
var chart;
var options;
function drawBasic() { 
      data = new google.visualization.DataTable();
      data.addColumn('datetime', 'year');
      data.addColumn('number', 'Property');

      data.addRows([
      ]);
      options = {
              width:'100%'
      }

      chart = new google.visualization.LineChart(document.getElementById('chart_div'));
      chart.draw(data, options);
    }

먼저 빈 차트를 그리는 코드입니다.

변수를 두 번째에 그릴 때도 사용할 것이기 때문에 함수 밖에 변수를 설정해줍니다.

저는 x축을 날짜별로 보여줄 거라 데이터 타입을 datetime으로 설정했습니다.

data 행은 두 번째 그릴 때 추가할 거라 빈 값으로 설정해주고 그려주면 끝납니다.

 

var year = [];
var month = [];
var day = [];
var value = [];	 	
<%for(GraphVO gv : glist){%>
year.push(<%=gv.getYear()%>);
month.push(<%=gv.getMonth()%>);
day.push(<%=gv.getDay()%>);
value.push(<%=gv.getMoney()%>);
<% }%>
var len = year.length;
function addData(){
    var arr = new Array();
    for(let i = 0; i<len; i++){
         arr = [new Date(year[i],month[i]-1,day[i]),value[i]];
         data.addRow(arr);
     }
    options = {
            pointSize: 5,
            width:'100%',
            hAxis: {
              title: 'Time',
              format:'yy-MM',
              ticks: [new Date(year[0],month[0]-1,day[0]),new Date(year[len-1],month[len-1]-1,day[len-1])]
            },
            explorer: { axis: 'horizontal' }
          };
    chart.draw(data, options);
}

데이터를 전부 출력하기 위해 컨트롤러에서 받아온 데이터를 변수 배열에 추가해주시고요

for문으로 위에 설정해둔 data 변수에 .addRow해서 일일이 추가해줍니다.

원하는 옵션도 추가해주시고 다시 그려주면 끝납니다.

 

더 쉬운 방법도 물론 있을 수 있으나 처음 사용하다 보니 미숙해서

빈 차트에 새로운 데이터를 덮어 씌우는 방법을 사용해봤습니다.

 

 

아래는 전체 코드입니다.

전체 코드 - https://github.com/seohakman/stockCommu/blob/main/src/main/webapp/member/FinancialGraph.jsp

 

GitHub - seohakman/stockCommu: 커뮤니티 사이트 만들기/ 개인 프로젝트

커뮤니티 사이트 만들기/ 개인 프로젝트. Contribute to seohakman/stockCommu development by creating an account on GitHub.

github.com

 

728x90
728x90

글쓰기 페이지는 로그인했을 때만 이동할 수 있게 만들어뒀다.

제목과 내용을 작성하고 첨부파일을 하나 넣을 수 있다.

 

 

아래는 jsp에서 컨트롤러로 값을 보내는 코드

이미지 사이즈를 재설정하는 imgscalr-lib와 첨부파일 기능을 만들기 위해서 cos.jar 라이브러리를 다운로드하여 사용했다.

파일을 업로드하기 위해서 form enctype 속성을 "multipart/form-data"로 설정해주었다.

이렇게 설정해주면 폼 값을 보낼때 인코딩하지 않고 값을 보낸다.

// 컨트롤러로 내용을 보낸다. 
<script>
    function mainSubmit(){
        document.fm.action="<%=request.getContextPath()%>이동할 컨트롤러";
        document.fm.method="post";
        document.fm.enctype="multipart/form-data"; 
    }
</script>
<form name=fm>
<table>
    <thead>
        <tr>
            <th><input id="subject" name="subject" type="text" placeholder="제목을 입력하세요" required></th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><textarea id="content" name="content" placeholder="내용을 입력하세요" required></textarea></td>
        </tr>
        <tr>
            <td id="filePath"> <input name="filename" type="file"> </td>
        </tr>
    </tbody>
    <tfoot>
        <tr>
            <td>
                <button type="submit" onclick="mainSubmit()">등록</button>
                <button type="button" onclick="history.back();">취소</button>
            </td>
        </tr>
    </tfoot>
</table>
</form>

아래는 컨트롤러에서 글을 DB에 등록하는 코드

sizeLimit는 등록하는 파일의 용량을 제한한다. 이미지 파일일 경우 이렇게 하면 너무 크다...

이전에 form에서 데이터 타입을 multipart/form-data 보냈기 때문에 이전의 request 영역에서 값을 읽어오는 것과 다르게

MultipartRequest 객체를 생성해 여기서 값을 읽는다.

//작성한 글을 DB에 넣는다.
int sizeLimit = 1024*1024*15;
MultipartRequest multi = new MultipartRequest(request, saveFullPath, sizeLimit, "utf-8", new DefaultFileRenamePolicy());

HttpSession session = request.getSession();
String subject = multi.getParameter("subject");
String content = multi.getParameter("content").replace("\r\n", "<br>");
String id = (String) session.getAttribute("id");
int midx = (int)session.getAttribute("midx");

// 열거자에 저장될 파일을 담는 객체를 생성한다.
Enumeration files = multi.getFileNames();
// 담긴 파일객체의 파일 이름을 얻는다.
String file = (String)files.nextElement();
//저장되는 파일 이름
String fileName = multi.getFilesystemName(file);
//원래 파일 이름
String originFileName = multi.getOriginalFileName(file);

MainDAO mdo = new MainDAO();
int value = mdo.insertMain(subject, content, id, midx, fileName);
PrintWriter out = response.getWriter();
if(value == 1) {
    response.sendRedirect(pj+"/main/index.do");
}else{
    out.println("<script>alert('글쓰기 실패');</script>");
}

아래는 DAO의 입력 메서드

public int insertMain(String subject, String content, String ID, int midx, String fileName) {
    // DB에 글을 넣는다.
    int value = 0;
    String sql = "insert into main(bidx,subject,content,midx,writer,viewcount,likecount,filename)" 
    	+ "values(bidx_main.nextval,?,?,?,?,?,?,?)";

    try {
        pstmt = conn.prepareStatement(sql);
        pstmt.setString(1, subject);
        pstmt.setString(2, content);
        pstmt.setInt(3, midx);
        pstmt.setString(4, ID);
        pstmt.setInt(5, 0);
        pstmt.setInt(6, 0);
        pstmt.setString(7, fileName);
        value = pstmt.executeUpdate();

    } catch (SQLException e) {
        e.printStackTrace();
    }
    return value;
}
728x90
728x90

DI 어노테이션을 사용한 방법

  • @Component

Spring Bean Configuration File을 통해 만든 xml의 context:component-scan 태그

- Namespaces에서 context를 체크한다.

<context:component-scan base-package="패키지이름"/>

xml의 context:component-scan 태그 base-package 속성에 패키지 이름을 적어 넣으면

해당 패키지 안에 있는 클래스를 로드하여 @Component 어노테이션에 있는 클래스를 Bean에 등록한다.

@Component 어노테이션의 경우 클래스에 필드가 없는 경우 사용한다.

 

  • @Configuration

자바 클래스를 설정으로 이용할 수 있다. 클래스 상단에 어노테이션을 적용한다.

클래스 안의 메서드를 @Bean 어노테이션으로 Bean으로 등록하고 메서드명은 xml 설정의  id와 같다.

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

@Configuration
public class ApplicationContext {

	@Bean
	public A methodA() {
		A a = new A();
		a.setName("이병건");
		a.setValue("나이: 41");
		return a;
	}
	@Bean
	public B methodB() {
		B b = new B();
		b.setName("BBB");
		b.setA(methodA()); // setter 주입
		return b;
	}
}

AOP (Aspect Oriented Programming 관점지향)

트랜잭션이나 로깅, 보안과 같이 여러 모듈에서 공통적으로 사용하는 기능을 해당 기능을 분리하여 관리할 수 있다.

Spring Bean Configuration File의 Namespaces에서 aop를 체크한다.

용어

  • Aspect : 공통의 관심사들로 이루어진 모듈
  • ex) 로그에 관련된 모듈을 모아둔 클래스/ 메서드 하나가 모듈 하나로 생각하면 된다.
  • Target : 공통 모듈(Aspect)이 적용될 곳 (클래스 또는 메서드)
  • Advice : 실제 적용될 공통 모듈 하나를 의미
  • Joinpoint : advice가 적용되어야 하는 시점
  • Pointcut : target이 상세화 된 것
<context:component-scan base-package="aopEx01"/>
	<bean id="LoggerAOP01" class="aopEx01.Aspect01"/>
	<aop:config>
		<aop:aspect id="Logger01" ref="LoggerAOP01"> <!-- 참조할 Bean -->
        	<!-- expression으로 적용될 곳을 지정 (aopEx01 패키지의 A 클래스) -->
			<aop:pointcut expression="within(aopEx01.A)" id="pointcutA"/>
			<aop:pointcut expression="within(aopEx01.B)" id="PointcutB"/>
			<aop:pointcut expression="within(aopEx01.C)" id="PointcutC"/>
            
            <!-- 상단에 pointcutA로 지정한 aopEx01 패키지 A 클래스의 
            	loggerAop01 메서드를 around로 지정 -->
			<aop:around method="loggerAop01" pointcut-ref="pointcutA"/>
			<aop:before method="loggerAop02" pointcut-ref="PointcutB"/>
			<!-- 오류가 나더라도 무조건 호출되는 모듈 aop:after -->
			<aop:after method="loggerAop03" pointcut-ref="PointcutC"/> 
			<!-- 핵심 로직이 정상 종료 되었을 때 호출되는 공통 모듈 -->
			<aop:after-returning method="loggerAop03" pointcut-ref="PointcutC"/>
			<!-- 핵심 로직이 오류가 발생하여 종료가 되었을 때 호출되는 공통모듈 -->
			<aop:after-throwing method="loggerAop03" pointcut-ref="PointcutC"/>
		</aop:aspect>
	</aop:config>

ProceedingJoinPoint 클래스

  • .getSignature() 호출되는 메서드에 대한 정보를 구한다.
  • .getTarget() 대상 객체를 구한다.
  • .getName 메서드의 이름을 구한다.
  • .toShortString 메서드의 이름을 반환한다.
  • .toLongString 메서드의 리턴타입, 파라미터 타입을 모두 포함해 반환한다.
  • .Proceed 다음 advice 또는 target의 메서드를 진행한다.

 

 

728x90
728x90

POJO (Plain Old Java Object)

특정 자바 모델이나 기능 프레임워크 등을 따르지 않은 자바 오브젝트를 지칭하는 말로 사용되었다.

자바 언어 사양 외에 어떠한 제한에도 묶이지 않은 자바 오브젝트로 다음과 같은 행동을 해서는 안된다.

- 미리 정의된 클래스의 확장

- 미리 정의된 인터페이스의 구현

- 미리 정의된 애너테이션을 포함

그러나 기술적 어려움이나 기타 이유로 많은 프레임워크들이 미리 정의된 애너테이션의 사용을 요구한다.


DI (Dependency Injection 의존성 주입) 

각각의 계층이나 서비스들 강에 의존성이 존재할 경우 프레임워크가 서로 연결시켜준다.

객체를 직접 생성하는게 아니라 외부에서 생성한 후 주입시켜주기 때문에

모듈 간의 결합도가 낮아지고 유연성이 높아진다.

DI의 종류 

- Setter Injection 

B b = new B();
A a = new A();
a.setB(b); // setter injection

- Construction Injection 생성자 주입

B b = new B();
A a = new A(b); // injection

spring의 DI

- 어노테이션을 활용한 DI

-> 어노테이션이란 @를 붙여 사용하는 특별한 의미가 있는 주석

-> 컴파일러가 특정 오류를 억제하도록 지시하는 것과 같이 프로그램 코드의 일부가 아닌

프로그램에 관한 데이터를 제공, 코드에 정보를 추가하는 정형화된 방법

-. xml을 활용한 DI

-> xml에서 bean으로 class를 등록해서 의존관계를 연결해주는 방식

 


IoC (Inversion of Control 제어 역행)

- 메소드나 객체의 호출 작업을 개발자가 결정하는 것이 아니라 외부에서 결정되는 것을 의미한다.

- 개발자는 프레임워크에 필요한 부품을 개발하고 조립하는 방식의 개발을 하게 되며 조립된 코드의 최종 호출은

개발자에 의해서 제어되는 것이 아니라 프레임워크의 내부에서 결정된 대로 이루어지게 되는데 이러한 현상을 제어의 역전이라고 표현한다.

- 의존적인 객체를 직접생성하거나 제어하는 것이 아니라 특정 객체에 필요한 객체를 외부에서 결정해서 연결해주므로

모듈 간의 결합도가 낮아지고 유연성이 높아진다.

728x90
728x90

제가 만든 커뮤니티 사이트의 로그인 페이지 입니다. 

기본적인 로그인 기능과 아이디/ 비밀번호 찾기 기능도 구현했습니다.

로그인 버튼으로 데이터를 전송하려면 아이디와 비밀번호 input 박스에 데이터를 필수적으로 작성해야 합니다.

아래는 로그인 기능의 jsp 코드입니다.

<script>
	function clickLogin(){
		document.fm.action="#이동할 컨트롤러";
		document.fm.method="post";
	}
</script>
<form name=fm>
<table>
    <tr>
      <td>아이디 :</td>
      <td><input type="text" required name="ID"></td>
    </tr>
    <tr>
      <td>비밀번호 :</td>
      <td><input type="password" required name="PWD"></td>
    </tr>
    <tr>
      <td colspan="2">
        <a href="#이동할 컨트롤러">아이디찾기</a>  /
        <a href="#이동할 컨트롤러">비밀번호찾기</a>
      </td>
    </tr>
    <tr>
      <td colspan="2"><a href="#이동할 컨트롤러">회원가입</a></td>
    </tr>
    <tr>
      <td colspan="2">
        <button type="submit" id="login-btn" onclick="clickLogin()"><span>로그인</span></button>
      </td>
    </tr>
</table>
</form>

아래는 servlet 컨트롤러에서 받아오는 파라미터와 로그인 기능을 수행하는 메서드입니다.

// 컨트롤러
// 로그인 버튼이 눌렷을때 로그인 기능을 동작시킨다.
// 1. 넘어온 값을 받는다.
String id = request.getParameter("ID");
String pwd = request.getParameter("PWD");
// 2.처리 (쿼리실행)
MemberDAO md = new MemberDAO();
MemberVO mv = null;
mv = md.memberLogin(id, pwd);
PrintWriter out = response.getWriter();

// 세션에 로그인할 때 받아온 값을 저장해 다른 페이지로 이동할 때에도 
// 로그인 상태를 유지하게한다.
HttpSession session = request.getSession();
if(mv != null) {
    session.setAttribute("midx", mv.getMidx());
    session.setAttribute("id", mv.getId());
    session.setAttribute("name", mv.getName());
    session.setAttribute("point", mv.getPoint());
    session.setAttribute("superMember", mv.getSupermember());
    session.setAttribute("password", mv.getPwd());
    // 3.이동
    // saveUrl이라는 로그인 페이지로 이동하기 전 url이 있을경우 그 페이지로 이동
    // 없을 경우 인덱스 페이지로 이동
    if(session.getAttribute("saveUrl") != null) {
        response.sendRedirect((String)session.getAttribute("saveUrl"));
    }else {
        response.sendRedirect(request.getContextPath()+"/main/index.do");
    }
}else {
    out.println("<script>alert('아이디, 비밀번호가 틀렸거나 존재하지 않는 회원입니다.');location.href='"+request.getContextPath()+"/member/memberLogin.do'</script>");

}

// DB에 로그인 기능을 실행하는 메서드
public MemberVO memberLogin(String ID, String PWD) {
    // id와 pwd를 파라미터로 받아온다.
    String sql = "select * from member where id = ? and pwd =?";
    ResultSet rs = null;
    MemberVO mv = null;
    try {
        pstmt = conn.prepareStatement(sql);
        pstmt.setString(1, ID);
        pstmt.setString(2, PWD);
        rs = pstmt.executeQuery();

        if(rs.next()) {
            mv = new MemberVO();
            mv.setMidx(rs.getInt("midx"));
            mv.setName(rs.getString("name"));
            mv.setId(rs.getString("id"));
            mv.setPwd(rs.getString("pwd"));
            mv.setSupermember(rs.getString("supermember"));
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }finally {
        try {
            rs.close();
            pstmt.close();
            conn.close();
        } catch (SQLException e) {

            e.printStackTrace();
        }
    }

    return mv;
}

 


아이디 찾기와 비밀번호 찾기는 같은 로직을 가지고 있다고 보면 됩니다.

아이디를 찾을 때 DB에서 이름과 이메일이 일치하는 값이 있을 경우에 ID를 받아와서 보여주면 되는데

비밀번호의 경우 일치하는 값을 추가하거나 일치했을 때 새로운 비밀번호를 설정하게 하는 등 기존의 로직에서 새로운 방법을 추가하는 것입니다.

jsp에서 form으로 이름과 이메일을 컨트롤러에 파라미터로 넘겨줍니다.

컨트롤러에서는 받은 파라미터를 다시 변수로 설정하고 만들어둔 메서드를 통해

DB와 일치하는 값이 있는지 비교하고 일치하는 값이 있을 경우 결과값을 받아옵니다.

이 값을 다시 웹페이지에 출력해주면 됩니다. 

//아이디 찾기 jsp
<script>
	function findIDbtn(){
		document.fm.action="<%=request.getContextPath()%>이동할 컨트롤러";
		document.fm.method="post";
	}
</script>
<form name=fm>
<table>
    <tr>
      <td>이름 :</td>
      <td><input type="text" name="name" required></td>
    </tr>
    <tr>
      <td>이메일 :</td>
      <td><input type="text" name="email" required></td>
    </tr>
    <tr>
      <td colspan="2">
        <button type="submit" id="findID-btn" onclick="findIDbtn()"><span>아이디 찾기</span></button>
      </td>
    </tr>
</table>
</form>

아래는 컨트롤러와 메서드 코드

sql 구문을 통해 DB에서 값을 검색하는데 여기서 table 이름과 column만 본인걸로 바꿔서 적용하면 될겁니다.

// 컨트롤러
// 아이디찾기 버튼을 클릭했을 때
PrintWriter out = response.getWriter();
String name = request.getParameter("name");
String email = request.getParameter("email");

MemberDAO md = new MemberDAO();
MemberVO mv = null;
mv = md.findID(name, email); // 아이디를 찾는 메서드
if(mv != null) {
    out.println("<script>alert('"+name+"님의 아이디는 "+mv.getId()+"입니다.');"
            + "location.href='"+request.getContextPath()+"이동할 컨트롤러'</script>");
}else {
    out.println("<script>alert('아이디가 존재하지 않습니다.');"
            + "location.href='"+request.getContextPath()+"이동할 컨트롤러'</script>");
}

//메서드
public MemberVO findID(String name, String email) {
    //아이디 찾기 메서드
    String sql = "select * from member where name = ? and email =?";
    ResultSet rs = null;
    MemberVO mv = null; // 회원정보를 저장하는 객체
    try {
        pstmt = conn.prepareStatement(sql);
        pstmt.setString(1, name);
        pstmt.setString(2, email);
        rs = pstmt.executeQuery();

        if(rs.next()) {
            mv = new MemberVO();
            mv.setMidx(rs.getInt("midx"));
            mv.setId(rs.getString("id"));
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }finally {
        try {
            rs.close();
            pstmt.close();
            conn.close();
        } catch (SQLException e) {

            e.printStackTrace();
        }
    }

    return mv;
}

 

728x90
728x90

커뮤니티 사이트를 운영하려면 먼저 회원관리가 필요하겠죠?

때문에 회원가입을 할 수 있는 페이지를 먼저 만들어 보겠습니다.

그전에 앞서 sql을 사용할 수 있는 DB에 회원 테이블을 만들어줍니다. 

회원 테이블

저는 회원번호(midx), 아이디, 비밀번호, 이메일, 회원 가입일, 포인트, 삭제 여부(delyn), 관리자 권한을 회원 테이블 칼럼으로 설정했습니다.  

회원가입 페이지에서 기본적인 로직은 먼저 빈 input값이 없는지 확인합니다.

이후 비밀번호 두 값이 일치하는지 확인합니다. 아이디 중복확인의 경우 가입자 본인이 클릭해야 작동되는데

누르지 않고 생성버튼을 누르더라도 생성 버튼을 눌렀을 때 중복확인 기능이 먼저 작동해서

중복된 아이디가 DB에 있을 경우 회원가입 처리가 되지 않고 경고창을 띄웁니다.

 

<script type="text/javascript">
	// 두 비밀번호 입력값이 일치하는지 확인 후 데이터 전송
	function check() {
		if(document.fm.PWD.value != document.fm.PWDCheck.value){
			alert("비밀번호가 일치하지 않습니다.");
			document.fm.PWDCheck.focus();
			return;
		}
		document.fm.action = "<%=request.getContextPath()%>/member/memberJoinAction.do";
		document.fm.method = "post";
	}
	// DB에 중복 된 아이디가 있는지 확인하는 함수
    // if 절은 없어도 됨 input에 required를 적어놨기 때문에
	function checkedID(){
		if(document.fm.ID.value == ""){
			alert("아이디를 입력하세요.");
			document.fm.ID.focus();
			return;
		}
		
		document.fm.action = "<%=request.getContextPath()%>/member/idCheckAction.do";
		document.fm.method = "post";
		document.fm.submit();
	}
</script>

<!-- main content -->
    <section id="home">
      <h1 id="homeTitle"> 회 원 가 입 </h1>
	  <form name=fm>
	  <table >
        <tr>
          <td>아이디 :</td>
          <td>
			<input type="text" name="ID" required> 
			<button type="button" class="check" onclick="checkedID()"> 중복확인 </button>
		  </td>
        </tr>
		<tr>
          <td>이름 :</td>
          <td><input type="text" name="name" required></td>
        </tr>
        <tr>
          <td>비밀번호 :</td>
          <td><input type="password" name="PWD" required></td>
        </tr>
		<tr>
          <td>비밀번호 확인 :</td>
          <td><input type="password" name="PWDCheck" required></td>
        </tr>
        <tr>
          <td>이메일 :</td>
          <td><input type="email" name="email" required></td>
        </tr>
        <tr>	
          <td colspan="2" class="tdJoin">
            <button type="submit" id="join-btn" onclick="check()"><span>생성</span></button>
          </td>
        </tr>
      </table>
      </form>
    </section>

중복 확인을 누를경우 checkedID() 함수가 작동되고 멤버 컨트롤러  idCheckAction.do로 파라미터가 넘어옵니다.

//servlet MemberController로 id중복확인 
//DB에 회원가입하려는 ID와 같은 ID가 있는지 확인한다.
String ID = request.getParameter("ID");

MemberDAO md = new MemberDAO(); // 메서드 집합 class
boolean bl = md.checkedID(ID);	// 중복확인 메서드
PrintWriter out = response.getWriter();
if(bl) {
    out.println("<script>alert('중복된 아이디가 있습니다.');location.href=
    '"+request.getContextPath()+"/member/memberJoin.do'</script>");
}else{
    out.println("<script>alert('사용해도 되는 아이디입니다.');location.href=
    '"+request.getContextPath()+"/member/memberJoin.do'</script>");
}

// MemberDAO class의 id중복확인 메서드
// private Connection conn;
// private PreparedStatement pstmt; 미리 전역번수로 설정한 변수들
public boolean checkedID(String ID) {
    ResultSet rs = null;
    //입력받은 ID와 같은 ID가 DB에 있는지 조건절로 확인한다.
    String sql = "select id from member where id = ?";
    try {
        pstmt = conn.prepareStatement(sql);
        pstmt.setString(1, ID);
        rs = pstmt.executeQuery();
        if(rs.next()) {
            return true;
        }
    }catch(Exception e) {
        e.printStackTrace();
    }

    try {
        rs.close();
        pstmt.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }
    return false;
}

생성 버튼을 눌렀을 경우 로직

//MemberController
//DB에 회원정보를 추가한다.
String ID = request.getParameter("ID");
String PWD = request.getParameter("PWD");
String name = request.getParameter("name");
String email = request.getParameter("email");

MemberDAO md = new MemberDAO();
boolean bl = md.checkedID(ID);  //id 중복확인을 누르지않고 회원가입을 하는 경우가 있으므로 
PrintWriter out = response.getWriter();
if(bl){
    out.println("<script>alert('중복된 아이디입니다.');location.href=
    '"+request.getContextPath()+"/member/memberJoin.do'</script>");
}else {
	// 중복된 아이디가 없는 경우 미리 생성된 DB테이블에 값을 넣는 메서드
    int value = md.insertMember(ID, PWD, name, email);
    if(value==1){
        response.sendRedirect(pj+"/main/index.do");
    }else{
       response.sendRedirect(pj+"/member/memberJoin.do");
    }
    
//MemberDAO class의 회원가입 메서드
//DB에 member로 테이블을 만들어 뒀다.
public int insertMember(String ID,String PWD,String name,String email){
    int value=0;		
    String sql="insert into member(midx,ID,PWD,name,email,point)"
            + "values(midx.nextval,?,?,?,?,?)";
    try{
    pstmt = conn.prepareStatement(sql);
    pstmt.setString(1, ID);
    pstmt.setString(2, PWD);
    pstmt.setString(3, name);
    pstmt.setString(4, email);
    pstmt.setInt(5, 0);
    value = pstmt.executeUpdate();

    }catch(Exception e){
        e.printStackTrace();
    }

    return value;
}

 

728x90

+ Recent posts