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和名字打印到屏幕上。

所以说,这个框架是个雏形,你加入更多的逻辑,它就可以演化为一个电子商务网站,一个博客。

你加入更多更多逻辑,它也可以演化为阿尔法狗。

我希望将之演化为一个博客,再实践开发中搞更多技术。

因为这是第一个我完全独立自主搭建,并理解的框架。

我将用两个月时间开发。到六月,期待开发成功。

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

然后,在维护开发中继续搞更多技术。 

posted on 2016-03-25 14:51  J·Marcus  阅读(5185)  评论(0编辑  收藏  举报

导航