SAStrutsを勉強してみる (3) - S2JDBCを使う -

2012-10-04T00:00:00+00:00 Java SAStruts

タイトル通り。S2JDBCを使ってMySQLデータベースに接続してテーブルにアクセスしてみる

pom.xml

<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>5.1.21</version>
</dependency>
<dependency>
  <groupId>javax.persistence</groupId>
  <artifactId>toplink-essentials</artifactId>
  <version>1.0</version>
</dependency>
<dependency>
  <groupId>org.apache.geronimo.specs</groupId>
  <artifactId>geronimo-jta_1.1_spec</artifactId>
  <version>1.0</version>
</dependency>
<dependency>
  <groupId>org.apache.geronimo.specs</groupId>
  <artifactId>geronimo-ejb_3.0_spec</artifactId>
  <version>1.0</version>
</dependency>

src/main/resources/s2jdbc.dicon

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN" "http://www.seasar.org/dtd/components24.dtd">
<components>
    <include path="jdbc.dicon"/>
    <include path="s2jdbc-internal.dicon" />
    <component name="jdbcManager" class="org.seasar.extension.jdbc.manager.JdbcManagerImpl">
        <property name="maxRows">0</property>
        <property name="fetchSize">0</property>
        <property name="queryTimeout">0</property>
        <property name="dialect">mysqlDialect</property>
    </component>
</components>

dialectはMySQL以外とかだとそれに応じた値を設定する。んでJDBC接続な情報はjdbc.diconに設定する

src/main/resources/jdbc.dicon

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE components PUBLIC "-//SEASAR2.1//DTD S2Container//EN" "http://www.seasar.org/dtd/components21.dtd">
<components namespace="jdbc">
    <include path="jta.dicon"/>

    <component name="xaDataSource" class="org.seasar.extension.dbcp.impl.XADataSourceImpl">
        <property name="driverClassName">"com.mysql.jdbc.Driver"</property>
        <property name="URL">"jdbc:mysql://localhost:3306/sample"</property>
        <property name="user">"username"</property>
        <property name="password">"password"</property>
    </component>

    <component name="connectionPool"
        class="org.seasar.extension.dbcp.impl.ConnectionPoolImpl">
        <property name="timeout">600</property>
        <property name="maxPoolSize">10</property>
        <property name="allowLocalTx">true</property>
        <destroyMethod name="close"/>
    </component>

    <component name="DataSource"
        class="org.seasar.extension.dbcp.impl.DataSourceImpl"
    />
</components>

んまぁxaDataSourceな所をいじれば良いみたい。でMySQLで

CREATE TABLE sample(
  id int auto_increment primary key,
  data varchar(255) NOT NULL UNIQUE,
  created_at datetime NOT NULL
) ENGINE=InnoDB

とかをデータベースにテーブルを作っておく。あとはクラス群を作る

sample.entity.Sample

package sample.entity;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

@Entity
@Table(name = "sample")
public class Sample {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    public int id;

    @Column(name = "data", nullable = false, unique = true)
    public String data;

    @Column(name = "created_at", nullable = false, unique = false)
    @Temporal(TemporalType.DATE)
    public Date date;

    @Override
    public String toString() {
        return String.format("[%s]: %s", id, data);
    }
}

publicにしたくなければ普通にgetter/setterを書けば良いみたい

参照

sample.service.SampleService

まぁService系を使ってデータベースとの手続きに関する処理を定義すれば良いのかも

package sample.service;

import java.util.List;
import javax.annotation.Resource;

import org.seasar.extension.jdbc.JdbcManager;
import org.seasar.extension.jdbc.OrderByItem;
import org.seasar.extension.jdbc.OrderByItem.OrderingSpec;
import org.seasar.extension.jdbc.exception.SEntityExistsException;
import org.seasar.extension.jdbc.where.SimpleWhere;
import org.seasar.framework.exception.SQLRuntimeException;

import sample.entity.Sample;

public class SampleService {

    @Resource
    private JdbcManager jdbcManager;

    public List<Sample> getSamples() {
        OrderByItem order = new OrderByItem("id", OrderingSpec.DESC);

        return jdbcManager.from(Sample.class).orderBy(order).getResultList();
    }

    public List<Sample> getSamples(String[] ids) {
        SimpleWhere where = new SimpleWhere();
        where.in("id", (Object[])ids);

        return jdbcManager.from(Sample.class).where(where).getResultList();
    }

    public Sample getSampleById(int id) {
        return jdbcManager.from(Sample.class).where("id = ?", id).getSingleResult();
    }

    public Sample createSample(Sample sample) {
        Sample createdSample = null;

        try {
            int rowUpdate = jdbcManager.insert(sample).execute();

            if (rowUpdate > 0) {
                createdSample = sample;
            }
        } catch (SEntityExistsException e) {
            e.printStackTrace();
        } catch (SQLRuntimeException e) {
            e.printStackTrace();
        }

        return createdSample;
    }

    public boolean deleteSamples(List<Sample> samples) {
        boolean deleteSuccessfulFlag = false;

        try {
            if (jdbcManager.deleteBatch(samples).execute().length > 0) {
                deleteSuccessfulFlag = true;
            }
        } catch (SQLRuntimeException e) {
            e.printStackTrace();
        }

        return deleteSuccessfulFlag;
    }
}

sample.form.Sample2Form

package sample.form;

import org.seasar.struts.annotation.IntegerType;
import org.seasar.struts.annotation.Required;

public class Sample2Form {

    @Required(target = "show")
    @IntegerType
    public String id;

    @Required(target = "add")
    public String data;

    @Required(target = "delete")
    public String[] checkId;
}

sample.action.Sample2Action

package sample.action;

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

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

import org.seasar.framework.beans.util.Beans;
import org.seasar.struts.annotation.ActionForm;
import org.seasar.struts.annotation.Execute;
import org.seasar.struts.enums.SaveType;
import org.seasar.struts.util.ResponseUtil;

import sample.entity.Sample;
import sample.form.Sample2Form;
import sample.service.SampleService;

public class Sample2Action {

    @Resource
    private HttpServletResponse response;

    @ActionForm
    @Resource
    protected Sample2Form sample2Form;

    @Resource
    private SampleService sampleService;

    public List<Sample> samples;

    @Execute(validator = false, removeActionForm = true)
    public String index() {
        samples = sampleService.getSamples();

        return "index.jsp";
    }

    @Execute(input = "?redirect=true", saveErrors = SaveType.SESSION, redirect = true)
    public String add() {
        Sample sample = Beans.createAndCopy(Sample.class, sample2Form).execute();
        sample.date = new Date();

        sampleService.createSample(sample);

        return new String();
    }

    @Execute(validator = false, urlPattern = "show/{id}")
    public String show() {
        Sample sample = sampleService.getSampleById(Integer.parseInt(sample2Form.id));

        if (sample != null) {
            ResponseUtil.write(sample.toString(), "text/plain");
        } else {
            try {
                response.sendError(404);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return null;
    }

    @Execute(input = "?redirect=true", saveErrors = SaveType.SESSION, redirect = true)
    public String delete() {
        List<Sample> samples = sampleService.getSamples(sample2Form.checkId);

        sampleService.deleteSamples(samples);

        return new String();
    }
}

src/main/webapp/WEB-INF/views/sample2/index.jsp

<html>
  <body>
    <html:errors />
    <s:form>
      <html:text property="data" />
      <input type="submit" name="add" value="追加" />
    </s:form>
    <s:form>
      <c:forEach var="sample" items="${samples}">
      <div>
        <html:checkbox property="checkId" value="${sample.id}" />
        <s:link href="show/${sample.id}"><c:out value="${sample.data}" /></s:link>
      </div>
      </c:forEach>
      <input type="submit" name="delete" value="削除" />
    </s:form>
  </body>
</html>

てな感じかと。

追記

Entityなサービスに関してはS2AbstractServiceを継承して使うのを推奨しているらしい。なので自前でServiceクラスな所でJdbcServiceを注入させるようなのは必要ない模様

SAStrutsを勉強してみる (4) - S2JUnit4でテスト - SAStrutsを勉強してみる (2) - ActionForm -