Chapter2

생성일: 2021년 9월 5일 오전 11:47

변수

변수란 단 하나의 값을 저장할 수 있는 메모리 공간.

변수의 초기화

변수를 사용하기 전에는 항상 변수를 초기화 해주어야 한다. (클래스 변수인스턴스 변수는 초기화를 생략할 수 있다.)

변수의 명명규칙

필수 규칙

  • 대소문자가 구분되며 길이의 제한이 없다. (True ≠ true) ac ≠ AC
  • 예약어(ex. if)를 사용할 수 없다
  • 숫자로 시작해서는 안된다
  • 특수문자는 _$ 만 허용한다.

권장 규칙

  • 클래스 이름의 첫 글자는 항상 대문자로 한다
  • 여러 단어로 이루어진 이름은 단어의 첫 글자를 대문자로 한다.
    • 카멜 케이스 : lastIndexOf (첫글자만 소문자 이후 단어마다 대문자로 시작)
    • 스네이크 케이스: last_index_of (단어마다 _를 사용)
    • 파스칼 케이스: LastIndexOf (모든 단어의 시작이 대문자)
  • 상수의 이름은 모두 대문자로 한다. 여러단어일 경우는 _를 사용하여 구분한다. (MAX_NUMBER)
  • 패키지 이름은 소문자로 한다

변수의 타입

변수의 타입은 크게 2가지로 나뉜다.

  • 기본형(primitive type)
    • 논리형(boolean), 문자형(char), 정수형(byte,short,int,long), 실수형(float,double) 계산을 위한 실제 값을 저장
  • 참조형(reference type)
    • 객체의 주소를 저장한다. 기본형을 제외한 나머지 타입 (변수 타입이 클래스)
    • 참조변수는 null 또는 객체의 주소를 값으로 가진다.
// 참조형의 선언
**클래스이름** 변수이름; -> 주소할당이전

// 참조형의 초기화
Date today = new Date(); // Date객체 생성후 주소를 today에 저장

기본형

상수(Constant) & 리터럴(literal)

상수란?

변수와 마찬가지로 '값을 저장할 수 있는 공간' 이지만 한번 값을 저장하면 다른 값으로 변경 불가능

상수를 사용하기 위해서는 final을 붙여주면 된다

final int MAX_SPEED = 10; 

MAX_SPEED = 11; -> (x)

상수를 사용할 때는 선언과 동시에 초기화를 항상 해줘야한다.

또한, 상수의 이름은 모두 대문자로 하는 것이 암묵적 관례이다.

리터럴(literal)이란?

그 자체로 값을 의미하는 것이다.

기본적으로 상수는 숫자 (1,221,123) 또는 문자 ('a','B')같이 그 자체로 값인 것을 의미 하는데 ****

프로그래밍에서의 상수는 따로 의미가 있기 때문에 리터럴이라는 단어를 사용하여 기본 상수의 의미를 구별하기로 하였다.

리터럴의 접미사

리터럴을 사용할 때는 항상 접미사를 붙여줘야한다.

// 정수형 접미사 사용 예제
long number = 10; // (x) -> 실행이 되긴함 권장 x
Long number = 10; // (x) -> 실행이 안됨
long number = 10L; // (o)
long number = 10_000L; // (o) JDK 1.7부터

//실수형 접미사 사용 예제
float pi = 3.14; // (x) 실수형의 기본 접미사는 double의 D이다
float pi = 3.14f; // (o)
float pu = 3.14F; // (o)

double rate = 1.618; // (o)
double rate = 1.168D; // (o)
double rate = 1.168d; // (o)

접미사 예제

타입이 불일치 할때

기본적으로 리터럴의 타입은 변수의 타입과 일치하는 것이 보통이지만 타입이 달라도 저장범위가 넓은 타입에 좁은 타입의 값을 저장하는 것은 허용이 된다.

// 모두 큰 범위
int i = 'A'; // 65가 저장
long l = 123; 
double d = 3.14f

문자 리터럴 , 문자열 리터럴

  • 문자 리터럴
    • 작은 따옴표 (``)로 문자 하나를 감싼 것
    • 무조건 작은 따옴표 안에 적어도 하나의 문자를 넣어야한다
  • 문자열 리터럴
    • 큰 따옴표 ("")로 두 문자 이상 감싼것
    • 큰 따옴표 안에 문자가 없어도 된다
String str = ""; // 내용이 없는 빈 문자열
char ch = ''; // (x) 적어도 하나의 문자가 있어야한다
char ch = ' '; // 공백이 있기 때문에 (o)

String의 클래스 선언

String은 클래스 입으로 객체를 생성 할 때 new를 사용 해야하지만 그냥 할당도 특별히 허용된다

String name = new String("java"); 뿐만아닌 String name = "java" 도 허용한다.

문자열의 덧셈

문자열은 기본적으로 기본형과 참조형의 구별 없이 어떤 타입의 변수도 문자열과 덧셈 연산을 수행하면 문자열이 된다.

그렇기 때문에 문자열로 형변환을 시켜줄 때 ""만 더해줘도 문자열이 된다.

