반응형

갈산동맛집 부평구청 서울감자탕!




안녕하세요? 나남입니다.



부평구청역에 있는 서울감자탕을 방문하게 되었어요



부평구청역 3번출구에서굴포천역 방면에

부평여성회관이 있는데

그 앞에 있는게 바로 서울감자탕이에요~~



굴포 먹거리타운은 유동인구가 많지 않지만

알려지지 않은 맛집들이 많이 있어서

자영업자분들이 쉽게 문을 닫지 않고

오랫동안 가게를 유지하고 있어요



이 곳 서울감자탕도 그런곳중 한 곳 인게

2002년부터 지금까지 운영하고 있어요~

그만큼 찾는 사람들이 있어서 유지할 수 있단거죠?











늦게퇴근하고 온지라 8시반쯤 방문해서

문을 닫지 않을까 걱정했는데

다행히 영업시간이 10시부터 22시까지 하더라고요



14년전통의 감자탕 전문점이라고 적혀있는데

이제는 16년전통의 감자탕 전문점이네요 ㅎㅎㅎ

since 2002 !








실내는 테이블석과 온돌형으로 이루어져있어요~









신발벗는게 싫어서 테이블석에 착석!


에어컨이 왕따시만한게 있어서 시원한 바람이 술술~~~




주요메뉴


메뉴

가격 

뼈해장국

7,000원 

우거지 해장국 

6,000원 

감자탕

2인 - 24,000원

3인 - 29,000원

4인 - 34,000원 

우리콩 감자탕 

2인 - 25,000원

3인 - 30,000원

4인 - 35,000원

등뼈찜

2~3인 - 34,000원

 3~4인 - 39,000원 











오이고추

콩자반

배추김치

깍두기

쌈장



기본반찬이에요







주문한 감자탕이 뚝딱나왔어요



오래끓이기도 했겠지만

돼지고기잡내제거를 위해 

들깨가루를 듬뿍 넣어서

고기냄새에 민감한

와이프 입맛도 저격했어요!!










보글보글보글보글보글

보글보글보글보글보글

보글보글보글보글보글







감자탕 먹고나서 볶음밥이 빠지면 섭하죠?

원래 라면사리를 먼저 먹고

볶음밥을 볶아야 진정한 먹짱인데

시간이 늦은 관계로 볶음밥만

호로록~~





주관적인 입맛으로 평을 해본다면?!


1. 고기냄새가 나지 않는다.

2. 오래 끓여서 고기가 뼈에서 잘 발려진다.

3. 볶음밥이 맛있다.






추가


사장님이 친절하심

부천에 자주 가는 감자탕집 보다 가까워서 더 자주 오게 될 것 같음

끝!








반응형
블로그 이미지

나남나여

일상 제품리뷰와 맛집/여행/사진을 좋아하고 IT 관련 프로그래밍 초급 & 고급 정보를 공유하는 블로그

,
반응형

안녕하세요? 나남입니다!


1994년의 기록적인 폭염을 이긴 2018년의 더위가 드디어 풀리려나 봅니다!!


기념으로 이번 포스팅은 평일 점심시간에 방문한 명동칼국수 본점입니다~!





명동에서 일한지 2년됐지만 항상 줄이 서있어서

가볼엄두를 못냈었는데

가본사람들의 말로는 기다리긴하지만

줄이 금방 줄어서 오래 기다리지 않는다고 하니 도전하게되었어요!!


주메뉴가 칼국수와 만두다 보니 회전율이 엄청납니다

( 빨리 먹는건 둘째치고 주문하면 바로 나온다고 보면 돼요! )



중국사람들은 물론이고

일본인, 베트남, 유럽, 미국인, 중동사람 등등 

외국사람들도 많아요~


( 아마도 외국에서 한국 여행 가이드 책에

명동교자는 맛집에 꼭 있을것 같다는 뇌피셜입니다 ㅎㅎㅎ )




점심시간에는 조금만 늦어도 1층에 사람들이 

가득차서 항상 3층으로 올라가서 먹어야 해요~


이더운날 3층까지 걸어가느냐? 노노!  건물내엘레베이터가 있으니 걱정하지 마세요!!^^





명동칼국수의 운영시간은 10시30분 ~ 21시30분까지네요


메뉴는 단순합니다.


- 칼국수

- 비빔국수

- 콩국수

- 만두



1966년부터 운영한 맛집의 메뉴판답게 소수의 메뉴만 판매하고 있어요







우리의 주문은 칼국수와 만두!


메뉴가 적고 사람이 가득찬 점심시간이다보니 칼국수를 계속 뽑고 있나봐요

주문과 동시에 화장실을 다녀왔는데 벌써 식사가 나왔어요!!! 

우와아아악~~~~~~~~~~~~




명동칼국수의 명물이라는 마늘맛김치와 칼국수가

이미 제 자리에서 날 먹어달라고 소리치고 있었어요!!!


명동칼국수는 맑은국물과 함께 

납작한 변씨만두 4개가 제공되고

그 위에 올라간 고명들......

특히 다진고기가 눈에 띕니다!!


고명과 면의 비율이 아주 자로 잰 듯 적당한 양이 올라갔어요!



일단 육수부텨 한입~!!


칼칼하지 않고 점도가 높은 구수한 닭육수~~~

일반적으로 점도가 높으면 텁텁하게 되는데

누구나 깔끔하게 먹을 수 있는 맛이에요~~~!!!!



면은?? 탄탄하지 않고 흐물흐물하지만 절대 불어서 흐물흐물한게 아니에요

먹기 편한 정도의 흐물거림(?)이라고 하는게 맞겠네요!


