'ITWeb/개발일반'에 해당되는 글 489건

  1. 2012.03.12 2. Spring MVC 에 MyBatis 적용해 보기. 2
  2. 2012.03.09 [링크공유] mybatis + spring from 구글.
  3. 2012.03.09 [링크공유] Spring MVC tutorial
  4. 2012.03.09 [기초] Spring MVC 구성해 보기.
  5. 2012.03.08 Spring Framework MVC + MyBatis Empty 설정 맛보기.
  6. 2012.03.08 Spring Framework 설정관련 기초.
  7. 2012.03.06 VIM no indent 설정.
  8. 2012.03.06 java classpath setting
  9. 2012.03.05 Spring Security Role 정의
  10. 2012.03.05 [펌] 2장 Intecept와 Granted Authority

2. Spring MVC 에 MyBatis 적용해 보기.

ITWeb/개발일반 2012. 3. 12. 10:36
Spring + Mybatis 연동은 sts 와 mybatis 문서를 기반으로 작성 하였습니다.

[소스코드]

- Eclipse import 하시면 프로젝트 확인 가능 합니다.


※ import/export 방법은 아래 글 참고하세요.
http://jjeong.tistory.com/564 


1. Spring MVC 구성해 보기.
2. Spring MVC 에 MyBatis 적용해 보기.
3. Spring MVC 에 Spring Security 적용해 보기. 
4. Spring MVC 에 Hibernate 적용해 보기. 
5. 2+3번 적용해 보기.
6. 3+4번 적용해 보기. 


- 소스코드를 첨부 하였으므로 요약 정보만 기술 합니다.

[pom.xml]

<!-- spring framework jdbc 설정 -->

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>spring-jdbc</artifactId>

            <version>${org.springframework-version}</version>

        </dependency>


<!-- mysql -->

        <dependency>

            <groupId>mysql</groupId>

            <artifactId>mysql-connector-java</artifactId>

            <version>5.1.18</version>

        </dependency>


<!-- mybatis -->

        <dependency>

            <groupId>org.mybatis</groupId>

            <artifactId>mybatis</artifactId>

            <version>3.0.6</version>

        </dependency>


<!-- mybatis spring -->

        <dependency>

            <groupId>org.mybatis</groupId>

            <artifactId>mybatis-spring</artifactId>

            <version>1.0.2</version>

        </dependency>


<!-- apache commons dbcp-->

        <dependency>

            <groupId>commons-dbcp</groupId>

            <artifactId>commons-dbcp</artifactId>

            <version>1.2.2</version>

        </dependency> 

- pom.xml 에서는 필요한 package depedency 를 작성해 줍니다.


[web.xml]

  <context-param>

    <param-name>contextConfigLocation</param-name>

    <param-value>

        /WEB-INF/spring/root-context.xml

        classpath:context/**/applicationContext*.xml

        </param-value>

  </context-param>

- spring framework 이 처음 로딩 될때 읽어 들여야 하는 설정파일들에 대한 path 를 잡아 줍니다.


[applicationContext-mybatis.xml]

    <bean id="propertyPlaceholderConfigurer"

        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">

        <property name="locations">

            <value>classpath:configuration/mybatis/config.properties</value>

        </property>

    </bean>


    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"

        destroy-method="close">

        <property name="driverClassName" value="${jdbc.driverClassName}" />

        <property name="url" value="${jdbc.url}" />

        <property name="username" value="${jdbc.username}" />

        <property name="password" value="${jdbc.password}" />

    </bean>



<!-- http://groups.google.com/group/ksug/browse_thread/thread/766cd1fd8ba39c96 -->

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

        <property name="dataSource" ref="dataSource" />

        <property name="mapperLocations" value="classpath*:sql/mybatis/mapper/**/*.xml" />

    </bean>
.... 중략

    <bean id="boardContentViewDAO" class="proto.board.dao.BoardContentViewDAOImpl">

        <property name="sqlSession" ref="sqlSession" />

    </bean> 

- dbcp 설정과 dao 에서 사용할 sqlSession 설정을 합니다.


[board.xml]

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE mapper

    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"

    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="proto.board.mapper">


    <select id="getBoardContentView" resultType="proto.board.domain.BoardContentVO">

    SELECT

        document_srl,

        title,

        content,

        user_id,

        nick_name,

        email_address,

        regdate

    FROM

        xedemodb.xe_documents

    WHERE

        document_srl=66

    </select>

</mapper>

- 사용한 테이블은 xpressengine 이 설치 되면 기본 생성되는 xe_documents 의 테이블 입니다.
- 기본 CRUD 에 대한 내용은 mybatis 문서를 참고 하시면 아주 쉽습니다.



[config.properties]

jdbc.driverClassName=com.mysql.jdbc.Driver

jdbc.url=jdbc:mysql://localhost:3306/xedemodb?autoReconnect=true

jdbc.username=root

jdbc.password=1234

※ jdbc url structure 참고

- 각자 접속 정보에 맞게 설정 하시면 됩니다.


[Class Flow - 초간단버전임]

http://localhost:8080/board/boardContentView

[BoardContentViewController.java]

    @Autowired

    private BoardContentViewService boardContentViewService;
    ...
    boardContentViewService.getBoardContentVO() 


[BoardContentViewServiceImpl.java]
- BoardContentViewService.java 는 interface 이므로 구현체인 BoardContentViewServiceImpl.java 확인

    @Autowired

    private BoardContentViewDAO boardContentViewDAO;


    public BoardContentVO getBoardContentVO() {

        return (BoardContentVO)boardContentViewDAO.getBoardContentVO();

    }

 

[BoardContentViewDAOImpl.java]
- BoardContentViewDAO.java 는 interface 이므로 구현체인 BoardContentViewDAOImpl.java 확인

    private SqlSession sqlSession;


    public void setSqlSession(SqlSession sqlSession) {

        this.sqlSession = sqlSession;

    }


    public BoardContentVO getBoardContentVO() {

        //boardContentVO.setContent("CONTENT");

        return (BoardContentVO) sqlSession.selectOne("proto.board.mapper.getBoardContentView");

    }


[board.xml]

<mapper namespace="proto.board.mapper">

    <select id="getBoardContentView" resultType="proto.board.domain.BoardContentVO">

    SELECT

        document_srl,

        title,

        content,

        user_id,

        nick_name,

        email_address,

        regdate

    FROM

        xedemodb.xe_documents

    WHERE

        document_srl=66

    </select>

</mapper>


[BoardContentViewVO.java]

public class BoardContentVO {

    private int documentSrl;

    private String title;

    private String content;

    private String nickname;

    private String email;

    private String regdate;


    public int getDocumentSrl() {

        return documentSrl;

    }

.... 중략

    public void setRegdate(String regdate) {

        this.regdate = regdate;

    }

}



자, 그럼 여기까지 아주 초간단 spring framework 과 mybatis 를 이용해서 SELECT 하는 것 까지 테스트 해봤습니다.
완전 기초 이니, 걍 참고만 하세요..
:

