팡이네

마이플랫폼에서 Base64 이미지 문자열을 이미지 컴포넌트에 표시하고자 할 때

java 단에서 먼저 해당 컬럼을  DB에서 조회한 다음 일반적인 DRRecordSet으로 반환하면

String 데이터 컬럼으로 변환되어 이미지 컴포넌트에 표시하지 못한다.


그래서 DRRecordSet을 새로 생성하여 해당 컬럼을 BLOB로 만들어서 반환하면

이미지 컴포넌트에서 이미지를 제대로 표시할 수 있다.


DSRecordSet rs = DB에서 조회한 목록


DSRecordSet rs2 = new DSRecordSet();

rs2.addColumn("base64Image", ColumnInfo.CY_COLINFO_BLOB, -1);


for (int i = 0; i < rs.getRowCount(); i++) {

int row = rs2.appendRow();

String imageData = rs.getColumn(row, "base64Image").toString();

rs2.setColumn(row, "base64Image", Base64.decode(imageData.getBytes()));

}


생성한 rs2를 반환한다.


이후 마이플랫폼에서 원하는 이미지 컴포넌트에 표시한다.


imgPhoto.ImageID = ds.GetColumn(nRow, 'base64Image');


단, 여기서 주의할 점은 이미지 컴포넌트 imgPhoto의 ImageID 값은 항상 null 이다.

그래서 if (imgPhoto.ImageID != '')와 같은 구문은 항상 거짓이 된다.


그리고 이미지 컴포넌트의 이미지를 지우거나 초기화할 경우 빈문자열 대신 null을 이용한다. imgPhoto.ImageID = null

Angular에서 localhost Web API를 호출할 때 아래와 같은 오류가 발생할 경우


http failure response for (unknown url) 0 unknown error


You’ve run afoul of the Same Origin Policy – it says that every AJAX request must match the exact hostprotocol, and port of your site. Things that might cause this:

서버측에 CORS(Cross-Orgion Resource Sharing) Header를 추가해준다.

그 외 방법은 아래 링크를 참조한다.

https://daveceddia.com/access-control-allow-origin-cors-errors-in-angular/

https://stackoverflow.com/questions/29024313/asp-net-webapi2-enable-cors-not-working-with-aspnet-webapi-cors-5-2-3


I just added custom headers to the Web.config and it worked like a charm.

On configuration - system.webServer:

<httpProtocol>   <customHeaders>     <add name="Access-Control-Allow-Origin" value="*" />     <add name="Access-Control-Allow-Headers" value="Content-Type" />   </customHeaders> </httpProtocol>


UbiReport에서 다단 설정을 할 경우 그룹 제목 부분 역시 다단으로 표시되어 이상한 보고서가 출력되는데 아래와 같이 마스터 서브 형태로 설정하면 깔끔한 보고서를 만들 수 있다.


1. 마스터 데이터 컴포넌트 추가

1.1 Group 데이터 컴포넌트 추가

1.1 마스터 데이터 컴포넌트 SQL 설정

1.2 그룹 편집 들어가서 그룹 추가 (GROUP_A) 한 뒤 마스터와 서브를 연결할 컬럼을 선택

1.3 GROUP_A Header 밴드를 아래와 같이 설정해준다.

그룹 옵션 > 그룹밴드 반복 체크

그룹 옵션 > 그룹별 페이지 생성 체크



2. GROUP_A Footer 밴드를 아래와 같이 설정한다.

2.1 컴포넌트 옵션 > 포함된 데이터 컴포넌트 크기 확장 체크


3. 페이지 마다 표시될 그룹 헤더 디자인

3.1 확인을 위해 전체 페이지 및 그룹별 페이지 출력 표시

page(), totalpage()

grouppage('A'), grouptotalpage('A')


4. GROUP_A Footer 밴드에 서브 데이터 컴포넌트 추가

4.1 단순한 N-up 형태의 데이터 컴포넌트 추가


5. 서브 데이터 컴포넌트 설정

5.1 단 개수와 진행방향을 설정해준다.


6. 마스터 데이터 컴포넌트와 서브 데이터 컴포넌트를 연결

6.1 서브 데이터 컴포넌트를 클릭하여 컴포넌트 탭의 SQL 결합 버튼 클릭한다.

6.2 마스터와 서브를 연결하는 컬럼을 추가한다.


7. 미리보기

7.1 전체 페이지가 17 페이지이며 그룹 1의 페이지는 4페이지

7.2 그룹1의 멤버들이 표시된다.


알프레스코 웹스크립트를 이용한 사이트 생성

/**
 * 사이트를 생성한다.
 * @param siteName		사이트명(빈칸, 특수문자 불가)
 * @param title			사이트 제목
 * @param description	사이트 설명
 * @param visibility	공개유형(PUBLIC/PRIVATE/MODERATED)
 * @return
 */
