안드로이드 팝업 메뉴를 선택적으로 적용해야 할 경우에 대한 코드다.


/res/menu/popup_menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:id="@+id/aaa"
        android:title="초기화" />
    <item android:id="@+id/bbb"
        android:title="로그인" />
    <item android:id="@+id/ccc"
        android:title="제온" />
    <item android:id="@+id/ddd"
        android:title="판테온" />
</menu> 


Java 코드에서 구현할 사항

PopupMenu popup = new PopupMenu(MainActivity.this, view);
popup.setOnMenuItemClickListener(MainActivity.this);
popup.inflate(R.menu.popup_menu);
popup.show(); 

PopupMenu popup = new PopupMenu(MainActivity.this, v);
popup.getMenuInflater().inflate(R.menu.popup_menu, popup.getMenu());
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
    public boolean onMenuItemClick(MenuItem item) {
        Toast.makeText(MainActivity.this, "You Clicked : " + item.getTitle(), Toast.LENGTH_SHORT).show();
        return true;
    }
});
popup.show();

PopupMenu popup = new PopupMenu(MainActivity.this, view);
Menu menu = popup.getMenu();
if(layoutMode.equals("0")){
    menu.add(Menu.NONE, R.id.aaa, Menu.NONE, "초기화");
    menu.add(Menu.NONE, R.id.bbb, Menu.NONE, "로그인");
} else if(layoutMode.equals("1")){
    menu.add(Menu.NONE, R.id.ccc, Menu.NONE, "제온");
    menu.add(Menu.NONE, R.id.ddd, Menu.NONE, "판테온");
}
popup.setOnMenuItemClickListener(MainActivity.this);
popup.show();


선택 적용하지 않고, 한꺼번에 나오게 하고자 한다면 popup.inflate(R.menu.popup_menu);

레이아웃 모드에 따라서 선택적으로 팝업메뉴가 나오게 하고 싶을 때는 위와 같이 구현해주면 된다.


팝업 메뉴를 완전 동적으로 추가하는 것은 https://link2me.tistory.com/1366 를 참조하면 된다.


동적 메뉴 생성 코드 예제

public class Menu_Item {
    private String shop_name;
    private String url;

    public Menu_Item() {
    }

    public Menu_Item(String shop_name, String url) {
        this.shop_name = shop_name;
        this.url = url;
    }

    public String getShop_name() {
        return shop_name;
    }

    public void setShop_name(String shop_name) {
        this.shop_name = shop_name;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }
}
 

package com.link2me.android.dnmenu;

public class MainActivity extends AppCompatActivity implements View.OnClickListener  {
    Context context;
    // ArrayList 선언
    ArrayList<Menu_Item> menuItems  = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_graphview);
        context = MainActivity.this;
        initView();
    }

    private void initView() {
        String url = "http://www.abc.com/chart/data.json";
        DataVolley(url);
        addMenuData();
    }

    private void addMenuData(){
        // 안드로이드에서 직접 추가를 하면 신규 사이트가 추가되거나 삭제 또는 변경시
        // 앱을 업그레이드해야만 현행 정보를 이용할 수 있다.
        MenuList("전체","http://www.abc.com/chart/data.json");
        MenuList("서울","http://www.abc.com/chart/data1.json");
        MenuList("경기","http://www.abc.com/chart/data2.json");
    }

    private void MenuList(String shop_name, String url){
        Menu_Item item = new Menu_Item();
        item.setShop_name(shop_name);
        item.setUrl(url);
        menuItems.add(item);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.back_btn:
                finish();
                overridePendingTransition(R.anim.rightin, R.anim.rightout);
                break;
            case R.id.home_btn:
                Intent intent = new Intent(MainActivity.this, Main.class);
                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
                startActivity(intent);
                break;
            case R.id.btnMenuList:
                // 팝업 메뉴 나오게 하는 방법
                PopupMenu popupMenu = new PopupMenu(this, view);
                Menu menu = popupMenu.getMenu();
                for(int i = 0; i < menuItems.size(); i++){
                    menu.add(Menu.NONE,i,Menu.NONE, menuItems.get(i).getShop_name());
                }
                popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
                    @Override
                    public boolean onMenuItemClick(MenuItem item) {
                        int i = item.getItemId();
                        Toast.makeText(context, item.getTitle() + " 선택했습니다", Toast.LENGTH_SHORT).show();
                        DataVolley(menuItems.get(i).getUrl());
                        return true;
                    }
                });
                popupMenu.show();
                break;
            default:
                break;
        }
    }
}
 



728x90
블로그 이미지

Link2Me

,

인프런 사이트에서 "Java로 배우는 자료구조" 강의를 듣고 있는데 강사가 설명을 너무 잘해준다.

기본기를 탄탄히 다지지 않은 상태에서 코딩을 배우다보니 기초가 부족하고 응용 하려고 할 때 시간을 많이 낭비한다.

튼튼한 기초를 쌓는것이 필요하여 강좌를 열심히 듣고 있다.

 

