Spring框架——ORM

对象关系映射(Object Relational Mapping)

介绍

一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术

框架

  • Hibernate
  • Mybatis
    ....

好处

  • 通用的资源管理
  • 集成事务管理
  • 统一常见的数据访问异常
  • 更容易测试

Spring集成Hibernate

集成思路

  1. localSessionFactoryBean作为Spring和Hibernate之间的介质,
  2. localSessionFactoryBean可以作为中转站,被Spring管理。

注入顺序

  • localSessionFactoryBean注入给DAO,
  • DAO注入给Sevice
  • Service注入给Controller

配置web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>cakessh</display-name>
	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>
	
	<!-- 非web配置文件 -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			classpath*:/applicationContext.xml
		</param-value>
	</context-param>
	
	<!-- 监听容器 -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	
	<!-- Dispatcher请求分发 -->
	<servlet>
		<servlet-name>springmvc</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<!-- web相关配置文件 -->
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring-mvc.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>springmvc</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>
	
	<!-- 字符编码过滤器 -->
	<!-- 解决中文乱码 -->
	<filter>
		<filter-name>CharacterEncodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>utf-8</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>CharacterEncodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	<!-- 打开一个session -->
	<filter>
		<filter-name>openSessionInView</filter-name>
		<filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>openSessionInView</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
</web-app>

配置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"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
		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">
 
	<!-- 自动扫描且只扫描@Controller -->
	<context:component-scan base-package="com.cakeonline">
		<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
	</context:component-scan>
	
	<!-- 注解驱动 -->
	<mvc:annotation-driven/>
	
	<!-- 静态资源直接响应 -->
	<!-- 不需要Dispather分发 -->
    <mvc:resources location="/static/" mapping="/static/**"/>
	
	<!-- 定义JSP文件的位置 --> 
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/"/>
		<property name="suffix" value=".jsp"/>
	</bean>
	
		
	<!-- 文件上传 -->
	<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">	
	</bean>
</beans>

