우선 smtp를 지원하는 메일서비스만 할 수 있습니다.
naver는 지원하긴 하지만, 조낸 써야지 smtp를 사용할 수 있습니다.
저는 일반사용자인데 으뜸사용자가 되야하는 듯 합니다.
그래서 그냥 지원해주는 gmail이랑 daum메일로 테스트를 해봤습니다. 잘 되는군요.

기존에 25포트가 디폴트로 메일을 사용했는데 보안 때문에 SSL을 사용하고, smtps라는 프로토콜로 465번포트로 하는군요.
이건 좀 더 공부를 해봐야할 듯 싶네요. 그냥 기존의 ssl을 사용하지 않는 메일은 host랑 id랑 password만 지정해주면 돼요.

우선 설정파일입니다.
applicationContext.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:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="
      http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
      http://www.springframework.org/schema/context
     http://www.springframework.org/schema/context/spring-context-2.5.xsd">
    
    <context:component-scan base-package="mailtest" />
   
    <!-- 일반용 
    <bean id="mailSender"
        class="org.springframework.mail.javamail.JavaMailSenderImpl"
        p:host="STMP서버주소"
        p:username="아이디"
        p:password="비밀번호" />
    -->
   
    <!-- gmail, hanmail 용 -->
    <bean id="mailSender"
        class="org.springframework.mail.javamail.JavaMailSenderImpl"
        p:host="한메일: pop.hanmail.net, 지메일:smtp.gmail.com"
        p:port="465"
        p:protocol="smtps"
        p:username="아이디"
        p:password="비밀번호">
        <property name="javaMailProperties">
            <props>
                <prop key="mail.smtps.auth">true</prop>
                <prop key="mail.smtps.startls.enable">true</prop>
                <prop key="mail.smtps.debug">true</prop>
            </props>
        </property>
    </bean>
   
    <bean id="templateMessage"
        class="org.springframework.mail.SimpleMailMessage"
        p:from="송신자 주소"
        p:to="수신자 주소"
        p:subject="안녕!" />
   
</beans>
[/code]
templateMessage는 임시로 메세지를 지정해주는 것으로 미리 지정할 껀 지정하는 겁니다.
물론, 나중에 java코드에서 수정이 가능합니다.

서비스부분입니다.
MailTestService.java
[code]
package mailtest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.stereotype.Service;

@Service
public class MailTestService
{
    @Autowired
    private MailSender mailSender;
   
    @Autowired
    private SimpleMailMessage simpleMailMessage;
   
    public void sendEmail()
    {
        SimpleMailMessage msg = new SimpleMailMessage(this.simpleMailMessage);
        msg.setText("난 종천이라고해!");
        this.mailSender.send(msg);
    }
}
[/code]
저기서 simpleMailMessage를 받아와서 text만 설정해줍니다. 저기서 msg.setTo하면 수신자도 설정할 수 있죠. 그리고 그냥 send메소드만 호출해주면 메일이 전송됩니다.

[code]
package mailtest;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MailTest
{
    public static void main(String[] args)
    {
        String configLocation = "applicationContext.xml";
        ApplicationContext context =
            new ClassPathXmlApplicationContext(configLocation);
       
        MailTestService mailTestService =
            (MailTestService) context.getBean("mailTestService");
       
        mailTestService.sendEmail();
    }
}
[/code]
더욱 심화된 기능은 reference를 참조하세요
http://static.springframework.org/spring/docs/2.5.x/reference/mail.html
 
Posted by 머드초보
,
 

넷빈즈는 초보자들이 쉽게 적응할 수 있도록 QuickStart를 제공합니다.
일종의 튜토리얼 같은 건데 참 잘 되어 있습니다.
스프링프레임워크에 관해서도 QuickStart가 있는데 어노테이션을 사용해서 더욱 쉽게 접근할 수 있도록 바꿔봤습니다.

http://www.netbeans.org/kb/61/web/quickstart-webapps-spring.html
요게 원문입니다. 영어지만, 그냥 코드만 보고 따라하셔도 스프링의 기초를 이해하실 수 있을껍니다.
이 예제를 조금 변경해봤습니다. 어노테이션을 이용한 HelloSpring으로-_-;(똑같이 하면 왠지 안될것같아서-_-)

우선 NetBeans6.1, JDK 5 or 6, GlassFish or Tomcat이 필요해요.