[링크공유] mybatis + spring from 구글.

ITWeb/개발일반 2012. 3. 9. 18:10
일단 시간이 부족한 관계로 링크만 오픈.

http://code.google.com/p/mybatis/wiki/Spring

[원본글]

Introduction to MyBatis-Spring

MyBatis-Spring helps you integrate your MyBatis code seamlessly with Spring. Using the classes in this library, Spring will load the necessary MyBatis factory and session classes for you. This library also provides an easy way to inject MyBatis data mappers into your service beans. Finally, MyBatis-Spring will handle transactions and translate MyBatis exceptions into Spring DataAccessExceptions.

Quick Setup

To use MyBatis with Spring you need at least two things defined in the Spring application context: an SqlSessionFactory and at least one data mapper class. In MyBatis-Spring, an SqlSessionFactoryBean is used to create an SqlSessionFactory. To configure the factory bean, put the following in the Spring XML configuration file:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
 
<property name="dataSource" ref="dataSource" />
</bean>

Notice that the SqlSessionFactory requires a DataSource. This can be any DataSource and should be configured just like any other Spring database connection.

Assume you have a data mapper class defined like the following:

public interface UserMapper {
 
@Select("SELECT * FROM user WHERE id = #{userId}")
 
User getUser(@Param("userId") String userId);
}

This interface is added to Spring using a MapperFactoryBean like the following:

<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
 
<property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" />
 
<property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>

Note that the mapper class specified must be an interface, not an actual implementation class. In this example, annotations are used to specify the SQL, but a MyBatis mapper XML file could also be used.

Once configured, you can inject mappers directly into your business/service objects in the same way you inject any other Spring bean. The MapperFactoryBean handles creating an SqlSession as well as closing it. If there is a Spring transaction in progress, the session will also be committed or rolled back when the transaction completes. Finally, any exceptions will be translated into Spring DataAccessExceptions.

Calling MyBatis data methods is now only one line of code:

public class FooServiceImpl implements FooService {

   
private UserMapper userMapper;

   
public void setUserMapper(UserMapper userMapper) {
       
this.userMapper = userMapper;
   
}

   
public User doSomeBusinessStuff(String userId) {
       
return this.userMapper.getUser(userId);
   
}

}

More info?

Download the pdf manual. You can find it in downloads. http://code.google.com/p/mybatis/downloads/list?can=3&q=Product%3DSpring

And have a look at JPetStore 6 that is built on top of MyBatis, Spring and Stripes: http://code.google.com/p/mybatis/downloads/list?can=3&q=Product%3DSample

Installation

MyBatis-Spring code and detailed documentation is available at the downloads section.

To use the MyBatis-Spring module, you just need to include the mybatis-spring jar file and its dependencies in the classpath.

If you are using Maven just add the following dependency to your pom.xml:

<dependency>
 
<groupId>org.mybatis</groupId>
 
<artifactId>mybatis-spring</artifactId>
 
<version>1.0.2</version>
</dependency>


 
:

[링크공유] Spring MVC tutorial

ITWeb/개발일반 2012. 3. 9. 14:34
Spring MVC 관련해서 발견한 괜찮은 사이트

※ 좋고 나쁨의 차이는 개인의 needs 에 따라 다르니 판단은 각자.. ㅎㅎ
- 삽질의 해결 실마리를 제공해준 사이트라 올려 봅니다. ㅋㅋ 
:

[기초] Spring MVC 구성해 보기.

ITWeb/개발일반 2012. 3. 9. 14:24
기냥 기초 부터 다시 작성해 보려 한다.

1. Spring MVC 구성해 보기.
2. Spring MVC 에 MyBatis 적용해 보기.
3. Spring MVC 에 Spring Security 적용해 보기. 
4. Spring MVC 에 Hibernate 적용해 보기. 
5. 2+3번 적용해 보기.
6. 3+4번 적용해 보기. 



[준비물]

- SpringSourceTool Suite 에서 Spring Project Template 중 MVC 로 기본 프로젝트 생성.
- 괜히 노가다 한다고 시간 빼지 말자.
- Eclipse 또는 STS
- JDK 1.6
- Maven
- Tomcat 

 

[pom.xml]
- 내가 가지고 있던 sts 버전땜시 spring framework 버전을 수정함. (3.0.6 -> 3.1.0)

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>proto.ncms</groupId>

    <artifactId>board</artifactId>

    <name>board</name>

    <packaging>war</packaging>

    <version>1.0.0-BUILD-SNAPSHOT</version>

    <properties>

        <java-version>1.6</java-version>

        <org.springframework-version>3.1.0.RELEASE</org.springframework-version>

        <org.aspectj-version>1.6.9</org.aspectj-version>

        <org.slf4j-version>1.5.10</org.slf4j-version>

    </properties>

    <dependencies>

        <!-- Spring -->

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>spring-context</artifactId>

            <version>${org.springframework-version}</version>

            <exclusions>

                <!-- Exclude Commons Logging in favor of SLF4j -->

                <exclusion>

                    <groupId>commons-logging</groupId>

                    <artifactId>commons-logging</artifactId>

                 </exclusion>

            </exclusions>

        </dependency>

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>spring-webmvc</artifactId>

            <version>${org.springframework-version}</version>

        </dependency>


        <!-- AspectJ -->

        <dependency>

            <groupId>org.aspectj</groupId>

            <artifactId>aspectjrt</artifactId>

            <version>${org.aspectj-version}</version>

        </dependency>


        <!-- Logging -->

        <dependency>

            <groupId>org.slf4j</groupId>

            <artifactId>slf4j-api</artifactId>

            <version>${org.slf4j-version}</version>

        </dependency>

        <dependency>

            <groupId>org.slf4j</groupId>

            <artifactId>jcl-over-slf4j</artifactId>

            <version>${org.slf4j-version}</version>

            <scope>runtime</scope>

        </dependency>

        <dependency>

            <groupId>org.slf4j</groupId>

            <artifactId>slf4j-log4j12</artifactId>

            <version>${org.slf4j-version}</version>

            <scope>runtime</scope>

        </dependency>

        <dependency>

            <groupId>log4j</groupId>

            <artifactId>log4j</artifactId>

            <version>1.2.15</version>

            <exclusions>

                <exclusion>

                    <groupId>javax.mail</groupId>

                    <artifactId>mail</artifactId>

                </exclusion>

                <exclusion>

                    <groupId>javax.jms</groupId>

                    <artifactId>jms</artifactId>

                </exclusion>

                <exclusion>

                    <groupId>com.sun.jdmk</groupId>

                    <artifactId>jmxtools</artifactId>

                </exclusion>

                <exclusion>

                    <groupId>com.sun.jmx</groupId>

                    <artifactId>jmxri</artifactId>

                </exclusion>

            </exclusions>

            <scope>runtime</scope>

        </dependency>


        <!-- @Inject -->

        <dependency>

            <groupId>javax.inject</groupId>

            <artifactId>javax.inject</artifactId>

            <version>1</version>

        </dependency>


        <!-- Servlet -->

        <dependency>

            <groupId>javax.servlet</groupId>

            <artifactId>servlet-api</artifactId>

            <version>2.5</version>

            <scope>provided</scope>

        </dependency>

        <dependency>

            <groupId>javax.servlet.jsp</groupId>

            <artifactId>jsp-api</artifactId>

            <version>2.1</version>

            <scope>provided</scope>

        </dependency>

        <dependency>

            <groupId>javax.servlet</groupId>

            <artifactId>jstl</artifactId>

            <version>1.2</version>

        </dependency>


        <!-- Test -->

        <dependency>

            <groupId>junit</groupId>

            <artifactId>junit</artifactId>

            <version>4.7</version>

            <scope>test</scope>

        </dependency>

    </dependencies>

    <build>

        <plugins>

            <plugin>

                <groupId>org.apache.maven.plugins</groupId>

                <artifactId>maven-compiler-plugin</artifactId>

                <configuration>

                    <source>${java-version}</source>

                    <target>${java-version}</target>

                </configuration>

            </plugin>

            <plugin>

                <groupId>org.apache.maven.plugins</groupId>

                <artifactId>maven-war-plugin</artifactId>

                <configuration>

                    <warName>abc</warName>

                </configuration>

            </plugin>

            <plugin>

                <groupId>org.apache.maven.plugins</groupId>

                <artifactId>maven-dependency-plugin</artifactId>

                <executions>

                    <execution>

                        <id>install</id>

                        <phase>install</phase>

                        <goals>

                            <goal>sources</goal>

                        </goals>

                    </execution>

                </executions>

            </plugin>

            <plugin>

                <groupId>org.apache.maven.plugins</groupId>

                <artifactId>maven-resources-plugin</artifactId>

                <version>2.5</version>

                <configuration>

                    <encoding>UTF-8</encoding>

                </configuration>

            </plugin>

        </plugins>

    </build>