public class Code01 {
    public static void main(String[] args) {
        // 클래스는 결국 하나의 타입이다. 마치 int, double 등 처럼.
        // 사용자가 정의한 새로운 타입이라는 의미에서 "사용자 정의 타입"이라고 부르기도 한다.
        // Person1 의 변수를 선언하고 사용한다.
        Person1 fst = new Person1();
        // fst 라는 변수가 만들어지지만 그 "안"에 사람이름과 전화번호가 저장되지는 않는다.
        // 이름과 전화번호를 저장할 Person1 객체는 new 명령으로 따로 만들어야 하고 변수 fst에는 그 객체의 주소(참조)를 저장할 수 있다.
        // 모든 프리미티브 타입(프로그램 자체가 기본적으로 제공해주는 타입)의 변수는 보통 변수이다. 즉 변수 자체에 값이 저장된다.
        // 프리미티브 타입이 아닌 모든 변수는 참조 변수이다.
        // 즉 실제 데이터가 저장될 "객체"는 new 명령으로 따로 만들어야 하고, 참조 변수에는 그 객체의 주소를 저장한다.
        // new 로 객체를 생성하면 이름을 가질 수 없다. 그래서 참조 변수가 필요하다.
        // 객체를 만들기 전에는 참조변수를 참조할 수 없다.
        fst.name = "John";
        fst.number = "010-1111-5555";
 
        System.out.println("Name :" + fst.name + ", Number : " + fst.number);
 
        Person1 snd = fst; // fst와 snd는 동일한 객체를 참조
        snd.name = "Tom";
        System.out.println("Name :" + fst.name + ", Number : " + fst.number);
        System.out.println("Name :" + snd.name + ", Number : " + snd.number);
 
        Person1 [] members = new Person1[100];
        members[0= fst;
        members[1= snd;
        members[2= new Person1(); // members[2]은 참조변수
        members[2].name = "데이비드";
        members[2].number ="010-2225-8789";
 
        System.out.println("First is " + members[0].name + " wiht mumber " + members[0].number);
        System.out.println("Second is " + members[1].name + " wiht mumber " + members[1].number);
        System.out.println("Third is " + members[2].name + " wiht mumber " + members[2].number);
 
    }
 
}
 
class Person1 {
    String name;
    String number;
}
 
 
cs

 

 

자바의 정석 동영상 강좌를 듣고, Android 앱을 구글링과 설계 로직을 구현 및 초보 실전 코딩을 하면서 기초가 강해야 한다는 걸 절실히 느낀다.

 

클래스 개념 이해 예제

// 클래스 : 객체(변수 + 메소드)를 정의해 놓은 것
// ① 설계도 ② 데이터 + 함수 ③ 사용자 정의 타입
// 클래스가 필요한 이유는 ? 객체를 생성하기 위해
class Tv {
    // Tv의 속성(멤버변수)
    String color;           // 색상
    boolean power;             // 전원상태(on/off)
    int channel;               // 채널
 
    // Tv의 기능(메서드)
    void power()   { // TV를 켜거나 끄는 기능을 하는 메서드
        power = !power;
    }
    void channelUp() { // TV의 채널을 높이는 기능을 하는 메서드
        ++channel;
    }
    void channelDown() { // TV의 채널을 낮추는 기능을 하는 메서드
        --channel;
    }
}
 
class MyMath {
    long add(long a, long b) {
        long result = a + b;
        return result;
        //    return a + b;    // 위의 두 줄을 이와 같이 한 줄로 간단히 할 수 있다.
    }
    long subtract(long a, long b) { return a - b; }
    long multiply(long a, long b) { return a * b; }
    double divide(double a, double b) {
        return a / b;
    }
}
 
// 하나의 소스 파일에는 하나의 public class 만 허용한다.
// 파일명은 public class 명과 일치한다.
public class ClassEX1 {
    public static void main(String[] args) {
        Tv t1;                 // Tv인스턴스를 참조하기 위한 변수 t를 선언
        t1 = new Tv();         // Tv인스턴스(객체)를 생성한다.
        System.out.println("t1 channel값은 " + t1.channel + "입니다.");
        t1.channel = 7;        // Tv인스턴스의 멤버변수 channel의 값을 7로 한다.
        System.out.println("t1의 channel값을 "+t1.channel+"로 변경하였습니다.");
        t1.channelDown();      // Tv인스턴스의 메서드 channelDown()을 호출한다.
        System.out.println("t1의 현재 채널은 " + t1.channel + " 입니다.");
 
        Tv t2 = new Tv();
        System.out.println("t2의 channel값은 " + t2.channel + "입니다.");
 
        t2 = t1; // t2 에 t1의 참조변수를 할당하라. 즉 t1의 참조변수가 가리키는 주소를 t2에 할당(대입)하라.
        // t2 에 원래 할당했던 주소의 객체와는 연결이 끊어진다.
        // t2 가 가리키는 객체의 주소가 0x200 이라고 하면
        // 0X200번지의 객체를 GC(Garbage Collector)가 자동으로 메모리에서 제거한다. (memory leak 방지)
        System.out.println("t2의 channel값은 " + t2.channel + "입니다.");
 
        System.out.println();
 
        MyMath mm = new MyMath();
        long result1 = mm.add(5L, 3L);
        long result2 = mm.subtract(5L, 3L);
        long result3 = mm.multiply(5L, 3L);
        double result4 = mm.divide(5L, 3L);
 
        System.out.println("add(5L, 3L) = " + result1);
        System.out.println("subtract(5L, 3L) = " + result2);
        System.out.println("multiply(5L, 3L) = " + result3);
        System.out.println("divide(5L, 3L) = " + result4);
    }
}
 
 

 

 

기본형 매개변수, 참조형 매개변수, 참조형 반환 예제

class Data {
    int x;
 
    public Data() { // 기본(default) 생성자
    }
    // 기본 생성자를 생략하면 컴파일러가 자동으로 추가해준다.
}
class Data2 { int x; }
class Data3 { int x; }
 
public class ClassEX2 {
    private static void change(int x) {
        // 기본형 매개변수는 값을 읽기만 한다.
        x = 1000;
        System.out.println("change() : x = " + x);
    }
 
    private static void change(Data2 d) { // 참조형 매개변수
        // 참조형 매개변수는 값을 읽고 쓸 수 있다.
        d.x = 1000;
        System.out.println("change() : x = " + d.x);
    }
 
    static Data3 copy(Data3 d) {
        Data3 tmp = new Data3();    // 새로운 객체 tmp를 생성한다.
        tmp.x = d.x;  // d.x의 값을 tmp.x에 복사한다.
        return tmp;   // 복사한 객체의 주소를 반환한다.
    }
 
    public static void main(String[] args) {
        System.out.println("기본형 매개변수 객체 생성의 값 변화");
        Data d = new Data();
        // 참조변수 d는 스택영역에 생성되고, new Data() 객체는 Heap 영역에 생성된다.
        // 참조변수 d에 Heap 영역에 생성된 객체의 주소를 할당한다.
        System.out.println("main() : x = " + d.x);
        d.x = 10;
        System.out.println("main() : x = " + d.x);
 
        change(d.x);
        System.out.println("After change(d.x)");
        System.out.println("main() : x = " + d.x);
 
        System.out.println();
 
        System.out.println("참조형 매개변수 객체 생성의 값 변화");
        Data2 d2 = new Data2();
        System.out.println("main() : x = " + d2.x);
        d2.x = 10;
        System.out.println("main() : x = " + d2.x);
 
        change(d2);
        System.out.println("After change(d2)");
        System.out.println("main() : x = " + d2.x);
 
        System.out.println();
 
        Data3 d3 = new Data3();
        d3.x = 10;
 
        Data3 d4 = copy(d3);
        System.out.println("d3.x ="+d3.x);
        System.out.println("d4.x="+d4.x);
    }
 
}
 

 

Object 타입 Integer 예제

public class ClassEX3 {
    public static void main(String[] args) {
        Integer a = 10// Integer 는 Object 타입
        System.out.println("Before: " + a);
        changeInteger(a);
        System.out.println("After: " + a);
 
        System.out.println();
 
        String s = "hello";
        changeString(s);
        System.out.println(s);
    }
 
    // 자바에서 Wrapper class 에 해당하는
    // Integer, Character, Byte, Boolean, Long, Double, Float, Short 클래스는 모두 Immutable 이다.
    // 그래서 heap 에 있는 같은 오브젝트를 레퍼런스 하고 있는 경우라도,
    // 새로운 연산이 적용되는 순간 새로운 오브젝트가 heap 에 새롭게 할당된다.
    //  Immutable Object 는 불변객체로써, 값이 변하지 않는다.
    //  변경하는 연산이 수행되면 변경하는 것 처럼 보이더라도 실제 메모리에는 새로운 객체가 할당되는 것이다.
    private static void changeInteger(Integer a) {
        a += 10;
    }
 
    public static void changeString(String param) {
        param += " world";
    }
}
 
 

 

 

728x90

'안드로이드 > Java 문법' 카테고리의 다른 글

[Java] 다형성  (0) 2019.06.30
How to validate IP address with regular expression  (0) 2019.06.17
자바 Arraylist  (0) 2019.05.26
Java BubbleSort  (0) 2019.05.13
java Singleton Design Pattern  (0) 2018.09.24
블로그 이미지

Link2Me

,

Arraylist 에 대한 기능을 테스트하고 적어둔다.

VSCode 에서 자바 Extension을 설치하고 테스트해봤는데 아직은 Eclispe 만큼 만족스럽지 못하더라.


중복 저장은 배제하고 지정한 개수만큼만 ArrayList 에 저장하는 로직이다.

1. 자료 입력이 들어오면 중복 검사를 한다.

2. 중복된 값이 없으면 저장한다.

3. 특정 개수 이상이면 최초 등록한 걸 지워라.


import java.util.ArrayList;
import java.util.Collections;

public class MyArrayList {
    static ArrayList<String> cars = new ArrayList<String>();
    static int Max = 3;
    
    public static void main(String[] args) {
        
        ItemAdd("Volvo");
        ItemAdd("BMW");
        ItemAdd("Ford");
        ItemAdd("Mazda");
        ItemAdd("KIA K5");
        
        //Collections.sort(cars);  // Sort cars
        //System.out.println(cars.contains("Ford")); // 값의 존재 여부 출력
        System.out.println(cars); // 배열 출력
        
        System.out.println("Arraylist 출력");
        for(int i=0; i < cars.size();i++) {
            System.out.println(cars.get(i));
        }

        cars.get(0); // 가져오기
        cars.set(0, "Opel"); // 변경하기
        System.out.println(cars); // 변경된 배열 출력
        
    }
    
    public static void ItemAdd(String str) {
        if(!cars.contains(str)) { // 중복 여부 검사
            cars.add(str); // 중복이 없으면 저장
        }
        if(cars.size()> Max) { // 특정 개수 이상이면
            cars.remove(0); // 가장 먼저 등록한 걸 지워라.
        }
    }
}



728x90

'안드로이드 > Java 문법' 카테고리의 다른 글

How to validate IP address with regular expression  (0) 2019.06.17
자바 클래스 개념 이해 예제  (0) 2019.05.27
Java BubbleSort  (0) 2019.05.13
java Singleton Design Pattern  (0) 2018.09.24
[Java] instanceof 연산자  (0) 2017.10.24
블로그 이미지

Link2Me

,

Visual Studio Code 는 거의 모든 언어를 지원한다.


Visual Studio Code에서 PHP 코딩에 유용한 Extension 을 설치해봤다.

설치한 extension 은 사용자 폴더 하위폴더에 .vscode 로 만들어져 있더라.

설치한 것이 마음에 안들면 이 폴더를 통째로 날리면 다시 설치할 수 있다. 개별로 지우는 것은 안해봤다.

이것 저것 Extension 을 설치해보니 사용하기에 좀 편해진 거 같다.

EditPlus 를 이용하여 날 코딩하던 걸 이걸로 변경해보면서 기능의 편리함을 체험해보려고 한다.

Local Web 연동처리는 Aptana Studio 도 같이 설치해서 활용하는 것이 좋을 거 같다.


Extension

 설 명

 PHP IntelliSense

 PHP를 위한 고급 자동완성 및 리팩터링을 지원한다.

 "PHP 실행파일이 설정되지 않았기때문에 유효성 검사를 할 수 없습니다."

 File > Preferences > Settings

 "php.validate.executablePath" : "C:/설치한 폴더/php.exe" 로 변경

 ※ php 버전은 7.X 버전이 설치된 폴더를 설정해준다.

 PHP 코드를 타이핑할때마다 문법을 체크해준다.

 PHP Formatter

 phpfmt - PHP formatter 를 설치한다.
 코드 정렬 단축키 : Shift + Alt + F (Windows), Shift + Option + F (MAC)
 HTML 과 혼용되어 있는 것은 정렬해주지 못하더라.

 Format HTML in PHP

 PHP 와 HTML 이 혼용된 파일에서 HTML 영역을 선택하여 마우스 우클릭하여

 코드를 깔끔하게 정렬할 수 있다.

 PHP Intelephense

 문서, 작업 영역, 기본 제공 생성자, 메서드 및 함수에 대한 자세한 서명 도움
 오류 허용 구문 분석기를 통해 열린 파일에 대한 여러 구문 분석 오류 진단

 Auto Close Tag

 HTML 닫기 태그를 자동으로 추가한다.

 Auto Rename Tag

 HTML 태그의 이름을 자동으로 바꾼다.

 ESLint

 자바스크립트 문법검사를 해준다.

 IntelliSense for CSS class names in HTML

 Bootstarp 라이브러리를 통해 개발할때 정말 유용한 플러그인

 작업 공간에 있는 정의를 기반으로 HTML Class 속성에 대한 CSS Class 이름을 자동 완성해 준다.

 jQuery Code Snippets

 

 Beautify

 




728x90
블로그 이미지

Link2Me

,

Visual Studio Code 를 설치해서 PHP Debuging 이 좀 더 편리한지 알아보는 중이다.


1. 한글 Pack 설치

   - 설치하면 메뉴가 한글로 나온다.

  

2. PHP Pack 설치

   https://code.visualstudio.com/docs/languages/php 에 기본 설치해야 할 PHP Extension 정보가 나온다.


3. APM(Apache + PHP + MySQL) 설치

   - 윈도우 기반에서 설치할 수 있는 툴은 autoset9, autoset10, xampp 가 있다.

   - 구글 검색하면 나온다.

   - 테스트를 해보니까 autoset9 은 제대로 지원을 못한다. autoset10 또는 xampp 를 설치하시라.


4. PHP 설치경로 설정

   - VS Code 프로그램에서 파일 - 기본설정 - 설정을 누른다.



php.validate.executablePath 를 추가하고 저장한다.


5. PHP 디버거 설정

    - https://marketplace.visualstudio.com/items?itemName=felixfbecker.php-debug 에서

    - DEBUG 를 설치한다.

    - 커서를 아래로 내려서 Installation 을 읽고 Download 를 누르면

      https://xdebug.org/download.php 에서 APM 설치한 PHP 버전에 맞는 버전을 다운로드 받는다.



    - 다운로드한 php_xdebug-2.7.2-7.2-vc15-x86_64.dll 파일을 PHP 파일이 설치된 하위 폴더 ext 에 옮긴다.


https://xdebug.org/wizard.php 를 브라우저에서 열고 phpinfo(); 내용을 CTRL + A를 눌러 복사한 다음 붙여넣기를 한다.

지원하지 않는다고 나온다.

      하지만 https://xdebug.org/docs/install#configure-php 에서 보면 오래된 PHP 버전도 지원한다고 나온다.


Autoset10 으로 설정하고 phpinfo() 내용을 CTRL + C로 복사하여 붙여넣기 했더니 아래와 같이 보여준다.


    - php.ini 파일을 열어 아래와같이 수정한다.

[XDebug]

zend_extension="C:/AutoSet10/Server/bin/ext/php_xdebug-2.7.2-7.2-vc15-x86_64.dll"
xdebug.remote_enable = 1
xdebug.remote_autostart = 1


    - 이제 APM(autoset10)을 재시작한다.


6. VS Code를 재시작하여 디버깅을 해본다.

   구글링을 해보니 PHP 코드 로직 테스트 등에는 결과를 알 수 있어 좋을 거 같다.


7. Web 서버와 연동 기능

   - PHP Server를 설치하니까 Web 브라우저로 내용을 보여주기는 한다.

   - Aptana Studio 와 다르게 Local 에 설치된 Web 서버와 직접 연결하여 보여주는 기능이 없는 것인지

     못찾은 것인지 모르겠다..






728x90
블로그 이미지

Link2Me

,

PHP 절차지형 방식으로 MySQL 을 연동한 코드를 PDO 방식으로 변환할 때 필요한 정보를 적어둔다.

PDO 는 CUBRID, MS SQL Server, Firebird/Interbase, IBM, Informix, MySQL, Oracle, ODBC and DB2, PostgreSQL, SQLite, 4D 등 12가지 DB를 지원한다.

 

PHP 절차지향
PDO
 mysql_fetch_assoc($result)  $stmt->fetch(PDO::FETCH_ASSOC)
 mysql_num_rows($result)  $stmt->rowCount()
 while ($row = mysql_fetch_assoc($result)) {}  foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {}

 

SELECT 변환 예제

 $sql="select count(*), access from members where userID='".$userID."'";
 $result=mysqli_query($db,$sql);
 if($row=mysqli_fetch_row($result)){
 $sql="select count(*), access from members where userID=?";
 $params = array($userID);
 $stmt = $this->db->prepare($sql);
 $stmt->execute($params);
 if($row = $stmt->fetch()){

 

Update 변환 예제

 $sql = "UPDATE rb_accessLog SET hit=hit+1 Where ipaddr='".$access_ip."' and LogID='".$userID."'";
 $result=mysqli_query($db,$sql);
 $sql = "UPDATE rb_accessLog SET hit=hit+1 Where ipaddr=? and LogID=?";
 try {
    $this->db->beginTransaction();
    $params = array($access_ip,$userID);
    $stmt = $this->db->prepare($sql);
    $stmt->execute($params);
    $this->db->commit();
 } catch (PDOException $pex) {
    $this->db->rollBack();
    echo "에러 : " . $pex -> getMessage();
 }

 

Insert 변환 예제

 $sql ="INSERT INTO bbs_imgpath (uid,relateduid,imgpath) values(NULL,";
 $sql.="'".$uid."', '".$v."')";
 mysqli_query($this->db,$sql);
 $key = "uid,relateduid,imgpath";
 $val = "NULL,$uid,$v";
 $this->getDbInsert('bbs_imgpath', $key, $val);

 

getDbInsert 함수는 아래와 같이 만들었다.

<?php
 function getDbInsert($table$key$val) {
        try {
            $params = explode(','$val); // 문자열을 분리하여 배열로 만듬
            $this->db->beginTransaction();
            $sql = "insert into " . $table . " (" . $key . ") values(" . $this->recur_quot(count($params)) . ")";
            $stmt = $this->db->prepare($sql);
            $status = $stmt->execute($params); // $params 는 배열 값
            if ($status) {
                $this->db->commit();
                return 1;
            } else {
                return 0;
            }
        } catch (PDOException $pex) {
            $this->db->rollBack();
            echo "에러 : " . $pex->getMessage();
        }
    }
 
    public function recur_quot($cnt) {
        $R = array();
        for ($i = 0$i < $cnt$i++) {
            array_push($R"?");
        }
        return implode(","$R); // 배열을 문자열로
    } 
 
?
 

 

Delete 변환 예제

 $sql = "DELETE FROM bbs_imgpath where imgpath='".$v."' and relateduid=".$uid;
 mysqli_query($this->db,$sql);
 
 $where = "imgpath=? and relateduid=?";
 $params = array($v,$uid);
 $this->getDbDelete('bbs_imgpath', $where, $params);

 

getDbDelete 함수는 아래와 같이 만들었다.

 
 
<?php
    public function getDbDelete($table$where$params) {
        if ($this->isDataExisted($table$where$params)) {
            try {
                $this->db->beginTransaction();
                $sql = "delete from " . $table . ($where ? ' where ' . $where : '');
                $stmt = $this->db->prepare($sql);
                $status = $stmt->execute($params);
                if ($status) {// action 실행여부에 대한 결과이지 실제 데이터 삭제와는 무관하네.
                    $this->db->commit();
                    return 1// 삭제 성공
                } else {
                    return 0// 삭제 실패
                }
            } catch (PDOException $pex) {
                $this->db->rollBack();
                echo "에러 : " . $pex->getMessage();
            }
        } else {
            return 0// 삭제할 데이터가 없음
        }
 
    }
 
    // 삭제할 데이터의 존재 유무 파악
    public function isDataExisted($table$where$params) {
        $sql = 'select * from ' . $table . ($where ? ' where ' . $where : '');
        $stmt = $this->db->prepare($sql);
        $stmt->execute($params);
        if ($row = $stmt->fetch()) {
            return $row;
        } else {
            return false;
        }
    }
 
?>
 

 

사용자 함수

편리하게 사용하기 위해 만든 함수는 아래와 같이 변경하면 된다.

다만, 검색조건을 입력시 SQL Injection 필터링 함수를 한번 거쳐서 where 조건문에서 해킹 방지를 해주는 것은 필수요소다.

    function getDbData($table,$where,$column) {
        global $db;
        $sql ='select '.$column.' from '.$table.($where?' where '. $where:'');
        //echo $sql;
        $result = mysqli_query($db,$sql);
        $row = mysqli_fetch_array($result);
        return $row;
    }
     // 검색조건에 일치하는 데이터 가져오기
    public function getDbData($table, $where, $column, $returntype = '') {
        $sql = 'select ' . $column . ' from ' . $table . ($where ? ' where ' . $where : '');
        $stmt = $this->db->prepare($sql);
        $stmt->execute();
        if ($returntype == 1) {
            return $stmt->fetch(PDO::FETCH_ASSOC);
        } else {
            return $stmt->fetch();
        }
    }
     // 검색조건에 일치하는 데이터 가져오기
    public function getDbDataAll($table, $where, $column) {
        $sql = 'select ' . $column . ' from ' . $table . ($where ? ' where ' . $this->getSqlFilter($where) : '');
        $stmt = $this->db->prepare($sql);
        $stmt->execute();
        return $stmt->fetchAll();
    }

 

 

관련으로 만든 Class 대부분은 아래와 같다.

 
<?php
class DBDataClass {
    protected $db// 변수를 선언한 클래스와 상속받은 클래스에서 참조할 수 있다.
 
    public function __construct() {
        $this->dbConnect();
        // construct 메소드는 객체가 생성(인스턴스화)될 때 자동으로 실행되는 특수한 메소드다.
    }
 
    private function dbConnect() {
        require_once 'dbinfo.php';
        try {
            // SQL PDO 객체 생성
            $this->db = new PDO(_DSN, _DBUSER, _DBPASS);
            $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $this->db->setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE);
        } catch(PDOException $ex) {
            die("오류 : " . $ex->getMessage());
        }
    }
 
    // 신규 자료 추가(ok)
    function getDbInsert($table$key$val) {
        try {
            $params = explode(','$val); // 문자열을 분리하여 배열로 만듬
            $this->db->beginTransaction();
            $sql = "insert into " . $table . " (" . $key . ") values(" . $this->recur_quot(count($params)) . ")";
            $stmt = $this->db->prepare($sql);
            $status = $stmt->execute($params); // $params 는 배열 값
            $this->db->commit();
            return 1;
        } catch (PDOException $pex) {
            $this->db->rollBack();
            echo "에러 : " . $pex->getMessage();
            return 0;
        }
    }
 
    public function recur_quot($cnt) {
        $R = array();
        for ($i = 0$i < $cnt$i++) {
            array_push($R"?");
        }
        return implode(","$R); // 배열을 문자열로
    }
 
    function getDbUpdate($table$set$params$where) {
        $sql = "update " . $table . " set " . $set . ($where ? ' where ' . $where : '');
        try {
            $this->db->beginTransaction();
            $stmt = $this->db->prepare($sql);
            $status = $stmt->execute($params);
            $this->db->commit();
            return 1;
        } catch (PDOException $pex) {
            $this->db->rollBack();
            echo "에러 : " . $pex->getMessage();
            return 0;
        }
    }
 
    public function getDbDelete($table$where$params) {
        if ($this->isDataExisted($table$where$params)) {
            try {
                $this->db->beginTransaction();
                $sql = "delete from " . $table . ($where ? ' where ' . $where : '');
                $stmt = $this->db->prepare($sql);
                $status = $stmt->execute($params);
 
                $this->db->commit();
 
                return 1// 삭제 성공
            } catch (PDOException $pex) {
                $this->db->rollBack();
                echo "에러 : " . $pex->getMessage();
            }
        } else {
            return 0// 삭제할 데이터가 없음
        }
 
    }
 
    // 삭제할 데이터의 존재 유무 파악
    public function isDataExisted($table$where$params) {
        $sql = 'select * from ' . $table . ($where ? ' where ' . $where : '');
        $stmt = $this->db->prepare($sql);
        $stmt->execute($params);
        if ($row = $stmt->fetch()) {
            return $row;
        } else {
            return false;
        }
    }
 
 
    // 검색조건에 일치하는 데이터 가져오기
    public function getDbData($table$where$column$returntype = '') {
        $sql = 'select ' . $column . ' from ' . $table . ($where ? ' where ' . $where : '');
        $stmt = $this->db->prepare($sql);
        $stmt->execute();
        if ($returntype == 1) {
            return $stmt->fetch(PDO::FETCH_ASSOC);
        } else {
            return $stmt->fetch();
        }
    }
 
    // 검색조건에 일치하는 데이터 가져오기
    public function getDbDataAll($table$where$column) {
        $sql = 'select ' . $column . ' from ' . $table . ($where ? ' where ' . $where : '');
        $stmt = $this->db->prepare($sql);
        $stmt->execute();
        return $stmt->fetchAll();
    }
 
    // DB Query result 함수
    function getDbresult($table,$where,$column) {
        $sql = 'select ' . $column . ' from ' . $table . ($where ? ' where ' .$where : '');
        $stmt = $this->db->prepare($sql);
        $stmt->execute();
        return $stmt->fetchAll();
    }
 
    // DB 레코드 총 수(ok)
    public function getDbRows($table$where) {
        $sql = 'select count(*) from ' . $table . ($where ? ' where ' . $where : '');
        $stmt = $this->db->prepare($sql);
        $stmt->execute();
        if ($row = $stmt->fetch()) {
            return $row[0];
        } else {
            return false;
        }
    }
}
?> 

 

 

 

 

728x90
블로그 이미지

Link2Me

,

그대가 엉터리 개발자라는 신호들


크리스 웨넘은 '그대가 엉터리 개발자라는 신호들(Signs that you're a bad programmer)'이라는 제목의 글에서 여섯 가지 신호를 이야기했다. 스스로 개발자인 저자 자신의 경험을 토대로 쓴 글이라는데, 내가 겪은 경험과도 정확하게 일치한다.

이러한 신호를 이야기하는 것은 우리 주변에서 누가 엉터리 개발자인지 골라내자는 것이 아니다. 오히려 좋은 프로그래머가 되기 위해서 누구나 거쳐 가는 단계라고 보는 편이 정확할 것이다. 우리는 모두 한 때는 (어쩌면 지금도) 엉터리 개발자였다.

첫 번째는 코드를 머리로 돌릴 수 있는 능력의 부재다. 엄청난 분량의 코드를 생각만으로 돌릴 수 있는 사람도 있고, 아주 짧은 코드만 돌릴 수 있는 사람도 있는데, 어쨌든 코드를 머리로 돌리는 능력은 개발자에게 기본이다. 이것은 바둑을 두는 프로기사에게 바둑판 위에 놓이지 않은 미래의 수를 읽어내는 능력이 필요한 것과 마찬가지다.

90년대에 빌 게이츠는 마이크로소프트가 수퍼스마트(Supersmart) 프로그래머만을 고용하기를 원한다고 말한 적이 있다. 그 말을 듣고 한 기자가 게이츠에게 수퍼스마트가 어떤 사람이냐고 물었다. 그러자 그는 자기가 작성한 코드의 내용을 6개월이 지난 시점에서도 컴퓨터 없이 (마치 눈앞에서 코드를 보고 있는 것처럼) 설명할 수 있는 사람이라고 대답했다.

그 정도까지는 아니더라도 회사에서 코드리뷰를 하다보면 자기가 아침에 작성한 코드의 내용을 설명하지 못하는 프로그래머가 있음을 알게 된다. 이런 개발자가 다른 사람이 작성한 코드를 읽을 수 없음은 물론이다. 이러한 능력의 부재는 어떤 면에서 노력으로 해결할 수 있는 것이 아니다. 이것은 개발자에게 필요한 최소한의 재능을 갖추지 못한 사례에 해당하므로 하루라도 빨리 다른 일을 시작하는 것이 더 나을 가능성이 높다.


두 번째는 자기가 사용하는 언어의 프로그래밍 모델을 제대로 이해하지 못하는 것이다. 이런 현상은 오랜 개발 경험을 쌓은 개발자 중에서도 어렵지 않게 발견된다. 객체지향 패러다임이 탑재된 C++가 처음 등장했을 때 많은 개발자들이 C++를 이용해서 C 코드를 작성했다. 마찬가지로 오랫동안 자바 언어를 사용해온 개발자가 객체지향 패러다임을 전혀 이해하지 못하고 있는 경우가 생각보다 많다. 함수 패러다임은 말할 필요도 없다.

오래 전에 자바 개발자를 고용하기 위한 기술인터뷰를 수행했을 때의 일이다. 내가 멀티쓰레딩과 관련한 질문을 하자 쓰레드 같은 것은 EJB 컨테이너가 알아서 관리해 주기 때문에 자기는 그런 것까지 알 필요가 없다고 대답한 사람이 있었다. 이런 사람은 이력서에 개발 경력이 5년이든 10년이든 상관이 없다. 끊임없는 학습과 자유분방한 창의력을 요구하는 프로그래밍이라는 행위를 기계적인 코딩, 단순히 반복되는 잡무, 혹은 하기 싫지만 어쩔 수 없이 하는 회사일로 대하는 사람은 앞으로 20년 동안 경험을 쌓아도 기술적으로 변화가 있을 리 없기 때문이다.


세 번째는 학습능력의 부재다. 요즘처럼 정보가 홍수처럼 쏟아져 나오는 시대에 그 모든 내용을 미리 다 알고 있는 사람이 어디에 있겠는가. 수많은 오픈소스 라이브러리, 새로운 기술, 패턴, 사례를 모두 꿰차고 있는 사람은 어디에도 없다. 많은 것을 알고 있는 것처럼 보이는 사람은 그만큼 열의를 갖고 학습을 하기 때문이다. 인터넷 검색을 하고, 코세라 강의를 듣고, 유투브 채널에 가입하고, 세미나에 참여하고, 책을 구입해서 읽으며 쉬지 않고 공부를 한다. 여기에서 중요한 것은 공부를 통해서 습득한 지식의 분량이 아니다. 중요한 것은 공부를 하는 방법, 즉 메타 지식에 해당하는 학습능력 자체다.

좋은 개발자는 낯선 기술이 등장하면 호기심을 품고 즐거운 심정이 되어 이곳저곳 건드려보지만, 엉터리 개발자는 입을 씰룩거리며 낯을 가린다. 이제 겨우 하나를 익혔더니 또 공부를 해야 하냐며 푸념을 한다. 낯선 대상을 두려워하는 것이 아니라 사실은 학습이라는 행위 자체를 두려워하는 것이다. 프로그래밍이라는 행위가 끝없는 학습으로 이루어져 있음을 이해하지 못하기 때문이다.


웨넘이 네 번째로 거론한 내용은 포인터(pointer)에 대한 이해부족인데, C나 C++를 사용하지 않으면 요즘에는 포인터를 직접 다룰 일이 없으므로 넘어가자. 웨넘의 이야기를 최근의 추세에 맞게 재구성하자면 타입시스템(type system)에 대한 이해부족이라고 이야기해도 좋을 것이다.


다섯 번째는 재귀(recursion) 알고리즘을 이해하는 능력이 없는 것이다. 이것은 맨 처음에 보았던 머리로 코드를 돌리는 능력과 밀접한 관련이 있다. 재귀를 이용해서 정수의 팩토리얼 값을 구하는 정도는 대부분의 개발자가 어렵지 않게 이해한다. 피보나치수열까지도 괜찮다. 트리구조의 노드를 순차적으로 방문하는 알고리즘도 기본적인 것까지는 무리 없이 이해한다.

하지만 하노이의 탑과 같은 알고리즘이 등장하면 숨이 막히기 시작한다. 꼬리재귀(tail recursion)가 왜 효율적인지, 일반적인 재귀 알고리즘을 어떻게 꼬리재귀 알고리즘으로 변환할 수 있는지 등을 이야기하다보면 한계를 느낀다. 이런 사람들은 개발자가 되어서 실전에 배치되어도 운영체제의 루프백(loopback) 주소라는 개념을 이해하지 못해서 애를 먹는다. 재귀라는 알고리즘의 작동방식이 머릿속에서 그려지지 않는 탓이다.


마지막은 코드에 대한 불신이다. 엉터리 개발자들은 정작 믿지 않아야 하는 코드를 신뢰하고, 믿어도 좋은 코드를 불신한다. 유닛테스트 코드를 작성하라고 시키면 실제로 검사되어야 하는 코드를 테스트하는 것이 아니라, 언어자체의 문법이나 라이브러리 코드의 API를 확인하는데 시간을 보낸다. 버그 투성이인 자신의 코드에 애착을 품고, 철저하게 검증된 라이브러리 코드를 의심한다.

전부는 아니더라도 이러한 여섯 가지 중에서 한 두 항목에서 뜨끔한 기분을 느낀 사람이 있을 것이다. 다시 한 번 말하지만 이 글의 목적은 엉터리 개발자를 추궁하자는 것이 아니다. 좋은 프로그래머가 되기 위해서 우리가 밟아온 과정, 혹은 앞으로 밟아야 하는 과정을 환기하여 다 같이 행복한 프로그래밍을 하자는 것이 목적이다. 다음에 기회가 있으면 “그대가 훌륭한 개발자라는 신호들”에 대해서도 이야기하도록 하겠다.


출처(2014/10/24 기사) : http://www.zdnet.co.kr/view/?no=20141024082051


2019.5월 기준

난 개발자라고 할 수 있는가? 라고 한다면 난 개발자라고 할 수준이 못된다.

지금도 난 서비스기획 업무를 더 잘하고 서비스 검증을 더 잘 한다.

서비스 기획을 했기 때문에 개발 해보면서 이런 기능이 필요하겠구나 하는 걸 찾아서 구현해본다.

요청자가 요구하지 않았더라도 필요한 기능을 구현해보려는 마음만 있는 초보 개발 수준이다.

개발을 배우면서 좀 더 이해한 것은 개발자와의 커뮤니케이션은 더 잘 할 수 있겠다 싶은 거~~


728x90
블로그 이미지

Link2Me

,

버블 정렬은 시간복잡도가 n의 제곱으로 늘어나기 때문에 시간이 굉장히 오래 걸린다.
정렬에 걸리는 시간은 오래 걸리지만 알고리즘이 단순하기 때문에 자주 사용된다.




class BubbleSort {
    public static void main(String[] args) {
        int[] data = {25,3,21,64,65,78,9,5,76,34,8,32,76};
        // bubble sort
        int n = data.length;
        for(int i = n-1; i>0; i--){
            for(int j=0; j < i; j++){
                if(data[j] > data[j+1]){ // 첫번째 수가 더 크면 데이터를 서로 교체하라.
                    int tmp = data[j]; // 첫번째 수를 임시 저장
                    data[j] = data[j+1];
                    data[j+1] = tmp;
                }
            }
        }

        System.out.print("\n\n====== Sorted Data =========\n");
        for(int k=0; k<n;k++)
            System.out.print(data[k] + ", ");

    }
}


문자열 버블 정렬

static void bubbleSort(){
    for(int i = n-1; i>0; i++){
        for(int j=0; j<i; j++){
            if(name[j].compareTo(name[j+1]) > 0){
                Strimg tmp = name[j];
                name[j] = name[j+1];
                name[j+1] = tmp;
            }
        }
    }
}


728x90

'안드로이드 > Java 문법' 카테고리의 다른 글

자바 클래스 개념 이해 예제  (0) 2019.05.27
자바 Arraylist  (0) 2019.05.26
java Singleton Design Pattern  (0) 2018.09.24
[Java] instanceof 연산자  (0) 2017.10.24
Java static 변수 이해하기  (1) 2017.10.20
블로그 이미지

Link2Me

,

delay를 주고 어떤 동작을 하고 싶다면 Handler클래스의 postDelayed 메소드를 이용한다.
Handler delayHandler = new Handler();
delayHandler.postDelayed(new Runnable() {
    @Override
    public void run() {
        //여기에 딜레이 후 시작할 작업들을 입력
    }
}, 3000); // 3초 지연을 준 후 시작



일정시간 지연후 처리 예제


final Handler delayHandler = new Handler();
delayHandler.postDelayed(new Runnable() {
    @Override
    public void run() {
        String msg =  macro_val;
        msg = msg + "\r";
        mSerialConnector.sendCommand(msg);
    }
}, 3000);


연속적인 시간 지연을 주는 코드를 테스트 해보고 적어둔다.

import android.content.Context;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;

import java.text.SimpleDateFormat;

public class MainActivity extends AppCompatActivity {
    Context mContext;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // System클래스의 currentTimeMillis()메서드를 활용
        SimpleDateFormat timeformat = new SimpleDateFormat( "HH시 mm분 ss초");
        String time_display = timeformat.format (System.currentTimeMillis());
        System.out.println("start : "+time_display);

        final Handler handler = new Handler();
        for(int i=0; i < 20; i++){
            final int finalI = i+1;
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    SimpleDateFormat timeformat = new SimpleDateFormat( "HH시 mm분 ss초");
                    String time_display = timeformat.format (System.currentTimeMillis());
                    if(finalI <= 10){
                        System.out.println(time_display);
                    } else if(finalI >= 17){
                        System.out.println("반복 횟수 : " + finalI);
                    }

                }
            }, 1000*(i+1));
        }

    }
}


