一:为什么学习Springboot
回顾我们之前写的项目,以及我们学会的技术越来越多,我们会发现项目变的越来越大,我们项目的配置文件变的非常复杂,并且配置文件非常多,jar包依赖也变得非常多,项目越来越臃肿,配置起来也越来越麻烦。而springboot可以简化我们的配置,达到开箱即用的效果。
Springboot与spring,springmvc之间有什么区别
spring:
主要用处是ioc用来管理对象,降低应用之间的一个耦合度。
aop主要用来控制事物。
springMVC:
springmvc提供了分离的方式让我们来简化web应用的开发,通过DispatcherServlet,ModelAndView等元素让我们开发web应用更加简单,但是无论是spring还是springmvc都有一个共同的特性,就是都需要大量的配置才可以使用。
springboot:
1:主要用来简化spring应用程序的初始化以及搭建过程。
1.1:将项目需要使用的很多依赖整合到了一起(简化了maven配置)
2.2:提供了很多很多的默认配置,用户可以不需要进行太多配置,即可启动项目(应用程序提供有自动的配置)
2:嵌入式的tomcat容器,我们不需要使用编译工具去管理tomcat。
3:springboot提供应用的测试以及监控等一条龙服务。
创建springboot项目的方式有两种:
1:搭建普通的maven项目,然后引入springboot的依赖即可。
2:下载官方的demo,然后使用编译工具导入即可。 Spring Initializr
项目结构:
1:springbootApplication类: 项目的入口,我们需要使用这个类来启动项目。
2:application.properties属性文件: 如果我们需要修改springboot的默认配置,需要将修改的配置写在这里。
3:static 存放所有web的静态资源(css,js,img等…)。
4:templates 存放我们项目页面的地方。
Spring Boot 中的 starter是什么
starter是springboot中的启动器,我们可以理解他为一组依赖的描述符,里面定义了所有当前启动器相关的依赖以及默认配置,我们只需要下载启动器就能吧所有相关依赖下载下来,并且所有的相关依赖版本都由启动器自动管理,不需要我们进行操心。
为什么我们访问ishangu包下的hello2Controller访问不到呢?
在项目中我们没有做任何配置,包括扫描路径我们也没有进行配置,访问hello2会出现404代表这个路径没有被springIOC容器扫描,那为什么hellocontroller就被扫描了呢?
为什么我们访问application.controller包下的helloController能访问到呢?
springboot提供有很多默认配置,其中就包括默认的扫描路径,而其默认的扫描路径是启动类所在的包,以及其所有的子包。
那么为什么springboot会默认扫描启动类下面的所有类呢?
@SpringBootApplication 用来表示这个类是springboot的启动类,这个启动类我们一般也称之为主配置类,@SpringBootApplication注解是一个组合注解,里面包含有以下注解:
@SpringBootConfiguration 用来修饰类,表示这个类是一个配置类(相当于配置文件),作用于spring中的@Configuration一致。
@EnableAutoConfiguration 开启自动配置的功能,以前配置文件中很多内容都需要我们自己去写,而springboot提供了很多默认的配置,而这些配置就是使用这个注解来开启的,使用这个注解之后,会自动加载spring-boot-autoConfiguration依赖里面的默认配置。
@ComponentScan( 用处是用于扫描所有spring的相关注解(相当于直接在xml中配置的扫描路径),默认扫描的是当前类所在的包下以及其所有子包。
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter( 过滤器
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
如何将bean配置到IOC容器中
方式一:@SpringBootConfiguration注解配合@Bean注解来讲一个类的对象放入到IOC容器之中。
@SpringBootConfiguration // 用来表示这个类相当于一个xml配置文件
public class BeanConfig {
/**
* @Bean 相当于之前xml中的 bean标签,会将方法的返回值放入到ioc容器里面
*/
@Bean
public Cat getCat(){
return new Cat();
}
}
方式二:使用@import注解导入
@RestController
@Import(Dog.class) // 将Dog的实例化对象放入到IOC容器之中
public class HelloController {
@Autowired
Cat cat;
@Autowired
Dog dog;
@RequestMapping("hello")
public String hello(){
System.out.println(cat);
System.out.println(dog);
return "hello";
}
}
方式三:使用@import注解配合importSelector接口
public class ConfigSelector implements ImportSelector {
/**
* 这里面要求返回的是实例化对象的全限定名
*/
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[] {"com.ishangu.springboot.Dog"};
}
@Nullable
@Override
public Predicate<String> getExclusionFilter() {
return null;
}
}
@RestController
@Import(ConfigSelector.class)
public class HelloController {
@Autowired
Cat cat;
@Autowired
Dog dog;
@RequestMapping("hello")
public String hello(){
System.out.println(cat);
System.out.println(dog);
return "hello";
}
}
方式四:使用@import注解配合importBeanDefinitionRegistrar接口
public class ConfigDeferredImport implements ImportBeanDefinitionRegistrar{
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
//判断ioc容器中是否有这个类型的bean,如果存在返回true,如果不存在返回false
boolean b = registry.containsBeanDefinition("com.ishangu.application.Dog");
if (!b){ //进入到if证明ioc容器中没有dog
RootBeanDefinition root = new RootBeanDefinition(Dog.class);
registry.registerBeanDefinition("dog",root);
}
}
}
@RestController
@Import(ConfigDeferredImport.class)
public class HelloController {
@Autowired
Cat cat;
@Autowired
Dog dog;
@RequestMapping("hello")
public String hello(){
System.out.println(cat);
System.out.println(dog);
return "hello";
}
}
方式五:引入xml配置文件中的bean(不推荐使用)
像之前一样写application.xml然后使用注解引入这个配置文件
@ImportResource(“application.xml”)
修改springboot默认配置
在我们springboot项目中一般都存在一个application.properties或者application.yml配置文件,这个文件是springboot的配置文件名称是绝对不能修改的,修改后springboot就不会加载这个文件了,我们可以在这个文件中修改springboot提供的默认配置,在springboot项目中允许properties和yml文件同时存在,并且两个文件都会进行加载,但是需要注意的有一点,那就是properties属性文件的优先级别较高,也就是说当我们在properties和yml中同时修改一项内容的时候springboot会以properties文件的内容为主。
#server.port=8888
server:
port: 9999
通过观察我们发现,当只有yml的时候启动项目端口是9999,当两者同时存在的时候启动的端口以properties中的端口为主。
SpringData-JPA
JAP是ORM持久层的规范,jpa自身只是定义了规范而已,其实现需要依靠ORM框架来进行实现。
JPA: 简称Java持久层Api,主要通过hibernate来提供实现,因为hibernate是全自动的ORM框架(mybatis只是半自动的ORM框架,所以没有实现JPA规范)。
需要注意的是,当我们引入JPA依赖之后,springboot并不知道我们想使用的数据库是什么,所以我们需要自己引入数据库的驱动包,并且springboot,并且spring也不知道我们数据源相关内容,所以只能让我们自己来配置。
springdatajpa给我们提供了很多Repository接口:
1:Repository接口 祖爷爷
1: 我们只需要在接口中写方法名称,只要方法名称写的规范,jpa会自动给我们生成查询的sql语句。
2:提供了@Query注解让我们可以在注解中写sql语句
2:CRUDRepository接口 爷爷
1:有Repository接口的所有功能
2:自身提供了很多CRUD的方法。
3:pagingAndSortingRepository接口 父亲
1:有CRUDRepository接口的所有功能
2:自身提供了分页和排序的功能
4:JPARepository接口 儿子
1:有pagingAndSortingRepository接口的所有功能,并且可以对父接口的返回值进行适配。
5:JPASpecificationExecutor接口 单独的
1:与上面几个完全没有任何关系,是一个自身独立的接口
2:主要用来实现的多条件查询
1:pom引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.22</version>
</dependency>
2:编写model类
package com.ishangu.springboot.model;
import javax.persistence.*;
/**
* 与数据库对应的model类
*/
@Entity //说明这个类是一个与数据库对应的model类
@Table(name="user") //当类名与数据库表名不一致的时候使用
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) //指定主键生成策略
@Column(name = "id") //指定对应数据库的列名
private Integer id;
@Column(name = "name") //指定对应数据库的列名
private String name;
@Column(name = "age") //指定对应数据库的列名
private Integer age;
@Column(name = "password") //指定对应数据库的列名
private String password;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", password='" + password + '\'' +
'}';
}
}
3: 编写dao层接口
package com.ishangu.springboot.repository;
import com.ishangu.springboot.model.User;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
// 泛型中存放的是model类的 类型以及,ID的类型
public interface UserRepository extends CrudRepository<User,Integer>{
/* @Query(value = "from User where name=:name and password=:password")
User login(@Param("name") String name ,@Param("password") String password);*/
// 方式二:要求查询时候必须要以find,get,read开头,findAll表示查询多个,findBy属性名表示根据属性来进行查询 ,后面可以不断的跟and或or来拼接多个属性。
User findByNameAndPassword(@Param("name") String name ,@Param("password") String password);
}
4:编写service以及其实现类
package com.ishangu.springboot.service;
import com.ishangu.springboot.model.User;
import java.util.List;
public interface UserService {
void save(User user);
void update(User user);
void delete(Integer id);
User login(String username,String password);
User findByID(Integer id);
List<User> findAll();
}
package com.ishangu.springboot.service.impl;
import com.ishangu.springboot.model.User;
import com.ishangu.springboot.repository.UserRepository;
import com.ishangu.springboot.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
@Service
public class UserServiceImpl implements UserService{
@Autowired
UserRepository repository;
@Override
public void save(User user) {
repository.save(user);
}
@Override
public void update(User user) {
repository.save(user);
}
@Override
public void delete(Integer id) {
repository.deleteById(id);
}
@Override
public User login(String username, String password) {
return repository.findByNameAndPassword(username,password);
}
@Override
public User findByID(Integer id) {
Optional<User> u = repository.findById(id);
return u.get();
}
@Override
public List<User> findAll() {
Iterable<User> all = repository.findAll();
return (List<User>) all;
}
}
5:编写controller
package com.ishangu.springboot.controller;
import com.ishangu.springboot.model.User;
import com.ishangu.springboot.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class UserController {
@Autowired
UserService service;
@RequestMapping("save")
public String save(User user){
service.save(user);
return "OK";
}
@RequestMapping("update")
public String update(User user){
service.update(user);
return "OK";
}
@RequestMapping("delete")
public String delete(Integer id){
service.delete(id);
return "OK";
}
@RequestMapping("login")
public User login(String name,String password){
return service.login(name,password);
}
@RequestMapping("findByID")
public User findByID(Integer id){
return service.findByID(id);
}
@RequestMapping("findAll")
public List<User> findAll(){
return service.findAll();
}
}
6: 启动项目进行测试。