</project>



[기타설정]

WEB-INF/web.xml
WEB-INF/spring/root-context.xml
WEB-INF/spring/appServlet/servlet-context.xml 

일단 다른 애덜이랑 연동할 일이 없으니까 그냥 default 설정으로 놔둬도 된다. 

 

※ 추가 작성할 패키지는 향후 MyBatis 와 연동 하기 위한 구조로 작성함.

proto.board
proto.board.web : Controller
proto.board.service : Biz logic
proto.board.domain : VO
proto.board.dao  : Data Access Object



[Controller 작성]
- 기본 HomeController.java 가 있으니 작성하기 전에 이게 잘 뜨는지 확인

[BoardContentViewController.java]

package proto.board.web;


import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Component;

import org.springframework.stereotype.Controller;

import org.springframework.ui.Model;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;


import proto.board.service.BoardContentViewService;


@Controller

public class BoardContentViewController {


    private static final Logger logger = LoggerFactory.getLogger(BoardContentViewController.class);


    @Autowired

    private BoardContentViewService boardContentViewService;


    @RequestMapping(value = "/boardContentView", method = RequestMethod.GET)

    public String boardContentView(Locale locale, Model model) {

        logger.info("Welcome home! the client locale is "+ locale.toString());

        logger.info("Autowired :  "+ boardContentViewService.getBoardContentVO());


        model.addAttribute("val", boardContentViewService.getBoardContentVO() );


        return "boardContentView";

    }

}


[boardContentView.jsp]

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<%@ page session="false" %>

<html>

<head>

    <title>BoardContentView</title>

</head>

<body>

<h1>

    BoardContentView

</h1>


<P>  The Request is ${val.content}. </P>

</body>

</html>  



[Domain 작성]

[BoardContentVO.java]

package proto.board.domain;


public class BoardContentVO {

    private int documentSrl;

    private String title;

    private String content;

    private String nickname;

    private String email;

    private String regdate;


    public int getDocumentSrl() {

        return documentSrl;

    }


    public void setDocumentSrl(int documentSrl) {

        this.documentSrl = documentSrl;

    }


    public String getTitle() {

        return title;

    }


    public void setTitle(String title) {

        this.title = title;

    }


    public String getContent() {

        return content;

    }


    public void setContent(String content) {

        this.content = content;

    }


    public String getNickname() {

        return nickname;

    }


    public void setNickname(String nickname) {

        this.nickname = nickname;

    }


    public String getEmail() {

        return email;

    }


    public void setEmail(String email) {

        this.email = email;

    }


    public String getRegdate() {

        return regdate;

    }


    public void setRegdate(String regdate) {

        this.regdate = regdate;

    }

} 



[Service 작성]

[BoardContentViewServiceImpl.java]

package proto.board.service;


import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;


import proto.board.dao.BoardContentViewDAO;

import proto.board.domain.BoardContentVO;


@Service

public class BoardContentViewServiceImpl implements BoardContentViewService {


    @Autowired

    private BoardContentViewDAO boardContentViewDAO;


    public BoardContentVO getBoardContentVO() {

        return (BoardContentVO)boardContentViewDAO.getBoardContentVO();

    }

}


[BoardContentViewService.java]

package proto.board.service;


import proto.board.domain.BoardContentVO;



public interface BoardContentViewService {

    BoardContentVO getBoardContentVO();

}



[DAO 작성]

[BoardContentViewDAOImpl.java]

package proto.board.dao;


import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Repository;


import proto.board.domain.BoardContentVO;


@Repository

public class BoardContentViewDAOImpl implements BoardContentViewDAO {


    private BoardContentVO boardContentVO = new BoardContentVO();


    public BoardContentVO getBoardContentVO() {

        boardContentVO.setContent("CONTENT");


        return boardContentVO;

    }

}


[BoardContentViewDAO.java] 

package proto.board.dao;


import proto.board.domain.BoardContentVO;


public interface BoardContentViewDAO {

    BoardContentVO getBoardContentVO();

} 



※ 자 그럼 build 를 하고 실행을 하봅시다.
[Eclipse Console 로그확인]
- 아래 로그는 실제 servlet-context.xml 에서 component-scan 일 잘 되었는지 확인하기 위함 이다.
- 이게 정상적으로 나오지 않을 경우는 "not found url mapping" 어쩌구 에러가 발생 합니다.

INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String proto.board.HomeController.home(java.util.Locale,org.springframework.ui.Model)

INFO : org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped "{[/boardContentView],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String proto.board.web.BoardContentViewController.boardContentView(java.util.Locale,org.springframework.ui.Model)



[Tomcat 실행결과]



:

Spring Framework MVC + MyBatis Empty 설정 맛보기.

ITWeb/개발일반 2012. 3. 8. 17:19
※ 본 설명은 sts (SpringSource Tool Suite) 에서 spring mvc 프로젝트를 생성 한후 수행한 내용 입니다.

[Project 생성]

1. Spring Template Project 에서 Spring MVC Project 를 선택 합니다.
- 아래 이미지는 Next 후 Setting 화면 입니다.

 