한 젓가락 당 마늘김치 한입 쏙~






그리고 이 문제의 만두!


가격이 꽤 높아서 주문할까 말까

고민했지만 결국 주문하게 된 만두!


일단 만두피는 굉장히 얇아서 안에 내용물이 보여요~

또, 좋은 고기를 사용했는지 고기냄새가 하나도 나지 않고

음미했을 때 부추의 향도 느낄 수 있어요!


만두를 한입 베어물면 안에서 칼국수 국물과 육즙이 쭉~~~~~~들어오는데

다시 생각해도 배고파지네요ㅠㅠ


카드명세서가 늘어나겠지만 맛은 완전 강추입니다.



가까운데 계신다면 모르겠지만

명동칼국수를 위해서 명동까지 왔다면 꼭 먹어봐야 할 잇(eat)메뉴입니다!!








반응형
블로그 이미지

나남나여

일상 제품리뷰와 맛집/여행/사진을 좋아하고 IT 관련 프로그래밍 초급 & 고급 정보를 공유하는 블로그

,
반응형

jquery 로 iframe form submit ( sample 포함 )




특정 페이지를 submit(호출)하기 위해

jsp 에서 iframe 을 사용했는데

iframe 의 src 에 넣은 link가

하필 보안에 위배되는 주소가 되어버렸습니다.



jsp 에서 iframe 에 사용한 src 를 어떻게 숨길지 고민하다

jqeury 를 사용해서 해당 페이지를 호출 후 

삭제하는 로직을 넣어보기로 했습니다.



변경전 jsp 구조샘플

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>TEST</title>
<link rel="stylesheet" type="text/css" href="./css/style.css">
<script type="text/javascript" src="./js/jquery.js"></script>
<script type="text/javascript" src="./js/index.js"></script>
<form id="frm" method="post" target="cgi">
<div>
---중략---
</div>
</form>    
<iframe name="iFrm" style="display: none;" src="https://tistory.com"></iframe>


iframe 에서 src 로 입력한 부분이 소스보기시 노출되어 보안문제 발생!

과감히 iframe 태그를 삭제하고 js 파일에서 작성하도록 합니다.



index.js 에서 jquery 를 이용한 iframe 생성

function init() {
	var iframe = $('');
	$( "body" ).append(iframe);
	var src = "https://tistory.com";
	iframe.attr('src',src).load(function(){
						$('#iFrm').remove()
						});
}




body 에 onload event 를 처리한 function 에 아래내용을 넣어줬습니다.


iframe 태그를 load 한 후 바로 삭제 했으니 남아있는게 없게 되었습니다!





궁금한점 있으면 댓글 작성해주세요!

반응형
블로그 이미지

나남나여

일상 제품리뷰와 맛집/여행/사진을 좋아하고 IT 관련 프로그래밍 초급 & 고급 정보를 공유하는 블로그

,
반응형

Apache ErrorDocument 설정 따라하기



apache 서버를 운영 중 오류 발생 시


 - 404 not found error 

 - 500 Internal Server Error 


등의 에러메세지가 그대로 노출됩니다.



개발시 에러메세지가 노출되면

오류메세지를 바로 확인 가능하기 때문에

개발하는 입장에서는 수정개발이

용이한 장점이 있습니다.




하지만 시스템 운영시에는??



일반 사용자가 알 수 없는 에러메시지를 봐야 할 필요가 있을까요?


A : "페이지 개발이 덜 되었네~"

B : "누가 개발한건지 디테일이 부족하네"

C : "우리가 쓰는 시스템에 심각한 문제가 있는거 아니야?"

D : "다른 기능은 정상동작하고 있는게 맞을까??"


이런 생각을 할 수도 있습니다.




또한 오류발생 시 서버 경로도 노출되기 때문에

프로그램을 조금이라도 아는 사람이

의도치 않은 경로로 접속할수도 있습니다.




위의 상황을 사전방지하기 위해선

오류발생 시 개발자가 의도한 화면이 

보여지도록 처리해야 합니다.




그럼 아파치 서버 내 에러페이지 전환방법을 알아보겠습니다.







1. httpd.conf 파일


#ErrorDocument 500 "The server made a boo boo."
#ErrorDocument 404 /missing.html
#ErrorDocument 402 http://www.example.com/subscription_info.html



아파치 서버 설치시 ErrorDocument 에 기본값이며,

3가지 방법으로 사용할 수 있는 것을 확인할 수 있습니다.

활성화 하는 방법은 vi 편집기를 이용하여 # 으로 된 주석을 풀거나

내려받아서 수정 후 다시 업로드 하면 되겠죠?






- 텍스트 표시

      : 입력된 text 를 표시해줍니다.


- 서버 내부 전환

      : 서버내 만들어 놓은 페이지로 전환합니다.


- 외부 경로 전환

      : 외부 페이지로 전환합니다.




텍스트 표시와 외부경로전환은 바로 입력하면 되는데 

서버내부전환은 어떻게 할까요?



2. DocumentRoot

서버내부전환은 root path 로 인식하는 DocumentRoot 를 확인합니다.


아파치 서버 설치 시 기본설정값은 아래위치입니다.



DocumentRoot "설치경로/htdocs"



ErrorDocument 404 "/errorpage/error404.html"
ErrorDocument 500 "/errorpage/error500.html"



위와 같이 작성하면 "설치경로/htdocs/errorpage/error404.html" 에 있는 페이지로 전환하게 되니

기본 root path 를 변경하시려면 DocumentRoot 의 경로를 변경해주시면 됩니다.


또한, 예제에서는 double quotation 이 빠진 상태로 나와있는데

RHEL 과 CentOS 에서는 double quotation 을 입력해야 정상적으로 작동을 합니다.



잘 안되거나 추가로 궁금한 부분이 있으면 밑에 댓글 달아주세요^^

반응형
블로그 이미지

나남나여

일상 제품리뷰와 맛집/여행/사진을 좋아하고 IT 관련 프로그래밍 초급 & 고급 정보를 공유하는 블로그

,
반응형



AES 암호화 방식을 통한 DBCP 암호화




암호화 처리는 어떤 데이터를 암호화 하느냐에 따라

일방향 암호화 처리를 할 것인지

양방향 암호화 처리를 할 것인지 결정하게 됩니다.



일방향암호화 : 사용자비밀번호와 같이 시스템관리자도 복호화가 필요없이 비교만 하면 되는 경우

양방향암호화 : 사용자이름, 휴대폰번호, 계좌번호 등 복호화하여 시스템운영상 확인이 필요한 경우


복호화가 필요한 경우는 암호화 했던 비밀키를 입력하여 풀어냅니다.



이번 포스팅에서는 tomcat 을 was 로 사용하는 경우

server.xml 에 평문으로 입력된 DB접속정보가 노출되어

2차 피해는 막자는 취지에서 샘플 소스를 공유합니다.



준비


AES 암호화를 위한 필요라이브러리

https://commons.apache.org/proper/commons-codec/download_codec.cgi



이클립스를 사용하는 경우 

commons-codec-1.11-bin.zip 파일 다운로드 받은 후 commons-codec-1.11.jar 를 java build path 에 등록합니다.




아래는 server.xml 에 등록된 DB 접속정보입니다.

username , password , url 정보가 평문으로 입력되어 있어 

인증되지 않은 사용자가 해당 파일을 오픈 했을 때 서버정보를 쉽게 알 수 있게 됩니다.







목표

username , password , url 와 같은 평문 저장을 원치 않는 속성을 암호화 처리


암호화 처리 방식 : AES-256

( SEED 방식도 많이 쓰니 다음에 정리하겠습니다..)




STEP 1.

라이브러리 등록 : commons-codec-1.11.jar


파일 다운로드 경로 : https://commons.apache.org/proper/commons-codec/download_codec.cgi


commons-codec-1.11-bin.zip 파일을 받아 압축을 풀면

해당 jar 라이브러리 파일이 존재하는데

Java Build Path에 등록합니다.





STEP 2

평문 데이터를 암호화 및 복호화 function 제공 ( AES256Util.java )



package com.encrypt;

import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;

public class AES256Util {
	private String iv;
	private Key keySpec;
	
	
	public AES256Util(String key) throws UnsupportedEncodingException {
		this.iv = key.substring(0,  16);
		byte[] keyBytes = new byte[16];
		byte[] b = key.getBytes("UTF-8");
		int len = b.length;
		if(len>keyBytes.length){
			len = keyBytes.length;
		}
		System.arraycopy(b,  0, keyBytes,  0 ,  len);
		SecretKeySpec keySpec  = new SecretKeySpec(keyBytes, "AES");
				
		this.keySpec = keySpec;
		
	}
	
	public String encrypt(String str) throws NoSuchAlgorithmException, GeneralSecurityException, UnsupportedEncodingException {
		Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
		c.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(iv.getBytes()));
		
		byte[] encrypted = c.doFinal(str.getBytes("UTF-8"));
		String enStr = new String(Base64.encodeBase64(encrypted));
		return enStr;
	}
	
	public String decrypt(String str) throws NoSuchAlgorithmException, GeneralSecurityException, UnsupportedEncodingException {
		Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
		c.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(iv.getBytes()));
		byte[] byteStr = Base64.decodeBase64(str.getBytes());
		return new String(c.doFinal(byteStr), "UTF-8");
	}
}


작업 내용 : 암호화 / 복호화 처리 함수 제공






STEP 3

서버정보 암호화 내용 확인 ( TestMain.java )




package com.encrypt;

import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;

public class TestMain {

	public static void main(String[] args) throws UnsupportedEncodingException, NoSuchAlgorithmException, GeneralSecurityException {
		AES256Util aes = new AES256Util("testestestestses");   // 암호화 키 16자리
			
		// 암호화 된 내용
		System.out.println("scott : " + aes.encrypt("scott"));  
		System.out.println("tiger : " + aes.encrypt("tiger"));
		  
	}

}


작업내용 : STEP 2 에서 작성한 함수를 main 을 통해서 테스트할 수 있습니다.



TestMain.java 실행결과



scott : BxoN1jurrKiXrlSSvf0/ng==
tiger : JcHanmccsCwU4Z4NpnYQKg==



복호화 했을 때 입력했던 값을 받을 수 있다면 성공!



System.out.println(aes.decrypt("BxoN1jurrKiXrlSSvf0/ng=="));
System.out.println(aes.decrypt("JcHanmccsCwU4Z4NpnYQKg=="));



STEP 4


암호화 된 정보를 복호화 하는 factory 를 생성


DBCP 의 기본은 org.apache.commons.dbcp.BasicDataSourceFacroty 를 사용하고 있는데

해당 class 파일을 decompile 후 아래와 같이 customizing 했습니다.



package com.encrypt;

import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import java.util.StringTokenizer;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.RefAddr;
import javax.naming.Reference;
import javax.naming.spi.ObjectFactory;
import javax.sql.DataSource;

import org.apache.tomcat.dbcp.dbcp.BasicDataSource;

public class EncryptDataSourceFactory implements ObjectFactory
{

