셋팅이 완료되었으니 이제 controller를 만들어봅시다.
src폴더에 openidtest.controller라는 package를 만듭시다.
그리고, OpenIDController클래스를 생성합니다.
OpendIDController.java
[code]
package openidtest.controller;

import java.io.IOException;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.openid4java.OpenIDException;
import org.openid4java.consumer.ConsumerManager;
import org.openid4java.consumer.VerificationResult;
import org.openid4java.discovery.DiscoveryInformation;
import org.openid4java.discovery.Identifier;
import org.openid4java.message.AuthRequest;
import org.openid4java.message.ParameterList;
import org.openid4java.server.RealmVerifier;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

public class OpenIDController
{
private ConsumerManager manager;
   
    @RequestMapping(value="/index.do", method=RequestMethod.GET)
    public String indexGetcontroller(ModelMap model)
    {
        return "index";
    }
   
    @SuppressWarnings("unchecked")
    @RequestMapping(value="/index.do", method=RequestMethod.POST)
    public String indexPostController(String openId, ModelMap model,
            HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException
    {
        try
        {
            manager = new ConsumerManager();
           
            String returnToUrl = "http://localhost:8080/OpenIdTest/verify.do";
           
            List discoveries = manager.discover(openId);
            if (discoveries.size() == 0)
            {
                model.addAttribute("noopenid", openId);
                return "index";
            }
            DiscoveryInformation discovered = manager.associate(discoveries);
            request.getSession().setAttribute("openid-disc", discovered);
            RealmVerifier rv = new RealmVerifier();
            rv.setEnforceRpId(false);
            manager.setRealmVerifier(rv);
            AuthRequest authReq = manager.authenticate(discovered, returnToUrl);
           
            if (!discovered.isVersion2())
            {
                // Option 1: GET HTTP-redirect to the OpenID Provider endpoint
                // The only method supported in OpenID 1.x
                // redirect-URL usually limited ~2048 bytes
                response.sendRedirect(authReq.getDestinationUrl(true));
                return null;
            } else {
                // Option 2: HTML FORM Redirection (Allows payloads >2048 bytes)

                // RequestDispatcher dispatcher =
                // getServletContext().getRequestDispatcher("formredirection.jsp");
                // httpReq.setAttribute("prameterMap",
                // response.getParameterMap());
                // httpReq.setAttribute("destinationUrl",
                // response.getDestinationUrl(false));
                // dispatcher.forward(request, response);
            }
           
        }
        catch (OpenIDException e)
        {
        }
        return null;
        //model.addAttribute("openId", openId);
        //return "index";
    }
   
    @RequestMapping(value="/verify.do", method=RequestMethod.GET)
    public String verifyController(String openId, ModelMap model,
            HttpServletRequest request,
            HttpServletResponse response) throws ServletException
    {
        try
        {
            ParameterList paramList = new ParameterList(request.getParameterMap());
            DiscoveryInformation discovered = (DiscoveryInformation) request
            .getSession().getAttribute("openid-disc");
           
            // extract the receiving URL from the HTTP request
            StringBuffer receivingURL = request.getRequestURL();
            String queryString = request.getQueryString();
            if (queryString != null && queryString.length() > 0)
                receivingURL.append("?").append(request.getQueryString());
           
            // verify the response; ConsumerManager needs to be the same
            // (static) instance used to place the authentication request
            VerificationResult verification = manager.verify(receivingURL.toString(),
                    paramList, discovered);
           
            // examine the verification result and extract the verified
            // identifier
            Identifier verified = verification.getVerifiedId();
            if (verified != null)
            {
                request.getSession()
                    .setAttribute("openid", verified.getIdentifier());
            }
        }
        catch (OpenIDException e)
        {
        }
       
        return "redirect:index.do";
    }
   
    @RequestMapping(value="/logout.do", method=RequestMethod.POST)
    public String logoutController(String openId, ModelMap model,
            HttpServletRequest request,
            HttpServletResponse response) throws ServletException
    {
        request.getSession().removeAttribute("openid");
        return "redirect:index.do";
    }
}
[/code]
WEB-IINF/jsp/index.jsp
[code]
<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title>오픈아이디 테스트</title>
</head>
<body>
<c:choose>
    <c:when test="${sessionScope.openid != null}">
        ${sessionScope.openid}님 환영합니다.
        <form action="logout.do" method="POST">
            <input type="submit" value="로그아웃"/>
        </form>
    </c:when>
    <c:otherwise>
        <form action="index.do" method="POST">
            <input type="text" id="openId" name="openId"/>
            <input type="submit" value="로그인"/>
        </form>
    </c:otherwise>
</c:choose>
<c:if test="${noopenid != null}">
    ${noopenid}는 없는 아이디입니다.
</c:if>
</body>
</html>
[/code]
view페이지에서 아이디를 치고, post요청을 하게 되면 indexPostController메소드가 호출이 됩니다. 여기서는 인증할 수 있는 URL을 redirect하게 됩니다. 그러면 OpenID를 제공하는 Provider에서 인증을 받고, returnURL로 이동을 해서 인증이 되었는지 확인 후 인증이 되면
Identifier verified = verification.getVerifiedId();
에서 Identifier 객체를 받을 수 있는데요. 이곳에서 오픈아이디를 구할 수 있습니다.

아 졸려-_-

 
Posted by 머드초보
,
 
우선 rath님이 올리신 글과 outsider님이 올리신 글을 참조했습니다.
(거의 똑같네-_-)

근데 이상하게 톰캣로그에서는 에러가 막 떨어지는데, 되네요-_-; 좀 더 확인해봐야겠네요 ㅠ

xrath님의 J2EE 환경에서 OpenID 지원 사이트 구축해보기
outsider님의 http://blog.outsider.ne.kr/164 http://blog.outsider.ne.kr/166

테스트환경은 TOMCAT6.0.18 + JDK 6u10 + Spring 2.5.6 입니다.

우선 http://code.sxip.com/ 이곳에서 라이브러리를 받습니다.
이클립스를 열어서 프로젝트를 하나 만듭시다.

Dynamic Web Project로 해서 만듭시다.
OpenIdTest라는 프로젝트로 만듭시다.

WEB-INF/lib에 라이브러리를 복사해야합니다. java-openid-sxip-0.9.4.jar이거 하나만 있으면 되는 줄 알았는데, lib폴더에 있는거 거의 다 필요하더군요-_-;
java-openid-sxip-0.9.4.jar
lib/commons-codec-1.3.jar
lib/commons-httpclient-3.0.1.jar
lib/commons-logging-1.03.jar
lib/htmlparser.jar
lib/openxri-client.jar
lib/openxri-syntax.jar
lib/endorsed/dom3-xercesImpl.jar
lib/endorsed/dom3-xml-apis.jar
lib/endorsed/xalan-2.6.0.jar
lib/xri/xmlsec-1.1.jar

그 외, 스프링과 jstl을 사용하기 위한 라이브러리를 복사합니다.
spring.jar
spring-webmvc.jar
standard.jar
jstl.jar

스프링을 위한 셋팅을 해봅시다.
web.xml파일을 수정합니다.
[code]
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    id="WebApp_ID" version="2.5">
    <display-name>OpenIdTest</display-name>

