SpringBoot(2.0)基于Grandle

233 阅读20分钟

springboot

一、微服务

​ 微服务架构是松耦合的分布式软件服务。在云中部署和服务的新技术。是一种架构风格。

​ 微服务架构”一词是在过去几年里涌现出来的,它用于描述一种独立部署的软件应用设计方式。这种架构方式并没有非常明确的定义,但有一些共同的特点就是围绕在业务能力、自动化布署、端到端的整合以及语言和数据的分散控制上面。

​ “微服务”- 这是在软件架构领域这个非常拥挤的街道上,冒出的一个新名词而已。虽然我们对这个新出的名词不屑一顾,但是它所描述的软件系统的风格越来越吸引我们的注意力。在过去的几年里,我们发现越来越多的项目开始使用这个风格,并且到目前为止得到的反馈都是积极的,以至于我身边的许多同事在设计企业架构时,都把它作为默认的构建方式,然而很不幸,到底什么是微服务,我们又如何来使用它,外界并没有太多的信息可供参考。

​ 总之,微服务这种架构风格就是把一组小服务演化成为一个单一的应用的一种方法。每个应用都运行在自己的进程中,并通过轻量级的机制保持通信,就像HTTP这样的API。这些服务要基于业务场景,并使用自动化布署工具进行独立的发布。可以有一个非常轻量级的集中式管理来协调这些服务,可以使用不同的语言来编写服务,也可以使用不同的数据存储。

​ 在开始解释什么是微服务之前,先介绍一下单体应用还是很有用的:把一个单体应用构建成为一个部分。企业应用通过是由三个重要部分组成:客户端界面(由HTML、Javascript组成,使用浏览器进行访问)、数据库(由许多的表组件构成一个通用的、相互关联的数据管理系统)、服务端应用。服务端应用处理HTTP请求、执行领域逻辑、检索并更新数据库中的数据、选择和填充HTML视图发送给客户端。这个服务端应用是一个单块结构也就是一个整体,这是一个可执行的单一逻辑,系统中的任何修改都将导致服务端应用重新编译和布署一个新版本。

​ 就这样一个单体应用很自然的被构建成了一个系统,虽然可以使用开发语言基本特性会把应用封装成类、函数、命名空间,但是业务中所有请求都要在单一的进程中处理完成,在某些场景中,你可以在开发人员的笔记本电脑中运行和测试,并且通过布署通道将测试通过的程序布署到生产环境中,你还可以水平扩展,利用负载均衡将实例布署到多台服务器中。

​ 的确,单体应用也是很成功的,但是越来越多的人感觉到了不妥,特别是应用程序被发布到了云的时候,变更发布周期被绑定了 —- 原来可以划分成小的应用、小的需要的变更,需要统一的进行编译和发布。随着时间的推移,软件开发者很难保持原有好的模块架构,使得一个模块的变更很难不会影响到其它的模块,而且在扩展方面也只能进行整体的扩展,而不能根据进行部分的扩展。这些原因导致了微服务架构风格的出现:以服务构建应用。这些服务还可以被独立布署、独立扩展,每个服务也都提供了清晰的模块边界,甚至不同的服务都可以使用不同的编程语言来实现,也可以由不同的团队进行管理。

​ 微服务的概念不是我们发明的,它至少起源于Unix时代的设计原则,我们认为这种风格所带来的好处,并没有引起足够多人的重视。

微服务架构特征

​ 我们没有办法对微服务有一个正式的定义,但我们可以尝试表述适合这种架构的共同特征来给它打上特性标签,共同特性并不代表每个服务都具备这些特点,但是我们真的期望大多数微服务架构能具备其中大部分特点。虽然我们的作者已经是松散社区的核心成员,但是我们也在尝试描述我们工作中或者我们了解的组件中所理解的微服务。我们并不依赖于那些已经明确过的定义。

组件化与服务

​ 只要我们一直在从事软件行业,我们的愿望就是,软件由很多组件组装在一起,如同物理现实世界中类似的构造方式。在过去的几十年里,我们已经看到了大部分语言平台公共库有了长足的进步。

​ 当我们在谈论组件时,我们遇到了组件定义方面的困难,我们给定的定义是:一个组件是软件中的一个部分,可以独立的替换和升级。

