달력

02

« 2012/02 »

  •  
  •  
  •  
  • 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
  •  
  •  
  •  
div 안에 텍스트를 수평중앙정렬하기 위해서는 text-align:center; 스타일을 주면 된다.
div 안에 텍스트를 수직중앙정렬을 하려면 vertical-align:middle; 스타일을 주면 될 것 같지만, 되지 않는다.
div 가 아닌 테이블의 경우 자동으로 수직으로도 정렬이 된다.
div 에서 수직으로 중앙정렬하기 위해서는 스타일에 display:table-cell; 속성을 주면 된다.

<div style="height:300px;text-align:right;display:table-cell;vertical-align:middle;">로그인 | 회원가입</div>

하지만 IE에서는 8.0 이상부터 위의 속성이 적용된다.
꼼수로는 div 의 height 값을 line-height 값과 동일하게 주면 된다.

<div style="height:300px;text-align:right;line-height:300px;">로그인 | 회원가입</div>


저작자 표시
Posted by 에드몽단테스
String cpath = new File(request.getServletPath()).getParent();
String localPath = application.getRealPath(cpath);
out.println(localPath);

저작자 표시
TAG jsp
Posted by 에드몽단테스
--skip-extended-insert

위의 옵션대로 하면 된다.

# mysqldump -u아이디 --skip-extended-insert  디비 테이블 > 파일명
저작자 표시
TAG MySQL
Posted by 에드몽단테스
RHEL 클론판인 CentOS를 사용중이다.

레드햇 계열의 배포판에선 SELinux가 기본으로 깔리니 서버데몬 세팅시 여기저기서 문제가 발생된다.

막 요래 ㅋㅋ

Forbidden

You don't have permission to access / on this server.

Additionally, a 403 Forbidden error was encountered while trying to use
an ErrorDocument to handle the request.


위와같은 문제 발생시 아래처럼 손보면 된다.

매번 까먹기에 포스팅을.

# setenforce 1
# cd /home/svrmngr
# ls -Z


     drwx------ svrmngr svrmngr user_u:object_r:user_home_dir_t    web


# chcon -R -t httpd_user_content_t web
# ls -Z


     drwx------ svrmngr svrmngr user_u:object_r:httpd_user_content_t web


# chmod -R 755 web


chron은 change contexts을 의미한다. 보안과 관련된 추가적인 속성이라 보면 된다.

출처 : http://todayis.net/vSix/index.php?pl=756
저작자 표시
Posted by 에드몽단테스
function twitter(url,msg) {
 var href = "http://twitter.com/home?status=" + encodeURIComponent(msg) + " " + encodeURIComponent(url);
 var a = window.open(href, 'twitter', '');
 if ( a ) {
  a.focus();
 }
 return false;
}

function facebook(url,msg) {
 var href = "http://www.facebook.com/sharer.php?u=" + url + "&t=" + encodeURIComponent(msg);
 var a = window.open(href, 'facebook', '');
 if ( a ) {
  a.focus();
 }
  return false;
}

function me2day(url,msg){
    var href = "http://me2day.net/posts/new?new_post[body]=" + url + "&new_post[tags]" + encodeURIComponent(msg);
    var a = window.open(href, 'Me2Day', '');
    if ( a ) {
     a.focus();
    }
     return false;
 }


호출 방법은 아래와 같다.

<a href="#twitter" onclick="return twitter(location.href, '제목');" alt="트위터에 글쓰기">트위터</a>


url은 사이트의 주소를 넣어주고, msg 에는 글에 추가될 제목등을 넣어준다.
저작자 표시
Posted by 에드몽단테스
2011/06/01 00:58

게시판 페이징 만들기 개발2011/06/01 00:58

게시판 페이징을 구성할 때 클래스로 미리 만들어 놓고 간단하게 호출해서 사용하곤 했는데, 그렇게 쓰다 보니 점차 불편한 점이 보였다.

  1. 페이징을 클래스로 만들다 보니 적용후에는 웹서버를 재시작할 필요가 생겼다. 개발서버라면 크게 문제가 되지 않지만 실서버일 경우 함부로 서버를 내릴 수 없다.
  2. 디자인을 포함하다보니 디자인을 수정하기가 쉽지 않다.