728x90
블로그 이미지

Link2Me

,

It depends on what is ENTER for your device.
In Windows it is CRLF (13 and then 10), Linux is LF (only 10.)
It's just a matter of what your device expects, because it can't see ENTER, just "byte 10, byte 13.


시리얼 통신에서 장비 콘솔 접속 제어 처리를 할 때 알아두어야 할 값이라 적어둔다.

    public final static char CR  = (char) 0x0D; // \r
    public final static char LF  = (char) 0x0A; // \n
    public final static char SPaceBar  = (char) 0x20;


윈도우상에서 콘솔로 접속하여 처리하던 걸 안드로이드에서 하려고 한다면 윈도우에서 사용하는 키를 알아야 동작한다는 점만 알면 다음 고려사항은 쉽게 풀린다.


Converting Control Codes to ASCII, Decimal and Hexadecimal
The ^ symbol stands for Ctrl

Ctrl    ASCII     Dec     Hex    Meaning
^@     NUL    000     00     Null character
^A     SOH    001     01     Start of Header
^B     STX    002     02     Start of Text
^C     ETX    003     03     End of Text
^D    EOT    004     04     End of Transmission
^E     ENQ     005     05     Enquiry
^F     ACK     006     06     Acknowledge
^G    BEL    007     07     Bell
^H     BS     008     08     Backspace
^I     HT     009     09    Horizontal tab
^J    LF     010     0A     Line feed
^K     VT     011     0B     Vertical tab
^L     FF    012     0C     Form feed
^M     CR     013     0D     Carriage return
^N     SO     014     0E     Shift out
^O     SI     015     0F     Shift in
^P     DLE     016     10     Data link escape
^Q     DCL     017     11     Xon (transmit on)
^R     DC2     018     12     Device control 2
^S     DC3     019     13    Xoff (transmit off)
^T     DC4     020     14     Device control 4
^U     NAK     021     15     Negative acknowledge
^V    SYN     022     16     Synchronous idle
^W    ETB     023     17     End of transmission
^X    CAN     024     18     Cancel
^Y    EM     025     19     End of medium
^Z    SUB     026     1A     Substitute
^[    ESC     027     1B     Escape
^\    FS     028     1C     File separator
^]    GS     029     1D     Group separator
^^    RS     030     1E    Record separator
^_    US     031     1F     Unit separator
        SP     032     20     Space