​ 微服务也会使用组件库,将一个软件组件化的主要方式就是将其分解成服务,我们定义的库是可以连接到程序并使用内存函数的的组件库,服务是进程外的组件,如Web请求服务或者远程调用来相互通信的组件。(这种定义的方式与其它面向对象程序中服务对象的概念是不一样的。)

​ 把服务当成组件(而不是组件库)的一个原因是服务可以独立布署,如果你有一个应用是由多个库组成并且运行在一个进程中,那么任何一点的改变都会引起整个应用的重新发布,但是将这个应用拆解为多个服务,你可以期待每个服务的变更仅需要发布相应的服务就可以,当然这也不是绝对的,比如导致服务接口变更的更新就需要相应服务的变化,但是良好的架构设计是通过聚合服务边界并且按照合约实现服务演化,最大限度地减少因为改变影响其他地方。

​ 把服务当成组件的另一个考虑是这会拥有更加清晰的接口,大多数的语言并没有一个很好的机制来定义一个明确显式的发布接口,通常只有文档和规范说明,让用户避免组件间过度紧密而导致高耦合,通过显示的远程调用机制,可以避免这种情况。

​ 使用服务也有其自身的缺点,远程调用比进程内部调用更加消耗性能,而且远程的API往往是粗粒度的,用起来不是很友好,对组件的职责进行变更,也会影响到进程间的交互,那么操作起来也比较困难。

​ 第一个可能性,我们看到每个服务是运行在独立的进程上的。注意,这只是第一个可能性。服务也可以由多个进程组成,它们是同时开发和部署的,如果一个应用进程和一个仅由该服务使用的数据库。

围绕业务能力进行组织

​ 当我们把一个大的应用拆分成小的部分时,我们的注意力主要集中在技术层面,拆分成UI团队、服务端的逻辑团队和数据库团队。当使用这种标准对团队进行划分时,甚至一个非常小的更变都将导致跨团队间项目协作,从而消耗时间和预算审批。一个高效的团队会针对这种情况进行改善,关注它们所涉及的应用逻辑,并从中做出较好的选择。换句话说,逻辑无处不在。康威定律就是一个例子。微服务的划分方法有所不同,它更倾向于围绕业务功能对服务结构进行划分、拆解,这些服务可以采用不同的技术栈来实现,包括用户界面,持久层存储,或任何对外协作,因此团队应该是跨职能的,包括开发所需要的全部技术:用户体验、数据库和项目管理。按照这种方式组织的公司是 www.comparethemarket.com,跨职能团队负责建立和操作每个产品并且每个产品都被分成若干单独的服务通过消息进行通信。

​ 大型的单体应用也可以按照业务功能进行模块化的,尽管这种例子不常见。当然,我们也会敦促一个大型团队在构建一个单体应用时按照业务线来进行划分,我们能看到主要问题在于,这种组件形式会导致很多的上下文依赖,如果这个系统跨越很多模块边界,对于一个单独团队是很难在短时间解决问题的。此外,我们发现模块化方式需要大量的规范去强制执行,而服务组件明确的划分,使得团队间的边界也变得清晰起来。

产品不是项目

​ 大多数的开发工作是使用这样一种模型:其目的是完成可以交付的软件,软件开发完成就交给了维护团队,该项目组也就解散了。

​ 微服务的支持者建议避免这种模型,认为一个团队应该负责产品的整个生命周期,一个很通用的概念就是Amazon’s的“you build, you run it”,它要求开发团队对软件产品的整个生命周期负责,这使得开发人员可以每天都关注产品的运行情况,而且也能够与用户保持紧密的联系,做一些必要的支持工作。

​ 产品方式开发意味着与业务能力紧紧捆绑在一起,而不是将软件看成是一系列完成的功能,他们会关注如何让软件帮助其用户提升业务能力。

​ 单体应用也可以采用上述产品的理念,但是更小粒度的服务可以更容易的创建开发者与用户之间的关系。

智能终端与弱管道

​ 当在不同的进程之间构建各种通信结构时,我们已经看到许多产品和方法,来强调将大量的智能特性融入到通信机制本身,这种情况的一个典型例子就是“企业服务总线”(Enterprise Service Bus,ESB)。ESB产品经常包括高度智能的设施来进行消息的路由、编排、转换,并应用业务规则。

