spring和JPA

Entity

使用@Entity注解使javabean类成为实体类。
一般使用@Id注解在成员变量或者其对应的get方法设置实体类的主键。

例子:

1package com.hgf.jpa.domain; 2 3import javax.persistence.Entity; 4import javax.persistence.Id; 5 6/** 7 * Created by hgf on 16/8/21. 8 */ 9@Entity 10public class Employee { 11 @Id 12 private int id; 13 private String name; 14 private long salary; 15 16 public Employee() { 17 } 18 19 public Employee(int id) { 20 this.id = id; 21 } 22 23 public int getId() { 24 return id; 25 } 26 27 public void setId(int id) { 28 this.id = id; 29 } 30 31 public String getName() { 32 return name; 33 } 34 35 public void setName(String name) { 36 this.name = name; 37 } 38 39 public long getSalary() { 40 return salary; 41 } 42 43 public void setSalary(long salary) { 44 this.salary = salary; 45 } 46 47 @Override 48 public String toString() { 49 return "Employee{" + 50 "id=" + id + 51 ", name='" + name + '\'' + 52 ", salary=" + salary + 53 '}'; 54 } 55} 56

注意:不能使用@Id注解在setter方法上面。

Entity Manager

Entity Manager负责对Entity类的持久化。Entity的集合成为persistent context。

JPA概念的关系

一个persistent identity只有一个对应的实体实例在entity persistent context中。

EntityManagerFactory负责生成EntityManager。每个EntityManagerFactory对应着唯一名字的persistent unit。

一般获取EntityManagerFactory是通过Persistent类的静态方法Persistence.createEntityManagerFactory并指定persisitent unit的名称,构造。

EntityManagerFactory emf = Persistence.createEntityManagerFactory("EmployeeService");

所有的EntityManager都是由EntityManagerFactory构造。
例如:
EntityManager em = emf.createEntityManager();

持久化一个实体

将数据持久化例子:

1Employee employee = new Employee(100); 2em.persist();

可能会出现PersistentException

更加规范:

1public Employee createEmployee(int id, String name, long salary){ 2 Employee employee = new Employee(id, name, salary); 3 em.persist(); 4}

查询数据

1public Employee findEmployee(int id){ 2 return em.find(Employee.class, id); 3}

删除数据

1public boolean removeEmployee(int id){ 2 Employee employee = findEmployee(id); 3 if(employee!=null){ 4 em.remove(employee); 5 } 6}

更新数据

1public Employee raiseEmployeeSalary(int id, long raise){ 2 Employee emp = em.findEmployee(id); 3 if(emp!=null){ 4 emp.setSalary(emp.getSalary()+raise); 5 return emp; 6 } 7}

事务

1em.getTransaction().begin(); 2//do somethings 3em.getTransaction().commit();

sql查询

查询一般使用Query或者TypedQuery表示。通过EntityManager的静态方法设置查询语句。

1TypedQuery<Employee> query = em.createQuery("select * from employee", Employee.class); 2List<Employee> employees = query.getResultList();

Spring JPA

核心概念

CURD Repository:CURD表示创建(Create),更新(Update),读取(Retrieve),删除(Delete)。

CURD Pepository 的接口核心方法如下,其中泛型类型分别值得是实体类的类型和Id的类型(ID的类型必须是可以序列化的)。

1public interface CrudRepository<T, ID extends Serializable> 2 extends Repository<T, ID> { 3 4 <S extends T> S save(S entity); 5 6 T findOne(ID primaryKey); 7 8 Iterable<T> findAll(); 9 10 Long count(); 11 12 void delete(T entity); 13 14 boolean exists(ID primaryKey); 15 16 // … more functionality omitted. 17}

spring 也提供JpaRepositoryMongoRepository,他们继承自CurdRepository,并且使用特定的持久化技术实现。

PagingAndSortingRepository集成自CurdRepository,提供了通用简单的分页方法。

PagingAndSortingRepository接口:

1public interface PagingAndSortingRepository<T, ID extends Serializable> 2 extends CrudRepository<T, ID> { 3 4 Iterable<T> findAll(Sort sort); 5 6 Page<T> findAll(Pageable pageable); 7}

如果每页显示User 20项,可以这么处理:

1PagingAndSortingRepository<User, Long> repository = //get access to a bean 2Page<User> users = repository.findAll(new PageRequest(1,20));

查询方法

使用Spring Data,查询方法分为四步:

  1. 声明一个继承自Repository(或者其子接口)的接口,并指定实体类和ID类型。

    interface PersonRepository extends Repository<Person, Long> { … }
    
  2. 接口中声明查询方法:

    1interface PersonRepository extends Repository<Person, Long> { 2 List<Person> findByLastname(String lastname); 3}
  3. 设置Spring,创建接口的代理实现。

    1import org.springframework.data.jpa.repository.config.EnableJpaRepositories; 2 3@EnableJpaRepositories 4class Config {} 5 6 7<?xml version="1.0" encoding="UTF-8"?> 8<beans xmlns="http://www.springframework.org/schema/beans" 9 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 10 xmlns:jpa="http://www.springframework.org/schema/data/jpa" 11 xsi:schemaLocation="http://www.springframework.org/schema/beans 12 http://www.springframework.org/schema/beans/spring-beans.xsd 13 http://www.springframework.org/schema/data/jpa 14 http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"> 15 16 <jpa:repositories base-package="com.acme.repositories"/> 17 18</beans>
  4. 将接口注入

    1public class SomeClient { 2 3 @Autowired 4 private PersonRepository repository; 5 6 public void doSomething() { 7 List<Person> persons = repository.findByLastname("Matthews"); 8 } 9}

定义repository接口

定义一个实体相关的repository接口,必须继承Repository或者其子类,并且确定实体类类型和ID类型,Id需要可序列化。

典型的可继承的接口有:RepositoryCrudRepositoryPagingAndSortingRepository

如果不想继承Spring data接口,可以使用@RepositoryDefinationg注解,在自定义的接口上。

继承自 定义了一系列用于处理实体类方法的CurdRepository,并且可以选择性的暴露操作实体的方法。

例子,选择性的暴露CRUD方法:

1@NoRepositoryBean 2interface MyBaseRepository<T, ID extends Serializable> extends Repository<T, ID> { 3 4 T findOne(ID id); 5 6 T save(T entity); 7} 8 9interface UserRepository extends MyBaseRepository<User, Long> { 10 User findByEmailAddress(EmailAddress emailAddress); 11}

注意:@NoRepositoryBean,使用该注解后给repository接口后,SpringData不会在运行时给该接口生成实现类。

使用多个Spring data模块

在项目中使用多个不同的Spring data模块时,Spring data会在类路径上检查repository工厂类,必须使用严格的Repository定义才能生成正确的repository,绑定到特定的Springdata模块。

严格定义:

  1. 使用特定模块对应的repository;
  2. 使用特定模块repository对应的注解。

例如:

1interface MyRepository extends JpaRepository<User, Long> { } 2 3@NoRepositoryBean 4interface MyBaseRepository<T, ID extends Serializable> extends JpaRepository<T, ID> { 56} 7 8interface UserRepository extends MyBaseRepository<User, Long> { 910}

上述例子中,MyRepositoryUserRepository继承自JPA模块的特定repository,他们在多个Springdata模块共用的时候是有效的。

1interface AmbiguousRepository extends Repository<User, Long> { 23} 4 5@NoRepositoryBean 6interface MyBaseRepository<T, ID extends Serializable> extends CrudRepository<T, ID> { 78} 9 10interface AmbiguousUserRepository extends MyBaseRepository<User, Long> { 1112}

上例中使用通用的repository接口,AmbiguousRepositoryAmbiguousUserRepository都继承自通用接口,在多个spring data模块的时候,相互之间不能互相区分,需要将通用的repository接口绑定到特定的repository。

1interface PersonRepository extends Repository<Person, Long> { 23} 4 5@Entity 6public class Person { 78} 9 10interface UserRepository extends Repository<User, Long> { 1112} 13 14@Document 15public class User { 1617}

上例中,PersonRepository接口继承自通用的接口,但是Person类使用了@Entity注解,该注解是特定的JPA注解,所以PersonRepository属于Spring Data JPA模块。
UserRepository接口也是通用的Sping data模块,@Document 注解是Spring Data MongoDB的注解。

1interface JpaPersonRepository extends Repository<Person, Long> { 23} 4 5interface MongoDBPersonRepository extends Repository<Person, Long> { 67} 8 9@Entity 10@Document 11public class Person { 1213}

上述类中,由于Person类注解了@Entity@Document,Spring data不知道对应的Repository,出现问题。

使用多种不同模块的注解在同一个实体类上,可以服用实体类的定义,但是Sping Data不能区分不同的模块绑定。

最简单的方式就是使用基于包名的模块分类。即使用同一个Spring Data模块的类放在一个包中。

例如:

1@EnableJpaRepositories(basePackages = "com.acme.repositories.jpa") 2@EnableMongoRepositories(basePackages = "com.acme.repositories.mongo") 3interface Configuration { }

上述定义中,基于包名划分Spring data模块,并且使用特定的模块扫描特定的包,就不会发生冲突。

定义查询方法

Spring data支持两种查询方式:

  1. 基于方法名的查询;
  2. 手动设定查询语句;

查询策略

设定查询策略方式:

  • 在XML中使用query-lookup-strategy
  • 在配置类中,使用EnableJpaRepoditory等注解时,设置注解的属性queryLookupStrategy

常见的策略:

  • CREATE 从方法名中构造保存数据请求。
  • USE_DECLARED_QUERY 尝试查找一个声明的query,找不到时会抛出异常。
  • CREATE_IF_NOT_FOUND 【默认】结合了CREATEUSE_DECLARED_QUERY,首先去查找声明的query,没有找到,则根据方法名创建query。

创建查询

查询的属性必须是被管理的实体类的属性!!!

常见的方法名前缀有:find…By, read…By, query…By, count…By, get…By,还可包含Distinct将结果去重。

By扮演者前缀和实际查询判断标准(where)的分隔符。

例子:

1public interface PersonRepository extends Repository<User, Long> { 2 3 List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname); 4 5 // Enables the distinct flag for the query 6 List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname); 7 List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname); 8 9 // 对一个参数忽略大小写 10 List<Person> findByLastnameIgnoreCase(String lastname); 11 // 对所有的参数都忽略大小写 12 List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname); 13 14 // Enabling static ORDER BY for a query 15 List<Person> findByLastnameOrderByFirstnameAsc(String lastname); 16 List<Person> findByLastnameOrderByFirstnameDesc(String lastname); 17}
  1. ANDORBetween, LessThan, GreaterThan, Like
  2. 使用IgnoreCase忽略某个属性的大小写;使用AllIgnoreCase忽略所有属性的大小写。
  3. OrderBy定义排序,后面可确定排序的方式。Asc递增排序;Desc递减排序。

属性表达式

属性必须是被管理的实体类的属性。该属性既可以是基础数据类型,也可以是某个实体的引用属性。

Person有Address属性,Address有ZipCode属性,那么根据ZipCode查询Person可以使用

List<Person> findByAddressZipCode(ZipCode zipCode);

解析方法先获取AddressZipCode,并且当做属性,并检查管理的实体类中是否有该属性,如果没有,则解析方法按照驼峰命名的规则,从右往左,查找符合的属性。先找AddressZipCode属性,如果找到AddressZip,那么再判断AddresZip类中是否有Code属性,依次类推。如果AddressZip 和Code 不符合,则找AddressZipCode

为了这种模糊的查找过程可以在方法名中使用_手动的定义遍历点。

List<Person> findByAddress_ZipCode(ZipCode zipCode);

强烈建议遵循java规范,使用驼峰命名,不适用_下划线。

特殊参数处理

Spring data会自动识别PageableSort参数,去动态实现分页和排序的功能。

例子:

1Page<User> findByLastname(String lastname, Pageable pageable); 2 3Slice<User> findByLastname(String lastname, Pageable pageable); 4 5List<User> findByLastname(String lastname, Sort sort); 6 7List<User> findByLastname(String lastname, Pageable pageable);

org.springframework.data.domain.Pageable是实现自动分页的。Page知道查询元素的总个数和页数,然后通过对所有元素的排序和数数确定每页的元素,每次查询都严重依赖排序。Slice是替代方案,Slice只知道是否还有下个分片。当结果集很大的时候使用Slice更加高效。

排序也可以通过Pageable实现,但是单纯的排序的话,最好使用Sort,并且返回一个List集合,不必再生成Page实例。

limit 查询结果

限制查询结果可以通过方法名中的firsttopDistinct限制。

1User findFirstByOrderByLastnameAsc(); 2 3User findTopByOrderByAgeDesc(); 4 5Page<User> queryFirst10ByLastname(String lastname, Pageable pageable); 6 7Slice<User> findTop3ByLastname(String lastname, Pageable pageable); 8 9List<User> findFirst10ByLastname(String lastname, Sort sort); 10 11List<User> findTop10ByLastname(String lastname, Pageable pageable);

如果在限制查询后分页,那么分页是在限制后分页。

Stream 查询结果

查询结果也可以处理成java8 的Stream类型。

1@Query("select u from User u") 2Stream<User> findAllByCustomQueryAndStream(); 3 4Stream<User> readAllByFirstnameNotNull(); 5 6@Query("select u from User u") 7Stream<User> streamAllPaged(Pageable pageable);

使用Stream后必须关闭stream!
可以通过Strea的close方法或者java7特性try-with-resource特性。
例如:

1try (Stream<User> stream = repository.findAllByCustomQueryAndStream()) { 2 stream.forEach(); 3}

异步查询

使用spring 异步方法执行能力,Repository 查询也可异步化。
这意味着这些方法会立即返回,实际的查询会作为一个task交给Spring TaskExecutor。

1@Async 2Future<User> findByFirstname(String firstname); 3 4@Async 5CompletableFuture<User> findOneByFirstname(String firstname); 6 7@Async 8ListenableFuture<User> findOneByLastname(String lastname);

创建repository实例

可以使用配置类和XML配置。

XML配置

1<?xml version="1.0" encoding="UTF-8"?> 2<beans:beans xmlns:beans="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns="http://www.springframework.org/schema/data/jpa" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans.xsd 7 http://www.springframework.org/schema/data/jpa 8 http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"> 9 10 <repositories base-package="com.acme.repositories" /> 11 12</beans:beans>

在上述设置中,spring会被指定扫描com.acme.repositories包和它的子包中继承自Repository或者它的子接口的接口。然后创建与查找到接口相关的FactoryBean,来生成代理类。每个代理bean的name都是使用接口名。

扫描的包名可以使用通配符设定。

过滤不需要的Repository。
在repositories标签中使用<include-filter /><exclude-filter />来实现过滤。

例如:

1<repositories base-package="com.acme.repositories"> 2 <context:exclude-filter type="regex" expression=".*SomeRepository" /> 3</repositories>

配置类

使用@EnableXXXXRepositories注解配置。

1@Configuration 2@EnableJpaRepositories("com.acme.repositories") 3class ApplicationConfiguration { 4 5 @Bean 6 public EntityManagerFactory entityManagerFactory() { 7 // … 8 } 9}

独立使用Spring Data Repository

在Spring 容器外可能也会用到Springdata Repository。

可以手动获取Repository。

1RepositoryFactorySupport factory =// Instantiate factory here 2UserRepository repository = factory.getRepository(UserRepository.class);

自定义Spring Data Repository

给某个repository添加新的方法

  1. 自定义新的接口
  2. 定义实现类并实现接口
  3. 在其他接口中使用自定义接口。

自定义接口:

1interface UserRepositoryCustom { 2 public void someCustomMethod(User user); 3}

实现接口:

1class UserRepositoryImpl implements UserRepositoryCustom { 2 3 public void someCustomMethod(User user) { 4 // Your custom implementation 5 } 6}

注意:自定义实现类只比自定义接口多了Impl,这样才能被找到!!!
使用repository-impl-postfix自定义实现类的后缀
实现类是一个常见的Spring bean,可以使用依赖注入。

使用自定义接口:

1interface UserRepository extends CrudRepository<User, Long>, UserRepositoryCustom { 2 3 // Declare query methods here 4}

给所有的Repository添加新的方法

给所有的Repository添加新的方法使用上节讲述的方法是行不通的。

为了所有的repository添加新的方法,首先需要添加一个中间接口定义所有的共享方法,中间接口继承自Repository或者其子接口

1@NoRepositoryBean 2public interface MyRepository<T, ID extends Serializable> 3 extends PagingAndSortingRepository<T, ID> { 4 5 void sharedCustomMethod(ID id); 6}

然后所有的独立Repository接口都必须集成自这个接口,而不是Repository接口。
然后实现中间接口,该类会作为repository代理类的基类。

1public class MyRepositoryImpl<T, ID extends Serializable> 2 extends SimpleJpaRepository<T, ID> implements MyRepository<T, ID> { 3 4 private final EntityManager entityManager; 5 6 public MyRepositoryImpl(JpaEntityInformation entityInformation, 7 EntityManager entityManager) { 8 super(entityInformation, entityManager); 9 10 // Keep the EntityManager around to used from the newly introduced methods. 11 this.entityManager = entityManager; 12 } 13 14 public void sharedCustomMethod(ID id) { 15 // implementation goes here 16 } 17}

中间接口实现类必须有一个与特定存储技术相关的Repository, 使用的 工厂实现。
如上例中,覆盖含有EntityInformation和一个含有特定存储技术的对象(上例中的EntityManager

在上例中,需要给中间接口添加@NoRepositoryBean注解,防止Spring给中间接口生成代理类与自己的实现冲突,得到意想不到的结果。

最后,使自定义Repository基类生效。

1@Configuration 2@EnableJpaRepositories(repositoryBaseClass = MyRepositoryImpl.class) 3class ApplicationConfiguration {} 4 5 6<repositories base-package="com.acme.repository" 7 repository-base-class="….MyRepositoryImpl" />

在EnableXXXXRepositories注解中添加repositoryBaseCLass属性。

Spring Data扩展

QueryDsl 扩展

QueryDsl是一个通过流式API实现的静态类型的像SQL语句的查询框架。

Spring Data通过QueryDslPredicateExecutor 与QueryDls整合。

1public interface QueryDslPredicateExecutor<T> { 2 3 T findOne(Predicate predicate); 4 5 Iterable<T> findAll(Predicate predicate); 6 7 long count(Predicate predicate); 8 9 boolean exists(Predicate predicate); 10 11 // … more functionality omitted. 12}

使用QueryDsl的特性,只需要在自己的Repository接口继承QueryDslPredicateExecutor

1interface UserRepository extends CrudRepository<User, Long>, QueryDslPredicateExecutor<User> { 2 3}

上例中支持基于QueryDslPredicate类的类型安全查询。

1Predicate predicate = user.firstname.equalsIgnoreCase("dave") 2 .and(user.lastname.startsWithIgnoreCase("mathews")); 3 4userRepository.findAll(predicate);

Spring data web support

使用@EnableSPringDataWebSupport开启Spring data web支持。

@EnableSPringDataWebSupport注册组件并且自动检测整合classpath上 出现的Spring HASTEOAS。

如果使用XML,

1<bean class="org.springframework.data.web.config.SpringDataWebConfiguration" /> 2 3<!-- 如果使用Spring HATEOAS,使用这个bean替换掉上面的bean --> 4<bean class="org.springframework.data.web.config.HateoasAwareSpringDataWebConfiguration" />

自动注册的组件有:

  • DomainClassConverter:Spring MVC可以解析请求参数或者路径上的参数为Repository重注册的实体类。
  • HandlerMethodArgumentResolver 使SpringMVC可以解析请求参数中的PageableSort实例。分别对应PageableHandlerMethodArgumentResolverSortHandlerMethodArgumentResolver两种resolver。

例如:

1@Controller 2@RequestMapping("/users") 3public class UserController { 4 5 @RequestMapping("/{id}") 6 public String showUserForm(@PathVariable("id") User user, Model model) { 7 8 model.addAttribute("user", user); 9 return "userForm"; 10 } 11}

上例中,直接解析参数中的id,并获取对应的User实例,而必须要显示的查询。DomainClassCOnverter会先获取路径上的id,然后使用findOne查询Repository中注册的实体类实例。

实体类必须实现CurdRepository才能通过DomainClassConverter转换。

HandlerMethodArgumentResolver例子:

1@Controller 2@RequestMapping("/users") 3public class UserController { 4 5 @Autowired UserRepository repository; 6 7 @RequestMapping 8 public String showUsers(Model model, Pageable pageable) { 9 10 model.addAttribute("users", repository.findAll(pageable)); 11 return "users"; 12 } 13}

这个方法会使SpringMVC尝试从请求中获取Pageable实例。

请求中的参数:

  • page: 想获取的页码,默认为0;
  • size: 每页的大小,默认20;
  • sort: 分页使用的排序方式,asc或者desc,例如sort=firstname&sortlastname,asc

想自定义方法行为,可继承SpringDataWebConfiguration或者HateoasAwareSpringDataWebConfiguration,然后覆盖pageableResolversortResolver,然后使用自定义配置使继承类生效,而不是直接使用@EnableXXX注解。

当有多个Pageable和Sort实例需要从请求中解析时,可以使用spring的@Qualifier注解区分不同的实例,然后请求的参数必须以${qualifier}_为前缀。

例如:

1public String showUsers(Model model, 2 @Qualifier("foo") Pageable first, 3 @Qualifier("bar") Pageable second) {}

请求参数:foo_pagebar_page

参数上默认的Pageable相当于PageRequest(0,20),可以使用@PageableDefaults注解在Pageable参数上来自定义分页参数。

Spring HATEOAS 带有表示层的PagedResources,可以通过Page转为PagedResource,转换功能由PagedResourcesAssembler提供。

1@Controller 2class PersonController { 3 4 @Autowired PersonRepository repository; 5 6 @RequestMapping(value = "/persons", method = RequestMethod.GET) 7 HttpEntity<PagedResources<Person>> persons(Pageable pageable, 8 PagedResourcesAssembler assembler) { 9 10 Page<Person> persons = repository.findAll(pageable); 11 return new ResponseEntity<>(assembler.toResources(persons), HttpStatus.OK); 12 } 13}
  • PagedResources中的内容为Page实例中的内容。
  • PagedResources会获取一个由PageRequest和Page中信息填充的PageMetadata实例。
  • PagedResources会获得一个prevnext连接。

例如,上述请求完成后的结果:

1{ "links" : [ { "rel" : "next", 2 "href" : "http://localhost:8080/persons?page=1&size=20 } 3 ], 4 "content" : [ 5// 20 Person instances rendered here 6 ], 7 "pageMetadata" : { 8 "size" : 20, 9 "totalElements" : 30, 10 "totalPages" : 2, 11 "number" : 0 12 } 13}

对于使用QueryDsl的,可能从Request请求中获取查询属性。使用QuerydslPredicateArgumentResolver完成查询解析。

例如:
?firstname=Dave&lastname=Matthews
会被解析成:

QUser.user.firstname.eq("Dave").and(QUser.user.lastname.eq("Matthews"))

当classpath中存在QueryDsl时,QuerydslPredicateArgumentResolver会在使用@EnableSpringDataWebSupport的时候自动激活。

使用@QueryPredicate注解会使Prediacte使用QueryDskPredicateExecutor执行。

由于在解析参数的时候,参数并不是一个实体的所有属性,不能唯一确定一个实体类,使用QuerydslPredicateroot属性设置实体类类型会比较好。

1@Controller 2class UserController { 3 4 @Autowired UserRepository repository; 5 6 @RequestMapping(value = "/", method = RequestMethod.GET) 7 String index(Model model, @QuerydslPredicate(root = User.class) Predicate predicate, 8 Pageable pageable, @RequestParam MultiValueMap<String, String> parameters) { 9 10 model.addAttribute("users", repository.findAll(predicate, pageable)); 11 12 return "index"; 13 } 14}

填充Repository

使用存储无关的JSON(通过Jackson)、XML(通过Spring OXM)作为数据源填充Repository。

例如,data.json

1[ { "_class" : "com.acme.Person", 2 "firstname" : "Dave", 3 "lastname" : "Matthews" }, 4 { "_class" : "com.acme.Person", 5 "firstname" : "Carter", 6 "lastname" : "Beauford" } ]

定义json数组,每一行使用_class定义本行的数据类 类型,其后为实体类的属性和值。

定义填充:

1<?xml version="1.0" encoding="UTF-8"?> 2<beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:repository="http://www.springframework.org/schema/data/repository" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans.xsd 7 http://www.springframework.org/schema/data/repository 8 http://www.springframework.org/schema/data/repository/spring-repository.xsd"> 9 10 <repository:jackson2-populator locations="classpath:data.json" /> 11 12</beans>

data.json会被反序列化,通过jackson的ObjectMapper读入。

传统web支持

1@Controller 2@RequestMapping("/users") 3public class UserController { 4 5 private final UserRepository userRepository; 6 7 @Autowired 8 public UserController(UserRepository userRepository) { 9 Assert.notNull(repository, "Repository must not be null!"); 10 this.userRepository = userRepository; 11 } 12 13 @RequestMapping("/{id}") 14 public String showUserForm(@PathVariable("id") Long id, Model model) { 15 16 // Do null check for id 17 User user = userRepository.findOne(id); 18 // Do null check for user 19 20 model.addAttribute("user", user); 21 return "user"; 22 } 23}
点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )