Ubuntu 에서 Apache 2.4 와 Tomcat 8 (2대) 연동하기

리눅스/APACHE|2019. 6. 12. 13:09
반응형

Apache 서버 : 49.247.214.95

Tomcat 서버 : 49.247.213.105

 

1. Apache 설치 및 설정

(Apache 서버에서)

[root@sysdocu ~]# apt-get -y update

[root@sysdocu ~]# apt-get -y install apache2

[root@sysdocu ~]# apt-get -y install libapache2-mod-jk

[root@sysdocu ~]# vi /etc/apache2/workers.properties

workers.tomcat_home=/usr/share/tomcat8    // Apache 서버에 이런 주소가 없어도 상관 없음
workers.java_home=/usr/lib/jvm/java-8-openjdk-amd64
# Define 1 real worker ajp13
worker.list=tomcat1
# Set properties for tomcat1 (ajp13)
worker.tomcat1.port = 8009
worker.tomcat1.host = 192.168.10.2   // Apache 와 Tomcat 을 하나의 서버로 운영한다면 'localhost' 로 변경
worker.tomcat1.type = ajp13
worker.tomcat1.lbfactor = 20

 

Tomcat 서버가 두 대라면, 아래와 같이 셋팅합니다.

worker.list= tomcat1, tomcat2    // 이름은 임의로 설정
 
worker.tomcat1.type=ajp13
worker.tomcat1.host=톰캣서버 IP
worker.tomcat1.port=8009
worker.tomcat1.lbfactor=1
 
worker.tomcat2.type=ajp13
worker.tomcat2.host=톰캣서버 IP
worker.tomcat2.port=8009
worker.tomcat2.lbfactor=2

 

[root@sysdocu ~]# vi /etc/apache2/mods-available/jk.conf

...(생략)...
JkWorkersFile /etc/apache2/workers.properties
...(생략)...

 

[root@sysdocu ~]# vi /etc/apache2/sites-enabled/000-default.conf