그래서 jsp로 재편을 했다. 다른 라이브러리를 사용할 수 없는 경우가 있을 수도 있어서 JSTL은 사용하지 않았다.

페이징을 구성하기 위해서는 우선 게시물의 총 갯수를 알아야 한다. 그래서 페이지를 나눌 수 있다.
한 페이지에 표시할 목록의 갯수가 필요하고, 페이지를 이동할 수 있도록 현재 페이지 번호가 필요하다.
또 검색을 포함한 경우 페이지를 이동했을때 검색어에 대한 정보도 필요하다.
페이지가 너무 많으면 단락별로 이동이 가능하도록 한 단락에 표시할 수 있는 페이지의 갯수도 필요하다.

[페이징을 위한 변수선언]
<%
String tmpPage = request.getParameter("pageNum");
int pageNum = tmpPage == null || tmpPage.equals("") ? 1 : Integer.parseInt(tmpPage);
int listRow = 10;
int pageRow = 10;
String link = "";

String keyword = request.getParameter("keyword");
String search = request.getParameter("search");
HashMap<String, Object> param = new HashMap<String, Object>();

if(keyword != null && !keyword.equals("")){
    param.put("keyword", keyword);
    link = "&amp;keyword="+keyword;
}
if(search != null && !search.equals("")){
    param.put("search", search);
    link = "&amp;search="+search;
}
param.put("offset", (pageNum-1) * listRow);
param.put("limit", listRow);
List memberList = mManager.getMemberList(param);
int total = mManager.getMemberListCount(param);
%>


[페이징 구현부분]
<%
        int page_total = (int)Math.ceil((float)total/listRow);
       
        StringBuilder sb_page = new StringBuilder();
        String uri = request.getRequestURI();
       
        int co = (int)((float)pageNum/pageRow);
        if((pageNum % pageRow) != 0)
            co++;
       
        int start_page = ((co-1) * pageRow) + 1;
        int end_page = start_page + pageRow - 1;
       
        // 맨처음
        sb_page.append("<a href=\""+uri+"?pageNum=1"+link+"\" >첫페이지</a>");
       
        // 이전단락
        if(pageNum > pageRow){
            int pre = end_page - pageRow;
            sb_page.append("&nbsp;<a href=\""+uri+"?pageNum="+pre+link+"\" class='prev'>이전단락</a>");
        }
       
        // 페이지
        if(page_total < end_page)
            end_page = page_total;
       
        for(int i = start_page; i <= end_page; i++){
            if(i == pageNum){
                sb_page.append("&nbsp;<span style=\"color:red;\">"+i+"</span>");
            }
            else{
                sb_page.append("&nbsp;<a href=\""+uri+"?pageNum="+i+link+"\" class='page_type'>"+i+"</a>");
            }
           
            // 마지막 페이지에는 페이지 구분문자('|')를 붙이지 않는다.
            if(i != end_page){
                //sb_page.append(" | ");
            }
        }
       
        // 다음단락
        if(end_page < page_total){
            int next = end_page+1;
            sb_page.append("&nbsp;<a href=\""+uri+"?pageNum="+next+link+"\" class='prev'>다음단락</a>");
        }
       
        // 맨마지막
        sb_page.append("&nbsp;<a href=\""+uri+"?pageNum="+page_total+link+"\" >마지막페이지</a>");
       
        // 페이징이 필요한 경우에만 표시
        if(start_page <= end_page){
            out.println(sb_page.toString());
        }
%>

mysql 경우  limit 쿼리를 이용해 페이징을 분리할 수 있는데,
분리가 되는 오프셋은 (pageNum-1) * listRow 로 구할 수 있다.
즉, 현재 페이지가 1이면 오프셋은 0이 되고 1페이지이면 오프셋이 listRow가 된다.