	  private static final String PROP_DEFAULTAUTOCOMMIT = "defaultAutoCommit";
	  private static final String PROP_DEFAULTREADONLY = "defaultReadOnly";
	  private static final String PROP_DEFAULTTRANSACTIONISOLATION = "defaultTransactionIsolation";
	  private static final String PROP_DEFAULTCATALOG = "defaultCatalog";
	  private static final String PROP_DRIVERCLASSNAME = "driverClassName";
	  private static final String PROP_MAXACTIVE = "maxActive";
	  private static final String PROP_MAXIDLE = "maxIdle";
	  private static final String PROP_MINIDLE = "minIdle";
	  private static final String PROP_INITIALSIZE = "initialSize";
	  private static final String PROP_MAXWAIT = "maxWait";
	  private static final String PROP_TESTONBORROW = "testOnBorrow";
	  private static final String PROP_TESTONRETURN = "testOnReturn";
	  private static final String PROP_TIMEBETWEENEVICTIONRUNSMILLIS = "timeBetweenEvictionRunsMillis";
	  private static final String PROP_NUMTESTSPEREVICTIONRUN = "numTestsPerEvictionRun";
	  private static final String PROP_MINEVICTABLEIDLETIMEMILLIS = "minEvictableIdleTimeMillis";
	  private static final String PROP_TESTWHILEIDLE = "testWhileIdle";
	  private static final String PROP_PASSWORD = "password";
	  private static final String PROP_URL = "url";
	  private static final String PROP_USERNAME = "username";
	  private static final String PROP_VALIDATIONQUERY = "validationQuery";
	  private static final String PROP_VALIDATIONQUERY_TIMEOUT = "validationQueryTimeout";
	  private static final String PROP_INITCONNECTIONSQLS = "initConnectionSqls";
	  private static final String PROP_ACCESSTOUNDERLYINGCONNECTIONALLOWED = "accessToUnderlyingConnectionAllowed";
	  private static final String PROP_REMOVEABANDONED = "removeAbandoned";
	  private static final String PROP_REMOVEABANDONEDTIMEOUT = "removeAbandonedTimeout";
	  private static final String PROP_LOGABANDONED = "logAbandoned";
	  private static final String PROP_POOLPREPAREDSTATEMENTS = "poolPreparedStatements";
	  private static final String PROP_MAXOPENPREPAREDSTATEMENTS = "maxOpenPreparedStatements";
	  private static final String PROP_CONNECTIONPROPERTIES = "connectionProperties";
	  private static final String[] ALL_PROPERTIES = { "defaultAutoCommit", "defaultReadOnly", "defaultTransactionIsolation", "defaultCatalog", "driverClassName", "maxActive", "maxIdle", "minIdle", "initialSize", "maxWait", "testOnBorrow", "testOnReturn", "timeBetweenEvictionRunsMillis", "numTestsPerEvictionRun", "minEvictableIdleTimeMillis", "testWhileIdle", "password", "url", "username", "validationQuery", "validationQueryTimeout", "initConnectionSqls", "accessToUnderlyingConnectionAllowed", "removeAbandoned", "removeAbandonedTimeout", "logAbandoned", "poolPreparedStatements", "maxOpenPreparedStatements", "connectionProperties" };
	  

	
  public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment)    throws Exception  {
	  
    if ((obj == null) || (!(obj instanceof Reference))) {
      return null;
    }
    Reference ref = (Reference)obj;
    if (!"javax.sql.DataSource".equals(ref.getClassName())) {
      return null;
    }
    Properties properties = new Properties();
    for (int i = 0; i < ALL_PROPERTIES.length; i++)
    {
      String propertyName = ALL_PROPERTIES[i];
      RefAddr ra = ref.get(propertyName);
      if (ra != null)
      {
        String propertyValue = ra.getContent().toString();
        properties.setProperty(propertyName, propertyValue);
      }
    }
    return createDataSource(properties);
  }
  
  public static DataSource createDataSource(Properties properties)
    throws Exception
  {
    BasicDataSource dataSource = new BasicDataSource();
    String value = null;
    
    value = properties.getProperty("defaultAutoCommit");
    if (value != null) {
      dataSource.setDefaultAutoCommit(Boolean.valueOf(value).booleanValue());
    }
    value = properties.getProperty("defaultReadOnly");
    if (value != null) {
      dataSource.setDefaultReadOnly(Boolean.valueOf(value).booleanValue());
    }
    value = properties.getProperty("defaultTransactionIsolation");
    if (value != null)
    {
      int level = -1;
      if ("NONE".equalsIgnoreCase(value)) {
        level = 0;
      } else if ("READ_COMMITTED".equalsIgnoreCase(value)) {
        level = 2;
      } else if ("READ_UNCOMMITTED".equalsIgnoreCase(value)) {
        level = 1;
      } else if ("REPEATABLE_READ".equalsIgnoreCase(value)) {
        level = 4;
      } else if ("SERIALIZABLE".equalsIgnoreCase(value)) {
        level = 8;
      } else {
        try
        {
          level = Integer.parseInt(value);
        }
        catch (NumberFormatException e)
        {
          System.err.println("Could not parse defaultTransactionIsolation: " + value);
          System.err.println("WARNING: defaultTransactionIsolation not set");
          System.err.println("using default value of database driver");
          level = -1;
        }
      }
      dataSource.setDefaultTransactionIsolation(level);
    }
    value = properties.getProperty("defaultCatalog");
    if (value != null) {
      dataSource.setDefaultCatalog(value);
    }
    value = properties.getProperty("driverClassName");
    if (value != null) {
      dataSource.setDriverClassName(value);
    }
    value = properties.getProperty("maxActive");
    if (value != null) {
      dataSource.setMaxActive(Integer.parseInt(value));
    }
    value = properties.getProperty("maxIdle");
    if (value != null) {
      dataSource.setMaxIdle(Integer.parseInt(value));
    }
    value = properties.getProperty("minIdle");
    if (value != null) {
      dataSource.setMinIdle(Integer.parseInt(value));
    }
    value = properties.getProperty("initialSize");
    if (value != null) {
      dataSource.setInitialSize(Integer.parseInt(value));
    }
    value = properties.getProperty("maxWait");
    if (value != null) {
      dataSource.setMaxWait(Long.parseLong(value));
    }
    value = properties.getProperty("testOnBorrow");
    if (value != null) {
      dataSource.setTestOnBorrow(Boolean.valueOf(value).booleanValue());
    }
    value = properties.getProperty("testOnReturn");
    if (value != null) {
      dataSource.setTestOnReturn(Boolean.valueOf(value).booleanValue());
    }
    value = properties.getProperty("timeBetweenEvictionRunsMillis");
    if (value != null) {
      dataSource.setTimeBetweenEvictionRunsMillis(Long.parseLong(value));
    }
    value = properties.getProperty("numTestsPerEvictionRun");
    if (value != null) {
      dataSource.setNumTestsPerEvictionRun(Integer.parseInt(value));
    }
    value = properties.getProperty("minEvictableIdleTimeMillis");
    if (value != null) {
      dataSource.setMinEvictableIdleTimeMillis(Long.parseLong(value));
    }
    value = properties.getProperty("testWhileIdle");
    if (value != null) {
      dataSource.setTestWhileIdle(Boolean.valueOf(value).booleanValue());
    }
    value = properties.getProperty("password");
    if (value != null) {
      dataSource.setPassword(decryptDBCPProperty(value));
    }
    value = properties.getProperty("url");
    if (value != null) {
      dataSource.setUrl(decryptDBCPProperty(value));
    }
    value = properties.getProperty("username");
    if (value != null) {
      dataSource.setUsername(decryptDBCPProperty(value));
    }
    value = properties.getProperty("validationQuery");
    if (value != null) {
      dataSource.setValidationQuery(value);
    }
    value = properties.getProperty("validationQueryTimeout");
    if (value != null) {
      dataSource.setValidationQueryTimeout(Integer.parseInt(value));
    }
    value = properties.getProperty("accessToUnderlyingConnectionAllowed");
    if (value != null) {
      dataSource.setAccessToUnderlyingConnectionAllowed(Boolean.valueOf(value).booleanValue());
    }
    value = properties.getProperty("removeAbandoned");
    if (value != null) {
      dataSource.setRemoveAbandoned(Boolean.valueOf(value).booleanValue());
    }
    value = properties.getProperty("removeAbandonedTimeout");
    if (value != null) {
      dataSource.setRemoveAbandonedTimeout(Integer.parseInt(value));
    }
    value = properties.getProperty("logAbandoned");
    if (value != null) {
      dataSource.setLogAbandoned(Boolean.valueOf(value).booleanValue());
    }
    value = properties.getProperty("poolPreparedStatements");
    if (value != null) {
      dataSource.setPoolPreparedStatements(Boolean.valueOf(value).booleanValue());
    }
    value = properties.getProperty("maxOpenPreparedStatements");
    if (value != null) {
      dataSource.setMaxOpenPreparedStatements(Integer.parseInt(value));
    }
    value = properties.getProperty("initConnectionSqls");
    if (value != null)
    {
      StringTokenizer tokenizer = new StringTokenizer(value, ";");
      dataSource.setConnectionInitSqls(Collections.list(tokenizer));
    }
    value = properties.getProperty("connectionProperties");
    if (value != null)
    {
      Properties p = getProperties(value);
      Enumeration e = p.propertyNames();
      while (e.hasMoreElements())
      {
        String propertyName = (String)e.nextElement();
        dataSource.addConnectionProperty(propertyName, p.getProperty(propertyName));
      }
    }
    if (dataSource.getInitialSize() > 0) {
      dataSource.getLogWriter();
    }
    return dataSource;
  }
  
  private static Properties getProperties(String propText)
    throws Exception
  {
    Properties p = new Properties();
    if (propText != null) {
      p.load(new ByteArrayInputStream(propText.replace(';', '\n').getBytes()));
    }
    return p;
  }
  
  
  private static String decryptDBCPProperty(String encryptStr) throws UnsupportedEncodingException, NoSuchAlgorithmException, GeneralSecurityException {
	  
	  AES256Util aes = new AES256Util("testestestestses");

	  return aes.decrypt(encryptStr);

  }
}