...(생략)...
DocumentRoot /var/www/html
JkMount /*.jsp tomcat1    // jsp 확장자는 tomcat1 서버에서 구동 되도록 설정을 추가 합니다.

...(생략)...

 

[root@sysdocu ~]# /etc/init.d/apache2 restart

 

2. Tomcat 설치 및 설정

(Tomcat 서버에서)

[root@sysdocu ~]# apt-get -y update

[root@sysdocu ~]# apt-get -y install tomcat8

[root@sysdocu ~]# vi /etc/tomcat8/server.xml

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />    // 주석 해제

 

[root@sysdocu ~]# /etc/init.d/tomcat8 restart

 

* Apache 서버에서 접속할 수 있게 iptables 방화벽에서 8009, 8080 포트를 오픈합니다.

 

3. 테스트

(Tomcat 서버에서)

[root@sysdocu ~]# vi /var/lib/tomcat8/webapps/ROOT/test.jsp

<%
String str = request.getParameter("name");
if(str == null)
{ str = "JSP"; }
%>
Hello, <%= str %>!!!

 

(PC 웹브라우저에서)

웹브라우저에서 아래와 같이 접속 테스트를 합니다.

 

http://192.168.10.2                      // 기본 아파치 index.html 페이지가 뜹니다.

http://192.168.10.2/test.jsp    // 톰캣 서버에서 생성한 test.jsp 페이지가 뜹니다.

 

반응형

댓글()

naverMap 을 전역 변수로 활용하기

반응형

네이버 맵을 사용하려고 보면

아래와 같이 public void onCreate(Bundle savedInstanceState) 영역 바깥쪽에 아래 코드를 넣어야 하고,

onMapReady 안에서만 naverMap 을 사용할 수 있었다.

이것은 액티비티가 열릴때 자동 실행되는 부분으로 모든 효과나 설정을 onMapReady 안에서만 처리가 가능했다.

사용자가 값을 변경해서 요청할 경우에는 사용하지 못하게... ㅜ.ㅜ

 

    @UiThread

    @Override

    public void onMapReady(@NonNull NaverMap naverMap) {

          naverMap.setMapType(NaverMap.MapType.Basic); // 지도 타입

          naverMap.setLayerGroupEnabled(NaverMap.LAYER_GROUP_TRANSIT, true); // 오버레이되는 정보 (대중교통 - 버스, 지하철)

        // 지정된 좌표로 카메라 이동

        CameraUpdate cameraUpdate = CameraUpdate.scrollTo(new LatLng(37.4685195, 126.8844555))

                                    .animate(CameraAnimation.Easing, 2000);

          naverMap.moveCamera(cameraUpdate);

    }

 

그래나 해결책을 찾았다. naverMap 을 전역 변수화 하면 다른곳에서도 사용이 가능하다.^^

 

public class MapActivity extends FragmentActivity implements OnMapReadyCallback {

    // 네이버맵 전역 변수
    private NaverMap NMap;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

 

          ... (생략) ...

          CameraUpdate cameraUpdate = CameraUpdate.scrollTo(new LatLng(37.5670135, 126.9783740))

                                                                              .animate(CameraAnimation.Easing, 2000);
          NMap.moveCamera(cameraUpdate); // 설정한 좌표로 카메라 이동 // onMapReady 밖에서도 사용 가능 ^^

          ... (생략) ...

    }

 

 

    // 네이버맵 초기 설정
    @UiThread
    @Override
    public void onMapReady(@NonNull NaverMap naverMap) {

        NMap = naverMap;

          NMap.setMapType(NaverMap.MapType.Basic); // 지도 타입
          NMap.setLayerGroupEnabled(NaverMap.LAYER_GROUP_TRANSIT, true); // 오버레이되는 정보 (대중교통 - 버스, 지하철)

    }

 

[참고] https://nittaku.tistory.com/69

            https://developers.google.com/maps/documentation/android-sdk/infowindows?hl=ko

반응형

댓글()

안드로이드 개발 Android GPS 정보 알아오기

반응형

안드로이드에서 GPS 정보를 가져온 후 자기 위치를 MAP 에 표시하거나 다른 사람에게 위치 정보를 알릴 수도 있습니다. 앱에서 GPS 정보는 아주 다양하게 쓰이기 때문에 별도의 클래스를 만들어서 사용하는 것이 좋겠죠. 스마트폰에 GPS 설정이 되어 있지 않을 때 팝업창을 띄워서 설정창으로 이동할 수 있는 소스도 추가가 되어 있습니다. 그리고 최근에 수정한 내용 중 API 23 버전부터 퍼미션을 추가해야 되는 부분도 참고 하시기 바랍니다.   

 

 

 먼저 AndroidManifest.xml  GPS 정보를 가져올 수 있도록 환경을 셋팅해야 합니다. 

<uses-permission android:name="android.permission.INTERNET" />

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

 

 GPS 정보를 알아오는 클래스에 대해서 알아봅니다. 클래스명은 GpsInfo.java 입니다. 추상클래스 Service 와 위치정보를 받아오기 위한 Listener 인터페이스 클래스 LocationListener 상속합니다. 그리고 GPS나 네트워크 사용유무, 얼마에 한번씩 데이터를 업데이트 할 것인지에 대한 변수들을 만듭니다. 실질적으로 위치정보를 알아오는 클래스는 LocationManager 입니다. 이것도 변수지정해 놓습니다. 

private final Context mContext;

  

// 현재 GPS 사용유무

boolean isGPSEnabled = false;

 

// 네트워크 사용유무

boolean isNetworkEnabled = false;

  

// GPS 상태값

boolean isGetLocation = false;

  

Location location;

double lat; // 위도

double lon; // 경도

  

// 최소 GPS 정보 업데이트 거리 10미터

private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10;

  

// 최소 GPS 정보 업데이트 시간 밀리세컨이므로 1분

private static final long MIN_TIME_BW_UPDATES = 1000 * 60 * 1;

  

protected LocationManager locationManager;

 

 다음은 GPS 위치값을 가져오기 위한 함수입니다. LocationManager 을 사용하였으며 requestLocationUpdates() 함수로 현재 정보를 업데이트 하고 getLastKnownLocation()

함수로 위치값을 가져옵니다. 

this.isGetLocation = true;

// 네트워크 정보로 부터 위치값 가져오기

if (isNetworkEnabled) {

    locationManager.requestLocationUpdates(

            LocationManager.NETWORK_PROVIDER,

            MIN_TIME_BW_UPDATES,

            MIN_DISTANCE_CHANGE_FOR_UPDATES, this);

    

    if (locationManager != null) {

        location = locationManager

                .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);

        if (location != null) {

            // 위도 경도 저장

            lat = location.getLatitude();

            lon = location.getLongitude();

        }

    }

}

 

if (isGPSEnabled) {

    if (location == null) {

        locationManager.requestLocationUpdates(

                LocationManager.GPS_PROVIDER,

                MIN_TIME_BW_UPDATES,

                MIN_DISTANCE_CHANGE_FOR_UPDATES, this);

        if (locationManager != null) {

            location = locationManager

                    .getLastKnownLocation(LocationManager.GPS_PROVIDER);

            if (location != null) {

                lat = location.getLatitude();

                lon = location.getLongitude();

            }

        }

    }

}

 

 위 함수를 실행전에 GPS 상태정보와 네트워크 정보를 가져와 제대로 환경이 되어있지 않다면 정보를 가져오는 부분을 스킵하겠죠. 

// GPS 정보 가져오기

isGPSEnabled = locationManager.isProviderEnabled(

                           LocationManager.GPS_PROVIDER);

  

// 현재 네트워크 상태 값 알아오기

isNetworkEnabled = locationManager.isProviderEnabled(

                               LocationManager.NETWORK_PROVIDER);

 

 이렇게 환경정보를 확인했는데 제대로 되어있지 않다면 GPS 정보가 제대로 설정 되어있는지 확인을 위한 alert 창을 띄우게 되고, 설정창으로 바로 가서 다시 GPS 를 사용할수 있도록 셋팅페이지로 가게 하는 기능입니다.

 

 

public void showSettingsAlert(){

    AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);

 

    alertDialog.setTitle("GPS 사용유무셋팅");

    alertDialog.setMessage("GPS 셋팅이 되지 않았을수도 있습니다.

            \n 설정창으로 가시겠습니까?");             

        // OK 를 누르게 되면 설정창으로 이동합니다.

    alertDialog.setPositiveButton("Settings", new DialogInterface.OnClickListener() {

        public void onClick(DialogInterface dialog,int which) {

            Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);

            mContext.startActivity(intent);

        }

    });

    // Cancle 하면 종료 합니다.

    alertDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {

        public void onClick(DialogInterface dialog, int which) {

        dialog.cancel();

        }

    });

 

    alertDialog.show();

}

 

 안드로이드가 업그레이드 되면서 보안을 좀더 강화했는데 AndroidManifest.xml 에만 퍼미션을 넣어서는 안됩니다. 소스에서 사용자에게 퍼미션을 요청하는 로직을 넣어야 합니다. 그렇지 않으면 다음과 같은 에러가 발생합니다. 

 

 일단 GpsInfo.class 에 퍼미션 체크 로직을 넣어야 에러가 사라집니다. 

if ( Build.VERSION.SDK_INT >= 23 &&

        ContextCompat.checkSelfPermission(

                mContext, android.Manifest.permission.ACCESS_FINE_LOCATION )

                != PackageManager.PERMISSION_GRANTED &&

        ContextCompat.checkSelfPermission(

                mContext, android.Manifest.permission.ACCESS_COARSE_LOCATION)

                != PackageManager.PERMISSION_GRANTED) {

 

    return null;

}

 

 아래는 GPS 정보를 가져오기 위한 GpsInfo.java  전체 소스입니다. 

import android.annotation.TargetApi;

import android.app.AlertDialog;

import android.app.Service;

import android.content.Context;

import android.content.DialogInterface;

import android.content.Intent;

import android.content.pm.PackageManager;

import android.location.Location;

import android.location.LocationListener;

import android.location.LocationManager;

import android.os.Build;

import android.os.Bundle;

import android.os.IBinder;

import android.provider.Settings;

import android.support.v4.content.ContextCompat;

 

public class GpsInfo extends Service implements LocationListener {

 

    private final Context mContext;

 

    // 현재 GPS 사용유무

    boolean isGPSEnabled = false;

 

    // 네트워크 사용유무

    boolean isNetworkEnabled = false;

 

    // GPS 상태값

    boolean isGetLocation = false;

 

    Location location;

    double lat; // 위도

    double lon; // 경도

 

    // 최소 GPS 정보 업데이트 거리 10미터

    private static final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10;

 

    // 최소 GPS 정보 업데이트 시간 밀리세컨이므로 1분

    private static final long MIN_TIME_BW_UPDATES = 1000 * 60 * 1;

 

    protected LocationManager locationManager;

 

    public GpsInfo(Context context) {

        this.mContext = context;

        getLocation();

    }

 

    @TargetApi(23)

    public Location getLocation() {

        if ( Build.VERSION.SDK_INT >= 23 &&

                ContextCompat.checkSelfPermission(

                        mContext, android.Manifest.permission.ACCESS_FINE_LOCATION )

                        != PackageManager.PERMISSION_GRANTED &&

                ContextCompat.checkSelfPermission(

                        mContext, android.Manifest.permission.ACCESS_COARSE_LOCATION)

                        != PackageManager.PERMISSION_GRANTED) {

 

            return null;

        }

 

        try {

            locationManager = (LocationManager) mContext

                    .getSystemService(LOCATION_SERVICE);

 

            // GPS 정보 가져오기

            isGPSEnabled = locationManager

                    .isProviderEnabled(LocationManager.GPS_PROVIDER);

 

            // 현재 네트워크 상태 값 알아오기

            isNetworkEnabled = locationManager

                    .isProviderEnabled(LocationManager.NETWORK_PROVIDER);

 

            if (!isGPSEnabled && !isNetworkEnabled) {

                // GPS 와 네트워크사용이 가능하지 않을때 소스 구현

            } else {

                this.isGetLocation = true;

                // 네트워크 정보로 부터 위치값 가져오기

                if (isNetworkEnabled) {

                    locationManager.requestLocationUpdates(

                            LocationManager.NETWORK_PROVIDER,

                            MIN_TIME_BW_UPDATES,

                            MIN_DISTANCE_CHANGE_FOR_UPDATES, this);

 

                    if (locationManager != null) {

                        location = locationManager

                                .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);

                        if (location != null) {

                            // 위도 경도 저장

                            lat = location.getLatitude();

                            lon = location.getLongitude();

                        }

                    }

                }

 

                if (isGPSEnabled) {

                    if (location == null) {

                        locationManager.requestLocationUpdates(

                                LocationManager.GPS_PROVIDER,

                                MIN_TIME_BW_UPDATES,

                                MIN_DISTANCE_CHANGE_FOR_UPDATES, this);

                        if (locationManager != null) {

                            location = locationManager

                                    .getLastKnownLocation(LocationManager.GPS_PROVIDER);

                            if (location != null) {

                                lat = location.getLatitude();

                                lon = location.getLongitude();

                            }

                        }

                    }

                }

            }

 

        } catch (Exception e) {

            e.printStackTrace();

        }

        return location;

    }

 

    /**

     * GPS 종료

     * */

    public void stopUsingGPS(){

        if(locationManager != null){

            locationManager.removeUpdates(GpsInfo.this);

        }

    }

 

    /**

     * 위도값을 가져옵니다.

     * */

    public double getLatitude(){

        if(location != null){

            lat = location.getLatitude();

        }

        return lat;

    }

 

    /**

     * 경도값을 가져옵니다.

     * */

    public double getLongitude(){

        if(location != null){

            lon = location.getLongitude();

        }

        return lon;

    }

 

    /**

     * GPS 나 wife 정보가 켜져있는지 확인합니다.

     * */

    public boolean isGetLocation() {

        return this.isGetLocation;

    }

 

    /**

     * GPS 정보를 가져오지 못했을때

     * 설정값으로 갈지 물어보는 alert 창

     * */

    public void showSettingsAlert(){

        AlertDialog.Builder alertDialog = new AlertDialog.Builder(mContext);

 

        alertDialog.setTitle("GPS 사용유무셋팅");

        alertDialog.setMessage("GPS 셋팅이 되지 않았을수도 있습니다. \n 설정창으로 가시겠습니까?");

 

                // OK 를 누르게 되면 설정창으로 이동합니다.

                alertDialog.setPositiveButton("Settings",

                        new DialogInterface.OnClickListener() {

                            public void onClick(DialogInterface dialog,int which) {

                                Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);

                                mContext.startActivity(intent);

                            }

                        });

        // Cancle 하면 종료 합니다.

        alertDialog.setNegativeButton("Cancel",

                new DialogInterface.OnClickListener() {

                    public void onClick(DialogInterface dialog, int which) {

                        dialog.cancel();

                    }

                });

 

        alertDialog.show();

    }

 

    @Override

    public IBinder onBind(Intent arg0) {

        return null;

    }

 

    public void onLocationChanged(Location location) {

        // TODO Auto-generated method stub

 

    }

 

    public void onStatusChanged(String provider, int status, Bundle extras) {

        // TODO Auto-generated method stub

 

    }

 

    public void onProviderEnabled(String provider) {

        // TODO Auto-generated method stub

 

    }

 

    public void onProviderDisabled(String provider) {

        // TODO Auto-generated method stub

 

    }

}

 

두 번째는 GPS 정보를 가져오는 Activity 에서의 퍼미션 체크 로직을 삽입해야 합니다. 기존에 없던 로직으로 callPermission() 함수가 그것입니다. 함수로 퍼미션 요청을 사용자에게 하면 그림과 같은 요청 팝업창이 뜹니다. 팝업창에서 DENY/ALLOW 하나를 선택하면 Override 한 onRequestPermissionsResult() 로 결과 값을 전달합니다.  

 

 

 이번에 추가한 callPermission() 와 onRequestPermissionsResult() 소스는 다음과 같습니다. 

@Override

public void onRequestPermissionsResult(int requestCode, String[] permissions,

                                       int[] grantResults) {

    if (requestCode == PERMISSIONS_ACCESS_FINE_LOCATION

            && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

 

        isAccessFineLocation = true;

 

    } else if (requestCode == PERMISSIONS_ACCESS_COARSE_LOCATION

            && grantResults[0] == PackageManager.PERMISSION_GRANTED){

 

        isAccessCoarseLocation = true;

    }

 

    if (isAccessFineLocation && isAccessCoarseLocation) {

        isPermission = true;

    }

}

 

// 전화번호 권한 요청

private void callPermission() {

    // Check the SDK version and whether the permission is already granted or not.

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M

            && checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION)

            != PackageManager.PERMISSION_GRANTED) {

 

        requestPermissions(

                new String[]{Manifest.permission.ACCESS_FINE_LOCATION},

                PERMISSIONS_ACCESS_FINE_LOCATION);

 

    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M

            && checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION)

            != PackageManager.PERMISSION_GRANTED){

 

        requestPermissions(

                new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},

                PERMISSIONS_ACCESS_COARSE_LOCATION);

    } else {

        isPermission = true;

    }

}

 

 GPS 정보를 사용하는 메인 Activity 전체 소스입니다. Toast 를 이용해 화면에 위치 정보를 띄우고 TextView 에 위도와 경도를 알려줍니다. 

import android.Manifest;

import android.app.Activity;

import android.content.pm.PackageManager;

import android.os.Build;

import android.os.Bundle;

import android.view.View;

import android.widget.Button;

import android.widget.TextView;

import android.widget.Toast;

 

/** GPS 샘플 */

public class GpsActivity extends Activity {

 

    private Button btnShowLocation;

    private TextView txtLat;

    private TextView txtLon;

    private final int PERMISSIONS_ACCESS_FINE_LOCATION = 1000;

    private final int PERMISSIONS_ACCESS_COARSE_LOCATION = 1001;

    private boolean isAccessFineLocation = false;

    private boolean isAccessCoarseLocation = false;

    private boolean isPermission = false;

 

    // GPSTracker class

    private GpsInfo gps;

 

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_gps);

 

        btnShowLocation = (Button) findViewById(R.id.btn_start);

        txtLat = (TextView) findViewById(R.id.tv_latitude);

        txtLon = (TextView) findViewById(R.id.tv_longitude);

 

        // GPS 정보를 보여주기 위한 이벤트 클래스 등록

        btnShowLocation.setOnClickListener(new View.OnClickListener() {

            public void onClick(View arg0) {

                // 권한 요청을 해야 함

                if (!isPermission) {

                    callPermission();

                    return;

                }

 

                gps = new GpsInfo(GpsActivity.this);

                // GPS 사용유무 가져오기

                if (gps.isGetLocation()) {

 

                    double latitude = gps.getLatitude();

                    double longitude = gps.getLongitude();

 

                    txtLat.setText(String.valueOf(latitude));

                    txtLon.setText(String.valueOf(longitude));

 

                    Toast.makeText(

                            getApplicationContext(),

                            "당신의 위치 - \n위도: " + latitude + "\n경도: " + longitude,

                            Toast.LENGTH_LONG).show();

                } else {

                    // GPS 를 사용할수 없으므로

                    gps.showSettingsAlert();

                }

            }

        });

 

        callPermission();  // 권한 요청을 해야 함

    }

 

    @Override

    public void onRequestPermissionsResult(int requestCode, String[] permissions,

                                           int[] grantResults) {

        if (requestCode == PERMISSIONS_ACCESS_FINE_LOCATION

                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

 

            isAccessFineLocation = true;

 

        } else if (requestCode == PERMISSIONS_ACCESS_COARSE_LOCATION

                && grantResults[0] == PackageManager.PERMISSION_GRANTED){

 

            isAccessCoarseLocation = true;

        }

 

        if (isAccessFineLocation && isAccessCoarseLocation) {

            isPermission = true;

        }

    }

 

    // 전화번호 권한 요청

    private void callPermission() {

        // Check the SDK version and whether the permission is already granted or not.

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M

                && checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION)

                != PackageManager.PERMISSION_GRANTED) {

 

            requestPermissions(

                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION},

                    PERMISSIONS_ACCESS_FINE_LOCATION);

 

        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M

                && checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION)

                != PackageManager.PERMISSION_GRANTED){

 

            requestPermissions(

                    new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},

                    PERMISSIONS_ACCESS_COARSE_LOCATION);

        } else {

            isPermission = true;

        }

    }

}

  

 

