最近发现JPA在处理单表时,很方便,但多表就比较复杂了。今天写一下端午这两天琢磨的多条件查询,还有多表联查。
文章比较长,大部分都是代码,不愿意看的代码copy下去,直接可以实现;想交流的可以看完,然后留言交流。
maven依赖啊,配置,继承写法等知识点不展开说了,之前写过一篇文章:
spring boot 配置及使用 spring data jpa
这里说一下更新的地方:
######################################################
###spring data JPA配置
######################################################
#指定JPA的DB
spring.jpa.database=MYSQL
#是否显示SQL
spring.jpa.show-sql=true
#执行DDL语句时,是创建create,创建删除create-drop,更新update
spring.jpa.hibernate.ddl-auto=update
#命名策略:当创建了entity,会在DB中创建一个表结构
#这个是驼峰命名法,遇到大写加下划线
#spring.jpa.hibernate.naming.physical-strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
#这个是默认写法,以属性名命名
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
#hibernate配置DB方言
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
说一点,命名策略的配置更新了,以前是:
org.hibernate.cfg.DefaultNamingStrategy
org.hibernate.cfg.ImprovedNamingStrategy
但我发现配置了之后无论使用哪种都是带下划线的,所以查找了一下资料,发现现在使用上面的两个配置:
PhysicalNamingStrategyStandardImpl 默认以属性名作为字段名;
SpringPhysicalNamingStrategy 以驼峰法拆分加下划线为字段名。
其他注解几乎都写明白了,不是重点不展开赘述了。
系统分4层:entity,repository,service,controller
模拟:一个用户可以有多个地址,但是一条地址记录,只能对应一个用户。
两个实体webuser和address
因为两个实体有共性,都需要主键,创建时间,销毁时间.....所以抽出来单独写一个类。
package com.wm.springboot.base;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;
import javax.persistence.Version;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Getter;
import lombok.Setter;
@MappedSuperclass //表明这是父类,可以将属性映射到子类中使用JPA生成表
public abstract class BaseEntity extends BaseClass {
@JSONField(ordinal=1) @Getter @Setter
@Id @GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="id",columnDefinition="int(30) comment '无意义自增主键'")
protected Integer id; //无意义自增主键
@JSONField(ordinal=2,format="yyyy-MM-dd HH:mm:ss") @Getter @Setter
@Column(name="createTime",columnDefinition="DATETIME comment '创建时间'")
protected Date createTime; //创建时间
@JSONField(ordinal=3,format="yyyy-MM-dd HH:mm:ss") @Getter @Setter
@Column(name="destroyTime",columnDefinition="DATETIME comment '销毁时间'")
protected Date destroyTime; //销毁时间
@JSONField(ordinal=4) @Getter @Setter
@Version @Column(name="version",nullable=false,columnDefinition="int(20) comment '版本号'")
protected Integer version;
@JSONField(ordinal=5) @Getter @Setter
@Column(length=1,name="isValid",nullable=false,columnDefinition="int(1) comment '是否启用,1:启用 0:不启用'")
protected Integer isValid; //是否启用
@Transient
@JSONField(ordinal=5) @Getter @Setter
protected String createTimeStart; //创建时间的开始点
@Transient
@JSONField(ordinal=6) @Getter @Setter
protected String createTimeEnd; //创建时间的结束点
}
1,由于是父类,所以不需要单独实例化,所以写成抽象类。
2,BaseClass不展开了,里面是国际化;这里只从baseEntity展开。
3,使用@MappedSuperclass注解,让子类在JPA生成表时可以使用父类继承来的属性。
4,@Getter @Setter 使用了插件lombok,自动生成getset方法,非常好用。多说一句:有人觉得这个东西改变了代码的写法,造成不好影响,我觉得目前使用来看,没给我造成什么不好影响,反而提高了我的效率。
5,@JSONField(ordinal=1) 继承了fastjson带的注解,这里仅做排序使用。其实可以不用写,我写习惯了。
6,@Id, 这个是生成表时的主键,按照数据库设计原则,主键应该是无意义自增主键。所以我觉得可以抽象出来放到父类;使每个表的主键都叫ID也不是什么问题;
7,@GeneratedValue(strategy=GenerationType.AUTO) 主键生成策略,自增;
8,@Column:网上一查一大堆。不过我的用法跟网上不太一样。简单说一下吧。
a),name,映射到表时的字段名,这个和上面讲的命名策略相关。
如果使用之前的策略或者加下划线的命名策略,这里只要使用驼峰写法的,都会自动加下划线。我不想要这种命名策略,所以使用:PhysicalNamingStrategyStandardImpl,这样其实name可以省略了,但是为了规范我还是写上了。
b),length 长度,比如String类型的属性 length写20,生成字段为varchar(20),这里注意:length的值要和后面写的columnDefinition中的例如:varchar(32)的值一致,不然启动时会报错。所以如果配置columnDefinition,建议可以不写length。
c),nullable:能否为空 true:可以为空 false:不能为空。
这里其实还有一个属性:unique,唯一性约束,我这里发现一个问题;如果设置了unique,那么启动时会报错,但是启动能成功!而且,去表中看,唯一性约束设置成功。报错的大概意思好像是还没表无法设置唯一性约束。这里我觉得有可能涉及到底层原因。有时间再深究吧。但是我看着这个报错又难受,我就退而求其次,使用columnDefinition设置字段的唯一性约束,并且好处是还可以设置字段的备注,或者映射到表中的字段类型,以及长度。
d),columnDefinition: 其实就是添加建表sql。例子代码都有。
9,@version 乐观锁,这个不是重点 不赘述了。
package com.wm.springboot.base;
import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Getter;
import lombok.Setter;
@MappedSuperclass //表明这是父类,可以将属性映射到子类中使用JPA生成表
public abstract class BaseUserEntity extends BaseEntity {
@JSONField(ordinal=1)
@Getter @Setter
@Column(length=32,name="userName",nullable=false,columnDefinition="varchar(32) unique comment '用户名'")
protected String userName; //用户名
@JSONField(ordinal=2) @Getter @Setter
@Column(length=32,name="password",nullable=false,columnDefinition="varchar(32) default '000000' comment '密码'")
protected String password; //密码
@JSONField(ordinal=3) @Getter @Setter
@Column(length=64,name="email",nullable=false,columnDefinition="varchar(64) unique comment '邮箱'")
protected String email; //邮箱号
@JSONField(ordinal=4) @Getter @Setter
@Column(length=11,name="phoneNo",nullable=false,columnDefinition="varchar(11) unique comment '电话号码'")
protected String phoneNo; //手机号
@JSONField(ordinal=5)
@Getter @Setter
@Column(length=32,name="realName",nullable=false,columnDefinition="varchar(32) comment '真实姓名'")
protected String realName; //真实姓名
}
注解参考上面解释。这么写的思路是,假设一个系统分管理用用户,和网站用户。这样用户也会有共同特性。所以再抽象一层。
package com.wm.springboot.sc.entity;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.wm.springboot.base.BaseUserEntity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* 用户信息表
* 原则:ID,用户名,邮箱号,手机号,微信ID都不可重复
* @author maybe
*/
@NoArgsConstructor
@AllArgsConstructor
/*
* @Entity说明这是一个实体bean,使用orm默认规则(类名=表名;属性名=字段名)关联DB;
* 如果想改变这种规则:1,可以配置@Entity的name来对应DB中的表名;@Entity(name="USER")
* 2,使用@Table来改变class和DB表名的映射规则;@Column来改变属性名和字段名的映射规则
*/
@Entity(name="WEBUSER")
public class WebUser extends BaseUserEntity{
@JSONField(ordinal=1) @Getter @Setter
@Column(length=32,name="nickName",columnDefinition="varchar(32) comment '昵称'")
private String nickName; //昵称
@JSONField(ordinal=2) @Getter @Setter
@Column(length=32,name="wxId",columnDefinition="varchar(32) unique comment '微信号'")
private String wxId; //微信ID
@JSONField(ordinal=3) @Getter @Setter
@OneToMany(mappedBy="webUser",cascade=CascadeType.ALL,fetch=FetchType.LAZY)
private Set addresses;
public WebUser(String username) {
this.userName = username;
}
@Override
public String toString() {
return JSONObject.toJSONString(this,true);
}
}
@NoArgsConstructor 无参构造器
@AllArgsConstructor 全参构造器 不过只是本类的全部参数,如果需要使用父类参数,还需要自己写构造器。
@Entity(name="WEBUSER") 将被此注解标注的实体,映射到数据库,表名为name名。
@OneToMany(mappedBy="webUser",cascade=CascadeType.ALL,fetch=FetchType.LAZY)
webuser是用户实体,一个用户对应多个地址,所以webuser是“一对多”中的“一”。在一的实体中,使用此注解标注。
mappedBy:标注该属性对应“多”的实体中的属性名。
cascade 表示级联操作。
fetch 加载方式,默认都是lazy加载。
重写toString方法,fastjson提供,将实体打印时,默认以json格式输出。 true的意思是标准json格式。
package com.wm.springboot.sc.entity;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.wm.springboot.base.BaseEntity;
import lombok.Getter;
import lombok.Setter;
@Entity(name="ADDRESS")
public class Address extends BaseEntity {
@JSONField(ordinal=1) @Getter @Setter
@Column(name="label",nullable=false,columnDefinition="varchar(16) comment '地址标签(家、公司)'")
private String label;
@JSONField(ordinal=2) @Getter @Setter
@Column(name="country",nullable=false,columnDefinition="varchar(16) comment '国家'")
private String country;
@JSONField(ordinal=3) @Getter @Setter
@Column(name="province",nullable=false,columnDefinition="varchar(32) comment '省份'")
private String province;
@JSONField(ordinal=4) @Getter @Setter
@Column(name="city",nullable=false,columnDefinition="varchar(32) comment '城市'")
private String city;
@JSONField(ordinal=5) @Getter @Setter
@Column(name="address",nullable=false,columnDefinition="varchar(255) comment '具体地址'")
private String address;
@JSONField(ordinal=6) @Getter @Setter
@ManyToOne(cascade=CascadeType.ALL,fetch=FetchType.LAZY,optional=true)
@JoinColumn(name="webUser_id",nullable=true)
private WebUser webUser;
@Override
public String toString() {
return JSONObject.toJSONString(this,true);
}
}
@ManyToOne(cascade=CascadeType.ALL,fetch=FetchType.LAZY,optional=true)
address表为“一对多”中的多,所以使用@ManyToOne注解,并且配合@JoinColumn注解使用。
如果单独使用@ManyToOne,那么会生成一张中间表来维护两张表关系,如果不想使用中间表使用@JoinColumn来生成外键维护两张表关系。
name="webUser_id",表示生成的外键名称,并且字段类型以webUser表的主键为准。
==================================================
比较简单了,普通的增删改JPA封装的很好了。这里重点说多条件查询及多表联查。先上代码。
package com.wm.springboot.sc.repository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.wm.springboot.sc.entity.WebUser;
@Repository
public interface WebUserRepository extends JpaRepository{
public Page findAll(Specification specification,Pageable pageable);
}
使用Specification来进行复杂条件查询,还可以使用Pageable进行分页查询。具体实现我们再service进行实现。
package com.wm.springboot.sc.repository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.wm.springboot.sc.entity.Address;
@Repository
public interface AddressRepository extends JpaRepository {
public Page findAll(Specification specification,Pageable pageable);
}
=====================================
面向接口变成我们先定义一下webuser的service
package com.wm.springboot.sc.service;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import com.wm.springboot.sc.entity.WebUser;
public interface WebUserService {
/**
* 单表条件查询
*/
public Page findAll(WebUser webUser,Pageable pageable);
/**
* 批量添加
* @param list
* @return
*/
public WebUser save(WebUser webUser);
/**
* 单个删除
* @param user
*/
public void deleteOne(int id);
/**
* 单个修改
*/
public WebUser update(WebUser webUser);
/**
* 根据ID查找
*/
public WebUser findOne(int id);
}
package com.wm.springboot.sc.service.impl;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import com.wm.springboot.sc.entity.WebUser;
import com.wm.springboot.sc.repository.WebUserRepository;
import com.wm.springboot.sc.service.WebUserService;
@Service("WebUserServiceImpl")
public class WebUserServiceImpl implements WebUserService {
@Autowired
private WebUserRepository webUserRepository;
@Override
public Page findAll(WebUser webUser, Pageable pageable) {
Page page = webUserRepository
.findAll((Root root, CriteriaQuery> query, CriteriaBuilder cb) -> {
List predicates = new ArrayList();
predicates.add(cb.like(root.get("userName").as(String.class), "%"+webUser.getUserName() + "%"));
predicates.add(cb.like(root.get("email").as(String.class), "%"+webUser.getEmail() + "%"));
predicates.add(cb.like(root.get("phoneNo").as(String.class), "%"+webUser.getPhoneNo() + "%"));
predicates.add(cb.equal(root.get("isValid").as(String.class), webUser.getIsValid()));
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
try {
if (null != webUser.getCreateTimeStart() && !"".equals(webUser.getCreateTimeStart()))
predicates.add(cb.greaterThanOrEqualTo(root.get("createTime").as(Date.class),
f.parse(webUser.getCreateTimeStart())));
if (null != webUser.getCreateTimeEnd() && !"".equals(webUser.getCreateTimeEnd()))
predicates.add(cb.lessThan(root.get("createTime").as(Date.class),
new Date(f.parse(webUser.getCreateTimeEnd()).getTime() + 24 * 3600 * 1000)));
} catch (ParseException e) {
e.printStackTrace();
}
return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
}, pageable);
return page;
}
@Override
@Transactional
public WebUser save(WebUser webUser) {
return webUserRepository.save(webUser);
}
@Override
public void deleteOne(int id) {
webUserRepository.delete(id);
}
@Override
public WebUser update(WebUser webUser) {
return webUserRepository.save(webUser);
}
@Override
public WebUser findOne(int id) {
return webUserRepository.findOne(id);
}
}
重点说一下实现的findAll方法。因为使用jdk8,进入接口Specification,发现是函数式接口,直接使用lambda表达时进行书写。关于lambda表达式:
lambda概念及实际使用举例
简述一下这段逻辑,有错误请指正:
进入相应的方法可以看到:
root应该就是来获得字段的。
CriteriaBuilder 是用来拼装查询条件的。 如like equal greaterThanOrEqualTo ......
将每一个Predicate添加到list,然后使用CriteriaQuery进行查询。
pageable,是用来分页查询的。
package com.wm.springboot.sc.service;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import com.wm.springboot.sc.entity.Address;
public interface AddressService {
public Address save(Address address);
public Page findAll(Pageable pageable,Address address);
}
package com.wm.springboot.sc.service.impl;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import com.wm.springboot.sc.entity.Address;
import com.wm.springboot.sc.entity.WebUser;
import com.wm.springboot.sc.repository.AddressRepository;
import com.wm.springboot.sc.service.AddressService;
@Service
public class AddressServiceImpl implements AddressService {
@Autowired
private AddressRepository addressRepository;
@Override
public Address save(Address address) {
return addressRepository.save(address);
}
@Override
public Page findAll(Pageable pageable,Address address) {
return addressRepository.findAll((Root root, CriteriaQuery> query, CriteriaBuilder cb)->{
List predicates = new ArrayList();
if(null!=address.getId()&&!"".equals(address.getId()))
predicates.add(cb.equal(root.get("id").as(Integer.class),address.getId()));
if(null!=address.getWebUser()&&!"".equals(address.getWebUser()))
predicates.add(cb.equal(root.get("webUser").get("id"),address.getWebUser().getId()));
return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
},pageable);
}
}
重点:root.package com.wm.springboot.sc.controller;
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.wm.springboot.modelUtils.Pages;
import com.wm.springboot.modelUtils.PagesUtils;
import com.wm.springboot.modelUtils.RespResult;
import com.wm.springboot.modelUtils.RespResultEnum;
import com.wm.springboot.modelUtils.RespResultUtil;
import com.wm.springboot.sc.entity.WebUser;
import com.wm.springboot.sc.service.WebUserService;
/**
* 网站用户控制器
* @author maybe
*/
@RequestMapping("/WebUser")
@RestController
public class WebUserController {
@Autowired
private WebUserService webUserService;
/**
* 分页查询所有用户(动态页数,每页大小,排序方式,排序字段)
* 包括动态条件查询(用户名,email,电话,是否启用,创建时间)
* 规则:无输入条件,默认查询全部。默认返回第一页 每页5条,默认asc排序,默认id排序。
*/
@RequestMapping(value="/findAll.do",method={RequestMethod.POST,RequestMethod.GET})
public RespResult> findAll(Pages pages,WebUser webUser){
return RespResultUtil.success(webUserService.findAll(webUser, PagesUtils.createPageRequest(pages)));
}
/**
* 添加
*/
@PostMapping(value="/save.do")
public RespResult> save(WebUser webUser){
webUser.setCreateTime(new Date());
webUser.setIsValid(1);
webUser.setVersion(2);
System.out.println(webUser.toString());
WebUser webUser2 = webUserService.save(webUser);
if(webUser2!=null) return RespResultUtil.success();
else return RespResultUtil.error(RespResultEnum.ERROR);
}
/**
* 单个删除
*/
@RequestMapping(value="/deleteOne.do",method= {RequestMethod.POST,RequestMethod.GET})
public RespResult> deleteOne(String id){
try {
webUserService.deleteOne(Integer.parseInt(id));
} catch (Exception e) {
return RespResultUtil.error(RespResultEnum.ERROR);
}
return RespResultUtil.success();
}
/**
* 修改
* @param webUser
* @return
*/
@RequestMapping(value="/update.do",method= {RequestMethod.POST,RequestMethod.GET})
public RespResult> update(WebUser webUser){
webUser.setVersion(webUserService.findOne(webUser.getId()).getVersion());
System.out.println(webUser.toString());
WebUser user = webUserService.update(webUser);
if(user!=null) return RespResultUtil.success();
else return RespResultUtil.error(RespResultEnum.ERROR);
}
}
RespResult、RespResultUtil为我自己封装的返回实体类。具体可参考:
哦,我还没来得及写。。。有空补上。
在说下Pages、PagesUtils类,这个也是我自己封装的分页相关的类:
package com.wm.springboot.modelUtils;
import com.alibaba.fastjson.JSON;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@AllArgsConstructor
@NoArgsConstructor
public class Pages {
@Getter @Setter
private int page;//第几页
@Getter @Setter
private int size;//每页显示几条内容
@Getter @Setter
private String sortColumn; //排序字段
@Getter @Setter
private String direction; //排序方式
@Override
public String toString() {
return JSON.toJSONString(this, true);
}
}
package com.wm.springboot.modelUtils;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.util.StringUtils;
public class PagesUtils {
//分页大小
private final static Integer SIZE = 5;
//默认页数 0开头
private final static Integer PAGE = 0;
//默认排序字段
private final static String ID = "id";
public static Pageable createPageRequest(Pages pages) {
return new PageRequest(pages.getPage()<=0?PAGE:pages.getPage(),
pages.getSize()<=0?SIZE:pages.getSize(),
new Sort(null!=pages.getDirection()&&!"".equals(pages.getDirection())&&pages.getDirection().equals("desc")?Direction.DESC:Direction.ASC,
StringUtils.isEmpty(pages.getSortColumn())?ID:pages.getSortColumn()));
}
}
这样的好处时,前台将页数,分页大小,排序字段,排序方式都从前台传入。灵活多变。还有一个没来得及补全的就是多字段排序。这个回来再添加。
package com.wm.springboot.sc.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.wm.springboot.modelUtils.Pages;
import com.wm.springboot.modelUtils.PagesUtils;
import com.wm.springboot.modelUtils.RespResult;
import com.wm.springboot.modelUtils.RespResultEnum;
import com.wm.springboot.modelUtils.RespResultUtil;
import com.wm.springboot.sc.entity.Address;
import com.wm.springboot.sc.service.AddressService;
@RestController
@RequestMapping(value="/address")
public class AddressController {
@Autowired
private AddressService addressService;
@RequestMapping(value="/save.do")
public RespResult> save(Address address){
address.setVersion(0);
address.setIsValid(1);
Address address2 = addressService.save(address);
System.out.println(address2);
if(address2!=null) return RespResultUtil.success();
return RespResultUtil.error(RespResultEnum.ERROR);
}
@RequestMapping(value="/findAll.do")
public RespResult> findAll(Address address,Pages pages){
System.out.println(address.toString());
return RespResultUtil.success(addressService.findAll(PagesUtils.createPageRequest(pages), address));
}
}
================================================================================================================
还有就是前台代码也可以稍微熟悉一下。所以下面看一下前台,使用html+jq实现。
直接上代码吧,一目了然。
id修改使用:
userName不能重复:
password:
email不能重复:
phoneNo不能重复:
realName:
测试多表联查
关联ID:
ID
USERNAME
EMAIL
PHONENO
REALNAME
DELETE
启动项目:
看到数据库生成的表:
可以看到父类的字段,备注等都有。
随手添加了几条数据。
然后测试两个表的findAll是否可以成功的进行关联查询及webuser的复杂条件查询。
测试结果:
复杂条件查询:
多表联查:
{
"code":0,
"msg":"处理成功",
"remindMsg":"处理成功",
"data":{
"content":[
{
"id":1,
"label":"1",
"country":"1",
"province":"1",
"city":"1",
"version":0,
"address":"1",
"isValid":1,
"webUser":{
"id":11,
"userName":"123",
"createTime":"2018-06-17 21:06:26",
"password":"123",
"addresses":[{
"id":3,
"label":"3",
"country":"3",
"province":"3",
"city":"3",
"version":0,
"address":"3",
"isValid":1,
"webUser":{"$ref":"$.data.content[0].webUser"}
},{
"id":2,
"label":"2",
"country":"2",
"province":"2",
"city":"2",
"version":0,
"address":"2",
"isValid":1,
"webUser":{"$ref":"$.data.content[0].webUser"}
},{"$ref":"$.data.content[0]"}],
"email":"222",
"phoneNo":"123",
"version":2,
"isValid":1,
"realName":"123"
}
},
{"$ref":"$.data.content[0].webUser.addresses[1]"},
{"$ref":"$.data.content[0].webUser.addresses[0]"}
],
"first":true,
"last":true,
"number":0,
"numberOfElements":3,
"size":5,
"sort":[{
"ascending":true,
"descending":false,
"direction":"ASC",
"ignoreCase":false,
"nullHandling":"NATIVE",
"property":"id"
}],
"totalElements":3,
"totalPages":1
}
}