当前位置:   article > 正文

Spring整合Hibernate实现Spring Data JPA

Spring整合Hibernate实现Spring Data JPA

在上一篇文章《Spring整合Hibernate实现JPA持久化》中,我们已经介绍了怎样在Spring容器中合理地集成Hibernate来实现JPA的ORM机制。但是,细心的读者会发现,上一篇文章中使用了EntityManager来直接与数据库交互,存在这一定的耦合度,更重要的是每当新增或修改新的实体Entity的管理时,都需要重复的实现EntityManager在Dao层的逻辑,有些过于模版化,重复劳动的问题存在,所以这篇文章就来介绍下解决这个问题所采用的Spring Data来自动化JPA的实现,听着很牛是吧!

l 基本储备技术介绍

l Spring Data如何实现JPA

l Spring Data JPA重构实例

一、基础储备技术介绍

在介绍如何实现之前,很有必要先介绍些储备内容。

首先,我们需要在Maven中引入spring-data-jpa软件包,参看如下内容:

<dependency>

<groupId>org.springframework.data</groupId>

<artifactId>spring-data-jpa</artifactId>

<version>1.10.1.RELEASE</version>

</dependency>

这里使用了1.10.1.RELEASE版本,注意不同版本与Spring和Hibernate版本的兼容,读者只需要按照上篇文章及这里的介绍实现即可。在这个软件包里,提供了JpaRepository接口(继承自Repository),它的作用就是留给开发者自定义Dao层接口时进行拓展继承的,其用来绑定@Entity模型以及模型对应的ID类型的,这样绑定声明后,在程序或容器启动时进行初始化时,Spring Data根据@Entity注解找到该实体,并通过反射和注解技术来获取实体类的类名字、属性以及方法等参数,然后通过其默认提供的18个方法API(这里不做介绍,读者可执行查阅资料了解),来实现对实体的管理及持久化的封装。

其次,Spring Data默认生成的实体持久化方法遵循着一种模式,有助于生成针对数据库的查询,比如:

findUserByFirstnameAndLastnameOrderByLastname()

针对这个方法,SpringData是这样的规定的:find/get/read是查询动词,不论使用哪个,功能都是一样的;User代表主题,指的是被定义为@Entity实体的类名;By仅仅是一个连接符而已,其主要是用来连接查询条件(断言),以及断言内查询条件的连接,比如:OrderByLastname;FirstnameAndLastnameOrderByLastname则比较明显,是查询SQL的条件断言,这里指的根据User的Firstname和Lastname查询记录,并根据Lastname生序排列结果,另外,还可以忽略断言条件的大小写,以及判断过滤等,具体里面的内容较多,建议读者查阅相关资料熟悉了解。

最后,我们来简单介绍下DSL(领域驱动语言):其思想主要是“求专不求全”,不像其它通用语言那样涵盖一切范围的问题,而是专门针对某一特定问题的计算机语言。在本质上,Spring Data中已经定义了一组小规模的领域驱动语言,并且持久化的细节支持,都是通过Repository方法的签名来描述的。但是,DSL也有其局限性,在其所提供的实体查询方法无法满足需求时,我们就得借助于@Query等来实现更为复杂的需求,具体会在下面实现部分介绍。

二、Spring Data如何实现JPA

1、定义查询方法,JpaRepository提供的CURD方法

UserRepository.java:

public interface UserRepository extends JpaRepository<User,String> {

// 这里不需要任何方法

}

使用JpaRepository绑定User实体(@Entity标注的实体类),并指定主键(ID)类型为String类型。此接口体内,不需要声明任何方法,直接使用由Spring Data默认提供的18个方法。

2、定义查询方法,JpaRepository规则支持的方法

UserRepository.java:

public interface UserRepository extends JpaRepository<User,String> {

// 定义查询方法,供JpaRepository默认18个方法无法满足时

User findByUsername(String userName);

// 定对查询方法,根据email或mobile查询多条记录

List<User> findByEmailOrMobile(String email,String mobile);

}

这里的两个方法,虽然是开发者自行定义的,但是它们满足Spring Data的规则,所以开发者不需要具体实现这些方法,所有的工作都交给SpringData自动完成。

3、声明自定义查询方法,采用@Query封装SQL操作

UserRepository.java:

public interface UserRepository extends JpaRepository<User,String> {

// 声明自定义查询,根据email模糊查询多条记录

@Query("select u from User u where u.email like '123456@%'")

List<User> findAllEmailUsers();

}

需要特殊说明的是,在SpringData默认的DSL不能满足需求时,那么就需要结合其支持的拓展注解@Query来灵活自定义更为复杂的SQL操作,当然这里只是为了演示用法,仅仅是实现了模糊匹配的查询。另外,findAllEmailUsers方法是用户自定义的,此时可以不需要符合Spring Data的规则,可随意命名。

4、混合自定义操作方法,与降级EntityManager结合

UserRepository.java:

public interface UserRepository extends JpaRepository<User,String> , UserExtRepository {

// 这里不需要任何方法

}

这里主要是在SpringData默认方法,以及@Query都不能满足需求时(虽然很少),就需要降级使用老版的EntityManager来实现了,当然,虽然结合使用了EntityManager,也就需要实现对应的接口,这里新建立了一个UserExtRepository接口,具体内容如下:

public interface UserExtRepository {

// 单一的Spring Data JPA无法完成的操作,

// 需要降低版本,结合EntityManager协同完成

public int batchUpdate(String email);

}

那么,接下来就得提供一个它的实现类:UserRepositoryImpl了,内容如下:

@Repository("UserRepositoryImpl")

public class UserRepositoryImpl implements UserExtRepository {

@PersistenceContext

private EntityManager em;

@Override

public intbatchUpdate(String email) {

String update = "update User u set u.status=1 where u.email='"+email+"'";

return em.createQuery(update).executeUpdate();

}

}

需要注意的是,SpringData在结合EntityManager实现JPA时,需要嵌入了EntityManager的实现类,如:UserRepositoryImpl,需要满足Spring Data的命名规则,其默认必须是采用xxxImpl的形式才能被识别,如果需要定义为别的格式命名,只需要在@EnableJpaRepositories开支持时(在Spring上下文配置中声明,这里使用的是JavaConfig方式),指定命名格式即可,具体如下实现:

@EnableJpaRepositories(basePackages="com.cwteam.orm.dao",repositoryImplementationPostfix="Helper")

同时,还有个需要注意的是,既然你想在Spring Data中混合使用EntityManager的功能,那么你的实现类的命名需要有一定规则,如:UserRepositoryImpl,其与我们继承JpaRepository的自定义类UserRepository相对应吧!另外,这里的basePackages的作用比较显示,用来指定扫描初始化Entity的位置。

三、Spring Data JPA重构实例

在完成了上面所有工作之后,接下来具体介绍下针对上一篇文章的例子重构,实际上改动量较小,主要修改Dao相关,以及控制器调用相关,具体各个新增或修改的内容已经在上面第二部分有介绍,这里直接罗列代码!

1、Dao层相关

新增UserRepository.java:

public interface UserRepository extends JpaRepository<User,String>,UserExtRepository {

// 定义查询方法,供JpaRepository默认18个方法无法满足时

User findByUsername(String userName);

// 定对查询方法,根据email或mobile查询多条记录

List<User> findByEmailOrMobile(String email,String mobile);

// 声明自定义查询,根据email模糊查询多条记录

@Query("select u from User u where u.email like '123456@%'")

List<User> findAllEmailUsers();

}

新增UserExtRepository.java:

public interface UserExtRepository {

// 单一的Spring Data JPA无法完成的操作,

// 需要降低版本,结合EntityManager协同完成

public int batchUpdate(String email);

}

新增UserRepositoryImpl.java:

@Repository("UserRepositoryImpl")

public class UserRepositoryImpl implements UserExtRepository {

@PersistenceContext

private EntityManager em;

@Override

public int batchUpdate(String email) {

String update = "update User u set u.status=1 where u.email='"+email+"'";

return em.createQuery(update).executeUpdate();

}

}

2、Service层

新增UserRepositoryService.java:

@Service("UserRepositoryService")

public class UserRepositoryService {

@Autowired

private UserRepository userRepository;

// 新增记录

@Transactional

public void saveUser(User user) {

userRepository.save(user);

}

// 更新记录

@Transactional

public void updateUser(User user) {

User result = findUserByID(user);

result.setUsername(user.getUsername());

result.setPassword(user.getPassword());

result.setEmail(user.getEmail());

result.setMobile(user.getMobile());

}

// 根据ID查询记录

public User findUserByID(User user) {

return userRepository.findOne(user.getId());

}

// 根据用户名查询

public User findByUsername(String username) {

return userRepository.findByUsername(username);

}

// 根据邮箱或手机查询

public List<User> findByEmailOrMobile(String email,String mobile) {

return userRepository.findByEmailOrMobile(email, mobile);

}

// 根据email模糊匹配

public List<User> findAllEmailUsers() {

return userRepository.findAllEmailUsers();

}

// 查询所有记录

public List<User> findUsersNoPage() {

return userRepository.findAll();

}

// 根据用户名删除记录

@Transactional

public void delete(User user) {

userRepository.delete(user);

}

// 批量修改status状态

@Transactional

public int batchUpdate(String email) {

return userRepository.batchUpdate(email);

}

}

3、Controller层

UserController.java:

@Controller

@RequestMapping("/user")

public class UserController {

@Autowired

UserRepositoryService userRepositoryService;

// 操作页面

@RequestMapping(value="/show",method=RequestMethod.GET)

public ModelAndView show() throws Exception {

// 业务逻辑处理

List<User> result = userRepositoryService.findUsersNoPage();

// 页面数据渲染

ModelAndView mav = new ModelAndView("test/user_operation");

mav.addObject("result", result);

return mav;

}

// 新增记录

@RequestMapping(value="/save",method=RequestMethod.POST)

public ModelAndView save(HttpServletRequest request) throws Exception {

User user = new User();

user.setUsername(request.getParameter("username"));

user.setPassword(request.getParameter("password"));

user.setMobile(request.getParameter("mobile"));

user.setEmail(request.getParameter("email"));

// 业务逻辑处理

userRepositoryService.saveUser(user);

// 页面数据渲染

ModelAndView mav = new ModelAndView("test/user_operation");

mav.addObject("result", userRepositoryService.findUsersNoPage());

return mav;

}

// 更新记录

@RequestMapping(value="/update",method=RequestMethod.POST)

public ModelAndView update(HttpServletRequest request) throws Exception {

User user = new User();

user.setId(request.getParameter("id"));

user.setUsername(request.getParameter("username"));

user.setPassword(request.getParameter("password"));

user.setMobile(request.getParameter("mobile"));

user.setEmail(request.getParameter("email"));

// 业务逻辑处理

userRepositoryService.updateUser(user);

// 页面数据渲染

ModelAndView mav = new ModelAndView("test/user_operation");

mav.addObject("result", userRepositoryService.findUsersNoPage());

return mav;

}

// 根据ID查询

@RequestMapping(value="/find",method=RequestMethod.GET)

public ModelAndView find(HttpServletRequest request) throws Exception {

User user = new User();

user.setId(request.getParameter("id"));

// 业务逻辑处理

User user2 = userRepositoryService.findUserByID(user);

List<User> result = new ArrayList<User>();

result.add(user2);

// 页面数据渲染

ModelAndView mav = new ModelAndView("test/user_operation");

mav.addObject("result", result);

return mav;

}

// 根据用户名查询

@RequestMapping(value="/findbyusername",method=RequestMethod.GET)

public ModelAndView findByUsername(HttpServletRequest request) throws Exception {

User user = new User();

user.setUsername(request.getParameter("username"));

// 业务逻辑处理

User userTmp = userRepositoryService.findByUsername(user.getUsername());

List<User> result = new ArrayList<User>();

result.add(userTmp);

// 页面数据渲染

ModelAndView mav = new ModelAndView("test/user_operation");

mav.addObject("result", result);

return mav;

}

// 根据email或mobile查询

@RequestMapping(value="/findbyemailormobile",method=RequestMethod.GET)

public ModelAndView findByEmailOrMobile(HttpServletRequest request) throws Exception {

User user = new User();

user.setEmail(request.getParameter("email"));

user.setMobile(request.getParameter("mobile"));

// 业务逻辑处理

List<User> result = userRepositoryService.findByEmailOrMobile(user.getEmail(), user.getMobile());

// 页面数据渲染

ModelAndView mav = new ModelAndView("test/user_operation");

mav.addObject("result", result);

return mav;

}

// 根据email模糊匹配查询

@RequestMapping(value="/findallemailusers",method=RequestMethod.GET)

public ModelAndView findAllEmailUsers(HttpServletRequest request) throws Exception {

// 业务逻辑处理

List<User> result = userRepositoryService.findAllEmailUsers();

// 页面数据渲染

ModelAndView mav = new ModelAndView("test/user_operation");

mav.addObject("result", result);

return mav;

}

// 根据ID删除记录

@RequestMapping(value="/delete",method=RequestMethod.GET)

public ModelAndView delete(HttpServletRequest request) throws Exception {

User user = new User();

user.setId(request.getParameter("id"));

// 业务逻辑处理

userRepositoryService.delete(user);

// 页面数据渲染

ModelAndView mav = new ModelAndView("test/user_operation");

mav.addObject("result", userRepositoryService.findUsersNoPage());

return mav;

}

// 根据email匹配批量修改

@RequestMapping(value="/batchupdate",method=RequestMethod.POST)

public ModelAndView extUpdate(HttpServletRequest request) throws Exception {

String email = request.getParameter("email");

// 业务逻辑处理

userRepositoryService.batchUpdate(email);

// 页面数据渲染

ModelAndView mav = new ModelAndView("test/user_operation");

mav.addObject("result", userRepositoryService.findUsersNoPage());

return mav;

}

}

4、View页面

具体的页面部分,请读者结合上一篇的jsp页面进行修改实现,具体实现的效果会在下面逻辑,读者也可以自行设计布局。

整体效果如下:

A、新增一条记录

新增cwteam7记录

B、修改一条记录

修改cwteam7的mobile值

C、根据ID查询

根据ID查询cwteam7记录

D、删除一条记录

删除cwteam7这条记录

E、根据用户名查询


根据用户名查询cwteam5记录

F、根据email或mobile查询

G、根据email模糊查询

查询条件,请查看UserRepository代码部分。

H、匹配email批量修改

修改的细节,请查看UserRepositoryImpl代码部分。

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号