저작자 표시
Posted by 에드몽단테스
2011/05/31 20:32

Timer 를 이용한 스케쥴 관리 개발2011/05/31 20:32

정기적인 호출이 필요한 경우 스케쥴관리를 위해 Timer 클래스를 이용한다.
이를 이용하면 리눅스의 crontab 효과를 낼 수 있다.

import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class UpdateSNS extends TimerTask{
    private URL url = null;
    private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
   
    public void run(){
        try{
            url = new URL("*****************");
            HttpURLConnection conn = (HttpURLConnection)url.openConnection();
            int code = conn.getResponseCode();
            conn.disconnect();
            conn = null;
            System.out.println(sdf.format(new Date())+" => "+code);
        }catch(Exception e){
            e.printStackTrace();
        }
    }
   
    public static void main(String[] args) throws Exception{
        UpdateSNS up = new UpdateSNS();
        Timer timer = new Timer();
       
        // 20분마다 호출
        timer.schedule(up, 0, 1000 * 60 * 20);
//        try{
//            Thread.sleep(5000);
//        }catch(Exception e){
//            e.printStackTrace();
//        }
//        timer.cancel();
    }
}

스케쥴관리를 위해서 Timer 객체를 만들고 schedule() 를 호출한다.
실제로 호출될 작업은 TimerTask 를 상속받아 run() 메소드에 오버라이드 시킨다.
파라메터로는 처음 시작시간과 주기적으로 실행할 시간을 적는다.
위의 예에서는 프로그램이 시작하자마자 스케쥴이 시작되고 20분마다 재호출된다.
스케쥴을 멈추기 위해서는 cancel() 함수를 호출한다.
위에서는 멈추지 않고 계속 호출하도록 하였기 때문에 주석처리하였다.

저작자 표시
TAG java, Timer
Posted by 에드몽단테스
2011/05/24 01:14

스크립트로 트위터 불러오기 개발2011/05/24 01:14

며칠전 트위터 api를 이용하여 블로그 혹은 홈페이지에 붙이는 작업을 적은 적이 있는데, 개인은 그런 경우가 없겠지만 공공기관이나 혹은 보안을 요하는 곳에서는 외부로 연결되는 모든 연결을 막아놓는다는 것을 알았다.
외부에서 들어오는 것 뿐만 아니라 외부로 나가는 것 포함해서 심지어는 80포트도 말이다.

서버에서 외부로 연결할 수 없다면 소켓이나 기타 연결함수 등은 사용할 수 없다는 얘기다.
방법을 생각해보다가 그러면 스크립트로 외부 api 를 호출해서 사용하면 되지 않을까? 라는 생각을 했다.
서버 프로그래밍이 아니니 막힐 일도 없고 말이다.
하지만, 이내 불가능하다는 것을 알았다.

스크립트로 ajax를 이용하여 외부의 api를 호출하니 동작을 하지 않았다.
생각을 해보니 그럴수도 있겠다는 생각이 들었다. 바로 '크로스도메인'.
스크립트로는 크로스도메인 때문에 open api 라 할지라도 호출할 수 없다.
그래서 다시 방법을 모색했다.

<script type="text/javascript">
//<![CDATA[
function twitterCallback2(twitters) {
  var max = twitters.length;
  for (var i=0; i<twitters.length; i++){
    var screen_name = twitters[i].user.screen_name;
    var name = twitters[i].user.name;
    var profile_image_url = twitters[i].user.profile_image_url;
    var status = twitters[i].text.replace(/((https?|s?ftp|ssh)\:\/\/[^"\s\<\>]*[^.,;'">\:\s\<\>\)\]\!])/g, function(url) {
      return '<a href="'+url+'">'+url+'</a>';
    }).replace(/\B@([_a-z0-9]+)/ig, function(reply) {
      return  reply.charAt(0)+'<a href="http://twitter.com/'+reply.substring(1)+'">'+reply.substring(1)+'</a>';
    });
    //if(status.indexOf('@') == -1) continue;
        document.getElementById('status_txt'+k).innerHTML = status;
        document.getElementById('status_time'+k).innerHTML = relative_time(twitters[i].created_at);
  }
}

