Archive

2021-01-04 TIL

|

2021-01-04 TIL


  • 오늘 한 것
    1. 이것이 리눅스다 CentOS/Linux 프록시 서버 - 서버에서 받아온 데이터를 캐시에 저장해두었다가 클라이언트에서 동일한 데이터 요청시 서버까지 안가고 캐시에서 꺼내서 전달해주는 프록시 서버의 설치와 운영에 대해 공부했다.
    2. 학원 비대면 수업(15:30~22:00) CMS 최종완성 - File Save / Load / Save As 기능을 구현하고 간단하지만 있을 기능은 다 있었던 CMS의 최종 완성본이 나왔다.
    3. 개인 프로젝트 주제 고민? - 자바의 GUI를 이용하여 무언가 만들어야하는데 역시 swing이나 FX만으로는 디자인이 너무 구리다.. 하긴 디자인이 중요한 것은 아니니 학사관리 프로그램이나 CMS, 예약 시스템, POS, 가계부 중에서 고민을 해봐야겠다.
    4. 투두리스트 최종 완성 - 바닐라 자바스크립트를 연습하려고 시작했던 투두리스트의 최종완성을 위해 애좀 먹었다. 삭제 버튼을 눌러서 화면과 로컬스토리지에서 해당 내용을 삭제하는 기능과 체크박스를 클릭하면 로컬스토리지에 저장해두고 새로고침 후에도 체크한 항목들을 보여주는 기능이 관건이었다. 추후 블로그 포스팅 예정이다.
    5. 블로그 포스팅 (Java Day Day 19, 20 , CentOS 프록시)

  • 내일 할 것
    1. 이것이 리눅스다 CentOS 공부
    2. 학원 비대면 수업(15:30~22:00) 스레드
    3. 개인 프로젝트 주제 선정
    4. Java FX 공부
    5. 블로그 포스팅 (Java Day 21, CentOS PXE, Javascript Day9)



  • 끝으로

연말연시 분위기와 생일 등으로 해이해져있던 나에게 채찍질하고 긴장의 끈을 다시 잡고 가야겠다. 블로그도 밀리지 않고 빠딱빠딱 잘 쓰자.

오늘의 한 줄 총평 : 빠딱빠딱


CentOS8 프록시 서버 설치와 운영

|

CentOS8 프록시 서버 설치와 운영


이것이 리눅스다 의 Chapter17 프록시 서버 설치와 운영의 실습내용입니다.



프록시 서버는 자신의 캐시에 데이터를 저장해놓고 클라에게 전달해주는 역할을 한다.

클라가 일일히 서버와 데이터를 주고 받고 할 필요없이 같은 데이터라면 프록시 서버의 캐시에서 꺼내오면 된다는 소리. 웹 서핑 할 때의 속도가 향상되어 사용자의 만족도가 올라간다.


그럼 준비를 해보자. dnf 명령으로 squid 패키지를 설치하자.

vi 혹은 gedit 편집기로 /etc/squid/squid.conf 파일을 다음과 같이 수정하고 저장하자.

conf1

conf2

conf3


acl (Access Control List)는 지정된 컴퓨터, 네트워크만 접속을 허가해주는 구문,

centos8의 이름으로 설정된 네트워크의 접근을 허용했으며,

캐시가 저장될 디렉토리를 지정해주고 데이터공간을 1000Mb, 16개의 하위 디렉토리와 또 그 하위로 256개의 디렉토리를 지정했다.


port

조금 전 conf 파일의 62행을 보면 포트번호가 3128로 지정되어있는 것을 볼 수 있다.

익숙한 8080 포트로 변경해도 좋지만 우선은 그냥 가자.

firewall-cmd 명령으로 3128 포트를 열어주고 reload를 하자.


아직 squid를 시작하지 말고 client 에서 테스트를 해보자.

firefox를 열고 프록시 세팅을 하자.

firefox의 [환경 설정]에서 [네트워크 설정]에서 프록시 접근 설정을 할 수 있다.

프록시설정


아무 사이트나 들어가보면 당연하지만 접속을 할 수가 없다.

접속불가


이제 server의 squid를 가동시켜주고 다시 client에서 웹서핑을 해보자.

active

성공

성.공.적.

웹 데이터는 캐시에 저장될 것이다.


마찬가지로 window 운영체제의 client에서도 프록시 서버를 설정할 수 있다.

끝.




참고자료


이것이 리눅스다 Chepter 17 프록시 서버 설치와 운영

Java Day 20 계산기 구현

|

Java Day 20 계산기 구현


  • 완성 화면