문자열 + Any Type = 문자열

// 예시
String name = "java";
String str = name + 0.8; // "java0.8"

int temp = 10;

Printf()

자바에서의 출력은 C언어와 비슷하다.

System.out.printf();를 사용하여 출력을 진행한다

지시자

Printf 예제

// 지시자 사용 예제
int age = 20;
System.out.printf("age:%d", age);

// 간격 맞추는법
System.out.printf("[%5d]",age); // [   20]
System.out.printf("[%05d]",age); // [00020]
System.out.printf("[%-5d]",age); //[20   ]

화면에서 입력받기

C언어에서 scanf를 사용하는것과 같이 자바에는 Scanner라는 객체가 있다.

사용하기 위해서는 import java.util.*; 를 import해야한다

그 후 Scanner 객체를 생성하고 nextLine()매소드를 호출하면 받을 수 있다.

// 사용 예제
import java.util.*; 
// 또는
import java.util.Scanner;

Scanner scanner = new Scanner(System.in); // 객체생성

String input = scanner.nextLine(); // input에 입력받는 내용 저장 문자열로 저장
int num = Integer.parseInt(input); // 입력받은 내용을 num에 int 타입으로 변환
// 숫자만 입력했을때 변환가능

//입력받자마자 변환 없이 정수로 받는법
int num = scanner.nextInt();

//입력 받자마자 실수로 받는법
float num = scanner.nextFloat();

//공백으로 받는법
String num = scanner.next(); 
int num = scanner.next(); // (x)반환형이다름

nextInt()nextFloat()매서드를 사용해 입력을 받으면 연속적인 값을 얻기 힘들기 때문에

nextLine()을 사용해서 받고 변환하여 사용하는 것을 책에서는 권장하고 있다.

진법 변환

  • 2의보수법을 사용하여 진법 변환을 한다.
  • 실수의 진법 변환
    • 10진 소수에 2를 곱한다
    • 위의 결과에서 소수부만 가져와서 다시 2를 소수부가 0이 될때까지 곱한다.
    • 나온 결과에서 정수부만 위에서 아래로 순서대로 적고 0.을 붙인다.
0.625를 변환

0.625 *2 = 1.25
0.25 * 2 = 0.5
0.5 * 2 = 1.0

0.101이 된다.

바이트 와 비트 와 워드

  • 8bit를 1Byte라 한다.
  • 1bit는 한자리의 2진수를 나타낸다.
  • 워드는 Cpu가 한번에 처리 할 수있는 데이터의 크기를 의미한다.
  • 32비트 컴퓨터의 워드는 4바이트이다.

문자형에서 유니코드 사용법

// 3 문장 다 '가'를 나타낸다.
char hch = '가';
char hch = 0xAC00;
char hch = '\uAc00';

// 특수문자 다룰 때는 c언어와 같다

// 2 문장은 같다
char ch = 'A';
char ch = 65;

오버플로우

  • 타입이 표현할 수 있는 값의 범위를 넘어서면 Overflow가 발생하면 제일 낮은값이 나온다.
  • 예를들어 2진수 0000에서 1을 뺴면 1111이 된다. 2의보수법으로 고쳐 표현하면 제일 낮은 값이 나온다.
  • 최대값 + 1 → 최소값 / 최소값 - 1 → 최대값

실수형에서의 오버플로우

  • 실수형은 저장할 수 있는 범위를 넘어나면 오버플로우가 발생하는데 정수형과 달리 변수의 값이 무한대가 된다.
  • 또한 언더플로우가 정수형과 달리 존재한다. → 자바에서 언더플로우 C언어랑
  • 실수형으로 표현할 수 없는 아주 작은 값을 넣었을 때의 변수의 값은 0이 된다.
  • float7자리 까지 double15자리 까지 표현이 가능하다.

실수형의 값 저장 방식

실수형은 값을 저장하기 위해서 부동소수점형태로 값을 저장한다.

부동소수점은 부호지수가수로 이루어져있다.

  • 부호
    • 1 bit를 차지하고 0이면 양수, 1이면 음수를 나타낸다
  • 지수
    • 부호가 있는 정수라고 생각하면 된다. 지수의 범위는 10의 n승 할때 제곱을 의미한다
    • flaot는 -127128까지 double은 -10231024까지 나타낸다.
  • 가수
    • 실제 값을 저장하는 부분으로 정밀도를 저장할 수 있다.
    • float는 2진수 23자리를 저장할 수 있다 = 약 7자리 (10진수로 고쳤을때)
    • double은 2진수 52자리를 저장할 수 있다. 약 15자리 (10진수로 고쳤을 때)

부동소숫점의 오차

  • 부동소수점은 기본적으로 2진수 이기 때문에 오차가 발생 할 수있다.
  • 파이 같은 무한소수를 정확하게 나타낼 수 없다.
  • 또는 예를들면 float같은 경우 7자리 수까지 밖에 나타내지 못하는데 7자리를 넘어가는 유한소수 일 경우에 오차가 발생 할 수 있다.

형변환(casting) 이란?

  • 형변환은 변수 또는 상수의 타입을 다른 타입으로 변환하는 것이다.