2. pom.xml 수정

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.prototype</groupId>

    <artifactId>board</artifactId>

    <name>prototype.board</name>

    <packaging>war</packaging>

    <version>1.0.0-BUILD-SNAPSHOT</version>

    <properties>

        <java-version>1.6</java-version>

        <org.springframework-version>3.1.0.RELEASE</org.springframework-version>

        <org.aspectj-version>1.6.9</org.aspectj-version>

        <org.slf4j-version>1.5.10</org.slf4j-version>

    </properties>

    <dependencies>

        <!-- Spring -->

<!-- spring framework context 설정 -->

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>spring-context</artifactId>

            <version>${org.springframework-version}</version>

            <exclusions>

                <!-- Exclude Commons Logging in favor of SLF4j -->

                <exclusion>

                    <groupId>commons-logging</groupId>

                    <artifactId>commons-logging</artifactId>

                 </exclusion>

            </exclusions>

        </dependency>


<!-- spring framework mvc 설정 -->

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>spring-webmvc</artifactId>

            <version>${org.springframework-version}</version>

        </dependency>


<!-- spring framework jdbc 설정 -->

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>spring-jdbc</artifactId>

            <version>${org.springframework-version}</version>

        </dependency>


<!-- mysql -->

        <dependency>

            <groupId>mysql</groupId>

            <artifactId>mysql-connector-java</artifactId>

            <version>5.1.18</version>

        </dependency>


<!-- mybatis -->

        <dependency>

            <groupId>org.mybatis</groupId>

            <artifactId>mybatis</artifactId>

            <version>3.0.6</version>

        </dependency>


<!-- mybatis spring -->

        <dependency>

            <groupId>org.mybatis</groupId>

            <artifactId>mybatis-spring</artifactId>

            <version>1.0.2</version>

        </dependency>



        <!-- AspectJ -->

        <dependency>

            <groupId>org.aspectj</groupId>

            <artifactId>aspectjrt</artifactId>

            <version>${org.aspectj-version}</version>

        </dependency>


        <!-- Logging -->

        <dependency>

            <groupId>org.slf4j</groupId>

            <artifactId>slf4j-api</artifactId>

            <version>${org.slf4j-version}</version>

        </dependency>

        <dependency>

            <groupId>org.slf4j</groupId>

            <artifactId>jcl-over-slf4j</artifactId>

            <version>${org.slf4j-version}</version>

            <scope>runtime</scope>

        </dependency>

        <dependency>

            <groupId>org.slf4j</groupId>

            <artifactId>slf4j-log4j12</artifactId>

            <version>${org.slf4j-version}</version>

            <scope>runtime</scope>

        </dependency>

        <dependency>

            <groupId>log4j</groupId>

            <artifactId>log4j</artifactId>

            <version>1.2.15</version>

            <exclusions>

                <exclusion>

                    <groupId>javax.mail</groupId>

                    <artifactId>mail</artifactId>

                </exclusion>

                <exclusion>

                    <groupId>javax.jms</groupId>

                    <artifactId>jms</artifactId>

                </exclusion>

                <exclusion>

                    <groupId>com.sun.jdmk</groupId>

                    <artifactId>jmxtools</artifactId>

                </exclusion>

                <exclusion>

                    <groupId>com.sun.jmx</groupId>

                    <artifactId>jmxri</artifactId>

                </exclusion>

            </exclusions>

            <scope>runtime</scope>

        </dependency>


        <!-- @Inject -->

        <dependency>

            <groupId>javax.inject</groupId>

            <artifactId>javax.inject</artifactId>

            <version>1</version>

        </dependency>


        <!-- Servlet -->

        <dependency>

            <groupId>javax.servlet</groupId>

            <artifactId>servlet-api</artifactId>

            <version>2.5</version>

            <scope>provided</scope>

        </dependency>

        <dependency>

            <groupId>javax.servlet.jsp</groupId>

            <artifactId>jsp-api</artifactId>

            <version>2.1</version>

            <scope>provided</scope>

        </dependency>

        <dependency>

            <groupId>javax.servlet</groupId>

            <artifactId>jstl</artifactId>

            <version>1.2</version>

        </dependency>


        <!-- Test -->

        <dependency>

            <groupId>junit</groupId>

            <artifactId>junit</artifactId>

            <version>4.7</version>

            <scope>test</scope>

        </dependency>

    </dependencies>

    <build>

        <plugins>

            <plugin>

                <groupId>org.apache.maven.plugins</groupId>

                <artifactId>maven-compiler-plugin</artifactId>

                <configuration>

                    <source>${java-version}</source>

                    <target>${java-version}</target>

                </configuration>

            </plugin>

            <plugin>

                <groupId>org.apache.maven.plugins</groupId>

                <artifactId>maven-war-plugin</artifactId>

                <configuration>

                    <warName>abc</warName>

                </configuration>

            </plugin>

            <plugin>

                <groupId>org.apache.maven.plugins</groupId>

                <artifactId>maven-dependency-plugin</artifactId>

                <executions>

                    <execution>

                        <id>install</id>

                        <phase>install</phase>

                        <goals>

                            <goal>sources</goal>

                        </goals>

                    </execution>

                </executions>

            </plugin>

            <plugin>

                <groupId>org.apache.maven.plugins</groupId>

                <artifactId>maven-resources-plugin</artifactId>

                <version>2.5</version>

                <configuration>

                    <encoding>UTF-8</encoding>

                </configuration>

            </plugin>

        </plugins>

    </build>

</project>


3. web.xml 수정

<?xml version="1.0" encoding="UTF-8"?>

<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">


    <!-- The definition of the Root Spring Container shared by all Servlets and Filters -->

    <context-param>

        <param-name>contextConfigLocation</param-name>

        <param-value>

            /WEB-INF/spring/root-context.xml

            classpath:context/applicationContext-root.xml

        </param-value>

    </context-param>


    <!-- Creates the Spring Container shared by all Servlets and Filters -->

    <listener>

        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

    </listener>


    <!-- Processes application requests -->

    <servlet>

        <servlet-name>appServlet</servlet-name>

        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

        <init-param>

            <param-name>contextConfigLocation</param-name>

            <param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>

        </init-param>

        <load-on-startup>1</load-on-startup>

    </servlet>


    <servlet-mapping>

        <servlet-name>appServlet</servlet-name>

        <url-pattern>/</url-pattern>

    </servlet-mapping>


</web-app>


4. mybatis 의 applicationContext 설정
- src/main/resources 하위에 아래와 같은 폴더와 파일을 만듭니다.


5. applicationContext-root.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">


    <!-- Application Root Context: defines shared resources visible to all other web components -->

    <import resource="applicationContext-mybatis.xml" />

</beans>


6. applicationContext-mybatis.xml

<?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:aop="http://www.springframework.org/schema/aop"

    xmlns:tx="http://www.springframework.org/schema/tx"

    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

                http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd

                http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">


    <bean

        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">

        <property name="locations">

            <value>classpath:configuration/mybatis/jdbc.properties</value>

        </property>

    </bean>


    <bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">

        <property name="driverClass"        value="${jdbc.driverClass}" />

        <property name="url"                value="${jdbc.url}" />

        <property name="username"           value="${jdbc.username}" />

        <property name="password"           value="${jdbc.password}" />

    </bean>


    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

        <property name="dataSource" ref="dataSource" />

<!--         <property name="configLocation" value="classpath:configuration/mybatis/config.xml" /> -->

<!--         <property name="mapperLocations" value="classpath:sql/mybatis/**/*.xml" /> -->

    </bean>


    <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">

        <constructor-arg ref="sqlSessionFactory" />

    </bean>


    <bean id="transactionManager"

        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

        <property name="dataSource" ref="dataSource" />

    </bean>


    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">

        <property name="transactionManager" ref="transactionManager" />

    </bean>

</beans>


7. mybatis/config.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "HTTP://mybatis.org/dtd/mybatis-3-config.dtd">


<configuration>

    <settings>

        <setting name="cacheEnabled" value="true" />

        <setting name="lazyLoadingEnabled" value="true" />

        <setting name="multipleResultSetsEnabled" value="true" />

        <setting name="useColumnLabel" value="true" />

        <setting name="useGeneratedKeys" value="false" />

        <setting name="enhancementEnabled" value="false" />

        <setting name="defaultExecutorType" value="SIMPLE" />

        <setting name="defaultStatementTimeout" value="25000" />

        <setting name="defaultListResultHandlerType" value="java.util.ArrayList" />

        <setting name="defaultMapResultHandlerType" value="java.util.HashMap" />

    </settings>


<!--  -->

<!--     <typeAliases /> -->


<!-- 상위 mybatis.xml 에서 mapperLocations 설정 시 하위 설정은 필요 없음  -->

<!-- mybatis 에서 작성한 SQL 문이 정의된 파일 지정 -->

<!-- Using classpath relative resources : <mapper resource="sql/com.proto.board.List.xml" /> -->

<!--     <mappers /> -->

</configuration>


8. mybatis/jdbc.properties

jdbc.datasource=jdbc/DataSource

jdbc.driverClass=com.mysql.jdbc.Driver

jdbc.url=jdbc:mysql://localhost:3306/mybatis?autoReconnect=true

jdbc.username=root

jdbc.password=1234


9. web.xml 에 applicationContext-root.xml 추가 (3번과 중복)

    <context-param>

        <param-name>contextConfigLocation</param-name>

        <param-value>

            /WEB-INF/spring/root-context.xml

            classpath:context/applicationContext-root.xml

        </param-value>

    </context-param>


10. Empty 설정이 잘 되었는지 확인하기
SpringMVC 템플릿의 경우 기본 HelloWorld 가 포함 되어 있으므로 서버 등록 후 정상적으로 동작 하는지 확인 하면 됩니다.
- Server 등록은 아래 처럼


11. 서버 실행이 잘 되었다면. Hello World 를 확인 할 수 있습니다.



※ 이제 empty project template 을 만들었으니 기본적인 게시판 모듈 구현을 시작하면 되겠습니다.
- 급하게 시작 하셔야 하는 분은 아래 링크 참고 하세요.




:

Spring Framework 설정관련 기초.

ITWeb/개발일반 2012. 3. 8. 11:20
[spring framework 에서 기본 설정의 시작]

web.xml



[web.xml 에서 contextConfigLocation]

[contextConfigLocation]

    <context-param>

        <param-name>contextConfigLocation</param-name>

        <param-value>

            classpath:applicationContext-business.xml

            /WEB-INF/applicationContext-security.xml

        </param-value>

    </context-param>


[classpath 의 path 는 어디 일까?]

- eclipse 에서 package explorer 로 보게 되면 해당 project 의  
    src/main/resources
에 해당한다.

- build 를 하게 되면 webapp 하위에
    /WEB-INF/classes
에 해당한다.

위에 src/main/resources 에 파일을 하나 생성해 놓고 빌드를 해보면 생성한 파일이 WEB-INF/classes 에 들어가 있는걸 볼 수 있다.  



[<import resource="" /> 의 Path]

예를 들면)
web.xml 에 아래와 같이 정의 되어 있다.
- web.xml 은 기본 /WEB-INF/web.xml 에 위치한다.

[Case 1]
<import resource="root-context.xml" />
이 경우 /WEB-INF/root-context.xml 을 찾는다.

[Case 2]
<import resource="context/root-context.xml" /> 
이 경우 /WEB-INF/context/root-context.xml 을 찾는다. 

[Case 3]
<import resource="/context/root-context.xml" /> 
이 경우 /WEB-INF/context/root-context.xml 을 찾는다. 
case 2 와 동일 하다. 



[참고URL]
 
:

VIM no indent 설정.

ITWeb/개발일반 2012. 3. 6. 17:21
[참고사이트]
http://vim.wikia.com/wiki/How_to_stop_auto_indenting


[명령어]
set noai nocin nosi inde=
:

java classpath setting

ITWeb/개발일반 2012. 3. 6. 15:03
[참고사이트]
http://docs.oracle.com/javase/tutorial/essential/environment/paths.html
http://javarevisited.blogspot.com/2011/01/how-classpath-work-in-java.html


[Windows 에서 Classpath 설정]
sdkTool -classpath classpath1;classpath2...

-or-

set CLASSPATH=classpath1;classpath2...

javac -classpath a.jar;b.jar example.java
javac -classpath C:\java\MyClasses;C:\java\OtherClasses example.java



[Linux 에서 Classpath 설정]
export CLASSPATH="your classpath" from either your .bash_profile or .bashrc

javac -classpath a.jar:b.jar example.java
javac -classpath /home/hadoop/app/hadoop example.java


[javac -help]
ubuntu:~/app/hadoop-0.21.0$ javac -help
Usage: javac <options> <source files>
where possible options include:
  -g                         Generate all debugging info
  -g:none                    Generate no debugging info
  -g:{lines,vars,source}     Generate only some debugging info
  -nowarn                    Generate no warnings
  -verbose                   Output messages about what the compiler is doing
  -deprecation               Output source locations where deprecated APIs are used
  -classpath <path>          Specify where to find user class files and annotation processors
  -cp <path>                 Specify where to find user class files and annotation processors
  -sourcepath <path>         Specify where to find input source files
  -bootclasspath <path>      Override location of bootstrap class files
  -extdirs <dirs>            Override location of installed extensions
  -endorseddirs <dirs>       Override location of endorsed standards path
  -proc:{none,only}          Control whether annotation processing and/or compilation is done.
  -processor <class1>[,<class2>,<class3>...]Names of the annotation processors to run; bypasses default discovery process
  -processorpath <path>      Specify where to find annotation processors
  -d <directory>             Specify where to place generated class files
  -s <directory>             Specify where to place generated source files
  -implicit:{none,class}     Specify whether or not to generate class files for implicitly referenced files
  -encoding <encoding>       Specify character encoding used by source files
  -source <release>          Provide source compatibility with specified release
  -target <release>          Generate class files for specific VM version
  -version                   Version information
  -help                      Print a synopsis of standard options
  -Akey[=value]              Options to pass to annotation processors
  -X                         Print a synopsis of nonstandard options
  -J<flag>                   Pass <flag> directly to the runtime system