​ 微服务社区主张采用另一种做法:智能终端和弱管道。使用微服务所构建的各个应用的目标都是尽可能实现“高内聚和低耦合”–他们拥有自己的领域逻辑,并且更多的是经典的UNIX的“过滤器”那样工作–即接收请求、处理逻辑、返回响应,这些应用通过使用简单的REST风格的协议来进行编排,而不去使用复杂的协议,比如:WS、BEPL或者集中式工具进行编排。

​ 有两种协议最经常被使用到:包含资源API的HTTP的请求-响应和轻量级消息通信协议。最为重要的建议为:

​ 微服务团队采用这样的原则和规范:基于互联网(广义上,包含Unix系统)构建系统。这样经常使用的资源几乎不用什么的代价就可以被开发者或者运行商缓存。

​ 第二种做法是通过轻量级消息总线来发布消息。这种的通信协议非常的单一(单一到只负责消息路由),像RabbitMQ或者ZeroMQ这样的简单的实现甚至像可靠的异步机制都没提供,以至于需要依赖产生或者消费消息的终端或者服务来处理这类问题。

​ 在一个单块系统中,各个组件在同一个进程中运行。它们相互之间的通信,要么通过方法调用,要么通过函数调用来进行。将一个单块系统改造为若干微服务的最大问题,在于对通信模式的改变。仅仅将内存中的方法调用转换为RPC调用这样天真的做法,会导致微服务之间产生繁琐的通信,使得系统表现变糟。取而代之的是,需要用更粗粒度的协议来替代细粒度的服务间通信。

二、创建自己的springboot程序

简便方法

登录start.spring.io选择自己需要的依赖以及构建工具。然后下载。

然后我们可以将下载下来的项目导入到ide中。然后启动项目。

@SpringBootApplication
public class DemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
	}

}

我们在导入之后,在为启动之前我们 可以修改一下build.gradle文件。覆盖以前的。

repositories {
	maven{
		url  'http://maven.aliyun.com/nexus/content/groups/public'
	}
	mavenCentral()
}

注解

@Controller   //将类变成控制类
@RequestMapping  //请求的路径
@ResponseBody    //请求  并且返回字符串本身
@RestController    //相当于Control+ResponBody

三、spring

多模块,每个模块都是jar文件,里面有很多类;

优点:

  • 大大简化了开发
  • 附加了很多能力
  • 可以装配对象之间的依赖关系

spring是一个容器,也是一个框架。

如何把自己的东西放入spring容器中呢?

定义一个配置类,也就是一个容器。

  • spring IOC 控制反转

    • 它是sprin的核心,spring帮我们管理JavaBean,并提供了一些常用的功能,帮我们装配对象之间的依赖关系。r如果要使用spring的强大功能,我们要定义一个容器类、配置类,把自动的Javabean放在里面。
    @Configguration //这个注解标志着一个配置类
    
    @Autowired //自动装配
    
  • spring AOP 面向切面的编程

    • spring的两个核心,IOC和AOP
      • Aop和oop正好相反,AOP是面向切面的编程,oop是面向对相的编程。
      • AOP是通过动态代理和反射机制为某个类在底层自动生成它的子类,并趁机植入一些代码。是动态地为当前的对象的某些方法的首尾增加一些代码。
  • spring DAO 数据访问

    • spring-jdbc为我们封装了很多操作数据的方法。
    • JDBCTemplate 这个类有很多方法,让我们可以选择操作数据库。
  • SpringMVC

    • spring给我们写好了一个类,DispatchServlet,它能截获用户的请求,它就找HandlerMapping(处理映射) 询问那个handler来处理这个请求,Handler处理完之后返回一字符串返回给DisPatchServlet。DispatchServlet找ViewRelover来把这个字符串解析成一个正真的视图文件,相应给客户。

四、Spring注解

1、标志一个配置类

@Configration  //标志一个配置类

2、自动装配

​ 有了这个注解不用get set方法

@Autowired //自动装配
private Person per;

@Autowried  //给参数自动装配
public void setD(double h){
  this.h=h;
}

//自动装配
public void setDi(@Autowried Person p){...}

3、自动扫描的注解