public boolean createSite(String siteName, String title, String description, String visibility)
{
	String doLoginUrl = ALFRESCO_SERVER_URL +"/share/page/dologin";
	String dashboardUrl = ALFRESCO_SERVER_URL +"/share/page/user/admin/dashboard";
	String createSiteUrl = ALFRESCO_SERVER_URL +"/share/service/modules/create-site";
	
	CloseableHttpClient client = getHttpClient();
	
	try
	{
		List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
		params.add(new BasicNameValuePair("username", ALFRESCO_ADMIN_ID));
		params.add(new BasicNameValuePair("password", ALFRESCO_ADMIN_PASS));
	
		HttpPost loginPost = new HttpPost(doLoginUrl);
		loginPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
		loginPost.setEntity(new UrlEncodedFormEntity(params));
		
		CloseableHttpResponse response = client.execute(loginPost);

		try
		{
			StatusLine statusLine = response.getStatusLine();
			
			//알프레스코는 로그인 후 Share 페이지로 이동하기 때문에
			//getStatusCode() 리턴값이 SC_OK가 아니라 SC_MOVED_TEMPORARILY
			if (statusLine.getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY)
			{
				org.apache.http.Header[] headers = loginPost.getAllHeaders();

				String JSESSIONID = "";
				String alfUsername3 = "";
				String alfLogin = "";
				
				//---------------------------------------
				//로그인 쿠키값 추출
				//---------------------------------------
				for (int i = 0; i < headers.length; i++)
				{
					Integer idxJsession = headers[i].toString().indexOf("JSESSIONID=");
					if (idxJsession > -1)
					{
						JSESSIONID = headers[i].toString().substring(idxJsession +11, idxJsession +11 +32);
					}
					
					Integer idxAlfUsername3 = headers[i].toString().indexOf("alfUsername3=");
					if (idxAlfUsername3 > -1)
					{
						alfUsername3 = headers[i].toString().substring(idxAlfUsername3 +13, idxAlfUsername3 +13 +5);
					}
					
					Integer idxAlfLogin = headers[i].toString().indexOf("alfLogin=");
					if (idxAlfLogin > -1)
					{
						alfLogin = headers[i].toString().substring(idxAlfLogin +9, idxAlfLogin +9 +10);
					}
				}
				
				//---------------------------------------
				//데시보드
				//---------------------------------------
				String cookie = "JSESSIONID="+ JSESSIONID +";"
						+ "alfLogin="+ alfLogin +";"
						+ "alfUsername3="+ alfUsername3 +";";
				
				HttpGet dashboadrGet = new HttpGet(dashboardUrl);
				dashboadrGet.setHeader("Content-Type", "application/json");
				dashboadrGet.setHeader("Accept", "application/json");
				dashboadrGet.setHeader("Cookie", cookie);
				
				CloseableHttpResponse response2 = client.execute(dashboadrGet);
				
				try
				{
					StatusLine statusLine2 = response2.getStatusLine();
					if (statusLine2.getStatusCode() == HttpStatus.SC_OK)
					{
						org.apache.http.Header[] headers2 = dashboadrGet.getAllHeaders();
						
						String csrfToken = "";
					
						for (int i = 0; i < headers2.length; i++)
						{
							Integer idxCsrfToken = headers2[i].toString().indexOf("Alfresco-CSRFToken=");
							if (idxCsrfToken > -1)
							{
								csrfToken = headers2[i].toString().substring(idxCsrfToken +19, idxCsrfToken +19 +50);
							}
						}
						
						//---------------------------------------
						//사이트 생성
						//---------------------------------------
						String cookie2 = cookie +" Alfresco-CSRFToken="+ csrfToken +";";
						
						JSONObject site = new JSONObject();
						site.put("shortName", siteName);
						site.put("sitePreset", "site-dashboard");
						site.put("title", title);
						site.put("description", description);
						site.put("visibility", visibility);

						HttpPost createSitePost = new HttpPost(createSiteUrl);
						createSitePost.setHeader("Content-Type", "application/json");
						createSitePost.setHeader("Accept", "application/json");
						createSitePost.setHeader("Cookie", cookie2);
						createSitePost.setEntity(new StringEntity(site.toString(), ContentType.create("text/plain", Consts.UTF_8)));
						
						CloseableHttpResponse response3 = client.execute(createSitePost);
						
						try
						{
							StatusLine statusLine3 = response3.getStatusLine();
							if (statusLine3.getStatusCode() == HttpStatus.SC_OK)
							{
								logger.info(String.format("★★★ %s Site Created!!!★★★", siteName));
								return true;
							}
							else
							{
								logger.error("Method failed createSitePost: "+ response3.getStatusLine());
							}
						}
						catch (Exception e)
						{
							logger.error(e.getMessage());
						}
						finally
						{
							response3.close();
						}
					}
					else
					{
						logger.error("Method failed dashboadrGet: "+ response2.getStatusLine());
					}
				}
				catch (Exception e)
				{
					logger.error(e.getMessage());
				}
				finally
				{
					response2.close();
				}
			}
			else
			{
				logger.error("Method failed loginPost: "+ response.getStatusLine());
			}
		}
		catch (Exception e)
		{
			logger.error(e.getMessage());
		}
		finally
		{
			response.close();
		}
	}
	catch (Exception e)
	{
		logger.error(e.getMessage());
	}
	
	return false;
}