:

Spring Security Role 정의

ITWeb/개발일반 2012. 3. 5. 18:03
내가 궁금했던건 이거다.

"ROLE_XXXX" 라는 걸 어디서 정의 하는 거냐?

별로 어렵지도 않은 내용인데.. 직관적인 설명을 잘 찾지 못했다.
결론을 정리 하면.. 바로 spring security 의 설정 부분인 아래 코드이다.
- 막상 내가 보니 어떤 파일인지 궁금해 하시는 분이 계실 것 같아..추가 합니다.
- web.xml 에서 추가한 security 관련 context 파일이 되겠습니다.

[web.xml]

    <context-param>

        <param-name>contextConfigLocation</param-name>

        <param-value>

            classpath:applicationContext-business.xml

            /WEB-INF/applicationContext-security.xml

        </param-value>

    </context-param>


[applicationContext-security.xml]

// 바로 아래 코드가 되겠구요.


<authentication-provider>
        <password-encoder hash="md5"/>
        <user-service>
            <user name="rod" password="a564de63c2d0da68cf47586ee05984d7" authorities="ROLE_SUPERVISOR, ROLE_USER, ROLE_TELLER" />
            <user name="dianne" password="65d15fe9156f9c4bbffd98085992a44e" authorities="ROLE_USER,ROLE_TELLER" />
            <user name="scott" password="2b58af6dddbd072ed27ffc86725d7d3a" authorities="ROLE_USER" />
            <user name="peter" password="22b5c9accc6e1ba628cedc63a72d57f8" authorities="ROLE_USER" />
        </user-service>
    </authentication-provider>


설정에서 보면.. 빨간색 부분이 정의를 하는 부분이다.
소스코드에서는 아래 파일 이다.

- RoleVoter.java 

/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited

 *

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *     http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */


package org.springframework.security.access.vote;


import java.util.Collection;


import org.springframework.security.access.AccessDecisionVoter;

import org.springframework.security.access.ConfigAttribute;

import org.springframework.security.core.Authentication;

import org.springframework.security.core.GrantedAuthority;


/**

 * Votes if any {@link ConfigAttribute#getAttribute()} starts with a prefix

 * indicating that it is a role. The default prefix string is <Code>ROLE_</code>,

 * but this may be overridden to any value. It may also be set to empty, which

 * means that essentially any attribute will be voted on. As described further

 * below, the effect of an empty prefix may not be quite desirable.

 * <p>

 * Abstains from voting if no configuration attribute commences with the role

 * prefix. Votes to grant access if there is an exact matching

 * {@link org.springframework.security.core.GrantedAuthority} to a <code>ConfigAttribute</code>

 * starting with the role prefix. Votes to deny access if there is no exact

 * matching <code>GrantedAuthority</code> to a <code>ConfigAttribute</code>

 * starting with the role prefix.

 * <p>

 * An empty role prefix means that the voter will vote for every

 * ConfigAttribute. When there are different categories of ConfigAttributes

 * used, this will not be optimal since the voter will be voting for attributes

 * which do not represent roles. However, this option may be of some use when

 * using pre-existing role names without a prefix, and no ability exists to

 * prefix them with a role prefix on reading them in, such as provided for

 * example in {@link org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl}.

 * <p>

 * All comparisons and prefixes are case sensitive.

 *

 * @author Ben Alex

 * @author colin sampaleanu

 */

public class RoleVoter implements AccessDecisionVoter<Object> {

    //~ Instance fields ================================================================================================


    private String rolePrefix = "ROLE_";


    //~ Methods ========================================================================================================


    public String getRolePrefix() {

        return rolePrefix;

    }


    /**

     * Allows the default role prefix of <code>ROLE_</code> to be overridden.

     * May be set to an empty value, although this is usually not desirable.

     *

     * @param rolePrefix the new prefix

     */

    public void setRolePrefix(String rolePrefix) {

        this.rolePrefix = rolePrefix;

    }


    public boolean supports(ConfigAttribute attribute) {

        if ((attribute.getAttribute() != null) && attribute.getAttribute().startsWith(getRolePrefix())) {

            return true;

        }

        else {

            return false;

        }

    }


    /**

     * This implementation supports any type of class, because it does not query

     * the presented secure object.

     *

     * @param clazz the secure object

     *

     * @return always <code>true</code>

     */

    public boolean supports(Class<?> clazz) {

        return true;

    }


    public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {

        int result = ACCESS_ABSTAIN;

        Collection<? extends GrantedAuthority> authorities = extractAuthorities(authentication);


        for (ConfigAttribute attribute : attributes) {

            if (this.supports(attribute)) {

                result = ACCESS_DENIED;


                // Attempt to find a matching granted authority

                for (GrantedAuthority authority : authorities) {

                    if (attribute.getAttribute().equals(authority.getAuthority())) {

                        return ACCESS_GRANTED;

                    }

                }

            }

        }


        return result;

    }


    Collection<? extends GrantedAuthority> extractAuthorities(Authentication authentication) {

        return authentication.getAuthorities();

    }

}


이넘들의 각 Class 간 flow 를 보면.. 아래 그림과 같다.
참고사이트 :  http://static.springsource.org/spring-security/site/docs/3.0.x/reference/authz-arch.html 

이미지 출처 :  http://whiteship.me/?tag=spring-security 



이제 어디서 정의 하는지는 확인을 했으니 이걸 매번 설정파일에 등록해 줄 수는 없으므로 jdbc-user-service 설정을 하는 걸 보도록 하자.

[참고사이트]
http://static.springsource.org/spring-security/site/docs/3.0.x/reference/ns-config.html 
-  http://www.mularien.com/blog/2008/07/07/5-minute-guide-to-spring-security/ 

2.2.3 Using other Authentication Providers

In practice you will need a more scalable source of user information than a few names added to the application context file. Most likely you will want to store your user information in something like a database or an LDAP server. LDAP namespace configuration is dealt with in the LDAP chapter, so we won't cover it here. If you have a custom implementation of Spring Security's UserDetailsService, called "myUserDetailsService" in your application context, then you can authenticate against this using

  <authentication-manager>
    <authentication-provider user-service-ref='myUserDetailsService'/>
  </authentication-manager>
  
        

If you want to use a database, then you can use

  <authentication-manager>
    <authentication-provider>
      <jdbc-user-service data-source-ref="securityDataSource"/>
    </authentication-provider>
  </authentication-manager>
  
        

Where securityDataSource is the name of a DataSource bean in the application context, pointing at a database containing the standard Spring Security user data tables. Alternatively, you could configure a Spring Security JdbcDaoImpl bean and point at that using the user-service-ref attribute:

  <authentication-manager>
    <authentication-provider user-service-ref='myUserDetailsService'/>
  </authentication-manager>

  <beans:bean id="myUserDetailsService"
      class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
    <beans:property name="dataSource" ref="dataSource"/>
  </beans:bean>
  
        