우선 처음에 프로젝트를 만듭니다.
New Project(Ctrl-Shift-N)을 선택해서 Web -> Web Application을 선택합니다.

프로젝트이름은 HelloSpring이라고 하고, Steps 4단계에서 Spring Web MVC 2.5를 선택하세요.
그리고 Finish를 클릭하세요.

그리고 F6을 누르면 GlassFish가 실행이 되고, 웹페이지가 뜨면서 아래와 같은 화면이 나올껍니다.

사용자 삽입 이미지


저 페이지는 index.jsp파일인데요. web.xml파일에 보면 welcome-file이 redirect.jsp로 되어있습니다. redirect.jsp파일을 열어보게 되면, index.htm을 요청하게 되어있습니다.
또 web.xml에서 servlet태그를 보면 *.htm요청으로 들어오는 놈들은 DispatcherServlet으로 넘기게 되어있습니다.
이 놈은 서블릿이름-servlet.xml파일을 설정파일을 사용합니다.
그러면 dispatcher-servlet.xml파일을 보게 되면, urlMapping이라는 bean이 있는데, 이 놈에서 mappings를 보면 index.htm이 요청일 경우 indexController를 실행하게 되어있습니다.
indexController는 아래에 bean으로 정의가 되어있죠.
indexController는 ParameterizableViewController클래스인데 이 클래스는 p:viewName값이 index인 것을 보여주는것이죠. index는 viewResolver bean에 의해서 /WEB-INF/jsp/index.jsp파일이죠.
그래서 index.jsp파일이 보여지는 것이죠.

초간단 설명을 마치고-_-; 폼에다가 이름을 입력하고, 전송하면 "Hello 이름!"을 리턴하는 프로그램을 만들어봅시다.

설정파일을 조금 변경해야합니다.
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"/>
요런 bean이 있는데, 이건 Controller의 클래스명으로 url매핑을 하는 겁니다. 즉 HelloController로 선언을 시켰으면 hello.htm요청으로 해당 컨트롤러를 호출할 수 있게 하는겁니다.
근데 이건 어노테이션을 사용하면 안 먹힙니다-_-; 걍 지워버립시다.
그리고, beans에 xmlns:context="http://www.springframework.org/schema/context"를 추가합니다.
그리고, xsi:schemaLocation에도
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
이렇게 추가합니다. 이는 <context: 를 사용하기 위함입니다.
그리고, 이 아래에 이걸 추가합니다.
<context:component-scan base-package="hellospring" />
이건 객체를 스캔하는 건데 @Service, @Controller, @Component 등의 어노테이션이 base--package아래있는 클래스들 전부 적용하게 합니다. 빈이름은 클래스명에 따라서 정해집니다. 예를 들어 HelloController이면 helloController라고 자동으로 등록됩니다.
그리고, urlMapping bean에다가 우리가 만들 HelloController를 등록합니다.
<prop key="/hello.htm">helloController</prop> 이렇게 한줄을 추가하면 됩니다.
바뀐 dispatcher-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:p="http://www.springframework.org/schema/p"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-2.5.xsd">
   
    <context:component-scan base-package="hellospring" />
   
    <bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="/index.htm">indexController</prop>
                <prop key="/hello.htm">helloController</prop>
            </props>
        </property>
    </bean>
   
    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver"
          p:prefix="/WEB-INF/jsp/"
          p:suffix=".jsp" />
   
    <bean name="indexController"
          class="org.springframework.web.servlet.mvc.ParameterizableViewController"
          p:viewName="index" />
   
</beans>
[/code]

우선 Service를 만들어봅시다.
Source Package에 오른쪽 버튼을 클릭하고, New -> Java Class를 선택합시다.
Class Name에는 HelloService라고 하고, Package에다가 hellospring.service라고 합시다.
[code]package hellospring.service;

@Service
public class HelloService {

    public String sayHello(String name) {
        return "Hello " + name + "!";
    }
}
[/code]
초간단 메소드입니다. name을 넣으면 Hello name! 을 리턴하게 하는 서비스입니다.

그 전에 폼으로 부터 데이터를 가져오는 bean을 하나 만들어봅시다.
Source Package에 오른쪽 버튼을 클릭하고, New -> Java Class를 선택합시다.
Class Name에는 Name이라고 하고, Package에다가 hellospring.domain라고 합시다.
[code]package hellospring.domain;