    <!-- SPRING FRAMEWORK DISPATCHER SERVLET CONFIGURATIONS -->
    <servlet>
        <servlet-name>spring</servlet-name>
        <servlet-class> org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <load-on-startup>2</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>spring</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file>redirect.jsp</welcome-file>
    </welcome-file-list>
</web-app>
[/code]
WebContent밑에 redirect.jsp파일을 생성합니다.
redirect.jsp
[code]
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>OPENID TEST</title>
</head>
<body>
<% response.sendRedirect("index.do"); %>
</body>
</html>
[/code]
WEB-INF 밑에 spring-servlet.xml을 생성합니다.
spring-servlet.xml
[code]
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- ANNOTATION CONTEXT DEFINITION -->
    <context:annotation-config />
    <context:component-scan base-package="openidtest" />
   
    <!-- VIEW RESOLVER CONFIGURATIONS -->
    <bean id="viewResolver"
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
   
</beans>
[/code]
아... 이제 셋팅이 완료되었어요.
다음 글에 계속.....-_-;

 
Posted by 머드초보
,
 
필터링 해야할 일이 생겨서 해봤습니다.

File클래스에는 list()메소드가 2개가 있습니다.
하나는 해당 디렉토리에서 모든 파일 리스트를 리턴하는 메소드입니다.
다른 하나는 필터링을 할 수 있게 FilenameFilter를 파라메터로 받는 list메소드가 있습니다.

두번째 것을 이용해서 원하는 파일을 필터링 할 수 있습니다.

FilenameFilter는 Interface입니다. 그래서 accept메소드를 구현하면 됩니다. 이 메소드에서 true값을 가지게 하는 값만이 String[]으로 반환이 됩니다.

[code]
import java.io.File;
import java.io.FilenameFilter;

public class FileFilterTest {