위 소스에서 중요내용

username, password, url 에 해당하는 부분을 복호화하도록 변경



변경전 : dataSource.setPassword(value);
변경후 : dataSource.setPassword(decryptDBCPProperty(value));


눈치빠른 분들은 아시겠지만

server.xml 에서 입력된 username, password , url 을 암호화 하는 부분이었습니다.

( 위 3가지 정보 중 필요한 부분만 암호화 처리해도 됩니다. )


STEP 5

server.xml 에 암호화 된 내용으로 개인정보 변경






여기서 중요한 부분은 STEP 4 에서 만든 factory 를 지정하여

DBCP 할 때 사용할 수 있도록 합니다.

default 값은 BasicDataSourceFactory 로 별도로 지정해주지 않으면

tomcat-dbcp.jar 에 있는 내용을 사용하게 되니

반드시 우리가 만든 factory 를 설정해주시기 바랍니다.




여기까지 작업하면 해당 내용이 암호화 처리가 됩니다!


궁금한점이나 안되는 부분있으면 댓글 달아주세요^^


반응형
블로그 이미지

나남나여

일상 제품리뷰와 맛집/여행/사진을 좋아하고 IT 관련 프로그래밍 초급 & 고급 정보를 공유하는 블로그

,
반응형

인천 설렁탕 맛있는집 옥천관




