본문 바로가기
국비학원/수업기록

국비 지원 개발자 과정_Day77

by 루팽 2023. 3. 20.

<시험1-애플리케이션 설계 평가자체크리스트>

web.xml에서 TestController.java를 Servlet으로 등록하는 태그를 작성

<servlet>
		<servlet-name>TestServlet</servlet-name>
		<servlet-class>com.kh.test.controller.TestController</servlet-class>
</servlet>

 

에서 작성한 Servlet 클래스를 mapping하는 태그를 작성

<servlet-mapping>
		<servlet-name>TestServlet</servlet-name>
		<url-pattern>/test/test.do</url-pattern>
</servlet-mapping>

 

기본 생성자와 파라미터 5개 생성자, 모든 필드에 대한 getter/setter를 작성

package com.kh.test.model;

public class Test {
	private int    seq 	   = 0;
	private String writer  = null;
	private String title   = null;
	private String content = null;
	private String regdate = null;
	
	public Test() {
	}
	
	public Test(int seq, String writer, String title, String content, String regdate) {
		this.seq = seq;
		this.writer = writer;
		this.title = title;
		this.content = content;
		this.regdate = regdate;
	}
	
	public int getSeq() {
		return seq;
	}
	
	public void setSeq(int seq) {
		this.seq = seq;
	}
	
	public String getWriter() {
		return writer;
	}
	
	public void setWriter(String writer) {
		this.writer = writer;
	}
	
	public String getTitle() {
		return title;
	}
	
	public void setTitle(String title) {
		this.title = title;
	}
	
	public String getContent() {
		return content;
	}
	
	public void setContent(String content) {
		this.content = content;
	}
	
	public String getRegdate() {
		return regdate;
	}
	
	public void setRegdate(String regdate) {
		this.regdate = regdate;
	}
}

 

TEST table과 연결하기 위한 클래스를 작성하고, TEST table의 모든 rows를 리턴하는 메서드를 작성

package com.kh.test.model;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.log4j.Logger;

public class TestDao {
	Logger logger = Logger.getLogger(TestDao.class);
	public static final String _DRIVER = "oracle.jdbc.driver.OracleDriver";
	public static final String _URL    = "jdbc:oracle:thin:@192.168.10.3:1521:xe";
	public static final String _USER   = "kh";
	public static final String _PW     = "kh";
	Connection con = null;
	PreparedStatement pstmt = null;
	ResultSet rs = null;
	private SqlSessionFactory sqlSessionFactory = null;
	SqlSession sqlSession = null;
	
	public TestDao() {
		sqlSessionFactory = MyBatisCommonFactory.getSqlSessionFactory();
	}	
	
	public List<Test> selectList() {
		StringBuilder sql = new StringBuilder();
		sql.append("SELECT seq, writer, title, content, regdate FROM test");
		List<Test> testList = new ArrayList<>();
		try {
			Class.forName(_DRIVER);
			con = DriverManager.getConnection(_URL, _USER, _PW);
			pstmt = con.prepareStatement(sql.toString());
			rs = pstmt.executeQuery();
			Test test = null;
			while(rs.next()) {
				test = new Test();
				test.setSeq(rs.getInt("seq"));
				test.setWriter(rs.getString("writer"));
				test.setTitle(rs.getString("title"));
				test.setContent(rs.getString("content"));
				test.setRegdate(rs.getString("regdate"));
				testList.add(test);
			}		
		} catch (Exception e) {
			logger.info("Exception : "+e.toString());
		}
		return testList;
	}
}

 

 

<시험2-애플리케이션 설계서술형(신)>

JSP directive tag 중, jstl 포매팅 라이브러리 사용 구문을 작성

<%@ taglib prefix=”fmt” uri=”<http://java.sun.com/jsp/jstl/fmt”> %>

 

Web Server와 Web Application Server의 차이점을 서술

Web Server는 HTTP 프로토콜을 기반으로 클라이언트가 웹 브라우저에서 어떠한 요청을 하면 그 요청을 받아 정적 컨텐츠 를 제공하는 서버이다.

WAS는 DB 조회 혹은 다양한 로직 처리를 요구하는 동적 컨텐츠 를 제공하기 위해 만들어진 Application 서버이다.

 

JSP directive tag 중, jstl core library를 사용할 때 필요한 태그를 서술

<%@ taglib prefix="c" uri="<http://java.sun.com/jsp/jstl/core>" %>

 

웹 서버프로그램에서 클라이언트 뷰 페이지로 처리된 결과 정보를 전송하려고 할 때 이용할 수 있는 객체를 2개 이상 서술

ServletContext, HttpServletRequest, HttpSession, PrintWriter

 