@ConponentScan(Package='com.cbbgs'//自动扫描加了下面注解的对象进入当前容器。
  
  
@Component    //普通的类
@Service     //逻辑层
@Controller  // 业务层
@Repository //持久层

4、引入xml文件

@ImportResource(“classpath:spring.xml”)
@Import(YouConfig.class)

5、@Bean用在方法上

@Bean //方法的返回的一个类也自动加载到容器里面
public Person fun(){
  return p;
}

五、springboot核心注解

1、加了这个注解就是启动类(核心注解)

@SpringBootApplication //启动类
@ComponentSacan(basePackages={"com.cv","cbbgs.cn"})  //其他的包下的类也可以扫描到
@Import(MyConfigrution.class)


//此注解类的部分源码为:
    @SpringBootConfiguration   //配置类注解
    @EnableAutoConfiguration  //启用自动配置
    @ComponentScan 			//组件扫描组件
    public @interface SpringBootApplication{   }

2、标志一个配置类

@Configration  //配置类

@ComponentSacan  //如果不指名包,就只能扫描当前包的加了Contrallor和其余两个注解的类


3、此注解只能定义在类前面; 加了这个注解的类就是处理请求的类。

@Controller    //用在控制层

4、方法返回的是字符串的本身,而不会去请求业务。

@RestController  //用在控制层

//这个注解相当于下面两个注解的意思
@Controller
@ResponseBody



5、请求映射的路径

@RequestMapping("/user/{a}") 


6、加在方法的参数前,获取URI路径变量的值(核心注解)

@PathVariable  

//用法
 	@RequestMapping("/user/{a}")
    @ResponseBody
    public String fun1(@PathVariable("a") String a){
        return "hell0"+a;
    }


7、接受请求参数(核心注解)

@RequestParam

//用法

//当我请求http://localhost:user1?name=zhangsan&password=123456时
  	@RequestMapping("/user1")
    @ResponseBody
    public String fun1(@RequestParam("name") String name,
                        @RequestParam("password") String password){
        return "hell0"+"----"+name+password;
    }

//当请求的字段和实体类的属性名一样的话可以实现自动封装

8、这个注解主要是用户返回响应体,返回什么就响应什么,不去请求业务

@ResponseBody  //返回响应体

六、springboot 的一些事

1、springboot类路径

Spring Boot的核心配置文件是application.properties或application.yml。

  • properties文件格式如下:
spring.datasource.url=jdbc:mysql://localhost:3306/test

  • yml文件的格式如下:
spring:
          datasource:
              ur: jdbc:mysql://localhost:3306/test 

  • 改变访问端口
   server.port=8081
  • 访问静态资源 只要把静态资源放在下面目录中就可以直接访问:
   { "classpath:/META-INF/resources/",
       "classpath:/resources/", 
        "classpath:/static/",
            "classpath:/public/" }

  • 欢迎页面
  • 只要定义个index.html且放在
"classpath:/META-INF/resources/",
“classpath:/resources/”, “classpath:/static/”, “classpath:/public/

只要定义个index.html且放在

2、springboot日志

SpringBoot已经为我们配置好了日志!我们只需要在定义日志的类中增加下面的代码即可。

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
//注意导报

Log log=LogFactory.getLog(UserClass.class);//用户自己的类
log.info("报错了");

在application.properties配置文件中配置在哪个包下用什么等级的日志

logging.level.cn.cbbgs=debug

Log Level: ERROR, WARN, INFO, DEBUG, or TRACE.

4.springboot自启动

在build.gradle中添加spring-boot-devtools即可。(坐标)

如果我们想让静态文件的修改不引起重新启动,那么在application.properties中添加: spring.devtools.restart.exclude=static/,public/

七、springboot jpa

当提供的方法不满足我们的需求时,我们需要在Dao层声明我们自己方法。这个方法需要按照它指定的命名规范来命名。系统提供的方法可以在service中直接使用,不用在dao中声明

一、了解spring data jpa的原理

从两个方面了解,一个是源码,一个是官网

如果springboot工程需要使用jpa来访问数据库,需要导入两个包

implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'mysql:mysql-connector-java:5.1.15'

一共需要导报

implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'mysql:mysql-connector-java:5.1.15'
    // https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl
runtime 'javax.servlet:jstl: 1.2'
    // https://mvnrepository.com/artifact/org.apache.tomcat.embed/tomcat-embed-jasper
compile'org.apache.tomcat.embed:tomcat-embed-jasper:9.0.27'

spring data 是spring的一个子项目,是数据访问的模块。

使用步骤
  • 1、准备好数据库
  • 2、配置依赖
  • 3、配置application.properties中配置数据源和spring jpa相关属性
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=123
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update  //create会清空数据
spring.jpa.show-sql=true
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp

  • 4、定义实体类(ORM技术对象关系映射)

    @Entity 					//实体
    @Table(name = "book")		//对应数据库中的表
    public class Book implements Serializable{
    	@Id 					//主键
    	@GeneratedValue(strategy = GenerationType.IDENTITY)//自增长(整型)
    	private Integer id;
    	private String bookName;
    	private String author;
    	public Integer getId() {
    		return id;
    	}
    	public void setId(Integer id) {
    		this.id = id;
    	}
    	public String getBookName() {
    		return bookName;
    	}
    	public void setBookName(String bookName) {
    		this.bookName = bookName;
    	}
    	public String getAuthor() {
    		return author;
    	}
    	public void setAuthor(String author) {
    		this.author = author;
    	}
    	
    }
    
  • 5、定义实体类仓库,其实是个接口,继承JpaRepository接口,我们 不需要实现实体类仓库的接口

@Repository  //Dao层的注解都不用加
public interface BookDao extends JpaRepository<Book, Integer>{  //第一个是数据源的类型  第二个是实体对应表的主键
	//自定义查询
	public List<Book> findByBookName(String bookName);
}

springboot jpa既能为我们写好了Dao的实现类,也帮我们把它放在了容器中。

JpaRepository为我们提供了如下方法

  <S extends T> S save(S entity); 
    Optional<T> findById(ID primaryKey); Iterable<T> 	findAll();
   long count(); 
   void delete(T entity); 
   boolean existsById(ID primaryKey);

//分页
Iterable<T> findAll(Sort sort);
 Page<T> findAll(Pageable pageable); 

//自定义查询
(findBy字段名)
Page<User> findByLastname(String lastname, Pageable pageable);

Slice<User> findByLastname(String lastname, Pageable pageable);

List<User> findByLastname(String lastname, Sort sort);

List<User> findByLastname(String lastname, Pageable pageable);


//具有排序的
User findFirstByOrderByLastnameAsc();

User findTopByOrderByAgeDesc();

Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);