계산기


  • 조건

    • 처음 화면에 표시될 내용은 0.

    • 숫자 버튼 클릭시마다 숫자의 마지막에 . 표시
    • 소수점 버튼 클릭시 숫자 중간에 .이 들어가고 이 때는 마지막에 . 이 없다
    • +/- 버튼 클릭시 양수, 음수 전환
    • [숫자] - [연산자] - [숫자] - [연산자] 클릭시 = (equal) 버튼을 클릭하지 않아도 계산의 중간 결과가 화면에 화면에 출력
    • backspace 클릭시 뒤에서부터 한 글자씩 삭제, 이 때 숫자의 마지막 . 은 지워지지 않는다
    • 한 자리 숫자일때 backspace 클릭시 0. 으로 초기화
    • CE 버튼 클릭시 화면에 0. 표시되나 중간 결과가 사라지진 않는다
    • C 클릭시 완전 초기화
    • 0 연타 해도 화면에 0이 연속으로 출력되지 않는다 (소수점 제외)


  • 순서도

    • 레이아웃 및 이벤트 걸기
    • 숫자를 처음 눌렀을 때와 아닐 때를 boolean 값으로 판별
    • 소수점이 눌렸을 때와 아닐 때를 boolean 값으로 판별
    • 사칙연산은 누른 연산자를 변수에 저장하여 switch문으로 연산
    • 각각의 버튼들 구현


  • 코딩

import java.awt.*;
import java.awt.event.*;