public class Name {
   
    private String value;
}
[/code]
여기서 getter, setter만드는 방법이 2가지가 있어요.

첫번째 방법은 Alt + Insert키를 누르면 Getter and Setter를 선택하면 해당 멤버변수에 대해서 나오는데 체크를 하고 Generate하면 됩니다.
두번째 방법은 소스에디터의 value에다가 마우스 오른쪽버튼을 클릭하고, Refactor -> Encapsulate선택하면 얘는 좀 더 상세하게 설정할 수 있습니다. 접근자를 수정할 수 있어요.
getter, setter가 완성이 되었습니다.

그 다음은 컨트롤러를 만들어봅시다.
Source Package에 오른쪽 버튼을 클릭하고, New -> Java Class를 선택합시다.
Class Name에는 HelloController라고 하고, Package에다가 hellospring.controller라고 합시다.
[code]@Controller
public class HelloController {

    @Autowired
    private HelloService helloService;
   
    private String formView = "nameView";
    private String successView = "helloView";
   
    @RequestMapping(method = RequestMethod.GET)
    public String hello() {
        return formView;
    }
   
    @RequestMapping(method = RequestMethod.POST)
    public String onSubmit(Name name, ModelMap model) {
        model.addAttribute("helloMessage", helloService.sayHello(name.getValue()));
        return successView;
    }
}
[/code]
여기서 보면 HelloService는 @Service라는 어노테이션을 사용해서 객체스캔으로 helloService라는 bean이름으로 등록이 되어있습니다. 그래서 @Autowired해버리면 helloService랑 자동으로 연결이 되죠.
그래서 helloService를 사용할 수 있습니다.

여기서 신기한 점은 @RequestMapping어노테이션이 있는데, GET방식이면 hello메소드를 호출하라는 겁니다.
그래서 처음에 form action을 하지 않은 상태에서는 hello메소드가 호출이 됩니다.
Controller어노테이션의 신기한점은 메소드의 리턴값이 String인데 이 값이 view이름이 됩니다.
formView는 nameView라고 적어놨는데, 이것은 viewResolver에 의해 nameView.jsp파일을 호출하게 됩니다.

더욱 신기한 점은 onSubmit메소드입니다. 값을 받아서 알아서 맞는 곳에다가 넣는 것 같습니다.
그리고 view에다가 값을 던져줄 때는 ModepMap이라는 클래스로 메소드파라메터에 넣고, 여기에 addAttribute를 해서 helloMessage값을 넣으면 됩니다.

이제 View를 만들어봅시다.
Web Page -> WEB-INF -> jsp를 선택하고 오른쪽 버튼 클릭, New해서 jsp선택.
formView이름을 nameView로 지었기 때문에 JSP File Name에 nameView라고 합니다.
[code]<body>
        <h2>Enter your name</h2>
        <form action="hello.htm" method="post">
            Name:
            <input type="text" name="value" />
            <input type="submit" value="OK" />
        </form>
    </body>
[/code]
action에서 hello.htm을 요청하는데 input필드는 한개입니다. 이름은 value입니다.
근데 신기하게도 우리가 만든 Controller를 보면 onSubmit에서 파라메터로 Name클래스로 받는 곳이 있습니다. 여기에 value멤버변수가 있는데 이름을 똑같이하면 그냥 Name클래스의 value값에 들어가버립니다-_-;

그럼 successView를 생성해봅시다.
Web Page -> WEB-INF -> jsp를 선택하고 오른쪽 버튼 클릭, New해서 jsp선택.
successView는 "helloView"라고 했기때문에 helloView라고 합니다.
[code]<h2>${helloMessage}</h2>
[/code]
라고 합니다. onSubmit메소드에서 넘겨주는 helloMessage값입니다.

그럼 이제 실행을 해봅시다.
http://localhost:8080/HelloSpring/hello.htm 라고 요청을 해봅시다.
그러면 Enter your name에다가 이름을 입력합시다.
이름이 나올껍니다.

사용자 삽입 이미지
사용자 삽입 이미지

아....자꾸 딴짓하네-_-; 일해야하는데-_-;

 
Posted by 머드초보
,
 

해당 메소드에서 catch해버리면 롤백이 안됩니다-_-;

