SpringMVC4+Hibernate4学习笔记-阿里云开发者社区

开发者社区> 开发与运维> 正文

SpringMVC4+Hibernate4学习笔记

简介:


(一)配置详解

(注:本文是以前几篇博客的简单合并,未做更新)

鉴于目前资料大多数都是基于spring3的配置,本人在最初搭建的时候遇到很多问题,由此记录下来仅供参考

使用的jar文件

springframework4.0.6(为了方便整个先导入)
hibernate4.3.6 /required/*下所有jar 以及 /optional下的c3p0(为了使用c3p0作为dataSource,使用其连接池)
jstl.jar standard.jar ——为了使用jstl标签库
apoalliance.jar ——在AOP一些地方依赖这个库
commons-logging.jar

配置详细步骤

  • 第一步,配置web.xml
     <?xml version="1.0" encoding="UTF-8"?>
     <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
                             http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         id="WebApp_ID" version="3.0">
    
         <display-name>app</display-name>
    
         <!-- context启动时加载hibennate的配置文件 -->
         <context-param>
             <param-name>contextConfigLocation</param-name>
             <param-value>/WEB-INF/spring-*.xml</param-value>
         </context-param>
    
         <listener>
             <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
         </listener>
    
         <!-- 设置spring的前端分发器,接受请求 -->
         <servlet>
             <servlet-name>myservlet</servlet-name>
             <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
             <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>myservlet</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    
        <!-- 默认错误页面的设置 -->
        <error-page>
            <error-code>404</error-code>
            <location>/WEB-INF/jsp/404.jsp</location>
        </error-page>
    
        <!-- <error-page>
        <exception-type>java.lang.Exception</exception-type>
            <location>/WEB-INF/jsp/exception.jsp</location>
        </error-page> -->
    
     </web-app>
    
  • 第二步,myservlet-servlet.xml(DispatcherServlet)的配置文件相关部分,注意,如果在配置中用到了aop,tx,mvc等标签,须在xmlns中导入。
      <?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:p="http://www.springframework.org/schema/p"
             xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx"
             xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
             xmlns:util="http://www.springframework.org/schema/util"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                                http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd 
                                http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd 
                                http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
                                http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">
    
          <!-- 扫描注解配置的包 -->
          <context:component-scan base-package="com.tan.*" />
    
          <!-- 基于注释的事务,当注释中发现@Transactional时,使用id为“transactionManager”的事务管理器 -->
          <!-- 如果没有设置transaction-manager的值,则spring以缺省默认的事务管理器来处理事务,默认事务管理器为第一个加载的事务管理器 -->
          <tx:annotation-driven transaction-manager="transactionManager" />
    
          <!-- 设置spring的mvc用注解 -->
          <mvc:annotation-driven />
    
          <!-- 设置handler的映射方式,前面注解是其中一种 -->
          <!-- HandlerMapping <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> 
          <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> -->
    
          <!-- 设置试图的解析ViewResolver -->
          <bean
              class="org.springframework.web.servlet.view.InternalResourceViewResolver">
          <!-- <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/> 此处不加这行似乎也能在jsp中用jstl,只要正确引入了tag-->
              <property name="prefix" value="/WEB-INF/jsp/" />
              <property name="suffix" value=".jsp" />
          </bean>
          <!-- 可以使用基于url的handlermapping <bean name="/hello" class="com.tan.controller.MyController"/> -->
      </beans>
    
  • 第三步,hibenate相关的配置,spring-hibernate.xml。配置数据源->交给sessionFactory->交给spring事物管理transactionManager->spring接手
      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:context="http://www.springframework.org/schema/context"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
             xmlns:aop="http://www.springframework.org/schema/aop"
             xsi:schemaLocation="http://www.springframework.org/schema/beans     
                                 http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                                 http://www.springframework.org/schema/context
                                 http://www.springframework.org/schema/context/spring-context-4.0.xsd
                                 http://www.springframework.org/schema/aop
                                 http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
                                 http://www.springframework.org/schema/tx
                                 http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
    
      <!-- Hibernate4 -->
      <!-- shiyongproperties文件保存jdbs以及hibernate的相关变量,在具体配置处使用属性zhi值,必须在Spring配置文件的最前面加载,放在src目录 -->
      <context:property-placeholder location="classpath:persistence-mysql.properties" />
    
      <!-- 获取数据源的几种方式DriverManagerDataSource、dbcp、c3p0,后两种支持连接池 -->
      <!-- class="org.apache.tomcat.dbcp.dbcp.BasicDataSource" 有连接池作用 -->
      <!-- class="org.springframework.jdbc.datasource.DriverManagerDataSource"无连接池作用 -->
      <!-- <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
               <property name="driverClassName" value="${jdbc.driverClassName}" /> 
               <property name="url" value="${jdbc.url}" /> 
               <property name="username" value="${jdbc.user}" /> 
               <property name="password" value="${jdbc.pass}" /> 
           </bean> -->
    
      <!-- c3p0 有连接池作用,使用properties文件下的属性值,也可以直接填-->
      <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
          <property name="driverClass" value="${jdbc.driverClassName}" />
          <property name="jdbcUrl" value="${jdbc.url}" />
          <property name="user" value="${jdbc.user}" />
          <property name="password" value="${jdbc.pass}" />
          <property name="minPoolSize" value="2" />
          <property name="maxPoolSize" value="50" />
          <property name="initialPoolSize" value="10" />
          <property name="maxIdleTime" value="60" />
          <property name="acquireIncrement" value="2" />
      </bean>
    
      <!-- 配置sessionFactory,统一管理一个数据库的连接 -->
      <bean id="sessionFactory"
          class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
          <property name="dataSource" ref="dataSource" />
          <property name="packagesToScan">
              <list>
                  <!-- 可以加多个包,需要hibenate映射的类的包 -->
                  <value>com.tan.model</value>
              </list>
          </property>
          <property name="hibernateProperties">
              <props>
                  <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
                  <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                  <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                  <!-- <prop key="hibernate.current_session_context_class">thread</prop> -->
              </props>
          </property>
      </bean>
    
      <!-- 配置Hibernate事务管理器 -->
      <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
          <property name="sessionFactory" ref="sessionFactory" />
      </bean>
    
      <!-- 配置事务异常封装 -->
      <bean id="persistenceExceptionTranslationPostProcessor" class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
      </beans>
    
  • 第四步,添加persistence-mysql.properties文件,如果在spring-hibenate.xml直接配置数据源的值,就不需要
      # jdbc.X
      jdbc.driverClassName=com.mysql.jdbc.Driver
      jdbc.url=jdbc:mysql://localhost:3306/springmvc(你的数据库名)?createDatabaseIfNotExist=true&amp;useUnicode=true&amp;characterEncoding=utf8
      jdbc.user=root
      jdbc.pass=
      # hibernate.X
      hibernate.connection.driverClass=com.mysql.jdbc.Driver
      hibernate.connection.url=jdbc:mysql://localhost:3306/springmvc(你的数据库名)
      hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
      hibernate.connection.username=root
      hibernate.connection.password=
      hibernate.show_sql=true
      hibernate.hbm2ddl.auto=update #如果没有表则创建,如果表结构更改则自动更新

(二)一些名词

  • MVC模型-视图-控制器

    Spring MVC中的mvc和通常的web框架如,django、ROR、thinkphp、lavarel等都是很类似的,个人感觉区别在于Spring MVC中的model层功能更多的是有DAO+Service两层来完成,像front dispatcher、controller、viewresolver和其他框架都是很类似的

  • DAO数据访问层

    DAO封装了对数据库的操作,可能是原子级的操作由Service组装,也可能是稍复杂的操作。供Service业务层调用

  • Service业务逻辑层

    封装了业务逻辑的相关操作,由控制器层调用,这一层不是必须的,也可经控制器直接调用DAO中的方法

  • AOP面向切面编程

    面向切面编程简单地理解就是把多个业务逻辑的共同功能模块提取出来,如回话管理、权限认证等。在django的auth模块,以及thinkphp的Behavior行为驱动层都是AOP的使用例子

  • DI依赖注入

    依赖注入的一个简单例子就是Service层中注入需要用到的一个或多个DAO,在Controller中注入Service,使用annotation注入极大简化了代码的编写

  • ORM对象关系映射

    这个与大多数orm框架的理念都是类似的,在hibernate中使用对象映射表,对象的实例映射表中一条记录

  • sessionFactory生成session的工厂

    负责创建session,session是hibernate暴露给开发者的操作数据库的接口,在DAO中使用session通过save/update/saveorupdate/delete等方法或者hsql、原生sql访问数据库

  • Tansaction事务

    这个与通常的数据库的事务的概念差不多,在springmvc与hibenate集成中,hibernate将transacition交给HibernateTransactionManager管理

  • Datasource

    数据源就是hibernate的连接数据库的方式。通常有springmvc自带的DriverManagerDataSource、c3p0、dbcp,后两种支持连接池


(三)完整实例

  • POJO类,负责和数据库映射

      package com.tan.model;
      import javax.persistence.*;
      @Entity(name = "users") //映射到users表
      public class Users {
    
          public Users() {
              super();
          }
      @Id
      @GeneratedValue(strategy = GenerationType.AUTO)
      @Column(name = "id")
      private Integer id;
      @Column(name = "first_name", length = 32)
      private String first_name;
      @Column(name = "age")
      private Integer age;
      @Column(name = "last_name", length = 32)
      private String last_name;
      public Integer getId() {
          return id;
      }
      public void setId(Integer id) {
          this.id = id;
      }
      public String getFirst_name() {
          return first_name;
      }
      public void setFirst_name(String first_name) {
          this.first_name = first_name;
      }
      public Integer getAge() {
          return age;
      }
      public void setAge(Integer age) {
          this.age = age;
      }
      public String getLast_name() {
          return last_name;
      }
      public void setLast_name(String last_name) {
          this.last_name = last_name;
      }
      }
    
  • DAO层

      package com.tan.model;
    
      import java.util.List;
      import javax.annotation.Resource;
      import org.hibernate.Query;
      import org.hibernate.Session;
      import org.hibernate.SessionFactory;
      import org.springframework.stereotype.Repository;
      @Repository
      public class UsersDAO {
      @Resource(name = "sessionFactory")  //使用annotation注入sessionFactory
          private SessionFactory sessionFactory;
          public void setSessionFactory(SessionFactory sessionFactory) {
          this.sessionFactory = sessionFactory;
      }
      public SessionFactory getSessionFactory() {
          return sessionFactory;
      }
      public List<Users> getAllUser() {
          String hsql = "from users";
          Session session = sessionFactory.getCurrentSession();
          Query query = session.createQuery(hsql);
          return query.list();
      }
      public void insert(Users u) {
          Session session = sessionFactory.getCurrentSession();
          session.save(u);
      }
      }
    
  • Service层

      package com.tan.service;
      import java.util.List;
      import javax.annotation.Resource;
      import org.springframework.stereotype.Service;
      import org.springframework.transaction.annotation.Transactional;
      import com.tan.model.Users;
      import com.tan.model.UsersDAO;
      @Service("userService")
      @Transactional   //开启事务
      public class UserService {
          @Resource
          private UsersDAO userDao;
          public int userCount() {
              return userDao.getAllUser().size();
      }
      @Transactional(readOnly = true)
      public List<Users> getAllUsers() {
          return userDao.getAllUser();
      }
      public void insert(Integer age, String first_name, String last_name) {
          Users u = new Users();
          u.setAge(age);
          u.setFirst_name(first_name);
          u.setLast_name(last_name);
          userDao.insert(u);
      }
      public void insert1(Users u) {
          userDao.insert(u);
      }
      public UsersDAO getUserDao() {
          return userDao;
      }
      public void setUserDao(UsersDAO userDao) {
          this.userDao = userDao;
      }
      }
    
  • controller层

      package com.tan.controller;
      import java.util.List;
      import org.springframework.stereotype.Controller;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RequestMethod;
      import org.springframework.web.bind.annotation.ResponseBody;
      import org.springframework.web.bind.annotation.RequestParam;
      import org.springframework.web.bind.annotation.PathVariable;
      import org.springframework.web.servlet.ModelAndView;//不要引入错误的modelandview
      import com.tan.model.Users;
      import com.tan.service.UserService;
      import javax.annotation.Resource;
      @Controller
      @RequestMapping("/user")  //映射url
      public class UserController {
      @Resource(name = "userService") //注入service层
      private UserService service;
          @RequestMapping(value = "/man", method = RequestMethod.GET)
      public ModelAndView hello2() {
      ModelAndView mv = new ModelAndView();  
      mv.addObject("message", "HelloMVC");
      // mv.setViewName("users");
      return mv;
      }
      @RequestMapping(value = "/count", method = RequestMethod.GET)
      public ModelAndView count() {
          int c = service.userCount();
          ModelAndView mv = new ModelAndView();
          mv.addObject("message", c);
          mv.setViewName("user/count");
          return mv;
      }
      @RequestMapping(value = "/list", method = RequestMethod.GET)
      @ResponseBody    //返回json
      public ModelAndView list() {
          List<Users> u = service.getAllUsers();
          ModelAndView mv = new ModelAndView();
          mv.addObject("u", u);
          // mv.setViewName("users");
          return mv;
      }
      @RequestMapping(value = "/add", method = RequestMethod.GET)
      public String insert() {
          return "user/add";
      }
      /*
       * @RequestMapping(value="/insert",method=RequestMethod.POST)
       * 
       * @ResponseBody public ModelAndView insert(
       * 
       * @RequestParam("age") Integer age,
       * 
       * @RequestParam("first_name") String first_name,
       * 
       * @RequestParam("last_name") String last_name ){
       * 
       * service.insert(age,first_name,last_name); ModelAndView mv = new
       * ModelAndView(); return mv;
       * 
       * }
       */
      @RequestMapping(value = "/insert", method = RequestMethod.POST)
      public String insert(Users u) {
          service.insert1(u);
          return "redirect:/user/list";
      }
      @RequestMapping("/path/{id}")   //pathinfo模式
      @ResponseBody
      public Integer path(@PathVariable("id") Integer id) {
      return id;
      }
      }