형변환을 하기 위해서는 변수나 리터럴 앞에 변환하고자 하는 타입을 괄호화 함께 붙여주면 명시적 형변환이 가능하다

double d = 85.4;
int score = (int)d; // 명시적 형변환

// 2진 정수로 변환한 문자열 얻는 법
Integer.toBinaryString(int i);

// 상수를 보다 작은 타입으로 변환 했을 때
double d = 1.0e100;
float f = (float)d; // INFINITY가 출력된다

double d = 1.e-50;
float f = (float)d; // 0.0이 출력된다.

// 실수형과 정수형의 변환
float f = 1.666;
int i = (int)f; // 1 **반올림이 되지 않는다**

자동형변환

서로 다른 타입간의 대입이나 연산을 할 때, 형변환으로 타입을 이치시키는 것이 원칙이지만 편의상 형변환을 생략할 수 있다. 이때 컴파일러가 이를 자동적으로 형변환 해주는 것을 자동형변환 이라고 한다.

자동 형변환은 기존의 값을 최대한 보존할 수 있는 타입으로 자동 형변환 한다. 즉 표현 범위가 좁은 타입에서 넓은 타입으로 형변환이 된다.

int i = 3;
double d = 1.0 + i; // i 가 3.0으로 자동형변환 된다. 

Reference

자바의 정석

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

[Java/Study] 오버라이드  (0) 2021.09.07
[Java/Study] 상속  (0) 2021.09.07
[Java/Study] 생성자  (0) 2021.09.07
[Java/Study] 변수와 메서드  (0) 2021.09.07
[Java/Study] 클래스와 객체  (0) 2021.09.06

MIME-TYPE

MIME-TYPE는 톰켓 컨테이너에서 미리 설정해 놓은 데이터 종류들을 말한다.

서버에서 자바의 I/O 스트림 클래스를 이용하여 웹 브라우저로 데이터를 전송할 때 지정하는 형식이다.

ex.) HTML로 전송할 때 : text/html 와 같은 형식이다.


서블릿의 응답처리 예제

서블릿에서 응답처리를 할 때는 다음과 같다.

  1. MINE-TYPE을 지정한다.
  2. 자바 I/O 스트림을 이용해 데이터를 출력할 PrintWriter객체를 생성한다.
  3. 출력 데이터를 HTML형식으로 작성하고 PrintWriter객체를 이용하여 데이터를 출력한다.
protected void doGet(HttpServletRequest request, HttpServletResponse response){
    request.setCharacterEncoding("utf-8"); // utf-8형식으로 지정
    response.setContentTpye("text/html;charset=utf-8"); // MINE-TYPE을 지정해준다
    PrintWriter out = response.getWriter(); // PrintWriter 객체를 이용하여 I/O로 데이터를 출력하기 위해 객체를 생성한다.
    
    //...
    //...
    out.print(data); // I/O 스트림으로 데이터를 출력
    
}

서블릿에서 비지니스 로직 처리방법

비지니스 로직이란?

  • 서버가 클라이언트로부터 요청을 받을 때 그 요청에 대해 작업을 수행하는 것을 의미한다.
  • 대부분의 비지니스 처리 작업은 데이터 베이스 연동 관련 작업이다.

DB(DataBase)를 연결하기 위해서는 MemberDAOMemberVO클래스가 사용이된다.

서블릿으로 회원정보를 조회할 때의 과정을 다음 그림과 같다.

  1. 웹브라우저가 서블릿에게 회원 정보를 요청한다.
  2. MeberServlet이 요청을 받은후 MeberDAO 객체를 생성하여 listMembers() 메서드를 호출한다.
  3. listMembers()에서 다시 connDB()매서드를 호출하여 데이터베이스와연결하고 회원정보를 조회한다.
  4. 조회된 회원정보를 MemberVO속성에 설정하고 ArrayLIst에 정보를 저장한다.
  5. 저장 된 정보를 MemberServlet으로 반환하고 저장된 정보를 차례대로 가져와서 HTML태그의 문자열로 만든다
  6. 만들어진 HTML 태그를 웹 브라우저로 전송해서 회원정보를 출력한다.
// MemberServlet 클래스 작성
@webServlet("/Member")
protected class MemberServlet extends HttpServlet{
    
    //doGet() 매소드
    protected class doGet(HttpServletRequest request, HttpServletResponse response){
        response.setContenType("text/html;charset=utf-8");
        printWrite out = response.getWriter();
        
        MemberDAO dao = new MemberDAO(); // DAO 객체 생성
        LIst<MemberVO> list = dao.listMembers(); // listMembers() 메서드를 사용하여 회원정보조회
        //...
    }
}


//MemberDAO 클래스 작성
public class MemberDAO{
    private Statement stmt;
    private Connection con;
    //...
    