function relative_time(time_value) {
  var values = time_value.split(" ");
  time_value = values[1] + " " + values[2] + ", " + values[5] + " " + values[3];
  var parsed_date = Date.parse(time_value);
  var relative_to = (arguments.length > 1) ? arguments[1] : new Date();
  var delta = parseInt((relative_to.getTime() - parsed_date) / 1000);
  delta = delta + (relative_to.getTimezoneOffset() * 60);

  if (delta < 60) {
    return '1분미만';
  } else if(delta < 120) {
    return '약1분전';
  } else if(delta < (60*60)) {
    return (parseInt(delta / 60)).toString() + '분전';
  } else if(delta < (120*60)) {
    return '약1시간전';
  } else if(delta < (24*60*60)) {
    return (parseInt(delta / 3600)).toString() + '시간전';
  } else if(delta < (48*60*60)) {
    return '약하루전';
  } else {
    return (parseInt(delta / 86400)).toString() + '일전';
  }
}
//]]>
</script>

<script type="text/javascript" src="http://twitter.com/statuses/user_timeline/admongdantes.json?callback=twitterCallback2&count=10"></script>


완전한 소스는 아니지만, 트위터의 스크립트를 이용하여 특정의 위치에 트윗내용을 불러올 수 있다.
이렇게 하면 서버에 영향을 받지 않고 스크립트 만으로도 트윗을 불러오는 것이 가능하다.

이론상으로는 완벽하고 실제 테스트했을 때도 완벽했다.
하지만, 실 서버에서는 트윗내용을 불러오지 못하는 경우가 발생했다.
아예 못불러오는 것은 아니고 불러오지 못하는 경우가 불러오는 경우보다 휠씬 많았다.(즉, 불안정해서 사용할 수 없었다.)

원인은 콜백함수인 twitterCallback2를 호출하지 못해서인데, 이유를 찾을 수 없었다. 늦게라도 호출이 되면 좋은데, 아예 호출을 하지 못했다. 스크립트 오류도 없었다. 그냥 되지 않았다. 난감하다.
네트워크 지연일까? 그렇다면 해결방법은 무엇일까? 클라이언트에게는 뭐라고 설명하지?


==================================
콜백함수가 호출되지 않았던 이유는 보안상 포트가 막혀있었다.
모든 포트가 막혀있던 것은 아니었기 때문에, 일부는 되고 또 일부는 되지 않았다.


'개발' 카테고리의 다른 글

게시판 페이징 만들기  (0) 2011/06/01
Timer 를 이용한 스케쥴 관리  (0) 2011/05/31
스크립트로 트위터 불러오기  (0) 2011/05/24
트위터 api를 이용하여 트윗목록 확인하기  (4) 2011/05/16
JDOM을 이용한 RSS 파싱  (0) 2011/05/07
php iconv 함수  (0) 2011/04/13
Posted by 에드몽단테스
갑작스레 트위터의 글을 홈페이지에 붙이는 작업이 생겼다.
그래서 부랴부랴 api를 찾아보는데 언어에서 막히고 사용방법에서 막히고 어디가 어떤건지도 모르겠고...
한참을 고생하다 겨우 필요한 api를 찾을 수 있었다.
다행이도 인증을 거치지 않고 아이디만 입력하면 작성한 글 및 멘션까지도 보여준다.
접근성을 고려하여 스크립트로 하지 않고 jsp로 직접 작성하였다. 작업할 서버의 상태를 모르기 때문에 라이브러리는 사용하지 않도록 하였다. 순수 jsp 코드다.

<%@ page import="java.io.*"%>
<%@ page import="java.net.*"%>
<%@ page import="java.util.*"%>
<%@ page import="java.util.regex.*"%>
<%@ page import="org.w3c.dom.*"%>
<%@ page import="org.xml.sax.InputSource"%>
<%@ page import="javax.xml.parsers.*"%>
<%
final String apiurl = "http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=admongdantes";
final int max_count = 10;