Client에서 아래와 같은 form 태그 내 형식을 통해 전송 된 HTTP 요청의 Parameter 정보를 Servlet 클래스의 doGet() 메소드 내에서 변수에 저장하는 구문을 작성

String nickname = request.getParameter("nickname");
String[] hobby = request.getParameter("hobby");

 

Client에서 아래와 같은 form 태그 내 형식을 통해 전송 된 HTTP 요청의 Parameter 정보를 Servlet 클래스의 doGet() 메소드 내에서 변수에 저장하는 구문을 작성

String phone= request.getParameter("phone");
String[] address = request.getParameter("address");

 

Servlet Filter의 기능과 용도에 대해 서술

Client로부터 Server로 요청이 들어오기 전에 서블릿을 거쳐서 필터링 하는 것을 서블릿 필터라고 한다.

공통적인 기능들을 서블릿이 호출되기 전에 수행(전처리)되게 하고 싶거나, 서블릿이 호출되고 난 뒤에 수행(후처리) 하고 싶으면 서블릿 필터로 구현하면 된다.

 

JSP directive tag 중 현재 페이지를 에러 처리용 페이지로 정의하는 구문을 작성

<%@ page isErrorPage=”true” %>

 


 

<get post 테스트 - MemberVO.java>

package com.example.demo.vo;

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

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class MemberVO {
	private String mem_id = null;
	private String mem_pw = null;
	private String mem_name = null;	
}

 

 

<get post 테스트 - RestfulController.java>

package com.example.demo.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.vo.MemberVO;

@RestController
@RequestMapping("/restful/*") // upmu[0]
public class RestfulController {
	Logger logger = LoggerFactory.getLogger(RestfulController.class);

	// <http://localhost:8000/restful/5>
	@GetMapping("{id}")
	public String main(@PathVariable int id) {
		logger.info("해시값 받아주는 어노테이션 : " + id);
		return String.valueOf(id);
	}
	
	// <http://localhost:8000/restful/get?mem_Id=kiwi&mem_pw=123&mem_name=키위>
	@GetMapping("get") // upmu[1]
	public String getTest(MemberVO mVO) {
		logger.info(mVO.toString());
		return "get요청 : " + mVO.getMem_id() + ", " + mVO.getMem_pw() + ", " + mVO.getMem_name();
	}

	// postman에서 테스트해야만하며 @RequestBody에 들어갈 값은 Body선택 후
	// row 체크하고 반드시 JSON선택해서 JSON 포맷으로 파라미터를 넘겨야함 - 주의할것!
	// @RequestBody에 타입을 선언하면 MessageConverter가 대신해줌 - 반드시 JSON포맷으로 넘길 것!
	// <http://localhost:8000/restful/post>
	@PostMapping("post")
	public String postTest(@RequestBody MemberVO mVO) {
		logger.info(mVO.toString());
		return "post요청 : " + mVO.getMem_id() + ", " + mVO.getMem_pw() + ", " + mVO.getMem_name();
	}
}

 

<이미지 업로드 - index.js>

import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import { BrowserRouter } from "react-router-dom";
import ImageUploader from "./service/imageUploader";

const imageUploader = new ImageUploader();
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <>
    <BrowserRouter>
      <App imageUploader={imageUploader} />
    </BrowserRouter>
  </>
);

 

<이미지 업로드 - App.jsx>

import { Route, Routes } from 'react-router-dom';
import './App.css';
import LoginPage from './components/auth/LoginPage';
import MemberPage from './components/page/MemberPage';

function App({imageUploader}) {
  return (
    <>
      <Routes>
        <Route path="/member" exact={true} element={<MemberPage imageUploader={imageUploader} />} />
      </Routes>
    </>
  );
}

export default App;

 

<이미지 업로드 - imageUploader.js>

class ImageUploader {
  // 여기에는 상태는 없어요
  async upload(file) {
    //upload했다면 그 URL전달
    //아래 수동으로 했던 거 지우고
    //return 'file';
    const data = new FormData(); // 외부 클라우드 시스템과 연동시에 꼭 필요한 객체
    // input type file에서 선택한 파일에대한 정보 담기
    data.append("file", file);
    // Cloudinary에서 제공하는 서비스를 이용하여 사용자가 선택한 파일에대한 URL정보만
    // 제공받아서 처리하므로 upload_preset은 unsigned로 받을 것
    data.append("upload_preset", "키"); // unsigned - 인증과정 없이 사용할 때
    /*
      POST를 이용하니까 POST에 추가하는 데이터 입력하고 fetch를 이용해서 여기 우리가 URL 만들고
      POST한 거 데이터를 전송한 다음에 완료가 되면 이제 result를 받아서 result에 있는 것을 json으로
      변환해서 리턴해 줄거예요
    */
    const result = await fetch(
      "<https://api.cloudinary.com/v1_1/키/upload>",
      {
        method: "POST",
        body: data,
      }
    );
    return await result.json();
  }
}

export default ImageUploader;
//https://cloudinary.com/documentation/upload_images

 

<이미지 업로드 - MemberPage.jsx>

import React, { useEffect, useState } from 'react'
import { jsonMemberListDB } from '../../service/dbLogic'

const MemberPage = ({imageUploader}) => {
  const [member, setMember] = useState({})

  useEffect(()=>{
    const memberList = async() => {
      const res = await jsonMemberListDB(member)
      console.log(res.data)
    }
    memberList()
  },[])  

  // async는 비동기처리시 사용함
  const imgChange = async(event) => {
    console.log(event.target.files[0])
    // async가 붙은 함수안에서만 await를 사용할 수 있음 - 파일이 업로드될때까지 기다림
    const uploaded = await imageUploader.upload(event.target.files[0])
    // public_id - 선택한 이미지의 실제 아이디가 아닌 cloudinary에서 부여하는 아이디값
    // 이 값으로 실제 이미지 링크 정보가 생성됨
    // format은 선택한 파일의 확장자
    // url 링크이미지 URL 정보
    console.log(`${uploaded.public_id} ${uploaded.format} ${uploaded.url}`)
  }

  return (
    <div>
      <h3>회원관리 페이지입니다</h3>
      <input type="file" name="mimg" id="mimg" onChange={imgChange} />
    </div>
  )
}

export default MemberPage

 

<카카오 api 로그인 - index.js>

import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import { BrowserRouter } from "react-router-dom";
import ImageUploader from "./service/imageUploader";

const imageUploader = new ImageUploader();
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <>
    <BrowserRouter>
      <App imageUploader={imageUploader} />
    </BrowserRouter>
  </>
);

 

<카카오 api 로그인 - App.jsx>

import { Route, Routes } from 'react-router-dom';
import './App.css';
import LoginPage from './components/auth/LoginPage';
import KakaoRedirectHandler from './components/kakao/KakaoRedirectHandler';
import MemberPage from './components/page/MemberPage';

function App({imageUploader}) {
  return (
    <>
      <Routes>
        <Route path='/' exact={true} element={<LoginPage />} />
        <Route path='/auth/kakao/callback' exact={true} element={<KakaoRedirectHandler />} />
        <Route path="/member" exact={true} element={<MemberPage imageUploader={imageUploader} />} />
      </Routes>
    </>
  );
}

export default App;

 

<카카오 api 로그인 - LoginPage.jsx>

import React from 'react'
import Image from 'react-bootstrap/Image'

const LoginPage = () => {
  const REDIRECT_URI = "http://localhost:3000/auth/kakao/callback"
  const KAKAO_AUTH_URL = `https://kauth.kakao.com/oauth/authorize?client_id=${process.env.REACT_APP_KAKAO_API_KEY}&redirect_uri=${REDIRECT_URI}&response_type=code`
  return (
    <div>
      <a href={KAKAO_AUTH_URL}>
      <Image src='/images/kakao/kakao_login_medium_wide.png' />
      </a>
    </div>
  )
}

export default LoginPage

 

<카카오 api 로그인 - KakaoRedirectHandler.jsx>

import axios from 'axios'
import React from 'react'
import qs from 'qs'

const KakaoRedirectHandler = () => {
  // 카카오서버에서 돌려주는 URL 뒤 쿼리스트링 가져오기
  // searchParams - URL 내의 GET 디코딩 된 쿼리 매개변수에 접근할 수 있는 URLSearchParams 객체를 반환
  let params = new URL(document.location).searchParams;
  let code = params.get("code");
  console.log(code)
  const grant_type = "authorization_code"
  const redirect_uri = "http://localhost:3000/auth/kakao/callback"
  const getToken = async() => {
    const payload = qs.stringify({
      grant_type: grant_type,
      client_id: process.env.REACT_APP_KAKAO_API_KEY,
      redirect_uri: redirect_uri,
      code: code
  })
    try {
      const res = await axios.post(
        "https://kauth.kakao.com/oauth/token",
        payload
      )
      window.kakao.init(process.env.REACT_APP_KAKAO_API_KEY)
      console.log(res.data.access_token)
      window.kakao.Auth.setAccessToken(res.data.access_token);
    } catch (error) {
      console.log(error)
    }
  }


  return (
    <div>
      {code}
    </div>
  )
}

export default KakaoRedirectHandler

댓글