사이트 정보 조회

public HashMap getSite(CloseableHttpClient client, String siteName)
{
	HttpGet method = null;
	
	try
	{
		//	/alfresco/s/api/sites/{shortname}
		String url = String.format("%s/api/sites/%s", ALFRESCO_SERVER_SVC, siteName);
		method = new HttpGet(url);
		
		CloseableHttpResponse response = client.execute(method);
		
		try
		{
			StatusLine statusLine = response.getStatusLine();
			
			if (statusLine.getStatusCode() == HttpStatus.SC_OK)
			{
				return createResponse(response);
			}
			else
			{
				logger.error(statusLine.getStatusCode() +" "+ statusLine.getReasonPhrase());
			}
		}
		finally
		{
			response.close();
		}
	}
	catch (Exception e)
	{
		e.printStackTrace();
	}
	finally
	{
		method.releaseConnection();
	}
	
	return null;
}

사이트 존재여부

/**
 * 사이트 존재여부
 * @param client
 * @param siteName	사이트명
 * @return
 */
public boolean existSite(CloseableHttpClient client, String siteName)
{
	return (this.getSite(client, siteName) != null);
}

JSON 데이터 변환

/**
 * 서버 반환 데이터를 HashMap으로 변환한다.
 * @param response
 * @return
 */
private HashMap createResponse(CloseableHttpResponse response)
{
	try
	{
		HttpEntity entity = response.getEntity();
		
		if (entity != null)
		{
			InputStream instream = entity.getContent();
			
			try
			{
				return createResponse(instream);
			}
			finally
			{
				instream.close();
			}
		}
	}
	catch (Exception e)
	{
		e.printStackTrace();
	}
	
	return null;
}

Alfresco Share Login 페이지에서 CSRF 필터 오류 해결법 2가지


알프레스코 5.0 버전으로 오면서 보안이 강화되어 기존 방법으로 CSRF 토큰값을 설정해도
오류가 발생한다. 아래 페이지에서 그 오류에 대한 해결법을 2가지 제시한다.


2번째 해법 - CSRF Token Filter 비활성


알프레스코의 아래 설정 파일에서 “CSRFPolicy” 설정 부분의 주석을 해제한다.

TOMCAT_HOME/shared/classes/alfresco/web-extension/share-config-custom.xml


<!-- Disable the CSRF Token Filter -->
<!--
<config evaluator="string-compare" condition="CSRFPolicy" replace="true">
<filter/>
</config>
-->


ComponentOne의 FlexGrid에서 Cell에 이미지 버튼을 표현하는 방법
아래의 방법은 일종의 이미지 버튼을 흉내내는 방법이다.

//이벤트 핸들러 추가
grdMain.MouseMove += new MouseEventHandler(grdMain_MouseMove);
grdMain.MouseDown += new MouseEventHandler(grdMain_MouseDown);

//커서 변경
private void grdMain_MouseMove(object sender, MouseEventArgs e)
{
	if (grdMain.MouseRow > 0)
	{
		if (grdMain.MouseCol == grdMain.Cols["ViewInfo"].Index)
			this.Cursor = Cursors.Hand;
		else
			this.Cursor = Cursors.Default;
	}
}

//마우스 클릭
private void grdMain_MouseDown(object sender, MouseEventArgs e)
{
	if (grdMain.MouseRow > 0)
	{
		if (grdMain.MouseCol == grdMain.Cols["ViewInfo"].Index)
		{
			Row row = grdMain.Rows[grdMain.MouseRow];
			string seqNo = row["SeqNo"].ToString();

			ViewInfo(seqNo);
		}
	}
}

//그리드 바인딩 후 아래와 같은 방법으로 이미지를 표시한다.
//전체 Row에 같은 이미지를 표시하고자 할 경우 아래와 같이 구현한다.
private void LoadCellImage()
{
	Hashtable ht = new Hashtable();
	ht.Add("", 특정 이미지);
	Column LinkCol = grdMain.Cols["ViewInfo"];
	LinkCol.ImageMap = ht;
	LinkCol.ImageAndText = false;
	LinkCol.ImageAlign = ImageAlignEnum.CenterCenter;
}

//해당 Row의 상태에 따라 다른 이미지를 표시하려면 아래의 메소드처럼 구현한다.
private void LoadCellImage()
{
	Hashtable ht = new Hashtable();

	//그리드 제목이 있을 경우 grdMain.Rows.Fixed부터 처리
	for (int i = grdMain.Rows.Fixed; i < grdMain.Rows.Count; i++)
	{
		Row row = grdMain.Rows[i];
		if (row["Exist"].ToString() == "Y")
		{
			ht.Add(row["SeqNo"].ToString(), 특정 이미지1);
		}
		else
		{
			ht.Add(row["SeqNo"].ToString(), 특정 이미지2);
		}
	}

	Column LinkCol = grdMain.Cols["SeqNo"];
	LinkCol.ImageMap = ht;
	LinkCol.ImageAndText = false;
	LinkCol.ImageAlign = ImageAlignEnum.CenterCenter;
}