    //listMembers() 메서드 구현
    public List<MemberVO> listMembers(){
        try{
            connDB(); // DataBase연결
            String query = "select * from t_member"; // 쿼리문으로 SQL조회할 때 사용
            ResultSet rs = stmt.executeQuery(query); // SQL문을 사용하여 회원정보를 조회
            while(rs.next()){
                String id = rs.getString("id");
                String pwd = rs.getString("pwd");
                //...

                MemberVO vo = new MemberVO(); // VO 객체 생성
                vo.setID(id);
                vo.setPwd(pwd);
                //...
                list.add(vo); // vo 객체를 ArrayLIst에 저장한다.
            }
            rs.close();
            stmt.close();
            con.close();
        } catch (Exception e){
        e.printStackTrace();
    }
    return list; // MemberVO 객체를 저장한 ArrayLIst를 반환한다.
}
    
	// connDB() 메서드 구현 DB연결
	private void connDB(){
        try{
            Class.forName(driver);
            System.out.println("Oracle 드라이버 로딩 성공");
            con = DriverManager.getConnection(url, user, pwd);
            System.out.println("Connection 생성 성공");
            stmt = con.createStatement();
            System.out.println("Statement 생성 성공");
        } catch (Exception e){
            e.printStackTrace();
        }
    }
}


// MemberVO 클래스 작성
public class MemberVO{
    private String id;
    private String pwd;
    //...
    
    
    //MemberVO 생성자
    public MemberVO(){
        System.out.println("MemberVO 생성자 호출");
    }
    
    public String getId(){
        return id;
    }
    public String setId(String id){
        this.id = id;
    }
    
    public String getPwd(){
    	return pwd;    
    }
    public String setPwd(String pwd){
        this.pwd = pwd;
    }
    //...
    
    
}

다음과 같이 이러한 클래스들을 이용하여 비지니스를 처리해준다.

 

 

이 글은 자바 웹을 다루는 기술에서 참고하였습니다

 

 

'Spring > Servlet' 카테고리의 다른 글

[Java/Servlet] 서블릿이란?  (0) 2021.08.17

서블릿이란?

서블릿은 서버 쪽에서 실행되면서 클라이언트의 요청에 따라 동적으로 서비스를 제공하는 자바 클래스 이다.


서블릿의 동작 순서

  1. 클라이언트웹서버에 요청을 한다.
  2. 웹서버웹 어플리케이션 서버(WAS)에게 위임을 한다.
  3. 웹 어플리케이션 서버(WAS)는 각 요청에 해당하는 서블릿을 실행한다
  4. 서블릿은 요청에 대한 기능을 수항 한 후 결과를 반환하여 클라이언트에 전송한다.

서블릿의 계층 구조


서블릿의 생명주기

생명주기 단계 호출 매서드 특징
초기화 init() 서블릿 요청시 한번만 호출 된다
서블릿 생성시 초기화 작업을 주로 한다.    
작업 수행 doGet()  
doPost() 서블릿 요청 시 매번 호출 된다  
실제로 클라이언트의 요청 작업을 여기서 수행한다.    
종료 destroy() 서블릿이 기능을 수행하고 메모리에서 소멸 될 때 호출이 된다.
서블릿의 마무리 작업을 주로 수행한다.    

서블릿 매핑하기

서블릿을 매핑하는 방법은 총 2가지가 있다.

  1. 각 프로젝트에 있는 web.xml에서 <servlet>, <servlet-mapping> 태그를 이용한다.
  2. 애너태이션(@WebServlet('/'))을 사용한다.

이중 web.xml에서 사용하는 방법은 매핑 할것들이 많아진다면 복잡해진다는 단접이 있다

이를 해결하기 위해서는 @WebServlet 애너테이션을 사용하여 표시하면 훨씬 가독성이 좋아진 다는 장점이 있다.

방법은 클래스 위에 @WebServlet 애너테이션을 붙여주거나 servlet 파일을 만들 때 설정하면 된다.

주의점으로는 반드시 HttpServlet 클래스를 상속받은 상태여야 한다.

@webServlet("/login")
public class LoginServlet extends HttpServlet{
    //...
}

이 때 중복된 매핑을 할시 오류가 나타남으로 주의해야 한다.


서블릿의 동작 과정

  1. 클라이언트 에서 http://localhost:8080/project/login으로 요청
  2. login이 메모리에 존재하는지 확인
  3. login을 메모리에 로드
  4. init()을 호출
  5. doGet()또는 doPost()를 호출
  6. 결과 응답

으로 동작이 진행된다. 만약 진행이되고 난 뒤 다른 클라이언트에서 또 login을 요청한다면

이 때는 init()이 호출이 되지 않는 다는 것을 볼 수 있다.

왜냐하면 첫번째 클라이언트에 의해 이미 메모리에 로드가 되어있기 때문에 doGet()또는 doPost()가 로드가 된다.

이때 서블릿에서 값을 가져 올 때는 request에서 getParmeter()를 사용해 값을 가져 올 수 있다.


서블릿의 응답 처리 방법

서블릿이 처리한 결과를 클라이언트에게 응답하기 위해서는 다음과 같다.

  1. doGet()이나 doPost()매서드 안에서 처리한다.
  2. javax.servlet.http.HttpServletResponse객체를 사용하여 응답을 처리한다,
  3. setContentType()을 이용해 클라이언트에게 전송할 데이터 종류를 지정한다.
  4. 클라이언트와 서블릿을 통신은 자바의 I/O스트림을 사용하여 응답을 처리한다.