public class MyCal extends Frame implements ActionListener {
	// 멤버필드
	private Label disp = new Label("0.", Label.RIGHT);
	private Button[] btn_num = new Button[12];
	private String[] str_num = { "7", "8", "9", "4", "5", "6", "1", "2", "3", "0", "+/-", "." };
	private Button[] btn_func = new Button[3];
	private String[] str_func = { "←", "CE", "C" };
	private Button[] btn_oper = new Button[4];
	private String[] str_oper = { "÷", "×", "-", "+" };
	private Button btn_equ = new Button("=");
	private double result = 0;
	private boolean dotCheck = true;
	private boolean decimal = false;
	private char operator = '+';

Label에 출력되는 값들을 표시하고 중복되는 코드를 방지하기 위해 배열을 이용해서 초기화한다.

결과값이 저장될 변수는 result이다.

boolean dotcheck로 숫자를 누른게 처음인지 판별, 처음이면 true 아니면 false이다.

boolean decimal로 소수점을 눌렀는지 판별, 누르면 true, 초기값은 false이다.

누른 연산자가 무엇인지 담기 위한 operator 변수, 초기값은 + 이다.


// 생성자
public MyCal() {
    super("계산기");
    buildGUI();
    setEvent();
    addWindowListener(new WindowAdapter() {
        @Override
        public void windowClosing(WindowEvent e) {
            System.exit(0);
        }
    });
    setSize(300, 400);
    setResizable(false);
    setVisible(true);
}

buildGUI() 메소드로 레이아웃을 구현한다.

setEvent() 메소드로 각각의 버튼에 이벤트를 건다.

익명 클래스를 이용해서 계산기 window의 X 버튼 클릭시 프로그램 종료를 구현한다.

이하 생략.

// buildGUI() 메소드
public void buildGUI() {// 레이아웃
    setLayout(new BorderLayout(5, 5));
    setBackground(Color.orange);
    Panel main_disp = new Panel(new BorderLayout(5, 5));
    main_disp.add("North", new Label());
    main_disp.add("West", new Label());
    main_disp.add("East", new Label());
    main_disp.add("South", new Label());
    disp.setBackground(Color.white);
    disp.setFont(new Font("SansSerif", Font.BOLD, 20));
    main_disp.add("Center", disp);
    add("North", main_disp);
    Panel main = new Panel(new GridLayout(5, 4, 5, 5));
    for (int i = 0; i < str_func.length; i++) {
        btn_func[i] = new Button(str_func[i]);
        btn_func[i].setFont(new Font("SansSerif", Font.BOLD, 20));
        main.add(btn_func[i]);
    }
    btn_oper[0] = new Button(str_oper[0]);
    btn_oper[0].setFont(new Font("SansSerif", Font.BOLD, 20));
    main.add(btn_oper[0]);
    for (int i = 0; i < str_num.length; i++) {
        btn_num[i] = new Button(str_num[i]);
        btn_num[i].setFont(new Font("SansSerif", Font.BOLD, 20));
        main.add(btn_num[i]);
        switch (i) {
            case 2:
                btn_oper[1] = new Button(str_oper[1]);
                btn_oper[1].setFont(new Font("SansSerif", Font.BOLD, 20));
                main.add(btn_oper[1]);
                break;
            case 5:
                btn_oper[2] = new Button(str_oper[2]);
                btn_oper[2].setFont(new Font("SansSerif", Font.BOLD, 20));
                main.add(btn_oper[2]);
                break;
            case 8:
                btn_oper[3] = new Button(str_oper[3]);
                btn_oper[3].setFont(new Font("SansSerif", Font.BOLD, 20));
                main.add(btn_oper[3]);
                break;
        }
        btn_equ.setFont(new Font("SansSerif", Font.BOLD, 20));
        main.add(btn_equ);
    }
    add("West", new Label());
    add("East", new Label());
    add("South", new Label());
    add("Center", main);
}

GridLayout은 순서대로만 넣어야해서 코드가 좀 복잡해졌다. 숫자 3개 넣고 연산자 1개가 들어갈 수 있도록 for문 안에 switch문으로 제어를 해주었다.


// setEvent() 메소드
public void setEvent() {// 이벤트 걸기
    for (int i = 0; i < btn_num.length; i++) {
        btn_num[i].addActionListener(this);
    }
    for (int i = 0; i < btn_oper.length; i++) {
        btn_oper[i].addActionListener(this);
    }
    btn_equ.addActionListener(this);
    for (int i = 0; i < btn_func.length; i++) {
        btn_func[i].addActionListener(this);
    }
}

for문으로 각각의 버튼 배열을 순회하며 이벤트를 건다.


@Override
public void actionPerformed(ActionEvent e) {
    for (int i = 0; i < btn_num.length - 2; i++) {
        if (e.getSource() == btn_num[i]) {
            if (dotCheck) {					// 숫자를 처음 눌렀을 때
                disp.setText(btn_num[i].getLabel() + ".");
                dotCheck = false;
            } else {						// 숫자를 누른게 처음이 아닐 때
                if (disp.getText().equals("0.") && btn_num[i].getLabel().equals("0"))
                    return; 				// 0 연타 막기
                if (!decimal) {				// 소수점 버튼 안눌렀을 때
                    String temp = disp.getText();
                    temp = temp.substring(0, temp.length() - 1);
                    disp.setText(temp + btn_num[i].getLabel() + ".");
                } else {					// 소수점 버튼 눌렀을 떄
                    String temp = disp.getText();
                    disp.setText(temp + btn_num[i].getLabel());
                }
            }
            return;
        }
    } // end for
    if (e.getSource() == btn_num[btn_num.length - 1]) {// 소수점 클릭시
        dotCheck = false;
        decimal = true;
        return;
    }
    if (e.getSource() == btn_num[btn_num.length - 2]) {// +/- 클릭시
        String temp = disp.getText();
        if (temp.equals("0.")) {
            return;
        } else {
            if (temp.charAt(0) != '-') {
                disp.setText("-" + temp);
            } else {
                disp.setText(temp.substring(1));
            }
        }
        return;
    } // end if
    for (int i = 0; i < btn_oper.length; i++) {// 연산자 클릭시
        if (e.getSource() == btn_oper[i]) {
            calc();
            operator = btn_oper[i].getLabel().charAt(0);
            dotCheck = true;
            decimal = false;
            return;
        }
    } // end for
    if (e.getSource() == btn_equ) {// 등호 클릭시
        calc();
        operator = '+';
        result = 0;
        return;
    }
    if (e.getSource() == btn_func[1]) {// CE 클릭시
        disp.setText("0.");
        dotCheck = true;
        decimal = false;
        return;
    }
    if (e.getSource() == btn_func[2]) {// C 클릭시
        disp.setText("0.");
        operator = '+';
        result = 0;
        dotCheck = true;
        decimal = false;
        return;
    }
    if (e.getSource() == btn_func[0]) {// backspace 클릭시
        String temp = disp.getText();
        if (temp.length() == 2) {// 정수 한 자리
            disp.setText("0.");
            dotCheck = true;
            decimal = false;
            operator = '+';
            return;
        }
        if (temp.length() == 3 && temp.charAt(0) == '-') {// 음수 한 자리
            disp.setText("0.");
            dotCheck = true;
            decimal = false;
            operator = '+';
            return;
        }
        if (temp.length() == 3 && temp.charAt(0) == '0') {// 소수 한 자리
            disp.setText("0.");
            dotCheck = true;
            decimal = false;
            operator = '+';
            return;
        }
        if (temp.charAt(temp.length() - 1) == '.') {	// 정수
            disp.setText(temp.substring(0, temp.length() - 2)+".");
        } else {										// 소수
            disp.setText(temp.substring(0, temp.length() - 1));
        }
        return;
    }
}

action event의 수행내용을 구현한다.


// calc() 메소드
public void calc() {// 계산 기능
    double value = Double.parseDouble(disp.getText());
    switch (operator) {
        case '+':
            result += value;
            break;
        case '-':
            result -= value;
            break;
        case '×':
            result *= value;
            break;
        case '÷':
            result /= value;
            break;
    }
    double temp = result - (int) result;

    if (temp > 0) {
        disp.setText(String.valueOf(result));
    } else {
        disp.setText(String.valueOf((int) result) + ".");
    }
}

결과값의 default는 double형이기에 int로 형변환한 결과값으로 빼주어 그 값이 0보다 큰지 아닌지로 정수와 소수를 구분한다. 소수면 그대로 출력하고 정수면 숫자의 뒤에 **. **이 붙는다



마치며


평소에 아무 생각없이 사용하던 계산기도 이렇게 만들기가 힘들었구나..

처음에는 막연히 어렵게만 느껴졌던 계산기였는데 원리를 알고 연습을 해보니 의외로 할만하다.

boolean 으로 스위치를 키고 끄듯이 활용 할 수 있는 방법을 배웠는데 앞으로 자주 보게 될 것 같다.

awt는 정말 비효율적이지만 dos창에서 벗어나려면 swing과 fx도 공부해야겠다.



Java Day 19 IO - File (2)

|

Java Day 19 IO - File (2)


