CORS란

CORS란 도메인 또는 포트가 다른 서버의 자원을 요청하는 매커니즘을 말합니다. 이때 요청을 할때는 corss-origin HTTP에 의해 요청됩니다.


이때 요청을 할때는 cross-origin HTTP에 의해 요청됩니다.


하지만 동일 출처 정책 때문에 CORS 상황이 발생시에 요청한 데이터를 브라우저에서 보안목적으로 차단합니다. 해당 문제를 해결하는 가장 쉬운 방법은 같은 도메인을 사용하는 것입니다. 하지만 요즘에는 각기 다른 용도로 사용되는 경우에는 개별 서버를 구축하기 때문에 이는 해결책이 될수 없습니다.


다른 해결방법은 서버에서 CORS 효청을 허용해주면 됩니다. 서버로 들어오는 모든 요청에 대해서 CORS 요청을 허용하기 위해서 Filter를 이용합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
public class CORSFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;

response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
response.setHeader("Access-Control-Allow-Origin", "3600");
response.setHeader("Access-Control-Allow-Origin", "x-auth-token, x-requested-with, origin, content-type, accept, sid");

chain.doFilter(req, res);
}
}
1
2
3
4
5
6
7
8
<filter>
<filter-name>cors</filter-name>
<filter-class>kr.co.spring.filter.SimpleCORSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>cors</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Access-Control-Allow-Methods

POST, PUT, DELETE 등 허용할 ACCESS METHOD를 설정할수 있습니다.

Access-Control-Max-Age

HTTP Request 요청에 앞서 Preflight Request 라는 요청이 발생되는데, 이는 해당 서버에 요청하는 메소드가 실행 가능한지(권한 여부) 확인을 위한 요청입니다. Preflight Reuqest는 OPTIONS 메소드를 통해 서버에 전달됩니다(Allow-Methods 설정에서 OPTIONS를 허용해야 합니다).


Access-Control-Max-Age는 Preflight Request를 캐시할 시간입니다. 단위는 초입니다. 캐시를 하게 된다면 해당 시간이 지난 뒤에 재 요청을 하게 됩니다.

Access-Control-Allow-Origin

허용할 도메인을 설정할수 있습니다. 값은 *로 설정하면 모든 도메인에서 허용하는 것이고, 특정 도메인만 설정할수 있습니다.

Comment and share

Spring-Test

스프링은 Junit을 이용하는 테스트 컨텍스트 프레임워크를 제공한다. 이를 이용하면 어노테이션을 이용하여 간편하게 컨텍스트를 사용할수 있다. 해당 방법이 없이 Bean을 사용하려면 직접 ApplicationContext를 생성하는 번거로운 작업을 진행하여야 하나 이로 인해 편하게 작업을 진행 할수 있다.

@ContextConfiguration

Comment and share

DataSourceUtils

in java, api

DataSource

DataSource는 ConnectionPool을 관리하기 위한 목적으로 사용되는 객체로 DataSource를 통해서 Connection을 얻어오고 반납하는 등의 작업을 구현합니다. ConnectionPool에는 여러개의 Connection 객체가 생성되어 운용되는데, 이를 직접 웹 어플리케이션에서 다루기 힘들기 때문에 DataSource라는 개념이 도입되었습니다.

DataSourceUtils

DataSourceUtils 클래스는 JNDI에서 연결을 얻고 필요한 경우 연결을 닫는 메소드를 제공하는 기능을 제공 합니다. 그리고 DataSourceTransactionManager로 쓰레드에 기반한 연결을 지원합니다.

DataSourceUtils에서 제공하는 메소드

getConnection(DataSource dataSource)

getConnection메소드는 제공 된 DataSource를 기반으로 하여 Connection을 생성해줍니다. Connection 생성은 트랜잭션 동기화 여부에 따라 다르게 작동합니다. 만약 트랜잭션 동기화가 활성화 되어 있다면 Connection을 생성하고 트랜잭션 저장소에 바인딩 합니다. 이후 트랜잭션 동기화 작업을 종료 할때까지 getConnection메소드를 호출하면 동일한 Connection을 반환하는 것을 확인할수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
public class DataSourceUtilsTest {
@Autowired
DataSource dataSource;

public void testGetConnection() {
TransactionSynchronizationManager.initSynchronization();

Connection conn1 = DataSourceUtils.getConnection(dataSource);
Connection conn2 = DataSourceUtils.getConnection(dataSource);

System.out.println("동일한 인스턴스 인가요? " + conn1.equals(conn2));
}
}