[code]
@Transactional(readOnly=true, rollbackFor={Throwable.class})
 public void insertData() throws Throwable {
  try {
   getSqlMapClientTemplate().insert("insertData");
   System.out.println("oracle에 insert성공");
   throw new IOException();
  } catch (IOException e) {
   System.out.println("io예외발생");
  }
 }
[/code]

여기서 처럼 IOException이 발생했는데 해당 트랜젝션으로 설정한 메소드에서 예외를 catch해버리면 롤백이 안되더라구요-_-;
그 메소드를 호출한 놈한테 가서 해야합니다.
main에서 호출했다고 하면, main에 가서

[code]
try {
   testInsertOracle.insertData();
  } catch (Throwable e) {
   System.out.println("예외발생");
  }
[/code]
요렇게 해줘야 합니다. 메소드에 있는 catch는 빼구요 ^^

 
Posted by 머드초보
,
 

http://mudchobo.tomeii.com/tt/257 에 이어서-_-;

오라클에서 해보겠습니다.
아 우선 오라클용 jdbc가 필요해요!
ojdbc6.jar 등의 jbdc ^^

걍 오라클용 dataSource로 바꿔주면 돼요-_-;

applicationContext.xml
[code]
<!-- oracle용 -->
 <bean id="dataSource"
  class="org.springframework.jdbc.datasource.DriverManagerDataSource"
  p:driverClassName="oracle.jdbc.driver.OracleDriver"
  p:url="jdbc:oracle:thin:@localhost:1521:XE"
  p:username="dbid" p:password="dbpw" />

<bean id="insertDataOracle" class="com.mudchobo.TestInsertOracle"
  p:sqlMapClient-ref="sqlMapClient"/>
[/code]
아까 그 TestInsert 인터페이스입니다.
TestInsert.java
[code]
package com.mudchobo;

import org.springframework.transaction.annotation.Transactional;

public interface TestInsert {

 @Transactional(readOnly=true, rollbackFor={Throwable.class})
 public void insertData() throws Throwable;
 
}
[/code]
저기 선언된 bean인 TestInsertOracle을 구현해봅시다.
TestInsertOracle.java
[code]
package com.mudchobo;

import java.io.IOException;

import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;

public class TestInsertOracle extends SqlMapClientDaoSupport implements
  TestInsert {

 @Override
 public void insertData() throws Throwable {
   getSqlMapClientTemplate().insert("insertData");
   System.out.println("oracle에 insert성공");
   throw new IOException();
 }
}
[/code]
MySQL처럼 IOException을 임의로 발생시킵니다.
main부분을 봅시다.
TestTransaction.java
[code]
package com.mudchobo;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestTransaction {

 public static void main(String[] args) {
  String[] configLocation = {"applicationContext.xml"};
  ApplicationContext context =
   new ClassPathXmlApplicationContext(configLocation);
 
  TestInsert testInsertOracle =
   (TestInsert) context.getBean("insertDataOracle");
 
  try {
   testInsertOracle.insertData();
  } catch (Throwable e) {
   System.out.println("예외발생");
  }
 }
}
[/code]
오라클에서는 readOnly로 걸어 놨는데도 불구하고 insert가 됩니다.
그리고 예외를 발생시켰기 때문에 rollbackfor 값을 Throwable로 줬기때문에 IOException이 발생했을 때 롤백하게 됩니다. 잘보면 롤백이 되어있습니다.

오라클에서 set transaction read only 라고 쿼리를 날리면 transaction을 read only로 해버릴 수 있더라구요.
뭐 그냥 그렇다구요-_-;

 
Posted by 머드초보
,
 

스프링에서 제공하는 트랜젝션을 MySQL과 Oracle에다가 적용을 해봤습니다.
제가 잘 이해를 못하는 건지 모르겠는데, Oracle에서는 ReadOnly가 안먹혀요-_-;
MySQL에서는 먹히는데....-_-; Oracle에서는 자체적으로 transaction에서 ReadOnly를 설정하는게 있더군요.
또 Oracle은 트랜젝션기반이라고 하더라구요. 암튼, 참 어렵습니다-_-;
우선 삽질한 코드입니다.
MySQL로 해보았습니다.