    public static void main(String[] args)
    {
        File file = new File("D:/");
        String[] list = file.list(new FilenameFilter()
        {
            @Override
            public boolean accept(File dir, String name)
            {
                return name.endsWith(".mp3");
            }
        });
       
        for (int i = 0; i < list.length; i++)
        {
            System.out.println(list[i]);
        }
    }
}
[/code]
[code]
01. War.mp3
01_Be.mp3
01 ) 나를 보낸다.mp3
더 크로스 3집 ['07 The Cross]- 01 Love Song.mp3
[/code]
음.....잘되는군요. 저 accept함수를 잘만 구현하면 원하는 형태로 구현할 수 있는 것 같습니다.

 
Posted by 머드초보
,
 
오늘 아침부터....저녁까지 케삽질을 하고 있었습니다.
제 PC에서는 한글로 잘 나왔는데, 실제 옮겨질 서버(Windows Server 2003)에서 돌리면 한글 부분이 물음표(???)로 나오는 현상이 있었습니다.

삽질하다 안되서 그 윈도우서버2003에 이클립스(Eclipse)를 설치했습니다-_-; 그리고, 소스코드를 옮겨놓으니....디폴트가 CP1252로 소스코드가 되어있어서 한글이 다 깨져서 보이더군요. 분명 한글윈도우서버2003인데 이상하더군요. (CP1252는 영문윈도우 코드페이지라는군요).
그래서 강제로 MS949로 바꾸고, 한글로 고쳤습니다.
그리고, 이클립스에서 실행하는 CONSOLE창에서는 제대로 나오는 겁니다.

하지만, 그 실행파일로 실행을 하면 그대로 한글이 깨집니다-_-;
그래서 생각했습니다. 자바를 실행할 때 뭔가 옵션이있다!
그래서 구글신님께 물어보니 이런 실행방법이 있었습니다.

[code]-Dfile.encoding=MS949[/code]
실행시 인코딩을 정하는 것 같습니다.

[code]
java -Dfile.encoding=MS949 ~~~메인클래스명
[/code]
이렇게 띄우니까 한글이 나오더군요!

젠장 하루종일 삽질했네-_-;

 
Posted by 머드초보
,
 
전시간에 이어서.....
이걸 좀 수정해봅시다.

우선 List를 받으려면 idx, 제목, 글쓴이의 정보가 필요합니다. 하지만, 기본적인 RESTful 웹서비스를 생성하게 되면 idx밖에 반환하지 않습니다. 이걸 고쳐봅시다.

boarddb.converter패키지에 WsboardsConverter클래스가 있습니다.
클래스 위에 XmlRootElement(name = "wsboards")라는 것이 붙어있습니다. 그렇습니다. 클래스형태가 바로 애노테이션 하나로 xml이 되버립니다-_-;(동작원리는 잘 모르겠네요-_-)
현재 데이터를 이런 식으로 반환합니다.
[code]<wsboards uri="http://localhost:9080/BoardWS2/resources/wsboards/">
    <wsboardRef uri="http://localhost:9080/BoardWS2/resources/wsboards/33/">
        <idx>33</idx>
    </wsboardRef>
[/code]
여기에 subject와 writer를 추가해봅시다.
wsboardRef쪽에다가 추가를 해야하니, WsboardRefConverter클래스를 봅시다.
@XmlRootElement(name = "wsboardRef")가 붙어있습니다. @XmlElement애노테이션을 붙이면 Element를 생성할 수 있습니다.
[code]@XmlElement
public String getWriter() {
    return entity.getWriter();
}
@XmlElement
public String getSubject() {
    return entity.getSubject();
}
[/code]
이렇게 2개를 추가했습니다. 그리고 게시판은 최근글이 마지막에 보여야하므로 쿼리를 수정합니다.
WsboardsResource클래스의 getEntities메소드를 봅시다.
쿼리를 아래와같이 수정합니다.
[code]SELECT e FROM Wsboard e ORDER BY e.idx DESC"[/code]
다시 테스트를 해봅시다.
이제 이렇게 나올겁니다.
[code]<wsboardRef uri="http://localhost:9080/BoardWS2/resources/wsboards/33/">
      <idx>33</idx>
      <subject>111</subject>
    <writer>11</writer>
</wsboardRef>[/code]
와우 List는 이제 구현이 다되었습니다-_-;

List를 가져올 때 총 게시물을 뽑아서 나중에 페이징을 할 때 사용해야합니다. 총게시물을 구하는 쿼리는
[code]SELECT count(e) FROM Wsboard e[/code]
이렇게 하면 되더군요.
그럼 WsboardsResource.java파일의 @GET부분을 다음과 같이 바꿉시다.
[code]try {
    Long count = (Long)PersistenceService.getInstance().createQuery("SELECT count(e) FROM Wsboard e").getSingleResult();
    return new WsboardsConverter(getEntities(start, max), context.getAbsolutePath(), count);
} finally {
    PersistenceService.getInstance().close();
}
[/code]
카운트값을 xml에 표기를 해야하니 WsboardsConverter를 수정해야겠죠?
[code]
private Long count; // 추가
public WsboardsConverter(Collection<Wsboard> entities, URI uri, Long count) {
        this.entities = entities;
        this.uri = uri;
        this.count = count;
    }
[/code]
count변수를 추가하고, 생성자를 저렇게 생성하도록 바꿉니다.
속성값으로 count를 추가해야겠죠?
[code]
@XmlAttribute(name = "count")
    public String getCount() {
        return count.toString();
    }
[/code]

이제 1개데이터 가져오기를 구현해봅시다. 사실.....이건 다 되어있군요. Test RESTful Web Service에서 {idx}에서 해당 idx를 넣고 Test눌렀을 때 정상적으로 나오면 된겁니다 ^^

이제 DELETE와 MODIFY 2개가 남았습니다.
DELETE를 구현하기 위해서는 db에 저장된 비밀번호와 입력한 비밀번호의 비교를 위해서 비밀번호를 받는 것을 하나 추가합시다. 저는 그냥 경로에 추가했습니다. 보안상 매우 안좋지만...-_-; 어떻게 하는지 몰라서-_-;

WsboardsResource.java파일에서 @Path("{idx}/") -> @Path("{idx}/{pwd}")로 바꿨습니다.
그리고, 1개의 PathParam을 받았던 것을 pwd도 받게 바꿨습니다. 그리고 WsboardResource클래스에 pwd를 추가하고, 생성자를 수정했습니다.

WsboardsResource.java파일
[code]@Path("{idx}/{pwd}")
public WsboardResource getWsboardResource(@PathParam("idx")
Integer id, @PathParam("pwd") String pwd) {  
    return new WsboardResource(id, pwd, context);
}
[/code]
WsboardResource.java파일
[code]private String pwd; //추가
public WsboardResource(Integer id, String pwd, UriInfo context) {
    this.id = id;
    this.pwd = pwd;
    this.context = context;
} // 생성자 수정
[/code]
이제 /wsboards/{idx}/{pwd}로 요청하면 idx와 pwd를 받을 수 있습니다.

DELETE를 수정해봅시다.
[code]@DELETE
public Response delete() {
    PersistenceService persistenceSvc = PersistenceService.getInstance();
    try {
        Wsboard entity = getEntity();
        if (entity.getPwd().equals(pwd)) {               
            persistenceSvc.beginTx();
            persistenceSvc.removeEntity(entity);
            persistenceSvc.commitTx();
            return Response.ok("success").build();
        }
    } finally {
        persistenceSvc.close();
    }
    return Response.ok("fail").build();
}
[/code]
간단합니다. 받은 pwd랑 현재 입력된 pwd랑 같은지 확인 후에 맞으면 지우고 success를 리턴하고, 틀리면 fail을 리턴합니다. 테스트를 해볼 수 있는데요. 한번 지워보시면
[code]Delete failed: Server returned --> Status: (200) Response: {success}
[/code]저는 이런 메시지를 받습니다. Delete failed라고 뜨는데요. 그래도 success라는 응답을 받고 db에서 보면 지워졌을 겁니다. 보면 DELETE는 뭔가 리턴을 하면 안되는 듯 합니다. 암튼...잘 되니...-_-;

이제 PUT을 수정해봅시다.
[code]@PUT
@ConsumeMime({"application/xml", "application/json"})
public Response put(WsboardConverter data) {
    PersistenceService persistenceSvc = PersistenceService.getInstance();
    try {
        Wsboard entity = getEntity();
        if (entity.getPwd().equals(pwd)) {
            persistenceSvc.beginTx();
            updateEntity(getEntity(), data.getEntity());
            persistenceSvc.commitTx();
            return Response.ok("success").build();
        }
    } finally {
        persistenceSvc.close();
    }
    return Response.ok("fail").build();
}
[/code]
이것도 그냥 pwd랑 같으면 수정시키고 success를 리턴하고, 틀리면 수정 안시키고 fail을 리턴합니다.
테스트해봅시다.
테스트할 때 주의사항이....xml로 데이터를 던져야 하는데요. idx빼고 모든 값이 다 들어가야합니다.
PUT으로 맞춰놓고, idx랑 pwd를 쓴 다음 content란에 이렇게 씁니다.
[code]<wsboard>
<pwd>1</pwd>
<writer>11</writer>
<subject>22</subject>
<content>33</content>
</wsboard>
[/code]
idx빼고 다 넣어야합니다. 그러면 업데이트가 됩니다.

아....다 됐네요. 아.....POST로 글쓰는 것을 빼먹고 안했는데요. 그냥 위처럼 XML로 넘겨주기만 하면 돼요 ^^
flex로 게시판 만드는 것도 해야하는데, 졸려서 내일로.....-_-;

내일은 선테크데이2008가야지-_-;

[JAVA] netbeans 초간단 게시판을 위한 RESTful WebService를 만들어봅시다-_-; (1)


[Flex/AIR] RESTful을 이용한 Web Service 게시판 클라이언트.

 
Posted by 머드초보
,