웹 브라우저에서 서블릿으로 데이터 전송하는 방법

GETPOST방식을 사용하여 전송할 수 있다.

HTTP에서는 GETPOST말고도 다른 것들이 많이 존재한다.

GET과 POST의 차이점

  • GET 방식
    • GET방식으로 데이터를 전송 할 때는 주소창에 name=value형태로 전송한 것이 보이기 때문에 보안에 취약하다.
    • 전송할 수 있는 데이터가 최대 255자이다.
    • doGet을 이용해서 서블릿에서 데이터를 처리한다.
  • POST 방식
    • 서블릿에 데이터를 전송할때 TCP/IP 프로토콜 데이터의 body 영역에 숨겨진 채 전송을 하므로 보안에 유리하다.
    • 전송할 수 있는 데이터가 무제한이다.
    • 서블릿에서 다시 가져오는 작업을 해야해서 GET보다 느리다
    • doPost()를 이용해 서블릿에서 데이터를 처리한다.

이를 둘이 동시에 사용하기 위해서는 doHandle()이라는 매서드를 doGet()doPost()에서 호출하여 doHandle()에서 한꺼번에 처리한다.

 

 

이 글은 자바 웹을 다루는 기술 에서 참고하였습니다

 

'Spring > Servlet' 카테고리의 다른 글

[Java/Servlet] 서블릿의 비지니스 로직 처리  (0) 2021.08.18

풀이

function solution(strings, n) {
    strings.sort((a,b) =>{
        if(a[n] > b[n]){
            return 1;
        } else if(a[n] < b[n]){
            return -1;
        }else{
            if(a > b){
                return 1;
            }else{
                return -1;
            }
        }
    });

    return strings;
}

풀이를 진행하기 위해서 처음으로 sort매소드를 사용하여 n번째의 문자열을 비교하고 만약 같다면 사전식으로 비교해 주었다.

더 나은 풀이

function solution(strings, n) {
    // strings 배열
    // n 번째 문자열 비교
    return strings.sort((s1, s2) => s1[n] === s2[n] ? s1.localeCompare(s2) : s1[n].localeCompare(s2[n]));
}

한 문 장으로 간결하게 정렬하여 가져왔다.
3항 연산자를 사용하여 같을 때를 비교하고 같다면
localeCompare라는 매소드를 사용하여 문자열을 비교한다.
다르면 n번째를 localeCompare를 사용하여 비교한다.

localeCompare

이 메소드는 인자로 string을 받는다

// 같을 때는 0을 반환
'a'.localeCompare('a') // 0

// 사전 순으로 앞에 있을 때 -1을 반환
'a'.localeCompare('b') // -1

// 사전 순으로 뒤에 있을 때 1을 반환
'b'.localeCompare('a') // 1

카카오톡 봇 만들기 (3)

지금까지 flask 실행을 하였다 . 이제부터 본격적으로 봇 테스트 기능을 이용하여 구축해보겠다.

기본 설정

테스트이기 때문에 일단 작동이 잘되는지 확인을 해보겠다.

우선 봇 관련 발화와 스킬관련 설정을 해야한다. 다시 카카오톡 봇 설정으로 들어가자

발화 설정

발화는 쉽게말하면 사용자가 카카오톡으로 친 채팅이라고 보면된다.

카카오톡에 등록한 사용자 발화에 대해서 제대로 서버에 json 형식으로 보내지는 것을 볼 수가 있다.

테스트를 위해서 "오늘의 메뉴"라고 등록을 한 뒤 엔터를 누르도록 하자.

스킬 설정

이제 우리가 사용하는 서버를 연결하기 위해서 스킬을 만들도록 하자

스킬탭으로 이동하여 다음과 같이 스킬을 생성하도록 하자.

여기서 중요한것은 url설정이다.

첫번 째로 https로 하면 제대로 동작하지 않는다. 꼭 http로 해야한다.

그리고 localhost:5000에는 Azure로 생성한 곳의 Ip를 넣어주도록하자.

현재 필자는 주소 뒤에 /message로 하였는데 이는 구현하기 나름이다.

그 후 다시 홈화면으로 돌아와서 스킬데이터 사용으로 봇응답을 설정해주고 파라미터에서도 스킬 등록을 해준뒤 저장을 해준다.

Flask 코드작성

이제 테스트하기 위한 코드를 작성해보도록하자. 예제 코드는 다음과 같다.

from flask import Flask, json, request, jsonify
import sys

app = Flask(__name__)

@app.route('/message', methods=['POST'])
def Message():
    content = request.get_json()
    content = content['userRequest']['utterance']
    content=content.replace("\n","")
    print(content)
    if content == u"오늘의 메뉴":
        dataSend = {
            "version" : "2.0",
            "template" : {
                "outputs" : [
                    {
                        "simpleText" : {
                            "text" : "테스트입니다."
                        }
                    }
                ]
            }
        }
    else:
        dataSend = {
            "version" : "2.0",
            "template" : {
                "outputs" : [
                    {
                        "simpleText" : {
                            "text" : "error입니다."
                        }
                    }
                ]
            }
        }
    return jsonify(dataSend)

