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

时间:2023-12-17 19:48:38

一,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>

六,运行

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

简简单单,毫无一点装饰的一个网页,但在服务器里进行了一系列的代码逻辑……

总体上,这个效果就是:用户输入这个地址,找到我们的服务器地址,localhost8080,我们的项目,RiXiangShop,然后通过spring解析路径,通过@Controller标签找到对应的controller,通过标签注入找到对应的service,再找到对应的dao,然后进行数据库持久化操作--查询所有用户,以List的数据结构返回,返回到service,返回到controller,response给前端jsp页面,jsp通过jstl将查询到的用户的id和名字打印到屏幕上。

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

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

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

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

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

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

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

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