트랜잭션이 동기화되어 있지 않을 경우에는 dataSource.getConnection()과 동일하게 작동합니다. 그래서 항상 새로운 Connection을 반환합니다.

1
2
3
4
5
6
7
8
9
10
11
public class DataSourceUtilsTest {
@Autowired
DataSource dataSource;

public void testGetConnection() {
Connection conn1 = DataSourceUtils.getConnection(dataSource);
Connection conn2 = DataSourceUtils.getConnection(dataSource);

System.out.println("동일한 인스턴스 인가요? " + conn1.equals(conn2));
}
}

releaseConnection(Connection conn, DataSource dataSource)

releaseConnection메소드 또한 getConnection와 비슷하게 동작 합니다. 만약 트랜잭션 동기화가 활성화 되어 있다면 트랜잭션 저장소에서 Connection을 초기화 합니다. 이때 Connection의 연결은 종료하지 않습니다. 그리고 release 후 다시 getConnection으로 Connection을 받아왔을때 동일한 값이라는 것을 확인 할수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class DataSourceUtilsTest {
@Autowired
DataSource dataSource;

public void testGetConnection() {
TransactionSynchronizationManager.initSynchronization();

Connection conn = DataSourceUtils.getConnection(dataSource);

DataSourceUtils.releaseConnection(conn, dataSource);
System.out.println("Connection이 종료 되었니? " + conn.isClosed());

Connection conn2 = DataSourceUtils.getConnection(dataSource);

System.out.println("동일한 Connection 인가요? " + conn.equals(conn2));
}
}

위와 같이 releaseConnection 메소드를 호출 하더라도 Connection은 종료되지 않는다. 단지 트랜잭션에서만 제거되었을 뿐이다. 이 때문에 사용시 주의할 필요가 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class DataSourceUtilsTest {
@Autowired
DataSource dataSource;

public void testGetConnection() {
TransactionSynchronizationManager.initSynchronization();

Connection conn = DataSourceUtils.getConnection(dataSource);

System.out.println("트랜잭션 저장소에 저장 중인가? " + DataSourceUtils.isConnectionTransactional(conn, dataSource));

DataSourceUtils.releaseConnection(conn, dataSource);

TransactionSynchronizationManager.unbindResource(dataSource);
TransactionSynchronizationManager.clearSynchronization();

System.out.println("Connection이 종료 되었니? " + conn.isClosed());
System.out.println("트랜잭션 저장소에 저장 중인가? " + DataSourceUtils.isConnectionTransactional(conn, dataSource));
}
}

결론

DataSourceUtils를 사용하면 동기화된 트랜잭션의 Connection을 가져와서 사용하기에 좋다. 하지만 releaseConnection은 Connection을 종료해주는 기능이 아니므로 사용시에 주의할 필요가 있다.

트랜잭션 동기화 상태가 아닌 Connection이라면 releaseConnection메소드를 호출하면 close 해준다.

Comment and share

JSON파일 출력(파일 작성)

소스코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public void writeJSON() {
String jsonString = "json파일에 저장할 내용",
path = "C:/json/",
fileName = "jsonTest.json";

FileWriter fileWriter = null;

File dirFile = new File(path),
fullFile = new File(path + fileName);

if (!dirFile.exists()) {
dirFile.mkdirs();
}

try {
fileWriter = new FileWriter(fullFile);
fileWriter.write(jsonString);
fileWriter.flush();
} catch(Exception e) {

} finally {
fileWriter.close();
}
}

설명

json파일을 작성하는 것은 기타 다른 파일을 작성하는 것과 별반 차이가 없다. 예제에서는 일반 string문자열을 저장하고 있지만 실제 JSON 데이터를 저장할 때도 JSONData를 JSONString으로 변환후에 저장하면 된다.

JSON파일 호출

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import com.google.gson.Gson;

