spring Data Jpa入门

参考资料
1:http://spring.io/blog/2011/02/10/getting-started-with-spring-data-jpa/
2:http://docs.spring.io/spring-data/jpa/docs/1.5.2.RELEASE/reference/html/
Spring Framework对JPA的支持本身就很强大,我们不用理会EntityManager的创建,事务处理等等.Spring又进步了,只需要声明一下方法接口,Spring Data JPA可以帮你完成数据访问层的实现代码,开发者把更多的心思放在业务逻辑和需求上吧!


一.基本样例,四步走:
1.声明一个接口继承Repository或其子接口之一,写上Domain类和它能处理的ID类型(实现了Serializable接口的主键)
public interface UserRepository extends Repository<User, Long> {...}
2.如果需要,就在这个接口扩展一些Repository没有实现的方法.比如
List<User> findByUsername(String username);
3.为这些接口设置spring来创建代理实例.可以通过JavaConfig方式:
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@EnableJpaRepositories
class Config {...}
4.获得注入的Repository实例来使用.
public class SomeClient {
@Autowired
private UserRepository repository;
public void doSomething() {
List<User> users = repository.findByUsername("Matthews");
}

}

二.Spring Data web支持:在MVC的JavaConfig类上标注@EnableSpringDataWebSupport就可以实现Spring Data JPA对web的支持.这项配置注册了两个基本组件:
1.DomainClassConverter:使Spring mvc能从请求参数或路径变量来解析库管理的domain类实例.
2.HandlerMethodArgumentResolver:使Spring mvc能从请求参数来解析Pageable和Sort实例.
1.如下例子,不用自己手工去查询,converter先将路径变量转换为User的id类型,再通过findOne(…)自动查询数据并转换user.(根据情况使用@PathVariable或@RequestParam,都不用,不会自动去查哦)
@RequestMapping("/{id}")
public String showUserForm(@PathVariable("id") User user, Model model) {
model.addAttribute("user", user);
return "userForm";
}
2.这个看起来是必须实现的一个自动解析转换.不然从request拿,再构造Pageable和Sort?太麻烦!如果不使用@EnableJpaRepositories,可以手动注册PageableHandlerArgumentResolver
@RequestMapping
public String showUsers(Model model, Pageable pageable) {
model.addAttribute("users", repository.findAll(pageable));
return "users";
}
注意:使用了@EnableJpaRepositories就不要自己去用RequestMappingHandlerAdapter.不然,就不要去用@EnableJpaRepositories,自己想办法注册DomainClassConverter和HandlerMethodArgumentResolver!

使用RequestMappingHandlerAdapter自定义注册DomainClassConverter的一个例子:

@Configuration
@ComponentScan(basePackages={"com.test.web"})
@EnableWebMvc
public class MvcConfig extends WebMvcConfigurerAdapter{
	public static final MediaType APPLICATION_JSON_UTF8 = new MediaType(MediaType.APPLICATION_JSON.getType(),
			MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("UTF-8"));
	public static final MediaType TEXT_HTML_UTF8 = new MediaType(MediaType.TEXT_HTML.getType(),
			MediaType.TEXT_HTML.getSubtype(), Charset.forName("UTF-8"));
	@Override
	public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
		configurer.enable();
	}
	@Override
	public void addResourceHandlers(ResourceHandlerRegistry registry) {
		registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
		registry.addResourceHandler("**/*.html").addResourceLocations("/");
	}
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
	}
	@Bean
	public FormattingConversionService mvcConversionService() {
		return new DefaultFormattingConversionService();
	}
	@Bean
	public DomainClassConverter<?> domainClassConverter() {
		return new DomainClassConverter<FormattingConversionService>(mvcConversionService());
	}
	@Bean
	public RequestMappingHandlerMapping requestMappingHandlerMapping(){
		return new RequestMappingHandlerMapping();
	}
	@Bean
	public RequestMappingHandlerAdapter requestMappingHandlerAdapter(){
		ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer();
		initializer.setConversionService(mvcConversionService());

		List<HttpMessageConverter<?>> converters=new ArrayList<HttpMessageConverter<?>>();
		MappingJackson2HttpMessageConverter converter=new MappingJackson2HttpMessageConverter();
		List<MediaType> mediaTypes=new ArrayList<MediaType>();
		mediaTypes.add(TEXT_HTML_UTF8);
		mediaTypes.add(APPLICATION_JSON_UTF8);
		converter.setSupportedMediaTypes(mediaTypes);
		converters.add(converter);

		RequestMappingHandlerAdapter adapter=new RequestMappingHandlerAdapter();
		adapter.setMessageConverters(converters);
		adapter.setWebBindingInitializer(initializer);
		return adapter;
	}

	@Bean
	public InternalResourceViewResolver internalResourceViewResolver() {
		InternalResourceViewResolver resolver = new InternalResourceViewResolver();
		resolver.setPrefix("/WEB-INF/");
		resolver.setSuffix(".jsp");
		return resolver;
	}
	@Bean
	public MultipartResolver multipartResolver(){
		CommonsMultipartResolver bean=new CommonsMultipartResolver();
		bean.setMaxUploadSize(8388608);
		return bean;
	}
}
三.对repository方法提供自定义实现,经常是有需要的.下面是个例子,比如已经有一个UserRepository:
1.先定义一个自定义接口.

public interface UserRepositoryCustom {
	boolean login(String username,String password);
}
2.然后让这个Repository接口继承spring data jpa自带的Repository和刚才自定义的接口.因为这个继承,所以这个UserRepository类型包含了CrudRepository和UserRepositoryCustom的所有可继承的方法.
public interface UserRepository extends CrudRepository<User, Long>,UserRepositoryCustom {
    void deleteAllInBatch();
}
3.实现刚才自定义的接口(不要去实现UserRepository).注意这个类的命名,不能随意,是以这个Repository接口的名字加上Impl后缀(这个后缀可通过@EnableJpaRepositories的repositoryImplementationPostfix来修改),还有一点要注意,这个类必须要在JpaRepositories仓库管理之下,即这个类要被包含在@EnableJpaRepositories的basePackages,否则出错.
public class UserRepositoryImpl implements UserRepositoryCustom {
	@Override
	public boolean login(String username, String password) {
		System.out.println("正在登录...");
		return false;
	}
}
类的层次结构如下:
     UserRepositoryCustom        CrudRepository
             /                            \                  /

UserRepositoryImpl       UserRepository


我们使用的时候,注入的是spring data jpa生成的UserRepository代理实现类实例,而不是UserRepositoryImpl实例.

上面是官方例子.下面是另一个设计,UserRepository只是继承spring data jpa的Repository(没有再继承其它自定义接口,可以实现JpaSpecificationExecutor这些API),不用定义UserRepositoryCustom,再写一个类UserRepositoryImpl,这个类也不用implement接口,用户自定义的方法声明就放在了UserRepository.然后实现放在UserRepositoryImpl.但类UserRepositoryImpl却不是实现UserRepository它,这样的类层次可能看起来不错.写起来就怪怪的,比如你在UserRepository改了方法名,UserRepositoryImpl没改过来(只在写代码编译阶段,还没运行)也没报错,所以此做不推荐,宁愿写多一个接口,把自定义的方法都扔这接口,层次也清楚

                                               CrudRepository
                                                        /
UserRepositoryImpl       UserRepository

spring data jpa的这两种设计,自定义实现类(上面的UserRepositoryImpl)好像没法直接调用spring data jpa本身的接口,在此实现类通过依赖注入也是可以实现的.比如在UserRepositoryImpl使用:

@Autowired
 private UserRepository userRepository;

这样你就可以方便调用spring data jpa的API了,当然你可以注入EntityManager再操作实体.

发现CrudRepository接口里面的几个参数和返回类型都是Iterable,迭代Iterable的方法有:

iterator是一个迭代器,可以边删除边迭代,它有一个指针的作用.但增强版的for是不能边删除边迭代的.

Iterable<User> users=userRepository.findAll();
for (Iterator<User> it=users.iterator();it.hasNext();){
User user = it.next();
System.out.println(user.getUsername());
}
for (User user:users){
System.out.println(user.getUsername());
}


源码下载:http://download.csdn.net/detail/xiejx618/7334523

你可能感兴趣的:(spring,jpa,jpa,Data)