if __name__ == "__main__":
    app.run(host='0.0.0.0',port=5000)

하나씩 코드를 살펴보도록 하자

우선 어노테이션을 사용하여 route를 설정해주도록 하자 이는 아무거나 원하는 것으로 설정하도록 하자

나는 /message로 설정하였다 이렇게 설정하면 쉽게말하면 http://localhost:5000/message로 이동했을 때의 기능을 보여준다고 하면된다.

methodsPOST형식으로 사용하였다. json으로 값을 받아야하기 때문에 POST로 하였다.

@app.route('/message', methods=['POST'])

밑의 def Message()부분이 이해 안된다면 이전 게시물을 참고하도록 하자

content = request.get_json() # 사용자가 입력한 정보를 json형태로 가져옴
content = content['userRequest']['utterance'] # user가 입력한 발화를 가져옴

content에서 userRequestutterance는 이전 게시물에서 사용자의 발화를 나타내는 정보라고 하였다. 이를 통해서 사용자가 입력한 정보를 가져오게 된다.

content=content.replace("\n","") # '\n'문자를 ""로 대체한다.
print(content) #사용자의 입력을 제대로 받는 지 확인하기 위한 수단

주의할 점이 있는데 사용자의 정보는 엔터를 받기 때문에 \n을 포함해서 반환이 된다. 이를 없애기 위해서는 여러가지 방법이 있는데 나는 replace를 사용하여 해결하였다.

다른방법으로는 split을 사용하거나 if문 안에서 판별을 할 때 오늘의 메뉴\n으로 비교하는 방법도 있다.

if content == u"오늘의 메뉴":
        dataSend = {
            "version" : "2.0",
            "template" : {
                "outputs" : [
                    {
                        "simpleText" : {
                            "text" : "테스트입니다."
                        }
                    }
                ]
            }
        }
    else:
        dataSend = {
            "version" : "2.0",
            "template" : {
                "outputs" : [
                    {
                        "simpleText" : {
                            "text" : "error입니다."
                        }
                    }
                ]
            }
        }
    return jsonify(dataSend)

"오늘의 메뉴"에 u를 붙여주는 이유는 unicode변환이라고 하는데 붙여주지 않아도 작동하는 것을 볼 수 있다.

그리고는 이전 게시물에서 보여주었던 형식을 차목하여 simpleText형으로 데이터를 dataSend라는 변수에 담아서 jsonify(dataSend)로 Json형식으로 보내주도록 한다.

이제 터미널에서 python3 파일명.py를 이용하여 서버를 작동하도록 한다.

작동 확인

작동확인을 위해서는 봇테스트 기능을 사용한다.

봇테스트를 키고 우리가 입력했던 "오늘의 메뉴"를 입력해보자.

정상적으로 작동하는 것을 볼 수 있다. 또한, 터미널 창에서도 제대로 작동하는 것을 볼 수 있다.

다음시간에는 엔티티 추가와 엔티티를 읽어오는 법과 quickreply에 대해서 구현해보도록하자

'Python > Flask' 카테고리의 다른 글

[Python/Flask] 카카오톡 봇 만들기 (2)  (0) 2021.06.30
[Python/Flask] 카카오톡 봇 만들기 (1)  (0) 2021.06.30

문제

문제 분류 : dp

코드

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <utility>
using namespace std;

int dp[1001] = { 0 };

int main() {
    cin.tie(NULL);
    cout.tie(NULL);
    ios::sync_with_stdio(false);
    int num;
    int max = 0;
    int max_dp = 1;
    int temp = 0;
    vector<int> vec;
    fill_n(dp, 1001, 1);
    cin >> num;
    for (int i = 0; i < num; i++) {
        cin >> temp;
        vec.push_back(temp);
    }
    for (int i = 1; i < num; i++) {
        max = 0;
        for (int j = 0; j < i; j++) {
            if (vec[i] > vec[j]) {
                if (dp[j] > max)
                    max = dp[j];
            }
        }
        dp[i] += max;
        if (dp[i] > max_dp)
            max_dp = dp[i];
    }    
    cout << max_dp;
}

설명

이 문제를 DP로 풀기위해서 다음과 같이 접근 하였다.

  1. 모든 dp 값을 1로 초기화 한다.

    • 왜냐하면 모두가 자기 자신을 수열로 가지기 때문이다.
  2. 기준 dp 값의 이전값들을 모두 탐색하여 기준 값보다 작을 경우 max라는 변수에 작은 부분의 dp의 값과 기준 dp의 값을 더한다 (n + 1)

  3. 반복하여 만약 max 값이 새로운 값보다 작다면 max 값을 변경하고 새로운 값으로 교체한다.

예시

