(一)配置详解
鉴于目前资料大多数都是基于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&useUnicode=true&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>