spring data jpa 实现多条件复杂查询及多表联查

32 篇文章 0 订阅

写了好多年了,求波点赞,收藏,关注,一键三连!!

 

最近发现JPA在处理单表时,很方便,但多表就比较复杂了。今天写一下端午这两天琢磨的多条件查询,还有多表联查。

文章比较长,大部分都是代码,不愿意看的代码copy下去,直接可以实现;想交流的可以看完,然后留言交流。

maven依赖啊,配置,继承写法等知识点不展开说了,之前写过一篇文章:

spring boot 配置及使用 spring data jpa

这里说一下更新的地方:

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

模拟:一个用户可以有多个地址,但是一条地址记录,只能对应一个用户。

entity:

两个实体webuser和address

因为两个实体有共性,都需要主键,创建时间,销毁时间.....所以抽出来单独写一个类。

entity父类:

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  乐观锁,这个不是重点 不赘述了。

用户子类BaseUserEntity:

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; //真实姓名
}

注解参考上面解释。这么写的思路是,假设一个系统分管理用用户,和网站用户。这样用户也会有共同特性。所以再抽象一层。

WebUser类:

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<Address> 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格式。

 

Address类:

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表的主键为准。

 

多表联查的重点是:@ManyToOne@JoinColumn@OneToMany注解的使用。

==================================================

实体搞完了,下面搞一下repository层

比较简单了,普通的增删改JPA封装的很好了。这里重点说多条件查询及多表联查。先上代码。

WebUserRepository

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<WebUser, Integer>{

	public Page<WebUser> findAll(Specification<WebUser> specification,Pageable pageable);
}

使用Specification来进行复杂条件查询,还可以使用Pageable进行分页查询。具体实现我们再service进行实现。

AddressRepository

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<Address, Integer> {
	
	public Page<Address> findAll(Specification<Address> specification,Pageable pageable);
}

 

=====================================

 

接下来是service层及repository的方法实现

面向接口变成我们先定义一下webuser的service

WebUserService

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<WebUser> 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);
}

实现类WebUserServiceImpl

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<WebUser> findAll(WebUser webUser, Pageable pageable) {
		Page<WebUser> page = webUserRepository
				.findAll((Root<WebUser> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {
					List<Predicate> predicates = new ArrayList<Predicate>();
					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,是用来分页查询的。

 

AddressService

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<Address> findAll(Pageable pageable,Address address);
}
 

实现类AddressServiceImpl

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<Address> findAll(Pageable pageable,Address address) {
		return addressRepository.findAll((Root<Address> root, CriteriaQuery<?> query, CriteriaBuilder cb)->{
			List<Predicate> predicates = new ArrayList<Predicate>();
			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.<WebUser>get("webUser").<Integer>get("id"),address.getWebUser().getId()));
			return query.where(predicates.toArray(new Predicate[predicates.size()])).getRestriction();
		},pageable);
	}

}
重点:root.<WebUser>get("webUser").<Integer>get("id")  通过获取address类中的属性webUser,得到一个webUser实体中的id,这个就是address中的外键。也是多表联查时的关键。

=======================================

 

controller层,访问控制器

 

先看一下webuserController

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<Page<WebUser>> 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类,这个也是我自己封装的分页相关的类:

pages类:

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);
	}
}

PagesUtils类

 

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()));
	}
}

这样的好处时,前台将页数,分页大小,排序字段,排序方式都从前台传入。灵活多变。还有一个没来得及补全的就是多字段排序。这个回来再添加。

 

然后是AddressController

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));
	}
	
}
================================================================================================================
到此,java部分已经完成。其实后面可以使用junit测试一下。但是我junit使用的不是很好,总感觉用的不是特别舒服。
 

还有就是前台代码也可以稍微熟悉一下。所以下面看一下前台,使用html+jq实现。

直接上代码吧,一目了然。

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" 
	xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<script type="text/javascript" src="/webjars/jquery/jquery.js"></script>
<script type="text/javascript" src="/js/test.js"></script>
</head>
<body>
	<div>
			<p>id修改使用:<input type="text" name="id" id="id"/></p>
			<p>userName不能重复:<input type="text" name="userName" id="userName"/></p>
			<p>password:<input type="text" name="password" id="password"/></p>
			<p>email不能重复:<input type="text" name="email" id="email"/></p>
			<p>phoneNo不能重复:<input type="text" name="phoneNo" id="phoneNo"/></p>
			<p>realName:<input type="text" name="realName" id="realName"/></p>
			<input type="button" value="提交" id="submit"/>
			<input type="button" value="修改" id="update"/>
	</div>
	<div>
		<form>
			<p>label:<input type="text" name="label" id="label"/></p>
			<p>country:<input type="text" name="country" id="country"/></p>
			<p>province:<input type="text" name="province" id="province"/></p>
			<p>city:<input type="text" name="city" id="city"/></p>
			<p>address:<input type="text" name="address" id="address"/></p>
			<input type="button" value="提交address" id="submitAddress"/>
		</form>
	</div>
	