728x90
블로그 이미지

Link2Me

,

baudRate, databits, stopbit,parity 등을 선택하는 코드를 구현하고 간단한 사항을 적어둔다.

SharedPreferences 에 저장된 값을 읽어서 세팅하는 화면에 표시하고, 저장된 값이 없으면 default 세팅값을 보여준다.

select한 값을 SharedPreferences에 저장하는 코드까지 필요한 기능은 모두 구현했다.


pref = getSharedPreferences("pref", Activity.MODE_PRIVATE);
String BaudRate = pref.getString("BaudRate", ""); // 저장된 값 읽어오기

baudSpinner = (Spinner) findViewById(R.id.baudRateValue);
ArrayAdapter<CharSequence> baudAdapter = ArrayAdapter.createFromResource(context, R.array.baud_rate,
        R.layout.my_spinner_textview);
baudAdapter.setDropDownViewResource(R.layout.my_spinner_textview);
baudSpinner.setAdapter(baudAdapter);
if (BaudRate != null) { // 저장된 값이 있으면
    int spinnerPosition = baudAdapter.getPosition(BaudRate);
    baudSpinner.setSelection(spinnerPosition);
} else {
    baudSpinner.setSelection(0); // 없으면 default 실행
}
baudSpinner.setOnItemSelectedListener(new MyBaudRateSelectedListener());

