对象关系映射(Object Relational Mapping)
介绍
一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术
框架
- Hibernate
- Mybatis
....
好处
- 通用的资源管理
- 集成事务管理
- 统一常见的数据访问异常
- 更容易测试
Spring集成Hibernate
集成思路
localSessionFactoryBean
作为Spring和Hibernate之间的介质,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";
}
}
过程
调用过程
- http请求(index.jsp)
- Controller控制器
- Service业务逻辑层
- DAO数据持久层
- sessionFactroy
- dataSource
- dbinfo.properties
依赖注入
- dataSource
- sessionFactroy
- DAO数据持久层
- Service业务逻辑层
- 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";
}
}