예제문제로 {10, 20 , 10, 30 , 20 , 50} 배열이 있을 경우

  1. dp[1]일 때

    1. dp[1] > dp [0] 이므로 dp[1] += dp[0] 이다.
  2. dp[2]일 때

    1. dp[2] == dp[0] 이므로 넘어간다.
    2. dp[2] < dp[1] 이므로 넘어간다.
  3. dp[3]일 때

    1. dp[3] > dp[0] 이므로 dp[3] += dp[0] 이다.
    2. dp[3] > dp[1] 이므로 dp[3] += dp[1] 이다.
    3. dp[3] > dp[2] 이므로 dp[3] += dp[2] 이다.

이렇게 반복해서 dp의 값중 가장 큰 값이 가장 긴 증가하는 부분 수열의 길이가 된다.

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

[BOJ] 1094번 : 01타일  (0) 2021.06.30

문제


문제의 종류는 DP 이다. 문제를 풀기위해서 타일의 개수를 세어보았다.

N = 1 일때는 1 이므로 1개이다.

N = 2 일때는 00, 11 이므로 2개이다.

N = 3 일떄는 111, 100, 001 이므로 3개이다.

N = 4 일때는 1111, 1100 , 1001, 0011 , 0000 이므로 총 5개이다.

N = 5 일때는 11111, 11100, 11001, 10011, 00111, 10000, 00100, 00001 이므로 총 8개이다.

N = 6 일때는 111111, 111100, 111001, 110011, 100111, 001111, 110000, 100100, 100001, 001100, 001001, 000011, 000000 총 13개이다.

N = 7 일때는 1111111, 0011111, 1001111, 1100111, 1110011, 1111001, 1111100, 1110000, 1100100, 1001100, 0011100, 1100001, 1000011, 0000111, 1000000, 0010000, 0000100, 0000001, 1001001, 0011001, 0011001 으로 총 13개이다.

이러한 반복을 통해 특정한 점화식을 이 식을 가진다는 것을 알 수 있다.

Dp[i] = Dp[i-1] + Dp[i-2]

이를 통해 구현 한 코드는 다음과 같다.

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <utility>
using namespace std;

int dp[1000001] = { 0,1,2,3 };

int main() {
    cin.tie(NULL);
    cout.tie(NULL);
    ios::sync_with_stdio(false);
    int num;
    for (int i = 4; i <= 1000000; i++) {
        dp[i] += (dp[i - 1] + dp[i - 2]) % 15746;
    }
    cin >> num;
    cout << dp[num];
}

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

[BOJ] 11053번 가장 긴 증가하는 부분 수열(LIS)  (0) 2021.07.02

카카오톡 봇만들기(2)

지난 시간 까지 가상머신 구축과 ssh 구축까지 완료하였다. 이번 시간에는 flask구축을 해보려고 한다.

Flask 설치

  • Flask 구축을 하기 위해서는 우선 SSH창을 킨다.
  • python 설치을 설치하기 전에 다음과 같은 명령어를 ssh창에서 입력한다.
  • sudo apt-get install update
  • sudo apt-get install upgrade
  • python 설치를 위해 다음과 같은 명령어를 입력한다.
  • sudo apt-get install python3
  • sudo apt-get install python3-pip
  • 이제 Flask과 다른 것들을 설치하기 위해서 다음과 같은 명령어를 입력한다.
  • pip install flaskpip install jsonifypip install bs4sudo apt-get install vim
  • pip install selenium
  • pip install selenium
  • pip install requests
  • 다음과 같은 파일들을 설치하는데 오류가 발생한다면 pip version을 업그레드 해주거나 혹은 pip3로 설치해보기를 바란다.

카카오톡 오픈빌더 사용

  • 카카오톡 오픈빌더를 사용하기 전에는 반드시 사전 승인이 필요하다. 사전승인이 안되었다면 좀더 기다려보길 바란다.
  • 카카오톡 오픈빌더 승인이 났다면 나의 봇에 들어가 봇을 생성하자

  • 봇을 만들었으면 시나리오를 추가하여 새로운 시나리오를 생성한다.

  • 엔티티를 만들기 전에 카카오톡 오픈빌더의 스킬에 대해서 알아보자

카카오톡 오픈빌더 스킬사용(응답별 JSON 포맷)

카카오톡 오픈빌더 도움말

  • 이 내용은 위의 링크를 참조하여 작성하였습니다.

  • 카카오톡 봇을 만들기 위해서는 이 Flask를 사용하기 전에 이 내용을 숙지해야할 필요가 있다.
  • 우리가 사용할 JSON 포맷위주로 살펴보도록 하겠다.

userRequest

  • 이 타입은 사용자의 정보를 담고 있다. 사용자의 발화와 시간대/언어, 반응한 블록의 정보를 추가적으로 포함하고 있다.

쉽게 말하면 사용자의 채팅이라고 생각할 수 있다.

상세필드

필드명 타입 설명
timezone string 사용자의 시간대를 반환합니다.한국에서 보낸 요청이라면 “Asia/Seoul”를 갖습니다.
block Block 사용자의 발화에 반응한 블록의 정보입니다.블록의 id와 name을 포함합니다.
utterance string 봇 시스템에 전달된 사용자의 발화입니다.
lang string 사용자의 언어를 반환합니다.한국에서 보낸 요청이라면 “kr”를 갖습니다.
user User 사용자의 정보입니다.

상세필드는 이런식으로 이루어져 있다. 하나하나 살펴보자

  1. timezone은 채팅을 입력한 사용자의 시간대를 가지고 있는 변수이다.
  2. block은 자세하게 모르겠는데 카카오톡 오픈빌더에서 봇을 구성할 때 웰컴 블록 이런식으로 여러가지 블록을 구성한다. 이 내용인 것 같다.
  3. utterance는 중요하다. 이는 사용자가 입력한 채팅을 가지고 있는 변수이다. 이를 많이 사용할 것 이다.
  4. lang은 어떤 언어를 사용했는지 반환한다. 한국에서면 kr을 가진다.
  5. user는 입력한 사용자의 정보이다. 입력한 사용자는 고유 id를 가지고 있다.

예시코드

{
 "userRequest": {
    "timezone": "Asia/Seoul",
    "params": {},
    "block": {
      "id": "<블록 id>",
      "name": "<블록 이름>"
    },
    "utterance": "<사용자 발화>",
    "lang": "kr",
    "user": {
      "id": "<사용자 botUserKey>",
      "type": "botUserKey",
      "properties": {
        "plusfriendUserKey": "<카카오톡 채널 사용자 id>"
      }
    }
  },
  "contexts": [],
  "bot": {
    "id": "<봇 id>",
    "name": "<봇 이름>"
  },
  "action": {
    "name": "<스킬 이름>",
    "clientExtra": null,
    "params": {},
    "id": "<스킬 id>",
    "detailParams": {}
  }
}

SkillResponse

  • 스킬응답으로 이는 vesion/template/context/data의 총 4가지로 구성이된다.

쉽게 말하자면 카카오톡 채팅 봇의 응답 의 형식으로 볼 수 있다.

예제 코드(기본형)

{
  "version": "2.0",
  "template": {
    ...
  },
  "context": {
    ...
  },
  "data": {
    ...
  }
}
  • 기본형은 다음과 같다.

SkillTemplate

  • SkillTemplate는 다음과 같이 2가지로 구성된다.
이름 타입 필수여부 제한
outputs Array y 1개 이상 3개 이하
quickReplies Array n 10개 이하

outputs(출력 그룹)

  • 출력 그룹은 여러 종류의 출력 요소를 포함한다. 출력요소들은 다음 표와 같다.
이름 설명 *캐로셀 가능 여부
simpleText 간단 텍스트 X
simpleImage 간단 이미지 X
basicCard 기본 카드 O
commerceCard 커머스 카드 O
listCard 리스트 카드 X
  • 캐로셀이란 여래 개의 출력 요소를 묶어서 제공한다. 사용할 때는 "carousel"이라고 적어서 사용한다.
simpleText
  • 이는 그냥 단순한 텍스트를 넘겨줄 때 사용한다. 기본 형과 출력 예제는 다음과 같다.

{
    "version": "2.0",
    "template": {
        "outputs": [
            {
                "simpleText": {
                    "text": "간단한 텍스트 요소입니다."
                }
            }
        ]
    }
}

나머지 값들은 카카오톡 오픈빌더 도움말을 참고 부탁드립니다.

flask 기본사용

  • 이제 Flask를 설정해보자 flask를 설정하기위해서 다음과 같은 명령어를 기본 ssh창에서 입력하자
  • mkdir 프로젝트이름vim server.py
  • cd 프로젝트이름
  • 이를 수행하여 server.py의 편집에 들어와서 다음과 같은 기본 코드를 작성해 보자.
  • vim을 사용할 때 편집은 i를 누르면 되고 끝내고 저장하고 편집을 나갈 때는 Esc버튼을 누른 이후 :wq를 입력하면 나갈 수 있다.
from flask import Flask

app = Flask(__name__)

@app.route('/')
def home():
    return "Hello, Flask"

if __name__ == 'main__':
    app.run(host='0.0.0.0', port=5000, debug=True)
  • Flask의 기본 형태이다. 이때 주의할 점으로는 app.run이 중요하다.
  • app.run에서 host0.0.0.0으로 되어있지 않으면 외부에서 접속을 할 수없고 local에서 만 사용이 가능하다.
  • 기본포트는 5000번 이지만 port를 5000이라고 적어두었다. 5000번 포트를 사용하기 때문에 Azure에서 반드시 인바운더리 규칙을 5000번으로 재설정 해두도록 하자(모르겠다면?)
  • debug는 오류가 났을 때 오류가 난 이유를 설명해주므로 켜두는 편이다.
  • 설정이 끝났으면 다음과 같은 명령어를 입력하여 파일을 실행해보자.
  • python3 server.py
  • 다음과 같은 주소로 들어가서 실행이 되는지 확인해보자.

http://가상머신 아이피주소:5000

'Python > Flask' 카테고리의 다른 글

[Python/Flask] 카카오톡 봇 만들기(3)  (0) 2021.07.08
[Python/Flask] 카카오톡 봇 만들기 (1)  (0) 2021.06.30

+ Recent posts