public class MyBaudRateSelectedListener implements AdapterView.OnItemSelectedListener {
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        baudRate = parent.getItemAtPosition(position).toString(); // 선택한 값을 저장하기 위해
    }

    public void onNothingSelected(AdapterView<?> parent){

    }
}

case R.id.btn_save: // 저장
    pref = getSharedPreferences("pref", Activity.MODE_PRIVATE);
    SharedPreferences.Editor editor = pref.edit();
    editor.putString("BaudRate", baudRate);
    editor.commit();

    Intent intent = new Intent(Setting.this, MainActivity.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
    startActivity(intent);
    break;



참고 : https://www.ftdichip.com/Android.htm 사이트에서 Java D2XX Update including FT4222H support 에 연결된 파일을 다운로드하여 java 파일과 resource 파일을 참조하면 구현하는데 도움된다.

728x90
블로그 이미지

Link2Me

,

CentOS 6 에서 Sendmail 발송하는 걸 처리하기 위해서 구글링하고 테스트한 것을 적어둔다.


#### CentOS Sendmail ####
# 설치 확인
cd /etc/mail/
# 디렉토리 경로가 없으면 sendmail은 설치되지 않는 것이다.
rpm -qa sendmail*

# sendmail 설치
yum install sendmail sendmail-cf

# sendmail 동작 여부 확인
service sendmail status

# 서비스 시작
service sendmail start

#sendmail.mc 수정
ll /etc/mail | grep sendmail
cp /etc/mail/sendmail.mc /etc/mail/sendmail.mc.original
cp /etc/mail/sendmail.cf /etc/mail/sendmail.cf.original
vi /etc/mail/sendmail.mc
# 에디터 상에서 53을 누르고 대문자 G를 누르면 아래와 같이 이동된다.
# 주석인 앞의 dnl 을 제거한다.
TRUST_AUTH_MECH(`EXTERNAL DIGEST-MD5 CRAM-MD5 LOGIN PLAIN’)dnl
define(`confAUTH_MECHANISMS’, `EXTERNAL GSSAPI DIGEST-MD5 CRAM-MD5 LOGIN PLAIN’)dnl

# 에디터 상에서 116을 누르고 대문자 G를 누르면 아래와 같이 116 라인으로 이동된다.
# 127.0.0.1 로 되어 있으면 내부에서만 사용한다는 의미이다.
# 여기서 127.0.0.1 을 0.0.0.0 으로 수정한다.
DAEMON_OPTIONS(`Port=smtp,Addr=0.0.0.0, Name=MTA’)dnl
# 저장하고 나온다.

# 원본과 수정본의 내용을 비교한다.
diff /etc/mail/sendmail.mc.original /etc/mail/sendmail.mc

# 메크로 처리 언어인 m4를 이용하여 sendmail.cf을 재생성한다.
m4 /etc/mail/sendmail.mc > /etc/mail/sendmail.cf
vi /etc/mail/sendmail.cf
# 95 G 를 하여 95 행으로 이동한다.
#Dj$w.Foo.COM
DjXXXXX.co.kr 또는 Dj$ naver.com <== 도메인을 직접 추가해준 것으로 발송 성공은 했으나 naver.com 으로 설정은 안해봐서..
* /etc/access 파일에 sendmail.cf 파일 95줄에 적은 도메인의 릴레이를 허용되어야 하며,
* /etc/mail/local-host-names 파일에도 이곳에 적은 도메인을 입력해 놓아야 한다.
# 보안을 위해 sendmail 버전 정보가 표시되지 않게 수정한다.
# SMTP initial login message (old $e macro)
O SmtpGreetingMessage=$j Sendmail $v/$Z; $b
O SmtpGreetingMessage=$j Sendmail; $b  로 수정한다.

* $j : 도메인 이름, $v : sendmail 버전, $Z : sendmail 버전, $b : 접속시간

# 그냥 메일 수신자에 해당하는 도메인을 한줄에 추가하면 된다.
# 주의할 것은 local-host-names 파일을 수정한 후에는 반드시 sendmail을 restart 해야지 수정 사항이 적용된다.
vi /etc/mail/local-host-names
abc.com


# sendmail 을 재시작한다.
service sendmail restart


# 포트 확인
netstat -anp | grep sendmail | grep LISTEN

# 25번 포트가 올라왔는지 여부 체크
netstat -nlp | grep 25

# 리부팅시 서비스 자동 실행 설정
chkconfig –list sendmail

# 방화벽에 25번 포트 등록 여부 확인
iptables -nL |grep 25

# 방화벽에 25번 포트 추가



728x90
블로그 이미지

Link2Me

,