인천 계양구 청천동 설렁탕집 옥천관








자부심이 느껴지는 업소명과

자신있게 맛있는집이라고 붙여놓은 간판




집에서 한우사골을 푹 끓여서 먹고 싶지만

그만큼의 노력을 쏟기에는 너무 힘듭니다ㅠ

집에서 하는 음식과 비슷한 곳을 찾아가기 위해 방황하다 알게된 옥천관.


집에서 차타고 10분 정도 거리에 있어

쉽게 오진 못하지만

설렁탕이 생각날 때면 이곳으로 핸들을 돌리곤 해요





물수건이 기본으로 나오고

기호에 따라 먹을 수 있는 소금과 후추


파와 김치는 항아리채 덜어먹을 수 있는곳을 좋아해요

이런 시스템이 남은음식 재사용 안하는

양심업소를 만든다 생각하거든요

( 손님들이 덜어먹다 남은 음식을 다시 넣어놓는 경우는 없겠죠..???;;; )









옥천관 메뉴판

도가니탕이 메인인데

가격이 착하지는 않아요ㅠ

설렁탕 만원시대를 여는 옥천관

한촌설렁탕, 신선설농탕과 비교하면 가격이 좀 비싸요ㅠ

체인점은 나름 단가를 낮추는 비결이 있겠죠?




사골,국물 국내산 (한우)입니다

이 때문에 단가가 올라갔겠죠?

일단 이 문구를 믿고 먹어봅니다!

( 고기는 호주산, 미국산 으로 적혀있어요. )














보글보글 푹 끓여서 나온 설렁탕이 나왔습니다!


한우사골 설렁탕의 위엄인가

뽀얀 국물 실화?!














설렁탕에는 파를 듬뿍 넣어 파국을 만들어야 제맛이지..훗










안에 들어간 고기와 숨어있는 당면.


개인적으로 설렁탕에는 소면이 좋지만

당면은 당면 나름의 통통튀는 식감이 있어요



과연 맛은?

집에서 하는 것과는 당연히 차이가 있지만

꽤 근접한 맛이라고 생각됩니다.


소금후추간을 하지 않고 먹었을 때

고소한 맛을 느낄 수 있었고

기름이 떠있다고 해서

비릿한 향이나 맛은 없었어요



흔한 체인점은 정형화된 레시피로 되어 있어

항상 평균이상은 하지만

최고점으로 가기엔 2% 부족하다 느끼곤 했거든요.


반대로 일반 가맹점은 모아니면 도인데

옥천관의 설렁탕은 윷 정도로 생각돼요~


가격까지 고려한다면 비슷하지만

더 나은 맛을 제공하기 위한 노력이라

생각한다면 이정도는 지불할 의향이 있습니다!









주차장은 들어가는 길이 매우 좁아

초보운전뿐 아니라 SUV 이상 차량은

조심해서 들어가야 합니다.







맛있는 외식생활 되세요~


- 피땀흘려 일한 월급으로 먹은 후기입니다 -




반응형
블로그 이미지

나남나여

일상 제품리뷰와 맛집/여행/사진을 좋아하고 IT 관련 프로그래밍 초급 & 고급 정보를 공유하는 블로그

,
반응형




부천작동 오리고기 산마루촌 가볼까!





오랜만에 먹으러 가는 오리고기!

오리고기는 집에서 자주 먹는편이지만

밖에서는 자주 안먹었던 것 같다..

어디로 갈까 고민하다가

예전에 갔던 곳 중 작동 오리고기 마을에

안간지 오래된것 같아 그쪽으로 가기로 했어요!





예전에는 골목골목을 통해서 와야 했던 곳이

새로운 길이 뚫리고 나서는 

큰 길 옆에 생기게 되었네요







자리는 매우 넓습니다.

제가 갔던 시간은 오후 3시...


점심시간도 저녁시간도 아닌

아주 애매한 시간으로

사람들이 다 먹고난 그릇들만 남아있었어요..;;

지금은 열심히 정리하는 시간~~








여긴 작은 룸으로 저녁예약이 되어 있었는데

단체로 약 12명까지 들어갈 수 있는 방이네요


큰방은 거의 20명도 들어갈 수 있는 것 같아요


주된 손님들은 50대 단체 손님들이나

가족단위로 오는 손님들이 주 고객이에요~








메뉴


오리고기는 역시 구이죠!


유황 생소금구이 (로그) 라고 써있는걸 주문하지만

양념으로 반반 주문했어요

( 메뉴에 적혀있진 않지만 반반 주문시 만원 추가 됩니다! )









상차림



부추 , 마늘 , 콘샐러드, 김치, 각종 쌈 등

반찬을 두군데로 놔주십니다~

로스 반반을 주문 하면 소금구이가 먼저 나와요~

필요한 반찬은 셀프로 추가해 드시면 됩니다!








생소금구이


오리고기는 자주 뒤집어줘야 안타고 맛있게 구워진다 해서

( 휘적휘적~~치익치익~~ )


오리구이는 기름조차도 안버려지게 하려고

가운데 감자를 눌러놨지만

틈새가 있었는지 기름이 쏙 빠져버렸어요!ㅠㅠ



꽤 쫀득쫀득한 식감으로 나의 배를 채워주는 소금구이!

