Java Web高级编程(持久化数据)

---JSR是JavaBean Validation的规范  Hibernate Validation是JSR349的参考实现
约束注解可以添加到字段 方法和方法参数上
配置bean



要在验证在方法之前执行 需要配置一些bean后处理器
RootContextConfiguration.java 
创建错误代码本地化 
   

    使用方法验证Bean后处理器 
  

为了保证递归验证 要加@Valid验证

为方法验证配置Spring Bean
1.标注接口 而非实现
接口被认为是实现契约编程的主要形式

在SpringMVC控制器中使用参数验证 
  
@Valid 告诉Spring在执行方法之前验证EmployeeForm
Errors errors 参数的存在告诉Spring吧验证错误传入到方法中 而不是抛出异常 在方法中处理异常 更加优雅 如果存在错误 就将用户列表返回到表单视图中
validation_en_US.properties里面是这样的
validate.employee.firstName=The first name is required.
JSP视图

还可以编写自己的验证约束 比如@email 因为email的验证的正则表达式很烦 可以抽象出来

---Spring 负责所有的事务管理和 EntityManager 的创建和关闭!!!

---虽然ORM可以帮你建表 但是实际情况中 永远自己建表

---在Tomcat中创建连接资源

<Resouce>定义将使Tomcat吧连接池DataSource暴露为JNDI资源 这样任何应用程序都可以通过 JNDI查询到该资源

---Hibernate Session代表了一个事务从开始到结束的整个生命周期 不是线程安全 必须在一个线程里面使用 他负责管理实体的状态
从数据库中获取实体的时候 该实体被附着到会话上 并一直作为会话的一部分 通过这种方法 实体的特定属性可以通过延迟加载的方式加载 同样 添加或更新一个实体的时候 这些修改也将被附着到会话上

---

最佳实践

@Access( AccessType.PROPERTY/FIELD ) 使用默认(PROPERTY) 即使用JavaBean 属性 其余的JPA注解大多数都是属性注解 如@Id @Basic @Temporal等
这些注解可以加在field上 或者 公开访问方法上 加在字段上 就要匹配JavaBean属性名 如果加在JavaBean访问方法上 则不需要


最佳实践
使用AccessType.PROPERTY 时就在JavaBean 方法上使用注解 使用 AccessType.FIELD 时 就在字段上添加注解 这将消除混淆 千万不能混用

---使用 Spring Framework 创建 Session Factory
不过在下面的实例中 用了 EntityManager 这个功能上有 Session Factory 的作用 所以没有这么写 !!!EntityManager啊!
RootContextConfiguration.java

=============================使用简单实体=================================
---创建实体并将它映射到表
@Entity @Table
@Entity ( name = "PublisherEntity" ) 实体名默认就是类名 注意哦 这个不是表 不过表面默认是
实体名


这个专用于模式生成 不过不建议使用

---JPA使用实体字段
创建代理键 id 一般用long

@Basic
更加显示的方式映射字段 fetch = FetchType.LAZY 表示属性值是从DB中立即读取(默认)还是只在访问时读取映射字段:例如int映射为 INTEGER BIGINT 或者对应的SQL数据类型

---指定类名和其他细节
@Column ( name = "PublisherName", nullable = false )
注意 这里的nullable = false 只用于模式生成 如果没启用 会被忽略

---持久化单元 就是将一个配置和一组实体类从逻辑上组合到一起 该配置将控制着附着到持久化单元的javax.persistence.EntityManager 实例和特定持久化单元中的EntityManager (不太懂 直接用spring好了)
EntityManager 可以很细粒度的吧?foo实体里面的EntityManager 不能控制bar实体?
=========================Spring Framework中使用JPA=========================
---maven依赖

---主要就是EntityManager的依赖注入

---EntityManager 功能等同与 Hibernate ORM的会话和JDBC的连接

---先编写代码 再设计一个支持代码的数据库

---EntityManager在功能上等于Hibernate ORM的会话和JDBC的连接 可以这么写
@PersistenceContext
EntityManager entityManager;
就一般的写@Inject或者@Autowired EntityManager不是线程安全的 而使用@PersistenceContext
意味着 仓库可以在多个线程中使用该实例 并且在后台每个线程都有自己的EntityManager实例 它们将代表你对事务进行管理
使用@PersistenceContext还有一个优点是可以为给定的 EntityManager实例指定一个持久化单元的名称
@PersistenceContext( unitName = "fooUnit" )
EntityManager entityManager;

=========================在 Spring Framework中配置持久化=====================


1.创建或者查找数据源

不过 这只能创建一个简单的数据源 该数据源返回的连接只能使用一次 并未提供连接池 所以不能用于生产
可以从属性文件中读取URL 用户名和密码 这样方便修改

这样写了之后 还要在Tomcat的context.xml中定义数据源

2.在代码中创建或查找持久化单元 并配置Spring将它注入到仓库中 
   

创建了一个map用于保存JPA的配置属性 放了一个模式生成属性 接下来创建了一个适配器

3.创建事务管理 使用@Transactional方法得到正确的处理
在 RootContextConfiguration.java 上使用注解@EnableTransactionManagement 激活事务管理和@Transactional方法拦截

默认事务管理将会查找一个名为txManager的bean 然后返回它可以找到的PlatformTransactionManager实现的第一个bean


=============================创建和使用JPA仓库============================


---注入持久化单元
为了在仓库中执行JPA操作 需要一个 EntityManager实例
每个仓库都有一个 EntityManager 实例


注意这里注入的 EntityManager并不是JPA供应商(Hibernate ORM)提供的那个 相反 它是真正的
EntityManager的一个代理实例

---实现标准CRUD操作

这里BookRepository可以有个扩展 其他的一些为空就可以了

要在Repository实现类中有下面这两个


因为需要访问I和E的类型(Class) 用于执行安全的JPA查询操作 获得类型的最佳方式是在构造函数
中 这个挺复杂的 所以 单抽出来写了一个类
在GenericJpaRepository中完成所有有趣的JPA操作
这里用的是 JPA API 不是很直观
==========================在服务中标记事务范围==============================
最佳实践 吧@Transactional注解标注在具体的类或者类方法上 而不是接口或者接口方法上
Bean验证注解是写在接口上的 是契约 @Transactional是具体的实现细节 不属于契约

配置

JpaTransactionManager被用于默认的事务管理器

使用@Transactional 标注在接口上的话 等同于标注了接口上的所有方法
最佳实践 将注解标注在具体的类或者类方法上 而不是接口或者接口方法上

==========================================================================
主要为了演示BCrypt
DefaultAuthenticationService.java

上面使用了BCrypt保护用户密码
==========================================================================

一个小例子


===Repository

===Service

===Controller

---在DTO和实体之间转换数据
将这里的Ticket作为DTO(数据传输对象) 并创建TicketEntity用于持久化到数据库中(比如Ticket里 面有一些新特性 JPA还未实现的 就要在TicketEntity里面去换成JPA可以实现的 )
}应用程序用的是Ticket 数据库持久化用的是TicketEntity;

====================使用 Spring Data JPA可以不用自己写Repository=================


解决 比如你要查找一本书 可以根据ISBN 作者 书名 等等查找 每个都要写差不多相似的查找代码 很烦 可以通过 Spring Data 解决 还有分页功能
你要做的就是创建一个接口 Spring Data 可以在运行时自动生成该接口的实现代码

Spring Framework 中常见的程序执行路径
'控制器针对服务接口编写' Spring 将拦截这些接口的调用 并执行所有必要的任务 例如Bean验证 启动事务或者异步调用方法 当服务方法返回时 Spring可能也会执行进一步的Bean验证 并提交或者回滚事务 同样 '访问代码针对仓库接口编写' 在调用仓库仓库方法的时候 Spring 将再次执行所有必要的任务
例如启动事务 当方法返回时 Spring 把所有抛出的异常都转换为DataAccessException

服务中编写业务逻辑 控制器中编写用户界面逻辑 所以仓库中不需要编写什么特别的代码 它只是
持久化和获取实体的公式化代码

---maven依赖

Spring Data JPA的CrudRepository<T, ID> 集成了许多CRUD操作 '''T表示实体类型 ID标识标识符类型'''

实现类 SimpleJpaRepository

使用方式

org.springframework.data.domain.Sort 封装了一些属性信息 以及指定方式对结果排序
org.springframework.data.domain.Pageable 封装了一个Sort对象和每页中实体的数目以及将要返回的那一页

如果希望仓库提供分页和排序 可以继承 PagingAndSortingRepository< T, ID extends Serializable >

findAll( Sort ) 对T进行排序 返回一个Inerable< T >
findAll( Pageable ) 返回一个Page< T >以Pageable指令指定的边界为限
Pageable封装了一个Sort对象和每页中实体的数目以及将要返回的那一页(都是整数) 在WEB应用程序中 Spring帮我们实现了两个Pageable对象

Spring Data 可以公式化仓库代码啊 太强大了 但是不太透明的感觉啊
!!!===为搜索实体创建查询方法 像下面那个方法 按照约定写 Spring就可以实现


名称应以find...By get...By或者read...By开头 然后紧接着匹配的属性名称 方法参数中提供了该属性的值

---查询方法名中可以添加多个属性 并用逻辑操作符分隔它们(Or And)等等


还可以用IgnoreCase显示的表示是否忽略大小写 eg, findByFirstNameOrLastNameAllIgnoreCase
这个叫做查询方法语言 非常强大 例如还有 After 和 IsAfter Like Contains StartsWith EndsWith Between IsBetween True IsTrue GreaterThan IsGreaterThan In Null IsNull Exists

---还可以自定义方法实现
---比如在下面的接口自定义了BookRepository的两个方法

---然后写一个 BookRepositoryImpl 去实现这个接口

---然后


在这里只要继承那个自己定义的接口就好 Spring 会自动匹配imp
在使用 Spring Data 查找 BookRepository 的时候 他首先查找相同包中名为 BookRepositoryImpl的类 并将该类实例化和封装为普通的 Spring bean 当调用这些自己写的自定义方法的时候 Spring Data都会把调用委托给该实现(Impl);

还可以自定义所有仓库 极少出现

---使用java配置Spring Data

---配置 Spring MVC 支持
Spring Data 可以自动将请求参数转为 Spring MVC 处理器参数方法参数 另外ia使用仓库的时候 它可以自动将请求参数和路径变量转换为实体类型

注意看这里的@PathVariable( "id" ) Person person 不是跟了@PathVariable( "id" ) long id


Spring Data 可以接受URL的ID 在Person仓库实现中使用 findOne(ID) 获得这一个Person对象
这消除了使用long类型ID方法参数从仓库中获取Person的手动代码;

配置这个的支持 通过@EnableSpringDataWebSupport 注册的bean包含了许多被初始化为默认值的设置 包括参数名称 最大页大小 默认的分页和排序值 在 RestServletContextConfiguration 设置

---分页 JSP写 
   

============================高级搜索=====================================
Spring Data 局限 不能动态查询

============================定义实体间的关系==============================
一对一
实体A最多只能关联到一个实体B 实体B也最多只能关联到一个实体A
如果是双向的 A中有B B中有A 则需要用@OneToOne标记 指定mappedBy特性
该特性告诉JPA提供者在关系的另一端对应"这个"实体的属性是哪个

一对多和多对一关系
更加常见 实际上 无论何时在一个实体中指定了一个一对多关系 通常会在另一个实体中指定一个
对应的多对一关系

本例中 一个申请人有多个简历 Applicant 中定义了一个简历的Set 该属性允许了持有Applicant的代码块直接浏览申请人的简历 而无须返回到服务或者仓库中
本例中 JPA得知关系是双向的 因为Resume类包含到Applicant的导航属性 只有一对多这边 需要mappedBy

@JoinColumn 指定了连接两个表的列的细节信息(就是外键?)
在 单向的一对多 关系中 它可以只用在关系的一段:@OneToMany这一边(Applicant) 对于这些关系 它表示了另一个实体的表的哪个列包含了当前实体的主键

在 单向的多对一 或者 双向一(多)对多(一) 中 @JoinColumn属于关系的@ManyToOne 这一边 (Resume);

对于这些关系 @JoinColumn 表示当前实体的表的哪个列包含了其他实体的主键,它也代替了该属性的@Column 注解

转载于:https://my.oschina.net/tjt/blog/643985

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值