API 23 버전부터 아래 에러가 난다면 두 가지 permission 을 추가해야 합니다. ACCESS_FINE_LOCATION 은 이미 있고 ACCESS_COARSE_LOCATION 만 추가하면 되겠죠. 

 

Call requires permission which may be rejected by user. Code should explicitly check to see if permission is available.

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>


출처: https://mainia.tistory.com/1153 [녹두장군 - 상상을 현실로]

 

 

 

반응형

댓글()

Android 액티비티를 팝업(Popup)으로 띄우기, 데이터 주고받기

반응형

MainActivity.java

 

public class MainActivity extends AppCompatActivity {

 

    TextView txtResult;

 

 

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

 

        txtResult = (TextView)findViewById(R.id.txtResult);

    }

 

    //버튼

    public void mOnPopupClick(View v){

        //데이터 담아서 팝업(액티비티) 호출

        Intent intent = new Intent(this, PopupActivity.class);

        intent.putExtra("data""Test Popup");

        startActivityForResult(intent, 1);

    }

 

    @Override

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

        if(requestCode==1){

            if(resultCode==RESULT_OK){

                //데이터 받기

                String result = data.getStringExtra("result");

                txtResult.setText(result);

            }

        }

    }

}

 

 

PopupActivity.java

 

public class PopupActivity extends Activity {

 

    TextView txtText;

 

 

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        //타이틀바 없애기

        requestWindowFeature(Window.FEATURE_NO_TITLE);

        setContentView(R.layout.popup_activity);

 

        //UI 객체생성

        txtText = (TextView)findViewById(R.id.txtText);

 

        //데이터 가져오기

        Intent intent = getIntent();

        String data = intent.getStringExtra("data");

        txtText.setText(data);

    }

 

    //확인 버튼 클릭

    public void mOnClose(View v){

        //데이터 전달하기

        Intent intent = new Intent();

        intent.putExtra("result""Close Popup");

        setResult(RESULT_OK, intent);

 

        //액티비티(팝업) 닫기

        finish();

    }

 

    @Override

    public boolean onTouchEvent(MotionEvent event) {

        //바깥레이어 클릭시 안닫히게

        if(event.getAction()==MotionEvent.ACTION_OUTSIDE){

            return false;

        }

        return true;

    }

 

    @Override

    public void onBackPressed() {

        //안드로이드 백버튼 막기

        return;

    }

}

* 10 : 타이틀바 없애기

* 17-18 : Intent 에서 data 가져오기

* 25-27 : Intent로 data 전달하기

* 34-40 : 바깥 레이어를 눌러도 닫히지 않게 하기

* 43-46 : 안드로이드 백버튼 막기

 

 

activity_main.xml

 

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical"

    android:padding="16dp"

    android:layout_width="match_parent"

    android:layout_height="match_parent">

    <LinearLayout

        android:paddingBottom="8dp"

        android:orientation="horizontal"

        android:layout_width="match_parent"

        android:layout_height="wrap_content">

        <TextView

            android:text="액티비티를 팝업으로 띄우기"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content" />

    </LinearLayout>

 

    <LinearLayout

        android:paddingBottom="8dp"

        android:orientation="horizontal"

        android:gravity="center"

        android:layout_width="match_parent"

        android:layout_height="wrap_content">

        <Button

            android:text="팝업"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:onClick="mOnPopupClick"/>

    </LinearLayout>

 

    <LinearLayout

        android:paddingBottom="8dp"

        android:orientation="horizontal"

        android:gravity="center"

        android:layout_width="match_parent"

        android:layout_height="wrap_content">

        <TextView

            android:id="@+id/txtResult"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content" />

    </LinearLayout>

 

</LinearLayout>

 

 

popup_activity.xml

 

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:background="#eeeeee"

    android:orientation="vertical"

    android:layout_width="300dp"

    android:layout_height="wrap_content">

 

    <!-- 타이틀바 -->

    <LinearLayout

        android:orientation="horizontal"

        android:layout_width="match_parent"

        android:layout_height="wrap_content">

        <TextView

            android:text="Notice"

            android:textSize="20sp"

            android:textColor="#fff"

            android:gravity="center"

            android:background="#ff7a00"

            android:layout_width="match_parent"

            android:layout_height="53dp" />

    </LinearLayout>

    <!-- //end 타이틀바 -->

 

    <!-- Notice -->

    <LinearLayout

        android:padding="24dp"

        android:orientation="vertical"

        android:layout_width="match_parent"

        android:layout_height="wrap_content">

        <TextView

            android:id="@+id/txtText"

            android:textSize="15sp"

            android:textColor="#000"

            android:alpha="0.87"

            android:gravity="center"

            android:layout_marginBottom="3dp"

            android:layout_width="match_parent"

            android:layout_height="wrap_content" />

    </LinearLayout>

    <!-- Notice -->

 

    <View

        android:background="#66bdbdbd"

        android:layout_width="match_parent"

        android:layout_height="1dp" />

 

    <!-- 닫기 버튼 -->

    <LinearLayout

        android:orientation="horizontal"

        android:gravity="center"

        android:layout_width="match_parent"

        android:layout_height="wrap_content">

        <Button

            android:text="확인"

            android:textSize="15sp"

            android:textColor="#ff7a00"

            android:padding="16dp"

            android:gravity="center"

            android:background="#00000000"

            android:layout_width="match_parent"

            android:layout_height="53dp"

            android:onClick="mOnClose"/>

    </LinearLayout>

    <!--// 닫기 버튼 -->