Slice<User> findTop3ByLastname(String lastname, Pageable pageable);

List<User> findFirst10ByLastname(String lastname, Sort sort);

List<User> findTop10ByLastname(String lastname, Pageable pageable);
  • 6、准备Service
@Service
public class BookService {
	@Autowired //Resourse
	private BookDao bookDao;
	public Book addBook(Book book) {
		return bookDao.save(book);
	}
  //自定义查询
  public List<Book> findByName(String name){
		return bookDao.findByBookName(name);
	}
}
  • 7、准备Controller
@Controller
public class Conntroller {
	@Autowired
	private BookService bookService;
	@RequestMapping("/addbook")
	@ResponseBody
	public Book saveBook(Book book) {
		return bookService.addBook(book);
	}
  
  	@RequestMapping("/findByName")
	@ResponseBody
	public List<Book> findByName(String name) {
		return bookService.finBookByName(name);
	}
}

启动starter http://localhost:8080/addbook3?bookName=sss&author=222

二、springboot jpa高级

1、当启动类和其他类不在一个包下

此时我们需要在启动类添加这个注解


@SpringBootApplication
@Import(MyConfig.class)  //加载自己的配置
@EntityScan("com.example.chenbin")  //加载实体类
public class Chenbin2Application {

	public static void main(String[] args) {
		SpringApplication.run(Chenbin2Application.class, args);
	}

}

需要在非启动类中建立自己的配置类

@Configuration	//配置类的的注解
@ComponentScan	//自动扫描包
@EnableJpaRepositories  //加载Dao的
public class MyConfig {

}

然后就可以了!

2、分页查询

1、默认查询所有的按分页显示
//分页查询
	public Page<Book> findPage(int pn,int ps){
		return bookDao.findAll(PageRequest.of(pn, ps));
	}
2、自定义分页查询(按书名分页查询)

dao

//自定义按书名分页查询
	public List<Book> findByBookName(String bn,Pageable page);

	//自定义按书名模糊分页查询
	public List<Book> findByBookNameLike(String bn,Pageable page);

service

//按书名分页查询
	public List<Book> findbyBookName(String bn,int pn, int ps){
		return bookDao.findByBookName(bn, PageRequest.of(pn, ps));
	}
	
	//按书名模糊分页查询并排序