필요한 lib입니다.
spring.jar - 스프링할껀데 필요하겠죠?-_-;
commons-logging.jar - 스프링하려면 이눔이 있어야 돼요-_-; 위에 있는 lib와 종속돼요-_-;
ibatis-2.3.0.677.jar - ibatis로 할껍니다. 이게 db연동을 쉽게 해주니까요-_-;
mysql-connector-java-5.1.5-bin.jar - mysql connector가 필요하겠죠!

프로젝트를 만듭시다. TestTransaction이라는 프로젝트를 만듭시다.
최상위 src폴더에다가 applicationContext.xml파일을 만듭시다.

applicationContext.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:p="http://www.springframework.org/schema/p"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xsi:schemaLocation="
  http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
  http://www.springframework.org/schema/tx
  http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">

 <tx:annotation-driven />
 
 <!-- MySQL용 -->
 <bean id="dataSource"
  class="org.springframework.jdbc.datasource.DriverManagerDataSource"
  p:driverClassName="com.mysql.jdbc.Driver"
  p:url="jdbc:mysql://db주소"
  p:username="dbid" p:password="dbpw" />
 
   <!--  Transaction manager for iBATIS Daos -->
 <bean id="transactionManager"
  class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
  p:dataSource-ref="dataSource" />
 
 <!-- SqlMap setup for iBATIS Database Layer -->
 <bean id="sqlMapClient"
  class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"
  p:dataSource-ref="dataSource"
  p:configLocation="classpath:SqlMapConfig.xml" />
 
<bean id="insertDataMysql" class="com.mudchobo.TestInsertMysql"
  p:sqlMapClient-ref="sqlMapClient"/>
</beans>
[/code]
TestInsert라는 interface를 작성해봅시다.
TestInsert.java
[code]
package com.mudchobo;

import org.springframework.transaction.annotation.Transactional;

public interface TestInsert {

 @Transactional(readOnly=true, rollbackFor={Throwable.class})
 public void insertData() throws Throwable;
}
[/code]
인터페이스에다가 트랜젝션을 걸어도 되더라구요-_-; 구현되는 모든놈이 저 옵션으로 트랜젝션이 먹히는 듯 합니다. 근데 별로 안좋은 방법인듯한데-_-; 그냥 메소드에 거는게.....-_-; 보면 readOnly옵션에다가 Throwable예외가 발생하면 롤백합니다.

구현해봅시다.
TestInsertMysql.java
[code]
package com.mudchobo;

import java.io.IOException;

import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;

public class TestInsertMysql extends SqlMapClientDaoSupport implements
  TestInsert {

 @Override
 public void insertData() throws Throwable {
   getSqlMapClientTemplate().insert("insertData");
   System.out.println("mysql에 insert성공");
   throw new IOException();
 }
}
[/code]
insert를 시키고, 강제로 IOException을 발생시켰습니다.

ibatis xml부분을 봅시다.
SqlMapConfig.xml
[code]
<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE sqlMapConfig     
    PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"     
    "http://ibatis.apache.org/dtd/sql-map-config-2.dtd">

<sqlMapConfig>
 <sqlMap resource="Insert.xml" />
</sqlMapConfig>
[/code]
Insert.xml
[code]
<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE sqlMap     
PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"     
"http://ibatis.apache.org/dtd/sql-map-2.dtd">

<sqlMap namespace="Sqlmap">
    <insert id="insertData">
     insert into TESTDATA (DATA) values ('MUDCHOBO')
    </insert>
</sqlMap>
[/code]
보시면 단순 insert를 하고 있습니다-_-;

main부분입니다.
TestTransaction.java
[code]
package com.mudchobo;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestTransaction {
 public static void main(String[] args) throws Throwable{
  String[] configLocation = {"applicationContext.xml"};
  ApplicationContext context =
   new ClassPathXmlApplicationContext(configLocation);
 
  TestInsert testInsertMysql =
   (TestInsert) context.getBean("insertData");
  try {
   testInsertMysql.insertData();
  } catch (Throwable e) {
   System.out.println("예외발생");
  }
}
[/code]
이걸 실행하면 트랜젝션이 readOnly이기 때문에 insert하려고 하면 에러가 나버리겠죠.
Connection is read-only. Queries leading to data modification are not allowed; nested exception is com.ibatis.common.jdbc.exception.NestedSQLException:
요런 에러를 보실 수 있습니다.

Oracle은 다음 장에서-_-;
http://mudchobo.tomeii.com/tt/258 여기에 계속-_-;

 
Posted by 머드초보
,