返回介绍

4.7.1 WEB支持

发布于 2020-08-26 12:31:29 字数 15911 浏览 992 评论 0 收藏 0

Spring Data带有很多的web支持。要使用它们,需要在classpath中加入Spring MVC的jar包,有的还需要整合Spring HATEOAS。通常情况下,只需在JavaConfig的配置类中使用@EnableSpringDataWebSupport注解即可。

Example 24. Enabling Spring Data web support(使用Spring Data的web支持)

@Configuration
@EnableWebMvc
@EnableSpringDataWebSupport
class WebConfiguration { }

@EnableSpringDataWebSupport注解会注册一些组件,我们会在之后讨论。它同样也会去检测classpath中的Spring HATEOAS,并且注册他们。

如果不想通过JavaConfig开启web支持,也可以使用xml配置,将SpringDataWebSupportHateoasAwareSpringDataWebSupport注册为Spring的bean。

Example 25. Enabling Spring Data web support in XML(使用xml配置)

<bean class="org.springframework.data.web.config.SpringDataWebConfiguration" />

<!-- If you're using Spring HATEOAS as well register this one *instead* of the former -->
<bean class="org.springframework.data.web.config.HateoasAwareSpringDataWebConfiguration" />

基础的web支持

上面的配置会注册一些基础组件:

  • DomainClassConverter:使Spring MVC可以从请求参数或路径变量中解析repository管理的域对象的实例。
  • HandlerMethodArgumentResolver:使Spring mvc能从请求参数来解析Pageable和Sort实例
DomainClassConverter

DomainClassConverter 允许开发者在SpringMVC控制层的方法中直接使用域对象类型(Domain types),而无需通过repository手动查找这个实例。

Example 26. A Spring MVC controller using domain types in method signatures (在Spring MVC控制层方法中直接使用域对象类型)

@Controller
@RequestMapping("/users")
public class UserController {

  @RequestMapping("/{id}")
  public String showUserForm(@PathVariable("id") User user, Model model) {

    model.addAttribute("user", user);
    return "userForm";
  }
}

上面的方法直接接收了一个User对象,开发者不需要做任何的搜索操作,转换器会自动将路径变量id转为User对象的id,并且调用了findOne()方法查询出User实体。

注意:当前的Repository 必须实现CrudRepository

HandlerMethodArgumentResolver

这个配置同时注册了PageableHandlerMethodArgumentResolverSortHandlerMethodArgumentResolver,是开发者可以在controller的方法中使用PageableSort作为参数。 Example 27. Using Pageable as controller method argument(在controller中使用Pageable作为参数)

@Controller
@RequestMapping("/users")
public class UserController {

  @Autowired UserRepository repository;

  @RequestMapping
  public String showUsers(Model model, Pageable pageable) {

    model.addAttribute("users", repository.findAll(pageable));
    return "users";
  }
}

通过上面的方法定义,Spring MVC会使用下面的默认配置尝试从请求参数中得到一个Pageable的实例。 Table 1. Request parameters evaluated for Pageable instances page(由于构造Pageable实例的请求参数)

参数名作用
page想要获取的页数,默认为0
size获取页的大小,默认为20
sort需要排序的属性,格式为property,property(,ASC/DESC),默认升序排序。支持多个字段排序,比如?sort=firstname&sort=lastname,asc

如果开发者想要自定义分页或排序的行为,可以继承SpringDataWebConfigurationHATEOAS-enabled,并重写pageableResolver()sortResolver()方法,引入自定义的配置文件来代替使用@Enable-注解。

开发者也可以针对多个表定义多个PageableSort实例,需要使用Spring的@Qualifier注解来区分它们。并且请求参数名要带有${qualifier}_的前缀。例子如下:

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

请求中需要带有foo_page和bar_page等参数。

默认的Pageable相当于new PageRequest(0, 20),但开发者可以在Pageable参数上使用@PageableDefaults来自定义。

超媒体分页

Spring HATEOAS有一个PagedResources类,它丰富了Page实体以及一些让用户更容易导航到资源的链接。Page转换到PagedResources是由一个实现了Spring HATEOAS ResourceAssembler接口的实现类:PagedResourcesAssembler提供转换的。 Example 28. Using a PagedResourcesAssembler as controller method argument(使用PagedResourcesAssembler当做方法参数)

@Controller
class PersonController {

  @Autowired PersonRepository repository;

  @RequestMapping(value = "/persons", method = RequestMethod.GET)
  HttpEntity<PagedResources<Person>> persons(Pageable pageable,
    PagedResourcesAssembler assembler) {

    Page<Person> persons = repository.findAll(pageable);
    return new ResponseEntity<>(assembler.toResources(persons), HttpStatus.OK);
  }
}

上面的toResources方法会执行以下的几个步骤:

  • Page对象的content会转换成为PagedResources对象的content。
  • PagedResources会的到一个PageMetadata的实体,包含从Page跟PageRequest得到的信息。
  • PagedResources会根据状态得到prev跟next链接,这些链接指向URI所匹配的方法。分页参数会根据PageableHandlerMethodArgumentResolver配置,以让其能够在后面的方法中解析使用。

假设我们数据库中存有30个人。发送一个GET请求http://localhost:8080/persons,得到的返回结果如下:

{ "links" : [ { "rel" : "next",
                "href" : "http://localhost:8080/persons?page=1&size=20 }
  ],
  "content" : [
     … // 20 Person instances rendered here
  ],
  "pageMetadata" : {
    "size" : 20,
    "totalElements" : 30,
    "totalPages" : 2,
    "number" : 0
  }
}

从返回结果中可以看出assembler生成了正确的URI,并根据默认配置设置了分页的请求参数。这意味着,如果我们更改了配置,这个链接会自动更改。默认情况下,assembler生成的链接会指向被调用的controller方法,但也可以通过重写PageResourceAssembler.toResource{...}方法提供一个自定义的链接。

QueryDSL web支持

对于那些集成了QueryDSL的存储可以从请求的查询参数中直接获得查询语句。 这意味着下面的针对User的请求参数:

?firstname=Dave&lastname=Matthews

会通过QuerydslPredicateArgumentResolver解析成:

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

如果使用了@EnableSpringDataWebSupport注解,并且classpath中包含Querydsl,那么该功能会自动开启。

在方法中加入@QuerydslPredicate注解,可以提供我们使用Predicate

@Controller
class UserController {

  @Autowired UserRepository repository;

  @RequestMapping(value = "/", method = RequestMethod.GET)
  String index(Model model, @QuerydslPredicate(root = User.class) Predicate predicate,     //1
          Pageable pageable, @RequestParam MultiValueMap<String, String> parameters) {

    model.addAttribute("users", repository.findAll(predicate, pageable));

    return "index";
  }
}
1.解析查询参数来匹配针对user的Predicate

默认的绑定如下:

  • 一个对象对应一个简单属性相当于eq
    ?firstname=2
    
  • 多个属性上对应一个对象相当于contains
    ?firstname=2&firstname=3
    
  • 简单属性对应一个集合相当于in
    ?firstname=[2,3,4,5]
    

这些绑定规则可以通过@QuerydslPredicatebindings属性或者使用Java 8新引入的default方法在repository接口中加入QuerydslBinderCustomizer方法来更改。

interface UserRepository extends CrudRepository<User, String>,
                                 QueryDslPredicateExecutor<User>,       //1         
                                  QuerydslBinderCustomizer<QUser> {      //2              

  @Override
  default public void customize(QuerydslBindings bindings, QUser user) {

    bindings.bind(user.username).first((path, value) -> path.contains(value))          //3
    bindings.bind(String.class)
      .first((StringPath path, String value) -> path.containsIgnoreCase(value));        //4 
    bindings.excluding(user.password);  //5                                         
  }
}

1.QueryDslPredicateExecutor provides access to specific finder methods for Predicate.
2.QuerydslBinderCustomizer defined on the repository interface will be automatically picked up and shortcuts @QuerydslPredicate(bindings=…​).
3.Define the binding for the username property to be a simple contains binding.
4.Define the default binding for String properties to be a case insensitive contains match.
5.Exclude the password property from Predicate resolution.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文