配置beans.xml(applicationContext.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:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee"
	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task"
	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/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd
		http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-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/task http://www.springframework.org/schema/task/spring-task-4.0.xsd">
	<description>Spring公共配置 </description>

	<!-- 配置Spring上下文的注解 -->
	<context:annotation-config />
	<!-- 使用annotation 自动注册bean, 并保证@Required、@Autowired的属性被注入 -->
	<context:component-scan base-package="com.cakeonline">
		<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" />
	</context:component-scan>
	
	<!-- hibernate -->
	<!-- 属性文件位置 -->
	<context:property-placeholder location="classpath:*.properties" />
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="${jdbc.driver}" />
		<property name="url" value="${jdbc.url}" />
		<property name="username" value="${jdbc.username}" />
		<property name="password" value="${jdbc.password}" />
	</bean>


	<!-- localSessionFactoryBean -->
	<bean id="sessionFactory"
		class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="packagesToScan" value="com.cakeonline.entity" />
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">${hibernate.dialect}</prop>
				<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
				<prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
				<prop key="hibernate.useUnicode">${hibernate.useUnicode}</prop>
				<prop key="hibernate.characterEncoding">${hibernate.characterEncoding}</prop>
				<prop key="current_session_context_class">thread</prop>
			</props>
		</property>
	</bean>
	<!-- 使用annotation定义事务 -->
	<bean id="transactionManager"
		class="org.springframework.orm.hibernate5.HibernateTransactionManager">
		<property name="sessionFactory" ref="sessionFactory" />
	</bean>
	<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
</beans>

dbinfo.properties

#mysql
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/cakeonline_db?useUnicode=true&characterEncoding=UTF-8
jdbc.username=root
jdbc.password=

#hibernate
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=true
hibernate.format_sql=false
hibernate.useUnicode=true
hibernate.characterEncoding=utf-8

实体Bean

  • @Entity

  • @Table(name= "table_name")

  • @Id

  • @GenericGenerator(name = "myassigned", strategy = "assigned")

  • @GeneratedValue(generator = "myassigned")

自定义主键

代码

@Entity
@Table(name = "tbl_user")
public class User {
	
	private String email;
	private String nickName;
	private String password;
	private Date registTime;
	
	@Id
	@GenericGenerator(name = "myassigned", strategy = "assigned")
	@GeneratedValue(generator = "myassigned")
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public String getNickName() {
		return nickName;
	}
	public void setNickName(String nickName) {
		this.nickName = nickName;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public Date getRegistTime() {
		return registTime;
	}
	public void setRegistTime(Date registTime) {
		this.registTime = registTime;
	}
	
}

DAO

  • @Repository

    • 表明是数据持久层
    • 命名方式与数据操作贴近
      • saveUser
      • updateUser
      • deleteUser
      • findByName
      • findById
  • @Resource

依赖注入的注解
依赖注入sessionFactory

  • @Id

代码

@Repository
public class UserDaoImpl {

	@Resource
	private SessionFactory sessionFactory;
	
	/**
	 * saveUser
	 * updateUser
	 * deleteUser
	 * findByName
	 * findById
	 * @return
	 */
	
	public List<User> findAll(){
		Query query = this.sessionFactory.getCurrentSession().createQuery("from User");
		return query.list();
	}
}

Service

  • @Serviec

    • 表明是业务逻辑层
    • 命名方式与实际业务贴近
      • regist
      • login
  • @Transactional(readOnly = true)

事务

  • @Resource

依赖注入的注解
依赖注入DAO

代码

@Service
@Transactional(readOnly = true)
public class UserServiceImpl {
	
	@Resource
	private UserDaoImpl userDaoImpl;
	/**
	 * regist
	 * login
	 * @return
	 */
	public List<User> listUsers(){
		return this.userDaoImpl.findAll();
	}
}

Controller

  • @Controller

注解表明是一个控制器

  • @RequestMapping("/controllername")

映射路径

  • @Resource

依赖注入的注解
依赖注入Service

代码

@Controller
@RequestMapping("/user")
public class UserController {
	
	@Resource
	private UserServiceImpl userServiceImpl;
	
	@RequestMapping("/list")
	public String list(Model model) {
		List<User> users = this.userServiceImpl.listUsers();
		model.addAttribute("users", users);
		return "list";
	}

}

过程

调用过程

  1. http请求(index.jsp)
  2. Controller控制器
  3. Service业务逻辑层
  4. DAO数据持久层
  5. sessionFactroy
  6. dataSource
  7. dbinfo.properties

依赖注入

  1. dataSource
  2. sessionFactroy
  3. DAO数据持久层
  4. Service业务逻辑层
  5. Controller控制器

数据校验

数据校验在项目中被广泛应用,一般分为前端数据校验和后端数据校验

后端数据校验可以采用JSR303进行数据校验
JSR303是一个运行时数据校验框架
它使得验证逻辑从业务代码中脱离出来
一般用于表单验证

注解

注解 功能
@NotNull 注解元素必须是非空
@Null 注解元素必须是空
@Digits 验证数字构成是否合法
@Future 验证是否在当前系统时间之后
@Past 验证是否在当前系统时间之前
@Max 验证值是否小于等于最大指定整数值
@Min 验证值是否大于等于最小指定整数值
@Pattern 验证字符串是否匹配指定的正则表达式
@Size 验证元素大小是否在指定范围内
@DecimalMax 验证值是否小于等于最大指定小数值
@DecimalMin 验证值是否大于等于最小指定小数值
@AssertTrue 被注解的元素必须为true
@AssertFalse 被注解的元素必须为false

用法

Entity

public class User {
//	@NotEmpty(message="登录账号不能为空!")
	@NotEmpty
	private String loginName;
//	@Pattern(regexp="[0-9a-zA-Z]{6,30}", message="密码是6-30个字符,必须是字母或数字组合!")
	@Pattern(regexp="[0-9a-zA-Z]{6,30}")
	private String password;
	@NotEmpty(message="邮箱不能为空!")
	@Email(message="邮件格式不正确!")
	private String email;
	@Past(message="生日不能晚于当前时间!")
	@DateTimeFormat(pattern="yyyy-MM-dd")
	private Date birthday;
	@Future(message="注册时间不能早于当前时间!")
	@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
	private Date registTime;
	@DecimalMin(value="1000.00", message="工资必须大于1000")
	@DecimalMax(value="10000.00", message="工资必须小于10000")
	@NumberFormat(pattern="#,###.##")
	private Double salary;
	public String getLoginName() {
		return loginName;
	}
	public void setLoginName(String loginName) {
		this.loginName = loginName;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getEmail() {
		return email;
	}
	public void setEmail(String email) {
		this.email = email;
	}
	public Date getBirthday() {
		return birthday;
	}
	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}
	public Date getRegistTime() {
		return registTime;
	}
	public void setRegistTime(Date registTime) {
		this.registTime = registTime;
	}
	public Double getSalary() {
		return salary;
	}
	public void setSalary(Double salary) {
		this.salary = salary;
	}
	
}

Controller

method(@Valid 实体类,BindingResult bindingResult,
HttpSession session, Model model){
      if(bindingResult.hasErrors()){
            model.addAttribute("user", user);
	    return "user";
      }else{
            session.setAttribute("user", user);
	    return "center";
      }
}
原文地址:https://www.cnblogs.com/occlive/p/13579935.html