  1. Scanner Class

    • java.util 패키지로 엄밀히 따지면 IO는 아니다.
    • 입력 값(문자열, 파일, 입력 스트림)을 정규 표현식으로 구분하여 문자열이나 기본 데이터 타입으로 토큰 할 수 있는 클래스. 정규 표현식은 언어를 표현 할 수 있는 문자식.
    • 생성자

    생성자


    • 메소드

    메소드


    //main 메소드 생략
    System.out.print("입력 : ");
    Scanner scan = new Scanner(System.in);
    int number = scan.nextInt();
    System.out.printf("스캔 : %d", number);
    scan.close(); // 사용 후 닫아주어야함
    //숫자를 입력받아 console에 출력
    


  2. 객체의 직렬화

    • 객체(객체의 메모리와 객체 정보 등)를 바이트 형태로 변환
    • 객체를 스트림을 이용해서 보관하거나 전송 할 수 있다.
    • 직렬화 가능한 클래스 만들기
      1. Serializable 인터페이스를 상속받는다
      2. Externalizable 인터페이스를 상속받는다
    import java.io.Serializable;
       
    public class Data implements Serializable {
    	private static final long serialVersionUID = 1L;
    	private int No;
    	private String name;
    	private String mail;
    	public int getNo() {
    		return No;
    	}
    	public void setNo(int no) {
    		No = no;
    	}
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public String getMail() {
    		return mail;
    	}
    	public void setMail(String mail) {
    		this.mail = mail;
    	}
    }
    


  3. ObjectStream

    • ObjectOutputStream : 객체를 직렬화하는 메소드를 제공해주는 스트림, writeObject()
    • ObjectInputStream : 객체를 역직렬화하는 메소드를 제공해주는 스트림, readObject()
    //main 메소드 생략
    ObjectOutputStream oos = null;
        try {
            oos = new ObjectOutputStream(new FileOutputStream("C:\\myProject\\obj.txt"));
            Data data = new Data();
            data.setNo(33);
            data.setName("홍길동");
            data.setMail("hong@gmail.com");
            oos.writeObject(data);
        } catch(FileNotFoundException e) {
            e.printStackTrace();
        } catch(IOException e) {
            e.printStackTrace();
        } finally {
            try { if(oos!=null) oos.close(); } catch(IOException e) {}
        }
    // c:/myProject/obj.txt 파일에 클래스 정보가 바이트로 전환되어 작성되어있다
    
    //main 메소드 생략
    ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(new FileInputStream("C:/myProject/obj.txt"));
            Data data = (Data)ois.readObject();
            System.out.println("번호 : " + data.getNo());
            System.out.println("이름 : " + data.getName());
            System.out.println("메일 : " + data.getMail());
        } catch(ClassNotFoundException e) {
            e.printStackTrace();
        } catch(FileNotFoundException e) {
            e.printStackTrace();
        } catch(IOException e) {
            e.printStackTrace();
        } finally {
            try { if(ois != null) ois.close();} catch(IOException e) {}
        }
    // 바이트 형태로 작성된 클래스 정보를 읽어와서 그 안의 정보들이 출력된다.
    





참고 자료


이것이자바다

자바프로그래밍100% 실전가이드

KG아이티뱅크 자바 강의자료

2021-01-02 TIL

|

2021-01-02 TIL


  • 오늘 한 것
    1. TO-DO-LIST JS구현 - 계획했던 기능들은 일단 다 완성을 했는데 몇몇 오류들을 손봐야한다. TO DO LIST 항목들을 삭제하고 로컬스토리지에서도 삭제를 해야하는데 그 연결방법을 좀 더 고민해봐야겠다. 체크박스 클릭시 체크가 되고 다시 누르면 체크가 풀려야하는데 안되는점. 흐미~아직은 반쪽짜리 앱이다. 우선 내일은 생일이니 하루 지나고 최종완성을 해야겠다.

  • 내일 할 것
    1. 생일 잘 보내기

  • 끝으로

Happy Brith.

오늘의 한 줄 총평 : Happy Brith