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

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

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

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

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

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

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

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

  • 相关阅读:
    SwiftUI使用URLSession发送https请求免证书验证
    IOS 时间格式 格式化说明
    句柄,文件描述符的理解
    Docker Swarm(8)
    Docker 自己的理解(9)
    eclipse导入idea项目
    写写最近的感悟为什么好久没更
    linux 命令行实现CPU 100%占用
    2.如何正确理解古典概率中的条件概率《zobol的考研概率论教程》
    1.为什么要从古典概率入门概率学《zobol的考研概率论教程》
  • 原文地址:https://www.cnblogs.com/rixiang/p/5319490.html
Copyright © 2020-2023  润新知