역시 고기는 구워야 제맛이죠~~








불고기



종이호일을 깔고 양념된 오리고기를 주시는데

개인적으로는 생소금구이가 더 맛있어요







볶음밥



양념을 먹은것은 이 볶음밥을 위해서였다!

라고 말했지만 이내 실망하고 말았다................

그냥 집에서 먹는 김치볶음밥이랑 별반 차이를 못느꼈어요ㅠ










전체적인 평가


가격 : ★★★☆☆

        Total 62,000 원 나왔어요~

        3명이서 먹으면 적당할 줄 알았는데 배부르진 않았어요

        삼겹살을 1인분씩 먹은 느낌이랄까...

        하지만 한 개 더 시키기엔 많은 느낌...중간단계가 없는듯



분위기 : ★★☆☆☆

           여긴 데이트하는 분위기는 아니고 몸보신으로 가는거니깐...

           주 고객층이 40~50대 단체손님이 많은 편인데 단체만 피하면 좋아요!

           오리고기가 기름이 많은 종목이라 바닥이 미끄러울 수 있으니 조심!



서비스 : ★☆☆☆☆

           처음 가게 들어선 순간 테이블에 먹다남은 그릇도 치워지지 않은 상태라

           주문도 안받고 계속 치우기만 하고 종업원..

           손님은 한번 쳐다보고 앉고 싶은 데 앉으라고 하면서

           창가쪽으로 앉으려고 하니 다른데 앉는게 어떠냐는;;;

           처음부터 어디 앉으라고 말을 하시지;;;

           점심때 바빴던건 알겠지만 좋은 서비스를 기대하지는 마시길~

           

           

        

내맘대로 맛 별점 : ★★★☆☆

                        오리고기 좋아해서 집에서 구워도 먹고 다른곳도 여럿 가봤지만

                        보통수준의 오리고기를 생각하면 될 것 같네요

                        



반응형
블로그 이미지

나남나여

일상 제품리뷰와 맛집/여행/사진을 좋아하고 IT 관련 프로그래밍 초급 & 고급 정보를 공유하는 블로그

,
반응형

plsql developer 편의기능집합



sql 툴을 사용할 때

편하게 사용할 수 있는 세팅을

미리 작업해놓거나

편의기능들을 알아두어

개발할 땐 집중해서 일할 수 있는

환경을 만들어놓고자 정리해놓습니다.



#plsql developer 세미콜론 단위로 실행

plsql 실행 시 블럭지정 후 실행해야 하는 불편함이 존재한다.

세미콜론 단위로 실행할 수 있도록 아래 옵션을 체크한다.

Tool > Preferences > preferences > Window Types > SQL Window > AuthSelect statement





#라인번호 표시

Tool > Preferences > preferences > Window Types > SQL Window > Show gutter ( line numbers) 체크





#null 값 색깔 표시

Tool > Preferences > preferences > Window Types > SQL Window > Null value cell color 에서 색 선택





#결과값 색상 번갈아가며 표시하지 않기

Tool > Preferences > preferences > Window Types > SQL Window > Alternate row color 의 Enabled 체크 해제








#sql 결과갯수제한

3가지 옵션이 있는데 주로 Fixed 로 100 정도 설정해놓습니다.

전체 데이터를 확인할 일은 생각보다 많이 없고 필요하면 추가조회하면 됩니다.


Tool > Preferences > preferences > Window Types > SQL Window > Records per Page




#연결 유지

Tool > Preferences > preferences > Oracle > Connection > Check connection 에 체크





#접속정보 저장

Tool > Preferences > preferences > Oracle > Logon History > Definition > Store with password 체크





#sql 실행내역 / sql history / sql 로그 확인

Edit > Recall Statement ( 단축키 Ctrl + E )


반응형
블로그 이미지

나남나여

일상 제품리뷰와 맛집/여행/사진을 좋아하고 IT 관련 프로그래밍 초급 & 고급 정보를 공유하는 블로그

,
반응형

오라클 최근 생성된 테이블, 뷰 확인




시스템운영 또는 프로젝트 진행중

테이블이나 뷰 생성 시

공유하지 않는다면 알 수 없습니다.



테이블 생성시간

테이블 컬럼변경 확인

테이블 변경여부 확인


위의 내용을 ALL_OBJECTS 테이블에서 조회하면

테이블이나 뷰의 신규/변경된 내역을 확인할 수 있습니다.


( DBA_OBJECTS = ALL_OBJECTS )


응용


최근 생성된 테이블 확인


SELECT OWNER
     , OBJECT_NAME
     , SUBOBJECT_NAME
     , OBJECT_TYPE
     , CREATED
     , LAST_DDL_TIME
     , TIMESTAMP
     , STATUS
     , TEMPORARY
  FROM ALL_OBJECTS 
 ORDER BY CREATED DESC ;



[결과]


OWNER

OBJECT_NAME

SUBOBJECT_NAME

OBJECT_TYPE

CREATED

LAST_DDL_TIME

TIMESTAMP

STATUS

TEMPORARY

201102 SP_PARAM_SELECT PROCEDURE 17/11/09 17/11/09 2017-11-09:15:55:54 VALID N
201102

DAILY_SALE

PR_DAILY_SALE_2016

TABLE 17/11/09 17/11/09 2017-11-09:15:49:36 VALID N
201102

JOB_PARA

TABLE 17/11/09 17/11/09 2017-11-09:15:41:59 VALID N





최근 변경된 테이블 확인


SELECT OWNER
     , OBJECT_NAME
     , SUBOBJECT_NAME
     , OBJECT_TYPE
     , CREATED
     , LAST_DDL_TIME
     , TIMESTAMP
     , STATUS
     , TEMPORARY
  FROM ALL_OBJECTS 
 ORDER BY LAST_DDL_TIME DESC ;