</LinearLayout>

팝업의 가로세로 길이는 직접 정해줍니다

 

 

AndroidMenifest.xml

 

<!-- 팝업 Activity -->

        <activity

            android:name=".PopupActivity"

            android:theme="@android:style/Theme.Dialog" />

* Popup으로 띄울 Activity의 Theme를 바꿔줍니다

 

 

결과

* 팝업 호출(데이터 전달) -> 팝업에서 전달받은 데이터 보여줌 , 팝업 닫기(데이터 전달) -> 데이터 받아서 보여줌

 

 



출처: https://ghj1001020.tistory.com/9 [혁준 블로그]

 

 

 

반응형

댓글()

MySQL general 로그를 logrotate 로 관리하기

리눅스/MySQL|2019. 6. 4. 12:06
반응형

1. general 로그 설정

 

[root@sysdocu ~]# vi /etc/my.cnf

[mysqld]

general_log_file  = /usr/local/mysql/data/general.log

general_log  = 1

 

 

2. logrotate 설정

 

[root@sysdocu ~]# vi /etc/logrotate.d/mysql

/usr/local/mysql/data/general.log {

    daily

    rotate 1    // 사용중인것 말고 날짜로 된것 하나만 보관하도록 한다

    dateext

    missingok

    sharedscripts

    create 660 mysql mysql

    postrotate

        /usr/local/mysql/bin/mysqladmin -uroot -p'00000000' flush-logs

    endscript

}

 

[root@sysdocu ~]# chmod 640 /etc/logrotate.d/mysql

 

강제 실행 테스트

[root@sysdocu ~]# logrotate -f /etc/logrotate.d/mysql

 

 

3. 로그 압축 백업 설정

 

용량이 큰 general 로그를 압축하여 보관하도록 한다.

 

[root@sysdocu ~]# vi /etc/crontab

59 23 * * * root sh /root/general_log.sh

 

[root@sysdocu ~]# vi /root/general_log.sh

!#/bin/bash

 

find /data2/general_log/ -ctime +200 -print -exec rm -f {} \;

date=`date +%Y%m%d`

tar cvzf /data2/general_log/general_log_${date}.tar.gz /data1/general.log-${date}

 

exit 0

 

[root@sysdocu ~]# chmod 700 /root/general_log.sh

 

반응형

댓글()

윈도우10 USB 부팅 디스크 만들기(우분투에서)

윈도우즈/OS 일반|2019. 6. 4. 09:35
반응형

우분투 리눅스에서 윈도우10 USB 부팅 디스크를 만드는 방법은 아래와 같습니다.

1. Window 10 ISO 다운로드

아래 링크에서 Window 10 ISO 파일을 다운로드 받습니다.

 

Windows 10 디스크 이미지 다운로드(ISO 파일)

www.microsoft.com

<Window 10 다운로드 화면>

2. WoeUSB 다운로드

우분투 터미널을 이용해 WoeUSB 설치합니다.

$ sudo add-apt-repository ppa:nilarimogard/webupd8 $ sudo apt update $ sudo apt install woeusb

<아이콘 모양>

3. USB 메모리 포맷

USB 부팅 디스크를 만들기 위해 USB 메모리를 포맷합니다. 포맷 종류(파일 시스템 종류)는 크게 '모든 시스템과 장치에 호환(FAT)', '대부분의 시스템과 호환(NTFS)', '리눅스 시스템과 호환(EXT4)', '암호화, 리눅스 시스템과 호환(LUKS + EXT4)' 4가지로 분류되는데 EXT4, LUKS+EXT4 를 제외한 나머지는 윈도우 파일 시스템으로 모든 또는 대부분의 시스템과 호환된다고 명시되어 있으나FAT 이나 NTFS 로 포맷을 했을 경우 부팅 디스크를 만드는 과정에서 오류가 발생할 수도 있습니다.

(화면 상에는 정상적으로 포맷된 것처럼 보이나 부팅 디스크를 만들 때 디바이스(USB)에 마운트된 모든 것들에 대한 언마운트 실행 오류가 발생합니다.)

그렇기 때문에 종류는 EXT4 또는 LUKS+EXT4 를 선택하여 포맷 진행합니다.

<USB 포맷>

<포맷 종류(EXT4)>

4. WoeUSB 로 부팅 디스크 설치

위 과정이 모두 진행되었다면 WoeUSB 를 실행하여 부팅 디스크를 설치합니다.

(Target device 는 USB 를 자동 인식합니다.)

<WoeUSB 부팅 디스크 설치>

 

 

[출처] https://m.blog.naver.com/PostView.nhn?blogId=sinjoker&logNo=221242863908&proxyReferer=https%3A%2F%2Fwww.google.com%2F

 

반응형

댓글()

haproxy on CentOS 7

리눅스/OS 일반|2019. 5. 29. 09:27
반응형

[root@sysdocu ~]# yum -y install haproxy

 

[root@sysdocu ~]# vi /etc/haproxy/haproxy.cfg

global
    log         127.0.0.1 local2
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon
    stats socket /var/lib/haproxy/stats

defaults
    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull
    option http-server-close
    option forwardfor       except 127.0.0.0/8
    option                  redispatch
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 3000

frontend  main *:80    // haproxy 구동시 사용할 포트를 지정
    acl url_static       path_beg       -i /static /images /javascript /stylesheets
    acl url_static       path_end       -i .jpg .gif .png .css .js

    use_backend static          if url_static
    default_backend             static    // 아래 backend 중에서 static 부분을 사용하겠다는 것. 여러개 미리 설정해놓고 선택하는 식

backend static
    balance     roundrobin    // roundrobin은 무조건 한번씩 번갈아 접속시키는 방식이다. source 값을 이용해도 된다.
    server      static 192.168.10.2:80 check    // 포워딩할 서버 IP 와 포트
    server      static 192.168.10.3:80 check    // 포워딩할 서버 IP 와 포트

backend app
    balance     roundrobin
    server  app1 127.0.0.1:5001 check
    server  app2 127.0.0.1:5002 check
    server  app3 127.0.0.1:5003 check
    server  app4 127.0.0.1:5004 check

 

[root@sysdocu ~]# systemctl enable haproxy

 

[root@sysdocu ~]# service haproxy start

 

반응형

댓글()

xml 파일로 말풍선 만들기

프로그래밍/Android (Java)|2019. 5. 27. 08:13
반응형

안드로이드에서 배경을 처리하기 위해서, 이미지나 컬러를 많이 사용한다.

그리고, res/drawable 폴더에 xml 파일을 만들어서 이미지처럼 사용할 수 도 있다.

 

이번 포스팅에서는 xml 파일 만을 이용하여, 아래와 같은 모양의 말풍선 layout 을 만들어보겠다.

 

 

화살표가 아래를 향하는 말풍선 구조는 이렇다.

 

<LinearLayout android:orientation="vertical"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_margin="10dip"

android:clickable="true" >

<FrameLayout android:src="@drawable/speech_box"

android:layout_width="match_parent"

android:layout_height="100dip">

</FrameLayout>

<ImageView android:src="@drawable/down_arrow_nor"

android:layout_width="30dip"

android:layout_height="30dip"

android:layout_gravity="center_horizontal" />

</LinearLayout>

 

그림으로 보면 이런 구조

 

좌우, 위로 향하는 화살표 말풍선은 잘 배치하면 된다.

말풍선 안에 단순 텍스트 뿐 아니라 이미지를 배치하거나 다른 레이아웃, 뷰를 쉽게 추가하기 위해서, 말풍선 바디 부분은 FrameLayout 을 사용했다.

 

사실 이 글에서 다루고 싶었던 내용은 삼각형 모양의 화살표를 xml 파일로 만드는 것이다.

알고보면 원리는 간단하다.

사각형을 그린 뒤, 45도 회전시킨 후, x, y 축으로 적당히 이동시켜서, 한쪽 모서리만 그려지게 만들면 된다.

 

아래로 향하는 화살표를 만들기 위해, drawable 폴더에 down_arrow_nor.xml 파일을 하나 만들어서 아래와 같이 사각형을 그려주도록 하자.

 

<?xml version="1.0" encoding="utf-8"?>

 

<item>

<shape android:shape="rectangle" >

<solid android:color="#88FFFFFF"/>

<padding 

android:left="0dip"

android:right="0dip"

android:top="0dip"

android:bottom="0dip"/>

</shape>

</item>

</layer-list>

 

