Spring MVC + jpa框架搭建,及全面分析


一,hibernate與jpa的關系

首先明確一點jpa是什么?以前我就搞不清楚jpa和hibernate的關系。

1,JPA(Java Persistence API)是Sun官方提出的Java持久化規范。它為Java開發人員提供了一種對象/關系映射工具來管理Java應用中的關系數據。而Hibernate是它的一種實現。除了Hibernate,還有EclipseLink(曾經的toplink),OpenJPA等可供選擇,所以使用Jpa的一個好處是,可以更換實現而不必改動太多代碼。
2,Hibernate作為JPA的一種實現,jpa的注解已經是hibernate的核心,hibernate只提供了一些補充,而不是兩套注解。hibernate對jpa的支持夠足量,在使用hibernate注解建議使用jpa。

(上面兩句話是磚家的回答,http://zhidao.baidu.com/link?url=Crp8dwDmn1BrSTabvPu409AmbJhfQ91mASpvWHvhXkfImPA4LZ1PZvp5iTqzQ3x3RzkT4CMfh6n8Yl8pAgb_WK)

 

由此可見,是hibernate實現了jpa。而hibernate實現jpa的結果是怎樣呢?

                   我的理解是有兩點:1充分體現orm思想。2jpa的注解非常方便。

 

總結下,JPA和Hibernate之間的關系。可以簡單的理解為JPA是標准接口,Hibernate是實現。那么Hibernate是如何實現與 JPA 的這種關系的呢。

Hibernate主要是通過三個組件來實現的,及hibernate-annotation、hibernate-entitymanager和hibernate-core。

 

由此又可見,hibernate還可以不去實現jpa。那是怎樣的情景呢?如果你單獨學習hibernate便會體驗到了。

在hibernate中,通常配置對象關系映射關系有兩種,一種是基於xml的方式,另一種是基於annotation的注解方式。

前者不贅述,而后者基於annotation的注解方式與jpa聯系緊密,因為它包含jpa的標准,並添加少量hibernate獨有的。

而在jpa出現之前,hibernate配置對象關聯映射只有基於xml的方式。

 

我是最不喜歡寫那種任何實體-數據庫映射信息都寫在配置文件xml里面的那種項目。所以使用注解是我心目中先進有力的方式。

所以,我選擇spring+jpa!

二,Spring MVC + jpa框架搭建思路分析

spring mvc也就是一個三層架構而已,最底下是:持久層。中間是:控制層。上層是:頁面。

為啥要分三層呢?因為最上層不需要與最底層聯通。按照軟件開發術語叫解耦。

所以,搭建spring mvc就是先搞,上層和中間,再搞中間和下層。

三,上層和中間

配置文件spring-mvc.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:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation=
       "http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
       http://www.springframework.org/schema/context 
       http://www.springframework.org/schema/context/spring-context-3.2.xsd
       http://www.springframework.org/schema/mvc 
       http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
       http://www.springframework.org/schema/util 
       http://www.springframework.org/schema/util/spring-util-3.2.xsd">

     <!-- 這個標簽注冊了Spring MVC分發請求到控制器所必須的DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter實例 -->
     <mvc:annotation-driven/>
     
    <context:component-scan base-package="com.controller"/>
    
    <!-- 定義視圖解析器viewResolver -->
    <bean id = "viewResolver"
           class = "org.springframework.web.servlet.view.InternalResourceViewResolver">
           <property name = "prefix" value = "/WEB-INF/jsp/"/>
           <property name = "suffix" value = ".jsp"/>
    </bean>
</beans>

 這個文件其實就是定義了對前端請求的處理,以及處理結果怎樣給到前端。也就是處理,上層-中間層間的關系。

具體講就是,spring先攔截了前端的請求,這個攔截配置在web.xml里面。不贅述。

前端的請求要找到對應的controller類。這時spring要通過注解。<context:component-scan base-package="com.controller"/>這一句,表明要自動掃描,com.controller包。

package com.controller;

import java.util.List;

import javax.annotation.Resource;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.entity.User;
import com.service.UserService;

@Controller
@RequestMapping("/path01/path02")
public class HelloController {

    @Resource(name = "userServiceImpl")
    private UserService userService;
    
    @RequestMapping("/hello.form")
    public String execute(Model model) throws Exception{
        List<User> users = userService.findAllUser();
        model.addAttribute("users",users);
        return "hello";
    }
    
}

有了@Controller這個注解就會被掃描到。

    <!-- 定義視圖解析器viewResolver -->
    <bean id = "viewResolver"
           class = "org.springframework.web.servlet.view.InternalResourceViewResolver">
           <property name = "prefix" value = "/WEB-INF/jsp/"/>
           <property name = "suffix" value = ".jsp"/>
    </bean>

這句定義怎樣將處理結果返回。返回到/WEB-INF/jsp/下面的jsp頁面。

<%@page pageEncoding="utf-8" contentType="text/html;charset=utf-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
    <title>Spring Hello World!</title>
</head>
<body>
      hello Spring MVC,日向 2016-03
       <c:forEach items="${users}" var="user">
           id為${user.id}||用戶名為${user.username}
       </c:forEach>
</body>
</html>

 關鍵是,<mvc:annotation-driven/>這一句。

<mvc:annotation-driven /> 是一種簡寫形式,完全可以手動配置替代這種簡寫形式,簡寫形式可以讓初學都快速應用默認配置方案。

<mvc:annotation-driven /> 會自動注冊DefaultAnnotationHandlerMapping與AnnotationMethodHandlerAdapter 兩個bean,是spring MVC為@Controllers分發請求所必須的。

(from:http://kingliu.iteye.com/blog/1972973)

所以<mvc:annotation-driven />的本質其實是DefaultAnnotationHandlerMapping與AnnotationMethodHandlerAdapter 兩個bean。

 

網上可以借鑒的回答:

http://kingliu.iteye.com/blog/1972973

http://zhidao.baidu.com/link?url=CvJjOeWrEtf8UXaiowxsDk2rDYHPm7h7GjKMb25Fdu6fWGEsoB3II4gORHOL6U_M3V7JLVfYfQVmDZhjzyIj82O8Vopjghl7Nv_-h9noYoS

四,中間和下層

spring-common.xml:

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    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.2.xsd
           http://www.springframework.org/schema/context 
           http://www.springframework.org/schema/context/spring-context-3.2.xsd
           http://www.springframework.org/schema/tx      
           http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">

    
    <!-- 配置數據源 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost/db_shop"></property>
        <property name="username" value="root"></property>
        <property name="password" value="1234"></property>
    </bean>
    

   <!-- LocalContainerEntityManagerFactoryBean spring配置jpa的三種方式之一,適用於所有環境的FactoryBean
                           ,能全面控制EntityManagerFactory配置 -->
   <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
       <property name="dataSource" ref="dataSource"/>
       <!-- 設定為自動掃描,spring新特性,有了packagesToScan,我們不再需要自己動手去實現實體類的掃描了 -->
       <property name="packagesToScan" value="com.entity"/>
       <property name="jpaVendorAdapter">
           <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
               <property name="showSql" value="true"/>
               <!-- generateDdl= true表示自動生成DDL-->
               <property name="generateDdl" value="true" />
               <property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
           </bean>
       </property>
    </bean>
    
    <!-- 定義事務管理器  --> 
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
   
    <!-- 注解掃描 -->
    <context:component-scan base-package="com" />  
  
     <!--對@Transactional這個注解進行的驅動,這是基於注解的方式使用事務配置聲明,這樣在具體應用中可以指定對哪些方法使用事務。 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
   
</beans>

 

dataSource作用:

public interface DataSource
該工廠用於提供到此 DataSource 對象表示的物理數據源的連接。作為 DriverManager 設施的替代項,DataSource 對象是獲取連接的首選方法。實現 DataSource 接口的對象通常在基於 JavaTM Naming and Directory Interface (JNDI) API 的命名服務中注冊。 DataSource 接口由驅動程序供應商實現。共有三種類型的實現: 基本實現 - 生成標准 Connection 對象 
連接池實現 - 生成自動參與連接池的 Connection 對象。此實現與中間層連接池管理器一起使用。 
分布式事務實現 - 生成一個 Connection 對象,該對象可用於分布式事務,並且幾乎始終參與連接池。此實現與中間層事務管理器一起使用,並且幾乎始終與連接池管理器一起使用。 
DataSource 對象的屬性在需要時可以修改。例如,如果將數據源移動到另一個服務器,則可更改與服務器相關的屬性。其優點是,因為可以更改數據源的屬性,所以任何訪問該數據源的代碼都無需更改。 通過 DataSource 對象訪問的驅動程序不會向 DriverManager 注冊。通過查找操作檢索 DataSource 對象,然后使用該對象創建 Connection 對象。使用基本的實現,通過 DataSource 對象獲取的連接與通過 DriverManager 設施獲取的連接相同。

 

entityManagerFactory:

配置entityManagerFactory說明這是配置的jpa。因為我記得hibernate是配置sessionFactory的。

entityManagerFactory,顧名思義,就是managerFactory的工廠。我們使用的類是LocalContainerEntityManagerFactoryBean。這表明是本地容器托管的,也就決定了是使用注解@PersistenceContext來獲取EntityManager對象的。

entityManagerFactory下面的一些具體配置就不詳解了,代碼中大致注釋了。

 

transactionManager:

設置jpa事務管理器。事務就是對一系列的數據庫操作進行統一的提交或回滾操作。這樣可以防止在一些意外(例如說突然斷電)的情況下出現亂數據,防止數據庫數據出現問題。

五,其它一些代碼

User:

package com.entity;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class User {
    private int id;
    private String username;
    @Id
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
}

UserDao:

package com.dao;

import java.util.List;

import com.entity.User;

public interface UserDao {
    public List<User> findAllUsers();
}

UserDaoImpl:

package com.daoimpl;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.FlushModeType;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.dao.UserDao;
import com.entity.User;

@Transactional
@Repository("userDaoImpl")
public class UserDaoImpl implements UserDao{
    
    @PersistenceContext
    protected EntityManager entityManager;

    @Override
    public List<User> findAllUsers() {
        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
        CriteriaQuery<User> criteriaQuery = criteriaBuilder.createQuery(User.class);
        Root<User> root = criteriaQuery.from(User.class);
        criteriaQuery.select(root);
        Predicate restrictions = criteriaBuilder.conjunction();
        criteriaQuery.where(restrictions);
        return entityManager.createQuery(criteriaQuery).setFlushMode(FlushModeType.COMMIT).getResultList();
    }

}

這段代碼是實際的持久化操作的代碼。通過@PersistenceContext注解獲取,EntityManager,進行持久化操作。@Transactional表示將事務處理托付給spring。

這段代碼實現的功能就是從數據庫中查詢所有的User。

UserService:

package com.service;

import java.util.List;

import com.entity.User;

public interface UserService {
    public List<User> findAllUser();
}

UserServiceImpl:

package com.serviceimpl;

import java.util.List;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.dao.UserDao;
import com.entity.User;
import com.service.UserService;

@Transactional
@Service("userServiceImpl")
public class UserServiceImpl implements UserService{
    
    @Resource(name = "userDaoImpl")
    private UserDao userDao;

    @Override
    public List<User> findAllUser() {
        return userDao.findAllUsers();
    }

}

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" 
    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_3_0.xsd">
  <display-name></display-name>   
  <!-- 加載所有的配置文件 -->  
  <context-param>  
    <param-name>contextConfigLocation</param-name>  
    <param-value>classpath:/spring-*.xml</param-value>  
  </context-param>  
  
   
  <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:/spring-mvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>*.form</url-pattern>
  </servlet-mapping>
  
  <!-- 配置Spring監聽 -->  
  <listener>  
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
  </listener>  
  
  
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>

六,運行

簡簡單單,毫無一點裝飾的一個網頁,但在服務器里進行了一系列的代碼邏輯……

總體上,這個效果就是:用戶輸入這個地址,找到我們的服務器地址,localhost8080,我們的項目,RiXiangShop,然后通過spring解析路徑,通過@Controller標簽找到對應的controller,通過標簽注入找到對應的service,再找到對應的dao,然后進行數據庫持久化操作--查詢所有用戶,以List的數據結構返回,返回到service,返回到controller,response給前端jsp頁面,jsp通過jstl將查詢到的用戶的id和名字打印到屏幕上。

所以說,這個框架是個雛形,你加入更多的邏輯,它就可以演化為一個電子商務網站,一個博客。

你加入更多更多邏輯,它也可以演化為阿爾法狗。

我希望將之演化為一個博客,再實踐開發中搞更多技術。

因為這是第一個我完全獨立自主搭建,並理解的框架。

我將用兩個月時間開發。到六月,期待開發成功。

之后希望可以搞個自己的域名,建一個自己的個人網站。

然后,在維護開發中繼續搞更多技術。 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM