昨日ポストした内容をSpringMVCでのWebアプリに拡張する。
今回も同様に全てインメモリで作る。使用するのは以下。
- jetty7
- hibernate3
- spring2.5.5
- h2
プロジェクト構成
Eclipseで新規Javaプロジェクト作成し、「WebContent/WEB-INF/classe」「WebContent/WEB-INF/jsp」フォルダを作成しておく。
出力先フォルダを「/WebContent/WEB-INF/classes」に設定する。
「WEB-INF」直下にweb.xml作成
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>*.form</url-pattern> </servlet-mapping> </web-app>
同じ場所に、springmvc-servlet.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" 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/tx http://www.springframework.org/schema/tx/spring-tx-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="etc9.dao,etc9.service,etc9.controller"/> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="org.h2.Driver"/> <property name="url" value="jdbc:h2:tcp://localhost:9092/spring"/> <property name="username" value="sa"/> <property name="password" value=""/> </bean> <tx:annotation-driven transaction-manager="txManager"/> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="hibernateProperties"> <value> hibernate.dialect = org.hibernate.dialect.H2Dialect hibernate.show_sql = true hibernate.format_sql = true hibernate.hbm2ddl.auto = create </value> </property> <property name="annotatedClasses"> <list><value>etc9.domain.Product</value></list> </property> </bean> </beans>
先に示したライブラリをクラスパスに追加する。jettyはJSPを使用するため、「\lib\jsp-2.1」内のライブラリも追加追加する。(ライブラリ多いので後でApache Ivy導入しよう・)
実装
パッケージは以下を作成することにする。
ProductController.javaから
package etc9.controller; ・・・ @Controller public class ProductController { @Autowired private ProductService indexService; @RequestMapping("/product") public ModelAndView product() { List<Product> productList = indexService.invoke("java"); ModelAndView mav = new ModelAndView(); mav.setViewName("/WEB-INF/jsp/product.jsp"); mav.addObject("productList", productList); return mav; } }
続いてDao
package etc9.dao; ・・・ public interface ProductDao { List<Product> loadProductsByCategory(final String category) throws DataAccessException; Product get(Long id); void save(Product product); }
package etc9.dao; ・・・ @Repository public class ProductDaoImpl implements ProductDao { private HibernateTemplate hibernateTemplate; @Autowired(required=true) public void setSessionFactory(SessionFactory sessionFactory) { this.hibernateTemplate = new HibernateTemplate(sessionFactory); } @Override @SuppressWarnings("unchecked") public List<Product> loadProductsByCategory(final String category) throws DataAccessException { return (List<Product>) this.hibernateTemplate.execute(new HibernateCallback(){ @Override public Object doInHibernate(Session session) throws HibernateException, SQLException { Criteria criteria = session.createCriteria(Product.class); criteria.add(Restrictions.eq("category", category)); criteria.setMaxResults(6); return criteria.list(); }}); } @Override public Product get(final Long id) { return (Product) this.hibernateTemplate.get(Product.class, id); } @Override public void save(final Product product) { this.hibernateTemplate.save(product); } }
続いてdomain
package etc9.domain; ・・・ @Entity public class Product { private Long id; private String name; private String category; private Integer price; public Product() {} public Product(String name, String category, Integer price) { this.name = name; this.category = category; this.price = price; } @Id @GeneratedValue(strategy = GenerationType.IDENTITY) public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getCategory() { return category; } public void setCategory(String category) { this.category = category; } public Integer getPrice() { return price; } public void setPrice(Integer price) { this.price = price; } }
続いてサービス
package etc9.service; ・・・ public interface ProductService { public List<Product> findProduct(String category); }
package etc9.service; ・・・ @Service("indexService") @Transactional public class ProductServiceImpl implements ProductService { @Autowired(required=true) private ProductDao productDao; @Transactional @Override public List<Product> findProduct(String category) { Product p1 = new Product("hibernate", "java", 1000); Product p2 = new Product("spring", "java", 1500); productDao.save(p1); productDao.save(p2); return productDao.loadProductsByCategory(category); } }
各実装クラスには、@Controller、@Repository、@Serviceのアノテーションを付与し、役割に応じた設定をspringに任せる。このへんの話はspringの本家のドキュメントか、日本語ならhttp://itpro.nikkeibp.co.jp/article/COLUMN/20090604/331310/?ST=develop&P=1とかを参照のこと。
最後にサーバ起動用のランチャーを作成
public class H2Server { private static final String TCP_PORT = "9092"; private static final String WEB_PORT = "8082"; private static final String BASE_DIR = "db\\h2"; private final org.h2.tools.Server tcpServer; private final org.h2.tools.Server webServer; public H2Server() { this(BASE_DIR, TCP_PORT, WEB_PORT); } public H2Server(String baseDir, String tcpPort, String WebPort) { try { tcpServer = org.h2.tools.Server.createTcpServer( new String[] { "-baseDir", baseDir, "-tcpPort", tcpPort }); webServer = org.h2.tools.Server.createWebServer( new String[] { "-baseDir", baseDir, "-tcpPort", WebPort }); } catch (Exception e) { throw new RuntimeException(e); } } public void stop() { Exception remindEx = null; try { tcpServer.stop(); }catch (Exception e) { remindEx = e; } try { webServer.start(); } catch (Exception e) { remindEx = e; } if (remindEx != null) throw new RuntimeException(remindEx); } public void start() { try { tcpServer.start(); webServer.start(); }catch (Exception e) { throw new RuntimeException(e); } } }
public class JettyServer { private static final int PORT = 8080; private static final String WAR_PATH = "WebContent"; private static final String CONTEXT_PATH = "/web"; private final org.eclipse.jetty.server.Server server; public JettyServer() { this(PORT, WAR_PATH, CONTEXT_PATH); } public JettyServer(int port, String warPath, String contextPath) { server = new org.eclipse.jetty.server.Server(port); ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); server.setHandler(context); WebAppContext web = new WebAppContext(warPath, contextPath); server.setHandler(web); } public void stop() { try { server.stop(); } catch (Exception e) { throw new RuntimeException(e); } } public void start() { try { server.start(); server.join(); } catch (Exception e) { throw new RuntimeException(e); } } }
最後にランチャー
package etc9.tools; public class ServerLauncher { public static void main(String[] args) { new H2Server().start(); new JettyServer().start(); } }
JSP
<%@ page contentType="text/html;charset=Shift_JIS" %> <%@ page session="false" %> <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %> <html> <head> <title>商品一覧</title> </head> <body> <div align="center" class="body"> <h2>商品一覧</h2> <table border="1"> <tr class="header"> <th align="center" width="80">商品ID</th> <th align="center" width="320">商品名</th> <th align="center" width="100">価格</th> </tr> <c:forEach items="${productList}" var="product"> <tr class="record"> <td align="center"> <c:out value="${product.id}" /> </td> <td align="left"> <c:out value="${product.name}" /> </td> <td align="right"> <c:out value="${product.price}" />円 </td> </tr> </c:forEach> </table> </div> </body> </html>
http://localhost:8080/web/product.formにアクセスして商品一覧が表示されれば成功。