public void readJSON() {
String path = "C:/json/",
fileName = "jsonTest.json";

JsonParser jsonParser = new JsonParser();

FileReader fileReader = null;

File file = new File(path + fileName);

if (file.isFile()) {
throw new Exception("존재하지 않는 파일입니다.");
}

try {
fileReader = new FileReader(file); // 1. FileReader 인스턴스를 생성합니다.

Object resultObj = gson.fromJson(fileReader, Object.class); // gson의 fromJson메서드의 첫번째 파라미터로는 Reader를 두번째 파라미터로는 Json 데이터 타입을 넘겨주면 된다.

// Map map = (Map) gson.fromJson(fileReader, Object.class); // 타입을 Object로 하고 casting 가능
// Map map = gson.fromJson(fileReader, Map.class); // 타입을 바로 Map으로 해서 casting 없이 사용 가능
} catch(Exception e) {

} finally {
fileReader.close();
}
}

설명

해당 소스코드는 구글에서 제공하는 Gson을 이용해서 parse를 한다. Gson의 fromJson은 첫번째 파라미터로 Reader와 두번째 파라미터로 데이터 타입을 받는다. 두번째 파라미터로 Object.class를 넘겨주니 모든 데이터 타입(원시 타입 포함)의 값을 오류없이 가져올수 있었다.

gson.fromJson(Reader, Type) : JSON 파일로 부터 데이터 가져오기
gson.fromJson(String, type) : JSONString 으로부터 각 데이터 타입으로 변환

Comment and share

1. json 출력

1
2
3
4
5
6
7
8
9
10
11
Map<String, Object> map = new HashMap<String, Object>();
map.put("id", "아이언맨");
map.put("name", "어벤저스");

Gson gson = new Gson();

String path = "C:\\test\\test1.json";

BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path), "UTF-8"));
writer.write(gson.toJson(map, Map.class));
writer.close();

2. json 입력

1
2
3
4
5
6
7
8
9
Gson gson = new Gson();

String path = "C:\\test\\test1.json";

BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(path), "UTF-8"));

Map<String, Object> map = gson.fromJson(reader, Map.class);

System.out.println(map);

json의 입력은 Gson을 사용하면 간편하게 처리할수 있다

Comment and share

1. 텍스트 파일 출력

1
2
3
4
5
6
7
8
9
10
String path = "./test.txt",
text = "안녕하세요\n"
+ "어서오세요\n"
+ "인사합니다";

BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream(path), "UTF-8"));

writer.write(text);
writer.close();

2. 텍스트 파일 입력

1
2
3
4
5
6
7
8
9
10
11
String path = "./test.txt",
str = "";

StringBuilder sb = new StringBuilder();

BufferedReader reader = new BufferedReader(
new InputStreamReader(new FileInputStream(path), "UTF-8"));

while((str = reader.readLine()) != null) {
sb.append(str);
}

FileReader/FileWriter는 인코딩 설정이 불가능 하므로 FileInputStream/FileOuputStream을 쓰자
많은 양의 데이터를 입출력 할시에 Buffer를 쓰는것과 안 쓰는것의 차이가 크다 => 버퍼를 쓰자
InputStream/OutputStream은 단위가 바이트단위라서 한글이 깨지므로 InputStreamReader/OutputStreamReader를 쓰자

Comment and share

1. 리스트의 메서드

.retainAll(Collection)

List와 Collection에서 중복되는 값만 남기고 모두 삭제한다. 결과는 바로 List에 적용 된다

1
2
3
4
5
6
7
8
9
10
11
12
List list1 = new ArrayList();
List list2 = new ArrayList();

list1.add("아이언맨");
list1.add("헐크");

list2.add("아이언맨");
list2.add("윈터솔져");

list1.retainAll(list2);

System.out.println(list1); // [아이언맨]

.removeAll()

List와 Collection에서 중복되는 내용을 모두 삭제한다. 결과는 바로 List에 적용 된다

1
2
3
4
5
6
7
8
9
10
11
12
List list1 = new ArrayList();
List list2 = new ArrayList();

list1.add("아이언맨");
list1.add("헐크");

list2.add("아이언맨");
list2.add("윈터솔져");

list1.removeAll(list2);

System.out.println(list1); // [헐크]

2. List와 Array 변환

List => Array로 변환

1
2
3
List<String> list = new ArrayList<String>();

String[] array = list.toArray();

Array => List로 변환

이건 배열 자체적인 기능은 제공하지 않아서 배열 util인 Arrays의 asList메서드를 활용한다

1
2
3
String[] array = new String[3];

List<String> list = Arrays.asList(array);

Comment and share

  • page 1 of 1

Moon Star

author.bio


author.job