}
二.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:
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; } }类的层次结构如下:
UserRepositoryImpl UserRepository
上面是官方例子.下面是另一个设计,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