public List<Book> findbyBookNameLike(String bn,int pn, int ps){
		return bookDao.findByBookNameLike(bn, PageRequest.of(pn, ps,Sort.by(Direction.DESC,"price")));
		}

controller

//分页查询
	@RequestMapping("/findPage")
	@ResponseBody
	public List<Book> findPage(@RequestParam("pn")int pn,@RequestParam("ps")int ps) {
	Page<Book> page = 	bookService.findPage(pn, ps);
	return page.getContent();
	}
	
	//按书名分页查询
	@RequestMapping("/findBookByNameAndPag")
	@ResponseBody
	public List<Book> findBookByNameAndPag(@RequestParam("bn")String bn,@RequestParam("pn") int pn,@RequestParam("ps") int ps){
		return bookService.findbyBookName(bn, pn, ps);
	}
	//按书名模糊分页查询
		@RequestMapping("/findBookByNameAndPagLike")
		@ResponseBody
		public List<Book> findBookByNameAndPagLike(@RequestParam("bn")String bn,@RequestParam("pn") int pn,@RequestParam("ps") int ps){
			return bookService.findbyBookNameLike(bn, pn, ps);
		}

3、修改(update)

更新一般返回的是一个整型

第一种通过save方法来修改

//直接在service层调用save()方法
//用save来修改
		@Transactional  //修改表涉及到事务
		public Book updateBookAuthor(Book book) {
			return bookDao.save(book);
		}



controller层
//更新
		@RequestMapping("/update")
		@ResponseBody
		public Book updateBook(Book book){
			return bookService.updateBookAuthor(book);
		}	

第二种通过@modifying注解和@Query来修改

@Query当我们的方法命名不符合规范时就使用@Query(sql语句)来指定sql语句

DAO层
//第二种方式修改
	@Transactional	
	@Modifying
	@Query("update Book b set b.price=?2 where b.id=?1")
	public int update(Integer id,Integer price);
	

service层

//修改价格
		
		public int updatePrice() {
			List<Book> books = bookDao.findAll();
			int count=0;
			for(Book book: books) {
				bookDao.update(book.getId(),33);
				count+=1;
			}
			return count;
			
		}

4、删除

按照命名规范参照查询的方法,将find改为delete就可以了

5、表关联

user表与depart表一对多、user表与role表多对多

@Entity
@Table(name = "ta_user")
public class User {
	@Id
	@GeneratedValue
	private Integer uid;
	private String userName;
	@ManyToOne				//关联的主键  一对多
	@JoinColumn(name="departid")
	private Depart depart;
	//多对多关联
	@ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.MERGE},fetch = FetchType.LAZY)
	@JoinTable(name="user_role",
				joinColumns = {@JoinColumn(name="uid")},
				inverseJoinColumns = {@JoinColumn(name="roleId")}
			)
	private List<Role> role;
	public Integer getUid() {
		return uid;
	}
	public void setUid(Integer uid) {
		this.uid = uid;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public Depart getDepart() {
		return depart;
	}
	public void setDepart(Depart depart) {
		this.depart = depart;
	}
	

}


####6、排序

dao层
//自定义按书名模糊分页查询
	public List<Book> findByBookNameLike(String bn,Pageable page);
	
service层

//按书名模糊分页查询并排序
		public List<Book> findbyBookNameLike(String bn,int pn, int ps){
			return bookDao.findByBookNameLike(bn, PageRequest.of(pn, ps,Sort.by(Direction.DESC,"price")));
		}

相当于在PageRequest.of后面加一个参数

如果不用用分页的排序

List<User> findByLastname(String lastname, Sort sort);

Sort sort = Sort.by("firstname").ascending()
  .and(Sort.by("lastname").descending());
 @Query("select u from User u where u.lastname like ?1%")
  List<User> findByAndSort(String lastname, Sort sort);

  @Query("select u.id, LENGTH(u.firstname) as fn_len from User u where u.lastname like ?1%")
  List<Object[]> findByAsArrayAndSort(String lastname, Sort sort);
}

repo.findByAndSort("lannister", new Sort("firstname"));               
repo.findByAndSort("stark", new Sort("LENGTH(firstname)"));           
repo.findByAndSort("targaryen", JpaSort.unsafe("LENGTH(firstname)")); 
repo.findByAsArrayAndSort("bolton", new Sort("fn_len"));         
List<User> findFirst10ByLastname(String lastname, Sort sort);

三、jpa命名规范