A.1 User Schema

The standard JDBC implementation of the UserDetailsService (JdbcDaoImpl) requires tables to load the password, account status (enabled or disabled) and a list of authorities (roles) for the user.

  create table users(
      username varchar_ignorecase(50) not null primary key,
      password varchar_ignorecase(50) not null,
      enabled boolean not null);

  create table authorities (
      username varchar_ignorecase(50) not null,
      authority varchar_ignorecase(50) not null,
      constraint fk_authorities_users foreign key(username) references users(username));
      create unique index ix_auth_username on authorities (username,authority);

A.1.1 Group Authorities

Spring Security 2.0 introduced support for group authorities in JdbcDaoImpl. The table structure if groups are enabled is as follows:

create table groups (
  id bigint generated by default as identity(start with 0) primary key,
  group_name varchar_ignorecase(50) not null);

create table group_authorities (
  group_id bigint not null,
  authority varchar(50) not null,
  constraint fk_group_authorities_group foreign key(group_id) references groups(id));

create table group_members (
  id bigint generated by default as identity(start with 0) primary key,
  username varchar(50) not null,
  group_id bigint not null,
  constraint fk_group_members_group foreign key(group_id) references groups(id));
        



Database-Backed Authentication

In my case, my application was already configured to use a JDBC DataSource, so pointing Spring Security at my JDBC data source was as easy as modifying the authentication-provider element to reference my already configured Spring bean:

    <authentication-provider>
	    <jdbc-user-service data-source-ref="dataSource"/>
    </authentication-provider>

Now, the immediate question I asked is – OK, what does the convention over configuration assume my database tables look like? If you look at the documentation of the JDBC authentication provider, you would expect to see that information there, but you’d be wrong.

Instead, you have to look at the SQL queries that are hard-coded in the JdbcDaoImpl class and infer the schema structure for yourself. This article has a graphical depiction of the basic schema down in section 5.4.

If you want to configure the queries that are used, simply match the available attributes on the jdbc-user-service element to the SQL queries in the Java class I referenced above. In my example, I wanted to simplify my schema by adding the user’s role directly to the user table. So I modified the XML configuration slightly as follows:

  <jdbc-user-service data-source-ref="dataSource" 
    authorities-by-username-query="select username,authority from users where username=?"/>

This allowed me to put values in the ‘authority’ column like ‘ROLE_ADMIN’ or ‘ROLE_USER’, which translate directly into Spring Security roles!


:

[펌] 2장 Intecept와 Granted Authority

ITWeb/개발일반 2012. 3. 5. 17:38
원본글 :  http://springmvc.egloos.com/506465 


리소스의 권한(Intercept) - 전장에 이어 계속

전장에 이어서 리소스의 권한설정을 계속 하도록 하겠습니다. 먼저 우리는 DelegatingFilterChain 클래스를 통해 스프링 시큐리티가 모든 URL요청을 가로챌 수 있도록 설정하는 법을 배웠습니다. 이제 스프링 컨텍스트에서 DelegatingFilterChain이 가로챈 요청을 세분화하는 방법을 알아보죠.

먼저 미리 작성한 security-context.xml을 열어 다음과 같은 네임스페이스를 설정해주도록 합시다.
<?xml version="1.0" encoding="UTF-8"?><beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">

이 네임스페이스는 security를 기본 xmlns로 선택하고 있는 컨텍스트 네임스페이스입니다. 요소명이 <beans:beans>로 된 점을 주의하시고 왜 이렇게 설정되있는지 확실히 이해하도록 노력하세요. 종종 이런 컨텍스트 파일 설정에 익숙하지 않으셔서 오류를 겪으시는 분들이 꽤 있습니다.

네임스페이스를 설정했다면 이제 본격적으로 시큐리티 설정을 해봅시다. 기본적인 테스트를 위해 다음과 같은 소스를 security-context.xml에 삽입합니다.

<http auto-config="true">
<intercept-url pattern="/-" access="ROLE_USER" />
</http>

<authentication-manager>
<authentication-provider>
<user-service>
<user name="guest" password="guest" authorities="ROLE_USER"/>
</user-service>
</authentication-provider>
</authentication-manager>

그 다음 테스트를 위해 서버를 기동해보세요. 성공했다면 다음과 같은 로그인 창이 뜨게 될 것입니다.


일단 이 로그인 창이 무엇을 위한 로그인 창인지 이해가 안되 조금 어안이 벙벙하실 수도 있습니다. 저같은 경우는 이 창을 보면서 "스프링 시큐리티를 사용하려면 온라인 인증을 받아야 하나?" 라는 생각을 먼저 했었습니다. 그도 그럴 것이 정말 한게 아무것도 없고 몇가지 XML설정만 해준 것이 끝이었거든요. 근데… 한참을 보고 나서야 알게 된 사실이지만 정말 놀랍게도 이것은 스프링 시큐리티가 모든 설정을 기본값으로 설정해준 덕에 우리가 얻게된 로그인 창이었습니다.

이번엔 아이디와 비밀번호에 각각 guest를 입력하고 Login 버튼을 클릭해봅시다. 아마 당신은 애초에 얻고자 했던 URL 리소스에 접근할 수 있을 것입니다. 스프링 시큐리티가 재미난 마술을 부린 것 같지 않습니까?

<http auto-config="true">

먼저 어떤 원리에서 Login 창이 뜨게 된건지부터 알아봅시다. 이 모든 마법은 바로 auto-config="true"에서 발생한 트릭이었습니다. 스프링 시큐리티는 기본적으로 Ahthorization(권한 부여)에 관한 대부분의 설정이 <http> 요소에 위치해 있으며 설정 가능한 모든 요소에 디폴트 값이 존재합니다. 그러므로 <http>요소의 auto-config 속성을 true로 잡아줌으로써 우리는 모든 디폴트 속성값으로 서버를 설정했던 셈이죠.

<intercept-url pattern="/-" access="ROLE_USER" />

그 다음 이 부분… 어디서 많이 본 단어가 나오지 않습니까? 제가 일전부터 리소스의 권한이라고 목청껏 떠들어댔던 intercept가 나오고 있습니다. <intercept-url>은 DelegatingFilterProxy에서 가로챈 요청을 좀 더 세부적으로 나눠주며(pattern) 접근할 수 있는 권한을 설정(access)합니다.


부여된 권한(Granted Authority)

그렇다면 대충 리소스의 권한은 이런 식으로 설정할 수 있다는 것을 알게 됬지만 문제는 ROLE_USER와 같이 부여된 권한(Granted Authority) 설정은 어디서 하게 되는 걸까요? 보호하고 싶은 리소스에 보호막을 씌웠지만 누군가 접근할 수 있도록 권한도 부여해야 하지 않습니까! 그리고 ROLE_USER라는 단어는 어디서 나오게 된 거고 꼭 이렇게 써야만 하나요?