<!-- 	<div> -->
<!-- 		<form> -->
<!-- 			<p>sender:<input type="text" name="sender" id="sender"/></p> -->
<!-- 			<p>addressee:<input type="text" name="addressee" id="addressee"/></p> -->
<!-- 			<p>msgTitle:<input type="text" name="msgTitle" id="msgTitle"/></p> -->
<!-- 			<p>msgText:<input type="text" name="msgText" id="msgText"/></p> -->
<!-- 			<input type="button" value="提交email" id="submitEmails"/> -->
<!-- 		</form> -->
<!-- 	</div> -->
	
	<div>
			<input type="button" value="查询所有" id="findAll"/>
			<input type="text" value="0" placeholder="页数" id="page" name="page"/> 
			<input type="text" value="15" placeholder="大小" id="size" name="size"/> 
			<input type="text" value="id" placeholder="排序列" id="sortColumn" name="sortColumn"/> 
			<input type="text" value="asc" placeholder="排序方式" id="direction" name="direction"/> 
			<input type="text" value="1" placeholder="是否启用" id="isValid" name="isValid"/>
			<input type="date" value="" placeholder="开始时间" id="createTimeStart" name="createTimeStart"/>
			<input type="date" value="" placeholder="结束时间" id="createTimeEnd" name="createTimeEnd"/>
			<input type="text" value="" placeholder="地址" id="addresses" name="addresses"/>
	</div>
	
	<h3>测试多表联查</h3>
	<div>
		关联ID:<input type="text" value="11" name="webUser" id="webUser"/>
		<input type="button" value="查询所有2" id="findAllAddress"/>
	</div>
	
	<div>
		<table>
			<thead>
				<tr>
					<td>ID</td>
					<td>USERNAME</td>
					<td>EMAIL</td>
					<td>PHONENO</td>
					<td>REALNAME</td>
					<td>DELETE</td>
				</tr>
			</thead>
			<tbody id="content">
			</tbody>
		</table>
	</div>
</body>
<script type="text/javascript">
	
	$(function(){
		
		$("#findAllAddress").click(function(){
			alert("123");
			$.post("/address/findAll.do",{
				webUser:$("#webUser").val(),
				id:$("#id").val()
			},function(data){
				alert(data.data.content);
			});
		});
		
		$("#submit").on('click', function() {
			
			var _userName = $("#userName").val();
			var _password = $("#password").val();
			var _email = $("#email").val();
			var _phoneNo = $("#phoneNo").val();
			var _realName = $("#realName").val();
			
			$.post("/WebUser/save.do", {
				userName : _userName,
				password : _password,
				email : _email,
				phoneNo : _phoneNo,
				realName : _realName
			}, function(data) {
				alert(data.msg);
			});
		});
		
		
		$("#submitAddress").on('click', function() {
			
			var _label = $("#label").val();
			var _country = $("#country").val();
			var _province = $("#province").val();
			var _city = $("#city").val();
			var _address = $("#address").val();
			
			$.post("/address/save.do", {
				label : _label,
				country : _country,
				province : _province,
				city : _city,
				address : _address
			}, function(data) {
				alert(data.msg);
			});
		});

		$("#update").on('click', function() {
			
			var _id = $("#id").val();
			var _userName = $("#userName").val();
			var _password = $("#password").val();
			var _email = $("#email").val();
			var _phoneNo = $("#phoneNo").val();
			var _realName = $("#realName").val();
			
			$.post("/WebUser/update.do", {
				id : _id,
				userName : _userName,
				password : _password,
				email : _email,
				phoneNo : _phoneNo,
				realName : _realName
			}, function(data) {
				alert(data.msg);
			});
		});

		$("#findAll").on(
				'click',
				function() {
					$.post("/WebUser/findAll.do", {
						page : $("#page").val(),
						size : $("#size").val(),
						sortColumn : $("#sortColumn").val(),
						direction : $("#direction").val(),
						userName : $("#userName").val(),
						email : $("#email").val(),
						phoneNo : $("#phoneNo").val(),
						isValid : $("#isValid").val(),
						createTimeStart : $("#createTimeStart").val(),
						createTimeEnd : $("#createTimeEnd").val()
					}, function(data) {
						$("#content").html();
						var html = "";
						$.each(data.data.content, function(i, val) {
							html += "<tr><td>" + val.id + "</td>" + "<td>"
									+ val.userName + "</td>" + "<td>" + val.email
									+ "</td>" + "<td>" + val.phoneNo + "</td>"
									+ "<td>" + val.realName + "</td>"
									+ '<td><a href="/WebUser/deleteOne.do?id='
									+ val.id + '">删除</a></td></tr>';
						});
						$("#content").html(html);
					});
				});
		
	})

	
</script>
</html>

 

启动项目:

看到数据库生成的表:

可以看到父类的字段,备注等都有。

 

随手添加了几条数据。

然后测试两个表的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
	}
}

 

  • 27
    点赞
  • 104
    收藏
    觉得还不错? 一键收藏
  • 14
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值