<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    大漠駝鈴

    置身浩瀚的沙漠,方向最為重要,希望此blog能向大漠駝鈴一樣,給我方向和指引。
    Java,Php,Shell,Python,服務(wù)器運(yùn)維,大數(shù)據(jù),SEO, 網(wǎng)站開發(fā)、運(yùn)維,云服務(wù)技術(shù)支持,IM服務(wù)供應(yīng)商, FreeSwitch搭建,技術(shù)支持等. 技術(shù)討論QQ群:428622099
    隨筆 - 238, 文章 - 3, 評(píng)論 - 117, 引用 - 0
    數(shù)據(jù)加載中……

    A Blog Application with Warp (continued)(3)

    A Blog Application with Warp (continued)

    First check out the previous tutorial on creating a Blog application to get yourself going. In that article, you saw how to add forms and a bit of interactivity. In this one, I'll demonstrate integration of Warp-persist, the JPA/Hibernate module. It is worthwhile reading the introduction to the Warp-persist module first. You will learn the following Warp concepts:

    The first thing to do is modify our data model POJO (Blog) and make it a mapped JPA entity:

    @Entity
    public class Blog {
    private Long id;
    private String subject;
    private String text;
     

    @Id @GeneratedValue
    public Long getId() {
    return id;

    //rest of the getters/setters + equals() + hashCode()

    }

    The most obvious addition here is that of a surrogate key, a Long field id that represents the identity of the object. We have also marked its getter as the identity and the class itself as a JPA entity with the @Id and @Entity annotations respectively.

    Remember that you absolutely must override equals() and hashCode() -- this is done by simply returning the equals and hashCode of the id field. It is a poor programming practice to create data model objects and not define equals() and hashCode() for them, it will lead to all kinds of problems if you do not.

    OK, let's drop in a simple persistence.xml into our /META-INF directory so that Hibernate knows our configuration. I've stolen this from the Warp-persist guide:

    <?xml version="1.0" encoding="UTF-8" ?>
    <persistence xmlns="http://java.sun.com/xml/ns/persistence"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
    http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">

    <!-- A JPA Persistence Unit -->
    <persistence-unit name="blogJpaUnit" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
     
    		<!-- JPA entities must be registered here -->
    <class>com.wideplay.misc.blog.Blog</class>

    <properties>
    			<!-- vendor-specific properties go here -->
    </properties>
    </persistence-unit>

    </persistence>

    Not much to notice here except that Hibernate is our persistence provider and we're using RESOURCE_LOCAL transactions. Inside the <properties> tag, however, you need to place all your configuration options (for whatever JPA vendor you choose). For Hibernate, mine looks like the following:

    <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/>
    <property name="hibernate.connection.url" value="jdbc:hsqldb:file:C:/temp/hsqltmp"/>
    <property name="hibernate.connection.username" value="sa"/>
    <property name="hibernate.connection.password" value=""/>
    <property name="hibernate.connection.pool_size" value="1"/>
    <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>

    <property name="hibernate.current_session_context_class" value="thread"/>
    <property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider"/>
    <property name="hibernate.hbm2ddl.auto" value="create"/>

     Again, it is mostly boilerplate. Never use this configuration directly in production, the following things that it assumes are almost certainly not what you will want in a real-world application:

    • Im using HSQLDB (a temporary in-memory database)
    • I am using Hibernate's default connection pool
    • I am creating the schema every time Hibernate starts up (hbm2ddl.auto=create)
    • I am not using any second-level cache

    Otherwise everything is fine. The session-context strategy is set to thread meaning that the current thread (in our case, that associated with a request) will be used as the context for an EntityManager. So different requests will see different EntityManagers.

    Now, we need to tell Warp that the persistence service is ready for use. This is done in the WarpModule (which you should remember from the Hello World example). This is roughly how your WarpModule should look:

    public class BlogModule implements WarpModule {

    public void configure(Warp warp) {
    warp.install(PersistenceService
    .usingJpa()
    .across(UnitOfWork.TRANSACTION)
    .buildModule()
    );

    warp.install(new AbstractModule() {
    protected void configure() {
    bindConstant().annotatedWith(JpaUnit.class)
    .to("blogJpaUnit");
    }
    });

    warp.addStartupListener(BlogStartupListener.class);
    }
    }

     And implement the startup listener to do some initialization work:

       public class BlogStartupListener implements StartupListener {
    @Inject PersistenceService service;

    public void onStartup() {
    service.start();
    }
    }

     This tells Warp-persist to start up JPA and make the persistence layer ready when Warp starts up. Likewise, you must tell Warp when to shutdown too (services like connection pools require explicit shutdowns):

       public class BlogShutdownListener implements ShutdownListener {
    @Inject EntityManagerFactory emf;

    public void onShutdown() {
    emf.close();
    }
    }

     Don't forget to add the BlogShutdownListener in your WarpModule configuration. You do not need to release any Warp resources explicitly (Warp acts on the Java Servlet destroy event).

    OK, wow, we're done a lot of setup work. Let's actually convert our blog's pages to use all this neat configuration. First the ListBlogs page:

    @URIMapping("/home")
    public class ListBlogs {
    @Finder(query = "from Blog", returnAs = ArrayList.class)
    public Collection<Blog> getBlogList() {
    return null;
    }
    }

     It looks completely different now! What happened? We've done a few things:

    • Gotten rid of the HashMap and @Singleton scoping
    • Converted our property getter for the blog list into a Dynamic Finder
    • Implemented a dummy stub for the Dynamic Finder

    The finder will be intercepted by warp-persist and replaced with the query provided in the @Finder annotation. In this case, we're selecting every Blog available in the persistent store and returning them as an ArrayList.

    Now lets do the Read page, this is similarly very simple. We will use a Dynamic Finder encapsulated in our @PreRender event handler method:

    @URIMapping("/blog/{id}")
    public class ViewBlog {
    private Blog blog;

    @Finder(query = "from Blog where id = :id")
    Blog fetchBlog(@Named("id") String id) {
    return null;
    }

    @OnEvent @PreRender @Transactional
    public void onView(String id) {
    this.blog = fetchBlog(Long.valueOf(id)); //dangerous, validate id first!
    }
    }

    Neat, because the page objects are managed by guice, dynamic dispatch will ensure that calling fetchBlog() invokes the intercepted Dynamic Finder instead of our dummy stub which returns null. It is important to make the @PreRender event handler transactional because we are using a session-per-transaction strategy. Let's do the same with ListBlogs too:

    @URIMapping("/home")
    public class ListBlogs {
    @Transactional
    @Finder(query = "from Blog", returnAs = ArrayList.class)
    public Collection<Blog> getBlogList() {
    return null;
    }
    }

    Typically we would prefer to encapsulate data access into an Accessor (Dao) style object. and run transactions on much coarser grained boundaries. But since our use case is very simple, I will leave it to your imagination to separate data access into its own semantic module/layer.

    Lastly for the good part: storing new blogs!

    @URIMapping("/blogs/compose")
    public class ComposeBlog {
    @Inject @Page private ListBlogs listBlogsPage;

    @Inject private Provider<EntityManager> em;

    private Blog newBlog = new Blog("", ""); //an empty blog

    @OnEvent @Transactional
    public ListBlogs save() {
    //save the new blog!
    em.get().persist(newBlog);

    //return to the list page
    return listBlogsPage;
    }

    public Blog getNewBlog() {
    return newBlog;
    }
    }

    This is fairly straightforward and should not need much explanation. We associate the new blog entity with the EntityManager by calling persist() and ensure that the button event handler is transactional.

    There is almost no change to the templates themselves, except that now we have switched the identity of our data object Blog to use a surrogate key. Let's use that key to reference blogs in our ListBlogs.html template:

    <?xml version="1.0" encoding="UTF-8"?>
    <html xmlns:w="http://www.wideplay.com/warp/schema/warp_core.xsd"
    xmlns="http://www.w3.org/1999/xhtml"
    xml:lang="en" lang="en">

    <head w:component="meta">
    <title>Warp :: List Blogs</title>
    </head>

    <body w:component="frame">
    <h1>A list of blog entries</h1>

    <table w:component="table" w:items="${blogList}">
    <td w:component="column" w:property="subject">
    <a w:component="hyperlink" w:target="blog" w:topic="${id}">
    ${subject}
    </a>
    </td>
    </table>

    <a href="blogs/compose">compose new entry</a>

    </body>
    </html>
    And that's it!

    posted on 2009-02-17 16:31 草原上的駱駝 閱讀(253) 評(píng)論(0)  編輯  收藏


    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 国产小视频免费观看| 亚洲区不卡顿区在线观看| 精品女同一区二区三区免费站| 999国内精品永久免费观看| 国产一级高清视频免费看| 亚洲色大成网站WWW久久九九 | 亚洲人成免费网站| 亚洲另类无码专区丝袜| 岛国岛国免费V片在线观看| 国产又黄又爽又猛免费app| 亚洲精品国产精品乱码视色| 亚洲中文字幕无码mv| 国产一级片免费看| 波多野结衣久久高清免费 | 亚洲精品麻豆av| h视频在线观看免费| 午夜私人影院免费体验区| 亚洲av无码乱码国产精品fc2| 亚洲欧美日韩综合久久久久| 国产福利免费在线观看| 亚洲精品偷拍视频免费观看| 亚洲AV无码第一区二区三区| 亚洲精品免费在线视频| 亚洲AV日韩精品久久久久| 在线播放国产不卡免费视频| 成年人免费视频观看| 亚洲黄色三级网站| 中文字幕免费不卡二区| 中文字幕亚洲专区| 男女作爱免费网站| 免费在线不卡视频| 国产综合成人亚洲区| 毛片大全免费观看| 亚洲中文字幕日本无线码| 午夜国产精品免费观看| 偷自拍亚洲视频在线观看| 亚洲成AV人片在线播放无码| 久久精品免费大片国产大片| 自拍偷自拍亚洲精品第1页| 亚洲阿v天堂在线2017免费| 亚洲精品不卡视频|