(四)注解式事务

  • 配置和使用

    • 在myservlet-servlet.xml里面添加

        <tx:annotation-driven transaction-manager="transactionManager" />
      

      不要加到spring-hibernate配置文件中,会产生session null错误

    • 确保数据库本身是支持事务的引擎

    • 在Service层使用事务,在整个类中用@Transactional声明会作用于所有public方法,在function里的@Transactional会覆盖class的. insert方法上没使用@Transactional,如果此时class上也没使用,则会报错,而insert1不会.

        package com.tan.service;
        import java.util.List;
        import javax.annotation.Resource;
        import org.springframework.stereotype.Service;
        import org.springframework.transaction.annotation.Transactional;
        import com.tan.model.Users;
        import com.tan.model.UsersDAO;
        @Service("userService")
        @Transactional(readOnly = true)   //开启事务
        public class UserService {
            @Resource
            private UsersDAO userDao;
            public int userCount() {
                return userDao.getAllUser().size();
        }
        @Transactional(readOnly = true)
        public List<Users> getAllUsers() {
            return userDao.getAllUser();
        }
      
        public void insert(Integer age, String first_name, String last_name) {
            Users u = new Users();
            u.setAge(age);
            u.setFirst_name(first_name);
            u.setLast_name(last_name);
            userDao.insert(u);
        }
      
        @Transactional(propagation = Propagation.REQUIRED, readOnly = false)
        public void insert1(Users u) {
            userDao.insert(u);
        }
        public UsersDAO getUserDao() {
            return userDao;
        }
        public void setUserDao(UsersDAO userDao) {
            this.userDao = userDao;
        }
        }
      
    • 事务属性

      • 传播行为(propagation=..)

        常用的几个

        • PROPAGATION_REQUIRED—-必须运行在事务中
        • PROPAGATION_SUPPORTS—-事务不必须,但如果有事务则运行在事务中
        • PROPAGATION_NEVER——-不能运行在事务中,如果有则抛出异常
        • ….
      • 隔离级别(isolation = ) 默认完全隔离,可以适当放松隔离优化性能

      • 只读(readOnly = true)
      • 超时(timeout = )
      • 回滚规则(rollback-for = )

(五)简单Session登录管理

  • session登录实例,实现了四个方法login/logout/doLogin/testLogin,加入前面UserController中

      @RequestMapping(value = "/doLogin", method = RequestMethod.POST)
      public String doLogin(HttpServletRequest req,@RequestParam("user") String username, @RequestParam("pass") String password) {
    
      //System.out.println(username+"_"+password);
          if (username.equals( "user") && password.equals( "pass")) {
              HttpSession s = req.getSession();
              s.setAttribute("isLogin", "y");
              return "redirect:/user/testLogin";
          } else {
              return "redirect:/user/login";
          }
      }
    
      @RequestMapping("/login")
      public String login() {
          return "user/login";
      }
    
      @RequestMapping("/testLogin")
      public String testLogin(HttpServletRequest req) {
          if (req.getSession().getAttribute("isLogin") == "y") {
              return "user/home";
          } else {
              return "user/login";
          }
      }
    
      @RequestMapping("/logout")
      public String logout(HttpServletRequest req) {
          req.getSession().setAttribute("isLogin", null);
          return "user/login";
      }
    
  • 相应视图

      //login.jsp//
      <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
      <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
      <html>
          <head>
              <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
              <title>Insert title here</title>
          </head>
      <body>
          <form action="/app/user/doLogin" method="post">
              user:<input type="text" name="user"><br /> 
              pass:<input type="text" name="pass"><br /> <input type="submit" value="login">
          </form>
      </body>
      </html>
    
      //home.jsp//
      <%@ page language="java" contentType="text/html; charset=UTF-8"
      pageEncoding="UTF-8"%>
      <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
      <html>
          <head>
              <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
              <title>Insert title here</title>
          </head>
      <body>
          yes,login
          <br />
          <a href="/app/user/logout">logout</a>
      </body>
      </html>




版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
开发与运维
使用钉钉扫一扫加入圈子
+ 订阅

集结各类场景实战经验,助你开发运维畅行无忧

其他文章