[결과]


OWNER

OBJECT_NAME

SUBOBJECT_NAME

OBJECT_TYPE

CREATED

LAST_DDL_TIME

TIMESTAMP

STATUS

TEMPORARY

201102

DAILY_SALE

PR_DAILY_SALE_2016 TABLE 17/11/09 17/11/09 2017-11-09:15:49:36 VALID N
201102

SP_PARAM_SELECT

PROCEDURE 17/11/09 17/11/09 2017-11-09:15:55:54 VALID N
201102

JOB_PARA

TABLE 17/11/09 17/11/09 2017-11-09:15:41:59 VALID N


oracle 11g 기준 ALL_OBJECT column comments



 컬럼명

컬럼 COMMENT 

ONWER

object 의 소유자

OBJECT_NAME

object 이름

SUBOBJECT_NAME

하위 object 이름 ( ex  파티션명 )

OBJECT_ID

object 번호

DATA_OBJECT_ID

data object 번호

OBJECT_TYPE

object 타입 ( table, index, view, function, procedure, partition, index partition 등 )

CREATED

object 생성시간

LAST_DDL_TIME

DDL 문( grant 와 revoke 포함 ) 으로 인한 마지막 수정시간 

TIMESTAMP

view나 package의 정의가 변경된 시간
( ex : 뷰의 컬럼갯수가 변경된 경우 ( view 의 select 문장이 변경되는것과 상관없음) )

TEMPORARY

temporary 객체로 만든 테이블인지 여부
( ex : create temporary table tb_emp ( empno varchar2(10 byte) ) )

GENERATED

object name이 시스템에 의해 생성되었는지 여부

SECONDARY

오라클 데이터 카트리지의 ODCIIndexCreate 메서드에 의해 생성된 부가적인 object인지 여부

NAMESPACE

object 의 네임스페이스

EDITION_NAME

향후 사용을 위한 예약 컬럼




ALL_OBJECTS vs USER_OBJECT 차이


USER_OBJECT : 로그인유저의 객체조회

ALL_OBJECT  : 전체 owner 의 객체조회 ( owner 컬럼을 사용하여 구분가능 )


ALL_OBJECTS view 에 권한이 없다면

USER_OBJECT 로 확인 가능합니다.

반응형
블로그 이미지

나남나여

일상 제품리뷰와 맛집/여행/사진을 좋아하고 IT 관련 프로그래밍 초급 & 고급 정보를 공유하는 블로그

,
반응형

영수증없이환불 ( feat. 홈플러스 n 이마트 )












사건은 지난 금요일 홈플러스에서 저녁을 먹고

밤9시반쯤 장본것 부터였어요..



장을보는데

"세일 세일!! 반값입니다~~~~~~~~"

어디선가 사자후를 외치는 직원분...




포도, 양상추, 다진채소, 샐러드 전부 50%!


'득템이다' 를 외치며

상태좋은것으로 골랐어요!



밤에 마트에서 할인상품을

고르는것도 알뜰쇼핑이죠~












문제의 일요일 저녁...



맛있게 저녁을 먹고

포도를 먹으려는데


우와아아아아아가가아각아아악!!!!!!!!!!!





곰팡이가 몽글몽글 피어있었어요ㅠㅠ











'아이고, 이걸 어쩌나ㅠㅠ 역시 싼게 비지떡이다..'

생각했지만 구매 후 이틀밖에 지나지 않았으니

환불해야지가 먼저 떠올랐어요



하지만 일요일 저녁 이미 문닫는 시간이 되어

다음날 환불하기로 마음먹었죠


( 어느덧 오후 11시 28분.. )








다음날



퇴근 후 차에 영수증을 가지러 갔는데

영수증이 없어요ㅠㅠ




영수증이 없어 환불포기해야되는건가

생각했지만 하나도 못먹은게 너무 억울해집니다.






포기하지 않고 홈플러스 앱을

뒤적뒤적 거리기 시작했어요!!























멤버십이나 한번 눌러볼까......



















응?? 포인트 적립내역 및 영수증 ???? 



영수증 !!!!!!

























오오!!!!!


홈플러스 포인트를 적립했더니 이렇게 앱에 전자영수증이 뙇!!!















잃어버린 영수증을 찾았어요!!!




고객서비스센터에 가서 침착하게

포도구매후 이틀밖에 지나지 않았는데

상태가 이렇게 되어

환불부탁드린다고 말씀드렸더니

친절하게 바로 환불해주셨답니다!


( 신선식품 교환환불은 구매후 7일까지 가능합니다 )




위에서 했던 것 같이

멤버십 > 마이페이지 > 포인트 적립내역 및 영수증

3단계를 거치면 전자영수증을 확인할 수 있습니다!






영수증이 없어서 환불하지 못한 과거는

옛날일이 되어버렸네요~^^







혹시 이마트도 전자영수증이 있나 봤더니

역시 있더라고요













교환 환불 시 영수증 잃어버려서

포기하지 마시고

멤버십 적립했다면

전자영수증이 저장되어 있으니

유용하게 사용하세요^^






+추가로 알게된 사실은

고객서비스센터에서

영수증 재발급 요청해도

다시 찾을 수 있대요^^

단, 포인트 적립했을 때만 가능하겠죠?




반응형
블로그 이미지

나남나여

일상 제품리뷰와 맛집/여행/사진을 좋아하고 IT 관련 프로그래밍 초급 & 고급 정보를 공유하는 블로그

,
반응형