String[][] info = null;
HttpURLConnection conn = null;
int max = 0;
int k = 0;
try{  
    URL url = new URL(apiurl);
    conn = (HttpURLConnection) url.openConnection();
    conn.setRequestProperty("accept-language","ko");
  
    DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    byte[] bytes = new byte[4096];
    InputStream in = conn.getInputStream();
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    while(true){
        int red = in.read(bytes);
        if(red < 0)
            break;
        baos.write(bytes, 0, red);
    }
    String xmlData = baos.toString("euc-kr");
    baos.close();
    in.close();
    conn.disconnect();
  
    Document doc = docBuilder.parse(new InputSource(new StringReader(xmlData)));
    Element el = (Element)doc.getElementsByTagName("statuses").item(0);
  
    max = el.getChildNodes().getLength();
    info = new String[max][];
    String reg = "(http:\\/\\/\\w+\\.\\w+(\\.\\w+)?(\\.\\w+)?/\\w+)";
    for(int i=0; i<max; i++){
        Node node = el.getChildNodes().item(i);
        if(!node.getNodeName().equals("status")){
            continue;
        }
        if(k >= max_count) break;
        Element el2 = (Element)node;
        String text = el2.getElementsByTagName("text").item(0).getFirstChild().getNodeValue();
        String created_at = el2.getElementsByTagName("created_at").item(0).getFirstChild().getNodeValue();
       
        Element el3 = (Element)(el2.getElementsByTagName("user").item(0));
        String name = el3.getElementsByTagName("name").item(0).getFirstChild().getNodeValue();
        String screen_name = el3.getElementsByTagName("screen_name").item(0).getFirstChild().getNodeValue();
        String profile_image_url = el3.getElementsByTagName("profile_image_url").item(0).getFirstChild().getNodeValue();
        Date date = new Date(created_at);
       
        Pattern p = Pattern.compile(reg);
        Matcher m = p.matcher(text);
        if(m.find()){
            text = text.replaceAll(reg, "<a href='"+m.group(1)+"' target='_blank'>"+m.group(1)+"</a>");
        }
        long cha = (System.currentTimeMillis() - date.getTime())/1000;
        String ago = "";
        if(cha < 60) {
            ago = "1분전";
        }
        else if(cha < 3600){
            ago = (cha / 60)+"분전";
        }
        else if(cha < 86400){
            ago = (cha / 60 / 60)+"시간전";
        }
        else{
            ago = (cha / 60 / 60 / 24)+"일전";
        }
        info[i] = new String[]{text,name,screen_name,profile_image_url,ago};
        k++;
    }
}catch(Exception e){
    e.printStackTrace();
}finally{
    try{if(conn != null) conn.disconnect(); } catch(Exception e){}
}
 %>
 
 <%if(k > 0){%>
 
<table border="1" width="100%">
 <%for(int i=0; i<max; i++){
     if(info[i] == null) continue;
 %>
 <tr>
     <td><img src="<%=info[i][3]%>" alt="" /></td>
     <td><%=info[i][1]%>&nbsp;<%=info[i][2]%><br /><%=info[i][0]%><br /><%=info[i][4]%></td>
 </tr>
 <%}%>
 </table>
 <%}else{%>
 <p>트래픽 초과로 잠시 데이터를 가져올 수 없습니다.</p>
 <%}%>

트윗내용에 링크가 있는 경우에는 그냥 표시하기에는 밋밋해서 하이퍼링크를 걸었다.
또 작성된 시간을 파악하여 현재시간을 기준으로 얼마나 시간이 지났는지도 표시하였다.

'개발' 카테고리의 다른 글

Timer 를 이용한 스케쥴 관리  (0) 2011/05/31
스크립트로 트위터 불러오기  (0) 2011/05/24
트위터 api를 이용하여 트윗목록 확인하기  (4) 2011/05/16
JDOM을 이용한 RSS 파싱  (0) 2011/05/07
php iconv 함수  (0) 2011/04/13
배너 스크립트  (0) 2011/04/08
Posted by 에드몽단테스
2011/05/07 09:22

JDOM을 이용한 RSS 파싱 개발2011/05/07 09:22

관심이 있는 블로그의 RSS를 한 곳으로 몰아서 볼 수 있도록 페이지를 구성했다.
왜냐하면 그런 RSS리더 프로그램들은 많이 있지만, 내 손으로 만들어 보고 싶기도 했고, 또 한 번 만들어 놓으면 다르게 유용하게 쓰일 수 있을 것 같아서였다.
하지만, 문제는 RSS파싱이이었다.

자바에는 기본적으로 XML을 파싱할 수 있는 라이브러리를 제공해주고 있다.
지금까지 그 라이브러리를 사용했었고, 또 문제가 된적도 없었다. 하지만 이번에 여러 블로그를 파싱하려고 보니 특정 블로그에서 파싱이 잘 되지 않는 문제가 발생했다. 원인은 아직도 잘 모른다. 검색의 신도 잘 알려주지 않았다.
그래서 예전에 본 JDOM을 찾아보기로 했다. 사용해 본적은 없지만 많은 사람들이 JDOM을 사용하고 있다는 것은 이미 알고 있었다. 그래서 자료를 찾아봤다.

아래는 JDOM을 이용하여 XML(RSS)을 파싱하는 간단한 예이다.

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.xml.sax.InputSource;

public List<RssPost>parseRss(String rssURL){
        URL url = null;
        ArrayList<RssPost> rssList = new ArrayList<RssPost>();
        try{
            SAXBuilder parser = new SAXBuilder();
            parser.setValidation(false);
            parser.setIgnoringElementContentWhitespace(true);
            url = new URL(rssURL);
            InputSource is = new InputSource(url.openStream());
            doc = parser.build(is);
           
            Element root = doc.getRootElement();
            Element channel = root.getChild("channel");
            List list = channel.getChildren("item");
            Element title = channel.getChild("title");
            String blog_title = title.getText();
           
            for(int i=0; i<list.size(); i++){
                Element el = (Element)list.get(i);
                String item_title = el.getChildText("title");
                String item_link = el.getChildText("link");
                String item_pubDate = el.getChildText("pubDate");
               
                RssPost post = new RssPost();
                post.setAddress(item_link);
                post.setBlogname(blog_title);
                post.setTitle(item_title);
                post.setWdate(item_pubDate);
                post.setRsslink(rssURL);
                rssList.add(post);
            }
        }catch(Exception e){
            e.printStackTrace();
        }
        return rssList;
    }

자바에서 기본적으로 제공해주는 것보다 간결하고 코드도 깔끔하다.
다음은 이 라이브러리를 가지고 만든 RSS 모음 사이트이다.

http://dantes98.cafe24.com/main/rssPostList.dan

문제는 각각의 블로그를 읽어 내용을 파싱하고 내 디비에 넣어야 하는데, 주기적으로 할 수 없다는 것이다.
cafe24에 호스팅을 받고 있는데, cron을 지원을 하고 있지 않다.
rss 업데이트 할 수 있는 페이지를 별도로 만들어 놓았지만, 직접 호출해야 한다. ㅡㅡ;
다른 방법을 찾아 보아야 겠다.

JDOM은 이곳에서 자세한 내용을 확인할 수 있다.


'개발' 카테고리의 다른 글

스크립트로 트위터 불러오기  (0) 2011/05/24
트위터 api를 이용하여 트윗목록 확인하기  (4) 2011/05/16
JDOM을 이용한 RSS 파싱  (0) 2011/05/07
php iconv 함수  (0) 2011/04/13
배너 스크립트  (0) 2011/04/08
뉴스기사 스크롤 자바스크립트  (0) 2011/04/01
TAG jdom, rss
Posted by 에드몽단테스