레이아웃에 이미지뷰를 띄워서 확인해보면 아래 그림과 같이 사각형이 그려진다. (배경 컬러 : #555500)

 

이제 이 사각형을 오른쪽으로 45도 돌려주면 아래와 같이 8각형 모양으로 나타난다. 이는 내가 이미지뷰에 지정한 사이즈 (50dip x 50dip) 의 영역 밖에서 각 모서리 부분이 그려졌기 때문이다.

<?xml version="1.0" encoding="utf-8"?>

 

<item>

<rotate android:fromDegrees="45"

android:toDegrees="45">

<shape android:shape="rectangle" >

<solid android:color="#88FFFFFF"/>

<padding 

android:left="0dip"

android:right="0dip"

android:top="0dip"

android:bottom="0dip"/>

</shape>

</rotate>

</item>

</layer-list>

이제 모서리 부분만 보이도록 이미지를 X, Y 축 방향으로 적당히 이동하면 된다.

그런데 여기서 주의할 점은, 이미지 회전 시 X,Y 축도 같이 45도 틀어졌다는 것이다.

그래서, X 축 방향으로만, 혹은 Y 축 방향으로만 움직인다고 해서 모서리만 보이거나 하지 않는다. 두 축에 대해 모두 이동을 해야 한다.

 

여러번 해보면서 자신이 생각하는 모양에 맞게 맞춰나가는게 좋다.

내가 사용한 값은 이렇다.

<?xml version="1.0" encoding="utf-8"?>

 

<item>

<rotate

android:fromDegrees="45"

android:toDegrees="45"

android:pivotX="135%"

android:pivotY="13%" >

<shape android:shape="rectangle" >

<solid android:color="#88FFFFFF"/>

<padding 

android:left="0dip"

android:right="0dip"

android:top="0dip"

android:bottom="0dip"/>

</shape>

</rotate>

</item>

</layer-list>



출처: https://bbulog.tistory.com/19 [뿔로그]

 

 

 

반응형

댓글()

원격으로 윈도우 서버 패스워드 변경하기

윈도우즈/OS 일반|2019. 5. 23. 17:53
반응형

1. 다운로드

아래 URL 에서 유틸리티를 다운로드하고 압축을 풉니다.

https://docs.microsoft.com/ko-kr/sysinternals/downloads/pspasswd

 

PsPasswd v1.24  /  June 29, 2016

PSTools.zip
3.04MB

* 유틸리티를 실행한 테스트 환경은 Windows 2016 였으며,

   해당 유틸리티로 Windows 2012 R2, Windows 2019 Server 패스워드를 변경해 보았습니다.

   이후 Windows 버전이 나온다면 테스트 해보거나, 업데이트된 유틸리티를 받아야 합니다.

 

 

2. 실행

사용 예 : pspasswd \\서버IP -u 로그인계정 -p 패스워드 바꿀계정 바꿀패스워드

C:\PSTools> pspasswd \\192.168.10.2 -u administrator -p 1111 administrator 2222 /accepteula

PsPasswd v1.24 - Local and remote password changer
Copyright (C) 2003-2016 Mark Russinovich
Sysinternals - www.sysinternals.com

Password successfully changed.

 

 

* 처음에 명령 실행할때는 유틸리티 라이센스 확인 창이 뜨지만 (agree 누름) 그 이후부터는 뜨지 않습니다.

  또는 /accepteula 옵션으로 eula 라이센스에 대한 물음을 안받게 할 수도 있습니다.

 

 

반응형

댓글()

MSSQL sqlserver 오류 15404 windows nt 그룹/사용자 에 대한 정보를 가져올 수 없습니다. 오류 코드 sqlstate 42000 connlsloginsysadmin

윈도우즈/MSSQL|2019. 5. 20. 09:44
반응형

메시지

[298] SQLServer 오류: 15404, Windows NT 그룹/사용자 'hostname'\administrator'에 대한 정보를 가져올 수 없습니다.오류 코드 0x534. [SQLSTATE 42000] (ConnIsLoginSysAdmin)

   

hostname은 컴퓨터명입니다. 그리고 administrator는 서버 설치 후 계정명을 바꾸었다면 다르게 나올수도 있습니다.

   

머 일단 이런 메시지가 나오면 확인해봐야 할 사항은

   

Microsoft SQL Server Management Studio 실행하셔서 머 Sa계정이나 시스템계정으로 로그인 하시고

   

개체탐색기 왼쪽에 보면 보안 >> 로그인 하위의 계정들 중에 hostname\administrator가 현재 OS의 계정과

   

동일한지 확인해보세요.

   

아마 십중팔구는 동일하지 않을꺼에요. 그러면 서버 처음 설치했을때는 hostnanme\administrator를 현재 계정명으로

바꿔줘야 합니다. 멀로 바꾸냐구요?

   

개체탐색기의 데이터베이스 연결된 명을 확인해보세요

   

두번째로 서버역할의 sysadmin에도 바꾼 hostname\administrator가 있는지 확인하세요. 보통 로그인의 계정정보를

변경하면 자동으로 sysadmin의 정보도 바뀝니다.

   

혹시 없으면 추가해주세요

 

 

[출처] SQLServer 오류: 15404 발생원인 및 해결방법|작성자 스팀

 

 

 

반응형

댓글()

sql server 복제에서는 서버 연결 시 실제 서버 이름이 필요합니다.

윈도우즈/MSSQL|2019. 5. 17. 16:01
반응형

개발사에서 웹 에서 게임 DB 에 내용을 거의 실시간으로 보여주기 위해 복제 DB 를 설정하다가
복제 생성시 아래와 같은 오류가 발생한다고 Help 요청이 들어왔다.

 

===================================

xxxxxxxxxxxxxx에 연결할 수 없습니다.

===================================

SQL Server 복제에서는 서버 연결 시 실제 서버 이름이 필요합니다. 서버 별칭, IP 주소 또는 다른 대체 이름을 통한 연결은 지원되지 않습니다. 실제 서버 이름 'xxxxxxxxxxxxxx'을(를) 지정하십시오. (Replication.Utilities)

------------------------------
프로그램 위치:

   위치: Microsoft.SqlServer.Management.UI.ReplicationSqlConnection.CheckServerAlias(ServerConnection conn)
   위치: Microsoft.SqlServer.Management.UI.ReplicationSqlConnection.ValidateConnection(UIConnectionInfo connInfo, IServerType server)
   위치: Microsoft.SqlServer.Management.UI.ConnectionDlg.Connector.ConnectionThreadUser()

 

해당 문제는 컴퓨터 이름을 변경시에 발생한다.

----------------------------- 


이유인 즉 mssql2008을 설치하면 설치시에 서버의 HostName 이  저장된다.
그 후에 해당 서버에 HostName 이 변경 되면서  게시나 복제를 할려면 옛날 서버 이름으로 접근을 해서 위와 같은 오류가 발생한 것이다.

아래와 같이 기존 @@SERVERNAME 이름을 현재 HostName 으로 변경해 주면 된다.

USE master
GO

-- 예전 서버 이름을 확인한다.
SELECT @@SERVERNAME

-- 예전 서버 이름을 버린다.
EXEC sp_dropserver 'Old Server Name', 'droplogins'    // 예전 서버 이름 입력
GO

-- 새 서버 이름을 등록한다.
EXEC sp_addserver 'New Server Name', 'local'    // 새 서버 이름 입력
GO

 

-- 반드시 '서비스 재시작'을 해야 적용 된다.

 

 

[출처] http://egloos.zum.com/runhanii/v/2606562

반응형

댓글()