곧바로 이런 문제의 해답을 얻을 순 없겠지만 원리에 근접하고, 유치하다 싶은 고민들은 보안의 원리를 깨우치는데 매우 중요한 역할을 담당합니다. 왜냐하면 이런 문제의 근본적인 해답은 바로 Authentication(인증), Authorization(권한부여)에 대한 깊은 이해에서 나오게 되기 때문이죠.

먼저의 모든 단어의 뜻은 무시하고 보안이란 맥락에서만 보았을 때 위에서 소개한 리소스의 권한(Intercept)은 Authentication(인증)의 영역에 포함됩니다. 우리가 무언가의 인증을 받은 후에 리소스에 접근할 권한을 얻게 되므로 리소스의 권한은 인증작업에 일부가 되는 셈이죠. 그렇다면 부여된 권한(Granted Authority)는 어디에 속할까요? 바로 Authorization(권한부여)에 속하게 됩니다. 권한을 부여하려면 먼저 권한부터 설정되있어야 하며 궁극적으로 설정된 권한을 유저에게 부여해줘야 하기 때문입니다.

그러므로 <http>요소는 Authentication(인증)의 범주에 속해있으며 스프링 시큐리티는 Authorization(권한부여)의 영역을 분할하기 위해 <authorization-manager>란 요소를 따로 사용하고 있습니다. 아래의 소스는 <authorization-manager>의 가장 하위 요소인 <user>인데요. 이 요소를 통해 우리는 작게나마 권한부여에서 수행할 역할에 대해 가늠할 수 있게 됩니다.

<user name="guest" password="guest" authorities="ROLE_USER"/>

먼저 인증받을 사용자의 아이디와 비밀번호를 입력한 뒤에 해당 사용자에게 권한(ROLE_USER)를 부여합니다. 부여할 권한이 꼭 ROLE_USER와 같을 필요는 없지만 별도의 튜닝이 없다면 가급적 'ROLE_' 이란 문자열로 시작해야 합니다. 왜냐하면 스프링 시큐리티는 RoleVoter라고 부여된 권한(Granted Authority)을 검사하는 클래스를 가지고 있는데 이 검사자가 문자열이 ROLE_이란 접두어로 시작하는 지를 검사하기 때문입니다. 만약 ROLE_이란 접두어로 시작하지 않는다면 시큐리티는 접근 보류(ACCESS_ABSTAIN)라는 결론을 짓게 됩니다.


org.springframework.security.access.AccessDecisionVoter의 int 상수
ACCESS_GRANTED(접근 승인, 값=1) : RoleVoter가 접근 결정자에게 접근을 승인할 것을 요청.
ACCESS_ABSTAIN(접근 보류, 값=0 : RoleVoter가 접근 결정자에게 접근을 보류할 것을 요청.
ACCESS_DENIED(접근 거부, 값=-1) : RoleVoter가 접근 결정자에게 접근을 거부할 것을 요청.

그러므로 이런 사실을 종합해본다면 부여할 권한의 이름 설정이 중요한 역할을 담당하며 또 <intercept-url>에서 선별한 자원에 사용자가 접근할 수 있게 하려면 <intercept-url access>의 값과 <user authorities>의 값이 서로 일치하게 만들어야 한다는 것입니다.

그리고 또 하나 기억해야 할 것은 지금은 우리가 <user-service>를 이용해 직접 사용자를 작성하고 있지만 향후 서비스에서 모든 사용자를 직접 매핑할 수는 없는 노릇이므로 앞으로 <jdbc-user-service>를 이용해 Authorization(권한 부여)의 대부분을 DB로 이전시켜야 한다는 것입니다. 그러므로 지금부터라도 데이터베이스에 단순히 사용자의 정보만 기록할 것이 아니라 권한, 그룹(퍼미션) 등 다양한 역할을 데이터베이스가 수행해야 한다는 사실을 기억해야 합니다.


스프링 시큐리티의 표현식 언어

스프링 표현식 언어를 사용하면 RoleVoter에서 수행하지 않는 보안설정을 표현식을 통해 추가할 수 있습니다.

<http auto-config="true" use-expressions="true">
<intercept-url pattern="/-" access="hasRole('ROLE_USER')"/>
</http>

위처럼 표현식 사용을 설정하면 아래의 표현식들의 사용이 가능해집니다. 표현식은 어디까지나 RoleVoter가 영향력을 가지는 <intercept access>에서만 설정할 수 있습니다.

hasIpAddress(ip) : 접근자의 IP주소가 매칭하는지 확인합니다.
hasRole(role) : 역할이 부여된 권한(Granted Authority)와 일치하는지 확인합니다.
hasAnyRole(role) : 부여된 역할 중 일치하는 항목이 있는지 확인합니다.
 예 - access = "hasAnyRole('ROLE_USER','ROLE_ADMIN')"

위의 표현식 외에도 다음과 같은 조건들을 access에서 사용할 수 있습니다.

permitAll : 모든 접근자를 항상 승인합니다.
denyAll : 모든 사용자의 접근을 거부합니다.
anonymous : 사용자가 익명 사용자인지 확인합니다.
authenticated : 인증된 사용자인지 확인합니다.
rememberMe : 사용자가 remember me를 사용해 인증했는지 확인합니다.
fullyAuthenticated : 사용자가 모든 크리덴셜을 갖춘 상태에서 인증했는지 확인합니다.

원한다면 표현식 사이에 AND, OR연산도 가능합니다.
access = "hasAnyRole('ROLE_USER','ROLE_ADMIN') or authenticated"



로그인 페이지 커스터마이징

<intercept-url pattern="/login" access="permitAll" />
<intercept-url pattern="/-" access="hasRole('ROLE_USER')"/>
<form-login login-page="/login" username-parameter="username" password-parameter="password" login-processing-url="/authentication" />

아마 스프링 시큐리티에서 제공하는 기본 로그인 창을 계속 이용하고 싶으신 분은 아무도 없으실 겁니다. <form-login> 요소를 이용하면 손쉽게 로그인 페이지를 커스터마이징하실 수 있습니다.

login-page : 로그인이 요청될 시에 이동할 URL을 설정합니다.
username-parameter : 로그인 아이디의 파라미터명 즉 name필드값을 설정합니다.
passoword-parameter : 비밀번호의 파라미터 명을 설정합니다.
login-processing-url : 폼에서 전송할 URL 값을 설정합니다. (action=login-processing-url)

여기서 주의할 점은 로그인 URL 인터셉터를 모든 리소스를 차단하는 인터셉터의 위쪽으로 배치시켜야 한다는 것입니다. 만약 그렇지 않다면 리디렉션 순환 오류로 정상적인 로그인 창이 뜨지 않으실 겁니다.

글이 길어지는 관계로 2장은 여기까지 마치고 3장에서 미처 다 하지 못한 <http>관련 어트리뷰트 설정법에 대해 자세히 다루도록 하겠습니다.
: